From b15c7aa4e607eb69890eff10c4a2e7b3ca3dd9a5 Mon Sep 17 00:00:00 2001 From: Andrew Magliozzi Date: Tue, 27 Sep 2011 09:55:02 -0400 Subject: [PATCH] Inital Commit --- README | 2 + app.js | 1621 ++++ bruml/README.markdown | 9 + bruml/archive/backchan-chatpage-orig.html | 183 + bruml/archive/backchan.chatpage.html | 183 + bruml/archive/bcfunctions.demo.html | 108 + bruml/images/accept.png | Bin 0 -> 781 bytes bruml/images/arrow_dn.png | Bin 0 -> 379 bytes bruml/images/arrow_up.png | Bin 0 -> 372 bytes bruml/images/delete.png | Bin 0 -> 715 bytes bruml/lib/paperboy/.package.json.un~ | Bin 0 -> 563 bytes bruml/lib/paperboy/LICENSE.txt | 19 + bruml/lib/paperboy/README.md | 96 + bruml/lib/paperboy/example/basic.js | 38 + .../paperboy/example/webroot/img/paperboy.jpg | Bin 0 -> 120181 bytes bruml/lib/paperboy/example/webroot/index.html | 11 + bruml/lib/paperboy/index.js | 1 + bruml/lib/paperboy/lib/paperboy.js | 302 + bruml/lib/paperboy/package.json | 11 + bruml/lib/paperboy/seed.yml | 6 + bruml/lib/socket.io/History.md | 236 + bruml/lib/socket.io/Makefile | 13 + bruml/lib/socket.io/README.md | 229 + bruml/lib/socket.io/example/benchmark.html | 61 + bruml/lib/socket.io/example/cert.crt | 21 + bruml/lib/socket.io/example/chat-ssl.html | 61 + bruml/lib/socket.io/example/chat.html | 69 + bruml/lib/socket.io/example/json.js | 18 + bruml/lib/socket.io/example/key.key | 27 + bruml/lib/socket.io/example/server-ssl.js | 66 + .../lib/socket.io/example/server.benchmark.js | 77 + bruml/lib/socket.io/example/server.js | 63 + bruml/lib/socket.io/index.js | 1 + bruml/lib/socket.io/lib/socket.io/client.js | 197 + bruml/lib/socket.io/lib/socket.io/index.js | 26 + bruml/lib/socket.io/lib/socket.io/listener.js | 166 + .../lib/socket.io/transports/flashsocket.js | 89 + .../lib/socket.io/transports/htmlfile.js | 49 + .../lib/socket.io/transports/jsonp-polling.js | 35 + .../lib/socket.io/transports/websocket.js | 208 + .../lib/socket.io/transports/xhr-multipart.js | 67 + .../lib/socket.io/transports/xhr-polling.js | 80 + bruml/lib/socket.io/lib/socket.io/utils.js | 52 + bruml/lib/socket.io/package.json | 21 + .../lib/socket.io/support/expresso/History.md | 128 + bruml/lib/socket.io/support/expresso/Makefile | 53 + .../lib/socket.io/support/expresso/Readme.md | 61 + .../socket.io/support/expresso/bin/expresso | 856 ++ .../support/expresso/deps/jscoverage/COPYING | 339 + .../expresso/deps/jscoverage/Makefile.am | 81 + .../expresso/deps/jscoverage/Makefile.in | 884 ++ .../expresso/deps/jscoverage/Readme.md | 8 + .../expresso/deps/jscoverage/aclocal.m4 | 872 ++ .../expresso/deps/jscoverage/config.guess | 1526 +++ .../expresso/deps/jscoverage/config.h.in | 92 + .../expresso/deps/jscoverage/config.rpath | 666 ++ .../expresso/deps/jscoverage/config.sub | 1658 ++++ .../expresso/deps/jscoverage/configure | 7971 ++++++++++++++++ .../expresso/deps/jscoverage/configure.ac | 88 + .../support/expresso/deps/jscoverage/depcomp | 589 ++ .../expresso/deps/jscoverage/doc/demo.html | 87 + .../expresso/deps/jscoverage/doc/doc.css | 45 + .../doc/example-inverted/index.html | 25 + .../jscoverage/doc/example-inverted/script.js | 20 + .../jsunit/app/css/jsUnitStyle.css | 50 + .../doc/example-jsunit/jsunit/app/css/readme | 10 + .../example-jsunit/jsunit/app/emptyPage.html | 11 + .../example-jsunit/jsunit/app/jsUnitCore.js | 534 ++ .../jsunit/app/jsUnitMockTimeout.js | 81 + .../jsunit/app/jsUnitTestManager.js | 705 ++ .../jsunit/app/jsUnitTestSuite.js | 44 + .../example-jsunit/jsunit/app/jsUnitTracer.js | 102 + .../jsunit/app/jsUnitVersionCheck.js | 59 + .../jsunit/app/main-counts-errors.html | 12 + .../jsunit/app/main-counts-failures.html | 13 + .../jsunit/app/main-counts-runs.html | 13 + .../jsunit/app/main-counts.html | 21 + .../example-jsunit/jsunit/app/main-data.html | 189 + .../jsunit/app/main-errors.html | 23 + .../example-jsunit/jsunit/app/main-frame.html | 19 + .../jsunit/app/main-loader.html | 45 + .../jsunit/app/main-progress.html | 25 + .../jsunit/app/main-results.html | 67 + .../jsunit/app/main-status.html | 13 + .../jsunit/app/testContainer.html | 16 + .../jsunit/app/testContainerController.html | 77 + .../doc/example-jsunit/jsunit/app/xbDebug.js | 306 + .../example-jsunit/jsunit/css/jsUnitStyle.css | 83 + .../example-jsunit/jsunit/images/green.gif | Bin 0 -> 811 bytes .../jsunit/images/logo_jsunit.gif | Bin 0 -> 2465 bytes .../jsunit/images/powerby-transparent.gif | Bin 0 -> 968 bytes .../doc/example-jsunit/jsunit/images/red.gif | Bin 0 -> 811 bytes .../jsunit/licenses/JDOM_license.txt | 56 + .../jsunit/licenses/Jetty_license.html | 213 + .../jsunit/licenses/MPL-1.1.txt | 470 + .../example-jsunit/jsunit/licenses/gpl-2.txt | 340 + .../example-jsunit/jsunit/licenses/index.html | 141 + .../jsunit/licenses/lgpl-2.1.txt | 504 + .../jsunit/licenses/mpl-tri-license-c.txt | 35 + .../jsunit/licenses/mpl-tri-license-html.txt | 35 + .../doc/example-jsunit/jsunit/readme.txt | 19 + .../doc/example-jsunit/jsunit/testRunner.html | 167 + .../jscoverage/doc/example-jsunit/script.js | 7 + .../jscoverage/doc/example-jsunit/test.html | 25 + .../deps/jscoverage/doc/example/index.html | 24 + .../deps/jscoverage/doc/example/script.js | 20 + .../expresso/deps/jscoverage/doc/faq.html | 164 + .../deps/jscoverage/doc/feed-icon-14x14.png | Bin 0 -> 689 bytes .../expresso/deps/jscoverage/doc/help.html | 45 + .../expresso/deps/jscoverage/doc/index.html | 151 + .../doc/instrumented-inverted/index.html | 25 + .../jscoverage-highlight.css | 38 + .../instrumented-inverted/jscoverage-ie.css | 89 + .../jscoverage-throbber.gif | Bin 0 -> 425 bytes .../doc/instrumented-inverted/jscoverage.css | 328 + .../doc/instrumented-inverted/jscoverage.html | 125 + .../doc/instrumented-inverted/jscoverage.js | 1024 ++ .../doc/instrumented-inverted/script.js | 65 + .../jscoverage/doc/instrumented/index.html | 24 + .../doc/instrumented/jscoverage-highlight.css | 38 + .../doc/instrumented/jscoverage-ie.css | 89 + .../doc/instrumented/jscoverage-throbber.gif | Bin 0 -> 425 bytes .../doc/instrumented/jscoverage.css | 328 + .../doc/instrumented/jscoverage.html | 125 + .../jscoverage/doc/instrumented/jscoverage.js | 1024 ++ .../jscoverage/doc/instrumented/script.js | 65 + .../expresso/deps/jscoverage/doc/license.html | 382 + .../expresso/deps/jscoverage/doc/links.html | 59 + .../expresso/deps/jscoverage/doc/manual.html | 701 ++ .../expresso/deps/jscoverage/doc/news.html | 214 + .../deps/jscoverage/doc/reset-fonts-grids.css | 7 + .../deps/jscoverage/doc/screenshot.png | Bin 0 -> 19071 bytes .../deps/jscoverage/doc/screenshot2.png | Bin 0 -> 20888 bytes .../deps/jscoverage/doc/screenshot3.png | Bin 0 -> 22690 bytes .../deps/jscoverage/doc/screenshot4.png | Bin 0 -> 20440 bytes .../deps/jscoverage/doc/screenshot5.png | Bin 0 -> 20738 bytes .../deps/jscoverage/doc/screenshot6.png | Bin 0 -> 28866 bytes .../deps/jscoverage/doc/screenshot7.png | Bin 0 -> 18924 bytes .../deps/jscoverage/doc/sh_html.min.js | 1 + .../deps/jscoverage/doc/sh_javascript.min.js | 1 + .../deps/jscoverage/doc/sh_main.min.js | 4 + .../deps/jscoverage/doc/sh_nedit.min.css | 1 + .../jscoverage/doc/siliconforks-16x16.png | Bin 0 -> 338 bytes .../expresso/deps/jscoverage/doc/style.css | 138 + .../expresso/deps/jscoverage/doc/users.html | 58 + .../expresso/deps/jscoverage/encoding.c | 315 + .../expresso/deps/jscoverage/encoding.h | 33 + .../deps/jscoverage/generate-resources.c | 58 + .../support/expresso/deps/jscoverage/global.h | 29 + .../expresso/deps/jscoverage/highlight.c | 478 + .../expresso/deps/jscoverage/highlight.h | 37 + .../deps/jscoverage/http-connection.c | 192 + .../expresso/deps/jscoverage/http-exchange.c | 494 + .../expresso/deps/jscoverage/http-host.c | 95 + .../expresso/deps/jscoverage/http-message.c | 900 ++ .../expresso/deps/jscoverage/http-server.c | 236 + .../expresso/deps/jscoverage/http-server.h | 208 + .../expresso/deps/jscoverage/http-url.c | 156 + .../expresso/deps/jscoverage/install-sh | 519 + .../deps/jscoverage/instrument-js.cpp | 1873 ++++ .../expresso/deps/jscoverage/instrument-js.h | 81 + .../expresso/deps/jscoverage/instrument.c | 226 + .../expresso/deps/jscoverage/instrument.h | 31 + .../expresso/deps/jscoverage/js/GNUmakefile | 15 + .../expresso/deps/jscoverage/js/Makefile.ref | 483 + .../expresso/deps/jscoverage/js/README.html | 54 + .../deps/jscoverage/js/SpiderMonkey.rsp | 11 + .../expresso/deps/jscoverage/js/aclocal.m4 | 9 + .../expresso/deps/jscoverage/js/bench.sh | 5 + .../expresso/deps/jscoverage/js/builtins.tbl | 98 + .../expresso/deps/jscoverage/js/config.mk | 206 + .../deps/jscoverage/js/config/Makefile.in | 106 + .../jscoverage/js/config/Moz/Milestone.pm | 232 + .../deps/jscoverage/js/config/autoconf.mk.in | 349 + .../jscoverage/js/config/check-sync-dirs.py | 108 + .../js/config/check-sync-exceptions | 6 + .../deps/jscoverage/js/config/config.mk | 884 ++ .../deps/jscoverage/js/config/fastcwd.pl | 66 + .../deps/jscoverage/js/config/gcc_hidden.h | 2 + .../deps/jscoverage/js/config/insure.mk | 53 + .../js/config/make-system-wrappers.pl | 59 + .../deps/jscoverage/js/config/milestone.pl | 112 + .../deps/jscoverage/js/config/milestone.txt | 13 + .../jscoverage/js/config/mkdepend/Makefile.in | 84 + .../jscoverage/js/config/mkdepend/cppsetup.c | 233 + .../deps/jscoverage/js/config/mkdepend/def.h | 184 + .../jscoverage/js/config/mkdepend/ifparser.c | 549 ++ .../jscoverage/js/config/mkdepend/ifparser.h | 83 + .../jscoverage/js/config/mkdepend/imakemdep.h | 733 ++ .../jscoverage/js/config/mkdepend/include.c | 337 + .../deps/jscoverage/js/config/mkdepend/main.c | 860 ++ .../js/config/mkdepend/mkdepend.man | 382 + .../jscoverage/js/config/mkdepend/parse.c | 686 ++ .../deps/jscoverage/js/config/mkdepend/pr.c | 124 + .../deps/jscoverage/js/config/nfspwd.pl | 50 + .../deps/jscoverage/js/config/nsinstall.c | 481 + .../deps/jscoverage/js/config/nsinstall.py | 139 + .../deps/jscoverage/js/config/pathsub.c | 247 + .../deps/jscoverage/js/config/pathsub.h | 74 + .../deps/jscoverage/js/config/preprocessor.pl | 671 ++ .../deps/jscoverage/js/config/revdepth-nt.pl | 48 + .../deps/jscoverage/js/config/revdepth.pl | 51 + .../deps/jscoverage/js/config/rules.mk | 2269 +++++ .../deps/jscoverage/js/config/system-headers | 1038 ++ .../deps/jscoverage/js/config/version.mk | 85 + .../deps/jscoverage/js/config/version_win.pl | 423 + .../expresso/deps/jscoverage/js/dtoa.c | 3321 +++++++ .../deps/jscoverage/js/editline/Makefile.ref | 143 + .../deps/jscoverage/js/editline/README | 83 + .../deps/jscoverage/js/editline/editline.3 | 175 + .../deps/jscoverage/js/editline/editline.c | 1368 +++ .../deps/jscoverage/js/editline/editline.h | 135 + .../deps/jscoverage/js/editline/sysunix.c | 182 + .../deps/jscoverage/js/editline/unix.h | 82 + .../deps/jscoverage/js/javascript-trace.d | 73 + .../expresso/deps/jscoverage/js/jitstats.tbl | 52 + .../deps/jscoverage/js/js-config.h.in | 55 + .../expresso/deps/jscoverage/js/js-config.in | 111 + .../expresso/deps/jscoverage/js/js.cpp | 4050 ++++++++ .../expresso/deps/jscoverage/js/js.mdp | Bin 0 -> 17922 bytes .../expresso/deps/jscoverage/js/js.msg | 309 + .../expresso/deps/jscoverage/js/js3240.rc | 79 + .../expresso/deps/jscoverage/js/jsOS240.def | 654 ++ .../expresso/deps/jscoverage/js/jsapi.cpp | 6060 ++++++++++++ .../expresso/deps/jscoverage/js/jsapi.h | 2699 ++++++ .../expresso/deps/jscoverage/js/jsarena.cpp | 450 + .../expresso/deps/jscoverage/js/jsarena.h | 318 + .../expresso/deps/jscoverage/js/jsarray.cpp | 3426 +++++++ .../expresso/deps/jscoverage/js/jsarray.h | 191 + .../expresso/deps/jscoverage/js/jsatom.cpp | 1064 +++ .../expresso/deps/jscoverage/js/jsatom.h | 458 + .../expresso/deps/jscoverage/js/jsbit.h | 253 + .../expresso/deps/jscoverage/js/jsbool.cpp | 182 + .../expresso/deps/jscoverage/js/jsbool.h | 75 + .../deps/jscoverage/js/jsbuiltins.cpp | 497 + .../expresso/deps/jscoverage/js/jsbuiltins.h | 374 + .../expresso/deps/jscoverage/js/jsclist.h | 139 + .../expresso/deps/jscoverage/js/jscntxt.cpp | 1394 +++ .../expresso/deps/jscoverage/js/jscntxt.h | 1247 +++ .../expresso/deps/jscoverage/js/jscompat.h | 57 + .../expresso/deps/jscoverage/js/jsconfig.mk | 181 + .../expresso/deps/jscoverage/js/jscpucfg.cpp | 388 + .../expresso/deps/jscoverage/js/jscpucfg.h | 212 + .../expresso/deps/jscoverage/js/jsdate.cpp | 2475 +++++ .../expresso/deps/jscoverage/js/jsdate.h | 124 + .../expresso/deps/jscoverage/js/jsdbgapi.cpp | 1954 ++++ .../expresso/deps/jscoverage/js/jsdbgapi.h | 500 + .../expresso/deps/jscoverage/js/jsdhash.cpp | 876 ++ .../expresso/deps/jscoverage/js/jsdhash.h | 588 ++ .../expresso/deps/jscoverage/js/jsdtoa.cpp | 572 ++ .../expresso/deps/jscoverage/js/jsdtoa.h | 131 + .../expresso/deps/jscoverage/js/jsdtracef.c | 318 + .../expresso/deps/jscoverage/js/jsdtracef.h | 81 + .../expresso/deps/jscoverage/js/jsemit.cpp | 6857 ++++++++++++++ .../expresso/deps/jscoverage/js/jsemit.h | 777 ++ .../expresso/deps/jscoverage/js/jsexn.cpp | 1376 +++ .../expresso/deps/jscoverage/js/jsexn.h | 96 + .../expresso/deps/jscoverage/js/jsfile.cpp | 2736 ++++++ .../expresso/deps/jscoverage/js/jsfile.h | 56 + .../expresso/deps/jscoverage/js/jsfile.msg | 90 + .../expresso/deps/jscoverage/js/jsfun.cpp | 2706 ++++++ .../expresso/deps/jscoverage/js/jsfun.h | 296 + .../expresso/deps/jscoverage/js/jsgc.cpp | 3763 ++++++++ .../expresso/deps/jscoverage/js/jsgc.h | 427 + .../expresso/deps/jscoverage/js/jshash.cpp | 476 + .../expresso/deps/jscoverage/js/jshash.h | 151 + .../expresso/deps/jscoverage/js/jsify.pl | 483 + .../expresso/deps/jscoverage/js/jsinterp.cpp | 7225 ++++++++++++++ .../expresso/deps/jscoverage/js/jsinterp.h | 591 ++ .../expresso/deps/jscoverage/js/jsinvoke.cpp | 42 + .../expresso/deps/jscoverage/js/jsiter.cpp | 1050 +++ .../expresso/deps/jscoverage/js/jsiter.h | 140 + .../expresso/deps/jscoverage/js/jskeyword.tbl | 124 + .../expresso/deps/jscoverage/js/jskwgen.cpp | 460 + .../expresso/deps/jscoverage/js/jslibmath.h | 69 + .../expresso/deps/jscoverage/js/jslock.cpp | 1417 +++ .../expresso/deps/jscoverage/js/jslock.h | 311 + .../expresso/deps/jscoverage/js/jslocko.asm | 60 + .../expresso/deps/jscoverage/js/jslog2.cpp | 94 + .../expresso/deps/jscoverage/js/jslong.cpp | 264 + .../expresso/deps/jscoverage/js/jslong.h | 412 + .../expresso/deps/jscoverage/js/jsmath.cpp | 721 ++ .../expresso/deps/jscoverage/js/jsmath.h | 63 + .../expresso/deps/jscoverage/js/jsnum.cpp | 1338 +++ .../expresso/deps/jscoverage/js/jsnum.h | 287 + .../expresso/deps/jscoverage/js/jsobj.cpp | 5563 +++++++++++ .../expresso/deps/jscoverage/js/jsobj.h | 735 ++ .../expresso/deps/jscoverage/js/json.cpp | 954 ++ .../expresso/deps/jscoverage/js/json.h | 107 + .../expresso/deps/jscoverage/js/jsopcode.cpp | 5304 +++++++++++ .../expresso/deps/jscoverage/js/jsopcode.h | 404 + .../expresso/deps/jscoverage/js/jsopcode.tbl | 557 ++ .../deps/jscoverage/js/jsoplengen.cpp | 121 + .../expresso/deps/jscoverage/js/jsotypes.h | 202 + .../expresso/deps/jscoverage/js/jsparse.cpp | 6822 ++++++++++++++ .../expresso/deps/jscoverage/js/jsparse.h | 508 + .../expresso/deps/jscoverage/js/jsprf.cpp | 1262 +++ .../expresso/deps/jscoverage/js/jsprf.h | 150 + .../expresso/deps/jscoverage/js/jsproto.tbl | 129 + .../expresso/deps/jscoverage/js/jsprvtd.h | 263 + .../expresso/deps/jscoverage/js/jspubtd.h | 727 ++ .../expresso/deps/jscoverage/js/jsregexp.cpp | 4772 ++++++++++ .../expresso/deps/jscoverage/js/jsregexp.h | 192 + .../expresso/deps/jscoverage/js/jsreops.tbl | 145 + .../expresso/deps/jscoverage/js/jsscan.cpp | 2017 ++++ .../expresso/deps/jscoverage/js/jsscan.h | 389 + .../expresso/deps/jscoverage/js/jsscope.cpp | 1955 ++++ .../expresso/deps/jscoverage/js/jsscope.h | 419 + .../expresso/deps/jscoverage/js/jsscript.cpp | 1891 ++++ .../expresso/deps/jscoverage/js/jsscript.h | 330 + .../expresso/deps/jscoverage/js/jsshell.msg | 51 + .../deps/jscoverage/js/jsstaticcheck.h | 57 + .../expresso/deps/jscoverage/js/jsstddef.h | 87 + .../expresso/deps/jscoverage/js/jsstr.cpp | 5347 +++++++++++ .../expresso/deps/jscoverage/js/jsstr.h | 662 ++ .../expresso/deps/jscoverage/js/jstracer.cpp | 8276 ++++++++++++++++ .../expresso/deps/jscoverage/js/jstracer.h | 552 ++ .../expresso/deps/jscoverage/js/jstypes.h | 490 + .../expresso/deps/jscoverage/js/jsutil.cpp | 345 + .../expresso/deps/jscoverage/js/jsutil.h | 168 + .../expresso/deps/jscoverage/js/jsversion.h | 243 + .../expresso/deps/jscoverage/js/jsxdrapi.cpp | 800 ++ .../expresso/deps/jscoverage/js/jsxdrapi.h | 220 + .../expresso/deps/jscoverage/js/jsxml.cpp | 8343 +++++++++++++++++ .../expresso/deps/jscoverage/js/jsxml.h | 298 + .../expresso/deps/jscoverage/js/lock_SunOS.s | 119 + .../deps/jscoverage/js/plify_jsdhash.sed | 35 + .../expresso/deps/jscoverage/js/prmjtime.cpp | 846 ++ .../expresso/deps/jscoverage/js/prmjtime.h | 103 + .../deps/jscoverage/js/ref-config/AIX4.1.mk | 65 + .../deps/jscoverage/js/ref-config/AIX4.2.mk | 64 + .../deps/jscoverage/js/ref-config/AIX4.3.mk | 65 + .../deps/jscoverage/js/ref-config/Cygwin.mk | 14 + .../deps/jscoverage/js/ref-config/Darwin.mk | 85 + .../jscoverage/js/ref-config/Darwin1.3.mk | 81 + .../jscoverage/js/ref-config/Darwin1.4.mk | 41 + .../jscoverage/js/ref-config/Darwin5.2.mk | 81 + .../jscoverage/js/ref-config/Darwin5.3.mk | 81 + .../deps/jscoverage/js/ref-config/Darwin64.mk | 72 + .../jscoverage/js/ref-config/HP-UXB.10.10.mk | 77 + .../jscoverage/js/ref-config/HP-UXB.10.20.mk | 77 + .../jscoverage/js/ref-config/HP-UXB.11.00.mk | 80 + .../deps/jscoverage/js/ref-config/IRIX.mk | 87 + .../deps/jscoverage/js/ref-config/IRIX5.3.mk | 44 + .../deps/jscoverage/js/ref-config/IRIX6.1.mk | 44 + .../deps/jscoverage/js/ref-config/IRIX6.2.mk | 44 + .../deps/jscoverage/js/ref-config/IRIX6.3.mk | 44 + .../deps/jscoverage/js/ref-config/IRIX6.5.mk | 44 + .../jscoverage/js/ref-config/Linux_All.mk | 105 + .../deps/jscoverage/js/ref-config/MSYS.mk | 7 + .../jscoverage/js/ref-config/Mac_OS10.0.mk | 82 + .../deps/jscoverage/js/ref-config/OSF1V4.0.mk | 72 + .../deps/jscoverage/js/ref-config/OSF1V5.0.mk | 69 + .../jscoverage/js/ref-config/SunOS4.1.4.mk | 101 + .../jscoverage/js/ref-config/SunOS5.10.mk | 50 + .../deps/jscoverage/js/ref-config/SunOS5.3.mk | 91 + .../deps/jscoverage/js/ref-config/SunOS5.4.mk | 92 + .../jscoverage/js/ref-config/SunOS5.5.1.mk | 44 + .../deps/jscoverage/js/ref-config/SunOS5.5.mk | 87 + .../deps/jscoverage/js/ref-config/SunOS5.6.mk | 89 + .../deps/jscoverage/js/ref-config/SunOS5.7.mk | 44 + .../deps/jscoverage/js/ref-config/SunOS5.8.mk | 44 + .../deps/jscoverage/js/ref-config/SunOS5.9.mk | 44 + .../deps/jscoverage/js/ref-config/WINNT4.0.mk | 118 + .../deps/jscoverage/js/ref-config/WINNT5.0.mk | 118 + .../deps/jscoverage/js/ref-config/WINNT5.1.mk | 118 + .../deps/jscoverage/js/ref-config/WINNT5.2.mk | 118 + .../deps/jscoverage/js/ref-config/WINNT6.0.mk | 118 + .../deps/jscoverage/js/ref-config/dgux.mk | 64 + .../expresso/deps/jscoverage/js/resource.h | 15 + .../expresso/deps/jscoverage/js/rules.mk | 206 + .../expresso/deps/jscoverage/js/time.sh | 13 + .../expresso/deps/jscoverage/js/win32.order | 384 + .../deps/jscoverage/jscoverage-help.txt | 12 + .../deps/jscoverage/jscoverage-highlight.css | 38 + .../deps/jscoverage/jscoverage-ie.css | 89 + .../deps/jscoverage/jscoverage-overlay.js | 211 + .../jscoverage/jscoverage-server-help.txt | 17 + .../deps/jscoverage/jscoverage-server.1 | 79 + .../deps/jscoverage/jscoverage-server.c | 1307 +++ .../deps/jscoverage/jscoverage-throbber.gif | Bin 0 -> 425 bytes .../expresso/deps/jscoverage/jscoverage.1 | 52 + .../expresso/deps/jscoverage/jscoverage.c | 142 + .../expresso/deps/jscoverage/jscoverage.css | 328 + .../expresso/deps/jscoverage/jscoverage.html | 125 + .../expresso/deps/jscoverage/jscoverage.js | 1024 ++ .../expresso/deps/jscoverage/jscoverage.jsm | 22 + .../deps/jscoverage/jscoverage.manifest | 2 + .../expresso/deps/jscoverage/jscoverage.xul | 36 + .../expresso/deps/jscoverage/m4/iconv.m4 | 180 + .../expresso/deps/jscoverage/m4/lib-ld.m4 | 110 + .../expresso/deps/jscoverage/m4/lib-link.m4 | 709 ++ .../expresso/deps/jscoverage/m4/lib-prefix.m4 | 185 + .../deps/jscoverage/make-bin-dist.sh.in | 24 + .../expresso/deps/jscoverage/make-dist.sh.in | 43 + .../support/expresso/deps/jscoverage/missing | 367 + .../expresso/deps/jscoverage/report.js | 76 + .../deps/jscoverage/resource-manager.c | 59 + .../deps/jscoverage/resource-manager.h | 46 + .../support/expresso/deps/jscoverage/stream.c | 129 + .../support/expresso/deps/jscoverage/stream.h | 57 + .../deps/jscoverage/tests/Makefile.am | 130 + .../deps/jscoverage/tests/Makefile.in | 846 ++ .../expresso/deps/jscoverage/tests/asprintf.c | 42 + .../deps/jscoverage/tests/asprintf.sh | 19 + .../expresso/deps/jscoverage/tests/charset.sh | 110 + .../expresso/deps/jscoverage/tests/chunked.sh | 74 + .../expresso/deps/jscoverage/tests/common.sh | 7 + ...ination-is-existing-directory.expected.err | 2 + .../tests/destination-is-file.expected.err | 2 + .../encoding-requires-argument.expected.err | 2 + .../deps/jscoverage/tests/encodings.c | 223 + .../deps/jscoverage/tests/encodings.sh | 19 + .../exclude-requires-argument.expected.err | 2 + .../expresso/deps/jscoverage/tests/fatal.sh | 110 + .../deps/jscoverage/tests/gethostbyname.c | 53 + .../deps/jscoverage/tests/gethostbyname.sh | 25 + .../expresso/deps/jscoverage/tests/help.sh | 35 + .../jscoverage/tests/http-client-bad-body.c | 98 + .../jscoverage/tests/http-client-bad-url.c | 77 + .../tests/http-client-close-after-request.c | 57 + .../jscoverage/tests/http-server-bad-body.c | 97 + .../tests/http-server-bad-headers.c | 97 + .../jscoverage/tests/http-server-charset.c | 144 + .../jscoverage/tests/http-server-chunked.c | 196 + .../tests/http-server-close-immediately.c | 60 + .../tests/invalid-option.expected.err | 2 + .../deps/jscoverage/tests/invalid-option.sh | 29 + .../javascript-ignore.expected/ignore.js | 106 + .../jscoverage/tests/javascript-ignore.sh | 28 + .../tests/javascript-ignore/ignore.js | 44 + .../tests/javascript-invalid.expected.err | 2 + .../javascript-invalid/javascript-invalid.js | 1 + .../tests/javascript-setter.expected.err | 1 + .../javascript-setter/javascript-setter.js | 3 + .../javascript-utf-8.js | 15 + .../deps/jscoverage/tests/javascript-utf-8.sh | 43 + .../javascript-utf-8/javascript-utf-8.js | 2 + .../tests/javascript-xml.expected.err | 1 + .../tests/javascript-xml/javascript-xml.js | 8 + .../javascript-array-comprehension.js | 32 + .../javascript.expected/javascript-assign.js | 51 + .../javascript.expected/javascript-colon.js | 24 + .../javascript.expected/javascript-comma.js | 12 + .../javascript.expected/javascript-cr.js | 12 + .../javascript.expected/javascript-crlf.js | 12 + .../javascript-debugger.js | 21 + .../javascript.expected/javascript-dec.js | 15 + .../javascript.expected/javascript-delete.js | 12 + .../javascript-destructuring.js | 96 + .../javascript.expected/javascript-do.js | 28 + .../javascript.expected/javascript-dot.js | 30 + .../javascript.expected/javascript-empty.js | 9 + .../javascript.expected/javascript-for.js | 51 + .../javascript.expected/javascript-foreach.js | 16 + .../javascript-function.js | 79 + .../javascript-generator-expression.js | 45 + .../javascript-generator.js | 32 + .../javascript-getter-setter.js | 31 + .../javascript.expected/javascript-hook.js | 15 + .../javascript.expected/javascript-if.js | 71 + .../javascript.expected/javascript-in.js | 19 + .../javascript.expected/javascript-inc.js | 15 + .../javascript-iso-8859-1.js | 15 + .../javascript.expected/javascript-lambda.js | 14 + .../javascript.expected/javascript-let.js | 148 + .../javascript.expected/javascript-lf.js | 12 + .../javascript.expected/javascript-new.js | 22 + .../javascript.expected/javascript-number.js | 57 + .../javascript.expected/javascript-object.js | 15 + .../javascript.expected/javascript-op.js | 108 + .../javascript.expected/javascript-primary.js | 21 + .../javascript.expected/javascript-rb.js | 24 + .../javascript.expected/javascript-rc.js | 15 + .../javascript.expected/javascript-rp.js | 12 + .../javascript-special-characters.js | 30 + .../javascript.expected/javascript-string.js | 36 + .../javascript.expected/javascript-switch.js | 55 + .../javascript.expected/javascript-throw.js | 21 + .../javascript.expected/javascript-try.js | 66 + .../javascript.expected/javascript-unaryop.js | 27 + .../javascript.expected/javascript-var.js | 15 + .../javascript.expected/javascript-while.js | 79 + .../javascript.expected/javascript-with.js | 30 + .../deps/jscoverage/tests/javascript.sh | 53 + .../javascript-array-comprehension.js | 14 + .../tests/javascript/javascript-assign.js | 14 + .../tests/javascript/javascript-colon.js | 7 + .../tests/javascript/javascript-comma.js | 1 + .../tests/javascript/javascript-cr.js | 1 + .../tests/javascript/javascript-crlf.js | 4 + .../tests/javascript/javascript-debugger.js | 6 + .../tests/javascript/javascript-dec.js | 2 + .../tests/javascript/javascript-delete.js | 1 + .../javascript/javascript-destructuring.js | 42 + .../tests/javascript/javascript-do.js | 10 + .../tests/javascript/javascript-dot.js | 8 + .../tests/javascript/javascript-empty.js | 0 .../tests/javascript/javascript-for.js | 22 + .../tests/javascript/javascript-foreach.js | 8 + .../tests/javascript/javascript-function.js | 38 + .../javascript-generator-expression.js | 18 + .../tests/javascript/javascript-generator.js | 11 + .../javascript/javascript-getter-setter.js | 19 + .../tests/javascript/javascript-hook.js | 2 + .../tests/javascript/javascript-if.js | 30 + .../tests/javascript/javascript-in.js | 4 + .../tests/javascript/javascript-inc.js | 2 + .../tests/javascript/javascript-iso-8859-1.js | 2 + .../tests/javascript/javascript-lambda.js | 3 + .../tests/javascript/javascript-let.js | 79 + .../tests/javascript/javascript-lf.js | 4 + .../tests/javascript/javascript-new.js | 4 + .../tests/javascript/javascript-number.js | 19 + .../tests/javascript/javascript-object.js | 2 + .../tests/javascript/javascript-op.js | 55 + .../tests/javascript/javascript-primary.js | 4 + .../tests/javascript/javascript-rb.js | 5 + .../tests/javascript/javascript-rc.js | 7 + .../tests/javascript/javascript-rp.js | 1 + .../javascript-special-characters.js | 11 + .../tests/javascript/javascript-string.js | 11 + .../tests/javascript/javascript-switch.js | 21 + .../tests/javascript/javascript-throw.js | 6 + .../tests/javascript/javascript-try.js | 32 + .../tests/javascript/javascript-unaryop.js | 6 + .../tests/javascript/javascript-var.js | 2 + .../tests/javascript/javascript-while.js | 35 + .../tests/javascript/javascript-with.js | 9 + .../deps/jscoverage/tests/json-cmp.js | 65 + .../expresso/deps/jscoverage/tests/json.c | 48 + .../expresso/deps/jscoverage/tests/json.sh | 19 + .../expresso/deps/jscoverage/tests/mkdirs.c | 42 + .../expresso/deps/jscoverage/tests/mkdirs.sh | 19 + .../expresso/deps/jscoverage/tests/netcat.pl | 35 + .../tests/no-arguments.expected.err | 2 + .../deps/jscoverage/tests/no-arguments.sh | 29 + ...-instrument-requires-argument.expected.err | 2 + .../tests/proxy-bad-request-body.sh | 58 + .../proxy-bad-response-body-javascript.sh | 53 + .../proxy-bad-response-body.expected.err | 1 + .../tests/proxy-bad-response-body.sh | 54 + .../tests/proxy-bad-response-headers.sh | 53 + .../deps/jscoverage/tests/proxy-no-server.sh | 49 + .../deps/jscoverage/tests/proxy-url.sh | 67 + .../expresso/deps/jscoverage/tests/proxy.sh | 143 + .../deps/jscoverage/tests/recursive-crlf.sh | 59 + .../jscoverage/tests/recursive-dir-list.c | 93 + .../jscoverage/tests/recursive-dir-list.sh | 19 + .../jscoverage/tests/recursive-exclude.sh | 41 + .../deps/jscoverage/tests/recursive-fatal.sh | 40 + .../tests/recursive-no-instrument.sh | 41 + .../tests/recursive.expected/1/1.css | 3 + .../tests/recursive.expected/1/1.html | 12 + .../tests/recursive.expected/1/1.js | 12 + .../tests/recursive.expected/1/2/2.css | 3 + .../tests/recursive.expected/1/2/2.html | 11 + .../tests/recursive.expected/1/2/2.js | 12 + .../tests/recursive.expected/image.png | Bin 0 -> 67 bytes .../tests/recursive.expected/index.html | 12 + .../tests/recursive.expected/script.js | 19 + .../tests/recursive.expected/style.css | 3 + .../tests/recursive.expected/unix.txt | 3 + .../tests/recursive.expected/windows.txt | 3 + .../jscoverage/tests/recursive.expected/x | 1 + .../deps/jscoverage/tests/recursive.sh | 55 + .../deps/jscoverage/tests/recursive/1/1.css | 3 + .../deps/jscoverage/tests/recursive/1/1.html | 12 + .../deps/jscoverage/tests/recursive/1/1.js | 1 + .../deps/jscoverage/tests/recursive/1/2/2.css | 3 + .../jscoverage/tests/recursive/1/2/2.html | 11 + .../deps/jscoverage/tests/recursive/1/2/2.js | 1 + .../deps/jscoverage/tests/recursive/image.png | Bin 0 -> 67 bytes .../jscoverage/tests/recursive/index.html | 12 + .../deps/jscoverage/tests/recursive/script.js | 6 + .../deps/jscoverage/tests/recursive/style.css | 3 + .../deps/jscoverage/tests/recursive/unix.txt | 3 + .../jscoverage/tests/recursive/windows.txt | 3 + .../deps/jscoverage/tests/recursive/x | 1 + .../tests/same-directory.expected.err | 1 + .../deps/jscoverage/tests/same-directory.sh | 30 + .../jscoverage/tests/server-bad-requests.sh | 104 + .../tests/server-close-after-request.sh | 47 + .../jscoverage/tests/server-content-types.sh | 68 + .../tests/server-directory-listing.expected | 4 + .../tests/server-directory-listing.sh | 57 + .../tests/server-directory-redirect.sh | 50 + .../jscoverage/tests/server-encoded-url.sh | 57 + .../deps/jscoverage/tests/server-error.sh | 61 + .../deps/jscoverage/tests/server-help.sh | 26 + .../jscoverage/tests/server-ip-address.sh | 68 + .../tests/server-shutdown-bad-method.sh | 49 + .../tests/server-shutdown.expected.err | 1 + .../deps/jscoverage/tests/server-shutdown.sh | 42 + .../jscoverage/tests/server-special-file.sh | 62 + .../tests/server-unreadable-directory.sh | 61 + .../tests/server-unreadable-file.sh | 62 + .../tests/server-verbose.expected.err | 4 + .../deps/jscoverage/tests/server-verbose.sh | 54 + .../deps/jscoverage/tests/server-version.sh | 25 + .../expresso/deps/jscoverage/tests/server.pl | 61 + .../expresso/deps/jscoverage/tests/server.sh | 216 + .../tests/source-does-not-exist.expected.err | 2 + .../tests/source-is-file.expected.err | 2 + .../deps/jscoverage/tests/store-bad-json.sh | 50 + .../tests/store-bad-request-body.sh | 48 + .../tests/store-bad-response-headers.sh | 56 + .../tests/store-bad-source-urls.expected.err | 3 + .../tests/store-bad-source-urls.expected.json | 14 + .../store-escaped-characters.expected.json | 6 + .../tests/store-escaped-characters.js | 11 + .../tests/store-escaped-characters.json | 3 + .../tests/store-escaped-characters.sh | 52 + .../jscoverage/tests/store-server-bad-body.sh | 59 + .../tests/store-server-closes-immediately.sh | 58 + .../tests/store-source-not-found.expected.err | 1 + .../store-source-not-found.expected.json | 6 + .../tests/store-source-not-found.json | 3 + .../tests/store-source-not-found.sh | 50 + .../tests/store-source-urls.expected.err | 3 + .../tests/store-source-urls.expected.json | 14 + ...store-unreachable-source-urls.expected.err | 3 + ...tore-unreachable-source-urls.expected.json | 14 + .../jscoverage/tests/store-unreadable-json.sh | 66 + .../jscoverage/tests/store-unwritable-json.sh | 58 + .../deps/jscoverage/tests/store.expected.json | 14 + .../expresso/deps/jscoverage/tests/store.json | 5 + .../expresso/deps/jscoverage/tests/store.sh | 137 + .../expresso/deps/jscoverage/tests/streams.c | 107 + .../expresso/deps/jscoverage/tests/streams.sh | 19 + .../tests/too-many-arguments.expected.err | 2 + .../deps/jscoverage/tests/valgrind.sh | 7 + .../expresso/deps/jscoverage/tests/version.sh | 29 + .../support/expresso/deps/jscoverage/util.c | 570 ++ .../support/expresso/deps/jscoverage/util.h | 133 + .../socket.io/support/expresso/docs/api.html | 1080 +++ .../support/expresso/docs/index.html | 377 + .../socket.io/support/expresso/docs/index.md | 290 + .../support/expresso/docs/layout/foot.html | 3 + .../support/expresso/docs/layout/head.html | 42 + .../lib/socket.io/support/expresso/lib/bar.js | 4 + .../lib/socket.io/support/expresso/lib/foo.js | 16 + .../socket.io/support/expresso/package.json | 12 + .../support/expresso/test/assert.test.js | 91 + .../support/expresso/test/async.test.js | 12 + .../support/expresso/test/bar.test.js | 13 + .../support/expresso/test/foo.test.js | 14 + .../support/expresso/test/http.test.js | 146 + .../expresso/test/serial/async.test.js | 39 + .../support/expresso/test/serial/http.test.js | 48 + .../support/node-websocket-client/LICENSE | 27 + .../support/node-websocket-client/Makefile | 8 + .../support/node-websocket-client/README.md | 41 + .../examples/client-unix.js | 12 + .../node-websocket-client/examples/client.js | 10 + .../examples/server-unix.js | 13 + .../node-websocket-client/lib/websocket.js | 562 ++ .../node-websocket-client/package.json | 22 + .../node-websocket-client/test/test-basic.js | 63 + .../test/test-readonly-attrs.js | 44 + .../test/test-ready-state.js | 23 + .../test/test-unix-send-fd.js | 63 + .../test/test-unix-sockets.js | 46 + .../support/socket.io-client/Makefile | 2 + .../support/socket.io-client/README.md | 208 + .../support/socket.io-client/lib/io.js | 25 + .../support/socket.io-client/lib/socket.js | 163 + .../support/socket.io-client/lib/transport.js | 141 + .../lib/transports/flashsocket.js | 53 + .../lib/transports/htmlfile.js | 73 + .../lib/transports/jsonp-polling.js | 116 + .../lib/transports/websocket.js | 65 + .../lib/transports/xhr-multipart.js | 36 + .../lib/transports/xhr-polling.js | 61 + .../socket.io-client/lib/transports/xhr.js | 135 + .../support/socket.io-client/lib/util.js | 60 + .../lib/vendor/web-socket-js/FABridge.js | 604 ++ .../lib/vendor/web-socket-js/README.txt | 109 + .../vendor/web-socket-js/WebSocketMain.swf | Bin 0 -> 180028 bytes .../web-socket-js/WebSocketMainInsecure.zip | Bin 0 -> 172823 bytes .../web-socket-js/flash-src/WebSocket.as | 452 + .../web-socket-js/flash-src/WebSocketMain.as | 88 + .../flash-src/WebSocketMainInsecure.as | 19 + .../flash-src/bridge/FABridge.as | 943 ++ .../vendor/web-socket-js/flash-src/build.sh | 10 + .../com/adobe/net/proxies/RFC2817Socket.as | 204 + .../flash-src/com/gsolo/encryption/MD5.as | 375 + .../flash-src/com/hurlant/crypto/Crypto.as | 287 + .../crypto/cert/MozillaRootCertificates.as | 3235 +++++++ .../hurlant/crypto/cert/X509Certificate.as | 218 + .../crypto/cert/X509CertificateCollection.as | 57 + .../flash-src/com/hurlant/crypto/hash/HMAC.as | 82 + .../com/hurlant/crypto/hash/IHMAC.as | 27 + .../com/hurlant/crypto/hash/IHash.as | 21 + .../flash-src/com/hurlant/crypto/hash/MAC.as | 137 + .../flash-src/com/hurlant/crypto/hash/MD2.as | 124 + .../flash-src/com/hurlant/crypto/hash/MD5.as | 204 + .../flash-src/com/hurlant/crypto/hash/SHA1.as | 106 + .../com/hurlant/crypto/hash/SHA224.as | 28 + .../com/hurlant/crypto/hash/SHA256.as | 115 + .../com/hurlant/crypto/hash/SHABase.as | 71 + .../flash-src/com/hurlant/crypto/prng/ARC4.as | 90 + .../com/hurlant/crypto/prng/IPRNG.as | 20 + .../com/hurlant/crypto/prng/Random.as | 119 + .../com/hurlant/crypto/prng/TLSPRF.as | 142 + .../com/hurlant/crypto/rsa/RSAKey.as | 339 + .../com/hurlant/crypto/symmetric/AESKey.as | 2797 ++++++ .../hurlant/crypto/symmetric/BlowFishKey.as | 375 + .../com/hurlant/crypto/symmetric/CBCMode.as | 55 + .../com/hurlant/crypto/symmetric/CFB8Mode.as | 61 + .../com/hurlant/crypto/symmetric/CFBMode.as | 64 + .../com/hurlant/crypto/symmetric/CTRMode.as | 58 + .../com/hurlant/crypto/symmetric/DESKey.as | 365 + .../com/hurlant/crypto/symmetric/ECBMode.as | 86 + .../com/hurlant/crypto/symmetric/ICipher.as | 21 + .../com/hurlant/crypto/symmetric/IMode.as | 15 + .../com/hurlant/crypto/symmetric/IPad.as | 32 + .../hurlant/crypto/symmetric/IStreamCipher.as | 21 + .../hurlant/crypto/symmetric/ISymmetricKey.as | 35 + .../com/hurlant/crypto/symmetric/IVMode.as | 110 + .../com/hurlant/crypto/symmetric/NullPad.as | 34 + .../com/hurlant/crypto/symmetric/OFBMode.as | 52 + .../com/hurlant/crypto/symmetric/PKCS5.as | 44 + .../com/hurlant/crypto/symmetric/SSLPad.as | 44 + .../hurlant/crypto/symmetric/SimpleIVMode.as | 60 + .../com/hurlant/crypto/symmetric/TLSPad.as | 42 + .../hurlant/crypto/symmetric/TripleDESKey.as | 88 + .../com/hurlant/crypto/symmetric/XTeaKey.as | 94 + .../com/hurlant/crypto/symmetric/aeskey.pl | 29 + .../com/hurlant/crypto/symmetric/dump.txt | 2304 +++++ .../com/hurlant/crypto/tests/AESKeyTest.as | 1220 +++ .../com/hurlant/crypto/tests/ARC4Test.as | 58 + .../hurlant/crypto/tests/BigIntegerTest.as | 39 + .../hurlant/crypto/tests/BlowFishKeyTest.as | 148 + .../com/hurlant/crypto/tests/CBCModeTest.as | 160 + .../com/hurlant/crypto/tests/CFB8ModeTest.as | 71 + .../com/hurlant/crypto/tests/CFBModeTest.as | 98 + .../com/hurlant/crypto/tests/CTRModeTest.as | 109 + .../com/hurlant/crypto/tests/DESKeyTest.as | 112 + .../com/hurlant/crypto/tests/ECBModeTest.as | 151 + .../com/hurlant/crypto/tests/HMACTest.as | 184 + .../com/hurlant/crypto/tests/ITestHarness.as | 20 + .../com/hurlant/crypto/tests/MD2Test.as | 56 + .../com/hurlant/crypto/tests/MD5Test.as | 58 + .../com/hurlant/crypto/tests/OFBModeTest.as | 101 + .../com/hurlant/crypto/tests/RSAKeyTest.as | 92 + .../com/hurlant/crypto/tests/SHA1Test.as | 198 + .../com/hurlant/crypto/tests/SHA224Test.as | 58 + .../com/hurlant/crypto/tests/SHA256Test.as | 60 + .../com/hurlant/crypto/tests/TLSPRFTest.as | 51 + .../com/hurlant/crypto/tests/TestCase.as | 42 + .../hurlant/crypto/tests/TripleDESKeyTest.as | 59 + .../com/hurlant/crypto/tests/XTeaKeyTest.as | 66 + .../com/hurlant/crypto/tls/BulkCiphers.as | 102 + .../com/hurlant/crypto/tls/CipherSuites.as | 117 + .../hurlant/crypto/tls/IConnectionState.as | 14 + .../hurlant/crypto/tls/ISecurityParameters.as | 29 + .../com/hurlant/crypto/tls/KeyExchanges.as | 24 + .../flash-src/com/hurlant/crypto/tls/MACs.as | 38 + .../hurlant/crypto/tls/SSLConnectionState.as | 171 + .../com/hurlant/crypto/tls/SSLEvent.as | 26 + .../crypto/tls/SSLSecurityParameters.as | 340 + .../com/hurlant/crypto/tls/TLSConfig.as | 70 + .../hurlant/crypto/tls/TLSConnectionState.as | 151 + .../com/hurlant/crypto/tls/TLSEngine.as | 895 ++ .../com/hurlant/crypto/tls/TLSError.as | 39 + .../com/hurlant/crypto/tls/TLSEvent.as | 27 + .../crypto/tls/TLSSecurityParameters.as | 197 + .../com/hurlant/crypto/tls/TLSSocket.as | 370 + .../com/hurlant/crypto/tls/TLSSocketEvent.as | 26 + .../com/hurlant/crypto/tls/TLSTest.as | 180 + .../com/hurlant/math/BarrettReduction.as | 90 + .../flash-src/com/hurlant/math/BigInteger.as | 1543 +++ .../com/hurlant/math/ClassicReduction.as | 35 + .../flash-src/com/hurlant/math/IReduction.as | 11 + .../com/hurlant/math/MontgomeryReduction.as | 85 + .../com/hurlant/math/NullReduction.as | 34 + .../flash-src/com/hurlant/math/bi_internal.as | 11 + .../flash-src/com/hurlant/util/ArrayUtil.as | 25 + .../flash-src/com/hurlant/util/Base64.as | 189 + .../flash-src/com/hurlant/util/Hex.as | 66 + .../flash-src/com/hurlant/util/Memory.as | 28 + .../com/hurlant/util/der/ByteString.as | 43 + .../flash-src/com/hurlant/util/der/DER.as | 210 + .../com/hurlant/util/der/IAsn1Type.as | 21 + .../flash-src/com/hurlant/util/der/Integer.as | 44 + .../flash-src/com/hurlant/util/der/OID.as | 35 + .../com/hurlant/util/der/ObjectIdentifier.as | 112 + .../flash-src/com/hurlant/util/der/PEM.as | 118 + .../com/hurlant/util/der/PrintableString.as | 49 + .../com/hurlant/util/der/Sequence.as | 90 + .../flash-src/com/hurlant/util/der/Set.as | 27 + .../flash-src/com/hurlant/util/der/Type.as | 94 + .../flash-src/com/hurlant/util/der/UTCTime.as | 60 + .../lib/vendor/web-socket-js/sample.html | 76 + .../lib/vendor/web-socket-js/swfobject.js | 4 + .../lib/vendor/web-socket-js/web_socket.js | 376 + .../support/socket.io-client/socket.io.js | 1922 ++++ bruml/lib/socket.io/tests/index.js | 18 + bruml/lib/socket.io/tests/listener.js | 157 + .../socket.io/tests/transports.flashsocket.js | 49 + .../socket.io/tests/transports.htmlfile.js | 217 + .../tests/transports.jsonp-polling.js | 149 + .../socket.io/tests/transports.websocket.js | 246 + .../tests/transports.xhr-multipart.js | 216 + .../socket.io/tests/transports.xhr-polling.js | 139 + bruml/lib/socket.io/tests/utils.js | 26 + bruml/lib/underscore/.npmignore | 4 + bruml/lib/underscore/LICENSE | 22 + bruml/lib/underscore/README | 19 + bruml/lib/underscore/index.html | 1560 +++ bruml/lib/underscore/index.js | 1 + bruml/lib/underscore/package.json | 12 + bruml/lib/underscore/underscore.js | 807 ++ bruml/node_modules/.bin/express | 1 + bruml/node_modules/express/.npmignore | 7 + bruml/node_modules/express/History.md | 719 ++ bruml/node_modules/express/LICENSE | 22 + bruml/node_modules/express/Makefile | 35 + bruml/node_modules/express/Readme.md | 143 + bruml/node_modules/express/bin/express | 417 + bruml/node_modules/express/index.js | 2 + bruml/node_modules/express/lib/express.js | 79 + bruml/node_modules/express/lib/http.js | 544 ++ bruml/node_modules/express/lib/https.js | 52 + bruml/node_modules/express/lib/request.js | 309 + bruml/node_modules/express/lib/response.js | 462 + .../express/lib/router/collection.js | 53 + .../node_modules/express/lib/router/index.js | 384 + .../express/lib/router/methods.js | 70 + .../node_modules/express/lib/router/route.js | 90 + bruml/node_modules/express/lib/utils.js | 139 + bruml/node_modules/express/lib/view.js | 459 + .../node_modules/express/lib/view/partial.js | 40 + bruml/node_modules/express/lib/view/view.js | 209 + .../express/node_modules/connect/.npmignore | 11 + .../express/node_modules/connect/LICENSE | 24 + .../express/node_modules/connect/index.js | 2 + .../node_modules/connect/lib/connect.js | 106 + .../express/node_modules/connect/lib/http.js | 212 + .../express/node_modules/connect/lib/https.js | 47 + .../express/node_modules/connect/lib/index.js | 45 + .../connect/lib/middleware/basicAuth.js | 93 + .../connect/lib/middleware/bodyParser.js | 92 + .../connect/lib/middleware/compiler.js | 163 + .../connect/lib/middleware/cookieParser.js | 46 + .../connect/lib/middleware/csrf.js | 105 + .../connect/lib/middleware/directory.js | 218 + .../connect/lib/middleware/errorHandler.js | 100 + .../connect/lib/middleware/favicon.js | 76 + .../connect/lib/middleware/limit.js | 78 + .../connect/lib/middleware/logger.js | 285 + .../connect/lib/middleware/methodOverride.js | 38 + .../connect/lib/middleware/profiler.js | 100 + .../connect/lib/middleware/query.js | 40 + .../connect/lib/middleware/responseTime.js | 34 + .../connect/lib/middleware/router.js | 379 + .../connect/lib/middleware/session.js | 346 + .../connect/lib/middleware/session/cookie.js | 126 + .../connect/lib/middleware/session/memory.js | 131 + .../connect/lib/middleware/session/session.js | 137 + .../connect/lib/middleware/session/store.js | 59 + .../connect/lib/middleware/static.js | 212 + .../connect/lib/middleware/vhost.js | 44 + .../express/node_modules/connect/lib/patch.js | 51 + .../connect/lib/public/directory.html | 75 + .../connect/lib/public/error.html | 13 + .../connect/lib/public/favicon.ico | Bin 0 -> 1406 bytes .../connect/lib/public/icons/page.png | Bin 0 -> 635 bytes .../connect/lib/public/icons/page_add.png | Bin 0 -> 739 bytes .../connect/lib/public/icons/page_attach.png | Bin 0 -> 794 bytes .../connect/lib/public/icons/page_code.png | Bin 0 -> 818 bytes .../connect/lib/public/icons/page_copy.png | Bin 0 -> 663 bytes .../connect/lib/public/icons/page_delete.png | Bin 0 -> 740 bytes .../connect/lib/public/icons/page_edit.png | Bin 0 -> 807 bytes .../connect/lib/public/icons/page_error.png | Bin 0 -> 793 bytes .../connect/lib/public/icons/page_excel.png | Bin 0 -> 817 bytes .../connect/lib/public/icons/page_find.png | Bin 0 -> 879 bytes .../connect/lib/public/icons/page_gear.png | Bin 0 -> 833 bytes .../connect/lib/public/icons/page_go.png | Bin 0 -> 779 bytes .../connect/lib/public/icons/page_green.png | Bin 0 -> 621 bytes .../connect/lib/public/icons/page_key.png | Bin 0 -> 801 bytes .../lib/public/icons/page_lightning.png | Bin 0 -> 839 bytes .../connect/lib/public/icons/page_link.png | Bin 0 -> 830 bytes .../lib/public/icons/page_paintbrush.png | Bin 0 -> 813 bytes .../connect/lib/public/icons/page_paste.png | Bin 0 -> 703 bytes .../connect/lib/public/icons/page_red.png | Bin 0 -> 641 bytes .../connect/lib/public/icons/page_refresh.png | Bin 0 -> 858 bytes .../connect/lib/public/icons/page_save.png | Bin 0 -> 774 bytes .../connect/lib/public/icons/page_white.png | Bin 0 -> 294 bytes .../lib/public/icons/page_white_acrobat.png | Bin 0 -> 591 bytes .../public/icons/page_white_actionscript.png | Bin 0 -> 664 bytes .../lib/public/icons/page_white_add.png | Bin 0 -> 512 bytes .../connect/lib/public/icons/page_white_c.png | Bin 0 -> 587 bytes .../lib/public/icons/page_white_camera.png | Bin 0 -> 656 bytes .../lib/public/icons/page_white_cd.png | Bin 0 -> 666 bytes .../lib/public/icons/page_white_code.png | Bin 0 -> 603 bytes .../lib/public/icons/page_white_code_red.png | Bin 0 -> 587 bytes .../public/icons/page_white_coldfusion.png | Bin 0 -> 592 bytes .../public/icons/page_white_compressed.png | Bin 0 -> 724 bytes .../lib/public/icons/page_white_copy.png | Bin 0 -> 309 bytes .../lib/public/icons/page_white_cplusplus.png | Bin 0 -> 621 bytes .../lib/public/icons/page_white_csharp.png | Bin 0 -> 700 bytes .../lib/public/icons/page_white_cup.png | Bin 0 -> 639 bytes .../lib/public/icons/page_white_database.png | Bin 0 -> 579 bytes .../lib/public/icons/page_white_delete.png | Bin 0 -> 536 bytes .../lib/public/icons/page_white_dvd.png | Bin 0 -> 638 bytes .../lib/public/icons/page_white_edit.png | Bin 0 -> 618 bytes .../lib/public/icons/page_white_error.png | Bin 0 -> 623 bytes .../lib/public/icons/page_white_excel.png | Bin 0 -> 663 bytes .../lib/public/icons/page_white_find.png | Bin 0 -> 676 bytes .../lib/public/icons/page_white_flash.png | Bin 0 -> 582 bytes .../lib/public/icons/page_white_freehand.png | Bin 0 -> 639 bytes .../lib/public/icons/page_white_gear.png | Bin 0 -> 402 bytes .../lib/public/icons/page_white_get.png | Bin 0 -> 516 bytes .../lib/public/icons/page_white_go.png | Bin 0 -> 612 bytes .../connect/lib/public/icons/page_white_h.png | Bin 0 -> 603 bytes .../public/icons/page_white_horizontal.png | Bin 0 -> 296 bytes .../lib/public/icons/page_white_key.png | Bin 0 -> 616 bytes .../lib/public/icons/page_white_lightning.png | Bin 0 -> 669 bytes .../lib/public/icons/page_white_link.png | Bin 0 -> 614 bytes .../lib/public/icons/page_white_magnify.png | Bin 0 -> 554 bytes .../lib/public/icons/page_white_medal.png | Bin 0 -> 706 bytes .../lib/public/icons/page_white_office.png | Bin 0 -> 779 bytes .../lib/public/icons/page_white_paint.png | Bin 0 -> 688 bytes .../public/icons/page_white_paintbrush.png | Bin 0 -> 618 bytes .../lib/public/icons/page_white_paste.png | Bin 0 -> 620 bytes .../lib/public/icons/page_white_php.png | Bin 0 -> 538 bytes .../lib/public/icons/page_white_picture.png | Bin 0 -> 650 bytes .../public/icons/page_white_powerpoint.png | Bin 0 -> 588 bytes .../lib/public/icons/page_white_put.png | Bin 0 -> 523 bytes .../lib/public/icons/page_white_ruby.png | Bin 0 -> 626 bytes .../lib/public/icons/page_white_stack.png | Bin 0 -> 317 bytes .../lib/public/icons/page_white_star.png | Bin 0 -> 565 bytes .../lib/public/icons/page_white_swoosh.png | Bin 0 -> 634 bytes .../lib/public/icons/page_white_text.png | Bin 0 -> 342 bytes .../public/icons/page_white_text_width.png | Bin 0 -> 315 bytes .../lib/public/icons/page_white_tux.png | Bin 0 -> 668 bytes .../lib/public/icons/page_white_vector.png | Bin 0 -> 644 bytes .../public/icons/page_white_visualstudio.png | Bin 0 -> 702 bytes .../lib/public/icons/page_white_width.png | Bin 0 -> 309 bytes .../lib/public/icons/page_white_word.png | Bin 0 -> 651 bytes .../lib/public/icons/page_white_world.png | Bin 0 -> 734 bytes .../lib/public/icons/page_white_wrench.png | Bin 0 -> 613 bytes .../lib/public/icons/page_white_zip.png | Bin 0 -> 386 bytes .../connect/lib/public/icons/page_word.png | Bin 0 -> 777 bytes .../connect/lib/public/icons/page_world.png | Bin 0 -> 903 bytes .../node_modules/connect/lib/public/style.css | 141 + .../express/node_modules/connect/lib/utils.js | 427 + .../express/node_modules/connect/meta.json | 1 + .../express/node_modules/connect/package.json | 24 + .../express/node_modules/connect/test.js | 20 + .../express/node_modules/mime/LICENSE | 19 + .../express/node_modules/mime/README.md | 54 + .../express/node_modules/mime/index.js | 1 + .../express/node_modules/mime/mime.js | 89 + .../express/node_modules/mime/mime.types | 1479 +++ .../express/node_modules/mime/node.types | 7 + .../express/node_modules/mime/package.json | 11 + .../express/node_modules/mime/test.js | 74 + .../express/node_modules/qs/History.md | 46 + .../express/node_modules/qs/Makefile | 7 + .../express/node_modules/qs/Readme.md | 49 + .../express/node_modules/qs/benchmark.js | 17 + .../express/node_modules/qs/examples.js | 48 + .../express/node_modules/qs/index.js | 2 + .../node_modules/qs/lib/querystring.js | 227 + .../express/node_modules/qs/package.json | 9 + .../qs/support/expresso/History.md | 128 + .../node_modules/qs/support/expresso/Makefile | 53 + .../qs/support/expresso/Readme.md | 61 + .../qs/support/expresso/bin/expresso | 856 ++ .../qs/support/expresso/docs/api.html | 1080 +++ .../qs/support/expresso/docs/index.html | 377 + .../qs/support/expresso/docs/index.md | 290 + .../qs/support/expresso/docs/layout/foot.html | 3 + .../qs/support/expresso/docs/layout/head.html | 42 + .../qs/support/expresso/lib/bar.js | 4 + .../qs/support/expresso/lib/foo.js | 16 + .../qs/support/expresso/package.json | 12 + .../qs/support/expresso/test/assert.test.js | 91 + .../qs/support/expresso/test/async.test.js | 12 + .../qs/support/expresso/test/bar.test.js | 13 + .../qs/support/expresso/test/foo.test.js | 14 + .../qs/support/expresso/test/http.test.js | 146 + .../expresso/test/serial/async.test.js | 39 + .../support/expresso/test/serial/http.test.js | 48 + .../node_modules/qs/support/should/History.md | 22 + .../node_modules/qs/support/should/Makefile | 6 + .../node_modules/qs/support/should/Readme.md | 248 + .../qs/support/should/examples/runner.js | 53 + .../node_modules/qs/support/should/index.js | 2 + .../node_modules/qs/support/should/lib/eql.js | 91 + .../qs/support/should/lib/should.js | 548 ++ .../qs/support/should/package.json | 8 + .../qs/support/should/test/should.test.js | 358 + .../node_modules/qs/test/parse.test.js | 141 + .../node_modules/qs/test/stringify.test.js | 95 + bruml/node_modules/express/package.json | 38 + bruml/node_modules/socket.io/.npmignore | 3 + bruml/node_modules/socket.io/History.md | 71 + bruml/node_modules/socket.io/Makefile | 20 + bruml/node_modules/socket.io/Readme.md | 343 + bruml/node_modules/socket.io/TODO | 5 + bruml/node_modules/socket.io/index.js | 8 + bruml/node_modules/socket.io/lib/logger.js | 96 + bruml/node_modules/socket.io/lib/manager.js | 966 ++ bruml/node_modules/socket.io/lib/namespace.js | 348 + bruml/node_modules/socket.io/lib/parser.js | 243 + bruml/node_modules/socket.io/lib/socket.io.js | 125 + bruml/node_modules/socket.io/lib/socket.js | 345 + bruml/node_modules/socket.io/lib/store.js | 98 + .../socket.io/lib/stores/memory.js | 143 + .../socket.io/lib/stores/redis.js | 248 + bruml/node_modules/socket.io/lib/transport.js | 534 ++ .../socket.io/lib/transports/flashsocket.js | 102 + .../socket.io/lib/transports/htmlfile.js | 82 + .../socket.io/lib/transports/http-polling.js | 135 + .../socket.io/lib/transports/http.js | 111 + .../socket.io/lib/transports/index.js | 12 + .../socket.io/lib/transports/jsonp-polling.js | 77 + .../socket.io/lib/transports/websocket.js | 350 + .../socket.io/lib/transports/xhr-polling.js | 72 + bruml/node_modules/socket.io/lib/util.js | 25 + bruml/node_modules/socket.io/new-old/app.js | 22 + .../node_modules/socket.io/new-old/index.jade | 34 + .../socket.io/new-old/layout.jade | 42 + .../socket.io/new-old/package.json | 9 + .../socket.io/new-old/public/js/main.js | 22 + bruml/node_modules/socket.io/package.json | 28 + bruml/old_bcserver.js | 259 + bruml/server.js | 117 + bruml/static/arrow_dn.png | Bin 0 -> 379 bytes bruml/static/arrow_up.png | Bin 0 -> 372 bytes bruml/static/general.css | 203 + bruml/static/index.html | 177 + bruml/static/main.js | 246 + bruml/static/rumlfavicon.ico | Bin 0 -> 11078 bytes db.js | 55 + emails/instructorInvite.ejs | 17 + emails/newCourse.ejs | 13 + emails/userActivation.ejs | 7 + emails/userNoSchool.ejs | 8 + emails/userPasswordReset.ejs | 10 + emails/userSchool.ejs | 8 + emails/userWelcome.ejs | 15 + emails/userWelcomeNoSchool.ejs | 15 + fcbackups/cp2s3.rb | 155 + fcbackups/fc_rotating_db_backup.sh | 69 + fcbackups/fcbackup_init.sh | 7 + log.js | 31 + mailer.js | 56 + models.js | 390 + models/user.js | 2 + node_modules/.bin/express | 1 + node_modules/.bin/jade | 1 + node_modules/async/LICENSE | 19 + node_modules/async/Makefile | 21 + node_modules/async/README.md | 970 ++ node_modules/async/async.min.js.gzip | Bin 0 -> 1859 bytes node_modules/async/deps/nodeunit.css | 70 + node_modules/async/deps/nodeunit.js | 1966 ++++ node_modules/async/dist/async.min.js | 1 + node_modules/async/index.js | 3 + node_modules/async/lib/async.js | 632 ++ node_modules/async/nodelint.cfg | 4 + node_modules/async/package.json | 16 + node_modules/async/test/test-async.js | 1367 +++ node_modules/async/test/test.html | 24 + node_modules/aws-lib/LICENSE | 19 + node_modules/aws-lib/README.md | 47 + node_modules/aws-lib/examples/ec2.js | 7 + node_modules/aws-lib/examples/prod-adv.js | 7 + node_modules/aws-lib/examples/ses.js | 15 + node_modules/aws-lib/lib/aws.js | 114 + node_modules/aws-lib/lib/ec2.js | 33 + node_modules/aws-lib/lib/prodAdv.js | 35 + node_modules/aws-lib/lib/ses.js | 29 + node_modules/aws-lib/lib/simpledb.js | 32 + node_modules/aws-lib/lib/sns.js | 32 + node_modules/aws-lib/lib/sqs.js | 32 + node_modules/aws-lib/node_modules/sax/LICENSE | 19 + .../aws-lib/node_modules/sax/README.md | 153 + .../node_modules/sax/examples/example.js | 41 + .../node_modules/sax/examples/not-pretty.xml | 8 + .../node_modules/sax/examples/pretty-print.js | 72 + .../node_modules/sax/examples/strict.dtd | 870 ++ .../node_modules/sax/examples/switch-bench.js | 45 + .../node_modules/sax/examples/test.html | 15 + .../node_modules/sax/examples/test.xml | 1254 +++ .../aws-lib/node_modules/sax/lib/sax.js | 620 ++ .../aws-lib/node_modules/sax/package.json | 7 + .../node_modules/sax/test/buffer-overrun.js | 25 + .../node_modules/sax/test/cdata-chunked.js | 11 + .../node_modules/sax/test/cdata-end-split.js | 15 + .../node_modules/sax/test/cdata-fake-end.js | 28 + .../node_modules/sax/test/cdata-multiple.js | 15 + .../aws-lib/node_modules/sax/test/cdata.js | 10 + .../aws-lib/node_modules/sax/test/index.js | 73 + .../aws-lib/node_modules/sax/test/issue-23.js | 43 + .../node_modules/sax/test/parser-position.js | 27 + .../sax/test/self-closing-child-strict.js | 40 + .../sax/test/self-closing-child.js | 40 + .../node_modules/sax/test/self-closing-tag.js | 25 + .../sax/test/trailing-non-whitespace.js | 17 + .../aws-lib/node_modules/xml2js/Cakefile | 12 + .../aws-lib/node_modules/xml2js/LICENSE | 19 + .../aws-lib/node_modules/xml2js/README.md | 41 + .../aws-lib/node_modules/xml2js/lib/xml2js.js | 96 + .../aws-lib/node_modules/xml2js/package.json | 29 + .../node_modules/xml2js/src/xml2js.coffee | 78 + .../xml2js/test/fixtures/sample.xml | 21 + .../xml2js/test/xml2js.test.coffee | 60 + node_modules/aws-lib/package.json | 28 + node_modules/aws-lib/test/common.js | 4 + node_modules/aws-lib/test/simpledb.test.js | 183 + node_modules/connect-mongo/.npmignore | 3 + node_modules/connect-mongo/History.md | 34 + node_modules/connect-mongo/Makefile | 5 + node_modules/connect-mongo/Readme.md | 71 + node_modules/connect-mongo/index.js | 2 + .../connect-mongo/lib/connect-mongo.js | 251 + node_modules/connect-mongo/package.json | 13 + .../connect-mongo/test/connect-mongo.test.js | 176 + node_modules/connect/.npmignore | 11 + node_modules/connect/LICENSE | 24 + node_modules/connect/index.js | 2 + node_modules/connect/lib/connect.js | 106 + node_modules/connect/lib/http.js | 212 + node_modules/connect/lib/https.js | 47 + node_modules/connect/lib/index.js | 45 + .../connect/lib/middleware/basicAuth.js | 93 + .../connect/lib/middleware/bodyParser.js | 92 + .../connect/lib/middleware/compiler.js | 163 + .../connect/lib/middleware/cookieParser.js | 46 + node_modules/connect/lib/middleware/csrf.js | 105 + .../connect/lib/middleware/directory.js | 222 + .../connect/lib/middleware/errorHandler.js | 100 + .../connect/lib/middleware/favicon.js | 76 + node_modules/connect/lib/middleware/limit.js | 78 + node_modules/connect/lib/middleware/logger.js | 299 + .../connect/lib/middleware/methodOverride.js | 38 + .../connect/lib/middleware/profiler.js | 100 + node_modules/connect/lib/middleware/query.js | 40 + .../connect/lib/middleware/responseTime.js | 34 + node_modules/connect/lib/middleware/router.js | 379 + .../connect/lib/middleware/session.js | 346 + .../connect/lib/middleware/session/cookie.js | 126 + .../connect/lib/middleware/session/memory.js | 131 + .../connect/lib/middleware/session/session.js | 137 + .../connect/lib/middleware/session/store.js | 59 + node_modules/connect/lib/middleware/static.js | 219 + node_modules/connect/lib/middleware/vhost.js | 44 + node_modules/connect/lib/patch.js | 67 + .../connect/lib/public/directory.html | 75 + node_modules/connect/lib/public/error.html | 13 + node_modules/connect/lib/public/favicon.ico | Bin 0 -> 1406 bytes .../connect/lib/public/icons/page.png | Bin 0 -> 635 bytes .../connect/lib/public/icons/page_add.png | Bin 0 -> 739 bytes .../connect/lib/public/icons/page_attach.png | Bin 0 -> 794 bytes .../connect/lib/public/icons/page_code.png | Bin 0 -> 818 bytes .../connect/lib/public/icons/page_copy.png | Bin 0 -> 663 bytes .../connect/lib/public/icons/page_delete.png | Bin 0 -> 740 bytes .../connect/lib/public/icons/page_edit.png | Bin 0 -> 807 bytes .../connect/lib/public/icons/page_error.png | Bin 0 -> 793 bytes .../connect/lib/public/icons/page_excel.png | Bin 0 -> 817 bytes .../connect/lib/public/icons/page_find.png | Bin 0 -> 879 bytes .../connect/lib/public/icons/page_gear.png | Bin 0 -> 833 bytes .../connect/lib/public/icons/page_go.png | Bin 0 -> 779 bytes .../connect/lib/public/icons/page_green.png | Bin 0 -> 621 bytes .../connect/lib/public/icons/page_key.png | Bin 0 -> 801 bytes .../lib/public/icons/page_lightning.png | Bin 0 -> 839 bytes .../connect/lib/public/icons/page_link.png | Bin 0 -> 830 bytes .../lib/public/icons/page_paintbrush.png | Bin 0 -> 813 bytes .../connect/lib/public/icons/page_paste.png | Bin 0 -> 703 bytes .../connect/lib/public/icons/page_red.png | Bin 0 -> 641 bytes .../connect/lib/public/icons/page_refresh.png | Bin 0 -> 858 bytes .../connect/lib/public/icons/page_save.png | Bin 0 -> 774 bytes .../connect/lib/public/icons/page_white.png | Bin 0 -> 294 bytes .../lib/public/icons/page_white_acrobat.png | Bin 0 -> 591 bytes .../public/icons/page_white_actionscript.png | Bin 0 -> 664 bytes .../lib/public/icons/page_white_add.png | Bin 0 -> 512 bytes .../connect/lib/public/icons/page_white_c.png | Bin 0 -> 587 bytes .../lib/public/icons/page_white_camera.png | Bin 0 -> 656 bytes .../lib/public/icons/page_white_cd.png | Bin 0 -> 666 bytes .../lib/public/icons/page_white_code.png | Bin 0 -> 603 bytes .../lib/public/icons/page_white_code_red.png | Bin 0 -> 587 bytes .../public/icons/page_white_coldfusion.png | Bin 0 -> 592 bytes .../public/icons/page_white_compressed.png | Bin 0 -> 724 bytes .../lib/public/icons/page_white_copy.png | Bin 0 -> 309 bytes .../lib/public/icons/page_white_cplusplus.png | Bin 0 -> 621 bytes .../lib/public/icons/page_white_csharp.png | Bin 0 -> 700 bytes .../lib/public/icons/page_white_cup.png | Bin 0 -> 639 bytes .../lib/public/icons/page_white_database.png | Bin 0 -> 579 bytes .../lib/public/icons/page_white_delete.png | Bin 0 -> 536 bytes .../lib/public/icons/page_white_dvd.png | Bin 0 -> 638 bytes .../lib/public/icons/page_white_edit.png | Bin 0 -> 618 bytes .../lib/public/icons/page_white_error.png | Bin 0 -> 623 bytes .../lib/public/icons/page_white_excel.png | Bin 0 -> 663 bytes .../lib/public/icons/page_white_find.png | Bin 0 -> 676 bytes .../lib/public/icons/page_white_flash.png | Bin 0 -> 582 bytes .../lib/public/icons/page_white_freehand.png | Bin 0 -> 639 bytes .../lib/public/icons/page_white_gear.png | Bin 0 -> 402 bytes .../lib/public/icons/page_white_get.png | Bin 0 -> 516 bytes .../lib/public/icons/page_white_go.png | Bin 0 -> 612 bytes .../connect/lib/public/icons/page_white_h.png | Bin 0 -> 603 bytes .../public/icons/page_white_horizontal.png | Bin 0 -> 296 bytes .../lib/public/icons/page_white_key.png | Bin 0 -> 616 bytes .../lib/public/icons/page_white_lightning.png | Bin 0 -> 669 bytes .../lib/public/icons/page_white_link.png | Bin 0 -> 614 bytes .../lib/public/icons/page_white_magnify.png | Bin 0 -> 554 bytes .../lib/public/icons/page_white_medal.png | Bin 0 -> 706 bytes .../lib/public/icons/page_white_office.png | Bin 0 -> 779 bytes .../lib/public/icons/page_white_paint.png | Bin 0 -> 688 bytes .../public/icons/page_white_paintbrush.png | Bin 0 -> 618 bytes .../lib/public/icons/page_white_paste.png | Bin 0 -> 620 bytes .../lib/public/icons/page_white_php.png | Bin 0 -> 538 bytes .../lib/public/icons/page_white_picture.png | Bin 0 -> 650 bytes .../public/icons/page_white_powerpoint.png | Bin 0 -> 588 bytes .../lib/public/icons/page_white_put.png | Bin 0 -> 523 bytes .../lib/public/icons/page_white_ruby.png | Bin 0 -> 626 bytes .../lib/public/icons/page_white_stack.png | Bin 0 -> 317 bytes .../lib/public/icons/page_white_star.png | Bin 0 -> 565 bytes .../lib/public/icons/page_white_swoosh.png | Bin 0 -> 634 bytes .../lib/public/icons/page_white_text.png | Bin 0 -> 342 bytes .../public/icons/page_white_text_width.png | Bin 0 -> 315 bytes .../lib/public/icons/page_white_tux.png | Bin 0 -> 668 bytes .../lib/public/icons/page_white_vector.png | Bin 0 -> 644 bytes .../public/icons/page_white_visualstudio.png | Bin 0 -> 702 bytes .../lib/public/icons/page_white_width.png | Bin 0 -> 309 bytes .../lib/public/icons/page_white_word.png | Bin 0 -> 651 bytes .../lib/public/icons/page_white_world.png | Bin 0 -> 734 bytes .../lib/public/icons/page_white_wrench.png | Bin 0 -> 613 bytes .../lib/public/icons/page_white_zip.png | Bin 0 -> 386 bytes .../connect/lib/public/icons/page_word.png | Bin 0 -> 777 bytes .../connect/lib/public/icons/page_world.png | Bin 0 -> 903 bytes node_modules/connect/lib/public/style.css | 141 + node_modules/connect/lib/utils.js | 427 + node_modules/connect/meta.json | 1 + .../connect/node_modules/mime/LICENSE | 19 + .../connect/node_modules/mime/README.md | 54 + .../connect/node_modules/mime/index.js | 1 + .../connect/node_modules/mime/mime.js | 89 + .../connect/node_modules/mime/mime.types | 1479 +++ .../connect/node_modules/mime/node.types | 7 + .../connect/node_modules/mime/package.json | 11 + .../connect/node_modules/mime/test.js | 74 + .../connect/node_modules/qs/History.md | 46 + node_modules/connect/node_modules/qs/Makefile | 7 + .../connect/node_modules/qs/Readme.md | 49 + .../connect/node_modules/qs/benchmark.js | 17 + .../connect/node_modules/qs/examples.js | 48 + node_modules/connect/node_modules/qs/index.js | 2 + .../node_modules/qs/lib/querystring.js | 227 + .../connect/node_modules/qs/package.json | 9 + .../qs/support/expresso/History.md | 128 + .../node_modules/qs/support/expresso/Makefile | 53 + .../qs/support/expresso/Readme.md | 61 + .../qs/support/expresso/bin/expresso | 856 ++ .../qs/support/expresso/docs/api.html | 1080 +++ .../qs/support/expresso/docs/index.html | 377 + .../qs/support/expresso/docs/index.md | 290 + .../qs/support/expresso/docs/layout/foot.html | 3 + .../qs/support/expresso/docs/layout/head.html | 42 + .../qs/support/expresso/lib/bar.js | 4 + .../qs/support/expresso/lib/foo.js | 16 + .../qs/support/expresso/package.json | 12 + .../qs/support/expresso/test/assert.test.js | 91 + .../qs/support/expresso/test/async.test.js | 12 + .../qs/support/expresso/test/bar.test.js | 13 + .../qs/support/expresso/test/foo.test.js | 14 + .../qs/support/expresso/test/http.test.js | 146 + .../expresso/test/serial/async.test.js | 39 + .../support/expresso/test/serial/http.test.js | 48 + .../node_modules/qs/support/should/History.md | 22 + .../node_modules/qs/support/should/Makefile | 6 + .../node_modules/qs/support/should/Readme.md | 248 + .../qs/support/should/examples/runner.js | 53 + .../node_modules/qs/support/should/index.js | 2 + .../node_modules/qs/support/should/lib/eql.js | 91 + .../qs/support/should/lib/should.js | 548 ++ .../qs/support/should/package.json | 8 + .../qs/support/should/test/should.test.js | 358 + .../node_modules/qs/test/parse.test.js | 141 + .../node_modules/qs/test/stringify.test.js | 95 + node_modules/connect/package.json | 24 + node_modules/connect/test.js | 65 + node_modules/ejs/History.md | 70 + node_modules/ejs/Makefile | 19 + node_modules/ejs/Readme.md | 142 + node_modules/ejs/benchmark.js | 14 + node_modules/ejs/ejs.js | 531 ++ node_modules/ejs/ejs.min.js | 2 + node_modules/ejs/examples/client.html | 5 + node_modules/ejs/examples/list.ejs | 7 + node_modules/ejs/examples/list.js | 16 + node_modules/ejs/index.js | 2 + node_modules/ejs/lib/ejs.js | 251 + node_modules/ejs/lib/filters.js | 198 + node_modules/ejs/lib/utils.js | 23 + node_modules/ejs/package.json | 8 + node_modules/ejs/support/compile.js | 173 + node_modules/ejs/support/expresso/History.md | 87 + node_modules/ejs/support/expresso/Makefile | 50 + node_modules/ejs/support/expresso/Readme.md | 39 + .../ejs/support/expresso/bin/expresso | 775 ++ .../ejs/support/expresso/docs/api.html | 989 ++ .../ejs/support/expresso/docs/index.html | 380 + .../ejs/support/expresso/docs/index.md | 292 + .../support/expresso/docs/layout/foot.html | 3 + .../support/expresso/docs/layout/head.html | 47 + node_modules/ejs/support/expresso/lib/bar.js | 4 + node_modules/ejs/support/expresso/lib/foo.js | 16 + .../ejs/support/expresso/package.json | 9 + .../ejs/support/expresso/test/assert.test.js | 84 + .../ejs/support/expresso/test/async.test.js | 6 + .../ejs/support/expresso/test/bar.test.js | 12 + .../ejs/support/expresso/test/foo.test.js | 13 + .../ejs/support/expresso/test/http.test.js | 76 + node_modules/ejs/test/ejs.test.js | 268 + node_modules/express-messages/.npmignore | 2 + node_modules/express-messages/History.md | 10 + node_modules/express-messages/Makefile | 9 + node_modules/express-messages/Readme.md | 63 + node_modules/express-messages/index.js | 31 + node_modules/express-messages/package.json | 8 + node_modules/express/.npmignore | 7 + node_modules/express/History.md | 719 ++ node_modules/express/LICENSE | 22 + node_modules/express/Makefile | 35 + node_modules/express/Readme.md | 143 + node_modules/express/bin/express | 417 + node_modules/express/index.js | 2 + node_modules/express/lib/express.js | 79 + node_modules/express/lib/http.js | 544 ++ node_modules/express/lib/https.js | 52 + node_modules/express/lib/request.js | 309 + node_modules/express/lib/response.js | 462 + node_modules/express/lib/router/collection.js | 53 + node_modules/express/lib/router/index.js | 384 + node_modules/express/lib/router/methods.js | 70 + node_modules/express/lib/router/route.js | 90 + node_modules/express/lib/utils.js | 139 + node_modules/express/lib/view.js | 459 + node_modules/express/lib/view/partial.js | 40 + node_modules/express/lib/view/view.js | 209 + .../express/node_modules/connect/.npmignore | 11 + .../express/node_modules/connect/LICENSE | 24 + .../express/node_modules/connect/index.js | 2 + .../node_modules/connect/lib/connect.js | 106 + .../express/node_modules/connect/lib/http.js | 212 + .../express/node_modules/connect/lib/https.js | 47 + .../express/node_modules/connect/lib/index.js | 45 + .../connect/lib/middleware/basicAuth.js | 93 + .../connect/lib/middleware/bodyParser.js | 92 + .../connect/lib/middleware/compiler.js | 163 + .../connect/lib/middleware/cookieParser.js | 46 + .../connect/lib/middleware/csrf.js | 105 + .../connect/lib/middleware/directory.js | 219 + .../connect/lib/middleware/errorHandler.js | 100 + .../connect/lib/middleware/favicon.js | 76 + .../connect/lib/middleware/limit.js | 78 + .../connect/lib/middleware/logger.js | 287 + .../connect/lib/middleware/methodOverride.js | 38 + .../connect/lib/middleware/profiler.js | 100 + .../connect/lib/middleware/query.js | 40 + .../connect/lib/middleware/responseTime.js | 34 + .../connect/lib/middleware/router.js | 379 + .../connect/lib/middleware/session.js | 346 + .../connect/lib/middleware/session/cookie.js | 126 + .../connect/lib/middleware/session/memory.js | 131 + .../connect/lib/middleware/session/session.js | 137 + .../connect/lib/middleware/session/store.js | 59 + .../connect/lib/middleware/static.js | 215 + .../connect/lib/middleware/vhost.js | 44 + .../express/node_modules/connect/lib/patch.js | 67 + .../connect/lib/public/directory.html | 75 + .../connect/lib/public/error.html | 13 + .../connect/lib/public/favicon.ico | Bin 0 -> 1406 bytes .../connect/lib/public/icons/page.png | Bin 0 -> 635 bytes .../connect/lib/public/icons/page_add.png | Bin 0 -> 739 bytes .../connect/lib/public/icons/page_attach.png | Bin 0 -> 794 bytes .../connect/lib/public/icons/page_code.png | Bin 0 -> 818 bytes .../connect/lib/public/icons/page_copy.png | Bin 0 -> 663 bytes .../connect/lib/public/icons/page_delete.png | Bin 0 -> 740 bytes .../connect/lib/public/icons/page_edit.png | Bin 0 -> 807 bytes .../connect/lib/public/icons/page_error.png | Bin 0 -> 793 bytes .../connect/lib/public/icons/page_excel.png | Bin 0 -> 817 bytes .../connect/lib/public/icons/page_find.png | Bin 0 -> 879 bytes .../connect/lib/public/icons/page_gear.png | Bin 0 -> 833 bytes .../connect/lib/public/icons/page_go.png | Bin 0 -> 779 bytes .../connect/lib/public/icons/page_green.png | Bin 0 -> 621 bytes .../connect/lib/public/icons/page_key.png | Bin 0 -> 801 bytes .../lib/public/icons/page_lightning.png | Bin 0 -> 839 bytes .../connect/lib/public/icons/page_link.png | Bin 0 -> 830 bytes .../lib/public/icons/page_paintbrush.png | Bin 0 -> 813 bytes .../connect/lib/public/icons/page_paste.png | Bin 0 -> 703 bytes .../connect/lib/public/icons/page_red.png | Bin 0 -> 641 bytes .../connect/lib/public/icons/page_refresh.png | Bin 0 -> 858 bytes .../connect/lib/public/icons/page_save.png | Bin 0 -> 774 bytes .../connect/lib/public/icons/page_white.png | Bin 0 -> 294 bytes .../lib/public/icons/page_white_acrobat.png | Bin 0 -> 591 bytes .../public/icons/page_white_actionscript.png | Bin 0 -> 664 bytes .../lib/public/icons/page_white_add.png | Bin 0 -> 512 bytes .../connect/lib/public/icons/page_white_c.png | Bin 0 -> 587 bytes .../lib/public/icons/page_white_camera.png | Bin 0 -> 656 bytes .../lib/public/icons/page_white_cd.png | Bin 0 -> 666 bytes .../lib/public/icons/page_white_code.png | Bin 0 -> 603 bytes .../lib/public/icons/page_white_code_red.png | Bin 0 -> 587 bytes .../public/icons/page_white_coldfusion.png | Bin 0 -> 592 bytes .../public/icons/page_white_compressed.png | Bin 0 -> 724 bytes .../lib/public/icons/page_white_copy.png | Bin 0 -> 309 bytes .../lib/public/icons/page_white_cplusplus.png | Bin 0 -> 621 bytes .../lib/public/icons/page_white_csharp.png | Bin 0 -> 700 bytes .../lib/public/icons/page_white_cup.png | Bin 0 -> 639 bytes .../lib/public/icons/page_white_database.png | Bin 0 -> 579 bytes .../lib/public/icons/page_white_delete.png | Bin 0 -> 536 bytes .../lib/public/icons/page_white_dvd.png | Bin 0 -> 638 bytes .../lib/public/icons/page_white_edit.png | Bin 0 -> 618 bytes .../lib/public/icons/page_white_error.png | Bin 0 -> 623 bytes .../lib/public/icons/page_white_excel.png | Bin 0 -> 663 bytes .../lib/public/icons/page_white_find.png | Bin 0 -> 676 bytes .../lib/public/icons/page_white_flash.png | Bin 0 -> 582 bytes .../lib/public/icons/page_white_freehand.png | Bin 0 -> 639 bytes .../lib/public/icons/page_white_gear.png | Bin 0 -> 402 bytes .../lib/public/icons/page_white_get.png | Bin 0 -> 516 bytes .../lib/public/icons/page_white_go.png | Bin 0 -> 612 bytes .../connect/lib/public/icons/page_white_h.png | Bin 0 -> 603 bytes .../public/icons/page_white_horizontal.png | Bin 0 -> 296 bytes .../lib/public/icons/page_white_key.png | Bin 0 -> 616 bytes .../lib/public/icons/page_white_lightning.png | Bin 0 -> 669 bytes .../lib/public/icons/page_white_link.png | Bin 0 -> 614 bytes .../lib/public/icons/page_white_magnify.png | Bin 0 -> 554 bytes .../lib/public/icons/page_white_medal.png | Bin 0 -> 706 bytes .../lib/public/icons/page_white_office.png | Bin 0 -> 779 bytes .../lib/public/icons/page_white_paint.png | Bin 0 -> 688 bytes .../public/icons/page_white_paintbrush.png | Bin 0 -> 618 bytes .../lib/public/icons/page_white_paste.png | Bin 0 -> 620 bytes .../lib/public/icons/page_white_php.png | Bin 0 -> 538 bytes .../lib/public/icons/page_white_picture.png | Bin 0 -> 650 bytes .../public/icons/page_white_powerpoint.png | Bin 0 -> 588 bytes .../lib/public/icons/page_white_put.png | Bin 0 -> 523 bytes .../lib/public/icons/page_white_ruby.png | Bin 0 -> 626 bytes .../lib/public/icons/page_white_stack.png | Bin 0 -> 317 bytes .../lib/public/icons/page_white_star.png | Bin 0 -> 565 bytes .../lib/public/icons/page_white_swoosh.png | Bin 0 -> 634 bytes .../lib/public/icons/page_white_text.png | Bin 0 -> 342 bytes .../public/icons/page_white_text_width.png | Bin 0 -> 315 bytes .../lib/public/icons/page_white_tux.png | Bin 0 -> 668 bytes .../lib/public/icons/page_white_vector.png | Bin 0 -> 644 bytes .../public/icons/page_white_visualstudio.png | Bin 0 -> 702 bytes .../lib/public/icons/page_white_width.png | Bin 0 -> 309 bytes .../lib/public/icons/page_white_word.png | Bin 0 -> 651 bytes .../lib/public/icons/page_white_world.png | Bin 0 -> 734 bytes .../lib/public/icons/page_white_wrench.png | Bin 0 -> 613 bytes .../lib/public/icons/page_white_zip.png | Bin 0 -> 386 bytes .../connect/lib/public/icons/page_word.png | Bin 0 -> 777 bytes .../connect/lib/public/icons/page_world.png | Bin 0 -> 903 bytes .../node_modules/connect/lib/public/style.css | 141 + .../express/node_modules/connect/lib/utils.js | 427 + .../express/node_modules/connect/meta.json | 1 + .../node_modules/connect-redis/History.md | 84 + .../node_modules/connect-redis/Makefile | 7 + .../node_modules/connect-redis/Readme.md | 35 + .../connect/node_modules/connect-redis/bm.js | 21 + .../node_modules/connect-redis/index.html | 232 + .../node_modules/connect-redis/index.js | 2 + .../connect-redis/lib/connect-redis.js | 141 + .../node_modules/connect-redis/package.json | 10 + .../node_modules/connect-redis/test.js | 61 + .../express/node_modules/connect/package.json | 24 + .../express/node_modules/connect/test.js | 39 + .../express/node_modules/mime/LICENSE | 19 + .../express/node_modules/mime/README.md | 54 + .../express/node_modules/mime/index.js | 1 + .../express/node_modules/mime/mime.js | 89 + .../express/node_modules/mime/mime.types | 1479 +++ .../express/node_modules/mime/node.types | 7 + .../express/node_modules/mime/package.json | 11 + .../express/node_modules/mime/test.js | 74 + .../express/node_modules/qs/History.md | 46 + node_modules/express/node_modules/qs/Makefile | 7 + .../express/node_modules/qs/Readme.md | 49 + .../express/node_modules/qs/benchmark.js | 17 + .../express/node_modules/qs/examples.js | 48 + node_modules/express/node_modules/qs/index.js | 2 + .../node_modules/qs/lib/querystring.js | 227 + .../express/node_modules/qs/package.json | 9 + .../qs/support/expresso/History.md | 128 + .../node_modules/qs/support/expresso/Makefile | 53 + .../qs/support/expresso/Readme.md | 61 + .../qs/support/expresso/bin/expresso | 856 ++ .../qs/support/expresso/docs/api.html | 1080 +++ .../qs/support/expresso/docs/index.html | 377 + .../qs/support/expresso/docs/index.md | 290 + .../qs/support/expresso/docs/layout/foot.html | 3 + .../qs/support/expresso/docs/layout/head.html | 42 + .../qs/support/expresso/lib/bar.js | 4 + .../qs/support/expresso/lib/foo.js | 16 + .../qs/support/expresso/package.json | 12 + .../qs/support/expresso/test/assert.test.js | 91 + .../qs/support/expresso/test/async.test.js | 12 + .../qs/support/expresso/test/bar.test.js | 13 + .../qs/support/expresso/test/foo.test.js | 14 + .../qs/support/expresso/test/http.test.js | 146 + .../expresso/test/serial/async.test.js | 39 + .../support/expresso/test/serial/http.test.js | 48 + .../node_modules/qs/support/should/History.md | 22 + .../node_modules/qs/support/should/Makefile | 6 + .../node_modules/qs/support/should/Readme.md | 248 + .../qs/support/should/examples/runner.js | 53 + .../node_modules/qs/support/should/index.js | 2 + .../node_modules/qs/support/should/lib/eql.js | 91 + .../qs/support/should/lib/should.js | 548 ++ .../qs/support/should/package.json | 8 + .../qs/support/should/test/should.test.js | 358 + .../node_modules/qs/test/parse.test.js | 141 + .../node_modules/qs/test/stringify.test.js | 95 + node_modules/express/package.json | 38 + node_modules/hat/README.markdown | 71 + node_modules/hat/example/hat.js | 4 + node_modules/hat/example/rack.js | 5 + node_modules/hat/index.js | 62 + node_modules/hat/package.json | 37 + node_modules/hat/test/id.js | 49 + node_modules/hat/test/rack.js | 62 + node_modules/hooks/.npmignore | 3 + node_modules/hooks/Makefile | 9 + node_modules/hooks/README.md | 306 + node_modules/hooks/hooks.alt.js | 134 + node_modules/hooks/hooks.js | 161 + node_modules/hooks/package.json | 30 + node_modules/hooks/test.js | 681 ++ node_modules/jade/.npmignore | 4 + node_modules/jade/History.md | 379 + node_modules/jade/LICENSE | 22 + node_modules/jade/Makefile | 30 + node_modules/jade/Readme.md | 651 ++ node_modules/jade/benchmarks/common.js | 32 + node_modules/jade/benchmarks/ejs.js | 24 + node_modules/jade/benchmarks/ejs/History.md | 50 + node_modules/jade/benchmarks/ejs/Makefile | 5 + node_modules/jade/benchmarks/ejs/Readme.md | 137 + node_modules/jade/benchmarks/ejs/benchmark.js | 14 + .../jade/benchmarks/ejs/examples/list.ejs | 7 + .../jade/benchmarks/ejs/examples/list.js | 16 + node_modules/jade/benchmarks/ejs/index.js | 2 + node_modules/jade/benchmarks/ejs/lib/ejs.js | 193 + .../jade/benchmarks/ejs/lib/filters.js | 198 + node_modules/jade/benchmarks/ejs/lib/utils.js | 23 + node_modules/jade/benchmarks/ejs/package.json | 8 + .../jade/benchmarks/ejs/test/ejs.test.js | 225 + .../jade/benchmarks/example-self.jade | 6 + node_modules/jade/benchmarks/example.ejs | 8 + node_modules/jade/benchmarks/example.haml | 6 + node_modules/jade/benchmarks/example.jade | 6 + node_modules/jade/benchmarks/example2.haml | 6 + .../benchmarks/haml-js/CHANGELOG.markdown | 47 + node_modules/jade/benchmarks/haml-js/LICENSE | 22 + .../jade/benchmarks/haml-js/README.markdown | 205 + .../jade/benchmarks/haml-js/lib/haml.js | 506 + .../jade/benchmarks/haml-js/package.json | 8 + .../benchmarks/haml-js/test/alt_attribs.haml | 4 + .../benchmarks/haml-js/test/alt_attribs.html | 1 + .../benchmarks/haml-js/test/div_nesting.haml | 5 + .../benchmarks/haml-js/test/div_nesting.html | 1 + .../jade/benchmarks/haml-js/test/doctype.haml | 5 + .../jade/benchmarks/haml-js/test/doctype.html | 5 + .../haml-js/test/embedded_code.haml | 6 + .../haml-js/test/embedded_code.html | 7 + .../benchmarks/haml-js/test/embedded_code.js | 7 + .../jade/benchmarks/haml-js/test/foreach.haml | 12 + .../jade/benchmarks/haml-js/test/foreach.html | 1 + .../jade/benchmarks/haml-js/test/foreach.js | 10 + .../jade/benchmarks/haml-js/test/meta.haml | 1 + .../jade/benchmarks/haml-js/test/meta.html | 1 + .../jade/benchmarks/haml-js/test/nanline.haml | 6 + .../jade/benchmarks/haml-js/test/nanline.html | 2 + .../haml-js/test/nested_context.haml | 6 + .../haml-js/test/nested_context.html | 1 + .../benchmarks/haml-js/test/nested_context.js | 8 + .../haml-js/test/no_self_close_div.haml | 8 + .../haml-js/test/no_self_close_div.html | 9 + .../haml-js/test/non-string-attribs.haml | 8 + .../haml-js/test/non-string-attribs.html | 1 + .../benchmarks/haml-js/test/script_css.haml | 12 + .../benchmarks/haml-js/test/script_css.html | 15 + .../benchmarks/haml-js/test/self_close.haml | 8 + .../benchmarks/haml-js/test/self_close.html | 1 + .../benchmarks/haml-js/test/self_close.js | 5 + .../benchmarks/haml-js/test/standard.haml | 14 + .../benchmarks/haml-js/test/standard.html | 3 + .../jade/benchmarks/haml-js/test/standard.js | 12 + .../benchmarks/haml-js/test/test-commonjs.js | 23 + .../jade/benchmarks/haml-js/test/test.js | 52 + node_modules/jade/benchmarks/haml.js | 25 + node_modules/jade/benchmarks/haml/.ignore | 1 + node_modules/jade/benchmarks/haml/History.md | 88 + node_modules/jade/benchmarks/haml/Makefile | 8 + node_modules/jade/benchmarks/haml/Readme.md | 339 + .../jade/benchmarks/haml/benchmarks/page.haml | 30 + .../jade/benchmarks/haml/benchmarks/run.js | 25 + .../jade/benchmarks/haml/examples/example.js | 15 + .../jade/benchmarks/haml/examples/page.haml | 22 + node_modules/jade/benchmarks/haml/index.js | 1 + node_modules/jade/benchmarks/haml/lib/haml.js | 666 ++ .../jade/benchmarks/haml/package.json | 10 + node_modules/jade/benchmarks/haml/seed.yml | 5 + .../benchmarks/haml/spec/fixtures/class.haml | 1 + .../benchmarks/haml/spec/fixtures/class.html | 1 + .../haml/spec/fixtures/classes.haml | 1 + .../haml/spec/fixtures/classes.html | 1 + .../haml/spec/fixtures/code.each.haml | 3 + .../haml/spec/fixtures/code.each.html | 4 + .../haml/spec/fixtures/code.each.index.haml | 3 + .../haml/spec/fixtures/code.each.index.html | 4 + .../fixtures/code.each.non-enumerable.haml | 3 + .../fixtures/code.each.non-enumerable.html | 1 + .../haml/spec/fixtures/code.escape.haml | 1 + .../haml/spec/fixtures/code.escape.html | 1 + .../benchmarks/haml/spec/fixtures/code.haml | 1 + .../benchmarks/haml/spec/fixtures/code.html | 1 + .../haml/spec/fixtures/code.if.haml | 3 + .../haml/spec/fixtures/code.if.html | 1 + .../haml/spec/fixtures/code.nested.haml | 5 + .../haml/spec/fixtures/code.nested.html | 1 + .../fixtures/comment.block.conditional.haml | 9 + .../fixtures/comment.block.conditional.html | 6 + .../haml/spec/fixtures/comment.block.haml | 5 + .../haml/spec/fixtures/comment.block.html | 5 + .../haml/spec/fixtures/comment.haml | 3 + .../haml/spec/fixtures/comment.html | 1 + .../haml/spec/fixtures/comment.tag.haml | 1 + .../haml/spec/fixtures/comment.tag.html | 2 + .../spec/fixtures/comment.text.complex.haml | 7 + .../spec/fixtures/comment.text.complex.html | 5 + .../haml/spec/fixtures/comment.text.haml | 2 + .../haml/spec/fixtures/comment.text.html | 1 + .../haml/spec/fixtures/context.haml | 1 + .../haml/spec/fixtures/context.html | 1 + .../benchmarks/haml/spec/fixtures/cr.haml | 1 + .../benchmarks/haml/spec/fixtures/cr.html | 3 + .../benchmarks/haml/spec/fixtures/crlf.haml | 2 + .../benchmarks/haml/spec/fixtures/crlf.html | 3 + .../haml/spec/fixtures/doctype.haml | 1 + .../haml/spec/fixtures/doctype.html | 1 + .../haml/spec/fixtures/doctype.xml.case.haml | 1 + .../haml/spec/fixtures/doctype.xml.case.html | 1 + .../haml/spec/fixtures/doctype.xml.haml | 1 + .../haml/spec/fixtures/doctype.xml.html | 1 + .../benchmarks/haml/spec/fixtures/error.haml | 3 + .../benchmarks/haml/spec/fixtures/escape.haml | 2 + .../benchmarks/haml/spec/fixtures/escape.html | 1 + .../benchmarks/haml/spec/fixtures/feed.haml | 11 + .../benchmarks/haml/spec/fixtures/feed.xml | 11 + .../haml/spec/fixtures/filter.cdata.haml | 3 + .../haml/spec/fixtures/filter.cdata.html | 3 + .../fixtures/filter.cdata.whitespace.haml | 7 + .../fixtures/filter.cdata.whitespace.html | 7 + .../haml/spec/fixtures/filter.javascript.haml | 8 + .../haml/spec/fixtures/filter.javascript.html | 9 + .../haml/spec/fixtures/filter.plain.haml | 5 + .../haml/spec/fixtures/filter.plain.html | 3 + .../benchmarks/haml/spec/fixtures/html.haml | 2 + .../benchmarks/haml/spec/fixtures/html.html | 1 + .../benchmarks/haml/spec/fixtures/id.haml | 1 + .../benchmarks/haml/spec/fixtures/id.html | 1 + .../haml/spec/fixtures/issue.#10.haml | 1 + .../haml/spec/fixtures/issue.#10.html | 1 + .../haml/spec/fixtures/issue.#8.haml | 4 + .../haml/spec/fixtures/issue.#8.html | 5 + .../haml/spec/fixtures/literals.haml | 1 + .../haml/spec/fixtures/literals.html | 1 + .../haml/spec/fixtures/namespace.haml | 1 + .../haml/spec/fixtures/namespace.tag.haml | 5 + .../haml/spec/fixtures/namespace.tag.html | 5 + .../haml/spec/fixtures/namespace.xml | 1 + .../haml/spec/fixtures/nesting.complex.haml | 6 + .../haml/spec/fixtures/nesting.complex.html | 6 + .../haml/spec/fixtures/nesting.simple.haml | 6 + .../haml/spec/fixtures/nesting.simple.html | 6 + .../haml/spec/fixtures/newlines.haml | 12 + .../haml/spec/fixtures/newlines.html | 9 + .../haml/spec/fixtures/tag.attrs.bools.haml | 1 + .../haml/spec/fixtures/tag.attrs.bools.html | 1 + .../haml/spec/fixtures/tag.attrs.escape.haml | 1 + .../haml/spec/fixtures/tag.attrs.escape.html | 1 + .../haml/spec/fixtures/tag.attrs.haml | 1 + .../haml/spec/fixtures/tag.attrs.html | 1 + .../haml/spec/fixtures/tag.class.haml | 1 + .../haml/spec/fixtures/tag.class.html | 1 + .../haml/spec/fixtures/tag.classes.haml | 1 + .../haml/spec/fixtures/tag.classes.html | 1 + .../haml/spec/fixtures/tag.code.haml | 1 + .../haml/spec/fixtures/tag.code.html | 1 + .../spec/fixtures/tag.code.no-escape.haml | 1 + .../spec/fixtures/tag.code.no-escape.html | 1 + .../haml/spec/fixtures/tag.complex.haml | 1 + .../haml/spec/fixtures/tag.complex.html | 1 + .../haml/spec/fixtures/tag.empty.haml | 7 + .../haml/spec/fixtures/tag.empty.html | 7 + .../haml/spec/fixtures/tag.escape.haml | 1 + .../haml/spec/fixtures/tag.escape.html | 1 + .../haml/spec/fixtures/tag.self-close.haml | 1 + .../haml/spec/fixtures/tag.self-close.html | 1 + .../haml/spec/fixtures/tag.simple.haml | 1 + .../haml/spec/fixtures/tag.simple.html | 1 + .../spec/fixtures/tag.text.block.complex.haml | 5 + .../spec/fixtures/tag.text.block.complex.html | 2 + .../haml/spec/fixtures/tag.text.block.haml | 5 + .../haml/spec/fixtures/tag.text.block.html | 1 + .../haml/spec/fixtures/tag.text.haml | 1 + .../haml/spec/fixtures/tag.text.html | 1 + .../haml/spec/fixtures/trailing-indent.haml | 4 + .../haml/spec/fixtures/trailing-indent.html | 2 + .../benchmarks/haml/spec/lib/images/bg.png | Bin 0 -> 154 bytes .../benchmarks/haml/spec/lib/images/hr.png | Bin 0 -> 321 bytes .../haml/spec/lib/images/loading.gif | Bin 0 -> 2608 bytes .../haml/spec/lib/images/sprites.bg.png | Bin 0 -> 4876 bytes .../haml/spec/lib/images/sprites.png | Bin 0 -> 3629 bytes .../benchmarks/haml/spec/lib/images/vr.png | Bin 0 -> 145 bytes .../jade/benchmarks/haml/spec/lib/jspec.css | 149 + .../benchmarks/haml/spec/lib/jspec.growl.js | 115 + .../benchmarks/haml/spec/lib/jspec.jquery.js | 79 + .../jade/benchmarks/haml/spec/lib/jspec.js | 1893 ++++ .../benchmarks/haml/spec/lib/jspec.nodejs.js | 18 + .../benchmarks/haml/spec/lib/jspec.shell.js | 39 + .../benchmarks/haml/spec/lib/jspec.timers.js | 90 + .../benchmarks/haml/spec/lib/jspec.xhr.js | 210 + .../jade/benchmarks/haml/spec/node.js | 10 + .../benchmarks/haml/spec/unit/spec.helper.js | 0 .../jade/benchmarks/haml/spec/unit/spec.js | 316 + node_modules/jade/benchmarks/haml2.js | 30 + node_modules/jade/benchmarks/jade-self.js | 43 + node_modules/jade/benchmarks/jade.js | 41 + node_modules/jade/bin/jade | 206 + node_modules/jade/examples/attributes.jade | 8 + node_modules/jade/examples/attributes.js | 12 + node_modules/jade/examples/code.jade | 8 + node_modules/jade/examples/code.js | 20 + node_modules/jade/examples/conditionals.jade | 8 + node_modules/jade/examples/conditionals.js | 59 + node_modules/jade/examples/csrf.jade | 5 + node_modules/jade/examples/csrf.js | 42 + node_modules/jade/examples/dynamicscript.jade | 5 + node_modules/jade/examples/dynamicscript.js | 20 + node_modules/jade/examples/each.jade | 3 + node_modules/jade/examples/each.js | 20 + node_modules/jade/examples/form.jade | 29 + node_modules/jade/examples/form.js | 22 + node_modules/jade/examples/includes.jade | 7 + node_modules/jade/examples/includes.js | 11 + node_modules/jade/examples/includes/foot.jade | 2 + node_modules/jade/examples/includes/head.jade | 4 + node_modules/jade/examples/layout-debug.js | 11 + node_modules/jade/examples/layout.jade | 14 + node_modules/jade/examples/layout.js | 11 + node_modules/jade/examples/mixins.jade | 16 + node_modules/jade/examples/mixins.js | 18 + node_modules/jade/examples/mixins/dialog.jade | 15 + .../jade/examples/mixins/profile.jade | 10 + node_modules/jade/examples/model.jade | 9 + node_modules/jade/examples/model.js | 124 + .../jade/examples/nested-filters.jade | 8 + node_modules/jade/examples/nested-filters.js | 73 + node_modules/jade/examples/rss.jade | 13 + node_modules/jade/examples/rss.js | 11 + node_modules/jade/examples/text.jade | 36 + node_modules/jade/examples/text.js | 10 + node_modules/jade/examples/whitespace.jade | 11 + node_modules/jade/examples/whitespace.js | 11 + node_modules/jade/index.js | 2 + node_modules/jade/jade.js | 2440 +++++ node_modules/jade/jade.min.js | 2 + node_modules/jade/lib/compiler.js | 440 + node_modules/jade/lib/doctypes.js | 19 + node_modules/jade/lib/filters.js | 92 + node_modules/jade/lib/index.js | 1 + node_modules/jade/lib/inline-tags.js | 28 + node_modules/jade/lib/jade.js | 318 + node_modules/jade/lib/lexer.js | 547 ++ node_modules/jade/lib/nodes/block-comment.js | 33 + node_modules/jade/lib/nodes/block.js | 54 + node_modules/jade/lib/nodes/code.js | 35 + node_modules/jade/lib/nodes/comment.js | 32 + node_modules/jade/lib/nodes/doctype.js | 29 + node_modules/jade/lib/nodes/each.js | 35 + node_modules/jade/lib/nodes/filter.js | 35 + node_modules/jade/lib/nodes/index.js | 18 + node_modules/jade/lib/nodes/mixin.js | 34 + node_modules/jade/lib/nodes/node.js | 14 + node_modules/jade/lib/nodes/tag.js | 80 + node_modules/jade/lib/nodes/text.js | 42 + node_modules/jade/lib/parser.js | 478 + node_modules/jade/lib/self-closing.js | 18 + node_modules/jade/lib/utils.js | 49 + node_modules/jade/package.json | 19 + .../jade/support/coffee-script/Cakefile | 134 + .../jade/support/coffee-script/LICENSE | 22 + .../jade/support/coffee-script/README | 48 + .../jade/support/coffee-script/Rakefile | 53 + .../jade/support/coffee-script/bin/cake | 8 + .../jade/support/coffee-script/bin/coffee | 8 + .../documentation/coffee/aliases.coffee | 11 + .../coffee/array_comprehensions.coffee | 7 + .../documentation/coffee/block_comment.coffee | 4 + .../documentation/coffee/cake_tasks.coffee | 9 + .../documentation/coffee/classes.coffee | 25 + .../documentation/coffee/comparisons.coffee | 5 + .../documentation/coffee/conditionals.coffee | 11 + .../documentation/coffee/embedded.coffee | 5 + .../documentation/coffee/existence.coffee | 8 + .../documentation/coffee/expressions.coffee | 9 + .../coffee/expressions_assignment.coffee | 1 + .../coffee/expressions_comprehension.coffee | 3 + .../coffee/expressions_try.coffee | 6 + .../documentation/coffee/fat_arrow.coffee | 6 + .../documentation/coffee/functions.coffee | 2 + .../documentation/coffee/heredocs.coffee | 5 + .../documentation/coffee/interpolation.coffee | 2 + .../coffee/interpolation_expression.coffee | 6 + .../coffee/multiple_return_values.coffee | 5 + .../coffee/object_comprehensions.coffee | 4 + .../coffee/object_extraction.coffee | 11 + .../coffee/objects_and_arrays.coffee | 17 + .../coffee/objects_reserved.coffee | 1 + .../documentation/coffee/overview.coffee | 28 + .../coffee/parallel_assignment.coffee | 4 + .../coffee/patterns_and_splats.coffee | 7 + .../documentation/coffee/prototypes.coffee | 2 + .../coffee/range_comprehensions.coffee | 6 + .../documentation/coffee/scope.coffee | 5 + .../documentation/coffee/slices.coffee | 6 + .../documentation/coffee/soaks.coffee | 1 + .../documentation/coffee/splats.coffee | 25 + .../documentation/coffee/splices.coffee | 5 + .../documentation/coffee/strings.coffee | 8 + .../documentation/coffee/switch.coffee | 10 + .../documentation/coffee/try.coffee | 7 + .../documentation/coffee/while.coffee | 10 + .../coffee-script/documentation/css/docs.css | 284 + .../coffee-script/documentation/css/idle.css | 64 + .../documentation/docs/browser.html | 24 + .../documentation/docs/cake.html | 43 + .../documentation/docs/coffee-script.html | 50 + .../documentation/docs/command.html | 148 + .../documentation/docs/docco.css | 185 + .../documentation/docs/grammar.html | 421 + .../documentation/docs/helpers.html | 37 + .../documentation/docs/index.html | 3 + .../documentation/docs/lexer.html | 431 + .../documentation/docs/nodes.html | 1245 +++ .../documentation/docs/optparse.html | 75 + .../documentation/docs/repl.html | 23 + .../documentation/docs/rewriter.html | 265 + .../documentation/docs/scope.html | 57 + .../documentation/docs/underscore.html | 296 + .../documentation/images/favicon.ico | Bin 0 -> 1406 bytes .../documentation/images/logo.png | Bin 0 -> 6059 bytes .../documentation/index.html.erb | 1364 +++ .../coffee-script/documentation/js/aliases.js | 17 + .../documentation/js/array_comprehensions.js | 20 + .../documentation/js/block_comment.js | 4 + .../documentation/js/cake_tasks.js | 10 + .../coffee-script/documentation/js/classes.js | 42 + .../documentation/js/comparisons.js | 3 + .../documentation/js/conditionals.js | 12 + .../documentation/js/embedded.js | 4 + .../documentation/js/existence.js | 5 + .../documentation/js/expressions.js | 5 + .../js/expressions_assignment.js | 2 + .../js/expressions_comprehension.js | 10 + .../documentation/js/expressions_try.js | 7 + .../documentation/js/fat_arrow.js | 11 + .../documentation/js/functions.js | 7 + .../documentation/js/heredocs.js | 2 + .../documentation/js/interpolation.js | 3 + .../js/interpolation_expression.js | 4 + .../js/multiple_return_values.js | 5 + .../documentation/js/object_comprehensions.js | 16 + .../documentation/js/object_extraction.js | 10 + .../documentation/js/objects_and_arrays.js | 17 + .../documentation/js/objects_reserved.js | 3 + .../documentation/js/overview.js | 34 + .../documentation/js/parallel_assignment.js | 4 + .../documentation/js/patterns_and_splats.js | 4 + .../documentation/js/prototypes.js | 3 + .../documentation/js/range_comprehensions.js | 19 + .../coffee-script/documentation/js/scope.js | 8 + .../coffee-script/documentation/js/slices.js | 4 + .../coffee-script/documentation/js/soaks.js | 2 + .../coffee-script/documentation/js/splats.js | 15 + .../coffee-script/documentation/js/splices.js | 3 + .../coffee-script/documentation/js/strings.js | 2 + .../coffee-script/documentation/js/switch.js | 23 + .../coffee-script/documentation/js/try.js | 8 + .../coffee-script/documentation/js/while.js | 17 + .../beautiful_code/binary_search.coffee | 16 + .../beautiful_code/quicksort_runtime.coffee | 13 + .../regular_expression_matcher.coffee | 34 + .../coffee-script/examples/blocks.coffee | 54 + .../coffee-script/examples/code.coffee | 171 + .../examples/computer_science/README | 4 + .../computer_science/binary_search.coffee | 25 + .../computer_science/bubble_sort.coffee | 11 + .../computer_science/linked_list.coffee | 108 + .../computer_science/luhn_algorithm.coffee | 36 + .../computer_science/merge_sort.coffee | 19 + .../computer_science/selection_sort.coffee | 23 + .../coffee-script/examples/poignant.coffee | 181 + .../coffee-script/examples/potion.coffee | 206 + .../coffee-script/examples/underscore.coffee | 684 ++ .../coffee-script/examples/web_server.coffee | 13 + .../jade/support/coffee-script/extras/EXTRAS | 7 + .../coffee-script/extras/coffee-script.js | 8 + .../support/coffee-script/extras/jsl.conf | 44 + .../jade/support/coffee-script/index.html | 2225 +++++ .../jade/support/coffee-script/lib/browser.js | 46 + .../jade/support/coffee-script/lib/cake.js | 73 + .../coffee-script/lib/coffee-script.js | 74 + .../jade/support/coffee-script/lib/command.js | 227 + .../jade/support/coffee-script/lib/grammar.js | 622 ++ .../jade/support/coffee-script/lib/helpers.js | 78 + .../jade/support/coffee-script/lib/index.js | 9 + .../jade/support/coffee-script/lib/lexer.js | 638 ++ .../jade/support/coffee-script/lib/nodes.js | 1981 ++++ .../support/coffee-script/lib/optparse.js | 107 + .../jade/support/coffee-script/lib/parser.js | 687 ++ .../jade/support/coffee-script/lib/repl.js | 38 + .../support/coffee-script/lib/rewriter.js | 378 + .../jade/support/coffee-script/lib/scope.js | 134 + .../support/coffee-script/lib/utilities.js | 12 + .../jade/support/coffee-script/package.json | 22 + .../support/coffee-script/src/browser.coffee | 41 + .../support/coffee-script/src/cake.coffee | 69 + .../coffee-script/src/coffee-script.coffee | 90 + .../support/coffee-script/src/command.coffee | 195 + .../support/coffee-script/src/grammar.coffee | 613 ++ .../support/coffee-script/src/helpers.coffee | 72 + .../support/coffee-script/src/index.coffee | 2 + .../support/coffee-script/src/lexer.coffee | 635 ++ .../support/coffee-script/src/nodes.coffee | 1710 ++++ .../support/coffee-script/src/optparse.coffee | 96 + .../support/coffee-script/src/repl.coffee | 35 + .../support/coffee-script/src/rewriter.coffee | 349 + .../support/coffee-script/src/scope.coffee | 109 + .../jade/support/coffee-script/test/test.html | 95 + .../coffee-script/test/test_arguments.coffee | 43 + .../coffee-script/test/test_assignment.coffee | 33 + .../coffee-script/test/test_break.coffee | 28 + .../coffee-script/test/test_chaining.coffee | 56 + .../coffee-script/test/test_classes.coffee | 291 + .../coffee-script/test/test_comments.coffee | 166 + .../test/test_compilation.coffee | 11 + .../test/test_compound_assignment.coffee | 26 + .../test/test_comprehensions.coffee | 172 + .../coffee-script/test/test_existence.coffee | 145 + .../test/test_expressions.coffee | 40 + .../coffee-script/test/test_functions.coffee | 346 + .../coffee-script/test/test_helpers.coffee | 49 + .../coffee-script/test/test_heredocs.coffee | 111 + .../support/coffee-script/test/test_if.coffee | 146 + .../coffee-script/test/test_importing.coffee | 3 + .../coffee-script/test/test_literals.coffee | 247 + .../coffee-script/test/test_module.coffee | 4 + .../coffee-script/test/test_operations.coffee | 154 + .../test/test_option_parser.coffee | 27 + .../test/test_pattern_matching.coffee | 160 + .../test_ranges_slices_and_splices.coffee | 75 + .../coffee-script/test/test_regexps.coffee | 45 + .../coffee-script/test/test_returns.coffee | 33 + .../coffee-script/test/test_splats.coffee | 125 + .../coffee-script/test/test_strings.coffee | 101 + .../coffee-script/test/test_switch.coffee | 98 + .../coffee-script/test/test_try_catch.coffee | 45 + .../coffee-script/test/test_while.coffee | 53 + node_modules/jade/support/compile.js | 173 + node_modules/jade/support/expresso/History.md | 97 + node_modules/jade/support/expresso/Makefile | 53 + node_modules/jade/support/expresso/Readme.md | 39 + .../jade/support/expresso/bin/expresso | 837 ++ .../jade/support/expresso/docs/api.html | 1048 +++ .../jade/support/expresso/docs/index.html | 373 + .../jade/support/expresso/docs/index.md | 290 + .../support/expresso/docs/layout/foot.html | 3 + .../support/expresso/docs/layout/head.html | 42 + node_modules/jade/support/expresso/lib/bar.js | 4 + node_modules/jade/support/expresso/lib/foo.js | 16 + .../jade/support/expresso/package.json | 12 + .../jade/support/expresso/test/assert.test.js | 84 + .../jade/support/expresso/test/async.test.js | 6 + .../jade/support/expresso/test/bar.test.js | 12 + .../jade/support/expresso/test/foo.test.js | 13 + .../jade/support/expresso/test/http.test.js | 82 + .../expresso/test/serial/async.test.js | 38 + .../support/expresso/test/serial/http.test.js | 47 + node_modules/jade/support/sass/History.md | 42 + node_modules/jade/support/sass/Makefile | 11 + node_modules/jade/support/sass/Readme.md | 167 + node_modules/jade/support/sass/index.js | 1 + node_modules/jade/support/sass/lib/sass.js | 299 + node_modules/jade/support/sass/package.json | 10 + node_modules/jade/support/sass/seed.yml | 4 + .../support/sass/spec/fixtures/collect.sass | 3 + .../support/sass/spec/fixtures/comment.css | 2 + .../support/sass/spec/fixtures/comment.sass | 6 + .../sass/spec/fixtures/continuation.css | 8 + .../sass/spec/fixtures/continuation.sass | 8 + .../support/sass/spec/fixtures/literal.css | 2 + .../support/sass/spec/fixtures/literal.sass | 4 + .../jade/support/sass/spec/fixtures/mixin.css | 8 + .../support/sass/spec/fixtures/mixin.sass | 11 + .../sass/spec/fixtures/mixin.undefined.sass | 2 + .../support/sass/spec/fixtures/properties.css | 3 + .../sass/spec/fixtures/properties.expand.css | 3 + .../sass/spec/fixtures/properties.expand.sass | 2 + .../spec/fixtures/properties.invalid.sass | 2 + .../sass/spec/fixtures/properties.nested.css | 13 + .../fixtures/properties.nested.invalid.sass | 5 + .../sass/spec/fixtures/properties.nested.sass | 13 + .../sass/spec/fixtures/properties.sass | 3 + .../support/sass/spec/fixtures/selectors.css | 6 + .../support/sass/spec/fixtures/selectors.sass | 10 + .../spec/fixtures/variables.alternate.css | 2 + .../spec/fixtures/variables.alternate.sass | 4 + .../support/sass/spec/fixtures/variables.css | 2 + .../sass/spec/fixtures/variables.regular.css | 2 + .../sass/spec/fixtures/variables.regular.sass | 3 + .../support/sass/spec/fixtures/variables.sass | 5 + .../jade/support/sass/spec/lib/images/bg.png | Bin 0 -> 154 bytes .../jade/support/sass/spec/lib/images/hr.png | Bin 0 -> 321 bytes .../support/sass/spec/lib/images/loading.gif | Bin 0 -> 2608 bytes .../sass/spec/lib/images/sprites.bg.png | Bin 0 -> 4876 bytes .../support/sass/spec/lib/images/sprites.png | Bin 0 -> 3629 bytes .../jade/support/sass/spec/lib/images/vr.png | Bin 0 -> 145 bytes .../jade/support/sass/spec/lib/jspec.css | 149 + .../jade/support/sass/spec/lib/jspec.growl.js | 115 + .../support/sass/spec/lib/jspec.jquery.js | 79 + .../jade/support/sass/spec/lib/jspec.js | 1893 ++++ .../support/sass/spec/lib/jspec.nodejs.js | 18 + .../jade/support/sass/spec/lib/jspec.shell.js | 39 + .../support/sass/spec/lib/jspec.timers.js | 90 + .../jade/support/sass/spec/lib/jspec.xhr.js | 210 + node_modules/jade/support/sass/spec/node.js | 9 + .../jade/support/sass/spec/spec.core.js | 134 + node_modules/jade/support/stylus/.npmignore | 5 + node_modules/jade/support/stylus/History.md | 231 + node_modules/jade/support/stylus/LICENSE | 22 + node_modules/jade/support/stylus/Makefile | 20 + node_modules/jade/support/stylus/Readme.md | 118 + node_modules/jade/support/stylus/bin/stylus | 456 + .../jade/support/stylus/bin/stylus-tutorial | 287 + node_modules/jade/support/stylus/bm.js | 22 + node_modules/jade/support/stylus/docs/bifs.md | 453 + .../jade/support/stylus/docs/comments.md | 17 + .../jade/support/stylus/docs/compare.md | 81 + .../jade/support/stylus/docs/conditionals.md | 107 + .../jade/support/stylus/docs/css-style.md | 77 + .../support/stylus/docs/error-reporting.md | 50 + .../jade/support/stylus/docs/escape.md | 27 + .../jade/support/stylus/docs/executable.md | 92 + .../jade/support/stylus/docs/font-face.md | 26 + .../jade/support/stylus/docs/functions.md | 192 + .../jade/support/stylus/docs/functions.url.md | 30 + .../jade/support/stylus/docs/import.md | 73 + .../jade/support/stylus/docs/interpolation.md | 43 + .../jade/support/stylus/docs/introspection.md | 39 + .../jade/support/stylus/docs/iteration.md | 100 + node_modules/jade/support/stylus/docs/js.md | 108 + .../jade/support/stylus/docs/keyframes.md | 52 + .../jade/support/stylus/docs/literal.md | 16 + .../jade/support/stylus/docs/media.md | 18 + .../jade/support/stylus/docs/middleware.md | 55 + .../jade/support/stylus/docs/mixins.md | 132 + .../jade/support/stylus/docs/operators.md | 418 + .../jade/support/stylus/docs/selectors.md | 132 + .../jade/support/stylus/docs/textmate.md | 7 + .../jade/support/stylus/docs/vargs.md | 84 + .../jade/support/stylus/docs/variables.md | 29 + .../Syntaxes/Stylus.tmLanguage | 166 + .../stylus/editors/Stylus.tmbundle/info.plist | 10 + .../support/stylus/examples/arithmetic.js | 12 + .../support/stylus/examples/arithmetic.styl | 29 + .../jade/support/stylus/examples/basic.js | 12 + .../jade/support/stylus/examples/basic.styl | 8 + .../jade/support/stylus/examples/builtins.js | 12 + .../support/stylus/examples/builtins.styl | 56 + .../jade/support/stylus/examples/comments.js | 11 + .../support/stylus/examples/comments.styl | 15 + .../jade/support/stylus/examples/compress.js | 12 + .../support/stylus/examples/conversions.js | 12 + .../support/stylus/examples/conversions.styl | 34 + .../jade/support/stylus/examples/functions.js | 12 + .../support/stylus/examples/functions.styl | 30 + .../jade/support/stylus/examples/images.js | 20 + .../jade/support/stylus/examples/images.styl | 12 + .../support/stylus/examples/images/gopher.jpg | Bin 0 -> 50615 bytes .../support/stylus/examples/images/jesus.gif | Bin 0 -> 40716 bytes .../support/stylus/examples/images/sprite.gif | Bin 0 -> 935 bytes .../stylus/examples/implicit-functions.js | 12 + .../stylus/examples/implicit-functions.styl | 23 + .../jade/support/stylus/examples/import.js | 12 + .../jade/support/stylus/examples/import.styl | 11 + .../support/stylus/examples/js-functions.js | 55 + .../support/stylus/examples/js-functions.styl | 23 + .../jade/support/stylus/examples/literal.js | 12 + .../jade/support/stylus/examples/literal.styl | 8 + .../support/stylus/examples/middleware.js | 22 + .../support/stylus/examples/mixins/box.styl | 14 + .../jade/support/stylus/examples/nesting.js | 12 + .../jade/support/stylus/examples/nesting.styl | 14 + .../jade/support/stylus/examples/variables.js | 12 + .../support/stylus/examples/variables.styl | 24 + node_modules/jade/support/stylus/index.js | 2 + .../jade/support/stylus/lib/colors.js | 156 + .../jade/support/stylus/lib/convert/css.js | 130 + .../support/stylus/lib/functions/image.js | 120 + .../support/stylus/lib/functions/index.js | 554 ++ .../support/stylus/lib/functions/index.styl | 131 + .../jade/support/stylus/lib/functions/url.js | 97 + node_modules/jade/support/stylus/lib/lexer.js | 672 ++ .../jade/support/stylus/lib/middleware.js | 198 + .../jade/support/stylus/lib/nodes/binop.js | 52 + .../jade/support/stylus/lib/nodes/block.js | 98 + .../jade/support/stylus/lib/nodes/boolean.js | 83 + .../jade/support/stylus/lib/nodes/call.js | 56 + .../jade/support/stylus/lib/nodes/charset.js | 42 + .../jade/support/stylus/lib/nodes/each.js | 55 + .../support/stylus/lib/nodes/expression.js | 143 + .../jade/support/stylus/lib/nodes/function.js | 92 + .../jade/support/stylus/lib/nodes/group.js | 78 + .../jade/support/stylus/lib/nodes/hsla.js | 230 + .../jade/support/stylus/lib/nodes/ident.js | 97 + .../jade/support/stylus/lib/nodes/if.js | 54 + .../jade/support/stylus/lib/nodes/import.js | 30 + .../jade/support/stylus/lib/nodes/index.js | 48 + .../support/stylus/lib/nodes/keyframes.js | 57 + .../jade/support/stylus/lib/nodes/literal.js | 70 + .../jade/support/stylus/lib/nodes/media.js | 42 + .../jade/support/stylus/lib/nodes/node.js | 175 + .../jade/support/stylus/lib/nodes/null.js | 61 + .../jade/support/stylus/lib/nodes/page.js | 43 + .../jade/support/stylus/lib/nodes/params.js | 71 + .../jade/support/stylus/lib/nodes/property.js | 47 + .../jade/support/stylus/lib/nodes/return.js | 43 + .../jade/support/stylus/lib/nodes/rgba.js | 243 + .../jade/support/stylus/lib/nodes/root.js | 50 + .../jade/support/stylus/lib/nodes/selector.js | 55 + .../jade/support/stylus/lib/nodes/string.js | 101 + .../jade/support/stylus/lib/nodes/ternary.js | 50 + .../jade/support/stylus/lib/nodes/unaryop.js | 45 + .../jade/support/stylus/lib/nodes/unit.js | 188 + .../jade/support/stylus/lib/parser.js | 1360 +++ .../jade/support/stylus/lib/renderer.js | 103 + .../jade/support/stylus/lib/stack/frame.js | 66 + .../jade/support/stylus/lib/stack/index.js | 146 + .../jade/support/stylus/lib/stack/scope.js | 53 + .../jade/support/stylus/lib/stylus.js | 132 + node_modules/jade/support/stylus/lib/token.js | 53 + node_modules/jade/support/stylus/lib/utils.js | 175 + .../support/stylus/lib/visitor/compiler.js | 370 + .../support/stylus/lib/visitor/evaluator.js | 911 ++ .../jade/support/stylus/lib/visitor/index.js | 32 + node_modules/jade/support/stylus/package.json | 16 + .../stylus/test/cases/arithmetic.color.css | 7 + .../stylus/test/cases/arithmetic.color.styl | 7 + .../support/stylus/test/cases/arithmetic.css | 12 + .../support/stylus/test/cases/arithmetic.styl | 18 + .../stylus/test/cases/arithmetic.unary.css | 16 + .../stylus/test/cases/arithmetic.unary.styl | 16 + .../stylus/test/cases/bifs.components.css | 9 + .../stylus/test/cases/bifs.components.styl | 9 + .../support/stylus/test/cases/bifs.dark.css | 5 + .../support/stylus/test/cases/bifs.dark.styl | 4 + .../stylus/test/cases/bifs.darken-by.css | 5 + .../stylus/test/cases/bifs.darken-by.styl | 4 + .../stylus/test/cases/bifs.image-size.css | 9 + .../stylus/test/cases/bifs.image-size.styl | 19 + .../support/stylus/test/cases/bifs.join.css | 11 + .../support/stylus/test/cases/bifs.join.styl | 11 + .../support/stylus/test/cases/bifs.last.css | 5 + .../support/stylus/test/cases/bifs.last.styl | 6 + .../support/stylus/test/cases/bifs.length.css | 10 + .../stylus/test/cases/bifs.length.styl | 18 + .../support/stylus/test/cases/bifs.light.css | 5 + .../support/stylus/test/cases/bifs.light.styl | 4 + .../stylus/test/cases/bifs.lighten-by.css | 6 + .../stylus/test/cases/bifs.lighten-by.styl | 6 + .../stylus/test/cases/bifs.lookup.complex.css | 4 + .../test/cases/bifs.lookup.complex.styl | 11 + .../support/stylus/test/cases/bifs.lookup.css | 3 + .../stylus/test/cases/bifs.lookup.styl | 8 + .../support/stylus/test/cases/bifs.match.css | 4 + .../support/stylus/test/cases/bifs.match.styl | 9 + .../test/cases/bifs.opposite-position.css | 8 + .../test/cases/bifs.opposite-position.styl | 9 + .../support/stylus/test/cases/bifs.rgba.css | 5 + .../support/stylus/test/cases/bifs.rgba.styl | 4 + .../support/stylus/test/cases/bifs.type.css | 11 + .../support/stylus/test/cases/bifs.type.styl | 12 + .../support/stylus/test/cases/bifs.unit.css | 6 + .../support/stylus/test/cases/bifs.unit.styl | 5 + .../stylus/test/cases/bifs.unquote.css | 5 + .../stylus/test/cases/bifs.unquote.styl | 8 + .../support/stylus/test/cases/bifs.url.css | 11 + .../support/stylus/test/cases/bifs.url.styl | 15 + .../support/stylus/test/cases/coercion.css | 6 + .../support/stylus/test/cases/coercion.styl | 5 + .../support/stylus/test/cases/comments.css | 11 + .../support/stylus/test/cases/comments.styl | 28 + .../stylus/test/cases/compress.units.css | 2 + .../stylus/test/cases/compress.units.styl | 18 + .../test/cases/conditional-assignment.css | 4 + .../test/cases/conditional-assignment.styl | 9 + .../test/cases/css.functions.single-line.css | 9 + .../test/cases/css.functions.single-line.styl | 13 + .../jade/support/stylus/test/cases/css.if.css | 8 + .../support/stylus/test/cases/css.if.styl | 21 + .../stylus/test/cases/css.keyframes.css | 48 + .../stylus/test/cases/css.keyframes.styl | 39 + .../support/stylus/test/cases/css.large.css | 172 + .../support/stylus/test/cases/css.large.styl | 172 + .../support/stylus/test/cases/css.media.css | 15 + .../support/stylus/test/cases/css.media.styl | 17 + .../stylus/test/cases/css.mixins.braces.css | 31 + .../stylus/test/cases/css.mixins.braces.styl | 53 + .../support/stylus/test/cases/css.mixins.css | 31 + .../stylus/test/cases/css.mixins.root.css | 26 + .../stylus/test/cases/css.mixins.root.styl | 25 + .../test/cases/css.mixins.root.wonky.css | 26 + .../test/cases/css.mixins.root.wonky.styl | 17 + .../support/stylus/test/cases/css.mixins.styl | 47 + .../stylus/test/cases/css.selectors.css | 37 + .../stylus/test/cases/css.selectors.styl | 53 + .../stylus/test/cases/css.whitespace.css | 37 + .../stylus/test/cases/css.whitespace.styl | 36 + .../jade/support/stylus/test/cases/escape.css | 4 + .../support/stylus/test/cases/escape.styl | 4 + .../support/stylus/test/cases/for.complex.css | 44 + .../stylus/test/cases/for.complex.styl | 28 + .../jade/support/stylus/test/cases/for.css | 52 + .../stylus/test/cases/for.function.css | 20 + .../stylus/test/cases/for.function.styl | 51 + .../jade/support/stylus/test/cases/for.styl | 44 + .../stylus/test/cases/function.arguments.css | 4 + .../stylus/test/cases/function.arguments.styl | 14 + .../stylus/test/cases/function.literals.css | 6 + .../stylus/test/cases/function.literals.styl | 12 + .../stylus/test/cases/functions.arg-calls.css | 3 + .../test/cases/functions.arg-calls.styl | 9 + .../stylus/test/cases/functions.call.css | 4 + .../stylus/test/cases/functions.call.styl | 7 + .../support/stylus/test/cases/functions.css | 11 + .../stylus/test/cases/functions.defaults.css | 15 + .../stylus/test/cases/functions.defaults.styl | 30 + .../test/cases/functions.multi-line.css | 9 + .../test/cases/functions.multi-line.styl | 25 + .../test/cases/functions.multiple-calls.css | 13 + .../test/cases/functions.multiple-calls.styl | 26 + .../test/cases/functions.nested-calls.css | 3 + .../test/cases/functions.nested-calls.styl | 9 + .../stylus/test/cases/functions.nested.css | 10 + .../stylus/test/cases/functions.nested.styl | 37 + .../stylus/test/cases/functions.property.css | 10 + .../stylus/test/cases/functions.property.styl | 11 + .../stylus/test/cases/functions.return.css | 15 + .../test/cases/functions.return.each.css | 10 + .../test/cases/functions.return.each.styl | 23 + .../stylus/test/cases/functions.return.styl | 86 + .../support/stylus/test/cases/functions.styl | 34 + .../stylus/test/cases/functions.variable.css | 9 + .../test/cases/functions.variable.ident.css | 3 + .../test/cases/functions.variable.ident.styl | 11 + .../stylus/test/cases/functions.variable.styl | 27 + .../jade/support/stylus/test/cases/if.css | 43 + .../support/stylus/test/cases/if.else.css | 6 + .../support/stylus/test/cases/if.else.styl | 16 + .../support/stylus/test/cases/if.mixin.css | 7 + .../support/stylus/test/cases/if.mixin.styl | 24 + .../support/stylus/test/cases/if.postfix.css | 61 + .../support/stylus/test/cases/if.postfix.styl | 110 + .../stylus/test/cases/if.selectors.css | 6 + .../stylus/test/cases/if.selectors.styl | 12 + .../jade/support/stylus/test/cases/if.styl | 99 + .../stylus/test/cases/import.basic.css | 9 + .../stylus/test/cases/import.basic.styl | 2 + .../stylus/test/cases/import.basic/a.styl | 5 + .../stylus/test/cases/import.basic/b.styl | 5 + .../stylus/test/cases/import.basic/c.styl | 3 + .../stylus/test/cases/import.complex.css | 9 + .../stylus/test/cases/import.complex.styl | 1 + .../stylus/test/cases/import.complex/a.styl | 4 + .../stylus/test/cases/import.complex/c.styl | 2 + .../test/cases/import.complex/nested/b.styl | 4 + .../stylus/test/cases/import.index.css | 9 + .../stylus/test/cases/import.index.styl | 2 + .../test/cases/import.index/vendor/a.styl | 2 + .../test/cases/import.index/vendor/b.styl | 2 + .../test/cases/import.index/vendor/c.styl | 2 + .../test/cases/import.index/vendor/index.styl | 4 + .../stylus/test/cases/import.literal.css | 2 + .../stylus/test/cases/import.literal.styl | 3 + .../stylus/test/cases/import.mixins.css | 7 + .../stylus/test/cases/import.mixins.styl | 9 + .../stylus/test/cases/import.ordering.css | 15 + .../stylus/test/cases/import.ordering.styl | 12 + .../test/cases/import.ordering/five.styl | 2 + .../test/cases/import.ordering/four.styl | 4 + .../test/cases/import.ordering/two.styl | 2 + .../support/stylus/test/cases/important.css | 6 + .../support/stylus/test/cases/important.styl | 6 + .../test/cases/interpolation.properties.css | 40 + .../test/cases/interpolation.properties.styl | 56 + .../stylus/test/cases/introspection.css | 7 + .../stylus/test/cases/introspection.styl | 14 + .../jade/support/stylus/test/cases/jquery.css | 3 + .../support/stylus/test/cases/jquery.styl | 5 + .../jade/support/stylus/test/cases/list.css | 3 + .../jade/support/stylus/test/cases/list.styl | 3 + .../support/stylus/test/cases/literal.css | 5 + .../support/stylus/test/cases/literal.styl | 7 + .../jade/support/stylus/test/cases/media.css | 14 + .../jade/support/stylus/test/cases/media.styl | 11 + .../stylus/test/cases/mixin.conditional.css | 19 + .../stylus/test/cases/mixin.conditional.styl | 36 + .../test/cases/mixin.order.conditional.css | 11 + .../test/cases/mixin.order.conditional.styl | 20 + .../support/stylus/test/cases/mixin.order.css | 9 + .../stylus/test/cases/mixin.order.nested.css | 9 + .../stylus/test/cases/mixin.order.nested.styl | 21 + .../stylus/test/cases/mixin.order.styl | 20 + .../stylus/test/cases/mixins.complex.css | 30 + .../test/cases/mixins.complex.fix-to.css | 15 + .../test/cases/mixins.complex.fix-to.styl | 28 + .../stylus/test/cases/mixins.complex.styl | 41 + .../stylus/test/cases/mixins.conditional.css | 3 + .../stylus/test/cases/mixins.conditional.styl | 8 + .../stylus/test/cases/mixins.nested.css | 7 + .../test/cases/mixins.nested.selectors.css | 21 + .../test/cases/mixins.nested.selectors.styl | 31 + .../stylus/test/cases/mixins.nested.styl | 14 + .../stylus/test/cases/mixins.order.2.css | 11 + .../stylus/test/cases/mixins.order.2.styl | 16 + .../stylus/test/cases/mixins.return.css | 4 + .../stylus/test/cases/mixins.return.styl | 8 + .../support/stylus/test/cases/mixins.root.css | 3 + .../stylus/test/cases/mixins.root.styl | 5 + .../support/stylus/test/cases/mixins/box.styl | 11 + .../stylus/test/cases/operator.range.css | 15 + .../stylus/test/cases/operator.range.styl | 23 + .../cases/operators.assignment.function.css | 15 + .../cases/operators.assignment.function.styl | 34 + .../test/cases/operators.assignment.mixin.css | 15 + .../cases/operators.assignment.mixin.styl | 39 + .../test/cases/operators.assignment.root.css | 19 + .../test/cases/operators.assignment.root.styl | 43 + .../stylus/test/cases/operators.complex.css | 9 + .../stylus/test/cases/operators.complex.styl | 32 + .../support/stylus/test/cases/operators.css | 32 + .../stylus/test/cases/operators.equality.css | 12 + .../stylus/test/cases/operators.equality.styl | 31 + .../stylus/test/cases/operators.in.css | 36 + .../stylus/test/cases/operators.in.styl | 50 + .../stylus/test/cases/operators.mixins.css | 10 + .../stylus/test/cases/operators.mixins.styl | 25 + .../test/cases/operators.precedence.css | 51 + .../test/cases/operators.precedence.styl | 82 + .../support/stylus/test/cases/operators.styl | 86 + .../stylus/test/cases/operators.subscript.css | 59 + .../test/cases/operators.subscript.range.css | 14 + .../test/cases/operators.subscript.range.styl | 15 + .../test/cases/operators.subscript.styl | 81 + .../jade/support/stylus/test/cases/page.css | 13 + .../jade/support/stylus/test/cases/page.styl | 13 + .../jade/support/stylus/test/cases/parent.css | 32 + .../support/stylus/test/cases/parent.styl | 33 + .../stylus/test/cases/properties.colons.css | 8 + .../stylus/test/cases/properties.colons.styl | 10 + .../support/stylus/test/cases/properties.css | 4 + .../stylus/test/cases/properties.one-line.css | 10 + .../test/cases/properties.one-line.styl | 11 + .../support/stylus/test/cases/properties.styl | 4 + .../cases/regression.107.lookup-failure.css | 12 + .../cases/regression.107.lookup-failure.styl | 13 + .../stylus/test/cases/regression.127.css | 3 + .../stylus/test/cases/regression.127.styl | 2 + .../stylus/test/cases/regression.130.css | 16 + .../stylus/test/cases/regression.130.styl | 6 + .../stylus/test/cases/regression.131.css | 6 + .../stylus/test/cases/regression.131.styl | 2 + .../stylus/test/cases/regression.137.css | 7 + .../stylus/test/cases/regression.137.styl | 7 + .../stylus/test/cases/regression.139.css | 5 + .../stylus/test/cases/regression.139.styl | 21 + .../stylus/test/cases/regression.142.css | 39 + .../stylus/test/cases/regression.142.styl | 54 + .../stylus/test/cases/regression.146.css | 30 + .../stylus/test/cases/regression.146.styl | 31 + .../stylus/test/cases/regression.153.css | 8 + .../stylus/test/cases/regression.153.styl | 9 + .../stylus/test/cases/regression.154.css | 8 + .../stylus/test/cases/regression.154.styl | 14 + .../stylus/test/cases/regression.156.css | 4 + .../stylus/test/cases/regression.156.styl | 6 + .../stylus/test/cases/rule.charset.css | 1 + .../stylus/test/cases/rule.charset.styl | 2 + .../jade/support/stylus/test/cases/rulset.css | 4 + .../stylus/test/cases/rulset.newline.css | 5 + .../stylus/test/cases/rulset.newline.styl | 5 + .../support/stylus/test/cases/rulset.styl | 3 + .../stylus/test/cases/scope.complex.css | 10 + .../stylus/test/cases/scope.complex.styl | 16 + .../jade/support/stylus/test/cases/scope.css | 5 + .../stylus/test/cases/scope.nested.css | 9 + .../stylus/test/cases/scope.nested.styl | 10 + .../jade/support/stylus/test/cases/scope.styl | 12 + .../stylus/test/cases/selectors.complex.css | 28 + .../stylus/test/cases/selectors.complex.styl | 27 + .../support/stylus/test/cases/selectors.css | 44 + .../test/cases/selectors.nested.comma.css | 9 + .../test/cases/selectors.nested.comma.styl | 8 + .../stylus/test/cases/selectors.nested.css | 34 + .../stylus/test/cases/selectors.nested.styl | 33 + .../stylus/test/cases/selectors.pseudo.css | 27 + .../stylus/test/cases/selectors.pseudo.styl | 24 + .../support/stylus/test/cases/selectors.styl | 41 + .../stylus/test/cases/self-assignment.css | 3 + .../stylus/test/cases/self-assignment.styl | 4 + .../support/stylus/test/cases/vargs.call.css | 24 + .../support/stylus/test/cases/vargs.call.styl | 40 + .../jade/support/stylus/test/cases/vargs.css | 30 + .../jade/support/stylus/test/cases/vargs.styl | 49 + .../support/stylus/test/cases/variable.css | 3 + .../support/stylus/test/cases/variable.styl | 4 + .../support/stylus/test/cases/variables.css | 12 + .../support/stylus/test/cases/variables.styl | 17 + .../jade/support/stylus/test/images/gif | Bin 0 -> 59920 bytes .../support/stylus/test/images/squirrel.jpeg | Bin 0 -> 21805 bytes .../jade/support/stylus/test/images/tux.png | Bin 0 -> 41236 bytes node_modules/jade/support/stylus/test/run.js | 81 + node_modules/jade/test/filters.test.js | 153 + node_modules/jade/test/fixtures/invalid.jade | 3 + node_modules/jade/test/fixtures/layout.jade | 3 + node_modules/jade/test/jade.test.js | 879 ++ node_modules/mongodb/.npmignore | 3 + node_modules/mongodb/HISTORY | 74 + node_modules/mongodb/Makefile | 50 + node_modules/mongodb/Readme.md | 386 + node_modules/mongodb/TODO. | 5 + node_modules/mongodb/deps/nodeunit/.npmignore | 3 + .../mongodb/deps/nodeunit/CONTRIBUTORS.md | 60 + node_modules/mongodb/deps/nodeunit/LICENSE | 19 + node_modules/mongodb/deps/nodeunit/Makefile | 126 + node_modules/mongodb/deps/nodeunit/README.md | 433 + .../mongodb/deps/nodeunit/bin/nodeunit | 108 + .../mongodb/deps/nodeunit/bin/nodeunit.json | 10 + .../mongodb/deps/nodeunit/deps/async.js | 623 ++ .../mongodb/deps/nodeunit/deps/ejs.js | 125 + .../mongodb/deps/nodeunit/deps/json2.js | 483 + .../mongodb/deps/nodeunit/doc/nodeunit.md | 60 + .../nodeunit/examples/browser/nodeunit.js | 1757 ++++ .../deps/nodeunit/examples/browser/suite1.js | 12 + .../deps/nodeunit/examples/browser/suite2.js | 13 + .../deps/nodeunit/examples/browser/test.html | 16 + .../deps/nodeunit/img/example_fail.png | Bin 0 -> 38642 bytes .../deps/nodeunit/img/example_pass.png | Bin 0 -> 14133 bytes node_modules/mongodb/deps/nodeunit/index.js | 3 + .../mongodb/deps/nodeunit/lib/assert.js | 316 + .../mongodb/deps/nodeunit/lib/core.js | 236 + .../mongodb/deps/nodeunit/lib/nodeunit.js | 80 + .../deps/nodeunit/lib/reporters/browser.js | 119 + .../deps/nodeunit/lib/reporters/default.js | 137 + .../deps/nodeunit/lib/reporters/html.js | 112 + .../deps/nodeunit/lib/reporters/index.js | 9 + .../deps/nodeunit/lib/reporters/junit.js | 194 + .../deps/nodeunit/lib/reporters/minimal.js | 117 + .../nodeunit/lib/reporters/skip_passed.js | 110 + .../mongodb/deps/nodeunit/lib/track.js | 50 + .../mongodb/deps/nodeunit/lib/types.js | 187 + .../mongodb/deps/nodeunit/lib/utils.js | 209 + .../mongodb/deps/nodeunit/man1/nodeunit.1 | 95 + .../mongodb/deps/nodeunit/nodelint.cfg | 4 + .../mongodb/deps/nodeunit/package.json | 53 + .../mongodb/deps/nodeunit/share/junit.xml.ejs | 19 + .../mongodb/deps/nodeunit/share/license.js | 11 + .../mongodb/deps/nodeunit/share/nodeunit.css | 70 + .../fixtures/coffee/mock_coffee_module.coffee | 4 + .../test/fixtures/dir/mock_module3.js | 1 + .../test/fixtures/dir/mock_module4.js | 1 + .../nodeunit/test/fixtures/mock_module1.js | 1 + .../nodeunit/test/fixtures/mock_module2.js | 1 + .../nodeunit/test/fixtures/raw_jscode1.js | 3 + .../nodeunit/test/fixtures/raw_jscode2.js | 3 + .../nodeunit/test/fixtures/raw_jscode3.js | 1 + .../mongodb/deps/nodeunit/test/test-base.js | 219 + .../nodeunit/test/test-failing-callbacks.js | 114 + .../deps/nodeunit/test/test-httputil.js | 55 + .../deps/nodeunit/test/test-runfiles.js | 214 + .../deps/nodeunit/test/test-runmodule.js | 125 + .../deps/nodeunit/test/test-runtest.js | 46 + .../deps/nodeunit/test/test-sandbox.js | 31 + .../deps/nodeunit/test/test-testcase.js | 234 + .../mongodb/deps/nodeunit/test/test.html | 26 + .../mongodb/deps/step/README.markdown | 71 + node_modules/mongodb/deps/step/lib/step.js | 154 + node_modules/mongodb/deps/step/package.json | 11 + .../mongodb/deps/step/test/callbackTest.js | 26 + .../mongodb/deps/step/test/errorTest.js | 27 + node_modules/mongodb/deps/step/test/fnTest.js | 21 + .../mongodb/deps/step/test/groupTest.js | 102 + node_modules/mongodb/deps/step/test/helper.js | 17 + .../mongodb/deps/step/test/parallelTest.js | 49 + node_modules/mongodb/docs/README.md | 14 + node_modules/mongodb/docs/collections.md | 112 + node_modules/mongodb/docs/database.md | 101 + node_modules/mongodb/docs/gridfs.md | 111 + node_modules/mongodb/docs/indexes.md | 75 + node_modules/mongodb/docs/insert.md | 125 + node_modules/mongodb/docs/queries.md | 278 + node_modules/mongodb/docs/replicaset.md | 40 + node_modules/mongodb/examples/admin.js | 62 + node_modules/mongodb/examples/blog.js | 109 + node_modules/mongodb/examples/capped.js | 34 + node_modules/mongodb/examples/cursor.js | 76 + node_modules/mongodb/examples/gridfs.js | 156 + node_modules/mongodb/examples/index_test.js | 66 + node_modules/mongodb/examples/info.js | 55 + node_modules/mongodb/examples/oplog.js | 119 + node_modules/mongodb/examples/queries.js | 132 + .../mongodb/examples/replSetServersQueries.js | 144 + .../mongodb/examples/replSetServersSimple.js | 75 + node_modules/mongodb/examples/simple.js | 50 + node_modules/mongodb/examples/strict.js | 43 + node_modules/mongodb/examples/types.js | 50 + node_modules/mongodb/examples/url.js | 17 + .../mongodb/external-libs/bson/Makefile | 19 + .../mongodb/external-libs/bson/binary.cc | 327 + .../mongodb/external-libs/bson/binary.h | 57 + .../mongodb/external-libs/bson/bson.cc | 1697 ++++ .../mongodb/external-libs/bson/bson.h | 61 + .../mongodb/external-libs/bson/code.cc | 185 + .../mongodb/external-libs/bson/code.h | 44 + .../mongodb/external-libs/bson/dbref.cc | 196 + .../mongodb/external-libs/bson/dbref.h | 49 + .../mongodb/external-libs/bson/index.js | 16 + .../mongodb/external-libs/bson/local.cc | 14 + .../mongodb/external-libs/bson/local.h | 14 + .../mongodb/external-libs/bson/long.cc | 596 ++ .../mongodb/external-libs/bson/long.h | 76 + .../mongodb/external-libs/bson/objectid.cc | 295 + .../mongodb/external-libs/bson/objectid.h | 54 + .../mongodb/external-libs/bson/test_bson.js | 328 + .../external-libs/bson/test_full_bson.js | 209 + .../mongodb/external-libs/bson/timestamp.cc | 592 ++ .../mongodb/external-libs/bson/timestamp.h | 79 + .../mongodb/external-libs/bson/wscript | 38 + node_modules/mongodb/index.js | 1 + node_modules/mongodb/install.sh | 20 + node_modules/mongodb/lib/mongodb/admin.js | 146 + .../mongodb/lib/mongodb/bson/binary.js | 123 + .../mongodb/lib/mongodb/bson/binary_parser.js | 392 + .../mongodb/lib/mongodb/bson/binary_utils.js | 29 + node_modules/mongodb/lib/mongodb/bson/bson.js | 1714 ++++ .../mongodb/lib/mongodb/bson/float_parser.js | 118 + .../mongodb/lib/mongodb/bson/objectid.js | 175 + .../mongodb/lib/mongodb/bson/timestamp.js | 791 ++ .../mongodb/lib/mongodb/collection.js | 1027 ++ .../lib/mongodb/commands/base_command.js | 26 + .../lib/mongodb/commands/db_command.js | 188 + .../lib/mongodb/commands/delete_command.js | 91 + .../lib/mongodb/commands/get_more_command.js | 96 + .../lib/mongodb/commands/insert_command.js | 99 + .../mongodb/commands/kill_cursor_command.js | 100 + .../lib/mongodb/commands/query_command.js | 151 + .../lib/mongodb/commands/update_command.js | 123 + .../mongodb/lib/mongodb/connection.js | 319 + .../mongodb/connections/repl_set_servers.js | 356 + .../mongodb/lib/mongodb/connections/server.js | 136 + node_modules/mongodb/lib/mongodb/cursor.js | 679 ++ node_modules/mongodb/lib/mongodb/db.js | 796 ++ .../mongodb/lib/mongodb/goog/math/long.js | 791 ++ .../mongodb/lib/mongodb/gridfs/chunk.js | 202 + .../mongodb/lib/mongodb/gridfs/grid.js | 96 + .../mongodb/lib/mongodb/gridfs/gridstore.js | 1240 +++ node_modules/mongodb/lib/mongodb/index.js | 102 + .../lib/mongodb/responses/mongo_reply.js | 58 + node_modules/mongodb/package.json | 67 + node_modules/mongodb/test/admin_test.js | 323 + .../mongodb/test/authentication_test.js | 144 + .../test/auxilliary/authentication_test.js | 195 + .../test/auxilliary/replicaset_auth_test.js | 147 + node_modules/mongodb/test/bson/bson_test.js | 631 ++ .../mongodb/test/bson/commands_test.js | 121 + node_modules/mongodb/test/collection_test.js | 634 ++ node_modules/mongodb/test/connect_test.js | 92 + node_modules/mongodb/test/connection_test.js | 84 + node_modules/mongodb/test/cursor_test.js | 954 ++ node_modules/mongodb/test/custom_pk_test.js | 79 + node_modules/mongodb/test/db_test.js | 305 + node_modules/mongodb/test/error_test.js | 267 + .../mongodb/test/exception_handling_test.js | 80 + node_modules/mongodb/test/find_test.js | 762 ++ .../test/gridstore/grid_store_file_test.js | 710 ++ .../test/gridstore/grid_store_stream_test.js | 82 + .../mongodb/test/gridstore/grid_store_test.js | 660 ++ .../mongodb/test/gridstore/grid_test.js | 102 + .../test/gridstore/iya_logo_final_bw.jpg | Bin 0 -> 74008 bytes .../test/gridstore/test_gs_weird_bug.png | Bin 0 -> 52184 bytes .../gridstore/test_gs_working_field_read.pdf | Bin 0 -> 130253 bytes node_modules/mongodb/test/index_test.js | 252 + node_modules/mongodb/test/insert_test.js | 646 ++ node_modules/mongodb/test/map_reduce_test.js | 299 + node_modules/mongodb/test/objectid_test.js | 134 + node_modules/mongodb/test/regexp_test.js | 105 + node_modules/mongodb/test/remove_test.js | 74 + .../mongodb/test/replicaset/connect_test.js | 323 + .../mongodb/test/replicaset/count_test.js | 174 + .../mongodb/test/replicaset/insert_test.js | 335 + .../test/replicaset/query_secondaries_test.js | 248 + node_modules/mongodb/test/streaming_test.js | 121 + node_modules/mongodb/test/tools/keyfile.txt | 1 + .../mongodb/test/tools/replica_set_manager.js | 522 ++ .../mongodb/test/tools/server_manager.js | 126 + node_modules/mongodb/test/unicode_test.js | 160 + node_modules/mongodb/tools/test_all.js | 122 + node_modules/mongoose/History.md | 410 + node_modules/mongoose/Makefile | 28 + node_modules/mongoose/README.md | 382 + node_modules/mongoose/docs/defaults.md | 29 + .../mongoose/docs/embedded-documents.md | 79 + .../mongoose/docs/finding-documents.md | 63 + node_modules/mongoose/docs/getters-setters.md | 52 + node_modules/mongoose/docs/indexes.md | 31 + node_modules/mongoose/docs/methods-statics.md | 44 + node_modules/mongoose/docs/middleware.md | 64 + .../mongoose/docs/model-definition.md | 136 + node_modules/mongoose/docs/validation.md | 90 + node_modules/mongoose/docs/virtuals.md | 79 + node_modules/mongoose/examples/schema.js | 74 + node_modules/mongoose/index.js | 7 + .../mongoose/lib/mongoose/collection.js | 167 + node_modules/mongoose/lib/mongoose/compat.js | 19 + .../mongoose/lib/mongoose/connection.js | 409 + .../mongoose/lib/mongoose/document.js | 775 ++ .../drivers/node-mongodb-native/collection.js | 104 + .../drivers/node-mongodb-native/connection.js | 84 + .../drivers/node-mongodb-native/objectid.js | 43 + node_modules/mongoose/lib/mongoose/error.js | 25 + node_modules/mongoose/lib/mongoose/index.js | 382 + node_modules/mongoose/lib/mongoose/model.js | 724 ++ .../mongoose/lib/mongoose/namedscope.js | 66 + node_modules/mongoose/lib/mongoose/promise.js | 145 + node_modules/mongoose/lib/mongoose/query.js | 945 ++ node_modules/mongoose/lib/mongoose/schema.js | 520 + .../mongoose/lib/mongoose/schema/array.js | 197 + .../mongoose/lib/mongoose/schema/boolean.js | 58 + .../mongoose/lib/mongoose/schema/date.js | 115 + .../lib/mongoose/schema/documentarray.js | 120 + .../mongoose/lib/mongoose/schema/index.js | 20 + .../mongoose/lib/mongoose/schema/mixed.js | 63 + .../mongoose/lib/mongoose/schema/number.js | 134 + .../mongoose/lib/mongoose/schema/objectid.js | 110 + .../mongoose/lib/mongoose/schema/string.js | 172 + .../mongoose/lib/mongoose/schemadefault.js | 18 + .../mongoose/lib/mongoose/schematype.js | 331 + .../mongoose/lib/mongoose/types/array.js | 340 + .../mongoose/lib/mongoose/types/document.js | 113 + .../lib/mongoose/types/documentarray.js | 106 + .../mongoose/lib/mongoose/types/index.js | 10 + .../mongoose/lib/mongoose/types/number.js | 82 + .../mongoose/lib/mongoose/types/objectid.js | 12 + node_modules/mongoose/lib/mongoose/utils.js | 479 + .../mongoose/lib/mongoose/virtualtype.js | 73 + node_modules/mongoose/package.json | 23 + .../mongoose/support/cli-table/History.md | 5 + .../mongoose/support/cli-table/Makefile | 14 + .../mongoose/support/cli-table/README.md | 77 + .../support/cli-table/examples/revs.js | 25 + .../mongoose/support/cli-table/index.js | 2 + .../support/cli-table/lib/cli-table/index.js | 205 + .../support/cli-table/lib/cli-table/utils.js | 81 + .../mongoose/support/cli-table/package.json | 11 + .../mongoose/support/cli-table/test/common.js | 6 + .../support/cli-table/test/index.test.js | 52 + .../mongoose/support/expresso/History.md | 128 + .../mongoose/support/expresso/Makefile | 53 + .../mongoose/support/expresso/Readme.md | 61 + .../mongoose/support/expresso/bin/expresso | 874 ++ .../mongoose/support/expresso/docs/api.html | 1080 +++ .../mongoose/support/expresso/docs/index.html | 377 + .../mongoose/support/expresso/docs/index.md | 290 + .../support/expresso/docs/layout/foot.html | 3 + .../support/expresso/docs/layout/head.html | 42 + .../mongoose/support/expresso/lib/bar.js | 4 + .../mongoose/support/expresso/lib/foo.js | 16 + .../mongoose/support/expresso/package.json | 12 + .../support/expresso/test/assert.test.js | 91 + .../support/expresso/test/async.test.js | 12 + .../support/expresso/test/bar.test.js | 13 + .../support/expresso/test/foo.test.js | 14 + .../support/expresso/test/http.test.js | 109 + .../expresso/test/serial/async.test.js | 39 + .../support/expresso/test/serial/http.test.js | 48 + .../mongoose/support/should.js/History.md | 22 + .../mongoose/support/should.js/Makefile | 6 + .../mongoose/support/should.js/Readme.md | 248 + .../support/should.js/examples/runner.js | 53 + .../mongoose/support/should.js/index.js | 2 + .../mongoose/support/should.js/lib/eql.js | 91 + .../mongoose/support/should.js/lib/should.js | 548 ++ .../mongoose/support/should.js/package.json | 8 + .../support/should.js/test/should.test.js | 358 + node_modules/mongoose/test/collection.test.js | 118 + node_modules/mongoose/test/common.js | 134 + node_modules/mongoose/test/connection.test.js | 46 + node_modules/mongoose/test/crash.test.js | 36 + node_modules/mongoose/test/document.test.js | 472 + .../node-mongodb-native/collection.test.js | 64 + node_modules/mongoose/test/index.test.js | 235 + .../mongoose/test/model.querying.test.js | 1415 +++ node_modules/mongoose/test/model.test.js | 3824 ++++++++ node_modules/mongoose/test/namedscope.test.js | 251 + node_modules/mongoose/test/promise.test.js | 167 + node_modules/mongoose/test/query.test.js | 751 ++ .../mongoose/test/schema.onthefly.test.js | 105 + node_modules/mongoose/test/schema.test.js | 842 ++ .../mongoose/test/types.array.test.js | 111 + .../mongoose/test/types.document.test.js | 83 + .../mongoose/test/types.documentarray.test.js | 31 + .../mongoose/test/types.number.test.js | 32 + node_modules/mongoose/test/utils.test.js | 154 + node_modules/mysql/License | 19 + node_modules/mysql/Makefile | 12 + node_modules/mysql/Readme.md | 269 + node_modules/mysql/benchmark/.insert.js.un~ | Bin 0 -> 25784 bytes node_modules/mysql/benchmark/.select.js.un~ | Bin 0 -> 102257 bytes .../node-mysql/.insert-select.js.un~ | Bin 0 -> 37447 bytes .../mysql/benchmark/node-mysql/.insert.js.un~ | Bin 0 -> 5117 bytes .../mysql/benchmark/node-mysql/.select.js.un~ | Bin 0 -> 35532 bytes .../mysql/benchmark/node-mysql/insert.js | 42 + .../mysql/benchmark/node-mysql/select.js | 40 + .../benchmark/php/.insert-select.php.un~ | Bin 0 -> 11569 bytes .../mysql/benchmark/php/insert-select.php | 40 + node_modules/mysql/index.js | 1 + node_modules/mysql/lib/.auth.js.un~ | Bin 0 -> 1046 bytes node_modules/mysql/lib/.client.js.un~ | Bin 0 -> 360005 bytes node_modules/mysql/lib/.constants.js.un~ | Bin 0 -> 167305 bytes node_modules/mysql/lib/.mysql.js.un~ | Bin 0 -> 15348 bytes .../mysql/lib/.outgoing_packet.js.un~ | Bin 0 -> 998 bytes node_modules/mysql/lib/.parser.js.un~ | Bin 0 -> 5173 bytes node_modules/mysql/lib/.query.js.un~ | Bin 0 -> 3790 bytes node_modules/mysql/lib/auth.js | 164 + node_modules/mysql/lib/client.js | 454 + node_modules/mysql/lib/constants.js | 673 ++ node_modules/mysql/lib/mysql.js | 11 + node_modules/mysql/lib/outgoing_packet.js | 79 + node_modules/mysql/lib/parser.js | 650 ++ node_modules/mysql/lib/query.js | 140 + .../node_modules/hashish/README.markdown | 191 + .../node_modules/hashish/examples/chain.js | 9 + .../node_modules/hashish/examples/map.js | 7 + .../mysql/node_modules/hashish/index.js | 253 + .../hashish/node_modules/traverse/.npmignore | 1 + .../hashish/node_modules/traverse/LICENSE | 24 + .../node_modules/traverse/README.markdown | 237 + .../node_modules/traverse/examples/json.js | 16 + .../node_modules/traverse/examples/leaves.js | 15 + .../traverse/examples/negative.js | 8 + .../node_modules/traverse/examples/scrub.js | 10 + .../traverse/examples/stringify.js | 38 + .../hashish/node_modules/traverse/index.js | 265 + .../node_modules/traverse/package.json | 18 + .../node_modules/traverse/test/circular.js | 115 + .../node_modules/traverse/test/date.js | 35 + .../node_modules/traverse/test/equal.js | 220 + .../node_modules/traverse/test/instance.js | 17 + .../node_modules/traverse/test/interface.js | 42 + .../node_modules/traverse/test/json.js | 47 + .../node_modules/traverse/test/keys.js | 29 + .../node_modules/traverse/test/leaves.js | 21 + .../traverse/test/lib/deep_equal.js | 92 + .../node_modules/traverse/test/mutability.js | 204 + .../node_modules/traverse/test/negative.js | 20 + .../hashish/node_modules/traverse/test/obj.js | 15 + .../node_modules/traverse/test/siblings.js | 35 + .../node_modules/traverse/test/stop.js | 41 + .../node_modules/traverse/test/stringify.js | 36 + .../node_modules/traverse/test/subexpr.js | 34 + .../node_modules/traverse/test/super_deep.js | 55 + .../mysql/node_modules/hashish/package.json | 33 + .../mysql/node_modules/hashish/test/hash.js | 250 + .../node_modules/hashish/test/property.js | 69 + node_modules/mysql/package.json | 26 + node_modules/mysql/test/.common.js.un~ | Bin 0 -> 22818 bytes .../mysql/test/.config.template.js.un~ | Bin 0 -> 4982 bytes node_modules/mysql/test/common.js | 25 + node_modules/mysql/test/config.js | 8 + node_modules/mysql/test/config.template.js | 8 + .../test/fast/.test-client-connect.js.un~ | Bin 0 -> 40697 bytes .../mysql/test/fast/.test-client.js.un~ | Bin 0 -> 13604 bytes node_modules/mysql/test/fast/test-client.js | 26 + .../mysql/test/fixture/.column_order.sql.un~ | Bin 0 -> 4070 bytes node_modules/mysql/test/fixture/columnia.sql | 54 + .../mysql/test/fixture/libmysql_password.c | 127 + node_modules/mysql/test/legacy/.common.js.un~ | Bin 0 -> 7278 bytes node_modules/mysql/test/legacy/common.js | 35 + .../test/legacy/simple/.test-auth-old.js.un~ | Bin 0 -> 18751 bytes .../test/legacy/simple/.test-auth.js.un~ | Bin 0 -> 47160 bytes .../test/legacy/simple/.test-client.js.un~ | Bin 0 -> 53021 bytes .../simple/.test-outgoing-packet.js.un~ | Bin 0 -> 1569 bytes .../test/legacy/simple/.test-parser.js.un~ | Bin 0 -> 49360 bytes .../test/legacy/simple/.test-query.js.un~ | Bin 0 -> 10746 bytes .../mysql/test/legacy/simple/test-auth.js | 118 + .../mysql/test/legacy/simple/test-client.js | 95 + .../legacy/simple/test-outgoing-packet.js | 134 + .../mysql/test/legacy/simple/test-parser.js | 387 + .../mysql/test/legacy/simple/test-query.js | 68 + node_modules/mysql/test/run.js | 7 + .../test/slow/.test-client-commands.js.un~ | Bin 0 -> 54167 bytes .../test/slow/.test-client-connect.js.un~ | Bin 0 -> 4199 bytes .../slow/.test-client-max-connections.js.un~ | Bin 0 -> 32474 bytes .../.test-client-query-column-ordering.js.un~ | Bin 0 -> 22081 bytes .../.test-client-query-error-handling.js.un~ | Bin 0 -> 91265 bytes .../mysql/test/slow/.test-client-query.js.un~ | Bin 0 -> 82754 bytes .../mysql/test/slow/test-client-commands.js | 35 + .../mysql/test/slow/test-client-connect.js | 94 + .../test/slow/test-client-max-connections.js | 69 + .../slow/test-client-query-column-ordering.js | 50 + .../slow/test-client-query-error-handling.js | 67 + .../mysql/test/slow/test-client-query.js | 129 + node_modules/mysql/tool/.pcap-mysql.js.un~ | Bin 0 -> 67872 bytes node_modules/mysql/tool/pcap-mysql.js | 48 + node_modules/socket.io/.npmignore | 3 + node_modules/socket.io/History.md | 95 + node_modules/socket.io/Makefile | 22 + node_modules/socket.io/Readme.md | 343 + node_modules/socket.io/examples/chat/app.js | 87 + .../socket.io/examples/chat/index.jade | 83 + .../socket.io/examples/chat/package.json | 11 + .../chat/public/stylesheets/mixins.styl | 96 + .../chat/public/stylesheets/style.css | 188 + .../chat/public/stylesheets/style.styl | 118 + .../socket.io/examples/irc-output/app.js | 81 + .../socket.io/examples/irc-output/index.jade | 28 + .../socket.io/examples/irc-output/irc.js | 164 + .../examples/irc-output/package.json | 10 + .../irc-output/public/stylesheets/style.styl | 69 + node_modules/socket.io/index.js | 8 + node_modules/socket.io/lib/logger.js | 96 + node_modules/socket.io/lib/manager.js | 1021 ++ node_modules/socket.io/lib/namespace.js | 349 + node_modules/socket.io/lib/parser.js | 243 + node_modules/socket.io/lib/socket.io.js | 128 + node_modules/socket.io/lib/socket.js | 345 + node_modules/socket.io/lib/store.js | 98 + node_modules/socket.io/lib/stores/memory.js | 143 + node_modules/socket.io/lib/stores/redis.js | 250 + node_modules/socket.io/lib/transport.js | 534 ++ .../socket.io/lib/transports/flashsocket.js | 102 + .../socket.io/lib/transports/htmlfile.js | 82 + .../socket.io/lib/transports/http-polling.js | 135 + node_modules/socket.io/lib/transports/http.js | 111 + .../socket.io/lib/transports/index.js | 12 + .../socket.io/lib/transports/jsonp-polling.js | 78 + .../socket.io/lib/transports/websocket.js | 350 + .../socket.io/lib/transports/xhr-polling.js | 72 + node_modules/socket.io/lib/util.js | 25 + .../socket.io/node_modules/policyfile/LICENSE | 19 + .../node_modules/policyfile/Makefile | 7 + .../node_modules/policyfile/README.md | 98 + .../node_modules/policyfile/doc/index.html | 375 + .../policyfile/examples/basic.fallback.js | 8 + .../node_modules/policyfile/examples/basic.js | 5 + .../node_modules/policyfile/index.js | 1 + .../node_modules/policyfile/lib/server.js | 289 + .../node_modules/policyfile/package.json | 32 + .../node_modules/policyfile/tests/ssl/ssl.crt | 21 + .../policyfile/tests/ssl/ssl.private.key | 27 + .../policyfile/tests/unit.test.js | 231 + .../socket.io/node_modules/redis/README.md | 567 ++ .../socket.io/node_modules/redis/changelog.md | 174 + .../node_modules/redis/examples/auth.js | 5 + .../node_modules/redis/examples/extend.js | 24 + .../node_modules/redis/examples/file.js | 32 + .../node_modules/redis/examples/mget.js | 5 + .../node_modules/redis/examples/monitor.js | 10 + .../node_modules/redis/examples/multi.js | 46 + .../node_modules/redis/examples/multi2.js | 29 + .../node_modules/redis/examples/psubscribe.js | 33 + .../node_modules/redis/examples/pub_sub.js | 41 + .../node_modules/redis/examples/simple.js | 17 + .../node_modules/redis/examples/subqueries.js | 15 + .../node_modules/redis/examples/subquery.js | 19 + .../redis/examples/unix_socket.js | 29 + .../node_modules/redis/examples/web_server.js | 31 + .../socket.io/node_modules/redis/index.js | 850 ++ .../node_modules/redis/lib/parser/hiredis.js | 41 + .../redis/lib/parser/javascript.js | 316 + .../socket.io/node_modules/redis/lib/queue.js | 58 + .../node_modules/redis/lib/to_array.js | 12 + .../socket.io/node_modules/redis/lib/util.js | 6 + .../node_modules/redis/multi_bench.js | 135 + .../socket.io/node_modules/redis/package.json | 26 + .../socket.io/node_modules/redis/test.js | 1234 +++ .../node_modules/redis/tests/buffer_bench.js | 89 + .../redis/tests/reconnect_test.js | 27 + .../node_modules/redis/tests/sub_quit_test.js | 18 + .../redis/tests/test_start_stop.js | 17 + .../node_modules/socket.io-client/.npmignore | 2 + .../node_modules/socket.io-client/History.md | 60 + .../node_modules/socket.io-client/Makefile | 20 + .../node_modules/socket.io-client/README.md | 246 + .../socket.io-client/bin/builder.js | 285 + .../socket.io-client/dist/WebSocketMain.swf | Bin 0 -> 175830 bytes .../dist/WebSocketMainInsecure.swf | Bin 0 -> 175953 bytes .../socket.io-client/dist/socket.io.js | 3692 ++++++++ .../socket.io-client/dist/socket.io.min.js | 2 + .../socket.io-client/lib/events.js | 184 + .../node_modules/socket.io-client/lib/io.js | 205 + .../node_modules/socket.io-client/lib/json.js | 322 + .../socket.io-client/lib/namespace.js | 242 + .../socket.io-client/lib/parser.js | 262 + .../socket.io-client/lib/socket.io-client.js | 1 + .../socket.io-client/lib/socket.js | 519 + .../socket.io-client/lib/transport.js | 234 + .../lib/transports/flashsocket.js | 186 + .../lib/transports/htmlfile.js | 172 + .../lib/transports/jsonp-polling.js | 217 + .../lib/transports/websocket.js | 185 + .../lib/transports/xhr-polling.js | 155 + .../socket.io-client/lib/transports/xhr.js | 213 + .../node_modules/socket.io-client/lib/util.js | 366 + .../lib/vendor/web-socket-js/README.md | 157 + .../vendor/web-socket-js/WebSocketMain.swf | Bin 0 -> 175830 bytes .../web-socket-js/WebSocketMainInsecure.zip | Bin 0 -> 166610 bytes .../flash-src/IWebSocketLogger.as | 8 + .../web-socket-js/flash-src/WebSocket.as | 464 + .../web-socket-js/flash-src/WebSocketEvent.as | 33 + .../web-socket-js/flash-src/WebSocketMain.as | 150 + .../flash-src/WebSocketMainInsecure.as | 19 + .../vendor/web-socket-js/flash-src/build.sh | 10 + .../com/adobe/net/proxies/RFC2817Socket.as | 204 + .../flash-src/com/gsolo/encryption/MD5.as | 375 + .../flash-src/com/hurlant/crypto/Crypto.as | 287 + .../crypto/cert/MozillaRootCertificates.as | 3235 +++++++ .../hurlant/crypto/cert/X509Certificate.as | 218 + .../crypto/cert/X509CertificateCollection.as | 57 + .../flash-src/com/hurlant/crypto/hash/HMAC.as | 82 + .../com/hurlant/crypto/hash/IHMAC.as | 27 + .../com/hurlant/crypto/hash/IHash.as | 21 + .../flash-src/com/hurlant/crypto/hash/MAC.as | 137 + .../flash-src/com/hurlant/crypto/hash/MD2.as | 124 + .../flash-src/com/hurlant/crypto/hash/MD5.as | 204 + .../flash-src/com/hurlant/crypto/hash/SHA1.as | 106 + .../com/hurlant/crypto/hash/SHA224.as | 28 + .../com/hurlant/crypto/hash/SHA256.as | 115 + .../com/hurlant/crypto/hash/SHABase.as | 71 + .../flash-src/com/hurlant/crypto/prng/ARC4.as | 90 + .../com/hurlant/crypto/prng/IPRNG.as | 20 + .../com/hurlant/crypto/prng/Random.as | 119 + .../com/hurlant/crypto/prng/TLSPRF.as | 142 + .../com/hurlant/crypto/rsa/RSAKey.as | 339 + .../com/hurlant/crypto/symmetric/AESKey.as | 2797 ++++++ .../hurlant/crypto/symmetric/BlowFishKey.as | 375 + .../com/hurlant/crypto/symmetric/CBCMode.as | 55 + .../com/hurlant/crypto/symmetric/CFB8Mode.as | 61 + .../com/hurlant/crypto/symmetric/CFBMode.as | 64 + .../com/hurlant/crypto/symmetric/CTRMode.as | 58 + .../com/hurlant/crypto/symmetric/DESKey.as | 365 + .../com/hurlant/crypto/symmetric/ECBMode.as | 86 + .../com/hurlant/crypto/symmetric/ICipher.as | 21 + .../com/hurlant/crypto/symmetric/IMode.as | 15 + .../com/hurlant/crypto/symmetric/IPad.as | 32 + .../hurlant/crypto/symmetric/IStreamCipher.as | 21 + .../hurlant/crypto/symmetric/ISymmetricKey.as | 35 + .../com/hurlant/crypto/symmetric/IVMode.as | 110 + .../com/hurlant/crypto/symmetric/NullPad.as | 34 + .../com/hurlant/crypto/symmetric/OFBMode.as | 52 + .../com/hurlant/crypto/symmetric/PKCS5.as | 44 + .../com/hurlant/crypto/symmetric/SSLPad.as | 44 + .../hurlant/crypto/symmetric/SimpleIVMode.as | 60 + .../com/hurlant/crypto/symmetric/TLSPad.as | 42 + .../hurlant/crypto/symmetric/TripleDESKey.as | 88 + .../com/hurlant/crypto/symmetric/XTeaKey.as | 94 + .../com/hurlant/crypto/symmetric/aeskey.pl | 29 + .../com/hurlant/crypto/symmetric/dump.txt | 2304 +++++ .../com/hurlant/crypto/tests/AESKeyTest.as | 1220 +++ .../com/hurlant/crypto/tests/ARC4Test.as | 58 + .../hurlant/crypto/tests/BigIntegerTest.as | 39 + .../hurlant/crypto/tests/BlowFishKeyTest.as | 148 + .../com/hurlant/crypto/tests/CBCModeTest.as | 160 + .../com/hurlant/crypto/tests/CFB8ModeTest.as | 71 + .../com/hurlant/crypto/tests/CFBModeTest.as | 98 + .../com/hurlant/crypto/tests/CTRModeTest.as | 109 + .../com/hurlant/crypto/tests/DESKeyTest.as | 112 + .../com/hurlant/crypto/tests/ECBModeTest.as | 151 + .../com/hurlant/crypto/tests/HMACTest.as | 184 + .../com/hurlant/crypto/tests/ITestHarness.as | 20 + .../com/hurlant/crypto/tests/MD2Test.as | 56 + .../com/hurlant/crypto/tests/MD5Test.as | 58 + .../com/hurlant/crypto/tests/OFBModeTest.as | 101 + .../com/hurlant/crypto/tests/RSAKeyTest.as | 92 + .../com/hurlant/crypto/tests/SHA1Test.as | 198 + .../com/hurlant/crypto/tests/SHA224Test.as | 58 + .../com/hurlant/crypto/tests/SHA256Test.as | 60 + .../com/hurlant/crypto/tests/TLSPRFTest.as | 51 + .../com/hurlant/crypto/tests/TestCase.as | 42 + .../hurlant/crypto/tests/TripleDESKeyTest.as | 59 + .../com/hurlant/crypto/tests/XTeaKeyTest.as | 66 + .../com/hurlant/crypto/tls/BulkCiphers.as | 102 + .../com/hurlant/crypto/tls/CipherSuites.as | 117 + .../hurlant/crypto/tls/IConnectionState.as | 14 + .../hurlant/crypto/tls/ISecurityParameters.as | 29 + .../com/hurlant/crypto/tls/KeyExchanges.as | 24 + .../flash-src/com/hurlant/crypto/tls/MACs.as | 38 + .../hurlant/crypto/tls/SSLConnectionState.as | 171 + .../com/hurlant/crypto/tls/SSLEvent.as | 26 + .../crypto/tls/SSLSecurityParameters.as | 340 + .../com/hurlant/crypto/tls/TLSConfig.as | 70 + .../hurlant/crypto/tls/TLSConnectionState.as | 151 + .../com/hurlant/crypto/tls/TLSEngine.as | 895 ++ .../com/hurlant/crypto/tls/TLSError.as | 39 + .../com/hurlant/crypto/tls/TLSEvent.as | 27 + .../crypto/tls/TLSSecurityParameters.as | 197 + .../com/hurlant/crypto/tls/TLSSocket.as | 370 + .../com/hurlant/crypto/tls/TLSSocketEvent.as | 26 + .../com/hurlant/crypto/tls/TLSTest.as | 180 + .../com/hurlant/math/BarrettReduction.as | 90 + .../flash-src/com/hurlant/math/BigInteger.as | 1543 +++ .../com/hurlant/math/ClassicReduction.as | 35 + .../flash-src/com/hurlant/math/IReduction.as | 11 + .../com/hurlant/math/MontgomeryReduction.as | 85 + .../com/hurlant/math/NullReduction.as | 34 + .../flash-src/com/hurlant/math/bi_internal.as | 11 + .../flash-src/com/hurlant/util/ArrayUtil.as | 25 + .../flash-src/com/hurlant/util/Base64.as | 189 + .../flash-src/com/hurlant/util/Hex.as | 66 + .../flash-src/com/hurlant/util/Memory.as | 28 + .../com/hurlant/util/der/ByteString.as | 43 + .../flash-src/com/hurlant/util/der/DER.as | 210 + .../com/hurlant/util/der/IAsn1Type.as | 21 + .../flash-src/com/hurlant/util/der/Integer.as | 44 + .../flash-src/com/hurlant/util/der/OID.as | 35 + .../com/hurlant/util/der/ObjectIdentifier.as | 112 + .../flash-src/com/hurlant/util/der/PEM.as | 118 + .../com/hurlant/util/der/PrintableString.as | 49 + .../com/hurlant/util/der/Sequence.as | 90 + .../flash-src/com/hurlant/util/der/Set.as | 27 + .../flash-src/com/hurlant/util/der/Type.as | 94 + .../flash-src/com/hurlant/util/der/UTCTime.as | 60 + .../lib/vendor/web-socket-js/sample.html | 75 + .../lib/vendor/web-socket-js/swfobject.js | 4 + .../lib/vendor/web-socket-js/web_socket.js | 349 + .../node_modules/.bin/uglifyjs | 1 + .../node_modules/uglify-js/README.html | 835 ++ .../node_modules/uglify-js/README.org | 437 + .../node_modules/uglify-js/bin/uglifyjs | 309 + .../node_modules/uglify-js/docstyle.css | 75 + .../node_modules/uglify-js/lib/parse-js.js | 1340 +++ .../node_modules/uglify-js/lib/process.js | 1774 ++++ .../uglify-js/lib/squeeze-more.js | 22 + .../node_modules/uglify-js/package.json | 22 + .../node_modules/uglify-js/test/beautify.js | 28 + .../node_modules/uglify-js/test/testparser.js | 402 + .../test/unit/compress/expected/array1.js | 1 + .../test/unit/compress/expected/array2.js | 1 + .../test/unit/compress/expected/array3.js | 1 + .../test/unit/compress/expected/array4.js | 1 + .../test/unit/compress/expected/assignment.js | 1 + .../unit/compress/expected/concatstring.js | 1 + .../test/unit/compress/expected/const.js | 1 + .../unit/compress/expected/empty-blocks.js | 1 + .../unit/compress/expected/forstatement.js | 1 + .../test/unit/compress/expected/if.js | 1 + .../test/unit/compress/expected/ifreturn.js | 1 + .../test/unit/compress/expected/issue10.js | 1 + .../test/unit/compress/expected/issue11.js | 1 + .../test/unit/compress/expected/issue13.js | 1 + .../test/unit/compress/expected/issue14.js | 1 + .../test/unit/compress/expected/issue16.js | 1 + .../test/unit/compress/expected/issue17.js | 1 + .../test/unit/compress/expected/issue20.js | 1 + .../test/unit/compress/expected/issue21.js | 1 + .../test/unit/compress/expected/issue25.js | 1 + .../test/unit/compress/expected/issue27.js | 1 + .../test/unit/compress/expected/issue28.js | 1 + .../test/unit/compress/expected/issue29.js | 1 + .../test/unit/compress/expected/issue30.js | 1 + .../test/unit/compress/expected/issue34.js | 1 + .../test/unit/compress/expected/issue4.js | 1 + .../test/unit/compress/expected/issue48.js | 1 + .../test/unit/compress/expected/issue50.js | 1 + .../test/unit/compress/expected/issue53.js | 1 + .../test/unit/compress/expected/issue54.1.js | 1 + .../test/unit/compress/expected/issue68.js | 1 + .../test/unit/compress/expected/issue69.js | 1 + .../test/unit/compress/expected/issue9.js | 1 + .../unit/compress/expected/strict-equals.js | 1 + .../test/unit/compress/expected/var.js | 1 + .../test/unit/compress/test/array1.js | 3 + .../test/unit/compress/test/array2.js | 4 + .../test/unit/compress/test/array3.js | 4 + .../test/unit/compress/test/array4.js | 6 + .../test/unit/compress/test/assignment.js | 20 + .../test/unit/compress/test/concatstring.js | 3 + .../test/unit/compress/test/const.js | 5 + .../test/unit/compress/test/empty-blocks.js | 4 + .../test/unit/compress/test/forstatement.js | 10 + .../uglify-js/test/unit/compress/test/if.js | 6 + .../test/unit/compress/test/ifreturn.js | 9 + .../test/unit/compress/test/issue10.js | 1 + .../test/unit/compress/test/issue11.js | 3 + .../test/unit/compress/test/issue13.js | 1 + .../test/unit/compress/test/issue14.js | 1 + .../test/unit/compress/test/issue16.js | 1 + .../test/unit/compress/test/issue17.js | 4 + .../test/unit/compress/test/issue20.js | 1 + .../test/unit/compress/test/issue21.js | 6 + .../test/unit/compress/test/issue25.js | 7 + .../test/unit/compress/test/issue27.js | 1 + .../test/unit/compress/test/issue28.js | 3 + .../test/unit/compress/test/issue29.js | 1 + .../test/unit/compress/test/issue30.js | 3 + .../test/unit/compress/test/issue34.js | 3 + .../test/unit/compress/test/issue4.js | 3 + .../test/unit/compress/test/issue48.js | 1 + .../test/unit/compress/test/issue50.js | 9 + .../test/unit/compress/test/issue53.js | 1 + .../test/unit/compress/test/issue54.1.js | 3 + .../test/unit/compress/test/issue68.js | 5 + .../test/unit/compress/test/issue69.js | 1 + .../test/unit/compress/test/issue9.js | 4 + .../test/unit/compress/test/strict-equals.js | 3 + .../uglify-js/test/unit/compress/test/var.js | 3 + .../uglify-js/test/unit/scripts.js | 55 + .../node_modules/uglify-js/tmp/instrument.js | 97 + .../node_modules/uglify-js/tmp/instrument2.js | 138 + .../node_modules/uglify-js/uglify-js.js | 17 + .../socket.io-client/package.json | 33 + .../socket.io-client/test/events.test.js | 121 + .../socket.io-client/test/io.test.js | 31 + .../test/node/builder.common.js | 102 + .../test/node/builder.test.js | 131 + .../socket.io-client/test/parser.test.js | 352 + .../socket.io-client/test/socket.test.js | 335 + .../socket.io-client/test/util.test.js | 156 + node_modules/socket.io/package.json | 29 + .../support/node-websocket-client/LICENSE | 27 + .../support/node-websocket-client/Makefile | 22 + .../support/node-websocket-client/README.md | 41 + .../examples/client-unix.js | 12 + .../node-websocket-client/examples/client.js | 10 + .../examples/server-unix.js | 13 + .../node-websocket-client/lib/websocket.js | 599 ++ .../node-websocket-client/package.json | 22 + .../node-websocket-client/test/test-basic.js | 68 + .../test/test-client-close.js | 43 + .../test/test-readonly-attrs.js | 43 + .../test/test-ready-state.js | 26 + .../test/test-server-close.js | 41 + .../test/test-unix-send-fd.js | 63 + .../test/test-unix-sockets.js | 46 + node_modules/socket.io/test/common.js | 244 + node_modules/socket.io/test/fixtures/cert.crt | 21 + node_modules/socket.io/test/fixtures/key.key | 27 + node_modules/socket.io/test/io.test.js | 125 + .../socket.io/test/leaks/socket.leaktest.js | 54 + node_modules/socket.io/test/manager.test.js | 646 ++ node_modules/socket.io/test/namespace.test.js | 247 + node_modules/socket.io/test/parser.test.js | 348 + node_modules/socket.io/test/socket.js | 15 + .../socket.io/test/stores.memory.test.js | 190 + .../socket.io/test/stores.redis.test.js | 240 + .../test/transports.flashsocket.test.js | 168 + .../test/transports.htmlfile.test.js | 458 + .../test/transports.jsonp-polling.test.js | 770 ++ .../test/transports.websocket.test.js | 1771 ++++ .../test/transports.xhr-polling.test.js | 2716 ++++++ package.json | 9 + public/archive/images/Guevedoces4.jpg | Bin 0 -> 9053 bytes public/archive/images/Guevedoces5.jpg | Bin 0 -> 20161 bytes public/archive/images/Hullhouse-addams.jpg | Bin 0 -> 43584 bytes public/archive/images/OraQuick_Test.gif | Bin 0 -> 47587 bytes public/archive/images/davidtennis.jpg | Bin 0 -> 969610 bytes public/archive/images/engraving_example.jpg | Bin 0 -> 47053 bytes public/archive/images/faculty_img19_sml.jpg | Bin 0 -> 24295 bytes public/archive/images/martin-luther-king2.jpg | Bin 0 -> 33301 bytes public/archive/images/no-image.gif | Bin 0 -> 2689 bytes public/archive/images/phaistos_disk2_lg.gif | Bin 0 -> 187271 bytes public/health_check.html | 1 + public/images/88x31.png | Bin 0 -> 5145 bytes public/images/arrow_up.png | Bin 0 -> 372 bytes public/images/bg.png | Bin 0 -> 992 bytes public/images/bg_main-heading.gif | Bin 0 -> 102 bytes public/images/blown-to-bits.png | Bin 0 -> 9744 bytes public/images/boston.com.png | Bin 0 -> 12362 bytes public/images/dropdown_arrow.png | Bin 0 -> 209 bytes public/images/fclogo.png | Bin 0 -> 10653 bytes public/images/finals-club-blk.png | Bin 0 -> 3836 bytes public/images/finals-club-wht.png | Bin 0 -> 3792 bytes public/images/harvard-crimson.jpg | Bin 0 -> 9874 bytes public/images/home.jpg | Bin 0 -> 63573 bytes public/images/keep-it-academic.png | Bin 0 -> 28151 bytes public/images/logo_finalsclub_footer.gif | Bin 0 -> 599 bytes public/images/logo_veritas_footer.gif | Bin 0 -> 4018 bytes public/images/the-chronicle.png | Bin 0 -> 14158 bytes public/javascripts/backchannel.js | 369 + public/javascripts/counts.js | 26 + public/javascripts/dropdown.js | 16 + public/javascripts/es5-shim.min.js | 14 + public/javascripts/fc.js | 70 + public/javascripts/jquery.tmpl.min.js | 1 + public/javascripts/templates/comment.js | 6 + public/javascripts/templates/post.js | 26 + public/stylesheets/backchannel.css | 259 + public/stylesheets/dropdown.css | 142 + public/stylesheets/fc.css | 526 ++ public/stylesheets/fc2.css | 880 ++ public/stylesheets/style.css | 89 + public/terms.pdf | Bin 0 -> 61262 bytes restart | 6 + schools.json | 12 + start | 16 + stop | 10 + util/boot.sh | 91 + util/haproxy.cfg | 27 + util/nightly-restart.sh | 23 + util/start.sh | 74 + views/activate.jade | 28 + views/archive/courses.jade | 11 + views/archive/index.jade | 14 + views/archive/learn.jade | 10 + views/archive/note.jade | 11 + views/archive/notes.jade | 15 + views/archive/notesLayout.jade | 26 + views/course/form.jade | 38 + views/course/index.jade | 29 + views/course/new.jade | 1 + views/footer.jade | 24 + views/index.jade | 13 + views/layout.jade | 27 + views/lecture/form.jade | 19 + views/lecture/index.jade | 39 + views/lecture/new.jade | 1 + views/login.jade | 39 + views/masthead.jade | 31 + views/notes/dropdown.jade | 15 + views/notes/form.jade | 20 + views/notes/index.jade | 97 + views/notes/layout.jade | 23 + views/notes/masthead.jade | 1 + views/notes/new.jade | 1 + views/notes/noteLayout.jade | 28 + views/notes/public.jade | 83 + views/profile/index.jade | 91 + views/register.jade | 56 + views/resetpw-error.jade | 6 + views/resetpw-success.jade | 8 + views/resetpw.jade | 48 + views/schools.jade | 32 + views/static/about.jade | 10 + views/static/conduct.jade | 14 + views/static/contact.jade | 22 + views/static/legal.jade | 336 + views/static/press.jade | 40 + views/static/privacy.jade | 8 + 3266 files changed, 489913 insertions(+) create mode 100644 README create mode 100644 app.js create mode 100644 bruml/README.markdown create mode 100644 bruml/archive/backchan-chatpage-orig.html create mode 100644 bruml/archive/backchan.chatpage.html create mode 100644 bruml/archive/bcfunctions.demo.html create mode 100755 bruml/images/accept.png create mode 100755 bruml/images/arrow_dn.png create mode 100755 bruml/images/arrow_up.png create mode 100755 bruml/images/delete.png create mode 100644 bruml/lib/paperboy/.package.json.un~ create mode 100644 bruml/lib/paperboy/LICENSE.txt create mode 100644 bruml/lib/paperboy/README.md create mode 100644 bruml/lib/paperboy/example/basic.js create mode 100644 bruml/lib/paperboy/example/webroot/img/paperboy.jpg create mode 100644 bruml/lib/paperboy/example/webroot/index.html create mode 100644 bruml/lib/paperboy/index.js create mode 100644 bruml/lib/paperboy/lib/paperboy.js create mode 100644 bruml/lib/paperboy/package.json create mode 100644 bruml/lib/paperboy/seed.yml create mode 100644 bruml/lib/socket.io/History.md create mode 100644 bruml/lib/socket.io/Makefile create mode 100644 bruml/lib/socket.io/README.md create mode 100644 bruml/lib/socket.io/example/benchmark.html create mode 100644 bruml/lib/socket.io/example/cert.crt create mode 100644 bruml/lib/socket.io/example/chat-ssl.html create mode 100644 bruml/lib/socket.io/example/chat.html create mode 100644 bruml/lib/socket.io/example/json.js create mode 100644 bruml/lib/socket.io/example/key.key create mode 100644 bruml/lib/socket.io/example/server-ssl.js create mode 100644 bruml/lib/socket.io/example/server.benchmark.js create mode 100644 bruml/lib/socket.io/example/server.js create mode 100644 bruml/lib/socket.io/index.js create mode 100644 bruml/lib/socket.io/lib/socket.io/client.js create mode 100644 bruml/lib/socket.io/lib/socket.io/index.js create mode 100644 bruml/lib/socket.io/lib/socket.io/listener.js create mode 100644 bruml/lib/socket.io/lib/socket.io/transports/flashsocket.js create mode 100644 bruml/lib/socket.io/lib/socket.io/transports/htmlfile.js create mode 100644 bruml/lib/socket.io/lib/socket.io/transports/jsonp-polling.js create mode 100644 bruml/lib/socket.io/lib/socket.io/transports/websocket.js create mode 100644 bruml/lib/socket.io/lib/socket.io/transports/xhr-multipart.js create mode 100644 bruml/lib/socket.io/lib/socket.io/transports/xhr-polling.js create mode 100644 bruml/lib/socket.io/lib/socket.io/utils.js create mode 100644 bruml/lib/socket.io/package.json create mode 100644 bruml/lib/socket.io/support/expresso/History.md create mode 100644 bruml/lib/socket.io/support/expresso/Makefile create mode 100644 bruml/lib/socket.io/support/expresso/Readme.md create mode 100755 bruml/lib/socket.io/support/expresso/bin/expresso create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/COPYING create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/Makefile.am create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/Makefile.in create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/Readme.md create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/aclocal.m4 create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/config.guess create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/config.h.in create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/config.rpath create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/config.sub create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/configure create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/configure.ac create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/depcomp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/demo.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/doc.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/index.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/script.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/jsUnitStyle.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/readme create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/emptyPage.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitCore.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitMockTimeout.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestManager.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestSuite.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTracer.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitVersionCheck.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-errors.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-failures.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-runs.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-data.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-errors.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-frame.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-loader.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-progress.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-results.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-status.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainer.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainerController.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/xbDebug.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/css/jsUnitStyle.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/green.gif create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/logo_jsunit.gif create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/powerby-transparent.gif create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/red.gif create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/JDOM_license.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/Jetty_license.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/MPL-1.1.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/gpl-2.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/index.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/lgpl-2.1.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-c.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-html.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/readme.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/testRunner.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/script.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/test.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example/index.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example/script.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/faq.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/feed-icon-14x14.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/help.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/index.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/index.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-highlight.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-ie.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-throbber.gif create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/script.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/index.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-highlight.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-ie.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-throbber.gif create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/script.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/license.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/links.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/manual.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/news.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/reset-fonts-grids.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot2.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot3.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot4.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot5.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot6.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot7.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/sh_html.min.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/sh_javascript.min.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/sh_main.min.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/sh_nedit.min.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/siliconforks-16x16.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/style.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/users.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/encoding.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/encoding.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/generate-resources.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/global.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/highlight.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/highlight.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/http-connection.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/http-exchange.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/http-host.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/http-message.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/http-server.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/http-server.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/http-url.c create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/install-sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/instrument-js.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/instrument-js.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/instrument.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/instrument.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/GNUmakefile create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/Makefile.ref create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/README.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/SpiderMonkey.rsp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/aclocal.m4 create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/bench.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/builtins.tbl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/Makefile.in create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/Moz/Milestone.pm create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/autoconf.mk.in create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/check-sync-dirs.py create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/check-sync-exceptions create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/config.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/fastcwd.pl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/gcc_hidden.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/insure.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/make-system-wrappers.pl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/milestone.pl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/milestone.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/Makefile.in create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/cppsetup.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/def.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/ifparser.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/ifparser.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/imakemdep.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/include.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/main.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/mkdepend.man create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/parse.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/pr.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nfspwd.pl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nsinstall.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nsinstall.py create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/pathsub.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/pathsub.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/preprocessor.pl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/revdepth-nt.pl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/revdepth.pl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/rules.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/system-headers create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/version.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/version_win.pl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/dtoa.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/Makefile.ref create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/README create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.3 create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/sysunix.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/unix.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/javascript-trace.d create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jitstats.tbl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js-config.h.in create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js-config.in create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.mdp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.msg create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js3240.rc create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsOS240.def create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsapi.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsapi.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarena.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarena.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarray.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarray.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsatom.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsatom.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbit.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbool.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbool.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbuiltins.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbuiltins.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsclist.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscntxt.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscntxt.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscompat.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsconfig.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscpucfg.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscpucfg.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdate.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdate.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdbgapi.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdbgapi.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdhash.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdhash.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtoa.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtoa.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtracef.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtracef.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsemit.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsemit.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsexn.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsexn.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.msg create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfun.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfun.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsgc.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsgc.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jshash.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jshash.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsify.pl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinterp.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinterp.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinvoke.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsiter.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsiter.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jskeyword.tbl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jskwgen.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslibmath.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslock.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslock.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslocko.asm create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslog2.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslong.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslong.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsmath.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsmath.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsnum.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsnum.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsobj.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsobj.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/json.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/json.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.tbl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsoplengen.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsotypes.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsparse.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsparse.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprf.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprf.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsproto.tbl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprvtd.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jspubtd.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsregexp.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsregexp.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsreops.tbl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscan.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscan.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscope.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscope.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscript.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscript.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsshell.msg create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstaticcheck.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstddef.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstr.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstr.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstracer.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstracer.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstypes.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsutil.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsutil.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsversion.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxdrapi.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxdrapi.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxml.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxml.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/lock_SunOS.s create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/plify_jsdhash.sed create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/prmjtime.cpp create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/prmjtime.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.1.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.2.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.3.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Cygwin.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin1.3.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin1.4.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin5.2.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin5.3.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin64.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.10.10.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.10.20.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.11.00.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX5.3.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.1.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.2.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.3.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.5.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Linux_All.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/MSYS.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Mac_OS10.0.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/OSF1V4.0.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/OSF1V5.0.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS4.1.4.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.10.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.3.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.4.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.5.1.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.5.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.6.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.7.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.8.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.9.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT4.0.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.0.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.1.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.2.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT6.0.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/dgux.mk create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/resource.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/rules.mk create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/time.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/js/win32.order create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-help.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-highlight.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-ie.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-overlay.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server-help.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server.1 create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-throbber.gif create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.1 create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.jsm create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.manifest create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.xul create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/iconv.m4 create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-ld.m4 create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-link.m4 create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-prefix.m4 create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/make-bin-dist.sh.in create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/make-dist.sh.in create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/missing create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/report.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/resource-manager.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/resource-manager.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/stream.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/stream.h create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/Makefile.am create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/Makefile.in create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/asprintf.c create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/asprintf.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/charset.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/chunked.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/common.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/destination-is-existing-directory.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/destination-is-file.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encoding-requires-argument.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encodings.c create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encodings.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/exclude-requires-argument.expected.err create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/fatal.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/gethostbyname.c create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/gethostbyname.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/help.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-bad-body.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-bad-url.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-close-after-request.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-bad-body.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-bad-headers.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-charset.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-chunked.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-close-immediately.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/invalid-option.expected.err create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/invalid-option.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore.expected/ignore.js create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore/ignore.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-invalid.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-invalid/javascript-invalid.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-setter.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-setter/javascript-setter.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8.expected/javascript-utf-8.js create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8/javascript-utf-8.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-xml.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-xml/javascript-xml.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-array-comprehension.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-assign.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-colon.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-comma.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-cr.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-crlf.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-debugger.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-dec.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-delete.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-destructuring.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-do.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-dot.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-empty.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-for.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-foreach.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-function.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-generator-expression.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-generator.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-getter-setter.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-hook.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-if.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-in.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-inc.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-iso-8859-1.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-lambda.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-let.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-lf.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-new.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-number.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-object.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-op.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-primary.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rb.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rc.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rp.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-special-characters.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-string.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-switch.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-throw.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-try.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-unaryop.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-var.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-while.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-with.js create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-array-comprehension.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-assign.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-colon.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-comma.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-cr.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-crlf.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-debugger.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-dec.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-delete.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-destructuring.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-do.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-dot.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-empty.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-for.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-foreach.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-function.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-generator-expression.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-generator.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-getter-setter.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-hook.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-if.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-in.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-inc.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-iso-8859-1.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-lambda.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-let.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-lf.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-new.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-number.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-object.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-op.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-primary.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rb.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rc.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rp.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-special-characters.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-string.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-switch.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-throw.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-try.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-unaryop.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-var.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-while.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-with.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json-cmp.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json.c create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/mkdirs.c create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/mkdirs.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/netcat.pl create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-arguments.expected.err create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-arguments.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-instrument-requires-argument.expected.err create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-request-body.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body-javascript.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body.expected.err create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-headers.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-no-server.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-url.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-crlf.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-dir-list.c create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-dir-list.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-exclude.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-fatal.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-no-instrument.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/image.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/index.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/script.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/style.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/unix.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/windows.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/x create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/image.png create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/index.html create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/script.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/style.css create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/unix.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/windows.txt create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/x create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/same-directory.expected.err create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/same-directory.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-bad-requests.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-close-after-request.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-content-types.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-listing.expected create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-listing.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-redirect.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-encoded-url.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-error.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-help.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-ip-address.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown-bad-method.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown.expected.err create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-special-file.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-unreadable-directory.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-unreadable-file.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-verbose.expected.err create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-verbose.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-version.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server.pl create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/source-does-not-exist.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/source-is-file.expected.err create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-json.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-request-body.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-response-headers.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-source-urls.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-source-urls.expected.json create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.expected.json create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.js create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.json create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-server-bad-body.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-server-closes-immediately.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.expected.json create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.json create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-urls.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-urls.expected.json create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreachable-source-urls.expected.err create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreachable-source-urls.expected.json create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreadable-json.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unwritable-json.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.expected.json create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.json create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/streams.c create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/streams.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/too-many-arguments.expected.err create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/valgrind.sh create mode 100755 bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/version.sh create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/util.c create mode 100644 bruml/lib/socket.io/support/expresso/deps/jscoverage/util.h create mode 100644 bruml/lib/socket.io/support/expresso/docs/api.html create mode 100644 bruml/lib/socket.io/support/expresso/docs/index.html create mode 100644 bruml/lib/socket.io/support/expresso/docs/index.md create mode 100644 bruml/lib/socket.io/support/expresso/docs/layout/foot.html create mode 100644 bruml/lib/socket.io/support/expresso/docs/layout/head.html create mode 100644 bruml/lib/socket.io/support/expresso/lib/bar.js create mode 100644 bruml/lib/socket.io/support/expresso/lib/foo.js create mode 100644 bruml/lib/socket.io/support/expresso/package.json create mode 100644 bruml/lib/socket.io/support/expresso/test/assert.test.js create mode 100644 bruml/lib/socket.io/support/expresso/test/async.test.js create mode 100644 bruml/lib/socket.io/support/expresso/test/bar.test.js create mode 100644 bruml/lib/socket.io/support/expresso/test/foo.test.js create mode 100644 bruml/lib/socket.io/support/expresso/test/http.test.js create mode 100644 bruml/lib/socket.io/support/expresso/test/serial/async.test.js create mode 100644 bruml/lib/socket.io/support/expresso/test/serial/http.test.js create mode 100644 bruml/lib/socket.io/support/node-websocket-client/LICENSE create mode 100644 bruml/lib/socket.io/support/node-websocket-client/Makefile create mode 100644 bruml/lib/socket.io/support/node-websocket-client/README.md create mode 100644 bruml/lib/socket.io/support/node-websocket-client/examples/client-unix.js create mode 100644 bruml/lib/socket.io/support/node-websocket-client/examples/client.js create mode 100644 bruml/lib/socket.io/support/node-websocket-client/examples/server-unix.js create mode 100644 bruml/lib/socket.io/support/node-websocket-client/lib/websocket.js create mode 100644 bruml/lib/socket.io/support/node-websocket-client/package.json create mode 100644 bruml/lib/socket.io/support/node-websocket-client/test/test-basic.js create mode 100644 bruml/lib/socket.io/support/node-websocket-client/test/test-readonly-attrs.js create mode 100644 bruml/lib/socket.io/support/node-websocket-client/test/test-ready-state.js create mode 100644 bruml/lib/socket.io/support/node-websocket-client/test/test-unix-send-fd.js create mode 100644 bruml/lib/socket.io/support/node-websocket-client/test/test-unix-sockets.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/Makefile create mode 100644 bruml/lib/socket.io/support/socket.io-client/README.md create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/io.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/socket.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/transport.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/transports/flashsocket.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/transports/htmlfile.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/transports/jsonp-polling.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/transports/websocket.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/transports/xhr-multipart.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/transports/xhr-polling.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/transports/xhr.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/util.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/FABridge.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/README.txt create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/WebSocketMain.swf create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/WebSocketMainInsecure.zip create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocket.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocketMain.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocketMainInsecure.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/bridge/FABridge.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/build.sh create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/adobe/net/proxies/RFC2817Socket.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/gsolo/encryption/MD5.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/Crypto.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/MozillaRootCertificates.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/X509Certificate.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/X509CertificateCollection.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/HMAC.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/IHMAC.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/IHash.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MAC.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MD2.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MD5.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA1.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA224.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA256.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHABase.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/ARC4.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/IPRNG.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/Random.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/TLSPRF.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/rsa/RSAKey.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/AESKey.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/BlowFishKey.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CBCMode.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CFB8Mode.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CFBMode.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CTRMode.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/DESKey.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ECBMode.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ICipher.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IMode.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IPad.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IStreamCipher.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ISymmetricKey.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IVMode.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/NullPad.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/OFBMode.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/PKCS5.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/SSLPad.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/SimpleIVMode.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/TLSPad.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/TripleDESKey.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/XTeaKey.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/aeskey.pl create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/dump.txt create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/AESKeyTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ARC4Test.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/BigIntegerTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/BlowFishKeyTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CBCModeTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CFB8ModeTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CFBModeTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CTRModeTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/DESKeyTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ECBModeTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/HMACTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ITestHarness.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/MD2Test.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/MD5Test.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/OFBModeTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/RSAKeyTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA1Test.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA224Test.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA256Test.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TLSPRFTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TestCase.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TripleDESKeyTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/XTeaKeyTest.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/BulkCiphers.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/CipherSuites.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/IConnectionState.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/ISecurityParameters.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/KeyExchanges.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/MACs.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLConnectionState.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLEvent.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLSecurityParameters.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSConfig.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSConnectionState.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSEngine.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSError.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSEvent.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSecurityParameters.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSocket.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSocketEvent.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSTest.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/BarrettReduction.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/BigInteger.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/ClassicReduction.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/IReduction.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/MontgomeryReduction.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/NullReduction.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/bi_internal.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/ArrayUtil.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/Base64.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/Hex.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/Memory.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/ByteString.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/DER.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/IAsn1Type.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Integer.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/OID.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/ObjectIdentifier.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/PEM.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/PrintableString.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Sequence.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Set.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Type.as create mode 100755 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/UTCTime.as create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/sample.html create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/swfobject.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/lib/vendor/web-socket-js/web_socket.js create mode 100644 bruml/lib/socket.io/support/socket.io-client/socket.io.js create mode 100644 bruml/lib/socket.io/tests/index.js create mode 100644 bruml/lib/socket.io/tests/listener.js create mode 100644 bruml/lib/socket.io/tests/transports.flashsocket.js create mode 100644 bruml/lib/socket.io/tests/transports.htmlfile.js create mode 100644 bruml/lib/socket.io/tests/transports.jsonp-polling.js create mode 100644 bruml/lib/socket.io/tests/transports.websocket.js create mode 100644 bruml/lib/socket.io/tests/transports.xhr-multipart.js create mode 100644 bruml/lib/socket.io/tests/transports.xhr-polling.js create mode 100644 bruml/lib/socket.io/tests/utils.js create mode 100644 bruml/lib/underscore/.npmignore create mode 100644 bruml/lib/underscore/LICENSE create mode 100644 bruml/lib/underscore/README create mode 100644 bruml/lib/underscore/index.html create mode 100644 bruml/lib/underscore/index.js create mode 100644 bruml/lib/underscore/package.json create mode 100644 bruml/lib/underscore/underscore.js create mode 120000 bruml/node_modules/.bin/express create mode 100644 bruml/node_modules/express/.npmignore create mode 100644 bruml/node_modules/express/History.md create mode 100644 bruml/node_modules/express/LICENSE create mode 100644 bruml/node_modules/express/Makefile create mode 100644 bruml/node_modules/express/Readme.md create mode 100755 bruml/node_modules/express/bin/express create mode 100644 bruml/node_modules/express/index.js create mode 100644 bruml/node_modules/express/lib/express.js create mode 100644 bruml/node_modules/express/lib/http.js create mode 100644 bruml/node_modules/express/lib/https.js create mode 100644 bruml/node_modules/express/lib/request.js create mode 100644 bruml/node_modules/express/lib/response.js create mode 100644 bruml/node_modules/express/lib/router/collection.js create mode 100644 bruml/node_modules/express/lib/router/index.js create mode 100644 bruml/node_modules/express/lib/router/methods.js create mode 100644 bruml/node_modules/express/lib/router/route.js create mode 100644 bruml/node_modules/express/lib/utils.js create mode 100644 bruml/node_modules/express/lib/view.js create mode 100644 bruml/node_modules/express/lib/view/partial.js create mode 100644 bruml/node_modules/express/lib/view/view.js create mode 100644 bruml/node_modules/express/node_modules/connect/.npmignore create mode 100644 bruml/node_modules/express/node_modules/connect/LICENSE create mode 100644 bruml/node_modules/express/node_modules/connect/index.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/connect.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/http.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/https.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/index.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/compiler.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/csrf.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/directory.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/favicon.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/limit.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/logger.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/methodOverride.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/profiler.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/query.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/responseTime.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/router.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/session.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/session/cookie.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/session/memory.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/session/session.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/session/store.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/static.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/middleware/vhost.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/patch.js create mode 100644 bruml/node_modules/express/node_modules/connect/lib/public/directory.html create mode 100644 bruml/node_modules/express/node_modules/connect/lib/public/error.html create mode 100644 bruml/node_modules/express/node_modules/connect/lib/public/favicon.ico create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_add.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_attach.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_code.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_copy.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_delete.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_edit.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_error.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_excel.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_find.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_gear.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_go.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_green.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_key.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_link.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_paste.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_red.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_save.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_word.png create mode 100755 bruml/node_modules/express/node_modules/connect/lib/public/icons/page_world.png create mode 100644 bruml/node_modules/express/node_modules/connect/lib/public/style.css create mode 100644 bruml/node_modules/express/node_modules/connect/lib/utils.js create mode 100644 bruml/node_modules/express/node_modules/connect/meta.json create mode 100644 bruml/node_modules/express/node_modules/connect/package.json create mode 100644 bruml/node_modules/express/node_modules/connect/test.js create mode 100644 bruml/node_modules/express/node_modules/mime/LICENSE create mode 100644 bruml/node_modules/express/node_modules/mime/README.md create mode 100644 bruml/node_modules/express/node_modules/mime/index.js create mode 100644 bruml/node_modules/express/node_modules/mime/mime.js create mode 100644 bruml/node_modules/express/node_modules/mime/mime.types create mode 100644 bruml/node_modules/express/node_modules/mime/node.types create mode 100644 bruml/node_modules/express/node_modules/mime/package.json create mode 100644 bruml/node_modules/express/node_modules/mime/test.js create mode 100644 bruml/node_modules/express/node_modules/qs/History.md create mode 100644 bruml/node_modules/express/node_modules/qs/Makefile create mode 100644 bruml/node_modules/express/node_modules/qs/Readme.md create mode 100644 bruml/node_modules/express/node_modules/qs/benchmark.js create mode 100644 bruml/node_modules/express/node_modules/qs/examples.js create mode 100644 bruml/node_modules/express/node_modules/qs/index.js create mode 100644 bruml/node_modules/express/node_modules/qs/lib/querystring.js create mode 100644 bruml/node_modules/express/node_modules/qs/package.json create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/History.md create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/Makefile create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/Readme.md create mode 100755 bruml/node_modules/express/node_modules/qs/support/expresso/bin/expresso create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/docs/api.html create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/docs/index.html create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/docs/index.md create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/docs/layout/foot.html create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/docs/layout/head.html create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/lib/bar.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/lib/foo.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/package.json create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/test/assert.test.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/test/async.test.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/test/bar.test.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/test/foo.test.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/test/http.test.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/test/serial/async.test.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/expresso/test/serial/http.test.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/should/History.md create mode 100644 bruml/node_modules/express/node_modules/qs/support/should/Makefile create mode 100644 bruml/node_modules/express/node_modules/qs/support/should/Readme.md create mode 100644 bruml/node_modules/express/node_modules/qs/support/should/examples/runner.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/should/index.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/should/lib/eql.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/should/lib/should.js create mode 100644 bruml/node_modules/express/node_modules/qs/support/should/package.json create mode 100644 bruml/node_modules/express/node_modules/qs/support/should/test/should.test.js create mode 100644 bruml/node_modules/express/node_modules/qs/test/parse.test.js create mode 100644 bruml/node_modules/express/node_modules/qs/test/stringify.test.js create mode 100644 bruml/node_modules/express/package.json create mode 100644 bruml/node_modules/socket.io/.npmignore create mode 100644 bruml/node_modules/socket.io/History.md create mode 100644 bruml/node_modules/socket.io/Makefile create mode 100644 bruml/node_modules/socket.io/Readme.md create mode 100644 bruml/node_modules/socket.io/TODO create mode 100644 bruml/node_modules/socket.io/index.js create mode 100644 bruml/node_modules/socket.io/lib/logger.js create mode 100644 bruml/node_modules/socket.io/lib/manager.js create mode 100644 bruml/node_modules/socket.io/lib/namespace.js create mode 100644 bruml/node_modules/socket.io/lib/parser.js create mode 100644 bruml/node_modules/socket.io/lib/socket.io.js create mode 100644 bruml/node_modules/socket.io/lib/socket.js create mode 100644 bruml/node_modules/socket.io/lib/store.js create mode 100644 bruml/node_modules/socket.io/lib/stores/memory.js create mode 100644 bruml/node_modules/socket.io/lib/stores/redis.js create mode 100644 bruml/node_modules/socket.io/lib/transport.js create mode 100644 bruml/node_modules/socket.io/lib/transports/flashsocket.js create mode 100644 bruml/node_modules/socket.io/lib/transports/htmlfile.js create mode 100644 bruml/node_modules/socket.io/lib/transports/http-polling.js create mode 100644 bruml/node_modules/socket.io/lib/transports/http.js create mode 100644 bruml/node_modules/socket.io/lib/transports/index.js create mode 100644 bruml/node_modules/socket.io/lib/transports/jsonp-polling.js create mode 100644 bruml/node_modules/socket.io/lib/transports/websocket.js create mode 100644 bruml/node_modules/socket.io/lib/transports/xhr-polling.js create mode 100644 bruml/node_modules/socket.io/lib/util.js create mode 100644 bruml/node_modules/socket.io/new-old/app.js create mode 100644 bruml/node_modules/socket.io/new-old/index.jade create mode 100644 bruml/node_modules/socket.io/new-old/layout.jade create mode 100644 bruml/node_modules/socket.io/new-old/package.json create mode 100644 bruml/node_modules/socket.io/new-old/public/js/main.js create mode 100644 bruml/node_modules/socket.io/package.json create mode 100644 bruml/old_bcserver.js create mode 100644 bruml/server.js create mode 100755 bruml/static/arrow_dn.png create mode 100755 bruml/static/arrow_up.png create mode 100644 bruml/static/general.css create mode 100644 bruml/static/index.html create mode 100644 bruml/static/main.js create mode 100644 bruml/static/rumlfavicon.ico create mode 100644 db.js create mode 100644 emails/instructorInvite.ejs create mode 100644 emails/newCourse.ejs create mode 100644 emails/userActivation.ejs create mode 100644 emails/userNoSchool.ejs create mode 100644 emails/userPasswordReset.ejs create mode 100644 emails/userSchool.ejs create mode 100644 emails/userWelcome.ejs create mode 100644 emails/userWelcomeNoSchool.ejs create mode 100755 fcbackups/cp2s3.rb create mode 100755 fcbackups/fc_rotating_db_backup.sh create mode 100755 fcbackups/fcbackup_init.sh create mode 100644 log.js create mode 100644 mailer.js create mode 100644 models.js create mode 100644 models/user.js create mode 120000 node_modules/.bin/express create mode 120000 node_modules/.bin/jade create mode 100644 node_modules/async/LICENSE create mode 100644 node_modules/async/Makefile create mode 100644 node_modules/async/README.md create mode 100644 node_modules/async/async.min.js.gzip create mode 100644 node_modules/async/deps/nodeunit.css create mode 100644 node_modules/async/deps/nodeunit.js create mode 100644 node_modules/async/dist/async.min.js create mode 100644 node_modules/async/index.js create mode 100644 node_modules/async/lib/async.js create mode 100644 node_modules/async/nodelint.cfg create mode 100644 node_modules/async/package.json create mode 100644 node_modules/async/test/test-async.js create mode 100644 node_modules/async/test/test.html create mode 100644 node_modules/aws-lib/LICENSE create mode 100644 node_modules/aws-lib/README.md create mode 100644 node_modules/aws-lib/examples/ec2.js create mode 100644 node_modules/aws-lib/examples/prod-adv.js create mode 100644 node_modules/aws-lib/examples/ses.js create mode 100644 node_modules/aws-lib/lib/aws.js create mode 100644 node_modules/aws-lib/lib/ec2.js create mode 100644 node_modules/aws-lib/lib/prodAdv.js create mode 100644 node_modules/aws-lib/lib/ses.js create mode 100644 node_modules/aws-lib/lib/simpledb.js create mode 100644 node_modules/aws-lib/lib/sns.js create mode 100644 node_modules/aws-lib/lib/sqs.js create mode 100644 node_modules/aws-lib/node_modules/sax/LICENSE create mode 100644 node_modules/aws-lib/node_modules/sax/README.md create mode 100644 node_modules/aws-lib/node_modules/sax/examples/example.js create mode 100644 node_modules/aws-lib/node_modules/sax/examples/not-pretty.xml create mode 100644 node_modules/aws-lib/node_modules/sax/examples/pretty-print.js create mode 100644 node_modules/aws-lib/node_modules/sax/examples/strict.dtd create mode 100755 node_modules/aws-lib/node_modules/sax/examples/switch-bench.js create mode 100644 node_modules/aws-lib/node_modules/sax/examples/test.html create mode 100644 node_modules/aws-lib/node_modules/sax/examples/test.xml create mode 100644 node_modules/aws-lib/node_modules/sax/lib/sax.js create mode 100644 node_modules/aws-lib/node_modules/sax/package.json create mode 100644 node_modules/aws-lib/node_modules/sax/test/buffer-overrun.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/cdata-chunked.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/cdata-end-split.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/cdata-fake-end.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/cdata-multiple.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/cdata.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/index.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/issue-23.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/parser-position.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/self-closing-child-strict.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/self-closing-child.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/self-closing-tag.js create mode 100644 node_modules/aws-lib/node_modules/sax/test/trailing-non-whitespace.js create mode 100644 node_modules/aws-lib/node_modules/xml2js/Cakefile create mode 100644 node_modules/aws-lib/node_modules/xml2js/LICENSE create mode 100644 node_modules/aws-lib/node_modules/xml2js/README.md create mode 100644 node_modules/aws-lib/node_modules/xml2js/lib/xml2js.js create mode 100644 node_modules/aws-lib/node_modules/xml2js/package.json create mode 100644 node_modules/aws-lib/node_modules/xml2js/src/xml2js.coffee create mode 100644 node_modules/aws-lib/node_modules/xml2js/test/fixtures/sample.xml create mode 100644 node_modules/aws-lib/node_modules/xml2js/test/xml2js.test.coffee create mode 100644 node_modules/aws-lib/package.json create mode 100644 node_modules/aws-lib/test/common.js create mode 100644 node_modules/aws-lib/test/simpledb.test.js create mode 100644 node_modules/connect-mongo/.npmignore create mode 100644 node_modules/connect-mongo/History.md create mode 100644 node_modules/connect-mongo/Makefile create mode 100644 node_modules/connect-mongo/Readme.md create mode 100644 node_modules/connect-mongo/index.js create mode 100644 node_modules/connect-mongo/lib/connect-mongo.js create mode 100644 node_modules/connect-mongo/package.json create mode 100644 node_modules/connect-mongo/test/connect-mongo.test.js create mode 100644 node_modules/connect/.npmignore create mode 100644 node_modules/connect/LICENSE create mode 100644 node_modules/connect/index.js create mode 100644 node_modules/connect/lib/connect.js create mode 100644 node_modules/connect/lib/http.js create mode 100644 node_modules/connect/lib/https.js create mode 100644 node_modules/connect/lib/index.js create mode 100644 node_modules/connect/lib/middleware/basicAuth.js create mode 100644 node_modules/connect/lib/middleware/bodyParser.js create mode 100644 node_modules/connect/lib/middleware/compiler.js create mode 100644 node_modules/connect/lib/middleware/cookieParser.js create mode 100644 node_modules/connect/lib/middleware/csrf.js create mode 100644 node_modules/connect/lib/middleware/directory.js create mode 100644 node_modules/connect/lib/middleware/errorHandler.js create mode 100644 node_modules/connect/lib/middleware/favicon.js create mode 100644 node_modules/connect/lib/middleware/limit.js create mode 100644 node_modules/connect/lib/middleware/logger.js create mode 100644 node_modules/connect/lib/middleware/methodOverride.js create mode 100644 node_modules/connect/lib/middleware/profiler.js create mode 100644 node_modules/connect/lib/middleware/query.js create mode 100644 node_modules/connect/lib/middleware/responseTime.js create mode 100644 node_modules/connect/lib/middleware/router.js create mode 100644 node_modules/connect/lib/middleware/session.js create mode 100644 node_modules/connect/lib/middleware/session/cookie.js create mode 100644 node_modules/connect/lib/middleware/session/memory.js create mode 100644 node_modules/connect/lib/middleware/session/session.js create mode 100644 node_modules/connect/lib/middleware/session/store.js create mode 100644 node_modules/connect/lib/middleware/static.js create mode 100644 node_modules/connect/lib/middleware/vhost.js create mode 100644 node_modules/connect/lib/patch.js create mode 100644 node_modules/connect/lib/public/directory.html create mode 100644 node_modules/connect/lib/public/error.html create mode 100644 node_modules/connect/lib/public/favicon.ico create mode 100755 node_modules/connect/lib/public/icons/page.png create mode 100755 node_modules/connect/lib/public/icons/page_add.png create mode 100755 node_modules/connect/lib/public/icons/page_attach.png create mode 100755 node_modules/connect/lib/public/icons/page_code.png create mode 100755 node_modules/connect/lib/public/icons/page_copy.png create mode 100755 node_modules/connect/lib/public/icons/page_delete.png create mode 100755 node_modules/connect/lib/public/icons/page_edit.png create mode 100755 node_modules/connect/lib/public/icons/page_error.png create mode 100755 node_modules/connect/lib/public/icons/page_excel.png create mode 100755 node_modules/connect/lib/public/icons/page_find.png create mode 100755 node_modules/connect/lib/public/icons/page_gear.png create mode 100755 node_modules/connect/lib/public/icons/page_go.png create mode 100755 node_modules/connect/lib/public/icons/page_green.png create mode 100755 node_modules/connect/lib/public/icons/page_key.png create mode 100755 node_modules/connect/lib/public/icons/page_lightning.png create mode 100755 node_modules/connect/lib/public/icons/page_link.png create mode 100755 node_modules/connect/lib/public/icons/page_paintbrush.png create mode 100755 node_modules/connect/lib/public/icons/page_paste.png create mode 100755 node_modules/connect/lib/public/icons/page_red.png create mode 100755 node_modules/connect/lib/public/icons/page_refresh.png create mode 100755 node_modules/connect/lib/public/icons/page_save.png create mode 100755 node_modules/connect/lib/public/icons/page_white.png create mode 100755 node_modules/connect/lib/public/icons/page_white_acrobat.png create mode 100755 node_modules/connect/lib/public/icons/page_white_actionscript.png create mode 100755 node_modules/connect/lib/public/icons/page_white_add.png create mode 100755 node_modules/connect/lib/public/icons/page_white_c.png create mode 100755 node_modules/connect/lib/public/icons/page_white_camera.png create mode 100755 node_modules/connect/lib/public/icons/page_white_cd.png create mode 100755 node_modules/connect/lib/public/icons/page_white_code.png create mode 100755 node_modules/connect/lib/public/icons/page_white_code_red.png create mode 100755 node_modules/connect/lib/public/icons/page_white_coldfusion.png create mode 100755 node_modules/connect/lib/public/icons/page_white_compressed.png create mode 100755 node_modules/connect/lib/public/icons/page_white_copy.png create mode 100755 node_modules/connect/lib/public/icons/page_white_cplusplus.png create mode 100755 node_modules/connect/lib/public/icons/page_white_csharp.png create mode 100755 node_modules/connect/lib/public/icons/page_white_cup.png create mode 100755 node_modules/connect/lib/public/icons/page_white_database.png create mode 100755 node_modules/connect/lib/public/icons/page_white_delete.png create mode 100755 node_modules/connect/lib/public/icons/page_white_dvd.png create mode 100755 node_modules/connect/lib/public/icons/page_white_edit.png create mode 100755 node_modules/connect/lib/public/icons/page_white_error.png create mode 100755 node_modules/connect/lib/public/icons/page_white_excel.png create mode 100755 node_modules/connect/lib/public/icons/page_white_find.png create mode 100755 node_modules/connect/lib/public/icons/page_white_flash.png create mode 100755 node_modules/connect/lib/public/icons/page_white_freehand.png create mode 100755 node_modules/connect/lib/public/icons/page_white_gear.png create mode 100755 node_modules/connect/lib/public/icons/page_white_get.png create mode 100755 node_modules/connect/lib/public/icons/page_white_go.png create mode 100755 node_modules/connect/lib/public/icons/page_white_h.png create mode 100755 node_modules/connect/lib/public/icons/page_white_horizontal.png create mode 100755 node_modules/connect/lib/public/icons/page_white_key.png create mode 100755 node_modules/connect/lib/public/icons/page_white_lightning.png create mode 100755 node_modules/connect/lib/public/icons/page_white_link.png create mode 100755 node_modules/connect/lib/public/icons/page_white_magnify.png create mode 100755 node_modules/connect/lib/public/icons/page_white_medal.png create mode 100755 node_modules/connect/lib/public/icons/page_white_office.png create mode 100755 node_modules/connect/lib/public/icons/page_white_paint.png create mode 100755 node_modules/connect/lib/public/icons/page_white_paintbrush.png create mode 100755 node_modules/connect/lib/public/icons/page_white_paste.png create mode 100755 node_modules/connect/lib/public/icons/page_white_php.png create mode 100755 node_modules/connect/lib/public/icons/page_white_picture.png create mode 100755 node_modules/connect/lib/public/icons/page_white_powerpoint.png create mode 100755 node_modules/connect/lib/public/icons/page_white_put.png create mode 100755 node_modules/connect/lib/public/icons/page_white_ruby.png create mode 100755 node_modules/connect/lib/public/icons/page_white_stack.png create mode 100755 node_modules/connect/lib/public/icons/page_white_star.png create mode 100755 node_modules/connect/lib/public/icons/page_white_swoosh.png create mode 100755 node_modules/connect/lib/public/icons/page_white_text.png create mode 100755 node_modules/connect/lib/public/icons/page_white_text_width.png create mode 100755 node_modules/connect/lib/public/icons/page_white_tux.png create mode 100755 node_modules/connect/lib/public/icons/page_white_vector.png create mode 100755 node_modules/connect/lib/public/icons/page_white_visualstudio.png create mode 100755 node_modules/connect/lib/public/icons/page_white_width.png create mode 100755 node_modules/connect/lib/public/icons/page_white_word.png create mode 100755 node_modules/connect/lib/public/icons/page_white_world.png create mode 100755 node_modules/connect/lib/public/icons/page_white_wrench.png create mode 100755 node_modules/connect/lib/public/icons/page_white_zip.png create mode 100755 node_modules/connect/lib/public/icons/page_word.png create mode 100755 node_modules/connect/lib/public/icons/page_world.png create mode 100644 node_modules/connect/lib/public/style.css create mode 100644 node_modules/connect/lib/utils.js create mode 100644 node_modules/connect/meta.json create mode 100644 node_modules/connect/node_modules/mime/LICENSE create mode 100644 node_modules/connect/node_modules/mime/README.md create mode 100644 node_modules/connect/node_modules/mime/index.js create mode 100644 node_modules/connect/node_modules/mime/mime.js create mode 100644 node_modules/connect/node_modules/mime/mime.types create mode 100644 node_modules/connect/node_modules/mime/node.types create mode 100644 node_modules/connect/node_modules/mime/package.json create mode 100644 node_modules/connect/node_modules/mime/test.js create mode 100644 node_modules/connect/node_modules/qs/History.md create mode 100644 node_modules/connect/node_modules/qs/Makefile create mode 100644 node_modules/connect/node_modules/qs/Readme.md create mode 100644 node_modules/connect/node_modules/qs/benchmark.js create mode 100644 node_modules/connect/node_modules/qs/examples.js create mode 100644 node_modules/connect/node_modules/qs/index.js create mode 100644 node_modules/connect/node_modules/qs/lib/querystring.js create mode 100644 node_modules/connect/node_modules/qs/package.json create mode 100644 node_modules/connect/node_modules/qs/support/expresso/History.md create mode 100644 node_modules/connect/node_modules/qs/support/expresso/Makefile create mode 100644 node_modules/connect/node_modules/qs/support/expresso/Readme.md create mode 100755 node_modules/connect/node_modules/qs/support/expresso/bin/expresso create mode 100644 node_modules/connect/node_modules/qs/support/expresso/docs/api.html create mode 100644 node_modules/connect/node_modules/qs/support/expresso/docs/index.html create mode 100644 node_modules/connect/node_modules/qs/support/expresso/docs/index.md create mode 100644 node_modules/connect/node_modules/qs/support/expresso/docs/layout/foot.html create mode 100644 node_modules/connect/node_modules/qs/support/expresso/docs/layout/head.html create mode 100644 node_modules/connect/node_modules/qs/support/expresso/lib/bar.js create mode 100644 node_modules/connect/node_modules/qs/support/expresso/lib/foo.js create mode 100644 node_modules/connect/node_modules/qs/support/expresso/package.json create mode 100644 node_modules/connect/node_modules/qs/support/expresso/test/assert.test.js create mode 100644 node_modules/connect/node_modules/qs/support/expresso/test/async.test.js create mode 100644 node_modules/connect/node_modules/qs/support/expresso/test/bar.test.js create mode 100644 node_modules/connect/node_modules/qs/support/expresso/test/foo.test.js create mode 100644 node_modules/connect/node_modules/qs/support/expresso/test/http.test.js create mode 100644 node_modules/connect/node_modules/qs/support/expresso/test/serial/async.test.js create mode 100644 node_modules/connect/node_modules/qs/support/expresso/test/serial/http.test.js create mode 100644 node_modules/connect/node_modules/qs/support/should/History.md create mode 100644 node_modules/connect/node_modules/qs/support/should/Makefile create mode 100644 node_modules/connect/node_modules/qs/support/should/Readme.md create mode 100644 node_modules/connect/node_modules/qs/support/should/examples/runner.js create mode 100644 node_modules/connect/node_modules/qs/support/should/index.js create mode 100644 node_modules/connect/node_modules/qs/support/should/lib/eql.js create mode 100644 node_modules/connect/node_modules/qs/support/should/lib/should.js create mode 100644 node_modules/connect/node_modules/qs/support/should/package.json create mode 100644 node_modules/connect/node_modules/qs/support/should/test/should.test.js create mode 100644 node_modules/connect/node_modules/qs/test/parse.test.js create mode 100644 node_modules/connect/node_modules/qs/test/stringify.test.js create mode 100644 node_modules/connect/package.json create mode 100644 node_modules/connect/test.js create mode 100644 node_modules/ejs/History.md create mode 100644 node_modules/ejs/Makefile create mode 100644 node_modules/ejs/Readme.md create mode 100644 node_modules/ejs/benchmark.js create mode 100644 node_modules/ejs/ejs.js create mode 100644 node_modules/ejs/ejs.min.js create mode 100644 node_modules/ejs/examples/client.html create mode 100644 node_modules/ejs/examples/list.ejs create mode 100644 node_modules/ejs/examples/list.js create mode 100644 node_modules/ejs/index.js create mode 100644 node_modules/ejs/lib/ejs.js create mode 100644 node_modules/ejs/lib/filters.js create mode 100644 node_modules/ejs/lib/utils.js create mode 100644 node_modules/ejs/package.json create mode 100644 node_modules/ejs/support/compile.js create mode 100644 node_modules/ejs/support/expresso/History.md create mode 100644 node_modules/ejs/support/expresso/Makefile create mode 100644 node_modules/ejs/support/expresso/Readme.md create mode 100755 node_modules/ejs/support/expresso/bin/expresso create mode 100644 node_modules/ejs/support/expresso/docs/api.html create mode 100644 node_modules/ejs/support/expresso/docs/index.html create mode 100644 node_modules/ejs/support/expresso/docs/index.md create mode 100644 node_modules/ejs/support/expresso/docs/layout/foot.html create mode 100644 node_modules/ejs/support/expresso/docs/layout/head.html create mode 100644 node_modules/ejs/support/expresso/lib/bar.js create mode 100644 node_modules/ejs/support/expresso/lib/foo.js create mode 100644 node_modules/ejs/support/expresso/package.json create mode 100644 node_modules/ejs/support/expresso/test/assert.test.js create mode 100644 node_modules/ejs/support/expresso/test/async.test.js create mode 100644 node_modules/ejs/support/expresso/test/bar.test.js create mode 100644 node_modules/ejs/support/expresso/test/foo.test.js create mode 100644 node_modules/ejs/support/expresso/test/http.test.js create mode 100644 node_modules/ejs/test/ejs.test.js create mode 100644 node_modules/express-messages/.npmignore create mode 100644 node_modules/express-messages/History.md create mode 100644 node_modules/express-messages/Makefile create mode 100644 node_modules/express-messages/Readme.md create mode 100644 node_modules/express-messages/index.js create mode 100644 node_modules/express-messages/package.json create mode 100644 node_modules/express/.npmignore create mode 100644 node_modules/express/History.md create mode 100644 node_modules/express/LICENSE create mode 100644 node_modules/express/Makefile create mode 100644 node_modules/express/Readme.md create mode 100755 node_modules/express/bin/express create mode 100644 node_modules/express/index.js create mode 100644 node_modules/express/lib/express.js create mode 100644 node_modules/express/lib/http.js create mode 100644 node_modules/express/lib/https.js create mode 100644 node_modules/express/lib/request.js create mode 100644 node_modules/express/lib/response.js create mode 100644 node_modules/express/lib/router/collection.js create mode 100644 node_modules/express/lib/router/index.js create mode 100644 node_modules/express/lib/router/methods.js create mode 100644 node_modules/express/lib/router/route.js create mode 100644 node_modules/express/lib/utils.js create mode 100644 node_modules/express/lib/view.js create mode 100644 node_modules/express/lib/view/partial.js create mode 100644 node_modules/express/lib/view/view.js create mode 100644 node_modules/express/node_modules/connect/.npmignore create mode 100644 node_modules/express/node_modules/connect/LICENSE create mode 100644 node_modules/express/node_modules/connect/index.js create mode 100644 node_modules/express/node_modules/connect/lib/connect.js create mode 100644 node_modules/express/node_modules/connect/lib/http.js create mode 100644 node_modules/express/node_modules/connect/lib/https.js create mode 100644 node_modules/express/node_modules/connect/lib/index.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/basicAuth.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/bodyParser.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/compiler.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/cookieParser.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/csrf.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/directory.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/errorHandler.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/favicon.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/limit.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/logger.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/methodOverride.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/profiler.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/query.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/responseTime.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/router.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/session.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/session/cookie.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/session/memory.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/session/session.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/session/store.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/static.js create mode 100644 node_modules/express/node_modules/connect/lib/middleware/vhost.js create mode 100644 node_modules/express/node_modules/connect/lib/patch.js create mode 100644 node_modules/express/node_modules/connect/lib/public/directory.html create mode 100644 node_modules/express/node_modules/connect/lib/public/error.html create mode 100644 node_modules/express/node_modules/connect/lib/public/favicon.ico create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_add.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_attach.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_code.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_copy.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_delete.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_edit.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_error.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_excel.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_find.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_gear.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_go.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_green.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_key.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_link.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_paste.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_red.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_save.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_word.png create mode 100755 node_modules/express/node_modules/connect/lib/public/icons/page_world.png create mode 100644 node_modules/express/node_modules/connect/lib/public/style.css create mode 100644 node_modules/express/node_modules/connect/lib/utils.js create mode 100644 node_modules/express/node_modules/connect/meta.json create mode 100644 node_modules/express/node_modules/connect/node_modules/connect-redis/History.md create mode 100644 node_modules/express/node_modules/connect/node_modules/connect-redis/Makefile create mode 100644 node_modules/express/node_modules/connect/node_modules/connect-redis/Readme.md create mode 100644 node_modules/express/node_modules/connect/node_modules/connect-redis/bm.js create mode 100644 node_modules/express/node_modules/connect/node_modules/connect-redis/index.html create mode 100644 node_modules/express/node_modules/connect/node_modules/connect-redis/index.js create mode 100644 node_modules/express/node_modules/connect/node_modules/connect-redis/lib/connect-redis.js create mode 100644 node_modules/express/node_modules/connect/node_modules/connect-redis/package.json create mode 100644 node_modules/express/node_modules/connect/node_modules/connect-redis/test.js create mode 100644 node_modules/express/node_modules/connect/package.json create mode 100644 node_modules/express/node_modules/connect/test.js create mode 100644 node_modules/express/node_modules/mime/LICENSE create mode 100644 node_modules/express/node_modules/mime/README.md create mode 100644 node_modules/express/node_modules/mime/index.js create mode 100644 node_modules/express/node_modules/mime/mime.js create mode 100644 node_modules/express/node_modules/mime/mime.types create mode 100644 node_modules/express/node_modules/mime/node.types create mode 100644 node_modules/express/node_modules/mime/package.json create mode 100644 node_modules/express/node_modules/mime/test.js create mode 100644 node_modules/express/node_modules/qs/History.md create mode 100644 node_modules/express/node_modules/qs/Makefile create mode 100644 node_modules/express/node_modules/qs/Readme.md create mode 100644 node_modules/express/node_modules/qs/benchmark.js create mode 100644 node_modules/express/node_modules/qs/examples.js create mode 100644 node_modules/express/node_modules/qs/index.js create mode 100644 node_modules/express/node_modules/qs/lib/querystring.js create mode 100644 node_modules/express/node_modules/qs/package.json create mode 100644 node_modules/express/node_modules/qs/support/expresso/History.md create mode 100644 node_modules/express/node_modules/qs/support/expresso/Makefile create mode 100644 node_modules/express/node_modules/qs/support/expresso/Readme.md create mode 100755 node_modules/express/node_modules/qs/support/expresso/bin/expresso create mode 100644 node_modules/express/node_modules/qs/support/expresso/docs/api.html create mode 100644 node_modules/express/node_modules/qs/support/expresso/docs/index.html create mode 100644 node_modules/express/node_modules/qs/support/expresso/docs/index.md create mode 100644 node_modules/express/node_modules/qs/support/expresso/docs/layout/foot.html create mode 100644 node_modules/express/node_modules/qs/support/expresso/docs/layout/head.html create mode 100644 node_modules/express/node_modules/qs/support/expresso/lib/bar.js create mode 100644 node_modules/express/node_modules/qs/support/expresso/lib/foo.js create mode 100644 node_modules/express/node_modules/qs/support/expresso/package.json create mode 100644 node_modules/express/node_modules/qs/support/expresso/test/assert.test.js create mode 100644 node_modules/express/node_modules/qs/support/expresso/test/async.test.js create mode 100644 node_modules/express/node_modules/qs/support/expresso/test/bar.test.js create mode 100644 node_modules/express/node_modules/qs/support/expresso/test/foo.test.js create mode 100644 node_modules/express/node_modules/qs/support/expresso/test/http.test.js create mode 100644 node_modules/express/node_modules/qs/support/expresso/test/serial/async.test.js create mode 100644 node_modules/express/node_modules/qs/support/expresso/test/serial/http.test.js create mode 100644 node_modules/express/node_modules/qs/support/should/History.md create mode 100644 node_modules/express/node_modules/qs/support/should/Makefile create mode 100644 node_modules/express/node_modules/qs/support/should/Readme.md create mode 100644 node_modules/express/node_modules/qs/support/should/examples/runner.js create mode 100644 node_modules/express/node_modules/qs/support/should/index.js create mode 100644 node_modules/express/node_modules/qs/support/should/lib/eql.js create mode 100644 node_modules/express/node_modules/qs/support/should/lib/should.js create mode 100644 node_modules/express/node_modules/qs/support/should/package.json create mode 100644 node_modules/express/node_modules/qs/support/should/test/should.test.js create mode 100644 node_modules/express/node_modules/qs/test/parse.test.js create mode 100644 node_modules/express/node_modules/qs/test/stringify.test.js create mode 100644 node_modules/express/package.json create mode 100644 node_modules/hat/README.markdown create mode 100644 node_modules/hat/example/hat.js create mode 100644 node_modules/hat/example/rack.js create mode 100644 node_modules/hat/index.js create mode 100644 node_modules/hat/package.json create mode 100644 node_modules/hat/test/id.js create mode 100644 node_modules/hat/test/rack.js create mode 100644 node_modules/hooks/.npmignore create mode 100644 node_modules/hooks/Makefile create mode 100644 node_modules/hooks/README.md create mode 100644 node_modules/hooks/hooks.alt.js create mode 100644 node_modules/hooks/hooks.js create mode 100644 node_modules/hooks/package.json create mode 100644 node_modules/hooks/test.js create mode 100644 node_modules/jade/.npmignore create mode 100644 node_modules/jade/History.md create mode 100644 node_modules/jade/LICENSE create mode 100644 node_modules/jade/Makefile create mode 100644 node_modules/jade/Readme.md create mode 100644 node_modules/jade/benchmarks/common.js create mode 100644 node_modules/jade/benchmarks/ejs.js create mode 100644 node_modules/jade/benchmarks/ejs/History.md create mode 100644 node_modules/jade/benchmarks/ejs/Makefile create mode 100644 node_modules/jade/benchmarks/ejs/Readme.md create mode 100644 node_modules/jade/benchmarks/ejs/benchmark.js create mode 100644 node_modules/jade/benchmarks/ejs/examples/list.ejs create mode 100644 node_modules/jade/benchmarks/ejs/examples/list.js create mode 100644 node_modules/jade/benchmarks/ejs/index.js create mode 100644 node_modules/jade/benchmarks/ejs/lib/ejs.js create mode 100644 node_modules/jade/benchmarks/ejs/lib/filters.js create mode 100644 node_modules/jade/benchmarks/ejs/lib/utils.js create mode 100644 node_modules/jade/benchmarks/ejs/package.json create mode 100644 node_modules/jade/benchmarks/ejs/test/ejs.test.js create mode 100644 node_modules/jade/benchmarks/example-self.jade create mode 100644 node_modules/jade/benchmarks/example.ejs create mode 100644 node_modules/jade/benchmarks/example.haml create mode 100644 node_modules/jade/benchmarks/example.jade create mode 100644 node_modules/jade/benchmarks/example2.haml create mode 100644 node_modules/jade/benchmarks/haml-js/CHANGELOG.markdown create mode 100644 node_modules/jade/benchmarks/haml-js/LICENSE create mode 100644 node_modules/jade/benchmarks/haml-js/README.markdown create mode 100755 node_modules/jade/benchmarks/haml-js/lib/haml.js create mode 100644 node_modules/jade/benchmarks/haml-js/package.json create mode 100644 node_modules/jade/benchmarks/haml-js/test/alt_attribs.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/alt_attribs.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/div_nesting.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/div_nesting.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/doctype.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/doctype.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/embedded_code.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/embedded_code.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/embedded_code.js create mode 100644 node_modules/jade/benchmarks/haml-js/test/foreach.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/foreach.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/foreach.js create mode 100644 node_modules/jade/benchmarks/haml-js/test/meta.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/meta.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/nanline.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/nanline.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/nested_context.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/nested_context.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/nested_context.js create mode 100644 node_modules/jade/benchmarks/haml-js/test/no_self_close_div.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/no_self_close_div.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/non-string-attribs.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/non-string-attribs.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/script_css.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/script_css.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/self_close.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/self_close.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/self_close.js create mode 100644 node_modules/jade/benchmarks/haml-js/test/standard.haml create mode 100644 node_modules/jade/benchmarks/haml-js/test/standard.html create mode 100644 node_modules/jade/benchmarks/haml-js/test/standard.js create mode 100644 node_modules/jade/benchmarks/haml-js/test/test-commonjs.js create mode 100644 node_modules/jade/benchmarks/haml-js/test/test.js create mode 100644 node_modules/jade/benchmarks/haml.js create mode 100644 node_modules/jade/benchmarks/haml/.ignore create mode 100644 node_modules/jade/benchmarks/haml/History.md create mode 100644 node_modules/jade/benchmarks/haml/Makefile create mode 100644 node_modules/jade/benchmarks/haml/Readme.md create mode 100644 node_modules/jade/benchmarks/haml/benchmarks/page.haml create mode 100644 node_modules/jade/benchmarks/haml/benchmarks/run.js create mode 100644 node_modules/jade/benchmarks/haml/examples/example.js create mode 100644 node_modules/jade/benchmarks/haml/examples/page.haml create mode 120000 node_modules/jade/benchmarks/haml/index.js create mode 100644 node_modules/jade/benchmarks/haml/lib/haml.js create mode 100644 node_modules/jade/benchmarks/haml/package.json create mode 100644 node_modules/jade/benchmarks/haml/seed.yml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/class.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/class.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/classes.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/classes.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.each.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.each.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.each.index.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.each.index.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.each.non-enumerable.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.each.non-enumerable.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.escape.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.escape.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.if.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.if.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.nested.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/code.nested.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.conditional.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.conditional.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.block.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.tag.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.tag.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.complex.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.complex.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/comment.text.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/context.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/context.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/cr.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/cr.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/crlf.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/crlf.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/doctype.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/doctype.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.case.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.case.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/doctype.xml.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/error.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/escape.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/escape.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/feed.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/feed.xml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.whitespace.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/filter.cdata.whitespace.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/filter.javascript.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/filter.javascript.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/filter.plain.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/filter.plain.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/html.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/html.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/id.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/id.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/issue.#10.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/issue.#10.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/issue.#8.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/issue.#8.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/literals.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/literals.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/namespace.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/namespace.tag.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/namespace.tag.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/namespace.xml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/nesting.complex.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/nesting.complex.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/nesting.simple.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/nesting.simple.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/newlines.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/newlines.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.bools.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.bools.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.escape.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.escape.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.attrs.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.class.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.class.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.classes.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.classes.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.no-escape.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.code.no-escape.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.complex.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.complex.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.empty.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.empty.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.escape.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.escape.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.self-close.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.self-close.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.simple.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.simple.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.complex.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.complex.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.block.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/tag.text.html create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/trailing-indent.haml create mode 100644 node_modules/jade/benchmarks/haml/spec/fixtures/trailing-indent.html create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/images/bg.png create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/images/hr.png create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/images/loading.gif create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/images/sprites.bg.png create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/images/sprites.png create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/images/vr.png create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/jspec.css create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/jspec.growl.js create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/jspec.jquery.js create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/jspec.js create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/jspec.nodejs.js create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/jspec.shell.js create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/jspec.timers.js create mode 100644 node_modules/jade/benchmarks/haml/spec/lib/jspec.xhr.js create mode 100644 node_modules/jade/benchmarks/haml/spec/node.js create mode 100644 node_modules/jade/benchmarks/haml/spec/unit/spec.helper.js create mode 100644 node_modules/jade/benchmarks/haml/spec/unit/spec.js create mode 100644 node_modules/jade/benchmarks/haml2.js create mode 100644 node_modules/jade/benchmarks/jade-self.js create mode 100644 node_modules/jade/benchmarks/jade.js create mode 100755 node_modules/jade/bin/jade create mode 100644 node_modules/jade/examples/attributes.jade create mode 100644 node_modules/jade/examples/attributes.js create mode 100644 node_modules/jade/examples/code.jade create mode 100644 node_modules/jade/examples/code.js create mode 100644 node_modules/jade/examples/conditionals.jade create mode 100644 node_modules/jade/examples/conditionals.js create mode 100644 node_modules/jade/examples/csrf.jade create mode 100644 node_modules/jade/examples/csrf.js create mode 100644 node_modules/jade/examples/dynamicscript.jade create mode 100644 node_modules/jade/examples/dynamicscript.js create mode 100644 node_modules/jade/examples/each.jade create mode 100644 node_modules/jade/examples/each.js create mode 100644 node_modules/jade/examples/form.jade create mode 100644 node_modules/jade/examples/form.js create mode 100644 node_modules/jade/examples/includes.jade create mode 100644 node_modules/jade/examples/includes.js create mode 100644 node_modules/jade/examples/includes/foot.jade create mode 100644 node_modules/jade/examples/includes/head.jade create mode 100644 node_modules/jade/examples/layout-debug.js create mode 100644 node_modules/jade/examples/layout.jade create mode 100644 node_modules/jade/examples/layout.js create mode 100644 node_modules/jade/examples/mixins.jade create mode 100644 node_modules/jade/examples/mixins.js create mode 100644 node_modules/jade/examples/mixins/dialog.jade create mode 100644 node_modules/jade/examples/mixins/profile.jade create mode 100644 node_modules/jade/examples/model.jade create mode 100644 node_modules/jade/examples/model.js create mode 100644 node_modules/jade/examples/nested-filters.jade create mode 100644 node_modules/jade/examples/nested-filters.js create mode 100644 node_modules/jade/examples/rss.jade create mode 100644 node_modules/jade/examples/rss.js create mode 100644 node_modules/jade/examples/text.jade create mode 100644 node_modules/jade/examples/text.js create mode 100644 node_modules/jade/examples/whitespace.jade create mode 100644 node_modules/jade/examples/whitespace.js create mode 100644 node_modules/jade/index.js create mode 100644 node_modules/jade/jade.js create mode 100644 node_modules/jade/jade.min.js create mode 100644 node_modules/jade/lib/compiler.js create mode 100644 node_modules/jade/lib/doctypes.js create mode 100644 node_modules/jade/lib/filters.js create mode 120000 node_modules/jade/lib/index.js create mode 100644 node_modules/jade/lib/inline-tags.js create mode 100644 node_modules/jade/lib/jade.js create mode 100644 node_modules/jade/lib/lexer.js create mode 100644 node_modules/jade/lib/nodes/block-comment.js create mode 100644 node_modules/jade/lib/nodes/block.js create mode 100644 node_modules/jade/lib/nodes/code.js create mode 100644 node_modules/jade/lib/nodes/comment.js create mode 100644 node_modules/jade/lib/nodes/doctype.js create mode 100644 node_modules/jade/lib/nodes/each.js create mode 100644 node_modules/jade/lib/nodes/filter.js create mode 100644 node_modules/jade/lib/nodes/index.js create mode 100644 node_modules/jade/lib/nodes/mixin.js create mode 100644 node_modules/jade/lib/nodes/node.js create mode 100644 node_modules/jade/lib/nodes/tag.js create mode 100644 node_modules/jade/lib/nodes/text.js create mode 100644 node_modules/jade/lib/parser.js create mode 100644 node_modules/jade/lib/self-closing.js create mode 100644 node_modules/jade/lib/utils.js create mode 100644 node_modules/jade/package.json create mode 100644 node_modules/jade/support/coffee-script/Cakefile create mode 100644 node_modules/jade/support/coffee-script/LICENSE create mode 100644 node_modules/jade/support/coffee-script/README create mode 100644 node_modules/jade/support/coffee-script/Rakefile create mode 100755 node_modules/jade/support/coffee-script/bin/cake create mode 100755 node_modules/jade/support/coffee-script/bin/coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/aliases.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/array_comprehensions.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/block_comment.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/cake_tasks.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/classes.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/comparisons.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/conditionals.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/embedded.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/existence.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/expressions.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/expressions_assignment.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/expressions_comprehension.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/expressions_try.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/fat_arrow.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/functions.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/heredocs.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/interpolation.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/interpolation_expression.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/multiple_return_values.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/object_comprehensions.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/object_extraction.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/objects_and_arrays.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/objects_reserved.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/overview.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/parallel_assignment.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/patterns_and_splats.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/prototypes.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/range_comprehensions.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/scope.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/slices.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/soaks.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/splats.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/splices.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/strings.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/switch.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/try.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/coffee/while.coffee create mode 100644 node_modules/jade/support/coffee-script/documentation/css/docs.css create mode 100644 node_modules/jade/support/coffee-script/documentation/css/idle.css create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/browser.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/cake.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/coffee-script.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/command.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/docco.css create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/grammar.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/helpers.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/index.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/lexer.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/nodes.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/optparse.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/repl.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/rewriter.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/scope.html create mode 100644 node_modules/jade/support/coffee-script/documentation/docs/underscore.html create mode 100644 node_modules/jade/support/coffee-script/documentation/images/favicon.ico create mode 100644 node_modules/jade/support/coffee-script/documentation/images/logo.png create mode 100644 node_modules/jade/support/coffee-script/documentation/index.html.erb create mode 100644 node_modules/jade/support/coffee-script/documentation/js/aliases.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/array_comprehensions.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/block_comment.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/cake_tasks.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/classes.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/comparisons.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/conditionals.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/embedded.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/existence.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/expressions.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/expressions_assignment.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/expressions_comprehension.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/expressions_try.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/fat_arrow.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/functions.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/heredocs.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/interpolation.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/interpolation_expression.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/multiple_return_values.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/object_comprehensions.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/object_extraction.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/objects_and_arrays.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/objects_reserved.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/overview.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/parallel_assignment.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/patterns_and_splats.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/prototypes.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/range_comprehensions.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/scope.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/slices.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/soaks.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/splats.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/splices.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/strings.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/switch.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/try.js create mode 100644 node_modules/jade/support/coffee-script/documentation/js/while.js create mode 100644 node_modules/jade/support/coffee-script/examples/beautiful_code/binary_search.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/beautiful_code/quicksort_runtime.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/beautiful_code/regular_expression_matcher.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/blocks.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/code.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/computer_science/README create mode 100644 node_modules/jade/support/coffee-script/examples/computer_science/binary_search.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/computer_science/bubble_sort.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/computer_science/linked_list.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/computer_science/luhn_algorithm.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/computer_science/merge_sort.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/computer_science/selection_sort.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/poignant.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/potion.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/underscore.coffee create mode 100644 node_modules/jade/support/coffee-script/examples/web_server.coffee create mode 100644 node_modules/jade/support/coffee-script/extras/EXTRAS create mode 100644 node_modules/jade/support/coffee-script/extras/coffee-script.js create mode 100644 node_modules/jade/support/coffee-script/extras/jsl.conf create mode 100644 node_modules/jade/support/coffee-script/index.html create mode 100644 node_modules/jade/support/coffee-script/lib/browser.js create mode 100755 node_modules/jade/support/coffee-script/lib/cake.js create mode 100755 node_modules/jade/support/coffee-script/lib/coffee-script.js create mode 100644 node_modules/jade/support/coffee-script/lib/command.js create mode 100644 node_modules/jade/support/coffee-script/lib/grammar.js create mode 100644 node_modules/jade/support/coffee-script/lib/helpers.js create mode 100644 node_modules/jade/support/coffee-script/lib/index.js create mode 100644 node_modules/jade/support/coffee-script/lib/lexer.js create mode 100644 node_modules/jade/support/coffee-script/lib/nodes.js create mode 100755 node_modules/jade/support/coffee-script/lib/optparse.js create mode 100755 node_modules/jade/support/coffee-script/lib/parser.js create mode 100644 node_modules/jade/support/coffee-script/lib/repl.js create mode 100644 node_modules/jade/support/coffee-script/lib/rewriter.js create mode 100644 node_modules/jade/support/coffee-script/lib/scope.js create mode 100644 node_modules/jade/support/coffee-script/lib/utilities.js create mode 100644 node_modules/jade/support/coffee-script/package.json create mode 100644 node_modules/jade/support/coffee-script/src/browser.coffee create mode 100644 node_modules/jade/support/coffee-script/src/cake.coffee create mode 100755 node_modules/jade/support/coffee-script/src/coffee-script.coffee create mode 100644 node_modules/jade/support/coffee-script/src/command.coffee create mode 100644 node_modules/jade/support/coffee-script/src/grammar.coffee create mode 100644 node_modules/jade/support/coffee-script/src/helpers.coffee create mode 100644 node_modules/jade/support/coffee-script/src/index.coffee create mode 100644 node_modules/jade/support/coffee-script/src/lexer.coffee create mode 100644 node_modules/jade/support/coffee-script/src/nodes.coffee create mode 100644 node_modules/jade/support/coffee-script/src/optparse.coffee create mode 100644 node_modules/jade/support/coffee-script/src/repl.coffee create mode 100644 node_modules/jade/support/coffee-script/src/rewriter.coffee create mode 100644 node_modules/jade/support/coffee-script/src/scope.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test.html create mode 100644 node_modules/jade/support/coffee-script/test/test_arguments.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_assignment.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_break.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_chaining.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_classes.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_comments.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_compilation.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_compound_assignment.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_comprehensions.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_existence.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_expressions.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_functions.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_helpers.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_heredocs.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_if.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_importing.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_literals.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_module.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_operations.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_option_parser.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_pattern_matching.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_ranges_slices_and_splices.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_regexps.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_returns.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_splats.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_strings.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_switch.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_try_catch.coffee create mode 100644 node_modules/jade/support/coffee-script/test/test_while.coffee create mode 100644 node_modules/jade/support/compile.js create mode 100644 node_modules/jade/support/expresso/History.md create mode 100644 node_modules/jade/support/expresso/Makefile create mode 100644 node_modules/jade/support/expresso/Readme.md create mode 100755 node_modules/jade/support/expresso/bin/expresso create mode 100644 node_modules/jade/support/expresso/docs/api.html create mode 100644 node_modules/jade/support/expresso/docs/index.html create mode 100644 node_modules/jade/support/expresso/docs/index.md create mode 100644 node_modules/jade/support/expresso/docs/layout/foot.html create mode 100644 node_modules/jade/support/expresso/docs/layout/head.html create mode 100644 node_modules/jade/support/expresso/lib/bar.js create mode 100644 node_modules/jade/support/expresso/lib/foo.js create mode 100644 node_modules/jade/support/expresso/package.json create mode 100644 node_modules/jade/support/expresso/test/assert.test.js create mode 100644 node_modules/jade/support/expresso/test/async.test.js create mode 100644 node_modules/jade/support/expresso/test/bar.test.js create mode 100644 node_modules/jade/support/expresso/test/foo.test.js create mode 100644 node_modules/jade/support/expresso/test/http.test.js create mode 100644 node_modules/jade/support/expresso/test/serial/async.test.js create mode 100644 node_modules/jade/support/expresso/test/serial/http.test.js create mode 100644 node_modules/jade/support/sass/History.md create mode 100644 node_modules/jade/support/sass/Makefile create mode 100644 node_modules/jade/support/sass/Readme.md create mode 120000 node_modules/jade/support/sass/index.js create mode 100644 node_modules/jade/support/sass/lib/sass.js create mode 100644 node_modules/jade/support/sass/package.json create mode 100644 node_modules/jade/support/sass/seed.yml create mode 100644 node_modules/jade/support/sass/spec/fixtures/collect.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/comment.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/comment.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/continuation.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/continuation.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/literal.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/literal.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/mixin.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/mixin.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/mixin.undefined.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/properties.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/properties.expand.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/properties.expand.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/properties.invalid.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/properties.nested.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/properties.nested.invalid.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/properties.nested.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/properties.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/selectors.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/selectors.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/variables.alternate.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/variables.alternate.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/variables.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/variables.regular.css create mode 100644 node_modules/jade/support/sass/spec/fixtures/variables.regular.sass create mode 100644 node_modules/jade/support/sass/spec/fixtures/variables.sass create mode 100644 node_modules/jade/support/sass/spec/lib/images/bg.png create mode 100644 node_modules/jade/support/sass/spec/lib/images/hr.png create mode 100644 node_modules/jade/support/sass/spec/lib/images/loading.gif create mode 100644 node_modules/jade/support/sass/spec/lib/images/sprites.bg.png create mode 100644 node_modules/jade/support/sass/spec/lib/images/sprites.png create mode 100644 node_modules/jade/support/sass/spec/lib/images/vr.png create mode 100644 node_modules/jade/support/sass/spec/lib/jspec.css create mode 100644 node_modules/jade/support/sass/spec/lib/jspec.growl.js create mode 100644 node_modules/jade/support/sass/spec/lib/jspec.jquery.js create mode 100644 node_modules/jade/support/sass/spec/lib/jspec.js create mode 100644 node_modules/jade/support/sass/spec/lib/jspec.nodejs.js create mode 100644 node_modules/jade/support/sass/spec/lib/jspec.shell.js create mode 100644 node_modules/jade/support/sass/spec/lib/jspec.timers.js create mode 100644 node_modules/jade/support/sass/spec/lib/jspec.xhr.js create mode 100644 node_modules/jade/support/sass/spec/node.js create mode 100644 node_modules/jade/support/sass/spec/spec.core.js create mode 100644 node_modules/jade/support/stylus/.npmignore create mode 100644 node_modules/jade/support/stylus/History.md create mode 100644 node_modules/jade/support/stylus/LICENSE create mode 100644 node_modules/jade/support/stylus/Makefile create mode 100644 node_modules/jade/support/stylus/Readme.md create mode 100755 node_modules/jade/support/stylus/bin/stylus create mode 100755 node_modules/jade/support/stylus/bin/stylus-tutorial create mode 100644 node_modules/jade/support/stylus/bm.js create mode 100644 node_modules/jade/support/stylus/docs/bifs.md create mode 100644 node_modules/jade/support/stylus/docs/comments.md create mode 100644 node_modules/jade/support/stylus/docs/compare.md create mode 100644 node_modules/jade/support/stylus/docs/conditionals.md create mode 100644 node_modules/jade/support/stylus/docs/css-style.md create mode 100644 node_modules/jade/support/stylus/docs/error-reporting.md create mode 100644 node_modules/jade/support/stylus/docs/escape.md create mode 100644 node_modules/jade/support/stylus/docs/executable.md create mode 100644 node_modules/jade/support/stylus/docs/font-face.md create mode 100644 node_modules/jade/support/stylus/docs/functions.md create mode 100644 node_modules/jade/support/stylus/docs/functions.url.md create mode 100644 node_modules/jade/support/stylus/docs/import.md create mode 100644 node_modules/jade/support/stylus/docs/interpolation.md create mode 100644 node_modules/jade/support/stylus/docs/introspection.md create mode 100644 node_modules/jade/support/stylus/docs/iteration.md create mode 100644 node_modules/jade/support/stylus/docs/js.md create mode 100644 node_modules/jade/support/stylus/docs/keyframes.md create mode 100644 node_modules/jade/support/stylus/docs/literal.md create mode 100644 node_modules/jade/support/stylus/docs/media.md create mode 100644 node_modules/jade/support/stylus/docs/middleware.md create mode 100644 node_modules/jade/support/stylus/docs/mixins.md create mode 100644 node_modules/jade/support/stylus/docs/operators.md create mode 100644 node_modules/jade/support/stylus/docs/selectors.md create mode 100644 node_modules/jade/support/stylus/docs/textmate.md create mode 100644 node_modules/jade/support/stylus/docs/vargs.md create mode 100644 node_modules/jade/support/stylus/docs/variables.md create mode 100644 node_modules/jade/support/stylus/editors/Stylus.tmbundle/Syntaxes/Stylus.tmLanguage create mode 100644 node_modules/jade/support/stylus/editors/Stylus.tmbundle/info.plist create mode 100644 node_modules/jade/support/stylus/examples/arithmetic.js create mode 100644 node_modules/jade/support/stylus/examples/arithmetic.styl create mode 100644 node_modules/jade/support/stylus/examples/basic.js create mode 100644 node_modules/jade/support/stylus/examples/basic.styl create mode 100644 node_modules/jade/support/stylus/examples/builtins.js create mode 100644 node_modules/jade/support/stylus/examples/builtins.styl create mode 100644 node_modules/jade/support/stylus/examples/comments.js create mode 100644 node_modules/jade/support/stylus/examples/comments.styl create mode 100644 node_modules/jade/support/stylus/examples/compress.js create mode 100644 node_modules/jade/support/stylus/examples/conversions.js create mode 100644 node_modules/jade/support/stylus/examples/conversions.styl create mode 100644 node_modules/jade/support/stylus/examples/functions.js create mode 100644 node_modules/jade/support/stylus/examples/functions.styl create mode 100644 node_modules/jade/support/stylus/examples/images.js create mode 100644 node_modules/jade/support/stylus/examples/images.styl create mode 100644 node_modules/jade/support/stylus/examples/images/gopher.jpg create mode 100644 node_modules/jade/support/stylus/examples/images/jesus.gif create mode 100644 node_modules/jade/support/stylus/examples/images/sprite.gif create mode 100644 node_modules/jade/support/stylus/examples/implicit-functions.js create mode 100644 node_modules/jade/support/stylus/examples/implicit-functions.styl create mode 100644 node_modules/jade/support/stylus/examples/import.js create mode 100644 node_modules/jade/support/stylus/examples/import.styl create mode 100644 node_modules/jade/support/stylus/examples/js-functions.js create mode 100644 node_modules/jade/support/stylus/examples/js-functions.styl create mode 100644 node_modules/jade/support/stylus/examples/literal.js create mode 100644 node_modules/jade/support/stylus/examples/literal.styl create mode 100644 node_modules/jade/support/stylus/examples/middleware.js create mode 100644 node_modules/jade/support/stylus/examples/mixins/box.styl create mode 100644 node_modules/jade/support/stylus/examples/nesting.js create mode 100644 node_modules/jade/support/stylus/examples/nesting.styl create mode 100644 node_modules/jade/support/stylus/examples/variables.js create mode 100644 node_modules/jade/support/stylus/examples/variables.styl create mode 100644 node_modules/jade/support/stylus/index.js create mode 100644 node_modules/jade/support/stylus/lib/colors.js create mode 100644 node_modules/jade/support/stylus/lib/convert/css.js create mode 100644 node_modules/jade/support/stylus/lib/functions/image.js create mode 100644 node_modules/jade/support/stylus/lib/functions/index.js create mode 100644 node_modules/jade/support/stylus/lib/functions/index.styl create mode 100644 node_modules/jade/support/stylus/lib/functions/url.js create mode 100644 node_modules/jade/support/stylus/lib/lexer.js create mode 100644 node_modules/jade/support/stylus/lib/middleware.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/binop.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/block.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/boolean.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/call.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/charset.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/each.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/expression.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/function.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/group.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/hsla.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/ident.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/if.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/import.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/index.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/keyframes.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/literal.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/media.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/node.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/null.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/page.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/params.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/property.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/return.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/rgba.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/root.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/selector.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/string.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/ternary.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/unaryop.js create mode 100644 node_modules/jade/support/stylus/lib/nodes/unit.js create mode 100644 node_modules/jade/support/stylus/lib/parser.js create mode 100644 node_modules/jade/support/stylus/lib/renderer.js create mode 100644 node_modules/jade/support/stylus/lib/stack/frame.js create mode 100644 node_modules/jade/support/stylus/lib/stack/index.js create mode 100644 node_modules/jade/support/stylus/lib/stack/scope.js create mode 100644 node_modules/jade/support/stylus/lib/stylus.js create mode 100644 node_modules/jade/support/stylus/lib/token.js create mode 100644 node_modules/jade/support/stylus/lib/utils.js create mode 100644 node_modules/jade/support/stylus/lib/visitor/compiler.js create mode 100644 node_modules/jade/support/stylus/lib/visitor/evaluator.js create mode 100644 node_modules/jade/support/stylus/lib/visitor/index.js create mode 100644 node_modules/jade/support/stylus/package.json create mode 100644 node_modules/jade/support/stylus/test/cases/arithmetic.color.css create mode 100644 node_modules/jade/support/stylus/test/cases/arithmetic.color.styl create mode 100644 node_modules/jade/support/stylus/test/cases/arithmetic.css create mode 100644 node_modules/jade/support/stylus/test/cases/arithmetic.styl create mode 100644 node_modules/jade/support/stylus/test/cases/arithmetic.unary.css create mode 100644 node_modules/jade/support/stylus/test/cases/arithmetic.unary.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.components.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.components.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.dark.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.dark.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.darken-by.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.darken-by.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.image-size.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.image-size.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.join.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.join.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.last.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.last.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.length.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.length.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.light.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.light.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.lighten-by.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.lighten-by.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.lookup.complex.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.lookup.complex.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.lookup.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.lookup.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.match.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.match.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.opposite-position.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.opposite-position.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.rgba.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.rgba.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.type.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.type.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.unit.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.unit.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.unquote.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.unquote.styl create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.url.css create mode 100644 node_modules/jade/support/stylus/test/cases/bifs.url.styl create mode 100644 node_modules/jade/support/stylus/test/cases/coercion.css create mode 100644 node_modules/jade/support/stylus/test/cases/coercion.styl create mode 100644 node_modules/jade/support/stylus/test/cases/comments.css create mode 100644 node_modules/jade/support/stylus/test/cases/comments.styl create mode 100644 node_modules/jade/support/stylus/test/cases/compress.units.css create mode 100644 node_modules/jade/support/stylus/test/cases/compress.units.styl create mode 100644 node_modules/jade/support/stylus/test/cases/conditional-assignment.css create mode 100644 node_modules/jade/support/stylus/test/cases/conditional-assignment.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.functions.single-line.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.functions.single-line.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.if.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.if.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.keyframes.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.keyframes.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.large.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.large.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.media.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.media.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.mixins.braces.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.mixins.braces.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.mixins.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.mixins.root.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.mixins.root.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.mixins.root.wonky.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.mixins.root.wonky.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.mixins.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.selectors.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.selectors.styl create mode 100644 node_modules/jade/support/stylus/test/cases/css.whitespace.css create mode 100644 node_modules/jade/support/stylus/test/cases/css.whitespace.styl create mode 100644 node_modules/jade/support/stylus/test/cases/escape.css create mode 100644 node_modules/jade/support/stylus/test/cases/escape.styl create mode 100644 node_modules/jade/support/stylus/test/cases/for.complex.css create mode 100644 node_modules/jade/support/stylus/test/cases/for.complex.styl create mode 100644 node_modules/jade/support/stylus/test/cases/for.css create mode 100644 node_modules/jade/support/stylus/test/cases/for.function.css create mode 100644 node_modules/jade/support/stylus/test/cases/for.function.styl create mode 100644 node_modules/jade/support/stylus/test/cases/for.styl create mode 100644 node_modules/jade/support/stylus/test/cases/function.arguments.css create mode 100644 node_modules/jade/support/stylus/test/cases/function.arguments.styl create mode 100644 node_modules/jade/support/stylus/test/cases/function.literals.css create mode 100644 node_modules/jade/support/stylus/test/cases/function.literals.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.arg-calls.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.arg-calls.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.call.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.call.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.defaults.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.defaults.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.multi-line.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.multi-line.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.multiple-calls.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.multiple-calls.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.nested-calls.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.nested-calls.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.nested.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.nested.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.property.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.property.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.return.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.return.each.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.return.each.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.return.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.variable.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.variable.ident.css create mode 100644 node_modules/jade/support/stylus/test/cases/functions.variable.ident.styl create mode 100644 node_modules/jade/support/stylus/test/cases/functions.variable.styl create mode 100644 node_modules/jade/support/stylus/test/cases/if.css create mode 100644 node_modules/jade/support/stylus/test/cases/if.else.css create mode 100644 node_modules/jade/support/stylus/test/cases/if.else.styl create mode 100644 node_modules/jade/support/stylus/test/cases/if.mixin.css create mode 100644 node_modules/jade/support/stylus/test/cases/if.mixin.styl create mode 100644 node_modules/jade/support/stylus/test/cases/if.postfix.css create mode 100644 node_modules/jade/support/stylus/test/cases/if.postfix.styl create mode 100644 node_modules/jade/support/stylus/test/cases/if.selectors.css create mode 100644 node_modules/jade/support/stylus/test/cases/if.selectors.styl create mode 100644 node_modules/jade/support/stylus/test/cases/if.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.basic.css create mode 100644 node_modules/jade/support/stylus/test/cases/import.basic.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.basic/a.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.basic/b.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.basic/c.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.complex.css create mode 100644 node_modules/jade/support/stylus/test/cases/import.complex.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.complex/a.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.complex/c.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.complex/nested/b.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.index.css create mode 100644 node_modules/jade/support/stylus/test/cases/import.index.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.index/vendor/a.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.index/vendor/b.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.index/vendor/c.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.index/vendor/index.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.literal.css create mode 100644 node_modules/jade/support/stylus/test/cases/import.literal.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.mixins.css create mode 100644 node_modules/jade/support/stylus/test/cases/import.mixins.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.ordering.css create mode 100644 node_modules/jade/support/stylus/test/cases/import.ordering.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.ordering/five.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.ordering/four.styl create mode 100644 node_modules/jade/support/stylus/test/cases/import.ordering/two.styl create mode 100644 node_modules/jade/support/stylus/test/cases/important.css create mode 100644 node_modules/jade/support/stylus/test/cases/important.styl create mode 100644 node_modules/jade/support/stylus/test/cases/interpolation.properties.css create mode 100644 node_modules/jade/support/stylus/test/cases/interpolation.properties.styl create mode 100644 node_modules/jade/support/stylus/test/cases/introspection.css create mode 100644 node_modules/jade/support/stylus/test/cases/introspection.styl create mode 100644 node_modules/jade/support/stylus/test/cases/jquery.css create mode 100644 node_modules/jade/support/stylus/test/cases/jquery.styl create mode 100644 node_modules/jade/support/stylus/test/cases/list.css create mode 100644 node_modules/jade/support/stylus/test/cases/list.styl create mode 100644 node_modules/jade/support/stylus/test/cases/literal.css create mode 100644 node_modules/jade/support/stylus/test/cases/literal.styl create mode 100644 node_modules/jade/support/stylus/test/cases/media.css create mode 100644 node_modules/jade/support/stylus/test/cases/media.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixin.conditional.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixin.conditional.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixin.order.conditional.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixin.order.conditional.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixin.order.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixin.order.nested.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixin.order.nested.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixin.order.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.complex.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.complex.fix-to.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.complex.fix-to.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.complex.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.conditional.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.conditional.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.nested.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.nested.selectors.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.nested.selectors.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.nested.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.order.2.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.order.2.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.return.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.return.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.root.css create mode 100644 node_modules/jade/support/stylus/test/cases/mixins.root.styl create mode 100644 node_modules/jade/support/stylus/test/cases/mixins/box.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operator.range.css create mode 100644 node_modules/jade/support/stylus/test/cases/operator.range.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.assignment.function.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.assignment.function.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.assignment.mixin.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.assignment.mixin.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.assignment.root.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.assignment.root.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.complex.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.complex.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.equality.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.equality.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.in.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.in.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.mixins.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.mixins.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.precedence.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.precedence.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.subscript.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.subscript.range.css create mode 100644 node_modules/jade/support/stylus/test/cases/operators.subscript.range.styl create mode 100644 node_modules/jade/support/stylus/test/cases/operators.subscript.styl create mode 100644 node_modules/jade/support/stylus/test/cases/page.css create mode 100644 node_modules/jade/support/stylus/test/cases/page.styl create mode 100644 node_modules/jade/support/stylus/test/cases/parent.css create mode 100644 node_modules/jade/support/stylus/test/cases/parent.styl create mode 100644 node_modules/jade/support/stylus/test/cases/properties.colons.css create mode 100644 node_modules/jade/support/stylus/test/cases/properties.colons.styl create mode 100644 node_modules/jade/support/stylus/test/cases/properties.css create mode 100644 node_modules/jade/support/stylus/test/cases/properties.one-line.css create mode 100644 node_modules/jade/support/stylus/test/cases/properties.one-line.styl create mode 100644 node_modules/jade/support/stylus/test/cases/properties.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.107.lookup-failure.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.107.lookup-failure.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.127.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.127.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.130.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.130.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.131.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.131.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.137.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.137.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.139.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.139.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.142.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.142.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.146.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.146.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.153.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.153.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.154.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.154.styl create mode 100644 node_modules/jade/support/stylus/test/cases/regression.156.css create mode 100644 node_modules/jade/support/stylus/test/cases/regression.156.styl create mode 100644 node_modules/jade/support/stylus/test/cases/rule.charset.css create mode 100644 node_modules/jade/support/stylus/test/cases/rule.charset.styl create mode 100644 node_modules/jade/support/stylus/test/cases/rulset.css create mode 100644 node_modules/jade/support/stylus/test/cases/rulset.newline.css create mode 100644 node_modules/jade/support/stylus/test/cases/rulset.newline.styl create mode 100644 node_modules/jade/support/stylus/test/cases/rulset.styl create mode 100644 node_modules/jade/support/stylus/test/cases/scope.complex.css create mode 100644 node_modules/jade/support/stylus/test/cases/scope.complex.styl create mode 100644 node_modules/jade/support/stylus/test/cases/scope.css create mode 100644 node_modules/jade/support/stylus/test/cases/scope.nested.css create mode 100644 node_modules/jade/support/stylus/test/cases/scope.nested.styl create mode 100644 node_modules/jade/support/stylus/test/cases/scope.styl create mode 100644 node_modules/jade/support/stylus/test/cases/selectors.complex.css create mode 100644 node_modules/jade/support/stylus/test/cases/selectors.complex.styl create mode 100644 node_modules/jade/support/stylus/test/cases/selectors.css create mode 100644 node_modules/jade/support/stylus/test/cases/selectors.nested.comma.css create mode 100644 node_modules/jade/support/stylus/test/cases/selectors.nested.comma.styl create mode 100644 node_modules/jade/support/stylus/test/cases/selectors.nested.css create mode 100644 node_modules/jade/support/stylus/test/cases/selectors.nested.styl create mode 100644 node_modules/jade/support/stylus/test/cases/selectors.pseudo.css create mode 100644 node_modules/jade/support/stylus/test/cases/selectors.pseudo.styl create mode 100644 node_modules/jade/support/stylus/test/cases/selectors.styl create mode 100644 node_modules/jade/support/stylus/test/cases/self-assignment.css create mode 100644 node_modules/jade/support/stylus/test/cases/self-assignment.styl create mode 100644 node_modules/jade/support/stylus/test/cases/vargs.call.css create mode 100644 node_modules/jade/support/stylus/test/cases/vargs.call.styl create mode 100644 node_modules/jade/support/stylus/test/cases/vargs.css create mode 100644 node_modules/jade/support/stylus/test/cases/vargs.styl create mode 100644 node_modules/jade/support/stylus/test/cases/variable.css create mode 100644 node_modules/jade/support/stylus/test/cases/variable.styl create mode 100644 node_modules/jade/support/stylus/test/cases/variables.css create mode 100644 node_modules/jade/support/stylus/test/cases/variables.styl create mode 100644 node_modules/jade/support/stylus/test/images/gif create mode 100644 node_modules/jade/support/stylus/test/images/squirrel.jpeg create mode 100644 node_modules/jade/support/stylus/test/images/tux.png create mode 100644 node_modules/jade/support/stylus/test/run.js create mode 100644 node_modules/jade/test/filters.test.js create mode 100644 node_modules/jade/test/fixtures/invalid.jade create mode 100644 node_modules/jade/test/fixtures/layout.jade create mode 100644 node_modules/jade/test/jade.test.js create mode 100644 node_modules/mongodb/.npmignore create mode 100644 node_modules/mongodb/HISTORY create mode 100644 node_modules/mongodb/Makefile create mode 100644 node_modules/mongodb/Readme.md create mode 100644 node_modules/mongodb/TODO. create mode 100644 node_modules/mongodb/deps/nodeunit/.npmignore create mode 100644 node_modules/mongodb/deps/nodeunit/CONTRIBUTORS.md create mode 100644 node_modules/mongodb/deps/nodeunit/LICENSE create mode 100644 node_modules/mongodb/deps/nodeunit/Makefile create mode 100644 node_modules/mongodb/deps/nodeunit/README.md create mode 100755 node_modules/mongodb/deps/nodeunit/bin/nodeunit create mode 100644 node_modules/mongodb/deps/nodeunit/bin/nodeunit.json create mode 100644 node_modules/mongodb/deps/nodeunit/deps/async.js create mode 100644 node_modules/mongodb/deps/nodeunit/deps/ejs.js create mode 100644 node_modules/mongodb/deps/nodeunit/deps/json2.js create mode 100644 node_modules/mongodb/deps/nodeunit/doc/nodeunit.md create mode 100644 node_modules/mongodb/deps/nodeunit/examples/browser/nodeunit.js create mode 100644 node_modules/mongodb/deps/nodeunit/examples/browser/suite1.js create mode 100644 node_modules/mongodb/deps/nodeunit/examples/browser/suite2.js create mode 100644 node_modules/mongodb/deps/nodeunit/examples/browser/test.html create mode 100644 node_modules/mongodb/deps/nodeunit/img/example_fail.png create mode 100644 node_modules/mongodb/deps/nodeunit/img/example_pass.png create mode 100644 node_modules/mongodb/deps/nodeunit/index.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/assert.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/core.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/nodeunit.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/reporters/browser.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/reporters/default.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/reporters/html.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/reporters/index.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/reporters/junit.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/reporters/minimal.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/reporters/skip_passed.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/track.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/types.js create mode 100644 node_modules/mongodb/deps/nodeunit/lib/utils.js create mode 100644 node_modules/mongodb/deps/nodeunit/man1/nodeunit.1 create mode 100644 node_modules/mongodb/deps/nodeunit/nodelint.cfg create mode 100644 node_modules/mongodb/deps/nodeunit/package.json create mode 100644 node_modules/mongodb/deps/nodeunit/share/junit.xml.ejs create mode 100644 node_modules/mongodb/deps/nodeunit/share/license.js create mode 100644 node_modules/mongodb/deps/nodeunit/share/nodeunit.css create mode 100644 node_modules/mongodb/deps/nodeunit/test/fixtures/coffee/mock_coffee_module.coffee create mode 100644 node_modules/mongodb/deps/nodeunit/test/fixtures/dir/mock_module3.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/fixtures/dir/mock_module4.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/fixtures/mock_module1.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/fixtures/mock_module2.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode1.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode2.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode3.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/test-base.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/test-failing-callbacks.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/test-httputil.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/test-runfiles.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/test-runmodule.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/test-runtest.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/test-sandbox.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/test-testcase.js create mode 100644 node_modules/mongodb/deps/nodeunit/test/test.html create mode 100644 node_modules/mongodb/deps/step/README.markdown create mode 100755 node_modules/mongodb/deps/step/lib/step.js create mode 100644 node_modules/mongodb/deps/step/package.json create mode 100644 node_modules/mongodb/deps/step/test/callbackTest.js create mode 100644 node_modules/mongodb/deps/step/test/errorTest.js create mode 100644 node_modules/mongodb/deps/step/test/fnTest.js create mode 100644 node_modules/mongodb/deps/step/test/groupTest.js create mode 100644 node_modules/mongodb/deps/step/test/helper.js create mode 100644 node_modules/mongodb/deps/step/test/parallelTest.js create mode 100644 node_modules/mongodb/docs/README.md create mode 100644 node_modules/mongodb/docs/collections.md create mode 100644 node_modules/mongodb/docs/database.md create mode 100644 node_modules/mongodb/docs/gridfs.md create mode 100644 node_modules/mongodb/docs/indexes.md create mode 100644 node_modules/mongodb/docs/insert.md create mode 100644 node_modules/mongodb/docs/queries.md create mode 100644 node_modules/mongodb/docs/replicaset.md create mode 100644 node_modules/mongodb/examples/admin.js create mode 100644 node_modules/mongodb/examples/blog.js create mode 100644 node_modules/mongodb/examples/capped.js create mode 100644 node_modules/mongodb/examples/cursor.js create mode 100644 node_modules/mongodb/examples/gridfs.js create mode 100644 node_modules/mongodb/examples/index_test.js create mode 100644 node_modules/mongodb/examples/info.js create mode 100644 node_modules/mongodb/examples/oplog.js create mode 100644 node_modules/mongodb/examples/queries.js create mode 100644 node_modules/mongodb/examples/replSetServersQueries.js create mode 100644 node_modules/mongodb/examples/replSetServersSimple.js create mode 100644 node_modules/mongodb/examples/simple.js create mode 100644 node_modules/mongodb/examples/strict.js create mode 100644 node_modules/mongodb/examples/types.js create mode 100644 node_modules/mongodb/examples/url.js create mode 100644 node_modules/mongodb/external-libs/bson/Makefile create mode 100644 node_modules/mongodb/external-libs/bson/binary.cc create mode 100644 node_modules/mongodb/external-libs/bson/binary.h create mode 100644 node_modules/mongodb/external-libs/bson/bson.cc create mode 100644 node_modules/mongodb/external-libs/bson/bson.h create mode 100644 node_modules/mongodb/external-libs/bson/code.cc create mode 100644 node_modules/mongodb/external-libs/bson/code.h create mode 100644 node_modules/mongodb/external-libs/bson/dbref.cc create mode 100644 node_modules/mongodb/external-libs/bson/dbref.h create mode 100644 node_modules/mongodb/external-libs/bson/index.js create mode 100644 node_modules/mongodb/external-libs/bson/local.cc create mode 100644 node_modules/mongodb/external-libs/bson/local.h create mode 100644 node_modules/mongodb/external-libs/bson/long.cc create mode 100644 node_modules/mongodb/external-libs/bson/long.h create mode 100644 node_modules/mongodb/external-libs/bson/objectid.cc create mode 100644 node_modules/mongodb/external-libs/bson/objectid.h create mode 100644 node_modules/mongodb/external-libs/bson/test_bson.js create mode 100644 node_modules/mongodb/external-libs/bson/test_full_bson.js create mode 100644 node_modules/mongodb/external-libs/bson/timestamp.cc create mode 100644 node_modules/mongodb/external-libs/bson/timestamp.h create mode 100644 node_modules/mongodb/external-libs/bson/wscript create mode 100755 node_modules/mongodb/index.js create mode 100755 node_modules/mongodb/install.sh create mode 100644 node_modules/mongodb/lib/mongodb/admin.js create mode 100644 node_modules/mongodb/lib/mongodb/bson/binary.js create mode 100644 node_modules/mongodb/lib/mongodb/bson/binary_parser.js create mode 100644 node_modules/mongodb/lib/mongodb/bson/binary_utils.js create mode 100644 node_modules/mongodb/lib/mongodb/bson/bson.js create mode 100644 node_modules/mongodb/lib/mongodb/bson/float_parser.js create mode 100644 node_modules/mongodb/lib/mongodb/bson/objectid.js create mode 100644 node_modules/mongodb/lib/mongodb/bson/timestamp.js create mode 100644 node_modules/mongodb/lib/mongodb/collection.js create mode 100644 node_modules/mongodb/lib/mongodb/commands/base_command.js create mode 100644 node_modules/mongodb/lib/mongodb/commands/db_command.js create mode 100644 node_modules/mongodb/lib/mongodb/commands/delete_command.js create mode 100644 node_modules/mongodb/lib/mongodb/commands/get_more_command.js create mode 100644 node_modules/mongodb/lib/mongodb/commands/insert_command.js create mode 100644 node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js create mode 100644 node_modules/mongodb/lib/mongodb/commands/query_command.js create mode 100644 node_modules/mongodb/lib/mongodb/commands/update_command.js create mode 100644 node_modules/mongodb/lib/mongodb/connection.js create mode 100644 node_modules/mongodb/lib/mongodb/connections/repl_set_servers.js create mode 100644 node_modules/mongodb/lib/mongodb/connections/server.js create mode 100644 node_modules/mongodb/lib/mongodb/cursor.js create mode 100644 node_modules/mongodb/lib/mongodb/db.js create mode 100644 node_modules/mongodb/lib/mongodb/goog/math/long.js create mode 100644 node_modules/mongodb/lib/mongodb/gridfs/chunk.js create mode 100644 node_modules/mongodb/lib/mongodb/gridfs/grid.js create mode 100644 node_modules/mongodb/lib/mongodb/gridfs/gridstore.js create mode 100644 node_modules/mongodb/lib/mongodb/index.js create mode 100644 node_modules/mongodb/lib/mongodb/responses/mongo_reply.js create mode 100755 node_modules/mongodb/package.json create mode 100644 node_modules/mongodb/test/admin_test.js create mode 100644 node_modules/mongodb/test/authentication_test.js create mode 100644 node_modules/mongodb/test/auxilliary/authentication_test.js create mode 100644 node_modules/mongodb/test/auxilliary/replicaset_auth_test.js create mode 100644 node_modules/mongodb/test/bson/bson_test.js create mode 100644 node_modules/mongodb/test/bson/commands_test.js create mode 100644 node_modules/mongodb/test/collection_test.js create mode 100644 node_modules/mongodb/test/connect_test.js create mode 100644 node_modules/mongodb/test/connection_test.js create mode 100644 node_modules/mongodb/test/cursor_test.js create mode 100644 node_modules/mongodb/test/custom_pk_test.js create mode 100644 node_modules/mongodb/test/db_test.js create mode 100644 node_modules/mongodb/test/error_test.js create mode 100644 node_modules/mongodb/test/exception_handling_test.js create mode 100644 node_modules/mongodb/test/find_test.js create mode 100644 node_modules/mongodb/test/gridstore/grid_store_file_test.js create mode 100644 node_modules/mongodb/test/gridstore/grid_store_stream_test.js create mode 100644 node_modules/mongodb/test/gridstore/grid_store_test.js create mode 100644 node_modules/mongodb/test/gridstore/grid_test.js create mode 100644 node_modules/mongodb/test/gridstore/iya_logo_final_bw.jpg create mode 100644 node_modules/mongodb/test/gridstore/test_gs_weird_bug.png create mode 100644 node_modules/mongodb/test/gridstore/test_gs_working_field_read.pdf create mode 100644 node_modules/mongodb/test/index_test.js create mode 100644 node_modules/mongodb/test/insert_test.js create mode 100644 node_modules/mongodb/test/map_reduce_test.js create mode 100644 node_modules/mongodb/test/objectid_test.js create mode 100644 node_modules/mongodb/test/regexp_test.js create mode 100644 node_modules/mongodb/test/remove_test.js create mode 100644 node_modules/mongodb/test/replicaset/connect_test.js create mode 100644 node_modules/mongodb/test/replicaset/count_test.js create mode 100644 node_modules/mongodb/test/replicaset/insert_test.js create mode 100644 node_modules/mongodb/test/replicaset/query_secondaries_test.js create mode 100644 node_modules/mongodb/test/streaming_test.js create mode 100644 node_modules/mongodb/test/tools/keyfile.txt create mode 100644 node_modules/mongodb/test/tools/replica_set_manager.js create mode 100644 node_modules/mongodb/test/tools/server_manager.js create mode 100644 node_modules/mongodb/test/unicode_test.js create mode 100644 node_modules/mongodb/tools/test_all.js create mode 100644 node_modules/mongoose/History.md create mode 100644 node_modules/mongoose/Makefile create mode 100644 node_modules/mongoose/README.md create mode 100644 node_modules/mongoose/docs/defaults.md create mode 100644 node_modules/mongoose/docs/embedded-documents.md create mode 100644 node_modules/mongoose/docs/finding-documents.md create mode 100644 node_modules/mongoose/docs/getters-setters.md create mode 100644 node_modules/mongoose/docs/indexes.md create mode 100644 node_modules/mongoose/docs/methods-statics.md create mode 100644 node_modules/mongoose/docs/middleware.md create mode 100644 node_modules/mongoose/docs/model-definition.md create mode 100644 node_modules/mongoose/docs/validation.md create mode 100644 node_modules/mongoose/docs/virtuals.md create mode 100644 node_modules/mongoose/examples/schema.js create mode 100644 node_modules/mongoose/index.js create mode 100644 node_modules/mongoose/lib/mongoose/collection.js create mode 100644 node_modules/mongoose/lib/mongoose/compat.js create mode 100644 node_modules/mongoose/lib/mongoose/connection.js create mode 100644 node_modules/mongoose/lib/mongoose/document.js create mode 100644 node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/collection.js create mode 100644 node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/connection.js create mode 100644 node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/objectid.js create mode 100644 node_modules/mongoose/lib/mongoose/error.js create mode 100644 node_modules/mongoose/lib/mongoose/index.js create mode 100644 node_modules/mongoose/lib/mongoose/model.js create mode 100644 node_modules/mongoose/lib/mongoose/namedscope.js create mode 100644 node_modules/mongoose/lib/mongoose/promise.js create mode 100644 node_modules/mongoose/lib/mongoose/query.js create mode 100644 node_modules/mongoose/lib/mongoose/schema.js create mode 100644 node_modules/mongoose/lib/mongoose/schema/array.js create mode 100644 node_modules/mongoose/lib/mongoose/schema/boolean.js create mode 100644 node_modules/mongoose/lib/mongoose/schema/date.js create mode 100644 node_modules/mongoose/lib/mongoose/schema/documentarray.js create mode 100644 node_modules/mongoose/lib/mongoose/schema/index.js create mode 100644 node_modules/mongoose/lib/mongoose/schema/mixed.js create mode 100644 node_modules/mongoose/lib/mongoose/schema/number.js create mode 100644 node_modules/mongoose/lib/mongoose/schema/objectid.js create mode 100644 node_modules/mongoose/lib/mongoose/schema/string.js create mode 100644 node_modules/mongoose/lib/mongoose/schemadefault.js create mode 100644 node_modules/mongoose/lib/mongoose/schematype.js create mode 100644 node_modules/mongoose/lib/mongoose/types/array.js create mode 100644 node_modules/mongoose/lib/mongoose/types/document.js create mode 100644 node_modules/mongoose/lib/mongoose/types/documentarray.js create mode 100644 node_modules/mongoose/lib/mongoose/types/index.js create mode 100644 node_modules/mongoose/lib/mongoose/types/number.js create mode 100644 node_modules/mongoose/lib/mongoose/types/objectid.js create mode 100644 node_modules/mongoose/lib/mongoose/utils.js create mode 100644 node_modules/mongoose/lib/mongoose/virtualtype.js create mode 100644 node_modules/mongoose/package.json create mode 100644 node_modules/mongoose/support/cli-table/History.md create mode 100644 node_modules/mongoose/support/cli-table/Makefile create mode 100644 node_modules/mongoose/support/cli-table/README.md create mode 100644 node_modules/mongoose/support/cli-table/examples/revs.js create mode 100644 node_modules/mongoose/support/cli-table/index.js create mode 100644 node_modules/mongoose/support/cli-table/lib/cli-table/index.js create mode 100644 node_modules/mongoose/support/cli-table/lib/cli-table/utils.js create mode 100644 node_modules/mongoose/support/cli-table/package.json create mode 100644 node_modules/mongoose/support/cli-table/test/common.js create mode 100644 node_modules/mongoose/support/cli-table/test/index.test.js create mode 100644 node_modules/mongoose/support/expresso/History.md create mode 100644 node_modules/mongoose/support/expresso/Makefile create mode 100644 node_modules/mongoose/support/expresso/Readme.md create mode 100755 node_modules/mongoose/support/expresso/bin/expresso create mode 100644 node_modules/mongoose/support/expresso/docs/api.html create mode 100644 node_modules/mongoose/support/expresso/docs/index.html create mode 100644 node_modules/mongoose/support/expresso/docs/index.md create mode 100644 node_modules/mongoose/support/expresso/docs/layout/foot.html create mode 100644 node_modules/mongoose/support/expresso/docs/layout/head.html create mode 100644 node_modules/mongoose/support/expresso/lib/bar.js create mode 100644 node_modules/mongoose/support/expresso/lib/foo.js create mode 100644 node_modules/mongoose/support/expresso/package.json create mode 100644 node_modules/mongoose/support/expresso/test/assert.test.js create mode 100644 node_modules/mongoose/support/expresso/test/async.test.js create mode 100644 node_modules/mongoose/support/expresso/test/bar.test.js create mode 100644 node_modules/mongoose/support/expresso/test/foo.test.js create mode 100644 node_modules/mongoose/support/expresso/test/http.test.js create mode 100644 node_modules/mongoose/support/expresso/test/serial/async.test.js create mode 100644 node_modules/mongoose/support/expresso/test/serial/http.test.js create mode 100644 node_modules/mongoose/support/should.js/History.md create mode 100644 node_modules/mongoose/support/should.js/Makefile create mode 100644 node_modules/mongoose/support/should.js/Readme.md create mode 100644 node_modules/mongoose/support/should.js/examples/runner.js create mode 100644 node_modules/mongoose/support/should.js/index.js create mode 100644 node_modules/mongoose/support/should.js/lib/eql.js create mode 100644 node_modules/mongoose/support/should.js/lib/should.js create mode 100644 node_modules/mongoose/support/should.js/package.json create mode 100644 node_modules/mongoose/support/should.js/test/should.test.js create mode 100644 node_modules/mongoose/test/collection.test.js create mode 100644 node_modules/mongoose/test/common.js create mode 100644 node_modules/mongoose/test/connection.test.js create mode 100644 node_modules/mongoose/test/crash.test.js create mode 100644 node_modules/mongoose/test/document.test.js create mode 100644 node_modules/mongoose/test/drivers/node-mongodb-native/collection.test.js create mode 100644 node_modules/mongoose/test/index.test.js create mode 100644 node_modules/mongoose/test/model.querying.test.js create mode 100644 node_modules/mongoose/test/model.test.js create mode 100644 node_modules/mongoose/test/namedscope.test.js create mode 100644 node_modules/mongoose/test/promise.test.js create mode 100644 node_modules/mongoose/test/query.test.js create mode 100644 node_modules/mongoose/test/schema.onthefly.test.js create mode 100644 node_modules/mongoose/test/schema.test.js create mode 100644 node_modules/mongoose/test/types.array.test.js create mode 100644 node_modules/mongoose/test/types.document.test.js create mode 100644 node_modules/mongoose/test/types.documentarray.test.js create mode 100644 node_modules/mongoose/test/types.number.test.js create mode 100644 node_modules/mongoose/test/utils.test.js create mode 100644 node_modules/mysql/License create mode 100644 node_modules/mysql/Makefile create mode 100644 node_modules/mysql/Readme.md create mode 100644 node_modules/mysql/benchmark/.insert.js.un~ create mode 100644 node_modules/mysql/benchmark/.select.js.un~ create mode 100644 node_modules/mysql/benchmark/node-mysql/.insert-select.js.un~ create mode 100644 node_modules/mysql/benchmark/node-mysql/.insert.js.un~ create mode 100644 node_modules/mysql/benchmark/node-mysql/.select.js.un~ create mode 100644 node_modules/mysql/benchmark/node-mysql/insert.js create mode 100644 node_modules/mysql/benchmark/node-mysql/select.js create mode 100644 node_modules/mysql/benchmark/php/.insert-select.php.un~ create mode 100644 node_modules/mysql/benchmark/php/insert-select.php create mode 100644 node_modules/mysql/index.js create mode 100644 node_modules/mysql/lib/.auth.js.un~ create mode 100644 node_modules/mysql/lib/.client.js.un~ create mode 100644 node_modules/mysql/lib/.constants.js.un~ create mode 100644 node_modules/mysql/lib/.mysql.js.un~ create mode 100644 node_modules/mysql/lib/.outgoing_packet.js.un~ create mode 100644 node_modules/mysql/lib/.parser.js.un~ create mode 100755 node_modules/mysql/lib/.query.js.un~ create mode 100644 node_modules/mysql/lib/auth.js create mode 100644 node_modules/mysql/lib/client.js create mode 100644 node_modules/mysql/lib/constants.js create mode 100644 node_modules/mysql/lib/mysql.js create mode 100644 node_modules/mysql/lib/outgoing_packet.js create mode 100644 node_modules/mysql/lib/parser.js create mode 100755 node_modules/mysql/lib/query.js create mode 100644 node_modules/mysql/node_modules/hashish/README.markdown create mode 100644 node_modules/mysql/node_modules/hashish/examples/chain.js create mode 100644 node_modules/mysql/node_modules/hashish/examples/map.js create mode 100644 node_modules/mysql/node_modules/hashish/index.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/.npmignore create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/LICENSE create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/README.markdown create mode 100755 node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/json.js create mode 100755 node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/leaves.js create mode 100755 node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/negative.js create mode 100755 node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/scrub.js create mode 100755 node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/stringify.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/index.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/package.json create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/circular.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/date.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/equal.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/instance.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/interface.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/json.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/keys.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/leaves.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/lib/deep_equal.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/mutability.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/negative.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/obj.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/siblings.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/stop.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/stringify.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/subexpr.js create mode 100644 node_modules/mysql/node_modules/hashish/node_modules/traverse/test/super_deep.js create mode 100644 node_modules/mysql/node_modules/hashish/package.json create mode 100644 node_modules/mysql/node_modules/hashish/test/hash.js create mode 100644 node_modules/mysql/node_modules/hashish/test/property.js create mode 100644 node_modules/mysql/package.json create mode 100644 node_modules/mysql/test/.common.js.un~ create mode 100644 node_modules/mysql/test/.config.template.js.un~ create mode 100644 node_modules/mysql/test/common.js create mode 100644 node_modules/mysql/test/config.js create mode 100644 node_modules/mysql/test/config.template.js create mode 100644 node_modules/mysql/test/fast/.test-client-connect.js.un~ create mode 100644 node_modules/mysql/test/fast/.test-client.js.un~ create mode 100644 node_modules/mysql/test/fast/test-client.js create mode 100644 node_modules/mysql/test/fixture/.column_order.sql.un~ create mode 100644 node_modules/mysql/test/fixture/columnia.sql create mode 100644 node_modules/mysql/test/fixture/libmysql_password.c create mode 100644 node_modules/mysql/test/legacy/.common.js.un~ create mode 100644 node_modules/mysql/test/legacy/common.js create mode 100644 node_modules/mysql/test/legacy/simple/.test-auth-old.js.un~ create mode 100644 node_modules/mysql/test/legacy/simple/.test-auth.js.un~ create mode 100644 node_modules/mysql/test/legacy/simple/.test-client.js.un~ create mode 100644 node_modules/mysql/test/legacy/simple/.test-outgoing-packet.js.un~ create mode 100644 node_modules/mysql/test/legacy/simple/.test-parser.js.un~ create mode 100644 node_modules/mysql/test/legacy/simple/.test-query.js.un~ create mode 100644 node_modules/mysql/test/legacy/simple/test-auth.js create mode 100644 node_modules/mysql/test/legacy/simple/test-client.js create mode 100644 node_modules/mysql/test/legacy/simple/test-outgoing-packet.js create mode 100644 node_modules/mysql/test/legacy/simple/test-parser.js create mode 100644 node_modules/mysql/test/legacy/simple/test-query.js create mode 100755 node_modules/mysql/test/run.js create mode 100644 node_modules/mysql/test/slow/.test-client-commands.js.un~ create mode 100644 node_modules/mysql/test/slow/.test-client-connect.js.un~ create mode 100644 node_modules/mysql/test/slow/.test-client-max-connections.js.un~ create mode 100644 node_modules/mysql/test/slow/.test-client-query-column-ordering.js.un~ create mode 100644 node_modules/mysql/test/slow/.test-client-query-error-handling.js.un~ create mode 100644 node_modules/mysql/test/slow/.test-client-query.js.un~ create mode 100644 node_modules/mysql/test/slow/test-client-commands.js create mode 100644 node_modules/mysql/test/slow/test-client-connect.js create mode 100644 node_modules/mysql/test/slow/test-client-max-connections.js create mode 100644 node_modules/mysql/test/slow/test-client-query-column-ordering.js create mode 100644 node_modules/mysql/test/slow/test-client-query-error-handling.js create mode 100644 node_modules/mysql/test/slow/test-client-query.js create mode 100755 node_modules/mysql/tool/.pcap-mysql.js.un~ create mode 100755 node_modules/mysql/tool/pcap-mysql.js create mode 100644 node_modules/socket.io/.npmignore create mode 100644 node_modules/socket.io/History.md create mode 100644 node_modules/socket.io/Makefile create mode 100644 node_modules/socket.io/Readme.md create mode 100644 node_modules/socket.io/examples/chat/app.js create mode 100644 node_modules/socket.io/examples/chat/index.jade create mode 100644 node_modules/socket.io/examples/chat/package.json create mode 100644 node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl create mode 100644 node_modules/socket.io/examples/chat/public/stylesheets/style.css create mode 100644 node_modules/socket.io/examples/chat/public/stylesheets/style.styl create mode 100644 node_modules/socket.io/examples/irc-output/app.js create mode 100644 node_modules/socket.io/examples/irc-output/index.jade create mode 100644 node_modules/socket.io/examples/irc-output/irc.js create mode 100644 node_modules/socket.io/examples/irc-output/package.json create mode 100644 node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl create mode 100644 node_modules/socket.io/index.js create mode 100644 node_modules/socket.io/lib/logger.js create mode 100644 node_modules/socket.io/lib/manager.js create mode 100644 node_modules/socket.io/lib/namespace.js create mode 100644 node_modules/socket.io/lib/parser.js create mode 100644 node_modules/socket.io/lib/socket.io.js create mode 100644 node_modules/socket.io/lib/socket.js create mode 100644 node_modules/socket.io/lib/store.js create mode 100644 node_modules/socket.io/lib/stores/memory.js create mode 100644 node_modules/socket.io/lib/stores/redis.js create mode 100644 node_modules/socket.io/lib/transport.js create mode 100644 node_modules/socket.io/lib/transports/flashsocket.js create mode 100644 node_modules/socket.io/lib/transports/htmlfile.js create mode 100644 node_modules/socket.io/lib/transports/http-polling.js create mode 100644 node_modules/socket.io/lib/transports/http.js create mode 100644 node_modules/socket.io/lib/transports/index.js create mode 100644 node_modules/socket.io/lib/transports/jsonp-polling.js create mode 100644 node_modules/socket.io/lib/transports/websocket.js create mode 100644 node_modules/socket.io/lib/transports/xhr-polling.js create mode 100644 node_modules/socket.io/lib/util.js create mode 100644 node_modules/socket.io/node_modules/policyfile/LICENSE create mode 100644 node_modules/socket.io/node_modules/policyfile/Makefile create mode 100644 node_modules/socket.io/node_modules/policyfile/README.md create mode 100644 node_modules/socket.io/node_modules/policyfile/doc/index.html create mode 100644 node_modules/socket.io/node_modules/policyfile/examples/basic.fallback.js create mode 100644 node_modules/socket.io/node_modules/policyfile/examples/basic.js create mode 100644 node_modules/socket.io/node_modules/policyfile/index.js create mode 100644 node_modules/socket.io/node_modules/policyfile/lib/server.js create mode 100644 node_modules/socket.io/node_modules/policyfile/package.json create mode 100644 node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.crt create mode 100644 node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.private.key create mode 100644 node_modules/socket.io/node_modules/policyfile/tests/unit.test.js create mode 100644 node_modules/socket.io/node_modules/redis/README.md create mode 100644 node_modules/socket.io/node_modules/redis/changelog.md create mode 100644 node_modules/socket.io/node_modules/redis/examples/auth.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/extend.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/file.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/mget.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/monitor.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/multi.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/multi2.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/psubscribe.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/pub_sub.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/simple.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/subqueries.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/subquery.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/unix_socket.js create mode 100644 node_modules/socket.io/node_modules/redis/examples/web_server.js create mode 100644 node_modules/socket.io/node_modules/redis/index.js create mode 100644 node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js create mode 100644 node_modules/socket.io/node_modules/redis/lib/parser/javascript.js create mode 100644 node_modules/socket.io/node_modules/redis/lib/queue.js create mode 100644 node_modules/socket.io/node_modules/redis/lib/to_array.js create mode 100644 node_modules/socket.io/node_modules/redis/lib/util.js create mode 100644 node_modules/socket.io/node_modules/redis/multi_bench.js create mode 100644 node_modules/socket.io/node_modules/redis/package.json create mode 100644 node_modules/socket.io/node_modules/redis/test.js create mode 100644 node_modules/socket.io/node_modules/redis/tests/buffer_bench.js create mode 100644 node_modules/socket.io/node_modules/redis/tests/reconnect_test.js create mode 100644 node_modules/socket.io/node_modules/redis/tests/sub_quit_test.js create mode 100644 node_modules/socket.io/node_modules/redis/tests/test_start_stop.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/.npmignore create mode 100644 node_modules/socket.io/node_modules/socket.io-client/History.md create mode 100644 node_modules/socket.io/node_modules/socket.io-client/Makefile create mode 100644 node_modules/socket.io/node_modules/socket.io-client/README.md create mode 100755 node_modules/socket.io/node_modules/socket.io-client/bin/builder.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMain.swf create mode 100644 node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMainInsecure.swf create mode 100644 node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.min.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/events.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/io.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/json.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/namespace.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/parser.js create mode 120000 node_modules/socket.io/node_modules/socket.io-client/lib/socket.io-client.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/socket.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/transport.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/transports/flashsocket.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/transports/htmlfile.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/transports/jsonp-polling.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/transports/websocket.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/transports/xhr-polling.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/transports/xhr.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/util.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/README.md create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/WebSocketMain.swf create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/WebSocketMainInsecure.zip create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/IWebSocketLogger.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocket.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocketEvent.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocketMain.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/WebSocketMainInsecure.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/build.sh create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/adobe/net/proxies/RFC2817Socket.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/gsolo/encryption/MD5.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/Crypto.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/MozillaRootCertificates.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/X509Certificate.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/X509CertificateCollection.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/HMAC.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/IHMAC.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/IHash.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MAC.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MD2.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MD5.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA1.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA224.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA256.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHABase.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/ARC4.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/IPRNG.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/Random.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/TLSPRF.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/rsa/RSAKey.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/AESKey.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/BlowFishKey.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CBCMode.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CFB8Mode.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CFBMode.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CTRMode.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/DESKey.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ECBMode.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ICipher.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IMode.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IPad.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IStreamCipher.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ISymmetricKey.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IVMode.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/NullPad.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/OFBMode.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/PKCS5.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/SSLPad.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/SimpleIVMode.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/TLSPad.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/TripleDESKey.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/XTeaKey.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/aeskey.pl create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/dump.txt create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/AESKeyTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ARC4Test.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/BigIntegerTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/BlowFishKeyTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CBCModeTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CFB8ModeTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CFBModeTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CTRModeTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/DESKeyTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ECBModeTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/HMACTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ITestHarness.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/MD2Test.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/MD5Test.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/OFBModeTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/RSAKeyTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA1Test.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA224Test.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA256Test.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TLSPRFTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TestCase.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TripleDESKeyTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/XTeaKeyTest.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/BulkCiphers.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/CipherSuites.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/IConnectionState.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/ISecurityParameters.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/KeyExchanges.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/MACs.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLConnectionState.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLEvent.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLSecurityParameters.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSConfig.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSConnectionState.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSEngine.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSError.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSEvent.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSecurityParameters.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSocket.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSocketEvent.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSTest.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/BarrettReduction.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/BigInteger.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/ClassicReduction.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/IReduction.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/MontgomeryReduction.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/NullReduction.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/math/bi_internal.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/ArrayUtil.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/Base64.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/Hex.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/Memory.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/ByteString.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/DER.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/IAsn1Type.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Integer.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/OID.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/ObjectIdentifier.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/PEM.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/PrintableString.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Sequence.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Set.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/Type.as create mode 100755 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/util/der/UTCTime.as create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/sample.html create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/swfobject.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/lib/vendor/web-socket-js/web_socket.js create mode 120000 node_modules/socket.io/node_modules/socket.io-client/node_modules/.bin/uglifyjs create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.html create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/README.org create mode 100755 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/bin/uglifyjs create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/docstyle.css create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/lib/parse-js.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/lib/process.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/lib/squeeze-more.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/package.json create mode 100755 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/beautify.js create mode 100755 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/testparser.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/array1.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/array2.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/array3.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/array4.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/assignment.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/concatstring.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/const.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/empty-blocks.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/forstatement.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/if.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/ifreturn.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue10.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue11.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue13.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue14.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue16.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue17.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue20.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue21.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue25.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue27.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue28.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue29.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue30.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue34.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue4.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue48.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue50.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue53.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue54.1.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue68.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue69.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/issue9.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/strict-equals.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/expected/var.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/array1.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/array2.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/array3.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/array4.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/assignment.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/concatstring.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/const.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/empty-blocks.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/forstatement.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/if.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/ifreturn.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue10.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue11.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue13.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue14.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue16.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue17.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue20.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue21.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue25.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue27.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue28.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue29.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue30.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue34.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue4.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue48.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue50.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue53.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue54.1.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue68.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue69.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/issue9.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/strict-equals.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/compress/test/var.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/test/unit/scripts.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/tmp/instrument2.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/node_modules/uglify-js/uglify-js.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/package.json create mode 100644 node_modules/socket.io/node_modules/socket.io-client/test/events.test.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/test/io.test.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/test/node/builder.common.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/test/node/builder.test.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/test/parser.test.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/test/socket.test.js create mode 100644 node_modules/socket.io/node_modules/socket.io-client/test/util.test.js create mode 100644 node_modules/socket.io/package.json create mode 100644 node_modules/socket.io/support/node-websocket-client/LICENSE create mode 100644 node_modules/socket.io/support/node-websocket-client/Makefile create mode 100644 node_modules/socket.io/support/node-websocket-client/README.md create mode 100644 node_modules/socket.io/support/node-websocket-client/examples/client-unix.js create mode 100644 node_modules/socket.io/support/node-websocket-client/examples/client.js create mode 100644 node_modules/socket.io/support/node-websocket-client/examples/server-unix.js create mode 100644 node_modules/socket.io/support/node-websocket-client/lib/websocket.js create mode 100644 node_modules/socket.io/support/node-websocket-client/package.json create mode 100644 node_modules/socket.io/support/node-websocket-client/test/test-basic.js create mode 100644 node_modules/socket.io/support/node-websocket-client/test/test-client-close.js create mode 100644 node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js create mode 100644 node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js create mode 100644 node_modules/socket.io/support/node-websocket-client/test/test-server-close.js create mode 100644 node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js create mode 100644 node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js create mode 100644 node_modules/socket.io/test/common.js create mode 100644 node_modules/socket.io/test/fixtures/cert.crt create mode 100644 node_modules/socket.io/test/fixtures/key.key create mode 100644 node_modules/socket.io/test/io.test.js create mode 100644 node_modules/socket.io/test/leaks/socket.leaktest.js create mode 100644 node_modules/socket.io/test/manager.test.js create mode 100644 node_modules/socket.io/test/namespace.test.js create mode 100644 node_modules/socket.io/test/parser.test.js create mode 100644 node_modules/socket.io/test/socket.js create mode 100644 node_modules/socket.io/test/stores.memory.test.js create mode 100644 node_modules/socket.io/test/stores.redis.test.js create mode 100644 node_modules/socket.io/test/transports.flashsocket.test.js create mode 100644 node_modules/socket.io/test/transports.htmlfile.test.js create mode 100644 node_modules/socket.io/test/transports.jsonp-polling.test.js create mode 100644 node_modules/socket.io/test/transports.websocket.test.js create mode 100644 node_modules/socket.io/test/transports.xhr-polling.test.js create mode 100644 package.json create mode 100644 public/archive/images/Guevedoces4.jpg create mode 100644 public/archive/images/Guevedoces5.jpg create mode 100644 public/archive/images/Hullhouse-addams.jpg create mode 100644 public/archive/images/OraQuick_Test.gif create mode 100644 public/archive/images/davidtennis.jpg create mode 100644 public/archive/images/engraving_example.jpg create mode 100644 public/archive/images/faculty_img19_sml.jpg create mode 100644 public/archive/images/martin-luther-king2.jpg create mode 100644 public/archive/images/no-image.gif create mode 100644 public/archive/images/phaistos_disk2_lg.gif create mode 100644 public/health_check.html create mode 100644 public/images/88x31.png create mode 100755 public/images/arrow_up.png create mode 100644 public/images/bg.png create mode 100755 public/images/bg_main-heading.gif create mode 100644 public/images/blown-to-bits.png create mode 100644 public/images/boston.com.png create mode 100644 public/images/dropdown_arrow.png create mode 100644 public/images/fclogo.png create mode 100644 public/images/finals-club-blk.png create mode 100644 public/images/finals-club-wht.png create mode 100644 public/images/harvard-crimson.jpg create mode 100644 public/images/home.jpg create mode 100644 public/images/keep-it-academic.png create mode 100644 public/images/logo_finalsclub_footer.gif create mode 100644 public/images/logo_veritas_footer.gif create mode 100644 public/images/the-chronicle.png create mode 100644 public/javascripts/backchannel.js create mode 100644 public/javascripts/counts.js create mode 100644 public/javascripts/dropdown.js create mode 100644 public/javascripts/es5-shim.min.js create mode 100644 public/javascripts/fc.js create mode 100644 public/javascripts/jquery.tmpl.min.js create mode 100644 public/javascripts/templates/comment.js create mode 100644 public/javascripts/templates/post.js create mode 100644 public/stylesheets/backchannel.css create mode 100644 public/stylesheets/dropdown.css create mode 100644 public/stylesheets/fc.css create mode 100644 public/stylesheets/fc2.css create mode 100644 public/stylesheets/style.css create mode 100644 public/terms.pdf create mode 100755 restart create mode 100644 schools.json create mode 100755 start create mode 100755 stop create mode 100755 util/boot.sh create mode 100644 util/haproxy.cfg create mode 100755 util/nightly-restart.sh create mode 100755 util/start.sh create mode 100644 views/activate.jade create mode 100644 views/archive/courses.jade create mode 100644 views/archive/index.jade create mode 100644 views/archive/learn.jade create mode 100644 views/archive/note.jade create mode 100644 views/archive/notes.jade create mode 100644 views/archive/notesLayout.jade create mode 100644 views/course/form.jade create mode 100644 views/course/index.jade create mode 100644 views/course/new.jade create mode 100644 views/footer.jade create mode 100644 views/index.jade create mode 100644 views/layout.jade create mode 100644 views/lecture/form.jade create mode 100644 views/lecture/index.jade create mode 100644 views/lecture/new.jade create mode 100644 views/login.jade create mode 100644 views/masthead.jade create mode 100644 views/notes/dropdown.jade create mode 100644 views/notes/form.jade create mode 100644 views/notes/index.jade create mode 100644 views/notes/layout.jade create mode 120000 views/notes/masthead.jade create mode 100644 views/notes/new.jade create mode 100644 views/notes/noteLayout.jade create mode 100644 views/notes/public.jade create mode 100644 views/profile/index.jade create mode 100644 views/register.jade create mode 100644 views/resetpw-error.jade create mode 100644 views/resetpw-success.jade create mode 100644 views/resetpw.jade create mode 100644 views/schools.jade create mode 100644 views/static/about.jade create mode 100644 views/static/conduct.jade create mode 100644 views/static/contact.jade create mode 100644 views/static/legal.jade create mode 100644 views/static/press.jade create mode 100644 views/static/privacy.jade diff --git a/README b/README new file mode 100644 index 0000000..91242ef --- /dev/null +++ b/README @@ -0,0 +1,2 @@ +Finals Club Development + diff --git a/app.js b/app.js new file mode 100644 index 0000000..032bc33 --- /dev/null +++ b/app.js @@ -0,0 +1,1621 @@ +/* vim: set ts=2: */ + +// Prerequisites + +var sys = require( 'sys' ); +var os = require( 'os' ); +var url = require( 'url' ); + +var express = require( 'express' ); +var mongoStore = require( 'connect-mongo' ); +var async = require( 'async' ); + +var db = require( './db.js' ); +var mongoose = require( './models.js' ).mongoose; +//var mysql = require( 'mysql' ); + +var Mailer = require( './mailer.js' ); +var hat = require('hat'); + +var connect = require( 'connect' ); +var Session = connect.middleware.session.Session; +var parseCookie = connect.utils.parseCookie; + +var log3 = function() {} + +var app = module.exports = express.createServer(); + +// Database + +var User = mongoose.model( 'User' ); +var School = mongoose.model( 'School' ); +var Course = mongoose.model( 'Course' ); +var Lecture = mongoose.model( 'Lecture' ); +var Note = mongoose.model( 'Note' ); + +var ArchivedCourse = mongoose.model( 'ArchivedCourse' ); +var ArchivedNote = mongoose.model( 'ArchivedNote' ); +var ArchivedSubject = mongoose.model( 'ArchivedSubject' ); + +var ObjectId = mongoose.SchemaTypes.ObjectId; + +// Mysql Init +/* +var sqlClient = mysql.createClient({ + host : process.env.MYSQL_DB_HOSTNAME || 'localhost', + user : process.env.MYSQL_DB_USER || 'root', + password : process.env.MYSQL_DB_PASS || 'root', + port : process.env.MYSQL_DB_PORT || 3306, + database : 'fcstatic', +}) +*/ + +// Configuration + +var ADMIN_EMAIL = process.env.DEV_EMAIL || 'info@finalsclub.org'; + +var serverHost = process.env.SERVER_HOST; +var serverPort = process.env.SERVER_PORT; + +if( serverHost ) { + console.log( 'Using server hostname defined in environment: %s', serverHost ); +} else { + serverHost = os.hostname(); + + console.log( 'No hostname defined, defaulting to os.hostname(): %s', serverHost ); +} + +app.configure( 'development', function() { + app.set( 'errorHandler', express.errorHandler( { dumpExceptions: true, showStack: true } ) ); + + app.set( 'dbHost', process.env.MONGO_HOST || 'localhost' ); + app.set( 'dbUri', 'mongodb://' + app.set( 'dbHost' ) + '/fc' ); + + app.set( 'awsAccessKey', process.env.AWS_ACCESS_KEY_ID ); + app.set( 'awsSecretKey', process.env.AWS_SECRET_ACCESS_KEY ); + + if ( !serverPort ) { + serverPort = 3000; + } +}); + +app.configure( 'production', function() { + app.set( 'errorHandler', express.errorHandler( { dumpExceptions: true, showStack: true } ) ); + + // XXX Disable view caching temp + app.disable( 'view cache' ) + + app.set( 'dbHost', process.env.MONGO_HOST || 'localhost' ); + app.set( 'dbUri', 'mongodb://' + app.set( 'dbHost' ) + '/fc' ); + + app.set( 'awsAccessKey', process.env.AWS_ACCESS_KEY_ID ); + app.set( 'awsSecretKey', process.env.AWS_SECRET_ACCESS_KEY ); + + if ( !serverPort ) { + serverPort = 80; + } +}); + +app.configure(function(){ + app.set( 'views', __dirname + '/views' ); + app.set( 'view engine', 'jade' ); + app.use( express.bodyParser() ); + + app.use( express.cookieParser() ); + + // sessions + app.set( 'sessionStore', new mongoStore( { + 'url' : app.set( 'dbUri' ) + })); + + app.use( express.session( { + 'secret' : 'finalsclub', + 'maxAge' : new Date(Date.now() + (60 * 60 * 24 * 30 * 1000)), + 'store' : app.set( 'sessionStore' ) + })); + + app.use( express.methodOverride() ); + app.use( app.router ); + app.use( express.static( __dirname + '/public' ) ); + + // use the error handler defined earlier + var errorHandler = app.set( 'errorHandler' ); + + app.use( errorHandler ); +}); + +// Mailers + +function sendUserActivation( user ) { + var message = { + 'to' : user.email, + + 'subject' : 'Activate your FinalsClub.org Account', + + 'template' : 'userActivation', + 'locals' : { + 'user' : user, + 'serverHost' : serverHost + } + }; + + mailer.send( message, function( err, result ) { + if( err ) { + // XXX: Add route to resend this email + + console.log( 'Error sending user activation email\nError Message: '+err.Message ); + } else { + console.log( 'Successfully sent user activation email.' ); + } + }); +} + +function sendUserWelcome( user, school ) { + var template = school ? 'userWelcome' : 'userWelcomeNoSchool'; + var message = { + 'to' : user.email, + + 'subject' : 'Welcome to FinalsClub', + + 'template' : template, + 'locals' : { + 'user' : user, + 'serverHost' : serverHost + } + }; + + mailer.send( message, function( err, result ) { + if( err ) { + // XXX: Add route to resend this email + + console.log( 'Error sending user welcome email\nError Message: '+err.Message ); + } else { + console.log( 'Successfully sent user welcome email.' ); + } + }); +} +// Middleware + +function loggedIn( req, res, next ) { + if( req.user ) { + next(); + } else { + req.flash( 'error', 'You must be logged in to access that feature!' ); + + res.redirect( '/' ); + } +} + +function loadUser( req, res, next ) { + var sid = req.sessionID; + + console.log( 'got request from session ID: %s', sid ); + + User.findOne( { session : sid }, function( err, user ) { + + log3(err); + log3(user); + + if( user ) { + req.user = user; + + req.user.loggedIn = true; + + log3( 'authenticated user: '+req.user._id+' / '+req.user.email+''); + + if( req.user.activated ) { + // is the user's profile complete? if not, redirect to their profile + if( ! req.user.isComplete ) { + if( url.parse( req.url ).pathname != '/profile' ) { + req.flash( 'info', 'Your profile is incomplete. Please complete your profile to fully activate your account.' ); + + res.redirect( '/profile' ); + } else { + next(); + } + } else { + next(); + } + } else { + req.flash( 'info', 'This account has not been activated. Check your email for the activation URL.' ); + + res.redirect( '/' ); + } + } else { + // stash the original request so we can redirect + var path = url.parse( req.url ).pathname; + req.session.redirect = path; + + req.user = {}; + + next(); + } + }); +} + +function loadSchool( req, res, next ) { + var user = req.user; + var schoolId = req.params.id; + + School.findById( schoolId, function( err, school ) { + if( school ) { + req.school = school; + + school.authorize( user, function( authorized ){ + req.school.authorized = authorized; + next(); + }); + } else { + req.flash( 'error', 'Invalid school specified!' ); + + res.redirect( '/' ); + } + }); +} + +function loadCourse( req, res, next ) { + var user = req.user; + var courseId = req.params.id; + + Course.findById( courseId, function( err, course ) { + if( course ) { + req.course = course; + + course.authorize( user, function( authorized ) { + req.course.authorized = authorized; + + next(); + }); + } else { + req.flash( 'error', 'Invalid course specified!' ); + + res.redirect( '/' ); + } + }); +} + +function loadLecture( req, res, next ) { + var user = req.user; + var lectureId = req.params.id; + + Lecture.findById( lectureId, function( err, lecture ) { + if( lecture ) { + req.lecture = lecture; + + lecture.authorize( user, function( authorized ) { + req.lecture.authorized = authorized; + + next(); + }); + } else { + req.flash( 'error', 'Invalid lecture specified!' ); + + res.redirect( '/' ); + } + }); +} + +function loadNote( req, res, next ) { + var user = req.user ? req.user : false; + var noteId = req.params.id; + + Note.findById( noteId, function( err, note ) { + if( note && user ) { + note.authorize( user, function( auth ) { + if( auth ) { + req.note = note; + + next(); + } else if ( note.public ) { + req.RO = true; + req.note = note; + + next(); + } else { + req.flash( 'error', 'You do not have permission to access that note.' ); + + res.redirect( '/' ); + } + }) + } else if ( note && note.public ) { + req.note = note; + req.RO = true; + + next(); + } else if ( note && !note.public ) { + req.session.redirect = '/note/' + note._id; + req.flash( 'error', 'You must be logged in to view that note.' ); + res.redirect( '/login' ); + } else { + req.flash( 'error', 'Invalid note specified!' ); + + res.redirect( '/login' ); + } + }); +} + +app.dynamicHelpers( { + // flash messages from express-messages + 'messages' : require( 'express-messages' ), + + 'user' : function( req, res ) { + return req.user; + }, + + 'session' : function( req, res ) { + return req.session; + } +}); + +// Routes + +app.get( '/', loadUser, function( req, res ) { + log3("get / page"); + + res.render( 'index' ); +}); + +app.get( '/schools', loadUser, function( req, res ) { + var user = req.user; + + // mongoose's documentation on sort is extremely poor, tread carefully + School.find( {} ).sort( 'name', '1' ).run( function( err, schools ) { + if( schools ) { + async.forEach( + schools, + function( school, callback ) { + school.authorize( user, function( authorized ) { + school.authorized = authorized; + + Course.find( { 'school' : school._id } ).sort( 'name', '1' ).run( function( err, courses ) { + if( courses.length > 0 ) { + school.courses = courses; + } else { + school.courses = []; + } + callback(); + }); + }); + }, + function( err ) { + res.render( 'schools', { 'schools' : schools } ); + } + ); + } else { + res.render( 'schools', { 'schools' : [] } ); + } + }); +}); + +app.get( '/:id/course/new', loadUser, loadSchool, function( req, res ) { + var school = req.school; + + if( ( ! school ) || ( ! school.authorized ) ) { + return res.redirect( '/schools' ); + } + + res.render( 'course/new', { 'school': school } ); +}); + +app.post( '/:id/course/new', loadUser, loadSchool, function( req, res ) { + var school = req.school; + var course = new Course; + var instructorEmail = req.body.email.toLowerCase(); + var instructorName = req.body.instructorName; + + if( ( ! school ) || ( ! school.authorized ) ) { + res.redirect( '/schools' ); + } + + if ( !instructorEmail || !instructorName ) { + req.flash( 'error', 'Invalid parameters!' ) + return res.render( 'course/new' ); + } + + course.number = req.body.number; + course.name = req.body.name; + course.description = req.body.description; + course.school = school._id; + course.creator = req.user._id; + course.subject = req.body.subject; + course.department = req.body.department; + + // find our instructor or invite them if necessary + User.findOne( { 'email' : instructorEmail }, function( err, user ) { + if ( !user ) { + var user = new User; + + user.name = instructorName + user.email = instructorEmail; + user.affil = 'Instructor'; + user.school = school.name; + + user.activated = false; + + if ( ( user.email === '' ) || ( !isValidEmail( user.email ) ) ) { + req.flash( 'error', 'Please enter a valid email' ); + return res.redirect( '/register' ); + } + user.save(function( err ) { + if ( err ) { + req.flash( 'error', 'Invalid parameters!' ) + return res.render( 'course/new' ); + } else { + var message = { + to : user.email, + + 'subject' : 'A non-profit open education initiative', + + 'template' : 'instructorInvite', + 'locals' : { + 'course' : course, + 'school' : school, + 'user' : user, + 'serverHost' : serverHost + } + }; + + mailer.send( message, function( err, result ) { + if( err ) { + console.log( 'Error inviting instructor to course!' ); + } else { + console.log( 'Successfully invited instructor to course.' ); + } + }); + + course.instructor = user._id; + course.save( function( err ) { + if( err ) { + // XXX: better validation + req.flash( 'error', 'Invalid parameters!' ); + + return res.render( 'course/new' ); + } else { + var message = { + to : ADMIN_EMAIL, + + 'subject' : school.name+' has a new course: '+course.name, + + 'template' : 'newCourse', + 'locals' : { + 'course' : course, + 'instructor' : user, + 'user' : req.user, + 'serverHost' : serverHost + } + }; + + mailer.send( message, function( err, result ) { + if ( err ) { + console.log( 'Error sending new course email to info@finalsclub.org' ) + } else { + console.log( 'Successfully invited instructor to course') + } + }) + res.redirect( '/schools' ); + } + }); + } + }) + } else { + if (user.affil === 'Instructor') { + course.instructor = user._id; + course.save( function( err ) { + if( err ) { + // XXX: better validation + req.flash( 'error', 'Invalid parameters!' ); + + return res.render( 'course/new' ); + } else { + var message = { + to : ADMIN_EMAIL, + + 'subject' : school.name+' has a new course: '+course.name, + + 'template' : 'newCourse', + 'locals' : { + 'course' : course, + 'instructor' : user, + 'user' : req.user, + 'serverHost' : serverHost + } + }; + + mailer.send( message, function( err, result ) { + if ( err ) { + console.log( 'Error sending new course email to info@finalsclub.org' ) + } else { + console.log( 'Successfully invited instructor to course') + } + }) + res.redirect( '/schools' ); + } + }); + } else { + req.flash( 'error', 'The existing user\'s email you entered is not an instructor' ); + res.render( 'course/new' ); + } + } + }) +}); + +app.get( '/course/:id', loadUser, loadCourse, function( req, res ) { + var userId = req.user._id; + var course = req.course; + + // are we subscribed to this course? + var subscribed = course.subscribed( userId ); + + // pull out our lectures + Lecture.find( { 'course' : course._id } ).sort( 'name', '1' ).run( function( err, lectures ) { + User.findById( course.instructor, function( err, instructor ) { + res.render( 'course/index', { 'course' : course, 'instructor': instructor, 'subscribed' : subscribed, 'lectures' : lectures } ); + }) + }); +}); + +app.get( '/course/:id/delete', loadUser, loadCourse, function( req, res) { + var course = req.course; + var user = req.user; + + if ( user.admin ) { + course.delete(function( err ) { + if ( err ) req.flash( 'info', 'There was a problem removing course: ' + err ) + else req.flash( 'info', 'Successfully removed course' ) + res.redirect( '/schools' ); + }); + } else { + req.flash( 'error', 'You don\'t have permission to do that' ) + res.redirect( '/schools' ); + } +}) + +// subscribe and unsubscribe to course networks +app.get( '/course/:id/subscribe', loadUser, loadCourse, function( req, res ) { + var course = req.course; + var userId = req.user._id; + + course.subscribe( userId, function( err ) { + if( err ) { + req.flash( 'error', 'Error subscribing to course!' ); + } + + res.redirect( '/course/' + course._id ); + }); +}); + +app.get( '/course/:id/unsubscribe', loadUser, loadCourse, function( req, res ) { + var course = req.course; + var userId = req.user._id; + + course.unsubscribe( userId, function( err ) { + if( err ) { + req.flash( 'error', 'Error unsubscribing from course!' ); + } + + res.redirect( '/course/' + course._id ); + }); +}); + +app.get( '/course/:id/lecture/new', loadUser, loadCourse, function( req, res ) { + var courseId = req.params.id; + var course = req.course; + var lecture = {}; + + if( ( ! course ) || ( ! course.authorized ) ) { + return res.redirect( '/course/' + courseId ); + } + + res.render( 'lecture/new', { 'lecture' : lecture } ); +}); + +app.post( '/course/:id/lecture/new', loadUser, loadCourse, function( req, res ) { + var courseId = req.params.id; + var course = req.course; + var lecture = new Lecture; + + if( ( ! course ) || ( ! course.authorized ) ) { + res.redirect( '/course/' + courseId ); + + return; + } + + lecture.name = req.body.name; + lecture.date = req.body.date; + lecture.course = course._id; + lecture.creator = req.user._id; + + lecture.save( function( err ) { + if( err ) { + // XXX: better validation + req.flash( 'error', 'Invalid parameters!' ); + + res.render( 'lecture/new', { 'lecture' : lecture } ); + } else { + res.redirect( '/course/' + course._id ); + } + }); +}); + +// lecture + +app.get( '/lecture/:id', loadUser, loadLecture, function( req, res ) { + var lecture = req.lecture; + + // grab the associated course (this should be done with DBRefs eventually ) + Course.findById( lecture.course, function( err, course ) { + if( course ) { + User.findById( course.instructor, function( err, instructor ) { + // pull out our notes + Note.find( { 'lecture' : lecture._id } ).sort( 'name', '1' ).run( function( err, notes ) { + if ( !req.user.loggedIn || !req.lecture.authorized ) { + notes = notes.filter(function( note ) { + if ( note.public ) return note; + }) + } + res.render( 'lecture/index', { + 'lecture' : lecture, + 'course' : course, + 'instructor' : instructor, + 'notes' : notes, + 'counts' : counts, + + 'javascripts' : [ 'counts.js' ] + }); + }); + }) + } else { + // with DBRefs we will be able to reassign orphaned courses/lecture/pads + + req.flash( 'error', 'That lecture is orphaned!' ); + + res.redirect( '/' ); + } + }); +}); + +app.get( '/lecture/:id/notes/new', loadUser, loadLecture, function( req, res ) { + var lectureId = req.params.id; + var lecture = req.lecture; + var note = {}; + + if( ( ! lecture ) || ( ! lecture.authorized ) ) { + res.redirect( '/lecture/' + lectureId ); + + return; + } + + res.render( 'notes/new', { 'note' : note } ); +}); + +app.post( '/lecture/:id/notes/new', loadUser, loadLecture, function( req, res ) { + var lectureId = req.params.id; + var lecture = req.lecture; + + if( ( ! lecture ) || ( ! lecture.authorized ) ) { + res.redirect( '/lecture/' + lectureId ); + + return; + } + + var note = new Note; + + note.name = req.body.name; + note.date = req.body.date; + note.lecture = lecture._id; + note.public = req.body.private ? false : true; + note.creator = req.user._id; + + note.save( function( err ) { + if( err ) { + // XXX: better validation + req.flash( 'error', 'Invalid parameters!' ); + + res.render( 'notes/new', { 'note' : note } ); + } else { + res.redirect( '/lecture/' + lecture._id ); + } + }); +}); + +// notes + +app.get( '/note/:id', loadUser, loadNote, function( req, res ) { + var note = req.note; + var roID = note.roID || false; + + var lectureId = note.lecture; + + if ( req.session.visited ) { + if ( req.session.visited.indexOf( note._id.toString() ) == -1 ) { + req.session.visited.push( note._id ); + note.addVisit(); + } + } else { + req.session.visited = []; + req.session.visited.push( note._id ); + note.addVisit(); + } + + if (roID) { + processReq(); + } else { + db.open('mongodb://' + app.set( 'dbHost' ) + '/etherpad/etherpad', function( err, epl ) { + epl.findOne( { key: 'pad2readonly:' + note._id }, function(err, record) { + if ( record ) { + roID = record.value.replace(/"/g, ''); + } else { + roID = false; + } + processReq(); + }) + }) + } + + function processReq() { + Lecture.findById( lectureId, function( err, lecture ) { + if( ! lecture ) { + req.flash( 'error', 'That notes page is orphaned!' ); + + res.redirect( '/' ); + } + Note.find( { 'lecture' : lecture._id }, function( err, otherNotes ) { + if( !req.RO ) { + // XXX User is logged in and sees full notepad + + res.render( 'notes/index', { + 'layout' : 'noteLayout', + 'host' : serverHost, + 'note' : note, + 'lecture' : lecture, + 'otherNotes' : otherNotes, + 'RO' : false, + 'roID' : roID, + 'stylesheets' : [ 'dropdown.css', 'fc2.css' ], + 'javascripts' : [ 'dropdown.js', 'counts.js', 'backchannel.js', 'jquery.tmpl.min.js' ] + }); + } else { + // XXX User is not logged in and sees notepad that is public + res.render( 'notes/public', { + 'layout' : 'noteLayout', + 'host' : serverHost, + 'note' : note, + 'otherNotes' : otherNotes, + 'roID' : roID, + 'lecture' : lecture, + 'stylesheets' : [ 'dropdown.css', 'fc2.css' ], + 'javascripts' : [ 'dropdown.js', 'counts.js', 'backchannel.js', 'jquery.tmpl.min.js' ] + }); + } + }); + }); + } +}); + +// static pages + +app.get( '/about', loadUser, function( req, res ) { + res.redirect( 'http://blog.finalsclub.org/about.html' ); + //res.render( 'static/about' ); +}); + +app.get( '/press', loadUser, function( req, res ) { + res.render( 'static/press' ); +}); + +app.get( '/conduct', loadUser, function( req, res ) { + res.render( 'static/conduct' ); +}); + +app.get( '/legal', loadUser, function( req, res ) { + res.redirect( 'http://blog.finalsclub.org/legal.html' ); + //res.render( 'static/legal' ); +}); + +app.get( '/contact', loadUser, function( req, res ) { + res.redirect( 'http://blog.finalsclub.org/contact.html' ); + //res.render( 'static/contact' ); +}); + +app.get( '/privacy', loadUser, function( req, res ) { + res.render( 'static/privacy' ); +}); + +// authentication + +app.get( '/login', function( req, res ) { + log3("get login page") + + res.render( 'login' ); +}); + +app.post( '/login', function( req, res ) { + var email = req.body.email; + var password = req.body.password; + log3("post login ...") + + User.findOne( { 'email' : email.toLowerCase() }, function( err, user ) { + log3(err) + log3(user) + + if( user ) { + if( ! user.activated ) { + // (undocumented) markdown-esque link functionality in req.flash + req.flash( 'error', 'This account isn\'t activated. Check your inbox or [click here](/resendActivation) to resend the activation email.' ); + + req.session.activateCode = user._id; + + res.render( 'login' ); + } else { + if( user.authenticate( password ) ) { + log3("pass ok") + + var sid = req.sessionID; + + user.session = sid; + + user.save( function() { + var redirect = req.session.redirect; + + // login complete, remember the user's email for next time + req.session.email = email; + + // alert the successful login + req.flash( 'info', 'Successfully logged in!' ); + + // redirect to profile if we don't have a stashed request + res.redirect( redirect || '/profile' ); + }); + } else { + req.flash( 'error', 'Invalid login!' ); + + res.render( 'login' ); + } + } + } else { + log3("bad login") + req.flash( 'error', 'Invalid login!' ); + + res.render( 'login' ); + } + }); +}); + +app.get( '/resetpw', function( req, res ) { + log3("get resetpw page"); + res.render( 'resetpw' ); +}); +app.get( '/resetpw/:id', function( req, res ) { + var resetPassCode = req.params.id + res.render( 'resetpw', { 'verify': true, 'resetPassCode' : resetPassCode } ); +}); + +app.post( '/resetpw', function( req, res ) { + log3("post resetpw"); + var email = req.body.email + + + User.findOne( { 'email' : email.toLowerCase() }, function( err, user ) { + if( user ) { + + var resetPassCode = hat(64); + user.setResetPassCode(resetPassCode); + + var resetPassUrl = 'http://' + serverHost + ((app.address().port != 80)? ':'+app.address().port: '') + '/resetpw/' + resetPassCode; + + user.save( function( err ) { + log3('save '+user.email); + + var message = { + 'to' : user.email, + + 'subject' : 'Your FinalsClub.org Password has been Reset!', + + 'template' : 'userPasswordReset', + 'locals' : { + 'resetPassCode' : resetPassCode, + 'resetPassUrl' : resetPassUrl + } + }; + + mailer.send( message, function( err, result ) { + if( err ) { + // XXX: Add route to resend this email + + console.log( 'Error sending user password reset email!' ); + } else { + console.log( 'Successfully sent user password reset email.' ); + } + + }); + + res.render( 'resetpw-success', { 'email' : email } ); + }); + } else { + res.render( 'resetpw-error', { 'email' : email } ); + } + }); +}); +app.post( '/resetpw/:id', function( req, res ) { + log3("post resetpw.code"); + var resetPassCode = req.params.id + var email = req.body.email + var pass1 = req.body.pass1 + var pass2 = req.body.pass2 + + User.findOne( { 'email' : email.toLowerCase() }, function( err, user ) { + var valid = false; + if( user ) { + var valid = user.resetPassword(resetPassCode, pass1, pass2); + if (valid) { + user.save( function( err ) { + res.render( 'resetpw-success', { 'verify' : true, 'email' : email, 'resetPassCode' : resetPassCode } ); + }); + } + } + + if (!valid) { + res.render( 'resetpw-error', { 'verify' : true, 'email' : email } ); + } + }); +}); + +app.get( '/register', function( req, res ) { + log3("get reg page"); + + School.find( {} ).sort( 'name', '1' ).run( function( err, schools ) { + res.render( 'register', { 'schools' : schools } ); + }) +}); + +app.post( '/register', function( req, res ) { + var sid = req.sessionId; + + var user = new User; + + user.email = req.body.email.toLowerCase(); + user.password = req.body.password; + user.session = sid; + user.school = req.body.school === 'Other' ? req.body.otherSchool : req.body.school; + user.name = req.body.name; + user.affil = req.body.affil; + user.activated = false; + + if ( ( user.email === '' ) || ( !isValidEmail( user.email ) ) ) { + req.flash( 'error', 'Please enter a valid email' ); + return res.redirect( '/register' ); + } + + if ( req.body.password.length < 6 ) { + req.flash( 'error', 'Please enter a password longer than eight characters' ); + return res.redirect( '/register' ); + } + + var hostname = user.email.split( '@' ).pop(); + + if( /^(finalsclub.org|sleepless.com)$/.test( hostname ) ) { + user.admin = true; + } + + user.save( function( err ) { + if ( err ) { + if( /dup key/.test( err.message ) ) { + // attempting to register an existing address + User.findOne({ 'email' : user.email }, function(err, result ) { + if (result.activated) { + req.flash( 'error', 'There is already someone registered with this email, if this is in error contact info@finalsclub.org for help' ) + return res.redirect( '/register' ) + } else { + req.flash( 'error', 'There is already someone registered with this email, if this is you, please check your email for the activation code' ) + return res.redirect( '/resendActivation' ) + } + }); + } else { + req.flash( 'error', 'An error occurred during registration.' ); + + return res.redirect( '/register' ); + } + } else { + // send user activation email + sendUserActivation( user ); + + School.findOne( { 'hostnames' : hostname }, function( err, school ) { + if( school ) { + sendUserWelcome( user, true ); + log3('school recognized '+school.name); + if (!school.users) school.users = []; + school.users.push( user._id ); + + school.save( function( err ) { + log3('school.save() done'); + req.flash( 'info', 'You have automatically been added to the ' + school.name + ' network. Please check your email for the activation link' ); + res.redirect( '/' ); + }); + var message = { + 'to' : ADMIN_EMAIL, + + 'subject' : 'FC User Registration : User added to ' + school.name, + + 'template' : 'userSchool', + 'locals' : { + 'user' : user + } + } + } else { + sendUserWelcome( user, false ); + req.flash( 'info', 'Your account has been created, please check your email for the activation link' ) + res.redirect( '/' ); + var message = { + 'to' : ADMIN_EMAIL, + + 'subject' : 'FC User Registration : Email did not match any schools', + + 'template' : 'userNoSchool', + 'locals' : { + 'user' : user + } + } + } + mailer.send( message, function( err, result ) { + if ( err ) { + + console.log( 'Error sending user has no school email to admin\nError Message: '+err.Message ); + } else { + console.log( 'Successfully sent user has no school email to admin.' ); + } + }) + + }); + } + + }); +}); + +app.get( '/resendActivation', function( req, res ) { + var activateCode = req.session.activateCode; + + User.findById( activateCode, function( err, user ) { + if( ( ! user ) || ( user.activated ) ) { + res.redirect( '/' ); + } else { + sendUserActivation( user ); + + req.flash( 'info', 'Your activation code has been resent.' ); + + res.redirect( '/login' ); + } + }); +}); + +app.get( '/activate/:code', function( req, res ) { + var code = req.params.code; + + // could break this out into a middleware + if( ! code ) { + res.redirect( '/' ); + } + + User.findById( code, function( err, user ) { + if( err || ! user ) { + req.flash( 'error', 'Invalid activation code!' ); + + res.redirect( '/' ); + } else { + user.activated = true; + + // regenerate our session and log in as the new user + req.session.regenerate( function() { + user.session = req.sessionID; + + user.save( function( err ) { + if( err ) { + req.flash( 'error', 'Unable to activate account.' ); + + res.redirect( '/' ); + } else { + req.flash( 'info', 'Account successfully activated. Please complete your profile.' ); + + res.redirect( '/profile' ); + } + }); + }); + } + }); +}); + +app.get( '/logout', function( req, res ) { + var sid = req.sessionID; + + User.findOne( { 'session' : sid }, function( err, user ) { + if( user ) { + user.session = ''; + + user.save( function( err ) { + res.redirect( '/' ); + }); + } else { + res.redirect( '/' ); + } + }); +}); + +app.get( '/profile', loadUser, loggedIn, function( req, res ) { + var user = req.user; + + res.render( 'profile/index', { 'user' : user } ); +}); + +app.post( '/profile', loadUser, loggedIn, function( req, res ) { + var user = req.user; + var fields = req.body; + + var error = false; + var wasComplete = user.isComplete; + + if( ! fields.name ) { + req.flash( 'error', 'Please enter a valid name!' ); + + error = true; + } else { + user.name = fields.name; + } + + if( [ 'Student', 'Teachers Assistant' ].indexOf( fields.affiliation ) == -1 ) { + req.flash( 'error', 'Please select a valid affiliation!' ); + + error = true; + } else { + user.affil = fields.affiliation; + } + + if( fields.existingPassword || fields.newPassword || fields.newPasswordConfirm ) { + // changing password + if( ( ! user.hashed ) || user.authenticate( fields.existingPassword ) ) { + if( fields.newPassword === fields.newPasswordConfirm ) { + // test password strength? + + user.password = fields.newPassword; + } else { + req.flash( 'error', 'Mismatch in new password!' ); + + error = true; + } + } else { + req.flash( 'error', 'Please supply your existing password.' ); + + error = true; + } + } + + user.major = fields.major; + user.bio = fields.bio; + + user.showName = ( fields.showName ? true : false ); + + if( ! error ) { + user.save( function( err ) { + if( err ) { + req.flash( 'error', 'Unable to save user profile!' ); + } else { + if( ( user.isComplete ) && ( ! wasComplete ) ) { + req.flash( 'info', 'Your account is now fully activated. Thank you for joining FinalsClub!' ); + + res.redirect( '/' ); + } else { + res.render( 'info', 'Your profile was successfully updated!' ); + + res.render( 'profile/index', { 'user' : user } ); + } + } + }); + } else { + res.render( 'profile/index', { 'user' : user } ); + } +}); + + +// Old Notes + +function loadSubject( req, res, next ) { + if( url.parse( req.url ).pathname.match(/subject/) ) { + ArchivedSubject.findOne({id: req.params.id }, function(err, subject) { + if ( err ) { + req.flash( 'error', 'Subject with this ID does not exist' ) + res.redirect( '/archive' ); + } else { + req.subject = subject; + next() + } + }) + } else { + next() + } +} + +function loadOldCourse( req, res, next ) { + if( url.parse( req.url ).pathname.match(/course/) ) { + ArchivedCourse.findOne({id: req.params.id }, function(err, course) { + if ( err ) { + req.flash( 'error', 'Course with this ID does not exist' ) + res.redirect( '/archive' ); + } else { + req.course = course; + next() + } + }) + } else { + next() + } +} + +var featuredCourses = [ + {name: 'The Human Mind', 'id': 1563}, + {name: 'Justice', 'id': 797}, + {name: 'Protest Literature', 'id': 1681}, + {name: 'Animal Cognition', 'id': 681}, + {name: 'Positive Psychology', 'id': 1793}, + {name: 'Social Psychology', 'id': 660}, + {name: 'The Book from Gutenberg to the Internet', 'id': 1439}, + {name: 'Cyberspace in Court', 'id': 1446}, + {name: 'Nazi Cinema', 'id': 2586}, + {name: 'Media and the American Mind', 'id': 2583}, + {name: 'Social Thought in Modern America', 'id': 2585}, + {name: 'Major British Writers II', 'id': 869}, + {name: 'Civil Procedure', 'id': 2589}, + {name: 'Evidence', 'id': 2590}, + {name: 'Management of Industrial and Nonprofit Organizations', 'id': 2591}, +]; + +app.get( '/learn', loadUser, function( req, res ) { + res.render( 'archive/learn', { 'courses' : featuredCourses } ); +}) + +app.get( '/learn/random', loadUser, function( req, res ) { + res.redirect( '/archive/course/'+ featuredCourses[Math.floor(Math.random()*featuredCourses.length)].id); +}) + +app.get( '/archive', loadUser, function( req, res ) { + ArchivedSubject.find({}).sort( 'name', '1' ).run( function( err, subjects ) { + if ( err ) { + req.flash( 'error', 'There was a problem gathering the archived courses, please try again later.' ); + res.redirect( '/' ); + } else { + res.render( 'archive/index', { 'subjects' : subjects } ); + } + }) +}) + +app.get( '/archive/subject/:id', loadUser, loadSubject, function( req, res ) { + ArchivedCourse.find({subject_id: req.params.id}).sort('name', '1').run(function(err, courses) { + if ( err ) { + req.flash( 'error', 'There are no archived courses' ); + res.redirect( '/' ); + } else { + res.render( 'archive/courses', { 'courses' : courses, 'subject': req.subject } ); + } + }) +}) + +app.get( '/archive/course/:id', loadUser, loadOldCourse, function( req, res ) { + ArchivedNote.find({course_id: req.params.id}).sort('name', '1').run(function(err, notes) { + if ( err ) { + req.flash( 'error', 'There are no notes in this course' ); + res.redirect( '/archive' ); + } else { + res.render( 'archive/notes', { 'notes' : notes, 'course' : req.course } ); + } + }) +}) + +app.get( '/archive/note/:id', loadUser, function( req, res ) { + ArchivedNote.findById(req.params.id, function(err, note) { + if ( err ) { + req.flash( 'error', 'This is not a valid id for a note' ); + res.redirect( '/archive' ); + } else { + ArchivedCourse.findOne({id: note.course_id}, function(err, course) { + if ( err ) { + req.flash( 'error', 'There is no course for this note' ) + res.redirect( '/archive' ) + } else { + res.render( 'archive/note', { 'layout' : 'notesLayout', 'note' : note, 'course': course } ); + } + }) + } + }) +}) + +// socket.io server + +var io = require( 'socket.io' ).listen( app ); + +var Post = mongoose.model( 'Post' ); + +io.set('authorization', function ( handshake, next ) { + var rawCookie = handshake.headers.cookie; + if (rawCookie) { + handshake.cookie = parseCookie(rawCookie); + handshake.sid = handshake.cookie['connect.sid']; + + if ( handshake.sid ) { + app.set( 'sessionStore' ).get( handshake.sid, function( err, session ) { + if( err ) { + handshake.user = false; + return next(null, true); + } else { + // bake a new session object for full r/w + handshake.session = new Session( handshake, session ); + + User.findOne( { session : handshake.sid }, function( err, user ) { + if( user ) { + handshake.user = user; + return next(null, true); + } else { + handshake.user = false; + return next(null, true); + } + }); + } + }) + } + } else { + data.user = false; + return next(null, true); + } +}); + + +var backchannel = io + .of( '/backchannel' ) + .on( 'connection', function( socket ) { + + socket.on('subscribe', function(lecture, cb) { + socket.join(lecture); + Post.find({'lecture': lecture}, function(err, posts) { + if (socket.handshake.user) { + cb(posts); + } else { + var posts = posts.filter( + function(post) { + if (post.public) + return post; + } + ) + cb(posts) + } + }); + }); + + socket.on('post', function(res) { + var post = new Post; + var _post = res.post; + var lecture = res.lecture; + post.lecture = lecture; + if ( _post.anonymous ) { + post.userid = 0; + post.userName = 'Anonymous'; + post.userAffil = 'N/A'; + } else { + post.userName = _post.userName; + post.userAffil = _post.userAffil; + } + + post.public = _post.public; + post.date = new Date(); + post.body = _post.body; + post.votes = []; + post.reports = []; + post.save(function(err) { + if (err) { + // XXX some error handling + console.log(err); + } else { + if (post.public) { + backchannel.in(lecture).emit('post', post); + } else { + privateEmit(lecture, 'post', post); + } + } + }); + }); + + socket.on('vote', function(res) { + var vote = res.vote; + var lecture = res.lecture; + Post.findById(vote.parentid, function( err, post ) { + if (!err) { + if (post.votes.indexOf(vote.userid) == -1) { + post.votes.push(vote.userid); + post.save(function(err) { + if (err) { + // XXX error handling + } else { + if (post.public) { + backchannel.in(lecture).emit('vote', vote); + } else { + privteEmit(lecture, 'vote', vote); + } + } + }); + } + } + }) + }); + + socket.on('report', function(res) { + var report = res.report; + var lecture = res.lecture; + Post.findById(report.parentid, function( err, post ){ + if (!err) { + if (post.reports.indexOf(report.userid) == -1) { + post.reports.push(report.userid); + post.save(function(err) { + if (err) { + // XXX error handling + } else { + if (post.public) { + backchannel.in(lecture).emit('report', report); + } else { + privateEmit(lecture, 'report', report); + } + } + }); + } + } + }) + }); + + socket.on('comment', function(res) { + var comment = res.comment; + var lecture = res.lecture; + console.log('anon', comment.anonymous); + if ( comment.anonymous ) { + comment.userid = 0; + comment.userName = 'Anonymous'; + comment.userAffil = 'N/A'; + } + Post.findById(comment.parentid, function( err, post ) { + if (!err) { + post.comments.push(comment); + post.date = new Date(); + post.save(function(err) { + if (err) { + console.log(err); + } else { + if (post.public) { + backchannel.in(lecture).emit('comment', comment); + } else { + privateEmit(lecture, 'comment', comment); + } + } + }) + } + }) + }); + + function privateEmit(lecture, event, data) { + backchannel.clients(lecture).forEach(function(socket) { + if (socket.handshake.user) + socket.emit(event, data); + }) + } + + socket.on('disconnect', function() { + //delete clients[socket.id]; + }); + }); + + +var counters = {}; + +var counts = io +.of( '/counts' ) +.on( 'connection', function( socket ) { + // pull out user/session information etc. + var handshake = socket.handshake; + var userID = handshake.user._id; + + var watched = []; + var noteID = null; + + var timer = null; + + socket.on( 'join', function( note ) { + if (handshake.user === false) { + noteID = note; + // XXX: replace by addToSet (once it's implemented in mongoose) + Note.findById( noteID, function( err, note ) { + if( note ) { + if( note.collaborators.indexOf( userID ) == -1 ) { + note.collaborators.push( userID ); + note.save(); + } + } + }); + } + }); + + socket.on( 'watch', function( l ) { + var sendCounts = function() { + var send = {}; + + Note.find( { '_id' : { '$in' : watched } }, function( err, notes ) { + async.forEach( + notes, + function( note, callback ) { + var id = note._id; + var count = note.collaborators.length; + + send[ id ] = count; + + callback(); + }, function() { + socket.emit( 'counts', send ); + + timer = setTimeout( sendCounts, 5000 ); + } + ); + }); + } + + Note.find( { 'lecture' : l }, [ '_id' ], function( err, notes ) { + notes.forEach( function( note ) { + watched.push( note._id ); + }); + }); + + sendCounts(); + }); + + socket.on( 'disconnect', function() { + clearTimeout( timer ); + + if (handshake.user === false) { + // XXX: replace with $pull once it's available + if( noteID ) { + Note.findById( noteID, function( err, note ) { + if( note ) { + var index = note.collaborators.indexOf( userID ); + + if( index != -1 ) { + note.collaborators.splice( index, 1 ); + } + + note.save(); + } + }); + } + } + }); +}); + +// Exception Catch-All + +process.on('uncaughtException', function (e) { + console.log("!!!!!! UNCAUGHT EXCEPTION\n" + e.stack); +}); + + +// Launch + +mongoose.connect( app.set( 'dbUri' ) ); +mongoose.connection.db.serverConfig.connection.autoReconnect = true + +var mailer = new Mailer( app.set('awsAccessKey'), app.set('awsSecretKey') ); + +app.listen( serverPort, function() { + console.log( "Express server listening on port %d in %s mode", app.address().port, app.settings.env ); + + // if run as root, downgrade to the owner of this file + if (process.getuid() === 0) { + require('fs').stat(__filename, function(err, stats) { + if (err) { return console.log(err); } + process.setuid(stats.uid); + }); + } +}); + +function isValidEmail(email) { + var re = /[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/; + return email.match(re); +} diff --git a/bruml/README.markdown b/bruml/README.markdown new file mode 100644 index 0000000..c4074d3 --- /dev/null +++ b/bruml/README.markdown @@ -0,0 +1,9 @@ +# backchannel + +is a reimplementation of the features of backchan.nl using a node.js +server with the socket.io module. It is intended for HTML5 capable +browsers supporting websockets. The project will migrate towards a component +stucture with a javascript library to be used on the HTML page and a node +module to be used on the server, each containing no presentation. Examples +of practical ways to skin the functionality will available as part of the +project. \ No newline at end of file diff --git a/bruml/archive/backchan-chatpage-orig.html b/bruml/archive/backchan-chatpage-orig.html new file mode 100644 index 0000000..e0227a8 --- /dev/null +++ b/bruml/archive/backchan-chatpage-orig.html @@ -0,0 +1,183 @@ + + + + + backchan.nl -- Meetings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ + + + +
+

Demo Conference

+

First meeting (13:00 — 17:00)

+ +Welcome to backchan.nl! This tool is a way for people in the audience to post responses to the panel live, and in a publicly visible venue. These responses can be questions, comments, links to related resources, or whatever else you think other people might be interested in. + +Even if you don't have anything to say, you can vote posts up or down that you think are useful or problematic. Highly ranked and comments will get brought up during the discussion section of the panel. +
+
+ + +
+ +
+
+ + b
+ + student +
+
+ + +
+
+ +
+
Who are you?
+
+
+ + + + + + + + + +
+ +
+ +
+
+
+
+ +
+
Conference Administration Password
+
+
+ + + + + + + + + +
+ Demo Conference
+ +
+
+
+
+ +
+
+ + + characters left: + + +
+
+ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+ + + + \ No newline at end of file diff --git a/bruml/archive/backchan.chatpage.html b/bruml/archive/backchan.chatpage.html new file mode 100644 index 0000000..e0227a8 --- /dev/null +++ b/bruml/archive/backchan.chatpage.html @@ -0,0 +1,183 @@ + + + + + backchan.nl -- Meetings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ + + + +
+

Demo Conference

+

First meeting (13:00 — 17:00)

+ +Welcome to backchan.nl! This tool is a way for people in the audience to post responses to the panel live, and in a publicly visible venue. These responses can be questions, comments, links to related resources, or whatever else you think other people might be interested in. + +Even if you don't have anything to say, you can vote posts up or down that you think are useful or problematic. Highly ranked and comments will get brought up during the discussion section of the panel. +
+
+ + +
+ +
+
+ + b
+ + student +
+
+ + +
+
+ +
+
Who are you?
+
+
+ + + + + + + + + +
+ +
+ +
+
+
+
+ +
+
Conference Administration Password
+
+
+ + + + + + + + + +
+ Demo Conference
+ +
+
+
+
+ +
+
+ + + characters left: + + +
+
+ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+ + + + \ No newline at end of file diff --git a/bruml/archive/bcfunctions.demo.html b/bruml/archive/bcfunctions.demo.html new file mode 100644 index 0000000..957020c --- /dev/null +++ b/bruml/archive/bcfunctions.demo.html @@ -0,0 +1,108 @@ + + + + + + + FinalsClub -- BC functions + + + + +
+ + +
+

The Human Mind

+

Lecture #6: April 3, 2001: Evolution

+

Use this section to react to the lecture: your posts will be seen by others immediately, and they can respond or vote your post up or down. Your post can be a question, comment, link to something related to the lecture, or whatever else you think other people might be interested in.

+

Even if you don't have anything to say, you can vote posts up or down that you think are useful or problematic. Highly ranked and comments will get brought up during the discussion section of the panel.

+
+ +
+
+
Beardsley
+
student
+
+ + +
+
+ +
+
Who are you?
+
+
+ + + + + + + + + +
+ +
+ +
+
+
+
+ +
+
Conference Administration Password
+
+
+ + + + + + + + + +
+ Demo Conference
+ +
+
+
+
+ +
+
+ + + characters left: + + +
+
+ +
+
+ +
+ +
+
diff --git a/bruml/images/accept.png b/bruml/images/accept.png new file mode 100755 index 0000000000000000000000000000000000000000..89c8129a490b329f3165f32fa0781701aab417ea GIT binary patch literal 781 zcmV+o1M>WdP)4-QibtN)VXQDpczE`xXAkUjh%RI>;okxb7K@0kpyQ1k_Y(|Oe7$m(^ zNYX>mI||sUbmn+c3<&FnE=4u#()KBS^SH8e)Qs5i!#lY=$-1gbH6VluzU=m=EP78&5vQ z-?+fFP-G2l&l_QzYealK$;1Rl?FkzXR&Jv@fBPNjCr#AYRyJ7UJQ0v#?)7Ott=>3`#-pV!7>9}>Q1jL)H6h&gkP@3nI=+F3nA~M>u#(n* z8T!#8oEw&-mED4!h4s!N@Jo3S7N&Q6%6l3}nlcd~X@>;uelvPsSkXIgg~e+^T1zSf z3SNj(5%jK~i8@b;C0fhdEP)RB*?~^j!LKVQ>(O&A{Xr%)RXLn#U zs4LtZ6rCMFY5|B2$)yG$6aaIF6w#wHUuW*nL5>vZR zlg{G&%mT~|kL3ei%GW0*UOHUMs5XI$4uxe-L?I@SAefq*207}Iqtjm#e5*fP53AiC z)C|RQfwzxx<#_WfANRGZx{+tFDl8~Q?;~Ve=lM^*8UTTnVL?HTDz8uta0D@d28E9S z_)i8aLz^UE6PPKymi;2GJ`34{eIia-CtfAt0H61rk0 SPTNud0000C4}Mrzlg<+1Y8PEBfUp0jJpx4B>@E+cy3`^(Gw`Mf+2&yxZm<$to~Vpgvg&QKNR z_f#1(r6svZt%iF?s+n<8X?B&!h3g9Dbb8_=MX}!;HiQSAh`bp^WMl~Z-44teO7W_Y zV4thSL{h;rJY7!l3%5J4H1!tIzB`Dv+YxO(haWeausGZYkI8^hWj6mzo=L0{%;yxzh{5!Htr?51 zvG|W62MzC8BZ76hRpCyO2zOn<%e)K>NHge!-~)Ap33OdWw6hsLYbCxGNt0%wk_2z7 zfyYvXheSG)5HRK1VB~%mq7Dmurw#bi@hEcOr3&G1ZiF*$M=&9nB#VNf&Q^r$4G5kp zTURh&s)E0%5&hyVD}sp<72~zmAY`Y(9aqO6CXF%=zFHGzO-A&I(pE}v70YQxCPJ{Y z4L+?5-crdLn3ZRPEs!A4ehEY3ZRpL~w9>@aMN+{F4dI@v&>(QDHQum!mG~E^$OS8l z!7?%Uwib*ROP67Hw`ika)gX-(8Ia`-u_IEhxG7U<13kSsMW+$lbb2dUMm5p6pa}cjgA+U$^mJ^AjD?&bdi)8~y+Q002ovPDHLkV1g8IMc@Dc literal 0 HcmV?d00001 diff --git a/bruml/lib/paperboy/.package.json.un~ b/bruml/lib/paperboy/.package.json.un~ new file mode 100644 index 0000000000000000000000000000000000000000..0f260ec20c3368e6c2238abba5ed9133d77cf2ae GIT binary patch literal 563 zcmWH`%$*;a=aT=FfvJdBVgK&t)M@KnB7St-y2@txn|*)I=EVMG^{a#K9auY`fq{V= zh(#0>l*&?ziZk=`l&q8t^bGV2m2`mOEI=#>#Eei3q~L6j7=y2E^ePsJZ2Sd~02%;E u!3<&e4+LQCXo^O;)CvJ$bgYC%$5#oUq0B(c3dEo|21Nzdcs6Z(z6t=xGAp(K literal 0 HcmV?d00001 diff --git a/bruml/lib/paperboy/LICENSE.txt b/bruml/lib/paperboy/LICENSE.txt new file mode 100644 index 0000000..6bd40a2 --- /dev/null +++ b/bruml/lib/paperboy/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2010 Debuggable Limited + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/bruml/lib/paperboy/README.md b/bruml/lib/paperboy/README.md new file mode 100644 index 0000000..1c7e004 --- /dev/null +++ b/bruml/lib/paperboy/README.md @@ -0,0 +1,96 @@ +# Paperboy + +## Purpose + +A node.js module for delivering static files. + +## Features + + * Configurable callbacks on most events + * ETag / 304 Support + * Custom HTTP headers + +## Example + +Example from example/basic.js: + + var + path = require('path'), + http = require('http'), + paperboy = require('../lib/paperboy'), + + PORT = 8003, + WEBROOT = path.join(path.dirname(__filename), 'webroot'); + + http.createServer(function(req, res) { + var ip = req.connection.remoteAddress; + paperboy + .deliver(WEBROOT, req, res) + .addHeader('Expires', 300) + .addHeader('X-PaperRoute', 'Node') + .before(function() { + console.log('Received Request'); + }) + .after(function(statCode) { + log(statCode, req.url, ip); + }) + .error(function(statCode, msg) { + res.writeHead(statCode, {'Content-Type': 'text/plain'}); + res.end("Error " + statCode); + log(statCode, req.url, ip, msg); + }) + .otherwise(function(err) { + res.writeHead(404, {'Content-Type': 'text/plain'}); + res.end("Error 404: File not found"); + log(404, req.url, ip, err); + }); + }).listen(PORT); + + function log(statCode, url, ip, err) { + var logStr = statCode + ' - ' + url + ' - ' + ip; + if (err) + logStr += ' - ' + err; + console.log(logStr); + } + +## API Docs + +### paperboy.deliver(webroot, req, res) + +Checks the `webroot` folder if it has a file that matches the `req.url` and streams it to the client. If `req.url` ends with a '/' (slash), 'index.html' is appended automatically. + +Parameters: + +* `webroot`: Absolute path where too look for static files to serve +* `req`: A `http.ServerRequest` object +* `res`: A `http.ServerResponse` object + +This returns an object with several functions that you can call, to modify how the static content is delivered. Each of these functions returns the object, so you can chain them, as shown in the example above. They each take a callback function, whose arguments and expected behavior are detailed below. + +#### before(callback()) + +Fires if a matching file was found in the `webroot` and is about to be delivered. The delivery can be canceled by returning `false` from within the callback. + +#### after(callback(statCode)) + +Fires after a file has been successfully delivered from the `webroot`. `statCode` contains the numeric HTTP status code that was sent to the client. You must close the connection yourself if the error callback fires! + +#### error(callback(statCode, msg)) + +Fires if there was an error delivering a file from the `webroot`. `statCode` contains the numeric HTTP status code that was sent to the client. `msg` contains the error message. You must close the connection yourself if the error callback fires! The default callback shows a minimal HTTP error page. + +#### otherwise(callback(err)) + +Fires if no matching file was found in the `webroot`. Also fires if `false` was returned in the `delegate.before()` callback. If there was a problem stating the file, `err` is set to the contents of that error message. The default callback shows a simple "HTTP 404 File Not Found" page. + +#### addHeader(callback(name, value)) + +Sets an arbitrary HTTP header. The header name `Expires` is special and expects the number of milliseconds till expiry, from which it will calculate the proper HTTP date. + +## License + +Paperboy is licensed under the MIT license. + +## Credits + +* [Jan Lehnardt](http://twitter.com/janl) for coming up with the name "Paperboy" diff --git a/bruml/lib/paperboy/example/basic.js b/bruml/lib/paperboy/example/basic.js new file mode 100644 index 0000000..bbc3fda --- /dev/null +++ b/bruml/lib/paperboy/example/basic.js @@ -0,0 +1,38 @@ +var + path = require('path'), + http = require('http'), + paperboy = require('../lib/paperboy'), + + PORT = 8003, + WEBROOT = path.join(path.dirname(__filename), 'webroot'); + +http.createServer(function(req, res) { + var ip = req.connection.remoteAddress; + paperboy + .deliver(WEBROOT, req, res) + .addHeader('Expires', 300) + .addHeader('X-PaperRoute', 'Node') + .before(function() { + console.log('Received Request'); + }) + .after(function(statCode) { + log(statCode, req.url, ip); + }) + // .error(function(statCode, msg) { + // res.writeHead(statCode, {'Content-Type': 'text/plain'}); + // res.end("Error " + statCode); + // log(statCode, req.url, ip, msg); + // }) + // .otherwise(function(err) { + // res.writeHead(404, {'Content-Type': 'text/plain'}); + // res.end("Error 404: File not found"); + // log(404, req.url, ip, err); + // }); +}).listen(PORT); + +function log(statCode, url, ip, err) { + var logStr = statCode + ' - ' + url + ' - ' + ip; + if (err) + logStr += ' - ' + err; + console.log(logStr); +} diff --git a/bruml/lib/paperboy/example/webroot/img/paperboy.jpg b/bruml/lib/paperboy/example/webroot/img/paperboy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b9b140f92889a3816e12ce89cd9a236515113525 GIT binary patch literal 120181 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�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 + + + + Paperboy Example + + +

It works!

+ + + \ No newline at end of file diff --git a/bruml/lib/paperboy/index.js b/bruml/lib/paperboy/index.js new file mode 100644 index 0000000..ba5cbcc --- /dev/null +++ b/bruml/lib/paperboy/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/paperboy'); \ No newline at end of file diff --git a/bruml/lib/paperboy/lib/paperboy.js b/bruml/lib/paperboy/lib/paperboy.js new file mode 100644 index 0000000..c232216 --- /dev/null +++ b/bruml/lib/paperboy/lib/paperboy.js @@ -0,0 +1,302 @@ +var + events = require('events'), + fs = require('fs'), + url = require('url'), + path = require('path'); + +exports.filepath = function (webroot, url) { + // Unescape URL to prevent security holes + url = decodeURIComponent(url); + // Append index.html if path ends with '/' + fp = path.normalize(path.join(webroot, (url.match(/\/$/)=='/') ? url+'index.html' : url)); + // Sanitize input, make sure people can't use .. to get above webroot + if (webroot[webroot.length - 1] !== '/') webroot += '/'; + if (fp.substr(0, webroot.length) != webroot) + return(['Permission Denied', null]); + else + return([null, fp]); +}; + +exports.streamFile = function (filepath, headerFields, stat, res, req, emitter) { + var + emitter = new events.EventEmitter(), + extension = filepath.split('.').pop(), + contentType = exports.contentTypes[extension] || 'application/octet-stream', + charset = exports.charsets[contentType]; + + process.nextTick( function() { + if (charset) + contentType += '; charset=' + charset; + headerFields['Content-Type'] = contentType; + + var etag = '"' + stat.ino + '-' + stat.size + '-' + Date.parse(stat.mtime) +'"'; + headerFields['ETag'] = etag; + + var statCode; + //Check to see if we can send a 304 and skip the send + if(req.headers['if-none-match'] == etag){ + statCode = 304; + headerFields['Content-Length'] = 0; + }else { + headerFields['Content-Length'] = stat.size; + statCode = 200; + if (headerFields['Expires'] != undefined) { + var expires = new Date; + expires.setTime(expires.getTime() + headerFields['Expires']); + headerFields['Expires'] = expires.toUTCString(); + } + } + + res.writeHead(statCode, headerFields); + + //If we sent a 304, skip sending a body + if (statCode == 304 || req.method === 'HEAD') { + res.end(); + emitter.emit("success", statCode); + } + else { + fs.createReadStream(filepath,{'flags': 'r', 'encoding': + 'binary', 'mode': 0666, 'bufferSize': 4 * 1024}) + .addListener("data", function(chunk){ + res.write(chunk, 'binary'); + }) + .addListener("end", function(){ + emitter.emit("success", statCode); + }) + .addListener("close",function() { + res.end(); + }) + .addListener("error", function (e) { + emitter.emit("error", 500, e); + }); + } + }); + return emitter; +}; + +exports.deliver = function (webroot, req, res) { + var + stream, + fpRes = exports.filepath(webroot, url.parse(req.url).pathname), + fpErr = fpRes[0], + filepath = fpRes[1], + beforeCallback, + afterCallback, + otherwiseCallback, + errorCallback, + headerFields = {}, + addHeaderCallback, + delegate = { + error: function (callback) { + errorCallback = callback; + return delegate; + }, + before: function (callback) { + beforeCallback = callback; + return delegate; + }, + after: function (callback) { + afterCallback = callback; + return delegate; + }, + otherwise: function (callback) { + otherwiseCallback = callback; + return delegate; + }, + addHeader: function (name, value) { + headerFields[name] = value; + return delegate; + } + }; + + process.nextTick(function() { + // Create default error and otherwise callbacks if none were given. + errorCallback = errorCallback || function(statCode) { + res.writeHead(statCode, {'Content-Type': 'text/html'}); + res.end("

HTTP " + statCode + "

"); + }; + otherwiseCallback = otherwiseCallback || function() { + res.writeHead(404, {'Content-Type': 'text/html'}); + res.end("

HTTP 404 File not found

"); + }; + + //If file is in a directory outside of the webroot, deny the request + if (fpErr) { + statCode = 403; + if (beforeCallback) + beforeCallback(); + errorCallback(403, 'Forbidden'); + } + else { + fs.stat(filepath, function (err, stat) { + if( (err || !stat.isFile())) { + var exactErr = err || 'File not found'; + if (beforeCallback) + beforeCallback(); + if (otherwiseCallback) + otherwiseCallback(exactErr); + } else { + //The before callback can abort the transfer by returning false + var cancel = beforeCallback && (beforeCallback() === false); + if (cancel && otherwiseCallback) { + otherwiseCallback(); + } + else { + stream = exports.streamFile(filepath, headerFields, stat, res, req) + + if(afterCallback){ + stream.addListener("success", afterCallback); + } + if(errorCallback){ + stream.addListener("error", errorCallback); + } + } + } + }); + } + }); + + return delegate; +}; + +exports.contentTypes = { + "aiff": "audio/x-aiff", + "arj": "application/x-arj-compressed", + "asf": "video/x-ms-asf", + "asx": "video/x-ms-asx", + "au": "audio/ulaw", + "avi": "video/x-msvideo", + "bcpio": "application/x-bcpio", + "ccad": "application/clariscad", + "cod": "application/vnd.rim.cod", + "com": "application/x-msdos-program", + "cpio": "application/x-cpio", + "cpt": "application/mac-compactpro", + "csh": "application/x-csh", + "css": "text/css", + "deb": "application/x-debian-package", + "dl": "video/dl", + "doc": "application/msword", + "drw": "application/drafting", + "dvi": "application/x-dvi", + "dwg": "application/acad", + "dxf": "application/dxf", + "dxr": "application/x-director", + "etx": "text/x-setext", + "ez": "application/andrew-inset", + "fli": "video/x-fli", + "flv": "video/x-flv", + "gif": "image/gif", + "gl": "video/gl", + "gtar": "application/x-gtar", + "gz": "application/x-gzip", + "hdf": "application/x-hdf", + "hqx": "application/mac-binhex40", + "html": "text/html", + "ice": "x-conference/x-cooltalk", + "ief": "image/ief", + "igs": "model/iges", + "ips": "application/x-ipscript", + "ipx": "application/x-ipix", + "jad": "text/vnd.sun.j2me.app-descriptor", + "jar": "application/java-archive", + "jpeg": "image/jpeg", + "jpg": "image/jpeg", + "js": "text/javascript", + "json": "application/json", + "latex": "application/x-latex", + "lsp": "application/x-lisp", + "lzh": "application/octet-stream", + "m": "text/plain", + "m3u": "audio/x-mpegurl", + "man": "application/x-troff-man", + "me": "application/x-troff-me", + "midi": "audio/midi", + "mif": "application/x-mif", + "mime": "www/mime", + "movie": "video/x-sgi-movie", + "mp4": "video/mp4", + "mpg": "video/mpeg", + "mpga": "audio/mpeg", + "ms": "application/x-troff-ms", + "nc": "application/x-netcdf", + "oda": "application/oda", + "ogm": "application/ogg", + "pbm": "image/x-portable-bitmap", + "pdf": "application/pdf", + "pgm": "image/x-portable-graymap", + "pgn": "application/x-chess-pgn", + "pgp": "application/pgp", + "pm": "application/x-perl", + "png": "image/png", + "pnm": "image/x-portable-anymap", + "ppm": "image/x-portable-pixmap", + "ppz": "application/vnd.ms-powerpoint", + "pre": "application/x-freelance", + "prt": "application/pro_eng", + "ps": "application/postscript", + "qt": "video/quicktime", + "ra": "audio/x-realaudio", + "rar": "application/x-rar-compressed", + "ras": "image/x-cmu-raster", + "rgb": "image/x-rgb", + "rm": "audio/x-pn-realaudio", + "rpm": "audio/x-pn-realaudio-plugin", + "rtf": "text/rtf", + "rtx": "text/richtext", + "scm": "application/x-lotusscreencam", + "set": "application/set", + "sgml": "text/sgml", + "sh": "application/x-sh", + "shar": "application/x-shar", + "silo": "model/mesh", + "sit": "application/x-stuffit", + "skt": "application/x-koan", + "smil": "application/smil", + "snd": "audio/basic", + "sol": "application/solids", + "spl": "application/x-futuresplash", + "src": "application/x-wais-source", + "stl": "application/SLA", + "stp": "application/STEP", + "sv4cpio": "application/x-sv4cpio", + "sv4crc": "application/x-sv4crc", + "svg": "image/svg+xml", + "swf": "application/x-shockwave-flash", + "tar": "application/x-tar", + "tcl": "application/x-tcl", + "tex": "application/x-tex", + "texinfo": "application/x-texinfo", + "tgz": "application/x-tar-gz", + "tiff": "image/tiff", + "tr": "application/x-troff", + "tsi": "audio/TSP-audio", + "tsp": "application/dsptype", + "tsv": "text/tab-separated-values", + "txt": "text/plain", + "unv": "application/i-deas", + "ustar": "application/x-ustar", + "vcd": "application/x-cdlink", + "vda": "application/vda", + "vivo": "video/vnd.vivo", + "vrm": "x-world/x-vrml", + "wav": "audio/x-wav", + "wax": "audio/x-ms-wax", + "wma": "audio/x-ms-wma", + "wmv": "video/x-ms-wmv", + "wmx": "video/x-ms-wmx", + "wrl": "model/vrml", + "wvx": "video/x-ms-wvx", + "xbm": "image/x-xbitmap", + "xlw": "application/vnd.ms-excel", + "xml": "text/xml", + "xpm": "image/x-xpixmap", + "xwd": "image/x-xwindowdump", + "xyz": "chemical/x-pdb", + "zip": "application/zip" +}; + +exports.charsets = { + 'text/javascript': 'UTF-8', + 'text/html': 'UTF-8' +}; diff --git a/bruml/lib/paperboy/package.json b/bruml/lib/paperboy/package.json new file mode 100644 index 0000000..c8fa0cd --- /dev/null +++ b/bruml/lib/paperboy/package.json @@ -0,0 +1,11 @@ +{ + "name":"paperboy", + "author":"Felix Geisendörfer ", + "version":"0.0.2", + "description":"A node.js module for delivering static files.", + "keywords": ["web", "server"], + "directories": { + "lib": "lib" + }, + "main": "lib/paperboy" +} diff --git a/bruml/lib/paperboy/seed.yml b/bruml/lib/paperboy/seed.yml new file mode 100644 index 0000000..2c3ddf9 --- /dev/null +++ b/bruml/lib/paperboy/seed.yml @@ -0,0 +1,6 @@ +--- + name: paperboy + author: Felix Geisendörfer + version: 0.0.1 + description: A node.js module for delivering static files. + tags: web server \ No newline at end of file diff --git a/bruml/lib/socket.io/History.md b/bruml/lib/socket.io/History.md new file mode 100644 index 0000000..0c3dfe6 --- /dev/null +++ b/bruml/lib/socket.io/History.md @@ -0,0 +1,236 @@ + +0.6.17 / 2011-03-30 +================== + + * Fixed the 'possible EventEmitter memory leak detected' bug for the XHR transport + * Reconnection support added to chat example. [3rd-Eden] + +0.6.16 / 2011-03-04 +=================== + + * Fixed cross domain xhr-polling in Safari [tifroz] + +0.6.15 / 2011-02-23 +=================== + + * Fixed memory leak in WebSocket transport [belorion] + +0.6.14 / 2011-02-18 +=================== + + * Fixed logging scope issue [shripad] + +0.6.13 / 2011-02-18 +=================== + + * Fixed references to listener when logging + +0.6.12 / 2011-02-18 +=================== + + * Fixed noDelay missing file descriptor problem + +0.6.11 / 2011-02-15 +=================== + + * Fixed; Make sure to not execute any other connection operations after WebSocket + write error. + * Added more error logging + +0.6.10 / 2011-02-09 +=================== + + * Added SSL chat example (`make example-ssl`) + * Fixed; possible write errors when a connection error event fires + +0.6.9 / 2011-02-06 +================== + + * 0.3 compatibility + * Updated socket.io client to 0.6.2 + * Fixed Flash inline policy serving for Firefox 4 + * Updated expresso + * Added comments and version number to socket.io/index + +0.6.8 / 2011-01-10 +================== + + * Fixed issue with terminating connection twice + +0.6.7 / 2011-01-09 +================== + + * Fixed situation where the connection drops but the client can still autoreconnect + through a different socket. In this case we still want to clear the FD but not + call onDisconnect immediately. + +0.6.6 / 2011-01-09 +================== + + * Note for Flash socket and inline policy on Firefox + * Destroy the fds on disconnect + * Restored 20 secs of polling so that node doesn't timeout the connections + +0.6.5 / 2011-01-09 +================== + + * Make sure not to trigger multiple timeouts when closing + * Important fix for polling transports. + +0.6.4 / 2011-01-05 +================== + + * Don't destroy the connection in _onClose. Destroying it will prevent the buffers from being flushed and will result in corrupted responses for the xhr-polling transport. + * Added try/catch block around JSON.parse and return an empty object literal if JSON parsing fails. + * Added missing .connect() to example + +0.6.3 / 2010-12-23 +================== + + * Changed polling default duration to 50 seconds + * might > will Adjusted to 85 column limit + * Support for resources that include slashes. Thanks @schamane + * Lazy loading of transports. Thanks @technoweenie Fixed README transports list + * OpenSSL clarifications (thanks @bmnds) + * Support for HAProxy load balancing (thanks Brian McKelvey) Backported Parser from 0.7 + * Fixed HTTP API in example (was outdated). Thanks deedubs + * 0.3 compatibility (thanks Arnout) + * `client.broadcast` now 300% faster Cleaned up chat example + * fixed bad pluralization. + * cleaned up grammar, missing punctuation, etc. + * Restored global `netserver` for flashsocket Now supporting `flashPolicyServer` option (thanks Arnout) Tests passing with and without sudo/root user Fixed noDelay/timeout/utf-8 for draft 76 (accidental typo) + * Close the netServer when the main http server closes, this way the event loop does not keep running. NOTE: this is patch for node 0.2.X, this is not required for node 0.3.X + * Fallback to try{}catch handling for node < 0.2.4 , node 0.3.X seems to capture the errors correctly using the error event. + * Added the flash policy server, it's enabled by default but can be turned off if needed. Socket.io will automatically fallback to serving the policy file inline if server is disabled or unable to start up. + * Make sure to only write to open transports (thanks JohnDav) + * _open is still false, so destroy the connection immediately upon websocket error + * Make sure .connection is not null on 'end' + * Proper fix for invalid websocket key + +0.6.1 / 2010-11-08 + + * Restored flash policy server, but with these changes: + - It's contingent on the listener flashPolicyServer option + - It's started by default if socket.io is started with root access + - It correctly closes the netserver upon all the dependent http servers being closed + - The handler for the inline request is still there regardless. This is important in the following circumstances, and has no performance hit + - The port 843 is filtered + - Flash at some point enables us to skip 843 checking altogether + - Tests compatibility + * Fixed connection timeout, noDelay and socket encoding for draft 76 (had been accidentally moved into the `else` block) + * Some stylistic fixes + +0.6.0 / 2010-11-01 +================== + + * Make sure to only write to open transports (thanks JohnDav) + * _open is still false, so destroy the connection immediately upon websocket error + * Make sure to disconnect directly onClose if the client is not handshaked and he can't possibly reconnect + * Make sure to end and destroy connection onDisconnect (for timeouts) + * Added missing .listen() call to example. Fixes #80. Thanks @machee + * Invalid transport test completed + * Initial stab at trying to detect invalid transport responses + * Make sure to provide a default for `log` if no log key was provided (internal) + * Removed unnecessary file extension verification when serving the client + * Removed unnecessary Client check upon connection + * Added support for /socket.io/WebSocketMain.swf + * Added test for /socket.io/WebSocketMain.swf + * Client serving ETag testing + * Added htmlfile transport tests + * Added extra byte to IE iframe bytes padding + * Invalid session id test + * end() before destroy()ing the socket for non-WebSocket or non-valid Upgrade requests + * Added test for non-socket.io requests + * Simplified index.js tests + * Moved listener tests into listener.js + * Make sure to call .end() when listening on connection 'end' event + * Make sure the file descriptor is destroyed on disconnection + * Fix for websocket client tracking test + * Inline (same port) flash socket policy request. + * If the server is not run with root privileges, then the flashsocket + transport will instead listen to all new connections on the main port + for policy requests. Flash policy requests happen to both port 843 and + the destination port: + http://www.lightsphere.com/dev/articles/flash_socket_policy.html + + * [websocket test] Fix sending message to client upon connecting + * [websocket test] Fix for connection and handshake test + * [client files serving] Leverage end() write() call + * [client serving] Make sure to not do a useless file lookup when file is cached + * Finished json encoding test + * Look for the heartbeat in the decoded message + * Refactored websocket transports tests to match polling/multipart helpers + * Added coverage testing to Makefile + * Added heartbeat test to multipart + * Added buffered messages test for multipart + * Added assertions for `connected` property for all the tests + * Multipart clients tracking test + * Multipart client>server message sending test + * Make sure to only close the client stream when the roundtrip is complete + * Multipart connection and handshake tests: + - Implemented HTTP client on top of net.Stream with multipart boundary parsing for testing + - Test for connection / server>client message sending + * Removed unnecessary check for this.connection (since we now access the socket through req.connection for all transports) + * Test for `duration` parameter + * Added `make example` to Makefile + * Added clients tracking test for long polling + * Added message buffering test for long polling + * Improve this.request/this.response/this.connection + * Add 'end' listener onConnect, applies to all transports + * Improved error handling onConnect + * Remove legacy `flush` calls + * Removed unnecessary closeTimeout clearing in jsonp polling + * Make sure to close on disconnect if _open = true + * Clear disconnection timeout on disconnection (double check) + * Make sure to clear closeTimeout for polling transports on close. + * Replaced empty with null in log option + * Comma first style for client serving tests + * Long polling integration tests + * Test for heartbeat message + * Added heartbeat timeout test + * Support for listener#log false + * Corrected onConnect signature to support a request and a socket, or a request and a response. + * Removed error checking for non-upgradeable sockets, since they'll be destroyed, and error handling is done onConnect + * Added tests for websocket client tracking + * Added tests for websocket message buffering + * Make sure disconnect timeout is cleared on websocket re-connect + * Updated the flash socket with error detection, and readystate detection. + * This is needed because when a error occures we close down the connection, + * and the stream will become unwriteable. + * Also changed to a single write instead of multiple writes. + * Moved error handling to onConnect to avoid messing with the http.Server global error handlers + * Do special error handling for websocket + * Clearing heartbeat interval upon closing the connection + * Added error listeners, if theses errors are not correcly caught, they will leak memory. + * This caused http://speedo.no.de/ to go up from 1mb per connection after a ECONNECTRESET message + * Added encode=UTF-8 in jsonp-polling.js and xhr-polling.js since UTF-8 is the default encoding for http.ServerResponse.write + * Replaced string.length with Buffer.byteLength in jsonp-polling.js, listener.js and xhr-polling.js because content-length header requires number of bytes and not the number of symbols in string + * Fix COR headers/requests for different ports on Safari. + * Clearing the references to request, response and connection upon disconnect. + * Every require is blocking and requiring the sys module over and over and over again just makes no sense + it hurt performance.. Not to mention.. that it's already included. + * Socket.IO-node now serves the client out of the box for easier implementation + * Memory caching and ETag support for static files + * Tests + * Simplified demo even further thanks to new static file serving + * Failing to pass an origin header would throw an exception and crash the server. Added some handling. + * .connected renamed to ._open, and adopted proper `connected` (fixes #41) + * example/client updated to latest socket.io client + * Better checking of WebSocket connections + * Better handling of SSL location (thanks @jdub) + * Fix for cross-domain websocket (fixes #42) + * Removed clients/clientsIndex and only using the index (fixes #28) + * Fixed WebSocket location header for ws/wss (Thanks @jdub, Fixes #40) + * Cross domain issues with xhr-polling addressed. Thanks Niko Kaiser (@nicokaiser) + * Added origin verification for incoming data. + * Make sure pathname is set (thanks steadicat & swarmation team) + * Fix for accessing routes that being with the namespace but are not a connection attempt. Thanks @steadicat from swarmation + * JSONP-polling support + * Graceful closing of connection for invalid websocket clients + * Make it possible to just require 'socket.io' + * Make sure to abort the connect() method upon bad upgrade / origin verification + * Support for automatic JSON encoding/decoding + * Simplified chat example to take advantage of JSON encoding/decoding + * Removed fs sync call from example + * Better `how to use` + * Make sure to send content-type text/plain to `ok` POST responses + diff --git a/bruml/lib/socket.io/Makefile b/bruml/lib/socket.io/Makefile new file mode 100644 index 0000000..1182db2 --- /dev/null +++ b/bruml/lib/socket.io/Makefile @@ -0,0 +1,13 @@ +test: + ./support/expresso/bin/expresso -I lib $(TESTFLAGS) tests/*.js + +test-cov: + @TESTFLAGS=--cov $(MAKE) test + +example: + node ./example/server.js + +example-ssl: + node ./example/server-ssl.js + +.PHONY: example diff --git a/bruml/lib/socket.io/README.md b/bruml/lib/socket.io/README.md new file mode 100644 index 0000000..3bb251f --- /dev/null +++ b/bruml/lib/socket.io/README.md @@ -0,0 +1,229 @@ +Socket.IO Server: Sockets for the rest of us +============================================ + +The `Socket.IO` server provides seamless support for a variety of transports intended for realtime communication. + +- WebSocket +- WebSocket over Flash (+ XML security policy support) +- XHR Polling +- XHR Multipart Streaming +- Forever Iframe +- JSONP Polling (for cross domain) + +## Requirements + +- Node v0.1.103+ with `crypto` module support (make sure you have OpenSSL + headers when installing Node to get it) +- The [Socket.IO client](http://github.com/LearnBoost/Socket.IO), to connect from the browser + +## How to use + +To run the demo, execute the following: + + git clone git://github.com/LearnBoost/Socket.IO-node.git socket.io + cd socket.io/example/ + sudo node server.js + +and point your browser to `http://localhost:8080`. In addition to `8080`, if the transport `flashsocket` is enabled, a server will be initialized to listen for requests on port `843`. + +### Implementing it on your project + +`Socket.IO` is designed not to take over an entire port or Node `http.Server` instance. This means that if you choose to have your HTTP server listen on port `80`, `socket.io` can intercept requests directed to it, and normal requests will still be served. + +By default, the server will intercept requests that contain `socket.io` in the path / resource part of the URI. You can change this as shown in the available options below. + +On the server: + + var http = require('http'), + io = require('./path/to/socket.io'), + + server = http.createServer(function(req, res){ + // your normal server code + res.writeHead(200, {'Content-Type': 'text/html'}); + res.end('

Hello world

'); + }); + + server.listen(80); + + // socket.io, I choose you + var socket = io.listen(server); + + socket.on('connection', function(client){ + // new client is here! + client.on('message', function(){ … }) + client.on('disconnect', function(){ … }) + }); + +On the client: + + + + +The [client-side](http://github.com/learnboost/socket.io) files are served automatically by `Socket.IO-node`. + +## Documentation + +### Listener + + io.listen(, [options]) + +Returns: a `Listener` instance + +Public Properties: + +- *server* + + An instance of _process.http.Server_. + +- *options* + + The passed-in options, combined with the defaults. + +- *clients* + + An object of clients, indexed by session ID. + +Methods: + +- *addListener(event, λ)* + + Adds a listener for the specified event. Optionally, you can pass it as an option to `io.listen`, prefixed by `on`. For example: `onClientConnect: function(){}` + +- *removeListener(event, λ)* + + Removes a listener from the listener array for the specified event. + +- *broadcast(message, [except])* + + Broadcasts a message to all clients. Optionally, you can pass a single session ID or array of session IDs to avoid broadcasting to, as the second argument. + +Options: + +- *resource* + + socket.io + + The resource is what allows the `socket.io` server to identify incoming connections from `socket.io` clients. Make sure they're in sync. + +- *flashPolicyServer* + + true + + Create a Flash Policy file server on port `843` (this is restricted port and you will need to have root permission). If you disable the FlashPolicy file server, Socket.IO will automatically fall back to serving the policy file inline. + + +- *transports* + + ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', + 'jsonp-polling'] + + A list of the accepted transports. + +- *transportOptions* + + An object of options to pass to each transport. For example `{ websocket: { closeTimeout: 8000 }}` + +- *log* + + ƒ(){ sys.log } + + The logging function. Defaults to outputting to `stdout` through `sys.log` + +Events: + +- *clientConnect(client)* + + Fired when a client is connected. Receives the Client instance as parameter. + +- *clientMessage(message, client)* + + Fired when a message from a client is received. Receives the message and Client instance as parameters. + +- *clientDisconnect(client)* + + Fired when a client is disconnected. Receives the Client instance as a parameter. + +Important note: `this` in the event listener refers to the `Listener` instance. + +### Client + + Client(listener, req, res) + +Public Properties: + +- *listener* + + The `Listener` instance to which this client belongs. + +- *connected* + + Whether the client is connected. + +- *connections* + + Number of times the client has connected. + +Methods: + +- *send(message)* + + Sends a message to the client. + +- *broadcast(message)* + + Sends a message to all other clients. Equivalent to Listener::broadcast(message, client.sessionId). + +## Protocol + +One of the design goals is that you should be able to implement whatever protocol you desire without `Socket.IO` getting in the way. `Socket.IO` has a minimal, unobtrusive protocol layer, consisting of two parts: + +* Connection handshake + + This is required to simulate a full duplex socket with transports such as XHR Polling or Server-sent Events (which is a "one-way socket"). The basic idea is that the first message received from the server will be a JSON object that contains a session ID used for further communications exchanged between the client and server. + + The concept of session also naturally benefits a full-duplex WebSocket, in the event of an accidental disconnection and a quick reconnection. Messages that the server intends to deliver to the client are cached temporarily until reconnection. + + The implementation of reconnection logic (potentially with retries) is left for the user. By default, transports that are keep-alive or open all the time (like WebSocket) have a timeout of 0 if a disconnection is detected. + +* Message batching + + Messages are buffered in order to optimize resources. In the event of the server trying to send multiple messages while a client is temporarily disconnected (eg: xhr polling), the messages are stacked and then encoded in a lightweight way, and sent to the client whenever it becomes available. + +Despite this extra layer, the messages are delivered unaltered to the various event listeners. You can `JSON.stringify()` objects, send XML, or even plain text. + +## Credits + +- Guillermo Rauch <guillermo@learnboost.com> ([Guille](http://github.com/guille)) + +- Arnout Kazemier ([3rd-Eden](http://github.com/3rd-Eden)) + +## License + +(The MIT License) + +Copyright (c) 2010 LearnBoost <dev@learnboost.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bruml/lib/socket.io/example/benchmark.html b/bruml/lib/socket.io/example/benchmark.html new file mode 100644 index 0000000..11dc315 --- /dev/null +++ b/bruml/lib/socket.io/example/benchmark.html @@ -0,0 +1,61 @@ + + + + socket.io client test + + + + + + + + +

Sample chat client

+

Connecting...

+
+ +
+ + + + + diff --git a/bruml/lib/socket.io/example/cert.crt b/bruml/lib/socket.io/example/cert.crt new file mode 100644 index 0000000..5883cd4 --- /dev/null +++ b/bruml/lib/socket.io/example/cert.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAMUSOvlaeyQHMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTAxMTE2MDkzMjQ5WhcNMTMxMTE1MDkzMjQ5WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEVwfPQQp4X +wtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+1FAE0c5o +exPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404WthquTqg +S7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy25IyBK3QJ +c+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWAQsqW+COL +0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABo1AwTjAdBgNVHQ4EFgQUDnV4d6mD +tOnluLoCjkUHTX/n4agwHwYDVR0jBBgwFoAUDnV4d6mDtOnluLoCjkUHTX/n4agw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAFwV4MQfTo+qMv9JMiyno +IEiqfOz4RgtmBqRnXUffcjS2dhc7/z+FPZnM79Kej8eLHoVfxCyWRHFlzm93vEdv +wxOCrD13EDOi08OOZfxWyIlCa6Bg8cMAKqQzd2OvQOWqlRWBTThBJIhWflU33izX +Qn5GdmYqhfpc+9ZHHGhvXNydtRQkdxVK2dZNzLBvBlLlRmtoClU7xm3A+/5dddeP +AQHEPtyFlUw49VYtZ3ru6KqPms7MKvcRhYLsy9rwSfuuniMlx4d0bDR7TOkw0QQS +A0N8MGQRQpzl4mw4jLzyM5d5QtuGBh2P6hPGa0YQxtI3RPT/p6ENzzBiAKXiSfzo +xw== +-----END CERTIFICATE----- diff --git a/bruml/lib/socket.io/example/chat-ssl.html b/bruml/lib/socket.io/example/chat-ssl.html new file mode 100644 index 0000000..b997bba --- /dev/null +++ b/bruml/lib/socket.io/example/chat-ssl.html @@ -0,0 +1,61 @@ + + + + socket.io client test + + + + + + + + +

Sample chat client

+

Connecting...

+
+ +
+ + + + + diff --git a/bruml/lib/socket.io/example/chat.html b/bruml/lib/socket.io/example/chat.html new file mode 100644 index 0000000..94104c4 --- /dev/null +++ b/bruml/lib/socket.io/example/chat.html @@ -0,0 +1,69 @@ + + + + socket.io client test + + + + + + + + +

Sample chat client

+

Connecting...

+
+ +
+ + + + + diff --git a/bruml/lib/socket.io/example/json.js b/bruml/lib/socket.io/example/json.js new file mode 100644 index 0000000..0dff7cc --- /dev/null +++ b/bruml/lib/socket.io/example/json.js @@ -0,0 +1,18 @@ +if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;} +Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+ +f(this.getUTCMonth()+1)+'-'+ +f(this.getUTCDate())+'T'+ +f(this.getUTCHours())+':'+ +f(this.getUTCMinutes())+':'+ +f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;} +c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+ +(c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';} +if(typeof value.toJSON==='function'){return stringify(value.toJSON());} +a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;iWelcome. Try the SSL Chat example.'); + res.end(); + break; + + case '/json.js': + case '/chat-ssl.html': + fs.readFile(__dirname + path, function(err, data){ + if (err) return send404(res); + res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'}) + res.write(data, 'utf8'); + res.end(); + }); + break; + + default: send404(res); + } +}), + +send404 = function(res){ + res.writeHead(404); + res.write('404'); + res.end(); +}; + +server.listen(443); + +// socket.io, I choose you +// simplest chat application evar +var io = io.listen(server) + , buffer = []; + +io.on('connection', function(client){ + client.send({ buffer: buffer }); + client.broadcast({ announcement: client.sessionId + ' connected' }); + + client.on('message', function(message){ + var msg = { message: [client.sessionId, message] }; + buffer.push(msg); + if (buffer.length > 15) buffer.shift(); + client.broadcast(msg); + }); + + client.on('disconnect', function(){ + client.broadcast({ announcement: client.sessionId + ' disconnected' }); + }); +}); diff --git a/bruml/lib/socket.io/example/server.benchmark.js b/bruml/lib/socket.io/example/server.benchmark.js new file mode 100644 index 0000000..a71cb4b --- /dev/null +++ b/bruml/lib/socket.io/example/server.benchmark.js @@ -0,0 +1,77 @@ +/** + * Important note: this application is not suitable for benchmarks! + */ + +var http = require('http') + , url = require('url') + , fs = require('fs') + , io = require('../') + , sys = require(process.binding('natives').util ? 'util' : 'sys') + , server; + +server = http.createServer(function(req, res){ + // your normal server code + var path = url.parse(req.url).pathname; + switch (path){ + case '/': + res.writeHead(200, {'Content-Type': 'text/html'}); + res.write([ + '

Welcome.

' + , '

Transports:

' + , '' + ].join('')); + res.end(); + break; + + case '/json.js': + case '/benchmark.html': + fs.readFile(__dirname + path, function(err, data){ + if (err) return send404(res); + res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'}) + res.write(data.toString().replace('{transport}' + , req.url.replace('/benchmark.html', '')) + , 'utf8'); + res.end(); + }); + break; + + default: send404(res); + } +}), + +send404 = function(res){ + res.writeHead(404); + res.write('404'); + res.end(); +}; + +server.listen(8080); + +// socket.io, I choose you +// simplest chat application evar +var io = io.listen(server) + , buffer = []; + +io.on('connection', function(client){ + // track latency and number of messages + client.latency = 0; + client.messages = 0; + + client.send(Date.now()); + + client.on('message', function(message){ + client.latency += + console.log('Message latency:', Date.now() - Number(message)); + }); + + client.on('disconnect', function(){ + console.log(); + }); +}); diff --git a/bruml/lib/socket.io/example/server.js b/bruml/lib/socket.io/example/server.js new file mode 100644 index 0000000..7f10e7f --- /dev/null +++ b/bruml/lib/socket.io/example/server.js @@ -0,0 +1,63 @@ +/** + * Important note: this application is not suitable for benchmarks! + */ + +var http = require('http') + , url = require('url') + , fs = require('fs') + , io = require('../') + , sys = require(process.binding('natives').util ? 'util' : 'sys') + , server; + +server = http.createServer(function(req, res){ + // your normal server code + var path = url.parse(req.url).pathname; + switch (path){ + case '/': + res.writeHead(200, {'Content-Type': 'text/html'}); + res.write('

Welcome. Try the chat example.

'); + res.end(); + break; + + case '/json.js': + case '/chat.html': + fs.readFile(__dirname + path, function(err, data){ + if (err) return send404(res); + res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'}) + res.write(data, 'utf8'); + res.end(); + }); + break; + + default: send404(res); + } +}), + +send404 = function(res){ + res.writeHead(404); + res.write('404'); + res.end(); +}; + +server.listen(8080); + +// socket.io, I choose you +// simplest chat application evar +var io = io.listen(server) + , buffer = []; + +io.on('connection', function(client){ + client.send({ buffer: buffer }); + client.broadcast({ announcement: client.sessionId + ' connected' }); + + client.on('message', function(message){ + var msg = { message: [client.sessionId, message] }; + buffer.push(msg); + if (buffer.length > 15) buffer.shift(); + client.broadcast(msg); + }); + + client.on('disconnect', function(){ + client.broadcast({ announcement: client.sessionId + ' disconnected' }); + }); +}); diff --git a/bruml/lib/socket.io/index.js b/bruml/lib/socket.io/index.js new file mode 100644 index 0000000..2f44485 --- /dev/null +++ b/bruml/lib/socket.io/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/socket.io'); \ No newline at end of file diff --git a/bruml/lib/socket.io/lib/socket.io/client.js b/bruml/lib/socket.io/lib/socket.io/client.js new file mode 100644 index 0000000..d859566 --- /dev/null +++ b/bruml/lib/socket.io/lib/socket.io/client.js @@ -0,0 +1,197 @@ +var urlparse = require('url').parse + , OutgoingMessage = require('http').OutgoingMessage + , Stream = require('net').Stream + , options = require('./utils').options + , encode = require('./utils').encode + , decode = require('./utils').decode + , merge = require('./utils').merge + , util = require(process.binding('natives').util ? 'util' : 'sys'); + +var Client = module.exports = function(listener, req, res, options, head){ + process.EventEmitter.call(this); + this.listener = listener; + this.options(merge({ + timeout: 8000, + heartbeatInterval: 10000, + closeTimeout: 0 + }, this.getOptions ? this.getOptions() : {}), options); + this.connections = 0; + this._open = false; + this._heartbeats = 0; + this.connected = false; + this.upgradeHead = head; + this._onConnect(req, res); +}; + +util.inherits(Client, process.EventEmitter); + +Client.prototype.send = function(message){ + if (!this._open || !(this.connection.readyState === 'open' || this.connection.readyState === 'writeOnly')){ + return this._queue(message); + } + this._write(encode(message)); + return this; +}; + +Client.prototype.broadcast = function(message){ + if (!('sessionId' in this)) return this; + this.listener.broadcast(message, this.sessionId); + return this; +}; + +Client.prototype._onMessage = function(data){ + var messages = decode(data); + if (messages === false) return this.listener.options.log('Bad message received from client ' + this.sessionId); + for (var i = 0, l = messages.length, frame; i < l; i++){ + frame = messages[i].substr(0, 3); + switch (frame){ + case '~h~': + return this._onHeartbeat(messages[i].substr(3)); + case '~j~': + try { + messages[i] = JSON.parse(messages[i].substr(3)); + } catch(e) { + messages[i] = {}; + } + break; + } + this.emit('message', messages[i]); + this.listener._onClientMessage(messages[i], this); + } +}; + +Client.prototype._onConnect = function(req, res){ + var self = this + , attachConnection = !this.connection; + + this.request = req; + this.response = res; + this.connection = req.connection; + + if(!attachConnection) attachConnection = !attachConnection && this.connection.eventsAttached === undefined; + this.connection.eventsAttached = true; + + if (attachConnection){ + function destroyConnection(){ + self._onClose(); + self.connection && self.connection.destroy() + }; + this.connection.addListener('end', destroyConnection); + this.connection.addListener('timeout', destroyConnection); + this.connection.addListener('error', destroyConnection); + } + + if (req){ + function destroyRequest(){ + req.destroy && req.destroy(); + }; + req.addListener('error', destroyRequest); + req.addListener('timeout', destroyRequest); + if (res){ + function destroyResponse(){ + res.destroy && res.destroy(); + } + res.addListener('error', destroyResponse); + res.addListener('timeout', destroyResponse); + } + if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout); + } +}; + + +Client.prototype._payload = function(){ + var payload = []; + + this.connections++; + this.connected = true; + this._open = true; + + if (!this.handshaked){ + this._generateSessionId(); + payload.push(this.sessionId); + this.handshaked = true; + } + + payload = payload.concat(this._writeQueue || []); + this._writeQueue = []; + + if (payload.length) this._write(encode(payload)); + if (this.connections === 1) this.listener._onClientConnect(this); + if (this.options.timeout) this._heartbeat(); +}; + +Client.prototype._heartbeat = function(){ + var self = this; + this._heartbeatInterval = setTimeout(function(){ + self.send('~h~' + ++self._heartbeats); + self._heartbeatTimeout = setTimeout(function(){ + self._onClose(); + }, self.options.timeout); + }, self.options.heartbeatInterval); +}; + +Client.prototype._onHeartbeat = function(h){ + if (h == this._heartbeats){ + clearTimeout(this._heartbeatTimeout); + this._heartbeat(); + } +}; + +Client.prototype._onClose = function(skipDisconnect){ + if (!this._open) return this; + var self = this; + if (this._heartbeatInterval) clearTimeout(this._heartbeatInterval); + if (this._heartbeatTimeout) clearTimeout(this._heartbeatTimeout); + this._open = false; + this.request = null; + this.response = null; + if (skipDisconnect !== false){ + if (this.handshaked){ + this._disconnectTimeout = setTimeout(function(){ + self._onDisconnect(); + }, this.options.closeTimeout); + } else + this._onDisconnect(); + } +}; + +Client.prototype._onDisconnect = function(){ + if (this._open) this._onClose(true); + if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout); + this._writeQueue = []; + this.connected = false; + if (this.handshaked){ + this.emit('disconnect'); + this.listener._onClientDisconnect(this); + this.handshaked = false; + } +}; + +Client.prototype._queue = function(message){ + this._writeQueue = this._writeQueue || []; + this._writeQueue.push(message); + return this; +}; + +Client.prototype._generateSessionId = function(){ + this.sessionId = Math.random().toString().substr(2); + return this; +}; + +Client.prototype._verifyOrigin = function(origin){ + var origins = this.listener.options.origins; + if (origins.indexOf('*:*') !== -1) { + return true; + } + if (origin) { + try { + var parts = urlparse(origin); + return origins.indexOf(parts.host + ':' + parts.port) !== -1 || + origins.indexOf(parts.host + ':*') !== -1 || + origins.indexOf('*:' + parts.port) !== -1; + } catch (ex) {} + } + return false; +}; + +for (var i in options) Client.prototype[i] = options[i]; diff --git a/bruml/lib/socket.io/lib/socket.io/index.js b/bruml/lib/socket.io/lib/socket.io/index.js new file mode 100644 index 0000000..053cfe0 --- /dev/null +++ b/bruml/lib/socket.io/lib/socket.io/index.js @@ -0,0 +1,26 @@ + +/** + * Listener creation shorcut + * + * @param {Server} node HTTP server + * @param {Object} options + * @api public + */ + +exports.listen = function(server, options){ + return new exports.Listener(server, options); +}; + +/** + * Listener constructor + * + * @api public + */ + +exports.Listener = require('./listener'); + +/** + * Version + */ + +exports.version = '0.6.17'; diff --git a/bruml/lib/socket.io/lib/socket.io/listener.js b/bruml/lib/socket.io/lib/socket.io/listener.js new file mode 100644 index 0000000..08aeb4c --- /dev/null +++ b/bruml/lib/socket.io/lib/socket.io/listener.js @@ -0,0 +1,166 @@ +var url = require('url') + , util = require(process.binding('natives').util ? 'util' : 'sys') + , fs = require('fs') + , options = require('./utils').options + , Client = require('./client') + , clientVersion = require('./../../support/socket.io-client/lib/io').io.version + , transports = {}; + +var Listener = module.exports = function(server, options){ + process.EventEmitter.call(this); + var self = this; + this.server = server; + this.options({ + origins: '*:*', + resource: 'socket.io', + flashPolicyServer: true, + transports: ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', + 'xhr-polling', 'jsonp-polling'], + transportOptions: {}, + log: util.log + }, options); + + if (!this.options.log) this.options.log = function(){}; + + this.clients = this.clientsIndex = {}; + this._clientCount = 0; + this._clientFiles = {}; + + var listeners = this.server.listeners('request'); + this.server.removeAllListeners('request'); + + this.server.addListener('request', function(req, res){ + if (self.check(req, res)) return; + for (var i = 0, len = listeners.length; i < len; i++){ + listeners[i].call(this, req, res); + } + }); + + this.server.addListener('upgrade', function(req, socket, head){ + if (!self.check(req, socket, true, head)){ + socket.end(); + socket.destroy(); + } + }); + + this.options.transports.forEach(function(name) { + if (!(name in transports)) + transports[name] = require('./transports/' + name); + if ('init' in transports[name]) transports[name].init(self); + }); + + this.options.log('socket.io ready - accepting connections'); +}; + +util.inherits(Listener, process.EventEmitter); +for (var i in options) Listener.prototype[i] = options[i]; + +Listener.prototype.broadcast = function(message, except){ + for (var i = 0, k = Object.keys(this.clients), l = k.length; i < l; i++){ + if (!except || ((typeof except == 'number' || typeof except == 'string') && k[i] != except) + || (Array.isArray(except) && except.indexOf(k[i]) == -1)){ + this.clients[k[i]].send(message); + } + } + return this; +}; + +Listener.prototype.check = function(req, res, httpUpgrade, head){ + var path = url.parse(req.url).pathname, parts, cn; + if (path && path.indexOf('/' + this.options.resource) === 0){ + parts = path.substr(2 + this.options.resource.length).split('/'); + if (this._serveClient(parts.join('/'), req, res)) return true; + if (!(parts[0] in transports)) return false; + if (parts[1]){ + cn = this.clients[parts[1]]; + if (cn){ + cn._onConnect(req, res); + } else { + req.connection.end(); + req.connection.destroy(); + this.options.log('Couldnt find client with session id "' + parts[1] + '"'); + } + } else { + this._onConnection(parts[0], req, res, httpUpgrade, head); + } + return true; + } + return false; +}; + +Listener.prototype._serveClient = function(file, req, res){ + var self = this + , clientPaths = { + 'socket.io.js': 'socket.io.js', + 'lib/vendor/web-socket-js/WebSocketMain.swf': 'lib/vendor/web-socket-js/WebSocketMain.swf', // for compat with old clients + 'WebSocketMain.swf': 'lib/vendor/web-socket-js/WebSocketMain.swf' + } + , types = { + swf: 'application/x-shockwave-flash', + js: 'text/javascript' + }; + + function write(path){ + if (req.headers['if-none-match'] == clientVersion){ + res.writeHead(304); + res.end(); + } else { + res.writeHead(200, self._clientFiles[path].headers); + res.end(self._clientFiles[path].content, self._clientFiles[path].encoding); + } + }; + + var path = clientPaths[file]; + + if (req.method == 'GET' && path !== undefined){ + if (path in this._clientFiles){ + write(path); + return true; + } + + fs.readFile(__dirname + '/../../support/socket.io-client/' + path, function(err, data){ + if (err){ + res.writeHead(404); + res.end('404'); + } else { + var ext = path.split('.').pop(); + self._clientFiles[path] = { + headers: { + 'Content-Length': data.length, + 'Content-Type': types[ext], + 'ETag': clientVersion + }, + content: data, + encoding: ext == 'swf' ? 'binary' : 'utf8' + }; + write(path); + } + }); + + return true; + } + + return false; +}; + +Listener.prototype._onClientConnect = function(client){ + this.clients[client.sessionId] = client; + this.options.log('Client '+ client.sessionId +' connected'); + this.emit('clientConnect', client); + this.emit('connection', client); +}; + +Listener.prototype._onClientMessage = function(data, client){ + this.emit('clientMessage', data, client); +}; + +Listener.prototype._onClientDisconnect = function(client){ + delete this.clients[client.sessionId]; + this.options.log('Client '+ client.sessionId +' disconnected'); + this.emit('clientDisconnect', client); +}; + +Listener.prototype._onConnection = function(transport, req, res, httpUpgrade, head){ + this.options.log('Initializing client with transport "'+ transport +'"'); + new transports[transport](this, req, res, this.options.transportOptions[transport], head); +}; diff --git a/bruml/lib/socket.io/lib/socket.io/transports/flashsocket.js b/bruml/lib/socket.io/lib/socket.io/transports/flashsocket.js new file mode 100644 index 0000000..bb8da3c --- /dev/null +++ b/bruml/lib/socket.io/lib/socket.io/transports/flashsocket.js @@ -0,0 +1,89 @@ +var net = require('net') + , util = require(process.binding('natives').util ? 'util' : 'sys') + , WebSocket = require('./websocket') + , listeners = [] + , netserver; + +var Flashsocket = module.exports = function(){ + WebSocket.apply(this, arguments); +}; + +util.inherits(Flashsocket, WebSocket); + +Flashsocket.httpUpgrade = true; + +Flashsocket.init = function(listener){ + listeners.push(listener); + + listener.server.on('close', function(){ + listeners.splice(listeners.indexOf(listener), 1); + + if (listeners.length === 0 && netserver){ + try { + netserver.close(); + } catch(e){ + listener.options.log('flashsocket netserver close error - ' + e.stack) + } + } + }); + + if (listener.options.flashPolicyServer && netserver === undefined){ + netserver = net.createServer(function(socket){ + socket.addListener('error', function(err){ + if (socket && socket.end){ + socket.end(); + socket.destroy(); + } + }); + + if(socket && socket.readyState == 'open') + socket.end(policy(listeners)); + }); + + try { + netserver.listen(843); + } catch(e){ + if (e.errno == 13) + listener.options.log('Your node instance does not have root privileges. ' + + 'This means that the flash XML policy file will be ' + + 'served inline instead of on port 843. This will slow ' + + 'down initial connections slightly.'); + netserver = null; + } + } + + // Could not listen on port 843 so policy requests will be inline + listener.server.addListener('connection', function(stream){ + var flashCheck = function (data) { + // Only check the initial data + stream.removeListener("data", flashCheck); + if (data[0] === 60 && data.length == 23) { + if (data == '\0') { + listener.options.log("Answering flash policy request inline"); + if (stream && stream.readyState == 'open'){ + var xml = policy([listener]); + stream.write(xml); + stream.end(); + } + } + } + }; + + stream.on('data', flashCheck); + }); +}; + +function policy(listeners) { + var xml = '\n\n\n'; + + listeners.forEach(function(l){ + [].concat(l.options.origins).forEach(function(origin){ + var parts = origin.split(':'); + xml += '\n'; + }); + }); + + xml += '\n'; + return xml; +}; diff --git a/bruml/lib/socket.io/lib/socket.io/transports/htmlfile.js b/bruml/lib/socket.io/lib/socket.io/transports/htmlfile.js new file mode 100644 index 0000000..e8cbae9 --- /dev/null +++ b/bruml/lib/socket.io/lib/socket.io/transports/htmlfile.js @@ -0,0 +1,49 @@ +var Client = require('../client') + , util = require(process.binding('natives').util ? 'util' : 'sys') + , qs = require('querystring'); + +var HTMLFile = module.exports = function(){ + Client.apply(this, arguments); +}; + +util.inherits(HTMLFile, Client); + +HTMLFile.prototype._onConnect = function(req, res){ + var self = this, body = ''; + switch (req.method){ + case 'GET': + Client.prototype._onConnect.call(this, req, res); + this.response.useChunkedEncodingByDefault = true; + this.response.shouldKeepAlive = true; + this.response.writeHead(200, { + 'Content-Type': 'text/html', + 'Connection': 'keep-alive', + 'Transfer-Encoding': 'chunked' + }); + this.response.write('' + new Array(245).join(' ')); + this._payload(); + break; + + case 'POST': + req.addListener('data', function(message){ + body += message; + }); + req.addListener('end', function(){ + try { + var msg = qs.parse(body); + self._onMessage(msg.data); + } catch(e){ + self.listener.options.log('htmlfile message handler error - ' + e.stack); + } + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.write('ok'); + res.end(); + }); + break; + } +}; + +HTMLFile.prototype._write = function(message){ + if (this._open) + this.response.write(''); //json for escaping +}; diff --git a/bruml/lib/socket.io/lib/socket.io/transports/jsonp-polling.js b/bruml/lib/socket.io/lib/socket.io/transports/jsonp-polling.js new file mode 100644 index 0000000..82ff634 --- /dev/null +++ b/bruml/lib/socket.io/lib/socket.io/transports/jsonp-polling.js @@ -0,0 +1,35 @@ +var XHRPolling = require('./xhr-polling') + , util = require(process.binding('natives').util ? 'util' : 'sys'); + +JSONPPolling = module.exports = function(){ + XHRPolling.apply(this, arguments); +}; + +util.inherits(JSONPPolling, XHRPolling); + +JSONPPolling.prototype.getOptions = function(){ + return { + timeout: null, // no heartbeats + closeTimeout: 8000, + duration: 20000 + }; +}; + +JSONPPolling.prototype._onConnect = function(req, res){ + this._index = req.url.match(/\/([0-9]+)\/?$/).pop(); + XHRPolling.prototype._onConnect.call(this, req, res); +}; + +JSONPPolling.prototype._write = function(message){ + if (this._open){ + if (this.request.headers.origin && !this._verifyOrigin(this.request.headers.origin)){ + message = "alert('Cross domain security restrictions not met');"; + } else { + message = "io.JSONP["+ this._index +"]._("+ JSON.stringify(message) +");"; + } + this.response.writeHead(200, {'Content-Type': 'text/javascript; charset=UTF-8', 'Content-Length': Buffer.byteLength(message)}); + this.response.write(message); + this.response.end(); + this._onClose(); + } +}; diff --git a/bruml/lib/socket.io/lib/socket.io/transports/websocket.js b/bruml/lib/socket.io/lib/socket.io/transports/websocket.js new file mode 100644 index 0000000..254db25 --- /dev/null +++ b/bruml/lib/socket.io/lib/socket.io/transports/websocket.js @@ -0,0 +1,208 @@ +var Client = require('../client') + , Stream = require('net').Stream + , EventEmitter = require('events').EventEmitter + , url = require('url') + , util = require(process.binding('natives').util ? 'util' : 'sys') + , crypto = require('crypto'); + +WebSocket = module.exports = function(){ + Client.apply(this, arguments); +}; + +util.inherits(WebSocket, Client); + +WebSocket.prototype._onConnect = function(req, socket){ + var self = this + , headers = []; + + if (!req.connection.setTimeout){ + req.connection.end(); + return false; + } + + this.parser = new Parser(); + this.parser.on('data', self._onMessage.bind(this)); + this.parser.on('error', self._onClose.bind(this)); + + Client.prototype._onConnect.call(this, req); + + if (this.request.headers.upgrade !== 'WebSocket' || !this._verifyOrigin(this.request.headers.origin)){ + this.listener.options.log('WebSocket connection invalid or Origin not verified'); + this._onClose(); + return false; + } + + var origin = this.request.headers.origin, + location = (origin && origin.substr(0, 5) == 'https' ? 'wss' : 'ws') + + '://' + this.request.headers.host + this.request.url; + + this.waitingForNonce = false; + if ('sec-websocket-key1' in this.request.headers){ + /* We need to send the 101 response immediately when using Draft 76 with + a load balancing proxy, such as HAProxy. In order to protect an + unsuspecting non-websocket HTTP server, HAProxy will not send the + 8-byte nonce through the connection until the Upgrade: WebSocket + request has been confirmed by the WebSocket server by a 101 response + indicating that the server can handle the upgraded protocol. We + therefore must send the 101 response immediately, and then wait for + the nonce to be forwarded to us afterward in order to finish the + Draft 76 handshake. + */ + + // If we don't have the nonce yet, wait for it. + if (!(this.upgradeHead && this.upgradeHead.length >= 8)) { + this.waitingForNonce = true; + } + + headers = [ + 'HTTP/1.1 101 WebSocket Protocol Handshake', + 'Upgrade: WebSocket', + 'Connection: Upgrade', + 'Sec-WebSocket-Origin: ' + origin, + 'Sec-WebSocket-Location: ' + location + ]; + + if ('sec-websocket-protocol' in this.request.headers){ + headers.push('Sec-WebSocket-Protocol: ' + this.request.headers['sec-websocket-protocol']); + } + } else { + headers = [ + 'HTTP/1.1 101 Web Socket Protocol Handshake', + 'Upgrade: WebSocket', + 'Connection: Upgrade', + 'WebSocket-Origin: ' + origin, + 'WebSocket-Location: ' + location + ]; + + } + + try { + this.connection.write(headers.concat('', '').join('\r\n')); + this.connection.setTimeout(0); + this.connection.setNoDelay(true); + this.connection.setEncoding('utf-8'); + } catch(e){ + this._onClose(); + return; + } + + if (this.waitingForNonce) { + // Since we will be receiving the binary nonce through the normal HTTP + // data event, set the connection to 'binary' temporarily + this.connection.setEncoding('binary'); + this._headers = headers; + } + else { + if (this._proveReception(headers)) this._payload(); + } + + this.buffer = ""; + + this.connection.addListener('data', function(data){ + if (self.waitingForNonce) { + self.buffer += data; + + if (self.buffer.length < 8) { return; } + // Restore the connection to utf8 encoding after receiving the nonce + self.connection.setEncoding('utf8'); + self.waitingForNonce = false; + // Stuff the nonce into the location where it's expected to be + self.upgradeHead = self.buffer.substr(0,8); + self.buffer = ''; + if (self._proveReception(self._headers)) { self._payload(); } + return; + } + + self.parser.add(data); + }); + +}; + +// http://www.whatwg.org/specs/web-apps/current-work/complete/network.html#opening-handshake +WebSocket.prototype._proveReception = function(headers){ + var self = this + , k1 = this.request.headers['sec-websocket-key1'] + , k2 = this.request.headers['sec-websocket-key2']; + + if (k1 && k2){ + var md5 = crypto.createHash('md5'); + + [k1, k2].forEach(function(k){ + var n = parseInt(k.replace(/[^\d]/g, '')), + spaces = k.replace(/[^ ]/g, '').length; + + if (spaces === 0 || n % spaces !== 0){ + self.listener.options.log('Invalid WebSocket key: "' + k + '". Dropping connection'); + self._onClose(); + return false; + } + + n /= spaces; + + md5.update(String.fromCharCode( + n >> 24 & 0xFF, + n >> 16 & 0xFF, + n >> 8 & 0xFF, + n & 0xFF)); + }); + + md5.update(this.upgradeHead.toString('binary')); + + try { + this.connection.write(md5.digest('binary'), 'binary'); + } catch(e){ + this._onClose(); + } + } + + return true; +}; + +WebSocket.prototype._write = function(message){ + try { + this.connection.write('\u0000', 'binary'); + this.connection.write(message, 'utf8'); + this.connection.write('\uffff', 'binary'); + } catch(e){ + this._onClose(); + } +}; + +WebSocket.httpUpgrade = true; + +function Parser(){ + this.buffer = ''; + this.i = 0; +}; + +Parser.prototype.__proto__ = EventEmitter.prototype; + +Parser.prototype.add = function(data){ + this.buffer += data; + this.parse(); +}; + +Parser.prototype.parse = function(){ + for (var i = this.i, chr, l = this.buffer.length; i < l; i++){ + chr = this.buffer[i]; + if (i === 0){ + if (chr != '\u0000') + this.error('Bad framing. Expected null byte as first frame'); + else + continue; + } + if (chr == '\ufffd'){ + this.emit('data', this.buffer.substr(1, this.buffer.length - 2)); + this.buffer = this.buffer.substr(i + 1); + this.i = 0; + return this.parse(); + } + } +}; + +Parser.prototype.error = function(reason){ + this.buffer = ''; + this.i = 0; + this.emit('error', reason); + return this; +}; diff --git a/bruml/lib/socket.io/lib/socket.io/transports/xhr-multipart.js b/bruml/lib/socket.io/lib/socket.io/transports/xhr-multipart.js new file mode 100644 index 0000000..b2a52dd --- /dev/null +++ b/bruml/lib/socket.io/lib/socket.io/transports/xhr-multipart.js @@ -0,0 +1,67 @@ +var Client = require('../client') + , util = require(process.binding('natives').util ? 'util' : 'sys') + , qs = require('querystring'); + +var Multipart = module.exports = function(){ + Client.apply(this, arguments); +}; + +util.inherits(Multipart, Client); + +Multipart.prototype._onConnect = function(req, res){ + var self = this, body = '', headers = {}; + // https://developer.mozilla.org/En/HTTP_Access_Control + if (req.headers.origin && this._verifyOrigin(req.headers.origin)){ + headers['Access-Control-Allow-Origin'] = '*'; + headers['Access-Control-Allow-Credentials'] = 'true'; + } + if (typeof req.headers['access-control-request-method'] !== 'undefined'){ + // CORS preflight message + headers['Access-Control-Allow-Methods'] = req.headers['access-control-request-method']; + res.writeHead(200, headers); + res.write('ok'); + res.end(); + return; + } + switch (req.method){ + case 'GET': + Client.prototype._onConnect.apply(this, [req, res]); + headers['Content-Type'] = 'multipart/x-mixed-replace;boundary="socketio"'; + headers['Connection'] = 'keep-alive'; + this.request.connection.addListener('end', function(){ self._onClose(); }); + this.response.useChunkedEncodingByDefault = false; + this.response.shouldKeepAlive = true; + this.response.writeHead(200, headers); + this.response.write("--socketio\n"); + if ('flush' in this.response) this.response.flush(); + this._payload(); + break; + + case 'POST': + headers['Content-Type'] = 'text/plain'; + req.addListener('data', function(message){ + body += message.toString(); + }); + req.addListener('end', function(){ + try { + var msg = qs.parse(body); + self._onMessage(msg.data); + } catch(e){ + self.listener.options.log('xhr-multipart message handler error - ' + e.stack); + } + res.writeHead(200, headers); + res.write('ok'); + res.end(); + body = ''; + }); + break; + } +}; + +Multipart.prototype._write = function(message){ + if (this._open){ + this.response.write("Content-Type: text/plain" + (message.length === 1 && message.charCodeAt(0) === 6 ? "; charset=us-ascii" : "") + "\n\n"); + this.response.write(message + "\n"); + this.response.write("--socketio\n"); + } +}; diff --git a/bruml/lib/socket.io/lib/socket.io/transports/xhr-polling.js b/bruml/lib/socket.io/lib/socket.io/transports/xhr-polling.js new file mode 100644 index 0000000..c4fa37f --- /dev/null +++ b/bruml/lib/socket.io/lib/socket.io/transports/xhr-polling.js @@ -0,0 +1,80 @@ +var Client = require('../client') + , util = require(process.binding('natives').util ? 'util' : 'sys') + , qs = require('querystring'); + +var Polling = module.exports = function(){ + Client.apply(this, arguments); +}; + +util.inherits(Polling, Client); + +Polling.prototype.getOptions = function(){ + return { + timeout: null, // no heartbeats + closeTimeout: 8000, + duration: 20000 + }; +}; + +Polling.prototype._onConnect = function(req, res){ + var self = this, body = ''; + switch (req.method){ + case 'GET': + Client.prototype._onConnect.apply(this, [req, res]); + this._closeTimeout = setTimeout(function(){ + self._write(''); + }, this.options.duration); + this._payload(); + break; + + case 'POST': + req.addListener('data', function(message){ + body += message; + }); + req.addListener('end', function(){ + var headers = {'Content-Type': 'text/plain'}; + if (req.headers.origin){ + if (self._verifyOrigin(req.headers.origin)){ + headers['Access-Control-Allow-Origin'] = '*'; + if (req.headers.cookie) headers['Access-Control-Allow-Credentials'] = 'true'; + } else { + res.writeHead(401); + res.write('unauthorized'); + res.end(); + return; + } + } + try { + // optimization: just strip first 5 characters here? + var msg = qs.parse(body); + self._onMessage(msg.data); + } catch(e){ + self.listener.options.log('xhr-polling message handler error - ' + e.stack); + } + res.writeHead(200, headers); + res.write('ok'); + res.end(); + }); + break; + } +}; + +Polling.prototype._onClose = function(){ + if (this._closeTimeout) clearTimeout(this._closeTimeout); + return Client.prototype._onClose.call(this); +}; + +Polling.prototype._write = function(message){ + if (this._open){ + var headers = {'Content-Type': 'text/plain; charset=UTF-8', 'Content-Length': Buffer.byteLength(message)}; + // https://developer.mozilla.org/En/HTTP_Access_Control + if (this.request.headers.origin && this._verifyOrigin(this.request.headers.origin)){ + headers['Access-Control-Allow-Origin'] = (this.request.headers.origin === 'null' ? '*' : this.request.headers.origin); + if (this.request.headers.cookie) headers['Access-Control-Allow-Credentials'] = 'true'; + } + this.response.writeHead(200, headers); + this.response.write(message); + this.response.end(); + this._onClose(); + } +}; diff --git a/bruml/lib/socket.io/lib/socket.io/utils.js b/bruml/lib/socket.io/lib/socket.io/utils.js new file mode 100644 index 0000000..ba2fdec --- /dev/null +++ b/bruml/lib/socket.io/lib/socket.io/utils.js @@ -0,0 +1,52 @@ +exports.options = { + options: function(options, merge){ + this.options = exports.merge(options || {}, merge || {}); + } +}; + +exports.merge = function(source, merge){ + for (var i in merge) source[i] = merge[i]; + return source; +}; + +var frame = '~m~'; + +function stringify(message){ + if (Object.prototype.toString.call(message) == '[object Object]'){ + return '~j~' + JSON.stringify(message); + } else { + return String(message); + } +}; + +exports.encode = function(messages){ + var ret = '', message, + messages = Array.isArray(messages) ? messages : [messages]; + for (var i = 0, l = messages.length; i < l; i++){ + message = messages[i] === null || messages[i] === undefined ? '' : stringify(messages[i]); + ret += frame + message.length + frame + message; + } + return ret; +}; + +exports.decode = function(data){ + var messages = [], number, n; + do { + if (data.substr(0, 3) !== frame) return messages; + data = data.substr(3); + number = '', n = ''; + for (var i = 0, l = data.length; i < l; i++){ + n = Number(data.substr(i, 1)); + if (data.substr(i, 1) == n){ + number += n; + } else { + data = data.substr(number.length + frame.length) + number = Number(number); + break; + } + } + messages.push(data.substr(0, number)); // here + data = data.substr(number); + } while(data !== ''); + return messages; +}; \ No newline at end of file diff --git a/bruml/lib/socket.io/package.json b/bruml/lib/socket.io/package.json new file mode 100644 index 0000000..688107c --- /dev/null +++ b/bruml/lib/socket.io/package.json @@ -0,0 +1,21 @@ +{ + "name": "socket.io" + , "description": "The cross-browser WebSocket" + , "version": "0.6.17" + , "author": "Guillermo Rauch " + , "contributors": [ + { "name": "Guillermo Rauch", "email": "rauchg@gmail.com" } + , { "name": "Arnout Kazemier", "email": "info@3rd-eden.com" } + ] + , "licenses": [{ + "type": "MIT" + , "url": "http://github.com/learnboost/Socket.IO-node/raw/master/README.md" + }] + , "repository": { + "type": "git" + , "url": "http://github.com/learnboost/Socket.IO-node.git" + } + , "engine": [ "node >=0.1.102" ] + , "main": "./index" + , "scripts": { "test" : "make test" } +} diff --git a/bruml/lib/socket.io/support/expresso/History.md b/bruml/lib/socket.io/support/expresso/History.md new file mode 100644 index 0000000..cb16fa9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/History.md @@ -0,0 +1,128 @@ + +0.7.2 / 2010-12-29 +================== + + * Fixed problem with `listen()` sometimes firing on the same tick [guillermo] + +0.7.1 / 2010-12-28 +================== + + * Fixed `assert.request()` client logic into an issue() function, fired upon the `listen()` callback if the server doesn't have an assigned fd. [guillermo] + * Removed `--watch` + +0.7.0 / 2010-11-19 +================== + + * Removed `assert` from test function signature + Just use `require('assert')` :) this will make integration + with libraries like [should](http://github.com/visionmedia/should) cleaner. + +0.6.4 / 2010-11-02 +================== + + * Added regexp support to `assert.response()` headers + * Removed `waitForExit` code, causing issues + +0.6.3 / 2010-11-02 +================== + + * Added `assert.response()` body RegExp support + * Fixed issue with _--serial_ not executing files sequentially. Closes #42 + * Fixed hang when modules use `setInterval` - monitor running tests & force the process to quit after all have completed + timeout [Steve Mason] + +0.6.2 / 2010-09-17 +================== + + * Added _node-jsocoverage_ to package.json (aka will respect npm's binroot) + * Added _-t, --timeout_ MS option, defaulting to 2000 ms + * Added _-s, --serial_ + * __PREFIX__ clobberable + * Fixed `assert.response()` for latest node + * Fixed cov reporting from exploding on empty files + +0.6.2 / 2010-08-03 +================== + + * Added `assert.type()` + * Renamed `assert.isNotUndefined()` to `assert.isDefined()` + * Fixed `assert.includes()` param ordering + +0.6.0 / 2010-07-31 +================== + + * Added _docs/api.html_ + * Added -w, --watch + * Added `Array` support to `assert.includes()` + * Added; outputting exceptions immediately. Closes #19 + * Fixed `assert.includes()` param ordering + * Fixed `assert.length()` param ordering + * Fixed jscoverage links + +0.5.0 / 2010-07-16 +================== + + * Added support for async exports + * Added timeout support to `assert.response()`. Closes #3 + * Added 4th arg callback support to `assert.response()` + * Added `assert.length()` + * Added `assert.match()` + * Added `assert.isUndefined()` + * Added `assert.isNull()` + * Added `assert.includes()` + * Added growlnotify support via -g, --growl + * Added -o, --only TESTS. Ex: --only "test foo()" --only "test foo(), test bar()" + * Removed profanity + +0.4.0 / 2010-07-09 +================== + + * Added reporting source coverage (respects --boring for color haters) + * Added callback to assert.response(). Closes #12 + * Fixed; putting exceptions to stderr. Closes #13 + +0.3.1 / 2010-06-28 +================== + + * Faster assert.response() + +0.3.0 / 2010-06-28 +================== + + * Added -p, --port NUM flags + * Added assert.response(). Closes #11 + +0.2.1 / 2010-06-25 +================== + + * Fixed issue with reporting object assertions + +0.2.0 / 2010-06-21 +================== + + * Added `make uninstall` + * Added better readdir() failure message + * Fixed `make install` for kiwi + +0.1.0 / 2010-06-15 +================== + + * Added better usage docs via --help + * Added better conditional color support + * Added pre exit assertion support + +0.0.3 / 2010-06-02 +================== + + * Added more room for filenames in test coverage + * Added boring output support via --boring (suppress colored output) + * Fixed async failure exit status + +0.0.2 / 2010-05-30 +================== + + * Fixed exit status for CI support + +0.0.1 / 2010-05-30 +================== + + * Initial release \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/Makefile b/bruml/lib/socket.io/support/expresso/Makefile new file mode 100644 index 0000000..8acfe56 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/Makefile @@ -0,0 +1,53 @@ + +PREFIX ?= /usr/local +BIN = bin/expresso +JSCOV = deps/jscoverage/node-jscoverage +DOCS = docs/index.md +HTMLDOCS = $(DOCS:.md=.html) + +test: $(BIN) + @./$(BIN) -I lib --growl $(TEST_FLAGS) test/*.test.js + +test-cov: + @./$(BIN) -I lib --cov $(TEST_FLAGS) test/*.test.js + +test-serial: + @./$(BIN) --serial -I lib $(TEST_FLAGS) test/serial/*.test.js + +install: install-jscov install-expresso + +uninstall: + rm -f $(PREFIX)/bin/expresso + rm -f $(PREFIX)/bin/node-jscoverage + +install-jscov: $(JSCOV) + install $(JSCOV) $(PREFIX)/bin + +install-expresso: + install $(BIN) $(PREFIX)/bin + +$(JSCOV): + cd deps/jscoverage && ./configure && make && mv jscoverage node-jscoverage + +clean: + @cd deps/jscoverage && git clean -fd + +docs: docs/api.html $(HTMLDOCS) + +%.html: %.md + @echo "... $< > $@" + @ronn -5 --pipe --fragment $< \ + | cat docs/layout/head.html - docs/layout/foot.html \ + > $@ + +docs/api.html: bin/expresso + dox \ + --title "Expresso" \ + --ribbon "http://github.com/visionmedia/expresso" \ + --desc "Insanely fast TDD framework for [node](http://nodejs.org) featuring code coverage reporting." \ + $< > $@ + +docclean: + rm -f docs/*.html + +.PHONY: test test-cov install uninstall install-expresso install-jscov clean docs docclean \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/Readme.md b/bruml/lib/socket.io/support/expresso/Readme.md new file mode 100644 index 0000000..05c972e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/Readme.md @@ -0,0 +1,61 @@ + +# Expresso + + TDD framework for [nodejs](http://nodejs.org). + +## Features + + - light-weight + - intuitive async support + - intuitive test runner executable + - test coverage support and reporting + - uses the _assert_ module + - `assert.eql()` alias of `assert.deepEqual()` + - `assert.response()` http response utility + - `assert.includes()` + - `assert.type()` + - `assert.isNull()` + - `assert.isUndefined()` + - `assert.isNotNull()` + - `assert.isDefined()` + - `assert.match()` + - `assert.length()` + +## Installation + +To install both expresso _and_ node-jscoverage run: + + $ make install + +To install expresso alone (no build required) run: + + $ make install-expresso + +Install via npm: + + $ npm install expresso + +## License + +(The MIT License) + +Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bruml/lib/socket.io/support/expresso/bin/expresso b/bruml/lib/socket.io/support/expresso/bin/expresso new file mode 100755 index 0000000..ec1edc8 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/bin/expresso @@ -0,0 +1,856 @@ +#!/usr/bin/env node + +/* + * Expresso + * Copyright(c) TJ Holowaychuk + * (MIT Licensed) + */ + +/** + * Module dependencies. + */ + +var assert = require('assert'), + childProcess = require('child_process'), + http = require('http'), + path = require('path'), + sys = require('sys'), + cwd = process.cwd(), + fs = require('fs'), + defer; + +/** + * Expresso version. + */ + +var version = '0.7.2'; + +/** + * Failure count. + */ + +var failures = 0; + + +/** + * Number of tests executed. + */ + +var testcount = 0; + +/** + * Whitelist of tests to run. + */ + +var only = []; + +/** + * Boring output. + */ + +var boring = false; + +/** + * Growl notifications. + */ + +var growl = false; + +/** + * Server port. + */ + +var port = 5555; + +/** + * Execute serially. + */ + +var serial = false; + +/** + * Default timeout. + */ + +var timeout = 2000; + +/** + * Quiet output. + */ + +var quiet = false; + +/** + * Usage documentation. + */ + +var usage = '' + + '[bold]{Usage}: expresso [options] ' + + '\n' + + '\n[bold]{Options}:' + + '\n -g, --growl Enable growl notifications' + + '\n -c, --coverage Generate and report test coverage' + + '\n -q, --quiet Suppress coverage report if 100%' + + '\n -t, --timeout MS Timeout in milliseconds, defaults to 2000' + + '\n -r, --require PATH Require the given module path' + + '\n -o, --only TESTS Execute only the comma sperated TESTS (can be set several times)' + + '\n -I, --include PATH Unshift the given path to require.paths' + + '\n -p, --port NUM Port number for test servers, starts at 5555' + + '\n -s, --serial Execute tests serially' + + '\n -b, --boring Suppress ansi-escape colors' + + '\n -v, --version Output version number' + + '\n -h, --help Display help information' + + '\n'; + +// Parse arguments + +var files = [], + args = process.argv.slice(2); + +while (args.length) { + var arg = args.shift(); + switch (arg) { + case '-h': + case '--help': + print(usage + '\n'); + process.exit(1); + break; + case '-v': + case '--version': + sys.puts(version); + process.exit(1); + break; + case '-i': + case '-I': + case '--include': + if (arg = args.shift()) { + require.paths.unshift(arg); + } else { + throw new Error('--include requires a path'); + } + break; + case '-o': + case '--only': + if (arg = args.shift()) { + only = only.concat(arg.split(/ *, */)); + } else { + throw new Error('--only requires comma-separated test names'); + } + break; + case '-p': + case '--port': + if (arg = args.shift()) { + port = parseInt(arg, 10); + } else { + throw new Error('--port requires a number'); + } + break; + case '-r': + case '--require': + if (arg = args.shift()) { + require(arg); + } else { + throw new Error('--require requires a path'); + } + break; + case '-t': + case '--timeout': + if (arg = args.shift()) { + timeout = parseInt(arg, 10); + } else { + throw new Error('--timeout requires an argument'); + } + break; + case '-c': + case '--cov': + case '--coverage': + defer = true; + childProcess.exec('rm -fr lib-cov && node-jscoverage lib lib-cov', function(err){ + if (err) throw err; + require.paths.unshift('lib-cov'); + run(files); + }) + break; + case '-q': + case '--quiet': + quiet = true; + break; + case '-b': + case '--boring': + boring = true; + break; + case '-g': + case '--growl': + growl = true; + break; + case '-s': + case '--serial': + serial = true; + break; + default: + if (/\.js$/.test(arg)) { + files.push(arg); + } + break; + } +} + +/** + * Colorized sys.error(). + * + * @param {String} str + */ + +function print(str){ + sys.error(colorize(str)); +} + +/** + * Colorize the given string using ansi-escape sequences. + * Disabled when --boring is set. + * + * @param {String} str + * @return {String} + */ + +function colorize(str){ + var colors = { bold: 1, red: 31, green: 32, yellow: 33 }; + return str.replace(/\[(\w+)\]\{([^]*?)\}/g, function(_, color, str){ + return boring + ? str + : '\x1B[' + colors[color] + 'm' + str + '\x1B[0m'; + }); +} + +// Alias deepEqual as eql for complex equality + +assert.eql = assert.deepEqual; + +/** + * Assert that `val` is null. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isNull = function(val, msg) { + assert.strictEqual(null, val, msg); +}; + +/** + * Assert that `val` is not null. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isNotNull = function(val, msg) { + assert.notStrictEqual(null, val, msg); +}; + +/** + * Assert that `val` is undefined. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isUndefined = function(val, msg) { + assert.strictEqual(undefined, val, msg); +}; + +/** + * Assert that `val` is not undefined. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isDefined = function(val, msg) { + assert.notStrictEqual(undefined, val, msg); +}; + +/** + * Assert that `obj` is `type`. + * + * @param {Mixed} obj + * @param {String} type + * @api public + */ + +assert.type = function(obj, type, msg){ + var real = typeof obj; + msg = msg || 'typeof ' + sys.inspect(obj) + ' is ' + real + ', expected ' + type; + assert.ok(type === real, msg); +}; + +/** + * Assert that `str` matches `regexp`. + * + * @param {String} str + * @param {RegExp} regexp + * @param {String} msg + */ + +assert.match = function(str, regexp, msg) { + msg = msg || sys.inspect(str) + ' does not match ' + sys.inspect(regexp); + assert.ok(regexp.test(str), msg); +}; + +/** + * Assert that `val` is within `obj`. + * + * Examples: + * + * assert.includes('foobar', 'bar'); + * assert.includes(['foo', 'bar'], 'foo'); + * + * @param {String|Array} obj + * @param {Mixed} val + * @param {String} msg + */ + +assert.includes = function(obj, val, msg) { + msg = msg || sys.inspect(obj) + ' does not include ' + sys.inspect(val); + assert.ok(obj.indexOf(val) >= 0, msg); +}; + +/** + * Assert length of `val` is `n`. + * + * @param {Mixed} val + * @param {Number} n + * @param {String} msg + */ + +assert.length = function(val, n, msg) { + msg = msg || sys.inspect(val) + ' has length of ' + val.length + ', expected ' + n; + assert.equal(n, val.length, msg); +}; + +/** + * Assert response from `server` with + * the given `req` object and `res` assertions object. + * + * @param {Server} server + * @param {Object} req + * @param {Object|Function} res + * @param {String} msg + */ + +assert.response = function(server, req, res, msg){ + // Check that the server is ready or defer + if (!server.fd) { + if (!('__deferred' in server)) { + server.__deferred = []; + } + server.__deferred.push(arguments); + if (!server.__started) { + server.listen(server.__port = port++, '127.0.0.1', function(){ + if (server.__deferred) { + process.nextTick(function(){ + server.__deferred.forEach(function(args){ + assert.response.apply(assert, args); + }); + }); + } + }); + server.__started = true; + } + return; + } + + // Callback as third or fourth arg + var callback = typeof res === 'function' + ? res + : typeof msg === 'function' + ? msg + : function(){}; + + // Default messate to test title + if (typeof msg === 'function') msg = null; + msg = msg || assert.testTitle; + msg += '. '; + + // Pending responses + server.__pending = server.__pending || 0; + server.__pending++; + + // Create client + if (!server.fd) { + server.listen(server.__port = port++, '127.0.0.1', issue); + } else { + issue(); + } + + function issue(){ + if (!server.client) + server.client = http.createClient(server.__port); + + // Issue request + var timer, + client = server.client, + method = req.method || 'GET', + status = res.status || res.statusCode, + data = req.data || req.body, + requestTimeout = req.timeout || 0; + + var request = client.request(method, req.url, req.headers); + + // Timeout + if (requestTimeout) { + timer = setTimeout(function(){ + --server.__pending || server.close(); + delete req.timeout; + assert.fail(msg + 'Request timed out after ' + requestTimeout + 'ms.'); + }, requestTimeout); + } + + if (data) request.write(data); + request.on('response', function(response){ + response.body = ''; + response.setEncoding('utf8'); + response.on('data', function(chunk){ response.body += chunk; }); + response.on('end', function(){ + --server.__pending || server.close(); + if (timer) clearTimeout(timer); + + // Assert response body + if (res.body !== undefined) { + var eql = res.body instanceof RegExp + ? res.body.test(response.body) + : res.body === response.body; + assert.ok( + eql, + msg + 'Invalid response body.\n' + + ' Expected: ' + sys.inspect(res.body) + '\n' + + ' Got: ' + sys.inspect(response.body) + ); + } + + // Assert response status + if (typeof status === 'number') { + assert.equal( + response.statusCode, + status, + msg + colorize('Invalid response status code.\n' + + ' Expected: [green]{' + status + '}\n' + + ' Got: [red]{' + response.statusCode + '}') + ); + } + + // Assert response headers + if (res.headers) { + var keys = Object.keys(res.headers); + for (var i = 0, len = keys.length; i < len; ++i) { + var name = keys[i], + actual = response.headers[name.toLowerCase()], + expected = res.headers[name], + eql = expected instanceof RegExp + ? expected.test(actual) + : expected == actual; + assert.ok( + eql, + msg + colorize('Invalid response header [bold]{' + name + '}.\n' + + ' Expected: [green]{' + expected + '}\n' + + ' Got: [red]{' + actual + '}') + ); + } + } + + // Callback + callback(response); + }); + }); + request.end(); + } +}; + +/** + * Pad the given string to the maximum width provided. + * + * @param {String} str + * @param {Number} width + * @return {String} + */ + +function lpad(str, width) { + str = String(str); + var n = width - str.length; + if (n < 1) return str; + while (n--) str = ' ' + str; + return str; +} + +/** + * Pad the given string to the maximum width provided. + * + * @param {String} str + * @param {Number} width + * @return {String} + */ + +function rpad(str, width) { + str = String(str); + var n = width - str.length; + if (n < 1) return str; + while (n--) str = str + ' '; + return str; +} + +/** + * Report test coverage. + * + * @param {Object} cov + */ + +function reportCoverage(cov) { + // Stats + print('\n [bold]{Test Coverage}\n'); + var sep = ' +------------------------------------------+----------+------+------+--------+', + lastSep = ' +----------+------+------+--------+'; + sys.puts(sep); + sys.puts(' | filename | coverage | LOC | SLOC | missed |'); + sys.puts(sep); + for (var name in cov) { + var file = cov[name]; + if (Array.isArray(file)) { + sys.print(' | ' + rpad(name, 40)); + sys.print(' | ' + lpad(file.coverage.toFixed(2), 8)); + sys.print(' | ' + lpad(file.LOC, 4)); + sys.print(' | ' + lpad(file.SLOC, 4)); + sys.print(' | ' + lpad(file.totalMisses, 6)); + sys.print(' |\n'); + } + } + sys.puts(sep); + sys.print(' ' + rpad('', 40)); + sys.print(' | ' + lpad(cov.coverage.toFixed(2), 8)); + sys.print(' | ' + lpad(cov.LOC, 4)); + sys.print(' | ' + lpad(cov.SLOC, 4)); + sys.print(' | ' + lpad(cov.totalMisses, 6)); + sys.print(' |\n'); + sys.puts(lastSep); + // Source + for (var name in cov) { + if (name.match(/\.js$/)) { + var file = cov[name]; + if ((file.coverage < 100) || !quiet) { + print('\n [bold]{' + name + '}:'); + print(file.source); + sys.print('\n'); + } + } + } +} + +/** + * Populate code coverage data. + * + * @param {Object} cov + */ + +function populateCoverage(cov) { + cov.LOC = + cov.SLOC = + cov.totalFiles = + cov.totalHits = + cov.totalMisses = + cov.coverage = 0; + for (var name in cov) { + var file = cov[name]; + if (Array.isArray(file)) { + // Stats + ++cov.totalFiles; + cov.totalHits += file.totalHits = coverage(file, true); + cov.totalMisses += file.totalMisses = coverage(file, false); + file.totalLines = file.totalHits + file.totalMisses; + cov.SLOC += file.SLOC = file.totalLines; + if (!file.source) file.source = []; + cov.LOC += file.LOC = file.source.length; + file.coverage = (file.totalHits / file.totalLines) * 100; + // Source + var width = file.source.length.toString().length; + file.source = file.source.map(function(line, i){ + ++i; + var hits = file[i] === 0 ? 0 : (file[i] || ' '); + if (!boring) { + if (hits === 0) { + hits = '\x1b[31m' + hits + '\x1b[0m'; + line = '\x1b[41m' + line + '\x1b[0m'; + } else { + hits = '\x1b[32m' + hits + '\x1b[0m'; + } + } + return '\n ' + lpad(i, width) + ' | ' + hits + ' | ' + line; + }).join(''); + } + } + cov.coverage = (cov.totalHits / cov.SLOC) * 100; +} + +/** + * Total coverage for the given file data. + * + * @param {Array} data + * @return {Type} + */ + +function coverage(data, val) { + var n = 0; + for (var i = 0, len = data.length; i < len; ++i) { + if (data[i] !== undefined && data[i] == val) ++n; + } + return n; +} + +/** + * Test if all files have 100% coverage + * + * @param {Object} cov + * @return {Boolean} + */ + +function hasFullCoverage(cov) { + for (var name in cov) { + var file = cov[name]; + if (file instanceof Array) { + if (file.coverage !== 100) { + return false; + } + } + } + return true; +} + +/** + * Run the given test `files`, or try _test/*_. + * + * @param {Array} files + */ + +function run(files) { + cursor(false); + if (!files.length) { + try { + files = fs.readdirSync('test').map(function(file){ + return 'test/' + file; + }); + } catch (err) { + print('\n failed to load tests in [bold]{./test}\n'); + ++failures; + process.exit(1); + } + } + runFiles(files); +} + +/** + * Show the cursor when `show` is true, otherwise hide it. + * + * @param {Boolean} show + */ + +function cursor(show) { + if (show) { + sys.print('\x1b[?25h'); + } else { + sys.print('\x1b[?25l'); + } +} + +/** + * Run the given test `files`. + * + * @param {Array} files + */ + +function runFiles(files) { + if (serial) { + (function next(){ + if (files.length) { + runFile(files.shift(), next); + } + })(); + } else { + files.forEach(runFile); + } +} + +/** + * Run tests for the given `file`, callback `fn()` when finished. + * + * @param {String} file + * @param {Function} fn + */ + +function runFile(file, fn) { + if (file.match(/\.js$/)) { + var title = path.basename(file), + file = path.join(cwd, file), + mod = require(file.replace(/\.js$/, '')); + (function check(){ + var len = Object.keys(mod).length; + if (len) { + runSuite(title, mod, fn); + } else { + setTimeout(check, 20); + } + })(); + } +} + +/** + * Report `err` for the given `test` and `suite`. + * + * @param {String} suite + * @param {String} test + * @param {Error} err + */ + +function error(suite, test, err) { + ++failures; + var name = err.name, + stack = err.stack ? err.stack.replace(err.name, '') : '', + label = test === 'uncaught' + ? test + : suite + ' ' + test; + print('\n [bold]{' + label + '}: [red]{' + name + '}' + stack + '\n'); +} + +/** + * Run the given tests, callback `fn()` when finished. + * + * @param {String} title + * @param {Object} tests + * @param {Function} fn + */ + +var dots = 0; +function runSuite(title, tests, fn) { + // Keys + var keys = only.length + ? only.slice(0) + : Object.keys(tests); + + // Setup + var setup = tests.setup || function(fn){ fn(); }; + + // Iterate tests + (function next(){ + if (keys.length) { + var key, + test = tests[key = keys.shift()]; + // Non-tests + if (key === 'setup') return next(); + + // Run test + if (test) { + try { + ++testcount; + assert.testTitle = key; + if (serial) { + sys.print('.'); + if (++dots % 25 === 0) sys.print('\n'); + setup(function(){ + if (test.length < 1) { + test(); + next(); + } else { + var id = setTimeout(function(){ + throw new Error("'" + key + "' timed out"); + }, timeout); + test(function(){ + clearTimeout(id); + next(); + }); + } + }); + } else { + test(function(fn){ + process.on('beforeExit', function(){ + try { + fn(); + } catch (err) { + error(title, key, err); + } + }); + }); + } + } catch (err) { + error(title, key, err); + } + } + if (!serial) next(); + } else if (serial) { + fn(); + } + })(); +} + +/** + * Report exceptions. + */ + +function report() { + cursor(true); + process.emit('beforeExit'); + if (failures) { + print('\n [bold]{Failures}: [red]{' + failures + '}\n\n'); + notify('Failures: ' + failures); + } else { + if (serial) print(''); + print('\n [green]{100%} ' + testcount + ' tests\n'); + notify('100% ok'); + } + if (typeof _$jscoverage === 'object') { + populateCoverage(_$jscoverage); + if (!hasFullCoverage(_$jscoverage) || !quiet) { + reportCoverage(_$jscoverage); + } + } +} + +/** + * Growl notify the given `msg`. + * + * @param {String} msg + */ + +function notify(msg) { + if (growl) { + childProcess.exec('growlnotify -name Expresso -m "' + msg + '"'); + } +} + +// Report uncaught exceptions + +process.on('uncaughtException', function(err){ + error('uncaught', 'uncaught', err); +}); + +// Show cursor + +['INT', 'TERM', 'QUIT'].forEach(function(sig){ + process.on('SIG' + sig, function(){ + cursor(true); + process.exit(1); + }); +}); + +// Report test coverage when available +// and emit "beforeExit" event to perform +// final assertions + +var orig = process.emit; +process.emit = function(event){ + if (event === 'exit') { + report(); + process.reallyExit(failures); + } + orig.apply(this, arguments); +}; + +// Run test files + +if (!defer) run(files); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/COPYING b/bruml/lib/socket.io/support/expresso/deps/jscoverage/COPYING new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/Makefile.am b/bruml/lib/socket.io/support/expresso/deps/jscoverage/Makefile.am new file mode 100644 index 0000000..2b36e6b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/Makefile.am @@ -0,0 +1,81 @@ +# Makefile.am - builds jscoverage +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = js + +AM_CFLAGS = -Ijs -Ijs/obj @XP_DEF@ +AM_CXXFLAGS = -Ijs -Ijs/obj @XP_DEF@ + +resources = jscoverage-help.txt jscoverage-server-help.txt \ + jscoverage.jsm jscoverage.manifest jscoverage.xul jscoverage-overlay.js \ + jscoverage.html \ + jscoverage.css jscoverage-ie.css jscoverage-highlight.css \ + jscoverage.js report.js \ + jscoverage-throbber.gif + +bin_PROGRAMS = jscoverage jscoverage-server +jscoverage_SOURCES = encoding.c encoding.h \ + highlight.c highlight.h \ + instrument.c instrument.h \ + instrument-js.cpp instrument-js.h \ + jscoverage.c global.h \ + resource-manager.c resource-manager.h \ + stream.c stream.h \ + util.c util.h \ + $(resources) +jscoverage_LDADD = js/obj/libjs.a -lm @LIBICONV@ @EXTRA_TIMER_LIBS@ +jscoverage_server_SOURCES = http-connection.c \ + http-exchange.c \ + http-host.c \ + http-message.c \ + http-server.c http-server.h \ + http-url.c \ + encoding.c encoding.h \ + highlight.c highlight.h \ + instrument-js.cpp instrument-js.h \ + jscoverage-server.c global.h \ + resource-manager.c resource-manager.h \ + stream.c stream.h \ + util.c util.h \ + $(resources) +jscoverage_server_LDADD = js/obj/libjs.a -lm @EXTRA_SOCKET_LIBS@ @EXTRA_THREAD_LIBS@ @LIBICONV@ @EXTRA_TIMER_LIBS@ + +noinst_PROGRAMS = generate-resources +generate_resources_SOURCES = generate-resources.c + +BUILT_SOURCES = resources.c + +resources.c: generate-resources $(resources) + $(srcdir)/generate-resources $(resources) > $@ + +dist_man_MANS = jscoverage.1 jscoverage-server.1 + +CLEANFILES = *.gcno *.exe resources.c *~ + +example: jscoverage + $(srcdir)/jscoverage --exclude=.svn doc/example doc/instrumented + +example-inverted: jscoverage + $(srcdir)/jscoverage --exclude=.svn doc/example-inverted doc/instrumented-inverted + +example-jsunit: jscoverage + $(srcdir)/jscoverage --exclude=.svn --no-instrument=jsunit doc/example-jsunit doc/instrumented-jsunit + +# override default install target so as not to recursively install subpackages +install: install-am diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/Makefile.in b/bruml/lib/socket.io/support/expresso/deps/jscoverage/Makefile.in new file mode 100644 index 0000000..a81160d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/Makefile.in @@ -0,0 +1,884 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am - builds jscoverage +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = jscoverage$(EXEEXT) jscoverage-server$(EXEEXT) +noinst_PROGRAMS = generate-resources$(EXEEXT) +subdir = . +DIST_COMMON = README $(am__configure_deps) $(dist_man_MANS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/config.h.in $(srcdir)/make-bin-dist.sh.in \ + $(srcdir)/make-dist.sh.in $(top_srcdir)/configure COPYING \ + config.guess config.rpath config.sub depcomp install-sh \ + missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = make-dist.sh make-bin-dist.sh +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am_generate_resources_OBJECTS = generate-resources.$(OBJEXT) +generate_resources_OBJECTS = $(am_generate_resources_OBJECTS) +generate_resources_LDADD = $(LDADD) +am__objects_1 = +am_jscoverage_OBJECTS = encoding.$(OBJEXT) highlight.$(OBJEXT) \ + instrument.$(OBJEXT) instrument-js.$(OBJEXT) \ + jscoverage.$(OBJEXT) resource-manager.$(OBJEXT) \ + stream.$(OBJEXT) util.$(OBJEXT) $(am__objects_1) +jscoverage_OBJECTS = $(am_jscoverage_OBJECTS) +jscoverage_DEPENDENCIES = js/obj/libjs.a +am_jscoverage_server_OBJECTS = http-connection.$(OBJEXT) \ + http-exchange.$(OBJEXT) http-host.$(OBJEXT) \ + http-message.$(OBJEXT) http-server.$(OBJEXT) \ + http-url.$(OBJEXT) encoding.$(OBJEXT) highlight.$(OBJEXT) \ + instrument-js.$(OBJEXT) jscoverage-server.$(OBJEXT) \ + resource-manager.$(OBJEXT) stream.$(OBJEXT) util.$(OBJEXT) \ + $(am__objects_1) +jscoverage_server_OBJECTS = $(am_jscoverage_server_OBJECTS) +jscoverage_server_DEPENDENCIES = js/obj/libjs.a +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +SOURCES = $(generate_resources_SOURCES) $(jscoverage_SOURCES) \ + $(jscoverage_server_SOURCES) +DIST_SOURCES = $(generate_resources_SOURCES) $(jscoverage_SOURCES) \ + $(jscoverage_server_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(dist_man_MANS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ +EXTRA_THREAD_LIBS = @EXTRA_THREAD_LIBS@ +EXTRA_TIMER_LIBS = @EXTRA_TIMER_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBICONV = @LTLIBICONV@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +XP_DEF = @XP_DEF@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = js +AM_CFLAGS = -Ijs -Ijs/obj @XP_DEF@ +AM_CXXFLAGS = -Ijs -Ijs/obj @XP_DEF@ +resources = jscoverage-help.txt jscoverage-server-help.txt \ + jscoverage.jsm jscoverage.manifest jscoverage.xul jscoverage-overlay.js \ + jscoverage.html \ + jscoverage.css jscoverage-ie.css jscoverage-highlight.css \ + jscoverage.js report.js \ + jscoverage-throbber.gif + +jscoverage_SOURCES = encoding.c encoding.h \ + highlight.c highlight.h \ + instrument.c instrument.h \ + instrument-js.cpp instrument-js.h \ + jscoverage.c global.h \ + resource-manager.c resource-manager.h \ + stream.c stream.h \ + util.c util.h \ + $(resources) + +jscoverage_LDADD = js/obj/libjs.a -lm @LIBICONV@ @EXTRA_TIMER_LIBS@ +jscoverage_server_SOURCES = http-connection.c \ + http-exchange.c \ + http-host.c \ + http-message.c \ + http-server.c http-server.h \ + http-url.c \ + encoding.c encoding.h \ + highlight.c highlight.h \ + instrument-js.cpp instrument-js.h \ + jscoverage-server.c global.h \ + resource-manager.c resource-manager.h \ + stream.c stream.h \ + util.c util.h \ + $(resources) + +jscoverage_server_LDADD = js/obj/libjs.a -lm @EXTRA_SOCKET_LIBS@ @EXTRA_THREAD_LIBS@ @LIBICONV@ @EXTRA_TIMER_LIBS@ +generate_resources_SOURCES = generate-resources.c +BUILT_SOURCES = resources.c +dist_man_MANS = jscoverage.1 jscoverage-server.1 +CLEANFILES = *.gcno *.exe resources.c *~ +all: $(BUILT_SOURCES) config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +.SUFFIXES: .c .cpp .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ + cd $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: $(am__configure_deps) + cd $(top_srcdir) && $(AUTOHEADER) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +make-dist.sh: $(top_builddir)/config.status $(srcdir)/make-dist.sh.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +make-bin-dist.sh: $(top_builddir)/config.status $(srcdir)/make-bin-dist.sh.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +generate-resources$(EXEEXT): $(generate_resources_OBJECTS) $(generate_resources_DEPENDENCIES) + @rm -f generate-resources$(EXEEXT) + $(LINK) $(generate_resources_OBJECTS) $(generate_resources_LDADD) $(LIBS) +jscoverage$(EXEEXT): $(jscoverage_OBJECTS) $(jscoverage_DEPENDENCIES) + @rm -f jscoverage$(EXEEXT) + $(CXXLINK) $(jscoverage_OBJECTS) $(jscoverage_LDADD) $(LIBS) +jscoverage-server$(EXEEXT): $(jscoverage_server_OBJECTS) $(jscoverage_server_DEPENDENCIES) + @rm -f jscoverage-server$(EXEEXT) + $(CXXLINK) $(jscoverage_server_OBJECTS) $(jscoverage_server_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encoding.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generate-resources.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/highlight.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-connection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-exchange.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-host.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-message.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-url.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/instrument-js.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/instrument.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jscoverage-server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jscoverage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resource-manager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d $(distdir) || mkdir $(distdir) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-recursive +all-am: Makefile $(PROGRAMS) $(MANS) config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-recursive + +install-exec-am: install-binPROGRAMS + +install-html: install-html-recursive + +install-info: install-info-recursive + +install-man: install-man1 + +install-pdf: install-pdf-recursive + +install-ps: install-ps-recursive + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-man + +uninstall-man: uninstall-man1 + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ + install-strip + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-binPROGRAMS \ + clean-generic clean-noinstPROGRAMS ctags ctags-recursive dist \ + dist-all dist-bzip2 dist-gzip dist-lzma dist-shar dist-tarZ \ + dist-zip distcheck distclean distclean-compile \ + distclean-generic distclean-hdr distclean-tags distcleancheck \ + distdir distuninstallcheck dvi dvi-am html html-am info \ + info-am install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-man1 install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-man uninstall-man1 + + +resources.c: generate-resources $(resources) + $(srcdir)/generate-resources $(resources) > $@ + +example: jscoverage + $(srcdir)/jscoverage --exclude=.svn doc/example doc/instrumented + +example-inverted: jscoverage + $(srcdir)/jscoverage --exclude=.svn doc/example-inverted doc/instrumented-inverted + +example-jsunit: jscoverage + $(srcdir)/jscoverage --exclude=.svn --no-instrument=jsunit doc/example-jsunit doc/instrumented-jsunit + +# override default install target so as not to recursively install subpackages +install: install-am +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/Readme.md b/bruml/lib/socket.io/support/expresso/deps/jscoverage/Readme.md new file mode 100644 index 0000000..7d7bda7 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/Readme.md @@ -0,0 +1,8 @@ +# node-jscoverage + + [JScoverage](http://siliconforks.com/jscoverage/) for node. + +## Installation + + $ ./configure && make && make install + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/aclocal.m4 b/bruml/lib/socket.io/support/expresso/deps/jscoverage/aclocal.m4 new file mode 100644 index 0000000..8c0fb02 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/aclocal.m4 @@ -0,0 +1,872 @@ +# generated automatically by aclocal 1.10.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(AC_AUTOCONF_VERSION, [2.61],, +[m4_warning([this file was generated for autoconf 2.61. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.10' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.10.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.10.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 13 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.60])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([m4/iconv.m4]) +m4_include([m4/lib-ld.m4]) +m4_include([m4/lib-link.m4]) +m4_include([m4/lib-prefix.m4]) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/config.guess b/bruml/lib/socket.io/support/expresso/deps/jscoverage/config.guess new file mode 100755 index 0000000..f32079a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/config.guess @@ -0,0 +1,1526 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. + +timestamp='2008-01-23' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/config.h.in b/bruml/lib/socket.io/support/expresso/deps/jscoverage/config.h.in new file mode 100644 index 0000000..fb3f802 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/config.h.in @@ -0,0 +1,92 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `asprintf' function. */ +#undef HAVE_ASPRINTF + +/* Define to 1 if you have the `getaddrinfo' function. */ +#undef HAVE_GETADDRINFO + +/* Define to 1 if you have the `gethostbyname_r' function. */ +#undef HAVE_GETHOSTBYNAME_R + +/* Define if you have the iconv() function and it works. */ +#undef HAVE_ICONV + +/* Define to 1 if you have the header file. */ +#undef HAVE_ICONV_H + +/* Define to 1 if you have the `inet_aton' function. */ +#undef HAVE_INET_ATON + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `MultiByteToWideChar' function. */ +#undef HAVE_MULTIBYTETOWIDECHAR + +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strndup' function. */ +#undef HAVE_STRNDUP + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_WINDOWS_H + +/* Define as const if the declaration of iconv() needs const. */ +#undef ICONV_CONST + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/config.rpath b/bruml/lib/socket.io/support/expresso/deps/jscoverage/config.rpath new file mode 100755 index 0000000..c547c68 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/config.rpath @@ -0,0 +1,666 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2007 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit , 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + darwin*) + case $cc_basename in + xlc*) + wl='-Wl,' + ;; + esac + ;; + mingw* | cygwin* | pw32* | os2*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + newsos6) + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + wl='-Wl,' + ;; + pgcc | pgf77 | pgf90) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + rdos*) + ;; + solaris*) + wl='-Wl,' + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + wl='-Wl,' + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we cannot use + # them. + ld_shlibs=no + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + interix[3-9]*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if test "$GCC" = yes ; then + : + else + case $cc_basename in + xlc*) + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd1*) + ld_shlibs=no + ;; + freebsd2.2*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + freebsd2*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER. +# Unlike libtool.m4, here we don't care about _all_ names of the library, but +# only about the one the linker finds when passed -lNAME. This is the last +# element of library_names_spec in libtool.m4, or possibly two of them if the +# linker has special search rules. +library_names_spec= # the last element of library_names_spec in libtool.m4 +libname_spec='lib$name' +case "$host_os" in + aix3*) + library_names_spec='$libname.a' + ;; + aix4* | aix5*) + library_names_spec='$libname$shrext' + ;; + amigaos*) + library_names_spec='$libname.a' + ;; + beos*) + library_names_spec='$libname$shrext' + ;; + bsdi[45]*) + library_names_spec='$libname$shrext' + ;; + cygwin* | mingw* | pw32*) + shrext=.dll + library_names_spec='$libname.dll.a $libname.lib' + ;; + darwin* | rhapsody*) + shrext=.dylib + library_names_spec='$libname$shrext' + ;; + dgux*) + library_names_spec='$libname$shrext' + ;; + freebsd1*) + ;; + freebsd* | dragonfly*) + case "$host_os" in + freebsd[123]*) + library_names_spec='$libname$shrext$versuffix' ;; + *) + library_names_spec='$libname$shrext' ;; + esac + ;; + gnu*) + library_names_spec='$libname$shrext' + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + library_names_spec='$libname$shrext' + ;; + interix[3-9]*) + library_names_spec='$libname$shrext' + ;; + irix5* | irix6* | nonstopux*) + library_names_spec='$libname$shrext' + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux* | k*bsd*-gnu) + library_names_spec='$libname$shrext' + ;; + knetbsd*-gnu) + library_names_spec='$libname$shrext' + ;; + netbsd*) + library_names_spec='$libname$shrext' + ;; + newsos6) + library_names_spec='$libname$shrext' + ;; + nto-qnx*) + library_names_spec='$libname$shrext' + ;; + openbsd*) + library_names_spec='$libname$shrext$versuffix' + ;; + os2*) + libname_spec='$name' + shrext=.dll + library_names_spec='$libname.a' + ;; + osf3* | osf4* | osf5*) + library_names_spec='$libname$shrext' + ;; + rdos*) + ;; + solaris*) + library_names_spec='$libname$shrext' + ;; + sunos4*) + library_names_spec='$libname$shrext$versuffix' + ;; + sysv4 | sysv4.3*) + library_names_spec='$libname$shrext' + ;; + sysv4*MP*) + library_names_spec='$libname$shrext' + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + library_names_spec='$libname$shrext' + ;; + uts4*) + library_names_spec='$libname$shrext' + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/configure b/bruml/lib/socket.io/support/expresso/deps/jscoverage/configure new file mode 100755 index 0000000..71e6752 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/configure @@ -0,0 +1,7971 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61 for jscoverage 0.4. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME='jscoverage' +PACKAGE_TARNAME='jscoverage' +PACKAGE_VERSION='0.4' +PACKAGE_STRING='jscoverage 0.4' +PACKAGE_BUGREPORT='' + +ac_unique_file="jscoverage.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +am__isrc +CYGPATH_W +PACKAGE +VERSION +ACLOCAL +AUTOCONF +AUTOMAKE +AUTOHEADER +MAKEINFO +install_sh +STRIP +INSTALL_STRIP_PROGRAM +mkdir_p +AWK +SET_MAKE +am__leading_dot +AMTAR +am__tar +am__untar +build +build_cpu +build_vendor +build_os +host +host_cpu +host_vendor +host_os +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +DEPDIR +am__include +am__quote +AMDEP_TRUE +AMDEP_FALSE +AMDEPBACKSLASH +CCDEPMODE +am__fastdepCC_TRUE +am__fastdepCC_FALSE +CXX +CXXFLAGS +ac_ct_CXX +CXXDEPMODE +am__fastdepCXX_TRUE +am__fastdepCXX_FALSE +LIBICONV +LTLIBICONV +CPP +GREP +EGREP +XP_DEF +EXTRA_SOCKET_LIBS +EXTRA_THREAD_LIBS +EXTRA_TIMER_LIBS +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures jscoverage 0.4 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/jscoverage] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of jscoverage 0.4:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --disable-rpath do not hardcode runtime library paths + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-gnu-ld assume the C compiler uses GNU ld default=no + --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib + --without-libiconv-prefix don't search for libiconv in includedir and libdir + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +jscoverage configure 0.4 +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by jscoverage $as_me 0.4, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +am__api_version='1.10' + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm -f conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +{ echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 +echo $ECHO_N "checking for a thread-safe mkdir -p... $ECHO_C" >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done +done +IFS=$as_save_IFS + +fi + + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ echo "$as_me:$LINENO: result: $MKDIR_P" >&5 +echo "${ECHO_T}$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } +set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + SET_MAKE= +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='jscoverage' + VERSION='0.4' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + +ac_config_headers="$ac_config_headers config.h" + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 +echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} + { (exit 1); exit 1; }; } + +{ echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6; } +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 +echo "$as_me: error: invalid value of canonical build" >&2;} + { (exit 1); exit 1; }; };; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6; } +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 +echo "$as_me: error: invalid value of canonical host" >&2;} + { (exit 1); exit 1; }; };; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + +# Checks for programs. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +{ echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + { echo "$as_me:$LINENO: checking for $CC option to accept ISO C99" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C99... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c99+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +#include + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +#define debug(...) fprintf (stderr, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + your preprocessor is broken; +#endif +#if BIG_OK +#else + your preprocessor is broken; +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\0'; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static void +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str; + int number; + float fnumber; + + while (*format) + { + switch (*format++) + { + case 's': // string + str = va_arg (args_copy, const char *); + break; + case 'd': // int + number = va_arg (args_copy, int); + break; + case 'f': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); +} + +int +main () +{ + + // Check bool. + _Bool success = false; + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + test_varargs ("s, d' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' + || dynamic_array[ni.number - 1] != 543); + + ; + return 0; +} +_ACEOF +for ac_arg in '' -std=gnu99 -c99 -qlanglvl=extc99 +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c99=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c99" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c99" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c99" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c99" >&6; } ;; +esac + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + +# Checks for libraries. + + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { echo "$as_me:$LINENO: checking for ld used by GCC" >&5 +echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6; } +else + { echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6; } +fi +if test "${acl_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break ;; + *) + test "$with_gnu_ld" != yes && break ;; + esac + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$acl_cv_path_LD" +if test -n "$LD"; then + { echo "$as_me:$LINENO: result: $LD" >&5 +echo "${ECHO_T}$LD" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +{ echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6; } +if test "${acl_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$acl_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$acl_cv_prog_gnu_ld + + + + + { echo "$as_me:$LINENO: checking for shared library run path origin" >&5 +echo $ECHO_N "checking for shared library run path origin... $ECHO_C" >&6; } +if test "${acl_cv_rpath+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + +fi +{ echo "$as_me:$LINENO: result: $acl_cv_rpath" >&5 +echo "${ECHO_T}$acl_cv_rpath" >&6; } + wl="$acl_cv_wl" + acl_libext="$acl_cv_libext" + acl_shlibext="$acl_cv_shlibext" + acl_libname_spec="$acl_cv_libname_spec" + acl_library_names_spec="$acl_cv_library_names_spec" + acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + acl_hardcode_direct="$acl_cv_hardcode_direct" + acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" + # Check whether --enable-rpath was given. +if test "${enable_rpath+set}" = set; then + enableval=$enable_rpath; : +else + enable_rpath=yes +fi + + + + acl_libdirstem=lib + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi + + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libiconv-prefix was given. +if test "${with_libiconv_prefix+set}" = set; then + withval=$with_libiconv_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi + +fi + + LIBICONV= + LTLIBICONV= + INCICONV= + LIBICONV_PREFIX= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='iconv ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$acl_hardcode_direct" = yes; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + LIBICONV_PREFIX="$basedir" + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBICONV="${LIBICONV}${LIBICONV:+ }$dep" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep" + ;; + esac + done + fi + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir" + done + fi + + + + + + + + + am_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCICONV; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { echo "$as_me:$LINENO: checking for iconv" >&5 +echo $ECHO_N "checking for iconv... $ECHO_C" >&6; } +if test "${am_cv_func_iconv+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + am_cv_func_iconv=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$am_save_LIBS" + fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_func_iconv" >&5 +echo "${ECHO_T}$am_cv_func_iconv" >&6; } + if test "$am_cv_func_iconv" = yes; then + { echo "$as_me:$LINENO: checking for working iconv" >&5 +echo $ECHO_N "checking for working iconv... $ECHO_C" >&6; } +if test "${am_cv_func_iconv_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + am_save_LIBS="$LIBS" + if test $am_cv_lib_iconv = yes; then + LIBS="$LIBS $LIBICONV" + fi + if test "$cross_compiling" = yes; then + case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include +int main () +{ + /* Test against AIX 5.1 bug: Failures are not distinguishable from successful + returns. */ + { + iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); + if (cd_utf8_to_88591 != (iconv_t)(-1)) + { + static const char input[] = "\342\202\254"; /* EURO SIGN */ + char buf[10]; + const char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_utf8_to_88591, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + return 1; + } + } +#if 0 /* This bug could be worked around by the caller. */ + /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + char buf[50]; + const char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_88591_to_utf8, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if ((int)res > 0) + return 1; + } + } +#endif + /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is + provided. */ + if (/* Try standardized names. */ + iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) + /* Try IRIX, OSF/1 names. */ + && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) + /* Try AIX names. */ + && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) + /* Try HP-UX names. */ + && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) + return 1; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + am_cv_func_iconv_works=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +am_cv_func_iconv_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + + LIBS="$am_save_LIBS" + +fi +{ echo "$as_me:$LINENO: result: $am_cv_func_iconv_works" >&5 +echo "${ECHO_T}$am_cv_func_iconv_works" >&6; } + case "$am_cv_func_iconv_works" in + *no) am_func_iconv=no am_cv_lib_iconv=no ;; + *) am_func_iconv=yes ;; + esac + else + am_func_iconv=no am_cv_lib_iconv=no + fi + if test "$am_func_iconv" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_ICONV 1 +_ACEOF + + fi + if test "$am_cv_lib_iconv" = yes; then + { echo "$as_me:$LINENO: checking how to link with libiconv" >&5 +echo $ECHO_N "checking how to link with libiconv... $ECHO_C" >&6; } + { echo "$as_me:$LINENO: result: $LIBICONV" >&5 +echo "${ECHO_T}$LIBICONV" >&6; } + else + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + + + + if test "$am_cv_func_iconv" = yes; then + { echo "$as_me:$LINENO: checking for iconv declaration" >&5 +echo $ECHO_N "checking for iconv declaration... $ECHO_C" >&6; } + if test "${am_cv_proto_iconv+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + am_cv_proto_iconv_arg1="" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + am_cv_proto_iconv_arg1="const" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" +fi + + am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + { echo "$as_me:$LINENO: result: ${ac_t:- + }$am_cv_proto_iconv" >&5 +echo "${ECHO_T}${ac_t:- + }$am_cv_proto_iconv" >&6; } + +cat >>confdefs.h <<_ACEOF +#define ICONV_CONST $am_cv_proto_iconv_arg1 +_ACEOF + + fi + + +# Checks for header files. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in pthread.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in iconv.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in windows.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for typedefs, structures, and compiler characteristics. +{ echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 +echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; } +if test "${ac_cv_c_bigendian+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # See if sys/param.h defines the BYTE_ORDER macro. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \ + && BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN) + bogus endian macros +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + # It does; now see whether it defined to BIG_ENDIAN or not. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_bigendian=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_bigendian=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # It does not; compile a test program. +if test "$cross_compiling" = yes; then + # try to guess the endianness by grepping values into an object file + ac_cv_c_bigendian=unknown + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; +short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; +void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } +short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; +short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; +void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } +int +main () +{ + _ascii (); _ebcdic (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then + ac_cv_c_bigendian=yes +fi +if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +echo "${ECHO_T}$ac_cv_c_bigendian" >&6; } +case $ac_cv_c_bigendian in + yes) + +cat >>confdefs.h <<\_ACEOF +#define WORDS_BIGENDIAN 1 +_ACEOF + ;; + no) + ;; + *) + { { echo "$as_me:$LINENO: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&5 +echo "$as_me: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} + { (exit 1); exit 1; }; } ;; +esac + + +# Checks for library functions. + + + + + + +for ac_func in getaddrinfo gethostbyname_r inet_aton strndup vasprintf asprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +{ echo "$as_me:$LINENO: checking for MultiByteToWideChar" >&5 +echo $ECHO_N "checking for MultiByteToWideChar... $ECHO_C" >&6; } +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +MultiByteToWideChar(0,0,0,0,0,0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MULTIBYTETOWIDECHAR 1 +_ACEOF + + jscoverage_have_multibytetowidechar=yes + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + jscoverage_have_multibytetowidechar=no + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + + +case "$host_os" in + mingw*) + XP_DEF='-DXP_WIN' + ;; + *) + XP_DEF='-DXP_UNIX' + ;; +esac + + + + +case "$host_os" in + mingw*) + EXTRA_SOCKET_LIBS='-lws2_32' + EXTRA_THREAD_LIBS='' + EXTRA_TIMER_LIBS='-lwinmm' + ;; + *) + EXTRA_SOCKET_LIBS='' + EXTRA_THREAD_LIBS='-lpthread' + EXTRA_TIMER_LIBS='' + ;; +esac + +if test "$am_cv_func_iconv" != yes && test "$jscoverage_have_multibytetowidechar" != yes +then + echo -ne '\033[1;31m' + { echo "$as_me:$LINENO: WARNING: neither iconv nor Windows character encoding conversion functions found" >&5 +echo "$as_me: WARNING: neither iconv nor Windows character encoding conversion functions found" >&2;} + { echo "$as_me:$LINENO: WARNING: only ASCII will be supported" >&5 +echo "$as_me: WARNING: only ASCII will be supported" >&2;} + echo -ne '\033[0m' +fi + +ac_config_files="$ac_config_files Makefile make-dist.sh make-bin-dist.sh tests/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by jscoverage $as_me 0.4, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +jscoverage config.status 0.4 +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "make-dist.sh") CONFIG_FILES="$CONFIG_FILES make-dist.sh" ;; + "make-bin-dist.sh") CONFIG_FILES="$CONFIG_FILES make-bin-dist.sh" ;; + "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +am__isrc!$am__isrc$ac_delim +CYGPATH_W!$CYGPATH_W$ac_delim +PACKAGE!$PACKAGE$ac_delim +VERSION!$VERSION$ac_delim +ACLOCAL!$ACLOCAL$ac_delim +AUTOCONF!$AUTOCONF$ac_delim +AUTOMAKE!$AUTOMAKE$ac_delim +AUTOHEADER!$AUTOHEADER$ac_delim +MAKEINFO!$MAKEINFO$ac_delim +install_sh!$install_sh$ac_delim +STRIP!$STRIP$ac_delim +INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim +mkdir_p!$mkdir_p$ac_delim +AWK!$AWK$ac_delim +SET_MAKE!$SET_MAKE$ac_delim +am__leading_dot!$am__leading_dot$ac_delim +AMTAR!$AMTAR$ac_delim +am__tar!$am__tar$ac_delim +am__untar!$am__untar$ac_delim +build!$build$ac_delim +build_cpu!$build_cpu$ac_delim +build_vendor!$build_vendor$ac_delim +build_os!$build_os$ac_delim +host!$host$ac_delim +host_cpu!$host_cpu$ac_delim +host_vendor!$host_vendor$ac_delim +host_os!$host_os$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +DEPDIR!$DEPDIR$ac_delim +am__include!$am__include$ac_delim +am__quote!$am__quote$ac_delim +AMDEP_TRUE!$AMDEP_TRUE$ac_delim +AMDEP_FALSE!$AMDEP_FALSE$ac_delim +AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim +CCDEPMODE!$CCDEPMODE$ac_delim +am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim +am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim +ac_ct_CXX!$ac_ct_CXX$ac_delim +CXXDEPMODE!$CXXDEPMODE$ac_delim +am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim +am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim +LIBICONV!$LIBICONV$ac_delim +LTLIBICONV!$LTLIBICONV$ac_delim +CPP!$CPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +XP_DEF!$XP_DEF$ac_delim +EXTRA_SOCKET_LIBS!$EXTRA_SOCKET_LIBS$ac_delim +EXTRA_THREAD_LIBS!$EXTRA_THREAD_LIBS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +CEOF$ac_eof +_ACEOF + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +EXTRA_TIMER_LIBS!$EXTRA_TIMER_LIBS$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 3; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # +_ACEOF + +# Transform confdefs.h into a sed script `conftest.defines', that +# substitutes the proper values into config.h.in to produce config.h. +rm -f conftest.defines conftest.tail +# First, append a space to every undef/define line, to ease matching. +echo 's/$/ /' >conftest.defines +# Then, protect against being on the right side of a sed subst, or in +# an unquoted here document, in config.status. If some macros were +# called several times there might be several #defines for the same +# symbol, which is useless. But do not sort them, since the last +# AC_DEFINE must be honored. +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where +# NAME is the cpp macro being defined, VALUE is the value it is being given. +# PARAMS is the parameter list in the macro definition--in most cases, it's +# just an empty string. +ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' +ac_dB='\\)[ (].*,\\1define\\2' +ac_dC=' ' +ac_dD=' ,' + +uniq confdefs.h | + sed -n ' + t rset + :rset + s/^[ ]*#[ ]*define[ ][ ]*// + t ok + d + :ok + s/[\\&,]/\\&/g + s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p + s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p + ' >>conftest.defines + +# Remove the space that was appended to ease matching. +# Then replace #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +# (The regexp can be short, since the line contains either #define or #undef.) +echo 's/ $// +s,^[ #]*u.*,/* & */,' >>conftest.defines + +# Break up conftest.defines: +ac_max_sed_lines=50 + +# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" +# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" +# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" +# et cetera. +ac_in='$ac_file_inputs' +ac_out='"$tmp/out1"' +ac_nxt='"$tmp/out2"' + +while : +do + # Write a here document: + cat >>$CONFIG_STATUS <<_ACEOF + # First, check the format of the line: + cat >"\$tmp/defines.sed" <<\\CEOF +/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def +/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def +b +:def +_ACEOF + sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS + ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in + sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail + grep . conftest.tail >/dev/null || break + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines conftest.tail + +echo "ac_result=$ac_in" >>$CONFIG_STATUS +cat >>$CONFIG_STATUS <<\_ACEOF + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" +# Compute $ac_file's index in $config_headers. +_am_arg=$ac_file +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { echo "$as_me:$LINENO: executing $ac_file commands" >&5 +echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir=$dirpart/$fdir + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + + esac +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/configure.ac b/bruml/lib/socket.io/support/expresso/deps/jscoverage/configure.ac new file mode 100644 index 0000000..33aa915 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/configure.ac @@ -0,0 +1,88 @@ +# configure.ac - configures jscoverage +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +AC_PREREQ(2.61) +AC_INIT([jscoverage], [0.4]) +AM_INIT_AUTOMAKE([-Wall foreign]) +AC_CONFIG_SRCDIR([jscoverage.c]) +AC_CONFIG_HEADERS([config.h]) +AC_CANONICAL_HOST + +# Checks for programs. +AC_PROG_CC +AC_PROG_CC_C99 +AC_PROG_CXX + +# Checks for libraries. +AM_ICONV + +# Checks for header files. +AC_CHECK_HEADERS([pthread.h]) +AC_CHECK_HEADERS([iconv.h]) +AC_CHECK_HEADERS([windows.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_BIGENDIAN + +# Checks for library functions. +AC_CHECK_FUNCS([getaddrinfo gethostbyname_r inet_aton strndup vasprintf asprintf]) +AC_MSG_CHECKING([for MultiByteToWideChar]) +AC_LANG(C) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[#include ]],[[MultiByteToWideChar(0,0,0,0,0,0);]])], + [AC_DEFINE([HAVE_MULTIBYTETOWIDECHAR], [1], [Define to 1 if you have the `MultiByteToWideChar' function.]) + jscoverage_have_multibytetowidechar=yes + AC_MSG_RESULT([yes])], + [jscoverage_have_multibytetowidechar=no + AC_MSG_RESULT([no])]) + +AC_SUBST([XP_DEF]) +case "$host_os" in + mingw*) + XP_DEF='-DXP_WIN' + ;; + *) + XP_DEF='-DXP_UNIX' + ;; +esac + +AC_SUBST([EXTRA_SOCKET_LIBS]) +AC_SUBST([EXTRA_THREAD_LIBS]) +AC_SUBST([EXTRA_TIMER_LIBS]) +case "$host_os" in + mingw*) + EXTRA_SOCKET_LIBS='-lws2_32' + EXTRA_THREAD_LIBS='' + EXTRA_TIMER_LIBS='-lwinmm' + ;; + *) + EXTRA_SOCKET_LIBS='' + EXTRA_THREAD_LIBS='-lpthread' + EXTRA_TIMER_LIBS='' + ;; +esac + +if test "$am_cv_func_iconv" != yes && test "$jscoverage_have_multibytetowidechar" != yes +then + echo -ne '\033@<:@1;31m' + AC_MSG_WARN([neither iconv nor Windows character encoding conversion functions found]) + AC_MSG_WARN([only ASCII will be supported]) + echo -ne '\033@<:@0m' +fi + +AC_CONFIG_FILES([Makefile make-dist.sh make-bin-dist.sh tests/Makefile]) +AC_OUTPUT diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/depcomp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/depcomp new file mode 100755 index 0000000..e5f9736 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/depcomp @@ -0,0 +1,589 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2007-03-29.01 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007 Free Software +# Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/demo.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/demo.html new file mode 100644 index 0000000..3d7729e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/demo.html @@ -0,0 +1,87 @@ + + + +JSCoverage - demo + + + + +
+

JSCoverage
code coverage for JavaScript

+
+
+
+

Demo

+

+ Several examples of JSCoverage in action are available online. For each demo, click the "Summary" tab + after the JavaScript code in the "Browser" tab has executed. See the manual + for more information. +

+
+
Simple demo
+
A trivial demonstration of JSCoverage. Simply choose a number and then click the "Summary" tab.
+
MochiKit test suite
+
The MochiKit library test suite, instrumented using JSCoverage.
+
jQuery test suite
+
The jQuery library test suite + (which uses the QUnit test framework), + instrumented using JSCoverage.
+
script.aculo.us test suite
+
The script.aculo.us library test suite, instrumented using JSCoverage. (For this one you + will have to click the links in the left frame to run the tests.)
+
MooTools test suite
+
The MooTools library test suite + (which uses the JSSpec test framework), + instrumented using JSCoverage.
+
+

Inverted mode

+

+ The following are examples of running JSCoverage in "inverted mode": + for each demo, click the "Coverage report" button after the JavaScript + code on the page has executed. +

+
+
Simple inverted mode demo
+
A trivial demonstration JSCoverage in "inverted mode". + Choose a number and then click the "Coverage report" button.
+
Simple JsUnit demo
+
A trivial demonstration of using JSCoverage with JsUnit. Once the + JsUnit unit tests have run, click the "Coverage report" button.
+
JsUnit test suite
+
JsUnit's own test suite, instrumented using JSCoverage. (Note: some versions of Safari seem to have trouble with the tests in the latest version of JsUnit.)
+
YUI test suite +
The YUI library test suite + (which uses the YUI Test test framework), + instrumented using JSCoverage. +
Dojo test suite +
The Dojo library test suite + (which uses the D.O.H. test framework), + instrumented using JSCoverage. (Note: Internet Explorer may generate errors for some tests in this suite.) +
+
+
+
+ +
+
+
+
+ Copyright © 2007, 2008 Silicon Forks siliconforks.com
+ jscoverage@siliconforks.com +
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/doc.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/doc.css new file mode 100644 index 0000000..9ac26f4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/doc.css @@ -0,0 +1,45 @@ +body { + margin-left: 3%; + margin-right: 3%; + font-family: sans-serif; +} + +pre { + margin-left: 3%; + margin-right: 3%; + padding: 1em; + border: 1px dotted black; + background-color: #eee; +} + +pre.sh_sourceCode { + background-color: #eee; +} + +table { + margin-left: 3%; + margin-right: 3%; + border-collapse: collapse; +} + +td { + vertical-align: top; + border-width: 0; + padding: 0; +} + +td.arrow { + vertical-align: middle; + font-size: xx-large; + padding-left: 20px; + padding-right: 20px; +} + +td pre { + margin: 0; +} + +img.icon { + vertical-align: middle; + border-width: 0px; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/index.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/index.html new file mode 100644 index 0000000..be0f8ea --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/index.html @@ -0,0 +1,25 @@ + + + +Example + + + + +
Please select your favorite number:
+
+
+
+
+
+ + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/script.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/script.js new file mode 100644 index 0000000..f36a51d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/script.js @@ -0,0 +1,20 @@ +function go(element) { + var message; + if (element.id === 'radio1') { + message = 'You selected the number 1.'; + } + else if (element.id === 'radio2') { + message = 'You selected the number 2.'; + } + else if (element.id === 'radio3') { + message = 'You selected the number 3.'; + } + else if (element.id === 'radio4') { + message = 'You selected the number 4.'; + } + var div = document.getElementById('request'); + div.className = 'black'; + div = document.getElementById('result'); + div.innerHTML = '

' + message + '

'; + div.innerHTML += '

If you are running the instrumented version of this program, you can click the "Coverage report" button to view a coverage report.

'; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/jsUnitStyle.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/jsUnitStyle.css new file mode 100644 index 0000000..358bffe --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/jsUnitStyle.css @@ -0,0 +1,50 @@ +body { + margin-top: 0; + margin-bottom: 0; + font-family: Verdana, Arial, Helvetica, sans-serif; + color: #000; + font-size: 0.8em; + background-color: #fff; +} + +a:link, a:visited { + color: #00F; +} + +a:hover { + color: #F00; +} + +h1 { + font-size: 1.2em; + font-weight: bold; + color: #039; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +h2 { + font-weight: bold; + color: #039; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +h3 { + font-weight: bold; + color: #039; + text-decoration: underline; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +h4 { + font-weight: bold; + color: #039; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +.jsUnitTestResultSuccess { + color: #000; +} + +.jsUnitTestResultNotSuccess { + color: #F00; +} \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/readme b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/readme new file mode 100644 index 0000000..f722210 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/readme @@ -0,0 +1,10 @@ +this file is required due to differences in behavior between Mozilla/Opera +and Internet Explorer. + +main-data.html calls kickOffTests() which calls top.testManager.start() +in the top most frame. top.testManager.start() initializes the output +frames using document.write and HTML containing a relative to the +jsUnitStyle.css file. In MSIE, the base href used to find the CSS file is +that of the top level frame however in Mozilla/Opera the base href is +that of main-data.html. This leads to not-found for the jsUnitStyle.css +in Mozilla/Opera. Creating app/css/jsUnitStyle.css works around this problem. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/emptyPage.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/emptyPage.html new file mode 100644 index 0000000..f9729dc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/emptyPage.html @@ -0,0 +1,11 @@ + + + + + emptyPage + + + + + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitCore.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitCore.js new file mode 100644 index 0000000..438513e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitCore.js @@ -0,0 +1,534 @@ +var JSUNIT_UNDEFINED_VALUE; +var JSUNIT_VERSION = 2.2; +var isTestPageLoaded = false; + +//hack for NS62 bug +function jsUnitFixTop() { + var tempTop = top; + if (!tempTop) { + tempTop = window; + while (tempTop.parent) { + tempTop = tempTop.parent; + if (tempTop.top && tempTop.top.jsUnitTestSuite) { + tempTop = tempTop.top; + break; + } + } + } + try { + window.top = tempTop; + } catch (e) { + } +} + +jsUnitFixTop(); + +/** + + * A more functional typeof + + * @param Object o + + * @return String + + */ +function _trueTypeOf(something) { + var result = typeof something; + try { + switch (result) { + case 'string': + case 'boolean': + case 'number': + break; + case 'object': + case 'function': + switch (something.constructor) + { + case String: + result = 'String'; + break; + case Boolean: + result = 'Boolean'; + break; + case Number: + result = 'Number'; + break; + case Array: + result = 'Array'; + break; + case RegExp: + result = 'RegExp'; + break; + case Function: + result = 'Function'; + break; + default: + var m = something.constructor.toString().match(/function\s*([^( ]+)\(/); + if (m) + result = m[1]; + else + break; + } + break; + } + } + finally { + result = result.substr(0, 1).toUpperCase() + result.substr(1); + return result; + } +} + +function _displayStringForValue(aVar) { + var result = '<' + aVar + '>'; + if (!(aVar === null || aVar === top.JSUNIT_UNDEFINED_VALUE)) { + result += ' (' + _trueTypeOf(aVar) + ')'; + } + return result; +} + +function fail(failureMessage) { + throw new JsUnitException("Call to fail()", failureMessage); +} + +function error(errorMessage) { + var errorObject = new Object(); + errorObject.description = errorMessage; + errorObject.stackTrace = getStackTrace(); + throw errorObject; +} + +function argumentsIncludeComments(expectedNumberOfNonCommentArgs, args) { + return args.length == expectedNumberOfNonCommentArgs + 1; +} + +function commentArg(expectedNumberOfNonCommentArgs, args) { + if (argumentsIncludeComments(expectedNumberOfNonCommentArgs, args)) + return args[0]; + + return null; +} + +function nonCommentArg(desiredNonCommentArgIndex, expectedNumberOfNonCommentArgs, args) { + return argumentsIncludeComments(expectedNumberOfNonCommentArgs, args) ? + args[desiredNonCommentArgIndex] : + args[desiredNonCommentArgIndex - 1]; +} + +function _validateArguments(expectedNumberOfNonCommentArgs, args) { + if (!( args.length == expectedNumberOfNonCommentArgs || + (args.length == expectedNumberOfNonCommentArgs + 1 && typeof(args[0]) == 'string') )) + error('Incorrect arguments passed to assert function'); +} + +function _assert(comment, booleanValue, failureMessage) { + if (!booleanValue) + throw new JsUnitException(comment, failureMessage); +} + +function assert() { + _validateArguments(1, arguments); + var booleanValue = nonCommentArg(1, 1, arguments); + + if (typeof(booleanValue) != 'boolean') + error('Bad argument to assert(boolean)'); + + _assert(commentArg(1, arguments), booleanValue === true, 'Call to assert(boolean) with false'); +} + +function assertTrue() { + _validateArguments(1, arguments); + var booleanValue = nonCommentArg(1, 1, arguments); + + if (typeof(booleanValue) != 'boolean') + error('Bad argument to assertTrue(boolean)'); + + _assert(commentArg(1, arguments), booleanValue === true, 'Call to assertTrue(boolean) with false'); +} + +function assertFalse() { + _validateArguments(1, arguments); + var booleanValue = nonCommentArg(1, 1, arguments); + + if (typeof(booleanValue) != 'boolean') + error('Bad argument to assertFalse(boolean)'); + + _assert(commentArg(1, arguments), booleanValue === false, 'Call to assertFalse(boolean) with true'); +} + +function assertEquals() { + _validateArguments(2, arguments); + var var1 = nonCommentArg(1, 2, arguments); + var var2 = nonCommentArg(2, 2, arguments); + _assert(commentArg(2, arguments), var1 === var2, 'Expected ' + _displayStringForValue(var1) + ' but was ' + _displayStringForValue(var2)); +} + +function assertNotEquals() { + _validateArguments(2, arguments); + var var1 = nonCommentArg(1, 2, arguments); + var var2 = nonCommentArg(2, 2, arguments); + _assert(commentArg(2, arguments), var1 !== var2, 'Expected not to be ' + _displayStringForValue(var2)); +} + +function assertNull() { + _validateArguments(1, arguments); + var aVar = nonCommentArg(1, 1, arguments); + _assert(commentArg(1, arguments), aVar === null, 'Expected ' + _displayStringForValue(null) + ' but was ' + _displayStringForValue(aVar)); +} + +function assertNotNull() { + _validateArguments(1, arguments); + var aVar = nonCommentArg(1, 1, arguments); + _assert(commentArg(1, arguments), aVar !== null, 'Expected not to be ' + _displayStringForValue(null)); +} + +function assertUndefined() { + _validateArguments(1, arguments); + var aVar = nonCommentArg(1, 1, arguments); + _assert(commentArg(1, arguments), aVar === top.JSUNIT_UNDEFINED_VALUE, 'Expected ' + _displayStringForValue(top.JSUNIT_UNDEFINED_VALUE) + ' but was ' + _displayStringForValue(aVar)); +} + +function assertNotUndefined() { + _validateArguments(1, arguments); + var aVar = nonCommentArg(1, 1, arguments); + _assert(commentArg(1, arguments), aVar !== top.JSUNIT_UNDEFINED_VALUE, 'Expected not to be ' + _displayStringForValue(top.JSUNIT_UNDEFINED_VALUE)); +} + +function assertNaN() { + _validateArguments(1, arguments); + var aVar = nonCommentArg(1, 1, arguments); + _assert(commentArg(1, arguments), isNaN(aVar), 'Expected NaN'); +} + +function assertNotNaN() { + _validateArguments(1, arguments); + var aVar = nonCommentArg(1, 1, arguments); + _assert(commentArg(1, arguments), !isNaN(aVar), 'Expected not NaN'); +} + +function assertObjectEquals() { + _validateArguments(2, arguments); + var var1 = nonCommentArg(1, 2, arguments); + var var2 = nonCommentArg(2, 2, arguments); + var type; + var msg = commentArg(2, arguments)?commentArg(2, arguments):''; + var isSame = (var1 === var2); + //shortpath for references to same object + var isEqual = ( (type = _trueTypeOf(var1)) == _trueTypeOf(var2) ); + if (isEqual && !isSame) { + switch (type) { + case 'String': + case 'Number': + isEqual = (var1 == var2); + break; + case 'Boolean': + case 'Date': + isEqual = (var1 === var2); + break; + case 'RegExp': + case 'Function': + isEqual = (var1.toString() === var2.toString()); + break; + default: //Object | Array + var i; + if (isEqual = (var1.length === var2.length)) + for (i in var1) + assertObjectEquals(msg + ' found nested ' + type + '@' + i + '\n', var1[i], var2[i]); + } + _assert(msg, isEqual, 'Expected ' + _displayStringForValue(var1) + ' but was ' + _displayStringForValue(var2)); + } +} + +assertArrayEquals = assertObjectEquals; + +function assertEvaluatesToTrue() { + _validateArguments(1, arguments); + var value = nonCommentArg(1, 1, arguments); + if (!value) + fail(commentArg(1, arguments)); +} + +function assertEvaluatesToFalse() { + _validateArguments(1, arguments); + var value = nonCommentArg(1, 1, arguments); + if (value) + fail(commentArg(1, arguments)); +} + +function assertHTMLEquals() { + _validateArguments(2, arguments); + var var1 = nonCommentArg(1, 2, arguments); + var var2 = nonCommentArg(2, 2, arguments); + var var1Standardized = standardizeHTML(var1); + var var2Standardized = standardizeHTML(var2); + + _assert(commentArg(2, arguments), var1Standardized === var2Standardized, 'Expected ' + _displayStringForValue(var1Standardized) + ' but was ' + _displayStringForValue(var2Standardized)); +} + +function assertHashEquals() { + _validateArguments(2, arguments); + var var1 = nonCommentArg(1, 2, arguments); + var var2 = nonCommentArg(2, 2, arguments); + for (var key in var1) { + assertNotUndefined("Expected hash had key " + key + " that was not found", var2[key]); + assertEquals( + "Value for key " + key + " mismatch - expected = " + var1[key] + ", actual = " + var2[key], + var1[key], var2[key] + ); + } + for (var key in var2) { + assertNotUndefined("Actual hash had key " + key + " that was not expected", var1[key]); + } +} + +function assertRoughlyEquals() { + _validateArguments(3, arguments); + var expected = nonCommentArg(1, 3, arguments); + var actual = nonCommentArg(2, 3, arguments); + var tolerance = nonCommentArg(3, 3, arguments); + assertTrue( + "Expected " + expected + ", but got " + actual + " which was more than " + tolerance + " away", + Math.abs(expected - actual) < tolerance + ); +} + +function assertContains() { + _validateArguments(2, arguments); + var contained = nonCommentArg(1, 2, arguments); + var container = nonCommentArg(2, 2, arguments); + assertTrue( + "Expected '" + container + "' to contain '" + contained + "'", + container.indexOf(contained) != -1 + ); +} + +function standardizeHTML(html) { + var translator = document.createElement("DIV"); + translator.innerHTML = html; + return translator.innerHTML; +} + +function isLoaded() { + return isTestPageLoaded; +} + +function setUp() { +} + +function tearDown() { +} + +function getFunctionName(aFunction) { + var regexpResult = aFunction.toString().match(/function(\s*)(\w*)/); + if (regexpResult && regexpResult.length >= 2 && regexpResult[2]) { + return regexpResult[2]; + } + return 'anonymous'; +} + +function getStackTrace() { + var result = ''; + + if (typeof(arguments.caller) != 'undefined') { // IE, not ECMA + for (var a = arguments.caller; a != null; a = a.caller) { + result += '> ' + getFunctionName(a.callee) + '\n'; + if (a.caller == a) { + result += '*'; + break; + } + } + } + else { // Mozilla, not ECMA + // fake an exception so we can get Mozilla's error stack + var testExcp; + try + { + foo.bar; + } + catch(testExcp) + { + var stack = parseErrorStack(testExcp); + for (var i = 1; i < stack.length; i++) + { + result += '> ' + stack[i] + '\n'; + } + } + } + + return result; +} + +function parseErrorStack(excp) +{ + var stack = []; + var name; + + if (!excp || !excp.stack) + { + return stack; + } + + var stacklist = excp.stack.split('\n'); + + for (var i = 0; i < stacklist.length - 1; i++) + { + var framedata = stacklist[i]; + + name = framedata.match(/^(\w*)/)[1]; + if (!name) { + name = 'anonymous'; + } + + stack[stack.length] = name; + } + // remove top level anonymous functions to match IE + + while (stack.length && stack[stack.length - 1] == 'anonymous') + { + stack.length = stack.length - 1; + } + return stack; +} + +function JsUnitException(comment, message) { + this.isJsUnitException = true; + this.comment = comment; + this.jsUnitMessage = message; + this.stackTrace = getStackTrace(); +} + +function warn() { + if (top.tracer != null) + top.tracer.warn(arguments[0], arguments[1]); +} + +function inform() { + if (top.tracer != null) + top.tracer.inform(arguments[0], arguments[1]); +} + +function info() { + inform(arguments[0], arguments[1]); +} + +function debug() { + if (top.tracer != null) + top.tracer.debug(arguments[0], arguments[1]); +} + +function setJsUnitTracer(aJsUnitTracer) { + top.tracer = aJsUnitTracer; +} + +function trim(str) { + if (str == null) + return null; + + var startingIndex = 0; + var endingIndex = str.length - 1; + + while (str.substring(startingIndex, startingIndex + 1) == ' ') + startingIndex++; + + while (str.substring(endingIndex, endingIndex + 1) == ' ') + endingIndex--; + + if (endingIndex < startingIndex) + return ''; + + return str.substring(startingIndex, endingIndex + 1); +} + +function isBlank(str) { + return trim(str) == ''; +} + +// the functions push(anArray, anObject) and pop(anArray) +// exist because the JavaScript Array.push(anObject) and Array.pop() +// functions are not available in IE 5.0 + +function push(anArray, anObject) { + anArray[anArray.length] = anObject; +} +function pop(anArray) { + if (anArray.length >= 1) { + delete anArray[anArray.length - 1]; + anArray.length--; + } +} + +function jsUnitGetParm(name) +{ + if (typeof(top.jsUnitParmHash[name]) != 'undefined') + { + return top.jsUnitParmHash[name]; + } + return null; +} + +if (top && typeof(top.xbDEBUG) != 'undefined' && top.xbDEBUG.on && top.testManager) +{ + top.xbDebugTraceObject('top.testManager.containerTestFrame', 'JSUnitException'); + // asserts + top.xbDebugTraceFunction('top.testManager.containerTestFrame', '_displayStringForValue'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'error'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'argumentsIncludeComments'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'commentArg'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'nonCommentArg'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', '_validateArguments'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', '_assert'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assert'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertTrue'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertEquals'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNotEquals'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNull'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNotNull'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertUndefined'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNotUndefined'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNaN'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNotNaN'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'isLoaded'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'setUp'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'tearDown'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'getFunctionName'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'getStackTrace'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'warn'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'inform'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'debug'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'setJsUnitTracer'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'trim'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'isBlank'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'newOnLoadEvent'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'push'); + top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'pop'); +} + +function newOnLoadEvent() { + isTestPageLoaded = true; +} + +function jsUnitSetOnLoad(windowRef, onloadHandler) +{ + var isKonqueror = navigator.userAgent.indexOf('Konqueror/') != -1 || + navigator.userAgent.indexOf('Safari/') != -1; + + if (typeof(windowRef.attachEvent) != 'undefined') { + // Internet Explorer, Opera + windowRef.attachEvent("onload", onloadHandler); + } else if (typeof(windowRef.addEventListener) != 'undefined' && !isKonqueror) { + // Mozilla, Konqueror + // exclude Konqueror due to load issues + windowRef.addEventListener("load", onloadHandler, false); + } else if (typeof(windowRef.document.addEventListener) != 'undefined' && !isKonqueror) { + // DOM 2 Events + // exclude Mozilla, Konqueror due to load issues + windowRef.document.addEventListener("load", onloadHandler, false); + } else if (typeof(windowRef.onload) != 'undefined' && windowRef.onload) { + windowRef.jsunit_original_onload = windowRef.onload; + windowRef.onload = function() { + windowRef.jsunit_original_onload(); + onloadHandler(); + }; + } else { + // browsers that do not support windowRef.attachEvent or + // windowRef.addEventListener will override a page's own onload event + windowRef.onload = onloadHandler; + } +} + +jsUnitSetOnLoad(window, newOnLoadEvent); \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitMockTimeout.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitMockTimeout.js new file mode 100644 index 0000000..99a4bf1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitMockTimeout.js @@ -0,0 +1,81 @@ +// Mock setTimeout, clearTimeout +// Contributed by Pivotal Computer Systems, www.pivotalsf.com + +var Clock = { + timeoutsMade: 0, + scheduledFunctions: {}, + nowMillis: 0, + reset: function() { + this.scheduledFunctions = {}; + this.nowMillis = 0; + this.timeoutsMade = 0; + }, + tick: function(millis) { + var oldMillis = this.nowMillis; + var newMillis = oldMillis + millis; + this.runFunctionsWithinRange(oldMillis, newMillis); + this.nowMillis = newMillis; + }, + runFunctionsWithinRange: function(oldMillis, nowMillis) { + var scheduledFunc; + var funcsToRun = []; + for (var timeoutKey in this.scheduledFunctions) { + scheduledFunc = this.scheduledFunctions[timeoutKey]; + if (scheduledFunc != undefined && + scheduledFunc.runAtMillis >= oldMillis && + scheduledFunc.runAtMillis <= nowMillis) { + funcsToRun.push(scheduledFunc); + this.scheduledFunctions[timeoutKey] = undefined; + } + } + + if (funcsToRun.length > 0) { + funcsToRun.sort(function(a, b) { + return a.runAtMillis - b.runAtMillis; + }); + for (var i = 0; i < funcsToRun.length; ++i) { + try { + this.nowMillis = funcsToRun[i].runAtMillis; + funcsToRun[i].funcToCall(); + if (funcsToRun[i].recurring) { + Clock.scheduleFunction(funcsToRun[i].timeoutKey, + funcsToRun[i].funcToCall, + funcsToRun[i].millis, + true); + } + } catch(e) { + } + } + this.runFunctionsWithinRange(oldMillis, nowMillis); + } + }, + scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { + Clock.scheduledFunctions[timeoutKey] = { + runAtMillis: Clock.nowMillis + millis, + funcToCall: funcToCall, + recurring: recurring, + timeoutKey: timeoutKey, + millis: millis + }; + } +}; + +function setTimeout(funcToCall, millis) { + Clock.timeoutsMade = Clock.timeoutsMade + 1; + Clock.scheduleFunction(Clock.timeoutsMade, funcToCall, millis, false); + return Clock.timeoutsMade; +} + +function setInterval(funcToCall, millis) { + Clock.timeoutsMade = Clock.timeoutsMade + 1; + Clock.scheduleFunction(Clock.timeoutsMade, funcToCall, millis, true); + return Clock.timeoutsMade; +} + +function clearTimeout(timeoutKey) { + Clock.scheduledFunctions[timeoutKey] = undefined; +} + +function clearInterval(timeoutKey) { + Clock.scheduledFunctions[timeoutKey] = undefined; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestManager.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestManager.js new file mode 100644 index 0000000..7d5bf0f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestManager.js @@ -0,0 +1,705 @@ +function jsUnitTestManager() { + this._windowForAllProblemMessages = null; + + this.container = top.frames.testContainer + this.documentLoader = top.frames.documentLoader; + this.mainFrame = top.frames.mainFrame; + + this.containerController = this.container.frames.testContainerController; + this.containerTestFrame = this.container.frames.testFrame; + + var mainData = this.mainFrame.frames.mainData; + + // form elements on mainData frame + this.testFileName = mainData.document.testRunnerForm.testFileName; + this.runButton = mainData.document.testRunnerForm.runButton; + this.traceLevel = mainData.document.testRunnerForm.traceLevel; + this.closeTraceWindowOnNewRun = mainData.document.testRunnerForm.closeTraceWindowOnNewRun; + this.timeout = mainData.document.testRunnerForm.timeout; + this.setUpPageTimeout = mainData.document.testRunnerForm.setUpPageTimeout; + + // image output + this.progressBar = this.mainFrame.frames.mainProgress.document.progress; + + this.problemsListField = this.mainFrame.frames.mainErrors.document.testRunnerForm.problemsList; + this.testCaseResultsField = this.mainFrame.frames.mainResults.document.resultsForm.testCases; + this.resultsTimeField = this.mainFrame.frames.mainResults.document.resultsForm.time; + + // 'layer' output frames + this.uiFrames = new Object(); + this.uiFrames.mainStatus = this.mainFrame.frames.mainStatus; + + var mainCounts = this.mainFrame.frames.mainCounts; + + this.uiFrames.mainCountsErrors = mainCounts.frames.mainCountsErrors; + this.uiFrames.mainCountsFailures = mainCounts.frames.mainCountsFailures; + this.uiFrames.mainCountsRuns = mainCounts.frames.mainCountsRuns; + this._baseURL = ""; + + this.setup(); +} + +// seconds to wait for each test page to load +jsUnitTestManager.TESTPAGE_WAIT_SEC = 120; +jsUnitTestManager.TIMEOUT_LENGTH = 20; + +// seconds to wait for setUpPage to complete +jsUnitTestManager.SETUPPAGE_TIMEOUT = 120; + +// milliseconds to wait between polls on setUpPages +jsUnitTestManager.SETUPPAGE_INTERVAL = 100; + +jsUnitTestManager.RESTORED_HTML_DIV_ID = "jsUnitRestoredHTML"; + +jsUnitTestManager.prototype.setup = function () { + this.totalCount = 0; + this.errorCount = 0; + this.failureCount = 0; + this._suiteStack = Array(); + + var initialSuite = new top.jsUnitTestSuite(); + push(this._suiteStack, initialSuite); +} + +jsUnitTestManager.prototype.start = function () { + this._baseURL = this.resolveUserEnteredTestFileName(); + var firstQuery = this._baseURL.indexOf("?"); + if (firstQuery >= 0) { + this._baseURL = this._baseURL.substring(0, firstQuery); + } + var lastSlash = this._baseURL.lastIndexOf("/"); + var lastRevSlash = this._baseURL.lastIndexOf("\\"); + if (lastRevSlash > lastSlash) { + lastSlash = lastRevSlash; + } + if (lastSlash > 0) { + this._baseURL = this._baseURL.substring(0, lastSlash + 1); + } + + this._timeRunStarted = new Date(); + this.initialize(); + setTimeout('top.testManager._nextPage();', jsUnitTestManager.TIMEOUT_LENGTH); +} + +jsUnitTestManager.prototype.getBaseURL = function () { + return this._baseURL; +} + +jsUnitTestManager.prototype.doneLoadingPage = function (pageName) { + //this.containerTestFrame.setTracer(top.tracer); + this._testFileName = pageName; + if (this.isTestPageSuite()) + this._handleNewSuite(); + else + { + this._testIndex = 0; + this._testsInPage = this.getTestFunctionNames(); + this._numberOfTestsInPage = this._testsInPage.length; + this._runTest(); + } +} + +jsUnitTestManager.prototype._handleNewSuite = function () { + var allegedSuite = this.containerTestFrame.suite(); + if (allegedSuite.isjsUnitTestSuite) { + var newSuite = allegedSuite.clone(); + if (newSuite.containsTestPages()) + push(this._suiteStack, newSuite); + this._nextPage(); + } + else { + this.fatalError('Invalid test suite in file ' + this._testFileName); + this.abort(); + } +} + +jsUnitTestManager.prototype._runTest = function () { + if (this._testIndex + 1 > this._numberOfTestsInPage) + { + // execute tearDownPage *synchronously* + // (unlike setUpPage which is asynchronous) + if (typeof this.containerTestFrame.tearDownPage == 'function') { + this.containerTestFrame.tearDownPage(); + } + + this._nextPage(); + return; + } + + if (this._testIndex == 0) { + this.storeRestoredHTML(); + if (typeof(this.containerTestFrame.setUpPage) == 'function') { + // first test for this page and a setUpPage is defined + if (typeof(this.containerTestFrame.setUpPageStatus) == 'undefined') { + // setUpPage() not called yet, so call it + this.containerTestFrame.setUpPageStatus = false; + this.containerTestFrame.startTime = new Date(); + this.containerTestFrame.setUpPage(); + // try test again later + setTimeout('top.testManager._runTest()', jsUnitTestManager.SETUPPAGE_INTERVAL); + return; + } + + if (this.containerTestFrame.setUpPageStatus != 'complete') { + top.status = 'setUpPage not completed... ' + this.containerTestFrame.setUpPageStatus + ' ' + (new Date()); + if ((new Date() - this.containerTestFrame.startTime) / 1000 > this.getsetUpPageTimeout()) { + this.fatalError('setUpPage timed out without completing.'); + if (!this.userConfirm('Retry Test Run?')) { + this.abort(); + return; + } + this.containerTestFrame.startTime = (new Date()); + } + // try test again later + setTimeout('top.testManager._runTest()', jsUnitTestManager.SETUPPAGE_INTERVAL); + return; + } + } + } + + top.status = ''; + // either not first test, or no setUpPage defined, or setUpPage completed + this.executeTestFunction(this._testsInPage[this._testIndex]); + this.totalCount++; + this.updateProgressIndicators(); + this._testIndex++; + setTimeout('top.testManager._runTest()', jsUnitTestManager.TIMEOUT_LENGTH); +} + +jsUnitTestManager.prototype._done = function () { + var secondsSinceRunBegan = (new Date() - this._timeRunStarted) / 1000; + this.setStatus('Done (' + secondsSinceRunBegan + ' seconds)'); + this._cleanUp(); + if (top.shouldSubmitResults()) { + this.resultsTimeField.value = secondsSinceRunBegan; + top.submitResults(); + } +} + +jsUnitTestManager.prototype._nextPage = function () { + this._restoredHTML = null; + if (this._currentSuite().hasMorePages()) { + this.loadPage(this._currentSuite().nextPage()); + } + else { + pop(this._suiteStack); + if (this._currentSuite() == null) + this._done(); + else + this._nextPage(); + } +} + +jsUnitTestManager.prototype._currentSuite = function () { + var suite = null; + + if (this._suiteStack && this._suiteStack.length > 0) + suite = this._suiteStack[this._suiteStack.length - 1]; + + return suite; +} + +jsUnitTestManager.prototype.calculateProgressBarProportion = function () { + if (this.totalCount == 0) + return 0; + var currentDivisor = 1; + var result = 0; + + for (var i = 0; i < this._suiteStack.length; i++) { + var aSuite = this._suiteStack[i]; + currentDivisor *= aSuite.testPages.length; + result += (aSuite.pageIndex - 1) / currentDivisor; + } + result += (this._testIndex + 1) / (this._numberOfTestsInPage * currentDivisor); + return result; +} + +jsUnitTestManager.prototype._cleanUp = function () { + this.containerController.setTestPage('./app/emptyPage.html'); + this.finalize(); + top.tracer.finalize(); +} + +jsUnitTestManager.prototype.abort = function () { + this.setStatus('Aborted'); + this._cleanUp(); +} + +jsUnitTestManager.prototype.getTimeout = function () { + var result = jsUnitTestManager.TESTPAGE_WAIT_SEC; + try { + result = eval(this.timeout.value); + } + catch (e) { + } + return result; +} + +jsUnitTestManager.prototype.getsetUpPageTimeout = function () { + var result = jsUnitTestManager.SETUPPAGE_TIMEOUT; + try { + result = eval(this.setUpPageTimeout.value); + } + catch (e) { + } + return result; +} + +jsUnitTestManager.prototype.isTestPageSuite = function () { + var result = false; + if (typeof(this.containerTestFrame.suite) == 'function') + { + result = true; + } + return result; +} + +jsUnitTestManager.prototype.getTestFunctionNames = function () { + var testFrame = this.containerTestFrame; + var testFunctionNames = new Array(); + var i; + + if (testFrame && typeof(testFrame.exposeTestFunctionNames) == 'function') + return testFrame.exposeTestFunctionNames(); + + if (testFrame && + testFrame.document && + typeof(testFrame.document.scripts) != 'undefined' && + testFrame.document.scripts.length > 0) { // IE5 and up + var scriptsInTestFrame = testFrame.document.scripts; + + for (i = 0; i < scriptsInTestFrame.length; i++) { + var someNames = this._extractTestFunctionNamesFromScript(scriptsInTestFrame[i]); + if (someNames) + testFunctionNames = testFunctionNames.concat(someNames); + } + } + else { + for (i in testFrame) { + if (i.substring(0, 4) == 'test' && typeof(testFrame[i]) == 'function') + push(testFunctionNames, i); + } + } + return testFunctionNames; +} + +jsUnitTestManager.prototype._extractTestFunctionNamesFromScript = function (aScript) { + var result; + var remainingScriptToInspect = aScript.text; + var currentIndex = this._indexOfTestFunctionIn(remainingScriptToInspect); + while (currentIndex != -1) { + if (!result) + result = new Array(); + + var fragment = remainingScriptToInspect.substring(currentIndex, remainingScriptToInspect.length); + result = result.concat(fragment.substring('function '.length, fragment.indexOf('('))); + remainingScriptToInspect = remainingScriptToInspect.substring(currentIndex + 12, remainingScriptToInspect.length); + currentIndex = this._indexOfTestFunctionIn(remainingScriptToInspect); + } + return result; +} + +jsUnitTestManager.prototype._indexOfTestFunctionIn = function (string) { + return string.indexOf('function test'); +} + +jsUnitTestManager.prototype.loadPage = function (testFileName) { + this._testFileName = testFileName; + this._loadAttemptStartTime = new Date(); + this.setStatus('Opening Test Page "' + this._testFileName + '"'); + this.containerController.setTestPage(this._testFileName); + this._callBackWhenPageIsLoaded(); +} + +jsUnitTestManager.prototype._callBackWhenPageIsLoaded = function () { + if ((new Date() - this._loadAttemptStartTime) / 1000 > this.getTimeout()) { + this.fatalError('Reading Test Page ' + this._testFileName + ' timed out.\nMake sure that the file exists and is a Test Page.'); + if (this.userConfirm('Retry Test Run?')) { + this.loadPage(this._testFileName); + return; + } else { + this.abort(); + return; + } + } + if (!this._isTestFrameLoaded()) { + setTimeout('top.testManager._callBackWhenPageIsLoaded();', jsUnitTestManager.TIMEOUT_LENGTH); + return; + } + this.doneLoadingPage(this._testFileName); +} + +jsUnitTestManager.prototype._isTestFrameLoaded = function () { + try { + return this.containerController.isPageLoaded(); + } + catch (e) { + } + return false; +} + +jsUnitTestManager.prototype.executeTestFunction = function (functionName) { + this._testFunctionName = functionName; + this.setStatus('Running test "' + this._testFunctionName + '"'); + var excep = null; + var timeBefore = new Date(); + try { + if (this._restoredHTML) + top.testContainer.testFrame.document.getElementById(jsUnitTestManager.RESTORED_HTML_DIV_ID).innerHTML = this._restoredHTML; + if (this.containerTestFrame.setUp !== JSUNIT_UNDEFINED_VALUE) + this.containerTestFrame.setUp(); + this.containerTestFrame[this._testFunctionName](); + } + catch (e1) { + excep = e1; + } + finally { + try { + if (this.containerTestFrame.tearDown !== JSUNIT_UNDEFINED_VALUE) + this.containerTestFrame.tearDown(); + } + catch (e2) { + //Unlike JUnit, only assign a tearDown exception to excep if there is not already an exception from the test body + if (excep == null) + excep = e2; + } + } + var timeTaken = (new Date() - timeBefore) / 1000; + if (excep != null) + this._handleTestException(excep); + var serializedTestCaseString = this._currentTestFunctionNameWithTestPageName(true) + "|" + timeTaken + "|"; + if (excep == null) + serializedTestCaseString += "S||"; + else { + if (typeof(excep.isJsUnitException) != 'undefined' && excep.isJsUnitException) + serializedTestCaseString += "F|"; + else { + serializedTestCaseString += "E|"; + } + serializedTestCaseString += this._problemDetailMessageFor(excep); + } + this._addOption(this.testCaseResultsField, + serializedTestCaseString, + serializedTestCaseString); +} + +jsUnitTestManager.prototype._currentTestFunctionNameWithTestPageName = function(useFullyQualifiedTestPageName) { + var testURL = this.containerTestFrame.location.href; + var testQuery = testURL.indexOf("?"); + if (testQuery >= 0) { + testURL = testURL.substring(0, testQuery); + } + if (!useFullyQualifiedTestPageName) { + if (testURL.substring(0, this._baseURL.length) == this._baseURL) + testURL = testURL.substring(this._baseURL.length); + } + return testURL + ':' + this._testFunctionName; +} + +jsUnitTestManager.prototype._addOption = function(listField, problemValue, problemMessage) { + if (typeof(listField.ownerDocument) != 'undefined' + && typeof(listField.ownerDocument.createElement) != 'undefined') { + // DOM Level 2 HTML method. + // this is required for Opera 7 since appending to the end of the + // options array does not work, and adding an Option created by new Option() + // and appended by listField.options.add() fails due to WRONG_DOCUMENT_ERR + var problemDocument = listField.ownerDocument; + var errOption = problemDocument.createElement('option'); + errOption.setAttribute('value', problemValue); + errOption.appendChild(problemDocument.createTextNode(problemMessage)); + listField.appendChild(errOption); + } + else { + // new Option() is DOM 0 + errOption = new Option(problemMessage, problemValue); + if (typeof(listField.add) != 'undefined') { + // DOM 2 HTML + listField.add(errOption, null); + } + else if (typeof(listField.options.add) != 'undefined') { + // DOM 0 + listField.options.add(errOption, null); + } + else { + // DOM 0 + listField.options[listField.length] = errOption; + } + } +} + +jsUnitTestManager.prototype._handleTestException = function (excep) { + var problemMessage = this._currentTestFunctionNameWithTestPageName(false) + ' '; + var errOption; + if (typeof(excep.isJsUnitException) == 'undefined' || !excep.isJsUnitException) { + problemMessage += 'had an error'; + this.errorCount++; + } + else { + problemMessage += 'failed'; + this.failureCount++; + } + var listField = this.problemsListField; + this._addOption(listField, + this._problemDetailMessageFor(excep), + problemMessage); +} + +jsUnitTestManager.prototype._problemDetailMessageFor = function (excep) { + var result = null; + if (typeof(excep.isJsUnitException) != 'undefined' && excep.isJsUnitException) { + result = ''; + if (excep.comment != null) + result += ('"' + excep.comment + '"\n'); + + result += excep.jsUnitMessage; + + if (excep.stackTrace) + result += '\n\nStack trace follows:\n' + excep.stackTrace; + } + else { + result = 'Error message is:\n"'; + result += + (typeof(excep.description) == 'undefined') ? + excep : + excep.description; + result += '"'; + if (typeof(excep.stack) != 'undefined') // Mozilla only + result += '\n\nStack trace follows:\n' + excep.stack; + } + return result; +} + +jsUnitTestManager.prototype._setTextOnLayer = function (layerName, str) { + try { + var content; + if (content = this.uiFrames[layerName].document.getElementById('content')) + content.innerHTML = str; + else + throw 'No content div found.'; + } + catch (e) { + var html = ''; + html += ''; + html += '<\/head>'; + html += '
'; + html += str; + html += '<\/div><\/body>'; + html += '<\/html>'; + this.uiFrames[layerName].document.write(html); + this.uiFrames[layerName].document.close(); + } +} + +jsUnitTestManager.prototype.setStatus = function (str) { + this._setTextOnLayer('mainStatus', 'Status:<\/b> ' + str); +} + +jsUnitTestManager.prototype._setErrors = function (n) { + this._setTextOnLayer('mainCountsErrors', 'Errors: <\/b>' + n); +} + +jsUnitTestManager.prototype._setFailures = function (n) { + this._setTextOnLayer('mainCountsFailures', 'Failures:<\/b> ' + n); +} + +jsUnitTestManager.prototype._setTotal = function (n) { + this._setTextOnLayer('mainCountsRuns', 'Runs:<\/b> ' + n); +} + +jsUnitTestManager.prototype._setProgressBarImage = function (imgName) { + this.progressBar.src = imgName; +} + +jsUnitTestManager.prototype._setProgressBarWidth = function (w) { + this.progressBar.width = w; +} + +jsUnitTestManager.prototype.updateProgressIndicators = function () { + this._setTotal(this.totalCount); + this._setErrors(this.errorCount); + this._setFailures(this.failureCount); + this._setProgressBarWidth(300 * this.calculateProgressBarProportion()); + + if (this.errorCount > 0 || this.failureCount > 0) + this._setProgressBarImage('../images/red.gif'); + else + this._setProgressBarImage('../images/green.gif'); +} + +jsUnitTestManager.prototype.showMessageForSelectedProblemTest = function () { + var problemTestIndex = this.problemsListField.selectedIndex; + if (problemTestIndex != -1) + this.fatalError(this.problemsListField[problemTestIndex].value); +} + +jsUnitTestManager.prototype.showMessagesForAllProblemTests = function () { + if (this.problemsListField.length == 0) + return; + + try { + if (this._windowForAllProblemMessages && !this._windowForAllProblemMessages.closed) + this._windowForAllProblemMessages.close(); + } + catch(e) { + } + + this._windowForAllProblemMessages = window.open('', '', 'width=600, height=350,status=no,resizable=yes,scrollbars=yes'); + var resDoc = this._windowForAllProblemMessages.document; + resDoc.write('Tests with problems - JsUnit<\/title><head><body>'); + resDoc.write('<p class="jsUnitSubHeading">Tests with problems (' + this.problemsListField.length + ' total) - JsUnit<\/p>'); + resDoc.write('<p class="jsUnitSubSubHeading"><i>Running on ' + navigator.userAgent + '</i></p>'); + for (var i = 0; i < this.problemsListField.length; i++) + { + resDoc.write('<p class="jsUnitDefault">'); + resDoc.write('<b>' + (i + 1) + '. '); + resDoc.write(this.problemsListField[i].text); + resDoc.write('<\/b><\/p><p><pre>'); + resDoc.write(this._makeHTMLSafe(this.problemsListField[i].value)); + resDoc.write('<\/pre><\/p>'); + } + + resDoc.write('<\/body><\/html>'); + resDoc.close(); +} + +jsUnitTestManager.prototype._makeHTMLSafe = function (string) { + string = string.replace(/&/g, '&'); + string = string.replace(/</g, '<'); + string = string.replace(/>/g, '>'); + return string; +} + +jsUnitTestManager.prototype._clearProblemsList = function () { + var listField = this.problemsListField; + var initialLength = listField.options.length; + + for (var i = 0; i < initialLength; i++) + listField.remove(0); +} + +jsUnitTestManager.prototype.initialize = function () { + this.setStatus('Initializing...'); + this._setRunButtonEnabled(false); + this._clearProblemsList(); + this.updateProgressIndicators(); + this.setStatus('Done initializing'); +} + +jsUnitTestManager.prototype.finalize = function () { + this._setRunButtonEnabled(true); +} + +jsUnitTestManager.prototype._setRunButtonEnabled = function (b) { + this.runButton.disabled = !b; +} + +jsUnitTestManager.prototype.getTestFileName = function () { + var rawEnteredFileName = this.testFileName.value; + var result = rawEnteredFileName; + + while (result.indexOf('\\') != -1) + result = result.replace('\\', '/'); + + return result; +} + +jsUnitTestManager.prototype.getTestFunctionName = function () { + return this._testFunctionName; +} + +jsUnitTestManager.prototype.resolveUserEnteredTestFileName = function (rawText) { + var userEnteredTestFileName = top.testManager.getTestFileName(); + + // only test for file:// since Opera uses a different format + if (userEnteredTestFileName.indexOf('http://') == 0 || userEnteredTestFileName.indexOf('https://') == 0 || userEnteredTestFileName.indexOf('file://') == 0) + return userEnteredTestFileName; + + return getTestFileProtocol() + this.getTestFileName(); +} + +jsUnitTestManager.prototype.storeRestoredHTML = function () { + if (document.getElementById && top.testContainer.testFrame.document.getElementById(jsUnitTestManager.RESTORED_HTML_DIV_ID)) + this._restoredHTML = top.testContainer.testFrame.document.getElementById(jsUnitTestManager.RESTORED_HTML_DIV_ID).innerHTML; +} + +jsUnitTestManager.prototype.fatalError = function(aMessage) { + if (top.shouldSubmitResults()) + this.setStatus(aMessage); + else + alert(aMessage); +} + +jsUnitTestManager.prototype.userConfirm = function(aMessage) { + if (top.shouldSubmitResults()) + return false; + else + return confirm(aMessage); +} + +function getTestFileProtocol() { + return getDocumentProtocol(); +} + +function getDocumentProtocol() { + var protocol = top.document.location.protocol; + + if (protocol == "file:") + return "file:///"; + + if (protocol == "http:") + return "http://"; + + if (protocol == 'https:') + return 'https://'; + + if (protocol == "chrome:") + return "chrome://"; + + return null; +} + +function browserSupportsReadingFullPathFromFileField() { + return !isOpera() && !isIE7(); +} + +function isOpera() { + return navigator.userAgent.toLowerCase().indexOf("opera") != -1; +} + +function isIE7() { + return navigator.userAgent.toLowerCase().indexOf("msie 7") != -1; +} + +function isBeingRunOverHTTP() { + return getDocumentProtocol() == "http://"; +} + +function getWebserver() { + if (isBeingRunOverHTTP()) { + var myUrl = location.href; + var myUrlWithProtocolStripped = myUrl.substring(myUrl.indexOf("/") + 2); + return myUrlWithProtocolStripped.substring(0, myUrlWithProtocolStripped.indexOf("/")); + } + return null; +} + +// the functions push(anArray, anObject) and pop(anArray) +// exist because the JavaScript Array.push(anObject) and Array.pop() +// functions are not available in IE 5.0 + +function push(anArray, anObject) { + anArray[anArray.length] = anObject; +} + +function pop(anArray) { + if (anArray.length >= 1) { + delete anArray[anArray.length - 1]; + anArray.length--; + } +} + +if (xbDEBUG.on) { + xbDebugTraceObject('window', 'jsUnitTestManager'); + xbDebugTraceFunction('window', 'getTestFileProtocol'); + xbDebugTraceFunction('window', 'getDocumentProtocol'); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestSuite.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestSuite.js new file mode 100644 index 0000000..3f3eb8c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestSuite.js @@ -0,0 +1,44 @@ +function jsUnitTestSuite() { + this.isjsUnitTestSuite = true; + this.testPages = Array(); + this.pageIndex = 0; +} + +jsUnitTestSuite.prototype.addTestPage = function (pageName) +{ + this.testPages[this.testPages.length] = pageName; +} + +jsUnitTestSuite.prototype.addTestSuite = function (suite) +{ + for (var i = 0; i < suite.testPages.length; i++) + this.addTestPage(suite.testPages[i]); +} + +jsUnitTestSuite.prototype.containsTestPages = function () +{ + return this.testPages.length > 0; +} + +jsUnitTestSuite.prototype.nextPage = function () +{ + return this.testPages[this.pageIndex++]; +} + +jsUnitTestSuite.prototype.hasMorePages = function () +{ + return this.pageIndex < this.testPages.length; +} + +jsUnitTestSuite.prototype.clone = function () +{ + var clone = new jsUnitTestSuite(); + clone.testPages = this.testPages; + return clone; +} + +if (xbDEBUG.on) +{ + xbDebugTraceObject('window', 'jsUnitTestSuite'); +} + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTracer.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTracer.js new file mode 100644 index 0000000..b120e39 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTracer.js @@ -0,0 +1,102 @@ +var TRACE_LEVEL_NONE = new JsUnitTraceLevel(0, null); +var TRACE_LEVEL_WARNING = new JsUnitTraceLevel(1, "#FF0000"); +var TRACE_LEVEL_INFO = new JsUnitTraceLevel(2, "#009966"); +var TRACE_LEVEL_DEBUG = new JsUnitTraceLevel(3, "#0000FF"); + +function JsUnitTracer(testManager) { + this._testManager = testManager; + this._traceWindow = null; + this.popupWindowsBlocked = false; +} + +JsUnitTracer.prototype.initialize = function() { + if (this._traceWindow != null && top.testManager.closeTraceWindowOnNewRun.checked) + this._traceWindow.close(); + this._traceWindow = null; +} + +JsUnitTracer.prototype.finalize = function() { + if (this._traceWindow != null) { + this._traceWindow.document.write('<\/body>\n<\/html>'); + this._traceWindow.document.close(); + } +} + +JsUnitTracer.prototype.warn = function() { + this._trace(arguments[0], arguments[1], TRACE_LEVEL_WARNING); +} + +JsUnitTracer.prototype.inform = function() { + this._trace(arguments[0], arguments[1], TRACE_LEVEL_INFO); +} + +JsUnitTracer.prototype.debug = function() { + this._trace(arguments[0], arguments[1], TRACE_LEVEL_DEBUG); +} + +JsUnitTracer.prototype._trace = function(message, value, traceLevel) { + if (!top.shouldSubmitResults() && this._getChosenTraceLevel().matches(traceLevel)) { + var traceString = message; + if (value) + traceString += ': ' + value; + var prefix = this._testManager.getTestFileName() + ":" + + this._testManager.getTestFunctionName() + " - "; + this._writeToTraceWindow(prefix, traceString, traceLevel); + } +} + +JsUnitTracer.prototype._getChosenTraceLevel = function() { + var levelNumber = eval(top.testManager.traceLevel.value); + return traceLevelByLevelNumber(levelNumber); +} + +JsUnitTracer.prototype._writeToTraceWindow = function(prefix, traceString, traceLevel) { + var htmlToAppend = '<p class="jsUnitDefault">' + prefix + '<font color="' + traceLevel.getColor() + '">' + traceString + '</font><\/p>\n'; + this._getTraceWindow().document.write(htmlToAppend); +} + +JsUnitTracer.prototype._getTraceWindow = function() { + if (this._traceWindow == null && !top.shouldSubmitResults() && !this.popupWindowsBlocked) { + this._traceWindow = window.open('', '', 'width=600, height=350,status=no,resizable=yes,scrollbars=yes'); + if (!this._traceWindow) + this.popupWindowsBlocked = true; + else { + var resDoc = this._traceWindow.document; + resDoc.write('<html>\n<head>\n<link rel="stylesheet" href="css/jsUnitStyle.css">\n<title>Tracing - JsUnit<\/title>\n<head>\n<body>'); + resDoc.write('<h2>Tracing - JsUnit<\/h2>\n'); + resDoc.write('<p class="jsUnitDefault"><i>(Traces are color coded: '); + resDoc.write('<font color="' + TRACE_LEVEL_WARNING.getColor() + '">Warning</font> - '); + resDoc.write('<font color="' + TRACE_LEVEL_INFO.getColor() + '">Information</font> - '); + resDoc.write('<font color="' + TRACE_LEVEL_DEBUG.getColor() + '">Debug</font>'); + resDoc.write(')</i></p>'); + } + } + return this._traceWindow; +} + +if (xbDEBUG.on) { + xbDebugTraceObject('window', 'JsUnitTracer'); +} + +function JsUnitTraceLevel(levelNumber, color) { + this._levelNumber = levelNumber; + this._color = color; +} + +JsUnitTraceLevel.prototype.matches = function(anotherTraceLevel) { + return this._levelNumber >= anotherTraceLevel._levelNumber; +} + +JsUnitTraceLevel.prototype.getColor = function() { + return this._color; +} + +function traceLevelByLevelNumber(levelNumber) { + switch (levelNumber) { + case 0: return TRACE_LEVEL_NONE; + case 1: return TRACE_LEVEL_WARNING; + case 2: return TRACE_LEVEL_INFO; + case 3: return TRACE_LEVEL_DEBUG; + } + return null; +} \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitVersionCheck.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitVersionCheck.js new file mode 100644 index 0000000..41c8862 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitVersionCheck.js @@ -0,0 +1,59 @@ +var versionRequest; + +function isOutOfDate(newVersionNumber) { + return JSUNIT_VERSION < newVersionNumber; +} + +function sendRequestForLatestVersion(url) { + versionRequest = createXmlHttpRequest(); + if (versionRequest) { + versionRequest.onreadystatechange = requestStateChanged; + versionRequest.open("GET", url, true); + versionRequest.send(null); + } +} + +function createXmlHttpRequest() { + if (window.XMLHttpRequest) + return new XMLHttpRequest(); + else if (window.ActiveXObject) + return new ActiveXObject("Microsoft.XMLHTTP"); +} + +function requestStateChanged() { + if (versionRequest && versionRequest.readyState == 4) { + if (versionRequest.status == 200) { + var latestVersion = versionRequest.responseText; + if (isOutOfDate(latestVersion)) + versionNotLatest(latestVersion); + else + versionLatest(); + } else + versionCheckError(); + } +} + +function checkForLatestVersion(url) { + setLatestVersionDivHTML("Checking for newer version..."); + try { + sendRequestForLatestVersion(url); + } catch (e) { + setLatestVersionDivHTML("An error occurred while checking for a newer version: " + e.message); + } +} + +function versionNotLatest(latestVersion) { + setLatestVersionDivHTML('<font color="red">A newer version of JsUnit, version ' + latestVersion + ', is available.</font>'); +} + +function versionLatest() { + setLatestVersionDivHTML("You are running the latest version of JsUnit."); +} + +function setLatestVersionDivHTML(string) { + document.getElementById("versionCheckDiv").innerHTML = string; +} + +function versionCheckError() { + setLatestVersionDivHTML("An error occurred while checking for a newer version."); +} \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-errors.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-errors.html new file mode 100644 index 0000000..ca726b5 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-errors.html @@ -0,0 +1,12 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <title> + + + + +
Errors: 0
+ + \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-failures.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-failures.html new file mode 100644 index 0000000..861c78b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-failures.html @@ -0,0 +1,13 @@ + + + + + + + + + +
Failures: 0
+ + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-runs.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-runs.html new file mode 100644 index 0000000..5429f8f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-runs.html @@ -0,0 +1,13 @@ + + + + + + + + + +
Runs: 0
+ + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts.html new file mode 100644 index 0000000..0431eae --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + <body> + <p>jsUnit uses frames in order to remove dependencies upon a browser's implementation of document.getElementById + and HTMLElement.innerHTML.</p> + </body> + + + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-data.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-data.html new file mode 100644 index 0000000..8a15b97 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-data.html @@ -0,0 +1,189 @@ + + + + + JsUnit main-data.html + + + + + + + + + + + + + + + +
JsUnit  +

JsUnit TestRunner

+ Running on + +
+ + www.jsunit.net  
+
+ + Powered By Pivotal + +
+ +
+ + + + + + + + +
+ + +   + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
Trace level:   Close old trace window on new run      Page load timeout:  + +       Setup page timeout:  + +
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-errors.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-errors.html new file mode 100644 index 0000000..cc76ff0 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-errors.html @@ -0,0 +1,23 @@ + + + + + JsUnit main-errors.html + + + + +
+ +
+

Errors and failures: 

+ +
+ +     + +
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-frame.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-frame.html new file mode 100644 index 0000000..af0dc7a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-frame.html @@ -0,0 +1,19 @@ + + + + jsUnit Main Frame + +> + + + + + + + + <body> + <p>Sorry, JsUnit requires frames.</p> + </body> + + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-loader.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-loader.html new file mode 100644 index 0000000..302c084 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-loader.html @@ -0,0 +1,45 @@ + + + + + jsUnit External Data Document loader + + + + + + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-progress.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-progress.html new file mode 100644 index 0000000..5ca52f6 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-progress.html @@ -0,0 +1,25 @@ + + + + + JsUnit main-progress.html + + + + + + + + + + +
Progress: + + + + +
progress image
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-results.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-results.html new file mode 100644 index 0000000..5a904cd --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-results.html @@ -0,0 +1,67 @@ + + + + + JsUnit main-results.html + + + + + + + + + + + + + + + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-status.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-status.html new file mode 100644 index 0000000..1053f5d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-status.html @@ -0,0 +1,13 @@ + + + + + JsUnit main-status.html + + + + +
Status: (Idle)
+ + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainer.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainer.html new file mode 100644 index 0000000..df6a997 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainer.html @@ -0,0 +1,16 @@ + + + + + JsUnit Test Container + + + + + + <body> + <p>Sorry, JsUnit requires frames.</p> + </body> + + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainerController.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainerController.html new file mode 100644 index 0000000..3130d76 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainerController.html @@ -0,0 +1,77 @@ + + + + + JsUnit Test Container Controller + + + + +Test Container Controller + + \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/xbDebug.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/xbDebug.js new file mode 100644 index 0000000..b7167ec --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/xbDebug.js @@ -0,0 +1,306 @@ +// xbDebug.js revision: 0.003 2002-02-26 + +/* ***** BEGIN LICENSE BLOCK ***** + * Licensed under Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * Full Terms at /xbProjects-srce/license/mpl-tri-license.txt + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Netscape code. + * + * The Initial Developer of the Original Code is + * Netscape Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): Bob Clary + * + * ***** END LICENSE BLOCK ***** */ + +/* +ChangeLog: + +2002-02-25: bclary - modified xbDebugTraceOject to make sure + that original versions of wrapped functions were not + rewrapped. This had caused an infinite loop in IE. + +2002-02-07: bclary - modified xbDebug.prototype.close to not null + the debug window reference. This can cause problems with + Internet Explorer if the page is refreshed. These issues will + be addressed at a later date. +*/ + +function xbDebug() +{ + this.on = false; + this.stack = new Array(); + this.debugwindow = null; + this.execprofile = new Object(); +} + +xbDebug.prototype.push = function () +{ + this.stack[this.stack.length] = this.on; + this.on = true; +} + +xbDebug.prototype.pop = function () +{ + this.on = this.stack[this.stack.length - 1]; + --this.stack.length; +} + +xbDebug.prototype.open = function () +{ + if (this.debugwindow && !this.debugwindow.closed) + this.close(); + + this.debugwindow = window.open('about:blank', 'DEBUGWINDOW', 'height=400,width=600,resizable=yes,scrollbars=yes'); + + this.debugwindow.title = 'xbDebug Window'; + this.debugwindow.document.write('xbDebug Window

Javascript Debug Window

'); + this.debugwindow.focus(); +} + +xbDebug.prototype.close = function () +{ + if (!this.debugwindow) + return; + + if (!this.debugwindow.closed) + this.debugwindow.close(); + + // bc 2002-02-07, other windows may still hold a reference to this: this.debugwindow = null; +} + +xbDebug.prototype.dump = function (msg) +{ + if (!this.on) + return; + + if (!this.debugwindow || this.debugwindow.closed) + this.open(); + + this.debugwindow.document.write(msg + '
'); + + return; +} + +var xbDEBUG = new xbDebug(); + +window.onunload = function () { + xbDEBUG.close(); +} + +function xbDebugGetFunctionName(funcref) +{ + + if (!funcref) + { + return ''; + } + + if (funcref.name) + return funcref.name; + + var name = funcref + ''; + name = name.substring(name.indexOf(' ') + 1, name.indexOf('(')); + funcref.name = name; + + if (!name) alert('name not defined'); + return name; +} + +// emulate functionref.apply for IE mac and IE win < 5.5 +function xbDebugApplyFunction(funcname, funcref, thisref, argumentsref) +{ + var rv; + + if (!funcref) + { + alert('xbDebugApplyFunction: funcref is null'); + } + + if (typeof(funcref.apply) != 'undefined') + return funcref.apply(thisref, argumentsref); + + var applyexpr = 'thisref.xbDebug_orig_' + funcname + '('; + var i; + + for (i = 0; i < argumentsref.length; i++) + { + applyexpr += 'argumentsref[' + i + '],'; + } + + if (argumentsref.length > 0) + { + applyexpr = applyexpr.substring(0, applyexpr.length - 1); + } + + applyexpr += ')'; + + return eval(applyexpr); +} + +function xbDebugCreateFunctionWrapper(scopename, funcname, precall, postcall) +{ + var wrappedfunc; + var scopeobject = eval(scopename); + var funcref = scopeobject[funcname]; + + scopeobject['xbDebug_orig_' + funcname] = funcref; + + wrappedfunc = function () + { + var rv; + + precall(scopename, funcname, arguments); + rv = xbDebugApplyFunction(funcname, funcref, scopeobject, arguments); + postcall(scopename, funcname, arguments, rv); + return rv; + }; + + if (typeof(funcref.constructor) != 'undefined') + wrappedfunc.constructor = funcref.constuctor; + + if (typeof(funcref.prototype) != 'undefined') + wrappedfunc.prototype = funcref.prototype; + + scopeobject[funcname] = wrappedfunc; +} + +function xbDebugCreateMethodWrapper(contextname, classname, methodname, precall, postcall) +{ + var context = eval(contextname); + var methodref = context[classname].prototype[methodname]; + + context[classname].prototype['xbDebug_orig_' + methodname] = methodref; + + var wrappedmethod = function () + { + var rv; + // eval 'this' at method run time to pick up reference to the object's instance + var thisref = eval('this'); + // eval 'arguments' at method run time to pick up method's arguments + var argsref = arguments; + + precall(contextname + '.' + classname, methodname, argsref); + rv = xbDebugApplyFunction(methodname, methodref, thisref, argsref); + postcall(contextname + '.' + classname, methodname, argsref, rv); + return rv; + }; + + return wrappedmethod; +} + +function xbDebugPersistToString(obj) +{ + var s = ''; + var p; + + if (obj == null) + return 'null'; + + switch (typeof(obj)) + { + case 'number': + return obj; + case 'string': + return '"' + obj + '"'; + case 'undefined': + return 'undefined'; + case 'boolean': + return obj + ''; + } + + if (obj.constructor) + return '[' + xbDebugGetFunctionName(obj.constructor) + ']'; + + return null; +} + +function xbDebugTraceBefore(scopename, funcname, funcarguments) +{ + var i; + var s = ''; + var execprofile = xbDEBUG.execprofile[scopename + '.' + funcname]; + if (!execprofile) + execprofile = xbDEBUG.execprofile[scopename + '.' + funcname] = { started: 0, time: 0, count: 0 }; + + for (i = 0; i < funcarguments.length; i++) + { + s += xbDebugPersistToString(funcarguments[i]); + if (i < funcarguments.length - 1) + s += ', '; + } + + xbDEBUG.dump('enter ' + scopename + '.' + funcname + '(' + s + ')'); + execprofile.started = (new Date()).getTime(); +} + +function xbDebugTraceAfter(scopename, funcname, funcarguments, rv) +{ + var i; + var s = ''; + var execprofile = xbDEBUG.execprofile[scopename + '.' + funcname]; + if (!execprofile) + xbDEBUG.dump('xbDebugTraceAfter: execprofile not created for ' + scopename + '.' + funcname); + else if (execprofile.started == 0) + xbDEBUG.dump('xbDebugTraceAfter: execprofile.started == 0 for ' + scopename + '.' + funcname); + else + { + execprofile.time += (new Date()).getTime() - execprofile.started; + execprofile.count++; + execprofile.started = 0; + } + + for (i = 0; i < funcarguments.length; i++) + { + s += xbDebugPersistToString(funcarguments[i]); + if (i < funcarguments.length - 1) + s += ', '; + } + + xbDEBUG.dump('exit ' + scopename + '.' + funcname + '(' + s + ')==' + xbDebugPersistToString(rv)); +} + +function xbDebugTraceFunction(scopename, funcname) +{ + xbDebugCreateFunctionWrapper(scopename, funcname, xbDebugTraceBefore, xbDebugTraceAfter); +} + +function xbDebugTraceObject(contextname, classname) +{ + var classref = eval(contextname + '.' + classname); + var p; + var sp; + + if (!classref || !classref.prototype) + return; + + for (p in classref.prototype) + { + sp = p + ''; + if (typeof(classref.prototype[sp]) == 'function' && (sp).indexOf('xbDebug_orig') == -1) + { + classref.prototype[sp] = xbDebugCreateMethodWrapper(contextname, classname, sp, xbDebugTraceBefore, xbDebugTraceAfter); + } + } +} + +function xbDebugDumpProfile() +{ + var p; + var execprofile; + var avg; + + for (p in xbDEBUG.execprofile) + { + execprofile = xbDEBUG.execprofile[p]; + avg = Math.round(100 * execprofile.time / execprofile.count) / 100; + xbDEBUG.dump('Execution profile ' + p + ' called ' + execprofile.count + ' times. Total time=' + execprofile.time + 'ms. Avg Time=' + avg + 'ms.'); + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/css/jsUnitStyle.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/css/jsUnitStyle.css new file mode 100644 index 0000000..cee6849 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/css/jsUnitStyle.css @@ -0,0 +1,83 @@ +body { + margin-top: 0; + margin-bottom: 0; + font-family: Verdana, Arial, Helvetica, sans-serif; + color: #000; + font-size: 0.8em; + background-color: #fff; +} + +a:link, a:visited { + color: #00F; +} + +a:hover { + color: #F00; +} + +h1 { + font-size: 1.2em; + font-weight: bold; + color: #039; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +h2 { + font-weight: bold; + color: #039; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +h3 { + font-weight: bold; + color: #039; + text-decoration: underline; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +h4 { + font-weight: bold; + color: #039; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +.jsUnitTestResultSuccess { + color: #000; +} + +.jsUnitTestResultNotSuccess { + color: #F00; +} + +.unselectedTab { + font-family: Verdana, Arial, Helvetica, sans-serif; + height: 26px; + background: #FFFFFF; + border-style: solid; + border-bottom-width: 1px; + border-top-width: 1px; + border-left-width: 1px; + border-right-width: 1px; +} + +.selectedTab { + font-family: Verdana, Arial, Helvetica, sans-serif; + height: 26px; + background: #DDDDDD; + font-weight: bold; + border-style: solid; + border-bottom-width: 0px; + border-top-width: 1px; + border-left-width: 1px; + border-right-width: 1px; +} + +.tabHeaderSeparator { + height: 26px; + background: #FFFFFF; + border-style: solid; + border-bottom-width: 1px; + border-top-width: 0px; + border-left-width: 0px; + border-right-width: 0px; +} \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/green.gif b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/green.gif new file mode 100644 index 0000000000000000000000000000000000000000..b57ca3425c90c3f8c404878f14f9cc1d08a52f50 GIT binary patch literal 811 zcmX|=PiPZC7{z~!35ksg&aSY8r670+SW)WV{tUtvv`H3dKN@*uU+c9 zV{wEXi2aEnL15PJBsX^%6Fh?E2~zK{uCf4cvse}^Lz*>*ZrB1JzBXy35W2O%H)!nh zBx=t8Z;l0wOfpu~oU<2_hevju4!@NJ%kFS~UqVWR5ivF8)MrP9y=@LSkb^kbx-Qqc z?sb#jD(mt@tcHvsOg*D2fjT8rsPXHY)Ek<{)Hi!w#k@LgD~&np1yn@DUl zt3IHC`)g;|ns`axjN%Thhy7ASrZ@~iKiq}~86F2b6+DFd>pZE`D@>i$_(}<_Kxj*7 z4w3qR)n>u>l1cbfrmeNPzZ4CH&~g+#Ax9-Gq3_~0(_yMlSS^iLbBEMPRI99foa|++ zi!8TD`$@-XFe->VY34}9jdMDeOcy0>PuYm}J|h$RITizEChf3jG9s&e?qs(C^?y+( z@SxK1mS>)l716d0{te84v6JCJ=ZhTO6Wcz%n$9U1S8ZEsJ3~5(+MN4pwRWQv+YW8t z*K-3dp3P4^oN?cmIB%2J7?+GB==gaqyGrmJQTPZ;8^vlVD1^ob7NH6S4QFL(UR488 zFz?~+^be$>t?)}5gEI{oi0GZvxbnj4$b?~djUCPEG?*+=G#AJ?kv)cz#U|Ahh3Khj djAc3ob9^rr^?S^2{)vPR%}RQ?x$!Ime*v7L$EE-P literal 0 HcmV?d00001 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/logo_jsunit.gif b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/logo_jsunit.gif new file mode 100644 index 0000000000000000000000000000000000000000..65b4bda26dfc3d8ba7ca1e7beb5618978361a4e8 GIT binary patch literal 2465 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 literal 0 HcmV?d00001 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/red.gif b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/red.gif new file mode 100644 index 0000000000000000000000000000000000000000..262550d9bd9bd1605bddd0912a05d4002bc86c91 GIT binary patch literal 811 zcmX|=PiPZC7{z~U6B1h$oLylFOF{4uu%cN1^^Xv=XhINb2@;Bj3eu_vTT$6dWeXlG zIThnUq(YGj-r9rUp->DY+3iIyJ$Ufop%5vptVH?;lyPQLox?JG^S(FldvEq??#hLp zTLy>NhTr>Q_#n{hPm=393=1B>$}u|LVO(Yw-exciSb!AE7M-vOE__|5o9TPgU0Afa=I0JU^VRZMP!O#0D9pj+)MK?;IZI7++F2SjnhKcS&A=uCvg#BBktgd}5^?R^m>R4dPuWw_qMgt9Dhs`(7%(+%hDDtb8Rc^;yEUl& zi#mY=<(9WRaim`sO;h9Fz!YdZ8SJ;d_=R1u<>Jc8tn}luX)0}}NJUZWdtWV8uX(Yp z&~#nZ*JtCH{8Y_p`@P3mlbpiXqQ!kl?oreOq^-yvP08Fkl?3_d fsVa=2Pc-J}ZY( literal 0 HcmV?d00001 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/JDOM_license.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/JDOM_license.txt new file mode 100644 index 0000000..86e1d54 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/JDOM_license.txt @@ -0,0 +1,56 @@ +/*-- + + $Id: JDOM_license.txt 81 2003-07-24 04:44:54Z edwardhieatt $ + + Copyright (C) 2000-2003 Jason Hunter & Brett McLaughlin. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the disclaimer that follows + these conditions in the documentation and/or other materials + provided with the distribution. + + 3. The name "JDOM" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact . + + 4. Products derived from this software may not be called "JDOM", nor + may "JDOM" appear in their name, without prior written permission + from the JDOM Project Management . + + In addition, we request (but do not require) that you include in the + end-user documentation provided with the redistribution and/or in the + software itself an acknowledgement equivalent to the following: + "This product includes software developed by the + JDOM Project (http://www.jdom.org/)." + Alternatively, the acknowledgment may be graphical using the logos + available at http://www.jdom.org/images/logos. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT + CONTRIBUTORS 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. + + This software consists of voluntary contributions made by many + individuals on behalf of the JDOM Project and was originally + created by Jason Hunter and + Brett McLaughlin . For more information on + the JDOM Project, please see . + + */ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/Jetty_license.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/Jetty_license.html new file mode 100644 index 0000000..9e470e3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/Jetty_license.html @@ -0,0 +1,213 @@ + + + Jetty License + + + + +
Jetty License
+
$Revision$
+ +Preamble: + +

+ + The intent of this document is to state the conditions under which the + Jetty Package may be copied, such that the Copyright Holder maintains some + semblance of control over the development of the package, while giving the + users of the package the right to use, distribute and make reasonable + modifications to the Package in accordance with the goals and ideals of + the Open Source concept as described at + http://www.opensource.org. + +

+ It is the intent of this license to allow commercial usage of the Jetty + package, so long as the source code is distributed or suitable visible + credit given or other arrangements made with the copyright holders. + +

Definitions: + +

+ +

    +
  • "Jetty" refers to the collection of Java classes that are + distributed as a HTTP server with servlet capabilities and + associated utilities. + +

    + +

  • "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + +

    + +

  • "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder. + +

    + +

  • "Copyright Holder" is whoever is named in the copyright or + copyrights for the package.
    + Mort Bay Consulting Pty. Ltd. (Australia) is the "Copyright + Holder" for the Jetty package. + +

    + +

  • "You" is you, if you're thinking about copying or distributing + this Package. + +

    + +

  • "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + +

    + +

  • "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +

    +

+ +0. The Jetty Package is Copyright (c) Mort Bay Consulting Pty. Ltd. +(Australia) and others. Individual files in this package may contain +additional copyright notices. The javax.servlet packages are copyright +Sun Microsystems Inc.

+ + 1. The Standard Version of the Jetty package is + available from http://jetty.mortbay.org. + +

+ + 2. You may make and distribute verbatim copies of the source form + of the Standard Version of this Package without restriction, provided that + you include this license and all of the original copyright notices + and associated disclaimers. + +

+ + 3. You may make and distribute verbatim copies of the compiled form of the + Standard Version of this Package without restriction, provided that you + include this license. + +

+ + 4. You may apply bug fixes, portability fixes and other modifications + derived from the Public Domain or from the Copyright Holder. A Package + modified in such a way shall still be considered the Standard Version. + +

+ + 5. You may otherwise modify your copy of this Package in any way, provided + that you insert a prominent notice in each changed file stating how and + when you changed that file, and provided that you do at least ONE of the + following: + +

+ +

+ a) Place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as ftp.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package.

+ + b) Use the modified Package only within your corporation or organization. + +

+ + c) Rename any non-standard classes so the names do not conflict + with standard classes, which must also be provided, and provide + a separate manual page for each non-standard class that clearly + documents how it differs from the Standard Version. + +

+ + d) Make other arrangements with the Copyright Holder. + +

+

+ +6. You may distribute modifications or subsets of this Package in source +code or compiled form, provided that you do at least ONE of the following:

+ +

+ a) Distribute this license and all original copyright messages, together + with instructions (in the about dialog, manual page or equivalent) on where + to get the complete Standard Version.

+ + b) Accompany the distribution with the machine-readable source of + the Package with your modifications. The modified package must include + this license and all of the original copyright notices and associated + disclaimers, together with instructions on where to get the complete + Standard Version. + +

+ + c) Make other arrangements with the Copyright Holder. + +

+

+ +7. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this Package. +You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you meet the other distribution requirements +of this license.

+ + 8. Input to or the output produced from the programs of this Package + do not automatically fall under the copyright of this Package, but + belong to whomever generated them, and may be sold commercially, and + may be aggregated with this Package. + +

+ + 9. Any program subroutines supplied by you and linked into this Package + shall not be considered part of this Package. + +

+ + 10. The name of the Copyright Holder may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +

+ + 11. This license may change with each release of a Standard Version of + the Package. You may choose to use the license associated with version + you are using or the license of the latest Standard Version. + +

+ + 12. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +

+ + 13. If any superior law implies a warranty, the sole remedy under such shall + be , at the Copyright Holders option either a) return of any price paid or + b) use or reasonable endeavours to repair or replace the software. + +

+ + 14. This license shall be read under the laws of Australia. + +

+ +

The End
+ +
This license was derived from the Artistic license published + on http://www.opensource.com
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/MPL-1.1.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/MPL-1.1.txt new file mode 100644 index 0000000..7a45bfe --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/MPL-1.1.txt @@ -0,0 +1,470 @@ + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/gpl-2.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/gpl-2.txt new file mode 100644 index 0000000..45645b4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/gpl-2.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/index.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/index.html new file mode 100644 index 0000000..7df3cfb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/index.html @@ -0,0 +1,141 @@ + + + + + + + + Licensing + + + + + + + + + +

JsUnit Licenses

+ JsUnit Home
+ edward@jsunit.net
+
+ +

Third-party licenses:

+
    +
  • JDOM: Portions of this software are copyright Copyright (C) 2000-2003 Jason Hunter & Brett McLaughlin. All + rights reserved. See JDOM_license.txt. +
  • Jetty: Portions of this software are copyright � Mort Bay Consulting Pty. Ltd. (Australia) and others. All + Rights Reserved. See Jetty_license.html. +
  • Individual files in this package may contain additional copyright notices. The javax.servlet packages are + copyright Sun Microsystems Inc. All Rights Reserved. +
+

+ +

JsUnit licenses:

+ JsUnit is licensed under 3 different licenses giving you the freedom + to use, modify and distribute JsUnit in a variety of fashions. +

+ +
    +
  1. +

    Mozilla Public License 1.1

    + +

    See mozilla.org + for more details.

    +
  2. + +
  3. +

    GNU Public License 2

    + +

    See www.gnu.org + for more details.

    +
  4. + +
  5. +

    GNU Lesser Public License 2.1

    + +

    See www.gnu.org + for more details.

    +
  6. +
+ +

+ Every Java and JavaScript source file in this distribution should be considered to be under the following licensing + terms. +

+        ***** BEGIN LICENSE BLOCK *****
+        - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+        -
+        - The contents of this file are subject to the Mozilla Public License Version
+        - 1.1 (the "License"); you may not use this file except in compliance with
+        - the License. You may obtain a copy of the License at
+        - http://www.mozilla.org/MPL/
+        -
+        - Software distributed under the License is distributed on an "AS IS" basis,
+        - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+        - for the specific language governing rights and limitations under the
+        - License.
+        -
+        - The Original Code is Edward Hieatt code.
+        -
+        - The Initial Developer of the Original Code is
+        - Edward Hieatt, edward@jsunit.net.
+        - Portions created by the Initial Developer are Copyright (C) 2003
+        - the Initial Developer. All Rights Reserved.
+        -
+        - Author Edward Hieatt, edward@jsunit.net
+        -
+        - Alternatively, the contents of this file may be used under the terms of
+        - either the GNU General Public License Version 2 or later (the "GPL"), or
+        - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+        - in which case the provisions of the GPL or the LGPL are applicable instead
+        - of those above. If you wish to allow use of your version of this file only
+        - under the terms of either the GPL or the LGPL, and not to allow others to
+        - use your version of this file under the terms of the MPL, indicate your
+        - decision by deleting the provisions above and replace them with the notice
+        - and other provisions required by the LGPL or the GPL. If you do not delete
+        - the provisions above, a recipient may use your version of this file under
+        - the terms of any one of the MPL, the GPL or the LGPL.
+        -
+        - ***** END LICENSE BLOCK *****
+    
+

+ + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/lgpl-2.1.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/lgpl-2.1.txt new file mode 100644 index 0000000..cbee875 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/lgpl-2.1.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-c.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-c.txt new file mode 100644 index 0000000..bd3ad22 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-c.txt @@ -0,0 +1,35 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is __________________________________________. + * + * The Initial Developer of the Original Code is + * ____________________________________________. + * Portions created by the Initial Developer are Copyright (C) 2___ + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-html.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-html.txt new file mode 100644 index 0000000..33f0980 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-html.txt @@ -0,0 +1,35 @@ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/readme.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/readme.txt new file mode 100644 index 0000000..d260774 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/readme.txt @@ -0,0 +1,19 @@ +JsUnit +Copyright (C) 2001-6 Edward Hieatt, edward@jsunit.net + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Please see http://www.jsunit.net/ for JsUnit documentation and +the "licenses" directory for license information. \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/testRunner.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/testRunner.html new file mode 100644 index 0000000..71a0c1a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/testRunner.html @@ -0,0 +1,167 @@ + + + + + +JsUnit Test Runner + + + + + + + + + + + + + + + + + + <body> + <p>Sorry, JsUnit requires support for frames.</p> + </body> + + + + \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/script.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/script.js new file mode 100644 index 0000000..8120054 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/script.js @@ -0,0 +1,7 @@ +function f() { + return true; +} + +function g() { + return true; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/test.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/test.html new file mode 100644 index 0000000..0d4d9bc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/test.html @@ -0,0 +1,25 @@ + + +Test + + + + + + + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example/index.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example/index.html new file mode 100644 index 0000000..e7230b5 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example/index.html @@ -0,0 +1,24 @@ + + + +Example + + + + +
Please select your favorite number:
+
+
+
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example/script.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example/script.js new file mode 100644 index 0000000..0589c76 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example/script.js @@ -0,0 +1,20 @@ +function go(element) { + var message; + if (element.id === 'radio1') { + message = 'You selected the number 1.'; + } + else if (element.id === 'radio2') { + message = 'You selected the number 2.'; + } + else if (element.id === 'radio3') { + message = 'You selected the number 3.'; + } + else if (element.id === 'radio4') { + message = 'You selected the number 4.'; + } + var div = document.getElementById('request'); + div.className = 'black'; + div = document.getElementById('result'); + div.innerHTML = '

' + message + '

'; + div.innerHTML += '

If you are running the instrumented version of this program, you can click the "Summary" tab to view a coverage report.

'; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/faq.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/faq.html new file mode 100644 index 0000000..7b783a8 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/faq.html @@ -0,0 +1,164 @@ + + + +JSCoverage - FAQ + + + + +
+

JSCoverage
code coverage for JavaScript

+
+
+
+

FAQ

+ +

Can I use JSCoverage to measure code coverage for a page on http://example.com/?

+ +

+ In order to measure the code coverage of a page on http://example.com/, + you must run jscoverage to create a jscoverage.html file on the + example.com server. You cannot use http://example.org/jscoverage.html + to measure the code coverage of a page located on http://example.com/. +

+ +

+ The fundamental reason for this limitation is the + Same Origin Policy + for untrusted JavaScript. +

+ +

+ (In fact, the current version of JSCoverage is slightly more restrictive + than this: it requires that the JavaScript being measured reside under the + same directory as the jscoverage.html file.) +

+ +

Why doesn't my test suite run under JSCoverage in Firefox 3?

+ +

+ Firefox 3 introduces new + security restrictions on local files. Depending on the way your + test suite is organized, this may cause problems for JSCoverage. + (You may get the error "uncaught exception: Permission denied to get property Window._$jscoverage".) + There are several workarounds: +

+ +
    +
  • Place your files on a web server instead of loading them from the file system. + This is usually the simplest solution.

    +
  • Organize your HTML files in your test suite in a flat directory structure. For example, suppose that + you instrument your test suite with this command:

    +
    +jscoverage src instrumented
    +
    +

    If all your HTML files are located directly under the src/ directory (i.e., not in a + subdirectory of src/), then you should not have any problems using Firefox 3.

    +
  • Set the Firefox preference named + security.fileuri.origin_policy + to 3.

    +
+ +

I'm trying to load my code with the URL + file:///C:/foo/bar/jscoverage.html?foo/bar.html + and I'm getting all kinds of JavaScript errors.

+ +

+ Internet Explorer 6 seems to have problems with a file: URL + that has a query string with a slash in it. +

+

+ As a workaround: +

+
    +
  • Place your files on a web server instead of loading them from the file system. + (http: URLs work fine.)

    +
  • Do not use a query string; enter your URL in the "URL" field in the "Browser" tab.

    +
  • Rearrange your directory structure so that bar.html + ends up in the same directory as jscoverage.html; then + you can use the URL + file:///C:/foo/bar/jscoverage.html?bar.html + with no slash in the query string.

    +
  • Use a different browser. (IE 7 seems to work.)

    +
+ +

JSCoverage changes my cursor to a busy cursor, and it never changes back!

+ +

+ Certain browsers (e. g., Internet Explorer 6, Opera, Safari) have trouble changing + the cursor. Try moving the mouse and your cursor should change back to normal. +

+ +

+ See this discussion for more information. +

+ +

JSCoverage hangs sometimes when rendering the coverage report.

+ +

+ With Internet Explorer 6 (I think I see a pattern here), garbage collection can cause performance problems. + (More information here.) +

+ +

Can JSCoverage be used with JsUnit?

+ +

+ It is necessary to run JSCoverage in inverted mode. You will have to + modify JsUnit to launch JSCoverage. +

+ +

+ See the directory doc/example-jsunit for an example. It + contains a copy of JsUnit version 2.2alpha11, with the file + jsunit/app/main-data.html slightly modified to add a button + which launches JSCoverage. It also contains a simple unit test file test.html. You + can instrument this example as follows: +

+ +
+jscoverage --no-instrument=jsunit doc/example-jsunit doc/instrumented-jsunit
+
+ +

+ You can then run the test.html file in JsUnit's jsunit/testRunner.html. + The simplest way to do this is probably to copy the contents of doc/instrumented-jsunit + to the root of a web server and then access the URL +

+ +
+http://127.0.0.1/jsunit/testRunner.html?testPage=http://127.0.0.1/test.html&autoRun=true
+
+ +

+ After the test suite has been run, click on the "Coverage report" button + to get a coverage report. +

+ +
+
+ +
+
+
+ Copyright © 2007, 2008 Silicon Forks siliconforks.com
+ jscoverage@siliconforks.com +
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/feed-icon-14x14.png b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/feed-icon-14x14.png new file mode 100644 index 0000000000000000000000000000000000000000..b3c949d2244f2c0c81d65e74719af2a1b56d06a3 GIT binary patch literal 689 zcmV;i0#5yjP)(tky!*UETcH-TCU7SrqEjJM#?B`_A)!p7(kFf9-P@=@15kkTkGK zgFusyy#KECqZzRdBLb=P?$(kUP;>kYTDeG&{|a+iOiRbI6nbQ)j#7bOf>iF=C+|_py<&Fo1F5cC*iEM?zZGC{ejNg4LWYp=S$L6Qaby6y zp$+F`250{%tU{Lg$5*ROH}y!1UKJS4*xqd7P(Y3JQF?lrnf?yerr%&6yGXLG1ur*B z{$&R1@Oj)yl@%rY5rh?j(j10Yz_DBs`AKFU_QnB;)(aqQmGi&ieOS|21^NP9UMpa< zU&p!f6RZ6Owp^X!EXA=0SbN&h?CrQK%Q3(=YBqqHD^9ZUM0Hxt-6-KT;>lf@j?Z+v zHm(}`>85I&E<7e}oz?6UwjAogowzGO8kSN7+2`b^$Az9L{K5*ko87EV45LT-`_##3 z>d3AGh@>=mbg34|6}+-gT9N+6Dr@44VEl44O&{&|w=qpbzC#iWMKa?5)>tI+KLQK@ Xq0QFqn(9Yl00000NkvXXu0mjfZ8t + + +JSCoverage - help + + + + +
+

JSCoverage
code coverage for JavaScript

+
+
+
+

Help

+

+ Questions, problems, suggestions, bug reports, and so on can be posted at the + online forum. +

+
+
+
+ +
+
+
+
+ Copyright © 2007, 2008 Silicon Forks siliconforks.com
+ jscoverage@siliconforks.com +
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/index.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/index.html new file mode 100644 index 0000000..7deca7e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/index.html @@ -0,0 +1,151 @@ + + + +JSCoverage - code coverage for JavaScript + + + + +
+

JSCoverage
code coverage for JavaScript

+
+
+
+

+ JSCoverage is a tool that measures code coverage for + JavaScript programs. +

+

+ Code coverage statistics show which lines of a program have + been executed (and which have been missed). This information is useful + for constructing comprehensive test suites (hence, it is often called + test coverage). +

+

+ JSCoverage works by instrumenting the JavaScript code used in web + pages. Code coverage statistics are collected while the instrumented + JavaScript code is executed in a web browser. +

+

+ JSCoverage supports the complete language syntax described in the + ECMAScript Language Specification (ECMA-262, 3rd edition). + JSCoverage works with any modern standards-compliant web browser - + including Internet Explorer (IE 6 and IE 7), Firefox (FF 2 and FF 3), + Opera, Safari, and Google Chrome - on Microsoft Windows and GNU/Linux. +

+

+ JSCoverage is free software, distributed under the + GNU General Public License version 2. +

+ +

Latest News RSS feed

+ +

December 11, 2008 - JSCoverage 0.4

+

+ JSCoverage 0.4 is available for download. +

+

+ This release includes many new features: +

+
    +
  • + The new jscoverage-server program is provided as an + alternative to the jscoverage program. The + jscoverage-server program is a simple HTTP server which + instruments JavaScript code as it is served; this allows you to execute + JavaScript and gather code coverage statistics without a preliminary + step of creating instrumented code. The jscoverage-server + program can either serve files directly from the filesystem or run as a + proxy server (with the --proxy option), instrumenting + JavaScript provided by another web server. +
  • + Using jscoverage-server, coverage reports can now be stored + to the filesystem. +
  • +
  • + JSCoverage now recognizes special JavaScript comments which specify that + certain lines of code should be ignored in coverage reports. +
  • +
  • + The new --encoding option provides better support for + different character encodings. +
  • +
  • + The JSCoverage user interface is now faster and more responsive. +
  • +
  • + The new --no-highlight option can be used to disable syntax + highlighting (giving better performance for large JavaScript files). +
  • +
  • + The build system has been modified so that make install + only installs the jscoverage and + jscoverage-server executables and their manual pages. + (Previous versions installed SpiderMonkey library and executable files, + which could conflict with other versions of SpiderMonkey installed on + your system.) +
  • +
  • + JSCoverage now supports several features beyond those found in the + ECMAScript Language Specification, including the following: +
      +
    • getters and setters +
    • for each loops +
    • generators and iterators +
    • the let keyword +
    • destructuring assignment +
    • array comprehensions +
    • expression closures +
    • generator expressions +
    + Use the new --js-version option to enable these features. +
  • +
+

+ The GCC C++ compiler (g++) is now required to compile + JSCoverage. (Previously, only the C compiler was needed.) +

+

+ Please report any bugs you find using the new bug tracker. +

+ +

March 31, 2008 - JSCoverage and Firefox 3

+

+ The JSCoverage FAQ has been updated to address problems using JSCoverage with Firefox 3. +

+ +

March 24, 2008 - JSCoverage in Debian GNU/Linux

+

+ JSCoverage is now available in the Debian unstable distribution. +

+ +

+ All news items... +

+
+
+
+ +
+
+
+
+ Copyright © 2007, 2008 Silicon Forks siliconforks.com
+ jscoverage@siliconforks.com +
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/index.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/index.html new file mode 100644 index 0000000..be0f8ea --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/index.html @@ -0,0 +1,25 @@ + + + +Example + + + + +
Please select your favorite number:
+
+
+
+
+
+ + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-highlight.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-highlight.css new file mode 100644 index 0000000..31a4695 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-highlight.css @@ -0,0 +1,38 @@ +/* + jscoverage-highlight.css - JSCoverage syntax highlighting style sheet + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/* keyword, type, symbol, cbracket */ +#sourceTable .k { + font-weight: bold; +} + +/* string, regexp, number */ +#sourceTable .s { + color: #006400; +} + +/* specialchar */ +#sourceTable .t { + color: #2e8b57; +} + +/* comment */ +#sourceTable .c { + font-style: italic; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-ie.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-ie.css new file mode 100644 index 0000000..afb2b80 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-ie.css @@ -0,0 +1,89 @@ +#headingDiv { + position: static; + margin-left: 10px; + margin-right: 10px; + padding-top: 0.5em; +} + +#tabs { + clear: all; + position: static; + top: auto; + left: auto; + right: auto; + height: auto; + margin-left: 10px; + margin-right: 10px; +} + +#tabs div { + position: relative; + height: auto; + line-height: normal; + padding-top: 5px; + padding-bottom: 5px; +} + +#tabs div.selected { + padding-bottom: 6px; + z-index: 2; +} + +.TabPage { + position: relative; + top: -1px; + left: auto; + right: auto; + bottom: auto; + clear: left; + margin-left: 10px; + margin-right: 10px; + padding: 10px; + z-index: 1; +} + +#locationDiv { + margin-bottom: 10px; +} + +#iframeDiv { + position: static; + width: 100%; +} + +#summaryDiv { + position: static; + width: 100%; +} + +#fileDiv { + margin-bottom: 10px; +} + +#sourceDiv { + position: static; + width: 100%; +} + +#storeDiv { + position: static; + width: 100%; +} + +/* some defaults */ + +.TabPage { + height: 650px; +} + +#iframeDiv { + height: 600px; +} + +#summaryDiv { + height: 600px; +} + +#sourceDiv { + height: 600px; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-throbber.gif b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-throbber.gif new file mode 100644 index 0000000000000000000000000000000000000000..f13c0b4ecc4327d891568b6494d60f0428741094 GIT binary patch literal 425 zcmZ?wbhEHbWM^P!c+AZJ1gxyA3JMB#c6JU94habfwY9Yk4GjwxEI4rBz=H=5{-XlL z|J;7AA;Hd$0j@@R2F#2={fa+X7`Yhu8FWB~fsAEf5&Ph&u(TrN>S}q#&`BOgn?s%^ zhV^T?;!vunS}Ag6b-d=(MIOf|ho~muQL2<$8FFRyeM?aWj}wbSQt>D~sr0mR%9Yjf zPE!>;PBMoq#ivwRwQ38{0bZhx9;cK;R1@$xKqa;6%azshgF*v64mgJ_#iR73%F-$k kU smaller than surrounding text. Because +the table already has font-size small, this would make the font-size within the +
 x-small.  So we don't rely on the default.
+*/
+table#sourceTable pre {
+  font-size: medium;
+}
+
+table#sourceTable td {
+  border: 0px;
+  padding-top: 0px;
+  padding-bottom: 0px;
+  padding-left: 10px;
+  padding-right: 10px;
+}
+
+table#sourceTable pre {
+  border: 0px;
+  margin: 0px;
+}
+
+.g {
+  background-color: #bfffbf;
+}
+
+.y {
+  background-color: #ffffbf;
+}
+
+.r {
+  background-color: #ffbfbf;
+}
+
+/*******************************************************************************
+store tab
+*/
+
+#storeDiv {
+  position: absolute;
+  top: 3em;
+  left: 1em;
+  right: 1em;
+  bottom: 1em;
+  overflow: auto;
+}
+
+/*******************************************************************************
+about tab
+*/
+
+p {
+  margin-top: 0;
+}
+
+/*******************************************************************************
+tabs
+*/
+
+#tabs {
+  position: absolute;
+  top: 3em;
+  left: 1.5em;
+  right: 1.5em;
+  height: 2em;
+}
+
+#tabs div {
+  background-color: white;
+  position: relative;
+  float: left;
+  border: 1px solid black;
+  border-bottom-width: 0;
+  cursor: pointer;
+  margin-left: 0.5em;
+  margin-right: 0.5em;
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  height: 2em;
+  z-index: 1;
+  line-height: 1.8em;
+}
+
+#tabs div.selected {
+  z-index: 3;
+  cursor: default;
+}
+
+#tabs div.disabled {
+  /* windows system color GrayText */
+  color: #808080;
+  cursor: default; 
+}
+
+.TabPage {
+  background-color: white;
+  border: 1px solid black;
+  position: absolute;
+  top: 5em;
+  left: 1.5em;
+  right: 1.5em;
+  bottom: 1.5em;
+  z-index: 2;
+  padding: 1em;
+  display: none;
+}
+
+#tabPages div.selected {
+  display: block;
+}
+
+img {
+  visibility: hidden;
+}
diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.html
new file mode 100644
index 0000000..601f62a
--- /dev/null
+++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.html
@@ -0,0 +1,125 @@
+
+
+
+
+
+JSCoverage
+
+
+
+
+
+
+
+
+
+

JSCoverage

+
+ +
+ +
+
Browser
+
Summary
+
Source
+
Store
+
About
+
+
+
+
+ URL: + +
+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
FileStatementsExecutedCoverage
+ Total: + 0 + 00 +
+
+
+ 0% +
+
+
+
+
+
+
+
+ + loading... +
+
+
+

+ This is version 0.4 of JSCoverage, a program that calculates code + coverage statistics for JavaScript. +

+

+ See http://siliconforks.com/jscoverage/ for more information. +

+

+ Copyright © 2007, 2008 siliconforks.com +

+
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.js new file mode 100644 index 0000000..9e2ea5b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.js @@ -0,0 +1,1024 @@ +/* + jscoverage.js - code coverage for JavaScript + Copyright (C) 2007, 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/** +Initializes the _$jscoverage object in a window. This should be the first +function called in the page. +@param w this should always be the global window object +*/ +function jscoverage_init(w) { + try { + // in Safari, "import" is a syntax error + Components.utils['import']('resource://gre/modules/jscoverage.jsm'); + jscoverage_isInvertedMode = true; + return; + } + catch (e) {} + + if (w.opener && w.opener.top._$jscoverage) { + // we are in inverted mode + jscoverage_isInvertedMode = true; + if (! w._$jscoverage) { + w._$jscoverage = w.opener.top._$jscoverage; + } + } + else { + // we are not in inverted mode + jscoverage_isInvertedMode = false; + if (! w._$jscoverage) { + w._$jscoverage = {}; + } + } +} + +var jscoverage_currentFile = null; +var jscoverage_currentLine = null; + +var jscoverage_inLengthyOperation = false; + +/* +Possible states: + isInvertedMode isServer isReport tabs +normal false false false Browser +inverted true false false +server, normal false true false Browser, Store +server, inverted true true false Store +report false false true +*/ +var jscoverage_isInvertedMode = false; +var jscoverage_isServer = false; +var jscoverage_isReport = false; + +jscoverage_init(window); + +function jscoverage_createRequest() { + // Note that the IE7 XMLHttpRequest does not support file URL's. + // http://xhab.blogspot.com/2006/11/ie7-support-for-xmlhttprequest.html + // http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx +//#JSCOVERAGE_IF + if (window.ActiveXObject) { + return new ActiveXObject("Microsoft.XMLHTTP"); + } + else { + return new XMLHttpRequest(); + } +} + +// http://www.quirksmode.org/js/findpos.html +function jscoverage_findPos(obj) { + var result = 0; + do { + result += obj.offsetTop; + obj = obj.offsetParent; + } + while (obj); + return result; +} + +// http://www.quirksmode.org/viewport/compatibility.html +function jscoverage_getViewportHeight() { +//#JSCOVERAGE_IF /MSIE/.test(navigator.userAgent) + if (self.innerHeight) { + // all except Explorer + return self.innerHeight; + } + else if (document.documentElement && document.documentElement.clientHeight) { + // Explorer 6 Strict Mode + return document.documentElement.clientHeight; + } + else if (document.body) { + // other Explorers + return document.body.clientHeight; + } + else { + throw "Couldn't calculate viewport height"; + } +//#JSCOVERAGE_ENDIF +} + +/** +Indicates visually that a lengthy operation has begun. The progress bar is +displayed, and the cursor is changed to busy (on browsers which support this). +*/ +function jscoverage_beginLengthyOperation() { + jscoverage_inLengthyOperation = true; + + var progressBar = document.getElementById('progressBar'); + progressBar.style.visibility = 'visible'; + ProgressBar.setPercentage(progressBar, 0); + var progressLabel = document.getElementById('progressLabel'); + progressLabel.style.visibility = 'visible'; + + /* blacklist buggy browsers */ +//#JSCOVERAGE_IF + if (! /Opera|WebKit/.test(navigator.userAgent)) { + /* + Change the cursor style of each element. Note that changing the class of the + element (to one with a busy cursor) is buggy in IE. + */ + var tabs = document.getElementById('tabs').getElementsByTagName('div'); + var i; + for (i = 0; i < tabs.length; i++) { + tabs.item(i).style.cursor = 'wait'; + } + } +} + +/** +Removes the progress bar and busy cursor. +*/ +function jscoverage_endLengthyOperation() { + var progressBar = document.getElementById('progressBar'); + ProgressBar.setPercentage(progressBar, 100); + setTimeout(function() { + jscoverage_inLengthyOperation = false; + progressBar.style.visibility = 'hidden'; + var progressLabel = document.getElementById('progressLabel'); + progressLabel.style.visibility = 'hidden'; + progressLabel.innerHTML = ''; + + var tabs = document.getElementById('tabs').getElementsByTagName('div'); + var i; + for (i = 0; i < tabs.length; i++) { + tabs.item(i).style.cursor = ''; + } + }, 50); +} + +function jscoverage_setSize() { +//#JSCOVERAGE_IF /MSIE/.test(navigator.userAgent) + var viewportHeight = jscoverage_getViewportHeight(); + + /* + border-top-width: 1px + padding-top: 10px + padding-bottom: 10px + border-bottom-width: 1px + margin-bottom: 10px + ---- + 32px + */ + var tabPages = document.getElementById('tabPages'); + var tabPageHeight = (viewportHeight - jscoverage_findPos(tabPages) - 32) + 'px'; + var nodeList = tabPages.childNodes; + var length = nodeList.length; + for (var i = 0; i < length; i++) { + var node = nodeList.item(i); + if (node.nodeType !== 1) { + continue; + } + node.style.height = tabPageHeight; + } + + var iframeDiv = document.getElementById('iframeDiv'); + // may not exist if we have removed the first tab + if (iframeDiv) { + iframeDiv.style.height = (viewportHeight - jscoverage_findPos(iframeDiv) - 21) + 'px'; + } + + var summaryDiv = document.getElementById('summaryDiv'); + summaryDiv.style.height = (viewportHeight - jscoverage_findPos(summaryDiv) - 21) + 'px'; + + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.style.height = (viewportHeight - jscoverage_findPos(sourceDiv) - 21) + 'px'; + + var storeDiv = document.getElementById('storeDiv'); + if (storeDiv) { + storeDiv.style.height = (viewportHeight - jscoverage_findPos(storeDiv) - 21) + 'px'; + } +//#JSCOVERAGE_ENDIF +} + +/** +Returns the boolean value of a string. Values 'false', 'f', 'no', 'n', 'off', +and '0' (upper or lower case) are false. +@param s the string +@return a boolean value +*/ +function jscoverage_getBooleanValue(s) { + s = s.toLowerCase(); + if (s === 'false' || s === 'f' || s === 'no' || s === 'n' || s === 'off' || s === '0') { + return false; + } + return true; +} + +function jscoverage_removeTab(id) { + var tab = document.getElementById(id + 'Tab'); + tab.parentNode.removeChild(tab); + var tabPage = document.getElementById(id + 'TabPage'); + tabPage.parentNode.removeChild(tabPage); +} + +/** +Initializes the contents of the tabs. This sets the initial values of the +input field and iframe in the "Browser" tab and the checkbox in the "Summary" +tab. +@param queryString this should always be location.search +*/ +function jscoverage_initTabContents(queryString) { + var showMissingColumn = false; + var parameters, parameter, i, index, url, name, value; + if (queryString.length > 0) { + // chop off the question mark + queryString = queryString.substring(1); + parameters = queryString.split(/&|;/); + for (i = 0; i < parameters.length; i++) { + parameter = parameters[i]; + index = parameter.indexOf('='); + if (index === -1) { + // still works with old syntax + url = parameter; + } + else { + name = parameter.substr(0, index); + value = parameter.substr(index + 1); + if (name === 'missing' || name === 'm') { + showMissingColumn = jscoverage_getBooleanValue(value); + } + else if (name === 'url' || name === 'u') { + url = value; + } + } + } + } + + var checkbox = document.getElementById('checkbox'); + checkbox.checked = showMissingColumn; + if (showMissingColumn) { + jscoverage_appendMissingColumn(); + } + + // this will automatically propagate to the input field + if (url) { + frames[0].location = url; + } + + // if the browser tab is absent, we have to initialize the summary tab + if (! document.getElementById('browserTab')) { + jscoverage_recalculateSummaryTab(); + } +} + +function jscoverage_body_load() { + var progressBar = document.getElementById('progressBar'); + ProgressBar.init(progressBar); + + function reportError(e) { + jscoverage_endLengthyOperation(); + var summaryThrobber = document.getElementById('summaryThrobber'); + summaryThrobber.style.visibility = 'hidden'; + var div = document.getElementById('summaryErrorDiv'); + div.innerHTML = 'Error: ' + e; + } + + if (jscoverage_isReport) { + jscoverage_beginLengthyOperation(); + var summaryThrobber = document.getElementById('summaryThrobber'); + summaryThrobber.style.visibility = 'visible'; + var request = jscoverage_createRequest(); + try { + request.open('GET', 'jscoverage.json', true); + request.onreadystatechange = function (event) { + if (request.readyState === 4) { + try { + if (request.status !== 0 && request.status !== 200) { + throw request.status; + } + var response = request.responseText; + if (response === '') { + throw 404; + } + var json = eval('(' + response + ')'); + var file; + for (file in json) { + var fileCoverage = json[file]; + _$jscoverage[file] = fileCoverage.coverage; + _$jscoverage[file].source = fileCoverage.source; + } + jscoverage_recalculateSummaryTab(); + summaryThrobber.style.visibility = 'hidden'; + } + catch (e) { + reportError(e); + } + } + }; + request.send(null); + } + catch (e) { + reportError(e); + } + + jscoverage_removeTab('browser'); + jscoverage_removeTab('store'); + } + else { + if (jscoverage_isInvertedMode) { + jscoverage_removeTab('browser'); + } + + if (! jscoverage_isServer) { + jscoverage_removeTab('store'); + } + } + + jscoverage_initTabControl(); + + jscoverage_initTabContents(location.search); +} + +function jscoverage_body_resize() { + if (/MSIE/.test(navigator.userAgent)) { + jscoverage_setSize(); + } +} + +// ----------------------------------------------------------------------------- +// tab 1 + +function jscoverage_updateBrowser() { + var input = document.getElementById("location"); + frames[0].location = input.value; +} + +function jscoverage_input_keypress(e) { + if (e.keyCode === 13) { + jscoverage_updateBrowser(); + } +} + +function jscoverage_button_click() { + jscoverage_updateBrowser(); +} + +function jscoverage_browser_load() { + /* update the input box */ + var input = document.getElementById("location"); + + /* sometimes IE seems to fire this after the tab has been removed */ + if (input) { + input.value = frames[0].location; + } +} + +// ----------------------------------------------------------------------------- +// tab 2 + +function jscoverage_createLink(file, line) { + var link = document.createElement("a"); + + var url; + var call; + var text; + if (line) { + url = file + ".jscoverage.html?" + line; + call = "jscoverage_get('" + file + "', " + line + ");"; + text = line.toString(); + } + else { + url = file + ".jscoverage.html"; + call = "jscoverage_get('" + file + "');"; + text = file; + } + + link.setAttribute('href', 'javascript:' + call); + link.appendChild(document.createTextNode(text)); + + return link; +} + +function jscoverage_recalculateSummaryTab(cc) { + var checkbox = document.getElementById('checkbox'); + var showMissingColumn = checkbox.checked; + + if (! cc) { + cc = window._$jscoverage; + } + if (! cc) { +//#JSCOVERAGE_IF 0 + throw "No coverage information found."; +//#JSCOVERAGE_ENDIF + } + + var tbody = document.getElementById("summaryTbody"); + while (tbody.hasChildNodes()) { + tbody.removeChild(tbody.firstChild); + } + + var totals = { files:0, statements:0, executed:0, coverage:0, skipped:0 }; + + var file; + var files = []; + for (file in cc) { + files.push(file); + } + files.sort(); + + var rowCounter = 0; + for (var f = 0; f < files.length; f++) { + file = files[f]; + var lineNumber; + var num_statements = 0; + var num_executed = 0; + var missing = []; + var fileCC = cc[file]; + var length = fileCC.length; + var currentConditionalEnd = 0; + var conditionals = null; + if (fileCC.conditionals) { + conditionals = fileCC.conditionals; + } + for (lineNumber = 0; lineNumber < length; lineNumber++) { + var n = fileCC[lineNumber]; + + if (lineNumber === currentConditionalEnd) { + currentConditionalEnd = 0; + } + else if (currentConditionalEnd === 0 && conditionals && conditionals[lineNumber]) { + currentConditionalEnd = conditionals[lineNumber]; + } + + if (currentConditionalEnd !== 0) { + continue; + } + + if (n === undefined || n === null) { + continue; + } + + if (n === 0) { + missing.push(lineNumber); + } + else { + num_executed++; + } + num_statements++; + } + + var percentage = ( num_statements === 0 ? 0 : parseInt(100 * num_executed / num_statements) ); + + var row = document.createElement("tr"); + row.className = ( rowCounter++ % 2 == 0 ? "odd" : "even" ); + + var cell = document.createElement("td"); + cell.className = 'leftColumn'; + var link = jscoverage_createLink(file); + cell.appendChild(link); + + row.appendChild(cell); + + cell = document.createElement("td"); + cell.className = 'numeric'; + cell.appendChild(document.createTextNode(num_statements)); + row.appendChild(cell); + + cell = document.createElement("td"); + cell.className = 'numeric'; + cell.appendChild(document.createTextNode(num_executed)); + row.appendChild(cell); + + // new coverage td containing a bar graph + cell = document.createElement("td"); + cell.className = 'coverage'; + var pctGraph = document.createElement("div"), + covered = document.createElement("div"), + pct = document.createElement("span"); + pctGraph.className = "pctGraph"; + if( num_statements === 0 ) { + covered.className = "skipped"; + pct.appendChild(document.createTextNode("N/A")); + } else { + covered.className = "covered"; + covered.style.width = percentage + "px"; + pct.appendChild(document.createTextNode(percentage + '%')); + } + pct.className = "pct"; + pctGraph.appendChild(covered); + cell.appendChild(pctGraph); + cell.appendChild(pct); + row.appendChild(cell); + + if (showMissingColumn) { + cell = document.createElement("td"); + for (var i = 0; i < missing.length; i++) { + if (i !== 0) { + cell.appendChild(document.createTextNode(", ")); + } + link = jscoverage_createLink(file, missing[i]); + cell.appendChild(link); + } + row.appendChild(cell); + } + + tbody.appendChild(row); + + totals['files'] ++; + totals['statements'] += num_statements; + totals['executed'] += num_executed; + totals['coverage'] += percentage; + if( num_statements === 0 ) { + totals['skipped']++; + } + + // write totals data into summaryTotals row + var tr = document.getElementById("summaryTotals"); + if (tr) { + var tds = tr.getElementsByTagName("td"); + tds[0].getElementsByTagName("span")[1].firstChild.nodeValue = totals['files']; + tds[1].firstChild.nodeValue = totals['statements']; + tds[2].firstChild.nodeValue = totals['executed']; + + var coverage = parseInt(totals['coverage'] / ( totals['files'] - totals['skipped'] ) ); + if( isNaN( coverage ) ) { + coverage = 0; + } + tds[3].getElementsByTagName("span")[0].firstChild.nodeValue = coverage + '%'; + tds[3].getElementsByTagName("div")[1].style.width = coverage + 'px'; + } + + } + jscoverage_endLengthyOperation(); +} + +function jscoverage_appendMissingColumn() { + var headerRow = document.getElementById('headerRow'); + var missingHeader = document.createElement('th'); + missingHeader.id = 'missingHeader'; + missingHeader.innerHTML = 'Missing'; + headerRow.appendChild(missingHeader); + var summaryTotals = document.getElementById('summaryTotals'); + var empty = document.createElement('td'); + empty.id = 'missingCell'; + summaryTotals.appendChild(empty); +} + +function jscoverage_removeMissingColumn() { + var missingNode; + missingNode = document.getElementById('missingHeader'); + missingNode.parentNode.removeChild(missingNode); + missingNode = document.getElementById('missingCell'); + missingNode.parentNode.removeChild(missingNode); +} + +function jscoverage_checkbox_click() { + if (jscoverage_inLengthyOperation) { + return false; + } + jscoverage_beginLengthyOperation(); + var checkbox = document.getElementById('checkbox'); + var showMissingColumn = checkbox.checked; + setTimeout(function() { + if (showMissingColumn) { + jscoverage_appendMissingColumn(); + } + else { + jscoverage_removeMissingColumn(); + } + jscoverage_recalculateSummaryTab(); + }, 50); + return true; +} + +// ----------------------------------------------------------------------------- +// tab 3 + +function jscoverage_makeTable() { + var coverage = _$jscoverage[jscoverage_currentFile]; + var lines = coverage.source; + + // this can happen if there is an error in the original JavaScript file + if (! lines) { + lines = []; + } + + var rows = ['']; + var i = 0; + var progressBar = document.getElementById('progressBar'); + var tableHTML; + var currentConditionalEnd = 0; + + function joinTableRows() { + tableHTML = rows.join(''); + ProgressBar.setPercentage(progressBar, 60); + /* + This may be a long delay, so set a timeout of 100 ms to make sure the + display is updated. + */ + setTimeout(appendTable, 100); + } + + function appendTable() { + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.innerHTML = tableHTML; + ProgressBar.setPercentage(progressBar, 80); + setTimeout(jscoverage_scrollToLine, 0); + } + + while (i < lines.length) { + var lineNumber = i + 1; + + if (lineNumber === currentConditionalEnd) { + currentConditionalEnd = 0; + } + else if (currentConditionalEnd === 0 && coverage.conditionals && coverage.conditionals[lineNumber]) { + currentConditionalEnd = coverage.conditionals[lineNumber]; + } + + var row = ''; + row += ''; + var timesExecuted = coverage[lineNumber]; + if (timesExecuted !== undefined && timesExecuted !== null) { + if (currentConditionalEnd !== 0) { + row += ''; + } + else { + row += ''; + } + row += ''; + row += ''; + row += '\n'; + rows[lineNumber] = row; + i++; + } + rows[i + 1] = '
' + lineNumber + ''; + } + else if (timesExecuted === 0) { + row += ''; + } + else { + row += ''; + } + row += timesExecuted; + row += '
' + lines[i] + '
'; + ProgressBar.setPercentage(progressBar, 40); + setTimeout(joinTableRows, 0); +} + +function jscoverage_scrollToLine() { + jscoverage_selectTab('sourceTab'); + if (! window.jscoverage_currentLine) { + jscoverage_endLengthyOperation(); + return; + } + var div = document.getElementById('sourceDiv'); + if (jscoverage_currentLine === 1) { + div.scrollTop = 0; + } + else { + var cell = document.getElementById('line-' + jscoverage_currentLine); + + // this might not be there if there is an error in the original JavaScript + if (cell) { + var divOffset = jscoverage_findPos(div); + var cellOffset = jscoverage_findPos(cell); + div.scrollTop = cellOffset - divOffset; + } + } + jscoverage_currentLine = 0; + jscoverage_endLengthyOperation(); +} + +/** +Loads the given file (and optional line) in the source tab. +*/ +function jscoverage_get(file, line) { + if (jscoverage_inLengthyOperation) { + return; + } + jscoverage_beginLengthyOperation(); + setTimeout(function() { + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.innerHTML = ''; + jscoverage_selectTab('sourceTab'); + if (file === jscoverage_currentFile) { + jscoverage_currentLine = line; + jscoverage_recalculateSourceTab(); + } + else { + if (jscoverage_currentFile === null) { + var tab = document.getElementById('sourceTab'); + tab.className = ''; + tab.onclick = jscoverage_tab_click; + } + jscoverage_currentFile = file; + jscoverage_currentLine = line || 1; // when changing the source, always scroll to top + var fileDiv = document.getElementById('fileDiv'); + fileDiv.innerHTML = jscoverage_currentFile; + jscoverage_recalculateSourceTab(); + return; + } + }, 50); +} + +/** +Calculates coverage statistics for the current source file. +*/ +function jscoverage_recalculateSourceTab() { + if (! jscoverage_currentFile) { + jscoverage_endLengthyOperation(); + return; + } + var progressLabel = document.getElementById('progressLabel'); + progressLabel.innerHTML = 'Calculating coverage ...'; + var progressBar = document.getElementById('progressBar'); + ProgressBar.setPercentage(progressBar, 20); + setTimeout(jscoverage_makeTable, 0); +} + +// ----------------------------------------------------------------------------- +// tabs + +/** +Initializes the tab control. This function must be called when the document is +loaded. +*/ +function jscoverage_initTabControl() { + var tabs = document.getElementById('tabs'); + var i; + var child; + var tabNum = 0; + for (i = 0; i < tabs.childNodes.length; i++) { + child = tabs.childNodes.item(i); + if (child.nodeType === 1) { + if (child.className !== 'disabled') { + child.onclick = jscoverage_tab_click; + } + tabNum++; + } + } + jscoverage_selectTab(0); +} + +/** +Selects a tab. +@param tab the integer index of the tab (0, 1, 2, or 3) + OR + the ID of the tab element + OR + the tab element itself +*/ +function jscoverage_selectTab(tab) { + if (typeof tab !== 'number') { + tab = jscoverage_tabIndexOf(tab); + } + var tabs = document.getElementById('tabs'); + var tabPages = document.getElementById('tabPages'); + var nodeList; + var tabNum; + var i; + var node; + + nodeList = tabs.childNodes; + tabNum = 0; + for (i = 0; i < nodeList.length; i++) { + node = nodeList.item(i); + if (node.nodeType !== 1) { + continue; + } + + if (node.className !== 'disabled') { + if (tabNum === tab) { + node.className = 'selected'; + } + else { + node.className = ''; + } + } + tabNum++; + } + + nodeList = tabPages.childNodes; + tabNum = 0; + for (i = 0; i < nodeList.length; i++) { + node = nodeList.item(i); + if (node.nodeType !== 1) { + continue; + } + + if (tabNum === tab) { + node.className = 'selected TabPage'; + } + else { + node.className = 'TabPage'; + } + tabNum++; + } +} + +/** +Returns an integer (0, 1, 2, or 3) representing the index of a given tab. +@param tab the ID of the tab element + OR + the tab element itself +*/ +function jscoverage_tabIndexOf(tab) { + if (typeof tab === 'string') { + tab = document.getElementById(tab); + } + var tabs = document.getElementById('tabs'); + var i; + var child; + var tabNum = 0; + for (i = 0; i < tabs.childNodes.length; i++) { + child = tabs.childNodes.item(i); + if (child.nodeType === 1) { + if (child === tab) { + return tabNum; + } + tabNum++; + } + } +//#JSCOVERAGE_IF 0 + throw "Tab not found"; +//#JSCOVERAGE_ENDIF +} + +function jscoverage_tab_click(e) { + if (jscoverage_inLengthyOperation) { + return; + } + var target; +//#JSCOVERAGE_IF + if (e) { + target = e.target; + } + else if (window.event) { + // IE + target = window.event.srcElement; + } + if (target.className === 'selected') { + return; + } + jscoverage_beginLengthyOperation(); + setTimeout(function() { + if (target.id === 'summaryTab') { + var tbody = document.getElementById("summaryTbody"); + while (tbody.hasChildNodes()) { + tbody.removeChild(tbody.firstChild); + } + } + else if (target.id === 'sourceTab') { + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.innerHTML = ''; + } + jscoverage_selectTab(target); + if (target.id === 'summaryTab') { + jscoverage_recalculateSummaryTab(); + } + else if (target.id === 'sourceTab') { + jscoverage_recalculateSourceTab(); + } + else { + jscoverage_endLengthyOperation(); + } + }, 50); +} + +// ----------------------------------------------------------------------------- +// progress bar + +var ProgressBar = { + init: function(element) { + element._percentage = 0; + + /* doing this via JavaScript crashes Safari */ +/* + var pctGraph = document.createElement('div'); + pctGraph.className = 'pctGraph'; + element.appendChild(pctGraph); + var covered = document.createElement('div'); + covered.className = 'covered'; + pctGraph.appendChild(covered); + var pct = document.createElement('span'); + pct.className = 'pct'; + element.appendChild(pct); +*/ + + ProgressBar._update(element); + }, + setPercentage: function(element, percentage) { + element._percentage = percentage; + ProgressBar._update(element); + }, + _update: function(element) { + var pctGraph = element.getElementsByTagName('div').item(0); + var covered = pctGraph.getElementsByTagName('div').item(0); + var pct = element.getElementsByTagName('span').item(0); + pct.innerHTML = element._percentage.toString() + '%'; + covered.style.width = element._percentage + 'px'; + } +}; + +// ----------------------------------------------------------------------------- +// reports + +function jscoverage_pad(s) { + return '0000'.substr(s.length) + s; +} + +function jscoverage_quote(s) { + return '"' + s.replace(/[\u0000-\u001f"\\\u007f-\uffff]/g, function (c) { + switch (c) { + case '\b': + return '\\b'; + case '\f': + return '\\f'; + case '\n': + return '\\n'; + case '\r': + return '\\r'; + case '\t': + return '\\t'; + // IE doesn't support this + /* + case '\v': + return '\\v'; + */ + case '"': + return '\\"'; + case '\\': + return '\\\\'; + default: + return '\\u' + jscoverage_pad(c.charCodeAt(0).toString(16)); + } + }) + '"'; +} + +function jscoverage_serializeCoverageToJSON() { + var json = []; + for (var file in _$jscoverage) { + var coverage = _$jscoverage[file]; + var array = []; + var length = coverage.length; + for (var line = 0; line < length; line++) { + var value = coverage[line]; + if (value === undefined || value === null) { + value = 'null'; + } + array.push(value); + } + json.push(jscoverage_quote(file) + ':[' + array.join(',') + ']'); + } + return '{' + json.join(',') + '}'; +} + +function jscoverage_storeButton_click() { + if (jscoverage_inLengthyOperation) { + return; + } + + jscoverage_beginLengthyOperation(); + var img = document.getElementById('storeImg'); + img.style.visibility = 'visible'; + + var request = jscoverage_createRequest(); + request.open('POST', '/jscoverage-store', true); + request.onreadystatechange = function (event) { + if (request.readyState === 4) { + var message; + try { + if (request.status !== 200 && request.status !== 201 && request.status !== 204) { + throw request.status; + } + message = request.responseText; + } + catch (e) { + if (e.toString().search(/^\d{3}$/) === 0) { + message = e + ': ' + request.responseText; + } + else { + message = 'Could not connect to server: ' + e; + } + } + + jscoverage_endLengthyOperation(); + var img = document.getElementById('storeImg'); + img.style.visibility = 'hidden'; + + var div = document.getElementById('storeDiv'); + div.appendChild(document.createTextNode(new Date() + ': ' + message)); + div.appendChild(document.createElement('br')); + } + }; + request.setRequestHeader('Content-Type', 'application/json'); + var json = jscoverage_serializeCoverageToJSON(); + request.setRequestHeader('Content-Length', json.length.toString()); + request.send(json); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/script.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/script.js new file mode 100644 index 0000000..5ea28fc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/script.js @@ -0,0 +1,65 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['script.js']) { + _$jscoverage['script.js'] = []; + _$jscoverage['script.js'][1] = 0; + _$jscoverage['script.js'][2] = 0; + _$jscoverage['script.js'][3] = 0; + _$jscoverage['script.js'][4] = 0; + _$jscoverage['script.js'][6] = 0; + _$jscoverage['script.js'][7] = 0; + _$jscoverage['script.js'][9] = 0; + _$jscoverage['script.js'][10] = 0; + _$jscoverage['script.js'][12] = 0; + _$jscoverage['script.js'][13] = 0; + _$jscoverage['script.js'][15] = 0; + _$jscoverage['script.js'][16] = 0; + _$jscoverage['script.js'][17] = 0; + _$jscoverage['script.js'][18] = 0; + _$jscoverage['script.js'][19] = 0; +} +_$jscoverage['script.js'][1]++; +function go(element) { + _$jscoverage['script.js'][2]++; + var message; + _$jscoverage['script.js'][3]++; + if (element.id === "radio1") { + _$jscoverage['script.js'][4]++; + message = "You selected the number 1."; + } + else { + _$jscoverage['script.js'][6]++; + if (element.id === "radio2") { + _$jscoverage['script.js'][7]++; + message = "You selected the number 2."; + } + else { + _$jscoverage['script.js'][9]++; + if (element.id === "radio3") { + _$jscoverage['script.js'][10]++; + message = "You selected the number 3."; + } + else { + _$jscoverage['script.js'][12]++; + if (element.id === "radio4") { + _$jscoverage['script.js'][13]++; + message = "You selected the number 4."; + } + } + } + } + _$jscoverage['script.js'][15]++; + var div = document.getElementById("request"); + _$jscoverage['script.js'][16]++; + div.className = "black"; + _$jscoverage['script.js'][17]++; + div = document.getElementById("result"); + _$jscoverage['script.js'][18]++; + div.innerHTML = "

" + message + "

"; + _$jscoverage['script.js'][19]++; + div.innerHTML += "

If you are running the instrumented version of this program, you can click the \"Coverage report\" button to view a coverage report.

"; +} +_$jscoverage['script.js'].source = ["function go(element) {"," var message;"," if (element.id === 'radio1') {"," message = 'You selected the number 1.';"," }"," else if (element.id === 'radio2') {"," message = 'You selected the number 2.';"," }"," else if (element.id === 'radio3') {"," message = 'You selected the number 3.';"," }"," else if (element.id === 'radio4') {"," message = 'You selected the number 4.';"," }"," var div = document.getElementById('request');"," div.className = 'black';"," div = document.getElementById('result');"," div.innerHTML = '<p>' + message + '</p>';"," div.innerHTML += '<p>If you are running the instrumented version of this program, you can click the \"Coverage report\" button to view a coverage report.</p>';","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/index.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/index.html new file mode 100644 index 0000000..e7230b5 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/index.html @@ -0,0 +1,24 @@ + + + +Example + + + + +
Please select your favorite number:
+
+
+
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-highlight.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-highlight.css new file mode 100644 index 0000000..31a4695 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-highlight.css @@ -0,0 +1,38 @@ +/* + jscoverage-highlight.css - JSCoverage syntax highlighting style sheet + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/* keyword, type, symbol, cbracket */ +#sourceTable .k { + font-weight: bold; +} + +/* string, regexp, number */ +#sourceTable .s { + color: #006400; +} + +/* specialchar */ +#sourceTable .t { + color: #2e8b57; +} + +/* comment */ +#sourceTable .c { + font-style: italic; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-ie.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-ie.css new file mode 100644 index 0000000..afb2b80 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-ie.css @@ -0,0 +1,89 @@ +#headingDiv { + position: static; + margin-left: 10px; + margin-right: 10px; + padding-top: 0.5em; +} + +#tabs { + clear: all; + position: static; + top: auto; + left: auto; + right: auto; + height: auto; + margin-left: 10px; + margin-right: 10px; +} + +#tabs div { + position: relative; + height: auto; + line-height: normal; + padding-top: 5px; + padding-bottom: 5px; +} + +#tabs div.selected { + padding-bottom: 6px; + z-index: 2; +} + +.TabPage { + position: relative; + top: -1px; + left: auto; + right: auto; + bottom: auto; + clear: left; + margin-left: 10px; + margin-right: 10px; + padding: 10px; + z-index: 1; +} + +#locationDiv { + margin-bottom: 10px; +} + +#iframeDiv { + position: static; + width: 100%; +} + +#summaryDiv { + position: static; + width: 100%; +} + +#fileDiv { + margin-bottom: 10px; +} + +#sourceDiv { + position: static; + width: 100%; +} + +#storeDiv { + position: static; + width: 100%; +} + +/* some defaults */ + +.TabPage { + height: 650px; +} + +#iframeDiv { + height: 600px; +} + +#summaryDiv { + height: 600px; +} + +#sourceDiv { + height: 600px; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-throbber.gif b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-throbber.gif new file mode 100644 index 0000000000000000000000000000000000000000..f13c0b4ecc4327d891568b6494d60f0428741094 GIT binary patch literal 425 zcmZ?wbhEHbWM^P!c+AZJ1gxyA3JMB#c6JU94habfwY9Yk4GjwxEI4rBz=H=5{-XlL z|J;7AA;Hd$0j@@R2F#2={fa+X7`Yhu8FWB~fsAEf5&Ph&u(TrN>S}q#&`BOgn?s%^ zhV^T?;!vunS}Ag6b-d=(MIOf|ho~muQL2<$8FFRyeM?aWj}wbSQt>D~sr0mR%9Yjf zPE!>;PBMoq#ivwRwQ38{0bZhx9;cK;R1@$xKqa;6%azshgF*v64mgJ_#iR73%F-$k kU smaller than surrounding text. Because +the table already has font-size small, this would make the font-size within the +
 x-small.  So we don't rely on the default.
+*/
+table#sourceTable pre {
+  font-size: medium;
+}
+
+table#sourceTable td {
+  border: 0px;
+  padding-top: 0px;
+  padding-bottom: 0px;
+  padding-left: 10px;
+  padding-right: 10px;
+}
+
+table#sourceTable pre {
+  border: 0px;
+  margin: 0px;
+}
+
+.g {
+  background-color: #bfffbf;
+}
+
+.y {
+  background-color: #ffffbf;
+}
+
+.r {
+  background-color: #ffbfbf;
+}
+
+/*******************************************************************************
+store tab
+*/
+
+#storeDiv {
+  position: absolute;
+  top: 3em;
+  left: 1em;
+  right: 1em;
+  bottom: 1em;
+  overflow: auto;
+}
+
+/*******************************************************************************
+about tab
+*/
+
+p {
+  margin-top: 0;
+}
+
+/*******************************************************************************
+tabs
+*/
+
+#tabs {
+  position: absolute;
+  top: 3em;
+  left: 1.5em;
+  right: 1.5em;
+  height: 2em;
+}
+
+#tabs div {
+  background-color: white;
+  position: relative;
+  float: left;
+  border: 1px solid black;
+  border-bottom-width: 0;
+  cursor: pointer;
+  margin-left: 0.5em;
+  margin-right: 0.5em;
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  height: 2em;
+  z-index: 1;
+  line-height: 1.8em;
+}
+
+#tabs div.selected {
+  z-index: 3;
+  cursor: default;
+}
+
+#tabs div.disabled {
+  /* windows system color GrayText */
+  color: #808080;
+  cursor: default; 
+}
+
+.TabPage {
+  background-color: white;
+  border: 1px solid black;
+  position: absolute;
+  top: 5em;
+  left: 1.5em;
+  right: 1.5em;
+  bottom: 1.5em;
+  z-index: 2;
+  padding: 1em;
+  display: none;
+}
+
+#tabPages div.selected {
+  display: block;
+}
+
+img {
+  visibility: hidden;
+}
diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.html
new file mode 100644
index 0000000..601f62a
--- /dev/null
+++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.html
@@ -0,0 +1,125 @@
+
+
+
+
+
+JSCoverage
+
+
+
+
+
+
+
+
+
+

JSCoverage

+
+ +
+ +
+
Browser
+
Summary
+
Source
+
Store
+
About
+
+
+
+
+ URL: + +
+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
FileStatementsExecutedCoverage
+ Total: + 0 + 00 +
+
+
+ 0% +
+
+
+
+
+
+
+
+ + loading... +
+
+
+

+ This is version 0.4 of JSCoverage, a program that calculates code + coverage statistics for JavaScript. +

+

+ See http://siliconforks.com/jscoverage/ for more information. +

+

+ Copyright © 2007, 2008 siliconforks.com +

+
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.js new file mode 100644 index 0000000..9e2ea5b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.js @@ -0,0 +1,1024 @@ +/* + jscoverage.js - code coverage for JavaScript + Copyright (C) 2007, 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/** +Initializes the _$jscoverage object in a window. This should be the first +function called in the page. +@param w this should always be the global window object +*/ +function jscoverage_init(w) { + try { + // in Safari, "import" is a syntax error + Components.utils['import']('resource://gre/modules/jscoverage.jsm'); + jscoverage_isInvertedMode = true; + return; + } + catch (e) {} + + if (w.opener && w.opener.top._$jscoverage) { + // we are in inverted mode + jscoverage_isInvertedMode = true; + if (! w._$jscoverage) { + w._$jscoverage = w.opener.top._$jscoverage; + } + } + else { + // we are not in inverted mode + jscoverage_isInvertedMode = false; + if (! w._$jscoverage) { + w._$jscoverage = {}; + } + } +} + +var jscoverage_currentFile = null; +var jscoverage_currentLine = null; + +var jscoverage_inLengthyOperation = false; + +/* +Possible states: + isInvertedMode isServer isReport tabs +normal false false false Browser +inverted true false false +server, normal false true false Browser, Store +server, inverted true true false Store +report false false true +*/ +var jscoverage_isInvertedMode = false; +var jscoverage_isServer = false; +var jscoverage_isReport = false; + +jscoverage_init(window); + +function jscoverage_createRequest() { + // Note that the IE7 XMLHttpRequest does not support file URL's. + // http://xhab.blogspot.com/2006/11/ie7-support-for-xmlhttprequest.html + // http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx +//#JSCOVERAGE_IF + if (window.ActiveXObject) { + return new ActiveXObject("Microsoft.XMLHTTP"); + } + else { + return new XMLHttpRequest(); + } +} + +// http://www.quirksmode.org/js/findpos.html +function jscoverage_findPos(obj) { + var result = 0; + do { + result += obj.offsetTop; + obj = obj.offsetParent; + } + while (obj); + return result; +} + +// http://www.quirksmode.org/viewport/compatibility.html +function jscoverage_getViewportHeight() { +//#JSCOVERAGE_IF /MSIE/.test(navigator.userAgent) + if (self.innerHeight) { + // all except Explorer + return self.innerHeight; + } + else if (document.documentElement && document.documentElement.clientHeight) { + // Explorer 6 Strict Mode + return document.documentElement.clientHeight; + } + else if (document.body) { + // other Explorers + return document.body.clientHeight; + } + else { + throw "Couldn't calculate viewport height"; + } +//#JSCOVERAGE_ENDIF +} + +/** +Indicates visually that a lengthy operation has begun. The progress bar is +displayed, and the cursor is changed to busy (on browsers which support this). +*/ +function jscoverage_beginLengthyOperation() { + jscoverage_inLengthyOperation = true; + + var progressBar = document.getElementById('progressBar'); + progressBar.style.visibility = 'visible'; + ProgressBar.setPercentage(progressBar, 0); + var progressLabel = document.getElementById('progressLabel'); + progressLabel.style.visibility = 'visible'; + + /* blacklist buggy browsers */ +//#JSCOVERAGE_IF + if (! /Opera|WebKit/.test(navigator.userAgent)) { + /* + Change the cursor style of each element. Note that changing the class of the + element (to one with a busy cursor) is buggy in IE. + */ + var tabs = document.getElementById('tabs').getElementsByTagName('div'); + var i; + for (i = 0; i < tabs.length; i++) { + tabs.item(i).style.cursor = 'wait'; + } + } +} + +/** +Removes the progress bar and busy cursor. +*/ +function jscoverage_endLengthyOperation() { + var progressBar = document.getElementById('progressBar'); + ProgressBar.setPercentage(progressBar, 100); + setTimeout(function() { + jscoverage_inLengthyOperation = false; + progressBar.style.visibility = 'hidden'; + var progressLabel = document.getElementById('progressLabel'); + progressLabel.style.visibility = 'hidden'; + progressLabel.innerHTML = ''; + + var tabs = document.getElementById('tabs').getElementsByTagName('div'); + var i; + for (i = 0; i < tabs.length; i++) { + tabs.item(i).style.cursor = ''; + } + }, 50); +} + +function jscoverage_setSize() { +//#JSCOVERAGE_IF /MSIE/.test(navigator.userAgent) + var viewportHeight = jscoverage_getViewportHeight(); + + /* + border-top-width: 1px + padding-top: 10px + padding-bottom: 10px + border-bottom-width: 1px + margin-bottom: 10px + ---- + 32px + */ + var tabPages = document.getElementById('tabPages'); + var tabPageHeight = (viewportHeight - jscoverage_findPos(tabPages) - 32) + 'px'; + var nodeList = tabPages.childNodes; + var length = nodeList.length; + for (var i = 0; i < length; i++) { + var node = nodeList.item(i); + if (node.nodeType !== 1) { + continue; + } + node.style.height = tabPageHeight; + } + + var iframeDiv = document.getElementById('iframeDiv'); + // may not exist if we have removed the first tab + if (iframeDiv) { + iframeDiv.style.height = (viewportHeight - jscoverage_findPos(iframeDiv) - 21) + 'px'; + } + + var summaryDiv = document.getElementById('summaryDiv'); + summaryDiv.style.height = (viewportHeight - jscoverage_findPos(summaryDiv) - 21) + 'px'; + + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.style.height = (viewportHeight - jscoverage_findPos(sourceDiv) - 21) + 'px'; + + var storeDiv = document.getElementById('storeDiv'); + if (storeDiv) { + storeDiv.style.height = (viewportHeight - jscoverage_findPos(storeDiv) - 21) + 'px'; + } +//#JSCOVERAGE_ENDIF +} + +/** +Returns the boolean value of a string. Values 'false', 'f', 'no', 'n', 'off', +and '0' (upper or lower case) are false. +@param s the string +@return a boolean value +*/ +function jscoverage_getBooleanValue(s) { + s = s.toLowerCase(); + if (s === 'false' || s === 'f' || s === 'no' || s === 'n' || s === 'off' || s === '0') { + return false; + } + return true; +} + +function jscoverage_removeTab(id) { + var tab = document.getElementById(id + 'Tab'); + tab.parentNode.removeChild(tab); + var tabPage = document.getElementById(id + 'TabPage'); + tabPage.parentNode.removeChild(tabPage); +} + +/** +Initializes the contents of the tabs. This sets the initial values of the +input field and iframe in the "Browser" tab and the checkbox in the "Summary" +tab. +@param queryString this should always be location.search +*/ +function jscoverage_initTabContents(queryString) { + var showMissingColumn = false; + var parameters, parameter, i, index, url, name, value; + if (queryString.length > 0) { + // chop off the question mark + queryString = queryString.substring(1); + parameters = queryString.split(/&|;/); + for (i = 0; i < parameters.length; i++) { + parameter = parameters[i]; + index = parameter.indexOf('='); + if (index === -1) { + // still works with old syntax + url = parameter; + } + else { + name = parameter.substr(0, index); + value = parameter.substr(index + 1); + if (name === 'missing' || name === 'm') { + showMissingColumn = jscoverage_getBooleanValue(value); + } + else if (name === 'url' || name === 'u') { + url = value; + } + } + } + } + + var checkbox = document.getElementById('checkbox'); + checkbox.checked = showMissingColumn; + if (showMissingColumn) { + jscoverage_appendMissingColumn(); + } + + // this will automatically propagate to the input field + if (url) { + frames[0].location = url; + } + + // if the browser tab is absent, we have to initialize the summary tab + if (! document.getElementById('browserTab')) { + jscoverage_recalculateSummaryTab(); + } +} + +function jscoverage_body_load() { + var progressBar = document.getElementById('progressBar'); + ProgressBar.init(progressBar); + + function reportError(e) { + jscoverage_endLengthyOperation(); + var summaryThrobber = document.getElementById('summaryThrobber'); + summaryThrobber.style.visibility = 'hidden'; + var div = document.getElementById('summaryErrorDiv'); + div.innerHTML = 'Error: ' + e; + } + + if (jscoverage_isReport) { + jscoverage_beginLengthyOperation(); + var summaryThrobber = document.getElementById('summaryThrobber'); + summaryThrobber.style.visibility = 'visible'; + var request = jscoverage_createRequest(); + try { + request.open('GET', 'jscoverage.json', true); + request.onreadystatechange = function (event) { + if (request.readyState === 4) { + try { + if (request.status !== 0 && request.status !== 200) { + throw request.status; + } + var response = request.responseText; + if (response === '') { + throw 404; + } + var json = eval('(' + response + ')'); + var file; + for (file in json) { + var fileCoverage = json[file]; + _$jscoverage[file] = fileCoverage.coverage; + _$jscoverage[file].source = fileCoverage.source; + } + jscoverage_recalculateSummaryTab(); + summaryThrobber.style.visibility = 'hidden'; + } + catch (e) { + reportError(e); + } + } + }; + request.send(null); + } + catch (e) { + reportError(e); + } + + jscoverage_removeTab('browser'); + jscoverage_removeTab('store'); + } + else { + if (jscoverage_isInvertedMode) { + jscoverage_removeTab('browser'); + } + + if (! jscoverage_isServer) { + jscoverage_removeTab('store'); + } + } + + jscoverage_initTabControl(); + + jscoverage_initTabContents(location.search); +} + +function jscoverage_body_resize() { + if (/MSIE/.test(navigator.userAgent)) { + jscoverage_setSize(); + } +} + +// ----------------------------------------------------------------------------- +// tab 1 + +function jscoverage_updateBrowser() { + var input = document.getElementById("location"); + frames[0].location = input.value; +} + +function jscoverage_input_keypress(e) { + if (e.keyCode === 13) { + jscoverage_updateBrowser(); + } +} + +function jscoverage_button_click() { + jscoverage_updateBrowser(); +} + +function jscoverage_browser_load() { + /* update the input box */ + var input = document.getElementById("location"); + + /* sometimes IE seems to fire this after the tab has been removed */ + if (input) { + input.value = frames[0].location; + } +} + +// ----------------------------------------------------------------------------- +// tab 2 + +function jscoverage_createLink(file, line) { + var link = document.createElement("a"); + + var url; + var call; + var text; + if (line) { + url = file + ".jscoverage.html?" + line; + call = "jscoverage_get('" + file + "', " + line + ");"; + text = line.toString(); + } + else { + url = file + ".jscoverage.html"; + call = "jscoverage_get('" + file + "');"; + text = file; + } + + link.setAttribute('href', 'javascript:' + call); + link.appendChild(document.createTextNode(text)); + + return link; +} + +function jscoverage_recalculateSummaryTab(cc) { + var checkbox = document.getElementById('checkbox'); + var showMissingColumn = checkbox.checked; + + if (! cc) { + cc = window._$jscoverage; + } + if (! cc) { +//#JSCOVERAGE_IF 0 + throw "No coverage information found."; +//#JSCOVERAGE_ENDIF + } + + var tbody = document.getElementById("summaryTbody"); + while (tbody.hasChildNodes()) { + tbody.removeChild(tbody.firstChild); + } + + var totals = { files:0, statements:0, executed:0, coverage:0, skipped:0 }; + + var file; + var files = []; + for (file in cc) { + files.push(file); + } + files.sort(); + + var rowCounter = 0; + for (var f = 0; f < files.length; f++) { + file = files[f]; + var lineNumber; + var num_statements = 0; + var num_executed = 0; + var missing = []; + var fileCC = cc[file]; + var length = fileCC.length; + var currentConditionalEnd = 0; + var conditionals = null; + if (fileCC.conditionals) { + conditionals = fileCC.conditionals; + } + for (lineNumber = 0; lineNumber < length; lineNumber++) { + var n = fileCC[lineNumber]; + + if (lineNumber === currentConditionalEnd) { + currentConditionalEnd = 0; + } + else if (currentConditionalEnd === 0 && conditionals && conditionals[lineNumber]) { + currentConditionalEnd = conditionals[lineNumber]; + } + + if (currentConditionalEnd !== 0) { + continue; + } + + if (n === undefined || n === null) { + continue; + } + + if (n === 0) { + missing.push(lineNumber); + } + else { + num_executed++; + } + num_statements++; + } + + var percentage = ( num_statements === 0 ? 0 : parseInt(100 * num_executed / num_statements) ); + + var row = document.createElement("tr"); + row.className = ( rowCounter++ % 2 == 0 ? "odd" : "even" ); + + var cell = document.createElement("td"); + cell.className = 'leftColumn'; + var link = jscoverage_createLink(file); + cell.appendChild(link); + + row.appendChild(cell); + + cell = document.createElement("td"); + cell.className = 'numeric'; + cell.appendChild(document.createTextNode(num_statements)); + row.appendChild(cell); + + cell = document.createElement("td"); + cell.className = 'numeric'; + cell.appendChild(document.createTextNode(num_executed)); + row.appendChild(cell); + + // new coverage td containing a bar graph + cell = document.createElement("td"); + cell.className = 'coverage'; + var pctGraph = document.createElement("div"), + covered = document.createElement("div"), + pct = document.createElement("span"); + pctGraph.className = "pctGraph"; + if( num_statements === 0 ) { + covered.className = "skipped"; + pct.appendChild(document.createTextNode("N/A")); + } else { + covered.className = "covered"; + covered.style.width = percentage + "px"; + pct.appendChild(document.createTextNode(percentage + '%')); + } + pct.className = "pct"; + pctGraph.appendChild(covered); + cell.appendChild(pctGraph); + cell.appendChild(pct); + row.appendChild(cell); + + if (showMissingColumn) { + cell = document.createElement("td"); + for (var i = 0; i < missing.length; i++) { + if (i !== 0) { + cell.appendChild(document.createTextNode(", ")); + } + link = jscoverage_createLink(file, missing[i]); + cell.appendChild(link); + } + row.appendChild(cell); + } + + tbody.appendChild(row); + + totals['files'] ++; + totals['statements'] += num_statements; + totals['executed'] += num_executed; + totals['coverage'] += percentage; + if( num_statements === 0 ) { + totals['skipped']++; + } + + // write totals data into summaryTotals row + var tr = document.getElementById("summaryTotals"); + if (tr) { + var tds = tr.getElementsByTagName("td"); + tds[0].getElementsByTagName("span")[1].firstChild.nodeValue = totals['files']; + tds[1].firstChild.nodeValue = totals['statements']; + tds[2].firstChild.nodeValue = totals['executed']; + + var coverage = parseInt(totals['coverage'] / ( totals['files'] - totals['skipped'] ) ); + if( isNaN( coverage ) ) { + coverage = 0; + } + tds[3].getElementsByTagName("span")[0].firstChild.nodeValue = coverage + '%'; + tds[3].getElementsByTagName("div")[1].style.width = coverage + 'px'; + } + + } + jscoverage_endLengthyOperation(); +} + +function jscoverage_appendMissingColumn() { + var headerRow = document.getElementById('headerRow'); + var missingHeader = document.createElement('th'); + missingHeader.id = 'missingHeader'; + missingHeader.innerHTML = 'Missing'; + headerRow.appendChild(missingHeader); + var summaryTotals = document.getElementById('summaryTotals'); + var empty = document.createElement('td'); + empty.id = 'missingCell'; + summaryTotals.appendChild(empty); +} + +function jscoverage_removeMissingColumn() { + var missingNode; + missingNode = document.getElementById('missingHeader'); + missingNode.parentNode.removeChild(missingNode); + missingNode = document.getElementById('missingCell'); + missingNode.parentNode.removeChild(missingNode); +} + +function jscoverage_checkbox_click() { + if (jscoverage_inLengthyOperation) { + return false; + } + jscoverage_beginLengthyOperation(); + var checkbox = document.getElementById('checkbox'); + var showMissingColumn = checkbox.checked; + setTimeout(function() { + if (showMissingColumn) { + jscoverage_appendMissingColumn(); + } + else { + jscoverage_removeMissingColumn(); + } + jscoverage_recalculateSummaryTab(); + }, 50); + return true; +} + +// ----------------------------------------------------------------------------- +// tab 3 + +function jscoverage_makeTable() { + var coverage = _$jscoverage[jscoverage_currentFile]; + var lines = coverage.source; + + // this can happen if there is an error in the original JavaScript file + if (! lines) { + lines = []; + } + + var rows = ['']; + var i = 0; + var progressBar = document.getElementById('progressBar'); + var tableHTML; + var currentConditionalEnd = 0; + + function joinTableRows() { + tableHTML = rows.join(''); + ProgressBar.setPercentage(progressBar, 60); + /* + This may be a long delay, so set a timeout of 100 ms to make sure the + display is updated. + */ + setTimeout(appendTable, 100); + } + + function appendTable() { + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.innerHTML = tableHTML; + ProgressBar.setPercentage(progressBar, 80); + setTimeout(jscoverage_scrollToLine, 0); + } + + while (i < lines.length) { + var lineNumber = i + 1; + + if (lineNumber === currentConditionalEnd) { + currentConditionalEnd = 0; + } + else if (currentConditionalEnd === 0 && coverage.conditionals && coverage.conditionals[lineNumber]) { + currentConditionalEnd = coverage.conditionals[lineNumber]; + } + + var row = ''; + row += ''; + var timesExecuted = coverage[lineNumber]; + if (timesExecuted !== undefined && timesExecuted !== null) { + if (currentConditionalEnd !== 0) { + row += ''; + } + else { + row += ''; + } + row += ''; + row += ''; + row += '\n'; + rows[lineNumber] = row; + i++; + } + rows[i + 1] = '
' + lineNumber + ''; + } + else if (timesExecuted === 0) { + row += ''; + } + else { + row += ''; + } + row += timesExecuted; + row += '
' + lines[i] + '
'; + ProgressBar.setPercentage(progressBar, 40); + setTimeout(joinTableRows, 0); +} + +function jscoverage_scrollToLine() { + jscoverage_selectTab('sourceTab'); + if (! window.jscoverage_currentLine) { + jscoverage_endLengthyOperation(); + return; + } + var div = document.getElementById('sourceDiv'); + if (jscoverage_currentLine === 1) { + div.scrollTop = 0; + } + else { + var cell = document.getElementById('line-' + jscoverage_currentLine); + + // this might not be there if there is an error in the original JavaScript + if (cell) { + var divOffset = jscoverage_findPos(div); + var cellOffset = jscoverage_findPos(cell); + div.scrollTop = cellOffset - divOffset; + } + } + jscoverage_currentLine = 0; + jscoverage_endLengthyOperation(); +} + +/** +Loads the given file (and optional line) in the source tab. +*/ +function jscoverage_get(file, line) { + if (jscoverage_inLengthyOperation) { + return; + } + jscoverage_beginLengthyOperation(); + setTimeout(function() { + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.innerHTML = ''; + jscoverage_selectTab('sourceTab'); + if (file === jscoverage_currentFile) { + jscoverage_currentLine = line; + jscoverage_recalculateSourceTab(); + } + else { + if (jscoverage_currentFile === null) { + var tab = document.getElementById('sourceTab'); + tab.className = ''; + tab.onclick = jscoverage_tab_click; + } + jscoverage_currentFile = file; + jscoverage_currentLine = line || 1; // when changing the source, always scroll to top + var fileDiv = document.getElementById('fileDiv'); + fileDiv.innerHTML = jscoverage_currentFile; + jscoverage_recalculateSourceTab(); + return; + } + }, 50); +} + +/** +Calculates coverage statistics for the current source file. +*/ +function jscoverage_recalculateSourceTab() { + if (! jscoverage_currentFile) { + jscoverage_endLengthyOperation(); + return; + } + var progressLabel = document.getElementById('progressLabel'); + progressLabel.innerHTML = 'Calculating coverage ...'; + var progressBar = document.getElementById('progressBar'); + ProgressBar.setPercentage(progressBar, 20); + setTimeout(jscoverage_makeTable, 0); +} + +// ----------------------------------------------------------------------------- +// tabs + +/** +Initializes the tab control. This function must be called when the document is +loaded. +*/ +function jscoverage_initTabControl() { + var tabs = document.getElementById('tabs'); + var i; + var child; + var tabNum = 0; + for (i = 0; i < tabs.childNodes.length; i++) { + child = tabs.childNodes.item(i); + if (child.nodeType === 1) { + if (child.className !== 'disabled') { + child.onclick = jscoverage_tab_click; + } + tabNum++; + } + } + jscoverage_selectTab(0); +} + +/** +Selects a tab. +@param tab the integer index of the tab (0, 1, 2, or 3) + OR + the ID of the tab element + OR + the tab element itself +*/ +function jscoverage_selectTab(tab) { + if (typeof tab !== 'number') { + tab = jscoverage_tabIndexOf(tab); + } + var tabs = document.getElementById('tabs'); + var tabPages = document.getElementById('tabPages'); + var nodeList; + var tabNum; + var i; + var node; + + nodeList = tabs.childNodes; + tabNum = 0; + for (i = 0; i < nodeList.length; i++) { + node = nodeList.item(i); + if (node.nodeType !== 1) { + continue; + } + + if (node.className !== 'disabled') { + if (tabNum === tab) { + node.className = 'selected'; + } + else { + node.className = ''; + } + } + tabNum++; + } + + nodeList = tabPages.childNodes; + tabNum = 0; + for (i = 0; i < nodeList.length; i++) { + node = nodeList.item(i); + if (node.nodeType !== 1) { + continue; + } + + if (tabNum === tab) { + node.className = 'selected TabPage'; + } + else { + node.className = 'TabPage'; + } + tabNum++; + } +} + +/** +Returns an integer (0, 1, 2, or 3) representing the index of a given tab. +@param tab the ID of the tab element + OR + the tab element itself +*/ +function jscoverage_tabIndexOf(tab) { + if (typeof tab === 'string') { + tab = document.getElementById(tab); + } + var tabs = document.getElementById('tabs'); + var i; + var child; + var tabNum = 0; + for (i = 0; i < tabs.childNodes.length; i++) { + child = tabs.childNodes.item(i); + if (child.nodeType === 1) { + if (child === tab) { + return tabNum; + } + tabNum++; + } + } +//#JSCOVERAGE_IF 0 + throw "Tab not found"; +//#JSCOVERAGE_ENDIF +} + +function jscoverage_tab_click(e) { + if (jscoverage_inLengthyOperation) { + return; + } + var target; +//#JSCOVERAGE_IF + if (e) { + target = e.target; + } + else if (window.event) { + // IE + target = window.event.srcElement; + } + if (target.className === 'selected') { + return; + } + jscoverage_beginLengthyOperation(); + setTimeout(function() { + if (target.id === 'summaryTab') { + var tbody = document.getElementById("summaryTbody"); + while (tbody.hasChildNodes()) { + tbody.removeChild(tbody.firstChild); + } + } + else if (target.id === 'sourceTab') { + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.innerHTML = ''; + } + jscoverage_selectTab(target); + if (target.id === 'summaryTab') { + jscoverage_recalculateSummaryTab(); + } + else if (target.id === 'sourceTab') { + jscoverage_recalculateSourceTab(); + } + else { + jscoverage_endLengthyOperation(); + } + }, 50); +} + +// ----------------------------------------------------------------------------- +// progress bar + +var ProgressBar = { + init: function(element) { + element._percentage = 0; + + /* doing this via JavaScript crashes Safari */ +/* + var pctGraph = document.createElement('div'); + pctGraph.className = 'pctGraph'; + element.appendChild(pctGraph); + var covered = document.createElement('div'); + covered.className = 'covered'; + pctGraph.appendChild(covered); + var pct = document.createElement('span'); + pct.className = 'pct'; + element.appendChild(pct); +*/ + + ProgressBar._update(element); + }, + setPercentage: function(element, percentage) { + element._percentage = percentage; + ProgressBar._update(element); + }, + _update: function(element) { + var pctGraph = element.getElementsByTagName('div').item(0); + var covered = pctGraph.getElementsByTagName('div').item(0); + var pct = element.getElementsByTagName('span').item(0); + pct.innerHTML = element._percentage.toString() + '%'; + covered.style.width = element._percentage + 'px'; + } +}; + +// ----------------------------------------------------------------------------- +// reports + +function jscoverage_pad(s) { + return '0000'.substr(s.length) + s; +} + +function jscoverage_quote(s) { + return '"' + s.replace(/[\u0000-\u001f"\\\u007f-\uffff]/g, function (c) { + switch (c) { + case '\b': + return '\\b'; + case '\f': + return '\\f'; + case '\n': + return '\\n'; + case '\r': + return '\\r'; + case '\t': + return '\\t'; + // IE doesn't support this + /* + case '\v': + return '\\v'; + */ + case '"': + return '\\"'; + case '\\': + return '\\\\'; + default: + return '\\u' + jscoverage_pad(c.charCodeAt(0).toString(16)); + } + }) + '"'; +} + +function jscoverage_serializeCoverageToJSON() { + var json = []; + for (var file in _$jscoverage) { + var coverage = _$jscoverage[file]; + var array = []; + var length = coverage.length; + for (var line = 0; line < length; line++) { + var value = coverage[line]; + if (value === undefined || value === null) { + value = 'null'; + } + array.push(value); + } + json.push(jscoverage_quote(file) + ':[' + array.join(',') + ']'); + } + return '{' + json.join(',') + '}'; +} + +function jscoverage_storeButton_click() { + if (jscoverage_inLengthyOperation) { + return; + } + + jscoverage_beginLengthyOperation(); + var img = document.getElementById('storeImg'); + img.style.visibility = 'visible'; + + var request = jscoverage_createRequest(); + request.open('POST', '/jscoverage-store', true); + request.onreadystatechange = function (event) { + if (request.readyState === 4) { + var message; + try { + if (request.status !== 200 && request.status !== 201 && request.status !== 204) { + throw request.status; + } + message = request.responseText; + } + catch (e) { + if (e.toString().search(/^\d{3}$/) === 0) { + message = e + ': ' + request.responseText; + } + else { + message = 'Could not connect to server: ' + e; + } + } + + jscoverage_endLengthyOperation(); + var img = document.getElementById('storeImg'); + img.style.visibility = 'hidden'; + + var div = document.getElementById('storeDiv'); + div.appendChild(document.createTextNode(new Date() + ': ' + message)); + div.appendChild(document.createElement('br')); + } + }; + request.setRequestHeader('Content-Type', 'application/json'); + var json = jscoverage_serializeCoverageToJSON(); + request.setRequestHeader('Content-Length', json.length.toString()); + request.send(json); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/script.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/script.js new file mode 100644 index 0000000..ac233a2 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/instrumented/script.js @@ -0,0 +1,65 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['script.js']) { + _$jscoverage['script.js'] = []; + _$jscoverage['script.js'][1] = 0; + _$jscoverage['script.js'][2] = 0; + _$jscoverage['script.js'][3] = 0; + _$jscoverage['script.js'][4] = 0; + _$jscoverage['script.js'][6] = 0; + _$jscoverage['script.js'][7] = 0; + _$jscoverage['script.js'][9] = 0; + _$jscoverage['script.js'][10] = 0; + _$jscoverage['script.js'][12] = 0; + _$jscoverage['script.js'][13] = 0; + _$jscoverage['script.js'][15] = 0; + _$jscoverage['script.js'][16] = 0; + _$jscoverage['script.js'][17] = 0; + _$jscoverage['script.js'][18] = 0; + _$jscoverage['script.js'][19] = 0; +} +_$jscoverage['script.js'][1]++; +function go(element) { + _$jscoverage['script.js'][2]++; + var message; + _$jscoverage['script.js'][3]++; + if (element.id === "radio1") { + _$jscoverage['script.js'][4]++; + message = "You selected the number 1."; + } + else { + _$jscoverage['script.js'][6]++; + if (element.id === "radio2") { + _$jscoverage['script.js'][7]++; + message = "You selected the number 2."; + } + else { + _$jscoverage['script.js'][9]++; + if (element.id === "radio3") { + _$jscoverage['script.js'][10]++; + message = "You selected the number 3."; + } + else { + _$jscoverage['script.js'][12]++; + if (element.id === "radio4") { + _$jscoverage['script.js'][13]++; + message = "You selected the number 4."; + } + } + } + } + _$jscoverage['script.js'][15]++; + var div = document.getElementById("request"); + _$jscoverage['script.js'][16]++; + div.className = "black"; + _$jscoverage['script.js'][17]++; + div = document.getElementById("result"); + _$jscoverage['script.js'][18]++; + div.innerHTML = "

" + message + "

"; + _$jscoverage['script.js'][19]++; + div.innerHTML += "

If you are running the instrumented version of this program, you can click the \"Summary\" tab to view a coverage report.

"; +} +_$jscoverage['script.js'].source = ["function go(element) {"," var message;"," if (element.id === 'radio1') {"," message = 'You selected the number 1.';"," }"," else if (element.id === 'radio2') {"," message = 'You selected the number 2.';"," }"," else if (element.id === 'radio3') {"," message = 'You selected the number 3.';"," }"," else if (element.id === 'radio4') {"," message = 'You selected the number 4.';"," }"," var div = document.getElementById('request');"," div.className = 'black';"," div = document.getElementById('result');"," div.innerHTML = '<p>' + message + '</p>';"," div.innerHTML += '<p>If you are running the instrumented version of this program, you can click the \"Summary\" tab to view a coverage report.</p>';","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/license.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/license.html new file mode 100644 index 0000000..0acc7a3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/license.html @@ -0,0 +1,382 @@ + + + +JSCoverage - license + + + + +
+

JSCoverage
code coverage for JavaScript

+
+
+
+

License

+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
+
+
+
+
+ +
+
+
+
+ Copyright © 2007, 2008 Silicon Forks siliconforks.com
+ jscoverage@siliconforks.com +
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/links.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/links.html new file mode 100644 index 0000000..df6d793 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/links.html @@ -0,0 +1,59 @@ + + + +JSCoverage - links + + + + +
+

JSCoverage
code coverage for JavaScript

+
+
+
+

Links

+

+ The design of JSCoverage has been influenced by other code coverage tools: +

+
+
gcov +
Code coverage for C/C++. +
Cobertura +
Code coverage for Java. +
coverage.py +
Code coverage for Python. +
+

+ The implementation of JSCoverage includes the following libraries: +

+
+
Mozilla SpiderMonkey +
JSCoverage uses Mozilla's JavaScript implementation to parse JavaScript. +
+
+
+
+ +
+
+
+
+ Copyright © 2007, 2008 Silicon Forks siliconforks.com
+ jscoverage@siliconforks.com +
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/manual.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/manual.html new file mode 100644 index 0000000..61d8e9e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/manual.html @@ -0,0 +1,701 @@ + + + +JSCoverage user manual + + + + + + + + +

JSCoverage user manual

+ +

+JSCoverage is a tool that measures code coverage for JavaScript programs. +

+ +

+JSCoverage works by adding instrumentation to JavaScript code before it is +executed in a web browser. JSCoverage provides several alternative ways of doing +this: +

+ +
    +
  • The simplest method is to use the jscoverage program to generate +instrumented JavaScript files. +
  • +
  • Alternatively, you can use the jscoverage-server program, a simple web server that instruments +JavaScript code as it is served. +
  • +
  • Finally, jscoverage-server can be run with the --proxy option to +act as a proxy server which instruments any JavaScript code proxied through it. +
  • +
+ +

+The jscoverage-server program (with or without the --proxy +option) has the advantage of being able to store coverage reports to the filesystem. +

+ +

Compiling JSCoverage

+ +

+You can compile JSCoverage on GNU/Linux or Microsoft Windows, using the GCC C++ compiler (g++). On +Windows you will require Cygwin or MinGW/MSYS. +

+ +

+You can extract and compile the code with the following commands: +

+ +
+tar jxvf jscoverage-0.4.tar.bz2
+cd jscoverage-0.4/
+./configure
+make
+
+ +

+This will create the jscoverage and jscoverage-server +executables (jscoverage.exe and jscoverage-server.exe +on Windows). You can install the executables in /usr/local with the +command: +

+ +
+make install
+
+ +

+Alternatively, you may simply copy the jscoverage executable and/or +the jscoverage-server executable to a suitable location in your +PATH. +

+ +

Using the jscoverage program

+ +

+To demonstrate how the jscoverage program works, we will use the +trivial example JavaScript code located in the +doc/example/ directory of the JSCoverage distribution. You can run +this example by viewing the file doc/example/index.html in your web browser. +

+ +

+Generating code coverage statistics for this example using the +jscoverage program involves the following steps: +

+ +

1. Instrumenting code

+ +

+The first step is to add instrumentation to your JavaScript code. You do this by +executing jscoverage with two arguments: +

+ +
+jscoverage SOURCE-DIRECTORY DESTINATION-DIRECTORY
+
+ +

+SOURCE-DIRECTORY is the directory containing the JavaScript code to be instrumented, +and DESTINATION-DIRECTORY is the name of the +directory to which jscoverage should output the instrumented code. +The jscoverage program will create DESTINATION-DIRECTORY if necessary and (recursively) copy +SOURCE-DIRECTORY to DESTINATION-DIRECTORY, instrumenting +any files ending with a .js extension. +

+ +

+The directory structure under SOURCE-DIRECTORY is preserved, so that if you have a file +SOURCE-DIRECTORY/dir/index.html referencing the script +SOURCE-DIRECTORY/dir/script.js, then +jscoverage will create a copy of the HTML file at +DESTINATION-DIRECTORY/dir/index.html and an instrumented +version of the script at +DESTINATION-DIRECTORY/dir/script.js. +In addition, jscoverage creates a file called jscoverage.html +which is used to execute the instrumented code. +

+ + + + + + + +
+SOURCE-DIRECTORY/
+  dir/
+    index.html
+    script.js
+
+
+DESTINATION-DIRECTORY/
+  dir/
+    index.html
+    script.js [instrumented]
+  jscoverage.html
+
+ +

+For the example code in the doc/example/ directory, you can execute the +following command line from the top-level directory of the JSCoverage distribution: +

+ +
+jscoverage doc/example doc/instrumented
+
+ +

+This will create the directory doc/instrumented/ and place an +instrumented copy of the code from doc/example/ in +doc/instrumented/. +

+ + + + + + + +
+doc/example/
+  index.html
+  script.js
+
+
+doc/instrumented/
+  index.html
+  script.js [instrumented]
+  jscoverage.html
+
+ +

2. Executing the instrumented code in a web browser

+ +

+Open the generated jscoverage.html file +(doc/instrumented/jscoverage.html) in your web browser. +The page contains a tabbed user interface: +

+ +
    +
  • The "Browser" tab is used to display pages with instrumented scripts. +
  • The "Summary" tab is used to display code coverage data. +
  • The "Source" tab is used to display JavaScript code, showing the number of times +each line of code was executed. +
  • The "About" tab displays information about the current version of JSCoverage. +
+ +

Screenshot

+ +

+The "Browser" tab contains an <iframe>, which is initially empty. +You can load a page into this frame by +entering its URL into the "URL" input field. +You can load any page located in DESTINATION-DIRECTORY/ +or a subdirectory underneath DESTINATION-DIRECTORY/; loading a page +from outside DESTINATION-DIRECTORY/, or from a foreign web +server, will give unexpected results. +

+ +

+For example, you can load the file doc/instrumented/index.html by typing +index.html in the "URL" input field (relative URLs are acceptable). +

+ +

+Alternatively, you can load a page into the <iframe> by +appending the page URL to the query string of the jscoverage.html URL. +For example, appending ?index.html to the jscoverage.html URL +will cause the index.html file to be loaded automatically. +

+ +

Screenshot

+ +

+For this example, the JavaScript does not execute automatically: +you have to select one of the radio buttons to execute the code. +

+ +

Screenshot

+ +

3. Generating a coverage report

+ +

+Once the JavaScript code in the page in the "Browser" tab has been executed, click on +the "Summary" tab. This will display the current code coverage statistics. +

+ +

Screenshot

+ +

+You can click the checkbox to show a list of statements missed during execution. +

+ +

Screenshot

+ +

+You can click one of the links to get a detailed view of a JavaScript source file. +

+ +

Screenshot

+ +

+As long as you do not reload the +jscoverage.html page, the coverage report statistics are +cumulative. If you execute more JavaScript in the frame in the "Browser" tab (e.g., by clicking on a link to +another scripted page, or by reloading the frame containing a scripted +page) and switch to the "Summary" tab again, +the coverage report will combine the statistics from the previous report with any newly generated statistics. +Reloading jscoverage.html resets all code coverage statistics to zero. +

+ +

Inverted mode

+ +

+In some situations it may be difficult to execute your code within the +JSCoverage "Browser" tab. For example, the code may assume that it is running in +the top-level browser window, generating errors if it is executed from within a +frame. JSCoverage has an alternative mode of operation, called inverted +mode, which may be useful in this case. +

+ +

+Normally you load jscoverage.html in your web browser, and in its +"Browser" tab you launch your test code. In inverted mode, you do the +opposite: you load your test page directly in your web browser, and from there +you launch JSCoverage. To do this you need to add some code to your test page: +

+ +
+window.open('path/to/jscoverage.html');
+
+ +

+The "path/to/jscoverage.html" should be a URL pointing to the +location of the jscoverage.html file (remember, this will be in the +top level of the DESTINATION-DIRECTORY you specified when running +the jscoverage executable). +

+ +

+You can place this code wherever you like in your page: for example, you could +attach it to a button: +

+ +
+<button onclick="window.open('path/to/jscoverage.html');">Coverage report</button>
+
+ +

+Note that you must use a window.open call; simply making a +link to jscoverage.html is not sufficient. +

+ +

+An example is located in the doc/example-inverted directory. +You can instrument the code with the jscoverage program: +

+ +
+jscoverage doc/example-inverted doc/instrumented-inverted
+
+ +

+You can load the page doc/instrumented-inverted/index.html +directly in your web browser. +From this page, you select one of the radio buttons and then click the "Coverage +report" button to launch the JSCoverage report. +

+ +

+Another example is located in the doc/example-jsunit directory. +See the FAQ for more information. +

+ +

jscoverage command line options

+ +

+The jscoverage program accepts the following options: +

+ +
+
-h, --help +
Display a brief help message. +
-V, --version +
Display the version of the program. +
-v, --verbose +
Explain what is being done. +
--encoding=ENCODING +
Assume that all JavaScript files use the given character encoding. The +default is ISO-8859-1. +
--exclude=PATH +
The command +
+jscoverage --exclude=PATH SOURCE-DIRECTORY DESTINATION-DIRECTORY
+
+copies SOURCE-DIRECTORY to DESTINATION-DIRECTORY +recursively, but does not copy SOURCE-DIRECTORY/PATH. +PATH must be a complete path relative to SOURCE-DIRECTORY. +PATH can be a file or a directory (in which case the directory and +its entire contents are skipped). This option may be given multiple times. +
--js-version=VERSION +
Use the specified JavaScript version; valid values for VERSION +are 1.0, 1.1, 1.2, ..., 1.8, +or ECMAv3 (the default). +
--no-highlight +
Do not perform syntax highlighting of JavaScript code. +
--no-instrument=PATH +
The command +
+jscoverage --no-instrument=PATH SOURCE-DIRECTORY DESTINATION-DIRECTORY
+
+copies SOURCE-DIRECTORY to DESTINATION-DIRECTORY +recursively, but does not instrument any JavaScript code in +SOURCE-DIRECTORY/PATH. PATH must be a complete +path relative to SOURCE-DIRECTORY. PATH can be a +(JavaScript) file or a directory (in which case any JavaScript files located +anywhere underneath the directory are not instrumented). This option may be +given multiple times. +
+ +

Query string options

+ +

+When accessing jscoverage.html in a web browser, you may provide a +query string consisting of options separated by ampersand (&) +or semicolon (;). Any option not containing an equals sign +(=) is considered to be a URL which will be loaded in the "Browser" +tab. +

+ +
+
u=URL, url=URL +
Load URL in the "Browser" tab. (This is the same as specifying +an option without an equals sign.) +
m=BOOLEAN, missing=BOOLEAN +
Determines whether to initially display the "Missing" column in the "Summary" +tab. BOOLEAN can be +true, t, yes, y, on, 1 +(to display the "Missing" column), or +false, f, no, n, off, 0 +(to hide the "Missing" column). By default, the "Missing" column is not displayed. +
+ +

Using the jscoverage-server program

+ +

+The jscoverage-server program is a simple web server. You can use +jscoverage-server to serve files from the doc/example/ +directory: +

+ +
+  cd doc/example
+  jscoverage-server --verbose
+
+ +

+Once the server is running, you can access the JSCoverage web interface by +visiting the URL http://127.0.0.1:8080/jscoverage.html, and you can +load the doc/example/index.html file by entering +index.html in the "URL" input field. (Or you can do this all in +one step by loading the URL +http://127.0.0.1:8080/jscoverage.html?index.html in your web +browser.) The +jscoverage-server program automatically instruments any served +JavaScript code, so that code coverage data will be gathered as the code is +executed in your browser. +

+ +

+The web interface is slightly different from that generated by the +jscoverage program: it has a new tab named "Store". +To store coverage data, click the "Store" tab. +

+ +

Screenshot

+ +

+When you click the "Store Report" button, the coverage data will be saved to a directory named jscoverage-report/. +You can view this stored report at any time by opening the file jscoverage-report/jscoverage.html in +your web browser - you don't need the jscoverage-server running to access it. +

+ +

+If you use the "Store" tab again to store coverage data, the new data will be merged with +the previous data in the jscoverage-report/ directory. This can be useful, +for instance, if you wish to run a set of tests in different browsers and generate an +aggregate report which combines the data for all of them. +

+ +

+You can stop the server by running another instance of jscoverage-server with the +--shutdown option: +

+ +
+  jscoverage-server --shutdown
+
+ +

Using jscoverage-server --proxy

+ +

+To use jscoverage-server as a proxy server, use the --proxy option: +

+ +
+  jscoverage-server --verbose --proxy
+
+ +

+Configure your browser to use an HTTP proxy with address 127.0.0.1 and port 8080. +You can then generate code coverage data for a web page on the server example.com +by accessing the JSCoverage web interface at the special URL http://example.com/jscoverage.html. +Note that this URL is not provided by the example.com server; it is automatically generated +by the proxy server whenever a URL with path /jscoverage.html is requested. +

+ +

jscoverage-server command line options

+ +
+
-h, --help +
Display a brief help message. +
-V, --version +
Display the version of the program. +
-v, --verbose +
Explain what is being done. +
--document-root=PATH +
Serve web content from the directory given by PATH. The default is +the current directory. This option may not be given with the --proxy option. +
--encoding=ENCODING +
Assume that all JavaScript files use the given character encoding. The +default is ISO-8859-1. Note that if you use the --proxy option, the +character encoding will be determined from the charset parameter in +the Content-Type HTTP header. +
--ip-address=ADDRESS +
Run the server on the IP address given by ADDRESS. The default is 127.0.0.1. Specify +0.0.0.0 to use any address. +
--js-version=VERSION +
Use the specified JavaScript version; valid values for VERSION +are 1.0, 1.1, 1.2, ..., 1.8, +or ECMAv3 (the default). +
--no-highlight +
Do not perform syntax highlighting of JavaScript code. +
--no-instrument=URL +
Do not instrument JavaScript code from URL. If you are running jscoverage-server +with the --proxy option, URL should be a full URL. For example: +
+jscoverage-server --proxy --no-instrument=http://example.com/scripts/
+
+Without --proxy, URL should be only the path portion of a URL: +
+jscoverage-server --no-instrument=/scripts/
+
+This option may be given multiple times. +
--port=PORT +
Run the server on the port given by PORT. The default is port 8080. +
--proxy +
Run as a proxy server. +
--report-dir=PATH +
Use the directory given by PATH for storing coverage reports. The default is +jscoverage-report/ in the current directory. +
--shutdown +
Stop a running instance of the server. +
+ +

Advanced topics

+ +

Storing coverage reports programmatically

+ +

+If you are executing a test suite using jscoverage-server, you can +store a coverage report programmatically by having your test suite call the +jscoverage_report function (automatically generated by +jscoverage-server) after all your tests have finished running: +

+ +
+if (window.jscoverage_report) {
+  jscoverage_report();
+}
+
+ +

+You can specify the name of the directory in which to store the report by +passing the name as a parameter to the jscoverage_report function: +

+ +
+if (window.jscoverage_report) {
+  // determine the directory name based on the browser
+  var directory;
+  if (/MSIE/.test(navigator.userAgent)) {
+    directory = 'IE';
+  }
+  else {
+    directory = 'other';
+  }
+  jscoverage_report(directory);
+}
+
+ +

+This directory will be a subdirectory under the jscoverage-report/ +directory (or whatever is specified with the --report-dir option). +Using the above example, the report would be stored to either +jscoverage-report/IE/ or jscoverage-report/other/. +

+ +

+It is not necessary that your test suite be executed within the +jscoverage.html web interface to store a coverage report. The URL +of the test suite can simply be loaded directly in a web browser. +

+ +

+The example in doc/example-jsunit/ demonstrates storing coverage +reports programmatically. +

+ +

Ignoring certain lines of code

+ +

+Sometimes you may wish to exclude certain lines of code from coverage +statistics. Some lines of code may be executed only in certain browsers; other +lines should never be executed at all (they may be present only to detect +programming errors). You can use specially formatted comments in your code to +tell JSCoverage to ignore certain lines of code. These lines will not be +included in the JSCoverage "Summary" tab; in the "Source" tab, these lines will +be indicated with the color yellow. +

+ +

+These comments take the following form: +

+ +
+//#JSCOVERAGE_IF CONDITION
+...
+//#JSCOVERAGE_ENDIF
+
+ +

+The comment must be formatted exactly as shown: it must be a line comment +starting with //, it must start in the first column, and it must be +followed by #JSCOVERAGE_IF or #JSCOVERAGE_ENDIF in +uppercase letters with no intervening white space. +

+ +

+The CONDITION is an ordinary JavaScript expression; if this +expression evaluates to true, then the lines of code between the +//#JSCOVERAGE_IF and //#JSCOVERAGE_ENDIF comments are +included in coverage statistics; otherwise, they are excluded from coverage +statistics. +

+ +

+For example: +

+ +
+function log(s) {
+  if (window.console) {
+//#JSCOVERAGE_IF window.console
+    console.log(s);
+//#JSCOVERAGE_ENDIF
+  }
+}
+
+ +

+You can exclude code from coverage statistics unconditionally by using +#JSCOVERAGE_IF 0 or #JSCOVERAGE_IF false: +

+ +
+function f(x) {
+  if (x === null) {
+//#JSCOVERAGE_IF 0
+    throw 'error';
+//#JSCOVERAGE_ENDIF
+  }
+  ...
+
+ +

+There is also a short form, which must appear on the line preceding an +if statement: +

+ +
+//#JSCOVERAGE_IF
+if (...) {
+  ...
+}
+else if (...) {
+  ...
+}
+...
+else {
+  ...
+}
+
+ +

+ +In this form, there is no condition on the //#JSCOVERAGE_IF line +and no //#JSCOVERAGE_ENDIF. You use this form to tell JSCoverage +that you expect only one branch of the if statement to be executed; +coverage statistics will not be collected for the other branch(es). For +example: +

+ +
+function log(s) {
+//#JSCOVERAGE_IF
+  if (window.console) {
+    console.log(s);
+  }
+  else if (window.opera) {
+    opera.postError(s);
+  }
+  else {
+    throw 'no logging function available';
+  }
+}
+
+ +

+Currently, //#JSCOVERAGE_IF comments are not recorded in stored coverage reports. +

+ +

Caveats

+ +
    +
  • JSCoverage adds instrumentation to JavaScript code, which will slow down execution speed. +Expect instrumented code to take at least twice as much time to run. +
  • JSCoverage currently instruments only .js files; it does not instrument code in <script> +elements in HTML files. +
  • HTML files must use relative URLs to reference scripts. If you use an absolute URL, your page will reference +the original uninstrumented script rather than the instrumented one, and no code coverage data will be collected. +
  • JSCoverage instruments physical lines of code rather than logical JavaScript statements; it works bests with code +that has exactly one statement per line. If you put multiple statements on a line, or split a line across two or more +statements, you may get strange results. +
  • JSCoverage uses frames. Some web pages that use frames may not function properly when run under JSCoverage, especially +those which try to access the top-level frame (window.top, target="_top", etc.). +
  • JSCoverage is distributed without any warranty. See the license for more details. +
+ +
+ Copyright © 2007, 2008 Silicon Forks siliconforks.com
+ jscoverage@siliconforks.com +
+ + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/news.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/news.html new file mode 100644 index 0000000..c51450f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/news.html @@ -0,0 +1,214 @@ + + + +JSCoverage - news + + + + + +
+

JSCoverage
code coverage for JavaScript

+
+
+
+

News RSS feed

+ +

December 11, 2008 - JSCoverage 0.4

+

+ JSCoverage 0.4 is available for download. +

+

+ This release includes many new features: +

+
    +
  • + The new jscoverage-server program is provided as an + alternative to the jscoverage program. The + jscoverage-server program is a simple HTTP server which + instruments JavaScript code as it is served; this allows you to execute + JavaScript and gather code coverage statistics without a preliminary + step of creating instrumented code. The jscoverage-server + program can either serve files directly from the filesystem or run as a + proxy server (with the --proxy option), instrumenting + JavaScript provided by another web server. +
  • + Using jscoverage-server, coverage reports can now be stored + to the filesystem. +
  • +
  • + JSCoverage now recognizes special JavaScript comments which specify that + certain lines of code should be ignored in coverage reports. +
  • +
  • + The new --encoding option provides better support for + different character encodings. +
  • +
  • + The JSCoverage user interface is now faster and more responsive. +
  • +
  • + The new --no-highlight option can be used to disable syntax + highlighting (giving better performance for large JavaScript files). +
  • +
  • + The build system has been modified so that make install + only installs the jscoverage and + jscoverage-server executables and their manual pages. + (Previous versions installed SpiderMonkey library and executable files, + which could conflict with other versions of SpiderMonkey installed on + your system.) +
  • +
  • + JSCoverage now supports several features beyond those found in the + ECMAScript Language Specification, including the following: +
      +
    • getters and setters +
    • for each loops +
    • generators and iterators +
    • the let keyword +
    • destructuring assignment +
    • array comprehensions +
    • expression closures +
    • generator expressions +
    + Use the new --js-version option to enable these features. +
  • +
+

+ The GCC C++ compiler (g++) is now required to compile + JSCoverage. (Previously, only the C compiler was needed.) +

+

+ Please report any bugs you find using the new bug tracker. +

+ +

March 31, 2008 - JSCoverage and Firefox 3

+

+ The JSCoverage FAQ has been updated to address problems using JSCoverage with Firefox 3. +

+ +

March 24, 2008 - JSCoverage in Debian GNU/Linux

+

+ JSCoverage is now available in the Debian unstable distribution. +

+ +

November 22, 2007 - JSCoverage 0.3.1

+

+ JSCoverage 0.3.1 is available for download. +

+

+ This release has a number of bug fixes: +

+
    +
  • + It should now be possible to run the native Windows version of jscoverage + with minimal privileges. +
  • +
  • + All files used by JSCoverage now use a jscoverage + prefix to avoid name collisions. +
  • +
  • + Compilation bugs which occurred under some versions of MSYS have been fixed. +
  • +
  • + Various documentation improvements. +
  • +
+ +

August 26, 2007 - JSCoverage 0.3

+

+ JSCoverage 0.3 is available for download. +

+

+ This release has the following new features: +

+
    +
  • + The coverage summary now displays bar graphs (thanks to Ross Simpson). +
  • +
  • + A progress bar is displayed for lengthy computations. +
  • +
  • + JavaScript syntax highlighting has improved. +
  • +
  • + The display of missed statements can be turned on and off. +
  • +
  • + New "inverted mode" provides better support for working with JsUnit. +
  • +
+ +

August 23, 2007 - JSCoverage in Linux Format magazine

+

+ JSCoverage is in the October 2007 issue of Linux Format magazine + (table of contents). +

+ +

July 31, 2007 - Subversion repository now available

+

+ See the download page for instructions on accessing the Subversion repository. +

+ +

July 8, 2007 - JSCoverage 0.2

+

+ JSCoverage 0.2 is available for download. +

+

+ JSCoverage 0.2 features a new tabbed user interface. +

+ +

July 1, 2007 - JSCoverage 0.1.1

+

+ JSCoverage 0.1.1 is available for download. +

+

+ JSCoverage 0.1.1 fixes a bug that can cause large JavaScript files to be truncated when viewed with Opera. +

+ +

June 15, 2007 - documentation of JSCoverage internals

+

+ A new document, + Parsing JavaScript with SpiderMonkey, + describes the technique used by JSCoverage to parse JavaScript programs. +

+ +

May 30, 2007 - new examples

+

+ Added some examples of running JSCoverage on popular JavaScript libraries. +

+ +

May 26, 2007 - JSCoverage 0.1

+

+ JSCoverage 0.1 is available for download. +

+
+
+
+ +
+
+
+
+ Copyright © 2007, 2008 Silicon Forks siliconforks.com
+ jscoverage@siliconforks.com +
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/reset-fonts-grids.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/reset-fonts-grids.css new file mode 100644 index 0000000..b3e042c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/reset-fonts-grids.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}del,ins{text-decoration:none;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}body{text-align:center;}#ft{clear:both;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;min-width:750px;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main,.yui-g .yui-u .yui-g{width:100%;}{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g .yui-u{width:48.1%;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;} .yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#bd:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#bd,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;} \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot.png b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..e523c8a91c2240a4bacb6c0c1bb56f8662368183 GIT binary patch literal 19071 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 Ut*%0hb2APxIDA4s{U9pj@4d-r0ssI2 literal 0 HcmV?d00001 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot3.png b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..d63c8620c7fc822b09cf19df554f4a24c59367d3 GIT binary patch literal 22690 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 Hpb~xorH`Hq literal 0 HcmV?d00001 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot5.png b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot5.png new file mode 100644 index 0000000000000000000000000000000000000000..ffbfabe470e3174a354b78ff2b3d7b3130d981a7 GIT binary patch literal 20738 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 v;ozp1UEt@iik0f}2N<; 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 ZGDP|)gzM$!9L!vRf}HB(!be8_{|{TlVdMY+ literal 0 HcmV?d00001 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot7.png b/bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/screenshot7.png new file mode 100644 index 0000000000000000000000000000000000000000..2d5120228e100e684a329c91ea94b81017aea9fb GIT binary patch literal 18924 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/g,"sh_keyword",-1],[/<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)/g,"sh_keyword",6,1],[/&(?:[A-Za-z0-9]+);/g,"sh_preproc",-1],[/<(?:\/)?[A-Za-z][A-Za-z0-9]*(?:\/)?>/g,"sh_keyword",-1],[/<(?:\/)?[A-Za-z][A-Za-z0-9]*/g,"sh_keyword",8,1]],[[/\?>/g,"sh_preproc",-2],[/([^=" \t>]+)([ \t]*)(=?)/g,["sh_type","sh_normal","sh_symbol"],-1],[/"/g,"sh_string",2]],[[/\\(?:\\|")/g,null,-1],[/"/g,"sh_string",-2]],[[/>/g,"sh_preproc",-2],[/([^=" \t>]+)([ \t]*)(=?)/g,["sh_type","sh_normal","sh_symbol"],-1],[/"/g,"sh_string",4]],[[/\\(?:\\|")/g,null,-1],[/"/g,"sh_string",-2]],[[/-->/g,"sh_comment",-2],[//g,"sh_comment",-2],[//g,"sh_comment",-2],[/ + + + + + + SpiderMonkey README + + + +

SpiderMonkey README

+ +

See the +SpiderMonkey +pages on the Mozilla Developer Center. + + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/SpiderMonkey.rsp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/SpiderMonkey.rsp new file mode 100644 index 0000000..fc162d9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/SpiderMonkey.rsp @@ -0,0 +1,11 @@ +mozilla/js/src/* +mozilla/js/src/config/* +mozilla/js/src/liveconnect/* +mozilla/js/src/liveconnect/_jni/* +mozilla/js/src/liveconnect/classes/* +mozilla/js/src/liveconnect/classes/netscape/* +mozilla/js/src/liveconnect/classes/netscape/javascript/* +mozilla/js/src/liveconnect/config/* +mozilla/js/src/liveconnect/macbuild/* +mozilla/js/src/liveconnect/macbuild/JavaSession/* +mozilla/js/src/macbuild/* diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/aclocal.m4 b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/aclocal.m4 new file mode 100644 index 0000000..538065c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/aclocal.m4 @@ -0,0 +1,9 @@ +dnl +dnl Local autoconf macros used with mozilla +dnl The contents of this file are under the Public Domain. +dnl + +builtin(include, build/autoconf/pkg.m4)dnl +builtin(include, build/autoconf/nspr.m4)dnl +builtin(include, build/autoconf/altoptions.m4)dnl + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/bench.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/bench.sh new file mode 100755 index 0000000..8b7fe75 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/bench.sh @@ -0,0 +1,5 @@ +#!/bin/bash +X="var d = Date.now();"; +for i in t/*.js; do X="$X load(\"$i\");"; done +X="$X print(Date.now() - d);" +echo $X | (./Darwin_OPT.OBJ/js -j || ./Linux_All_OPT.OBJ/js -j) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/builtins.tbl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/builtins.tbl new file mode 100644 index 0000000..a725d97 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/builtins.tbl @@ -0,0 +1,98 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=0 ft=C: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 22, 2008. + * + * The Initial Developer of the Original Code is + * Andreas Gal + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * This file declares builtin functions that can be called from JITted code. + * Each line starts with "BUILTIN" and an integer, the number of arguments the + * builtin takes. Builtins with no arguments are not supported. + * + * The macro arguments are: + * + * - 'extern' to indicate extern linkage for these functions and the associated + * CallInfo. + * + * - The return type. This identifier must name one of the _JS_TYPEINFO_* + * macros defined in jsbuiltins.h. + * + * - The builtin name. Prefixed with "js_" this gives the native function name. + * + * - The parameter types. + * + * - The cse flag. 1 if the builtin call can be optimized away by common + * subexpression elimination; otherwise 0. This should be 1 only if the + * function is idempotent and the return value is determined solely by the + * arguments. + * + * - The fold flag. Reserved. The same as cse for now. + */ + +/* + * NB: bool FASTCALL is not compatible with Nanojit's calling convention usage. + * Do not use bool FASTCALL, use JSBool only! + */ + +BUILTIN2(extern, JSVAL, js_BoxDouble, CONTEXT, DOUBLE, 1, 1) +BUILTIN2(extern, JSVAL, js_BoxInt32, CONTEXT, INT32, 1, 1) +BUILTIN1(extern, DOUBLE, js_UnboxDouble, JSVAL, 1, 1) +BUILTIN1(extern, INT32, js_UnboxInt32, JSVAL, 1, 1) +BUILTIN2(extern, DOUBLE, js_dmod, DOUBLE, DOUBLE, 1, 1) +BUILTIN2(extern, INT32, js_imod, INT32, INT32, 1, 1) +BUILTIN1(extern, INT32, js_DoubleToInt32, DOUBLE, 1, 1) +BUILTIN1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, 1) + +BUILTIN2(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, 1, 1) +BUILTIN2(extern, INT32, js_StringToInt32, CONTEXT, STRING, 1, 1) +BUILTIN3(extern, JSVAL, js_Any_getprop, CONTEXT, OBJECT, STRING, 0, 0) +BUILTIN4(extern, BOOL, js_Any_setprop, CONTEXT, OBJECT, STRING, JSVAL, 0, 0) +BUILTIN3(extern, JSVAL, js_Any_getelem, CONTEXT, OBJECT, INT32, 0, 0) +BUILTIN4(extern, BOOL, js_Any_setelem, CONTEXT, OBJECT, INT32, JSVAL, 0, 0) +BUILTIN3(extern, OBJECT, js_FastValueToIterator, CONTEXT, UINT32, JSVAL, 0, 0) +BUILTIN2(extern, JSVAL, js_FastCallIteratorNext, CONTEXT, OBJECT, 0, 0) +BUILTIN2(FRIEND, BOOL, js_CloseIterator, CONTEXT, JSVAL, 0, 0) +BUILTIN2(extern, SIDEEXIT, js_CallTree, INTERPSTATE, FRAGMENT, 0, 0) +BUILTIN2(extern, OBJECT, js_FastNewObject, CONTEXT, OBJECT, 0, 0) +BUILTIN3(extern, BOOL, js_AddProperty, CONTEXT, OBJECT, SCOPEPROP, 0, 0) +BUILTIN3(extern, BOOL, js_HasNamedProperty, CONTEXT, OBJECT, STRING, 0, 0) +BUILTIN3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, INT32, 0, 0) +BUILTIN3(extern, JSVAL, js_CallGetter, CONTEXT, OBJECT, SCOPEPROP, 0, 0) +BUILTIN2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, 1) +BUILTIN2(extern, STRING, js_TypeOfBoolean, CONTEXT, INT32, 1, 1) +BUILTIN2(extern, DOUBLE, js_BooleanOrUndefinedToNumber, CONTEXT, INT32, 1, 1) +BUILTIN2(extern, STRING, js_BooleanOrUndefinedToString, CONTEXT, INT32, 1, 1) +BUILTIN2(extern, STRING, js_ObjectToString, CONTEXT, OBJECT, 0, 0) +BUILTIN1(extern, OBJECT, js_Arguments, CONTEXT, 0, 0) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config.mk new file mode 100644 index 0000000..ddd96ed --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config.mk @@ -0,0 +1,206 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +ifdef JS_DIST +DIST = $(JS_DIST) +else +DIST = $(DEPTH)/../../dist +endif + +# Set os+release dependent make variables +OS_ARCH := $(subst /,_,$(shell uname -s | sed /\ /s//_/)) + +# Attempt to differentiate between SunOS 5.4 and x86 5.4 +OS_CPUARCH := $(shell uname -m) +ifeq ($(OS_CPUARCH),i86pc) +OS_RELEASE := $(shell uname -r)_$(OS_CPUARCH) +else +ifeq ($(OS_ARCH),AIX) +OS_RELEASE := $(shell uname -v).$(shell uname -r) +else +OS_RELEASE := $(shell uname -r) +endif +endif +ifeq ($(OS_ARCH),IRIX64) +OS_ARCH := IRIX +endif + +# Handle output from win32 unames other than Netscape's version +ifeq (,$(filter-out Windows_95 Windows_98 CYGWIN_95-4.0 CYGWIN_98-4.10, $(OS_ARCH))) + OS_ARCH := WIN95 +endif +ifeq ($(OS_ARCH),WIN95) + OS_ARCH := WINNT + OS_RELEASE := 4.0 +endif +ifeq ($(OS_ARCH), Windows_NT) + OS_ARCH := WINNT + OS_MINOR_RELEASE := $(shell uname -v) + ifeq ($(OS_MINOR_RELEASE),00) + OS_MINOR_RELEASE = 0 + endif + OS_RELEASE := $(OS_RELEASE).$(OS_MINOR_RELEASE) +endif +ifeq (CYGWIN_NT,$(findstring CYGWIN_NT,$(OS_ARCH))) + OS_RELEASE := $(patsubst CYGWIN_NT-%,%,$(OS_ARCH)) + OS_ARCH := WINNT +endif +ifeq ($(OS_ARCH), CYGWIN32_NT) + OS_ARCH := WINNT +endif +ifeq (MINGW32_NT,$(findstring MINGW32_NT,$(OS_ARCH))) + OS_RELEASE := $(patsubst MINGW32_NT-%,%,$(OS_ARCH)) + OS_ARCH := WINNT +endif + +# Virtually all Linux versions are identical. +# Any distinctions are handled in linux.h +ifeq ($(OS_ARCH),Linux) +OS_CONFIG := Linux_All +else +ifeq ($(OS_ARCH),dgux) +OS_CONFIG := dgux +else +ifeq ($(OS_ARCH),Darwin) +OS_CONFIG := Darwin +else +ifeq ($(OS_ARCH),Darwin64) +OS_CONFIG := Darwin64 +else +OS_CONFIG := $(OS_ARCH)$(OS_OBJTYPE)$(OS_RELEASE) +endif +endif +endif +endif + +ASFLAGS = +DEFINES = + +ifeq ($(OS_ARCH), WINNT) +INSTALL = nsinstall +CP = cp +else +INSTALL = $(DIST)/bin/nsinstall +CP = cp +endif + +ifdef BUILD_OPT +ifdef USE_MSVC +OPTIMIZER = -O2 -GL +INTERP_OPTIMIZER = -O2 -GL +BUILTINS_OPTIMIZER = -O2 -GL +LDFLAGS += -LTCG +else +OPTIMIZER = -Os -fstrict-aliasing -fno-exceptions -fno-rtti -Wstrict-aliasing=2 +BUILTINS_OPTIMIZER = -O9 -fstrict-aliasing -fno-exceptions -fno-rtti +INTERP_OPTIMIZER = -O3 -fstrict-aliasing -fno-exceptions -fno-rtti +endif +DEFINES += -UDEBUG -DNDEBUG -UDEBUG_$(USER) +OBJDIR_TAG = _OPT +else +ifdef USE_MSVC +OPTIMIZER = -Zi +INTERP_OPTIMIZER = -Zi +BUILTINS_OPTIMIZER = $(INTERP_OPTIMIZER) +else +OPTIMIZER = -g3 -fstrict-aliasing -fno-exceptions -fno-rtti -Wstrict-aliasing=2 +INTERP_OPTIMIZER = -g3 -fstrict-aliasing -fno-exceptions -fno-rtti +BUILTINS_OPTIMIZER = $(INTERP_OPTIMIZER) +endif +DEFINES += -DDEBUG -DDEBUG_$(USER) +OBJDIR_TAG = _DBG +endif + +SO_SUFFIX = so + +NS_USE_NATIVE = 1 + +# Java stuff +CLASSDIR = $(DEPTH)/liveconnect/classes +JAVA_CLASSES = $(patsubst %.java,%.class,$(JAVA_SRCS)) +TARGETS += $(addprefix $(CLASSDIR)/$(OBJDIR)/$(JARPATH)/, $(JAVA_CLASSES)) +JAVAC = $(JDK)/bin/javac +JAVAC_FLAGS = -classpath "$(CLASSPATH)" -d $(CLASSDIR)/$(OBJDIR) +ifeq ($(OS_ARCH), WINNT) + SEP = ; +else + SEP = : +endif +CLASSPATH = $(JDK)/lib/classes.zip$(SEP)$(CLASSDIR)/$(OBJDIR) + +include $(DEPTH)/ref-config/$(OS_CONFIG).mk + +ifndef OBJ_SUFFIX +ifdef USE_MSVC +OBJ_SUFFIX = obj +else +OBJ_SUFFIX = o +endif +endif + +ifndef HOST_BIN_SUFFIX +ifeq ($(OS_ARCH),WINNT) +HOST_BIN_SUFFIX = .exe +else +HOST_BIN_SUFFIX = +endif +endif + +# Name of the binary code directories +ifdef OBJROOT +# prepend $(DEPTH) to the root unless it is an absolute path +OBJDIR = $(if $(filter /%,$(OBJROOT)),$(OBJROOT),$(DEPTH)/$(OBJROOT)) +else +ifeq ($(DEPTH),.) +OBJDIR = $(OS_CONFIG)$(OBJDIR_TAG).$(if $(BUILD_IDG),OBJD,OBJ) +else +OBJDIR = $(DEPTH)/$(OS_CONFIG)$(OBJDIR_TAG).$(if $(BUILD_IDG),OBJD,OBJ) +endif +endif + +VPATH = $(OBJDIR) + +LCJAR = js15lc30.jar + +# Library name +LIBDIR := lib +ifeq ($(CPU_ARCH), x86_64) +LIBDIR := lib64 +endif + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/Makefile.in b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/Makefile.in new file mode 100644 index 0000000..39f9912 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/Makefile.in @@ -0,0 +1,106 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Robert Ginda +# John Taylor +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +# For sanity's sake, we compile nsinstall without the wrapped system +# headers, so that we can use it to set up the wrapped system headers. +VISIBILITY_FLAGS = + +ifneq (,$(CROSS_COMPILE)$(filter-out WINNT OS2,$(OS_ARCH))) +ifneq ($(OS_ARCH), WINCE) +HOST_PROGRAM = nsinstall$(HOST_BIN_SUFFIX) +HOST_CSRCS = nsinstall.c pathsub.c +endif +endif + +PLSRCS = nfspwd.pl revdepth.pl + +TARGETS = $(HOST_PROGRAM) $(PLSRCS:.pl=) $(SIMPLE_PROGRAMS) + +# IMPORTANT: Disable NSBUILDROOT for this directory only, otherwise we have +# a recursive rule for finding nsinstall and the Perl scripts. +ifdef NSBUILDROOT +override NSBUILDROOT := +endif + +ifdef GNU_CC +MODULE_OPTIMIZE_FLAGS = -O3 +endif + +ifndef COMPILER_DEPEND +ifndef MOZ_NATIVE_MAKEDEPEND +DIRS += mkdepend +endif +endif + +include $(topsrcdir)/config/config.mk + +# Do not install util programs +NO_INSTALL=1 + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) +ifdef HOST_PROGRAM + $(INSTALL) $(HOST_PROGRAM) $(DIST)/bin +endif + +ifdef WRAP_SYSTEM_INCLUDES +export:: + if test ! -d system_wrappers; then mkdir system_wrappers; fi + $(PERL) $(srcdir)/preprocessor.pl $(DEFINES) $(ACDEFINES) \ + -DBUILD_STATIC_LIBS=$(BUILD_STATIC_LIBS) \ + $(srcdir)/system-headers | $(PERL) $(srcdir)/make-system-wrappers.pl system_wrappers + $(INSTALL) system_wrappers $(DIST)/include + +GARBAGE_DIRS += system_wrappers +endif + +FORCE: + +ifdef MKDEPEND_DIR +clean clobber realclean clobber_all:: + cd $(MKDEPEND_DIR); $(MAKE) $@ +endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/Moz/Milestone.pm b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/Moz/Milestone.pm new file mode 100644 index 0000000..8dd1449 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/Moz/Milestone.pm @@ -0,0 +1,232 @@ +#!/usr/bin/perl -w +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Win32 Version System. +# +# The Initial Developer of the Original Code is Netscape Communications Corporation +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +package Moz::Milestone; +use strict; + +use vars qw($officialMilestone + $milestone); + +local $Moz::Milestone::milestone; +local $Moz::Milestone::officialMilestone; + +# +# Usage: getOfficialMilestone($milestoneFile) +# Returns full milestone (x.x.x.x[ab12pre+]) +# +sub getOfficialMilestone($) { + my $mfile = $_[0]; + open(FILE,"$mfile") || + die ("Can't open $mfile for reading!"); + + my $num = ; + while($num =~ /^\s*#/ || $num !~ /^\d/) { + $num = ; + } + + close(FILE); + if ($num !~ /^\d/) { return; } + chomp($num); + # Remove extra ^M caused by using dos-mode line-endings + chop $num if (substr($num, -1, 1) eq "\r"); + $Moz::Milestone::officialMilestone = $num; + $Moz::Milestone::milestone = &getMilestoneNum; + return $num; +} + +# +# Usage: getMilestoneNum($num) +# Returns: milestone without a + if it exists. +# +sub getMilestoneNum { + if (defined($Moz::Milestone::milestone)) { + return $Moz::Milestone::milestone; + } + + if (defined($Moz::Milestone::officialMilestone)) { + $Moz::Milestone::milestone = $Moz::Milestone::officialMilestone; + } else { + $Moz::Milestone::milestone = $_[0]; + } + + if ($Moz::Milestone::milestone =~ /\+$/) { # for x.x.x+, strip off the + + $Moz::Milestone::milestone =~ s/\+$//; + } + + return $Moz::Milestone::milestone; +} + +# +# Usage: getMilestoneQualifier($num) +# Returns: + if it exists. +# +sub getMilestoneQualifier { + my $milestoneQualifier; + if (defined($Moz::Milestone::officialMilestone)) { + $milestoneQualifier = $Moz::Milestone::officialMilestone; + } else { + $milestoneQualifier = $_[0]; + } + + if ($milestoneQualifier =~ /\+$/) { + return "+"; + } +} + +sub getMilestoneMajor { + my $milestoneMajor; + if (defined($Moz::Milestone::milestone)) { + $milestoneMajor = $Moz::Milestone::milestone; + } else { + $milestoneMajor = $_[0]; + } + my @parts = split(/\./,$milestoneMajor); + return $parts[0]; +} + +sub getMilestoneMinor { + my $milestoneMinor; + if (defined($Moz::Milestone::milestone)) { + $milestoneMinor = $Moz::Milestone::milestone; + } else { + $milestoneMinor = $_[0]; + } + my @parts = split(/\./,$milestoneMinor); + + if ($#parts < 1 ) { return 0; } + return $parts[1]; +} + +sub getMilestoneMini { + my $milestoneMini; + if (defined($Moz::Milestone::milestone)) { + $milestoneMini = $Moz::Milestone::milestone; + } else { + $milestoneMini = $_[0]; + } + my @parts = split(/\./,$milestoneMini); + + if ($#parts < 2 ) { return 0; } + return $parts[2]; +} + +sub getMilestoneMicro { + my $milestoneMicro; + if (defined($Moz::Milestone::milestone)) { + $milestoneMicro = $Moz::Milestone::milestone; + } else { + $milestoneMicro = $_[0]; + } + my @parts = split(/\./,$milestoneMicro); + + if ($#parts < 3 ) { return 0; } + return $parts[3]; +} + +sub getMilestoneAB { + my $milestoneAB; + if (defined($Moz::Milestone::milestone)) { + $milestoneAB = $Moz::Milestone::milestone; + } else { + $milestoneAB = $_[0]; + } + + if ($milestoneAB =~ /a/) { return "alpha"; } + if ($milestoneAB =~ /b/) { return "beta"; } + return "final"; +} + +# +# build_file($template_file,$output_file) +# +sub build_file($$) { + my @FILE; + my @MILESTONE_PARTS; + my $MINI_VERSION = 0; + my $MICRO_VERSION = 0; + my $OFFICIAL = 0; + my $QUALIFIER = ""; + + if (!defined($Moz::Milestone::milestone)) { die("$0: no milestone file set!\n"); } + @MILESTONE_PARTS = split(/\./, &getMilestoneNum); + if ($#MILESTONE_PARTS >= 2) { + $MINI_VERSION = 1; + } else { + $MILESTONE_PARTS[2] = 0; + } + if ($#MILESTONE_PARTS >= 3) { + $MICRO_VERSION = 1; + } else { + $MILESTONE_PARTS[3] = 0; + } + if (! &getMilestoneQualifier) { + $OFFICIAL = 1; + } else { + $QUALIFIER = "+"; + } + + if (-e $_[0]) { + open(FILE, "$_[0]") || die("$0: Can't open $_[0] for reading!\n"); + @FILE = ; + close(FILE); + + open(FILE, ">$_[1]") || die("$0: Can't open $_[1] for writing!\n"); + + # + # There will be more of these based on what we need for files. + # + foreach(@FILE) { + s/__MOZ_MAJOR_VERSION__/$MILESTONE_PARTS[0]/g; + s/__MOZ_MINOR_VERSION__/$MILESTONE_PARTS[1]/g; + s/__MOZ_MINI_VERSION__/$MILESTONE_PARTS[2]/g; + s/__MOZ_MICRO_VERSION__/$MILESTONE_PARTS[3]/g; + if ($MINI_VERSION) { + s/__MOZ_OPTIONAL_MINI_VERSION__/.$MILESTONE_PARTS[2]/g; + } + if ($MICRO_VERSION) { + s/__MOZ_OPTIONAL_MICRO_VERSION__/.$MILESTONE_PARTS[3]/g; + } + + print FILE $_; + } + close(FILE); + } else { + die("$0: $_[0] doesn't exist for autoversioning!\n"); + } + +} + +1; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/autoconf.mk.in b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/autoconf.mk.in new file mode 100644 index 0000000..d82e614 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/autoconf.mk.in @@ -0,0 +1,349 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is this file as it was released upon August 6, 1998. +# +# The Initial Developer of the Original Code is +# Christopher Seawood. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Benjamin Smedberg +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# A netscape style .mk file for autoconf builds + +INCLUDED_AUTOCONF_MK = 1 +USE_AUTOCONF = 1 +MOZILLA_CLIENT = 1 +target = @target@ +ac_configure_args = @ac_configure_args@ +BUILD_MODULES = @BUILD_MODULES@ +MOZILLA_VERSION = @MOZILLA_VERSION@ + +MOZ_BUILD_APP = @MOZ_BUILD_APP@ +MOZ_APP_NAME = @MOZ_APP_NAME@ +MOZ_APP_DISPLAYNAME = @MOZ_APP_DISPLAYNAME@ +MOZ_APP_VERSION = @MOZ_APP_VERSION@ + +MOZ_PKG_SPECIAL = @MOZ_PKG_SPECIAL@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +includedir = @includedir@ +libdir = @libdir@ +datadir = @datadir@ +mandir = @mandir@ + +installdir = $(libdir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION) +sdkdir = $(libdir)/$(MOZ_APP_NAME)-devel-$(MOZ_APP_VERSION) + +DIST = $(DEPTH)/dist + +MOZ_JS_LIBS = @MOZ_JS_LIBS@ + +MOZ_SYNC_BUILD_FILES = @MOZ_SYNC_BUILD_FILES@ + +MOZ_DEBUG = @MOZ_DEBUG@ +MOZ_DEBUG_MODULES = @MOZ_DEBUG_MODULES@ +MOZ_PROFILE_MODULES = @MOZ_PROFILE_MODULES@ +MOZ_DEBUG_ENABLE_DEFS = @MOZ_DEBUG_ENABLE_DEFS@ +MOZ_DEBUG_DISABLE_DEFS = @MOZ_DEBUG_DISABLE_DEFS@ +MOZ_DEBUG_FLAGS = @MOZ_DEBUG_FLAGS@ +MOZ_DEBUG_LDFLAGS=@MOZ_DEBUG_LDFLAGS@ +MOZ_DBGRINFO_MODULES = @MOZ_DBGRINFO_MODULES@ +MOZ_EXTENSIONS = @MOZ_EXTENSIONS@ +MOZ_IMG_DECODERS= @MOZ_IMG_DECODERS@ +MOZ_IMG_ENCODERS= @MOZ_IMG_ENCODERS@ +MOZ_JSDEBUGGER = @MOZ_JSDEBUGGER@ +MOZ_PERF_METRICS = @MOZ_PERF_METRICS@ +MOZ_LEAKY = @MOZ_LEAKY@ +MOZ_MEMORY = @MOZ_MEMORY@ +MOZ_JPROF = @MOZ_JPROF@ +MOZ_SHARK = @MOZ_SHARK@ +MOZ_CALLGRIND = @MOZ_CALLGRIND@ +MOZ_VTUNE = @MOZ_VTUNE@ +DEHYDRA_PATH = @DEHYDRA_PATH@ + +ENABLE_EAZEL_PROFILER=@ENABLE_EAZEL_PROFILER@ +EAZEL_PROFILER_CFLAGS=@EAZEL_PROFILER_CFLAGS@ +EAZEL_PROFILER_LIBS=@EAZEL_PROFILER_LIBS@ +GC_LEAK_DETECTOR = @GC_LEAK_DETECTOR@ +NS_TRACE_MALLOC = @NS_TRACE_MALLOC@ +INCREMENTAL_LINKER = @INCREMENTAL_LINKER@ +MACOSX_DEPLOYMENT_TARGET = @MACOSX_DEPLOYMENT_TARGET@ +BUILD_STATIC_LIBS = @BUILD_STATIC_LIBS@ +ENABLE_TESTS = @ENABLE_TESTS@ +JS_ULTRASPARC_OPTS = @JS_ULTRASPARC_OPTS@ +JS_STATIC_BUILD = @JS_STATIC_BUILD@ + +TAR=@TAR@ + +# The MOZ_UI_LOCALE var is used to build a particular locale. Do *not* +# use the var to change any binary files. Do *not* use this var unless you +# write rules for the "clean-locale" and "locale" targets. +MOZ_UI_LOCALE = @MOZ_UI_LOCALE@ + +MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS = @MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS@ +MOZ_COMPONENT_NSPR_LIBS=@MOZ_COMPONENT_NSPR_LIBS@ + +MOZ_FIX_LINK_PATHS=@MOZ_FIX_LINK_PATHS@ + +XPCOM_FROZEN_LDOPTS=@XPCOM_FROZEN_LDOPTS@ +XPCOM_LIBS=@XPCOM_LIBS@ +MOZ_TIMELINE=@MOZ_TIMELINE@ + +ENABLE_STRIP = @ENABLE_STRIP@ +PKG_SKIP_STRIP = @PKG_SKIP_STRIP@ + +MOZ_POST_DSO_LIB_COMMAND = @MOZ_POST_DSO_LIB_COMMAND@ +MOZ_POST_PROGRAM_COMMAND = @MOZ_POST_PROGRAM_COMMAND@ + +MOZ_BUILD_ROOT = @MOZ_BUILD_ROOT@ + +MOZ_INSURE = @MOZ_INSURE@ +MOZ_INSURIFYING = @MOZ_INSURIFYING@ +MOZ_INSURE_DIRS = @MOZ_INSURE_DIRS@ +MOZ_INSURE_EXCLUDE_DIRS = @MOZ_INSURE_EXCLUDE_DIRS@ + +MOZ_NATIVE_NSPR = @MOZ_NATIVE_NSPR@ + +CROSS_COMPILE = @CROSS_COMPILE@ + +WCHAR_CFLAGS = @WCHAR_CFLAGS@ + +OS_CPPFLAGS = @CPPFLAGS@ +OS_CFLAGS = $(OS_CPPFLAGS) @CFLAGS@ +OS_CXXFLAGS = $(OS_CPPFLAGS) @CXXFLAGS@ +OS_LDFLAGS = @LDFLAGS@ + +OS_COMPILE_CFLAGS = $(OS_CPPFLAGS) @COMPILE_CFLAGS@ +OS_COMPILE_CXXFLAGS = $(OS_CPPFLAGS) @COMPILE_CXXFLAGS@ + +OS_INCLUDES = $(NSPR_CFLAGS) +OS_LIBS = @LIBS@ +ACDEFINES = @MOZ_DEFINES@ + +WARNINGS_AS_ERRORS = @WARNINGS_AS_ERRORS@ + +MOZ_OPTIMIZE = @MOZ_OPTIMIZE@ +MOZ_OPTIMIZE_FLAGS = @MOZ_OPTIMIZE_FLAGS@ +MOZ_OPTIMIZE_LDFLAGS = @MOZ_OPTIMIZE_LDFLAGS@ +MOZ_OPTIMIZE_SIZE_TWEAK = @MOZ_OPTIMIZE_SIZE_TWEAK@ + +MOZ_RTTI_FLAGS_ON = @_MOZ_RTTI_FLAGS_ON@ + +MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE = @MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE@ +PROFILE_GEN_CFLAGS = @PROFILE_GEN_CFLAGS@ +PROFILE_GEN_LDFLAGS = @PROFILE_GEN_LDFLAGS@ +PROFILE_USE_CFLAGS = @PROFILE_USE_CFLAGS@ +PROFILE_USE_LDFLAGS = @PROFILE_USE_LDFLAGS@ + +WIN_TOP_SRC = @WIN_TOP_SRC@ +CYGWIN_WRAPPER = @CYGWIN_WRAPPER@ +AS_PERL = @AS_PERL@ +CYGDRIVE_MOUNT = @CYGDRIVE_MOUNT@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AR_EXTRACT = @AR_EXTRACT@ +AR_LIST = @AR_LIST@ +AR_DELETE = @AR_DELETE@ +AS = @AS@ +ASFLAGS = @ASFLAGS@ +AS_DASH_C_FLAG = @AS_DASH_C_FLAG@ +LD = @LD@ +RC = @RC@ +RCFLAGS = @RCFLAGS@ +WINDRES = @WINDRES@ +USE_SHORT_LIBNAME = @USE_SHORT_LIBNAME@ +IMPLIB = @IMPLIB@ +FILTER = @FILTER@ +BIN_FLAGS = @BIN_FLAGS@ +MIDL = @MIDL@ +MIDL_FLAGS = @MIDL_FLAGS@ +_MSC_VER = @_MSC_VER@ + +DLL_PREFIX = @DLL_PREFIX@ +LIB_PREFIX = @LIB_PREFIX@ +OBJ_SUFFIX = @OBJ_SUFFIX@ +LIB_SUFFIX = @LIB_SUFFIX@ +DLL_SUFFIX = @DLL_SUFFIX@ +BIN_SUFFIX = @BIN_SUFFIX@ +ASM_SUFFIX = @ASM_SUFFIX@ +IMPORT_LIB_SUFFIX = @IMPORT_LIB_SUFFIX@ +USE_N32 = @USE_N32@ +HAVE_64BIT_OS = @HAVE_64BIT_OS@ + +# Temp hack. It is not my intention to leave this crap in here for ever. +# Im talking to fur right now to solve the problem without introducing +# NS_USE_NATIVE to the build system -ramiro. +NS_USE_NATIVE = @NS_USE_NATIVE@ + +CC = @CC@ +CXX = @CXX@ + +CC_VERSION = @CC_VERSION@ +CXX_VERSION = @CXX_VERSION@ + +GNU_AS = @GNU_AS@ +GNU_LD = @GNU_LD@ +GNU_CC = @GNU_CC@ +GNU_CXX = @GNU_CXX@ +HAVE_GCC3_ABI = @HAVE_GCC3_ABI@ +INTEL_CC = @INTEL_CC@ +INTEL_CXX = @INTEL_CXX@ + +HOST_CC = @HOST_CC@ +HOST_CXX = @HOST_CXX@ +HOST_CFLAGS = @HOST_CFLAGS@ +HOST_CXXFLAGS = @HOST_CXXFLAGS@ +HOST_OPTIMIZE_FLAGS = @HOST_OPTIMIZE_FLAGS@ +HOST_NSPR_MDCPUCFG = @HOST_NSPR_MDCPUCFG@ +HOST_AR = @HOST_AR@ +HOST_AR_FLAGS = @HOST_AR_FLAGS@ +HOST_LD = @HOST_LD@ +HOST_RANLIB = @HOST_RANLIB@ +HOST_BIN_SUFFIX = @HOST_BIN_SUFFIX@ + +HOST_OS_ARCH = @HOST_OS_ARCH@ +host_cpu = @host_cpu@ +host_vendor = @host_vendor@ +host_os = @host_os@ + +TARGET_NSPR_MDCPUCFG = @TARGET_NSPR_MDCPUCFG@ +TARGET_CPU = @TARGET_CPU@ +TARGET_VENDOR = @TARGET_VENDOR@ +TARGET_OS = @TARGET_OS@ +TARGET_MD_ARCH = @TARGET_MD_ARCH@ +TARGET_XPCOM_ABI = @TARGET_XPCOM_ABI@ + +AUTOCONF = @AUTOCONF@ +PERL = @PERL@ +PYTHON = @PYTHON@ +RANLIB = @RANLIB@ +WHOAMI = @WHOAMI@ +UNZIP = @UNZIP@ +ZIP = @ZIP@ +XARGS = @XARGS@ +STRIP = @STRIP@ +DOXYGEN = @DOXYGEN@ +MAKE = @MAKE@ +PBBUILD_BIN = @PBBUILD@ +SDP = @SDP@ +NSINSTALL_BIN = @NSINSTALL_BIN@ + +NSPR_CONFIG = @NSPR_CONFIG@ +NSPR_CFLAGS = @NSPR_CFLAGS@ +NSPR_LIBS = @NSPR_LIBS@ + +USE_DEPENDENT_LIBS = @USE_DEPENDENT_LIBS@ + +# MKSHLIB_FORCE_ALL is used to force the linker to include all object +# files present in an archive. MKSHLIB_UNFORCE_ALL reverts the linker +# to normal behavior. Makefile's that create shared libraries out of +# archives use these flags to force in all of the .o files in the +# archives into the shared library. +WRAP_MALLOC_LIB = @WRAP_MALLOC_LIB@ +WRAP_MALLOC_CFLAGS = @WRAP_MALLOC_CFLAGS@ +DSO_CFLAGS = @DSO_CFLAGS@ +DSO_PIC_CFLAGS = @DSO_PIC_CFLAGS@ +MKSHLIB = @MKSHLIB@ +MKCSHLIB = @MKCSHLIB@ +MKSHLIB_FORCE_ALL = @MKSHLIB_FORCE_ALL@ +MKSHLIB_UNFORCE_ALL = @MKSHLIB_UNFORCE_ALL@ +DSO_LDOPTS = @DSO_LDOPTS@ +DLL_SUFFIX = @DLL_SUFFIX@ + +NO_LD_ARCHIVE_FLAGS = @NO_LD_ARCHIVE_FLAGS@ + +MOZ_TOOLKIT_REGISTRY_CFLAGS = \ + $(TK_CFLAGS) + +MOZ_NATIVE_MAKEDEPEND = @SYSTEM_MAKEDEPEND@ + +# Used for LD_LIBRARY_PATH +LIBS_PATH = @LIBS_PATH@ + +MOZ_AUTO_DEPS = @MOZ_AUTO_DEPS@ +COMPILER_DEPEND = @COMPILER_DEPEND@ +MDDEPDIR := @MDDEPDIR@ + +MOZ_DEMANGLE_SYMBOLS = @MOZ_DEMANGLE_SYMBOLS@ + +# XXX - these need to be cleaned up and have real checks added -cls +CM_BLDTYPE=dbg +AWT_11=1 +MOZ_BITS=32 +OS_TARGET=@OS_TARGET@ +OS_ARCH=@OS_ARCH@ +OS_RELEASE=@OS_RELEASE@ +OS_TEST=@OS_TEST@ + +TARGET_DEVICE = @TARGET_DEVICE@ + +# For AIX build +AIX_OBJMODEL = @AIX_OBJMODEL@ + +# For OS/2 build +MOZ_OS2_TOOLS = @MOZ_OS2_TOOLS@ +MOZ_OS2_USE_DECLSPEC = @MOZ_OS2_USE_DECLSPEC@ +MOZ_OS2_HIGH_MEMORY = @MOZ_OS2_HIGH_MEMORY@ + +MOZILLA_OFFICIAL = @MOZILLA_OFFICIAL@ +BUILD_OFFICIAL = @BUILD_OFFICIAL@ +MOZ_MILESTONE_RELEASE = @MOZ_MILESTONE_RELEASE@ + +# Win32 options +MOZ_PROFILE = @MOZ_PROFILE@ +MOZ_BROWSE_INFO = @MOZ_BROWSE_INFO@ +MOZ_TOOLS_DIR = @MOZ_TOOLS_DIR@ +MOZ_DEBUG_SYMBOLS = @MOZ_DEBUG_SYMBOLS@ +MOZ_QUANTIFY = @MOZ_QUANTIFY@ +MSMANIFEST_TOOL = @MSMANIFEST_TOOL@ +WIN32_REDIST_DIR = @WIN32_REDIST_DIR@ +WIN32_CRT_SRC_DIR = @WIN32_CRT_SRC_DIR@ +WIN32_CUSTOM_CRT_DIR = @WIN32_CUSTOM_CRT_DIR@ + +# Codesighs tools option, enables win32 mapfiles. +MOZ_MAPINFO = @MOZ_MAPINFO@ + +WINCE = @WINCE@ + +MACOS_SDK_DIR = @MACOS_SDK_DIR@ +NEXT_ROOT = @NEXT_ROOT@ +GCC_VERSION = @GCC_VERSION@ +XCODEBUILD_VERSION= @XCODEBUILD_VERSION@ +HAS_XCODE_2_1 = @HAS_XCODE_2_1@ +UNIVERSAL_BINARY= @UNIVERSAL_BINARY@ +HAVE_DTRACE= @HAVE_DTRACE@ + +VISIBILITY_FLAGS = @VISIBILITY_FLAGS@ +WRAP_SYSTEM_INCLUDES = @WRAP_SYSTEM_INCLUDES@ + +HAVE_ARM_SIMD= @HAVE_ARM_SIMD@ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/check-sync-dirs.py b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/check-sync-dirs.py new file mode 100644 index 0000000..916696e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/check-sync-dirs.py @@ -0,0 +1,108 @@ +# check-sync-dirs.py --- check that one directory is an exact subset of another +# +# Usage: python check-sync-dirs.py COPY ORIGINAL +# +# Check that the files present in the directory tree COPY are exact +# copies of their counterparts in the directory tree ORIGINAL. COPY +# need not have all the files in ORIGINAL, but COPY may not have files +# absent from ORIGINAL. +# +# Each directory in COPY may have a file named +# 'check-sync-exceptions', which lists files in COPY that need not be +# the same as the corresponding file in ORIGINAL, or exist at all in +# ORIGINAL. (The 'check-sync-exceptions' file itself is always +# treated as exceptional.) Blank lines and '#' comments in the file +# are ignored. + +import sys +import os +from os.path import join +import filecmp +import textwrap +import fnmatch + +if len(sys.argv) != 3: + print >> sys.stderr, "Usage: %s COPY ORIGINAL" % sys.argv[0] + sys.exit(1) + +copy = sys.argv[1] +original = sys.argv[2] + +# Ignore detritus left lying around by editing tools. +ignored_patterns = ['*~', '.#*', '#*#', '*.orig', '*.rej'] + +# Return the contents of FILENAME, a 'check-sync-exceptions' file, as +# a dictionary whose keys are exactly the list of filenames, along +# with the basename of FILENAME itself. If FILENAME does not exist, +# return the empty dictionary. +def read_exceptions(filename): + if (os.path.exists(filename)): + f = file(filename) + exceptions={} + for line in f: + line = line.strip() + if line != '' and line[0] != '#': + exceptions[line] = None + exceptions[os.path.basename (filename)] = None + f.close() + return exceptions + else: + return {} + +# Return true if FILENAME matches any pattern in the list of filename +# patterns PATTERNS. +def fnmatch_any(filename, patterns): + for pattern in patterns: + if fnmatch.fnmatch(filename, pattern): + return True + return False + +# Check the contents of the directory tree COPY against ORIGINAL. For each +# file that differs, apply REPORT to COPY, ORIGINAL, and the file's +# relative path. COPY and ORIGINAL should be absolute. Ignore files +# that match patterns given in the list IGNORE. +def check(copy, original, ignore, report): + os.chdir(copy) + for (dirpath, dirnames, filenames) in os.walk('.'): + exceptions = read_exceptions(join(dirpath, 'check-sync-exceptions')) + for filename in filenames: + if filename in exceptions: + continue + if fnmatch_any(filename, ignore): + continue + relative_name = join(dirpath, filename) + original_name = join(original, relative_name) + if (os.path.exists(original_name) + and filecmp.cmp(relative_name, original_name)): + continue + report(copy, original, relative_name) + + +differences_found = False + +# Print an error message for DIFFERING, which was found to differ +# between COPY and ORIGINAL. Set the global variable differences_found. +def report(copy, original, differing): + global differences_found + if not differences_found: + print >> sys.stderr, "TEST-FAIL | build file copies are not in sync" + print >> sys.stderr, "file(s) found in: %s" % (copy) + print >> sys.stderr, ("differ from their originals in: %s" + % (original)) + print >> sys.stderr, "file differs: %s" % (differing) + differences_found = True + +check(os.path.abspath(copy), + os.path.abspath(original), + ignored_patterns, + report) + +if differences_found: + msg=('''In general, the files in '%s' should always be exact copies of +originals in '%s'. A change made to one should also be made to the +other. See 'check-sync-dirs.py' for more details.''' + % (copy, original)) + print >> sys.stderr, textwrap.fill(msg, 75) + sys.exit(1) + +sys.exit(0) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/check-sync-exceptions b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/check-sync-exceptions new file mode 100644 index 0000000..7c0bc47 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/check-sync-exceptions @@ -0,0 +1,6 @@ +Makefile.in +autoconf.mk.in +check-sync-dirs.py + +# This is a copy of nspr's config/make-system-wrappers.pl. +make-system-wrappers.pl diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/config.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/config.mk new file mode 100644 index 0000000..d19ca4a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/config.mk @@ -0,0 +1,884 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Benjamin Smedberg +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# config.mk +# +# Determines the platform and builds the macros needed to load the +# appropriate platform-specific .mk file, then defines all (most?) +# of the generic macros. +# + +# Define an include-at-most-once flag +INCLUDED_CONFIG_MK = 1 + +EXIT_ON_ERROR = set -e; # Shell loops continue past errors without this. + +ifndef topsrcdir +topsrcdir = $(DEPTH) +endif + +ifndef INCLUDED_AUTOCONF_MK +include $(DEPTH)/config/autoconf.mk +endif +ifndef INCLUDED_INSURE_MK +ifdef MOZ_INSURIFYING +include $(topsrcdir)/config/insure.mk +endif +endif + +COMMA = , + +# Sanity check some variables +CHECK_VARS := \ + XPI_NAME \ + LIBRARY_NAME \ + MODULE \ + DEPTH \ + SHORT_LIBNAME \ + XPI_PKGNAME \ + INSTALL_EXTENSION_ID \ + $(NULL) + +# checks for internal spaces or trailing spaces in the variable +# named by $x +check-variable = $(if $(filter-out 0 1,$(words $($(x))z)),$(error Spaces are not allowed in $(x))) + +$(foreach x,$(CHECK_VARS),$(check-variable)) + +# FINAL_TARGET specifies the location into which we copy end-user-shipped +# build products (typelibs, components, chrome). +# +# It will usually be the well-loved $(DIST)/bin, today, but can also be an +# XPI-contents staging directory for ambitious and right-thinking extensions. +FINAL_TARGET = $(if $(XPI_NAME),$(DIST)/xpi-stage/$(XPI_NAME),$(DIST)/bin) + +# MAKE_JARS_TARGET is a staging area for make-jars.pl. When packaging in +# the jar format, make-jars leaves behind a directory structure that's not +# needed in $(FINAL_TARGET). For both, flat, and symlink, the directory +# structure contains the chrome, so leave it in $(FINAL_TARGET). +ifeq (jar,$(MOZ_CHROME_FILE_FORMAT)) +MAKE_JARS_TARGET = $(if $(XPI_NAME),$(FINAL_TARGET).stage,$(DIST)/chrome-stage) +else +MAKE_JARS_TARGET = $(FINAL_TARGET) +endif + +# +# The VERSION_NUMBER is suffixed onto the end of the DLLs we ship. +# Since the longest of these is 5 characters without the suffix, +# be sure to not set VERSION_NUMBER to anything longer than 3 +# characters for Win16's sake. +# +VERSION_NUMBER = 50 + +ifeq ($(HOST_OS_ARCH),WINNT) +win_srcdir := $(subst $(topsrcdir),$(WIN_TOP_SRC),$(srcdir)) +BUILD_TOOLS = $(WIN_TOP_SRC)/build/unix +else +win_srcdir := $(srcdir) +BUILD_TOOLS = $(topsrcdir)/build/unix +endif + +CONFIG_TOOLS = $(MOZ_BUILD_ROOT)/config +AUTOCONF_TOOLS = $(topsrcdir)/build/autoconf + +ifeq ($(OS_ARCH),QNX) +ifeq ($(OS_TARGET),NTO) +LD := qcc -Vgcc_ntox86 -nostdlib +else +LD := $(CC) +endif +endif +ifeq ($(OS_ARCH),BeOS) +BEOS_ADDON_WORKAROUND = 1 +endif + +# +# Strip off the excessively long version numbers on these platforms, +# but save the version to allow multiple versions of the same base +# platform to be built in the same tree. +# +ifneq (,$(filter FreeBSD HP-UX IRIX Linux NetBSD OpenBSD OSF1 SunOS,$(OS_ARCH))) +OS_RELEASE := $(basename $(OS_RELEASE)) + +# Allow the user to ignore the OS_VERSION, which is usually irrelevant. +ifdef WANT_MOZILLA_CONFIG_OS_VERSION +OS_VERS := $(suffix $(OS_RELEASE)) +OS_VERSION := $(shell echo $(OS_VERS) | sed 's/-.*//') +endif + +endif + +OS_CONFIG := $(OS_ARCH)$(OS_RELEASE) + +FINAL_LINK_LIBS = $(DEPTH)/config/final-link-libs +FINAL_LINK_COMPS = $(DEPTH)/config/final-link-comps +FINAL_LINK_COMP_NAMES = $(DEPTH)/config/final-link-comp-names + +MOZ_UNICHARUTIL_LIBS = $(LIBXUL_DIST)/lib/$(LIB_PREFIX)unicharutil_s.$(LIB_SUFFIX) +MOZ_WIDGET_SUPPORT_LIBS = $(DIST)/lib/$(LIB_PREFIX)widgetsupport_s.$(LIB_SUFFIX) + +ifdef MOZ_MEMORY +ifneq ($(OS_ARCH),WINNT) +JEMALLOC_LIBS = $(MKSHLIB_FORCE_ALL) $(call EXPAND_LIBNAME,jemalloc) $(MKSHLIB_UNFORCE_ALL) +endif +endif + +# determine debug-related options +_DEBUG_CFLAGS := +_DEBUG_LDFLAGS := + +ifndef MOZ_DEBUG + # global debugging is disabled + # check if it was explicitly enabled for this module + ifneq (, $(findstring $(MODULE), $(MOZ_DEBUG_MODULES))) + MOZ_DEBUG:=1 + endif +else + # global debugging is enabled + # check if it was explicitly disabled for this module + ifneq (, $(findstring ^$(MODULE), $(MOZ_DEBUG_MODULES))) + MOZ_DEBUG:= + endif +endif + +ifdef MOZ_DEBUG + _DEBUG_CFLAGS += $(MOZ_DEBUG_ENABLE_DEFS) + XULPPFLAGS += $(MOZ_DEBUG_ENABLE_DEFS) +else + _DEBUG_CFLAGS += $(MOZ_DEBUG_DISABLE_DEFS) + XULPPFLAGS += $(MOZ_DEBUG_DISABLE_DEFS) +endif + +# determine if -g should be passed to the compiler, based on +# the current module, and the value of MOZ_DBGRINFO_MODULES + +ifdef MOZ_DEBUG + MOZ_DBGRINFO_MODULES += ALL_MODULES + pattern := ALL_MODULES ^ALL_MODULES +else + MOZ_DBGRINFO_MODULES += ^ALL_MODULES + pattern := ALL_MODULES ^ALL_MODULES +endif + +ifdef MODULE + # our current Makefile specifies a module name - add it to our pattern + pattern += $(MODULE) ^$(MODULE) +endif + +# start by finding the first relevant module name +# (remember that the order of the module names in MOZ_DBGRINFO_MODULES +# is reversed from the order the user specified to configure - +# this allows the user to put general names at the beginning +# of the list, and to override them with explicit module names later +# in the list) + +first_match:=$(firstword $(filter $(pattern), $(MOZ_DBGRINFO_MODULES))) + +ifeq ($(first_match), $(MODULE)) + # the user specified explicitly that + # this module should be compiled with -g + _DEBUG_CFLAGS += $(MOZ_DEBUG_FLAGS) + _DEBUG_LDFLAGS += $(MOZ_DEBUG_LDFLAGS) +else + ifeq ($(first_match), ^$(MODULE)) + # the user specified explicitly that this module + # should not be compiled with -g (nothing to do) + else + ifeq ($(first_match), ALL_MODULES) + # the user didn't mention this module explicitly, + # but wanted all modules to be compiled with -g + _DEBUG_CFLAGS += $(MOZ_DEBUG_FLAGS) + _DEBUG_LDFLAGS += $(MOZ_DEBUG_LDFLAGS) + else + ifeq ($(first_match), ^ALL_MODULES) + # the user didn't mention this module explicitly, + # but wanted all modules to be compiled without -g (nothing to do) + endif + endif + endif +endif + + +# append debug flags +# (these might have been above when processing MOZ_DBGRINFO_MODULES) +OS_CFLAGS += $(_DEBUG_CFLAGS) +OS_CXXFLAGS += $(_DEBUG_CFLAGS) +OS_LDFLAGS += $(_DEBUG_LDFLAGS) + +# MOZ_PROFILE equivs for win32 +ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_) +ifdef MOZ_DEBUG +ifneq (,$(MOZ_BROWSE_INFO)$(MOZ_BSCFILE)) +OS_CFLAGS += -FR +OS_CXXFLAGS += -FR +endif +else # ! MOZ_DEBUG + +# MOZ_DEBUG_SYMBOLS generates debug symbols in separate PDB files. +# Used for generating an optimized build with debugging symbols. +# Used in the Windows nightlies to generate symbols for crash reporting. +ifdef MOZ_DEBUG_SYMBOLS +OS_CXXFLAGS += -Zi -UDEBUG -DNDEBUG +OS_CFLAGS += -Zi -UDEBUG -DNDEBUG +OS_LDFLAGS += -DEBUG -OPT:REF -OPT:nowin98 +endif + +ifdef MOZ_QUANTIFY +# -FIXED:NO is needed for Quantify to work, but it increases the size +# of executables, so only use it if building for Quantify. +WIN32_EXE_LDFLAGS += -FIXED:NO + +# We need -OPT:NOICF to prevent identical methods from being merged together. +# Otherwise, Quantify doesn't know which method was actually called when it's +# showing you the profile. +OS_LDFLAGS += -OPT:NOICF +endif + +# +# Handle trace-malloc in optimized builds. +# No opt to give sane callstacks. +# +ifdef NS_TRACE_MALLOC +MOZ_OPTIMIZE_FLAGS=-Zi -Od -UDEBUG -DNDEBUG +OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF -OPT:nowin98 +endif # NS_TRACE_MALLOC + +endif # MOZ_DEBUG +endif # WINNT && !GNU_CC + +# +# Build using PIC by default +# Do not use PIC if not building a shared lib (see exceptions below) +# + +ifndef BUILD_STATIC_LIBS +_ENABLE_PIC=1 +endif +ifneq (,$(FORCE_SHARED_LIB)$(FORCE_USE_PIC)) +_ENABLE_PIC=1 +endif + +# In Firefox, all components are linked into either libxul or the static +# meta-component, and should be compiled with PIC. +ifdef MOZ_META_COMPONENT +_ENABLE_PIC=1 +endif + +# If module is going to be merged into the nsStaticModule, +# make sure that the entry points are translated and +# the module is built static. + +ifdef IS_COMPONENT +ifdef EXPORT_LIBRARY +ifneq (,$(BUILD_STATIC_LIBS)) +ifdef MODULE_NAME +DEFINES += -DXPCOM_TRANSLATE_NSGM_ENTRY_POINT=1 +FORCE_STATIC_LIB=1 +endif +endif +endif +endif + +# Determine if module being compiled is destined +# to be merged into libxul + +ifdef MOZ_ENABLE_LIBXUL +ifdef LIBXUL_LIBRARY +ifdef IS_COMPONENT +ifdef MODULE_NAME +DEFINES += -DXPCOM_TRANSLATE_NSGM_ENTRY_POINT=1 +else +$(error Component makefile does not specify MODULE_NAME.) +endif +endif +FORCE_STATIC_LIB=1 +_ENABLE_PIC=1 +SHORT_LIBNAME= +endif +endif + +# If we are building this component into an extension/xulapp, it cannot be +# statically linked. In the future we may want to add a xulapp meta-component +# build option. + +ifdef XPI_NAME +_ENABLE_PIC=1 +ifdef IS_COMPONENT +EXPORT_LIBRARY= +FORCE_STATIC_LIB= +FORCE_SHARED_LIB=1 +endif +endif + +# +# Disable PIC if necessary +# + +ifndef _ENABLE_PIC +DSO_CFLAGS= +ifeq ($(OS_ARCH)_$(HAVE_GCC3_ABI),Darwin_1) +DSO_PIC_CFLAGS=-mdynamic-no-pic +else +DSO_PIC_CFLAGS= +endif +endif + +# This comes from configure +ifdef MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE +NO_PROFILE_GUIDED_OPTIMIZE = 1 +endif + +# Enable profile-based feedback +ifndef NO_PROFILE_GUIDED_OPTIMIZE +ifdef MOZ_PROFILE_GENERATE +# No sense in profiling tools +ifndef INTERNAL_TOOLS +OS_CFLAGS += $(PROFILE_GEN_CFLAGS) +OS_CXXFLAGS += $(PROFILE_GEN_CFLAGS) +OS_LDFLAGS += $(PROFILE_GEN_LDFLAGS) +ifeq (WINNT,$(OS_ARCH)) +AR_FLAGS += -LTCG +endif +endif # INTERNAL_TOOLS +endif # MOZ_PROFILE_GENERATE + +ifdef MOZ_PROFILE_USE +ifndef INTERNAL_TOOLS +OS_CFLAGS += $(PROFILE_USE_CFLAGS) +OS_CXXFLAGS += $(PROFILE_USE_CFLAGS) +OS_LDFLAGS += $(PROFILE_USE_LDFLAGS) +ifeq (WINNT,$(OS_ARCH)) +AR_FLAGS += -LTCG +endif +endif # INTERNAL_TOOLS +endif # MOZ_PROFILE_USE +endif # NO_PROFILE_GUIDED_OPTIMIZE + + +# Does the makefile specifies the internal XPCOM API linkage? +ifneq (,$(MOZILLA_INTERNAL_API)$(LIBXUL_LIBRARY)) +DEFINES += -DMOZILLA_INTERNAL_API +endif + +# Force XPCOM/widget/gfx methods to be _declspec(dllexport) when we're +# building libxul libraries +ifdef MOZ_ENABLE_LIBXUL +ifdef LIBXUL_LIBRARY +DEFINES += \ + -D_IMPL_NS_COM \ + -DEXPORT_XPT_API \ + -DEXPORT_XPTC_API \ + -D_IMPL_NS_COM_OBSOLETE \ + -D_IMPL_NS_GFX \ + -D_IMPL_NS_WIDGET \ + -DIMPL_XREAPI \ + -DIMPL_NS_NET \ + -DIMPL_THEBES \ + $(NULL) + +ifndef MOZ_NATIVE_ZLIB +DEFINES += -DZLIB_INTERNAL +endif +endif +endif + +# Force _all_ exported methods to be |_declspec(dllexport)| when we're +# building them into the executable. + +ifeq (,$(filter-out WINNT WINCE OS2, $(OS_ARCH))) +ifdef BUILD_STATIC_LIBS +DEFINES += \ + -D_IMPL_NS_GFX \ + -D_IMPL_NS_MSG_BASE \ + -D_IMPL_NS_WIDGET \ + $(NULL) +endif +endif + +# Flags passed to make-jars.pl + +MAKE_JARS_FLAGS = \ + -t $(topsrcdir) \ + -f $(MOZ_CHROME_FILE_FORMAT) \ + $(NULL) + +ifdef USE_EXTENSION_MANIFEST +MAKE_JARS_FLAGS += -e +endif + +ifdef BOTH_MANIFESTS +MAKE_JARS_FLAGS += --both-manifests +endif + +TAR_CREATE_FLAGS = -cvhf + +ifeq ($(OS_ARCH),BSD_OS) +TAR_CREATE_FLAGS = -cvLf +endif + +ifeq ($(OS_ARCH),OS2) +TAR_CREATE_FLAGS = -cvf +endif + +# +# Personal makefile customizations go in these optional make include files. +# +MY_CONFIG := $(DEPTH)/config/myconfig.mk +MY_RULES := $(DEPTH)/config/myrules.mk + +# +# Default command macros; can be overridden in .mk. +# +CCC = $(CXX) +NFSPWD = $(CONFIG_TOOLS)/nfspwd +PURIFY = purify $(PURIFYOPTIONS) +QUANTIFY = quantify $(QUANTIFYOPTIONS) +ifdef CROSS_COMPILE +XPIDL_COMPILE = $(CYGWIN_WRAPPER) $(LIBXUL_DIST)/host/bin/host_xpidl$(HOST_BIN_SUFFIX) +XPIDL_LINK = $(CYGWIN_WRAPPER) $(LIBXUL_DIST)/host/bin/host_xpt_link$(HOST_BIN_SUFFIX) +else +XPIDL_COMPILE = $(CYGWIN_WRAPPER) $(LIBXUL_DIST)/bin/xpidl$(BIN_SUFFIX) +XPIDL_LINK = $(CYGWIN_WRAPPER) $(LIBXUL_DIST)/bin/xpt_link$(BIN_SUFFIX) +endif + +# Java macros +JAVA_GEN_DIR = _javagen +JAVA_DIST_DIR = $(DEPTH)/$(JAVA_GEN_DIR) +JAVA_IFACES_PKG_NAME = org/mozilla/interfaces + +REQ_INCLUDES = -I$(srcdir) -I. $(foreach d,$(REQUIRES),-I$(DIST)/include/$d) -I$(DIST)/include +ifdef LIBXUL_SDK +REQ_INCLUDES_SDK = $(foreach d,$(REQUIRES),-I$(LIBXUL_SDK)/include/$d) -I$(LIBXUL_SDK)/include +endif + +INCLUDES = $(LOCAL_INCLUDES) $(REQ_INCLUDES) $(REQ_INCLUDES_SDK) -I$(PUBLIC) $(OS_INCLUDES) + +ifndef MOZILLA_INTERNAL_API +INCLUDES += -I$(LIBXUL_DIST)/sdk/include +endif + +# The entire tree should be subject to static analysis using the XPCOM +# script. Additional scripts may be added by specific subdirectories. + +DEHYDRA_SCRIPT = $(topsrcdir)/xpcom/analysis/static-checking.js + +DEHYDRA_MODULES = \ + $(topsrcdir)/xpcom/analysis/final.js \ + $(NULL) + +TREEHYDRA_MODULES = \ + $(topsrcdir)/xpcom/analysis/outparams.js \ + $(topsrcdir)/xpcom/analysis/stack.js \ + $(topsrcdir)/xpcom/analysis/flow.js \ + $(NULL) + +DEHYDRA_ARGS = \ + --topsrcdir=$(topsrcdir) \ + --objdir=$(DEPTH) \ + --dehydra-modules=$(subst $(NULL) ,$(COMMA),$(strip $(DEHYDRA_MODULES))) \ + --treehydra-modules=$(subst $(NULL) ,$(COMMA),$(strip $(TREEHYDRA_MODULES))) \ + $(NULL) + +DEHYDRA_FLAGS = -fplugin=$(DEHYDRA_PATH) -fplugin-arg='$(DEHYDRA_SCRIPT) $(DEHYDRA_ARGS)' + +ifdef DEHYDRA_PATH +OS_CXXFLAGS += $(DEHYDRA_FLAGS) +endif + +CFLAGS = $(OS_CFLAGS) +CXXFLAGS = $(OS_CXXFLAGS) +LDFLAGS = $(OS_LDFLAGS) $(MOZ_FIX_LINK_PATHS) + +# Allow each module to override the *default* optimization settings +# by setting MODULE_OPTIMIZE_FLAGS if the developer has not given +# arguments to --enable-optimize +ifdef MOZ_OPTIMIZE +ifeq (1,$(MOZ_OPTIMIZE)) +ifdef MODULE_OPTIMIZE_FLAGS +CFLAGS += $(MODULE_OPTIMIZE_FLAGS) +CXXFLAGS += $(MODULE_OPTIMIZE_FLAGS) +else +CFLAGS += $(MOZ_OPTIMIZE_FLAGS) +CXXFLAGS += $(MOZ_OPTIMIZE_FLAGS) +endif # MODULE_OPTIMIZE_FLAGS +else +CFLAGS += $(MOZ_OPTIMIZE_FLAGS) +CXXFLAGS += $(MOZ_OPTIMIZE_FLAGS) +endif # MOZ_OPTIMIZE == 1 +LDFLAGS += $(MOZ_OPTIMIZE_LDFLAGS) +endif # MOZ_OPTIMIZE + +ifdef CROSS_COMPILE +HOST_CFLAGS += $(HOST_OPTIMIZE_FLAGS) +else +ifdef MOZ_OPTIMIZE +ifeq (1,$(MOZ_OPTIMIZE)) +ifdef MODULE_OPTIMIZE_FLAGS +HOST_CFLAGS += $(MODULE_OPTIMIZE_FLAGS) +else +HOST_CFLAGS += $(MOZ_OPTIMIZE_FLAGS) +endif # MODULE_OPTIMIZE_FLAGS +else +HOST_CFLAGS += $(MOZ_OPTIMIZE_FLAGS) +endif # MOZ_OPTIMIZE == 1 +endif # MOZ_OPTIMIZE +endif # CROSS_COMPILE + + +ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_) +#// Currently, unless USE_STATIC_LIBS is defined, the multithreaded +#// DLL version of the RTL is used... +#// +#//------------------------------------------------------------------------ +ifdef USE_STATIC_LIBS +RTL_FLAGS=-MT # Statically linked multithreaded RTL +ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)) +ifndef MOZ_NO_DEBUG_RTL +RTL_FLAGS=-MTd # Statically linked multithreaded MSVC4.0 debug RTL +endif +endif # MOZ_DEBUG || NS_TRACE_MALLOC + +else # !USE_STATIC_LIBS + +RTL_FLAGS=-MD # Dynamically linked, multithreaded RTL +ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)) +ifndef MOZ_NO_DEBUG_RTL +RTL_FLAGS=-MDd # Dynamically linked, multithreaded MSVC4.0 debug RTL +endif +endif # MOZ_DEBUG || NS_TRACE_MALLOC +endif # USE_STATIC_LIBS +endif # WINNT && !GNU_CC + +ifeq ($(OS_ARCH),Darwin) +# Darwin doesn't cross-compile, so just set both types of flags here. +HOST_CMFLAGS += -fobjc-exceptions +HOST_CMMFLAGS += -fobjc-exceptions +OS_COMPILE_CMFLAGS += -fobjc-exceptions +OS_COMPILE_CMMFLAGS += -fobjc-exceptions +endif + +COMPILE_CFLAGS = $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS) $(PROFILER_CFLAGS) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CFLAGS) +COMPILE_CXXFLAGS = $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS) $(PROFILER_CFLAGS) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(CXXFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CXXFLAGS) +COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) +COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) + +ifndef CROSS_COMPILE +HOST_CFLAGS += $(RTL_FLAGS) +endif + +# +# Name of the binary code directories +# +# Override defaults + +# We need to know where to find the libraries we +# put on the link line for binaries, and should +# we link statically or dynamic? Assuming dynamic for now. + +ifneq (WINNT_,$(OS_ARCH)_$(GNU_CC)) +ifneq (,$(filter-out WINCE,$(OS_ARCH))) +LIBS_DIR = -L$(DIST)/bin -L$(DIST)/lib +ifdef LIBXUL_SDK +LIBS_DIR += -L$(LIBXUL_SDK)/bin -L$(LIBXUL_SDK)/lib +endif +endif +endif + +# Default location of include files +IDL_DIR = $(DIST)/idl +ifdef MODULE +PUBLIC = $(DIST)/include/$(MODULE) +else +PUBLIC = $(DIST)/include +endif + +XPIDL_FLAGS = -I$(srcdir) -I$(IDL_DIR) +ifdef LIBXUL_SDK +XPIDL_FLAGS += -I$(LIBXUL_SDK)/idl +endif + +SDK_PUBLIC = $(DIST)/sdk/include +SDK_IDL_DIR = $(DIST)/sdk/idl +SDK_LIB_DIR = $(DIST)/sdk/lib +SDK_BIN_DIR = $(DIST)/sdk/bin + +DEPENDENCIES = .md + +MOZ_COMPONENT_LIBS=$(XPCOM_LIBS) $(MOZ_COMPONENT_NSPR_LIBS) + +ifdef GC_LEAK_DETECTOR +XPCOM_LIBS += -lboehm +endif + +ifeq (xpconnect, $(findstring xpconnect, $(BUILD_MODULES))) +DEFINES += -DXPCONNECT_STANDALONE +endif + +ifeq ($(OS_ARCH),OS2) +ELF_DYNSTR_GC = echo +else +ELF_DYNSTR_GC = : +endif + +ifndef CROSS_COMPILE +ifdef USE_ELF_DYNSTR_GC +ifdef MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS +ELF_DYNSTR_GC = $(DEPTH)/config/elf-dynstr-gc +endif +endif +endif + +ifeq ($(OS_ARCH),Darwin) +ifdef NEXT_ROOT +export NEXT_ROOT +PBBUILD = NEXT_ROOT= $(PBBUILD_BIN) +else # NEXT_ROOT +PBBUILD = $(PBBUILD_BIN) +endif # NEXT_ROOT +PBBUILD_SETTINGS = GCC_VERSION="$(GCC_VERSION)" SYMROOT=build ARCHS="$(OS_TEST)" +ifdef MACOS_SDK_DIR +PBBUILD_SETTINGS += SDKROOT="$(MACOS_SDK_DIR)" +endif # MACOS_SDK_DIR +ifdef MACOSX_DEPLOYMENT_TARGET +export MACOSX_DEPLOYMENT_TARGET +PBBUILD_SETTINGS += MACOSX_DEPLOYMENT_TARGET="$(MACOSX_DEPLOYMENT_TARGET)" +endif # MACOSX_DEPLOYMENT_TARGET +ifdef MOZ_OPTIMIZE +ifeq (2,$(MOZ_OPTIMIZE)) +# Only override project defaults if the config specified explicit settings +PBBUILD_SETTINGS += GCC_MODEL_TUNING= OPTIMIZATION_CFLAGS="$(MOZ_OPTIMIZE_FLAGS)" +endif # MOZ_OPTIMIZE=2 +endif # MOZ_OPTIMIZE +ifeq (1,$(HAS_XCODE_2_1)) +# Xcode 2.1 puts its build products in a directory corresponding to the +# selected build style/configuration. +XCODE_PRODUCT_DIR = build/$(BUILDSTYLE) +else +XCODE_PRODUCT_DIR = build +endif # HAS_XCODE_2_1=1 +endif # OS_ARCH=Darwin + + +ifdef MOZ_NATIVE_MAKEDEPEND +MKDEPEND_DIR = +MKDEPEND = $(CYGWIN_WRAPPER) $(MOZ_NATIVE_MAKEDEPEND) +else +MKDEPEND_DIR = $(CONFIG_TOOLS)/mkdepend +MKDEPEND = $(CYGWIN_WRAPPER) $(MKDEPEND_DIR)/mkdepend$(BIN_SUFFIX) +endif + +# Set link flags according to whether we want a console. +ifdef MOZ_WINCONSOLE +ifeq ($(MOZ_WINCONSOLE),1) +ifeq ($(OS_ARCH),OS2) +BIN_FLAGS += -Zlinker -PM:VIO +endif +ifeq ($(OS_ARCH),WINNT) +ifdef GNU_CC +WIN32_EXE_LDFLAGS += -mconsole +else +WIN32_EXE_LDFLAGS += -SUBSYSTEM:CONSOLE +endif +endif +else # MOZ_WINCONSOLE +ifeq ($(OS_ARCH),OS2) +BIN_FLAGS += -Zlinker -PM:PM +endif +ifeq ($(OS_ARCH),WINNT) +ifdef GNU_CC +WIN32_EXE_LDFLAGS += -mwindows +else +WIN32_EXE_LDFLAGS += -SUBSYSTEM:WINDOWS +endif +endif +endif +endif + +# Flags needed to link against the component library +ifdef MOZ_COMPONENTLIB +MOZ_COMPONENTLIB_EXTRA_DSO_LIBS = mozcomps xpcom_compat + +# Tell the linker where NSS is, if we're building crypto +ifeq ($(OS_ARCH),Darwin) +ifeq (,$(findstring crypto,$(MOZ_META_COMPONENTS))) +MOZ_COMPONENTLIB_EXTRA_LIBS = $(foreach library, $(patsubst -l%, $(LIB_PREFIX)%$(DLL_SUFFIX), $(filter -l%, $(NSS_LIBS))), -dylib_file @executable_path/$(library):$(DIST)/bin/$(library)) +endif +endif +endif + +# If we're building a component on MSVC, we don't want to generate an +# import lib, because that import lib will collide with the name of a +# static version of the same library. +ifeq ($(GNU_LD)$(OS_ARCH),WINNT) +ifdef IS_COMPONENT +LDFLAGS += -IMPLIB:fake.lib +DELETE_AFTER_LINK = fake.lib fake.exp +endif +endif + +# +# Include any personal overrides the user might think are needed. +# +-include $(topsrcdir)/$(MOZ_BUILD_APP)/app-config.mk +-include $(MY_CONFIG) + +###################################################################### +# Now test variables that might have been set or overridden by $(MY_CONFIG). + +DEFINES += -DOSTYPE=\"$(OS_CONFIG)\" +DEFINES += -DOSARCH=$(OS_ARCH) + +# For profiling +ifdef ENABLE_EAZEL_PROFILER +ifndef INTERNAL_TOOLS +ifneq ($(LIBRARY_NAME), xpt) +ifneq (, $(findstring $(shell $(topsrcdir)/build/unix/print-depth-path.sh | awk -F/ '{ print $$2; }'), $(MOZ_PROFILE_MODULES))) +PROFILER_CFLAGS = $(EAZEL_PROFILER_CFLAGS) -DENABLE_EAZEL_PROFILER +PROFILER_LIBS = $(EAZEL_PROFILER_LIBS) +endif +endif +endif +endif + +###################################################################### + +GARBAGE += $(DEPENDENCIES) $(MKDEPENDENCIES) $(MKDEPENDENCIES).bak core $(wildcard core.[0-9]*) $(wildcard *.err) $(wildcard *.pure) $(wildcard *_pure_*.o) Templates.DB + +ifeq ($(OS_ARCH),Darwin) +ifndef NSDISTMODE +NSDISTMODE=absolute_symlink +endif +PWD := $(shell pwd) +endif + +ifdef NSINSTALL_BIN +NSINSTALL = $(CYGWIN_WRAPPER) $(NSINSTALL_BIN) +else +ifeq (WINNT,$(CROSS_COMPILE)$(OS_ARCH)) +NSINSTALL = $(CYGWIN_WRAPPER) $(MOZ_TOOLS_DIR)/bin/nsinstall +else +ifeq (OS2,$(CROSS_COMPILE)$(OS_ARCH)) +NSINSTALL = $(MOZ_TOOLS_DIR)/nsinstall +else +NSINSTALL = $(CONFIG_TOOLS)/nsinstall +endif # OS2 +endif # WINNT +endif # NSINSTALL_BIN + + +ifeq (,$(CROSS_COMPILE)$(filter-out WINNT OS2, $(OS_ARCH))) +INSTALL = $(NSINSTALL) +else +ifeq ($(NSDISTMODE),copy) +# copy files, but preserve source mtime +INSTALL = $(NSINSTALL) -t +else +ifeq ($(NSDISTMODE),absolute_symlink) +# install using absolute symbolic links +ifeq ($(OS_ARCH),Darwin) +INSTALL = $(NSINSTALL) -L $(PWD) +else +INSTALL = $(NSINSTALL) -L `$(NFSPWD)` +endif # Darwin +else +# install using relative symbolic links +INSTALL = $(NSINSTALL) -R +endif # absolute_symlink +endif # copy +endif # WINNT/OS2 + +ifeq (,$(filter-out WINCE,$(OS_ARCH))) +NSINSTALL = $(CYGWIN_WRAPPER) nsinstall +INSTALL = $(CYGWIN_WRAPPER) nsinstall +endif + +# Use nsinstall in copy mode to install files on the system +SYSINSTALL = $(NSINSTALL) -t + +ifeq ($(OS_ARCH),WINNT) +ifneq (,$(CYGDRIVE_MOUNT)) +export CYGDRIVE_MOUNT +endif +endif + +# +# Localization build automation +# + +# Because you might wish to "make locales AB_CD=ab-CD", we don't hardcode +# MOZ_UI_LOCALE directly, but use an intermediate variable that can be +# overridden by the command line. (Besides, AB_CD is prettier). +AB_CD = $(MOZ_UI_LOCALE) + +ifndef L10NBASEDIR +L10NBASEDIR = $(error L10NBASEDIR not defined by configure) +endif + +EXPAND_LOCALE_SRCDIR = $(if $(filter en-US,$(AB_CD)),$(topsrcdir)/$(1)/en-US,$(L10NBASEDIR)/$(AB_CD)/$(subst /locales,,$(1))) + +ifdef relativesrcdir +LOCALE_SRCDIR = $(call EXPAND_LOCALE_SRCDIR,$(relativesrcdir)) +endif + +ifdef LOCALE_SRCDIR +# if LOCALE_MERGEDIR is set, use mergedir first, then the localization, +# and finally en-US +ifdef LOCALE_MERGEDIR +MAKE_JARS_FLAGS += -c $(LOCALE_MERGEDIR)/$(subst /locales,,$(relativesrcdir)) +endif +MAKE_JARS_FLAGS += -c $(LOCALE_SRCDIR) +ifdef LOCALE_MERGEDIR +MAKE_JARS_FLAGS += -c $(topsrcdir)/$(relativesrcdir)/en-US +endif +endif + +ifeq (,$(filter WINCE WINNT OS2,$(OS_ARCH))) +RUN_TEST_PROGRAM = $(DIST)/bin/run-mozilla.sh +endif + +# +# Java macros +# + +# Make sure any compiled classes work with at least JVM 1.4 +JAVAC_FLAGS += -source 1.4 + +ifdef MOZ_DEBUG +JAVAC_FLAGS += -g +endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/fastcwd.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/fastcwd.pl new file mode 100644 index 0000000..c327ccf --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/fastcwd.pl @@ -0,0 +1,66 @@ +#!perl5 +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +sub fastcwd { + local($odev, $oino, $cdev, $cino, $tdev, $tino); + local(@path, $path); + local(*DIR); + + ($cdev, $cino) = stat('.'); + for (;;) { + ($odev, $oino) = ($cdev, $cino); + chdir('..'); + ($cdev, $cino) = stat('.'); + last if $odev == $cdev && $oino == $cino; + opendir(DIR, '.'); + for (;;) { + $_ = readdir(DIR); + next if $_ eq '.'; + next if $_ eq '..'; + + last unless $_; + ($tdev, $tino) = lstat($_); + last unless $tdev != $odev || $tino != $oino; + } + closedir(DIR); + unshift(@path, $_); + } + chdir($path = '/' . join('/', @path)); + $path; +} +1; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/gcc_hidden.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/gcc_hidden.h new file mode 100644 index 0000000..58140c1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/gcc_hidden.h @@ -0,0 +1,2 @@ +/* Begin all files as hidden visibility */ +#pragma GCC visibility push(hidden) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/insure.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/insure.mk new file mode 100644 index 0000000..fc796eb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/insure.mk @@ -0,0 +1,53 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +INCLUDED_INSURE_MK = 1 + +INSURE_MATCH_SCRIPT=$(topsrcdir)/build/autoconf/match-dir.sh + +INSURE_EXCLUDE=$(shell $(INSURE_MATCH_SCRIPT) $(MOZ_INSURE_EXCLUDE_DIRS)) + +INSURE_INCLUDE=$(shell $(INSURE_MATCH_SCRIPT) $(MOZ_INSURE_DIRS)) + +ifeq ($(INSURE_EXCLUDE),0) + +ifeq ($(INSURE_INCLUDE),1) +CC := $(MOZ_INSURE) +CXX := $(MOZ_INSURE) +endif # INSURE_INCLUDE == 1 + +endif # INSURE_EXCLUDE == 0 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/make-system-wrappers.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/make-system-wrappers.pl new file mode 100644 index 0000000..31c9af4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/make-system-wrappers.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# IBM Corporation. +# Portions created by the Initial Developer are Copyright (C) 2004 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Brian Ryner +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +$output_dir = shift; + +while () { + chomp; + if (-e "$output_dir/$_") { + next; + } + + if (/(.*)\/[^\/*]/) { + mkdir "$output_dir/$1"; + } + + open OUT, ">$output_dir/$_"; + print OUT "#pragma GCC system_header\n"; # suppress include_next warning + print OUT "#pragma GCC visibility push(default)\n"; + print OUT "#include_next \<$_\>\n"; + print OUT "#pragma GCC visibility pop\n"; + close OUT; +} + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/milestone.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/milestone.pl new file mode 100644 index 0000000..e3cee2a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/milestone.pl @@ -0,0 +1,112 @@ +#!/usr/bin/perl -w +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Win32 Version System. +# +# The Initial Developer of the Original Code is Netscape Communications Corporation +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +use Getopt::Long; + +use strict; +use vars qw( + $OBJDIR + $SRCDIR + $TOPSRCDIR + $SCRIPTDIR + @TEMPLATE_FILE + $MILESTONE_FILE + $MILESTONE + $MILESTONE_NUM + @MILESTONE_PARTS + $MINI_VERSION + $MICRO_VERSION + $opt_debug + $opt_template + $opt_help + ); + +$SCRIPTDIR = $0; +$SCRIPTDIR =~ s/[^\/]*$//; +push(@INC,$SCRIPTDIR); + +require "Moz/Milestone.pm"; + +&GetOptions('topsrcdir=s' => \$TOPSRCDIR, 'srcdir=s' => \$SRCDIR, 'objdir=s' => \$OBJDIR, 'debug', 'help', 'template'); + +if (defined($opt_help)) { + &usage(); + exit; +} + +if (defined($opt_template)) { + @TEMPLATE_FILE = @ARGV; + if ($opt_debug) { + print("TEMPLATE_FILE = --@TEMPLATE_FILE--\n"); + } +} + +if (!defined($SRCDIR)) { $SRCDIR = '.'; } +if (!defined($OBJDIR)) { $OBJDIR = '.'; } + +$MILESTONE_FILE = "$TOPSRCDIR/config/milestone.txt"; +@MILESTONE_PARTS = (0, 0, 0, 0); + +# +# Grab milestone (top line of $MILESTONE_FILE that starts with a digit) +# +my $milestone = Moz::Milestone::getOfficialMilestone($MILESTONE_FILE); + +if (defined(@TEMPLATE_FILE)) { + my $TFILE; + + foreach $TFILE (@TEMPLATE_FILE) { + my $BUILT_FILE = "$OBJDIR/$TFILE"; + $TFILE = "$SRCDIR/$TFILE.tmpl"; + + if (-e $TFILE) { + + Moz::Milestone::build_file($TFILE,$BUILT_FILE); + + } else { + warn("$0: No such file $TFILE!\n"); + } + } +} else { + print "$milestone\n"; +} + +sub usage() { + print <s_value = NULL; + } + return (sp); +} + +pperror(tag, x0,x1,x2,x3,x4) + int tag,x0,x1,x2,x3,x4; +{ + warning("\"%s\", line %d: ", currentinc->i_file, currentfile->f_line); + warning(x0,x1,x2,x3,x4); +} + + +yyerror(s) + register char *s; +{ + fatalerr("Fatal error: %s\n", s); +} +#else /* not CPP */ + +#include "ifparser.h" +struct _parse_data { + struct filepointer *filep; + struct inclist *inc; + char *filename; + const char *line; +}; + +static const char * +my_if_errors (IfParser *ip, const char *cp, const char *expecting) +{ + struct _parse_data *pd = (struct _parse_data *) ip->data; + int lineno = pd->filep->f_line; + char *filename = pd->filename; + char prefix[300]; + int prefixlen; + int i; + + sprintf (prefix, "\"%s\":%d", filename, lineno); + prefixlen = strlen(prefix); + fprintf (stderr, "%s: %s", prefix, pd->line); + i = cp - pd->line; + if (i > 0 && pd->line[i-1] != '\n') { + putc ('\n', stderr); + } + for (i += prefixlen + 3; i > 0; i--) { + putc (' ', stderr); + } + fprintf (stderr, "^--- expecting %s\n", expecting); + return NULL; +} + + +#define MAXNAMELEN 256 + +static struct symtab ** +lookup_variable (IfParser *ip, const char *var, int len) +{ + char tmpbuf[MAXNAMELEN + 1]; + struct _parse_data *pd = (struct _parse_data *) ip->data; + + if (len > MAXNAMELEN) + return 0; + + strncpy (tmpbuf, var, len); + tmpbuf[len] = '\0'; + return isdefined (tmpbuf, pd->inc, NULL); +} + + +static int +my_eval_defined (IfParser *ip, const char *var, int len) +{ + if (lookup_variable (ip, var, len)) + return 1; + else + return 0; +} + +#define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_') + +static long +my_eval_variable (IfParser *ip, const char *var, int len) +{ + long val; + struct symtab **s; + + s = lookup_variable (ip, var, len); + if (!s) + return 0; + do { + var = (*s)->s_value; + if (!isvarfirstletter(*var) || !strcmp((*s)->s_name, var)) + break; + s = lookup_variable (ip, var, strlen(var)); + } while (s); + + var = ParseIfExpression(ip, var, &val); + if (var && *var) debug(4, ("extraneous: '%s'\n", var)); + return val; +} + +int +cppsetup(char *filename, + char *line, + struct filepointer *filep, + struct inclist *inc) +{ + IfParser ip; + struct _parse_data pd; + long val = 0; + + pd.filep = filep; + pd.inc = inc; + pd.line = line; + pd.filename = filename; + ip.funcs.handle_error = my_if_errors; + ip.funcs.eval_defined = my_eval_defined; + ip.funcs.eval_variable = my_eval_variable; + ip.data = (char *) &pd; + + (void) ParseIfExpression (&ip, line, &val); + if (val) + return IF; + else + return IFFALSE; +} +#endif /* CPP */ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/def.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/def.h new file mode 100644 index 0000000..d6e5f89 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/def.h @@ -0,0 +1,184 @@ +/* $Xorg: def.h,v 1.4 2001/02/09 02:03:16 xorgcvs Exp $ */ +/* + +Copyright (c) 1993, 1994, 1998 The Open Group. + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/config/makedepend/def.h,v 3.14 2003/01/17 17:09:49 tsi Exp $ */ + +#ifndef NO_X11 +#include +#include +#endif +#include +#include +#include +#include +#if 0 +#ifndef X_NOT_POSIX +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE +#endif +#endif +#endif +#include +#include +#include + +#define MAXDEFINES 512 +#define MAXFILES 1024 +#define MAXINCFILES 256 /* "-include" files */ +#define MAXDIRS 1024 +#define SYMTABINC 10 /* must be > 1 for define() to work right */ +#define TRUE 1 +#define FALSE 0 + +/* the following must match the directives table in main.c */ +#define IF 0 +#define IFDEF 1 +#define IFNDEF 2 +#define ELSE 3 +#define ENDIF 4 +#define DEFINE 5 +#define UNDEF 6 +#define INCLUDE 7 +#define LINE 8 +#define PRAGMA 9 +#define ERROR 10 +#define IDENT 11 +#define SCCS 12 +#define ELIF 13 +#define EJECT 14 +#define WARNING 15 +#define INCLUDENEXT 16 +#define IFFALSE 17 /* pseudo value --- never matched */ +#define ELIFFALSE 18 /* pseudo value --- never matched */ +#define INCLUDEDOT 19 /* pseudo value --- never matched */ +#define IFGUESSFALSE 20 /* pseudo value --- never matched */ +#define ELIFGUESSFALSE 21 /* pseudo value --- never matched */ +#define INCLUDENEXTDOT 22 /* pseudo value --- never matched */ + +#ifdef DEBUG +extern int _debugmask; +/* + * debug levels are: + * + * 0 show ifn*(def)*,endif + * 1 trace defined/!defined + * 2 show #include + * 3 show #include SYMBOL + * 4-6 unused + */ +#define debug(level,arg) { if (_debugmask & (1 << level)) warning arg; } +#else +#define debug(level,arg) /**/ +#endif /* DEBUG */ + +typedef unsigned char boolean; + +struct symtab { + char *s_name; + char *s_value; +}; + +/* possible i_flag */ +#define DEFCHECKED (1<<0) /* whether defines have been checked */ +#define NOTIFIED (1<<1) /* whether we have revealed includes */ +#define MARKED (1<<2) /* whether it's in the makefile */ +#define SEARCHED (1<<3) /* whether we have read this */ +#define FINISHED (1<<4) /* whether we are done reading this */ +#define INCLUDED_SYM (1<<5) /* whether #include SYMBOL was found + Can't use i_list if TRUE */ +struct inclist { + char *i_incstring; /* string from #include line */ + char *i_file; /* path name of the include file */ + struct inclist **i_list; /* list of files it itself includes */ + int i_listlen; /* length of i_list */ + struct symtab **i_defs; /* symbol table for this file and its + children when merged */ + int i_ndefs; /* current # defines */ + boolean *i_merged; /* whether we have merged child + defines */ + unsigned char i_flags; +}; + +struct filepointer { + char *f_name; + char *f_p; + char *f_base; + char *f_end; + long f_len; + long f_line; + long cmdinc_count; + char **cmdinc_list; + long cmdinc_line; +}; + +#include +#if defined(macII) && !defined(__STDC__) /* stdlib.h fails to define these */ +char *malloc(), *realloc(); +#endif /* macII */ + +char *copy(char *str); +int match(char *str, char **list); +char *base_name(char *file); +char *getnextline(struct filepointer *fp); +struct symtab **slookup(char *symbol, struct inclist *file); +struct symtab **isdefined(char *symbol, struct inclist *file, + struct inclist **srcfile); +struct symtab **fdefined(char *symbol, struct inclist *file, + struct inclist **srcfile); +struct filepointer *getfile(char *file); +void included_by(struct inclist *ip, + struct inclist *newfile); +struct inclist *newinclude(char *newfile, char *incstring); +void inc_clean (void); +struct inclist *inc_path(char *file, char *include, int type); + +void freefile(struct filepointer *fp); + +void define2(char *name, char *val, struct inclist *file); +void define(char *def, struct inclist *file); +void undefine(char *symbol, struct inclist *file); +int find_includes(struct filepointer *filep, + struct inclist *file, + struct inclist *file_red, + int recursion, boolean failOK); + +void recursive_pr_include(struct inclist *head, + char *file, char *base); +void add_include(struct filepointer *filep, + struct inclist *file, + struct inclist *file_red, + char *include, int type, + boolean failOK); + +int cppsetup(char *filename, + char *line, + struct filepointer *filep, + struct inclist *inc); + + +extern void fatalerr(char *, ...); +extern void warning(char *, ...); +extern void warning1(char *, ...); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/ifparser.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/ifparser.c new file mode 100644 index 0000000..d8d9e76 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/ifparser.c @@ -0,0 +1,549 @@ +/* + * $Xorg: ifparser.c,v 1.3 2000/08/17 19:41:50 cpqbld Exp $ + * + * Copyright 1992 Network Computing Devices, Inc. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Network Computing Devices may not be + * used in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Network Computing Devices makes + * no representations about the suitability of this software for any purpose. + * It is provided ``as is'' without express or implied warranty. + * + * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jim Fulton + * Network Computing Devices, Inc. + * + * Simple if statement processor + * + * This module can be used to evaluate string representations of C language + * if constructs. It accepts the following grammar: + * + * EXPRESSION := VALUE + * | VALUE BINOP EXPRESSION + * | VALUE '?' EXPRESSION ':' EXPRESSION + * + * VALUE := '(' EXPRESSION ')' + * | '!' VALUE + * | '-' VALUE + * | '+' VALUE + * | '~' VALUE + * | 'defined' '(' variable ')' + * | 'defined' variable + * | # variable '(' variable-list ')' + * | variable + * | number + * + * BINOP := '*' | '/' | '%' + * | '+' | '-' + * | '<<' | '>>' + * | '<' | '>' | '<=' | '>=' + * | '==' | '!=' + * | '&' | '^' | '|' + * | '&&' | '||' + * + * The normal C order of precedence is supported. + * + * + * External Entry Points: + * + * ParseIfExpression parse a string for #if + */ +/* $XFree86: xc/config/makedepend/ifparser.c,v 3.11 2002/09/23 01:48:08 tsi Exp $ */ + +#include "ifparser.h" +#include +#include +#include + +/**************************************************************************** + Internal Macros and Utilities for Parser + ****************************************************************************/ + +#define DO(val) if (!(val)) return NULL +#define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff)) +#define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++ +#define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_') + + +static const char * +parse_variable (IfParser *g, const char *cp, const char **varp) +{ + SKIPSPACE (cp); + + if (!isvarfirstletter (*cp)) + return CALLFUNC(g, handle_error) (g, cp, "variable name"); + + *varp = cp; + /* EMPTY */ + for (cp++; isalnum(*cp) || *cp == '_'; cp++) ; + return cp; +} + + +static const char * +parse_number (IfParser *g, const char *cp, long *valp) +{ + long base = 10; + SKIPSPACE (cp); + + if (!isdigit(*cp)) + return CALLFUNC(g, handle_error) (g, cp, "number"); + + *valp = 0; + + if (*cp == '0') { + cp++; + if ((*cp == 'x') || (*cp == 'X')) { + base = 16; + cp++; + } else { + base = 8; + } + } + + /* Ignore overflows and assume ASCII, what source is usually written in */ + while (1) { + int increment = -1; + if (base == 8) { + if ((*cp >= '0') && (*cp <= '7')) + increment = *cp++ - '0'; + } else if (base == 16) { + if ((*cp >= '0') && (*cp <= '9')) + increment = *cp++ - '0'; + else if ((*cp >= 'A') && (*cp <= 'F')) + increment = *cp++ - ('A' - 10); + else if ((*cp >= 'a') && (*cp <= 'f')) + increment = *cp++ - ('a' - 10); + } else { /* Decimal */ + if ((*cp >= '0') && (*cp <= '9')) + increment = *cp++ - '0'; + } + if (increment < 0) + break; + *valp = (*valp * base) + increment; + } + + /* Skip trailing qualifiers */ + while (*cp == 'U' || *cp == 'u' || *cp == 'L' || *cp == 'l') cp++; + return cp; +} + +static const char * +parse_character (IfParser *g, const char *cp, long *valp) +{ + char val; + + SKIPSPACE (cp); + if (*cp == '\\') + switch (cp[1]) { + case 'n': val = '\n'; break; + case 't': val = '\t'; break; + case 'v': val = '\v'; break; + case 'b': val = '\b'; break; + case 'r': val = '\r'; break; + case 'f': val = '\f'; break; + case 'a': val = '\a'; break; + case '\\': val = '\\'; break; + case '?': val = '\?'; break; + case '\'': val = '\''; break; + case '\"': val = '\"'; break; + case 'x': val = (char) strtol (cp + 2, NULL, 16); break; + default: val = (char) strtol (cp + 1, NULL, 8); break; + } + else + val = *cp; + while (*cp != '\'') cp++; + *valp = (long) val; + return cp; +} + +static const char * +parse_value (IfParser *g, const char *cp, long *valp) +{ + const char *var, *varend; + + *valp = 0; + + SKIPSPACE (cp); + if (!*cp) + return cp; + + switch (*cp) { + case '(': + DO (cp = ParseIfExpression (g, cp + 1, valp)); + SKIPSPACE (cp); + if (*cp != ')') + return CALLFUNC(g, handle_error) (g, cp, ")"); + + return cp + 1; /* skip the right paren */ + + case '!': + DO (cp = parse_value (g, cp + 1, valp)); + *valp = !(*valp); + return cp; + + case '-': + DO (cp = parse_value (g, cp + 1, valp)); + *valp = -(*valp); + return cp; + + case '+': + DO (cp = parse_value (g, cp + 1, valp)); + return cp; + + case '~': + DO (cp = parse_value (g, cp + 1, valp)); + *valp = ~(*valp); + return cp; + + case '#': + DO (cp = parse_variable (g, cp + 1, &var)); + SKIPSPACE (cp); + if (*cp != '(') + return CALLFUNC(g, handle_error) (g, cp, "("); + do { + DO (cp = parse_variable (g, cp + 1, &var)); + SKIPSPACE (cp); + } while (*cp && *cp != ')'); + if (*cp != ')') + return CALLFUNC(g, handle_error) (g, cp, ")"); + *valp = 1; /* XXX */ + return cp + 1; + + case '\'': + DO (cp = parse_character (g, cp + 1, valp)); + if (*cp != '\'') + return CALLFUNC(g, handle_error) (g, cp, "'"); + return cp + 1; + + case 'd': + if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) { + int paren = 0; + int len; + + cp += 7; + SKIPSPACE (cp); + if (*cp == '(') { + paren = 1; + cp++; + } + DO (cp = parse_variable (g, cp, &var)); + len = cp - var; + SKIPSPACE (cp); + if (paren && *cp != ')') + return CALLFUNC(g, handle_error) (g, cp, ")"); + *valp = (*(g->funcs.eval_defined)) (g, var, len); + return cp + paren; /* skip the right paren */ + } + /* fall out */ + } + + if (isdigit(*cp)) { + DO (cp = parse_number (g, cp, valp)); + } else if (!isvarfirstletter(*cp)) + return CALLFUNC(g, handle_error) (g, cp, "variable or number"); + else { + DO (cp = parse_variable (g, cp, &var)); + varend = cp; + SKIPSPACE(cp); + if (*cp != '(') { + *valp = (*(g->funcs.eval_variable)) (g, var, varend - var); + } else { + do { + long dummy; + DO (cp = ParseIfExpression (g, cp + 1, &dummy)); + SKIPSPACE(cp); + if (*cp == ')') + break; + if (*cp != ',') + return CALLFUNC(g, handle_error) (g, cp, ","); + } while (1); + + *valp = 1; /* XXX */ + cp++; + } + } + + return cp; +} + + + +static const char * +parse_product (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_value (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '*': + DO (cp = parse_product (g, cp + 1, &rightval)); + *valp = (*valp * rightval); + break; + + case '/': + DO (cp = parse_product (g, cp + 1, &rightval)); + *valp = (*valp / rightval); + break; + + case '%': + DO (cp = parse_product (g, cp + 1, &rightval)); + *valp = (*valp % rightval); + break; + } + return cp; +} + + +static const char * +parse_sum (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_product (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '+': + DO (cp = parse_sum (g, cp + 1, &rightval)); + *valp = (*valp + rightval); + break; + + case '-': + DO (cp = parse_sum (g, cp + 1, &rightval)); + *valp = (*valp - rightval); + break; + } + return cp; +} + + +static const char * +parse_shift (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_sum (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '<': + if (cp[1] == '<') { + DO (cp = parse_shift (g, cp + 2, &rightval)); + *valp = (*valp << rightval); + } + break; + + case '>': + if (cp[1] == '>') { + DO (cp = parse_shift (g, cp + 2, &rightval)); + *valp = (*valp >> rightval); + } + break; + } + return cp; +} + + +static const char * +parse_inequality (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_shift (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '<': + if (cp[1] == '=') { + DO (cp = parse_inequality (g, cp + 2, &rightval)); + *valp = (*valp <= rightval); + } else { + DO (cp = parse_inequality (g, cp + 1, &rightval)); + *valp = (*valp < rightval); + } + break; + + case '>': + if (cp[1] == '=') { + DO (cp = parse_inequality (g, cp + 2, &rightval)); + *valp = (*valp >= rightval); + } else { + DO (cp = parse_inequality (g, cp + 1, &rightval)); + *valp = (*valp > rightval); + } + break; + } + return cp; +} + + +static const char * +parse_equality (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_inequality (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '=': + if (cp[1] == '=') + cp++; + DO (cp = parse_equality (g, cp + 1, &rightval)); + *valp = (*valp == rightval); + break; + + case '!': + if (cp[1] != '=') + break; + DO (cp = parse_equality (g, cp + 2, &rightval)); + *valp = (*valp != rightval); + break; + } + return cp; +} + + +static const char * +parse_band (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_equality (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '&': + if (cp[1] != '&') { + DO (cp = parse_band (g, cp + 1, &rightval)); + *valp = (*valp & rightval); + } + break; + } + return cp; +} + + +static const char * +parse_bxor (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_band (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '^': + DO (cp = parse_bxor (g, cp + 1, &rightval)); + *valp = (*valp ^ rightval); + break; + } + return cp; +} + + +static const char * +parse_bor (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_bxor (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '|': + if (cp[1] != '|') { + DO (cp = parse_bor (g, cp + 1, &rightval)); + *valp = (*valp | rightval); + } + break; + } + return cp; +} + + +static const char * +parse_land (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_bor (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '&': + if (cp[1] != '&') + return CALLFUNC(g, handle_error) (g, cp, "&&"); + DO (cp = parse_land (g, cp + 2, &rightval)); + *valp = (*valp && rightval); + break; + } + return cp; +} + + +static const char * +parse_lor (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_land (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '|': + if (cp[1] != '|') + return CALLFUNC(g, handle_error) (g, cp, "||"); + DO (cp = parse_lor (g, cp + 2, &rightval)); + *valp = (*valp || rightval); + break; + } + return cp; +} + + +static const char * +parse_cond(IfParser *g, const char *cp, long *valp) +{ + long trueval, falseval; + + DO (cp = parse_lor (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '?': + DO (cp = parse_cond (g, cp + 1, &trueval)); + SKIPSPACE (cp); + if (*cp != ':') + return CALLFUNC(g, handle_error) (g, cp, ":"); + DO (cp = parse_cond (g, cp + 1, &falseval)); + *valp = (*valp ? trueval : falseval); + break; + } + return cp; +} + + +/**************************************************************************** + External Entry Points + ****************************************************************************/ + +const char * +ParseIfExpression (IfParser *g, const char *cp, long *valp) +{ + return parse_cond (g, cp, valp); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/ifparser.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/ifparser.h new file mode 100644 index 0000000..89d2a2f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/ifparser.h @@ -0,0 +1,83 @@ +/* + * $Xorg: ifparser.h,v 1.3 2000/08/17 19:41:51 cpqbld Exp $ + * + * Copyright 1992 Network Computing Devices, Inc. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Network Computing Devices may not be + * used in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Network Computing Devices makes + * no representations about the suitability of this software for any purpose. + * It is provided ``as is'' without express or implied warranty. + * + * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jim Fulton + * Network Computing Devices, Inc. + * + * Simple if statement processor + * + * This module can be used to evaluate string representations of C language + * if constructs. It accepts the following grammar: + * + * EXPRESSION := VALUE + * | VALUE BINOP EXPRESSION + * | VALUE '?' EXPRESSION ':' EXPRESSION + * + * VALUE := '(' EXPRESSION ')' + * | '!' VALUE + * | '-' VALUE + * | '~' VALUE + * | 'defined' '(' variable ')' + * | variable + * | number + * + * BINOP := '*' | '/' | '%' + * | '+' | '-' + * | '<<' | '>>' + * | '<' | '>' | '<=' | '>=' + * | '==' | '!=' + * | '&' | '^' | '|' + * | '&&' | '||' + * + * The normal C order of precedence is supported. + * + * + * External Entry Points: + * + * ParseIfExpression parse a string for #if + */ + +/* $XFree86: xc/config/makedepend/ifparser.h,v 3.5 2001/07/25 15:04:40 dawes Exp $ */ + +#include + +typedef int Bool; +#define False 0 +#define True 1 + +typedef struct _if_parser { + struct { /* functions */ + const char *(*handle_error) (struct _if_parser *, const char *, + const char *); + long (*eval_variable) (struct _if_parser *, const char *, int); + int (*eval_defined) (struct _if_parser *, const char *, int); + } funcs; + char *data; +} IfParser; + +const char *ParseIfExpression ( + IfParser *, + const char *, + long * +); + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/imakemdep.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/imakemdep.h new file mode 100644 index 0000000..5c58351 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/imakemdep.h @@ -0,0 +1,733 @@ + +/* $XConsortium: imakemdep.h,v 1.83 95/04/07 19:47:46 kaleb Exp $ */ +/* $XFree86: xc/config/imake/imakemdep.h,v 3.12 1995/07/08 10:22:17 dawes Exp $ */ +/* + +Copyright (c) 1993, 1994 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from the X Consortium. + +*/ + + +/* + * This file contains machine-dependent constants for the imake utility. + * When porting imake, read each of the steps below and add in any necessary + * definitions. In general you should *not* edit ccimake.c or imake.c! + */ + +#ifdef CCIMAKE +/* + * Step 1: imake_ccflags + * Define any special flags that will be needed to get imake.c to compile. + * These will be passed to the compile along with the contents of the + * make variable BOOTSTRAPCFLAGS. + */ +#ifdef hpux +#ifdef hp9000s800 +#define imake_ccflags "-DSYSV" +#else +#define imake_ccflags "-Wc,-Nd4000,-Ns3000 -DSYSV" +#endif +#endif + +#if defined(macII) || defined(_AUX_SOURCE) +#define imake_ccflags "-DmacII -DSYSV" +#endif + +#ifdef stellar +#define imake_ccflags "-DSYSV" +#endif + +#if defined(USL) || defined(Oki) || defined(NCR) +#define imake_ccflags "-Xc -DSVR4" +#endif + +#ifdef sony +#if defined(SYSTYPE_SYSV) || defined(_SYSTYPE_SYSV) +#define imake_ccflags "-DSVR4" +#else +#include +#if NEWSOS < 41 +#define imake_ccflags "-Dbsd43 -DNOSTDHDRS" +#else +#if NEWSOS < 42 +#define imake_ccflags "-Dbsd43" +#endif +#endif +#endif +#endif + +#ifdef _CRAY +#define imake_ccflags "-DSYSV -DUSG" +#endif + +#if defined(_IBMR2) || defined(aix) +#define imake_ccflags "-Daix -DSYSV" +#endif + +#ifdef Mips +# if defined(SYSTYPE_BSD) || defined(BSD) || defined(BSD43) +# define imake_ccflags "-DBSD43" +# else +# define imake_ccflags "-DSYSV" +# endif +#endif + +#ifdef is68k +#define imake_ccflags "-Dluna -Duniosb" +#endif + +#ifdef SYSV386 +# ifdef SVR4 +# define imake_ccflags "-Xc -DSVR4" +# else +# define imake_ccflags "-DSYSV" +# endif +#endif + +#ifdef SVR4 +# ifdef i386 +# define imake_ccflags "-Xc -DSVR4" +# endif +#endif + +#ifdef SYSV +# ifdef i386 +# define imake_ccflags "-DSYSV" +# endif +#endif + +#ifdef __convex__ +#define imake_ccflags "-fn -tm c1" +#endif + +#ifdef apollo +#define imake_ccflags "-DX_NOT_POSIX" +#endif + +#ifdef WIN32 +#define imake_ccflags "-nologo -batch -D__STDC__" +#endif + +#ifdef __uxp__ +#define imake_ccflags "-DSVR4 -DANSICPP" +#endif + +#ifdef __sxg__ +#define imake_ccflags "-DSYSV -DUSG -DNOSTDHDRS" +#endif + +#ifdef sequent +#define imake_ccflags "-DX_NOT_STDC_ENV -DX_NOT_POSIX" +#endif + +#ifdef _SEQUENT_ +#define imake_ccflags "-DSYSV -DUSG" +#endif + +#if defined(SX) || defined(PC_UX) +#define imake_ccflags "-DSYSV" +#endif + +#ifdef nec_ews_svr2 +#define imake_ccflags "-DUSG" +#endif + +#if defined(nec_ews_svr4) || defined(_nec_ews_svr4) || defined(_nec_up) || defined(_nec_ft) +#define imake_ccflags "-DSVR4" +#endif + +#ifdef MACH +#define imake_ccflags "-DNOSTDHDRS" +#endif + +/* this is for OS/2 under EMX. This won't work with DOS */ +#if defined(__EMX__) +#define imake_ccflags "-DBSD43" +#endif + +#else /* not CCIMAKE */ +#ifndef MAKEDEPEND +/* + * Step 2: dup2 + * If your OS doesn't have a dup2() system call to duplicate one file + * descriptor onto another, define such a mechanism here (if you don't + * already fall under the existing category(ies). + */ +#if defined(SYSV) && !defined(_CRAY) && !defined(Mips) && !defined(_SEQUENT_) +#define dup2(fd1,fd2) ((fd1 == fd2) ? fd1 : (close(fd2), \ + fcntl(fd1, F_DUPFD, fd2))) +#endif + + +/* + * Step 3: FIXUP_CPP_WHITESPACE + * If your cpp collapses tabs macro expansions into a single space and + * replaces escaped newlines with a space, define this symbol. This will + * cause imake to attempt to patch up the generated Makefile by looking + * for lines that have colons in them (this is why the rules file escapes + * all colons). One way to tell if you need this is to see whether or not + * your Makefiles have no tabs in them and lots of @@ strings. + */ +#if defined(sun) || defined(SYSV) || defined(SVR4) || defined(hcx) || defined(WIN32) || (defined(AMOEBA) && defined(CROSS_COMPILE)) +#define FIXUP_CPP_WHITESPACE +#endif +#ifdef WIN32 +#define REMOVE_CPP_LEADSPACE +#define INLINE_SYNTAX +#define MAGIC_MAKE_VARS +#endif +#ifdef __minix_vmd +#define FIXUP_CPP_WHITESPACE +#endif + +/* + * Step 4: USE_CC_E, DEFAULT_CC, DEFAULT_CPP + * If you want to use cc -E instead of cpp, define USE_CC_E. + * If use cc -E but want a different compiler, define DEFAULT_CC. + * If the cpp you need is not in /lib/cpp, define DEFAULT_CPP. + */ +#ifdef hpux +#define USE_CC_E +#endif +#ifdef WIN32 +#define USE_CC_E +#define DEFAULT_CC "cl" +#endif +#ifdef apollo +#define DEFAULT_CPP "/usr/lib/cpp" +#endif +#if defined(_IBMR2) && !defined(DEFAULT_CPP) +#define DEFAULT_CPP "/usr/lpp/X11/Xamples/util/cpp/cpp" +#endif +#if defined(sun) && defined(SVR4) +#define DEFAULT_CPP "/usr/ccs/lib/cpp" +#endif +#ifdef __bsdi__ +#define DEFAULT_CPP "/usr/bin/cpp" +#endif +#ifdef __uxp__ +#define DEFAULT_CPP "/usr/ccs/lib/cpp" +#endif +#ifdef __sxg__ +#define DEFAULT_CPP "/usr/lib/cpp" +#endif +#ifdef _CRAY +#define DEFAULT_CPP "/lib/pcpp" +#endif +#if defined(__386BSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#define DEFAULT_CPP "/usr/libexec/cpp" +#endif +#ifdef MACH +#define USE_CC_E +#endif +#ifdef __minix_vmd +#define DEFAULT_CPP "/usr/lib/cpp" +#endif +#if defined(__EMX__) +/* expects cpp in PATH */ +#define DEFAULT_CPP "cpp" +#endif + +/* + * Step 5: cpp_argv + * The following table contains the flags that should be passed + * whenever a Makefile is being generated. If your preprocessor + * doesn't predefine any unique symbols, choose one and add it to the + * end of this table. Then, do the following: + * + * a. Use this symbol in Imake.tmpl when setting MacroFile. + * b. Put this symbol in the definition of BootstrapCFlags in your + * .cf file. + * c. When doing a make World, always add "BOOTSTRAPCFLAGS=-Dsymbol" + * to the end of the command line. + * + * Note that you may define more than one symbol (useful for platforms + * that support multiple operating systems). + */ + +#define ARGUMENTS 50 /* number of arguments in various arrays */ +char *cpp_argv[ARGUMENTS] = { + "cc", /* replaced by the actual program to exec */ + "-I.", /* add current directory to include path */ +#ifdef unix + "-Uunix", /* remove unix symbol so that filename unix.c okay */ +#endif +#if defined(__386BSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(MACH) +# ifdef __i386__ + "-D__i386__", +# endif +# ifdef __x86_64__ + "-D__x86_64__", +# endif +# ifdef __GNUC__ + "-traditional", +# endif +#endif +#ifdef M4330 + "-DM4330", /* Tektronix */ +#endif +#ifdef M4310 + "-DM4310", /* Tektronix */ +#endif +#if defined(macII) || defined(_AUX_SOURCE) + "-DmacII", /* Apple A/UX */ +#endif +#ifdef USL + "-DUSL", /* USL */ +#endif +#ifdef sony + "-Dsony", /* Sony */ +#if !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV) && NEWSOS < 42 + "-Dbsd43", +#endif +#endif +#ifdef _IBMR2 + "-D_IBMR2", /* IBM RS-6000 (we ensured that aix is defined above */ +#ifndef aix +#define aix /* allow BOOTSTRAPCFLAGS="-D_IBMR2" */ +#endif +#endif /* _IBMR2 */ +#ifdef aix + "-Daix", /* AIX instead of AOS */ +#ifndef ibm +#define ibm /* allow BOOTSTRAPCFLAGS="-Daix" */ +#endif +#endif /* aix */ +#ifdef ibm + "-Dibm", /* IBM PS/2 and RT under both AOS and AIX */ +#endif +#ifdef luna + "-Dluna", /* OMRON luna 68K and 88K */ +#ifdef luna1 + "-Dluna1", +#endif +#ifdef luna88k /* need not on UniOS-Mach Vers. 1.13 */ + "-traditional", /* for some older version */ +#endif /* instead of "-DXCOMM=\\#" */ +#ifdef uniosb + "-Duniosb", +#endif +#ifdef uniosu + "-Duniosu", +#endif +#endif /* luna */ +#ifdef _CRAY /* Cray */ + "-Ucray", +#endif +#ifdef Mips + "-DMips", /* Define and use Mips for Mips Co. OS/mach. */ +# if defined(SYSTYPE_BSD) || defined(BSD) || defined(BSD43) + "-DBSD43", /* Mips RISCOS supports two environments */ +# else + "-DSYSV", /* System V environment is the default */ +# endif +#endif /* Mips */ +#ifdef MOTOROLA + "-DMOTOROLA", /* Motorola Delta Systems */ +# ifdef SYSV + "-DSYSV", +# endif +# ifdef SVR4 + "-DSVR4", +# endif +#endif /* MOTOROLA */ +#ifdef i386 + "-Di386", +# ifdef SVR4 + "-DSVR4", +# endif +# ifdef SYSV + "-DSYSV", +# ifdef ISC + "-DISC", +# ifdef ISC40 + "-DISC40", /* ISC 4.0 */ +# else +# ifdef ISC202 + "-DISC202", /* ISC 2.0.2 */ +# else +# ifdef ISC30 + "-DISC30", /* ISC 3.0 */ +# else + "-DISC22", /* ISC 2.2.1 */ +# endif +# endif +# endif +# endif +# ifdef SCO + "-DSCO", +# ifdef SCO324 + "-DSCO324", +# endif +# endif +# endif +# ifdef ESIX + "-DESIX", +# endif +# ifdef ATT + "-DATT", +# endif +# ifdef DELL + "-DDELL", +# endif +#endif +#ifdef SYSV386 /* System V/386 folks, obsolete */ + "-Di386", +# ifdef SVR4 + "-DSVR4", +# endif +# ifdef ISC + "-DISC", +# ifdef ISC40 + "-DISC40", /* ISC 4.0 */ +# else +# ifdef ISC202 + "-DISC202", /* ISC 2.0.2 */ +# else +# ifdef ISC30 + "-DISC30", /* ISC 3.0 */ +# else + "-DISC22", /* ISC 2.2.1 */ +# endif +# endif +# endif +# endif +# ifdef SCO + "-DSCO", +# ifdef SCO324 + "-DSCO324", +# endif +# endif +# ifdef ESIX + "-DESIX", +# endif +# ifdef ATT + "-DATT", +# endif +# ifdef DELL + "-DDELL", +# endif +#endif +#ifdef __osf__ + "-D__osf__", +# ifdef __mips__ + "-D__mips__", +# endif +# ifdef __alpha + "-D__alpha", +# endif +# ifdef __i386__ + "-D__i386__", +# endif +# ifdef __GNUC__ + "-traditional", +# endif +#endif +#ifdef Oki + "-DOki", +#endif +#ifdef sun +#ifdef SVR4 + "-DSVR4", +#endif +#endif +#ifdef WIN32 + "-DWIN32", + "-nologo", + "-batch", + "-D__STDC__", +#endif +#ifdef NCR + "-DNCR", /* NCR */ +#endif +#ifdef linux + "-traditional", + "-Dlinux", +#endif +#ifdef __uxp__ + "-D__uxp__", +#endif +#ifdef __sxg__ + "-D__sxg__", +#endif +#ifdef nec_ews_svr2 + "-Dnec_ews_svr2", +#endif +#ifdef AMOEBA + "-DAMOEBA", +# ifdef CROSS_COMPILE + "-DCROSS_COMPILE", +# ifdef CROSS_i80386 + "-Di80386", +# endif +# ifdef CROSS_sparc + "-Dsparc", +# endif +# ifdef CROSS_mc68000 + "-Dmc68000", +# endif +# else +# ifdef i80386 + "-Di80386", +# endif +# ifdef sparc + "-Dsparc", +# endif +# ifdef mc68000 + "-Dmc68000", +# endif +# endif +#endif +#ifdef __minix_vmd + "-Dminix", +#endif + +#if defined(__EMX__) + "-traditional", + "-Demxos2", +#endif + +}; +#else /* else MAKEDEPEND */ +/* + * Step 6: predefs + * If your compiler and/or preprocessor define any specific symbols, add + * them to the the following table. The definition of struct symtab is + * in util/makedepend/def.h. + */ +struct symtab predefs[] = { +#ifdef apollo + {"apollo", "1"}, +#endif +#ifdef ibm032 + {"ibm032", "1"}, +#endif +#ifdef ibm + {"ibm", "1"}, +#endif +#ifdef aix + {"aix", "1"}, +#endif +#ifdef sun + {"sun", "1"}, +#endif +#ifdef sun2 + {"sun2", "1"}, +#endif +#ifdef sun3 + {"sun3", "1"}, +#endif +#ifdef sun4 + {"sun4", "1"}, +#endif +#ifdef sparc + {"sparc", "1"}, +#endif +#ifdef __sparc__ + {"__sparc__", "1"}, +#endif +#ifdef hpux + {"hpux", "1"}, +#endif +#ifdef __hpux + {"__hpux", "1"}, +#endif +#ifdef __hp9000s800 + {"__hp9000s800", "1"}, +#endif +#ifdef __hp9000s700 + {"__hp9000s700", "1"}, +#endif +#ifdef vax + {"vax", "1"}, +#endif +#ifdef VMS + {"VMS", "1"}, +#endif +#ifdef cray + {"cray", "1"}, +#endif +#ifdef CRAY + {"CRAY", "1"}, +#endif +#ifdef _CRAY + {"_CRAY", "1"}, +#endif +#ifdef att + {"att", "1"}, +#endif +#ifdef mips + {"mips", "1"}, +#endif +#ifdef __mips__ + {"__mips__", "1"}, +#endif +#ifdef ultrix + {"ultrix", "1"}, +#endif +#ifdef stellar + {"stellar", "1"}, +#endif +#ifdef mc68000 + {"mc68000", "1"}, +#endif +#ifdef mc68020 + {"mc68020", "1"}, +#endif +#ifdef __GNUC__ + {"__GNUC__", "1"}, +#endif +#if __STDC__ + {"__STDC__", "1"}, +#endif +#ifdef __HIGHC__ + {"__HIGHC__", "1"}, +#endif +#ifdef CMU + {"CMU", "1"}, +#endif +#ifdef luna + {"luna", "1"}, +#ifdef luna1 + {"luna1", "1"}, +#endif +#ifdef luna2 + {"luna2", "1"}, +#endif +#ifdef luna88k + {"luna88k", "1"}, +#endif +#ifdef uniosb + {"uniosb", "1"}, +#endif +#ifdef uniosu + {"uniosu", "1"}, +#endif +#endif +#ifdef ieeep754 + {"ieeep754", "1"}, +#endif +#ifdef is68k + {"is68k", "1"}, +#endif +#ifdef m68k + {"m68k", "1"}, +#endif +#ifdef m88k + {"m88k", "1"}, +#endif +#ifdef __m88k__ + {"__m88k__", "1"}, +#endif +#ifdef bsd43 + {"bsd43", "1"}, +#endif +#ifdef hcx + {"hcx", "1"}, +#endif +#ifdef sony + {"sony", "1"}, +#ifdef SYSTYPE_SYSV + {"SYSTYPE_SYSV", "1"}, +#endif +#ifdef _SYSTYPE_SYSV + {"_SYSTYPE_SYSV", "1"}, +#endif +#endif +#ifdef __OSF__ + {"__OSF__", "1"}, +#endif +#ifdef __osf__ + {"__osf__", "1"}, +#endif +#ifdef __alpha + {"__alpha", "1"}, +#endif +#ifdef __DECC + {"__DECC", "1"}, +#endif +#ifdef __decc + {"__decc", "1"}, +#endif +#ifdef __uxp__ + {"__uxp__", "1"}, +#endif +#ifdef __sxg__ + {"__sxg__", "1"}, +#endif +#ifdef _SEQUENT_ + {"_SEQUENT_", "1"}, + {"__STDC__", "1"}, +#endif +#ifdef __bsdi__ + {"__bsdi__", "1"}, +#endif +#ifdef nec_ews_svr2 + {"nec_ews_svr2", "1"}, +#endif +#ifdef nec_ews_svr4 + {"nec_ews_svr4", "1"}, +#endif +#ifdef _nec_ews_svr4 + {"_nec_ews_svr4", "1"}, +#endif +#ifdef _nec_up + {"_nec_up", "1"}, +#endif +#ifdef SX + {"SX", "1"}, +#endif +#ifdef nec + {"nec", "1"}, +#endif +#ifdef _nec_ft + {"_nec_ft", "1"}, +#endif +#ifdef PC_UX + {"PC_UX", "1"}, +#endif +#ifdef sgi + {"sgi", "1"}, +#endif +#ifdef __sgi + {"__sgi", "1"}, +#endif +#ifdef __FreeBSD__ + {"__FreeBSD__", "1"}, +#endif +#ifdef __NetBSD__ + {"__NetBSD__", "1"}, +#endif +#ifdef __OpenBSD__ + {"__OpenBSD__", "1"}, +#endif +#ifdef __EMX__ + {"__EMX__", "1"}, +#endif + /* add any additional symbols before this line */ + {NULL, NULL} +}; + +#endif /* MAKEDEPEND */ +#endif /* CCIMAKE */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/include.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/include.c new file mode 100644 index 0000000..3b89f26 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/include.c @@ -0,0 +1,337 @@ +/* $Xorg: include.c,v 1.4 2001/02/09 02:03:16 xorgcvs Exp $ */ +/* + +Copyright (c) 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/config/makedepend/include.c,v 3.7 2001/12/14 19:53:20 dawes Exp $ */ + + +#include "def.h" + +#ifdef _MSC_VER +#include +static int +does_file_exist(char *file) +{ + WIN32_FILE_ATTRIBUTE_DATA data; + BOOL b = GetFileAttributesExA(file, GetFileExInfoStandard, &data); + if (!b) + return 0; + return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0; +} +#else +static int +does_file_exist(char *file) +{ + struct stat sb; + return stat(file, &sb) == 0 && !S_ISDIR(sb.st_mode); +} +#endif + +extern struct inclist inclist[ MAXFILES ], + *inclistp, *inclistnext; +extern char *includedirs[ ], + **includedirsnext; +extern char *notdotdot[ ]; +extern boolean show_where_not; +extern boolean warn_multiple; + +static boolean +isdot(char *p) +{ + if(p && *p++ == '.' && *p++ == '\0') + return(TRUE); + return(FALSE); +} + +static boolean +isdotdot(char *p) +{ + if(p && *p++ == '.' && *p++ == '.' && *p++ == '\0') + return(TRUE); + return(FALSE); +} + +static boolean +issymbolic(char *dir, char *component) +{ +#ifdef S_IFLNK + struct stat st; + char buf[ BUFSIZ ], **pp; + + sprintf(buf, "%s%s%s", dir, *dir ? "/" : "", component); + for (pp=notdotdot; *pp; pp++) + if (strcmp(*pp, buf) == 0) + return (TRUE); + if (lstat(buf, &st) == 0 + && (st.st_mode & S_IFMT) == S_IFLNK) { + *pp++ = copy(buf); + if (pp >= ¬dotdot[ MAXDIRS ]) + fatalerr("out of .. dirs, increase MAXDIRS\n"); + return(TRUE); + } +#endif + return(FALSE); +} + +/* + * Occasionally, pathnames are created that look like .../x/../y + * Any of the 'x/..' sequences within the name can be eliminated. + * (but only if 'x' is not a symbolic link!!) + */ +static void +remove_dotdot(char *path) +{ + register char *end, *from, *to, **cp; + char *components[ MAXFILES ], + newpath[ BUFSIZ ]; + boolean component_copied; + + /* + * slice path up into components. + */ + to = newpath; + if (*path == '/') + *to++ = '/'; + *to = '\0'; + cp = components; + for (from=end=path; *end; end++) + if (*end == '/') { + while (*end == '/') + *end++ = '\0'; + if (*from) + *cp++ = from; + from = end; + } + *cp++ = from; + *cp = NULL; + + /* + * Recursively remove all 'x/..' component pairs. + */ + cp = components; + while(*cp) { + if (!isdot(*cp) && !isdotdot(*cp) && isdotdot(*(cp+1)) + && !issymbolic(newpath, *cp)) + { + char **fp = cp + 2; + char **tp = cp; + + do + *tp++ = *fp; /* move all the pointers down */ + while (*fp++); + if (cp != components) + cp--; /* go back and check for nested ".." */ + } else { + cp++; + } + } + /* + * Concatenate the remaining path elements. + */ + cp = components; + component_copied = FALSE; + while(*cp) { + if (component_copied) + *to++ = '/'; + component_copied = TRUE; + for (from = *cp; *from; ) + *to++ = *from++; + *to = '\0'; + cp++; + } + *to++ = '\0'; + + /* + * copy the reconstituted path back to our pointer. + */ + strcpy(path, newpath); +} + +/* + * Add an include file to the list of those included by 'file'. + */ +struct inclist * +newinclude(char *newfile, char *incstring) +{ + register struct inclist *ip; + + /* + * First, put this file on the global list of include files. + */ + ip = inclistp++; + if (inclistp == inclist + MAXFILES - 1) + fatalerr("out of space: increase MAXFILES\n"); + ip->i_file = copy(newfile); + + if (incstring == NULL) + ip->i_incstring = ip->i_file; + else + ip->i_incstring = copy(incstring); + + inclistnext = inclistp; + return(ip); +} + +void +included_by(struct inclist *ip, struct inclist *newfile) +{ + register int i; + + if (ip == NULL) + return; + /* + * Put this include file (newfile) on the list of files included + * by 'file'. If 'file' is NULL, then it is not an include + * file itself (i.e. was probably mentioned on the command line). + * If it is already on the list, don't stick it on again. + */ + if (ip->i_list == NULL) { + ip->i_list = (struct inclist **) + malloc(sizeof(struct inclist *) * ++ip->i_listlen); + ip->i_merged = (boolean *) + malloc(sizeof(boolean) * ip->i_listlen); + } else { + for (i=0; ii_listlen; i++) + if (ip->i_list[ i ] == newfile) { + i = strlen(newfile->i_file); + if (!(ip->i_flags & INCLUDED_SYM) && + !(i > 2 && + newfile->i_file[i-1] == 'c' && + newfile->i_file[i-2] == '.')) + { + /* only bitch if ip has */ + /* no #include SYMBOL lines */ + /* and is not a .c file */ + if (warn_multiple) + { + warning("%s includes %s more than once!\n", + ip->i_file, newfile->i_file); + warning1("Already have\n"); + for (i=0; ii_listlen; i++) + warning1("\t%s\n", ip->i_list[i]->i_file); + } + } + return; + } + ip->i_list = (struct inclist **) realloc(ip->i_list, + sizeof(struct inclist *) * ++ip->i_listlen); + ip->i_merged = (boolean *) + realloc(ip->i_merged, sizeof(boolean) * ip->i_listlen); + } + ip->i_list[ ip->i_listlen-1 ] = newfile; + ip->i_merged[ ip->i_listlen-1 ] = FALSE; +} + +void +inc_clean (void) +{ + register struct inclist *ip; + + for (ip = inclist; ip < inclistp; ip++) { + ip->i_flags &= ~MARKED; + } +} + +struct inclist * +inc_path(char *file, char *include, int type) +{ + static char path[ BUFSIZ ]; + register char **pp, *p; + register struct inclist *ip; + + /* + * Check all previously found include files for a path that + * has already been expanded. + */ + if ((type == INCLUDE) || (type == INCLUDEDOT)) + inclistnext = inclist; + ip = inclistnext; + + for (; ip->i_file; ip++) { + if ((strcmp(ip->i_incstring, include) == 0) && + !(ip->i_flags & INCLUDED_SYM)) { + inclistnext = ip + 1; + return ip; + } + } + + if (inclistnext == inclist) { + /* + * If the path was surrounded by "" or is an absolute path, + * then check the exact path provided. + */ + if ((type == INCLUDEDOT) || + (type == INCLUDENEXTDOT) || + (*include == '/')) { + if (does_file_exist(include)) + return newinclude(include, include); + if (show_where_not) + warning1("\tnot in %s\n", include); + } + + /* + * If the path was surrounded by "" see if this include file is + * in the directory of the file being parsed. + */ + if ((type == INCLUDEDOT) || (type == INCLUDENEXTDOT)) { + for (p=file+strlen(file); p>file; p--) + if (*p == '/') + break; + if (p == file) { + strcpy(path, include); + } else { + strncpy(path, file, (p-file) + 1); + path[ (p-file) + 1 ] = '\0'; + strcpy(path + (p-file) + 1, include); + } + remove_dotdot(path); + if (does_file_exist(path)) + return newinclude(path, include); + if (show_where_not) + warning1("\tnot in %s\n", path); + } + } + + /* + * Check the include directories specified. Standard include dirs + * should be at the end. + */ + if ((type == INCLUDE) || (type == INCLUDEDOT)) + includedirsnext = includedirs; + pp = includedirsnext; + + for (; *pp; pp++) { + sprintf(path, "%s/%s", *pp, include); + remove_dotdot(path); + if (does_file_exist(path)) { + includedirsnext = pp + 1; + return newinclude(path, include); + } + if (show_where_not) + warning1("\tnot in %s\n", path); + } + + return NULL; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/main.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/main.c new file mode 100644 index 0000000..a86866f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/main.c @@ -0,0 +1,860 @@ +/* $Xorg: main.c,v 1.5 2001/02/09 02:03:16 xorgcvs Exp $ */ +/* + +Copyright (c) 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/config/makedepend/main.c,v 3.32 2003/03/26 20:43:48 tsi Exp $ */ + +#include "def.h" +#ifdef hpux +#define sigvec sigvector +#endif /* hpux */ + +#ifdef X_POSIX_C_SOURCE +#define _POSIX_C_SOURCE X_POSIX_C_SOURCE +#include +#undef _POSIX_C_SOURCE +#else +#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) +#include +#else +#define _POSIX_SOURCE +#include +#undef _POSIX_SOURCE +#endif +#endif + +#include + +#ifdef MINIX +#define USE_CHMOD 1 +#endif + +#ifdef DEBUG +int _debugmask; +#endif + +/* #define DEBUG_DUMP */ +#ifdef DEBUG_DUMP +#define DBG_PRINT(file, fmt, args) fprintf(file, fmt, args) +#else +#define DBG_PRINT(file, fmt, args) /* empty */ +#endif + +#define DASH_INC_PRE "#include \"" +#define DASH_INC_POST "\"" + +char *ProgramName; + +char *directives[] = { + "if", + "ifdef", + "ifndef", + "else", + "endif", + "define", + "undef", + "include", + "line", + "pragma", + "error", + "ident", + "sccs", + "elif", + "eject", + "warning", + "include_next", + NULL +}; + +#define MAKEDEPEND +#include "imakemdep.h" /* from config sources */ +#undef MAKEDEPEND + +struct inclist inclist[ MAXFILES ], + *inclistp = inclist, + *inclistnext = inclist, + maininclist; + +static char *filelist[ MAXFILES ]; +char *includedirs[ MAXDIRS + 1 ], + **includedirsnext = includedirs; +char *notdotdot[ MAXDIRS ]; +static int cmdinc_count = 0; +static char *cmdinc_list[ 2 * MAXINCFILES ]; +char *objprefix = ""; +char *objsuffix = OBJSUFFIX; +static char *startat = "# DO NOT DELETE"; +int width = 78; +static boolean append = FALSE; +boolean printed = FALSE; +boolean verbose = FALSE; +boolean show_where_not = FALSE; +/* Warn on multiple includes of same file */ +boolean warn_multiple = FALSE; + +static void setfile_cmdinc(struct filepointer *filep, long count, char **list); +static void redirect(char *line, char *makefile); + +static +#ifdef SIGNALRETURNSINT +int +#else +void +#endif +catch (int sig) +{ + fflush (stdout); + fatalerr ("got signal %d\n", sig); +} + +#if defined(USG) || (defined(i386) && defined(SYSV)) || defined(WIN32) || defined(__UNIXOS2__) || defined(Lynx_22) || defined(__CYGWIN__) +#define USGISH +#endif + +#ifndef USGISH +#ifdef X_NOT_POSIX +#define sigaction sigvec +#define sa_handler sv_handler +#define sa_mask sv_mask +#define sa_flags sv_flags +#endif +struct sigaction sig_act; +#endif /* USGISH */ + +int +main(int argc, char *argv[]) +{ + char **fp = filelist; + char **incp = includedirs; + char *p; + struct inclist *ip; + char *makefile = NULL; + struct filepointer *filecontent; + struct symtab *psymp = predefs; + char *endmarker = NULL; + char *defincdir = NULL; + char **undeflist = NULL; + int numundefs = 0, i; + register char offset; + + ProgramName = argv[0]; + + while (psymp->s_name) + { + define2(psymp->s_name, psymp->s_value, &maininclist); + psymp++; + } + if (argc == 2 && argv[1][0] == '@') { + struct stat ast; + int afd; + char *args; + char **nargv; + int nargc; + char quotechar = '\0'; + + nargc = 1; + if ((afd = open(argv[1]+1, O_RDONLY)) < 0) + fatalerr("cannot open \"%s\"\n", argv[1]+1); + fstat(afd, &ast); + args = (char *)malloc(ast.st_size + 1); + if ((ast.st_size = read(afd, args, ast.st_size)) < 0) + fatalerr("failed to read %s\n", argv[1]+1); + args[ast.st_size] = '\0'; + close(afd); + for (p = args; *p; p++) { + if (quotechar) { + if (quotechar == '\\' || + (*p == quotechar && p[-1] != '\\')) + quotechar = '\0'; + continue; + } + switch (*p) { + case '\\': + case '"': + case '\'': + quotechar = *p; + break; + case ' ': + case '\n': + *p = '\0'; + if (p > args && p[-1]) + nargc++; + break; + } + } + if (p[-1]) + nargc++; + nargv = (char **)malloc(nargc * sizeof(char *)); + nargv[0] = argv[0]; + argc = 1; + for (p = args; argc < nargc; p += strlen(p) + 1) + if (*p) nargv[argc++] = p; + argv = nargv; + } + for(argc--, argv++; argc; argc--, argv++) { + /* if looking for endmarker then check before parsing */ + if (endmarker && strcmp (endmarker, *argv) == 0) { + endmarker = NULL; + continue; + } + if (**argv != '-') { + /* treat +thing as an option for C++ */ + if (endmarker && **argv == '+') + continue; + *fp++ = argv[0]; + continue; + } + switch(argv[0][1]) { + case '-': + endmarker = &argv[0][2]; + if (endmarker[0] == '\0') endmarker = "--"; + break; + case 'D': + offset = 2; + if (argv[0][2] == '\0') { + argv++; + argc--; + offset = 0; + } + /* offset +1 here since first def letter + * cannot be `=` + */ + for (p = argv[0] + offset + 1; *p; p++) + if (*p == '=') { + *p = ' '; + break; + } + define(argv[0] + offset, &maininclist); + break; + case 'I': + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = argv[0]+2; + if (**(incp-1) == '\0') { + *(incp-1) = *(++argv); + argc--; + } + break; + case 'U': + /* Undef's override all -D's so save them up */ + numundefs++; + if (numundefs == 1) + undeflist = malloc(sizeof(char *)); + else + undeflist = realloc(undeflist, + numundefs * sizeof(char *)); + offset = 2; + if (argv[0][2] == '\0') { + argv++; + argc--; + offset = 0; + } + undeflist[numundefs - 1] = argv[0] + offset; + break; + case 'Y': + defincdir = argv[0]+2; + break; + /* do not use if endmarker processing */ + case 'a': + if (endmarker) break; + append = TRUE; + break; + case 'w': + if (endmarker) break; + if (argv[0][2] == '\0') { + argv++; + argc--; + width = atoi(argv[0]); + } else + width = atoi(argv[0]+2); + break; + case 'o': + if (endmarker) break; + if (argv[0][2] == '\0') { + argv++; + argc--; + objsuffix = argv[0]; + } else + objsuffix = argv[0]+2; + break; + case 'p': + if (endmarker) break; + if (argv[0][2] == '\0') { + argv++; + argc--; + objprefix = argv[0]; + } else + objprefix = argv[0]+2; + break; + case 'v': + if (endmarker) break; + verbose = TRUE; +#ifdef DEBUG + if (argv[0][2]) + _debugmask = atoi(argv[0]+2); +#endif + break; + case 's': + if (endmarker) break; + startat = argv[0]+2; + if (*startat == '\0') { + startat = *(++argv); + argc--; + } + if (*startat != '#') + fatalerr("-s flag's value should start %s\n", + "with '#'."); + break; + case 'f': + if (endmarker) break; + makefile = argv[0]+2; + if (*makefile == '\0') { + makefile = *(++argv); + argc--; + } + break; + + case 'm': + warn_multiple = TRUE; + break; + + /* Ignore -O, -g so we can just pass ${CFLAGS} to + makedepend + */ + case 'O': + case 'g': + break; + case 'i': + if (strcmp(&argv[0][1],"include") == 0) { + char *buf; + if (argc<2) + fatalerr("option -include is a " + "missing its parameter\n"); + if (cmdinc_count >= MAXINCFILES) + fatalerr("Too many -include flags.\n"); + argc--; + argv++; + buf = malloc(strlen(DASH_INC_PRE) + + strlen(argv[0]) + + strlen(DASH_INC_POST) + 1); + if(!buf) + fatalerr("out of memory at " + "-include string\n"); + cmdinc_list[2 * cmdinc_count + 0] = argv[0]; + cmdinc_list[2 * cmdinc_count + 1] = buf; + cmdinc_count++; + break; + } + /* intentional fall through */ + default: + if (endmarker) break; + /* fatalerr("unknown opt = %s\n", argv[0]); */ + warning("ignoring option %s\n", argv[0]); + } + } + /* Now do the undefs from the command line */ + for (i = 0; i < numundefs; i++) + undefine(undeflist[i], &maininclist); + if (numundefs > 0) + free(undeflist); + + if (!defincdir) { +#ifdef PREINCDIR + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = PREINCDIR; +#endif +#ifdef __UNIXOS2__ + { + char *emxinc = getenv("C_INCLUDE_PATH"); + /* can have more than one component */ + if (emxinc) { + char *beg, *end; + beg= (char*)strdup(emxinc); + for (;;) { + end = (char*)strchr(beg,';'); + if (end) *end = 0; + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many include dirs\n"); + *incp++ = beg; + if (!end) break; + beg = end+1; + } + } + } +#else /* !__UNIXOS2__, does not use INCLUDEDIR at all */ + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = INCLUDEDIR; +#endif + +#ifdef EXTRAINCDIR + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = EXTRAINCDIR; +#endif + +#ifdef POSTINCDIR + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = POSTINCDIR; +#endif + } else if (*defincdir) { + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = defincdir; + } + + redirect(startat, makefile); + + /* + * catch signals. + */ +#ifdef USGISH +/* should really reset SIGINT to SIG_IGN if it was. */ +#ifdef SIGHUP + signal (SIGHUP, catch); +#endif + signal (SIGINT, catch); +#ifdef SIGQUIT + signal (SIGQUIT, catch); +#endif + signal (SIGILL, catch); +#ifdef SIGBUS + signal (SIGBUS, catch); +#endif + signal (SIGSEGV, catch); +#ifdef SIGSYS + signal (SIGSYS, catch); +#endif +#else + sig_act.sa_handler = catch; +#if defined(_POSIX_SOURCE) || !defined(X_NOT_POSIX) + sigemptyset(&sig_act.sa_mask); + sigaddset(&sig_act.sa_mask, SIGINT); + sigaddset(&sig_act.sa_mask, SIGQUIT); +#ifdef SIGBUS + sigaddset(&sig_act.sa_mask, SIGBUS); +#endif + sigaddset(&sig_act.sa_mask, SIGILL); + sigaddset(&sig_act.sa_mask, SIGSEGV); + sigaddset(&sig_act.sa_mask, SIGHUP); + sigaddset(&sig_act.sa_mask, SIGPIPE); +#ifdef SIGSYS + sigaddset(&sig_act.sa_mask, SIGSYS); +#endif +#else + sig_act.sa_mask = ((1<<(SIGINT -1)) + |(1<<(SIGQUIT-1)) +#ifdef SIGBUS + |(1<<(SIGBUS-1)) +#endif + |(1<<(SIGILL-1)) + |(1<<(SIGSEGV-1)) + |(1<<(SIGHUP-1)) + |(1<<(SIGPIPE-1)) +#ifdef SIGSYS + |(1<<(SIGSYS-1)) +#endif + ); +#endif /* _POSIX_SOURCE */ + sig_act.sa_flags = 0; + sigaction(SIGHUP, &sig_act, (struct sigaction *)0); + sigaction(SIGINT, &sig_act, (struct sigaction *)0); + sigaction(SIGQUIT, &sig_act, (struct sigaction *)0); + sigaction(SIGILL, &sig_act, (struct sigaction *)0); +#ifdef SIGBUS + sigaction(SIGBUS, &sig_act, (struct sigaction *)0); +#endif + sigaction(SIGSEGV, &sig_act, (struct sigaction *)0); +#ifdef SIGSYS + sigaction(SIGSYS, &sig_act, (struct sigaction *)0); +#endif +#endif /* USGISH */ + + /* + * now peruse through the list of files. + */ + for(fp=filelist; *fp; fp++) { + DBG_PRINT(stderr,"file: %s\n",*fp); + filecontent = getfile(*fp); + setfile_cmdinc(filecontent, cmdinc_count, cmdinc_list); + ip = newinclude(*fp, (char *)NULL); + + find_includes(filecontent, ip, ip, 0, FALSE); + freefile(filecontent); + recursive_pr_include(ip, ip->i_file, base_name(*fp)); + inc_clean(); + } + if (printed) + printf("\n"); + return 0; +} + +#ifdef __UNIXOS2__ +/* + * eliminate \r chars from file + */ +static int +elim_cr(char *buf, int sz) +{ + int i,wp; + for (i= wp = 0; if_name = file; + if ((fd = open(file, O_RDONLY)) < 0) { + warning("cannot open \"%s\"\n", file); + content->f_p = content->f_base = content->f_end = (char *)malloc(1); + *content->f_p = '\0'; + return(content); + } + fstat(fd, &st); + content->f_base = (char *)malloc(st.st_size+1); + if (content->f_base == NULL) + fatalerr("cannot allocate mem\n"); + if ((st.st_size = read(fd, content->f_base, st.st_size)) < 0) + fatalerr("failed to read %s\n", file); +#ifdef __UNIXOS2__ + st.st_size = elim_cr(content->f_base,st.st_size); +#endif + close(fd); + content->f_len = st.st_size+1; + content->f_p = content->f_base; + content->f_end = content->f_base + st.st_size; + *content->f_end = '\0'; + content->f_line = 0; + content->cmdinc_count = 0; + content->cmdinc_list = NULL; + content->cmdinc_line = 0; + return(content); +} + +void +setfile_cmdinc(struct filepointer* filep, long count, char** list) +{ + filep->cmdinc_count = count; + filep->cmdinc_list = list; + filep->cmdinc_line = 0; +} + +void +freefile(struct filepointer *fp) +{ + free(fp->f_base); + free(fp); +} + +char *copy(char *str) +{ + char *p = (char *)malloc(strlen(str) + 1); + + strcpy(p, str); + return(p); +} + +int +match(char *str, char **list) +{ + int i; + + for (i=0; *list; i++, list++) + if (strcmp(str, *list) == 0) + return(i); + return(-1); +} + +/* + * Get the next line. We only return lines beginning with '#' since that + * is all this program is ever interested in. + */ +char *getnextline(struct filepointer *filep) +{ + char *p, /* walking pointer */ + *eof, /* end of file pointer */ + *bol; /* beginning of line pointer */ + int lineno; /* line number */ + boolean whitespace = FALSE; + + /* + * Fake the "-include" line files in form of #include to the + * start of each file. + */ + if (filep->cmdinc_line < filep->cmdinc_count) { + char *inc = filep->cmdinc_list[2 * filep->cmdinc_line + 0]; + char *buf = filep->cmdinc_list[2 * filep->cmdinc_line + 1]; + filep->cmdinc_line++; + sprintf(buf,"%s%s%s",DASH_INC_PRE,inc,DASH_INC_POST); + DBG_PRINT(stderr,"%s\n",buf); + return(buf); + } + + p = filep->f_p; + eof = filep->f_end; + if (p >= eof) + return((char *)NULL); + lineno = filep->f_line; + + for (bol = p--; ++p < eof; ) { + if ((bol == p) && ((*p == ' ') || (*p == '\t'))) + { + /* Consume leading white-spaces for this line */ + while (((p+1) < eof) && ((*p == ' ') || (*p == '\t'))) + { + p++; + bol++; + } + whitespace = TRUE; + } + + if (*p == '/' && (p+1) < eof && *(p+1) == '*') { + /* Consume C comments */ + *(p++) = ' '; + *(p++) = ' '; + while (p < eof && *p) { + if (*p == '*' && (p+1) < eof && *(p+1) == '/') { + *(p++) = ' '; + *(p++) = ' '; + break; + } + if (*p == '\n') + lineno++; + *(p++) = ' '; + } + --p; + } + else if (*p == '/' && (p+1) < eof && *(p+1) == '/') { + /* Consume C++ comments */ + *(p++) = ' '; + *(p++) = ' '; + while (p < eof && *p) { + if (*p == '\\' && (p+1) < eof && + *(p+1) == '\n') { + *(p++) = ' '; + lineno++; + } + else if (*p == '?' && (p+3) < eof && + *(p+1) == '?' && + *(p+2) == '/' && + *(p+3) == '\n') { + *(p++) = ' '; + *(p++) = ' '; + *(p++) = ' '; + lineno++; + } + else if (*p == '\n') + break; /* to process end of line */ + *(p++) = ' '; + } + --p; + } + else if (*p == '\\' && (p+1) < eof && *(p+1) == '\n') { + /* Consume backslash line terminations */ + *(p++) = ' '; + *p = ' '; + lineno++; + } + else if (*p == '?' && (p+3) < eof && + *(p+1) == '?' && *(p+2) == '/' && *(p+3) == '\n') { + /* Consume trigraph'ed backslash line terminations */ + *(p++) = ' '; + *(p++) = ' '; + *(p++) = ' '; + *p = ' '; + lineno++; + } + else if (*p == '\n') { + lineno++; + if (*bol == '#') { + char *cp; + + *(p++) = '\0'; + /* punt lines with just # (yacc generated) */ + for (cp = bol+1; + *cp && (*cp == ' ' || *cp == '\t'); cp++); + if (*cp) goto done; + --p; + } + bol = p+1; + whitespace = FALSE; + } + } + if (*bol != '#') + bol = NULL; +done: + if (bol && whitespace) { + warning("%s: non-portable whitespace encountered at line %d\n", + filep->f_name, lineno); + } + filep->f_p = p; + filep->f_line = lineno; +#ifdef DEBUG_DUMP + if (bol) + DBG_PRINT(stderr,"%s\n",bol); +#endif + return(bol); +} + +/* + * Strip the file name down to what we want to see in the Makefile. + * It will have objprefix and objsuffix around it. + */ +char *base_name(char *file) +{ + char *p; + + file = copy(file); + for(p=file+strlen(file); p>file && *p != '.'; p--) ; + + if (*p == '.') + *p = '\0'; + return(file); +} + +#if defined(USG) && !defined(CRAY) && !defined(SVR4) && !defined(__UNIXOS2__) && !defined(clipper) && !defined(__clipper__) +int rename (char *from, char *to) +{ + (void) unlink (to); + if (link (from, to) == 0) { + unlink (from); + return 0; + } else { + return -1; + } +} +#endif /* USGISH */ + +void +redirect(char *line, char *makefile) +{ + struct stat st; + FILE *fdin, *fdout; + char backup[ BUFSIZ ], + buf[ BUFSIZ ]; + boolean found = FALSE; + int len; + + /* + * if makefile is "-" then let it pour onto stdout. + */ + if (makefile && *makefile == '-' && *(makefile+1) == '\0') { + puts(line); + return; + } + + /* + * use a default makefile is not specified. + */ + if (!makefile) { + if (stat("Makefile", &st) == 0) + makefile = "Makefile"; + else if (stat("makefile", &st) == 0) + makefile = "makefile"; + else + fatalerr("[mM]akefile is not present\n"); + } + else + stat(makefile, &st); + if ((fdin = fopen(makefile, "r")) == NULL) + fatalerr("cannot open \"%s\"\n", makefile); + sprintf(backup, "%s.bak", makefile); + unlink(backup); +#if defined(WIN32) || defined(__UNIXOS2__) || defined(__CYGWIN__) + fclose(fdin); +#endif + if (rename(makefile, backup) < 0) + fatalerr("cannot rename %s to %s\n", makefile, backup); +#if defined(WIN32) || defined(__UNIXOS2__) || defined(__CYGWIN__) + if ((fdin = fopen(backup, "r")) == NULL) + fatalerr("cannot open \"%s\"\n", backup); +#endif + if ((fdout = freopen(makefile, "w", stdout)) == NULL) + fatalerr("cannot open \"%s\"\n", backup); + len = strlen(line); + while (!found && fgets(buf, BUFSIZ, fdin)) { + if (*buf == '#' && strncmp(line, buf, len) == 0) + found = TRUE; + fputs(buf, fdout); + } + if (!found) { + if (verbose) + warning("Adding new delimiting line \"%s\" and dependencies...\n", + line); + puts(line); /* same as fputs(fdout); but with newline */ + } else if (append) { + while (fgets(buf, BUFSIZ, fdin)) { + fputs(buf, fdout); + } + } + fflush(fdout); +#if defined(USGISH) || defined(_SEQUENT_) || defined(USE_CHMOD) + chmod(makefile, st.st_mode); +#else + fchmod(fileno(fdout), st.st_mode); +#endif /* USGISH */ +} + +void +fatalerr(char *msg, ...) +{ + va_list args; + fprintf(stderr, "%s: error: ", ProgramName); + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + exit (1); +} + +void +warning(char *msg, ...) +{ + va_list args; + fprintf(stderr, "%s: warning: ", ProgramName); + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); +} + +void +warning1(char *msg, ...) +{ + va_list args; + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/mkdepend.man b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/mkdepend.man new file mode 100644 index 0000000..595c87e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/mkdepend.man @@ -0,0 +1,382 @@ +.\" $Xorg: mkdepend.man,v 1.5 2001/02/09 02:03:16 xorgcvs Exp $ +.\" Copyright (c) 1993, 1994, 1998 The Open Group +.\" +.\" Permission to use, copy, modify, distribute, and sell this software and its +.\" documentation for any purpose is hereby granted without fee, provided that +.\" the above copyright notice appear in all copies and that both that +.\" copyright notice and this permission notice appear in supporting +.\" documentation. +.\" +.\" The above copyright notice and this permission notice shall be included in +.\" all copies or substantial portions of the Software. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +.\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +.\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +.\" THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +.\" WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +.\" OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +.\" SOFTWARE. +.\" +.\" Except as contained in this notice, the name of The Open Group shall not +.\" be used in advertising or otherwise to promote the sale, use or other +.\" dealing in this Software without prior written authorization from The +.\" Open Group. +.\" +.\" $XFree86: xc/config/makedepend/mkdepend.man,v 1.7 2002/12/14 02:39:45 dawes Exp $ +.\" +.TH MAKEDEPEND 1 __xorgversion__ +.UC 4 +.SH NAME +makedepend \- create dependencies in makefiles +.SH SYNOPSIS +.B makedepend +[ +.BI \-D name\fB=\fPdef +] [ +.BI \-D name +] [ +.BI \-I includedir +] [ +.BI \-Y includedir +] [ +.B \-a +] [ +.BI \-f makefile +] [ +.BI \-include \ file +] [ +.BI \-o objsuffix +] [ +.BI \-p objprefix +] [ +.BI \-s string +] [ +.BI \-w width +] [ +.B \-v +] [ +.B \-m +] [ +\-\^\- +.I otheroptions +\-\^\- +] +.I sourcefile +\&.\|.\|. +.br +.SH DESCRIPTION +The +.B makedepend +program reads each +.I sourcefile +in sequence and parses it like a C-preprocessor, +processing all +.I #include, +.I #define, +.I #undef, +.I #ifdef, +.I #ifndef, +.I #endif, +.I #if, +.I #elif +and +.I #else +directives so that it can correctly tell which +.I #include, +directives would be used in a compilation. +Any +.I #include, +directives can reference files having other +.I #include +directives, and parsing will occur in these files as well. +.PP +Every file that a +.I sourcefile +includes, +directly or indirectly, +is what +.B makedepend +calls a \fIdependency.\fP +These dependencies are then written to a +.I makefile +in such a way that +.B make(1) +will know which object files must be recompiled when a dependency has changed. +.PP +By default, +.B makedepend +places its output in the file named +.I makefile +if it exists, otherwise +.I Makefile. +An alternate makefile may be specified with the +.B \-f +option. +It first searches the makefile for +the line +.sp +\& # DO NOT DELETE THIS LINE \-\^\- make depend depends on it. +.sp +or one provided with the +.B \-s +option, +as a delimiter for the dependency output. +If it finds it, it will delete everything +following this to the end of the makefile +and put the output after this line. +If it doesn't find it, the program +will append the string to the end of the makefile +and place the output following that. +For each +.I sourcefile +appearing on the command line, +.B makedepend +puts lines in the makefile of the form +.sp + sourcefile.o:\0dfile .\|.\|. +.sp +Where \fIsourcefile.o\fP is the name from the command +line with its suffix replaced with ``.o'', +and \fIdfile\fP is a dependency discovered in a +.I #include +directive while parsing +.I sourcefile +or one of the files it included. +.SH EXAMPLE +Normally, +.B makedepend +will be used in a makefile target so that typing ``make depend'' will +bring the dependencies up to date for the makefile. +For example, +.nf + SRCS\0=\0file1.c\0file2.c\0.\|.\|. + CFLAGS\0=\0\-O\0\-DHACK\0\-I\^.\^.\^/foobar\0\-xyz + depend: + makedepend\0\-\^\-\0$(CFLAGS)\0\-\^\-\0$(SRCS) +.fi +.SH OPTIONS +The program +will ignore any option that it does not understand so that you may use +the same arguments that you would for +.B cc(1). +.TP 5 +.B \-D\fIname\fP=\fIdef\fP \fRor\fP \-D\fIname\fP +Define. +This places a definition for +.I name +in +.B makedepend's +symbol table. +Without +.I =def\| +the symbol becomes defined as ``1''. +.TP 5 +.B \-I\fIincludedir\fP +Include directory. +This option tells +.B makedepend +to prepend +.I includedir +to its list of directories to search when it encounters +a +.I #include +directive. +By default, +.B makedepend +only searches the standard include directories (usually /usr/include +and possibly a compiler-dependent directory). +.TP 5 +.B \-Y\fIincludedir\fP +Replace all of the standard include directories with the single specified +include directory; you can omit the +.I includedir +to simply prevent searching the standard include directories. +.TP 5 +.B \-a +Append the dependencies to the end of the file instead of replacing them. +.TP 5 +.B \-f\fImakefile\fP +Filename. +This allows you to specify an alternate makefile in which +.B makedepend +can place its output. +Specifying ``\-'' as the file name (i.e., \fB\-f\-\fP) sends the +output to standard output instead of modifying an existing file. +.TP 5 +.B \-include \fIfile\fP +Process file as input, and include all the resulting output +before processing the regular input file. This has the same +affect as if the specified file is an include statement that +appears before the very first line of the regular input file. +.TP 5 +.B \-o\fIobjsuffix\fP +Object file suffix. +Some systems may have object files whose suffix is something other +than ``.o''. +This option allows you to specify another suffix, such as +``.b'' with +.I \-o.b +or ``:obj'' +with +.I \-o:obj +and so forth. +.TP 5 +.B \-p\fIobjprefix\fP +Object file prefix. +The prefix is prepended to the name of the object file. This is +usually used to designate a different directory for the object file. +The default is the empty string. +.TP 5 +.B \-s\fIstring\fP +Starting string delimiter. +This option permits you to specify +a different string for +.B makedepend +to look for in the makefile. +.TP 5 +.B \-w\fIwidth\fP +Line width. +Normally, +.B makedepend +will ensure that every output line that it writes will be no wider than +78 characters for the sake of readability. +This option enables you to change this width. +.TP 5 +.B \-v +Verbose operation. +This option causes +.B makedepend +to emit the list of files included by each input file. +.TP 5 +.B \-m +Warn about multiple inclusion. +This option causes +.B makedepend +to produce a warning if any input file includes another file more than +once. In previous versions of +.B makedepend +this was the default behavior; the default has been changed to better +match the behavior of the C compiler, which does not consider multiple +inclusion to be an error. This option is provided for backward +compatibility, and to aid in debugging problems related to multiple +inclusion. +.TP 5 +.B "\-\^\- \fIoptions\fP \-\^\-" +If +.B makedepend +encounters a double hyphen (\-\^\-) in the argument list, +then any unrecognized argument following it +will be silently ignored; a second double hyphen terminates this +special treatment. +In this way, +.B makedepend +can be made to safely ignore esoteric compiler arguments that might +normally be found in a CFLAGS +.B make +macro (see the +.B EXAMPLE +section above). +All options that +.B makedepend +recognizes and appear between the pair of double hyphens +are processed normally. +.SH ALGORITHM +The approach used in this program enables it to run an order of magnitude +faster than any other ``dependency generator'' I have ever seen. +Central to this performance are two assumptions: +that all files compiled by a single +makefile will be compiled with roughly the same +.I \-I +and +.I \-D +options; +and that most files in a single directory will include largely the +same files. +.PP +Given these assumptions, +.B makedepend +expects to be called once for each makefile, with +all source files that are maintained by the +makefile appearing on the command line. +It parses each source and include +file exactly once, maintaining an internal symbol table +for each. +Thus, the first file on the command line will take an amount of time +proportional to the amount of time that a normal C preprocessor takes. +But on subsequent files, if it encounters an include file +that it has already parsed, it does not parse it again. +.PP +For example, +imagine you are compiling two files, +.I file1.c +and +.I file2.c, +they each include the header file +.I header.h, +and the file +.I header.h +in turn includes the files +.I def1.h +and +.I def2.h. +When you run the command +.sp + makedepend\0file1.c\0file2.c +.sp +.B makedepend +will parse +.I file1.c +and consequently, +.I header.h +and then +.I def1.h +and +.I def2.h. +It then decides that the dependencies for this file are +.sp + file1.o:\0header.h\0def1.h\0def2.h +.sp +But when the program parses +.I file2.c +and discovers that it, too, includes +.I header.h, +it does not parse the file, +but simply adds +.I header.h, +.I def1.h +and +.I def2.h +to the list of dependencies for +.I file2.o. +.SH "SEE ALSO" +cc(1), make(1) +.SH BUGS +.B makedepend +parses, but does not currently evaluate, the SVR4 #predicate(token-list) +preprocessor expression; such expressions are simply assumed to be true. +This may cause the wrong +.I #include +directives to be evaluated. +.PP +Imagine you are parsing two files, +say +.I file1.c +and +.I file2.c, +each includes the file +.I def.h. +The list of files that +.I def.h +includes might truly be different when +.I def.h +is included by +.I file1.c +than when it is included by +.I file2.c. +But once +.B makedepend +arrives at a list of dependencies for a file, +it is cast in concrete. +.SH AUTHOR +Todd Brunhoff, Tektronix, Inc. and MIT Project Athena diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/parse.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/parse.c new file mode 100644 index 0000000..968d2c4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/parse.c @@ -0,0 +1,686 @@ +/* $Xorg: parse.c,v 1.6 2001/02/09 02:03:16 xorgcvs Exp $ */ +/* + +Copyright (c) 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/config/makedepend/parse.c,v 1.12 2002/02/26 05:09:10 tsi Exp $ */ + +#include "def.h" + +extern char *directives[]; +extern struct inclist inclist[ MAXFILES ], + *inclistnext, + maininclist; +extern char *includedirs[ ], + **includedirsnext; + +static int deftype (char *line, struct filepointer *filep, + struct inclist *file_red, struct inclist *file, + int parse_it); +static int zero_value(char *filename, char *exp, struct filepointer *filep, + struct inclist *file_red); +static int merge2defines(struct inclist *file1, struct inclist *file2); + +static int +gobble(struct filepointer *filep, struct inclist *file, + struct inclist *file_red) +{ + char *line; + int type; + + while ((line = getnextline(filep))) { + switch(type = deftype(line, filep, file_red, file, FALSE)) { + case IF: + case IFFALSE: + case IFGUESSFALSE: + case IFDEF: + case IFNDEF: + type = gobble(filep, file, file_red); + while ((type == ELIF) || (type == ELIFFALSE) || + (type == ELIFGUESSFALSE)) + type = gobble(filep, file, file_red); + if (type == ELSE) + (void)gobble(filep, file, file_red); + break; + case ELSE: + case ENDIF: + debug(0,("%s, line %d: #%s\n", + file->i_file, filep->f_line, + directives[type])); + return(type); + case DEFINE: + case UNDEF: + case INCLUDE: + case INCLUDEDOT: + case PRAGMA: + case ERROR: + case IDENT: + case SCCS: + case EJECT: + case WARNING: + case INCLUDENEXT: + case INCLUDENEXTDOT: + break; + case ELIF: + case ELIFFALSE: + case ELIFGUESSFALSE: + return(type); + case -1: + warning("%s", file_red->i_file); + if (file_red != file) + warning1(" (reading %s)", file->i_file); + warning1(", line %d: unknown directive == \"%s\"\n", + filep->f_line, line); + break; + } + } + return(-1); +} + +/* + * Decide what type of # directive this line is. + */ +static int +deftype (char *line, struct filepointer *filep, + struct inclist *file_red, struct inclist *file, int parse_it) +{ + register char *p; + char *directive, savechar, *q; + register int ret; + + /* + * Parse the directive... + */ + directive=line+1; + while (*directive == ' ' || *directive == '\t') + directive++; + + p = directive; + while ((*p == '_') || (*p >= 'a' && *p <= 'z')) + p++; + savechar = *p; + *p = '\0'; + ret = match(directive, directives); + *p = savechar; + + /* If we don't recognize this compiler directive or we happen to just + * be gobbling up text while waiting for an #endif or #elif or #else + * in the case of an #elif we must check the zero_value and return an + * ELIF or an ELIFFALSE. + */ + + if (ret == ELIF && !parse_it) + { + while (*p == ' ' || *p == '\t') + p++; + /* + * parse an expression. + */ + debug(0,("%s, line %d: #elif %s ", + file->i_file, filep->f_line, p)); + ret = zero_value(file->i_file, p, filep, file_red); + if (ret != IF) + { + debug(0,("false...\n")); + if (ret == IFFALSE) + return(ELIFFALSE); + else + return(ELIFGUESSFALSE); + } + else + { + debug(0,("true...\n")); + return(ELIF); + } + } + + if (ret < 0 || ! parse_it) + return(ret); + + /* + * now decide how to parse the directive, and do it. + */ + while (*p == ' ' || *p == '\t') + p++; + q = p + strlen(p); + do { + q--; + } while (*q == ' ' || *q == '\t'); + q[1] = '\0'; + switch (ret) { + case IF: + /* + * parse an expression. + */ + ret = zero_value(file->i_file, p, filep, file_red); + debug(0,("%s, line %d: %s #if %s\n", + file->i_file, filep->f_line, ret?"false":"true", p)); + break; + case IFDEF: + case IFNDEF: + debug(0,("%s, line %d: #%s %s\n", + file->i_file, filep->f_line, directives[ret], p)); + case UNDEF: + /* + * separate the name of a single symbol. + */ + while (isalnum(*p) || *p == '_') + *line++ = *p++; + *line = '\0'; + break; + case INCLUDE: + case INCLUDENEXT: + debug(2,("%s, line %d: #include%s %s\n", + file->i_file, filep->f_line, + (ret == INCLUDE) ? "" : "_next", p)); + + /* Support ANSI macro substitution */ + while (1) { + struct symtab **sym; + + if (!*p || *p == '"' || *p == '<') + break; + + sym = isdefined(p, file_red, NULL); + if (!sym) + break; + + p = (*sym)->s_value; + debug(3,("%s : #includes SYMBOL %s = %s\n", + file->i_incstring, + (*sym) -> s_name, + (*sym) -> s_value)); + /* mark file as having included a 'soft include' */ + file->i_flags |= INCLUDED_SYM; + } + + /* + * Separate the name of the include file. + */ + while (*p && *p != '"' && *p != '<') + p++; + if (! *p) + return(-2); + if (*p++ == '"') { + if (ret == INCLUDE) + ret = INCLUDEDOT; + else + ret = INCLUDENEXTDOT; + while (*p && *p != '"') + *line++ = *p++; + } else + while (*p && *p != '>') + *line++ = *p++; + *line = '\0'; + break; + case DEFINE: + /* + * copy the definition back to the beginning of the line. + */ + strcpy (line, p); + break; + case ELSE: + case ENDIF: + case ELIF: + case PRAGMA: + case ERROR: + case IDENT: + case SCCS: + case EJECT: + case WARNING: + debug(0,("%s, line %d: #%s\n", + file->i_file, filep->f_line, directives[ret])); + /* + * nothing to do. + */ + break; + } + return(ret); +} + +struct symtab ** +fdefined(char *symbol, struct inclist *file, struct inclist **srcfile) +{ + struct inclist **ip; + struct symtab **val; + int i; + static int recurse_lvl = 0; + + if (file->i_flags & DEFCHECKED) + return(NULL); + debug(2,("Looking for %s in %s\n", symbol, file->i_file)); + file->i_flags |= DEFCHECKED; + if ((val = slookup(symbol, file))) + debug(1,("%s defined in %s as %s\n", + symbol, file->i_file, (*val)->s_value)); + if (val == NULL && file->i_list) + { + for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++) + if (file->i_merged[i]==FALSE) { + val = fdefined(symbol, *ip, srcfile); + file->i_merged[i]=merge2defines(file,*ip); + if (val!=NULL) break; + } + } + else if (val != NULL && srcfile != NULL) *srcfile = file; + recurse_lvl--; + file->i_flags &= ~DEFCHECKED; + + return(val); +} + +struct symtab ** +isdefined(char *symbol, struct inclist *file, struct inclist **srcfile) +{ + struct symtab **val; + + if ((val = slookup(symbol, &maininclist))) { + debug(1,("%s defined on command line\n", symbol)); + if (srcfile != NULL) *srcfile = &maininclist; + return(val); + } + if ((val = fdefined(symbol, file, srcfile))) + return(val); + debug(1,("%s not defined in %s\n", symbol, file->i_file)); + return(NULL); +} + +/* + * Return type based on if the #if expression evaluates to 0 + */ +static int +zero_value(char *filename, + char *exp, + struct filepointer *filep, + struct inclist *file_red) +{ + if (cppsetup(filename, exp, filep, file_red)) + return(IFFALSE); + else + return(IF); +} + +void +define2(char *name, char *val, struct inclist *file) +{ + int first, last, below; + register struct symtab **sp = NULL, **dest; + struct symtab *stab; + + /* Make space if it's needed */ + if (file->i_defs == NULL) + { + file->i_defs = (struct symtab **) + malloc(sizeof (struct symtab*) * SYMTABINC); + file->i_ndefs = 0; + } + else if (!(file->i_ndefs % SYMTABINC)) + file->i_defs = (struct symtab **) + realloc(file->i_defs, + sizeof(struct symtab*)*(file->i_ndefs+SYMTABINC)); + + if (file->i_defs == NULL) + fatalerr("malloc()/realloc() failure in insert_defn()\n"); + + below = first = 0; + last = file->i_ndefs - 1; + while (last >= first) + { + /* Fast inline binary search */ + register char *s1; + register char *s2; + register int middle = (first + last) / 2; + + /* Fast inline strchr() */ + s1 = name; + s2 = file->i_defs[middle]->s_name; + while (*s1++ == *s2++) + if (s2[-1] == '\0') break; + + /* If exact match, set sp and break */ + if (*--s1 == *--s2) + { + sp = file->i_defs + middle; + break; + } + + /* If name > i_defs[middle] ... */ + if (*s1 > *s2) + { + below = first; + first = middle + 1; + } + /* else ... */ + else + { + below = last = middle - 1; + } + } + + /* Search is done. If we found an exact match to the symbol name, + just replace its s_value */ + if (sp != NULL) + { + debug(1,("redefining %s from %s to %s in file %s\n", + name, (*sp)->s_value, val, file->i_file)); + free((*sp)->s_value); + (*sp)->s_value = copy(val); + return; + } + + sp = file->i_defs + file->i_ndefs++; + dest = file->i_defs + below + 1; + while (sp > dest) + { + *sp = sp[-1]; + sp--; + } + stab = (struct symtab *) malloc(sizeof (struct symtab)); + if (stab == NULL) + fatalerr("malloc()/realloc() failure in insert_defn()\n"); + + debug(1,("defining %s to %s in file %s\n", name, val, file->i_file)); + stab->s_name = copy(name); + stab->s_value = copy(val); + *sp = stab; +} + +void +define(char *def, struct inclist *file) +{ + char *val; + + /* Separate symbol name and its value */ + val = def; + while (isalnum(*val) || *val == '_') + val++; + if (*val) + *val++ = '\0'; + while (*val == ' ' || *val == '\t') + val++; + + if (!*val) + val = "1"; + define2(def, val, file); +} + +struct symtab ** +slookup(char *symbol, struct inclist *file) +{ + register int first = 0; + register int last = file->i_ndefs - 1; + + if (file) while (last >= first) + { + /* Fast inline binary search */ + register char *s1; + register char *s2; + register int middle = (first + last) / 2; + + /* Fast inline strchr() */ + s1 = symbol; + s2 = file->i_defs[middle]->s_name; + while (*s1++ == *s2++) + if (s2[-1] == '\0') break; + + /* If exact match, we're done */ + if (*--s1 == *--s2) + { + return file->i_defs + middle; + } + + /* If symbol > i_defs[middle] ... */ + if (*s1 > *s2) + { + first = middle + 1; + } + /* else ... */ + else + { + last = middle - 1; + } + } + return(NULL); +} + +static int +merge2defines(struct inclist *file1, struct inclist *file2) +{ + int i; + + if ((file1==NULL) || (file2==NULL) || + !(file2->i_flags & FINISHED)) + return 0; + + for (i=0; i < file2->i_listlen; i++) + if (file2->i_merged[i]==FALSE) + return 0; + + { + int first1 = 0; + int last1 = file1->i_ndefs - 1; + + int first2 = 0; + int last2 = file2->i_ndefs - 1; + + int first=0; + struct symtab** i_defs = NULL; + int deflen=file1->i_ndefs+file2->i_ndefs; + + debug(2,("merging %s into %s\n", + file2->i_file, file1->i_file)); + + if (deflen>0) + { + /* make sure deflen % SYMTABINC == 0 is still true */ + deflen += (SYMTABINC - deflen % SYMTABINC) % SYMTABINC; + i_defs=(struct symtab**) + malloc(deflen*sizeof(struct symtab*)); + if (i_defs==NULL) return 0; + } + + while ((last1 >= first1) && (last2 >= first2)) + { + char *s1=file1->i_defs[first1]->s_name; + char *s2=file2->i_defs[first2]->s_name; + + if (strcmp(s1,s2) < 0) + i_defs[first++]=file1->i_defs[first1++]; + else if (strcmp(s1,s2) > 0) + i_defs[first++]=file2->i_defs[first2++]; + else /* equal */ + { + i_defs[first++]=file2->i_defs[first2++]; + first1++; + } + } + while (last1 >= first1) + { + i_defs[first++]=file1->i_defs[first1++]; + } + while (last2 >= first2) + { + i_defs[first++]=file2->i_defs[first2++]; + } + + if (file1->i_defs) free(file1->i_defs); + file1->i_defs=i_defs; + file1->i_ndefs=first; + + return 1; + } +} + +void +undefine(char *symbol, struct inclist *file) +{ + register struct symtab **ptr; + struct inclist *srcfile; + while ((ptr = isdefined(symbol, file, &srcfile)) != NULL) + { + srcfile->i_ndefs--; + for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++) + *ptr = ptr[1]; + } +} + +int +find_includes(struct filepointer *filep, struct inclist *file, + struct inclist *file_red, int recursion, boolean failOK) +{ + struct inclist *inclistp; + char **includedirsp; + register char *line; + register int type; + boolean recfailOK; + + while ((line = getnextline(filep))) { + switch(type = deftype(line, filep, file_red, file, TRUE)) { + case IF: + doif: + type = find_includes(filep, file, + file_red, recursion+1, failOK); + while ((type == ELIF) || (type == ELIFFALSE) || + (type == ELIFGUESSFALSE)) + type = gobble(filep, file, file_red); + if (type == ELSE) + gobble(filep, file, file_red); + break; + case IFFALSE: + case IFGUESSFALSE: + doiffalse: + if (type == IFGUESSFALSE || type == ELIFGUESSFALSE) + recfailOK = TRUE; + else + recfailOK = failOK; + type = gobble(filep, file, file_red); + if (type == ELSE) + find_includes(filep, file, + file_red, recursion+1, recfailOK); + else + if (type == ELIF) + goto doif; + else + if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE)) + goto doiffalse; + break; + case IFDEF: + case IFNDEF: + if ((type == IFDEF && isdefined(line, file_red, NULL)) + || (type == IFNDEF && !isdefined(line, file_red, NULL))) { + debug(1,(type == IFNDEF ? + "line %d: %s !def'd in %s via %s%s\n" : "", + filep->f_line, line, + file->i_file, file_red->i_file, ": doit")); + type = find_includes(filep, file, + file_red, recursion+1, failOK); + while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE) + type = gobble(filep, file, file_red); + if (type == ELSE) + gobble(filep, file, file_red); + } + else { + debug(1,(type == IFDEF ? + "line %d: %s !def'd in %s via %s%s\n" : "", + filep->f_line, line, + file->i_file, file_red->i_file, ": gobble")); + type = gobble(filep, file, file_red); + if (type == ELSE) + find_includes(filep, file, + file_red, recursion+1, failOK); + else if (type == ELIF) + goto doif; + else if (type == ELIFFALSE || type == ELIFGUESSFALSE) + goto doiffalse; + } + break; + case ELSE: + case ELIFFALSE: + case ELIFGUESSFALSE: + case ELIF: + if (!recursion) + gobble(filep, file, file_red); + case ENDIF: + if (recursion) + return(type); + case DEFINE: + define(line, file); + break; + case UNDEF: + if (!*line) { + warning("%s", file_red->i_file); + if (file_red != file) + warning1(" (reading %s)", file->i_file); + warning1(", line %d: incomplete undef == \"%s\"\n", + filep->f_line, line); + break; + } + undefine(line, file_red); + break; + case INCLUDE: + case INCLUDEDOT: + case INCLUDENEXT: + case INCLUDENEXTDOT: + inclistp = inclistnext; + includedirsp = includedirsnext; + debug(2,("%s, reading %s, includes %s\n", + file_red->i_file, file->i_file, line)); + add_include(filep, file, file_red, line, type, failOK); + inclistnext = inclistp; + includedirsnext = includedirsp; + break; + case ERROR: + case WARNING: + warning("%s", file_red->i_file); + if (file_red != file) + warning1(" (reading %s)", file->i_file); + warning1(", line %d: %s\n", + filep->f_line, line); + break; + + case PRAGMA: + case IDENT: + case SCCS: + case EJECT: + break; + case -1: + warning("%s", file_red->i_file); + if (file_red != file) + warning1(" (reading %s)", file->i_file); + warning1(", line %d: unknown directive == \"%s\"\n", + filep->f_line, line); + break; + case -2: + warning("%s", file_red->i_file); + if (file_red != file) + warning1(" (reading %s)", file->i_file); + warning1(", line %d: incomplete include == \"%s\"\n", + filep->f_line, line); + break; + } + } + file->i_flags |= FINISHED; + debug(2,("finished with %s\n", file->i_file)); + return(-1); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/pr.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/pr.c new file mode 100644 index 0000000..e864793 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/mkdepend/pr.c @@ -0,0 +1,124 @@ +/* $Xorg: pr.c,v 1.4 2001/02/09 02:03:16 xorgcvs Exp $ */ +/* + +Copyright (c) 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/config/makedepend/pr.c,v 1.5 2001/12/14 19:53:21 dawes Exp $ */ + +#include "def.h" + +extern struct inclist inclist[ MAXFILES ], + *inclistp; +extern char *objprefix; +extern char *objsuffix; +extern int width; +extern boolean printed; +extern boolean verbose; +extern boolean show_where_not; + +void +add_include(struct filepointer *filep, struct inclist *file, + struct inclist *file_red, char *include, int type, + boolean failOK) +{ + register struct inclist *newfile; + register struct filepointer *content; + + /* + * First decide what the pathname of this include file really is. + */ + newfile = inc_path(file->i_file, include, type); + if (newfile == NULL) { + if (failOK) + return; + if (file != file_red) + warning("%s (reading %s, line %d): ", + file_red->i_file, file->i_file, filep->f_line); + else + warning("%s, line %d: ", file->i_file, filep->f_line); + warning1("cannot find include file \"%s\"\n", include); + show_where_not = TRUE; + newfile = inc_path(file->i_file, include, type); + show_where_not = FALSE; + } + + if (newfile) { + included_by(file, newfile); + if (!(newfile->i_flags & SEARCHED)) { + newfile->i_flags |= SEARCHED; + content = getfile(newfile->i_file); + find_includes(content, newfile, file_red, 0, failOK); + freefile(content); + } + } +} + +static void +pr(struct inclist *ip, char *file, char *base) +{ + static char *lastfile; + static int current_len; + register int len, i; + char buf[ BUFSIZ ]; + + printed = TRUE; + len = strlen(ip->i_file)+1; + if (current_len + len > width || file != lastfile) { + lastfile = file; + sprintf(buf, "\n%s%s%s: %s", objprefix, base, objsuffix, + ip->i_file); + len = current_len = strlen(buf); + } + else { + buf[0] = ' '; + strcpy(buf+1, ip->i_file); + current_len += len; + } + fwrite(buf, len, 1, stdout); + + /* + * If verbose is set, then print out what this file includes. + */ + if (! verbose || ip->i_list == NULL || ip->i_flags & NOTIFIED) + return; + ip->i_flags |= NOTIFIED; + lastfile = NULL; + printf("\n# %s includes:", ip->i_file); + for (i=0; ii_listlen; i++) + printf("\n#\t%s", ip->i_list[ i ]->i_incstring); +} + +void +recursive_pr_include(struct inclist *head, char *file, char *base) +{ + int i; + + if (head->i_flags & MARKED) + return; + head->i_flags |= MARKED; + if (head->i_file != file) + pr(head, file, base); + for (i=0; ii_listlen; i++) + recursive_pr_include(head->i_list[ i ], file, base); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nfspwd.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nfspwd.pl new file mode 100644 index 0000000..2f0e4fb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nfspwd.pl @@ -0,0 +1,50 @@ +#! perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +require "fastcwd.pl"; + +$_ = &fastcwd; +if (m@^/[uh]/@o || s@^/tmp_mnt/@/@o) { + print("$_\n"); +} elsif ((($user, $rest) = m@^/usr/people/(\w+)/(.*)@o) + && readlink("/u/$user") eq "/usr/people/$user") { + print("/u/$user/$rest\n"); +} else { + chop($host = `hostname`); + print("/h/$host$_\n"); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nsinstall.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nsinstall.c new file mode 100644 index 0000000..b6ca0e3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nsinstall.c @@ -0,0 +1,481 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* +** Netscape portable install command. +** +** Brendan Eich, 7/20/95 +*/ +#include /* OSF/1 requires this before grp.h, so put it first */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathsub.h" + +#ifdef HAVE_GETOPT_H +#include +#endif + +#ifdef SUNOS4 +#include "sunos4.h" +#endif + +#ifdef NEXTSTEP +#include +#endif + +#ifdef __QNX__ +#include +#endif + +#ifdef NEED_S_ISLNK +#if !defined(S_ISLNK) && defined(S_IFLNK) +#define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) +#endif +#endif + +#ifndef _DIRECTORY_SEPARATOR +#define _DIRECTORY_SEPARATOR "/" +#endif /* _DIRECTORY_SEPARATOR */ + +#ifdef NEED_FCHMOD_PROTO +extern int fchmod(int fildes, mode_t mode); +#endif + +static void +usage(void) +{ + fprintf(stderr, + "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n" + " %*s [-DdltR] file [file ...] directory\n", + program, (int) strlen(program), ""); + exit(2); +} + +static int +mkdirs(char *path, mode_t mode) +{ + char *cp; + struct stat sb; + int res; + int l; + + /* strip trailing "/." */ + l = strlen(path); + if(l > 1 && path[l - 1] == '.' && path[l - 2] == '/') + path[l - 2] = 0; + + while (*path == '/' && path[1] == '/') + path++; + for (cp = strrchr(path, '/'); cp && cp != path && *(cp - 1) == '/'; cp--); + if (cp && cp != path) { + *cp = '\0'; + if ((lstat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) && + mkdirs(path, mode) < 0) { + return -1; + } + *cp = '/'; + } + + res = mkdir(path, mode); + if ((res != 0) && (errno == EEXIST)) + return 0; + else + return res; +} + +static uid_t +touid(char *owner) +{ + struct passwd *pw; + uid_t uid; + char *cp; + + pw = getpwnam(owner); + if (pw) + return pw->pw_uid; + uid = strtol(owner, &cp, 0); + if (uid == 0 && cp == owner) + fail("cannot find uid for %s", owner); + return uid; +} + +static gid_t +togid(char *group) +{ + struct group *gr; + gid_t gid; + char *cp; + + gr = getgrnam(group); + if (gr) + return gr->gr_gid; + gid = strtol(group, &cp, 0); + if (gid == 0 && cp == group) + fail("cannot find gid for %s", group); + return gid; +} + +static void +copyfile( char *name, char *toname, mode_t mode, char *group, char *owner, + int dotimes, uid_t uid, gid_t gid ) +{ + int fromfd, tofd = -1, cc, wc, exists; + char buf[BUFSIZ], *bp; + struct stat sb, tosb; + struct utimbuf utb; + + exists = (lstat(toname, &tosb) == 0); + + fromfd = open(name, O_RDONLY); + if (fromfd < 0 || fstat(fromfd, &sb) < 0) + fail("cannot access %s", name); + if (exists) { + if (S_ISREG(tosb.st_mode)) { + /* See if we can open it. This is more reliable than 'access'. */ + tofd = open(toname, O_CREAT | O_WRONLY, 0666); + } + if (tofd < 0) { + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); + } + } + if (tofd < 0) { + tofd = open(toname, O_CREAT | O_WRONLY, 0666); + if (tofd < 0) + fail("cannot create %s", toname); + } + + bp = buf; + while ((cc = read(fromfd, bp, sizeof buf)) > 0) + { + while ((wc = write(tofd, bp, (unsigned int)cc)) > 0) + { + if ((cc -= wc) == 0) + break; + bp += wc; + } + if (wc < 0) + fail("cannot write to %s", toname); + } + if (cc < 0) + fail("cannot read from %s", name); + + if (ftruncate(tofd, sb.st_size) < 0) + fail("cannot truncate %s", toname); +#if !defined(VMS) + if (dotimes) + { + utb.actime = sb.st_atime; + utb.modtime = sb.st_mtime; + if (utime(toname, &utb) < 0) + fail("cannot set times of %s", toname); + } +#ifdef HAVE_FCHMOD + if (fchmod(tofd, mode) < 0) +#else + if (chmod(toname, mode) < 0) +#endif + fail("cannot change mode of %s", toname); +#endif + if ((owner || group) && fchown(tofd, uid, gid) < 0) + fail("cannot change owner of %s", toname); + + /* Must check for delayed (NFS) write errors on close. */ + if (close(tofd) < 0) + fail("cannot write to %s", toname); + close(fromfd); +#if defined(VMS) + if (chmod(toname, (mode & (S_IREAD | S_IWRITE))) < 0) + fail("cannot change mode of %s", toname); + if (dotimes) + { + utb.actime = sb.st_atime; + utb.modtime = sb.st_mtime; + if (utime(toname, &utb) < 0) + fail("cannot set times of %s", toname); + } +#endif +} + +static void +copydir( char *from, char *to, mode_t mode, char *group, char *owner, + int dotimes, uid_t uid, gid_t gid) +{ + int i; + DIR *dir; + struct dirent *ep; + struct stat sb; + char *base, *destdir, *direntry, *destentry; + + base = xbasename(from); + + /* create destination directory */ + destdir = xmalloc((unsigned int)(strlen(to) + 1 + strlen(base) + 1)); + sprintf(destdir, "%s%s%s", to, _DIRECTORY_SEPARATOR, base); + if (mkdirs(destdir, mode) != 0) { + fail("cannot make directory %s\n", destdir); + return; + } + + dir = opendir(from); + + direntry = xmalloc((unsigned int)PATH_MAX); + destentry = xmalloc((unsigned int)PATH_MAX); + + while ((ep = readdir(dir))) + { + if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) + continue; + + sprintf(direntry, "%s/%s", from, ep->d_name); + sprintf(destentry, "%s%s%s", destdir, _DIRECTORY_SEPARATOR, ep->d_name); + + if (stat(direntry, &sb) == 0 && S_ISDIR(sb.st_mode)) + copydir( direntry, destdir, mode, group, owner, dotimes, uid, gid ); + else + copyfile( direntry, destentry, mode, group, owner, dotimes, uid, gid ); + } + + free(direntry); + free(destentry); + closedir(dir); +} + +int +main(int argc, char **argv) +{ + int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc; + mode_t mode = 0755; + char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ]; + uid_t uid; + gid_t gid; + struct stat sb, tosb, fromsb; + struct utimbuf utb; + + program = argv[0]; + cwd = linkname = linkprefix = owner = group = 0; + onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0; + + while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) { + switch (opt) { + case 'C': + cwd = optarg; + break; + case 'D': + onlydir = 1; + break; + case 'd': + dodir = 1; + break; + case 'l': + dolink = 1; + break; + case 'L': + linkprefix = optarg; + lplen = strlen(linkprefix); + dolink = 1; + break; + case 'R': + dolink = dorelsymlink = 1; + break; + case 'm': + mode = strtoul(optarg, &cp, 8); + if (mode == 0 && cp == optarg) + usage(); + break; + case 'o': + owner = optarg; + break; + case 'g': + group = optarg; + break; + case 't': + dotimes = 1; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc < 2 - onlydir) + usage(); + + todir = argv[argc-1]; + if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) && + mkdirs(todir, 0777) < 0) { + fail("cannot make directory %s", todir); + } + if (onlydir) + return 0; + + if (!cwd) { +#ifndef NEEDS_GETCWD +#ifndef GETCWD_CANT_MALLOC + cwd = getcwd(0, PATH_MAX); +#else + cwd = malloc(PATH_MAX + 1); + cwd = getcwd(cwd, PATH_MAX); +#endif +#else + cwd = malloc(PATH_MAX + 1); + cwd = getwd(cwd); +#endif + } + + xchdir(todir); +#ifndef NEEDS_GETCWD +#ifndef GETCWD_CANT_MALLOC + todir = getcwd(0, PATH_MAX); +#else + todir = malloc(PATH_MAX + 1); + todir = getcwd(todir, PATH_MAX); +#endif +#else + todir = malloc(PATH_MAX + 1); + todir = getwd(todir); +#endif + tdlen = strlen(todir); + xchdir(cwd); + tdlen = strlen(todir); + + uid = owner ? touid(owner) : (uid_t)(-1); + gid = group ? togid(group) : (gid_t)(-1); + + while (--argc > 0) { + name = *argv++; + len = strlen(name); + base = xbasename(name); + bnlen = strlen(base); + toname = xmalloc((unsigned int)(tdlen + 1 + bnlen + 1)); + sprintf(toname, "%s%s%s", todir, _DIRECTORY_SEPARATOR, base); + exists = (lstat(toname, &tosb) == 0); + + if (dodir) { + /* -d means create a directory, always */ + if (exists && !S_ISDIR(tosb.st_mode)) { + (void) unlink(toname); + exists = 0; + } + if (!exists && mkdir(toname, mode) < 0) + fail("cannot make directory %s", toname); + if ((owner || group) && chown(toname, uid, gid) < 0) + fail("cannot change owner of %s", toname); + } else if (dolink) { + if (access(name, R_OK) != 0) { + fail("cannot access %s", name); + } + if (*name == '/') { + /* source is absolute pathname, link to it directly */ + linkname = 0; + } else { + if (linkprefix) { + /* -L implies -l and prefixes names with a $cwd arg. */ + len += lplen + 1; + linkname = xmalloc((unsigned int)(len + 1)); + sprintf(linkname, "%s/%s", linkprefix, name); + } else if (dorelsymlink) { + /* Symlink the relative path from todir to source name. */ + linkname = xmalloc(PATH_MAX); + + if (*todir == '/') { + /* todir is absolute: skip over common prefix. */ + lplen = relatepaths(todir, cwd, linkname); + strcpy(linkname + lplen, name); + } else { + /* todir is named by a relative path: reverse it. */ + reversepath(todir, name, len, linkname); + xchdir(cwd); + } + + len = strlen(linkname); + } + name = linkname; + } + + /* Check for a pre-existing symlink with identical content. */ + if ((exists && (!S_ISLNK(tosb.st_mode) || + readlink(toname, buf, sizeof buf) != len || + strncmp(buf, name, (unsigned int)len) != 0)) || + ((stat(name, &fromsb) == 0) && + (fromsb.st_mtime > tosb.st_mtime))) { + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); + exists = 0; + } + if (!exists && symlink(name, toname) < 0) + fail("cannot make symbolic link %s", toname); +#ifdef HAVE_LCHOWN + if ((owner || group) && lchown(toname, uid, gid) < 0) + fail("cannot change owner of %s", toname); +#endif + + if (linkname) { + free(linkname); + linkname = 0; + } + } else { + /* Copy from name to toname, which might be the same file. */ + if( stat(name, &sb) == 0 && S_IFDIR & sb.st_mode ) + { + /* then is directory: must explicitly create destination dir */ + /* and manually copy files over */ + copydir( name, todir, mode, group, owner, dotimes, uid, gid ); + } + else + { + copyfile(name, toname, mode, group, owner, dotimes, uid, gid); + } + } + + free(toname); + } + + free(cwd); + free(todir); + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nsinstall.py b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nsinstall.py new file mode 100644 index 0000000..fd4e253 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/nsinstall.py @@ -0,0 +1,139 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla. +# +# The Initial Developer of the Original Code is +# the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Axel Hecht +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# This is a partial python port of nsinstall. +# It's intended to be used when there's no natively compile nsinstall +# available, and doesn't intend to be fully equivalent. +# Its major use is for l10n repackaging on systems that don't have +# a full build environment set up. +# The basic limitation is, it doesn't even try to link and ignores +# all related options. + +from optparse import OptionParser +import os +import os.path +import sys +import shutil + +usage = "usage: %prog [options] arg1 [arg2 ...] target-directory" +p = OptionParser(usage=usage) + +p.add_option('-D', action="store_true", + help="Create a single directory only") +p.add_option('-t', action="store_true", + help="Preserve time stamp") +p.add_option('-m', action="store", + help="Set mode", metavar="mode") +p.add_option('-d', action="store_true", + help="Create directories in target") +p.add_option('-R', action="store_true", + help="Use relative symbolic links (ignored)") +p.add_option('-l', action="store_true", + help="Create link (ignored)") +p.add_option('-L', action="store", metavar="linkprefix", + help="Link prefix (ignored)") + +# The remaining arguments are not used in our tree, thus they're not +# implented. +def BadArg(option, opt, value, parser): + parser.error('option not supported: %s' % opt) + +p.add_option('-C', action="callback", metavar="CWD", + callback=BadArg, + help="NOT SUPPORTED") +p.add_option('-o', action="callback", callback=BadArg, + help="Set owner (NOT SUPPORTED)", metavar="owner") +p.add_option('-g', action="callback", callback=BadArg, + help="Set group (NOT SUPPORTED)", metavar="group") + +(options, args) = p.parse_args() + +if options.m: + # mode is specified + try: + options.m = int(options.m, 8) + except: + sys.stderr.write('nsinstall: ' + options.m + ' is not a valid mode\n') + sys.exit(1) + +# just create one directory? +if options.D: + if len(args) != 1: + sys.exit(1) + if os.path.exists(args[0]): + if not os.path.isdir(args[0]): + sys.stderr.write('nsinstall: ' + args[0] + ' is not a directory\n') + sys.exit(1) + if options.m: + os.chmod(args[0], options.m) + sys.exit() + if options.m: + os.makedirs(args[0], options.m) + else: + os.makedirs(args[0]) + sys.exit() + +# nsinstall arg1 [...] directory +if len(args) < 2: + p.error('not enough arguments') + +# set up handler +if options.d: + # we're supposed to create directories + def handleTarget(srcpath, targetpath): + # target directory was already created, just use mkdir + os.mkdir(dest) +else: + # we're supposed to copy files + def handleTarget(srcpath, targetpath): + if options.t: + shutil.copy2(srcpath, targetpath) + else: + shutil.copy(srcpath, targetpath) + +# the last argument is the target directory +target = args.pop() +# ensure target directory +if not os.path.isdir(target): + os.makedirs(target) + +for f in args: + dest = os.path.join(target, + os.path.basename(os.path.normpath(f))) + handleTarget(f, dest) + if options.m: + os.chmod(dest, options.m) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/pathsub.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/pathsub.c new file mode 100644 index 0000000..8384e5f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/pathsub.c @@ -0,0 +1,247 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* +** Pathname subroutines. +** +** Brendan Eich, 8/29/95 +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathsub.h" + +#ifdef USE_REENTRANT_LIBC +#include +#endif + +#ifdef SUNOS4 +#include "sunos4.h" +#endif + +#ifndef D_INO +#define D_INO d_ino +#endif + +char *program; + +void +fail(char *format, ...) +{ + int error; + va_list ap; + +#ifdef USE_REENTRANT_LIBC + R_STRERROR_INIT_R(); +#endif + + error = errno; + fprintf(stderr, "%s: ", program); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + if (error) { + +#ifdef USE_REENTRANT_LIBC + R_STRERROR_R(errno); + fprintf(stderr, ": %s", r_strerror_r); +#else + fprintf(stderr, ": %s", strerror(errno)); +#endif + } + + putc('\n', stderr); + exit(1); +} + +char * +getcomponent(char *path, char *name) +{ + if (*path == '\0') + return 0; + if (*path == '/') { + *name++ = '/'; + } else { + do { + *name++ = *path++; + } while (*path != '/' && *path != '\0'); + } + *name = '\0'; + while (*path == '/') + path++; + return path; +} + +#ifdef LAME_READDIR +#include +/* +** The static buffer in Unixware's readdir is too small. +*/ +struct dirent *readdir(DIR *d) +{ + static struct dirent *buf = NULL; + + if(buf == NULL) + buf = (struct dirent *) malloc(sizeof(struct dirent) + MAXPATHLEN); + return(readdir_r(d, buf)); +} +#endif + +char * +ino2name(ino_t ino, char *dir) +{ + DIR *dp; + struct dirent *ep; + char *name; + + dp = opendir(".."); + if (!dp) + fail("cannot read parent directory"); + for (;;) { + if (!(ep = readdir(dp))) + fail("cannot find current directory"); + if (ep->D_INO == ino) + break; + } + name = xstrdup(ep->d_name); + closedir(dp); + return name; +} + +void * +xmalloc(size_t size) +{ + void *p = malloc(size); + if (!p) + fail("cannot allocate %u bytes", size); + return p; +} + +char * +xstrdup(char *s) +{ + return strcpy(xmalloc(strlen(s) + 1), s); +} + +char * +xbasename(char *path) +{ + char *cp; + + while ((cp = strrchr(path, '/')) && cp[1] == '\0') + *cp = '\0'; + if (!cp) return path; + return cp + 1; +} + +void +xchdir(char *dir) +{ + if (chdir(dir) < 0) + fail("cannot change directory to %s", dir); +} + +int +relatepaths(char *from, char *to, char *outpath) +{ + char *cp, *cp2; + int len; + char buf[NAME_MAX]; + + assert(*from == '/' && *to == '/'); + for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++) + if (*cp == '\0') + break; + while (cp[-1] != '/') + cp--, cp2--; + if (cp - 1 == to) { + /* closest common ancestor is /, so use full pathname */ + len = strlen(strcpy(outpath, to)); + if (outpath[len] != '/') { + outpath[len++] = '/'; + outpath[len] = '\0'; + } + } else { + len = 0; + while ((cp2 = getcomponent(cp2, buf)) != 0) { + strcpy(outpath + len, "../"); + len += 3; + } + while ((cp = getcomponent(cp, buf)) != 0) { + sprintf(outpath + len, "%s/", buf); + len += strlen(outpath + len); + } + } + return len; +} + +void +reversepath(char *inpath, char *name, int len, char *outpath) +{ + char *cp, *cp2; + char buf[NAME_MAX]; + struct stat sb; + + cp = strcpy(outpath + PATH_MAX - (len + 1), name); + cp2 = inpath; + while ((cp2 = getcomponent(cp2, buf)) != 0) { + if (strcmp(buf, ".") == 0) + continue; + if (strcmp(buf, "..") == 0) { + if (stat(".", &sb) < 0) + fail("cannot stat current directory"); + name = ino2name(sb.st_ino, ".."); + len = strlen(name); + cp -= len + 1; + strcpy(cp, name); + cp[len] = '/'; + free(name); + xchdir(".."); + } else { + cp -= 3; + strncpy(cp, "../", 3); + xchdir(buf); + } + } + strcpy(outpath, cp); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/pathsub.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/pathsub.h new file mode 100644 index 0000000..ab1a7fe --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/pathsub.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef pathsub_h___ +#define pathsub_h___ +/* +** Pathname subroutines. +** +** Brendan Eich, 8/29/95 +*/ +#include +#include + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +/* + * Just prevent stupidity + */ +#undef NAME_MAX +#define NAME_MAX 256 + +extern char *program; + +extern void fail(char *format, ...); +extern char *getcomponent(char *path, char *name); +extern char *ino2name(ino_t ino, char *dir); +extern void *xmalloc(size_t size); +extern char *xstrdup(char *s); +extern char *xbasename(char *path); +extern void xchdir(char *dir); + +/* Relate absolute pathnames from and to returning the result in outpath. */ +extern int relatepaths(char *from, char *to, char *outpath); + +/* XXX changes current working directory -- caveat emptor */ +extern void reversepath(char *inpath, char *name, int len, char *outpath); + +#endif /* pathsub_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/preprocessor.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/preprocessor.pl new file mode 100644 index 0000000..3da6654 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/preprocessor.pl @@ -0,0 +1,671 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; tab-width: 4; indent-tabs-mode: nil; -*- +# +# Preprocessor +# Version 1.1 +# +# Copyright (c) 2002, 2003, 2004 by Ian Hickson +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Thanks to bryner and bsmedberg for suggestions. +# Thanks to jon rekai for a patch to not require File::Spec 0.8. + +use strict; + +# takes as arguments the files to process +# defaults to stdin +# output to stdout + +my $stack = new stack; +my $marker = '#'; + +# command line arguments +my @includes; +while ($_ = $ARGV[0], defined($_) && /^-./) { + shift; + last if /^--$/os; + if (/^-D(.*)$/os) { + for ($1) { + if (/^([\w\.]+)=(.*)$/os) { + $stack->define($1, $2); + } elsif (/^([\w\.]+)$/os) { + $stack->define($1, 1); + } else { + die "$0: invalid argument to -D: $_\n"; + } + } + } elsif (/^-F(.*)$/os) { + for ($1) { + if (/^(\w+)$/os) { + $stack->filter($1, 1); + } else { + die "$0: invalid argument to -F: $_\n"; + } + } + } elsif (/^-I(.*)$/os) { + push(@includes, $1); + } elsif (/^-E$/os) { + foreach (keys %ENV) { + # define all variables that have valid names + $stack->define($_, $ENV{$_}) unless m/\W/; + } + } elsif (/^-d$/os) { + $stack->{'dependencies'} = 1; + } elsif (/^--line-endings=crlf$/os) { + $stack->{'lineEndings'} = "\x0D\x0A"; + } elsif (/^--line-endings=cr$/os) { + $stack->{'lineEndings'} = "\x0D"; + } elsif (/^--line-endings=lf$/os) { + $stack->{'lineEndings'} = "\x0A"; + } elsif (/^--line-endings=(.+)$/os) { + die "$0: unrecognised line ending: $1\n"; + } elsif (/^--marker=(.)$/os) { + $marker = $1; + } else { + die "$0: invalid argument: $_\n"; + } +} +unshift(@ARGV, '-') unless @ARGV; +unshift(@ARGV, @includes); + +# do the work +foreach (@ARGV) { include($stack, $_); } +exit(0); + +######################################################################## + +package main; +use File::Spec; +use File::Spec::Unix; # on all platforms, because the #include syntax is unix-based + +# Note: Ideally we would use File::Spec 0.8. When this becomes +# possible, add "0.8" to the first "use" line above, then replace +# occurrences of "::_0_8::" with "->" below. And remove the code for +# File::Spec 0.8 much lower down the file. + +sub include { + my($stack, $filename) = @_; + my $directory = $stack->{'variables'}->{'DIRECTORY'}; + if ($filename ne '-') { + $filename = File::Spec::_0_8::rel2abs($filename, $directory); + # splitpath expects forward-slash paths on windows, so we have to + # change the slashes if using Activestate Perl. + $filename =~ s?\\?/?g if "$^O" eq "MSWin32"; + my($volume, $path) = File::Spec::_0_8::splitpath($filename); + $directory = File::Spec::_0_8::catpath($volume, $path, ''); + } + local $stack->{'variables'}->{'DIRECTORY'} = $directory; + local $stack->{'variables'}->{'FILE'} = $filename; + local $stack->{'variables'}->{'LINE'} = 0; + local *FILE; + open(FILE, $filename) or die "Couldn't open $filename: $!\n"; + my $lineout = 0; + while () { + # on cygwin, line endings are screwed up, so normalise them. + s/[\x0D\x0A]+$/\n/os if ($^O eq 'msys' || $^O eq 'cygwin' || "$^O" eq "MSWin32"); + $stack->newline; + if (/^\Q$marker\E([a-z]+)\n?$/os) { # argumentless processing instruction + process($stack, $1); + } elsif (/^\Q$marker\E([a-z]+)\s(.*?)\n?$/os) { # processing instruction with arguments + process($stack, $1, $2); + } elsif (/^\Q$marker\E/os) { # comment + # ignore it + } elsif ($stack->enabled) { + next if $stack->{'dependencies'}; + + # set the current line number in JavaScript if necessary + my $linein = $stack->{'variables'}->{'LINE'}; + if (++$lineout != $linein) { + if ($filename =~ /\.js(|\.in)$/o) { + $stack->print("//\@line $linein \"$filename\"\n") + } + $lineout = $linein; + } + + # print it, including any newlines + $stack->print(filtered($stack, $_)); + } + } + close(FILE); +} + +sub process { + my($stack, $instruction, @arguments) = @_; + my $method = 'preprocessor'->can($instruction); + if (not defined($method)) { + fatal($stack, 'unknown instruction', $instruction); + } + eval { &$method($stack, @arguments) }; + if ($@) { + fatal($stack, "error evaluating $instruction:", $@); + } +} + +sub filtered { + my($stack, $text) = @_; + foreach my $filter (sort keys %{$stack->{'filters'}}) { + next unless $stack->{'filters'}->{$filter}; + my $method = 'filter'->can($filter); + if (not defined($method)) { + fatal($stack, 'unknown filter', $filter); + } + $text = eval { &$method($stack, $text) }; + if ($@) { + fatal($stack, "error using $filter:", $@); + } + } + return $text; +} + +sub fatal { + my $stack = shift; + my $filename = $stack->{'variables'}->{'FILE'}; + local $" = ' '; + print STDERR "$0:$filename:$.: @_\n"; + exit(1); +} + + +######################################################################## + +package stack; + +# condition evaluated just prior to this context was false +use constant COND_FALSE => 0; + +# condition evaluated just prior to this context was true +use constant COND_TRUE => 1; + +# some prior condition at this level already evaluated to true (or a +# parent condition evaluated to false or must be ignored), so we're +# ignoring all remaining conditions at current level (and nested +# conditions, too) +use constant COND_COMPLETED => 2; + +sub new { + return bless { + 'variables' => { + # %ENV, + 'LINE' => 0, # the line number in the source file + 'DIRECTORY' => '', # current directory + 'FILE' => '', # source filename + '1' => 1, # for convenience (the constant '1' is thus true) + }, + 'filters' => { + # filters + }, + 'values' => [], # the value of the last condition evaluated at the nth level + 'lastConditionState' => [], # whether the condition in the nth-level context was true, false, or not applicable + 'conditionState' => COND_TRUE, + 'dependencies' => 0, # whether we are showing dependencies + 'lineEndings' => "\n", # default to platform conventions + }; +} + +sub newline { + my $self = shift; + $self->{'variables'}->{'LINE'}++; +} + +sub define { + my $self = shift; + my($variable, $value) = @_; + die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/; + $self->{'variables'}->{$variable} = $value; +} + +sub defined { + my $self = shift; + my($variable) = @_; + die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/; + return defined($self->{'variables'}->{$variable}); +} + +sub undefine { + my $self = shift; + my($variable) = @_; + die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/; + delete($self->{'variables'}->{$variable}); +} + +sub get { + my $self = shift; + my($variable, $required) = @_; + die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/; + my $value = $self->{'variables'}->{$variable}; + if (defined($value)) { + return $value; + } else { + die "variable '$variable' is not defined\n" if $required; + return ''; + } +} + +sub replace { + my $self = shift; + my ($value) = @_; + + ${$self->{'values'}}[-1] = $value; + $self->{'conditionState'} = $self->{'conditionState'} != COND_FALSE + ? COND_COMPLETED + : $value ? COND_TRUE : COND_FALSE; +} + +sub push { + my $self = shift; + my($value) = @_; + + push(@{$self->{'values'}}, $value); + my $lastCondition = $self->{'conditionState'}; + push(@{$self->{'lastConditionState'}}, $lastCondition); + $self->{'conditionState'} = $lastCondition != COND_TRUE + ? COND_COMPLETED + : $value ? COND_TRUE : COND_FALSE; +} + +sub pop { + my $self = shift; + $self->{'conditionState'} = pop(@{$self->{'lastConditionState'}}); + return pop(@{$self->{'values'}}); +} + +sub enabled { + my $self = shift; + return $self->{'conditionState'} == COND_TRUE; +} + +sub disabled { + my $self = shift; + return $self->{'conditionState'} != COND_TRUE; +} + +sub filter { + my $self = shift; + my($filter, $value) = @_; + die "not a valid filter name: '$filter'\n" if $filter =~ m/\W/; + $self->{'filters'}->{$filter} = $value; +} + +sub expand { + my $self = shift; + my($line) = @_; + $line =~ s/__(\w+)__/$self->get($1)/gose; + return $line; +} + +sub print { + my $self = shift; + return if $self->{'dependencies'}; + foreach my $line (@_) { + if (chomp $line) { + CORE::print("$line$self->{'lineEndings'}"); + } else { + CORE::print($line); + } + } +} + +sub visit { + my $self = shift; + my($filename) = @_; + my $directory = $stack->{'variables'}->{'DIRECTORY'}; + $filename = File::Spec::_0_8::abs2rel(File::Spec::_0_8::rel2abs($filename, $directory)); + CORE::print("$filename\n"); +} + +######################################################################## + +package preprocessor; + +sub define { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + my $argument = shift; + for ($argument) { + /^(\w+)\s(.*)$/os && do { + return $stack->define($1, $2); + }; + /^(\w+)$/os && do { + return $stack->define($1, 1); + }; + die "invalid argument: '$_'\n"; + } +} + +sub undef { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + $stack->undefine(@_); +} + +sub ifdef { + my $stack = shift; + my $variable = shift; + my $replace = defined(shift); + die "argument expected\n" unless defined($variable); + if ($replace) { + $stack->replace($stack->defined($variable)); + } else { + $stack->push($stack->defined($variable)); + } +} + +sub ifndef { + my $stack = shift; + my $variable = shift; + my $replace = defined(shift); + die "argument expected\n" unless defined($variable); + if ($replace) { + $stack->replace(not $stack->defined($variable)); + } else { + $stack->push(not $stack->defined($variable)); + } +} + +sub if { + my $stack = shift; + die "argument expected\n" unless @_; + my $argument = shift; + my $replace = defined(shift); + for ($argument) { + /^(\w+)==(.*)$/os && do { + # equality + if ($replace) { + return $stack->replace($stack->get($1) eq $2); + } else { + return $stack->push($stack->get($1) eq $2); + } + }; + /^(\w+)!=(.*)$/os && do { + # inequality + if ($replace) { + return $stack->replace($stack->get($1) ne $2); + } else { + return $stack->push($stack->get($1) ne $2); + } + }; + /^(\w+)$/os && do { + # true value + if ($replace) { + return $stack->replace($stack->get($1)); + } else { + return $stack->push($stack->get($1)); + } + }; + /^!(\w+)$/os && do { + # false value + if ($replace) { + return $stack->replace(not $stack->get($1)); + } else { + return $stack->push(not $stack->get($1)); + } + }; + die "invalid argument: '$_'\n"; + } +} + +sub else { + my $stack = shift; + die "argument unexpected\n" if @_; + $stack->replace(1); +} + +sub elif { + my $stack = shift; + die "argument expected\n" unless @_; + &if($stack, @_, 1); +} + +sub elifdef { + my $stack = shift; + die "argument expected\n" unless @_; + &ifdef($stack, @_, 1); +} + +sub elifndef { + my $stack = shift; + die "argument expected\n" unless @_; + &ifndef($stack, @_, 1); +} + +sub endif { + my $stack = shift; + die "argument unexpected\n" if @_; + $stack->pop; +} + +sub error { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + my $line = $stack->expand(@_); + die "$line\n"; +} + +sub expand { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + my $line = $stack->expand(@_); + $stack->print("$line\n"); +} + +sub literal { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + my $line = shift; + $stack->print("$line\n"); +} + +sub include { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + my $filename = File::Spec::_0_8::catpath(File::Spec::_0_8::splitpath(@_)); + if ($stack->{'dependencies'}) { + $stack->visit($filename); + } else { + main::include($stack, $filename); + } +} + +sub includesubst { + my ($stack, $filename) = @_; + return if $stack->disabled; + die "argument expected\n" unless $filename; + $filename =~ s/@(\w+)@/$stack->get($1, 1)/gose; + $filename = File::Spec::_0_8::catpath(File::Spec::_0_8::splitpath($filename)); + if ($stack->{'dependencies'}) { + $stack->visit($filename); + } else { + main::include($stack, $filename); + } +} + +sub filter { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + foreach (split(/\s/os, shift)) { + $stack->filter($_, 1); + } +} + +sub unfilter { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + foreach (split(/\s/os, shift)) { + $stack->filter($_, 0); + } +} + + +######################################################################## + +package filter; + +sub emptyLines { + my($stack, $text) = @_; + $text = "" if $text eq "\n"; + return $text; +} + +sub spaces { + my($stack, $text) = @_; + $text =~ s/ +/ /gos; # middle spaces + $text =~ s/^ //gos; # start spaces + $text =~ s/ (\n?)$/$1/gos; # end spaces + return $text; +} + +sub slashslash { + my($stack, $text) = @_; + $text =~ s|//.*?(\n?)$|$1|gos; + return $text; +} + +sub substitution { + my($stack, $text) = @_; + $text =~ s/@(\w+)@/$stack->get($1, 1)/gose; + return $text; +} + +sub attemptSubstitution { + my($stack, $text) = @_; + $text =~ s/@(\w+)@/$stack->get($1, 0)/gose; + return $text; +} + +######################################################################## + +######################################################################## +# This code is from File::Spec::Unix 0.8. +# It is not considered a part of the preprocessor.pl source file +# This code is licensed under the same license as File::Spec itself. + +package File::Spec::_0_8; + +use Cwd; + +sub rel2abs { + my ($path, $base) = @_; + if ( ! File::Spec->file_name_is_absolute( $path ) ) { + if ( !defined( $base ) || $base eq '' ) { + $base = cwd() ; + } elsif ( ! File::Spec->file_name_is_absolute( $base ) ) { + $base = rel2abs( $base ); + } else { + $base = File::Spec->canonpath( $base ); + } + $path = File::Spec->catdir( $base, $path ); + } + return File::Spec->canonpath( $path ); +} + +sub splitdir { + return split m|/|, $_[1], -1; # Preserve trailing fields +} + +sub splitpath { + my ($path, $nofile) = @_; + + my ($volume,$directory,$file) = ('','',''); + + if ( $nofile ) { + $directory = $path; + } + else { + $path =~ m|^ ( (?: .* / (?: \.\.?\Z(?!\n) )? )? ) ([^/]*) |xs; + $directory = $1; + $file = $2; + } + + return ($volume,$directory,$file); +} + +sub catpath { + my ($volume,$directory,$file) = @_; + + if ( $directory ne '' && + $file ne '' && + substr( $directory, -1 ) ne '/' && + substr( $file, 0, 1 ) ne '/' + ) { + $directory .= "/$file" ; + } + else { + $directory .= $file ; + } + + return $directory ; +} + +sub abs2rel { + my($path,$base) = @_; + + # Clean up $path + if ( ! File::Spec->file_name_is_absolute( $path ) ) { + $path = rel2abs( $path ) ; + } + else { + $path = File::Spec->canonpath( $path ) ; + } + + # Figure out the effective $base and clean it up. + if ( !defined( $base ) || $base eq '' ) { + $base = cwd(); + } + elsif ( ! File::Spec->file_name_is_absolute( $base ) ) { + $base = rel2abs( $base ) ; + } + else { + $base = File::Spec->canonpath( $base ) ; + } + + # Now, remove all leading components that are the same + my @pathchunks = File::Spec::_0_8::splitdir( $path); + my @basechunks = File::Spec::_0_8::splitdir( $base); + + while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) { + shift @pathchunks ; + shift @basechunks ; + } + + $path = CORE::join( '/', @pathchunks ); + $base = CORE::join( '/', @basechunks ); + + # $base now contains the directories the resulting relative path + # must ascend out of before it can descend to $path_directory. So, + # replace all names with $parentDir + $base =~ s|[^/]+|..|g ; + + # Glue the two together, using a separator if necessary, and preventing an + # empty result. + if ( $path ne '' && $base ne '' ) { + $path = "$base/$path" ; + } else { + $path = "$base$path" ; + } + + return File::Spec->canonpath( $path ) ; +} + +# End code from File::Spec::Unix 0.8. +######################################################################## diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/revdepth-nt.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/revdepth-nt.pl new file mode 100644 index 0000000..8853268 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/revdepth-nt.pl @@ -0,0 +1,48 @@ +#! perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +require "/ns/config/fastcwd.pl"; + +$cur = &fastcwd; +chdir($ARGV[0]); +$newcur = &fastcwd; +$newcurlen = length($newcur); + +# Skip common separating / unless $newcur is "/" +$cur = substr($cur, $newcurlen + ($newcurlen > 1)); +print $cur; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/revdepth.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/revdepth.pl new file mode 100644 index 0000000..3ec4272 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/revdepth.pl @@ -0,0 +1,51 @@ +#! perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +unshift(@INC, '/usr/lib/perl'); +unshift(@INC, '/usr/local/lib/perl'); + +require "fastcwd.pl"; + +$cur = &fastcwd; +chdir($ARGV[0]); +$newcur = &fastcwd; +$newcurlen = length($newcur); + +# Skip common separating / unless $newcur is "/" +$cur = substr($cur, $newcurlen + ($newcurlen > 1)); +print $cur; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/rules.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/rules.mk new file mode 100644 index 0000000..6168216 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/rules.mk @@ -0,0 +1,2269 @@ +# vim:set ts=8 sw=8 sts=8 noet: +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Chase Phillips +# Benjamin Smedberg +# Jeff Walden +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +NO_DIST_INSTALL = 1 + +ifndef topsrcdir +topsrcdir = $(DEPTH) +endif + +ifndef MOZILLA_DIR +MOZILLA_DIR = $(topsrcdir) +endif + +ifndef INCLUDED_CONFIG_MK +include $(topsrcdir)/config/config.mk +endif + +ifndef INCLUDED_VERSION_MK +include $(topsrcdir)/config/version.mk +endif + +REPORT_BUILD = @echo $(notdir $<) + +ifeq ($(OS_ARCH),OS2) +EXEC = +else +EXEC = exec +endif + +# ELOG prints out failed command when building silently (gmake -s). +ifneq (,$(findstring -s,$(MAKEFLAGS))) + ELOG := $(EXEC) sh $(BUILD_TOOLS)/print-failed-commands.sh +else + ELOG := +endif + +ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH))) +ifndef GNU_CC +_LIBNAME_RELATIVE_PATHS=1 +endif +endif + +ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH))) +PWD := $(shell pwd) +_VPATH_SRCS = $(if $(filter /%,$<),$<,$(PWD)/$<) +else +_VPATH_SRCS = $< +endif + +# Add $(DIST)/lib to VPATH so that -lfoo dependencies are followed +VPATH += $(DIST)/lib +ifdef LIBXUL_SDK +VPATH += $(LIBXUL_SDK)/lib +endif + +# EXPAND_LIBNAME - $(call EXPAND_LIBNAME,foo) +# expands to foo.lib on platforms with import libs and -lfoo otherwise + +# EXPAND_LIBNAME_PATH - $(call EXPAND_LIBNAME_PATH,foo,dir) +# expands to dir/foo.lib on platforms with import libs and +# -Ldir -lfoo otherwise + +# EXPAND_MOZLIBNAME - $(call EXPAND_MOZLIBNAME,foo) +# expands to $(DIST)/lib/foo.lib on platforms with import libs and +# -lfoo otherwise + +ifdef _LIBNAME_RELATIVE_PATHS +EXPAND_LIBNAME = $(foreach lib,$(1),$(LIB_PREFIX)$(lib).$(LIB_SUFFIX)) +EXPAND_LIBNAME_PATH = $(foreach lib,$(1),$(2)/$(LIB_PREFIX)$(lib).$(LIB_SUFFIX)) +EXPAND_MOZLIBNAME = $(foreach lib,$(1),$(DIST)/lib/$(LIB_PREFIX)$(lib).$(LIB_SUFFIX)) +else +EXPAND_LIBNAME = $(addprefix -l,$(1)) +EXPAND_LIBNAME_PATH = -L$(2) $(addprefix -l,$(1)) +EXPAND_MOZLIBNAME = $(addprefix -l,$(1)) +endif + +ifdef EXTRA_DSO_LIBS +EXTRA_DSO_LIBS := $(call EXPAND_MOZLIBNAME,$(EXTRA_DSO_LIBS)) +endif + +# +# Library rules +# +# If BUILD_STATIC_LIBS or FORCE_STATIC_LIB is set, build a static library. +# Otherwise, build a shared library. +# + +ifndef LIBRARY +ifdef LIBRARY_NAME +ifneq (,$(filter OS2 WINNT WINCE,$(OS_ARCH))) +ifdef SHORT_LIBNAME +LIBRARY_NAME := $(SHORT_LIBNAME) +endif +endif +LIBRARY := $(LIB_PREFIX)$(LIBRARY_NAME).$(LIB_SUFFIX) +endif +endif + +ifndef HOST_LIBRARY +ifdef HOST_LIBRARY_NAME +HOST_LIBRARY := $(LIB_PREFIX)$(HOST_LIBRARY_NAME).$(LIB_SUFFIX) +endif +endif + +ifdef LIBRARY +ifneq (_1,$(FORCE_SHARED_LIB)_$(BUILD_STATIC_LIBS)) +ifdef MKSHLIB + +ifdef LIB_IS_C_ONLY +MKSHLIB = $(MKCSHLIB) +endif + +ifdef MAKE_FRAMEWORK +SHARED_LIBRARY := $(LIBRARY_NAME) +else +SHARED_LIBRARY := $(DLL_PREFIX)$(LIBRARY_NAME)$(DLL_SUFFIX) +endif + +ifeq ($(OS_ARCH),OS2) +DEF_FILE := $(SHARED_LIBRARY:.dll=.def) +endif + +ifneq (,$(filter OS2 WINNT WINCE,$(OS_ARCH))) +IMPORT_LIBRARY := $(LIB_PREFIX)$(LIBRARY_NAME).$(IMPORT_LIB_SUFFIX) +endif + +ifdef MOZ_ENABLE_LIBXUL +EMBED_MANIFEST_AT=2 +endif + +endif # MKSHLIB +endif # FORCE_SHARED_LIB && !BUILD_STATIC_LIBS +endif # LIBRARY + +ifeq (,$(BUILD_STATIC_LIBS)$(FORCE_STATIC_LIB)) +LIBRARY := $(NULL) +endif + +ifeq (_1,$(FORCE_SHARED_LIB)_$(BUILD_STATIC_LIBS)) +SHARED_LIBRARY := $(NULL) +DEF_FILE := $(NULL) +IMPORT_LIBRARY := $(NULL) +endif + +ifdef FORCE_STATIC_LIB +ifndef FORCE_SHARED_LIB +SHARED_LIBRARY := $(NULL) +DEF_FILE := $(NULL) +IMPORT_LIBRARY := $(NULL) +endif +endif + +ifdef FORCE_SHARED_LIB +ifndef FORCE_STATIC_LIB +LIBRARY := $(NULL) +endif +endif + +ifdef JAVA_LIBRARY_NAME +JAVA_LIBRARY := $(JAVA_LIBRARY_NAME).jar +endif + +ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH))) +ifndef GNU_CC + +# +# All C++ files share a PDB file per directory. For parallel builds, this PDB +# file is shared and locked by MSPDBSRV.EXE, starting with MSVC8 SP1. If +# you're using MSVC 7.1 or MSVC8 without SP1, don't do parallel builds. +# +# The final PDB for libraries and programs is created by the linker and uses +# a different name from the single PDB file created by the compiler. See +# bug 462740. +# +COMPILE_PDBFILE = generated.pdb +LINK_PDBFILE = $(basename $(@F)).pdb +ifdef MOZ_DEBUG +CODFILE=$(basename $(@F)).cod +endif + +ifdef MOZ_MAPINFO +ifdef LIBRARY_NAME +MAPFILE=$(LIBRARY_NAME).map +else +MAPFILE=$(basename $(@F)).map +endif # LIBRARY_NAME +endif # MOZ_MAPINFO + +ifdef DEFFILE +OS_LDFLAGS += -DEF:$(DEFFILE) +EXTRA_DEPS += $(DEFFILE) +endif + +ifdef MAPFILE +OS_LDFLAGS += -MAP:$(MAPFILE) +#CFLAGS += -Fm$(MAPFILE) +#CXXFLAGS += -Fm$(MAPFILE) +endif + +#ifdef CODFILE +#CFLAGS += -Fa$(CODFILE) -FAsc +#CFLAGS += -Fa$(CODFILE) -FAsc +#endif + +endif # !GNU_CC + +ifdef ENABLE_CXX_EXCEPTIONS +ifdef GNU_CC +CXXFLAGS += -fexceptions +else +ifeq (,$(filter-out 1200 1300 1310,$(_MSC_VER))) +CXXFLAGS += -GX +else +CXXFLAGS += -EHsc +endif # _MSC_VER +endif # GNU_CC +endif # ENABLE_CXX_EXCEPTIONS +endif # WINNT + +ifeq (,$(filter-out WINNT WINCE,$(HOST_OS_ARCH))) +HOST_PDBFILE=$(basename $(@F)).pdb +endif + +ifndef TARGETS +TARGETS = $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(JAVA_LIBRARY) +endif + +ifndef OBJS +_OBJS = \ + $(JRI_STUB_CFILES) \ + $(addsuffix .$(OBJ_SUFFIX), $(JMC_GEN)) \ + $(CSRCS:.c=.$(OBJ_SUFFIX)) \ + $(patsubst %.cc,%.$(OBJ_SUFFIX),$(CPPSRCS:.cpp=.$(OBJ_SUFFIX))) \ + $(CMSRCS:.m=.$(OBJ_SUFFIX)) \ + $(CMMSRCS:.mm=.$(OBJ_SUFFIX)) \ + $(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX)) +OBJS = $(strip $(_OBJS)) +endif + +ifndef HOST_OBJS +_HOST_OBJS = \ + $(addprefix host_,$(HOST_CSRCS:.c=.$(OBJ_SUFFIX))) \ + $(addprefix host_,$(patsubst %.cc,%.$(OBJ_SUFFIX),$(HOST_CPPSRCS:.cpp=.$(OBJ_SUFFIX)))) \ + $(addprefix host_,$(HOST_CMSRCS:.m=.$(OBJ_SUFFIX))) \ + $(addprefix host_,$(HOST_CMMSRCS:.mm=.$(OBJ_SUFFIX))) +HOST_OBJS = $(strip $(_HOST_OBJS)) +endif + +LIBOBJS := $(addprefix \", $(OBJS)) +LIBOBJS := $(addsuffix \", $(LIBOBJS)) + +ifndef MOZ_AUTO_DEPS +ifneq (,$(OBJS)$(XPIDLSRCS)$(SDK_XPIDLSRCS)$(SIMPLE_PROGRAMS)) +MDDEPFILES = $(addprefix $(MDDEPDIR)/,$(OBJS:.$(OBJ_SUFFIX)=.pp)) +ifndef NO_GEN_XPT +MDDEPFILES += $(addprefix $(MDDEPDIR)/,$(XPIDLSRCS:.idl=.xpt)) \ + $(addprefix $(MDDEPDIR)/,$(SDK_XPIDLSRCS:.idl=.xpt)) +endif +endif +endif + +ALL_TRASH = \ + $(GARBAGE) $(TARGETS) $(OBJS) $(PROGOBJS) LOGS TAGS a.out \ + $(filter-out $(ASFILES),$(OBJS:.$(OBJ_SUFFIX)=.s)) $(OBJS:.$(OBJ_SUFFIX)=.ii) \ + $(OBJS:.$(OBJ_SUFFIX)=.i) \ + $(HOST_PROGOBJS) $(HOST_OBJS) $(IMPORT_LIBRARY) $(DEF_FILE)\ + $(EXE_DEF_FILE) so_locations _gen _stubs $(wildcard *.res) $(wildcard *.RES) \ + $(wildcard *.pdb) $(CODFILE) $(MAPFILE) $(IMPORT_LIBRARY) \ + $(SHARED_LIBRARY:$(DLL_SUFFIX)=.exp) $(wildcard *.ilk) \ + $(PROGRAM:$(BIN_SUFFIX)=.exp) $(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=.exp) \ + $(PROGRAM:$(BIN_SUFFIX)=.lib) $(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=.lib) \ + $(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=.$(OBJ_SUFFIX)) \ + $(wildcard gts_tmp_*) $(LIBRARY:%.a=.%.timestamp) +ALL_TRASH_DIRS = \ + $(GARBAGE_DIRS) /no-such-file + +ifdef QTDIR +GARBAGE += $(MOCSRCS) +endif + +ifdef SIMPLE_PROGRAMS +GARBAGE += $(SIMPLE_PROGRAMS:%=%.$(OBJ_SUFFIX)) +endif + +ifdef HOST_SIMPLE_PROGRAMS +GARBAGE += $(HOST_SIMPLE_PROGRAMS:%=%.$(OBJ_SUFFIX)) +endif + +# +# the Solaris WorkShop template repository cache. it occasionally can get +# out of sync, so targets like clobber should kill it. +# +ifeq ($(OS_ARCH),SunOS) +ifeq ($(GNU_CXX),) +GARBAGE_DIRS += SunWS_cache +endif +endif + +ifeq ($(OS_ARCH),OpenVMS) +GARBAGE += $(wildcard *.*_defines) +ifdef SHARED_LIBRARY +VMS_SYMVEC_FILE = $(SHARED_LIBRARY:$(DLL_SUFFIX)=_symvec.opt) +ifdef MOZ_DEBUG +VMS_SYMVEC_FILE_MODULE = $(topsrcdir)/build/unix/vms/$(notdir $(SHARED_LIBRARY:$(DLL_SUFFIX)=_dbg_symvec.opt)) +else +VMS_SYMVEC_FILE_MODULE = $(topsrcdir)/build/unix/vms/$(notdir $(SHARED_LIBRARY:$(DLL_SUFFIX)=_symvec.opt)) +endif +VMS_SYMVEC_FILE_COMP = $(topsrcdir)/build/unix/vms/component_symvec.opt +GARBAGE += $(VMS_SYMVEC_FILE) +ifdef IS_COMPONENT +DSO_LDOPTS := $(filter-out -auto_symvec,$(DSO_LDOPTS)) $(VMS_SYMVEC_FILE) +endif +endif +endif + +XPIDL_GEN_DIR = _xpidlgen + +ifdef MOZ_UPDATE_XTERM +# Its good not to have a newline at the end of the titlebar string because it +# makes the make -s output easier to read. Echo -n does not work on all +# platforms, but we can trick sed into doing it. +UPDATE_TITLE = sed -e "s!Y!$@ in $(shell $(BUILD_TOOLS)/print-depth-path.sh)/$(dir)!" $(MOZILLA_DIR)/config/xterm.str; +UPDATE_TITLE_export = sed -e "s!Y!export in $(shell $(BUILD_TOOLS)/print-depth-path.sh)/$*!" $(MOZILLA_DIR)/config/xterm.str; +UPDATE_TITLE_libs = sed -e "s!Y!libs in $(shell $(BUILD_TOOLS)/print-depth-path.sh)/$*!" $(MOZILLA_DIR)/config/xterm.str; +UPDATE_TITLE_tools = sed -e "s!Y!tools in $(shell $(BUILD_TOOLS)/print-depth-path.sh)/$*!" $(MOZILLA_DIR)/config/xterm.str; +endif + +LOOP_OVER_DIRS = \ + @$(EXIT_ON_ERROR) \ + $(foreach dir,$(DIRS),$(UPDATE_TITLE) $(MAKE) -C $(dir) $@; ) true + +# we only use this for the makefiles target and other stuff that doesn't matter +LOOP_OVER_PARALLEL_DIRS = \ + @$(EXIT_ON_ERROR) \ + $(foreach dir,$(PARALLEL_DIRS),$(UPDATE_TITLE) $(MAKE) -C $(dir) $@; ) true + +LOOP_OVER_STATIC_DIRS = \ + @$(EXIT_ON_ERROR) \ + $(foreach dir,$(STATIC_DIRS),$(UPDATE_TITLE) $(MAKE) -C $(dir) $@; ) true + +LOOP_OVER_TOOL_DIRS = \ + @$(EXIT_ON_ERROR) \ + $(foreach dir,$(TOOL_DIRS),$(UPDATE_TITLE) $(MAKE) -C $(dir) $@; ) true + +ifdef PARALLEL_DIRS +# create a bunch of fake targets for order-only processing +PARALLEL_DIRS_export = $(addsuffix _export,$(PARALLEL_DIRS)) +PARALLEL_DIRS_libs = $(addsuffix _libs,$(PARALLEL_DIRS)) +PARALLEL_DIRS_tools = $(addsuffix _tools,$(PARALLEL_DIRS)) + +.PHONY: $(PARALLEL_DIRS_export) $(PARALLEL_DIRS_libs) $(PARALLEL_DIRS_tools) +endif + +# +# Now we can differentiate between objects used to build a library, and +# objects used to build an executable in the same directory. +# +ifndef PROGOBJS +PROGOBJS = $(OBJS) +endif + +ifndef HOST_PROGOBJS +HOST_PROGOBJS = $(HOST_OBJS) +endif + +# MAKE_DIRS: List of directories to build while looping over directories. +# A Makefile that needs $(MDDEPDIR) created but doesn't set any of these +# variables we know to check can just set NEED_MDDEPDIR explicitly. +ifneq (,$(OBJS)$(XPIDLSRCS)$(SDK_XPIDLSRCS)$(SIMPLE_PROGRAMS)$(NEED_MDDEPDIR)) +MAKE_DIRS += $(CURDIR)/$(MDDEPDIR) +GARBAGE_DIRS += $(MDDEPDIR) +endif + +# +# Tags: emacs (etags), vi (ctags) +# TAG_PROGRAM := ctags -L - +# +TAG_PROGRAM = xargs etags -a + +# +# Turn on C++ linking if we have any .cpp or .mm files +# (moved this from config.mk so that config.mk can be included +# before the CPPSRCS are defined) +# +ifneq ($(CPPSRCS)$(CMMSRCS),) +CPP_PROG_LINK = 1 +endif + +# +# Make sure to wrap static libs inside linker specific flags to turn on & off +# inclusion of all symbols inside the static libs +# +ifndef NO_LD_ARCHIVE_FLAGS +ifdef SHARED_LIBRARY_LIBS +EXTRA_DSO_LDOPTS := $(MKSHLIB_FORCE_ALL) $(SHARED_LIBRARY_LIBS) $(MKSHLIB_UNFORCE_ALL) $(EXTRA_DSO_LDOPTS) +endif +endif + +# +# This will strip out symbols that the component should not be +# exporting from the .dynsym section. +# +ifdef IS_COMPONENT +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS) +endif # IS_COMPONENT + +# +# Enforce the requirement that MODULE_NAME must be set +# for components in static builds +# +ifdef IS_COMPONENT +ifdef EXPORT_LIBRARY +ifndef FORCE_SHARED_LIB +ifndef MODULE_NAME +$(error MODULE_NAME is required for components which may be used in static builds) +endif +endif +endif +endif + +# +# MacOS X specific stuff +# + +ifeq ($(OS_ARCH),Darwin) +ifdef SHARED_LIBRARY +ifdef IS_COMPONENT +EXTRA_DSO_LDOPTS += -bundle +else +EXTRA_DSO_LDOPTS += -dynamiclib -install_name @executable_path/$(SHARED_LIBRARY) -compatibility_version 1 -current_version 1 -single_module +endif +endif +endif + +# +# On NetBSD a.out systems, use -Bsymbolic. This fixes what would otherwise be +# fatal symbol name clashes between components. +# +ifeq ($(OS_ARCH),NetBSD) +ifeq ($(DLL_SUFFIX),.so.1.0) +ifdef IS_COMPONENT +EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic +endif +endif +endif + +ifeq ($(OS_ARCH),FreeBSD) +ifdef IS_COMPONENT +EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic +endif +endif + +ifeq ($(OS_ARCH),NetBSD) +ifneq (,$(filter arc cobalt hpcmips mipsco newsmips pmax sgimips,$(OS_TEST))) +ifeq ($(MODULE),layout) +OS_CFLAGS += -Wa,-xgot +OS_CXXFLAGS += -Wa,-xgot +endif +endif +endif + +ifeq ($(OS_ARCH),Linux) +ifneq (,$(filter mips mipsel,$(OS_TEST))) +ifeq ($(MODULE),layout) +OS_CFLAGS += -Wa,-xgot +OS_CXXFLAGS += -Wa,-xgot +endif +endif +endif + +# +# HP-UXBeOS specific section: for COMPONENTS only, add -Bsymbolic flag +# which uses internal symbols first +# +ifeq ($(OS_ARCH),HP-UX) +ifdef IS_COMPONENT +ifeq ($(GNU_CC)$(GNU_CXX),) +EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic +ifneq ($(HAS_EXTRAEXPORTS),1) +MKSHLIB += -Wl,+eNSGetModule -Wl,+eerrno +MKCSHLIB += +eNSGetModule +eerrno +ifneq ($(OS_TEST),ia64) +MKSHLIB += -Wl,+e_shlInit +MKCSHLIB += +e_shlInit +endif # !ia64 +endif # !HAS_EXTRAEXPORTS +endif # non-gnu compilers +endif # IS_COMPONENT +endif # HP-UX + +ifeq ($(OS_ARCH),AIX) +ifdef IS_COMPONENT +ifneq ($(HAS_EXTRAEXPORTS),1) +MKSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall +MKCSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall +endif # HAS_EXTRAEXPORTS +endif # IS_COMPONENT +endif # AIX + +# +# OSF1: add -B symbolic flag for components +# +ifeq ($(OS_ARCH),OSF1) +ifdef IS_COMPONENT +ifeq ($(GNU_CC)$(GNU_CXX),) +EXTRA_DSO_LDOPTS += -B symbolic +endif +endif +endif + +# +# Linux: add -Bsymbolic flag for components +# +ifeq ($(OS_ARCH),Linux) +ifdef IS_COMPONENT +EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic +endif +endif + +# +# MINGW32 +# +ifeq ($(OS_ARCH),WINNT) +ifdef GNU_CC +ifndef IS_COMPONENT +DSO_LDOPTS += -Wl,--out-implib -Wl,$(IMPORT_LIBRARY) +endif +endif +endif + +ifeq ($(USE_TVFS),1) +IFLAGS1 = -rb +IFLAGS2 = -rb +else +IFLAGS1 = -m 644 +IFLAGS2 = -m 755 +endif + +ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) +OUTOPTION = -Fo# eol +else +OUTOPTION = -o # eol +endif # WINNT && !GNU_CC +ifneq (,$(filter WINCE,$(OS_ARCH))) +OUTOPTION = -Fo# eol +endif + +ifeq ($(OS_TARGET), WINCE) +OUTOPTION = -Fo# eol +HOST_OUTOPTION = -Fo# eol +else + +ifeq (,$(CROSS_COMPILE)) +HOST_OUTOPTION = $(OUTOPTION) +else +HOST_OUTOPTION = -o # eol +endif + +endif +################################################################################ + +# SUBMAKEFILES: List of Makefiles for next level down. +# This is used to update or create the Makefiles before invoking them. +SUBMAKEFILES += $(addsuffix /Makefile, $(DIRS) $(TOOL_DIRS) $(PARALLEL_DIRS)) + +# The root makefile doesn't want to do a plain export/libs, because +# of the tiers and because of libxul. Suppress the default rules in favor +# of something else. Makefiles which use this var *must* provide a sensible +# default rule before including rules.mk +ifndef SUPPRESS_DEFAULT_RULES +ifdef TIERS + +DIRS += $(foreach tier,$(TIERS),$(tier_$(tier)_dirs)) +STATIC_DIRS += $(foreach tier,$(TIERS),$(tier_$(tier)_staticdirs)) + +default all alldep:: + $(EXIT_ON_ERROR) \ + $(foreach tier,$(TIERS),$(MAKE) tier_$(tier); ) true + +else + +default all:: + @$(EXIT_ON_ERROR) \ + $(foreach dir,$(STATIC_DIRS),$(MAKE) -C $(dir); ) true + $(MAKE) export + $(MAKE) libs + $(MAKE) tools + +# Do depend as well +alldep:: + $(MAKE) export + $(MAKE) depend + $(MAKE) libs + $(MAKE) tools + +endif # TIERS +endif # SUPPRESS_DEFAULT_RULES + +ifeq ($(filter s,$(MAKEFLAGS)),) +ECHO := echo +QUIET := +else +ECHO := true +QUIET := -q +endif + +MAKE_TIER_SUBMAKEFILES = +$(if $(tier_$*_dirs),$(MAKE) $(addsuffix /Makefile,$(tier_$*_dirs))) + +export_tier_%: + @$(ECHO) "$@" + @$(MAKE_TIER_SUBMAKEFILES) + @$(EXIT_ON_ERROR) \ + $(foreach dir,$(tier_$*_dirs),$(MAKE) -C $(dir) export; ) true + +libs_tier_%: + @$(ECHO) "$@" + @$(MAKE_TIER_SUBMAKEFILES) + @$(EXIT_ON_ERROR) \ + $(foreach dir,$(tier_$*_dirs),$(MAKE) -C $(dir) libs; ) true + +tools_tier_%: + @$(ECHO) "$@" + @$(MAKE_TIER_SUBMAKEFILES) + @$(EXIT_ON_ERROR) \ + $(foreach dir,$(tier_$*_dirs),$(MAKE) -C $(dir) tools; ) true + +$(foreach tier,$(TIERS),tier_$(tier)):: + @$(ECHO) "$@: $($@_staticdirs) $($@_dirs)" + @$(EXIT_ON_ERROR) \ + $(foreach dir,$($@_staticdirs),$(MAKE) -C $(dir); ) true + $(MAKE) export_$@ + $(MAKE) libs_$@ + +# Do everything from scratch +everything:: + $(MAKE) clean + $(MAKE) alldep + +# Add dummy depend target for tinderboxes +depend:: + +ifdef ALL_PLATFORMS +all_platforms:: $(NFSPWD) + @d=`$(NFSPWD)`; \ + if test ! -d LOGS; then rm -rf LOGS; mkdir LOGS; else true; fi; \ + for h in $(PLATFORM_HOSTS); do \ + echo "On $$h: $(MAKE) $(ALL_PLATFORMS) >& LOGS/$$h.log";\ + rsh $$h -n "(chdir $$d; \ + $(MAKE) $(ALL_PLATFORMS) >& LOGS/$$h.log; \ + echo DONE) &" 2>&1 > LOGS/$$h.pid & \ + sleep 1; \ + done + +$(NFSPWD): + cd $(@D); $(MAKE) $(@F) +endif + +# Target to only regenerate makefiles +makefiles: $(SUBMAKEFILES) +ifneq (,$(DIRS)$(TOOL_DIRS)$(PARALLEL_DIRS)) + +$(LOOP_OVER_PARALLEL_DIRS) + +$(LOOP_OVER_DIRS) + +$(LOOP_OVER_TOOL_DIRS) +endif + +ifdef PARALLEL_DIRS +export:: $(PARALLEL_DIRS_export) + +$(PARALLEL_DIRS_export): %_export: %/Makefile + +@$(UPDATE_TITLE_export) $(MAKE) -C $* export +endif + +export:: $(SUBMAKEFILES) $(MAKE_DIRS) $(if $(EXPORTS)$(XPIDLSRCS)$(SDK_HEADERS)$(SDK_XPIDLSRCS),$(PUBLIC)) $(if $(SDK_HEADERS)$(SDK_XPIDLSRCS),$(SDK_PUBLIC)) $(if $(XPIDLSRCS),$(IDL_DIR)) $(if $(SDK_XPIDLSRCS),$(SDK_IDL_DIR)) + +$(LOOP_OVER_DIRS) + +$(LOOP_OVER_TOOL_DIRS) + +ifdef PARALLEL_DIRS +tools:: $(PARALLEL_DIRS_tools) + +$(PARALLEL_DIRS_tools): %_tools: %/Makefile + +@$(UPDATE_TITLE_tools) $(MAKE) -C $* tools +endif + +tools:: $(SUBMAKEFILES) $(MAKE_DIRS) + +$(LOOP_OVER_DIRS) +ifdef TOOL_DIRS + @$(EXIT_ON_ERROR) \ + $(foreach dir,$(TOOL_DIRS),$(UPDATE_TITLE) $(MAKE) -C $(dir) libs; ) true +endif + +# +# Rule to create list of libraries for final link +# +export:: +ifdef LIBRARY_NAME +ifdef EXPORT_LIBRARY +ifdef IS_COMPONENT +ifdef BUILD_STATIC_LIBS + @$(PERL) -I$(MOZILLA_DIR)/config $(MOZILLA_DIR)/config/build-list.pl $(FINAL_LINK_COMPS) $(LIBRARY_NAME) +ifdef MODULE_NAME + @$(PERL) -I$(MOZILLA_DIR)/config $(MOZILLA_DIR)/config/build-list.pl $(FINAL_LINK_COMP_NAMES) $(MODULE_NAME) +endif +endif +else + $(PERL) -I$(MOZILLA_DIR)/config $(MOZILLA_DIR)/config/build-list.pl $(FINAL_LINK_LIBS) $(LIBRARY_NAME) +endif # IS_COMPONENT +endif # EXPORT_LIBRARY +endif # LIBRARY_NAME + +# Create dependencies on static (and shared EXTRA_DSO_LIBS) libraries +LIBS_DEPS = $(filter %.$(LIB_SUFFIX), $(LIBS)) +HOST_LIBS_DEPS = $(filter %.$(LIB_SUFFIX), $(HOST_LIBS)) +DSO_LDOPTS_DEPS = $(EXTRA_DSO_LIBS) $(filter %.$(LIB_SUFFIX), $(EXTRA_DSO_LDOPTS)) + +############################################## +ifdef PARALLEL_DIRS +libs:: $(PARALLEL_DIRS_libs) + +$(PARALLEL_DIRS_libs): %_libs: %/Makefile + +@$(UPDATE_TITLE_libs) $(MAKE) -C $* libs +endif + +libs:: $(SUBMAKEFILES) $(MAKE_DIRS) $(HOST_LIBRARY) $(LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY) $(HOST_PROGRAM) $(PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(SIMPLE_PROGRAMS) $(JAVA_LIBRARY) +ifndef NO_DIST_INSTALL +ifdef LIBRARY +ifdef EXPORT_LIBRARY # Stage libs that will be linked into a static build +ifdef IS_COMPONENT + $(INSTALL) $(IFLAGS1) $(LIBRARY) $(DEPTH)/staticlib/components +else + $(INSTALL) $(IFLAGS1) $(LIBRARY) $(DEPTH)/staticlib +endif +endif # EXPORT_LIBRARY +ifdef DIST_INSTALL +ifdef IS_COMPONENT + $(error Shipping static component libs makes no sense.) +else + $(INSTALL) $(IFLAGS1) $(LIBRARY) $(DIST)/lib +endif +endif # DIST_INSTALL +endif # LIBRARY +ifdef SHARED_LIBRARY +ifdef IS_COMPONENT + $(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)/components + $(ELF_DYNSTR_GC) $(FINAL_TARGET)/components/$(SHARED_LIBRARY) +ifdef BEOS_ADDON_WORKAROUND + ( cd $(FINAL_TARGET)/components && $(CC) -nostart -o $(SHARED_LIBRARY).stub $(SHARED_LIBRARY) ) +endif +else # ! IS_COMPONENT +ifneq (,$(filter OS2 WINNT WINCE,$(OS_ARCH))) + $(INSTALL) $(IFLAGS2) $(IMPORT_LIBRARY) $(DIST)/lib +else + $(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(DIST)/lib +endif + $(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET) +ifdef BEOS_ADDON_WORKAROUND + ( cd $(FINAL_TARGET) && $(CC) -nostart -o $(SHARED_LIBRARY).stub $(SHARED_LIBRARY) ) +endif +endif # IS_COMPONENT +endif # SHARED_LIBRARY +ifdef PROGRAM + $(INSTALL) $(IFLAGS2) $(PROGRAM) $(FINAL_TARGET) +endif +ifdef SIMPLE_PROGRAMS + $(INSTALL) $(IFLAGS2) $(SIMPLE_PROGRAMS) $(FINAL_TARGET) +endif +ifdef HOST_PROGRAM + $(INSTALL) $(IFLAGS2) $(HOST_PROGRAM) $(DIST)/host/bin +endif +ifdef HOST_SIMPLE_PROGRAMS + $(INSTALL) $(IFLAGS2) $(HOST_SIMPLE_PROGRAMS) $(DIST)/host/bin +endif +ifdef HOST_LIBRARY + $(INSTALL) $(IFLAGS1) $(HOST_LIBRARY) $(DIST)/host/lib +endif +ifdef JAVA_LIBRARY +ifdef IS_COMPONENT + $(INSTALL) $(IFLAGS1) $(JAVA_LIBRARY) $(FINAL_TARGET)/components +else + $(INSTALL) $(IFLAGS1) $(JAVA_LIBRARY) $(FINAL_TARGET) +endif +endif # JAVA_LIBRARY +endif # !NO_DIST_INSTALL + +$(LOOP_OVER_DIRS) + +############################################## + +ifndef NO_PROFILE_GUIDED_OPTIMIZE +ifneq (,$(MOZ_PROFILE_GENERATE)$(MOZ_PROFILE_USE)) +ifeq ($(OS_ARCH)_$(GNU_CC)$(INTERNAL_TOOLS), WINNT_) +# Force re-linking when building with PGO, since +# the MSVC linker does all the work. We force re-link +# in both stages so you can do depend builds with PGO. +ifdef SHARED_LIBRARY +$(SHARED_LIBRARY): FORCE +BINARY_BASENAME = $(SHARED_LIBRARY:$(DLL_SUFFIX)=) +endif +ifdef PROGRAM +$(PROGRAM): FORCE +BINARY_BASENAME = $(PROGRAM:$(BIN_SUFFIX)=) +endif + +ifdef MOZ_PROFILE_USE +# In the second pass, we need to merge the pgc files into the pgd file. +# The compiler would do this for us automatically if they were in the right +# place, but they're in dist/bin. +ifdef BINARY_BASENAME +export:: + $(PYTHON) $(topsrcdir)/build/win32/pgomerge.py \ + $(BINARY_BASENAME) $(DIST)/bin +endif +endif # MOZ_PROFILE_USE +endif # WINNT_ +endif # MOZ_PROFILE_GENERATE || MOZ_PROFILE_USE +endif # NO_PROFILE_GUIDED_OPTIMIZE + +############################################## + +checkout: + $(MAKE) -C $(topsrcdir) -f client.mk checkout + +run_viewer: $(FINAL_TARGET)/viewer + cd $(FINAL_TARGET); \ + MOZILLA_FIVE_HOME=`pwd` \ + LD_LIBRARY_PATH=".:$(LIBS_PATH):$$LD_LIBRARY_PATH" \ + viewer + +clean clobber realclean clobber_all:: $(SUBMAKEFILES) + -rm -f $(ALL_TRASH) + -rm -rf $(ALL_TRASH_DIRS) + +-$(LOOP_OVER_PARALLEL_DIRS) + +-$(LOOP_OVER_DIRS) + +-$(LOOP_OVER_STATIC_DIRS) + +-$(LOOP_OVER_TOOL_DIRS) + +distclean:: $(SUBMAKEFILES) + +-$(LOOP_OVER_PARALLEL_DIRS) + +-$(LOOP_OVER_DIRS) + +-$(LOOP_OVER_STATIC_DIRS) + +-$(LOOP_OVER_TOOL_DIRS) + -rm -rf $(ALL_TRASH_DIRS) + -rm -f $(ALL_TRASH) \ + Makefile .HSancillary \ + $(wildcard *.$(OBJ_SUFFIX)) $(wildcard *.ho) $(wildcard host_*.o*) \ + $(wildcard *.$(LIB_SUFFIX)) $(wildcard *$(DLL_SUFFIX)) \ + $(wildcard *.$(IMPORT_LIB_SUFFIX)) +ifeq ($(OS_ARCH),OS2) + -rm -f $(PROGRAM:.exe=.map) +endif + +alltags: + rm -f TAGS + find $(topsrcdir) -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' -o -name '*.idl' \) -print | $(TAG_PROGRAM) + +# +# PROGRAM = Foo +# creates OBJS, links with LIBS to create Foo +# +$(PROGRAM): $(PROGOBJS) $(LIBS_DEPS) $(EXTRA_DEPS) $(EXE_DEF_FILE) $(RESFILE) Makefile Makefile.in +ifeq (WINCE,$(OS_ARCH)) + $(LD) -NOLOGO -OUT:$@ $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(PROGOBJS) $(RESFILE) $(LIBS) $(EXTRA_LIBS) $(OS_LIBS) +else +ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) + $(LD) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(PROGOBJS) $(RESFILE) $(LIBS) $(EXTRA_LIBS) $(OS_LIBS) +ifdef MSMANIFEST_TOOL + @if test -f $@.manifest; then \ + if test -f "$(srcdir)/$@.manifest"; then \ + mt.exe -NOLOGO -MANIFEST "$(win_srcdir)/$@.manifest" $@.manifest -OUTPUTRESOURCE:$@\;1; \ + else \ + mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ + fi; \ + rm -f $@.manifest; \ + fi +endif # MSVC with manifest tool +else +ifeq ($(CPP_PROG_LINK),1) + $(CCC) -o $@ $(CXXFLAGS) $(WRAP_MALLOC_CFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(SOLARIS_JEMALLOC_LDFLAGS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) $(BIN_FLAGS) $(WRAP_MALLOC_LIB) $(PROFILER_LIBS) $(EXE_DEF_FILE) +else # ! CPP_PROG_LINK + $(CC) -o $@ $(CFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(SOLARIS_JEMALLOC_LDFLAGS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) +endif # CPP_PROG_LINK +endif # WINNT && !GNU_CC +endif # WINCE + +ifdef ENABLE_STRIP + $(STRIP) $@ +endif +ifdef MOZ_POST_PROGRAM_COMMAND + $(MOZ_POST_PROGRAM_COMMAND) $@ +endif +ifeq ($(OS_ARCH),BeOS) +ifdef BEOS_PROGRAM_RESOURCE + xres -o $@ $(BEOS_PROGRAM_RESOURCE) + mimeset $@ +endif +endif # BeOS + +$(HOST_PROGRAM): $(HOST_PROGOBJS) $(HOST_LIBS_DEPS) $(HOST_EXTRA_DEPS) Makefile Makefile.in +ifeq (WINCE,$(OS_ARCH)) + $(HOST_LD) -NOLOGO -OUT:$@ $(HOST_OBJS) $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) +else +ifeq (_WINNT,$(GNU_CC)_$(HOST_OS_ARCH)) + $(HOST_LD) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $(HOST_OBJS) $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) +ifdef MSMANIFEST_TOOL + @if test -f $@.manifest; then \ + mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ + rm -f $@.manifest; \ + fi +endif # MSVC with manifest tool +else +ifeq ($(CPP_PROG_LINK),1) + $(HOST_CXX) -o $@ $(HOST_CXXFLAGS) $(HOST_LDFLAGS) $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) +else + $(HOST_CC) -o $@ $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) +endif # CPP_PROG_LINK +endif +endif + +# +# This is an attempt to support generation of multiple binaries +# in one directory, it assumes everything to compile Foo is in +# Foo.o (from either Foo.c or Foo.cpp). +# +# SIMPLE_PROGRAMS = Foo Bar +# creates Foo.o Bar.o, links with LIBS to create Foo, Bar. +# +$(SIMPLE_PROGRAMS): %$(BIN_SUFFIX): %.$(OBJ_SUFFIX) $(LIBS_DEPS) $(EXTRA_DEPS) Makefile Makefile.in +ifeq (WINCE,$(OS_ARCH)) + $(LD) -nologo -entry:main -out:$@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS) $(OS_LIBS) +else +ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) + $(LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS) $(OS_LIBS) +ifdef MSMANIFEST_TOOL + @if test -f $@.manifest; then \ + mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ + rm -f $@.manifest; \ + fi +endif # MSVC with manifest tool +else +ifeq ($(CPP_PROG_LINK),1) + $(CCC) $(WRAP_MALLOC_CFLAGS) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(SOLARIS_JEMALLOC_LDFLAGS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) $(WRAP_MALLOC_LIB) $(PROFILER_LIBS) $(BIN_FLAGS) +else + $(CC) $(WRAP_MALLOC_CFLAGS) $(CFLAGS) $(OUTOPTION)$@ $< $(WIN32_EXE_LDFLAGS) $(SOLARIS_JEMALLOC_LDFLAGS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) $(WRAP_MALLOC_LIB) $(PROFILER_LIBS) $(BIN_FLAGS) +endif # CPP_PROG_LINK +endif # WINNT && !GNU_CC +endif # WINCE + +ifdef ENABLE_STRIP + $(STRIP) $@ +endif +ifdef MOZ_POST_PROGRAM_COMMAND + $(MOZ_POST_PROGRAM_COMMAND) $@ +endif + +$(HOST_SIMPLE_PROGRAMS): host_%$(HOST_BIN_SUFFIX): host_%.$(OBJ_SUFFIX) $(HOST_LIBS_DEPS) $(HOST_EXTRA_DEPS) Makefile Makefile.in +ifeq (WINCE,$(OS_ARCH)) + $(HOST_LD) -NOLOGO -OUT:$@ $(WIN32_EXE_LDFLAGS) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS) +else +ifeq (WINNT_,$(HOST_OS_ARCH)_$(GNU_CC)) + $(HOST_LD) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) +else +ifneq (,$(HOST_CPPSRCS)$(USE_HOST_CXX)) + $(HOST_CXX) $(HOST_OUTOPTION)$@ $(HOST_CXXFLAGS) $(INCLUDES) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS) +else + $(HOST_CC) $(HOST_OUTOPTION)$@ $(HOST_CFLAGS) $(INCLUDES) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS) +endif +endif +endif + +# +# Purify target. Solaris/sparc only to start. +# Purify does not recognize "egcs" or "c++" so we go with +# "gcc" and "g++" for now. +# +pure: $(PROGRAM) +ifeq ($(CPP_PROG_LINK),1) + $(PURIFY) $(CCC) -o $^.pure $(CXXFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) +else + $(PURIFY) $(CC) -o $^.pure $(CFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) +endif +ifndef NO_DIST_INSTALL + $(INSTALL) $(IFLAGS2) $^.pure $(FINAL_TARGET) +endif + +quantify: $(PROGRAM) +ifeq ($(CPP_PROG_LINK),1) + $(QUANTIFY) $(CCC) -o $^.quantify $(CXXFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) +else + $(QUANTIFY) $(CC) -o $^.quantify $(CFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) +endif +ifndef NO_DIST_INSTALL + $(INSTALL) $(IFLAGS2) $^.quantify $(FINAL_TARGET) +endif + +# +# This allows us to create static versions of the shared libraries +# that are built using other static libraries. Confused...? +# +ifdef SHARED_LIBRARY_LIBS +ifeq (,$(GNU_LD)$(filter-out OS2 WINNT WINCE, $(OS_ARCH))) +ifneq (,$(BUILD_STATIC_LIBS)$(FORCE_STATIC_LIB)) +LOBJS += $(SHARED_LIBRARY_LIBS) +endif +else +ifneq (,$(filter OSF1 BSD_OS FreeBSD NetBSD OpenBSD SunOS Darwin,$(OS_ARCH))) +CLEANUP1 := | egrep -v '(________64ELEL_|__.SYMDEF)' +CLEANUP2 := rm -f ________64ELEL_ __.SYMDEF +else +CLEANUP2 := true +endif +SUB_LOBJS = $(shell for lib in $(SHARED_LIBRARY_LIBS); do $(AR_LIST) $${lib} $(CLEANUP1); done;) +endif +endif +ifdef MOZILLA_PROBE_LIBS +PROBE_LOBJS = $(shell for lib in $(MOZILLA_PROBE_LIBS); do $(AR_LIST) $${lib} $(CLEANUP1); done;) +endif +ifdef DTRACE_PROBE_OBJ +EXTRA_DEPS += $(DTRACE_PROBE_OBJ) +endif + +$(LIBRARY): $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS) $(EXTRA_DEPS) Makefile Makefile.in + rm -f $@ +ifneq (,$(GNU_LD)$(filter-out OS2 WINNT WINCE, $(OS_ARCH))) +ifdef SHARED_LIBRARY_LIBS + @rm -f $(SUB_LOBJS) + @for lib in $(SHARED_LIBRARY_LIBS); do $(AR_EXTRACT) $${lib}; $(CLEANUP2); done +endif +endif + $(AR) $(AR_FLAGS) $(OBJS) $(LOBJS) $(SUB_LOBJS) + $(RANLIB) $@ + @rm -f foodummyfilefoo $(SUB_LOBJS) + +ifeq (,$(filter-out WINNT WINCE, $(OS_ARCH))) +$(IMPORT_LIBRARY): $(SHARED_LIBRARY) +endif + +ifeq ($(OS_ARCH),OS2) +$(DEF_FILE): $(OBJS) $(SHARED_LIBRARY_LIBS) + rm -f $@ + echo LIBRARY $(LIBRARY_NAME) INITINSTANCE TERMINSTANCE > $@ + echo PROTMODE >> $@ + echo CODE LOADONCALL MOVEABLE DISCARDABLE >> $@ + echo DATA PRELOAD MOVEABLE MULTIPLE NONSHARED >> $@ + echo EXPORTS >> $@ +ifeq ($(IS_COMPONENT),1) +ifeq ($(HAS_EXTRAEXPORTS),1) +ifndef MOZ_OS2_USE_DECLSPEC + $(FILTER) $(OBJS) $(SHARED_LIBRARY_LIBS) >> $@ +endif +else + echo _NSGetModule >> $@ +endif +else +ifndef MOZ_OS2_USE_DECLSPEC + $(FILTER) $(OBJS) $(SHARED_LIBRARY_LIBS) >> $@ +endif +endif + $(ADD_TO_DEF_FILE) + +ifdef MOZ_OS2_USE_DECLSPEC +$(IMPORT_LIBRARY): $(SHARED_LIBRARY) +else +$(IMPORT_LIBRARY): $(DEF_FILE) +endif + rm -f $@ + $(IMPLIB) $@ $^ + $(RANLIB) $@ +endif # OS/2 + +$(HOST_LIBRARY): $(HOST_OBJS) Makefile + rm -f $@ + $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS) + $(HOST_RANLIB) $@ + +ifdef NO_LD_ARCHIVE_FLAGS +SUB_SHLOBJS = $(SUB_LOBJS) +endif + +ifdef HAVE_DTRACE +ifndef XP_MACOSX +ifdef DTRACE_PROBE_OBJ +ifndef DTRACE_LIB_DEPENDENT +$(DTRACE_PROBE_OBJ): $(OBJS) + dtrace -G -C -32 -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(OBJS) +endif +endif +endif +endif + +# On Darwin (Mac OS X), dwarf2 debugging uses debug info left in .o files, +# so instead of deleting .o files after repacking them into a dylib, we make +# symlinks back to the originals. The symlinks are a no-op for stabs debugging, +# so no need to conditionalize on OS version or debugging format. + +$(SHARED_LIBRARY): $(OBJS) $(LOBJS) $(DEF_FILE) $(RESFILE) $(SHARED_LIBRARY_LIBS) $(EXTRA_DEPS) $(DSO_LDOPTS_DEPS) Makefile Makefile.in +ifndef INCREMENTAL_LINKER + rm -f $@ +endif +ifeq ($(OS_ARCH),OpenVMS) + @if test ! -f $(VMS_SYMVEC_FILE); then \ + if test -f $(VMS_SYMVEC_FILE_MODULE); then \ + echo Creating specific component options file $(VMS_SYMVEC_FILE); \ + cp $(VMS_SYMVEC_FILE_MODULE) $(VMS_SYMVEC_FILE); \ + fi; \ + fi +ifdef IS_COMPONENT + @if test ! -f $(VMS_SYMVEC_FILE); then \ + echo Creating generic component options file $(VMS_SYMVEC_FILE); \ + cp $(VMS_SYMVEC_FILE_COMP) $(VMS_SYMVEC_FILE); \ + fi +endif +endif # OpenVMS +ifdef NO_LD_ARCHIVE_FLAGS +ifdef SHARED_LIBRARY_LIBS + @rm -f $(SUB_SHLOBJS) + @for lib in $(SHARED_LIBRARY_LIBS); do $(AR_EXTRACT) $${lib}; $(CLEANUP2); done +ifeq ($(OS_ARCH),Darwin) + @echo Making symlinks to the original object files in the archive libraries $(SHARED_LIBRARY_LIBS) + @for lib in $(SHARED_LIBRARY_LIBS); do \ + libdir=`echo $$lib|sed -e 's,/[^/]*\.a,,'`; \ + ofiles=`$(AR_LIST) $${lib}`; \ + for ofile in $$ofiles; do \ + if [ -f $$libdir/$$ofile ]; then \ + rm -f $$ofile; \ + ln -s $$libdir/$$ofile $$ofile; \ + fi; \ + done; \ + done +endif +endif # SHARED_LIBRARY_LIBS +endif # NO_LD_ARCHIVE_FLAGS +ifdef DTRACE_LIB_DEPENDENT + @rm -f $(PROBE_LOBJS) + @for lib in $(MOZILLA_PROBE_LIBS); do $(AR_EXTRACT) $${lib}; $(CLEANUP2); done +ifndef XP_MACOSX + dtrace -G -C -32 -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(PROBE_LOBJS) +endif + @for lib in $(MOZILLA_PROBE_LIBS); do \ + ofiles=`$(AR_LIST) $${lib}`; \ + $(AR_DELETE) $${lib} $$ofiles; \ + done + $(MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(LOBJS) $(SUB_SHLOBJS) $(DTRACE_PROBE_OBJ) $(PROBE_LOBJS) $(RESFILE) $(LDFLAGS) $(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) $(DEF_FILE) $(SHLIB_LDENDFILE) + @rm -f $(PROBE_LOBJS) + @rm -f $(DTRACE_PROBE_OBJ) + @for lib in $(MOZILLA_PROBE_LIBS); do \ + if [ -L $${lib} ]; then rm -f `readlink $${lib}`; fi; \ + done + @rm -f $(MOZILLA_PROBE_LIBS) + +else # ! DTRACE_LIB_DEPENDENT + $(MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(DTRACE_PROBE_OBJ) $(LOBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) $(DEF_FILE) $(SHLIB_LDENDFILE) +endif # DTRACE_LIB_DEPENDENT + +ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) +ifdef MSMANIFEST_TOOL +ifdef EMBED_MANIFEST_AT + @if test -f $@.manifest; then \ + mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;$(EMBED_MANIFEST_AT); \ + rm -f $@.manifest; \ + fi +endif # EMBED_MANIFEST_AT +endif # MSVC with manifest tool +endif # WINNT && !GCC +ifeq ($(OS_ARCH),Darwin) +else # non-Darwin + @rm -f $(SUB_SHLOBJS) +endif # Darwin + @rm -f foodummyfilefoo $(DELETE_AFTER_LINK) + chmod +x $@ +ifdef ENABLE_STRIP + $(STRIP) $@ +endif +ifdef MOZ_POST_DSO_LIB_COMMAND + $(MOZ_POST_DSO_LIB_COMMAND) $@ +endif + +ifdef MOZ_AUTO_DEPS +ifdef COMPILER_DEPEND +ifeq (__SunOS,$(GNU_CC)_$(GNU_CXX)_$(OS_ARCH)) +_MDDEPFILE = $(MDDEPDIR)/$(@F).pp + +define MAKE_DEPS_AUTO_CC +if test -d $(@D); then \ + echo "Building deps for $< using Sun Studio cc"; \ + $(CC) $(COMPILE_CFLAGS) -xM $< >$(_MDDEPFILE) ; \ +fi +endef +define MAKE_DEPS_AUTO_CXX +if test -d $(@D); then \ + echo "Building deps for $< using Sun Studio CC"; \ + $(CXX) $(COMPILE_CXXFLAGS) -xM $< >$(_MDDEPFILE) ; \ +fi +endef +endif # Sun Studio on Solaris +else # COMPILER_DEPEND +# +# Generate dependencies on the fly +# +_MDDEPFILE = $(MDDEPDIR)/$(@F).pp + +define MAKE_DEPS_AUTO +if test -d $(@D); then \ + echo "Building deps for $<"; \ + $(MKDEPEND) -o'.$(OBJ_SUFFIX)' -f- $(DEFINES) $(ACDEFINES) $(INCLUDES) $< 2>/dev/null | sed -e "s|^[^ ]*/||" > $(_MDDEPFILE) ; \ +fi +endef + +MAKE_DEPS_AUTO_CC = $(MAKE_DEPS_AUTO) +MAKE_DEPS_AUTO_CXX = $(MAKE_DEPS_AUTO) + +endif # COMPILER_DEPEND + +endif # MOZ_AUTO_DEPS + +ifdef MOZ_MEMORY +ifeq ($(OS_ARCH),SunOS) +SOLARIS_JEMALLOC_LDFLAGS = $(call EXPAND_LIBNAME_PATH,jemalloc,$(DIST)/lib) +endif +endif + +# Rules for building native targets must come first because of the host_ prefix +host_%.$(OBJ_SUFFIX): %.c Makefile Makefile.in + $(REPORT_BUILD) + $(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) + +host_%.$(OBJ_SUFFIX): %.cpp Makefile Makefile.in + $(REPORT_BUILD) + $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) + +host_%.$(OBJ_SUFFIX): %.cc Makefile Makefile.in + $(REPORT_BUILD) + $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) + +host_%.$(OBJ_SUFFIX): %.m Makefile Makefile.in + $(REPORT_BUILD) + $(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(HOST_CMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) + +host_%.$(OBJ_SUFFIX): %.mm Makefile Makefile.in + $(REPORT_BUILD) + $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(HOST_CMMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) + +%: %.c Makefile Makefile.in + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CC) + $(ELOG) $(CC) $(CFLAGS) $(LDFLAGS) $(OUTOPTION)$@ $(_VPATH_SRCS) + +%.$(OBJ_SUFFIX): %.c Makefile Makefile.in + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CC) + $(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(_VPATH_SRCS) + +moc_%.cpp: %.h Makefile Makefile.in + $(MOC) $< $(OUTOPTION)$@ + +ifdef ASFILES +# The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept +# a '-c' flag. +%.$(OBJ_SUFFIX): %.$(ASM_SUFFIX) Makefile Makefile.in + $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS) +endif + +%.$(OBJ_SUFFIX): %.S Makefile Makefile.in + $(AS) -o $@ $(ASFLAGS) -c $< + +%: %.cpp Makefile Makefile.in + @$(MAKE_DEPS_AUTO_CXX) + $(CCC) $(OUTOPTION)$@ $(CXXFLAGS) $(_VPATH_SRCS) $(LDFLAGS) + +# +# Please keep the next two rules in sync. +# +%.$(OBJ_SUFFIX): %.cc Makefile Makefile.in + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CXX) + $(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) + +%.$(OBJ_SUFFIX): %.cpp Makefile Makefile.in + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CXX) +ifdef STRICT_CPLUSPLUS_SUFFIX + echo "#line 1 \"$*.cpp\"" | cat - $*.cpp > t_$*.cc + $(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) t_$*.cc + rm -f t_$*.cc +else + $(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) +endif #STRICT_CPLUSPLUS_SUFFIX + +$(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.mm Makefile Makefile.in + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CXX) + $(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $(_VPATH_SRCS) + +$(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.m Makefile Makefile.in + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CC) + $(ELOG) $(CC) -o $@ -c $(COMPILE_CFLAGS) $(COMPILE_CMFLAGS) $(_VPATH_SRCS) + +%.s: %.cpp + $(CCC) -S $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) + +%.s: %.cc + $(CCC) -S $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) + +%.s: %.c + $(CC) -S $(COMPILE_CFLAGS) $(_VPATH_SRCS) + +%.i: %.cpp + $(CCC) -C -E $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) > $*.i + +%.i: %.cc + $(CCC) -C -E $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) > $*.i + +%.i: %.c + $(CC) -C -E $(COMPILE_CFLAGS) $(_VPATH_SRCS) > $*.i + +%.i: %.mm + $(CCC) -C -E $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $(_VPATH_SRCS) > $*.i + +%.res: %.rc + @echo Creating Resource file: $@ +ifeq ($(OS_ARCH),OS2) + $(RC) $(RCFLAGS:-D%=-d %) -i $(subst /,\,$(srcdir)) -r $< $@ +else +ifdef GNU_CC + $(RC) $(RCFLAGS) $(filter-out -U%,$(DEFINES)) $(INCLUDES:-I%=--include-dir %) $(OUTOPTION)$@ $(_VPATH_SRCS) +else + $(RC) $(RCFLAGS) -r $(DEFINES) $(INCLUDES) $(OUTOPTION)$@ $(_VPATH_SRCS) +endif +endif + +# need 3 separate lines for OS/2 +%: %.pl + rm -f $@ + cp $< $@ + chmod +x $@ + +%: %.sh + rm -f $@; cp $< $@; chmod +x $@ + +# Cancel these implicit rules +# +%: %,v + +%: RCS/%,v + +%: s.% + +%: SCCS/s.% + +############################################################################### +# Java rules +############################################################################### +ifneq (,$(filter OS2 WINNT WINCE,$(OS_ARCH))) +SEP := ; +else +SEP := : +endif + +EMPTY := +SPACE := $(EMPTY) $(EMPTY) + +# Cygwin and MSYS have their own special path form, but javac expects the source +# and class paths to be in the DOS form (i.e. e:/builds/...). This function +# does the appropriate conversion on Windows, but is a noop on other systems. +ifeq (,$(filter-out WINNT WINCE, $(HOST_OS_ARCH))) +ifdef CYGWIN_WRAPPER +normalizepath = $(foreach p,$(1),$(shell cygpath -m $(p))) +else +# assume MSYS +# We use 'pwd -W' to get DOS form of the path. However, since the given path +# could be a file or a non-existent path, we cannot call 'pwd -W' directly +# on the path. Instead, we extract the root path (i.e. "c:/"), call 'pwd -W' +# on it, then merge with the rest of the path. +root-path = $(shell echo $(1) | sed -e "s|\(/[^/]*\)/\?\(.*\)|\1|") +non-root-path = $(shell echo $(1) | sed -e "s|\(/[^/]*\)/\?\(.*\)|\2|") +normalizepath = $(foreach p,$(1),$(if $(filter /%,$(1)),$(shell cd $(call root-path,$(1)) && pwd -W)$(call non-root-path,$(1)),$(1))) +endif +else +normalizepath = $(1) +endif + +_srcdir = $(call normalizepath,$(srcdir)) +ifdef JAVA_SOURCEPATH +SP = $(subst $(SPACE),$(SEP),$(call normalizepath,$(strip $(JAVA_SOURCEPATH)))) +_JAVA_SOURCEPATH = ".$(SEP)$(_srcdir)$(SEP)$(SP)" +else +_JAVA_SOURCEPATH = ".$(SEP)$(_srcdir)" +endif + +ifdef JAVA_CLASSPATH +CP = $(subst $(SPACE),$(SEP),$(call normalizepath,$(strip $(JAVA_CLASSPATH)))) +_JAVA_CLASSPATH = ".$(SEP)$(CP)" +else +_JAVA_CLASSPATH = . +endif + +_JAVA_DIR = _java +$(_JAVA_DIR):: + $(NSINSTALL) -D $@ + +$(_JAVA_DIR)/%.class: %.java Makefile Makefile.in $(_JAVA_DIR) + $(CYGWIN_WRAPPER) $(JAVAC) $(JAVAC_FLAGS) -classpath $(_JAVA_CLASSPATH) \ + -sourcepath $(_JAVA_SOURCEPATH) -d $(_JAVA_DIR) $(_VPATH_SRCS) + +$(JAVA_LIBRARY): $(addprefix $(_JAVA_DIR)/,$(JAVA_SRCS:.java=.class)) Makefile Makefile.in + $(JAR) cf $@ -C $(_JAVA_DIR) . + +GARBAGE_DIRS += $(_JAVA_DIR) + +############################################################################### +# Update Makefiles +############################################################################### + +# In GNU make 3.80, makefiles must use the /cygdrive syntax, even if we're +# processing them with AS perl. See bug 232003 +ifdef AS_PERL +CYGWIN_TOPSRCDIR = -nowrap -p $(topsrcdir) -wrap +endif + +# Note: Passing depth to make-makefile is optional. +# It saves the script some work, though. +Makefile: Makefile.in + @$(PERL) $(AUTOCONF_TOOLS)/make-makefile -t $(topsrcdir) -d $(DEPTH) $(CYGWIN_TOPSRCDIR) + +ifdef SUBMAKEFILES +# VPATH does not work on some machines in this case, so add $(srcdir) +$(SUBMAKEFILES): % : $(srcdir)/%.in + $(PERL) $(AUTOCONF_TOOLS)/make-makefile -t $(topsrcdir) -d $(DEPTH) $(CYGWIN_TOPSRCDIR) $@ +endif + +ifdef AUTOUPDATE_CONFIGURE +$(topsrcdir)/configure: $(topsrcdir)/configure.in + (cd $(topsrcdir) && $(AUTOCONF)) && (cd $(DEPTH) && ./config.status --recheck) +endif + +############################################################################### +# Bunch of things that extend the 'export' rule (in order): +############################################################################### + +################################################################################ +# Copy each element of EXPORTS to $(PUBLIC) + +ifneq ($(EXPORTS)$(XPIDLSRCS)$(SDK_HEADERS)$(SDK_XPIDLSRCS),) +$(SDK_PUBLIC) $(PUBLIC):: + $(NSINSTALL) -D $@ +endif + +ifdef MOZ_JAVAXPCOM +ifneq ($(XPIDLSRCS)$(SDK_XPIDLSRCS),) +$(JAVA_DIST_DIR):: + $(NSINSTALL) -D $@ +endif +endif + +ifneq ($(XPI_NAME),) +$(FINAL_TARGET): + $(NSINSTALL) -D $@ + +export:: $(FINAL_TARGET) +endif + +ifndef NO_DIST_INSTALL +ifneq ($(EXPORTS),) +export:: $(EXPORTS) $(PUBLIC) + $(INSTALL) $(IFLAGS1) $^ +endif + +ifneq ($(SDK_HEADERS),) +export:: $(SDK_HEADERS) $(SDK_PUBLIC) + $(INSTALL) $(IFLAGS1) $^ + +export:: $(SDK_HEADERS) $(PUBLIC) + $(INSTALL) $(IFLAGS1) $^ +endif +endif # NO_DIST_INSTALL + +################################################################################ +# Copy each element of PREF_JS_EXPORTS + +ifdef GRE_MODULE +PREF_DIR = greprefs +else +ifneq (,$(XPI_NAME)$(LIBXUL_SDK)) +PREF_DIR = defaults/preferences +else +PREF_DIR = defaults/pref +endif +endif + +ifneq ($(PREF_JS_EXPORTS),) +# on win32, pref files need CRLF line endings... see bug 206029 +ifeq (WINNT,$(OS_ARCH)) +PREF_PPFLAGS = --line-endings=crlf +endif + +ifndef NO_DIST_INSTALL +$(FINAL_TARGET)/$(PREF_DIR): + $(NSINSTALL) -D $@ + +libs:: $(FINAL_TARGET)/$(PREF_DIR) $(PREF_JS_EXPORTS) + $(EXIT_ON_ERROR) \ + for i in $(PREF_JS_EXPORTS); do \ + dest=$(FINAL_TARGET)/$(PREF_DIR)/`basename $$i`; \ + $(RM) -f $$dest; \ + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $$i > $$dest; \ + done +endif +endif + +################################################################################ +# Copy each element of AUTOCFG_JS_EXPORTS to $(FINAL_TARGET)/defaults/autoconfig + +ifneq ($(AUTOCFG_JS_EXPORTS),) +$(FINAL_TARGET)/defaults/autoconfig:: + $(NSINSTALL) -D $@ + +ifndef NO_DIST_INSTALL +export:: $(AUTOCFG_JS_EXPORTS) $(FINAL_TARGET)/defaults/autoconfig + $(INSTALL) $(IFLAGS1) $^ +endif + +endif +################################################################################ +# Export the elements of $(XPIDLSRCS) & $(SDK_XPIDLSRCS), +# generating .h and .xpt files and moving them to the appropriate places. + +ifneq ($(XPIDLSRCS)$(SDK_XPIDLSRCS),) + +export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS)) + +ifndef XPIDL_MODULE +XPIDL_MODULE = $(MODULE) +endif + +ifeq ($(XPIDL_MODULE),) # we need $(XPIDL_MODULE) to make $(XPIDL_MODULE).xpt +export:: FORCE + @echo + @echo "*** Error processing XPIDLSRCS:" + @echo "Please define MODULE or XPIDL_MODULE when defining XPIDLSRCS," + @echo "so we have a module name to use when creating MODULE.xpt." + @echo; sleep 2; false +endif + +$(SDK_IDL_DIR) $(IDL_DIR):: + $(NSINSTALL) -D $@ + +# generate .h files from into $(XPIDL_GEN_DIR), then export to $(PUBLIC); +# warn against overriding existing .h file. +$(XPIDL_GEN_DIR)/.done: + @if test ! -d $(XPIDL_GEN_DIR); then echo Creating $(XPIDL_GEN_DIR)/.done; rm -rf $(XPIDL_GEN_DIR); mkdir $(XPIDL_GEN_DIR); fi + @touch $@ + +# don't depend on $(XPIDL_GEN_DIR), because the modification date changes +# with any addition to the directory, regenerating all .h files -> everything. + +$(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_COMPILE) $(XPIDL_GEN_DIR)/.done + $(REPORT_BUILD) + $(ELOG) $(XPIDL_COMPILE) -m header -w $(XPIDL_FLAGS) -o $(XPIDL_GEN_DIR)/$* $(_VPATH_SRCS) + @if test -n "$(findstring $*.h, $(EXPORTS) $(SDK_HEADERS))"; \ + then echo "*** WARNING: file $*.h generated from $*.idl overrides $(srcdir)/$*.h"; else true; fi + +ifndef NO_GEN_XPT +# generate intermediate .xpt files into $(XPIDL_GEN_DIR), then link +# into $(XPIDL_MODULE).xpt and export it to $(FINAL_TARGET)/components. +$(XPIDL_GEN_DIR)/%.xpt: %.idl $(XPIDL_COMPILE) $(XPIDL_GEN_DIR)/.done + $(REPORT_BUILD) + $(ELOG) $(XPIDL_COMPILE) -m typelib -w $(XPIDL_FLAGS) -e $@ -d $(MDDEPDIR)/$*.pp $(_VPATH_SRCS) + +# no need to link together if XPIDLSRCS contains only XPIDL_MODULE +ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS))) +$(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS) $(SDK_XPIDLSRCS)) Makefile.in Makefile $(XPIDL_LINK) + $(XPIDL_LINK) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS) $(SDK_XPIDLSRCS)) +endif # XPIDL_MODULE.xpt != XPIDLSRCS + +libs:: $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt +ifndef NO_DIST_INSTALL + $(INSTALL) $(IFLAGS1) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(FINAL_TARGET)/components +endif + +endif # NO_GEN_XPT + +GARBAGE_DIRS += $(XPIDL_GEN_DIR) + +endif # XPIDLSRCS || SDK_XPIDLSRCS + +ifneq ($(XPIDLSRCS),) +# export .idl files to $(IDL_DIR) +ifndef NO_DIST_INSTALL +export:: $(XPIDLSRCS) $(IDL_DIR) + $(INSTALL) $(IFLAGS1) $^ + +export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS)) $(PUBLIC) + $(INSTALL) $(IFLAGS1) $^ +endif # NO_DIST_INSTALL + +endif # XPIDLSRCS + + + +# +# General rules for exporting idl files. +# +# WORK-AROUND ONLY, for mozilla/tools/module-deps/bootstrap.pl build. +# Bug to fix idl dependency problems w/o this extra build pass is +# http://bugzilla.mozilla.org/show_bug.cgi?id=145777 +# +$(IDL_DIR):: + $(NSINSTALL) -D $@ + +export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS) + +ifneq ($(XPIDLSRCS)$(SDK_XPIDLSRCS),) +ifndef NO_DIST_INSTALL +export-idl:: $(XPIDLSRCS) $(SDK_XPIDLSRCS) $(IDL_DIR) + $(INSTALL) $(IFLAGS1) $^ +endif +endif + +$(LOOP_OVER_PARALLEL_DIRS) + +$(LOOP_OVER_DIRS) + +$(LOOP_OVER_TOOL_DIRS) + + + + +ifneq ($(SDK_XPIDLSRCS),) +# export .idl files to $(IDL_DIR) & $(SDK_IDL_DIR) +ifndef NO_DIST_INSTALL +export:: $(SDK_XPIDLSRCS) $(IDL_DIR) + $(INSTALL) $(IFLAGS1) $^ + +export:: $(SDK_XPIDLSRCS) $(SDK_IDL_DIR) + $(INSTALL) $(IFLAGS1) $^ + +export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(SDK_XPIDLSRCS)) $(PUBLIC) + $(INSTALL) $(IFLAGS1) $^ + +export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(SDK_XPIDLSRCS)) $(SDK_PUBLIC) + $(INSTALL) $(IFLAGS1) $^ +endif + +endif # SDK_XPIDLSRCS + + + +ifdef MOZ_JAVAXPCOM +ifneq ($(XPIDLSRCS)$(SDK_XPIDLSRCS),) + +JAVA_XPIDLSRCS = $(XPIDLSRCS) $(SDK_XPIDLSRCS) + +# A single IDL file can contain multiple interfaces, which result in multiple +# Java interface files. So use hidden dependency files. +JAVADEPFILES = $(addprefix $(JAVA_GEN_DIR)/.,$(JAVA_XPIDLSRCS:.idl=.java.pp)) + +$(JAVA_GEN_DIR): + $(NSINSTALL) -D $@ +GARBAGE_DIRS += $(JAVA_GEN_DIR) + +# generate .java files into _javagen/[package name dirs] +_JAVA_GEN_DIR = $(JAVA_GEN_DIR)/$(JAVA_IFACES_PKG_NAME) +$(_JAVA_GEN_DIR): + $(NSINSTALL) -D $@ + +$(JAVA_GEN_DIR)/.%.java.pp: %.idl $(XPIDL_COMPILE) $(_JAVA_GEN_DIR) + $(REPORT_BUILD) + $(ELOG) $(XPIDL_COMPILE) -m java -w -I$(srcdir) -I$(IDL_DIR) -o $(_JAVA_GEN_DIR)/$* $(_VPATH_SRCS) + @touch $@ + +# "Install" generated Java interfaces. We segregate them based on the XPI_NAME. +# If XPI_NAME is not set, install into the "default" directory. +ifneq ($(XPI_NAME),) +JAVA_INSTALL_DIR = $(JAVA_DIST_DIR)/$(XPI_NAME) +else +JAVA_INSTALL_DIR = $(JAVA_DIST_DIR)/default +endif + +$(JAVA_INSTALL_DIR): + $(NSINSTALL) -D $@ + +export:: $(JAVA_DIST_DIR) $(JAVADEPFILES) $(JAVA_INSTALL_DIR) + (cd $(JAVA_GEN_DIR) && tar $(TAR_CREATE_FLAGS) - .) | (cd $(JAVA_INSTALL_DIR) && tar -xf -) + +endif # XPIDLSRCS || SDK_XPIDLSRCS +endif # MOZ_JAVAXPCOM + +################################################################################ +# Copy each element of EXTRA_COMPONENTS to $(FINAL_TARGET)/components +ifdef EXTRA_COMPONENTS +libs:: $(EXTRA_COMPONENTS) +ifndef NO_DIST_INSTALL + $(INSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/components +endif + +endif + +ifdef EXTRA_PP_COMPONENTS +libs:: $(EXTRA_PP_COMPONENTS) +ifndef NO_DIST_INSTALL + $(EXIT_ON_ERROR) \ + $(NSINSTALL) -D $(FINAL_TARGET)/components; \ + for i in $^; do \ + dest=$(FINAL_TARGET)/components/`basename $$i`; \ + $(RM) -f $$dest; \ + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $$i > $$dest; \ + done +endif + +endif + +################################################################################ +# Copy each element of EXTRA_JS_MODULES to $(FINAL_TARGET)/modules +ifdef EXTRA_JS_MODULES +libs:: $(EXTRA_JS_MODULES) +ifndef NO_DIST_INSTALL + $(INSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/modules +endif + +endif + +ifdef EXTRA_PP_JS_MODULES +libs:: $(EXTRA_PP_JS_MODULES) +ifndef NO_DIST_INSTALL + $(EXIT_ON_ERROR) \ + $(NSINSTALL) -D $(FINAL_TARGET)/modules; \ + for i in $^; do \ + dest=$(FINAL_TARGET)/modules/`basename $$i`; \ + $(RM) -f $$dest; \ + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $$i > $$dest; \ + done +endif + +endif + +################################################################################ +# SDK + +ifneq (,$(SDK_LIBRARY)) +$(SDK_LIB_DIR):: + $(NSINSTALL) -D $@ + +ifndef NO_DIST_INSTALL +libs:: $(SDK_LIBRARY) $(SDK_LIB_DIR) + $(INSTALL) $(IFLAGS2) $^ +endif + +endif # SDK_LIBRARY + +ifneq (,$(SDK_BINARY)) +$(SDK_BIN_DIR):: + $(NSINSTALL) -D $@ + +ifndef NO_DIST_INSTALL +libs:: $(SDK_BINARY) $(SDK_BIN_DIR) + $(INSTALL) $(IFLAGS2) $^ +endif + +endif # SDK_BINARY + +################################################################################ +# CHROME PACKAGING + +JAR_MANIFEST := $(srcdir)/jar.mn + +chrome:: + $(MAKE) realchrome + +$(LOOP_OVER_PARALLEL_DIRS) + +$(LOOP_OVER_DIRS) + +$(LOOP_OVER_TOOL_DIRS) + +$(FINAL_TARGET)/chrome: + $(NSINSTALL) -D $@ + +# libs realchrome:: $(CHROME_DEPS) $(FINAL_TARGET)/chrome +# ifndef NO_DIST_INSTALL +# @$(EXIT_ON_ERROR) \ +# if test -f $(JAR_MANIFEST); then \ +# $(PYTHON) $(MOZILLA_DIR)/config/JarMaker.py \ +# $(QUIET) -j $(FINAL_TARGET)/chrome \ +# $(MAKE_JARS_FLAGS) $(XULPPFLAGS) $(DEFINES) $(ACDEFINES) \ +# $(JAR_MANIFEST); \ +# fi +# endif + +ifneq ($(DIST_FILES),) +libs:: $(DIST_FILES) + @$(EXIT_ON_ERROR) \ + for f in $(DIST_FILES); do \ + dest=$(FINAL_TARGET)/`basename $$f`; \ + $(RM) -f $$dest; \ + $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \ + $(XULAPP_DEFINES) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \ + $(srcdir)/$$f > $$dest; \ + done +endif + +ifneq ($(DIST_CHROME_FILES),) +libs:: $(DIST_CHROME_FILES) + @$(EXIT_ON_ERROR) \ + for f in $(DIST_CHROME_FILES); do \ + dest=$(FINAL_TARGET)/chrome/`basename $$f`; \ + $(RM) -f $$dest; \ + $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \ + $(XULAPP_DEFINES) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \ + $(srcdir)/$$f > $$dest; \ + done +endif + +ifneq ($(XPI_PKGNAME),) +libs realchrome:: +ifdef STRIP_XPI +ifndef MOZ_DEBUG + @echo "Stripping $(XPI_PKGNAME) package directory..." + @echo $(FINAL_TARGET) + @cd $(FINAL_TARGET) && find . ! -type d \ + ! -name "*.js" \ + ! -name "*.xpt" \ + ! -name "*.gif" \ + ! -name "*.jpg" \ + ! -name "*.png" \ + ! -name "*.xpm" \ + ! -name "*.txt" \ + ! -name "*.rdf" \ + ! -name "*.sh" \ + ! -name "*.properties" \ + ! -name "*.dtd" \ + ! -name "*.html" \ + ! -name "*.xul" \ + ! -name "*.css" \ + ! -name "*.xml" \ + ! -name "*.jar" \ + ! -name "*.dat" \ + ! -name "*.tbl" \ + ! -name "*.src" \ + ! -name "*.reg" \ + $(PLATFORM_EXCLUDE_LIST) \ + -exec $(STRIP) $(STRIP_FLAGS) {} >/dev/null 2>&1 \; +endif +endif + @echo "Packaging $(XPI_PKGNAME).xpi..." + cd $(FINAL_TARGET) && $(ZIP) -qr ../$(XPI_PKGNAME).xpi * +endif + +ifdef INSTALL_EXTENSION_ID +ifndef XPI_NAME +$(error XPI_NAME must be set for INSTALL_EXTENSION_ID) +endif + +libs:: + $(RM) -rf "$(DIST)/bin/extensions/$(INSTALL_EXTENSION_ID)" + $(NSINSTALL) -D "$(DIST)/bin/extensions/$(INSTALL_EXTENSION_ID)" + cd $(FINAL_TARGET) && tar $(TAR_CREATE_FLAGS) - . | (cd "../../bin/extensions/$(INSTALL_EXTENSION_ID)" && tar -xf -) + +endif + +ifneq (,$(filter flat symlink,$(MOZ_CHROME_FILE_FORMAT))) +_JAR_REGCHROME_DISABLE_JAR=1 +else +_JAR_REGCHROME_DISABLE_JAR=0 +endif + +REGCHROME = $(PERL) -I$(MOZILLA_DIR)/config $(MOZILLA_DIR)/config/add-chrome.pl \ + $(if $(filter gtk2,$(MOZ_WIDGET_TOOLKIT)),-x) \ + $(if $(CROSS_COMPILE),-o $(OS_ARCH)) $(FINAL_TARGET)/chrome/installed-chrome.txt \ + $(_JAR_REGCHROME_DISABLE_JAR) + +REGCHROME_INSTALL = $(PERL) -I$(MOZILLA_DIR)/config $(MOZILLA_DIR)/config/add-chrome.pl \ + $(if $(filter gtk2,$(MOZ_WIDGET_TOOLKIT)),-x) \ + $(if $(CROSS_COMPILE),-o $(OS_ARCH)) $(DESTDIR)$(mozappdir)/chrome/installed-chrome.txt \ + $(_JAR_REGCHROME_DISABLE_JAR) + + +################################################################################ +# Testing frameworks support +################################################################################ + +ifdef ENABLE_TESTS + +ifdef XPCSHELL_TESTS +ifndef MODULE +$(error Must define MODULE when defining XPCSHELL_TESTS.) +endif + +# Test file installation +libs:: + @$(EXIT_ON_ERROR) \ + for testdir in $(XPCSHELL_TESTS); do \ + $(INSTALL) \ + $(srcdir)/$$testdir/*.js \ + $(DEPTH)/_tests/xpcshell-simple/$(MODULE)/$$testdir; \ + done + +# Path formats on Windows are hard. We require a topsrcdir formatted so that +# it may be passed to nsILocalFile.initWithPath (in other words, an absolute +# path of the form X:\path\to\topsrcdir), which we store in NATIVE_TOPSRCDIR. +# We require a forward-slashed path to topsrcdir so that it may be combined +# with a relative forward-slashed path for loading scripts, both dynamically +# and statically for head/test/tail JS files. Of course, on non-Windows none +# of this matters, and things will work correctly because everything's +# forward-slashed, everywhere, always. +ifdef CYGWIN_WRAPPER +NATIVE_TOPSRCDIR := `cygpath -wa $(topsrcdir)` +FWDSLASH_TOPSRCDIR := `cygpath -ma $(topsrcdir)` +else +FWDSLASH_TOPSRCDIR := $(topsrcdir) +ifeq ($(HOST_OS_ARCH),WINNT) +NATIVE_TOPSRCDIR := $(subst /,\\,$(WIN_TOP_SRC)) +else +NATIVE_TOPSRCDIR := $(topsrcdir) +endif +endif # CYGWIN_WRAPPER + +# Test execution +check:: + @$(EXIT_ON_ERROR) \ + for testdir in $(XPCSHELL_TESTS); do \ + $(RUN_TEST_PROGRAM) \ + $(topsrcdir)/tools/test-harness/xpcshell-simple/test_all.sh \ + $(DIST)/bin/xpcshell \ + $(FWDSLASH_TOPSRCDIR) \ + $(NATIVE_TOPSRCDIR) \ + $(DEPTH)/_tests/xpcshell-simple/$(MODULE)/$$testdir; \ + done + +# Test execution +check-interactive:: + @$(EXIT_ON_ERROR) \ + $(RUN_TEST_PROGRAM) \ + $(topsrcdir)/tools/test-harness/xpcshell-simple/test_one.sh \ + $(DIST)/bin/xpcshell \ + $(FWDSLASH_TOPSRCDIR) \ + $(NATIVE_TOPSRCDIR) \ + $(DEPTH)/_tests/xpcshell-simple/$(MODULE)/$$testdir \ + $(SOLO_FILE) 1; + +# Test execution +check-one:: + @$(EXIT_ON_ERROR) \ + $(RUN_TEST_PROGRAM) \ + $(topsrcdir)/tools/test-harness/xpcshell-simple/test_one.sh \ + $(DIST)/bin/xpcshell \ + $(FWDSLASH_TOPSRCDIR) \ + $(NATIVE_TOPSRCDIR) \ + $(DEPTH)/_tests/xpcshell-simple/$(MODULE)/$$testdir \ + $(SOLO_FILE) 0; + +endif # XPCSHELL_TESTS + +endif # ENABLE_TESTS + + +############################################################################# +# Dependency system +############################################################################# +ifdef COMPILER_DEPEND +depend:: + @echo "$(MAKE): No need to run depend target.\ + Using compiler-based depend." 1>&2 +ifeq ($(GNU_CC)$(GNU_CXX),) +# Non-GNU compilers + @echo "`echo '$(MAKE):'|sed 's/./ /g'`"\ + '(Compiler-based depend was turned on by "--enable-md".)' 1>&2 +else +# GNU compilers + @space="`echo '$(MAKE): '|sed 's/./ /g'`";\ + echo "$$space"'Since you are using a GNU compiler,\ + it is on by default.' 1>&2; \ + echo "$$space"'To turn it off, pass --disable-md to configure.' 1>&2 +endif + +else # ! COMPILER_DEPEND + +ifndef MOZ_AUTO_DEPS + +define MAKE_DEPS_NOAUTO + $(MKDEPEND) -w1024 -o'.$(OBJ_SUFFIX)' -f- $(DEFINES) $(ACDEFINES) $(INCLUDES) $< 2>/dev/null | sed -e "s|^[^ ]*/||" > $@ +endef + +$(MDDEPDIR)/%.pp: %.c + $(REPORT_BUILD) + @$(MAKE_DEPS_NOAUTO) + +$(MDDEPDIR)/%.pp: %.cpp + $(REPORT_BUILD) + @$(MAKE_DEPS_NOAUTO) + +$(MDDEPDIR)/%.pp: %.s + $(REPORT_BUILD) + @$(MAKE_DEPS_NOAUTO) + +ifneq (,$(OBJS)$(XPIDLSRCS)$(SDK_XPIDLSRCS)$(SIMPLE_PROGRAMS)) +depend:: $(SUBMAKEFILES) $(MAKE_DIRS) $(MDDEPFILES) +else +depend:: $(SUBMAKEFILES) +endif + +$(LOOP_OVER_PARALLEL_DIRS) + +$(LOOP_OVER_DIRS) + +$(LOOP_OVER_TOOL_DIRS) + +dependclean:: $(SUBMAKEFILES) + rm -f $(MDDEPFILES) + +$(LOOP_OVER_PARALLEL_DIRS) + +$(LOOP_OVER_DIRS) + +$(LOOP_OVER_TOOL_DIRS) + +endif # MOZ_AUTO_DEPS + +endif # COMPILER_DEPEND + + +############################################################################# +# MDDEPDIR is the subdirectory where all the dependency files are placed. +# This uses a make rule (instead of a macro) to support parallel +# builds (-jN). If this were done in the LOOP_OVER_DIRS macro, two +# processes could simultaneously try to create the same directory. +# +# We use $(CURDIR) in the rule's target to ensure that we don't find +# a dependency directory in the source tree via VPATH (perhaps from +# a previous build in the source tree) and thus neglect to create a +# dependency directory in the object directory, where we really need +# it. + +$(CURDIR)/$(MDDEPDIR): + @if test ! -d $@; then echo Creating $@; rm -rf $@; mkdir $@; else true; fi + +ifneq (,$(filter-out all chrome default export realchrome tools clean clobber clobber_all distclean realclean,$(MAKECMDGOALS))) +ifneq (,$(OBJS)$(XPIDLSRCS)$(SDK_XPIDLSRCS)$(SIMPLE_PROGRAMS)) +MDDEPEND_FILES := $(strip $(wildcard $(MDDEPDIR)/*.pp)) + +ifneq (,$(MDDEPEND_FILES)) +ifdef PERL +# The script mddepend.pl checks the dependencies and writes to stdout +# one rule to force out-of-date objects. For example, +# foo.o boo.o: FORCE +# The script has an advantage over including the *.pp files directly +# because it handles the case when header files are removed from the build. +# 'make' would complain that there is no way to build missing headers. +ifeq (,$(MAKE_RESTARTS)) +$(MDDEPDIR)/.all.pp: FORCE + @$(PERL) $(BUILD_TOOLS)/mddepend.pl $@ $(MDDEPEND_FILES) +endif +-include $(MDDEPDIR)/.all.pp +else +include $(MDDEPEND_FILES) +endif +endif + +endif +endif +############################################################################# + +-include $(topsrcdir)/$(MOZ_BUILD_APP)/app-rules.mk +-include $(MY_RULES) + +# +# This speeds up gmake's processing if these files don't exist. +# +$(MY_CONFIG) $(MY_RULES): + @touch $@ + +# +# Generate Emacs tags in a file named TAGS if ETAGS was set in $(MY_CONFIG) +# or in $(MY_RULES) +# +ifdef ETAGS +ifneq ($(CSRCS)$(CPPSRCS)$(HEADERS),) +all:: TAGS +TAGS:: $(CSRCS) $(CPPSRCS) $(HEADERS) + $(ETAGS) $(CSRCS) $(CPPSRCS) $(HEADERS) +endif +endif + +################################################################################ +# Special gmake rules. +################################################################################ + + +# +# Disallow parallel builds with MSVC < 8 +# +ifneq (,$(filter 1200 1300 1310,$(_MSC_VER))) +.NOTPARALLEL: +endif + +# +# Re-define the list of default suffixes, so gmake won't have to churn through +# hundreds of built-in suffix rules for stuff we don't need. +# +.SUFFIXES: + +# +# Fake targets. Always run these rules, even if a file/directory with that +# name already exists. +# +.PHONY: all all_platforms alltags boot checkout chrome realchrome clean clobber clobber_all export install libs makefiles realclean run_viewer run_apprunner tools $(DIRS) $(TOOL_DIRS) FORCE check check-interactive check-one + +# Used as a dependency to force targets to rebuild +FORCE: + +# Delete target if error occurs when building target +.DELETE_ON_ERROR: + +# Properly set LIBPATTERNS for the platform +.LIBPATTERNS = $(if $(IMPORT_LIB_SUFFIX),$(LIB_PREFIX)%.$(IMPORT_LIB_SUFFIX)) $(LIB_PREFIX)%.$(LIB_SUFFIX) $(DLL_PREFIX)%$(DLL_SUFFIX) + +tags: TAGS + +TAGS: $(SUBMAKEFILES) $(CSRCS) $(CPPSRCS) $(wildcard *.h) + -etags $(CSRCS) $(CPPSRCS) $(wildcard *.h) + +$(LOOP_OVER_PARALLEL_DIRS) + +$(LOOP_OVER_DIRS) + +echo-variable-%: + @echo $($*) + +echo-tiers: + @echo $(TIERS) + +echo-dirs: + @echo $(DIRS) + +echo-module: + @echo $(MODULE) + +echo-requires: + @echo $(REQUIRES) + +echo-requires-recursive:: +ifdef _REPORT_ALL_DIRS + @echo $(subst $(topsrcdir)/,,$(srcdir)): $(MODULE): $(REQUIRES) +else + @$(if $(REQUIRES),echo $(subst $(topsrcdir)/,,$(srcdir)): $(MODULE): $(REQUIRES)) +endif + +$(LOOP_OVER_PARALLEL_DIRS) + +$(LOOP_OVER_DIRS) + +echo-depth-path: + @$(topsrcdir)/build/unix/print-depth-path.sh + +echo-module-name: + @$(topsrcdir)/build/package/rpm/print-module-name.sh + +echo-module-filelist: + @$(topsrcdir)/build/package/rpm/print-module-filelist.sh + +showtargs: +ifneq (,$(filter $(PROGRAM) $(HOST_PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $(LIBRARY) $(SHARED_LIBRARY),$(TARGETS))) + @echo -------------------------------------------------------------------------------- + @echo "PROGRAM = $(PROGRAM)" + @echo "SIMPLE_PROGRAMS = $(SIMPLE_PROGRAMS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "SHARED_LIBRARY = $(SHARED_LIBRARY)" + @echo "SHARED_LIBRARY_LIBS = $(SHARED_LIBRARY_LIBS)" + @echo "LIBS = $(LIBS)" + @echo "DEF_FILE = $(DEF_FILE)" + @echo "IMPORT_LIBRARY = $(IMPORT_LIBRARY)" + @echo "STATIC_LIBS = $(STATIC_LIBS)" + @echo "SHARED_LIBS = $(SHARED_LIBS)" + @echo "EXTRA_DSO_LIBS = $(EXTRA_DSO_LIBS)" + @echo "EXTRA_DSO_LDOPTS = $(EXTRA_DSO_LDOPTS)" + @echo "DEPENDENT_LIBS = $(DEPENDENT_LIBS)" + @echo -------------------------------------------------------------------------------- +endif + +$(LOOP_OVER_PARALLEL_DIRS) + +$(LOOP_OVER_DIRS) + +showbuild: + @echo "MOZ_BUILD_ROOT = $(MOZ_BUILD_ROOT)" + @echo "MOZ_WIDGET_TOOLKIT = $(MOZ_WIDGET_TOOLKIT)" + @echo "CC = $(CC)" + @echo "CXX = $(CXX)" + @echo "CCC = $(CCC)" + @echo "CPP = $(CPP)" + @echo "LD = $(LD)" + @echo "AR = $(AR)" + @echo "IMPLIB = $(IMPLIB)" + @echo "FILTER = $(FILTER)" + @echo "MKSHLIB = $(MKSHLIB)" + @echo "MKCSHLIB = $(MKCSHLIB)" + @echo "RC = $(RC)" + @echo "CFLAGS = $(CFLAGS)" + @echo "OS_CFLAGS = $(OS_CFLAGS)" + @echo "COMPILE_CFLAGS = $(COMPILE_CFLAGS)" + @echo "CXXFLAGS = $(CXXFLAGS)" + @echo "OS_CXXFLAGS = $(OS_CXXFLAGS)" + @echo "COMPILE_CXXFLAGS = $(COMPILE_CXXFLAGS)" + @echo "COMPILE_CMFLAGS = $(COMPILE_CMFLAGS)" + @echo "COMPILE_CMMFLAGS = $(COMPILE_CMMFLAGS)" + @echo "LDFLAGS = $(LDFLAGS)" + @echo "OS_LDFLAGS = $(OS_LDFLAGS)" + @echo "DSO_LDOPTS = $(DSO_LDOPTS)" + @echo "OS_INCLUDES = $(OS_INCLUDES)" + @echo "OS_LIBS = $(OS_LIBS)" + @echo "EXTRA_LIBS = $(EXTRA_LIBS)" + @echo "BIN_FLAGS = $(BIN_FLAGS)" + @echo "INCLUDES = $(INCLUDES)" + @echo "DEFINES = $(DEFINES)" + @echo "ACDEFINES = $(ACDEFINES)" + @echo "BIN_SUFFIX = $(BIN_SUFFIX)" + @echo "LIB_SUFFIX = $(LIB_SUFFIX)" + @echo "DLL_SUFFIX = $(DLL_SUFFIX)" + @echo "IMPORT_LIB_SUFFIX = $(IMPORT_LIB_SUFFIX)" + @echo "INSTALL = $(INSTALL)" + +showhost: + @echo "HOST_CC = $(HOST_CC)" + @echo "HOST_CXX = $(HOST_CXX)" + @echo "HOST_CFLAGS = $(HOST_CFLAGS)" + @echo "HOST_LDFLAGS = $(HOST_LDFLAGS)" + @echo "HOST_LIBS = $(HOST_LIBS)" + @echo "HOST_EXTRA_LIBS = $(HOST_EXTRA_LIBS)" + @echo "HOST_EXTRA_DEPS = $(HOST_EXTRA_DEPS)" + @echo "HOST_PROGRAM = $(HOST_PROGRAM)" + @echo "HOST_OBJS = $(HOST_OBJS)" + @echo "HOST_PROGOBJS = $(HOST_PROGOBJS)" + @echo "HOST_LIBRARY = $(HOST_LIBRARY)" + +showbuildmods:: + @echo "Build Modules = $(BUILD_MODULES)" + @echo "Module dirs = $(BUILD_MODULE_DIRS)" + +zipmakes: +ifneq (,$(filter $(PROGRAM) $(SIMPLE_PROGRAMS) $(LIBRARY) $(SHARED_LIBRARY),$(TARGETS))) + zip $(DEPTH)/makefiles $(subst $(topsrcdir),$(MOZ_SRC)/mozilla,$(srcdir)/Makefile.in) +endif + +$(LOOP_OVER_PARALLEL_DIRS) + +$(LOOP_OVER_DIRS) + +documentation: + @cd $(DEPTH) + $(DOXYGEN) $(DEPTH)/config/doxygen.cfg + +check:: $(SUBMAKEFILES) $(MAKE_DIRS) + +$(LOOP_OVER_PARALLEL_DIRS) + +$(LOOP_OVER_DIRS) + +$(LOOP_OVER_TOOL_DIRS) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/system-headers b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/system-headers new file mode 100644 index 0000000..9d61c0e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/system-headers @@ -0,0 +1,1038 @@ +A4Stuff.h +activscp.h +AEDataModel.h +AEObjects.h +AEPackObject.h +AERegistry.h +AEUtils.h +afxcmn.h +afxcoll.h +afxcview.h +afxdisp.h +afxdtctl.h +afxext.h +afxmt.h +afxpriv.h +afxtempl.h +afxwin.h +algorithm +Aliases.h +all.h +alloca.h +alloc.h +alsa/asoundlib.h +alsa/pcm.h +alsa/mixer.h +ansi_parms.h +a.out.h +app/Cursor.h +Appearance.h +AppFileInfo.h +AppKit.h +AppleEvents.h +Application.h +app/Message.h +app/MessageRunner.h +arpa/inet.h +arpa/nameser.h +asm/sigcontext.h +asm/signal.h +ASRegistry.h +assert.h +atk/atk.h +atlbase.h +atlcom.h +atlconv.h +atlctl.cpp +atlctl.h +ATLCTL.H +atlhost.h +atlimpl.cpp +atlwin.cpp +ATSTypes.h +ATSUnicode.h +Balloons.h +base/pblock.h +base/PCR_Base.h +base/session.h +basetyps.h +be/app/Application.h +Beep.h +be/kernel/image.h +be/kernel/OS.h +bfd.h +Bitmap.h +bsd/libc.h +bsd/syscall.h +bstring.h +builtin.h +Button.h +byteswap.h +#if MOZ_ENABLE_LIBXUL!=1 +#define WRAP_CAIRO_HEADERS +#endif +#if MOZ_TREE_CAIRO!=1 +#define WRAP_CAIRO_HEADERS +#endif +#ifdef WRAP_CAIRO_HEADERS +cairo.h +cairo-atsui.h +cairo-beos.h +cairo-ft.h +cairo-glitz.h +cairo-os2.h +cairo-pdf.h +cairo-ps.h +cairo-quartz.h +cairo-win32.h +cairo-xlib.h +cairo-xlib-xrender.h +cairo-directfb.h +cairo-qpainter.h +#endif +dfiff.h +fusion/reactor.h +fusion/property.h +fusion/conf.h +fusion/build.h +fusion/hash.h +fusion/shm/shm.h +fusion/shm/shm_internal.h +fusion/shm/pool.h +fusion/ref.h +fusion/fusion_internal.h +fusion/lock.h +fusion/types.h +fusion/vector.h +fusion/call.h +fusion/shmalloc.h +fusion/protocol.h +fusion/fusion.h +fusion/arena.h +fusion/object.h +directfbgl.h +directfb_version.h +directfb.h +directfb_util.h +directfb_keynames.h +dgiff.h +direct/util.h +direct/memcpy.h +direct/interface.h +direct/conf.h +direct/tree.h +direct/signals.h +direct/build.h +direct/interface_implementation.h +direct/utf8.h +direct/serial.h +direct/hash.h +direct/direct.h +direct/clock.h +direct/types.h +direct/mem.h +direct/thread.h +direct/debug.h +direct/stream.h +direct/messages.h +direct/trace.h +direct/modules.h +direct/log.h +direct/system.h +direct/list.h +dfb_types.h +directfb_strings.h +directfb_keyboard.h +callconv.h +Carbon/Carbon.h +CarbonEvents.h +Carbon.h +cassert +c_asm.h +cctype +cderr.h +cerrno +cert.h +CFBase.h +CFBundle.h +CFData.h +CFDictionary.h +cf.h +CFNumber.h +CFPlugIn.h +CFPreferences.h +CFString.h +CFURL.h +CGAffineTransform.h +CheckBox.h +climits +Clipboard.h +cmplrs/stsupport.h +Cocoa/Cocoa.h +CodeFragments.h +comdef.h +commctrl.h +COMMCTRL.H +commdlg.h +compat.h +condapi.h +ConditionalMacros.h +config.h +conio.h +console.h +ControlDefinitions.h +Controls.h +CoreFoundation/CoreFoundation.h +CoreServices/CoreServices.h +CPalmRec.cpp +Cpalmrec.h +CPCatgry.cpp +CPDbBMgr.h +CPString.cpp +CPString.h +crtdbg.h +crt_externs.h +crypt.h +cstdio +cstdlib +cstring +ctime +ctype.h +curl/curl.h +curl/easy.h +curl/types.h +curses.h +cxxabi.h +DateTimeUtils.h +dbus/dbus.h +dbus/dbus-glib.h +dbus/dbus-glib-lowlevel.h +ddeml.h +Debug.h +dem.h +descrip.h +Devices.h +Dialogs.h +direct.h +dirent.h +DiskInit.h +dlfcn.h +dlgs.h +dl.h +docobj.h +dos/dosextens.h +dos.h +Drag.h +DriverServices.h +DriverSynchronization.h +DropInPanel.h +dvidef.h +elf.h +endian.h +Entry.h +errno.h +Errors.h +Events.h +exdisp.h +ExDisp.h +exe386.h +execinfo.h +extras.h +fabdef.h +fcntl.h +features.h +fibdef.h +File.h +filehdr.h +files.h +Files.h +FindDirectory.h +Finder.h +FinderRegistry.h +FixMath.h +float.h +Folders.h +fontconfig/fontconfig.h +fontconfig/fcfreetype.h +Font.h +Fonts.h +fp.h +fpieee.h +frame/log.h +frame/req.h +freetype/freetype.h +freetype/ftcache.h +freetype/ftglyph.h +freetype/ftsynth.h +freetype/ftoutln.h +freetype/ttnameid.h +freetype/tttables.h +freetype/t1tables.h +fribidi/fribidi.h +FSp_fopen.h +fstream.h +ft2build.h +gconf/gconf-client.h +Gdiplus.h +gdk/gdkevents.h +gdk/gdk.h +gdk/gdkkeysyms.h +gdk/gdkpango.h +gdk/gdkprivate.h +gdk/gdkscreen.h +gdk/gdkregion.h +gdk/gdkwindow.h +gdk/gdkx.h +gdk/gdkdirectfb.h +gdk-pixbuf/gdk-pixbuf.h +Gestalt.h +getopt.h +glibconfig.h +glib.h +glib-object.h +gmodule.h +gnome.h +gnu/libc-version.h +grp.h +gssapi_generic.h +gssapi/gssapi_generic.h +gssapi/gssapi.h +gssapi.h +gtk/gtkbindings.h +gtk/gtkbutton.h +gtk/gtkclipboard.h +gtk/gtkcontainer.h +gtk/gtkdialog.h +gtk/gtkentry.h +gtk/gtkfixed.h +gtk/gtk.h +gtk/gtkiconfactory.h +gtk/gtkimage.h +gtk/gtkimmulticontext.h +gtk/gtkinvisible.h +gtk/gtkmain.h +gtk/gtkmessagedialog.h +gtk/gtkobject.h +gtk/gtkprinter.h +gtk/gtkprintjob.h +gtk/gtkprintunixdialog.h +gtk/gtkprivate.h +gtk/gtkselection.h +gtk/gtksignal.h +gtk/gtksocket.h +gtk/gtkstock.h +gtk/gtkstyle.h +gtk/gtktextview.h +gtk/gtkvscrollbar.h +gtk/gtkwidget.h +gtk/gtkwindow.h +gtk/gtkversion.h +HIToolbox/HIToolbox.h +hlink.h +htiface.h +ia64/sys/inline.h +Icons.h +iconv.h +IDL.h +ieeefp.h +ifaddrs.h +image.h +imagehlp.h +imm.h +initguid.h +InterfaceDefs.h +InternetConfig.h +IntlResources.h +ints.h +intshcut.h +inttypes.h +iodef.h +io.h +IOKit/IOKitLib.h +IOKit/IOMessage.h +IOKit/pwr_mgt/IOPMLib.h +iomanip +iostream +iostream.h +jar.h +JavaControl.h +JavaEmbedding/JavaControl.h +JavaVM/jni.h +JManager.h +JNIEnvTests.h +jni.h +#if MOZ_NATIVE_JPEG==1 +jpeglib.h +#endif +JVMManagerTests.h +Kerberos/Kerberos.h +kernel/image.h +kernel/OS.h +key.h +keyt.h +keythi.h +LAction.h +langinfo.h +LApplication.h +LArray.h +LArrayIterator.h +LAttachable.h +LAttachment.h +LaunchServices.h +lber.h +LBroadcaster.h +LButton.h +lcache.h +LCaption.h +LCheckBox.h +LCicnButton.h +LClipboard.h +LCommander.h +LComparator.h +LControl.h +ldap.h +ldaplog.h +ldappr.h +ldap_ssl.h +LDataStream.h +ldfcn.h +LDialogBox.h +ldif.h +LDocApplication.h +LDocument.h +LDragAndDrop.h +LDragTask.h +LEditField.h +LEditText.h +LEventDispatcher.h +LFile.h +LFileStream.h +LFileTypeList.h +LFocusBox.h +LGrafPortView.h +LHandleStream.h +libc_r.h +libelf.h +libelf/libelf.h +libgen.h +libgnome/gnome-url.h +libgnome/libgnome.h +libgnomeui/gnome-icon-lookup.h +libgnomeui/gnome-icon-theme.h +libgnomeui/gnome-ui-init.h +libgnomevfs/gnome-vfs-application-registry.h +libgnomevfs/gnome-vfs-file-info.h +libgnomevfs/gnome-vfs.h +libgnomevfs/gnome-vfs-init.h +libgnomevfs/gnome-vfs-mime.h +libgnomevfs/gnome-vfs-mime-handlers.h +libgnomevfs/gnome-vfs-mime-info.h +libgnomevfs/gnome-vfs-mime-utils.h +libgnomevfs/gnome-vfs-ops.h +libgnomevfs/gnome-vfs-standard-callbacks.h +libIDL/IDL.h +lib$routines.h +limits +limits.h +link.h +linux/kernel.h +linux/limits.h +linux/rtc.h +linux/version.h +list +List.h +Lists.h +LiveConnectManagerTests.h +LListBox.h +LListener.h +LMenuBar.h +LMenu.h +LModelDirector.h +LModelObject.h +LModelProperty.h +loader.h +locale +locale.h +LOffscreenView.h +logkeys.h +logstrng.h +Looper.h +LowMem.h +LPane.h +LPeriodical.h +LPicture.h +LPlaceHolder.h +LPrintout.h +LProgressBar.h +LPushButton.h +LRadioGroup.h +LRadioGroupView.h +LRunArray.h +LScroller.h +LSharable.h +LSingleDoc.h +LStaticText.h +LStdControl.h +LStream.h +LString.h +LTabGroup.h +LTabGroupView.h +LTableArrayStorage.h +LTableMonoGeometry.h +LTableSingleSelector.h +LTableView.h +LTextEditView.h +LTextTableView.h +LUndoer.h +LVariableArray.h +LView.h +LWindow.h +m68881.h +MacErrors.h +MacHeadersCarbon.h +machine/ansi.h +machine/builtins.h +machine/clock.h +machine/endian.h +machine/frame.h +machine/inline.h +machine/limits.h +machine/signal.h +machine/trap.h +mach/mach_host.h +mach/mach_init.h +mach/mach_interface.h +mach/mach_port.h +mach-o/dyld.h +MacLocales.h +MacMemory.h +MacTCP.h +MacTypes.h +MacWindows.h +malloc.h +map +mapicode.h +mapidefs.h +mapiguid.h +mapi.h +mapitags.h +mapiutil.h +mapix.h +Math64.h +math.h +mbstring.h +mem.h +memory +memory.h +Memory.h +MenuBar.h +Menu.h +Menus.h +Message.h +Mime.h +MixedMode.h +mlang.h +mmsystem.h +model.h +Movies.h +mpw/errno.h +mshtmhst.h +mshtml.h +mswsock.h +Multiprocessing.h +mutex.h +Navigation.h +ncompat.h +ncurses.h +netCore.h +netdb.h +net/if.h +netinet/in.h +netinet/in_systm.h +netinet/tcp.h +new +newexe.h +new.h +nl_types.h +NodeInfo.h +nss.h +nssilock.h +objbase.h +objidl.h +Objsafe.h +ojiapitests.h +ole2.h +oleidl.h +OpenTptInternet.h +OpenTransport.h +os2.h +OS.h +osreldate.h +OSUtils.h +Packages.h +Palettes.h +PALM_CMN.H +pango-engine.h +pango-glyph.h +pango-modules.h +pango/pangocairo.h +pango/pangofc-decoder.h +pango/pangofc-font.h +pango/pangofc-fontmap.h +pango/pango-break.h +pango/pango-fontmap.h +pango/pango.h +pango/pangoxft.h +pango/pangox.h +pango/pango-utils.h +pango-types.h +pascal.h +Patches.h +Path.h +pcfs/pc_dir.h +Pgenerr.h +PGenErr.h +Ph.h +photon/Pg.h +photon/PhProto.h +photon/PhRender.h +photon/PpProto.h +photon/PtProgress.h +photon/PtServer.h +photon/PtWebClient.h +photon/PxImage.h +pk11func.h +pk11pub.h +pkcs11t.h +PLStringFuncs.h +PMApplication.h +pmddim.h +poll.h +Polygon.h +portable.h +Power.h +PP_ClassHeaders.cp +PP_Constants.h +PPCToolbox.h +PP_DebugHeaders.cp +PP_KeyCodes.h +PP_Macros.h +PP_Messages.h +PP_Prefix.h +PP_Resources.h +PP_Types.h +Printing.h +Print/PMPrintingDialogExtensions.h +private/qucomextra_p.h +Processes.h +process.h +Process.h +proto/dos.h +proto/exec.h +psap.h +Pt.h +pthread.h +pwd.h +Python.h +QDOffscreen.h +Quickdraw.h +QuickDraw.h +QuickTimeComponents.h +quipu/attr.h +rasdlg.h +raserror.h +ras.h +regex.h +Region.h +resolv.h +Resources.h +Retrace.h +rld_interface.h +rmsdef.h +Roster.h +rpc.h +rpcproxy.h +rpc/types.h +sane/sane.h +sane/sanei.h +sane/saneopts.h +Scrap.h +Screen.h +Script.h +ScrollBar.h +seccomon.h +sec.h +secmod.h +secmodt.h +secrng.h +security.h +secutil.h +semaphore.h +servprov.h +setjmp.h +SFNTLayoutTypes.h +SFNTTypes.h +share.h +shellapi.h +shlguid.h +shlobj.h +sigcontext.h +signal.h +SimpleGameSound.h +SIOUX.h +size_t.h +someincludefile.h +Sound.h +sqlite3.h +ssdef.h +sslerr.h +ssl.h +sslproto.h +sstream +stack +StandardFile.h +starlet.h +stat.h +statreg.cpp +statreg.h +stdarg.h +stdbool.h +stddef.h +stdint.h +stdio.h +stdlib.h +storage/FindDirectory.h +StorageKit.h +string +StringCompare.h +string.h +String.h +strings.h +Strings.h +StringView.h +stropts.h +strstrea.h +structs.h +stsdef.h +SupportDefs.h +support/String.h +support/SupportDefs.h +support/TLS.h +svrcore.h +symconst.h +sym.h +synch.h +syncmgr.h +sys/atomic_op.h +sys/bitypes.h +sys/byteorder.h +syscall.h +sys/cdefs.h +sys/cfgodm.h +sys/elf.h +sys/endian.h +sys/errno.h +sys/fault.h +sys/fcntl.h +sys/file.h +sys/filio.h +sys/frame.h +sys/immu.h +sys/inttypes.h +sys/ioccom.h +sys/ioctl.h +sys/ipc.h +sys/ldr.h +sys/link.h +sys/locking.h +syslog.h +sys/lwp.h +sys/machine.h +sys/mman.h +sys/mmu.h +sys/mount.h +sys/mpctl.h +sys/param.h +sys/pda.h +sys/poll.h +sys/ppc.h +sys/prctl.h +sys/priv.h +sys/procfs.h +sys/pstat.h +sys/ptrace.h +sys/queue.h +sys/reg.h +sys/regset.h +sys/resource.h +sys/sched.h +sys/select.h +sys/sem.h +sys/sendfile.h +sys/shm.h +sys/siginfo.h +sys/signal.h +sys/socket.h +sys/sockio.h +sys/sparc/frame.h +sys/stack.h +sys/statfs.h +sys/stat.h +sys/statvfs.h +sys/syscall.h +sys/sysctl.h +sys/sysinfo.h +sys/sysmp.h +sys/syssgi.h +sys/systeminfo.h +sys/timeb.h +sys/time.h +sys/times.h +sys/ttycom.h +sys/types.h +sys/ucontext.h +sys/uio.h +sys/un.h +sys/unistd.h +sys/utsname.h +sys/vfs.h +sys/wait.h +tables.h +TArray.h +TArrayIterator.h +task.h +tchar.h +TCHAR.H +termios.h +TextCommon.h +TextEdit.h +TextEncodingConverter.h +TextServices.h +TextUtils.h +TextView.h +th/PCR_Th.h +thread.h +ThreadManagerTests.h +Threads.h +time.h +Timer.h +tlhelp32.h +ToolUtils.h +trace.h +Traps.h +typeinfo +types.h +Types.h +UAppleEventsMgr.h +UAttachments.h +ucontext.h +uconv.h +UCursor.h +ucx$inetdef.h +UDebugging.h +UDesktop.h +UDrawingState.h +UDrawingUtils.h +UEnvironment.h +UEventMgr.h +UException.h +UExtractFromAEDesc.h +UGWorld.h +UKeyFilters.h +ulocks.h +ulserrno.h +UMemoryMgr.h +UModalDialogs.h +UNavServicesDialogs.h +UnicodeBlockObjects.h +UnicodeConverter.h +UnicodeUtilities.h +unidef.h +unikbd.h +unistd.h +unix.h +unixio.h +unixlib.h +unknwn.h +UPrinting.h +UQuickTime.h +UReanimator.h +URegions.h +URegistrar.h +UResourceMgr.h +urlhist.h +urlmon.h +UScrap.h +UScreenPort.h +UTCUtils.h +UTETextAction.h +UTEViewTextAction.h +UTextEdit.h +UTextTraits.h +utility +utime.h +UWindows.h +values.h +varargs.h +vcclr.h +vector +View.h +Volume.h +wab.h +wait.h +wchar.h +winbase.h +win/compobj.h +windef.h +Window.h +windows.h +Windows.h +windowsx.h +Wininet.h +winnls.h +winperf.h +winreg.h +Winreg.h +winsock2.h +winsock.h +winspool.h +winsvc.h +winuser.h +winver.h +wmem.h +workbench/startup.h +wtypes.h +wx/image.h +wx/listctrl.h +wx/log.h +wx/toolbar.h +wx/wx.h +wx/xrc/xmlres.h +X11/cursorfont.h +X11/extensions/Print.h +X11/extensions/shape.h +X11/extensions/XIElib.h +X11/extensions/XShm.h +X11/extensions/Xrender.h +X11/Intrinsic.h +X11/keysymdef.h +X11/keysym.h +X11/Shell.h +X11/StringDefs.h +X11/Xatom.h +X11/Xft/Xft.h +X11/Xfuncproto.h +X11/X.h +X11/XKBlib.h +X11/Xlib.h +X11/Xlibint.h +X11/Xlocale.h +X11/Xos.h +X11/Xutil.h +xpt_struct.h +xpt_xdr.h +zmouse.h +sslt.h +smime.h +cms.h +sechash.h +secoidt.h +certdb.h +secerr.h +nssb64.h +secasn1.h +secder.h +certt.h +ocsp.h +keyhi.h +cryptohi.h +crmf.h +pk11pqg.h +cmmf.h +base64.h +secdert.h +secitem.h +secmime.h +nssckbi.h +pkcs12.h +p12plcy.h +pk11sdr.h +nspr.h +pratom.h +prbit.h +prclist.h +prcmon.h +prcountr.h +prcvar.h +prdtoa.h +prenv.h +prerr.h +prerror.h +prinet.h +prinit.h +prinrval.h +prio.h +pripcsem.h +prlink.h +prlock.h +prlog.h +prlong.h +prmem.h +prmon.h +prmwait.h +prnetdb.h +prolock.h +prpdce.h +prprf.h +prproces.h +prrng.h +prrwlock.h +prshm.h +prshma.h +prsystem.h +prthread.h +prtime.h +prtpool.h +prtrace.h +prtypes.h +prvrsion.h +plbase64.h +plerror.h +plgetopt.h +plresolv.h +plstr.h +plarenas.h +plarena.h +plhash.h +#if MOZ_NATIVE_PNG==1 +png.h +#endif +#if MOZ_NATIVE_ZLIB==1 +zlib.h +#endif +#if MOZ_ENABLE_LIBXUL!=1 +#if BUILD_STATIC_LIBS!=1 +#define WRAP_LCMS_HEADERS +#endif +#endif +#if MOZ_NATIVE_LCMS==1 +#define WRAP_LCMS_HEADERS +#endif +#ifdef WRAP_LCMS_HEADERS +icc34.h +lcms.h +#endif +#ifdef MOZ_ENABLE_STARTUP_NOTIFICATION +libsn/sn.h +libsn/sn-common.h +libsn/sn-launchee.h +libsn/sn-launcher.h +libsn/sn-monitor.h +libsn/sn-util.h +#endif +#if MOZ_NATIVE_HUNSPELL==1 +hunspell.hxx +#endif +#if MOZ_NATIVE_BZ2==1 +bzlib.h +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/version.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/version.mk new file mode 100644 index 0000000..3993b3f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/version.mk @@ -0,0 +1,85 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Win32 Version System. +# +# The Initial Developer of the Original Code is Netscape Communications Corporation +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +ifndef INCLUDED_VERSION_MK +INCLUDED_VERSION_MK=1 + +# Windows gmake build: +# Build default .rc file if $(RESFILE) isn't defined. +# TODO: +# PBI : Private build info. Not used currently. +# Guessing the best way would be to set an env var. +# BINARY : Binary name. Not used currently. +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +ifndef RESFILE +RCFILE=./module.rc +RESFILE=./module.res +_RC_STRING = -QUIET 1 -DEPTH $(DEPTH) -TOPSRCDIR $(topsrcdir) -BITS $(MOZ_BITS) -OBJDIR . -SRCDIR $(srcdir) -DISPNAME $(MOZ_APP_DISPLAYNAME) +ifneq ($(BUILD_OFFICIAL)_$(MOZILLA_OFFICIAL),_) +_RC_STRING += -OFFICIAL 1 +endif +ifdef MOZ_DEBUG +_RC_STRING += -DEBUG 1 +endif +ifdef MODULE +_RC_STRING += -MODNAME $(MODULE) +endif +ifdef PROGRAM +_RC_STRING += -BINARY $(PROGRAM) +else +ifdef _PROGRAM +_RC_STRING += -BINARY $(_PROGRAM) +else +ifdef SHARED_LIBRARY +_RC_STRING += -BINARY $(SHARED_LIBRARY) +endif +endif +endif +ifdef RCINCLUDE +_RC_STRING += -RCINCLUDE $(srcdir)/$(RCINCLUDE) +endif + +GARBAGE += $(RESFILE) $(RCFILE) + +#dummy target so $(RCFILE) doesn't become the default =P +all:: + +$(RCFILE): $(RCINCLUDE) $(topsrcdir)/config/version_win.pl + $(PERL) $(topsrcdir)/config/version_win.pl $(_RC_STRING) + +endif # RESFILE +endif # Windows + +endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/version_win.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/version_win.pl new file mode 100644 index 0000000..094530e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/config/version_win.pl @@ -0,0 +1,423 @@ +#!/usr/bin/perl -w + +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Win32 Version System. +# +# The Initial Developer of the Original Code is Brian Bober +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#use diagnostics; +require strict; +my $dir = $0; +$dir =~ s/[^\/]*$//; +push(@INC, "$dir"); +require "Moz/Milestone.pm"; +use Getopt::Long; +use Getopt::Std; +use POSIX; + +# Calculate the number of days since Jan. 1, 2000 from a buildid string +sub daysFromBuildID +{ + my ($buildid,) = @_; + + my ($y, $m, $d, $h) = ($buildid =~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/); + $d || die("Unrecognized buildid string."); + + my $secondstodays = 60 * 60 * 24; + return (POSIX::mktime(00, 00, 00, $d, $m, $y - 1900) - + POSIX::mktime(00, 00, 00, 01, 01, 100)) / $secondstodays; +} + +#Creates version resource file + +#Paramaters are passed on the command line: + +#Example: -MODNAME nsToolkitCompsModule -DEBUG=1 + +# DEBUG - Mozilla's global debug variable - tells if its debug version +# OFFICIAL - tells Mozilla is building a milestone or nightly +# MSTONE - tells which milestone is being built; +# OBJDIR - Holds the object directory; +# MODNAME - tells what the name of the module is like nsBMPModule +# DEPTH - Holds the path to the root obj dir +# TOPSRCDIR - Holds the path to the root mozilla dir +# SRCDIR - Holds module.ver and source +# BINARY - Holds the name of the binary file +# DISPNAME - Holds the display name of the built application +# BITS - 16 or 32 bit +# RCINCLUDE - Holds the name of the RC File to include or "" +# QUIET - Turns off output + +#Description and Comment come from module.ver +#Bug 23560 +#http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/rc_7x2d.asp + +#Get next .ver file entry +sub getNextEntry +{ + while () + { + my $mline = $_; + ($mline) = split(/#/,$mline); + my ($entry, $value)=split(/=/,$mline,2); + if (defined($entry)) + { + if (defined($value)) + { + $entry =~ s/^\s*(.*?)\s*$/$1/; + $value =~ s/^\s*(.*?)\s*$/$1/; + return ($entry,$value); + } + } + } + return undef; +} + +my ($quiet,$objdir,$debug,$official,$milestone,$buildid,$module,$binary,$depth,$rcinclude,$bits,$srcdir,$fileversion,$productversion); + +GetOptions( "QUIET" => \$quiet, + "DEBUG=s" => \$debug, + "OFFICIAL=s" => \$official, + "MSTONE=s" => \$milestone, + "MODNAME=s" => \$module, + "BINARY=s" => \$binary, + "DISPNAME=s" => \$displayname, + "SRCDIR=s" => \$srcdir, + "TOPSRCDIR=s" => \$topsrcdir, + "DEPTH=s" => \$depth, + "RCINCLUDE=s" => \$rcinclude, + "OBJDIR=s" => \$objdir, + "BITS=s" => \$bits); +if (!defined($debug)) {$debug="";} +if (!defined($official)) {$official="";} +if (!defined($milestone)) {$milestone="";} +if (!defined($module)) {$module="";} +if (!defined($binary)) {$binary="";} +if (!defined($displayname)) {$displayname="Mozilla";} +if (!defined($depth)) {$depth=".";} +if (!defined($rcinclude)) {$rcinclude="";} +if (!defined($objdir)) {$objdir=".";} +if (!defined($srcdir)) {$srcdir=".";} +if (!defined($topsrcdir)) {$topsrcdir=".";} +if (!defined($bits)) {$bits="";} +my $mfversion = "Personal"; +my $mpversion = "Personal"; +my @fileflags = ("0"); +my $comment=""; +my $description=""; +if (!defined($module)) +{ + $module = $binary; + ($module) = split(/\./,$module); +} + +my $fileos = "VOS__WINDOWS32"; +if ($bits eq "16") { $fileos="VOS__WINDOWS16"; } + +my $bufferstr=" "; + +my $MILESTONE_FILE = "$topsrcdir/config/milestone.txt"; +my $BUILDID_FILE = "$depth/config/buildid"; + +#Read module.ver file +#Version file overrides for WIN32: +#WIN32_MODULE_COMMENT +#WIN32_MODULE_DESCRIPTION +#WIN32_MODULE_FILEVERSION +#WIN32_MODULE_COMPANYNAME +#WIN32_MODULE_FILEVERSION_STRING +#WIN32_MODULE_NAME +#WIN32_MODULE_COPYRIGHT +#WIN32_MODULE_TRADEMARKS +#WIN32_MODULE_ORIGINAL_FILENAME +#WIN32_MODULE_PRODUCTNAME +#WIN32_MODULE_PRODUCTVERSION +#WIN32_MODULE_PRODUCTVERSION_STRING + +#Override values obtained from the .ver file +my $override_comment; +my $override_description; +my $override_fileversion; +my $override_company; +my $override_mfversion; +my $override_module; +my $override_copyright; +my $override_trademarks; +my $override_filename; +my $override_productname; +my $override_productversion; +my $override_mpversion; +if (open(VERFILE, "<$srcdir/module.ver")) +{ + + my ($a,$b) = getNextEntry(); + while (defined($a)) + { + if ($a eq "WIN32_MODULE_COMMENT") { $override_comment = $b; } + if ($a eq "WIN32_MODULE_DESCRIPTION") { $override_description = $b; } + if ($a eq "WIN32_MODULE_FILEVERSION") { $override_fileversion = $b; } + if ($a eq "WIN32_MODULE_COMPANYNAME") { $override_company = $b; } + if ($a eq "WIN32_MODULE_FILEVERSION_STRING") { $override_mfversion = $b; } + if ($a eq "WIN32_MODULE_NAME") { $override_module = $b; } + if ($a eq "WIN32_MODULE_COPYRIGHT") { $override_copyright = $b; } + if ($a eq "WIN32_MODULE_TRADEMARKS") { $override_trademarks = $b; } + if ($a eq "WIN32_MODULE_ORIGINAL_FILENAME") { $override_filename = $b; } + if ($a eq "WIN32_MODULE_PRODUCTNAME") { $override_productname = $b; } + if ($a eq "WIN32_MODULE_PRODUCTVERSION") { $override_productversion = $b; } + if ($a eq "WIN32_MODULE_PRODUCTVERSION_STRING") { $override_mpversion = $b; } + ($a,$b) = getNextEntry(); + } + close(VERFILE) +} +else +{ + if (!$quiet || $quiet ne "1") { print "$bufferstr" . "WARNING: No module.ver file included ($module, $binary). Default values used\n"; } +} +#Get rid of trailing and leading whitespace +$debug =~ s/^\s*(.*)\s*$/$1/; +$comment =~ s/^\s*(.*)\s*$/$1/; +$official =~ s/^\s*(.*)\s*$/$1/; +$milestone =~ s/^\s*(.*)\s*$/$1/; +$description =~ s/^\s*(.*)\s*$/$1/; +$module =~ s/^\s*(.*)\s*$/$1/; +$depth =~ s/^\s*(.*)\s*$/$1/; +$binary =~ s/^\s*(.*)\s*$/$1/; +$displayname =~ s/^\s*(.*)\s*$/$1/; + +open(BUILDID, "<", $BUILDID_FILE) || die("Couldn't open buildid file: $BUILDID_FILE"); +$buildid = ; +$buildid =~ s/\s*$//; +close BUILDID; + +my $daycount = daysFromBuildID($buildid); + +if ($milestone eq "") { + $milestone = Moz::Milestone::getOfficialMilestone($MILESTONE_FILE); +} + +$mfversion = $mpversion = $milestone; + +if ($debug eq "1") +{ + push @fileflags, "VS_FF_DEBUG"; + $mpversion .= " Debug"; + $mfversion .= " Debug"; +} + +if ($official ne "1") { + push @fileflags, "VS_FF_PRIVATEBUILD"; +} + +if ($milestone =~ /[a-z]/) { + push @fileflags, "VS_FF_PRERELEASE"; +} + +my @mstone = split(/\./,$milestone); +$mstone[1] =~s/\D.*$//; +if (!$mstone[2]) { + $mstone[2] = "0"; +} +else { + $mstone[2] =~s/\D.*$//; +} +$fileversion = $productversion="$mstone[0],$mstone[1],$mstone[2],$daycount"; + +my $copyright = "License: MPL 1.1/GPL 2.0/LGPL 2.1"; +my $company = "Mozilla Foundation"; +my $trademarks = "Mozilla"; +my $productname = $displayname; + + +if (defined($override_comment)){$override_comment =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $comment=$override_comment;} +if (defined($override_description)){$override_description =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $description=$override_description;} +if (defined($override_fileversion)){$fileversion=$override_fileversion;} +if (defined($override_mfversion)){$mfversion=$override_mfversion;} +if (defined($override_company)){$company=$override_company;} +if (defined($override_module)){$override_module =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $module=$override_module;} +if (defined($override_copyright)){$override_copyright =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $copyright=$override_copyright;} +if (defined($override_trademarks)){$override_trademarks =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $trademarks=$override_trademarks;} +if (defined($override_filename)){$binary=$override_filename;} +if (defined($override_productname)){$override_productname =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $productname=$override_productname;} +if (defined($override_productversion)){$productversion=$override_productversion;} +if (defined($override_mpversion)){$mpversion=$override_mpversion;} + + +#Override section + +open(RCFILE, ">$objdir/module.rc") || die("Can't edit module.rc - It must be locked.\n"); +print RCFILE qq{ +// ***** BEGIN LICENSE BLOCK ***** +// Version: MPL 1.1/GPL 2.0/LGPL 2.1 +// +// The contents of this file are subject to the Mozilla Public License Version +// 1.1 (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, +// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +// for the specific language governing rights and limitations under the +// License. +// +// The Original Code is the Win32 Version System. +// +// The Initial Developer of the Original Code is Brian Bober +// Portions created by the Initial Developer are Copyright (C) 2001 +// the Initial Developer. All Rights Reserved. +// +// Contributor(s): +// +// Alternatively, the contents of this file may be used under the terms of +// either the GNU General Public License Version 2 or later (the "GPL"), or +// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +// in which case the provisions of the GPL or the LGPL are applicable instead +// of those above. If you wish to allow use of your version of this file only +// under the terms of either the GPL or the LGPL, and not to allow others to +// use your version of this file under the terms of the MPL, indicate your +// decision by deleting the provisions above and replace them with the notice +// and other provisions required by the GPL or the LGPL. If you do not delete +// the provisions above, a recipient may use your version of this file under +// the terms of any one of the MPL, the GPL or the LGPL. +// +// ***** END LICENSE BLOCK ***** + +#include + +// Note: if you contain versioning information in an included +// RC script, it will be discarded +// Use module.ver to explicitly set these values + +// Do not edit this file. Changes won't affect the build. + +}; + +my $versionlevel=0; +my $insideversion=0; +if (open(RCINCLUDE, "<$rcinclude")) +{ + print RCFILE "// From included resource $rcinclude\n"; +# my $mstring=""; + while () + { + $_ =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; + print RCFILE $_; +# my $instr=$_; +# chomp($instr); +# $mstring .= "$instr\;"; + } + close(RCINCLUDE); +# $mstring =~ s/\/\*.*\*\///g; +# my @mlines = split(/\;/,$mstring); +# for(@mlines) +# { +# my ($nocomment)=split(/\/\//,$_); +# if (defined($nocomment) && $nocomment ne "") +# { +# my ($firststring,$secondstring) = split(/\s+/,$nocomment); +# if (!defined($firststring)) {$firststring="";} +# if (!defined($secondstring)) {$secondstring="";} +# if ($secondstring eq "VERSIONINFO") +# { +#if (!$quiet || $quiet ne "1") { +# print "$bufferstr" . "WARNING: Included RC file ($rcinclude, $module, $binary)\n"; +# print "$bufferstr" . "WARNING: contains versioning information that will be discarded\n"; +# print "$bufferstr" . "WARNING: Remove it and use relevant overrides (in module.ver)\n"; +#} +# $versionlevel = 0; +# $insideversion = 1; +# } +# if ($firststring eq "BEGIN") { $versionlevel++; } +# if ($secondstring eq "END") +# { +# $versionlevel--; +# if ($insideversion==1 && $versionlevel==0) {$versionlevel=0;} +# } +# my $includecheck = $firststring . $secondstring; +# $includecheck =~ s/<|>/"/g; +# $includecheck = lc($includecheck); +# if ($includecheck ne "#include\"winver.h\"") +# { +# if ($insideversion == 0 && $versionlevel == 0) +# { +# print RCFILE "$nocomment\n"; +# } +# } +# } +# } + +} + +my $fileflags = join(' | ', @fileflags); + +print RCFILE qq{ + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +1 VERSIONINFO + FILEVERSION $fileversion + PRODUCTVERSION $productversion + FILEFLAGSMASK 0x3fL + FILEFLAGS $fileflags + FILEOS $fileos + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "$comment" + VALUE "LegalCopyright", "$copyright" + VALUE "CompanyName", "$company" + VALUE "FileDescription", "$description" + VALUE "FileVersion", "$mfversion" + VALUE "ProductVersion", "$mpversion" + VALUE "InternalName", "$module" + VALUE "LegalTrademarks", "$trademarks" + VALUE "OriginalFilename", "$binary" + VALUE "ProductName", "$productname" + VALUE "BuildID", "$buildid" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +}; +close(RCFILE); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/dtoa.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/dtoa.c new file mode 100644 index 0000000..86e8adc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/dtoa.c @@ -0,0 +1,3321 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ + +/* On a machine with IEEE extended-precision registers, it is + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_8087 for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_MC68k for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic (D_floating). + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. + * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and strtod and dtoa should round accordingly. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and Honor_FLT_ROUNDS is not #defined. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define NO_LONG_LONG on machines that do not have a "long long" + * integer type (of >= 64 bits). On such machines, you can + * #define Just_16 to store 16 bits per 32-bit Long when doing + * high-precision integer arithmetic. Whether this speeds things + * up or slows things down depends on the machine and the number + * being converted. If long long is available and the name is + * something other than "long long", #define Llong to be the name, + * and if "unsigned Llong" does not work as an unsigned version of + * Llong, #define #ULLong to be the corresponding unsigned type. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + * if memory is available and otherwise does something you deem + * appropriate. If MALLOC is undefined, malloc will be invoked + * directly -- and assumed always to succeed. + * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making + * memory allocations from a private pool of memory when possible. + * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, + * unless #defined to be a different length. This default length + * suffices to get rid of MALLOC calls except for unusual cases, + * such as decimal-to-binary conversion of a very long string of + * digits. The longest string dtoa can return is about 751 bytes + * long. For conversions by strtod of strings of 800 digits and + * all dtoa conversions in single-threaded executions with 8-byte + * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte + * pointers, PRIVATE_MEM >= 7112 appears adequate. + * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK + * #defined automatically on IEEE systems. On such systems, + * when INFNAN_CHECK is #defined, strtod checks + * for Infinity and NaN (case insensitively). On some systems + * (e.g., some HP systems), it may be necessary to #define NAN_WORD0 + * appropriately -- to the most significant word of a quiet NaN. + * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) + * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, + * strtod also accepts (case insensitively) strings of the form + * NaN(x), where x is a string of hexadecimal digits and spaces; + * if there is only one string of hexadecimal digits, it is taken + * for the 52 fraction bits of the resulting NaN; if there are two + * or more strings of hex digits, the first is for the high 20 bits, + * the second and subsequent for the low 32 bits, with intervening + * white space ignored; but if this results in none of the 52 + * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 + * and NAN_WORD1 are used instead. + * #define MULTIPLE_THREADS if the system offers preemptively scheduled + * multiple threads. In this case, you must provide (or suitably + * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed + * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed + * in pow5mult, ensures lazy evaluation of only one copy of high + * powers of 5; omitting this lock would introduce a small + * probability of wasting memory, but would otherwise be harmless.) + * You must also invoke freedtoa(s) to free the value s returned by + * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. + * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that + * avoids underflows on inputs whose result does not underflow. + * If you #define NO_IEEE_Scale on a machine that uses IEEE-format + * floating-point numbers and flushes underflows to zero rather + * than implementing gradual underflow, then you must also #define + * Sudden_Underflow. + * #define USE_LOCALE to use the current locale's decimal_point value. + * #define SET_INEXACT if IEEE arithmetic is being used and extra + * computation should be done to set the inexact flag when the + * result is inexact and avoid setting inexact when the result + * is exact. In this case, dtoa.c must be compiled in + * an environment, perhaps provided by #include "dtoa.c" in a + * suitable wrapper, that defines two functions, + * int get_inexact(void); + * void clear_inexact(void); + * such that get_inexact() returns a nonzero value if the + * inexact bit is already set, and clear_inexact() sets the + * inexact bit to 0. When SET_INEXACT is #defined, strtod + * also does extra computations to set the underflow and overflow + * flags when appropriate (i.e., when the result is tiny and + * inexact or when it is a numeric value rounded to +-infinity). + * #define NO_ERRNO if strtod should not assign errno = ERANGE when + * the result overflows to +-Infinity or underflows to 0. + */ + +#ifndef Long +#define Long long +#endif +#ifndef ULong +typedef unsigned Long ULong; +#endif + +#ifdef DEBUG +#include "stdio.h" +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#include "stdlib.h" +#include "string.h" + +#ifdef USE_LOCALE +#include "locale.h" +#endif + +#ifdef MALLOC +#ifdef KR_headers +extern char *MALLOC(); +#else +extern void *MALLOC(size_t); +#endif +#else +#define MALLOC malloc +#endif + +#ifndef Omit_Private_Memory +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) +static double private_mem[PRIVATE_mem], *pmem_next = private_mem; +#endif + +#undef IEEE_Arith +#undef Avoid_Underflow +#ifdef IEEE_MC68k +#define IEEE_Arith +#endif +#ifdef IEEE_8087 +#define IEEE_Arith +#endif + +#ifdef IEEE_Arith +#ifndef NO_INFNAN_CHECK +#undef INFNAN_CHECK +#define INFNAN_CHECK +#endif +#else +#undef INFNAN_CHECK +#endif + +#include "errno.h" + +#ifdef Bad_float_h + +#ifdef IEEE_Arith +#define DBL_DIG 15 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define FLT_RADIX 2 +#endif /*IEEE_Arith*/ + +#ifdef IBM +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 75 +#define DBL_MAX_EXP 63 +#define FLT_RADIX 16 +#define DBL_MAX 7.2370055773322621e+75 +#endif + +#ifdef VAX +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 38 +#define DBL_MAX_EXP 127 +#define FLT_RADIX 2 +#define DBL_MAX 1.7014118346046923e+38 +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#else /* ifndef Bad_float_h */ +#include "float.h" +#endif /* Bad_float_h */ + +#ifndef __MATH_H__ +#include "math.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONST +#ifdef KR_headers +#define CONST /* blank */ +#else +#define CONST const +#endif +#endif + +#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 +Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. +#endif + +typedef union { double d; ULong L[2]; } U; + +#define dval(x) ((x).d) +#ifdef IEEE_8087 +#define word0(x) ((x).L[1]) +#define word1(x) ((x).L[0]) +#else +#define word0(x) ((x).L[0]) +#define word1(x) ((x).L[1]) +#endif + +/* The following definition of Storeinc is appropriate for MIPS processors. + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +#if defined(IEEE_8087) + defined(VAX) +#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ +((unsigned short *)a)[0] = (unsigned short)c, a++) +#else +#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ +((unsigned short *)a)[1] = (unsigned short)c, a++) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#ifdef IEEE_Arith +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Bias 1023 +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#ifndef NO_IEEE_Scale +#define Avoid_Underflow +#ifdef Flush_Denorm /* debugging option */ +#undef Sudden_Underflow +#endif +#endif + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#ifdef Honor_FLT_ROUNDS +#define Rounding rounding +#undef Check_FLT_ROUNDS +#define Check_FLT_ROUNDS +#else +#define Rounding Flt_Rounds +#endif + +#else /* ifndef IEEE_Arith */ +#undef Check_FLT_ROUNDS +#undef Honor_FLT_ROUNDS +#undef SET_INEXACT +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#undef Flt_Rounds +#define Flt_Rounds 0 +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Bias 65 +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#undef Flt_Rounds +#define Flt_Rounds 1 +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Bias 129 +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif /* IBM, VAX */ +#endif /* IEEE_Arith */ + +#ifndef IEEE_Arith +#define ROUND_BIASED +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) a = rnd_prod(a, b) +#define rounded_quotient(a,b) a = rnd_quot(a, b) +#ifdef KR_headers +extern double rnd_prod(), rnd_quot(); +#else +extern double rnd_prod(double, double), rnd_quot(double, double); +#endif +#else +#define rounded_product(a,b) a *= b +#define rounded_quotient(a,b) a /= b +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Pack_32 +#define Pack_32 +#endif + +#ifdef KR_headers +#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff) +#else +#define FFFFFFFF 0xffffffffUL +#endif + +#ifdef NO_LONG_LONG +#undef ULLong +#ifdef Just_16 +#undef Pack_32 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per Long. + */ +#endif +#else /* long long available */ +#ifndef Llong +#define Llong long long +#endif +#ifndef ULLong +#define ULLong unsigned Llong +#endif +#endif /* NO_LONG_LONG */ + +#ifndef MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ +#define FREE_DTOA_LOCK(n) /*nothing*/ +#endif + +#define Kmax 15 + + struct +Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; + }; + + typedef struct Bigint Bigint; + + static Bigint *freelist[Kmax+1]; + + static Bigint * +Balloc +#ifdef KR_headers + (k) int k; +#else + (int k) +#endif +{ + int x; + Bigint *rv; +#ifndef Omit_Private_Memory + size_t len; +#endif + + ACQUIRE_DTOA_LOCK(0); + if ((rv = freelist[k])) { + freelist[k] = rv->next; + } + else { + x = 1 << k; +#ifdef Omit_Private_Memory + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); +#else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + if (pmem_next - private_mem + len <= PRIVATE_mem) { + rv = (Bigint*)pmem_next; + pmem_next += len; + } + else + rv = (Bigint*)MALLOC(len*sizeof(double)); +#endif + rv->k = k; + rv->maxwds = x; + } + FREE_DTOA_LOCK(0); + rv->sign = rv->wds = 0; + return rv; + } + + static void +Bfree +#ifdef KR_headers + (v) Bigint *v; +#else + (Bigint *v) +#endif +{ + if (v) { + ACQUIRE_DTOA_LOCK(0); + v->next = freelist[v->k]; + freelist[v->k] = v; + FREE_DTOA_LOCK(0); + } + } + +#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ +y->wds*sizeof(Long) + 2*sizeof(int)) + + static Bigint * +multadd +#ifdef KR_headers + (b, m, a) Bigint *b; int m, a; +#else + (Bigint *b, int m, int a) /* multiply by m and add a */ +#endif +{ + int i, wds; +#ifdef ULLong + ULong *x; + ULLong carry, y; +#else + ULong carry, *x, y; +#ifdef Pack_32 + ULong xi, z; +#endif +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + carry = a; + do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = (ULong) y & FFFFFFFF; +#else +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + carry; + carry = y >> 16; + *x++ = y & 0xffff; +#endif +#endif + } + while(++i < wds); + if (carry) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = (ULong) carry; + b->wds = wds; + } + return b; + } + + static Bigint * +s2b +#ifdef KR_headers + (s, nd0, nd, y9) CONST char *s; int nd0, nd; ULong y9; +#else + (CONST char *s, int nd0, int nd, ULong y9) +#endif +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(k); + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(k+1); + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do b = multadd(b, 10, *s++ - '0'); + while(++i < nd0); + s++; + } + else + s += 10; + for(; i < nd; i++) + b = multadd(b, 10, *s++ - '0'); + return b; + } + + static int +hi0bits +#ifdef KR_headers + (x) register ULong x; +#else + (register ULong x) +#endif +{ + register int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; + } + + static int +lo0bits +#ifdef KR_headers + (y) ULong *y; +#else + (ULong *y) +#endif +{ + register int k; + register ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x) + return 32; + } + *y = x; + return k; + } + + static Bigint * +i2b +#ifdef KR_headers + (i) int i; +#else + (int i) +#endif +{ + Bigint *b; + + b = Balloc(1); + b->x[0] = i; + b->wds = 1; + return b; + } + + static Bigint * +mult +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int k, wa, wb, wc; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; +#ifdef Pack_32 + ULong z2; +#endif +#endif + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + for(x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef ULLong + for(; xb < xbe; xc0++) { + if ((y = *xb++)) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = (ULong) z & FFFFFFFF; + } + while(x < xae); + *xc = (ULong) carry; + } + } +#else +#ifdef Pack_32 + for(; xb < xbe; xb++, xc0++) { + if (y = *xb & 0xffff) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } + while(x < xae); + *xc = carry; + } + if (y = *xb >> 16) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } + while(x < xae); + *xc = z2; + } + } +#else + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } + while(x < xae); + *xc = carry; + } + } +#endif +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; + } + + static Bigint *p5s; + + static Bigint * +pow5mult +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + Bigint *b1, *p5, *p51; + int i; + static int p05[3] = { 5, 25, 125 }; + + if ((i = k & 3)) + b = multadd(b, p05[i-1], 0); + + if (!(k >>= 2)) + return b; + if (!(p5 = p5s)) { + /* first time */ +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p5 = p5s)) { + p5 = p5s = i2b(625); + p5->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p5 = p5s = i2b(625); + p5->next = 0; +#endif + } + for(;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + } + if (!(k >>= 1)) + break; + if (!(p51 = p5->next)) { +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p51 = p5->next)) { + p51 = p5->next = mult(p5,p5); + p51->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p51 = p5->next = mult(p5,p5); + p51->next = 0; +#endif + } + p5 = p51; + } + return b; + } + + static Bigint * +lshift +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for(i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + x1 = b1->x; + for(i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + while(x < xe); + if ((*x1 = z)) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#endif + else do + *x1++ = *x++; + while(x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; + } + + static int +cmp +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for(;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; + } + + static Bigint * +diff +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int i, wa, wb; + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; +#ifdef Pack_32 + ULong z; +#endif +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = (ULong) y & FFFFFFFF; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = (ULong) y & FFFFFFFF; + } +#else +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } +#endif +#endif + while(!*--xc) + wa--; + c->wds = wa; + return c; + } + + static double +ulp +#ifdef KR_headers + (x) U x; +#else + (U x) +#endif +{ + register Long L; + U a; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + word0(a) = L; + word1(a) = 0; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(a) = 0x80000 >> L; + word1(a) = 0; + } + else { + word0(a) = 0; + L -= Exp_shift; + word1(a) = L >= 31 ? 1 : 1 << 31 - L; + } + } +#endif +#endif + return dval(a); + } + + static double +b2d +#ifdef KR_headers + (a, e) Bigint *a; int *e; +#else + (Bigint *a, int *e) +#endif +{ + ULong *xa, *xa0, w, y, z; + int k; + U d; +#ifdef VAX + ULong d0, d1; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + d0 = Exp_1 | y >> (Ebits - k); + w = xa > xa0 ? *--xa : 0; + d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + d0 = Exp_1 | y << k | z >> (32 - k); + y = xa > xa0 ? *--xa : 0; + d1 = z << k | y >> (32 - k); + } + else { + d0 = Exp_1 | y; + d1 = z; + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; + y = xa > xa0 ? *--xa : 0; + d1 = w << k + 16 | y << k; +#endif + ret_d: +#ifdef VAX + word0(d) = d0 >> 16 | d0 << 16; + word1(d) = d1 >> 16 | d1 << 16; +#else +#undef d0 +#undef d1 +#endif + return dval(d); + } + + static Bigint * +d2b +#ifdef KR_headers + (d, e, bits) U d; int *e, *bits; +#else + (U d, int *e, int *bits) +#endif +{ + Bigint *b; + int de, k; + ULong *x, y, z; +#ifndef Sudden_Underflow + int i; +#endif +#ifdef VAX + ULong d0, d1; + d0 = word0(d) >> 16 | word0(d) << 16; + d1 = word1(d) >> 16 | word1(d) << 16; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + +#ifdef Pack_32 + b = Balloc(1); +#else + b = Balloc(2); +#endif + x = b->x; + + z = d0 & Frac_mask; + d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow + de = (int)(d0 >> Exp_shift); +#ifndef IBM + z |= Exp_msk11; +#endif +#else + if ((de = (int)(d0 >> Exp_shift))) + z |= Exp_msk1; +#endif +#ifdef Pack_32 + if ((y = d1)) { + if ((k = lo0bits(&y))) { + x[0] = y | z << (32 - k); + z >>= k; + } + else + x[0] = y; +#ifndef Sudden_Underflow + i = +#endif + b->wds = (x[1] = z) ? 2 : 1; + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + x[0] = z; +#ifndef Sudden_Underflow + i = +#endif + b->wds = 1; + k += 32; + } +#else + if (y = d1) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while(!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; + } +#undef d0 +#undef d1 + + static double +ratio +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + U da, db; + int k, ka, kb; + + dval(da) = b2d(a, &ka); + dval(db) = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + word0(da) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(da) *= 1 << k; + } + else { + k = -k; + word0(db) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(db) *= 1 << k; + } +#else + if (k > 0) + word0(da) += k*Exp_msk1; + else { + k = -k; + word0(db) += k*Exp_msk1; + } +#endif + return dval(da) / dval(db); + } + + static CONST double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif + }; + + static CONST double +#ifdef IEEE_Arith +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, +#ifdef Avoid_Underflow + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-53 */ +#else + 1e-256 +#endif + }; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 +#define n_bigtens 5 +#else +#ifdef IBM +bigtens[] = { 1e16, 1e32, 1e64 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +bigtens[] = { 1e16, 1e32 }; +static CONST double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + +#ifdef INFNAN_CHECK + +#ifndef NAN_WORD0 +#define NAN_WORD0 0x7ff80000 +#endif + +#ifndef NAN_WORD1 +#define NAN_WORD1 0 +#endif + + static int +match +#ifdef KR_headers + (sp, t) char **sp, *t; +#else + (CONST char **sp, CONST char *t) +#endif +{ + int c, d; + CONST char *s = *sp; + + while((d = *t++)) { + if ((c = *++s) >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != d) + return 0; + } + *sp = s + 1; + return 1; + } + +#ifndef No_Hex_NaN + static void +hexnan +#ifdef KR_headers + (rvp, sp) U *rvp; CONST char **sp; +#else + (U *rvp, CONST char **sp) +#endif +{ + ULong c, x[2]; + CONST char *s; + int havedig, udx0, xshift; + + x[0] = x[1] = 0; + havedig = xshift = 0; + udx0 = 1; + s = *sp; + /* allow optional initial 0x or 0X */ + while((c = *(CONST unsigned char*)(s+1)) && c <= ' ') + ++s; + if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) + s += 2; + while((c = *(CONST unsigned char*)++s)) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c += 10 - 'a'; + else if (c >= 'A' && c <= 'F') + c += 10 - 'A'; + else if (c <= ' ') { + if (udx0 && havedig) { + udx0 = 0; + xshift = 1; + } + continue; + } +#ifdef GDTOA_NON_PEDANTIC_NANCHECK + else if (/*(*/ c == ')' && havedig) { + *sp = s + 1; + break; + } + else + return; /* invalid form: don't change *sp */ +#else + else { + do { + if (/*(*/ c == ')') { + *sp = s + 1; + break; + } + } while((c = *++s)); + break; + } +#endif + havedig = 1; + if (xshift) { + xshift = 0; + x[0] = x[1]; + x[1] = 0; + } + if (udx0) + x[0] = (x[0] << 4) | (x[1] >> 28); + x[1] = (x[1] << 4) | c; + } + if ((x[0] &= 0xfffff) || x[1]) { + word0(*rvp) = Exp_mask | x[0]; + word1(*rvp) = x[1]; + } + } +#endif /*No_Hex_NaN*/ +#endif /* INFNAN_CHECK */ + + static double +_strtod +#ifdef KR_headers + (s00, se) CONST char *s00; char **se; +#else + (CONST char *s00, char **se) +#endif +{ +#ifdef Avoid_Underflow + int scale; +#endif + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + CONST char *s, *s0, *s1; + double aadj, adj; + U aadj1, rv, rv0; + Long L; + ULong y, z; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef USE_LOCALE + CONST char *s2; +#endif + +#ifdef __GNUC__ + delta = bb = bd = bs = 0; +#endif + + sign = nz0 = nz = 0; + dval(rv) = 0.; + for(s = s00;;s++) switch(*s) { + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) + goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; + } + break2: + if (*s == '0') { + nz0 = 1; + while(*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < 16) + z = 10*z + c - '0'; + nd0 = nd; +#ifdef USE_LOCALE + s1 = localeconv()->decimal_point; + if (c == *s1) { + c = '.'; + if (*++s1) { + s2 = s; + for(;;) { + if (*++s2 != *s1) { + c = 0; + break; + } + if (!*++s1) { + s = s2; + break; + } + } + } + } +#endif + if (c == '.') { + c = *++s; + if (!nd) { + for(; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for(; c >= '0' && c <= '9'; c = *++s) { + have_dig: + nz++; + if (c -= '0') { + nf += nz; + for(i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 1) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 1) + z = 10*z + c; + nz = 0; + } + } + } + dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + goto ret0; + } + s00 = s; + esign = 0; + switch(c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while(c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 19999; /* safe for 16 bit ints */ + else + e = (int)L; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) { +#ifdef INFNAN_CHECK + /* Check for Nan and Infinity */ + switch(c) { + case 'i': + case 'I': + if (match(&s,"nf")) { + --s; + if (!match(&s,"inity")) + ++s; + word0(rv) = 0x7ff00000; + word1(rv) = 0; + goto ret; + } + break; + case 'n': + case 'N': + if (match(&s, "an")) { + word0(rv) = NAN_WORD0; + word1(rv) = NAN_WORD1; +#ifndef No_Hex_NaN + if (*s == '(') /*)*/ + hexnan(&rv, &s); +#endif + goto ret; + } + } +#endif /* INFNAN_CHECK */ + ret0: + s = s00; + sign = 0; + } + goto ret; + } + e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + dval(rv) = y; + if (k > 9) { +#ifdef SET_INEXACT + if (k > DBL_DIG) + oldinexact = get_inexact(); +#endif + dval(rv) = tens[k - 9] * dval(rv) + z; + } + bd0 = 0; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT +#ifndef Honor_FLT_ROUNDS + && Flt_Rounds == 1 +#endif +#endif + ) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + /* rv = */ rounded_product(dval(rv), tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + e -= i; + dval(rv) *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ + vax_ovfl_check: + word0(rv) -= P*Exp_msk1; + /* rv = */ rounded_product(dval(rv), tens[e]); + if ((word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + word0(rv) += P*Exp_msk1; +#else + /* rv = */ rounded_product(dval(rv), tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + /* rv = */ rounded_quotient(dval(rv), tens[-e]); + goto ret; + } +#endif + } + e1 += nd - k; + +#ifdef IEEE_Arith +#ifdef SET_INEXACT + inexact = 1; + if (k <= DBL_DIG) + oldinexact = get_inexact(); +#endif +#ifdef Avoid_Underflow + scale = 0; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif +#endif /*IEEE_Arith*/ + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if ((i = e1 & 15)) + dval(rv) *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { + ovfl: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith +#ifdef Honor_FLT_ROUNDS + switch(rounding) { + case 0: /* toward 0 */ + case 3: /* toward -infinity */ + word0(rv) = Big0; + word1(rv) = Big1; + break; + default: + word0(rv) = Exp_mask; + word1(rv) = 0; + } +#else /*Honor_FLT_ROUNDS*/ + word0(rv) = Exp_mask; + word1(rv) = 0; +#endif /*Honor_FLT_ROUNDS*/ +#ifdef SET_INEXACT + /* set overflow bit */ + dval(rv0) = 1e300; + dval(rv0) *= dval(rv0); +#endif +#else /*IEEE_Arith*/ + word0(rv) = Big0; + word1(rv) = Big1; +#endif /*IEEE_Arith*/ + if (bd0) + goto retfree; + goto ret; + } + e1 >>= 4; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(rv) -= P*Exp_msk1; + dval(rv) *= bigtens[j]; + if ((z = word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(rv) = Big0; + word1(rv) = Big1; + } + else + word0(rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + e1 = -e1; + if ((i = e1 & 15)) + dval(rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + scale = 2*P; + for(j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; zap j low bits */ + if (j >= 32) { + word1(rv) = 0; + if (j >= 53) + word0(rv) = (P+2)*Exp_msk1; + else + word0(rv) &= 0xffffffff << (j-32); + } + else + word1(rv) &= 0xffffffff << j; + } +#else + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + /* The last multiplication could underflow. */ + dval(rv0) = dval(rv); + dval(rv) *= tinytens[j]; + if (!dval(rv)) { + dval(rv) = 2.*dval(rv0); + dval(rv) *= tinytens[j]; +#endif + if (!dval(rv)) { + undfl: + dval(rv) = 0.; +#ifndef NO_ERRNO + errno = ERANGE; +#endif + if (bd0) + goto retfree; + goto ret; + } +#ifndef Avoid_Underflow + word0(rv) = Tiny0; + word1(rv) = Tiny1; + /* The refinement below will clean + * this approximation up. + */ + } +#endif + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bd0 = s2b(s0, nd0, nd, y); + + for(;;) { + bd = Balloc(bd0->k); + Bcopy(bd, bd0); + bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) + bs2++; +#endif +#ifdef Avoid_Underflow + j = bbe - scale; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#else /*Avoid_Underflow*/ +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else /*Sudden_Underflow*/ + j = bbe; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + bb2 += j; + bd2 += j; +#ifdef Avoid_Underflow + bd2 += scale; +#endif + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + } + if (bb2 > 0) + bb = lshift(bb, bb2); + if (bd5 > 0) + bd = pow5mult(bd, bd5); + if (bd2 > 0) + bd = lshift(bd, bd2); + if (bs2 > 0) + bs = lshift(bs, bs2); + delta = diff(bb, bd); + dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) { + if (i < 0) { + /* Error is less than an ulp */ + if (!delta->x[0] && delta->wds <= 1) { + /* exact */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (rounding) { + if (dsign) { + adj = 1.; + goto apply_adj; + } + } + else if (!dsign) { + adj = -1.; + if (!word1(rv) + && !(word0(rv) & Frac_mask)) { + y = word0(rv) & Exp_mask; +#ifdef Avoid_Underflow + if (!scale || y > 2*P*Exp_msk1) +#else + if (y) +#endif + { + delta = lshift(delta,Log2P); + if (cmp(delta, bs) <= 0) + adj = -0.5; + } + } + apply_adj: +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) + <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= + P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + dval(rv) += adj*ulp(rv); + word0(rv) -= P*Exp_msk1; + } + else +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + dval(rv) += adj*ulp(rv); + } + break; + } + adj = ratio(delta, bs); + if (adj < 1.) + adj = 1.; + if (adj <= 0x7ffffffe) { + /* adj = rounding ? ceil(adj) : floor(adj); */ + y = adj; + if (y != adj) { + if (!((rounding>>1) ^ dsign)) + y++; + adj = y; + } + } +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + adj *= ulp(rv); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + word0(rv) -= P*Exp_msk1; + goto cont; + } +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + adj *= ulp(rv); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + goto cont; + } +#endif /*Honor_FLT_ROUNDS*/ + + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask +#ifdef IEEE_Arith +#ifdef Avoid_Underflow + || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1 +#else + || (word0(rv) & Exp_mask) <= Exp_msk1 +#endif +#endif + ) { +#ifdef SET_INEXACT + if (!delta->x[0] && delta->wds <= 1) + inexact = 0; +#endif + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + delta = lshift(delta,Log2P); + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (dsign) { + if ((word0(rv) & Bndry_mask1) == Bndry_mask1 + && word1(rv) == ( +#ifdef Avoid_Underflow + (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : +#endif + 0xffffffff)) { + /*boundary case -- increment exponent*/ + word0(rv) = (word0(rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ; + word1(rv) = 0; +#ifdef Avoid_Underflow + dsign = 0; +#endif + break; + } + } + else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { + drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow /*{{*/ + L = word0(rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else +#ifdef Avoid_Underflow + if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) +#else + if (L <= Exp_msk1) +#endif /*Avoid_Underflow*/ +#endif /*IBM*/ + goto undfl; + L -= Exp_msk1; +#else /*Sudden_Underflow}{*/ +#ifdef Avoid_Underflow + if (scale) { + L = word0(rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + goto undfl; + } + } +#endif /*Avoid_Underflow*/ + L = (word0(rv) & Exp_mask) - Exp_msk1; +#endif /*Sudden_Underflow}}*/ + word0(rv) = L | Bndry_mask1; + word1(rv) = 0xffffffff; +#ifdef IBM + goto cont; +#else + break; +#endif + } +#ifndef ROUND_BIASED + if (!(word1(rv) & LSB)) + break; +#endif + if (dsign) + dval(rv) += ulp(rv); +#ifndef ROUND_BIASED + else { + dval(rv) -= ulp(rv); +#ifndef Sudden_Underflow + if (!dval(rv)) + goto undfl; +#endif + } +#ifdef Avoid_Underflow + dsign = 1 - dsign; +#endif +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (dsign) + aadj = dval(aadj1) = 1.; + else if (word1(rv) || word0(rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (word1(rv) == Tiny1 && !word0(rv)) + goto undfl; +#endif + aadj = 1.; + dval(aadj1) = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + dval(aadj1) = -aadj; + } + } + else { + aadj *= 0.5; + dval(aadj1) = dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch(Rounding) { + case 2: /* towards +infinity */ + dval(aadj1) -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + dval(aadj1) += 0.5; + } +#else + if (Flt_Rounds == 0) + dval(aadj1) += 0.5; +#endif /*Check_FLT_ROUNDS*/ + } + y = word0(rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + dval(rv0) = dval(rv); + word0(rv) -= P*Exp_msk1; + adj = dval(aadj1) * ulp(rv); + dval(rv) += adj; + if ((word0(rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(rv0) == Big0 && word1(rv0) == Big1) + goto ovfl; + word0(rv) = Big0; + word1(rv) = Big1; + goto cont; + } + else + word0(rv) += P*Exp_msk1; + } + else { +#ifdef Avoid_Underflow + if (scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = (ULong) aadj) <= 0) + z = 1; + aadj = z; + dval(aadj1) = dsign ? aadj : -aadj; + } + word0(aadj1) += (2*P+1)*Exp_msk1 - y; + } + adj = dval(aadj1) * ulp(rv); + dval(rv) += adj; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + dval(rv0) = dval(rv); + word0(rv) += P*Exp_msk1; + adj = dval(aadj1) * ulp(rv); + dval(rv) += adj; +#ifdef IBM + if ((word0(rv) & Exp_mask) < P*Exp_msk1) +#else + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (word0(rv0) == Tiny0 + && word1(rv0) == Tiny1) + goto undfl; + word0(rv) = Tiny0; + word1(rv) = Tiny1; + goto cont; + } + else + word0(rv) -= P*Exp_msk1; + } + else { + adj = dval(aadj1) * ulp(rv); + dval(rv) += adj; + } +#else /*Sudden_Underflow*/ + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj > 1.) { + dval(aadj1) = (double)(int)(aadj + 0.5); + if (!dsign) + dval(aadj1) = -dval(aadj1); + } + adj = dval(aadj1) * ulp(rv); + dval(rv) += adj; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + } + z = word0(rv) & Exp_mask; +#ifndef SET_INEXACT +#ifdef Avoid_Underflow + if (!scale) +#endif + if (y == z) { + /* Can we stop now? */ + L = (Long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } +#endif + cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(rv0) = Exp_1 + (70 << Exp_shift); + word1(rv0) = 0; + dval(rv0) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif +#ifdef Avoid_Underflow + if (scale) { + word0(rv0) = Exp_1 - 2*P*Exp_msk1; + word1(rv0) = 0; + dval(rv) *= dval(rv0); +#ifndef NO_ERRNO + /* try to avoid the bug of testing an 8087 register value */ + if (word0(rv) == 0 && word1(rv) == 0) + errno = ERANGE; +#endif + } +#endif /* Avoid_Underflow */ +#ifdef SET_INEXACT + if (inexact && !(word0(rv) & Exp_mask)) { + /* set underflow bit */ + dval(rv0) = 1e-300; + dval(rv0) *= dval(rv0); + } +#endif + retfree: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); + ret: + if (se) + *se = (char *)s; + return sign ? -dval(rv) : dval(rv); + } + + static int +quorem +#ifdef KR_headers + (b, S) Bigint *b, *S; +#else + (Bigint *b, Bigint *S) +#endif +{ + int n; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; +#ifdef Pack_32 + ULong si, z, zs; +#endif +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG + /*debug*/ if (q > 9) + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = (ULong) y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + if (!*bxe) { + bx = b->x; + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = (ULong) y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; + } + +#ifndef MULTIPLE_THREADS + static char *dtoa_result; +#endif + + static char * +#ifdef KR_headers +rv_alloc(i) int i; +#else +rv_alloc(int i) +#endif +{ + int j, k, *r; + + j = sizeof(ULong); + for(k = 0; + sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (unsigned) i; + j <<= 1) + k++; + r = (int*)Balloc(k); + *r = k; + return +#ifndef MULTIPLE_THREADS + dtoa_result = +#endif + (char *)(r+1); + } + + static char * +#ifdef KR_headers +nrv_alloc(s, rve, n) char *s, **rve; int n; +#else +nrv_alloc(CONST char *s, char **rve, int n) +#endif +{ + char *rv, *t; + + t = rv = rv_alloc(n); + while((*t = *s++)) t++; + if (rve) + *rve = t; + return rv; + } + +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + + void +#ifdef KR_headers +freedtoa(s) char *s; +#else +freedtoa(char *s) +#endif +{ + Bigint *b = (Bigint *)((int *)s - 1); + b->maxwds = 1 << (b->k = *(int*)b); + Bfree(b); +#ifndef MULTIPLE_THREADS + if (s == dtoa_result) + dtoa_result = 0; +#endif + } + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + + static char * +dtoa +#ifdef KR_headers + (d, mode, ndigits, decpt, sign, rve) + U d; int mode, ndigits, *decpt, *sign; char **rve; +#else + (U d, int mode, int ndigits, int *decpt, int *sign, char **rve) +#endif +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick; + Long L; +#ifndef Sudden_Underflow + int denorm; + ULong x; +#endif + Bigint *b, *b1, *delta, *mlo, *mhi, *S; + U d2, eps; + double ds; + char *s, *s0; +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif + +#ifdef __GNUC__ + ilim = ilim1 = 0; + mlo = NULL; +#endif + +#ifndef MULTIPLE_THREADS + if (dtoa_result) { + freedtoa(dtoa_result); + dtoa_result = 0; + } +#endif + + if (word0(d) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(d) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((word0(d) & Exp_mask) == Exp_mask) +#else + if (word0(d) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; +#ifdef IEEE_Arith + if (!word1(d) && !(word0(d) & 0xfffff)) + return nrv_alloc("Infinity", rve, 8); +#endif + return nrv_alloc("NaN", rve, 3); + } +#endif +#ifdef IBM + dval(d) += 0; /* normalize */ +#endif + if (!dval(d)) { + *decpt = 1; + return nrv_alloc("0", rve, 1); + } + +#ifdef SET_INEXACT + try_quick = oldinexact = get_inexact(); + inexact = 1; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (*sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif + + b = d2b(d, &be, &bbits); +#ifdef Sudden_Underflow + i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#else + if ((i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) { +#endif + dval(d2) = dval(d); + word0(d2) &= Frac_mask1; + word0(d2) |= Exp_11; +#ifdef IBM + if (j = 11 - hi0bits(word0(d2) & Frac_mask)) + dval(d2) /= 1 << j; +#endif + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) + : word1(d) << (32 - i); + dval(d2) = x; + word0(d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (dval(d) < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + +#ifndef SET_INEXACT +#ifdef Check_FLT_ROUNDS + try_quick = Rounding == 1; +#else + try_quick = 1; +#endif +#endif /*SET_INEXACT*/ + + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + switch(mode) { + case 0: + case 1: + ilim = ilim1 = -1; + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + s = s0 = rv_alloc(i); + +#ifdef Honor_FLT_ROUNDS + if (mode > 1 && rounding != 1) + leftright = 0; +#endif + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + dval(d2) = dval(d); + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + dval(d) /= bigtens[n_bigtens-1]; + ieps++; + } + for(; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + dval(d) /= ds; + } + else if ((j1 = -k)) { + dval(d) *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + dval(d) *= bigtens[i]; + } + } + if (k_check && dval(d) < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + dval(d) *= 10.; + ieps++; + } + dval(eps) = ieps*dval(d) + 7.; + word0(eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + dval(d) -= 5.; + if (dval(d) > dval(eps)) + goto one_digit; + if (dval(d) < -dval(eps)) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + dval(eps) = 0.5/tens[ilim-1] - dval(eps); + for(i = 0;;) { + L = (ULong) dval(d); + dval(d) -= L; + *s++ = '0' + (int)L; + if (dval(d) < dval(eps)) + goto ret1; + if (1. - dval(d) < dval(eps)) + goto bump_up; + if (++i >= ilim) + break; + dval(eps) *= 10.; + dval(d) *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ + dval(eps) *= tens[ilim-1]; + for(i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d)); + if (!(dval(d) -= L)) + ilim = i; + *s++ = '0' + (int)L; + if (i == ilim) { + if (dval(d) > 0.5 + dval(eps)) + goto bump_up; + else if (dval(d) < 0.5 - dval(eps)) { + while(*--s == '0'); + s++; + goto ret1; + } + break; + } + } +#ifndef No_leftright + } +#endif + fast_failed: + s = s0; + dval(d) = dval(d2); + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || dval(d) <= 5*ds) + goto no_digits; + goto one_digit; + } + for(i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d) / ds); + dval(d) -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (dval(d) < 0) { + L--; + dval(d) += ds; + } +#endif + *s++ = '0' + (int)L; + if (!dval(d)) { +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (i == ilim) { +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(rounding) { + case 0: goto ret1; + case 2: goto bump_up; + } +#endif + dval(d) += dval(d); + if (dval(d) > ds || (dval(d) == ds && L & 1)) { + bump_up: + while(*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + } + goto ret1; + } + + m2 = b2; + m5 = b5; + mhi = mlo = 0; + if (leftright) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + b2 += i; + s2 += i; + mhi = i2b(1); + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + b1 = mult(mhi, b); + Bfree(b); + b = b1; + } + if ((j = b5 - m5)) + b = pow5mult(b, j); + } + else + b = pow5mult(b, b5); + } + S = i2b(1); + if (s5 > 0) + S = pow5mult(S, s5); + + /* Check for special case that d is a normalized power of 2. */ + + spec_case = 0; + if ((mode < 2 || leftright) +#ifdef Honor_FLT_ROUNDS + && rounding == 1 +#endif + ) { + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & ~Exp_msk1) +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ +#ifdef Pack_32 + if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f)) + i = 32 - i; +#else + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) + i = 16 - i; +#endif + if (i > 4) { + i -= 4; + b2 += i; + m2 += i; + s2 += i; + } + else if (i < 4) { + i += 28; + b2 += i; + m2 += i; + s2 += i; + } + if (b2 > 0) + b = lshift(b, b2); + if (s2 > 0) + S = lshift(S, s2); + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (leftright) + mhi = multadd(mhi, 10, 0); + ilim = ilim1; + } + } + if (ilim <= 0 && (mode == 3 || mode == 5)) { + if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + /* no digits, fcvt style */ + no_digits: + /* MOZILLA CHANGE: Always return a non-empty string. */ + *s++ = '0'; + k = 0; + goto ret; + } + one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) + mhi = lshift(mhi, m2); + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + } + + for(i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); +#ifndef ROUND_BIASED + if (j1 == 0 && mode != 1 && !(word1(d) & 1) +#ifdef Honor_FLT_ROUNDS + && rounding >= 1 +#endif + ) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; +#ifdef SET_INEXACT + else if (!b->x[0] && b->wds <= 1) + inexact = 0; +#endif + *s++ = dig; + goto ret; + } +#endif + if (j < 0 || (j == 0 && mode != 1 +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + )) { + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto accept_dig; + } +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(rounding) { + case 0: goto accept_dig; + case 2: goto keep_dig; + } +#endif /*Honor_FLT_ROUNDS*/ + if (j1 > 0) { + b = lshift(b, 1); + j1 = cmp(b, S); + if ((j1 > 0 || (j1 == 0 && dig & 1)) + && dig++ == '9') + goto round_9_up; + } + accept_dig: + *s++ = dig; + goto ret; + } + if (j1 > 0) { +#ifdef Honor_FLT_ROUNDS + if (!rounding) + goto accept_dig; +#endif + if (dig == '9') { /* possible if i == 1 */ + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } +#ifdef Honor_FLT_ROUNDS + keep_dig: +#endif + *s++ = dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (mlo == mhi) + mlo = mhi = multadd(mhi, 10, 0); + else { + mlo = multadd(mlo, 10, 0); + mhi = multadd(mhi, 10, 0); + } + } + } + else + for(i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto ret; + } + if (i >= ilim) + break; + b = multadd(b, 10, 0); + } + + /* Round off last digit */ + +#ifdef Honor_FLT_ROUNDS + switch(rounding) { + case 0: goto trimzeros; + case 2: goto roundoff; + } +#endif + b = lshift(b, 1); + j = cmp(b, S); + if (j > 0 || (j == 0 && dig & 1)) { + roundoff: + while(*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { +#ifdef Honor_FLT_ROUNDS + trimzeros: +#endif + while(*--s == '0'); + s++; + } + ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + ret1: +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(d) = Exp_1 + (70 << Exp_shift); + word1(d) = 0; + dval(d) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif + Bfree(b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; + } +#ifdef __cplusplus +} +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/Makefile.ref b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/Makefile.ref new file mode 100644 index 0000000..c902c88 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/Makefile.ref @@ -0,0 +1,143 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Simmule Turner and Rich Salz. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. +# +# This software is not subject to any license of the American Telephone +# and Telegraph Company or of the Regents of the University of California. +# +# Permission is granted to anyone to use this software for any purpose on +# any computer system, and to alter it and redistribute it freely, subject +# to the following restrictions: +# 1. The authors are not responsible for the consequences of use of this +# software, no matter how awful, even if they arise from flaws in it. +# 2. The origin of this software must not be misrepresented, either by +# explicit claim or by omission. Since few users ever read sources, +# credits must appear in the documentation. +# 3. Altered versions must be plainly marked as such, and must not be +# misrepresented as being the original software. Since few users +# ever read sources, credits must appear in the documentation. +# 4. This notice may not be removed or altered. +# + +# +# Unix makefile for editline library. +# + +## Set your options: +## -DANSI_ARROWS ANSI arrows keys work like emacs. +## -DHAVE_STDLIB Have . +## -DHAVE_TCGETATTR Have tcgetattr(), tcsetattr(). +## -DHAVE_TERMIO Have "struct termio" and +## (If neither of above two, we use and BSD ioctl's) +## -DHIDE Make static functions static (non debug). +## -DHIST_SIZE=n History size. +## -DNEED_STRDUP Don't have strdup(). +## -DUNIQUE_HISTORY Don't save command if same as last one. +## -DUSE_DIRENT Use , not ? +## -DUSE_TERMCAP Use the termcap library for terminal size +## see LDFLAGS, below, if you set this. +## -DNEED_PERROR Don't have perror() (used in testit) + +## If you have -DUSE_TERMCAP, set this as appropriate: +#LDFLAGS = -ltermlib +#LDFLAGS = -ltermcap + +DEFS = -DANSI_ARROWS -DHAVE_TCGETATTR -DHIDE -DUSE_DIRENT -DSYS_UNIX \ + -DHAVE_STDLIB -DUNIQUE_HISTORY + +DEPTH = .. + +include $(DEPTH)/config.mk + +LOCAL_OBJDIR = $(OBJDIR)/editline + +# +# Default IEEE libm +# +CFLAGS += -DXP_UNIX $(OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) \ + -DJSFILE $(XCFLAGS) $(DEFS) + +INCFILES = editline.h +.INIT: $(INCFILES) +.KEEP_STATE: +EDITLINE_CFILES = editline.c sysunix.c + +EDITLINE_OBJS = $(addprefix $(LOCAL_OBJDIR)/, $(EDITLINE_CFILES:.c=.o)) + +LIBRARY = $(LOCAL_OBJDIR)/libedit.a + +all: $(LIBRARY) + +export: + +# make objects to depen on $(LOCAL_OBJDIR) only when it exists +$(EDITLINE_OBJS) : $(filter-out $(wildcard $(LOCAL_OBJDIR)), $(LOCAL_OBJDIR)) + +$(LOCAL_OBJDIR) : + mkdir -p $@ + +$(LOCAL_OBJDIR)/%: %.c + $(CC) -o $@ $(CFLAGS) $*.c $(LDFLAGS) + +$(LOCAL_OBJDIR)/%.o: %.c + $(CC) -o $@ -c $(CFLAGS) $*.c + +$(LOCAL_OBJDIR)/%.o: %.s + $(AS) -o $@ $(ASFLAGS) $*.s + +$(LIBRARY): $(EDITLINE_OBJS) + $(AR) rv $@ $? + $(RANLIB) $@ + +#libedit.a : $(EDITLINE_OBJS) +# $(AR) cru $(LOCAL_OBJDIR)/libedit.a $(EDITLINE_OBJS) +# $(RANLIB) $(LOCAL_OBJDIR)/libedit.a + +clean: + rm -rf $(EDITLINE_OBJS) $(EDITLINE_OBJS:.o=.d) + +clobber: clean + rm -rf $(LIBRARY) $(DEPENDENCIES) + if test -d $(LOCAL_OBJDIR); then rmdir $(LOCAL_OBJDIR); fi + +SUFFIXES: .i +%.i: %.c + $(CC) -C -E $(CFLAGS) $< > $*.i diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/README b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/README new file mode 100644 index 0000000..53ec359 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/README @@ -0,0 +1,83 @@ +The files in this directory provide simple line-editing and history +support for the standalone javascript engine, through the 'editline' +library. + +editline has only been enabled for those platforms on which it is +known to build; to try it on a different platform, define JS_EDITLINE +before building. Line editing (and js.c) is not a supported feature +of the javascript library, so your mileage my vary. + +The editline API is a compatible subset of the FSF readline API; if +you have readline installed and would like to link to that instead, +define JS_READLINE. Note that the readline library is distributed +under the GPL, so any resulting binaries are not legally +distributable. + +The editline files used here have been modified to work with the js +build system and to quiet some compiler warnings, and also to remove +filename-completion support. + +If anyone knows of a more recent version of these files, or a site on +which they are being maintained, please let me know! + +Mike McCabe, mccabe@netscape.com + + +The original README file distributed with the editline library follows. + + + +This is a line-editing library. It can be linked into almost any +program to provide command-line editing and recall. + +It is call-compatible with the FSF readline library, but it is a +fraction of the size (and offers fewer features). It does not use +standard I/O. It is distributed under a "C News-like" copyright. + +Configuration is done in the Makefile. Type "make testit" to get +a small slow shell for testing. + +An earlier version was distributed with Byron's rc. Principal +changes over that version include: + Faster. + Is eight-bit clean (thanks to brendan@cs.widener.edu) + Written in K&R C, but ANSI compliant (gcc all warnings) + Propagates EOF properly; rc trip test now passes + Doesn't need or use or provide memmove. + More robust + Calling sequence changed to be compatible with readline. + Test program, new manpage, better configuration + More system-independant; includes Unix and OS-9 support. + +This contains some changes since the posting to comp.sources.misc: + Bugfix for completion on absolute pathnames. + Better handling of M-n versus showing raw 8bit chars. + Better signal handling. + Now supports termios/termio/sgttyb ioctl's. + Add M-m command to toggle how 8bit data is displayed. + +There is one known bug: + History-searching redraws the line wrong if the text + retrieved is shorter then the prompt. + +Enjoy, + Rich $alz + + + Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + + This software is not subject to any license of the American Telephone + and Telegraph Company or of the Regents of the University of California. + + Permission is granted to anyone to use this software for any purpose on + any computer system, and to alter it and redistribute it freely, subject + to the following restrictions: + 1. The authors are not responsible for the consequences of use of this + software, no matter how awful, even if they arise from flaws in it. + 2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. Since few users ever read sources, + credits must appear in the documentation. + 3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. Since few users + ever read sources, credits must appear in the documentation. + 4. This notice may not be removed or altered. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.3 b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.3 new file mode 100644 index 0000000..21a72ca --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.3 @@ -0,0 +1,175 @@ +.TH EDITLINE 3 +.SH NAME +editline \- command-line editing library with history +.SH SYNOPSIS +.nf +.B "char *" +.B "readline(prompt)" +.B " char *prompt;" + +.B "void" +.B "add_history(line)" +.B " char *line;" +.fi +.SH DESCRIPTION +.I Editline +is a library that provides an line-editing interface with text recall. +It is intended to be compatible with the +.I readline +library provided by the Free Software Foundation, but much smaller. +The bulk of this manual page describes the user interface. +.PP +The +.I readline +routine returns a line of text with the trailing newline removed. +The data is returned in a buffer allocated with +.IR malloc (3), +so the space should be released with +.IR free (3) +when the calling program is done with it. +Before accepting input from the user, the specified +.I prompt +is displayed on the terminal. +.PP +The +.I add_history +routine makes a copy of the specified +.I line +and adds it to the internal history list. +.SS "User Interface" +A program that uses this library provides a simple emacs-like editing +interface to its users. +A line may be edited before it is sent to the calling program by typing either +control characters or escape sequences. +A control character, shown as a caret followed by a letter, is typed by +holding down the ``control'' key while the letter is typed. +For example, ``^A'' is a control-A. +An escape sequence is entered by typing the ``escape'' key followed by one or +more characters. +The escape key is abbreviated as ``ESC.'' +Note that unlike control keys, case matters in escape sequences; ``ESC\ F'' +is not the same as ``ESC\ f''. +.PP +An editing command may be typed anywhere on the line, not just at the +beginning. +In addition, a return may also be typed anywhere on the line, not just at +the end. +.PP +Most editing commands may be given a repeat count, +.IR n , +where +.I n +is a number. +To enter a repeat count, type the escape key, the number, and then +the command to execute. +For example, ``ESC\ 4\ ^f'' moves forward four characters. +If a command may be given a repeat count then the text ``[n]'' is given at the +end of its description. +.PP +The following control characters are accepted: +.RS +.nf +.ta \w'ESC DEL 'u +^A Move to the beginning of the line +^B Move left (backwards) [n] +^D Delete character [n] +^E Move to end of line +^F Move right (forwards) [n] +^G Ring the bell +^H Delete character before cursor (backspace key) [n] +^I Complete filename (tab key); see below +^J Done with line (return key) +^K Kill to end of line (or column [n]) +^L Redisplay line +^M Done with line (alternate return key) +^N Get next line from history [n] +^P Get previous line from history [n] +^R Search backward (forward if [n]) through history for text; +\& must start line if text begins with an uparrow +^T Transpose characters +^V Insert next character, even if it is an edit command +^W Wipe to the mark +^X^X Exchange current location and mark +^Y Yank back last killed text +^[ Start an escape sequence (escape key) +^]c Move forward to next character ``c'' +^? Delete character before cursor (delete key) [n] +.fi +.RE +.PP +The following escape sequences are provided. +.RS +.nf +.ta \w'ESC DEL 'u +ESC\ ^H Delete previous word (backspace key) [n] +ESC\ DEL Delete previous word (delete key) [n] +ESC\ SP Set the mark (space key); see ^X^X and ^Y above +ESC\ \. Get the last (or [n]'th) word from previous line +ESC\ \? Show possible completions; see below +ESC\ < Move to start of history +ESC\ > Move to end of history +ESC\ b Move backward a word [n] +ESC\ d Delete word under cursor [n] +ESC\ f Move forward a word [n] +ESC\ l Make word lowercase [n] +ESC\ m Toggle if 8bit chars display normally or with ``M\-'' prefix +ESC\ u Make word uppercase [n] +ESC\ y Yank back last killed text +ESC\ v Show library version +ESC\ w Make area up to mark yankable +ESC\ nn Set repeat count to the number nn +ESC\ C Read from environment variable ``_C_'', where C is +\& an uppercase letter +.fi +.RE +.PP +The +.I editline +library has a small macro facility. +If you type the escape key followed by an uppercase letter, +.IR C , +then the contents of the environment variable +.I _C_ +are read in as if you had typed them at the keyboard. +For example, if the variable +.I _L_ +contains the following: +.RS +^A^Kecho '^V^[[H^V^[[2J'^M +.RE +Then typing ``ESC L'' will move to the beginning of the line, kill the +entire line, enter the echo command needed to clear the terminal (if your +terminal is like a VT-100), and send the line back to the shell. +.PP +The +.I editline +library also does filename completion. +Suppose the root directory has the following files in it: +.RS +.nf +.ta \w'core 'u +bin vmunix +core vmunix.old +.fi +.RE +If you type ``rm\ /v'' and then the tab key. +.I Editline +will then finish off as much of the name as possible by adding ``munix''. +Because the name is not unique, it will then beep. +If you type the escape key and a question mark, it will display the +two choices. +If you then type a period and a tab, the library will finish off the filename +for you: +.RS +.nf +.RI "rm /v[TAB]" munix .TAB old +.fi +.RE +The tab key is shown by ``[TAB]'' and the automatically-entered text +is shown in italics. +.SH "BUGS AND LIMITATIONS" +Cannot handle lines more than 80 columns. +.SH AUTHORS +Simmule R. Turner +and Rich $alz . +Original manual page by DaviD W. Sanderson . diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.c new file mode 100644 index 0000000..8ca93b3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.c @@ -0,0 +1,1368 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Simmule Turner and Rich Salz. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * 1. The authors are not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * 4. This notice may not be removed or altered. + */ + + +/* +** Main editing routines for editline library. +*/ +#include "editline.h" +#include +#include +#include + +/* +** Manifest constants. +*/ +#define SCREEN_WIDTH 80 +#define SCREEN_ROWS 24 +#define NO_ARG (-1) +#define DEL 127 +#define CTL(x) ((x) & 0x1F) +#define ISCTL(x) ((x) && (x) < ' ') +#define UNCTL(x) ((x) + 64) +#define META(x) ((x) | 0x80) +#define ISMETA(x) ((x) & 0x80) +#define UNMETA(x) ((x) & 0x7F) +#if !defined(HIST_SIZE) +#define HIST_SIZE 20 +#endif /* !defined(HIST_SIZE) */ + +/* +** Command status codes. +*/ +typedef enum _STATUS { + CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal +} STATUS; + +/* +** The type of case-changing to perform. +*/ +typedef enum _CASE { + TOupper, TOlower +} CASE; + +/* +** Key to command mapping. +*/ +typedef struct _KEYMAP { + CHAR Key; + STATUS (*Function)(); +} KEYMAP; + +/* +** Command history structure. +*/ +typedef struct _HISTORY { + int Size; + int Pos; + CHAR *Lines[HIST_SIZE]; +} HISTORY; + +/* +** Globals. +*/ +int rl_eof; +int rl_erase; +int rl_intr; +int rl_kill; +int rl_quit; + +STATIC CHAR NIL[] = ""; +STATIC CONST CHAR *Input = NIL; +STATIC CHAR *Line; +STATIC CONST char *Prompt; +STATIC CHAR *Yanked; +STATIC char *Screen; +STATIC char NEWLINE[]= CRLF; +STATIC HISTORY H; +STATIC int Repeat; +STATIC int End; +STATIC int Mark; +STATIC int OldPoint; +STATIC int Point; +STATIC int PushBack; +STATIC int Pushed; +STATIC int Signal; +FORWARD KEYMAP Map[32]; +FORWARD KEYMAP MetaMap[16]; +STATIC SIZE_T Length; +STATIC SIZE_T ScreenCount; +STATIC SIZE_T ScreenSize; +STATIC char *backspace; +STATIC int TTYwidth; +STATIC int TTYrows; + +/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */ +int rl_meta_chars = 0; + +/* +** Declarations. +*/ +STATIC CHAR *editinput(); +#if defined(USE_TERMCAP) +#include +#include +#include +#endif /* defined(USE_TERMCAP) */ + +/* +** TTY input/output functions. +*/ + +STATIC void +TTYflush() +{ + if (ScreenCount) { + (void)write(1, Screen, ScreenCount); + ScreenCount = 0; + } +} + +STATIC void +TTYput(c) + CHAR c; +{ + Screen[ScreenCount] = c; + if (++ScreenCount >= ScreenSize - 1) { + ScreenSize += SCREEN_INC; + RENEW(Screen, char, ScreenSize); + } +} + +STATIC void +TTYputs(p) + CHAR *p; +{ + while (*p) + TTYput(*p++); +} + +STATIC void +TTYshow(c) + CHAR c; +{ + if (c == DEL) { + TTYput('^'); + TTYput('?'); + } + else if (ISCTL(c)) { + TTYput('^'); + TTYput(UNCTL(c)); + } + else if (rl_meta_chars && ISMETA(c)) { + TTYput('M'); + TTYput('-'); + TTYput(UNMETA(c)); + } + else + TTYput(c); +} + +STATIC void +TTYstring(p) + CHAR *p; +{ + while (*p) + TTYshow(*p++); +} + +STATIC unsigned int +TTYget() +{ + CHAR c; + + TTYflush(); + if (Pushed) { + Pushed = 0; + return PushBack; + } + if (*Input) + return *Input++; + return read(0, &c, (SIZE_T)1) == 1 ? c : EOF; +} + +#define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b')) + +STATIC void +TTYbackn(n) + int n; +{ + while (--n >= 0) + TTYback(); +} + +STATIC void +TTYinfo() +{ + static int init; +#if defined(USE_TERMCAP) + char *term; + char buff[2048]; + char *bp, *p; +#endif /* defined(USE_TERMCAP) */ +#if defined(TIOCGWINSZ) + struct winsize W; +#endif /* defined(TIOCGWINSZ) */ + + if (init) { +#if defined(TIOCGWINSZ) + /* Perhaps we got resized. */ + if (ioctl(0, TIOCGWINSZ, &W) >= 0 + && W.ws_col > 0 && W.ws_row > 0) { + TTYwidth = (int)W.ws_col; + TTYrows = (int)W.ws_row; + } +#endif /* defined(TIOCGWINSZ) */ + return; + } + init++; + + TTYwidth = TTYrows = 0; +#if defined(USE_TERMCAP) + bp = &buff[0]; + if ((term = getenv("TERM")) == NULL) + term = "dumb"; + if (tgetent(buff, term) < 0) { + TTYwidth = SCREEN_WIDTH; + TTYrows = SCREEN_ROWS; + return; + } + p = tgetstr("le", &bp); + backspace = p ? strdup(p) : NULL; + TTYwidth = tgetnum("co"); + TTYrows = tgetnum("li"); +#endif /* defined(USE_TERMCAP) */ + +#if defined(TIOCGWINSZ) + if (ioctl(0, TIOCGWINSZ, &W) >= 0) { + TTYwidth = (int)W.ws_col; + TTYrows = (int)W.ws_row; + } +#endif /* defined(TIOCGWINSZ) */ + + if (TTYwidth <= 0 || TTYrows <= 0) { + TTYwidth = SCREEN_WIDTH; + TTYrows = SCREEN_ROWS; + } +} + + +STATIC void +reposition() +{ + int i; + CHAR *p; + + TTYput('\r'); + TTYputs((CONST CHAR *)Prompt); + for (i = Point, p = Line; --i >= 0; p++) + TTYshow(*p); +} + +STATIC void +left(Change) + STATUS Change; +{ + TTYback(); + if (Point) { + if (ISCTL(Line[Point - 1])) + TTYback(); + else if (rl_meta_chars && ISMETA(Line[Point - 1])) { + TTYback(); + TTYback(); + } + } + if (Change == CSmove) + Point--; +} + +STATIC void +right(Change) + STATUS Change; +{ + TTYshow(Line[Point]); + if (Change == CSmove) + Point++; +} + +STATIC STATUS +ring_bell() +{ + TTYput('\07'); + TTYflush(); + return CSstay; +} + +STATIC STATUS +do_macro(c) + unsigned int c; +{ + CHAR name[4]; + + name[0] = '_'; + name[1] = c; + name[2] = '_'; + name[3] = '\0'; + + if ((Input = (CHAR *)getenv((char *)name)) == NULL) { + Input = NIL; + return ring_bell(); + } + return CSstay; +} + +STATIC STATUS +do_forward(move) + STATUS move; +{ + int i; + CHAR *p; + + i = 0; + do { + p = &Line[Point]; + for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++) + if (move == CSmove) + right(CSstay); + + for (; Point < End && isalnum(*p); Point++, p++) + if (move == CSmove) + right(CSstay); + + if (Point == End) + break; + } while (++i < Repeat); + + return CSstay; +} + +STATIC STATUS +do_case(type) + CASE type; +{ + int i; + int end; + int count; + CHAR *p; + + (void)do_forward(CSstay); + if (OldPoint != Point) { + if ((count = Point - OldPoint) < 0) + count = -count; + Point = OldPoint; + if ((end = Point + count) > End) + end = End; + for (i = Point, p = &Line[i]; i < end; i++, p++) { + if (type == TOupper) { + if (islower(*p)) + *p = toupper(*p); + } + else if (isupper(*p)) + *p = tolower(*p); + right(CSmove); + } + } + return CSstay; +} + +STATIC STATUS +case_down_word() +{ + return do_case(TOlower); +} + +STATIC STATUS +case_up_word() +{ + return do_case(TOupper); +} + +STATIC void +ceol() +{ + int extras; + int i; + CHAR *p; + + for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) { + TTYput(' '); + if (ISCTL(*p)) { + TTYput(' '); + extras++; + } + else if (rl_meta_chars && ISMETA(*p)) { + TTYput(' '); + TTYput(' '); + extras += 2; + } + } + + for (i += extras; i > Point; i--) + TTYback(); +} + +STATIC void +clear_line() +{ + Point = -strlen(Prompt); + TTYput('\r'); + ceol(); + Point = 0; + End = 0; + Line[0] = '\0'; +} + +STATIC STATUS +insert_string(p) + CHAR *p; +{ + SIZE_T len; + int i; + CHAR *new; + CHAR *q; + + len = strlen((char *)p); + if (End + len >= Length) { + if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL) + return CSstay; + if (Length) { + COPYFROMTO(new, Line, Length); + DISPOSE(Line); + } + Line = new; + Length += len + MEM_INC; + } + + for (q = &Line[Point], i = End - Point; --i >= 0; ) + q[len + i] = q[i]; + COPYFROMTO(&Line[Point], p, len); + End += len; + Line[End] = '\0'; + TTYstring(&Line[Point]); + Point += len; + + return Point == End ? CSstay : CSmove; +} + +STATIC STATUS +redisplay() +{ + TTYputs((CONST CHAR *)NEWLINE); + TTYputs((CONST CHAR *)Prompt); + TTYstring(Line); + return CSmove; +} + +STATIC STATUS +toggle_meta_mode() +{ + rl_meta_chars = ! rl_meta_chars; + return redisplay(); +} + + +STATIC CHAR * +next_hist() +{ + return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos]; +} + +STATIC CHAR * +prev_hist() +{ + return H.Pos == 0 ? NULL : H.Lines[--H.Pos]; +} + +STATIC STATUS +do_insert_hist(p) + CHAR *p; +{ + if (p == NULL) + return ring_bell(); + Point = 0; + reposition(); + ceol(); + End = 0; + return insert_string(p); +} + +STATIC STATUS +do_hist(move) + CHAR *(*move)(); +{ + CHAR *p; + int i; + + i = 0; + do { + if ((p = (*move)()) == NULL) + return ring_bell(); + } while (++i < Repeat); + return do_insert_hist(p); +} + +STATIC STATUS +h_next() +{ + return do_hist(next_hist); +} + +STATIC STATUS +h_prev() +{ + return do_hist(prev_hist); +} + +STATIC STATUS +h_first() +{ + return do_insert_hist(H.Lines[H.Pos = 0]); +} + +STATIC STATUS +h_last() +{ + return do_insert_hist(H.Lines[H.Pos = H.Size - 1]); +} + +/* +** Return zero if pat appears as a substring in text. +*/ +STATIC int +substrcmp(text, pat, len) + char *text; + char *pat; + int len; +{ + char c; + + if ((c = *pat) == '\0') + return *text == '\0'; + for ( ; *text; text++) + if (*text == c && strncmp(text, pat, len) == 0) + return 0; + return 1; +} + +STATIC CHAR * +search_hist(search, move) + CHAR *search; + CHAR *(*move)(); +{ + static CHAR *old_search; + int len; + int pos; + int (*match)(); + char *pat; + + /* Save or get remembered search pattern. */ + if (search && *search) { + if (old_search) + DISPOSE(old_search); + old_search = (CHAR *)strdup((char *)search); + } + else { + if (old_search == NULL || *old_search == '\0') + return NULL; + search = old_search; + } + + /* Set up pattern-finder. */ + if (*search == '^') { + match = strncmp; + pat = (char *)(search + 1); + } + else { + match = substrcmp; + pat = (char *)search; + } + len = strlen(pat); + + for (pos = H.Pos; (*move)() != NULL; ) + if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0) + return H.Lines[H.Pos]; + H.Pos = pos; + return NULL; +} + +STATIC STATUS +h_search() +{ + static int Searching; + CONST char *old_prompt; + CHAR *(*move)(); + CHAR *p; + + if (Searching) + return ring_bell(); + Searching = 1; + + clear_line(); + old_prompt = Prompt; + Prompt = "Search: "; + TTYputs((CONST CHAR *)Prompt); + move = Repeat == NO_ARG ? prev_hist : next_hist; + p = editinput(); + Prompt = old_prompt; + Searching = 0; + TTYputs((CONST CHAR *)Prompt); + if (p == NULL && Signal > 0) { + Signal = 0; + clear_line(); + return redisplay(); + } + p = search_hist(p, move); + clear_line(); + if (p == NULL) { + (void)ring_bell(); + return redisplay(); + } + return do_insert_hist(p); +} + +STATIC STATUS +fd_char() +{ + int i; + + i = 0; + do { + if (Point >= End) + break; + right(CSmove); + } while (++i < Repeat); + return CSstay; +} + +STATIC void +save_yank(begin, i) + int begin; + int i; +{ + if (Yanked) { + DISPOSE(Yanked); + Yanked = NULL; + } + + if (i < 1) + return; + + if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) { + COPYFROMTO(Yanked, &Line[begin], i); + Yanked[i] = '\0'; + } +} + +STATIC STATUS +delete_string(count) + int count; +{ + int i; + CHAR *p; + + if (count <= 0 || End == Point) + return ring_bell(); + + if (count == 1 && Point == End - 1) { + /* Optimize common case of delete at end of line. */ + End--; + p = &Line[Point]; + i = 1; + TTYput(' '); + if (ISCTL(*p)) { + i = 2; + TTYput(' '); + } + else if (rl_meta_chars && ISMETA(*p)) { + i = 3; + TTYput(' '); + TTYput(' '); + } + TTYbackn(i); + *p = '\0'; + return CSmove; + } + if (Point + count > End && (count = End - Point) <= 0) + return CSstay; + + if (count > 1) + save_yank(Point, count); + + for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++) + p[0] = p[count]; + ceol(); + End -= count; + TTYstring(&Line[Point]); + return CSmove; +} + +STATIC STATUS +bk_char() +{ + int i; + + i = 0; + do { + if (Point == 0) + break; + left(CSmove); + } while (++i < Repeat); + + return CSstay; +} + +STATIC STATUS +bk_del_char() +{ + int i; + + i = 0; + do { + if (Point == 0) + break; + left(CSmove); + } while (++i < Repeat); + + return delete_string(i); +} + +STATIC STATUS +kill_line() +{ + int i; + + if (Repeat != NO_ARG) { + if (Repeat < Point) { + i = Point; + Point = Repeat; + reposition(); + (void)delete_string(i - Point); + } + else if (Repeat > Point) { + right(CSmove); + (void)delete_string(Repeat - Point - 1); + } + return CSmove; + } + + save_yank(Point, End - Point); + Line[Point] = '\0'; + ceol(); + End = Point; + return CSstay; +} + +STATIC STATUS +insert_char(c) + int c; +{ + STATUS s; + CHAR buff[2]; + CHAR *p; + CHAR *q; + int i; + + if (Repeat == NO_ARG || Repeat < 2) { + buff[0] = c; + buff[1] = '\0'; + return insert_string(buff); + } + + if ((p = NEW(CHAR, Repeat + 1)) == NULL) + return CSstay; + for (i = Repeat, q = p; --i >= 0; ) + *q++ = c; + *q = '\0'; + Repeat = 0; + s = insert_string(p); + DISPOSE(p); + return s; +} + +STATIC STATUS +meta() +{ + unsigned int c; + KEYMAP *kp; + + if ((c = TTYget()) == EOF) + return CSeof; +#if defined(ANSI_ARROWS) + /* Also include VT-100 arrows. */ + if (c == '[' || c == 'O') + switch (c = TTYget()) { + default: return ring_bell(); + case EOF: return CSeof; + case 'A': return h_prev(); + case 'B': return h_next(); + case 'C': return fd_char(); + case 'D': return bk_char(); + } +#endif /* defined(ANSI_ARROWS) */ + + if (isdigit(c)) { + for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); ) + Repeat = Repeat * 10 + c - '0'; + Pushed = 1; + PushBack = c; + return CSstay; + } + + if (isupper(c)) + return do_macro(c); + for (OldPoint = Point, kp = MetaMap; kp->Function; kp++) + if (kp->Key == c) + return (*kp->Function)(); + + return ring_bell(); +} + +STATIC STATUS +emacs(c) + unsigned int c; +{ + STATUS s; + KEYMAP *kp; + + if (rl_meta_chars && ISMETA(c)) { + Pushed = 1; + PushBack = UNMETA(c); + return meta(); + } + for (kp = Map; kp->Function; kp++) + if (kp->Key == c) + break; + s = kp->Function ? (*kp->Function)() : insert_char((int)c); + if (!Pushed) + /* No pushback means no repeat count; hacky, but true. */ + Repeat = NO_ARG; + return s; +} + +STATIC STATUS +TTYspecial(c) + unsigned int c; +{ + if (ISMETA(c)) + return CSdispatch; + + if (c == rl_erase || c == DEL) + return bk_del_char(); + if (c == rl_kill) { + if (Point != 0) { + Point = 0; + reposition(); + } + Repeat = NO_ARG; + return kill_line(); + } + if (c == rl_eof && Point == 0 && End == 0) + return CSeof; + if (c == rl_intr) { + Signal = SIGINT; + return CSsignal; + } + if (c == rl_quit) { + Signal = SIGQUIT; + return CSeof; + } + + return CSdispatch; +} + +STATIC CHAR * +editinput() +{ + unsigned int c; + + Repeat = NO_ARG; + OldPoint = Point = Mark = End = 0; + Line[0] = '\0'; + + Signal = -1; + while ((c = TTYget()) != EOF) + switch (TTYspecial(c)) { + case CSdone: + return Line; + case CSeof: + return NULL; + case CSsignal: + return (CHAR *)""; + case CSmove: + reposition(); + break; + case CSdispatch: + switch (emacs(c)) { + case CSdone: + return Line; + case CSeof: + return NULL; + case CSsignal: + return (CHAR *)""; + case CSmove: + reposition(); + break; + case CSdispatch: + case CSstay: + break; + } + break; + case CSstay: + break; + } + return NULL; +} + +STATIC void +hist_add(p) + CHAR *p; +{ + int i; + + if ((p = (CHAR *)strdup((char *)p)) == NULL) + return; + if (H.Size < HIST_SIZE) + H.Lines[H.Size++] = p; + else { + DISPOSE(H.Lines[0]); + for (i = 0; i < HIST_SIZE - 1; i++) + H.Lines[i] = H.Lines[i + 1]; + H.Lines[i] = p; + } + H.Pos = H.Size - 1; +} + +/* +** For compatibility with FSF readline. +*/ +/* ARGSUSED0 */ +void +rl_reset_terminal(p) + char *p; +{ +} + +void +rl_initialize() +{ +} + +char * +readline(prompt) + CONST char *prompt; +{ + CHAR *line; + int s; + + if (Line == NULL) { + Length = MEM_INC; + if ((Line = NEW(CHAR, Length)) == NULL) + return NULL; + } + + TTYinfo(); + rl_ttyset(0); + hist_add(NIL); + ScreenSize = SCREEN_INC; + Screen = NEW(char, ScreenSize); + Prompt = prompt ? prompt : (char *)NIL; + TTYputs((CONST CHAR *)Prompt); + if ((line = editinput()) != NULL) { + line = (CHAR *)strdup((char *)line); + TTYputs((CHAR *)NEWLINE); + TTYflush(); + } + rl_ttyset(1); + DISPOSE(Screen); + DISPOSE(H.Lines[--H.Size]); + if (Signal > 0) { + s = Signal; + Signal = 0; + (void)kill(getpid(), s); + } + return (char *)line; +} + +void +add_history(p) + char *p; +{ + if (p == NULL || *p == '\0') + return; + +#if defined(UNIQUE_HISTORY) + if (H.Size && strcmp(p, H.Lines[H.Size - 1]) == 0) + return; +#endif /* defined(UNIQUE_HISTORY) */ + hist_add((CHAR *)p); +} + + +STATIC STATUS +beg_line() +{ + if (Point) { + Point = 0; + return CSmove; + } + return CSstay; +} + +STATIC STATUS +del_char() +{ + return delete_string(Repeat == NO_ARG ? 1 : Repeat); +} + +STATIC STATUS +end_line() +{ + if (Point != End) { + Point = End; + return CSmove; + } + return CSstay; +} + +STATIC STATUS +accept_line() +{ + Line[End] = '\0'; + return CSdone; +} + +STATIC STATUS +transpose() +{ + CHAR c; + + if (Point) { + if (Point == End) + left(CSmove); + c = Line[Point - 1]; + left(CSstay); + Line[Point - 1] = Line[Point]; + TTYshow(Line[Point - 1]); + Line[Point++] = c; + TTYshow(c); + } + return CSstay; +} + +STATIC STATUS +quote() +{ + unsigned int c; + + return (c = TTYget()) == EOF ? CSeof : insert_char((int)c); +} + +STATIC STATUS +wipe() +{ + int i; + + if (Mark > End) + return ring_bell(); + + if (Point > Mark) { + i = Point; + Point = Mark; + Mark = i; + reposition(); + } + + return delete_string(Mark - Point); +} + +STATIC STATUS +mk_set() +{ + Mark = Point; + return CSstay; +} + +STATIC STATUS +exchange() +{ + unsigned int c; + + if ((c = TTYget()) != CTL('X')) + return c == EOF ? CSeof : ring_bell(); + + if ((c = Mark) <= End) { + Mark = Point; + Point = c; + return CSmove; + } + return CSstay; +} + +STATIC STATUS +yank() +{ + if (Yanked && *Yanked) + return insert_string(Yanked); + return CSstay; +} + +STATIC STATUS +copy_region() +{ + if (Mark > End) + return ring_bell(); + + if (Point > Mark) + save_yank(Mark, Point - Mark); + else + save_yank(Point, Mark - Point); + + return CSstay; +} + +STATIC STATUS +move_to_char() +{ + unsigned int c; + int i; + CHAR *p; + + if ((c = TTYget()) == EOF) + return CSeof; + for (i = Point + 1, p = &Line[i]; i < End; i++, p++) + if (*p == c) { + Point = i; + return CSmove; + } + return CSstay; +} + +STATIC STATUS +fd_word() +{ + return do_forward(CSmove); +} + +STATIC STATUS +fd_kill_word() +{ + int i; + + (void)do_forward(CSstay); + if (OldPoint != Point) { + i = Point - OldPoint; + Point = OldPoint; + return delete_string(i); + } + return CSstay; +} + +STATIC STATUS +bk_word() +{ + int i; + CHAR *p; + + i = 0; + do { + for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--) + left(CSmove); + + for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--) + left(CSmove); + + if (Point == 0) + break; + } while (++i < Repeat); + + return CSstay; +} + +STATIC STATUS +bk_kill_word() +{ + (void)bk_word(); + if (OldPoint != Point) + return delete_string(OldPoint - Point); + return CSstay; +} + +STATIC int +argify(line, avp) + CHAR *line; + CHAR ***avp; +{ + CHAR *c; + CHAR **p; + CHAR **new; + int ac; + int i; + + i = MEM_INC; + if ((*avp = p = NEW(CHAR*, i))== NULL) + return 0; + + for (c = line; isspace(*c); c++) + continue; + if (*c == '\n' || *c == '\0') + return 0; + + for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) { + if (isspace(*c)) { + *c++ = '\0'; + if (*c && *c != '\n') { + if (ac + 1 == i) { + new = NEW(CHAR*, i + MEM_INC); + if (new == NULL) { + p[ac] = NULL; + return ac; + } + COPYFROMTO(new, p, i * sizeof (char **)); + i += MEM_INC; + DISPOSE(p); + *avp = p = new; + } + p[ac++] = c; + } + } + else + c++; + } + *c = '\0'; + p[ac] = NULL; + return ac; +} + +STATIC STATUS +last_argument() +{ + CHAR **av; + CHAR *p; + STATUS s; + int ac; + + if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL) + return ring_bell(); + + if ((p = (CHAR *)strdup((char *)p)) == NULL) + return CSstay; + ac = argify(p, &av); + + if (Repeat != NO_ARG) + s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell(); + else + s = ac ? insert_string(av[ac - 1]) : CSstay; + + if (ac) + DISPOSE(av); + DISPOSE(p); + return s; +} + +STATIC KEYMAP Map[32] = { + { CTL('@'), ring_bell }, + { CTL('A'), beg_line }, + { CTL('B'), bk_char }, + { CTL('D'), del_char }, + { CTL('E'), end_line }, + { CTL('F'), fd_char }, + { CTL('G'), ring_bell }, + { CTL('H'), bk_del_char }, + { CTL('J'), accept_line }, + { CTL('K'), kill_line }, + { CTL('L'), redisplay }, + { CTL('M'), accept_line }, + { CTL('N'), h_next }, + { CTL('O'), ring_bell }, + { CTL('P'), h_prev }, + { CTL('Q'), ring_bell }, + { CTL('R'), h_search }, + { CTL('S'), ring_bell }, + { CTL('T'), transpose }, + { CTL('U'), ring_bell }, + { CTL('V'), quote }, + { CTL('W'), wipe }, + { CTL('X'), exchange }, + { CTL('Y'), yank }, + { CTL('Z'), ring_bell }, + { CTL('['), meta }, + { CTL(']'), move_to_char }, + { CTL('^'), ring_bell }, + { CTL('_'), ring_bell }, + { 0, NULL } +}; + +STATIC KEYMAP MetaMap[16]= { + { CTL('H'), bk_kill_word }, + { DEL, bk_kill_word }, + { ' ', mk_set }, + { '.', last_argument }, + { '<', h_first }, + { '>', h_last }, + { 'b', bk_word }, + { 'd', fd_kill_word }, + { 'f', fd_word }, + { 'l', case_down_word }, + { 'm', toggle_meta_mode }, + { 'u', case_up_word }, + { 'y', yank }, + { 'w', copy_region }, + { 0, NULL } +}; + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.h new file mode 100644 index 0000000..e820049 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/editline.h @@ -0,0 +1,135 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Simmule Turner and Rich Salz. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * 1. The authors are not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * 4. This notice may not be removed or altered. + */ + +/* +** Internal header file for editline library. +*/ +#include +#if defined(HAVE_STDLIB) +#include +#include +#endif /* defined(HAVE_STDLIB) */ +#if defined(SYS_UNIX) +#include "unix.h" +#endif /* defined(SYS_UNIX) */ +#if defined(SYS_OS9) +#include "os9.h" +#endif /* defined(SYS_OS9) */ + +#if !defined(SIZE_T) +#define SIZE_T unsigned int +#endif /* !defined(SIZE_T) */ + +typedef unsigned char CHAR; + +#if defined(HIDE) +#define STATIC static +#else +#define STATIC /* NULL */ +#endif /* !defined(HIDE) */ + +#if !defined(CONST) +#if defined(__STDC__) +#define CONST const +#else +#define CONST +#endif /* defined(__STDC__) */ +#endif /* !defined(CONST) */ + + +#define MEM_INC 64 +#define SCREEN_INC 256 + +#define DISPOSE(p) free((char *)(p)) +#define NEW(T, c) \ + ((T *)malloc((unsigned int)(sizeof (T) * (c)))) +#define RENEW(p, T, c) \ + (p = (T *)realloc((char *)(p), (unsigned int)(sizeof (T) * (c)))) +#define COPYFROMTO(new, p, len) \ + (void)memcpy((char *)(new), (char *)(p), (int)(len)) + + +/* +** Variables and routines internal to this package. +*/ +extern int rl_eof; +extern int rl_erase; +extern int rl_intr; +extern int rl_kill; +extern int rl_quit; +extern char *rl_complete(); +extern int rl_list_possib(); +extern void rl_ttyset(); +extern void rl_add_slash(); + +#if !defined(HAVE_STDLIB) +extern char *getenv(); +extern char *malloc(); +extern char *realloc(); +extern char *memcpy(); +extern char *strcat(); +extern char *strchr(); +extern char *strrchr(); +extern char *strcpy(); +extern char *strdup(); +extern int strcmp(); +extern int strlen(); +extern int strncmp(); +#endif /* !defined(HAVE_STDLIB) */ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/sysunix.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/sysunix.c new file mode 100644 index 0000000..17227ea --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/sysunix.c @@ -0,0 +1,182 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Simmule Turner and Rich Salz. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * 1. The authors are not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * 4. This notice may not be removed or altered. + */ + + +/* +** Unix system-dependant routines for editline library. +*/ +#include "editline.h" + +#if defined(HAVE_TCGETATTR) +#include + +void +rl_ttyset(Reset) + int Reset; +{ + static struct termios old; + struct termios new; + + if (Reset == 0) { + (void)tcgetattr(0, &old); + rl_erase = old.c_cc[VERASE]; + rl_kill = old.c_cc[VKILL]; + rl_eof = old.c_cc[VEOF]; + rl_intr = old.c_cc[VINTR]; + rl_quit = old.c_cc[VQUIT]; + + new = old; + new.c_cc[VINTR] = -1; + new.c_cc[VQUIT] = -1; + new.c_lflag &= ~(ECHO | ICANON); + new.c_iflag &= ~(ISTRIP | INPCK); + new.c_cc[VMIN] = 1; + new.c_cc[VTIME] = 0; + (void)tcsetattr(0, TCSADRAIN, &new); + } + else + (void)tcsetattr(0, TCSADRAIN, &old); +} + +#else +#if defined(HAVE_TERMIO) +#include + +void +rl_ttyset(Reset) + int Reset; +{ + static struct termio old; + struct termio new; + + if (Reset == 0) { + (void)ioctl(0, TCGETA, &old); + rl_erase = old.c_cc[VERASE]; + rl_kill = old.c_cc[VKILL]; + rl_eof = old.c_cc[VEOF]; + rl_intr = old.c_cc[VINTR]; + rl_quit = old.c_cc[VQUIT]; + + new = old; + new.c_cc[VINTR] = -1; + new.c_cc[VQUIT] = -1; + new.c_lflag &= ~(ECHO | ICANON); + new.c_iflag &= ~(ISTRIP | INPCK); + new.c_cc[VMIN] = 1; + new.c_cc[VTIME] = 0; + (void)ioctl(0, TCSETAW, &new); + } + else + (void)ioctl(0, TCSETAW, &old); +} + +#else +#include + +void +rl_ttyset(Reset) + int Reset; +{ + static struct sgttyb old_sgttyb; + static struct tchars old_tchars; + struct sgttyb new_sgttyb; + struct tchars new_tchars; + + if (Reset == 0) { + (void)ioctl(0, TIOCGETP, &old_sgttyb); + rl_erase = old_sgttyb.sg_erase; + rl_kill = old_sgttyb.sg_kill; + + (void)ioctl(0, TIOCGETC, &old_tchars); + rl_eof = old_tchars.t_eofc; + rl_intr = old_tchars.t_intrc; + rl_quit = old_tchars.t_quitc; + + new_sgttyb = old_sgttyb; + new_sgttyb.sg_flags &= ~ECHO; + new_sgttyb.sg_flags |= RAW; +#if defined(PASS8) + new_sgttyb.sg_flags |= PASS8; +#endif /* defined(PASS8) */ + (void)ioctl(0, TIOCSETP, &new_sgttyb); + + new_tchars = old_tchars; + new_tchars.t_intrc = -1; + new_tchars.t_quitc = -1; + (void)ioctl(0, TIOCSETC, &new_tchars); + } + else { + (void)ioctl(0, TIOCSETP, &old_sgttyb); + (void)ioctl(0, TIOCSETC, &old_tchars); + } +} +#endif /* defined(HAVE_TERMIO) */ +#endif /* defined(HAVE_TCGETATTR) */ + +void +rl_add_slash(path, p) + char *path; + char *p; +{ + struct stat Sb; + + if (stat(path, &Sb) >= 0) + (void)strcat(p, S_ISDIR(Sb.st_mode) ? "/" : " "); +} + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/unix.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/unix.h new file mode 100644 index 0000000..c99b729 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/editline/unix.h @@ -0,0 +1,82 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Simmule Turner and Rich Salz. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * 1. The authors are not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * 4. This notice may not be removed or altered. + */ + + +/* +** Editline system header file for Unix. +*/ + +#define CRLF "\r\n" +#define FORWARD STATIC + +#include +#include + +#if defined(USE_DIRENT) +#include +typedef struct dirent DIRENTRY; +#else +#include +typedef struct direct DIRENTRY; +#endif /* defined(USE_DIRENT) */ + +#if !defined(S_ISDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif /* !defined(S_ISDIR) */ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/javascript-trace.d b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/javascript-trace.d new file mode 100644 index 0000000..258c6cd --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/javascript-trace.d @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Copyright (C) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * javascript provider probes + * + * function-entry (filename, classname, funcname) + * function-info (filename, classname, funcname, lineno, + * runfilename, runlineno) + * function-args (filename, classname, funcname, argc, argv, argv0, + * argv1, argv2, argv3, argv4) + * function-rval (filename, classname, funcname, lineno, rval, rval0) + * function-return (filename, classname, funcname) + * object-create-start (filename, classname) + * object-create (filename, classname, *object, rlineno) + * object-create-done (filename, classname) + * object-finalize (NULL, classname, *object) + * execute-start (filename, lineno) + * execute-done (filename, lineno) + */ + +provider javascript { + probe function__entry(char *, char *, char *); + probe function__info(char *, char *, char *, int, char *, int); + probe function__args(char *, char *, char *, int, void *, void *, void *, + void *, void *, void *); + probe function__rval(char *, char *, char *, int, void *, void *); + probe function__return(char *, char *, char *); + probe object__create__start(char *, char *); + probe object__create__done(char *, char *); + /* XXX must use unsigned longs here instead of uintptr_t for OS X + (Apple radar: 5194316 & 5565198) */ + probe object__create(char *, char *, unsigned long, int); + probe object__finalize(char *, char *, unsigned long); + probe execute__start(char *, int); + probe execute__done(char *, int); +}; + +/* +#pragma D attributes Unstable/Unstable/Common provider mozilla provider +#pragma D attributes Private/Private/Unknown provider mozilla module +#pragma D attributes Private/Private/Unknown provider mozilla function +#pragma D attributes Unstable/Unstable/Common provider mozilla name +#pragma D attributes Unstable/Unstable/Common provider mozilla args +*/ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jitstats.tbl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jitstats.tbl new file mode 100644 index 0000000..047d390 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jitstats.tbl @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=0 ft=C: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 22, 2008. + * + * The Initial Developer of the Original Code is + * Brian Crowder + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +JITSTAT(recorderStarted) +JITSTAT(recorderAborted) +JITSTAT(traceCompleted) +JITSTAT(sideExitIntoInterpreter) +JITSTAT(typeMapMismatchAtEntry) +JITSTAT(returnToDifferentLoopHeader) +JITSTAT(traceTriggered) +JITSTAT(globalShapeMismatchAtEntry) +JITSTAT(treesTrashed) +JITSTAT(slotPromoted) +JITSTAT(unstableLoopVariable) +JITSTAT(breakLoopExits) +JITSTAT(returnLoopExits) +JITSTAT(mergedLoopExits) +JITSTAT(noCompatInnerTrees) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js-config.h.in b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js-config.h.in new file mode 100644 index 0000000..600253e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js-config.h.in @@ -0,0 +1,55 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef js_config_h___ +#define js_config_h___ + +/* Definitions set at build time that affect SpiderMonkey's public API. + This header file is generated by the SpiderMonkey configure script, + and installed along with jsapi.h. */ + +/* Define to 1 if SpiderMonkey should support multi-threaded clients. */ +#undef JS_THREADSAFE + +/* Define to 1 if SpiderMonkey should support the ability to perform + entirely too much GC. */ +#undef JS_GC_ZEAL + +#endif /* js_config_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js-config.in b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js-config.in new file mode 100644 index 0000000..59b4719 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js-config.in @@ -0,0 +1,111 @@ +#!/bin/sh + +prefix='@prefix@' +mozilla_version='@MOZILLA_VERSION@' +LIBRARY_NAME='@LIBRARY_NAME@' +NSPR_CFLAGS='@NSPR_CFLAGS@' +JS_CONFIG_LIBS='@JS_CONFIG_LIBS@' +MOZ_JS_LIBS='@MOZ_JS_LIBS@' + +usage() +{ + cat <&2 +fi + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + ;; + --prefix) + echo_prefix=yes + ;; + --exec-prefix=*) + exec_prefix=$optarg + ;; + --exec-prefix) + echo_exec_prefix=yes + ;; + --includedir=*) + includedir=$optarg + ;; + --includedir) + echo_includedir=yes + ;; + --libdir=*) + libdir=$optarg + ;; + --libdir) + echo_libdir=yes + ;; + --version) + echo "$mozilla_version" + ;; + --cflags) + echo_cflags=yes + ;; + --libs) + echo_libs=yes + ;; + *) + usage 1 1>&2 + ;; + esac + shift +done + +# Set variables that may be dependent upon other variables +if test -z "$exec_prefix"; then + exec_prefix=@exec_prefix@ +fi +if test -z "$includedir"; then + includedir=@includedir@ +fi +if test -z "$libdir"; then + libdir=@libdir@ +fi + +if test "$echo_prefix" = "yes"; then + echo $prefix +fi + +if test "$echo_exec_prefix" = "yes"; then + echo $exec_prefix +fi + +if test "$echo_includedir" = "yes"; then + echo $includedir +fi + +if test "$echo_libdir" = "yes"; then + echo $libdir +fi + +if test "$echo_cflags" = "yes"; then + echo "-I$includedir/js $NSPR_CFLAGS" +fi + +if test "$echo_libs" = "yes"; then + echo "$MOZ_JS_LIBS $JS_CONFIG_LIBS" +fi diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.cpp new file mode 100644 index 0000000..9ffc847 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.cpp @@ -0,0 +1,4050 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS shell. + */ +#include "jsstddef.h" +#include +#include +#include +#include +#include +#include "jstypes.h" +#include "jsarena.h" +#include "jsutil.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsparse.h" +#include "jsscope.h" +#include "jsscript.h" + +#ifdef LIVECONNECT +#include "jsjava.h" +#endif + +#ifdef JSDEBUGGER +#include "jsdebug.h" +#ifdef JSDEBUGGER_JAVA_UI +#include "jsdjava.h" +#endif /* JSDEBUGGER_JAVA_UI */ +#ifdef JSDEBUGGER_C_UI +#include "jsdb.h" +#endif /* JSDEBUGGER_C_UI */ +#endif /* JSDEBUGGER */ + +#ifdef XP_UNIX +#include +#include +#include +#endif + +#if defined(XP_WIN) || defined(XP_OS2) +#include /* for isatty() */ +#endif + +typedef enum JSShellExitCode { + EXITCODE_RUNTIME_ERROR = 3, + EXITCODE_FILE_NOT_FOUND = 4, + EXITCODE_OUT_OF_MEMORY = 5 +} JSShellExitCode; + +size_t gStackChunkSize = 8192; + +/* Assume that we can not use more than 5e5 bytes of C stack by default. */ +static size_t gMaxStackSize = 500000; +static jsuword gStackBase; + +static size_t gScriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA; + +static JSBool gEnableBranchCallback = JS_FALSE; +static uint32 gBranchCount; +static uint32 gBranchLimit; + +int gExitCode = 0; +JSBool gQuitting = JS_FALSE; +FILE *gErrFile = NULL; +FILE *gOutFile = NULL; + +static JSBool reportWarnings = JS_TRUE; +static JSBool compileOnly = JS_FALSE; + +typedef enum JSShellErrNum { +#define MSG_DEF(name, number, count, exception, format) \ + name = number, +#include "jsshell.msg" +#undef MSG_DEF + JSShellErr_Limit +#undef MSGDEF +} JSShellErrNum; + +static const JSErrorFormatString * +my_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber); +static JSObject * +split_setup(JSContext *cx); + +#ifdef EDITLINE +JS_BEGIN_EXTERN_C +extern char *readline(const char *prompt); +extern void add_history(char *line); +JS_END_EXTERN_C +#endif + +static JSBool +GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) { +#ifdef EDITLINE + /* + * Use readline only if file is stdin, because there's no way to specify + * another handle. Are other filehandles interactive? + */ + if (file == stdin) { + char *linep = readline(prompt); + if (!linep) + return JS_FALSE; + if (linep[0] != '\0') + add_history(linep); + strcpy(bufp, linep); + JS_free(cx, linep); + bufp += strlen(bufp); + *bufp++ = '\n'; + *bufp = '\0'; + } else +#endif + { + char line[256]; + fprintf(gOutFile, prompt); + fflush(gOutFile); + if (!fgets(line, sizeof line, file)) + return JS_FALSE; + strcpy(bufp, line); + } + return JS_TRUE; +} + +static JSBool +my_BranchCallback(JSContext *cx, JSScript *script) +{ + if (++gBranchCount == gBranchLimit) { + if (script) { + if (script->filename) + fprintf(gErrFile, "%s:", script->filename); + fprintf(gErrFile, "%u: script branch callback (%u callbacks)\n", + script->lineno, gBranchLimit); + } else { + fprintf(gErrFile, "native branch callback (%u callbacks)\n", + gBranchLimit); + } + gBranchCount = 0; + return JS_FALSE; + } +#ifdef JS_THREADSAFE + if ((gBranchCount & 0xff) == 1) { +#endif + if ((gBranchCount & 0x3fff) == 1) + JS_MaybeGC(cx); +#ifdef JS_THREADSAFE + else + JS_YieldRequest(cx); + } +#endif + return JS_TRUE; +} + +static void +SetContextOptions(JSContext *cx) +{ + jsuword stackLimit; + + if (gMaxStackSize == 0) { + /* + * Disable checking for stack overflow if limit is zero. + */ + stackLimit = 0; + } else { +#if JS_STACK_GROWTH_DIRECTION > 0 + stackLimit = gStackBase + gMaxStackSize; +#else + stackLimit = gStackBase - gMaxStackSize; +#endif + } + JS_SetThreadStackLimit(cx, stackLimit); + JS_SetScriptStackQuota(cx, gScriptStackQuota); + if (gEnableBranchCallback) { + JS_SetBranchCallback(cx, my_BranchCallback); + JS_ToggleOptions(cx, JSOPTION_NATIVE_BRANCH_CALLBACK); + } +} + +static void +Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY) +{ + JSBool ok, hitEOF; + JSScript *script; + jsval result; + JSString *str; + char buffer[4096]; + char *bufp; + int lineno; + int startline; + FILE *file; + uint32 oldopts; + + if (forceTTY || !filename || strcmp(filename, "-") == 0) { + file = stdin; + } else { + file = fopen(filename, "r"); + if (!file) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, + JSSMSG_CANT_OPEN, filename, strerror(errno)); + gExitCode = EXITCODE_FILE_NOT_FOUND; + return; + } + } + + SetContextOptions(cx); + + if (!forceTTY && !isatty(fileno(file))) { + /* + * It's not interactive - just execute it. + * + * Support the UNIX #! shell hack; gobble the first line if it starts + * with '#'. TODO - this isn't quite compatible with sharp variables, + * as a legal js program (using sharp variables) might start with '#'. + * But that would require multi-character lookahead. + */ + int ch = fgetc(file); + if (ch == '#') { + while((ch = fgetc(file)) != EOF) { + if (ch == '\n' || ch == '\r') + break; + } + } + ungetc(ch, file); + + oldopts = JS_GetOptions(cx); + JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL); + script = JS_CompileFileHandle(cx, obj, filename, file); + JS_SetOptions(cx, oldopts); + if (script) { + if (!compileOnly) + (void)JS_ExecuteScript(cx, obj, script, NULL); + JS_DestroyScript(cx, script); + } + + if (file != stdin) + fclose(file); + return; + } + + /* It's an interactive filehandle; drop into read-eval-print loop. */ + lineno = 1; + hitEOF = JS_FALSE; + do { + bufp = buffer; + *bufp = '\0'; + + /* + * Accumulate lines until we get a 'compilable unit' - one that either + * generates an error (before running out of source) or that compiles + * cleanly. This should be whenever we get a complete statement that + * coincides with the end of a line. + */ + startline = lineno; + do { + if (!GetLine(cx, bufp, file, startline == lineno ? "js> " : "")) { + hitEOF = JS_TRUE; + break; + } + bufp += strlen(bufp); + lineno++; + } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer))); + + /* Clear any pending exception from previous failed compiles. */ + JS_ClearPendingException(cx); + script = JS_CompileScript(cx, obj, buffer, strlen(buffer), "typein", + startline); + if (script) { + if (!compileOnly) { + ok = JS_ExecuteScript(cx, obj, script, &result); + if (ok && !JSVAL_IS_VOID(result)) { + str = JS_ValueToString(cx, result); + if (str) + fprintf(gOutFile, "%s\n", JS_GetStringBytes(str)); + else + ok = JS_FALSE; + } + } + JS_DestroyScript(cx, script); + } + } while (!hitEOF && !gQuitting); + fprintf(gOutFile, "\n"); + if (file != stdin) + fclose(file); + return; +} + +static int +usage(void) +{ + fprintf(gErrFile, "%s\n", JS_GetImplementationVersion()); + fprintf(gErrFile, "usage: js [-zKPswWxCi] [-b branchlimit] [-c stackchunksize] [-o option] [-v version] [-f scriptfile] [-e script] [-S maxstacksize] " +#ifdef JS_GC_ZEAL +"[-Z gczeal] " +#endif +"[scriptfile] [scriptarg...]\n"); + return 2; +} + +static struct { + const char *name; + uint32 flag; +} js_options[] = { + {"strict", JSOPTION_STRICT}, + {"werror", JSOPTION_WERROR}, + {"atline", JSOPTION_ATLINE}, + {"xml", JSOPTION_XML}, + {"relimit", JSOPTION_RELIMIT}, + {"anonfunfix", JSOPTION_ANONFUNFIX}, + {"jit", JSOPTION_JIT}, + {NULL, 0} +}; + +extern JSClass global_class; + +static int +ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc) +{ + int i, j, length; + JSObject *argsObj; + char *filename = NULL; + JSBool isInteractive = JS_TRUE; + JSBool forceTTY = JS_FALSE; + + /* + * Scan past all optional arguments so we can create the arguments object + * before processing any -f options, which must interleave properly with + * -v and -w options. This requires two passes, and without getopt, we'll + * have to keep the option logic here and in the second for loop in sync. + */ + for (i = 0; i < argc; i++) { + if (argv[i][0] != '-' || argv[i][1] == '\0') { + ++i; + break; + } + switch (argv[i][1]) { + case 'b': + case 'c': + case 'f': + case 'e': + case 'v': + case 'S': +#ifdef JS_GC_ZEAL + case 'Z': +#endif + ++i; + break; + default:; + } + } + + /* + * Create arguments early and define it to root it, so it's safe from any + * GC calls nested below, and so it is available to -f arguments. + */ + argsObj = JS_NewArrayObject(cx, 0, NULL); + if (!argsObj) + return 1; + if (!JS_DefineProperty(cx, obj, "arguments", OBJECT_TO_JSVAL(argsObj), + NULL, NULL, 0)) { + return 1; + } + + length = argc - i; + for (j = 0; j < length; j++) { + JSString *str = JS_NewStringCopyZ(cx, argv[i++]); + if (!str) + return 1; + if (!JS_DefineElement(cx, argsObj, j, STRING_TO_JSVAL(str), + NULL, NULL, JSPROP_ENUMERATE)) { + return 1; + } + } + + for (i = 0; i < argc; i++) { + if (argv[i][0] != '-' || argv[i][1] == '\0') { + filename = argv[i++]; + isInteractive = JS_FALSE; + break; + } + + switch (argv[i][1]) { + case 'v': + if (++i == argc) + return usage(); + + JS_SetVersion(cx, (JSVersion) atoi(argv[i])); + break; + +#ifdef JS_GC_ZEAL + case 'Z': + if (++i == argc) + return usage(); + JS_SetGCZeal(cx, atoi(argv[i])); + break; +#endif + + case 'w': + reportWarnings = JS_TRUE; + break; + + case 'W': + reportWarnings = JS_FALSE; + break; + + case 's': + JS_ToggleOptions(cx, JSOPTION_STRICT); + break; + + case 'E': + JS_ToggleOptions(cx, JSOPTION_RELIMIT); + break; + + case 'x': + JS_ToggleOptions(cx, JSOPTION_XML); + break; + + case 'j': + JS_ToggleOptions(cx, JSOPTION_JIT); +#if defined(JS_TRACER) && defined(DEBUG) +extern struct JSClass jitstats_class; +extern void js_InitJITStatsClass(JSContext *cx, JSObject *glob); + js_InitJITStatsClass(cx, JS_GetGlobalObject(cx)); + JS_DefineObject(cx, JS_GetGlobalObject(cx), "tracemonkey", + &jitstats_class, NULL, 0); +#endif + break; + + case 'o': + if (++i == argc) + return usage(); + + for (j = 0; js_options[j].name; ++j) { + if (strcmp(js_options[j].name, argv[i]) == 0) { + JS_ToggleOptions(cx, js_options[j].flag); + break; + } + } + break; + + case 'P': + if (JS_GET_CLASS(cx, JS_GetPrototype(cx, obj)) != &global_class) { + JSObject *gobj; + + if (!JS_SealObject(cx, obj, JS_TRUE)) + return JS_FALSE; + gobj = JS_NewObject(cx, &global_class, NULL, NULL); + if (!gobj) + return JS_FALSE; + if (!JS_SetPrototype(cx, gobj, obj)) + return JS_FALSE; + JS_SetParent(cx, gobj, NULL); + JS_SetGlobalObject(cx, gobj); + obj = gobj; + } + break; + + case 'b': + gBranchLimit = atoi(argv[++i]); + gEnableBranchCallback = (gBranchLimit != 0); + break; + + case 'c': + /* set stack chunk size */ + gStackChunkSize = atoi(argv[++i]); + break; + + case 'f': + if (++i == argc) + return usage(); + + Process(cx, obj, argv[i], JS_FALSE); + + /* + * XXX: js -f foo.js should interpret foo.js and then + * drop into interactive mode, but that breaks the test + * harness. Just execute foo.js for now. + */ + isInteractive = JS_FALSE; + break; + + case 'e': + { + jsval rval; + + if (++i == argc) + return usage(); + + /* Pass a filename of -e to imitate PERL */ + JS_EvaluateScript(cx, obj, argv[i], strlen(argv[i]), + "-e", 1, &rval); + + isInteractive = JS_FALSE; + break; + + } + case 'C': + compileOnly = JS_TRUE; + isInteractive = JS_FALSE; + break; + + case 'i': + isInteractive = forceTTY = JS_TRUE; + break; + + case 'S': + if (++i == argc) + return usage(); + + /* Set maximum stack size. */ + gMaxStackSize = atoi(argv[i]); + break; + + case 'z': + obj = split_setup(cx); + if (!obj) + return gExitCode; + break; +#ifdef MOZ_SHARK + case 'k': + JS_ConnectShark(); + break; +#endif + default: + return usage(); + } + } + + if (filename || isInteractive) + Process(cx, obj, filename, forceTTY); + return gExitCode; +} + +static JSBool +Version(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if (argc > 0 && JSVAL_IS_INT(argv[0])) + *rval = INT_TO_JSVAL(JS_SetVersion(cx, (JSVersion) JSVAL_TO_INT(argv[0]))); + else + *rval = INT_TO_JSVAL(JS_GetVersion(cx)); + return JS_TRUE; +} + +static JSBool +Options(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + uint32 optset, flag; + uintN i, j, found; + JSString *str; + const char *opt; + char *names; + + optset = 0; + for (i = 0; i < argc; i++) { + str = JS_ValueToString(cx, argv[i]); + if (!str) + return JS_FALSE; + opt = JS_GetStringBytes(str); + for (j = 0; js_options[j].name; j++) { + if (strcmp(js_options[j].name, opt) == 0) { + optset |= js_options[j].flag; + break; + } + } + } + optset = JS_ToggleOptions(cx, optset); + + names = NULL; + found = 0; + while (optset != 0) { + flag = optset; + optset &= optset - 1; + flag &= ~optset; + for (j = 0; js_options[j].name; j++) { + if (js_options[j].flag == flag) { + names = JS_sprintf_append(names, "%s%s", + names ? "," : "", js_options[j].name); + found++; + break; + } + } + } + if (!found) + names = strdup(""); + if (!names) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + str = JS_NewString(cx, names, strlen(names)); + if (!str) { + free(names); + return JS_FALSE; + } + *rval = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + uintN i; + JSString *str; + const char *filename; + JSScript *script; + JSBool ok; + uint32 oldopts; + + for (i = 0; i < argc; i++) { + str = JS_ValueToString(cx, argv[i]); + if (!str) + return JS_FALSE; + argv[i] = STRING_TO_JSVAL(str); + filename = JS_GetStringBytes(str); + errno = 0; + oldopts = JS_GetOptions(cx); + JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL); + script = JS_CompileFile(cx, obj, filename); + JS_SetOptions(cx, oldopts); + if (!script) { + ok = JS_FALSE; + } else { + ok = !compileOnly + ? JS_ExecuteScript(cx, obj, script, NULL) + : JS_TRUE; + JS_DestroyScript(cx, script); + } + if (!ok) + return JS_FALSE; + } + + return JS_TRUE; +} + +/* + * function readline() + * Provides a hook for scripts to read a line from stdin. + */ +static JSBool +ReadLine(JSContext *cx, uintN argc, jsval *vp) +{ +#define BUFSIZE 256 + FILE *from; + char *buf, *tmp; + size_t bufsize, buflength, gotlength; + JSBool sawNewline; + JSString *str; + + from = stdin; + buflength = 0; + bufsize = BUFSIZE; + buf = (char *) JS_malloc(cx, bufsize); + if (!buf) + return JS_FALSE; + + sawNewline = JS_FALSE; + while ((gotlength = + js_fgets(buf + buflength, bufsize - buflength, from)) > 0) { + buflength += gotlength; + + /* Are we done? */ + if (buf[buflength - 1] == '\n') { + buf[buflength - 1] = '\0'; + sawNewline = JS_TRUE; + break; + } else if (buflength < bufsize - 1) { + break; + } + + /* Else, grow our buffer for another pass. */ + bufsize *= 2; + if (bufsize > buflength) { + tmp = (char *) JS_realloc(cx, buf, bufsize); + } else { + JS_ReportOutOfMemory(cx); + tmp = NULL; + } + + if (!tmp) { + JS_free(cx, buf); + return JS_FALSE; + } + + buf = tmp; + } + + /* Treat the empty string specially. */ + if (buflength == 0) { + *vp = feof(from) ? JSVAL_NULL : JS_GetEmptyStringValue(cx); + JS_free(cx, buf); + return JS_TRUE; + } + + /* Shrink the buffer to the real size. */ + tmp = (char *) JS_realloc(cx, buf, buflength); + if (!tmp) { + JS_free(cx, buf); + return JS_FALSE; + } + + buf = tmp; + + /* + * Turn buf into a JSString. Note that buflength includes the trailing null + * character. + */ + str = JS_NewString(cx, buf, sawNewline ? buflength - 1 : buflength); + if (!str) { + JS_free(cx, buf); + return JS_FALSE; + } + + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +#ifdef JS_TRACER +static jsval JS_FASTCALL +Print_tn(JSContext *cx, JSString *str) +{ + char *bytes = JS_EncodeString(cx, str); + if (!bytes) + return JSVAL_ERROR_COOKIE; + fprintf(gOutFile, "%s\n", bytes); + JS_free(cx, bytes); + fflush(gOutFile); + return JSVAL_VOID; +} +#endif + +static JSBool +Print(JSContext *cx, uintN argc, jsval *vp) +{ + jsval *argv; + uintN i; + JSString *str; + char *bytes; + + argv = JS_ARGV(cx, vp); + for (i = 0; i < argc; i++) { + str = JS_ValueToString(cx, argv[i]); + if (!str) + return JS_FALSE; + bytes = JS_EncodeString(cx, str); + if (!bytes) + return JS_FALSE; + fprintf(gOutFile, "%s%s", i ? " " : "", bytes); + JS_free(cx, bytes); + } + + fputc('\n', gOutFile); + fflush(gOutFile); + + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; +} + +static JSBool +Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +static JSBool +Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ +#ifdef LIVECONNECT + JSJ_SimpleShutdown(); +#endif + + JS_ConvertArguments(cx, argc, argv,"/ i", &gExitCode); + + gQuitting = JS_TRUE; + return JS_FALSE; +} + +static JSBool +GC(JSContext *cx, uintN argc, jsval *vp) +{ + JSRuntime *rt; + uint32 preBytes; + + rt = cx->runtime; + preBytes = rt->gcBytes; + JS_GC(cx); + + fprintf(gOutFile, "before %lu, after %lu, break %08lx\n", + (unsigned long)preBytes, (unsigned long)rt->gcBytes, +#ifdef XP_UNIX + (unsigned long)sbrk(0) +#else + 0 +#endif + ); +#ifdef JS_GCMETER + js_DumpGCStats(rt, stdout); +#endif + *vp = JSVAL_VOID; + return JS_TRUE; +} + +static JSBool +GCParameter(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + const char *paramName; + JSGCParamKey param; + uint32 value; + + if (argc == 0) { + str = JS_ValueToString(cx, JSVAL_VOID); + JS_ASSERT(str); + } else { + str = JS_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + vp[2] = STRING_TO_JSVAL(str); + } + paramName = JS_GetStringBytes(str); + if (!paramName) + return JS_FALSE; + if (strcmp(paramName, "maxBytes") == 0) { + param = JSGC_MAX_BYTES; + } else if (strcmp(paramName, "maxMallocBytes") == 0) { + param = JSGC_MAX_MALLOC_BYTES; + } else { + JS_ReportError(cx, + "the first argument argument must be either maxBytes " + "or maxMallocBytes"); + return JS_FALSE; + } + + if (!JS_ValueToECMAUint32(cx, argc < 2 ? JSVAL_VOID : vp[3], &value)) + return JS_FALSE; + if (value == 0) { + JS_ReportError(cx, + "the second argument must be convertable to uint32 with " + "non-zero value"); + return JS_FALSE; + } + JS_SetGCParameter(cx->runtime, param, value); + *vp = JSVAL_VOID; + return JS_TRUE; +} + +#ifdef JS_GC_ZEAL +static JSBool +GCZeal(JSContext *cx, uintN argc, jsval *vp) +{ + uint32 zeal; + + if (!JS_ValueToECMAUint32(cx, argc == 0 ? JSVAL_VOID : vp[2], &zeal)) + return JS_FALSE; + JS_SetGCZeal(cx, (uint8)zeal); + *vp = JSVAL_VOID; + return JS_TRUE; +} +#endif /* JS_GC_ZEAL */ + +typedef struct JSCountHeapNode JSCountHeapNode; + +struct JSCountHeapNode { + void *thing; + int32 kind; + JSCountHeapNode *next; +}; + +typedef struct JSCountHeapTracer { + JSTracer base; + JSDHashTable visited; + JSBool ok; + JSCountHeapNode *traceList; + JSCountHeapNode *recycleList; +} JSCountHeapTracer; + +static void +CountHeapNotify(JSTracer *trc, void *thing, uint32 kind) +{ + JSCountHeapTracer *countTracer; + JSDHashEntryStub *entry; + JSCountHeapNode *node; + + JS_ASSERT(trc->callback == CountHeapNotify); + countTracer = (JSCountHeapTracer *)trc; + if (!countTracer->ok) + return; + + entry = (JSDHashEntryStub *) + JS_DHashTableOperate(&countTracer->visited, thing, JS_DHASH_ADD); + if (!entry) { + JS_ReportOutOfMemory(trc->context); + countTracer->ok = JS_FALSE; + return; + } + if (entry->key) + return; + entry->key = thing; + + node = countTracer->recycleList; + if (node) { + countTracer->recycleList = node->next; + } else { + node = (JSCountHeapNode *) JS_malloc(trc->context, sizeof *node); + if (!node) { + countTracer->ok = JS_FALSE; + return; + } + } + node->thing = thing; + node->kind = kind; + node->next = countTracer->traceList; + countTracer->traceList = node; +} + +static JSBool +CountHeap(JSContext *cx, uintN argc, jsval *vp) +{ + void* startThing; + int32 startTraceKind; + jsval v; + int32 traceKind, i; + JSString *str; + char *bytes; + JSCountHeapTracer countTracer; + JSCountHeapNode *node; + size_t counter; + + static const struct { + const char *name; + int32 kind; + } traceKindNames[] = { + { "all", -1 }, + { "object", JSTRACE_OBJECT }, + { "double", JSTRACE_DOUBLE }, + { "string", JSTRACE_STRING }, +#if JS_HAS_XML_SUPPORT + { "xml", JSTRACE_XML }, +#endif + }; + + startThing = NULL; + startTraceKind = 0; + if (argc > 0) { + v = JS_ARGV(cx, vp)[0]; + if (JSVAL_IS_TRACEABLE(v)) { + startThing = JSVAL_TO_TRACEABLE(v); + startTraceKind = JSVAL_TRACE_KIND(v); + } else if (v != JSVAL_NULL) { + JS_ReportError(cx, + "the first argument is not null or a heap-allocated " + "thing"); + return JS_FALSE; + } + } + + traceKind = -1; + if (argc > 1) { + str = JS_ValueToString(cx, JS_ARGV(cx, vp)[1]); + if (!str) + return JS_FALSE; + bytes = JS_GetStringBytes(str); + if (!bytes) + return JS_FALSE; + for (i = 0; ;) { + if (strcmp(bytes, traceKindNames[i].name) == 0) { + traceKind = traceKindNames[i].kind; + break; + } + if (++i == JS_ARRAY_LENGTH(traceKindNames)) { + JS_ReportError(cx, "trace kind name '%s' is unknown", bytes); + return JS_FALSE; + } + } + } + + JS_TRACER_INIT(&countTracer.base, cx, CountHeapNotify); + if (!JS_DHashTableInit(&countTracer.visited, JS_DHashGetStubOps(), + NULL, sizeof(JSDHashEntryStub), + JS_DHASH_DEFAULT_CAPACITY(100))) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + countTracer.ok = JS_TRUE; + countTracer.traceList = NULL; + countTracer.recycleList = NULL; + + if (!startThing) { + JS_TraceRuntime(&countTracer.base); + } else { + JS_SET_TRACING_NAME(&countTracer.base, "root"); + JS_CallTracer(&countTracer.base, startThing, startTraceKind); + } + + counter = 0; + while ((node = countTracer.traceList) != NULL) { + if (traceKind == -1 || node->kind == traceKind) + counter++; + countTracer.traceList = node->next; + node->next = countTracer.recycleList; + countTracer.recycleList = node; + JS_TraceChildren(&countTracer.base, node->thing, node->kind); + } + while ((node = countTracer.recycleList) != NULL) { + countTracer.recycleList = node->next; + JS_free(cx, node); + } + JS_DHashTableFinish(&countTracer.visited); + + return countTracer.ok && JS_NewNumberValue(cx, (jsdouble) counter, vp); +} + +static JSScript * +ValueToScript(JSContext *cx, jsval v) +{ + JSScript *script; + JSFunction *fun; + + if (!JSVAL_IS_PRIMITIVE(v) && + JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass) { + script = (JSScript *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + } else { + fun = JS_ValueToFunction(cx, v); + if (!fun) + return NULL; + script = FUN_SCRIPT(fun); + } + + if (!script) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, + JSSMSG_SCRIPTS_ONLY); + } + + return script; +} + +static JSBool +GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp, + int32 *ip) +{ + jsval v; + uintN intarg; + JSScript *script; + + *scriptp = cx->fp->down->script; + *ip = 0; + if (argc != 0) { + v = argv[0]; + intarg = 0; + if (!JSVAL_IS_PRIMITIVE(v) && + (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass || + JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass)) { + script = ValueToScript(cx, v); + if (!script) + return JS_FALSE; + *scriptp = script; + intarg++; + } + if (argc > intarg) { + if (!JS_ValueToInt32(cx, argv[intarg], ip)) + return JS_FALSE; + } + } + return JS_TRUE; +} + +static JSTrapStatus +TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, + void *closure) +{ + JSString *str; + JSStackFrame *caller; + + str = (JSString *) closure; + caller = JS_GetScriptedCaller(cx, NULL); + if (!JS_EvaluateScript(cx, caller->scopeChain, + JS_GetStringBytes(str), JS_GetStringLength(str), + caller->script->filename, caller->script->lineno, + rval)) { + return JSTRAP_ERROR; + } + if (!JSVAL_IS_VOID(*rval)) + return JSTRAP_RETURN; + return JSTRAP_CONTINUE; +} + +static JSBool +Trap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSString *str; + JSScript *script; + int32 i; + + if (argc == 0) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_TRAP_USAGE); + return JS_FALSE; + } + argc--; + str = JS_ValueToString(cx, argv[argc]); + if (!str) + return JS_FALSE; + argv[argc] = STRING_TO_JSVAL(str); + if (!GetTrapArgs(cx, argc, argv, &script, &i)) + return JS_FALSE; + return JS_SetTrap(cx, script, script->code + i, TrapHandler, str); +} + +static JSBool +Untrap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSScript *script; + int32 i; + + if (!GetTrapArgs(cx, argc, argv, &script, &i)) + return JS_FALSE; + JS_ClearTrap(cx, script, script->code + i, NULL, NULL); + return JS_TRUE; +} + +static JSBool +LineToPC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSScript *script; + int32 i; + uintN lineno; + jsbytecode *pc; + + if (argc == 0) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE); + return JS_FALSE; + } + script = cx->fp->down->script; + if (!GetTrapArgs(cx, argc, argv, &script, &i)) + return JS_FALSE; + lineno = (i == 0) ? script->lineno : (uintN)i; + pc = JS_LineNumberToPC(cx, script, lineno); + if (!pc) + return JS_FALSE; + *rval = INT_TO_JSVAL(PTRDIFF(pc, script->code, jsbytecode)); + return JS_TRUE; +} + +static JSBool +PCToLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSScript *script; + int32 i; + uintN lineno; + + if (!GetTrapArgs(cx, argc, argv, &script, &i)) + return JS_FALSE; + lineno = JS_PCToLineNumber(cx, script, script->code + i); + if (!lineno) + return JS_FALSE; + *rval = INT_TO_JSVAL(lineno); + return JS_TRUE; +} + +#ifdef DEBUG + +static void +UpdateSwitchTableBounds(JSScript *script, uintN offset, + uintN *start, uintN *end) +{ + jsbytecode *pc; + JSOp op; + ptrdiff_t jmplen; + jsint low, high, n; + + pc = script->code + offset; + op = (JSOp) *pc; + switch (op) { + case JSOP_TABLESWITCHX: + jmplen = JUMPX_OFFSET_LEN; + goto jump_table; + case JSOP_TABLESWITCH: + jmplen = JUMP_OFFSET_LEN; + jump_table: + pc += jmplen; + low = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + n = high - low + 1; + break; + + case JSOP_LOOKUPSWITCHX: + jmplen = JUMPX_OFFSET_LEN; + goto lookup_table; + case JSOP_LOOKUPSWITCH: + jmplen = JUMP_OFFSET_LEN; + lookup_table: + pc += jmplen; + n = GET_INDEX(pc); + pc += INDEX_LEN; + jmplen += JUMP_OFFSET_LEN; + break; + + default: + /* [condswitch] switch does not have any jump or lookup tables. */ + JS_ASSERT(op == JSOP_CONDSWITCH); + return; + } + + *start = (uintN)(pc - script->code); + *end = *start + (uintN)(n * jmplen); +} + +static void +SrcNotes(JSContext *cx, JSScript *script) +{ + uintN offset, delta, caseOff, switchTableStart, switchTableEnd; + jssrcnote *notes, *sn; + JSSrcNoteType type; + const char *name; + uint32 index; + JSAtom *atom; + JSString *str; + + fprintf(gOutFile, "\nSource notes:\n"); + offset = 0; + notes = SCRIPT_NOTES(script); + switchTableEnd = switchTableStart = 0; + for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + delta = SN_DELTA(sn); + offset += delta; + type = (JSSrcNoteType) SN_TYPE(sn); + name = js_SrcNoteSpec[type].name; + if (type == SRC_LABEL) { + /* Check if the source note is for a switch case. */ + if (switchTableStart <= offset && offset < switchTableEnd) { + name = "case"; + } else { + JS_ASSERT(script->code[offset] == JSOP_NOP); + } + } + fprintf(gOutFile, "%3u: %5u [%4u] %-8s", + (uintN) PTRDIFF(sn, notes, jssrcnote), offset, delta, name); + switch (type) { + case SRC_SETLINE: + fprintf(gOutFile, " lineno %u", (uintN) js_GetSrcNoteOffset(sn, 0)); + break; + case SRC_FOR: + fprintf(gOutFile, " cond %u update %u tail %u", + (uintN) js_GetSrcNoteOffset(sn, 0), + (uintN) js_GetSrcNoteOffset(sn, 1), + (uintN) js_GetSrcNoteOffset(sn, 2)); + break; + case SRC_IF_ELSE: + fprintf(gOutFile, " else %u elseif %u", + (uintN) js_GetSrcNoteOffset(sn, 0), + (uintN) js_GetSrcNoteOffset(sn, 1)); + break; + case SRC_COND: + case SRC_WHILE: + case SRC_PCBASE: + case SRC_PCDELTA: + case SRC_DECL: + case SRC_BRACE: + fprintf(gOutFile, " offset %u", (uintN) js_GetSrcNoteOffset(sn, 0)); + break; + case SRC_LABEL: + case SRC_LABELBRACE: + case SRC_BREAK2LABEL: + case SRC_CONT2LABEL: + index = js_GetSrcNoteOffset(sn, 0); + JS_GET_SCRIPT_ATOM(script, index, atom); + JS_ASSERT(ATOM_IS_STRING(atom)); + str = ATOM_TO_STRING(atom); + fprintf(gOutFile, " atom %u (", index); + js_FileEscapedString(gOutFile, str, 0); + putc(')', gOutFile); + break; + case SRC_FUNCDEF: { + const char *bytes; + JSObject *obj; + JSFunction *fun; + + index = js_GetSrcNoteOffset(sn, 0); + JS_GET_SCRIPT_OBJECT(script, index, obj); + fun = (JSFunction *) JS_GetPrivate(cx, obj); + str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT); + bytes = str ? JS_GetStringBytes(str) : "N/A"; + fprintf(gOutFile, " function %u (%s)", index, bytes); + break; + } + case SRC_SWITCH: + fprintf(gOutFile, " length %u", (uintN) js_GetSrcNoteOffset(sn, 0)); + caseOff = (uintN) js_GetSrcNoteOffset(sn, 1); + if (caseOff) + fprintf(gOutFile, " first case offset %u", caseOff); + UpdateSwitchTableBounds(script, offset, + &switchTableStart, &switchTableEnd); + break; + case SRC_CATCH: + delta = (uintN) js_GetSrcNoteOffset(sn, 0); + if (delta) { + if (script->main[offset] == JSOP_LEAVEBLOCK) + fprintf(gOutFile, " stack depth %u", delta); + else + fprintf(gOutFile, " guard delta %u", delta); + } + break; + default:; + } + fputc('\n', gOutFile); + } +} + +static JSBool +Notes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + uintN i; + JSScript *script; + + for (i = 0; i < argc; i++) { + script = ValueToScript(cx, argv[i]); + if (!script) + continue; + + SrcNotes(cx, script); + } + return JS_TRUE; +} + +JS_STATIC_ASSERT(JSTRY_CATCH == 0); +JS_STATIC_ASSERT(JSTRY_FINALLY == 1); +JS_STATIC_ASSERT(JSTRY_ITER == 2); + +static const char* const TryNoteNames[] = { "catch", "finally", "iter" }; + +static JSBool +TryNotes(JSContext *cx, JSScript *script) +{ + JSTryNote *tn, *tnlimit; + + if (script->trynotesOffset == 0) + return JS_TRUE; + + tn = JS_SCRIPT_TRYNOTES(script)->vector; + tnlimit = tn + JS_SCRIPT_TRYNOTES(script)->length; + fprintf(gOutFile, "\nException table:\n" + "kind stack start end\n"); + do { + JS_ASSERT(tn->kind < JS_ARRAY_LENGTH(TryNoteNames)); + fprintf(gOutFile, " %-7s %6u %8u %8u\n", + TryNoteNames[tn->kind], tn->stackDepth, + tn->start, tn->start + tn->length); + } while (++tn != tnlimit); + return JS_TRUE; +} + +static JSBool +Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSBool lines; + uintN i; + JSScript *script; + + if (argc > 0 && + JSVAL_IS_STRING(argv[0]) && + !strcmp(JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), "-l")) { + lines = JS_TRUE; + argv++, argc--; + } else { + lines = JS_FALSE; + } + for (i = 0; i < argc; i++) { + script = ValueToScript(cx, argv[i]); + if (!script) + return JS_FALSE; + if (VALUE_IS_FUNCTION(cx, argv[i])) { + JSFunction *fun = JS_ValueToFunction(cx, argv[i]); + if (fun && (fun->flags & JSFUN_FLAGS_MASK)) { + uint16 flags = fun->flags; + fputs("flags:", stdout); + +#define SHOW_FLAG(flag) if (flags & JSFUN_##flag) fputs(" " #flag, stdout); + + SHOW_FLAG(LAMBDA); + SHOW_FLAG(SETTER); + SHOW_FLAG(GETTER); + SHOW_FLAG(BOUND_METHOD); + SHOW_FLAG(HEAVYWEIGHT); + SHOW_FLAG(THISP_STRING); + SHOW_FLAG(THISP_NUMBER); + SHOW_FLAG(THISP_BOOLEAN); + SHOW_FLAG(EXPR_CLOSURE); + SHOW_FLAG(INTERPRETED); + +#undef SHOW_FLAG + putchar('\n'); + } + } + + if (!js_Disassemble(cx, script, lines, stdout)) + return JS_FALSE; + SrcNotes(cx, script); + TryNotes(cx, script); + } + return JS_TRUE; +} + +static JSBool +DisassFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSString *str; + const char *filename; + JSScript *script; + JSBool ok; + uint32 oldopts; + + if (!argc) + return JS_TRUE; + + str = JS_ValueToString(cx, argv[0]); + if (!str) + return JS_FALSE; + argv[0] = STRING_TO_JSVAL(str); + + filename = JS_GetStringBytes(str); + oldopts = JS_GetOptions(cx); + JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL); + script = JS_CompileFile(cx, obj, filename); + JS_SetOptions(cx, oldopts); + if (!script) + return JS_FALSE; + + obj = JS_NewScriptObject(cx, script); + if (!obj) + return JS_FALSE; + + *rval = OBJECT_TO_JSVAL(obj); /* I like to root it, root it. */ + ok = Disassemble(cx, obj, 1, rval, rval); /* gross, but works! */ + *rval = JSVAL_VOID; + + return ok; +} + +static JSBool +DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ +#define LINE_BUF_LEN 512 + uintN i, len, line1, line2, bupline; + JSScript *script; + FILE *file; + char linebuf[LINE_BUF_LEN]; + jsbytecode *pc, *end; + JSBool ok; + static char sep[] = ";-------------------------"; + + ok = JS_TRUE; + for (i = 0; ok && i < argc; i++) { + script = ValueToScript(cx, argv[i]); + if (!script) + return JS_FALSE; + + if (!script->filename) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, + JSSMSG_FILE_SCRIPTS_ONLY); + return JS_FALSE; + } + + file = fopen(script->filename, "r"); + if (!file) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, + JSSMSG_CANT_OPEN, script->filename, + strerror(errno)); + return JS_FALSE; + } + + pc = script->code; + end = pc + script->length; + + /* burn the leading lines */ + line2 = JS_PCToLineNumber(cx, script, pc); + for (line1 = 0; line1 < line2 - 1; line1++) + fgets(linebuf, LINE_BUF_LEN, file); + + bupline = 0; + while (pc < end) { + line2 = JS_PCToLineNumber(cx, script, pc); + + if (line2 < line1) { + if (bupline != line2) { + bupline = line2; + fprintf(gOutFile, "%s %3u: BACKUP\n", sep, line2); + } + } else { + if (bupline && line1 == line2) + fprintf(gOutFile, "%s %3u: RESTORE\n", sep, line2); + bupline = 0; + while (line1 < line2) { + if (!fgets(linebuf, LINE_BUF_LEN, file)) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, + JSSMSG_UNEXPECTED_EOF, + script->filename); + ok = JS_FALSE; + goto bail; + } + line1++; + fprintf(gOutFile, "%s %3u: %s", sep, line1, linebuf); + } + } + + len = js_Disassemble1(cx, script, pc, + PTRDIFF(pc, script->code, jsbytecode), + JS_TRUE, stdout); + if (!len) { + ok = JS_FALSE; + goto bail; + } + pc += len; + } + + bail: + fclose(file); + } + return ok; +#undef LINE_BUF_LEN +} + +static JSBool +Tracing(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSBool bval; + JSString *str; + +#if JS_THREADED_INTERP + JS_ReportError(cx, "tracing not supported in JS_THREADED_INTERP builds"); + return JS_FALSE; +#else + if (argc == 0) { + *rval = BOOLEAN_TO_JSVAL(cx->tracefp != 0); + return JS_TRUE; + } + + switch (JS_TypeOfValue(cx, argv[0])) { + case JSTYPE_NUMBER: + bval = JSVAL_IS_INT(argv[0]) + ? JSVAL_TO_INT(argv[0]) + : (jsint) *JSVAL_TO_DOUBLE(argv[0]); + break; + case JSTYPE_BOOLEAN: + bval = JSVAL_TO_BOOLEAN(argv[0]); + break; + default: + str = JS_ValueToString(cx, argv[0]); + if (!str) + return JS_FALSE; + JS_ReportError(cx, "tracing: illegal argument %s", + JS_GetStringBytes(str)); + return JS_FALSE; + } + cx->tracefp = bval ? stderr : NULL; + return JS_TRUE; +#endif +} + +static void +DumpScope(JSContext *cx, JSObject *obj, FILE *fp) +{ + uintN i; + JSScope *scope; + JSScopeProperty *sprop; + jsval v; + JSString *str; + + i = 0; + scope = OBJ_SCOPE(obj); + for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { + if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop)) + continue; + fprintf(fp, "%3u %p ", i, (void *)sprop); + + v = ID_TO_VALUE(sprop->id); + if (JSID_IS_INT(sprop->id)) { + fprintf(fp, "[%ld]", (long)JSVAL_TO_INT(v)); + } else { + if (JSID_IS_ATOM(sprop->id)) { + str = JSVAL_TO_STRING(v); + } else { + JS_ASSERT(JSID_IS_OBJECT(sprop->id)); + str = js_ValueToString(cx, v); + fputs("object ", fp); + } + if (!str) + fputs("", fp); + else + js_FileEscapedString(fp, str, '"'); + } +#define DUMP_ATTR(name) if (sprop->attrs & JSPROP_##name) fputs(" " #name, fp) + DUMP_ATTR(ENUMERATE); + DUMP_ATTR(READONLY); + DUMP_ATTR(PERMANENT); + DUMP_ATTR(GETTER); + DUMP_ATTR(SETTER); +#undef DUMP_ATTR + + fprintf(fp, " slot %lu flags %x shortid %d\n", + (unsigned long)sprop->slot, sprop->flags, sprop->shortid); + } +} + +static JSBool +DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + uintN i; + JSString *str; + const char *bytes; + jsid id; + JSObject *obj2; + JSProperty *prop; + jsval value; + + for (i = 0; i < argc; i++) { + str = JS_ValueToString(cx, argv[i]); + if (!str) + return JS_FALSE; + argv[i] = STRING_TO_JSVAL(str); + bytes = JS_GetStringBytes(str); + if (strcmp(bytes, "arena") == 0) { +#ifdef JS_ARENAMETER + JS_DumpArenaStats(stdout); +#endif + } else if (strcmp(bytes, "atom") == 0) { + js_DumpAtoms(cx, gOutFile); + } else if (strcmp(bytes, "global") == 0) { + DumpScope(cx, cx->globalObject, stdout); + } else { + if (!JS_ValueToId(cx, STRING_TO_JSVAL(str), &id)) + return JS_FALSE; + if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) + return JS_FALSE; + if (prop) { + OBJ_DROP_PROPERTY(cx, obj2, prop); + if (!OBJ_GET_PROPERTY(cx, obj, id, &value)) + return JS_FALSE; + } + if (!prop || !JSVAL_IS_OBJECT(value)) { + fprintf(gErrFile, "js: invalid stats argument %s\n", + bytes); + continue; + } + obj = JSVAL_TO_OBJECT(value); + if (obj) + DumpScope(cx, obj, stdout); + } + } + return JS_TRUE; +} + +static JSBool +DumpHeap(JSContext *cx, uintN argc, jsval *vp) +{ + char *fileName; + jsval v; + void* startThing; + uint32 startTraceKind; + const char *badTraceArg; + void *thingToFind; + size_t maxDepth; + void *thingToIgnore; + FILE *dumpFile; + JSBool ok; + + fileName = NULL; + if (argc > 0) { + v = JS_ARGV(cx, vp)[0]; + if (v != JSVAL_NULL) { + JSString *str; + + str = JS_ValueToString(cx, v); + if (!str) + return JS_FALSE; + JS_ARGV(cx, vp)[0] = STRING_TO_JSVAL(str); + fileName = JS_GetStringBytes(str); + } + } + + startThing = NULL; + startTraceKind = 0; + if (argc > 1) { + v = JS_ARGV(cx, vp)[1]; + if (JSVAL_IS_TRACEABLE(v)) { + startThing = JSVAL_TO_TRACEABLE(v); + startTraceKind = JSVAL_TRACE_KIND(v); + } else if (v != JSVAL_NULL) { + badTraceArg = "start"; + goto not_traceable_arg; + } + } + + thingToFind = NULL; + if (argc > 2) { + v = JS_ARGV(cx, vp)[2]; + if (JSVAL_IS_TRACEABLE(v)) { + thingToFind = JSVAL_TO_TRACEABLE(v); + } else if (v != JSVAL_NULL) { + badTraceArg = "toFind"; + goto not_traceable_arg; + } + } + + maxDepth = (size_t)-1; + if (argc > 3) { + v = JS_ARGV(cx, vp)[3]; + if (v != JSVAL_NULL) { + uint32 depth; + + if (!JS_ValueToECMAUint32(cx, v, &depth)) + return JS_FALSE; + maxDepth = depth; + } + } + + thingToIgnore = NULL; + if (argc > 4) { + v = JS_ARGV(cx, vp)[4]; + if (JSVAL_IS_TRACEABLE(v)) { + thingToIgnore = JSVAL_TO_TRACEABLE(v); + } else if (v != JSVAL_NULL) { + badTraceArg = "toIgnore"; + goto not_traceable_arg; + } + } + + if (!fileName) { + dumpFile = stdout; + } else { + dumpFile = fopen(fileName, "w"); + if (!dumpFile) { + JS_ReportError(cx, "can't open %s: %s", fileName, strerror(errno)); + return JS_FALSE; + } + } + + ok = JS_DumpHeap(cx, dumpFile, startThing, startTraceKind, thingToFind, + maxDepth, thingToIgnore); + if (dumpFile != stdout) + fclose(dumpFile); + return ok; + + not_traceable_arg: + JS_ReportError(cx, "argument '%s' is not null or a heap-allocated thing", + badTraceArg); + return JS_FALSE; +} + +#endif /* DEBUG */ + +#ifdef TEST_CVTARGS +#include + +static const char * +EscapeWideString(jschar *w) +{ + static char enuf[80]; + static char hex[] = "0123456789abcdef"; + jschar u; + unsigned char b, c; + int i, j; + + if (!w) + return ""; + for (i = j = 0; i < sizeof enuf - 1; i++, j++) { + u = w[j]; + if (u == 0) + break; + b = (unsigned char)(u >> 8); + c = (unsigned char)(u); + if (b) { + if (i >= sizeof enuf - 6) + break; + enuf[i++] = '\\'; + enuf[i++] = 'u'; + enuf[i++] = hex[b >> 4]; + enuf[i++] = hex[b & 15]; + enuf[i++] = hex[c >> 4]; + enuf[i] = hex[c & 15]; + } else if (!isprint(c)) { + if (i >= sizeof enuf - 4) + break; + enuf[i++] = '\\'; + enuf[i++] = 'x'; + enuf[i++] = hex[c >> 4]; + enuf[i] = hex[c & 15]; + } else { + enuf[i] = (char)c; + } + } + enuf[i] = 0; + return enuf; +} + +#include + +static JSBool +ZZ_formatter(JSContext *cx, const char *format, JSBool fromJS, jsval **vpp, + va_list *app) +{ + jsval *vp; + va_list ap; + jsdouble re, im; + + printf("entering ZZ_formatter"); + vp = *vpp; + ap = *app; + if (fromJS) { + if (!JS_ValueToNumber(cx, vp[0], &re)) + return JS_FALSE; + if (!JS_ValueToNumber(cx, vp[1], &im)) + return JS_FALSE; + *va_arg(ap, jsdouble *) = re; + *va_arg(ap, jsdouble *) = im; + } else { + re = va_arg(ap, jsdouble); + im = va_arg(ap, jsdouble); + if (!JS_NewNumberValue(cx, re, &vp[0])) + return JS_FALSE; + if (!JS_NewNumberValue(cx, im, &vp[1])) + return JS_FALSE; + } + *vpp = vp + 2; + *app = ap; + printf("leaving ZZ_formatter"); + return JS_TRUE; +} + +static JSBool +ConvertArgs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSBool b = JS_FALSE; + jschar c = 0; + int32 i = 0, j = 0; + uint32 u = 0; + jsdouble d = 0, I = 0, re = 0, im = 0; + char *s = NULL; + JSString *str = NULL; + jschar *w = NULL; + JSObject *obj2 = NULL; + JSFunction *fun = NULL; + jsval v = JSVAL_VOID; + JSBool ok; + + if (!JS_AddArgumentFormatter(cx, "ZZ", ZZ_formatter)) + return JS_FALSE;; + ok = JS_ConvertArguments(cx, argc, argv, "b/ciujdIsSWofvZZ*", + &b, &c, &i, &u, &j, &d, &I, &s, &str, &w, &obj2, + &fun, &v, &re, &im); + JS_RemoveArgumentFormatter(cx, "ZZ"); + if (!ok) + return JS_FALSE; + fprintf(gOutFile, + "b %u, c %x (%c), i %ld, u %lu, j %ld\n", + b, c, (char)c, i, u, j); + fprintf(gOutFile, + "d %g, I %g, s %s, S %s, W %s, obj %s, fun %s\n" + "v %s, re %g, im %g\n", + d, I, s, str ? JS_GetStringBytes(str) : "", EscapeWideString(w), + JS_GetStringBytes(JS_ValueToString(cx, OBJECT_TO_JSVAL(obj2))), + fun ? JS_GetStringBytes(JS_DecompileFunction(cx, fun, 4)) : "", + JS_GetStringBytes(JS_ValueToString(cx, v)), re, im); + return JS_TRUE; +} +#endif + +static JSBool +BuildDate(JSContext *cx, uintN argc, jsval *vp) +{ + char version[20] = "\n"; +#if JS_VERSION < 150 + sprintf(version, " for version %d\n", JS_VERSION); +#endif + fprintf(gOutFile, "built on %s at %s%s", __DATE__, __TIME__, version); + *vp = JSVAL_VOID; + return JS_TRUE; +} + +static JSBool +Clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if (argc != 0 && !JS_ValueToObject(cx, argv[0], &obj)) + return JS_FALSE; + JS_ClearScope(cx, obj); + return JS_TRUE; +} + +static JSBool +Intern(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + str = JS_ValueToString(cx, argc == 0 ? JSVAL_VOID : vp[2]); + if (!str) + return JS_FALSE; + if (!JS_InternUCStringN(cx, JS_GetStringChars(str), + JS_GetStringLength(str))) { + return JS_FALSE; + } + *vp = JSVAL_VOID; + return JS_TRUE; +} + +static JSBool +Clone(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFunction *fun; + JSObject *funobj, *parent, *clone; + + fun = JS_ValueToFunction(cx, argv[0]); + if (!fun) + return JS_FALSE; + funobj = JS_GetFunctionObject(fun); + if (argc > 1) { + if (!JS_ValueToObject(cx, argv[1], &parent)) + return JS_FALSE; + } else { + parent = JS_GetParent(cx, funobj); + } + clone = JS_CloneFunctionObject(cx, funobj, parent); + if (!clone) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(clone); + return JS_TRUE; +} + +static JSBool +Seal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSObject *target; + JSBool deep = JS_FALSE; + + if (!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep)) + return JS_FALSE; + if (!target) + return JS_TRUE; + return JS_SealObject(cx, target, deep); +} + +static JSBool +GetPDA(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *vobj, *aobj, *pdobj; + JSBool ok; + JSPropertyDescArray pda; + JSPropertyDesc *pd; + uint32 i; + jsval v; + + if (!JS_ValueToObject(cx, argc == 0 ? JSVAL_VOID : vp[2], &vobj)) + return JS_FALSE; + if (!vobj) + return JS_TRUE; + + aobj = JS_NewArrayObject(cx, 0, NULL); + if (!aobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(aobj); + + ok = JS_GetPropertyDescArray(cx, vobj, &pda); + if (!ok) + return JS_FALSE; + pd = pda.array; + for (i = 0; i < pda.length; i++) { + pdobj = JS_NewObject(cx, NULL, NULL, NULL); + if (!pdobj) { + ok = JS_FALSE; + break; + } + + /* Protect pdobj from GC by setting it as an element of aobj now */ + v = OBJECT_TO_JSVAL(pdobj); + ok = JS_SetElement(cx, aobj, i, &v); + if (!ok) + break; + + ok = JS_SetProperty(cx, pdobj, "id", &pd->id) && + JS_SetProperty(cx, pdobj, "value", &pd->value) && + (v = INT_TO_JSVAL(pd->flags), + JS_SetProperty(cx, pdobj, "flags", &v)) && + (v = INT_TO_JSVAL(pd->slot), + JS_SetProperty(cx, pdobj, "slot", &v)) && + JS_SetProperty(cx, pdobj, "alias", &pd->alias); + if (!ok) + break; + } + JS_PutPropertyDescArray(cx, &pda); + return ok; +} + +static JSBool +GetSLX(JSContext *cx, uintN argc, jsval *vp) +{ + JSScript *script; + + script = ValueToScript(cx, argc == 0 ? JSVAL_VOID : vp[2]); + if (!script) + return JS_FALSE; + *vp = INT_TO_JSVAL(js_GetScriptLineExtent(script)); + return JS_TRUE; +} + +static JSBool +ToInt32(JSContext *cx, uintN argc, jsval *vp) +{ + int32 i; + + if (!JS_ValueToInt32(cx, argc == 0 ? JSVAL_VOID : vp[2], &i)) + return JS_FALSE; + return JS_NewNumberValue(cx, i, vp); +} + +static JSBool +StringsAreUTF8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + *rval = JS_CStringsAreUTF8() ? JSVAL_TRUE : JSVAL_FALSE; + return JS_TRUE; +} + +static JSBool +StackQuota(JSContext *cx, uintN argc, jsval *vp) +{ + uint32 n; + + if (argc == 0) + return JS_NewNumberValue(cx, (double) gScriptStackQuota, vp); + if (!JS_ValueToECMAUint32(cx, JS_ARGV(cx, vp)[0], &n)) + return JS_FALSE; + gScriptStackQuota = n; + JS_SetScriptStackQuota(cx, gScriptStackQuota); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; +} + +static const char* badUTF8 = "...\xC0..."; +static const char* bigUTF8 = "...\xFB\xBF\xBF\xBF\xBF..."; +static const jschar badSurrogate[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 }; + +static JSBool +TestUTF8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + int32 mode = 1; + jschar chars[20]; + size_t charsLength = 5; + char bytes[20]; + size_t bytesLength = 20; + if (argc && !JS_ValueToInt32(cx, *argv, &mode)) + return JS_FALSE; + + /* The following throw errors if compiled with UTF-8. */ + switch (mode) { + /* mode 1: malformed UTF-8 string. */ + case 1: + JS_NewStringCopyZ(cx, badUTF8); + break; + /* mode 2: big UTF-8 character. */ + case 2: + JS_NewStringCopyZ(cx, bigUTF8); + break; + /* mode 3: bad surrogate character. */ + case 3: + JS_EncodeCharacters(cx, badSurrogate, 6, bytes, &bytesLength); + break; + /* mode 4: use a too small buffer. */ + case 4: + JS_DecodeBytes(cx, "1234567890", 10, chars, &charsLength); + break; + default: + JS_ReportError(cx, "invalid mode parameter"); + return JS_FALSE; + } + return !JS_IsExceptionPending (cx); +} + +static JSBool +ThrowError(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JS_ReportError(cx, "This is an error"); + return JS_FALSE; +} + +#define LAZY_STANDARD_CLASSES + +/* A class for easily testing the inner/outer object callbacks. */ +typedef struct ComplexObject { + JSBool isInner; + JSBool frozen; + JSObject *inner; + JSObject *outer; +} ComplexObject; + +static JSObject * +split_create_outer(JSContext *cx); + +static JSObject * +split_create_inner(JSContext *cx, JSObject *outer); + +static ComplexObject * +split_get_private(JSContext *cx, JSObject *obj); + +static JSBool +split_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + ComplexObject *cpx; + jsid asId; + + cpx = split_get_private(cx, obj); + if (!cpx) + return JS_TRUE; + if (!cpx->isInner && cpx->inner) { + /* Make sure to define this property on the inner object. */ + if (!JS_ValueToId(cx, *vp, &asId)) + return JS_FALSE; + return OBJ_DEFINE_PROPERTY(cx, cpx->inner, asId, *vp, NULL, NULL, + JSPROP_ENUMERATE, NULL); + } + return JS_TRUE; +} + +static JSBool +split_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + ComplexObject *cpx; + + cpx = split_get_private(cx, obj); + if (!cpx) + return JS_TRUE; + if (!cpx->isInner && cpx->inner) { + if (JSVAL_IS_STRING(id)) { + JSString *str; + + str = JSVAL_TO_STRING(id); + return JS_GetUCProperty(cx, cpx->inner, JS_GetStringChars(str), + JS_GetStringLength(str), vp); + } + if (JSVAL_IS_INT(id)) + return JS_GetElement(cx, cpx->inner, JSVAL_TO_INT(id), vp); + return JS_TRUE; + } + + return JS_TRUE; +} + +static JSBool +split_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + ComplexObject *cpx; + + cpx = split_get_private(cx, obj); + if (!cpx) + return JS_TRUE; + if (!cpx->isInner && cpx->inner) { + if (JSVAL_IS_STRING(id)) { + JSString *str; + + str = JSVAL_TO_STRING(id); + return JS_SetUCProperty(cx, cpx->inner, JS_GetStringChars(str), + JS_GetStringLength(str), vp); + } + if (JSVAL_IS_INT(id)) + return JS_SetElement(cx, cpx->inner, JSVAL_TO_INT(id), vp); + return JS_TRUE; + } + + return JS_TRUE; +} + +static JSBool +split_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + ComplexObject *cpx; + jsid asId; + + cpx = split_get_private(cx, obj); + if (!cpx) + return JS_TRUE; + if (!cpx->isInner && cpx->inner) { + /* Make sure to define this property on the inner object. */ + if (!JS_ValueToId(cx, *vp, &asId)) + return JS_FALSE; + return OBJ_DELETE_PROPERTY(cx, cpx->inner, asId, vp); + } + return JS_TRUE; +} + +static JSBool +split_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp) +{ + ComplexObject *cpx; + JSObject *iterator; + + switch (enum_op) { + case JSENUMERATE_INIT: + cpx = (ComplexObject *) JS_GetPrivate(cx, obj); + + if (!cpx->isInner && cpx->inner) + obj = cpx->inner; + + iterator = JS_NewPropertyIterator(cx, obj); + if (!iterator) + return JS_FALSE; + + *statep = OBJECT_TO_JSVAL(iterator); + if (idp) + *idp = JSVAL_ZERO; + break; + + case JSENUMERATE_NEXT: + iterator = (JSObject*)JSVAL_TO_OBJECT(*statep); + if (!JS_NextProperty(cx, iterator, idp)) + return JS_FALSE; + + if (!JSVAL_IS_VOID(*idp)) + break; + /* Fall through. */ + + case JSENUMERATE_DESTROY: + /* Let GC at our iterator object. */ + *statep = JSVAL_NULL; + break; + } + + return JS_TRUE; +} + +static JSBool +split_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp) +{ + ComplexObject *cpx; + + cpx = split_get_private(cx, obj); + if (!cpx) + return JS_TRUE; + if (!cpx->isInner && cpx->inner) { + jsid asId; + JSProperty *prop; + + if (!JS_ValueToId(cx, id, &asId)) + return JS_FALSE; + + if (!OBJ_LOOKUP_PROPERTY(cx, cpx->inner, asId, objp, &prop)) + return JS_FALSE; + if (prop) + OBJ_DROP_PROPERTY(cx, cpx->inner, prop); + + return JS_TRUE; + } + +#ifdef LAZY_STANDARD_CLASSES + if (!(flags & JSRESOLVE_ASSIGNING)) { + JSBool resolved; + + if (!JS_ResolveStandardClass(cx, obj, id, &resolved)) + return JS_FALSE; + + if (resolved) { + *objp = obj; + return JS_TRUE; + } + } +#endif + + /* XXX For additional realism, let's resolve some random property here. */ + return JS_TRUE; +} + +static void +split_finalize(JSContext *cx, JSObject *obj) +{ + JS_free(cx, JS_GetPrivate(cx, obj)); +} + +static uint32 +split_mark(JSContext *cx, JSObject *obj, void *arg) +{ + ComplexObject *cpx; + + cpx = (ComplexObject *) JS_GetPrivate(cx, obj); + + if (!cpx->isInner && cpx->inner) { + /* Mark the inner object. */ + JS_MarkGCThing(cx, cpx->inner, "ComplexObject.inner", arg); + } + + return 0; +} + +static JSObject * +split_outerObject(JSContext *cx, JSObject *obj) +{ + ComplexObject *cpx; + + cpx = (ComplexObject *) JS_GetPrivate(cx, obj); + return cpx->isInner ? cpx->outer : obj; +} + +static JSObject * +split_innerObject(JSContext *cx, JSObject *obj) +{ + ComplexObject *cpx; + + cpx = (ComplexObject *) JS_GetPrivate(cx, obj); + if (cpx->frozen) { + JS_ASSERT(!cpx->isInner); + return obj; + } + return !cpx->isInner ? cpx->inner : obj; +} + +static JSExtendedClass split_global_class = { + {"split_global", + JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE | JSCLASS_HAS_PRIVATE | + JSCLASS_GLOBAL_FLAGS | JSCLASS_IS_EXTENDED, + split_addProperty, split_delProperty, + split_getProperty, split_setProperty, + (JSEnumerateOp)split_enumerate, + (JSResolveOp)split_resolve, + JS_ConvertStub, split_finalize, + NULL, NULL, NULL, NULL, NULL, NULL, + split_mark, NULL}, + NULL, split_outerObject, split_innerObject, + NULL, NULL, NULL, NULL, NULL +}; + +JSObject * +split_create_outer(JSContext *cx) +{ + ComplexObject *cpx; + JSObject *obj; + + cpx = (ComplexObject *) JS_malloc(cx, sizeof *obj); + if (!cpx) + return NULL; + cpx->isInner = JS_FALSE; + cpx->frozen = JS_TRUE; + cpx->inner = NULL; + cpx->outer = NULL; + + obj = JS_NewObject(cx, &split_global_class.base, NULL, NULL); + if (!obj || !JS_SetParent(cx, obj, NULL)) { + JS_free(cx, cpx); + return NULL; + } + + if (!JS_SetPrivate(cx, obj, cpx)) { + JS_free(cx, cpx); + return NULL; + } + + return obj; +} + +static JSObject * +split_create_inner(JSContext *cx, JSObject *outer) +{ + ComplexObject *cpx, *outercpx; + JSObject *obj; + + JS_ASSERT(JS_GET_CLASS(cx, outer) == &split_global_class.base); + + cpx = (ComplexObject *) JS_malloc(cx, sizeof *cpx); + if (!cpx) + return NULL; + cpx->isInner = JS_TRUE; + cpx->frozen = JS_FALSE; + cpx->inner = NULL; + cpx->outer = outer; + + obj = JS_NewObject(cx, &split_global_class.base, NULL, NULL); + if (!obj || !JS_SetParent(cx, obj, NULL) || !JS_SetPrivate(cx, obj, cpx)) { + JS_free(cx, cpx); + return NULL; + } + + outercpx = (ComplexObject *) JS_GetPrivate(cx, outer); + outercpx->inner = obj; + outercpx->frozen = JS_FALSE; + + return obj; +} + +static ComplexObject * +split_get_private(JSContext *cx, JSObject *obj) +{ + do { + if (JS_GET_CLASS(cx, obj) == &split_global_class.base) + return (ComplexObject *) JS_GetPrivate(cx, obj); + obj = JS_GetParent(cx, obj); + } while (obj); + + return NULL; +} + +static JSBool +sandbox_enumerate(JSContext *cx, JSObject *obj) +{ + jsval v; + JSBool b; + + if (!JS_GetProperty(cx, obj, "lazy", &v) || !JS_ValueToBoolean(cx, v, &b)) + return JS_FALSE; + return !b || JS_EnumerateStandardClasses(cx, obj); +} + +static JSBool +sandbox_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp) +{ + jsval v; + JSBool b, resolved; + + if (!JS_GetProperty(cx, obj, "lazy", &v) || !JS_ValueToBoolean(cx, v, &b)) + return JS_FALSE; + if (b && (flags & JSRESOLVE_ASSIGNING) == 0) { + if (!JS_ResolveStandardClass(cx, obj, id, &resolved)) + return JS_FALSE; + if (resolved) { + *objp = obj; + return JS_TRUE; + } + } + *objp = NULL; + return JS_TRUE; +} + +static JSClass sandbox_class = { + "sandbox", + JSCLASS_NEW_RESOLVE, + JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_PropertyStub, + sandbox_enumerate, (JSResolveOp)sandbox_resolve, + JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSBool +EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + JSString *str; + JSObject *sobj; + JSContext *scx; + const jschar *src; + size_t srclen; + JSBool lazy, ok; + jsval v; + JSStackFrame *fp; + + sobj = NULL; + if (!JS_ConvertArguments(cx, argc, argv, "S / o", &str, &sobj)) + return JS_FALSE; + + scx = JS_NewContext(JS_GetRuntime(cx), gStackChunkSize); + if (!scx) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + +#ifdef JS_THREADSAFE + JS_BeginRequest(scx); +#endif + src = JS_GetStringChars(str); + srclen = JS_GetStringLength(str); + lazy = JS_FALSE; + if (srclen == 4 && + src[0] == 'l' && src[1] == 'a' && src[2] == 'z' && src[3] == 'y') { + lazy = JS_TRUE; + srclen = 0; + } + + if (!sobj) { + sobj = JS_NewObject(scx, &sandbox_class, NULL, NULL); + if (!sobj || (!lazy && !JS_InitStandardClasses(scx, sobj))) { + ok = JS_FALSE; + goto out; + } + v = BOOLEAN_TO_JSVAL(lazy); + ok = JS_SetProperty(cx, sobj, "lazy", &v); + if (!ok) + goto out; + } + + if (srclen == 0) { + *rval = OBJECT_TO_JSVAL(sobj); + ok = JS_TRUE; + } else { + fp = JS_GetScriptedCaller(cx, NULL); + JS_SetGlobalObject(scx, sobj); + JS_ToggleOptions(scx, JSOPTION_DONT_REPORT_UNCAUGHT); + ok = JS_EvaluateUCScript(scx, sobj, src, srclen, + fp->script->filename, + JS_PCToLineNumber(cx, fp->script, + fp->regs->pc), + rval); + if (!ok) { + if (JS_GetPendingException(scx, &v)) + JS_SetPendingException(cx, v); + else + JS_ReportOutOfMemory(cx); + } + } + +out: +#ifdef JS_THREADSAFE + JS_EndRequest(scx); +#endif + JS_DestroyContext(scx); + return ok; +} + +static int32 JS_FASTCALL +ShapeOf_tn(JSObject *obj) +{ + if (!obj) + return 0; + if (!OBJ_IS_NATIVE(obj)) + return -1; + return OBJ_SHAPE(obj); +} + +static JSBool +ShapeOf(JSContext *cx, uintN argc, jsval *vp) +{ + jsval v = JS_ARGV(cx, vp)[0]; + if (!JSVAL_IS_OBJECT(v)) { + JS_ReportError(cx, "shapeOf: object expected"); + return JS_FALSE; + } + return JS_NewNumberValue(cx, ShapeOf_tn(JSVAL_TO_OBJECT(v)), vp); +} + +#ifdef JS_THREADSAFE + +static JSBool +Sleep_fn(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble t_secs; + PRUint32 t_ticks; + jsrefcount rc; + + if (!JS_ValueToNumber(cx, argc == 0 ? JSVAL_VOID : vp[2], &t_secs)) + return JS_FALSE; + + if (t_secs < 0 || JSDOUBLE_IS_NaN(t_secs)) + t_secs = 0; + + rc = JS_SuspendRequest(cx); + t_ticks = (PRUint32)(PR_TicksPerSecond() * t_secs); + if (PR_Sleep(t_ticks) == PR_SUCCESS) + *vp = JSVAL_TRUE; + else + *vp = JSVAL_FALSE; + JS_ResumeRequest(cx, rc); + return JS_TRUE; +} + +typedef struct ScatterThreadData ScatterThreadData; +typedef struct ScatterData ScatterData; + +typedef enum ScatterStatus { + SCATTER_WAIT, + SCATTER_GO, + SCATTER_CANCEL +} ScatterStatus; + +struct ScatterData { + ScatterThreadData *threads; + jsval *results; + PRLock *lock; + PRCondVar *cvar; + ScatterStatus status; +}; + +struct ScatterThreadData { + jsint index; + ScatterData *shared; + PRThread *thr; + JSContext *cx; + jsval fn; +}; + +static void +DoScatteredWork(JSContext *cx, ScatterThreadData *td) +{ + jsval *rval = &td->shared->results[td->index]; + + if (!JS_CallFunctionValue(cx, NULL, td->fn, 0, NULL, rval)) { + *rval = JSVAL_VOID; + JS_GetPendingException(cx, rval); + JS_ClearPendingException(cx); + } +} + +static void +RunScatterThread(void *arg) +{ + ScatterThreadData *td; + ScatterStatus st; + JSContext *cx; + + td = (ScatterThreadData *)arg; + cx = td->cx; + + /* Wait for go signal. */ + PR_Lock(td->shared->lock); + while ((st = td->shared->status) == SCATTER_WAIT) + PR_WaitCondVar(td->shared->cvar, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(td->shared->lock); + + if (st == SCATTER_CANCEL) + return; + + /* We are go. */ + JS_SetContextThread(cx); + JS_SetThreadStackLimit(cx, 0); + JS_BeginRequest(cx); + DoScatteredWork(cx, td); + JS_EndRequest(cx); + JS_ClearContextThread(cx); +} + +/* + * scatter(fnArray) - Call each function in `fnArray` without arguments, each + * in a different thread. When all threads have finished, return an array: the + * return values. Errors are not propagated; if any of the function calls + * fails, the corresponding element in the results array gets the exception + * object, if any, else (undefined). + */ +static JSBool +Scatter(JSContext *cx, uintN argc, jsval *vp) +{ + jsuint i; + jsuint n; /* number of threads */ + JSObject *inArr; + JSObject *arr; + ScatterData sd; + JSBool ok; + jsrefcount rc; + + if (!gEnableBranchCallback) { + /* Enable the branch callback, for periodic scope-sharing. */ + gEnableBranchCallback = JS_TRUE; + JS_SetBranchCallback(cx, my_BranchCallback); + JS_ToggleOptions(cx, JSOPTION_NATIVE_BRANCH_CALLBACK); + } + + sd.lock = NULL; + sd.cvar = NULL; + sd.results = NULL; + sd.threads = NULL; + sd.status = SCATTER_WAIT; + + if (argc == 0 || JSVAL_IS_PRIMITIVE(JS_ARGV(cx, vp)[0])) { + JS_ReportError(cx, "the first argument must be an object"); + goto fail; + } + + inArr = JSVAL_TO_OBJECT(JS_ARGV(cx, vp)[0]); + ok = JS_GetArrayLength(cx, inArr, &n); + if (!ok) + goto out; + if (n == 0) + goto success; + + sd.lock = PR_NewLock(); + if (!sd.lock) + goto fail; + + sd.cvar = PR_NewCondVar(sd.lock); + if (!sd.cvar) + goto fail; + + sd.results = (jsval *) malloc(n * sizeof(jsval)); + if (!sd.results) + goto fail; + for (i = 0; i < n; i++) { + sd.results[i] = JSVAL_VOID; + ok = JS_AddRoot(cx, &sd.results[i]); + if (!ok) { + while (i-- > 0) + JS_RemoveRoot(cx, &sd.results[i]); + free(sd.results); + sd.results = NULL; + goto fail; + } + } + + sd.threads = (ScatterThreadData *) malloc(n * sizeof(ScatterThreadData)); + if (!sd.threads) + goto fail; + for (i = 0; i < n; i++) { + sd.threads[i].index = i; + sd.threads[i].shared = &sd; + sd.threads[i].thr = NULL; + sd.threads[i].cx = NULL; + sd.threads[i].fn = JSVAL_NULL; + + ok = JS_AddRoot(cx, &sd.threads[i].fn); + if (ok && !JS_GetElement(cx, inArr, (jsint) i, &sd.threads[i].fn)) { + JS_RemoveRoot(cx, &sd.threads[i].fn); + ok = JS_FALSE; + } + if (!ok) { + while (i-- > 0) + JS_RemoveRoot(cx, &sd.threads[i].fn); + free(sd.threads); + sd.threads = NULL; + goto fail; + } + } + + for (i = 1; i < n; i++) { + JSContext *newcx = JS_NewContext(JS_GetRuntime(cx), 8192); + if (!newcx) + goto fail; + JS_SetGlobalObject(newcx, JS_GetGlobalObject(cx)); + JS_ClearContextThread(newcx); + sd.threads[i].cx = newcx; + } + + for (i = 1; i < n; i++) { + PRThread *t = PR_CreateThread(PR_USER_THREAD, + RunScatterThread, + &sd.threads[i], + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + if (!t) { + /* Failed to start thread. */ + PR_Lock(sd.lock); + sd.status = SCATTER_CANCEL; + PR_NotifyAllCondVar(sd.cvar); + PR_Unlock(sd.lock); + while (i-- > 1) + PR_JoinThread(sd.threads[i].thr); + goto fail; + } + + sd.threads[i].thr = t; + } + PR_Lock(sd.lock); + sd.status = SCATTER_GO; + PR_NotifyAllCondVar(sd.cvar); + PR_Unlock(sd.lock); + + DoScatteredWork(cx, &sd.threads[0]); + + rc = JS_SuspendRequest(cx); + for (i = 1; i < n; i++) { + PR_JoinThread(sd.threads[i].thr); + } + JS_ResumeRequest(cx, rc); + +success: + arr = JS_NewArrayObject(cx, n, sd.results); + if (!arr) + goto fail; + *vp = OBJECT_TO_JSVAL(arr); + ok = JS_TRUE; + +out: + if (sd.threads) { + JSContext *acx; + + for (i = 0; i < n; i++) { + JS_RemoveRoot(cx, &sd.threads[i].fn); + acx = sd.threads[i].cx; + if (acx) { + JS_SetContextThread(acx); + JS_DestroyContext(acx); + } + } + free(sd.threads); + } + if (sd.results) { + for (i = 0; i < n; i++) + JS_RemoveRoot(cx, &sd.results[i]); + free(sd.results); + } + if (sd.cvar) + PR_DestroyCondVar(sd.cvar); + if (sd.lock) + PR_DestroyLock(sd.lock); + + return ok; + +fail: + ok = JS_FALSE; + goto out; +} + +#endif + +JS_DEFINE_TRCINFO_1(Print, (2, (static, JSVAL_FAIL, Print_tn, CONTEXT, STRING, 0, 0))) +JS_DEFINE_TRCINFO_1(ShapeOf, (1, (static, INT32, ShapeOf_tn, OBJECT, 0, 0))) + +/* We use a mix of JS_FS and JS_FN to test both kinds of natives. */ +static JSFunctionSpec shell_functions[] = { + JS_FS("version", Version, 0,0,0), + JS_FS("options", Options, 0,0,0), + JS_FS("load", Load, 1,0,0), + JS_FN("readline", ReadLine, 0,0), + JS_TN("print", Print, 0,0, Print_trcinfo), + JS_FS("help", Help, 0,0,0), + JS_FS("quit", Quit, 0,0,0), + JS_FN("gc", GC, 0,0), + JS_FN("gcparam", GCParameter, 2,0), + JS_FN("countHeap", CountHeap, 0,0), +#ifdef JS_GC_ZEAL + JS_FN("gczeal", GCZeal, 1,0), +#endif + JS_FS("trap", Trap, 3,0,0), + JS_FS("untrap", Untrap, 2,0,0), + JS_FS("line2pc", LineToPC, 0,0,0), + JS_FS("pc2line", PCToLine, 0,0,0), + JS_FN("stackQuota", StackQuota, 0,0), + JS_FS("stringsAreUTF8", StringsAreUTF8, 0,0,0), + JS_FS("testUTF8", TestUTF8, 1,0,0), + JS_FS("throwError", ThrowError, 0,0,0), +#ifdef DEBUG + JS_FS("dis", Disassemble, 1,0,0), + JS_FS("disfile", DisassFile, 1,0,0), + JS_FS("dissrc", DisassWithSrc, 1,0,0), + JS_FN("dumpHeap", DumpHeap, 0,0), + JS_FS("notes", Notes, 1,0,0), + JS_FS("tracing", Tracing, 0,0,0), + JS_FS("stats", DumpStats, 1,0,0), +#endif +#ifdef TEST_CVTARGS + JS_FS("cvtargs", ConvertArgs, 0,0,12), +#endif + JS_FN("build", BuildDate, 0,0), + JS_FS("clear", Clear, 0,0,0), + JS_FN("intern", Intern, 1,0), + JS_FS("clone", Clone, 1,0,0), + JS_FS("seal", Seal, 1,0,1), + JS_FN("getpda", GetPDA, 1,0), + JS_FN("getslx", GetSLX, 1,0), + JS_FN("toint32", ToInt32, 1,0), + JS_FS("evalcx", EvalInContext, 1,0,0), + JS_TN("shapeOf", ShapeOf, 1,0, ShapeOf_trcinfo), +#ifdef MOZ_SHARK + JS_FS("startShark", js_StartShark, 0,0,0), + JS_FS("stopShark", js_StopShark, 0,0,0), + JS_FS("connectShark", js_ConnectShark, 0,0,0), + JS_FS("disconnectShark", js_DisconnectShark, 0,0,0), +#endif +#ifdef MOZ_CALLGRIND + JS_FS("startCallgrind", js_StartCallgrind, 0,0,0), + JS_FS("stopCallgrind", js_StopCallgrind, 0,0,0), + JS_FS("dumpCallgrind", js_DumpCallgrind, 1,0,0), +#endif +#ifdef MOZ_VTUNE + JS_FS("startVtune", js_StartVtune, 1,0,0), + JS_FS("stopVtune", js_StopVtune, 0,0,0), + JS_FS("pauseVtune", js_PauseVtune, 0,0,0), + JS_FS("resumeVtune", js_ResumeVtune, 0,0,0), +#endif +#ifdef DEBUG_ARRAYS + JS_FS("arrayInfo", js_ArrayInfo, 1,0,0), +#endif +#ifdef JS_THREADSAFE + JS_FN("sleep", Sleep_fn, 1,0), + JS_FN("scatter", Scatter, 1,0), +#endif + JS_FS_END +}; + +static const char shell_help_header[] = +"Command Description\n" +"======= ===========\n"; + +static const char *const shell_help_messages[] = { +"version([number]) Get or set JavaScript version number", +"options([option ...]) Get or toggle JavaScript options", +"load(['foo.js' ...]) Load files named by string arguments", +"readline() Read a single line from stdin", +"print([exp ...]) Evaluate and print expressions", +"help([name ...]) Display usage and help messages", +"quit() Quit the shell", +"gc() Run the garbage collector", +"gcparam(name, value)\n" +" Wrapper for JS_SetGCParameter. The name must be either 'maxBytes' or\n" +" 'maxMallocBytes' and the value must be convertable to a positive uint32", +"countHeap([start[, kind]])\n" +" Count the number of live GC things in the heap or things reachable from\n" +" start when it is given and is not null. kind is either 'all' (default) to\n" +" count all things or one of 'object', 'double', 'string', 'function',\n" +" 'qname', 'namespace', 'xml' to count only things of that kind", +#ifdef JS_GC_ZEAL +"gczeal(level) How zealous the garbage collector should be", +#endif +"trap([fun, [pc,]] exp) Trap bytecode execution", +"untrap(fun[, pc]) Remove a trap", +"line2pc([fun,] line) Map line number to PC", +"pc2line(fun[, pc]) Map PC to line number", +"stackQuota([number]) Query/set script stack quota", +"stringsAreUTF8() Check if strings are UTF-8 encoded", +"testUTF8(mode) Perform UTF-8 tests (modes are 1 to 4)", +"throwError() Throw an error from JS_ReportError", +#ifdef DEBUG +"dis([fun]) Disassemble functions into bytecodes", +"disfile('foo.js') Disassemble script file into bytecodes", +"dissrc([fun]) Disassemble functions with source lines", +"dumpHeap([fileName[, start[, toFind[, maxDepth[, toIgnore]]]]])\n" +" Interface to JS_DumpHeap with output sent to file", +"notes([fun]) Show source notes for functions", +"tracing([toggle]) Turn tracing on or off", +"stats([string ...]) Dump 'arena', 'atom', 'global' stats", +#endif +#ifdef TEST_CVTARGS +"cvtargs(arg1..., arg12) Test argument formatter", +#endif +"build() Show build date and time", +"clear([obj]) Clear properties of object", +"intern(str) Internalize str in the atom table", +"clone(fun[, scope]) Clone function object", +"seal(obj[, deep]) Seal object, or object graph if deep", +"getpda(obj) Get the property descriptors for obj", +"getslx(obj) Get script line extent", +"toint32(n) Testing hook for JS_ValueToInt32", +"evalcx(s[, o])\n" +" Evaluate s in optional sandbox object o\n" +" if (s == '' && !o) return new o with eager standard classes\n" +" if (s == 'lazy' && !o) return new o with lazy standard classes", +"shapeOf(obj) Get the shape of obj (an implementation detail)", +#ifdef MOZ_SHARK +"startShark() Start a Shark session.\n" +" Shark must be running with programatic sampling.", +"stopShark() Stop a running Shark session.", +"connectShark() Connect to Shark.\n" +" The -k switch does this automatically.", +"disconnectShark() Disconnect from Shark.", +#endif +#ifdef MOZ_CALLGRIND +"startCallgrind() Start callgrind instrumentation.\n", +"stopCallgrind() Stop callgrind instumentation.", +"dumpCallgrind([name]) Dump callgrind counters.\n", +#endif +#ifdef MOZ_VTUNE +"startVtune([filename]) Start vtune instrumentation.\n", +"stopVtune() Stop vtune instumentation.", +"pauseVtune() Pause vtune collection.\n", +"resumeVtune() Resume vtune collection.\n", +#endif +#ifdef DEBUG_ARRAYS +"arrayInfo(a1, a2, ...) Report statistics about arrays.", +#endif +#ifdef JS_THREADSAFE +"sleep(dt) Sleep for dt seconds", +"scatter(fns) Call functions concurrently (ignoring errors)", +#endif +}; + +/* Help messages must match shell functions. */ +JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) + 1 == + JS_ARRAY_LENGTH(shell_functions)); + +#ifdef DEBUG +static void +CheckHelpMessages() +{ + const char *const *m; + const char *lp; + + /* Each message must begin with "function_name(" prefix. */ + for (m = shell_help_messages; m != JS_ARRAY_END(shell_help_messages); ++m) { + lp = strchr(*m, '('); + JS_ASSERT(lp); + JS_ASSERT(memcmp(shell_functions[m - shell_help_messages].name, + *m, lp - *m) == 0); + } +} +#else +# define CheckHelpMessages() ((void) 0) +#endif + +static JSBool +Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + uintN i, j; + int did_header, did_something; + JSType type; + JSFunction *fun; + JSString *str; + const char *bytes; + + fprintf(gOutFile, "%s\n", JS_GetImplementationVersion()); + if (argc == 0) { + fputs(shell_help_header, gOutFile); + for (i = 0; shell_functions[i].name; i++) + fprintf(gOutFile, "%s\n", shell_help_messages[i]); + } else { + did_header = 0; + for (i = 0; i < argc; i++) { + did_something = 0; + type = JS_TypeOfValue(cx, argv[i]); + if (type == JSTYPE_FUNCTION) { + fun = JS_ValueToFunction(cx, argv[i]); + str = fun->atom ? ATOM_TO_STRING(fun->atom) : NULL; + } else if (type == JSTYPE_STRING) { + str = JSVAL_TO_STRING(argv[i]); + } else { + str = NULL; + } + if (str) { + bytes = JS_GetStringBytes(str); + for (j = 0; shell_functions[j].name; j++) { + if (!strcmp(bytes, shell_functions[j].name)) { + if (!did_header) { + did_header = 1; + fputs(shell_help_header, gOutFile); + } + did_something = 1; + fprintf(gOutFile, "%s\n", shell_help_messages[j]); + break; + } + } + } + if (!did_something) { + str = JS_ValueToString(cx, argv[i]); + if (!str) + return JS_FALSE; + fprintf(gErrFile, "Sorry, no help for %s\n", + JS_GetStringBytes(str)); + } + } + } + return JS_TRUE; +} + +static JSObject * +split_setup(JSContext *cx) +{ + JSObject *outer, *inner, *arguments; + + outer = split_create_outer(cx); + if (!outer) + return NULL; + JS_SetGlobalObject(cx, outer); + + inner = split_create_inner(cx, outer); + if (!inner) + return NULL; + + if (!JS_DefineFunctions(cx, inner, shell_functions)) + return NULL; + JS_ClearScope(cx, outer); + + /* Create a dummy arguments object. */ + arguments = JS_NewArrayObject(cx, 0, NULL); + if (!arguments || + !JS_DefineProperty(cx, inner, "arguments", OBJECT_TO_JSVAL(arguments), + NULL, NULL, 0)) { + return NULL; + } + +#ifndef LAZY_STANDARD_CLASSES + if (!JS_InitStandardClasses(cx, inner)) + return NULL; +#endif + + return inner; +} + +/* + * Define a JS object called "it". Give it class operations that printf why + * they're being called for tutorial purposes. + */ +enum its_tinyid { + ITS_COLOR, ITS_HEIGHT, ITS_WIDTH, ITS_FUNNY, ITS_ARRAY, ITS_RDONLY +}; + +static JSPropertySpec its_props[] = { + {"color", ITS_COLOR, JSPROP_ENUMERATE, NULL, NULL}, + {"height", ITS_HEIGHT, JSPROP_ENUMERATE, NULL, NULL}, + {"width", ITS_WIDTH, JSPROP_ENUMERATE, NULL, NULL}, + {"funny", ITS_FUNNY, JSPROP_ENUMERATE, NULL, NULL}, + {"array", ITS_ARRAY, JSPROP_ENUMERATE, NULL, NULL}, + {"rdonly", ITS_RDONLY, JSPROP_READONLY, NULL, NULL}, + {NULL,0,0,NULL,NULL} +}; + +static JSBool +its_item(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + *rval = OBJECT_TO_JSVAL(obj); + if (argc != 0) + JS_SetCallReturnValue2(cx, argv[0]); + return JS_TRUE; +} + +static JSBool +its_bindMethod(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + char *name; + JSObject *method; + + if (!JS_ConvertArguments(cx, argc, argv, "so", &name, &method)) + return JS_FALSE; + + *rval = OBJECT_TO_JSVAL(method); + + if (JS_TypeOfValue(cx, *rval) != JSTYPE_FUNCTION) { + JSString *valstr = JS_ValueToString(cx, *rval); + if (valstr) { + JS_ReportError(cx, "can't bind method %s to non-callable object %s", + name, JS_GetStringBytes(valstr)); + } + return JS_FALSE; + } + + if (!JS_DefineProperty(cx, obj, name, *rval, NULL, NULL, JSPROP_ENUMERATE)) + return JS_FALSE; + + return JS_SetParent(cx, method, obj); +} + +static JSFunctionSpec its_methods[] = { + {"item", its_item, 0,0,0}, + {"bindMethod", its_bindMethod, 2,0,0}, + {NULL,NULL,0,0,0} +}; + +#ifdef JSD_LOWLEVEL_SOURCE +/* + * This facilitates sending source to JSD (the debugger system) in the shell + * where the source is loaded using the JSFILE hack in jsscan. The function + * below is used as a callback for the jsdbgapi JS_SetSourceHandler hook. + * A more normal embedding (e.g. mozilla) loads source itself and can send + * source directly to JSD without using this hook scheme. + */ +static void +SendSourceToJSDebugger(const char *filename, uintN lineno, + jschar *str, size_t length, + void **listenerTSData, JSDContext* jsdc) +{ + JSDSourceText *jsdsrc = (JSDSourceText *) *listenerTSData; + + if (!jsdsrc) { + if (!filename) + filename = "typein"; + if (1 == lineno) { + jsdsrc = JSD_NewSourceText(jsdc, filename); + } else { + jsdsrc = JSD_FindSourceForURL(jsdc, filename); + if (jsdsrc && JSD_SOURCE_PARTIAL != + JSD_GetSourceStatus(jsdc, jsdsrc)) { + jsdsrc = NULL; + } + } + } + if (jsdsrc) { + jsdsrc = JSD_AppendUCSourceText(jsdc,jsdsrc, str, length, + JSD_SOURCE_PARTIAL); + } + *listenerTSData = jsdsrc; +} +#endif /* JSD_LOWLEVEL_SOURCE */ + +static JSBool its_noisy; /* whether to be noisy when finalizing it */ +static JSBool its_enum_fail;/* whether to fail when enumerating it */ + +static JSBool +its_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + if (its_noisy) { + fprintf(gOutFile, "adding its property %s,", + JS_GetStringBytes(JS_ValueToString(cx, id))); + fprintf(gOutFile, " initial value %s\n", + JS_GetStringBytes(JS_ValueToString(cx, *vp))); + } + return JS_TRUE; +} + +static JSBool +its_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + if (its_noisy) { + fprintf(gOutFile, "deleting its property %s,", + JS_GetStringBytes(JS_ValueToString(cx, id))); + fprintf(gOutFile, " current value %s\n", + JS_GetStringBytes(JS_ValueToString(cx, *vp))); + } + return JS_TRUE; +} + +static JSBool +its_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + if (its_noisy) { + fprintf(gOutFile, "getting its property %s,", + JS_GetStringBytes(JS_ValueToString(cx, id))); + fprintf(gOutFile, " current value %s\n", + JS_GetStringBytes(JS_ValueToString(cx, *vp))); + } + return JS_TRUE; +} + +static JSBool +its_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + char *str; + if (its_noisy) { + fprintf(gOutFile, "setting its property %s,", + JS_GetStringBytes(JS_ValueToString(cx, id))); + fprintf(gOutFile, " new value %s\n", + JS_GetStringBytes(JS_ValueToString(cx, *vp))); + } + + if (!JSVAL_IS_STRING(id)) + return JS_TRUE; + + str = JS_GetStringBytes(JSVAL_TO_STRING(id)); + if (!strcmp(str, "noisy")) + return JS_ValueToBoolean(cx, *vp, &its_noisy); + else if (!strcmp(str, "enum_fail")) + return JS_ValueToBoolean(cx, *vp, &its_enum_fail); + + return JS_TRUE; +} + +/* + * Its enumerator, implemented using the "new" enumerate API, + * see class flags. + */ +static JSBool +its_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp) +{ + JSObject *iterator; + + switch (enum_op) { + case JSENUMERATE_INIT: + if (its_noisy) + fprintf(gOutFile, "enumerate its properties\n"); + + iterator = JS_NewPropertyIterator(cx, obj); + if (!iterator) + return JS_FALSE; + + *statep = OBJECT_TO_JSVAL(iterator); + if (idp) + *idp = JSVAL_ZERO; + break; + + case JSENUMERATE_NEXT: + if (its_enum_fail) { + JS_ReportError(cx, "its enumeration failed"); + return JS_FALSE; + } + + iterator = (JSObject *) JSVAL_TO_OBJECT(*statep); + if (!JS_NextProperty(cx, iterator, idp)) + return JS_FALSE; + + if (!JSVAL_IS_VOID(*idp)) + break; + /* Fall through. */ + + case JSENUMERATE_DESTROY: + /* Allow our iterator object to be GC'd. */ + *statep = JSVAL_NULL; + break; + } + + return JS_TRUE; +} + +static JSBool +its_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp) +{ + if (its_noisy) { + fprintf(gOutFile, "resolving its property %s, flags {%s,%s,%s}\n", + JS_GetStringBytes(JS_ValueToString(cx, id)), + (flags & JSRESOLVE_QUALIFIED) ? "qualified" : "", + (flags & JSRESOLVE_ASSIGNING) ? "assigning" : "", + (flags & JSRESOLVE_DETECTING) ? "detecting" : ""); + } + return JS_TRUE; +} + +static JSBool +its_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) +{ + if (its_noisy) + fprintf(gOutFile, "converting it to %s type\n", JS_GetTypeName(cx, type)); + return JS_TRUE; +} + +static void +its_finalize(JSContext *cx, JSObject *obj) +{ + if (its_noisy) + fprintf(gOutFile, "finalizing it\n"); +} + +static JSClass its_class = { + "It", JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE, + its_addProperty, its_delProperty, its_getProperty, its_setProperty, + (JSEnumerateOp)its_enumerate, (JSResolveOp)its_resolve, + its_convert, its_finalize, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +JSErrorFormatString jsShell_ErrorFormatString[JSErr_Limit] = { +#define MSG_DEF(name, number, count, exception, format) \ + { format, count, JSEXN_ERR } , +#include "jsshell.msg" +#undef MSG_DEF +}; + +static const JSErrorFormatString * +my_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber) +{ + if ((errorNumber > 0) && (errorNumber < JSShellErr_Limit)) + return &jsShell_ErrorFormatString[errorNumber]; + return NULL; +} + +static void +my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) +{ + int i, j, k, n; + char *prefix, *tmp; + const char *ctmp; + + if (!report) { + fprintf(gErrFile, "%s\n", message); + return; + } + + /* Conditionally ignore reported warnings. */ + if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) + return; + + prefix = NULL; + if (report->filename) + prefix = JS_smprintf("%s:", report->filename); + if (report->lineno) { + tmp = prefix; + prefix = JS_smprintf("%s%u: ", tmp ? tmp : "", report->lineno); + JS_free(cx, tmp); + } + if (JSREPORT_IS_WARNING(report->flags)) { + tmp = prefix; + prefix = JS_smprintf("%s%swarning: ", + tmp ? tmp : "", + JSREPORT_IS_STRICT(report->flags) ? "strict " : ""); + JS_free(cx, tmp); + } + + /* embedded newlines -- argh! */ + while ((ctmp = strchr(message, '\n')) != 0) { + ctmp++; + if (prefix) + fputs(prefix, gErrFile); + fwrite(message, 1, ctmp - message, gErrFile); + message = ctmp; + } + + /* If there were no filename or lineno, the prefix might be empty */ + if (prefix) + fputs(prefix, gErrFile); + fputs(message, gErrFile); + + if (!report->linebuf) { + fputc('\n', gErrFile); + goto out; + } + + /* report->linebuf usually ends with a newline. */ + n = strlen(report->linebuf); + fprintf(gErrFile, ":\n%s%s%s%s", + prefix, + report->linebuf, + (n > 0 && report->linebuf[n-1] == '\n') ? "" : "\n", + prefix); + n = PTRDIFF(report->tokenptr, report->linebuf, char); + for (i = j = 0; i < n; i++) { + if (report->linebuf[i] == '\t') { + for (k = (j + 8) & ~7; j < k; j++) { + fputc('.', gErrFile); + } + continue; + } + fputc('.', gErrFile); + j++; + } + fputs("^\n", gErrFile); + out: + if (!JSREPORT_IS_WARNING(report->flags)) { + if (report->errorNumber == JSMSG_OUT_OF_MEMORY) { + gExitCode = EXITCODE_OUT_OF_MEMORY; + } else { + gExitCode = EXITCODE_RUNTIME_ERROR; + } + } + JS_free(cx, prefix); +} + +#if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX) +static JSBool +Exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFunction *fun; + const char *name, **nargv; + uintN i, nargc; + JSString *str; + pid_t pid; + int status; + + fun = JS_ValueToFunction(cx, argv[-2]); + if (!fun) + return JS_FALSE; + if (!fun->atom) + return JS_TRUE; + name = JS_GetStringBytes(ATOM_TO_STRING(fun->atom)); + nargc = 1 + argc; + nargv = JS_malloc(cx, (nargc + 1) * sizeof(char *)); + if (!nargv) + return JS_FALSE; + nargv[0] = name; + for (i = 1; i < nargc; i++) { + str = JS_ValueToString(cx, argv[i-1]); + if (!str) { + JS_free(cx, nargv); + return JS_FALSE; + } + nargv[i] = JS_GetStringBytes(str); + } + nargv[nargc] = 0; + pid = fork(); + switch (pid) { + case -1: + perror("js"); + break; + case 0: + (void) execvp(name, (char **)nargv); + perror("js"); + exit(127); + default: + while (waitpid(pid, &status, 0) < 0 && errno == EINTR) + continue; + break; + } + JS_free(cx, nargv); + return JS_TRUE; +} +#endif + +static JSBool +global_enumerate(JSContext *cx, JSObject *obj) +{ +#ifdef LAZY_STANDARD_CLASSES + return JS_EnumerateStandardClasses(cx, obj); +#else + return JS_TRUE; +#endif +} + +static JSBool +global_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp) +{ +#ifdef LAZY_STANDARD_CLASSES + if ((flags & JSRESOLVE_ASSIGNING) == 0) { + JSBool resolved; + + if (!JS_ResolveStandardClass(cx, obj, id, &resolved)) + return JS_FALSE; + if (resolved) { + *objp = obj; + return JS_TRUE; + } + } +#endif + +#if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX) + if ((flags & (JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING)) == 0) { + /* + * Do this expensive hack only for unoptimized Unix builds, which are + * not used for benchmarking. + */ + char *path, *comp, *full; + const char *name; + JSBool ok, found; + JSFunction *fun; + + if (!JSVAL_IS_STRING(id)) + return JS_TRUE; + path = getenv("PATH"); + if (!path) + return JS_TRUE; + path = JS_strdup(cx, path); + if (!path) + return JS_FALSE; + name = JS_GetStringBytes(JSVAL_TO_STRING(id)); + ok = JS_TRUE; + for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) { + if (*comp != '\0') { + full = JS_smprintf("%s/%s", comp, name); + if (!full) { + JS_ReportOutOfMemory(cx); + ok = JS_FALSE; + break; + } + } else { + full = (char *)name; + } + found = (access(full, X_OK) == 0); + if (*comp != '\0') + free(full); + if (found) { + fun = JS_DefineFunction(cx, obj, name, Exec, 0, + JSPROP_ENUMERATE); + ok = (fun != NULL); + if (ok) + *objp = obj; + break; + } + } + JS_free(cx, path); + return ok; + } +#else + return JS_TRUE; +#endif +} + +JSClass global_class = { + "global", JSCLASS_NEW_RESOLVE | JSCLASS_GLOBAL_FLAGS, + JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_PropertyStub, + global_enumerate, (JSResolveOp) global_resolve, + JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSBool +env_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ +/* XXX porting may be easy, but these don't seem to supply setenv by default */ +#if !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS + JSString *idstr, *valstr; + const char *name, *value; + int rv; + + idstr = JS_ValueToString(cx, id); + valstr = JS_ValueToString(cx, *vp); + if (!idstr || !valstr) + return JS_FALSE; + name = JS_GetStringBytes(idstr); + value = JS_GetStringBytes(valstr); +#if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX + { + char *waste = JS_smprintf("%s=%s", name, value); + if (!waste) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + rv = putenv(waste); +#ifdef XP_WIN + /* + * HPUX9 at least still has the bad old non-copying putenv. + * + * Per mail from , OSF1 also has a putenv + * that will crash if you pass it an auto char array (so it must place + * its argument directly in the char *environ[] array). + */ + free(waste); +#endif + } +#else + rv = setenv(name, value, 1); +#endif + if (rv < 0) { + JS_ReportError(cx, "can't set envariable %s to %s", name, value); + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(valstr); +#endif /* !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS */ + return JS_TRUE; +} + +static JSBool +env_enumerate(JSContext *cx, JSObject *obj) +{ + static JSBool reflected; + char **evp, *name, *value; + JSString *valstr; + JSBool ok; + + if (reflected) + return JS_TRUE; + + for (evp = (char **)JS_GetPrivate(cx, obj); (name = *evp) != NULL; evp++) { + value = strchr(name, '='); + if (!value) + continue; + *value++ = '\0'; + valstr = JS_NewStringCopyZ(cx, value); + if (!valstr) { + ok = JS_FALSE; + } else { + ok = JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr), + NULL, NULL, JSPROP_ENUMERATE); + } + value[-1] = '='; + if (!ok) + return JS_FALSE; + } + + reflected = JS_TRUE; + return JS_TRUE; +} + +static JSBool +env_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp) +{ + JSString *idstr, *valstr; + const char *name, *value; + + if (flags & JSRESOLVE_ASSIGNING) + return JS_TRUE; + + idstr = JS_ValueToString(cx, id); + if (!idstr) + return JS_FALSE; + name = JS_GetStringBytes(idstr); + value = getenv(name); + if (value) { + valstr = JS_NewStringCopyZ(cx, value); + if (!valstr) + return JS_FALSE; + if (!JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr), + NULL, NULL, JSPROP_ENUMERATE)) { + return JS_FALSE; + } + *objp = obj; + } + return JS_TRUE; +} + +static JSClass env_class = { + "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE, + JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, env_setProperty, + env_enumerate, (JSResolveOp) env_resolve, + JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +#ifdef NARCISSUS + +static JSBool +defineProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + JSString *str; + jsval value; + JSBool dontDelete, readOnly, dontEnum; + const jschar *chars; + size_t length; + uintN attrs; + + dontDelete = readOnly = dontEnum = JS_FALSE; + if (!JS_ConvertArguments(cx, argc, argv, "Sv/bbb", + &str, &value, &dontDelete, &readOnly, &dontEnum)) { + return JS_FALSE; + } + chars = JS_GetStringChars(str); + length = JS_GetStringLength(str); + attrs = dontEnum ? 0 : JSPROP_ENUMERATE; + if (dontDelete) + attrs |= JSPROP_PERMANENT; + if (readOnly) + attrs |= JSPROP_READONLY; + return JS_DefineUCProperty(cx, obj, chars, length, value, NULL, NULL, + attrs); +} + +static JSBool +Evaluate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + /* function evaluate(source, filename, lineno) { ... } */ + JSString *source; + const char *filename = ""; + jsuint lineno = 0; + uint32 oldopts; + JSBool ok; + + if (argc == 0) { + *rval = JSVAL_VOID; + return JS_TRUE; + } + + if (!JS_ConvertArguments(cx, argc, argv, "S/su", + &source, &filename, &lineno)) { + return JS_FALSE; + } + + oldopts = JS_GetOptions(cx); + JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO); + ok = JS_EvaluateUCScript(cx, obj, JS_GetStringChars(source), + JS_GetStringLength(source), filename, + lineno, rval); + JS_SetOptions(cx, oldopts); + + return ok; +} + +#include +#include + +/* + * Returns a JS_malloc'd string (that the caller needs to JS_free) + * containing the directory (non-leaf) part of |from| prepended to |leaf|. + * If |from| is empty or a leaf, MakeAbsolutePathname returns a copy of leaf. + * Returns NULL to indicate an error. + */ +static char * +MakeAbsolutePathname(JSContext *cx, const char *from, const char *leaf) +{ + size_t dirlen; + char *dir; + const char *slash = NULL, *cp; + + cp = from; + while (*cp) { + if (*cp == '/' +#ifdef XP_WIN + || *cp == '\\' +#endif + ) { + slash = cp; + } + + ++cp; + } + + if (!slash) { + /* We were given a leaf or |from| was empty. */ + return JS_strdup(cx, leaf); + } + + /* Else, we were given a real pathname, return that + the leaf. */ + dirlen = slash - from + 1; + dir = (char*) JS_malloc(cx, dirlen + strlen(leaf) + 1); + if (!dir) + return NULL; + + strncpy(dir, from, dirlen); + strcpy(dir + dirlen, leaf); /* Note: we can't use strcat here. */ + + return dir; +} + +static JSBool +snarf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSString *str; + const char *filename; + char *pathname; + JSStackFrame *fp; + JSBool ok; + off_t cc, len; + char *buf; + FILE *file; + + str = JS_ValueToString(cx, argv[0]); + if (!str) + return JS_FALSE; + filename = JS_GetStringBytes(str); + + /* Get the currently executing script's name. */ + fp = JS_GetScriptedCaller(cx, NULL); + JS_ASSERT(fp && fp->script->filename); + pathname = MakeAbsolutePathname(cx, fp->script->filename, filename); + if (!pathname) + return JS_FALSE; + + ok = JS_FALSE; + len = 0; + buf = NULL; + file = fopen(pathname, "rb"); + if (!file) { + JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno)); + } else { + if (fseek(file, 0, SEEK_END) == EOF) { + JS_ReportError(cx, "can't seek end of %s", pathname); + } else { + len = ftell(file); + if (len == -1 || fseek(file, 0, SEEK_SET) == EOF) { + JS_ReportError(cx, "can't seek start of %s", pathname); + } else { + buf = (char*) JS_malloc(cx, len + 1); + if (buf) { + cc = fread(buf, 1, len, file); + if (cc != len) { + JS_free(cx, buf); + JS_ReportError(cx, "can't read %s: %s", pathname, + (cc < 0) ? strerror(errno) + : "short read"); + } else { + len = (size_t)cc; + ok = JS_TRUE; + } + } + } + } + fclose(file); + } + JS_free(cx, pathname); + if (!ok) { + JS_free(cx, buf); + return ok; + } + + buf[len] = '\0'; + str = JS_NewString(cx, buf, len); + if (!str) { + JS_free(cx, buf); + return JS_FALSE; + } + *rval = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +#endif /* NARCISSUS */ + +static JSBool +ContextCallback(JSContext *cx, uintN contextOp) +{ + if (contextOp == JSCONTEXT_NEW) { + JS_SetErrorReporter(cx, my_ErrorReporter); + JS_SetVersion(cx, JSVERSION_LATEST); + SetContextOptions(cx); + } + return JS_TRUE; +} + +int +main(int argc, char **argv, char **envp) +{ + int stackDummy; + JSRuntime *rt; + JSContext *cx; + JSObject *glob, *it, *envobj; + int result; +#ifdef LIVECONNECT + JavaVM *java_vm = NULL; +#endif +#ifdef JSDEBUGGER + JSDContext *jsdc; +#ifdef JSDEBUGGER_JAVA_UI + JNIEnv *java_env; + JSDJContext *jsdjc; +#endif +#ifdef JSDEBUGGER_C_UI + JSBool jsdbc; +#endif /* JSDEBUGGER_C_UI */ +#endif /* JSDEBUGGER */ + + CheckHelpMessages(); + setlocale(LC_ALL, ""); + + gStackBase = (jsuword)&stackDummy; + +#ifdef XP_OS2 + /* these streams are normally line buffered on OS/2 and need a \n, * + * so we need to unbuffer then to get a reasonable prompt */ + setbuf(stdout,0); + setbuf(stderr,0); +#endif + + gErrFile = stderr; + gOutFile = stdout; + + argc--; + argv++; + + rt = JS_NewRuntime(64L * 1024L * 1024L); + if (!rt) + return 1; + JS_SetContextCallback(rt, ContextCallback); + + cx = JS_NewContext(rt, gStackChunkSize); + if (!cx) + return 1; + +#ifdef JS_THREADSAFE + JS_BeginRequest(cx); +#endif + + glob = JS_NewObject(cx, &global_class, NULL, NULL); + if (!glob) + return 1; +#ifdef LAZY_STANDARD_CLASSES + JS_SetGlobalObject(cx, glob); +#else + if (!JS_InitStandardClasses(cx, glob)) + return 1; +#endif + if (!JS_DefineFunctions(cx, glob, shell_functions)) + return 1; + + it = JS_DefineObject(cx, glob, "it", &its_class, NULL, 0); + if (!it) + return 1; + if (!JS_DefineProperties(cx, it, its_props)) + return 1; + if (!JS_DefineFunctions(cx, it, its_methods)) + return 1; + +#ifdef JSDEBUGGER + /* + * XXX A command line option to enable debugging (or not) would be good + */ + jsdc = JSD_DebuggerOnForUser(rt, NULL, NULL); + if (!jsdc) + return 1; + JSD_JSContextInUse(jsdc, cx); +#ifdef JSD_LOWLEVEL_SOURCE + JS_SetSourceHandler(rt, SendSourceToJSDebugger, jsdc); +#endif /* JSD_LOWLEVEL_SOURCE */ +#ifdef JSDEBUGGER_JAVA_UI + jsdjc = JSDJ_CreateContext(); + if (! jsdjc) + return 1; + JSDJ_SetJSDContext(jsdjc, jsdc); + java_env = JSDJ_CreateJavaVMAndStartDebugger(jsdjc); +#ifdef LIVECONNECT + if (java_env) + (*java_env)->GetJavaVM(java_env, &java_vm); +#endif + /* + * XXX This would be the place to wait for the debugger to start. + * Waiting would be nice in general, but especially when a js file + * is passed on the cmd line. + */ +#endif /* JSDEBUGGER_JAVA_UI */ +#ifdef JSDEBUGGER_C_UI + jsdbc = JSDB_InitDebugger(rt, jsdc, 0); +#endif /* JSDEBUGGER_C_UI */ +#endif /* JSDEBUGGER */ + +#ifdef LIVECONNECT + if (!JSJ_SimpleInit(cx, glob, java_vm, getenv("CLASSPATH"))) + return 1; +#endif + + envobj = JS_DefineObject(cx, glob, "environment", &env_class, NULL, 0); + if (!envobj || !JS_SetPrivate(cx, envobj, envp)) + return 1; + +#ifdef NARCISSUS + { + jsval v; + static const char Object_prototype[] = "Object.prototype"; + + if (!JS_DefineFunction(cx, glob, "snarf", snarf, 1, 0)) + return 1; + if (!JS_DefineFunction(cx, glob, "evaluate", Evaluate, 3, 0)) + return 1; + + if (!JS_EvaluateScript(cx, glob, + Object_prototype, sizeof Object_prototype - 1, + NULL, 0, &v)) { + return 1; + } + if (!JS_DefineFunction(cx, JSVAL_TO_OBJECT(v), "__defineProperty__", + defineProperty, 5, 0)) { + return 1; + } + } +#endif + + result = ProcessArgs(cx, glob, argv, argc); + +#ifdef JSDEBUGGER + if (jsdc) { +#ifdef JSDEBUGGER_C_UI + if (jsdbc) + JSDB_TermDebugger(jsdc); +#endif /* JSDEBUGGER_C_UI */ + JSD_DebuggerOff(jsdc); + } +#endif /* JSDEBUGGER */ + +#ifdef JS_THREADSAFE + JS_EndRequest(cx); +#endif + + JS_DestroyContext(cx); + JS_DestroyRuntime(rt); + JS_ShutDown(); + return result; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.mdp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.mdp new file mode 100644 index 0000000000000000000000000000000000000000..8da64fb6b61a5a047ac54c88020cf397fa7eaa25 GIT binary patch literal 17922 zcmeI3-A)rh6vxj}3RDD&d|#MMV&sNEPuNv)f8dOnd+p zzn{e$6YhNi?|2EX)acnQgDY|a;b!UCWV@63|IgWTeltmvNxQmvcQFOMum#Wqbafqp z-*j~~frGB@o|<2Sd3X%hU>ZUe!_g;E=^g^HFT9`K(=~N!2=qcf47Th_&0ktvsJALV z_P(WOMQm5lkO&X~B0vO)01+SpM1Tko0U|&IhyW2tJb^Ek)njD=KEonp`@bi?A8O!q z1k%ulCqM&`flDw5mtp91;p9#-48~ysCSmFfIVdEl1TuK`n>sB1>yua)(V<}Uhmc4P zcSRbk+nKzQfmYspKJfu8zqq~EY)EJ*Ka7_jq5K_pU7#=+iY1irQ=5_ zgd-eN#w&D8u6T+EtRSS)b*yH+AvBjqme*(*KeV_l*AcAJW?MollVk6%p(w>Jw*z)x z_)YH!+#57ZbuttWi;dn9FZC^YhC811meAXtdTR2&Lus@lZ3f(~vHXs(Yes#K>PSa@ zAf10BKcF^Ql!2%UjeJfj{v%ql#&Z14pThVJje)pM!Z~T3exYT!Q`Yh5WefIa3Z)W; z;i}*oJ&Se>Tj7}Q2(Rte52nhlt(C8~1D2ng`+uFoJ=%+R-yV9tJ==Y!JgEEm>X5bG% C_`cBq literal 0 HcmV?d00001 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.msg b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.msg new file mode 100644 index 0000000..f3a711b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js.msg @@ -0,0 +1,309 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This is the JavaScript error message file. + * + * The format for each JS error message is: + * + * MSG_DEF(, , , , + * ) + * + * where ; + * is a legal C identifer that will be used in the + * JS engine source. + * + * is an unique integral value identifying this error. + * + * is an integer literal specifying the total number of + * replaceable arguments in the following format string. + * + * is an exception index from the enum in jsexn.c; + * JSEXN_NONE for none. The given exception index will be raised by the + * engine when the corresponding error occurs. + * + * is a string literal, optionally containing sequences + * {X} where X is an integer representing the argument number that will + * be replaced with a string value when the error is reported. + * + * e.g. + * + * MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 73, JSEXN_NONE, 2, + * "{0} is not a member of the {1} family") + * + * can be used: + * + * JS_ReportErrorNumber(JSMSG_NOT_A_SUBSPECIES, "Rhino", "Monkey"); + * + * to report: + * + * "Rhino is not a member of the Monkey family" + * + * Before adding a new MSG_DEF at the end, look for JSMSG_UNUSED free + * index placeholders in the middle of the list. + */ + +MSG_DEF(JSMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "") +MSG_DEF(JSMSG_NOT_DEFINED, 1, 1, JSEXN_REFERENCEERR, "{0} is not defined") +MSG_DEF(JSMSG_INACTIVE, 2, 0, JSEXN_INTERNALERR, "nothing active on context") +MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, 3, JSEXN_TYPEERR, "{0} requires more than {1} argument{2}") +MSG_DEF(JSMSG_BAD_CHAR, 4, 1, JSEXN_INTERNALERR, "invalid format character {0}") +MSG_DEF(JSMSG_BAD_TYPE, 5, 1, JSEXN_TYPEERR, "unknown type {0}") +MSG_DEF(JSMSG_ALLOC_OVERFLOW, 6, 0, JSEXN_INTERNALERR, "allocation size overflow") +MSG_DEF(JSMSG_CANT_UNLOCK, 7, 0, JSEXN_INTERNALERR, "can't unlock memory") +MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 8, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}") +MSG_DEF(JSMSG_NO_CONSTRUCTOR, 9, 1, JSEXN_TYPEERR, "{0} has no constructor") +MSG_DEF(JSMSG_CANT_ALIAS, 10, 3, JSEXN_TYPEERR, "can't alias {0} to {1} in class {2}") +MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION, 11, 1, JSEXN_TYPEERR, "{0} is not a scripted function") +MSG_DEF(JSMSG_BAD_SORT_ARG, 12, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument") +MSG_DEF(JSMSG_BAD_ATOMIC_NUMBER, 13, 1, JSEXN_INTERNALERR, "internal error: no index for atom {0}") +MSG_DEF(JSMSG_TOO_MANY_LITERALS, 14, 0, JSEXN_INTERNALERR, "too many literals") +MSG_DEF(JSMSG_CANT_WATCH, 15, 1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}") +MSG_DEF(JSMSG_STACK_UNDERFLOW, 16, 2, JSEXN_INTERNALERR, "internal error compiling {0}: stack underflow at pc {1}") +MSG_DEF(JSMSG_NEED_DIET, 17, 1, JSEXN_INTERNALERR, "{0} too large") +MSG_DEF(JSMSG_TOO_MANY_LOCAL_ROOTS, 18, 0, JSEXN_ERR, "out of local root space") +MSG_DEF(JSMSG_READ_ONLY, 19, 1, JSEXN_ERR, "{0} is read-only") +MSG_DEF(JSMSG_BAD_FORMAL, 20, 0, JSEXN_SYNTAXERR, "malformed formal parameter") +MSG_DEF(JSMSG_BAD_ITERATOR, 21, 3, JSEXN_TYPEERR, "{0} has invalid {1} value {2}") +MSG_DEF(JSMSG_NOT_FUNCTION, 22, 1, JSEXN_TYPEERR, "{0} is not a function") +MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 23, 1, JSEXN_TYPEERR, "{0} is not a constructor") +MSG_DEF(JSMSG_SCRIPT_STACK_QUOTA, 24, 0, JSEXN_INTERNALERR, "script stack space quota is exhausted") +MSG_DEF(JSMSG_TOO_DEEP, 25, 1, JSEXN_INTERNALERR, "{0} nested too deeply") +MSG_DEF(JSMSG_OVER_RECURSED, 26, 0, JSEXN_INTERNALERR, "too much recursion") +MSG_DEF(JSMSG_IN_NOT_OBJECT, 27, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}") +MSG_DEF(JSMSG_BAD_NEW_RESULT, 28, 1, JSEXN_TYPEERR, "invalid new expression result {0}") +MSG_DEF(JSMSG_BAD_SHARP_DEF, 29, 1, JSEXN_ERR, "invalid sharp variable definition #{0}=") +MSG_DEF(JSMSG_BAD_SHARP_USE, 30, 1, JSEXN_ERR, "invalid sharp variable use #{0}#") +MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 31, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}") +MSG_DEF(JSMSG_BAD_BYTECODE, 32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}") +MSG_DEF(JSMSG_BAD_RADIX, 33, 1, JSEXN_ERR, "illegal radix {0}") +MSG_DEF(JSMSG_PAREN_BEFORE_LET, 34, 0, JSEXN_SYNTAXERR, "missing ( before let head") +MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_ERR, "can't convert {0} to an integer") +MSG_DEF(JSMSG_CYCLIC_VALUE, 36, 1, JSEXN_ERR, "cyclic {0} value") +MSG_DEF(JSMSG_COMPILE_EXECED_SCRIPT, 37, 0, JSEXN_TYPEERR, "cannot compile over a script that is currently executing") +MSG_DEF(JSMSG_CANT_CONVERT_TO, 38, 2, JSEXN_TYPEERR, "can't convert {0} to {1}") +MSG_DEF(JSMSG_NO_PROPERTIES, 39, 1, JSEXN_TYPEERR, "{0} has no properties") +MSG_DEF(JSMSG_CANT_FIND_CLASS, 40, 1, JSEXN_TYPEERR, "can't find class id {0}") +MSG_DEF(JSMSG_CANT_XDR_CLASS, 41, 1, JSEXN_TYPEERR, "can't XDR class {0}") +MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 42, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})") +MSG_DEF(JSMSG_UNKNOWN_FORMAT, 43, 1, JSEXN_INTERNALERR, "unknown bytecode format {0}") +MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 44, 0, JSEXN_SYNTAXERR, "too many constructor arguments") +MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS, 45, 0, JSEXN_SYNTAXERR, "too many function arguments") +MSG_DEF(JSMSG_BAD_QUANTIFIER, 46, 1, JSEXN_SYNTAXERR, "invalid quantifier {0}") +MSG_DEF(JSMSG_MIN_TOO_BIG, 47, 1, JSEXN_SYNTAXERR, "overlarge minimum {0}") +MSG_DEF(JSMSG_MAX_TOO_BIG, 48, 1, JSEXN_SYNTAXERR, "overlarge maximum {0}") +MSG_DEF(JSMSG_OUT_OF_ORDER, 49, 1, JSEXN_SYNTAXERR, "maximum {0} less than minimum") +MSG_DEF(JSMSG_BAD_DESTRUCT_DECL, 50, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration") +MSG_DEF(JSMSG_BAD_DESTRUCT_ASS, 51, 0, JSEXN_SYNTAXERR, "invalid destructuring assignment operator") +MSG_DEF(JSMSG_PAREN_AFTER_LET, 52, 0, JSEXN_SYNTAXERR, "missing ) after let head") +MSG_DEF(JSMSG_CURLY_AFTER_LET, 53, 0, JSEXN_SYNTAXERR, "missing } after let block") +MSG_DEF(JSMSG_MISSING_PAREN, 54, 0, JSEXN_SYNTAXERR, "unterminated parenthetical") +MSG_DEF(JSMSG_UNTERM_CLASS, 55, 1, JSEXN_SYNTAXERR, "unterminated character class {0}") +MSG_DEF(JSMSG_TRAILING_SLASH, 56, 0, JSEXN_SYNTAXERR, "trailing \\ in regular expression") +MSG_DEF(JSMSG_BAD_CLASS_RANGE, 57, 0, JSEXN_SYNTAXERR, "invalid range in character class") +MSG_DEF(JSMSG_BAD_FLAG, 58, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}") +MSG_DEF(JSMSG_NO_INPUT, 59, 5, JSEXN_SYNTAXERR, "no input for /{0}/{1}{2}{3}{4}") +MSG_DEF(JSMSG_CANT_OPEN, 60, 2, JSEXN_ERR, "can't open {0}: {1}") +MSG_DEF(JSMSG_BAD_STRING_MASK, 61, 1, JSEXN_ERR, "invalid string escape mask {0}") +MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 62, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") +MSG_DEF(JSMSG_END_OF_DATA, 63, 0, JSEXN_INTERNALERR, "unexpected end of data") +MSG_DEF(JSMSG_SEEK_BEYOND_START, 64, 0, JSEXN_INTERNALERR, "illegal seek beyond start") +MSG_DEF(JSMSG_SEEK_BEYOND_END, 65, 0, JSEXN_INTERNALERR, "illegal seek beyond end") +MSG_DEF(JSMSG_END_SEEK, 66, 0, JSEXN_INTERNALERR, "illegal end-based seek") +MSG_DEF(JSMSG_WHITHER_WHENCE, 67, 1, JSEXN_INTERNALERR, "unknown seek whence: {0}") +MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC, 68, 0, JSEXN_INTERNALERR, "bad script XDR magic number") +MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL, 69, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters") +MSG_DEF(JSMSG_MISSING_FORMAL, 70, 0, JSEXN_SYNTAXERR, "missing formal parameter") +MSG_DEF(JSMSG_PAREN_AFTER_FORMAL, 71, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters") +MSG_DEF(JSMSG_CURLY_BEFORE_BODY, 72, 0, JSEXN_SYNTAXERR, "missing { before function body") +MSG_DEF(JSMSG_CURLY_AFTER_BODY, 73, 0, JSEXN_SYNTAXERR, "missing } after function body") +MSG_DEF(JSMSG_PAREN_BEFORE_COND, 74, 0, JSEXN_SYNTAXERR, "missing ( before condition") +MSG_DEF(JSMSG_PAREN_AFTER_COND, 75, 0, JSEXN_SYNTAXERR, "missing ) after condition") +MSG_DEF(JSMSG_UNUSED76, 76, 0, JSEXN_NONE, "unused76") +MSG_DEF(JSMSG_NAME_AFTER_DOT, 77, 0, JSEXN_SYNTAXERR, "missing name after . operator") +MSG_DEF(JSMSG_BRACKET_IN_INDEX, 78, 0, JSEXN_SYNTAXERR, "missing ] in index expression") +MSG_DEF(JSMSG_UNUSED79, 79, 0, JSEXN_NONE, "unused79") +MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH, 80, 0, JSEXN_SYNTAXERR, "missing ( before switch expression") +MSG_DEF(JSMSG_PAREN_AFTER_SWITCH, 81, 0, JSEXN_SYNTAXERR, "missing ) after switch expression") +MSG_DEF(JSMSG_CURLY_BEFORE_SWITCH, 82, 0, JSEXN_SYNTAXERR, "missing { before switch body") +MSG_DEF(JSMSG_COLON_AFTER_CASE, 83, 0, JSEXN_SYNTAXERR, "missing : after case label") +MSG_DEF(JSMSG_WHILE_AFTER_DO, 84, 0, JSEXN_SYNTAXERR, "missing while after do-loop body") +MSG_DEF(JSMSG_PAREN_AFTER_FOR, 85, 0, JSEXN_SYNTAXERR, "missing ( after for") +MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT, 86, 0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer") +MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND, 87, 0, JSEXN_SYNTAXERR, "missing ; after for-loop condition") +MSG_DEF(JSMSG_PAREN_AFTER_FOR_CTRL, 88, 0, JSEXN_SYNTAXERR, "missing ) after for-loop control") +MSG_DEF(JSMSG_CURLY_BEFORE_TRY, 89, 0, JSEXN_SYNTAXERR, "missing { before try block") +MSG_DEF(JSMSG_CURLY_AFTER_TRY, 90, 0, JSEXN_SYNTAXERR, "missing } after try block") +MSG_DEF(JSMSG_PAREN_BEFORE_CATCH, 91, 0, JSEXN_SYNTAXERR, "missing ( before catch") +MSG_DEF(JSMSG_CATCH_IDENTIFIER, 92, 0, JSEXN_SYNTAXERR, "missing identifier in catch") +MSG_DEF(JSMSG_PAREN_AFTER_CATCH, 93, 0, JSEXN_SYNTAXERR, "missing ) after catch") +MSG_DEF(JSMSG_CURLY_BEFORE_CATCH, 94, 0, JSEXN_SYNTAXERR, "missing { before catch block") +MSG_DEF(JSMSG_CURLY_AFTER_CATCH, 95, 0, JSEXN_SYNTAXERR, "missing } after catch block") +MSG_DEF(JSMSG_CURLY_BEFORE_FINALLY, 96, 0, JSEXN_SYNTAXERR, "missing { before finally block") +MSG_DEF(JSMSG_CURLY_AFTER_FINALLY, 97, 0, JSEXN_SYNTAXERR, "missing } after finally block") +MSG_DEF(JSMSG_CATCH_OR_FINALLY, 98, 0, JSEXN_SYNTAXERR, "missing catch or finally after try") +MSG_DEF(JSMSG_PAREN_BEFORE_WITH, 99, 0, JSEXN_SYNTAXERR, "missing ( before with-statement object") +MSG_DEF(JSMSG_PAREN_AFTER_WITH, 100, 0, JSEXN_SYNTAXERR, "missing ) after with-statement object") +MSG_DEF(JSMSG_CURLY_IN_COMPOUND, 101, 0, JSEXN_SYNTAXERR, "missing } in compound statement") +MSG_DEF(JSMSG_NO_VARIABLE_NAME, 102, 0, JSEXN_SYNTAXERR, "missing variable name") +MSG_DEF(JSMSG_COLON_IN_COND, 103, 0, JSEXN_SYNTAXERR, "missing : in conditional expression") +MSG_DEF(JSMSG_PAREN_AFTER_ARGS, 104, 0, JSEXN_SYNTAXERR, "missing ) after argument list") +MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 105, 0, JSEXN_SYNTAXERR, "missing ] after element list") +MSG_DEF(JSMSG_COLON_AFTER_ID, 106, 0, JSEXN_SYNTAXERR, "missing : after property id") +MSG_DEF(JSMSG_CURLY_AFTER_LIST, 107, 0, JSEXN_SYNTAXERR, "missing } after property list") +MSG_DEF(JSMSG_PAREN_IN_PAREN, 108, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical") +MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 109, 0, JSEXN_SYNTAXERR, "missing ; before statement") +MSG_DEF(JSMSG_NO_RETURN_VALUE, 110, 1, JSEXN_TYPEERR, "function {0} does not always return a value") +MSG_DEF(JSMSG_DUPLICATE_FORMAL, 111, 1, JSEXN_TYPEERR, "duplicate formal argument {0}") +MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 112, 1, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?{0}") +MSG_DEF(JSMSG_UNUSED113, 113, 0, JSEXN_NONE, "unused113") +MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 114, 0, JSEXN_SYNTAXERR, "more than one switch default") +MSG_DEF(JSMSG_TOO_MANY_CASES, 115, 0, JSEXN_INTERNALERR, "too many switch cases") +MSG_DEF(JSMSG_BAD_SWITCH, 116, 0, JSEXN_SYNTAXERR, "invalid switch statement") +MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 117, 0, JSEXN_SYNTAXERR, "invalid for/in left-hand side") +MSG_DEF(JSMSG_CATCH_AFTER_GENERAL, 118, 0, JSEXN_SYNTAXERR, "catch after unconditional catch") +MSG_DEF(JSMSG_CATCH_WITHOUT_TRY, 119, 0, JSEXN_SYNTAXERR, "catch without try") +MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 120, 0, JSEXN_SYNTAXERR, "finally without try") +MSG_DEF(JSMSG_LABEL_NOT_FOUND, 121, 0, JSEXN_SYNTAXERR, "label not found") +MSG_DEF(JSMSG_TOUGH_BREAK, 122, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch") +MSG_DEF(JSMSG_BAD_CONTINUE, 123, 0, JSEXN_SYNTAXERR, "continue must be inside loop") +MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 124, 1, JSEXN_SYNTAXERR, "{0} not in function") +MSG_DEF(JSMSG_BAD_LABEL, 125, 0, JSEXN_SYNTAXERR, "invalid label") +MSG_DEF(JSMSG_DUPLICATE_LABEL, 126, 0, JSEXN_SYNTAXERR, "duplicate label") +MSG_DEF(JSMSG_VAR_HIDES_ARG, 127, 1, JSEXN_TYPEERR, "variable {0} redeclares argument") +MSG_DEF(JSMSG_BAD_VAR_INIT, 128, 0, JSEXN_SYNTAXERR, "invalid variable initialization") +MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 129, 0, JSEXN_SYNTAXERR, "invalid assignment left-hand side") +MSG_DEF(JSMSG_BAD_OPERAND, 130, 1, JSEXN_SYNTAXERR, "invalid {0} operand") +MSG_DEF(JSMSG_BAD_PROP_ID, 131, 0, JSEXN_SYNTAXERR, "invalid property id") +MSG_DEF(JSMSG_RESERVED_ID, 132, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier") +MSG_DEF(JSMSG_SYNTAX_ERROR, 133, 0, JSEXN_SYNTAXERR, "syntax error") +MSG_DEF(JSMSG_BAD_SHARP_VAR_DEF, 134, 0, JSEXN_SYNTAXERR, "invalid sharp variable definition") +MSG_DEF(JSMSG_BAD_PROTOTYPE, 135, 1, JSEXN_TYPEERR, "'prototype' property of {0} is not an object") +MSG_DEF(JSMSG_MISSING_EXPONENT, 136, 0, JSEXN_SYNTAXERR, "missing exponent") +MSG_DEF(JSMSG_OUT_OF_MEMORY, 137, 0, JSEXN_ERR, "out of memory") +MSG_DEF(JSMSG_UNTERMINATED_STRING, 138, 0, JSEXN_SYNTAXERR, "unterminated string literal") +MSG_DEF(JSMSG_TOO_MANY_PARENS, 139, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression") +MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 140, 0, JSEXN_SYNTAXERR, "unterminated comment") +MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 141, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal") +MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 142, 0, JSEXN_SYNTAXERR, "invalid flag after regular expression") +MSG_DEF(JSMSG_SHARPVAR_TOO_BIG, 143, 0, JSEXN_SYNTAXERR, "overlarge sharp variable number") +MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 144, 0, JSEXN_SYNTAXERR, "illegal character") +MSG_DEF(JSMSG_BAD_OCTAL, 145, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") +MSG_DEF(JSMSG_BAD_INDIRECT_CALL, 146, 1, JSEXN_EVALERR, "function {0} must be called directly, and not by way of a function of another name") +MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 147, 1, JSEXN_INTERNALERR, "uncaught exception: {0}") +MSG_DEF(JSMSG_INVALID_BACKREF, 148, 0, JSEXN_SYNTAXERR, "non-octal digit in an escape sequence that doesn't match a back-reference") +MSG_DEF(JSMSG_BAD_BACKREF, 149, 0, JSEXN_SYNTAXERR, "back-reference exceeds number of capturing parentheses") +MSG_DEF(JSMSG_PRECISION_RANGE, 150, 1, JSEXN_RANGEERR, "precision {0} out of range") +MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 151, 1, JSEXN_SYNTAXERR, "invalid {0} usage") +MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 152, 0, JSEXN_RANGEERR, "invalid array length") +MSG_DEF(JSMSG_CANT_DESCRIBE_PROPS, 153, 1, JSEXN_TYPEERR, "can't describe non-native properties of class {0}") +MSG_DEF(JSMSG_BAD_APPLY_ARGS, 154, 1, JSEXN_TYPEERR, "second argument to Function.prototype.{0} must be an array") +MSG_DEF(JSMSG_REDECLARED_VAR, 155, 2, JSEXN_TYPEERR, "redeclaration of {0} {1}") +MSG_DEF(JSMSG_UNDECLARED_VAR, 156, 1, JSEXN_TYPEERR, "assignment to undeclared variable {0}") +MSG_DEF(JSMSG_ANON_NO_RETURN_VALUE, 157, 0, JSEXN_TYPEERR, "anonymous function does not always return a value") +MSG_DEF(JSMSG_DEPRECATED_USAGE, 158, 1, JSEXN_REFERENCEERR, "deprecated {0} usage") +MSG_DEF(JSMSG_BAD_URI, 159, 0, JSEXN_URIERR, "malformed URI sequence") +MSG_DEF(JSMSG_GETTER_ONLY, 160, 0, JSEXN_TYPEERR, "setting a property that has only a getter") +MSG_DEF(JSMSG_TRAILING_COMMA, 161, 0, JSEXN_SYNTAXERR, "trailing comma is not legal in ECMA-262 object initializers") +MSG_DEF(JSMSG_UNDEFINED_PROP, 162, 1, JSEXN_REFERENCEERR, "reference to undefined property {0}") +MSG_DEF(JSMSG_USELESS_EXPR, 163, 0, JSEXN_TYPEERR, "useless expression") +MSG_DEF(JSMSG_REDECLARED_PARAM, 164, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}") +MSG_DEF(JSMSG_NEWREGEXP_FLAGGED, 165, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another") +MSG_DEF(JSMSG_RESERVED_SLOT_RANGE, 166, 0, JSEXN_RANGEERR, "reserved slot index out of range") +MSG_DEF(JSMSG_CANT_DECODE_PRINCIPALS, 167, 0, JSEXN_INTERNALERR, "can't decode JSPrincipals") +MSG_DEF(JSMSG_CANT_SEAL_OBJECT, 168, 1, JSEXN_ERR, "can't seal {0} objects") +MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS, 169, 0, JSEXN_SYNTAXERR, "too many catch variables") +MSG_DEF(JSMSG_BAD_XML_MARKUP, 170, 0, JSEXN_SYNTAXERR, "invalid XML markup") +MSG_DEF(JSMSG_BAD_XML_CHARACTER, 171, 0, JSEXN_SYNTAXERR, "illegal XML character") +MSG_DEF(JSMSG_BAD_DEFAULT_XML_NAMESPACE,172,0,JSEXN_SYNTAXERR, "invalid default XML namespace") +MSG_DEF(JSMSG_BAD_XML_NAME_SYNTAX, 173, 0, JSEXN_SYNTAXERR, "invalid XML name") +MSG_DEF(JSMSG_BRACKET_AFTER_ATTR_EXPR,174, 0, JSEXN_SYNTAXERR, "missing ] after attribute expression") +MSG_DEF(JSMSG_NESTING_GENERATOR, 175, 1, JSEXN_TYPEERR, "already executing generator {0}") +MSG_DEF(JSMSG_CURLY_IN_XML_EXPR, 176, 0, JSEXN_SYNTAXERR, "missing } in XML expression") +MSG_DEF(JSMSG_BAD_XML_NAMESPACE, 177, 1, JSEXN_TYPEERR, "invalid XML namespace {0}") +MSG_DEF(JSMSG_BAD_XML_ATTR_NAME, 178, 1, JSEXN_TYPEERR, "invalid XML attribute name {0}") +MSG_DEF(JSMSG_BAD_XML_NAME, 179, 1, JSEXN_TYPEERR, "invalid XML name {0}") +MSG_DEF(JSMSG_BAD_XML_CONVERSION, 180, 1, JSEXN_TYPEERR, "can't convert {0} to XML") +MSG_DEF(JSMSG_BAD_XMLLIST_CONVERSION, 181, 1, JSEXN_TYPEERR, "can't convert {0} to XMLList") +MSG_DEF(JSMSG_BAD_GENERATOR_SEND, 182, 1, JSEXN_TYPEERR, "attempt to send {0} to newborn generator") +MSG_DEF(JSMSG_NO_ASSIGN_IN_XML_ATTR, 183, 0, JSEXN_SYNTAXERR, "missing = in XML attribute") +MSG_DEF(JSMSG_BAD_XML_ATTR_VALUE, 184, 0, JSEXN_SYNTAXERR, "invalid XML attribute value") +MSG_DEF(JSMSG_XML_TAG_NAME_MISMATCH, 185, 1, JSEXN_SYNTAXERR, "XML tag name mismatch (expected {0})") +MSG_DEF(JSMSG_BAD_XML_TAG_SYNTAX, 186, 0, JSEXN_SYNTAXERR, "invalid XML tag syntax") +MSG_DEF(JSMSG_BAD_XML_LIST_SYNTAX, 187, 0, JSEXN_SYNTAXERR, "invalid XML list syntax") +MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") +MSG_DEF(JSMSG_CANT_SET_XML_ATTRS, 189, 0, JSEXN_INTERNALERR, "can't set XML property attributes") +MSG_DEF(JSMSG_END_OF_XML_SOURCE, 190, 0, JSEXN_SYNTAXERR, "unexpected end of XML source") +MSG_DEF(JSMSG_END_OF_XML_ENTITY, 191, 0, JSEXN_SYNTAXERR, "unexpected end of XML entity") +MSG_DEF(JSMSG_BAD_XML_QNAME, 192, 0, JSEXN_SYNTAXERR, "invalid XML qualified name") +MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 193, 0, JSEXN_SYNTAXERR, "invalid for each loop") +MSG_DEF(JSMSG_BAD_XMLLIST_PUT, 194, 1, JSEXN_TYPEERR, "can't set property {0} in XMLList") +MSG_DEF(JSMSG_UNKNOWN_XML_ENTITY, 195, 1, JSEXN_TYPEERR, "unknown XML entity {0}") +MSG_DEF(JSMSG_BAD_XML_NCR, 196, 1, JSEXN_TYPEERR, "malformed XML character {0}") +MSG_DEF(JSMSG_UNDEFINED_XML_NAME, 197, 1, JSEXN_REFERENCEERR, "reference to undefined XML name {0}") +MSG_DEF(JSMSG_DUPLICATE_XML_ATTR, 198, 1, JSEXN_TYPEERR, "duplicate XML attribute {0}") +MSG_DEF(JSMSG_TOO_MANY_LOCALS, 199, 0, JSEXN_SYNTAXERR, "too many local variables") +MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 200, 0, JSEXN_INTERNALERR, "array initialiser too large") +MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX, 201, 0, JSEXN_INTERNALERR, "regular expression too complex") +MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 202, 0, JSEXN_INTERNALERR, "buffer too small") +MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 203, 1, JSEXN_TYPEERR, "bad surrogate character {0}") +MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 204, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large") +MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 205, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}") +MSG_DEF(JSMSG_USER_DEFINED_ERROR, 206, 0, JSEXN_ERR, "JS_ReportError was called") +MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 207, 1, JSEXN_TYPEERR, "wrong constructor called for {0}") +MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 208, 1, JSEXN_TYPEERR, "generator function {0} returns a value") +MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 209, 0, JSEXN_TYPEERR, "anonymous generator function returns a value") +MSG_DEF(JSMSG_NAME_AFTER_FOR_PAREN, 210, 0, JSEXN_SYNTAXERR, "missing name after for (") +MSG_DEF(JSMSG_IN_AFTER_FOR_NAME, 211, 0, JSEXN_SYNTAXERR, "missing in after for") +MSG_DEF(JSMSG_BAD_ITERATOR_RETURN, 212, 2, JSEXN_TYPEERR, "{0}.{1} returned a primitive value") +MSG_DEF(JSMSG_KEYWORD_NOT_NS, 213, 0, JSEXN_SYNTAXERR, "keyword is used as namespace") +MSG_DEF(JSMSG_BAD_GENERATOR_YIELD, 214, 1, JSEXN_TYPEERR, "yield from closing generator {0}") +MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 215, 1, JSEXN_SYNTAXERR, "{0} expression must be parenthesized") +MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 216, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side") +MSG_DEF(JSMSG_NON_XML_FILTER, 217, 1, JSEXN_TYPEERR, "XML filter is applied to non-XML value {0}") +MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 218, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value") +MSG_DEF(JSMSG_NON_LIST_XML_METHOD, 219, 2, JSEXN_TYPEERR, "cannot call {0} method on an XML list with {1} elements") +MSG_DEF(JSMSG_BAD_DELETE_OPERAND, 220, 0, JSEXN_SYNTAXERR, "invalid delete operand") +MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 221, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand") +MSG_DEF(JSMSG_NULL_OR_UNDEFINED, 222, 2, JSEXN_TYPEERR, "{0} is {1}") +MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK, 223, 0, JSEXN_SYNTAXERR, "let declaration not directly within block") +MSG_DEF(JSMSG_BAD_OBJECT_INIT, 224, 0, JSEXN_SYNTAXERR, "invalid object initializer") +MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS, 225, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties") +MSG_DEF(JSMSG_EVAL_ARITY, 226, 0, JSEXN_TYPEERR, "eval accepts only one parameter") +MSG_DEF(JSMSG_MISSING_FUN_ARG, 227, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}") diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js3240.rc b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js3240.rc new file mode 100644 index 0000000..1a9f62c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/js3240.rc @@ -0,0 +1,79 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winver.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 4,0,0,0 + PRODUCTVERSION 4,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x10004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "FileDescription", "Netscape 32-bit JavaScript Module\0" + VALUE "FileVersion", "4.0\0" + VALUE "InternalName", "JS3240\0" + VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0" + VALUE "LegalTrademarks", "Netscape, Mozilla\0" + VALUE "OriginalFilename", "js3240.dll\0" + VALUE "ProductName", "NETSCAPE\0" + VALUE "ProductVersion", "4.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winver.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsOS240.def b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsOS240.def new file mode 100644 index 0000000..8f27d64 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsOS240.def @@ -0,0 +1,654 @@ +; ***** BEGIN LICENSE BLOCK ***** +; Version: MPL 1.1/GPL 2.0/LGPL 2.1 +; +; The contents of this file are subject to the Mozilla Public License Version +; 1.1 (the "License"); you may not use this file except in compliance with +; the License. You may obtain a copy of the License at +; http://www.mozilla.org/MPL/ +; +; Software distributed under the License is distributed on an "AS IS" basis, +; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +; for the specific language governing rights and limitations under the +; License. +; +; The Original Code is Mozilla Communicator client code, released +; March 31, 1998. +; +; The Initial Developer of the Original Code is +; Netscape Communications Corporation. +; Portions created by the Initial Developer are Copyright (C) 1998 +; the Initial Developer. All Rights Reserved. +; +; Contributor(s): +; +; Alternatively, the contents of this file may be used under the terms of +; either of the GNU General Public License Version 2 or later (the "GPL"), +; or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +; in which case the provisions of the GPL or the LGPL are applicable instead +; of those above. If you wish to allow use of your version of this file only +; under the terms of either the GPL or the LGPL, and not to allow others to +; use your version of this file under the terms of the MPL, indicate your +; decision by deleting the provisions above and replace them with the notice +; and other provisions required by the GPL or the LGPL. If you do not delete +; the provisions above, a recipient may use your version of this file under +; the terms of any one of the MPL, the GPL or the LGPL. +; +; ***** END LICENSE BLOCK ***** + +LIBRARY JS3240 INITINSTANCE TERMINSTANCE +PROTMODE + +DESCRIPTION 'Netscape OS/2 JavaScript Library' + + +CODE LOADONCALL MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE MULTIPLE NONSHARED + + +EXPORTS +;====================== win16 exports these at least... =========== +; JS_Init = JS_Init @2 +; JS_Finish = JS_Finish @3 +; JS_GetNaNValue +; JS_GetNegativeInfinityValue +; JS_GetPositiveInfinityValue +; JS_GetEmptyStringValue +; JS_ConvertValue +; JS_ValueToObject +; JS_ValueToFunction +; JS_ValueToString +; JS_ValueToNumber +; JS_ValueToBoolean +; JS_TypeOfValue +; JS_GetTypeName +; JS_Lock +; JS_Unlock +; JS_NewContext +; JS_DestroyContext +; JS_ContextIterator +; JS_GetGlobalObject +; JS_SetGlobalObject +; JS_InitStandardClasses +;; JS_GetStaticLink +; JS_malloc +; JS_realloc +; JS_free +; JS_strdup +; JS_NewDouble +; JS_NewDoubleValue +; JS_AddRoot +; JS_RemoveRoot +; JS_LockGCThing +; JS_UnlockGCThing +; JS_GC +; JS_PropertyStub +; JS_EnumerateStub +; JS_ResolveStub +; JS_ConvertStub +; JS_FinalizeStub +; JS_InitClass +; JS_GetClass +; JS_InstanceOf +; JS_GetPrivate +; JS_SetPrivate +; JS_GetInstancePrivate +; JS_GetPrototype +; JS_GetParent +; JS_SetParent +; JS_GetConstructor +; JS_NewObject +; JS_DefineObject +; JS_DefineConstDoubles +; JS_DefineProperties +; JS_DefineProperty +; JS_DefinePropertyWithTinyId +; JS_AliasProperty +; JS_LookupProperty +; JS_GetProperty +; JS_SetProperty +; JS_DeleteProperty +; JS_NewArrayObject +; JS_DefineElement +; JS_AliasElement +; JS_LookupElement +; JS_GetElement +; JS_SetElement +; JS_DeleteElement +; JS_ClearScope +; JS_NewFunction +; JS_GetFunctionObject +; JS_GetFunctionName +; JS_DefineFunctions +; JS_DefineFunction +; JS_CompileScript +; JS_DestroyScript +; JS_CompileFunction +; JS_DecompileScript +; JS_DecompileFunction +; JS_DecompileFunctionBody +; JS_ExecuteScript +; JS_EvaluateScript +; JS_CallFunction +; JS_CallFunctionName +; JS_CallFunctionValue +; JS_SetBranchCallback +; JS_IsRunning +; JS_IsConstructing +; JS_SetCallReturnValue2 +; JS_NewString +; JS_NewStringCopyN +; JS_NewStringCopyZ +; JS_InternString +; JS_GetStringBytes +; JS_GetStringLength +; JS_CompareStrings +; JS_ReportError +; JS_ReportOutOfMemory +; JS_SetErrorReporter +; JS_NewRegExpObject +; JS_SetRegExpInput +; JS_ClearRegExpStatics +;================================================= + + +;00001:jsstr (OFFSET:0x00002e17, SIZE:0x0000ae17): +; - Public Definitions: +; js_EmptySubString +; js_CompareStrings +; js_HashString +; js_ValueToString +; js_StringToObject +; js_FinalizeString +; js_NewStringCopyZ +; js_NewString +; js_InitStringClass +; js_NewStringCopyN +; js_BoyerMooreHorspool +; +; +;00002:jsscript (OFFSET:0x0000dc2e, SIZE:0x00003abb): +; - Public Definitions: +; js_LineNumberToPC +; js_PCToLineNumber +; js_GetSrcNote +; js_DestroyScript +; js_NewScript +; +; +;00003:jsscope (OFFSET:0x000116e9, SIZE:0x00004f82): +; - Public Definitions: +; js_hash_scope_ops +; js_list_scope_ops +; js_DestroyProperty +; js_NewProperty +; js_IdToValue +; js_HashValue +; js_DestroyScope +; js_MutateScope +; js_DropScope +; js_HoldScope +; js_NewScope +; js_GetMutableScope +; js_HoldProperty +; js_DropProperty +; +; +;00004:jsscan (OFFSET:0x0001666b, SIZE:0x00008890): +; - Public Definitions: +; js_MatchToken +; js_FlushNewlines +; js_PeekTokenSameLine +; js_UngetToken +; js_GetToken +; js_PeekToken +; js_ReportCompileError + js_CloseTokenStream + js_NewBufferTokenStream +; js_NewTokenStream +; js_InitScanner +; +; +;00005:jsregexp (OFFSET:0x0001eefb, SIZE:0x0000eee4): +; - Public Definitions: +; js_RegExpClass +; reopsize +; js_NewRegExpObject +; js_InitRegExpClass +; js_FreeRegExpStatics +; js_InitRegExpStatics +; js_ExecuteRegExp +; js_NewRegExpOpt +; js_DestroyRegExp +; js_NewRegExp +; +; +;00006:jsparse (OFFSET:0x0002dddf, SIZE:0x00010b71): +; - Public Definitions: +; js_ParseFunctionBody + js_Parse +; +; +;00007:jsopcode (OFFSET:0x0003e950, SIZE:0x0000d362): +; - Public Definitions: +; js_EscapeMap +; js_NumCodeSpecs +; js_CodeSpec +; js_incop_str +; js_true_str +; js_false_str +; js_this_str +; js_null_str +; js_void_str +; js_typeof_str +; js_delete_str +; js_new_str +; js_ValueToSource +; js_DecompileScript +; js_DecompileCode +; js_DecompileFunction +; js_puts +; js_printf +; js_GetPrinterOutput +; js_DestroyPrinter +; js_NewPrinter +; js_EscapeString +; js_Disassemble1 +; js_Disassemble +; +;00008:jsobj (OFFSET:0x0004bcb2, SIZE:0x000090a4): +; - Public Definitions: +; js_WithClass +; js_ObjectClass +; js_TryValueOf +; js_ValueToNonNullObject +; js_TryMethod +; js_ObjectToString +; js_SetClassPrototype +; js_DeleteProperty2 +; js_DeleteProperty +; js_SetProperty +; js_GetProperty +; js_FindVariableScope +; js_FindVariable +; js_FindProperty +; js_LookupProperty +; js_DefineProperty +; js_FreeSlot +; js_AllocSlot +; js_FinalizeObject +; js_GetClassPrototype +; js_NewObject +; js_InitObjectClass +; js_ValueToObject +; js_obj_toString +; js_SetSlot +; js_GetSlot +; +; +;00009:jsnum (OFFSET:0x00054d56, SIZE:0x00004f29): +; - Public Definitions: +; js_ValueToInt32 +; js_NumberToObject +; js_FinalizeDouble +; js_InitNumberClass +; js_NumberToString +; js_NewDoubleValue +; js_NewDouble +; js_ValueToNumber +; +; +;00010:jsmath (OFFSET:0x00059c7f, SIZE:0x000054b6): +; - Public Definitions: +; js_InitMathClass +; +; +;00011:jsjava (OFFSET:0x0005f135, SIZE:0x00022aad): +; - Public Definitions: +; js_Hooks +; MojaSrcLog +; finalizeTask + JSJ_FindCurrentJSContext +; JSJ_GetPrincipals + JSJ_IsSafeMethod + JSJ_InitContext + JSJ_Init + js_JSErrorToJException + js_JavaErrorReporter + js_RemoveReflection + js_ReflectJObjectToJSObject + js_convertJObjectToJSValue + js_convertJSValueToJObject + js_ReflectJSObjectToJObject +; js_ReflectJClassToJSObject + JSJ_ExitJS + JSJ_EnterJS + JSJ_CurrentContext + JSJ_IsEnabled +;added in GA code - DSR70297 + JSJ_Finish + JSJ_IsCalledFromJava + js_GetJSPrincipalsFromJavaCaller + +; +; +;00012:jsinterp (OFFSET:0x00081be2, SIZE:0x00012274): +; - Public Definitions: +; js_Call +; js_Interpret +; js_SetLocalVariable +; js_GetLocalVariable +; js_SetArgument +; js_GetArgument +; js_FlushPropertyCacheByProp +; js_FlushPropertyCache +; +; +;00013:jsgc (OFFSET:0x00093e56, SIZE:0x00004f8d): +; - Public Definitions: +; js_ForceGC +; js_UnlockGCThing +; js_LockGCThing +; js_GC +; js_AllocGCThing +; js_RemoveRoot +; js_AddRoot +; js_FinishGC +; js_InitGC +; +; +;00014:jsfun (OFFSET:0x00098de3, SIZE:0x0000977c): +; - Public Definitions: +; js_FunctionClass +; js_ClosureClass +; js_CallClass +; js_DefineFunction +; js_NewFunction +; js_InitCallAndClosureClasses +; js_InitFunctionClass +; js_ValueToFunction +; js_SetCallVariable +; js_GetCallVariable +; js_PutCallObject +; js_GetCallObject +; +; +;00015:jsemit (OFFSET:0x000a255f, SIZE:0x000077be): +; - Public Definitions: +; js_SrcNoteName +; js_SrcNoteArity + js_FinishTakingSrcNotes +; js_MoveSrcNotes +; js_GetSrcNoteOffset +; js_BumpSrcNoteDelta +; js_NewSrcNote3 +; js_NewSrcNote2 +; js_PopStatement +; js_EmitContinue +; js_EmitBreak +; js_SetSrcNoteOffset +; js_NewSrcNote +; js_PushStatement +; js_MoveCode +; js_SetJumpOffset +; js_Emit3 +; js_Emit2 +; js_Emit1 +; js_UpdateDepth +; js_SrcNoteLength +; js_CancelLastOpcode + js_InitCodeGenerator +; +; +;00016:jsdbgapi (OFFSET:0x000a9d1d, SIZE:0x000057db): +; - Public Definitions: +; js_watchpoint_list +; js_trap_list +; JS_SetAnnotationInFrame +; JS_GetAnnotationFromFrame +; JS_GetJSPrincipalArrayFromFrame +; JS_NextJSFrame +; JS_InitJSFrameIterator + JS_LineNumberToPC + JS_PCToLineNumber + JS_ClearAllWatchPoints + JS_ClearWatchPoint + JS_SetWatchPoint + JS_HandleTrap + JS_ClearAllTraps + JS_ClearScriptTraps + JS_ClearTrap + JS_GetTrapOpcode + JS_SetTrap +;DSR070297 - added in GA code + JS_FrameIterator + JS_GetFrameAnnotation + JS_GetFramePrincipalArray + JS_GetFrameScript + JS_GetScriptFilename + JS_SetFrameAnnotation + JS_GetFramePC + JS_GetFunctionScript + +; +; +;00017:jsdate (OFFSET:0x000af4f8, SIZE:0x00009a8e): +; - Public Definitions: + js_DateGetSeconds + js_DateGetMinutes + js_DateGetHours + js_DateGetDate + js_DateGetMonth + js_DateGetYear + js_NewDateObject +; js_InitDateClass +; +; +;00018:jscntxt (OFFSET:0x000b8f86, SIZE:0x00003732): +; - Public Definitions: +; js_InterpreterHooks +; js_ReportIsNotDefined +; js_ReportErrorAgain +; js_ReportErrorVA +; js_ContextIterator +; js_DestroyContext +; js_NewContext +; js_SetInterpreterHooks +; +; +;00019:jsbool (OFFSET:0x000bc6b8, SIZE:0x00003375): +; - Public Definitions: +; js_BooleanToString +; js_BooleanToObject +; js_InitBooleanClass +; js_ValueToBoolean +; +; +;00020:jsatom (OFFSET:0x000bfa2d, SIZE:0x000058d0): +; - Public Definitions: +; js_valueOf_str +; js_toString_str +; js_length_str +; js_eval_str +; js_constructor_str +; js_class_prototype_str +; js_assign_str +; js_anonymous_str +; js_Object_str +; js_Array_str +; js_type_str +; js_DropUnmappedAtoms + js_FreeAtomMap + js_InitAtomMap +; js_GetAtom +; js_DropAtom +; js_IndexAtom +; js_ValueToStringAtom +; js_AtomizeString +; js_AtomizeDouble +; js_AtomizeInt +; js_AtomizeBoolean +; js_AtomizeObject +; js_HoldAtom +; js_MarkAtomState +; js_FreeAtomState +; js_Atomize +; js_InitAtomState +; +; +;00021:jsarray (OFFSET:0x000c52fd, SIZE:0x00007c86): +; - Public Definitions: +; js_ArrayClass +; js_SetArrayLength +; js_GetArrayLength +; js_InitArrayClass +; js_NewArrayObject +; PR_qsort +; +; +;00022:jsapi (OFFSET:0x000ccf83, SIZE:0x0000de8c): +; - Public Definitions: + JS_ClearRegExpStatics + JS_SetRegExpInput + JS_NewRegExpObject + JS_SetErrorReporter + JS_CompareStrings + JS_GetStringLength + JS_GetStringBytes + JS_InternString + JS_NewStringCopyZ + JS_NewStringCopyN + JS_NewString + JS_IsRunning + JS_SetBranchCallback + JS_CallFunctionValue + JS_CallFunctionName + JS_CallFunction + JS_EvaluateScriptForPrincipals + JS_EvaluateScript + JS_ExecuteScript + JS_DecompileFunctionBody + JS_DecompileFunction + JS_DecompileScript + JS_CompileFunctionForPrincipals + JS_CompileFunction + JS_DestroyScript + JS_CompileScriptForPrincipals + JS_CompileScript + JS_DefineFunction + JS_GetFunctionName + JS_GetFunctionObject + JS_NewFunction + JS_ClearScope + JS_DeleteElement + JS_SetElement + JS_GetElement + JS_LookupElement + JS_AliasElement + JS_DefineElement + JS_SetArrayLength + JS_GetArrayLength + JS_NewArrayObject + JS_DeleteProperty + JS_SetProperty + JS_GetProperty + JS_LookupProperty + JS_AliasProperty + JS_DefinePropertyWithTinyId + JS_DefineProperty + JS_DefineConstDoubles + JS_DefineObject + JS_NewObject + JS_GetConstructor + JS_SetParent + JS_GetParent + JS_SetPrototype + JS_GetPrototype + JS_GetInstancePrivate + JS_SetPrivate + JS_GetPrivate + JS_InstanceOf + JS_GetClass + JS_DefineFunctions + JS_DefineProperties + JS_InitClass + JS_FinalizeStub + JS_ConvertStub + JS_ResolveStub + JS_EnumerateStub + JS_PropertyStub + JS_GC + JS_UnlockGCThing + JS_LockGCThing + JS_RemoveRoot + JS_AddRoot + JS_NewDoubleValue + JS_NewDouble + JS_strdup + JS_free + JS_realloc + JS_ReportOutOfMemory + JS_malloc + JS_GetScopeChain + JS_InitStandardClasses + JS_SetGlobalObject + JS_GetGlobalObject + JS_SetVersion + JS_GetVersion + JS_ContextIterator + JS_GetTaskState + JS_DestroyContext + JS_NewContext + JS_Unlock + JS_Lock + JS_Finish + JS_Init + JS_GetTypeName + JS_TypeOfValue + JS_ValueToBoolean + JS_ValueToInt32 + JS_ValueToNumber + JS_ValueToString + JS_ValueToFunction + JS_ValueToObject + JS_ReportError + JS_ConvertValue + JS_GetEmptyStringValue + JS_GetPositiveInfinityValue + JS_GetNegativeInfinityValue + JS_GetNaNValue +;DSR062897 - added for GA code + JS_MaybeGC + JS_GetScriptPrincipals + JS_IsAssigning + JS_SetCharSetInfo +;brendan@mozilla.org, 2-Sept-2000 + JS_SetCallReturnValue2 + JS_SetGCCallback + JS_SetGCCallbackRT + JS_AddExternalStringFinalizer + JS_RemoveExternalStringFinalizer + JS_NewExternalString +; +; +;00023:prmjtime (OFFSET:0x000dae0f, SIZE:0x00008986): +; - Public Definitions: + PRMJ_FormatTimeUSEnglish + PRMJ_gmtime + PRMJ_FormatTime + PRMJ_mktime + PRMJ_ComputeTime + PRMJ_localtime + PRMJ_ExplodeTime + PRMJ_ToLocal + PRMJ_ToGMT + PRMJ_NowLocal + PRMJ_DSTOffset + PRMJ_NowS + PRMJ_NowMS + PRMJ_Now + PRMJ_ToExtendedTime + PRMJ_ToBaseTime + PRMJ_setDST + PRMJ_LocalGMTDifference + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsapi.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsapi.cpp new file mode 100644 index 0000000..db713c8 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsapi.cpp @@ -0,0 +1,6060 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript API. + */ +#include "jsstddef.h" +#include +#include +#include +#include +#include "jstypes.h" +#include "jsarena.h" /* Added by JSIFY */ +#include "jsutil.h" /* Added by JSIFY */ +#include "jsclist.h" +#include "jsdhash.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdate.h" +#include "jsdtoa.h" +#include "jsemit.h" +#include "jsexn.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsmath.h" +#include "jsnum.h" +#include "json.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsregexp.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "prmjtime.h" +#include "jsstaticcheck.h" + +#if !defined JS_THREADSAFE && defined JS_TRACER +#include "jstracer.h" +#endif + +#if JS_HAS_FILE_OBJECT +#include "jsfile.h" +#endif + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#ifdef HAVE_VA_LIST_AS_ARRAY +#define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap)) +#else +#define JS_ADDRESSOF_VA_LIST(ap) (&(ap)) +#endif + +#if defined(JS_THREADSAFE) +#define CHECK_REQUEST(cx) \ + JS_ASSERT((cx)->requestDepth || (cx)->thread == (cx)->runtime->gcThread) +#else +#define CHECK_REQUEST(cx) ((void)0) +#endif + +JS_PUBLIC_API(int64) +JS_Now() +{ + return PRMJ_Now(); +} + +JS_PUBLIC_API(jsval) +JS_GetNaNValue(JSContext *cx) +{ + return DOUBLE_TO_JSVAL(cx->runtime->jsNaN); +} + +JS_PUBLIC_API(jsval) +JS_GetNegativeInfinityValue(JSContext *cx) +{ + return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity); +} + +JS_PUBLIC_API(jsval) +JS_GetPositiveInfinityValue(JSContext *cx) +{ + return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity); +} + +JS_PUBLIC_API(jsval) +JS_GetEmptyStringValue(JSContext *cx) +{ + return STRING_TO_JSVAL(cx->runtime->emptyString); +} + +static JSBool +TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, + jsval **vpp, va_list *app) +{ + const char *format; + JSArgumentFormatMap *map; + + format = *formatp; + for (map = cx->argumentFormatMap; map; map = map->next) { + if (!strncmp(format, map->format, map->length)) { + *formatp = format + map->length; + return map->formatter(cx, format, fromJS, vpp, app); + } + } + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format); + return JS_FALSE; +} + +JS_PUBLIC_API(JSBool) +JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, + ...) +{ + va_list ap; + JSBool ok; + + va_start(ap, format); + ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap); + va_end(ap); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, + const char *format, va_list ap) +{ + jsval *sp; + JSBool required; + char c; + JSFunction *fun; + jsdouble d; + JSString *str; + JSObject *obj; + + CHECK_REQUEST(cx); + sp = argv; + required = JS_TRUE; + while ((c = *format++) != '\0') { + if (isspace(c)) + continue; + if (c == '/') { + required = JS_FALSE; + continue; + } + if (sp == argv + argc) { + if (required) { + fun = js_ValueToFunction(cx, &argv[-2], 0); + if (fun) { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%u", argc); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_MORE_ARGS_NEEDED, + JS_GetFunctionName(fun), numBuf, + (argc == 1) ? "" : "s"); + } + return JS_FALSE; + } + break; + } + switch (c) { + case 'b': + *va_arg(ap, JSBool *) = js_ValueToBoolean(*sp); + break; + case 'c': + if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *))) + return JS_FALSE; + break; + case 'i': + if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *))) + return JS_FALSE; + break; + case 'u': + if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *))) + return JS_FALSE; + break; + case 'j': + if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *))) + return JS_FALSE; + break; + case 'd': + if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *))) + return JS_FALSE; + break; + case 'I': + if (!JS_ValueToNumber(cx, *sp, &d)) + return JS_FALSE; + *va_arg(ap, jsdouble *) = js_DoubleToInteger(d); + break; + case 's': + case 'S': + case 'W': + str = js_ValueToString(cx, *sp); + if (!str) + return JS_FALSE; + *sp = STRING_TO_JSVAL(str); + if (c == 's') { + const char *bytes = js_GetStringBytes(cx, str); + if (!bytes) + return JS_FALSE; + *va_arg(ap, const char **) = bytes; + } else if (c == 'W') { + const jschar *chars = js_GetStringChars(cx, str); + if (!chars) + return JS_FALSE; + *va_arg(ap, const jschar **) = chars; + } else { + *va_arg(ap, JSString **) = str; + } + break; + case 'o': + if (!js_ValueToObject(cx, *sp, &obj)) + return JS_FALSE; + *sp = OBJECT_TO_JSVAL(obj); + *va_arg(ap, JSObject **) = obj; + break; + case 'f': + obj = js_ValueToFunctionObject(cx, sp, 0); + if (!obj) + return JS_FALSE; + *sp = OBJECT_TO_JSVAL(obj); + *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj); + break; + case 'v': + *va_arg(ap, jsval *) = *sp; + break; + case '*': + break; + default: + format--; + if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp, + JS_ADDRESSOF_VA_LIST(ap))) { + return JS_FALSE; + } + /* NB: the formatter already updated sp, so we continue here. */ + continue; + } + sp++; + } + return JS_TRUE; +} + +JS_PUBLIC_API(jsval *) +JS_PushArguments(JSContext *cx, void **markp, const char *format, ...) +{ + va_list ap; + jsval *argv; + + va_start(ap, format); + argv = JS_PushArgumentsVA(cx, markp, format, ap); + va_end(ap); + return argv; +} + +JS_PUBLIC_API(jsval *) +JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap) +{ + uintN argc; + jsval *argv, *sp; + char c; + const char *cp; + JSString *str; + JSFunction *fun; + JSStackHeader *sh; + + CHECK_REQUEST(cx); + *markp = NULL; + argc = 0; + for (cp = format; (c = *cp) != '\0'; cp++) { + /* + * Count non-space non-star characters as individual jsval arguments. + * This may over-allocate stack, but we'll fix below. + */ + if (isspace(c) || c == '*') + continue; + argc++; + } + sp = js_AllocStack(cx, argc, markp); + if (!sp) + return NULL; + argv = sp; + while ((c = *format++) != '\0') { + if (isspace(c) || c == '*') + continue; + switch (c) { + case 'b': + *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int)); + break; + case 'c': + *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int)); + break; + case 'i': + case 'j': + /* + * Use JS_New{Double,Number}Value here and in the next two cases, + * not js_New{Double,Number}InRootedValue, as sp may point to an + * unrooted location. + */ + if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp)) + goto bad; + break; + case 'u': + if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp)) + goto bad; + break; + case 'd': + case 'I': + if (!JS_NewDoubleValue(cx, va_arg(ap, jsdouble), sp)) + goto bad; + break; + case 's': + str = JS_NewStringCopyZ(cx, va_arg(ap, char *)); + if (!str) + goto bad; + *sp = STRING_TO_JSVAL(str); + break; + case 'W': + str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *)); + if (!str) + goto bad; + *sp = STRING_TO_JSVAL(str); + break; + case 'S': + str = va_arg(ap, JSString *); + *sp = STRING_TO_JSVAL(str); + break; + case 'o': + *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *)); + break; + case 'f': + fun = va_arg(ap, JSFunction *); + *sp = fun ? OBJECT_TO_JSVAL(FUN_OBJECT(fun)) : JSVAL_NULL; + break; + case 'v': + *sp = va_arg(ap, jsval); + break; + default: + format--; + if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp, + JS_ADDRESSOF_VA_LIST(ap))) { + goto bad; + } + /* NB: the formatter already updated sp, so we continue here. */ + continue; + } + sp++; + } + + /* + * We may have overallocated stack due to a multi-character format code + * handled by a JSArgumentFormatter. Give back that stack space! + */ + JS_ASSERT(sp <= argv + argc); + if (sp < argv + argc) { + /* Return slots not pushed to the current stack arena. */ + cx->stackPool.current->avail = (jsuword)sp; + + /* Reduce the count of slots the GC will scan in this stack segment. */ + sh = cx->stackHeaders; + JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc); + sh->nslots -= argc - (sp - argv); + } + return argv; + +bad: + js_FreeStack(cx, *markp); + return NULL; +} + +JS_PUBLIC_API(void) +JS_PopArguments(JSContext *cx, void *mark) +{ + CHECK_REQUEST(cx); + js_FreeStack(cx, mark); +} + +JS_PUBLIC_API(JSBool) +JS_AddArgumentFormatter(JSContext *cx, const char *format, + JSArgumentFormatter formatter) +{ + size_t length; + JSArgumentFormatMap **mpp, *map; + + length = strlen(format); + mpp = &cx->argumentFormatMap; + while ((map = *mpp) != NULL) { + /* Insert before any shorter string to match before prefixes. */ + if (map->length < length) + break; + if (map->length == length && !strcmp(map->format, format)) + goto out; + mpp = &map->next; + } + map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map); + if (!map) + return JS_FALSE; + map->format = format; + map->length = length; + map->next = *mpp; + *mpp = map; +out: + map->formatter = formatter; + return JS_TRUE; +} + +JS_PUBLIC_API(void) +JS_RemoveArgumentFormatter(JSContext *cx, const char *format) +{ + size_t length; + JSArgumentFormatMap **mpp, *map; + + length = strlen(format); + mpp = &cx->argumentFormatMap; + while ((map = *mpp) != NULL) { + if (map->length == length && !strcmp(map->format, format)) { + *mpp = map->next; + JS_free(cx, map); + return; + } + mpp = &map->next; + } +} + +JS_PUBLIC_API(JSBool) +JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp) +{ + JSBool ok; + JSObject *obj; + JSString *str; + jsdouble d, *dp; + + CHECK_REQUEST(cx); + switch (type) { + case JSTYPE_VOID: + *vp = JSVAL_VOID; + ok = JS_TRUE; + break; + case JSTYPE_OBJECT: + ok = js_ValueToObject(cx, v, &obj); + if (ok) + *vp = OBJECT_TO_JSVAL(obj); + break; + case JSTYPE_FUNCTION: + *vp = v; + obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK); + ok = (obj != NULL); + break; + case JSTYPE_STRING: + str = js_ValueToString(cx, v); + ok = (str != NULL); + if (ok) + *vp = STRING_TO_JSVAL(str); + break; + case JSTYPE_NUMBER: + ok = JS_ValueToNumber(cx, v, &d); + if (ok) { + dp = js_NewWeaklyRootedDouble(cx, d); + ok = (dp != NULL); + if (ok) + *vp = DOUBLE_TO_JSVAL(dp); + } + break; + case JSTYPE_BOOLEAN: + *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(v)); + return JS_TRUE; + default: { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, + numBuf); + ok = JS_FALSE; + break; + } + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp) +{ + CHECK_REQUEST(cx); + return js_ValueToObject(cx, v, objp); +} + +JS_PUBLIC_API(JSFunction *) +JS_ValueToFunction(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK); +} + +JS_PUBLIC_API(JSFunction *) +JS_ValueToConstructor(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK); +} + +JS_PUBLIC_API(JSString *) +JS_ValueToString(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + return js_ValueToString(cx, v); +} + +JS_PUBLIC_API(JSString *) +JS_ValueToSource(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + return js_ValueToSource(cx, v); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) +{ + JSTempValueRooter tvr; + + CHECK_REQUEST(cx); + JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); + *dp = js_ValueToNumber(cx, &tvr.u.value); + JS_POP_TEMP_ROOT(cx, &tvr); + return !JSVAL_IS_NULL(tvr.u.value); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip) +{ + JSTempValueRooter tvr; + + CHECK_REQUEST(cx); + JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); + *ip = js_ValueToECMAInt32(cx, &tvr.u.value); + JS_POP_TEMP_ROOT(cx, &tvr); + return !JSVAL_IS_NULL(tvr.u.value); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip) +{ + JSTempValueRooter tvr; + + CHECK_REQUEST(cx); + JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); + *ip = js_ValueToECMAUint32(cx, &tvr.u.value); + JS_POP_TEMP_ROOT(cx, &tvr); + return !JSVAL_IS_NULL(tvr.u.value); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip) +{ + JSTempValueRooter tvr; + + CHECK_REQUEST(cx); + JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); + *ip = js_ValueToInt32(cx, &tvr.u.value); + JS_POP_TEMP_ROOT(cx, &tvr); + return !JSVAL_IS_NULL(tvr.u.value); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip) +{ + JSTempValueRooter tvr; + + CHECK_REQUEST(cx); + JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); + *ip = js_ValueToUint16(cx, &tvr.u.value); + JS_POP_TEMP_ROOT(cx, &tvr); + return !JSVAL_IS_NULL(tvr.u.value); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp) +{ + CHECK_REQUEST(cx); + *bp = js_ValueToBoolean(v); + return JS_TRUE; +} + +JS_PUBLIC_API(JSType) +JS_TypeOfValue(JSContext *cx, jsval v) +{ + JSType type; + JSObject *obj; + JSObjectOps *ops; + JSClass *clasp; + + CHECK_REQUEST(cx); + if (JSVAL_IS_OBJECT(v)) { + type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */ + obj = JSVAL_TO_OBJECT(v); + if (obj) { + JSObject *wrapped; + + wrapped = js_GetWrappedObject(cx, obj); + if (wrapped) + obj = wrapped; + + ops = obj->map->ops; +#if JS_HAS_XML_SUPPORT + if (ops == &js_XMLObjectOps.base) { + type = JSTYPE_XML; + } else +#endif + { + /* + * ECMA 262, 11.4.3 says that any native object that implements + * [[Call]] should be of type "function". Note that RegExp and + * Script are both of type "function" for compatibility with + * older SpiderMonkeys. + */ + clasp = OBJ_GET_CLASS(cx, obj); + if ((ops == &js_ObjectOps) + ? (clasp->call + ? clasp == &js_ScriptClass + : clasp == &js_FunctionClass) + : ops->call != NULL) { + type = JSTYPE_FUNCTION; + } else { +#ifdef NARCISSUS + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + + if (!OBJ_GET_PROPERTY(cx, obj, + ATOM_TO_JSID(cx->runtime->atomState + .__call__Atom), + &v)) { + JS_ClearPendingException(cx); + } else if (VALUE_IS_FUNCTION(cx, v)) { + type = JSTYPE_FUNCTION; + } +#endif + } + } + } + } else if (JSVAL_IS_NUMBER(v)) { + type = JSTYPE_NUMBER; + } else if (JSVAL_IS_STRING(v)) { + type = JSTYPE_STRING; + } else if (JSVAL_IS_BOOLEAN(v)) { + type = JSTYPE_BOOLEAN; + } else { + type = JSTYPE_VOID; + } + return type; +} + +JS_PUBLIC_API(const char *) +JS_GetTypeName(JSContext *cx, JSType type) +{ + if ((uintN)type >= (uintN)JSTYPE_LIMIT) + return NULL; + return JS_TYPE_STR(type); +} + +/************************************************************************/ + +/* + * Has a new runtime ever been created? This flag is used to detect unsafe + * changes to js_CStringsAreUTF8 after a runtime has been created, and to + * ensure that "first checks" on runtime creation are run only once. + */ +#ifdef DEBUG +static JSBool js_NewRuntimeWasCalled = JS_FALSE; +#endif + +JS_PUBLIC_API(JSRuntime *) +JS_NewRuntime(uint32 maxbytes) +{ + JSRuntime *rt; + +#ifdef DEBUG + if (!js_NewRuntimeWasCalled) { + /* + * This code asserts that the numbers associated with the error names + * in jsmsg.def are monotonically increasing. It uses values for the + * error names enumerated in jscntxt.c. It's not a compile-time check + * but it's better than nothing. + */ + int errorNumber = 0; +#define MSG_DEF(name, number, count, exception, format) \ + JS_ASSERT(name == errorNumber++); +#include "js.msg" +#undef MSG_DEF + +#define MSG_DEF(name, number, count, exception, format) \ + JS_BEGIN_MACRO \ + uintN numfmtspecs = 0; \ + const char *fmt; \ + for (fmt = format; *fmt != '\0'; fmt++) { \ + if (*fmt == '{' && isdigit(fmt[1])) \ + ++numfmtspecs; \ + } \ + JS_ASSERT(count == numfmtspecs); \ + JS_END_MACRO; +#include "js.msg" +#undef MSG_DEF + + js_NewRuntimeWasCalled = JS_TRUE; + } +#endif /* DEBUG */ + + rt = (JSRuntime *) malloc(sizeof(JSRuntime)); + if (!rt) + return NULL; + + /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ + memset(rt, 0, sizeof(JSRuntime)); + JS_INIT_CLIST(&rt->contextList); + JS_INIT_CLIST(&rt->trapList); + JS_INIT_CLIST(&rt->watchPointList); + + if (!js_InitDtoa()) + goto bad; + if (!js_InitGC(rt, maxbytes)) + goto bad; + if (!js_InitAtomState(rt)) + goto bad; + if (!js_InitDeflatedStringCache(rt)) + goto bad; +#ifdef JS_THREADSAFE + if (!js_InitThreadPrivateIndex(js_ThreadDestructorCB)) + goto bad; + rt->gcLock = JS_NEW_LOCK(); + if (!rt->gcLock) + goto bad; + rt->gcDone = JS_NEW_CONDVAR(rt->gcLock); + if (!rt->gcDone) + goto bad; + rt->requestDone = JS_NEW_CONDVAR(rt->gcLock); + if (!rt->requestDone) + goto bad; + /* this is asymmetric with JS_ShutDown: */ + if (!js_SetupLocks(8, 16)) + goto bad; + rt->rtLock = JS_NEW_LOCK(); + if (!rt->rtLock) + goto bad; + rt->stateChange = JS_NEW_CONDVAR(rt->gcLock); + if (!rt->stateChange) + goto bad; + rt->titleSharingDone = JS_NEW_CONDVAR(rt->gcLock); + if (!rt->titleSharingDone) + goto bad; + rt->titleSharingTodo = NO_TITLE_SHARING_TODO; + rt->debuggerLock = JS_NEW_LOCK(); + if (!rt->debuggerLock) + goto bad; +#endif + if (!js_InitPropertyTree(rt)) + goto bad; + +#if !defined JS_THREADSAFE && defined JS_TRACER + js_InitJIT(&rt->traceMonitor); +#endif + + return rt; + +bad: + JS_DestroyRuntime(rt); + return NULL; +} + +JS_PUBLIC_API(void) +JS_DestroyRuntime(JSRuntime *rt) +{ +#ifdef DEBUG + /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */ + if (!JS_CLIST_IS_EMPTY(&rt->contextList)) { + JSContext *cx, *iter = NULL; + uintN cxcount = 0; + while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) { + fprintf(stderr, +"JS API usage error: found live context at %p\n", + cx); + cxcount++; + } + fprintf(stderr, +"JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n", + cxcount, (cxcount == 1) ? "" : "s"); + } +#endif + +#if !defined JS_THREADSAFE && defined JS_TRACER + js_FinishJIT(&rt->traceMonitor); +#endif + + js_FreeRuntimeScriptState(rt); + js_FinishAtomState(rt); + + /* + * Free unit string storage only after all strings have been finalized, so + * that js_FinalizeString can detect unit strings and avoid calling free + * on their chars storage. + */ + js_FinishUnitStrings(rt); + + /* + * Finish the deflated string cache after the last GC and after + * calling js_FinishAtomState, which finalizes strings. + */ + js_FinishDeflatedStringCache(rt); + js_FinishGC(rt); +#ifdef JS_THREADSAFE + if (rt->gcLock) + JS_DESTROY_LOCK(rt->gcLock); + if (rt->gcDone) + JS_DESTROY_CONDVAR(rt->gcDone); + if (rt->requestDone) + JS_DESTROY_CONDVAR(rt->requestDone); + if (rt->rtLock) + JS_DESTROY_LOCK(rt->rtLock); + if (rt->stateChange) + JS_DESTROY_CONDVAR(rt->stateChange); + if (rt->titleSharingDone) + JS_DESTROY_CONDVAR(rt->titleSharingDone); + if (rt->debuggerLock) + JS_DESTROY_LOCK(rt->debuggerLock); +#else + GSN_CACHE_CLEAR(&rt->gsnCache); +#endif + js_FinishPropertyTree(rt); + free(rt); +} + +JS_PUBLIC_API(void) +JS_ShutDown(void) +{ +#ifdef JS_OPMETER + extern void js_DumpOpMeters(); + + js_DumpOpMeters(); +#endif + + js_FinishDtoa(); +#ifdef JS_THREADSAFE + js_CleanupLocks(); +#endif + PRMJ_NowShutdown(); +} + +JS_PUBLIC_API(void *) +JS_GetRuntimePrivate(JSRuntime *rt) +{ + return rt->data; +} + +JS_PUBLIC_API(void) +JS_SetRuntimePrivate(JSRuntime *rt, void *data) +{ + rt->data = data; +} + +JS_PUBLIC_API(void) +JS_BeginRequest(JSContext *cx) +{ +#ifdef JS_THREADSAFE + JSRuntime *rt; + + JS_ASSERT(cx->thread->id == js_CurrentThreadId()); + if (!cx->requestDepth) { + JS_ASSERT(cx->gcLocalFreeLists == &js_GCEmptyFreeListSet); + + /* Wait until the GC is finished. */ + rt = cx->runtime; + JS_LOCK_GC(rt); + + /* NB: we use cx->thread here, not js_GetCurrentThread(). */ + if (rt->gcThread != cx->thread) { + while (rt->gcLevel > 0) + JS_AWAIT_GC_DONE(rt); + } + + /* Indicate that a request is running. */ + rt->requestCount++; + cx->requestDepth = 1; + cx->outstandingRequests++; + JS_UNLOCK_GC(rt); + return; + } + cx->requestDepth++; + cx->outstandingRequests++; +#endif +} + +JS_PUBLIC_API(void) +JS_EndRequest(JSContext *cx) +{ +#ifdef JS_THREADSAFE + JSRuntime *rt; + JSTitle *title, **todop; + JSBool shared; + + CHECK_REQUEST(cx); + JS_ASSERT(cx->requestDepth > 0); + JS_ASSERT(cx->outstandingRequests > 0); + if (cx->requestDepth == 1) { + /* Lock before clearing to interlock with ClaimScope, in jslock.c. */ + rt = cx->runtime; + JS_LOCK_GC(rt); + cx->requestDepth = 0; + cx->outstandingRequests--; + + /* See whether cx has any single-threaded titles to start sharing. */ + todop = &rt->titleSharingTodo; + shared = JS_FALSE; + while ((title = *todop) != NO_TITLE_SHARING_TODO) { + if (title->ownercx != cx) { + todop = &title->u.link; + continue; + } + *todop = title->u.link; + title->u.link = NULL; /* null u.link for sanity ASAP */ + + /* + * If js_DropObjectMap returns null, we held the last ref to scope. + * The waiting thread(s) must have been killed, after which the GC + * collected the object that held this scope. Unlikely, because it + * requires that the GC ran (e.g., from an operation callback) + * during this request, but possible. + */ + if (js_DropObjectMap(cx, TITLE_TO_MAP(title), NULL)) { + js_InitLock(&title->lock); + title->u.count = 0; /* NULL may not pun as 0 */ + js_FinishSharingTitle(cx, title); /* set ownercx = NULL */ + shared = JS_TRUE; + } + } + if (shared) + JS_NOTIFY_ALL_CONDVAR(rt->titleSharingDone); + + js_RevokeGCLocalFreeLists(cx); + + /* Give the GC a chance to run if this was the last request running. */ + JS_ASSERT(rt->requestCount > 0); + rt->requestCount--; + if (rt->requestCount == 0) + JS_NOTIFY_REQUEST_DONE(rt); + + JS_UNLOCK_GC(rt); + return; + } + + cx->requestDepth--; + cx->outstandingRequests--; +#endif +} + +/* Yield to pending GC operations, regardless of request depth */ +JS_PUBLIC_API(void) +JS_YieldRequest(JSContext *cx) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(cx->thread); + CHECK_REQUEST(cx); + JS_ResumeRequest(cx, JS_SuspendRequest(cx)); +#endif +} + +JS_PUBLIC_API(jsrefcount) +JS_SuspendRequest(JSContext *cx) +{ +#ifdef JS_THREADSAFE + jsrefcount saveDepth = cx->requestDepth; + + while (cx->requestDepth) { + cx->outstandingRequests++; /* compensate for JS_EndRequest */ + JS_EndRequest(cx); + } + return saveDepth; +#else + return 0; +#endif +} + +JS_PUBLIC_API(void) +JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(!cx->requestDepth); + while (--saveDepth >= 0) { + JS_BeginRequest(cx); + cx->outstandingRequests--; /* compensate for JS_BeginRequest */ + } +#endif +} + +JS_PUBLIC_API(void) +JS_Lock(JSRuntime *rt) +{ + JS_LOCK_RUNTIME(rt); +} + +JS_PUBLIC_API(void) +JS_Unlock(JSRuntime *rt) +{ + JS_UNLOCK_RUNTIME(rt); +} + +JS_PUBLIC_API(JSContextCallback) +JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback) +{ + JSContextCallback old; + + old = rt->cxCallback; + rt->cxCallback = cxCallback; + return old; +} + +JS_PUBLIC_API(JSContext *) +JS_NewContext(JSRuntime *rt, size_t stackChunkSize) +{ + return js_NewContext(rt, stackChunkSize); +} + +JS_PUBLIC_API(void) +JS_DestroyContext(JSContext *cx) +{ + js_DestroyContext(cx, JSDCM_FORCE_GC); +} + +JS_PUBLIC_API(void) +JS_DestroyContextNoGC(JSContext *cx) +{ + js_DestroyContext(cx, JSDCM_NO_GC); +} + +JS_PUBLIC_API(void) +JS_DestroyContextMaybeGC(JSContext *cx) +{ + js_DestroyContext(cx, JSDCM_MAYBE_GC); +} + +JS_PUBLIC_API(void *) +JS_GetContextPrivate(JSContext *cx) +{ + return cx->data; +} + +JS_PUBLIC_API(void) +JS_SetContextPrivate(JSContext *cx, void *data) +{ + cx->data = data; +} + +JS_PUBLIC_API(JSRuntime *) +JS_GetRuntime(JSContext *cx) +{ + return cx->runtime; +} + +JS_PUBLIC_API(JSContext *) +JS_ContextIterator(JSRuntime *rt, JSContext **iterp) +{ + return js_ContextIterator(rt, JS_TRUE, iterp); +} + +JS_PUBLIC_API(JSVersion) +JS_GetVersion(JSContext *cx) +{ + return JSVERSION_NUMBER(cx); +} + +JS_PUBLIC_API(JSVersion) +JS_SetVersion(JSContext *cx, JSVersion version) +{ + JSVersion oldVersion; + + JS_ASSERT(version != JSVERSION_UNKNOWN); + JS_ASSERT((version & ~JSVERSION_MASK) == 0); + + oldVersion = JSVERSION_NUMBER(cx); + if (version == oldVersion) + return oldVersion; + + /* We no longer support 1.4 or below. */ + if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4) + return oldVersion; + + cx->version = (cx->version & ~JSVERSION_MASK) | version; + js_OnVersionChange(cx); + return oldVersion; +} + +static struct v2smap { + JSVersion version; + const char *string; +} v2smap[] = { + {JSVERSION_1_0, "1.0"}, + {JSVERSION_1_1, "1.1"}, + {JSVERSION_1_2, "1.2"}, + {JSVERSION_1_3, "1.3"}, + {JSVERSION_1_4, "1.4"}, + {JSVERSION_ECMA_3, "ECMAv3"}, + {JSVERSION_1_5, "1.5"}, + {JSVERSION_1_6, "1.6"}, + {JSVERSION_1_7, "1.7"}, + {JSVERSION_1_8, "1.8"}, + {JSVERSION_DEFAULT, js_default_str}, + {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */ +}; + +JS_PUBLIC_API(const char *) +JS_VersionToString(JSVersion version) +{ + int i; + + for (i = 0; v2smap[i].string; i++) + if (v2smap[i].version == version) + return v2smap[i].string; + return "unknown"; +} + +JS_PUBLIC_API(JSVersion) +JS_StringToVersion(const char *string) +{ + int i; + + for (i = 0; v2smap[i].string; i++) + if (strcmp(v2smap[i].string, string) == 0) + return v2smap[i].version; + return JSVERSION_UNKNOWN; +} + +JS_PUBLIC_API(uint32) +JS_GetOptions(JSContext *cx) +{ + return cx->options; +} + +#define SYNC_OPTIONS_TO_VERSION(cx) \ + JS_BEGIN_MACRO \ + if ((cx)->options & JSOPTION_XML) \ + (cx)->version |= JSVERSION_HAS_XML; \ + else \ + (cx)->version &= ~JSVERSION_HAS_XML; \ + JS_END_MACRO + +JS_PUBLIC_API(uint32) +JS_SetOptions(JSContext *cx, uint32 options) +{ + uint32 oldopts = cx->options; + cx->options = options; + SYNC_OPTIONS_TO_VERSION(cx); + return oldopts; +} + +JS_PUBLIC_API(uint32) +JS_ToggleOptions(JSContext *cx, uint32 options) +{ + uint32 oldopts = cx->options; + cx->options ^= options; + SYNC_OPTIONS_TO_VERSION(cx); + return oldopts; +} + +JS_PUBLIC_API(const char *) +JS_GetImplementationVersion(void) +{ + return "JavaScript-C 1.8.0 pre-release 1 2007-10-03"; +} + + +JS_PUBLIC_API(JSObject *) +JS_GetGlobalObject(JSContext *cx) +{ + return cx->globalObject; +} + +JS_PUBLIC_API(void) +JS_SetGlobalObject(JSContext *cx, JSObject *obj) +{ + cx->globalObject = obj; + +#if JS_HAS_XML_SUPPORT + cx->xmlSettingFlags = 0; +#endif +} + +JS_BEGIN_EXTERN_C + +JSObject * +js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj) +{ + JSDHashTable *table; + JSBool resolving; + JSRuntime *rt; + JSResolvingKey key; + JSResolvingEntry *entry; + JSObject *fun_proto, *obj_proto; + + /* If cx has no global object, use obj so prototypes can be found. */ + if (!cx->globalObject) + JS_SetGlobalObject(cx, obj); + + /* Record Function and Object in cx->resolvingTable, if we are resolving. */ + table = cx->resolvingTable; + resolving = (table && table->entryCount); + rt = cx->runtime; + key.obj = obj; + if (resolving) { + key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]); + entry = (JSResolvingEntry *) + JS_DHashTableOperate(table, &key, JS_DHASH_ADD); + if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) { + /* Already resolving Function, record Object too. */ + JS_ASSERT(entry->key.obj == obj); + key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]); + entry = (JSResolvingEntry *) + JS_DHashTableOperate(table, &key, JS_DHASH_ADD); + } + if (!entry) { + JS_ReportOutOfMemory(cx); + return NULL; + } + JS_ASSERT(!entry->key.obj && entry->flags == 0); + entry->key = key; + entry->flags = JSRESFLAG_LOOKUP; + } else { + key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]); + if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) + return NULL; + + key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]); + if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) { + key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]); + JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE); + return NULL; + } + + table = cx->resolvingTable; + } + + /* Initialize the function class first so constructors can be made. */ + if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Function), + &fun_proto)) { + fun_proto = NULL; + goto out; + } + if (!fun_proto) { + fun_proto = js_InitFunctionClass(cx, obj); + if (!fun_proto) + goto out; + } else { + JSObject *ctor; + + ctor = JS_GetConstructor(cx, fun_proto); + if (!ctor) { + fun_proto = NULL; + goto out; + } + OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(CLASS_ATOM(cx, Function)), + OBJECT_TO_JSVAL(ctor), 0, 0, 0, NULL); + } + + /* Initialize the object class next so Object.prototype works. */ + if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object), + &obj_proto)) { + fun_proto = NULL; + goto out; + } + if (!obj_proto) + obj_proto = js_InitObjectClass(cx, obj); + if (!obj_proto) { + fun_proto = NULL; + goto out; + } + + /* Function.prototype and the global object delegate to Object.prototype. */ + OBJ_SET_PROTO(cx, fun_proto, obj_proto); + if (!OBJ_GET_PROTO(cx, obj)) + OBJ_SET_PROTO(cx, obj, obj_proto); + +out: + /* If resolving, remove the other entry (Object or Function) from table. */ + JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE); + if (!resolving) { + /* If not resolving, remove the first entry added above, for Object. */ + JS_ASSERT(key.id == \ + ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function])); + key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]); + JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE); + } + return fun_proto; +} + +JS_END_EXTERN_C + +JS_PUBLIC_API(JSBool) +JS_InitStandardClasses(JSContext *cx, JSObject *obj) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + + /* Define a top-level property 'undefined' with the undefined value. */ + atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID]; + if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID, + NULL, NULL, JSPROP_PERMANENT, NULL)) { + return JS_FALSE; + } + + /* Function and Object require cooperative bootstrapping magic. */ + if (!js_InitFunctionAndObjectClasses(cx, obj)) + return JS_FALSE; + + /* Initialize the rest of the standard objects and functions. */ + return js_InitArrayClass(cx, obj) && + js_InitBlockClass(cx, obj) && + js_InitBooleanClass(cx, obj) && + js_InitCallClass(cx, obj) && + js_InitExceptionClasses(cx, obj) && + js_InitMathClass(cx, obj) && + js_InitNumberClass(cx, obj) && + js_InitJSONClass(cx, obj) && + js_InitRegExpClass(cx, obj) && + js_InitStringClass(cx, obj) && + js_InitEval(cx, obj) && +#if JS_HAS_SCRIPT_OBJECT + js_InitScriptClass(cx, obj) && +#endif +#if JS_HAS_XML_SUPPORT + js_InitXMLClasses(cx, obj) && +#endif +#if JS_HAS_FILE_OBJECT + js_InitFileClass(cx, obj) && +#endif +#if JS_HAS_GENERATORS + js_InitIteratorClasses(cx, obj) && +#endif + js_InitDateClass(cx, obj); +} + +#define CLASP(name) (&js_##name##Class) +#define EXT_CLASP(name) (&js_##name##Class.base) +#define EAGER_ATOM(name) ATOM_OFFSET(name), NULL +#define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL +#define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name) +#define EAGER_ATOM_AND_EXT_CLASP(name) EAGER_CLASS_ATOM(name), EXT_CLASP(name) +#define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str + +typedef struct JSStdName { + JSObjectOp init; + size_t atomOffset; /* offset of atom pointer in JSAtomState */ + const char *name; /* null if atom is pre-pinned, else name */ + JSClass *clasp; +} JSStdName; + +static JSAtom * +StdNameToAtom(JSContext *cx, JSStdName *stdn) +{ + size_t offset; + JSAtom *atom; + const char *name; + + offset = stdn->atomOffset; + atom = OFFSET_TO_ATOM(cx->runtime, offset); + if (!atom) { + name = stdn->name; + if (name) { + atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED); + OFFSET_TO_ATOM(cx->runtime, offset) = atom; + } + } + return atom; +} + +/* + * Table of class initializers and their atom offsets in rt->atomState. + * If you add a "standard" class, remember to update this table. + */ +static JSStdName standard_class_atoms[] = { + {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)}, + {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)}, + {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)}, + {js_InitBlockClass, EAGER_ATOM_AND_CLASP(Block)}, + {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)}, + {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)}, + {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)}, + {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)}, + {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)}, + {js_InitCallClass, EAGER_ATOM_AND_CLASP(Call)}, + {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)}, + {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)}, +#if JS_HAS_SCRIPT_OBJECT + {js_InitScriptClass, EAGER_ATOM_AND_CLASP(Script)}, +#endif +#if JS_HAS_XML_SUPPORT + {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)}, + {js_InitNamespaceClass, EAGER_ATOM_AND_EXT_CLASP(Namespace)}, + {js_InitQNameClass, EAGER_ATOM_AND_EXT_CLASP(QName)}, +#endif +#if JS_HAS_FILE_OBJECT + {js_InitFileClass, EAGER_ATOM_AND_CLASP(File)}, +#endif +#if JS_HAS_GENERATORS + {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)}, +#endif + {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)}, + {NULL, 0, NULL, NULL} +}; + +/* + * Table of top-level function and constant names and their init functions. + * If you add a "standard" global function or property, remember to update + * this table. + */ +static JSStdName standard_class_names[] = { + /* ECMA requires that eval be a direct property of the global object. */ + {js_InitEval, EAGER_ATOM(eval), NULL}, + + /* Global properties and functions defined by the Number class. */ + {js_InitNumberClass, LAZY_ATOM(NaN), NULL}, + {js_InitNumberClass, LAZY_ATOM(Infinity), NULL}, + {js_InitNumberClass, LAZY_ATOM(isNaN), NULL}, + {js_InitNumberClass, LAZY_ATOM(isFinite), NULL}, + {js_InitNumberClass, LAZY_ATOM(parseFloat), NULL}, + {js_InitNumberClass, LAZY_ATOM(parseInt), NULL}, + + /* String global functions. */ + {js_InitStringClass, LAZY_ATOM(escape), NULL}, + {js_InitStringClass, LAZY_ATOM(unescape), NULL}, + {js_InitStringClass, LAZY_ATOM(decodeURI), NULL}, + {js_InitStringClass, LAZY_ATOM(encodeURI), NULL}, + {js_InitStringClass, LAZY_ATOM(decodeURIComponent), NULL}, + {js_InitStringClass, LAZY_ATOM(encodeURIComponent), NULL}, +#if JS_HAS_UNEVAL + {js_InitStringClass, LAZY_ATOM(uneval), NULL}, +#endif + + /* Exception constructors. */ + {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)}, + +#if JS_HAS_XML_SUPPORT + {js_InitAnyNameClass, EAGER_ATOM_AND_CLASP(AnyName)}, + {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)}, + {js_InitXMLClass, LAZY_ATOM(XMLList), &js_XMLClass}, + {js_InitXMLClass, LAZY_ATOM(isXMLName), NULL}, +#endif + +#if JS_HAS_GENERATORS + {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)}, + {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)}, +#endif + + {NULL, 0, NULL, NULL} +}; + +static JSStdName object_prototype_names[] = { + /* Object.prototype properties (global delegates to Object.prototype). */ + {js_InitObjectClass, EAGER_ATOM(proto), NULL}, + {js_InitObjectClass, EAGER_ATOM(parent), NULL}, + {js_InitObjectClass, EAGER_ATOM(count), NULL}, +#if JS_HAS_TOSOURCE + {js_InitObjectClass, EAGER_ATOM(toSource), NULL}, +#endif + {js_InitObjectClass, EAGER_ATOM(toString), NULL}, + {js_InitObjectClass, EAGER_ATOM(toLocaleString), NULL}, + {js_InitObjectClass, EAGER_ATOM(valueOf), NULL}, +#if JS_HAS_OBJ_WATCHPOINT + {js_InitObjectClass, LAZY_ATOM(watch), NULL}, + {js_InitObjectClass, LAZY_ATOM(unwatch), NULL}, +#endif + {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), NULL}, + {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), NULL}, + {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), NULL}, +#if JS_HAS_GETTER_SETTER + {js_InitObjectClass, LAZY_ATOM(defineGetter), NULL}, + {js_InitObjectClass, LAZY_ATOM(defineSetter), NULL}, + {js_InitObjectClass, LAZY_ATOM(lookupGetter), NULL}, + {js_InitObjectClass, LAZY_ATOM(lookupSetter), NULL}, +#endif + + {NULL, 0, NULL, NULL} +}; + +JS_PUBLIC_API(JSBool) +JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id, + JSBool *resolved) +{ + JSString *idstr; + JSRuntime *rt; + JSAtom *atom; + JSStdName *stdnm; + uintN i; + + CHECK_REQUEST(cx); + *resolved = JS_FALSE; + + rt = cx->runtime; + JS_ASSERT(rt->state != JSRTS_DOWN); + if (rt->state == JSRTS_LANDING || !JSVAL_IS_STRING(id)) + return JS_TRUE; + + idstr = JSVAL_TO_STRING(id); + + /* Check whether we're resolving 'undefined', and define it if so. */ + atom = rt->atomState.typeAtoms[JSTYPE_VOID]; + if (idstr == ATOM_TO_STRING(atom)) { + *resolved = JS_TRUE; + return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID, + NULL, NULL, JSPROP_PERMANENT, NULL); + } + + /* Try for class constructors/prototypes named by well-known atoms. */ + stdnm = NULL; + for (i = 0; standard_class_atoms[i].init; i++) { + atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset); + if (idstr == ATOM_TO_STRING(atom)) { + stdnm = &standard_class_atoms[i]; + break; + } + } + + if (!stdnm) { + /* Try less frequently used top-level functions and constants. */ + for (i = 0; standard_class_names[i].init; i++) { + atom = StdNameToAtom(cx, &standard_class_names[i]); + if (!atom) + return JS_FALSE; + if (idstr == ATOM_TO_STRING(atom)) { + stdnm = &standard_class_names[i]; + break; + } + } + + if (!stdnm && !OBJ_GET_PROTO(cx, obj)) { + /* + * Try even less frequently used names delegated from the global + * object to Object.prototype, but only if the Object class hasn't + * yet been initialized. + */ + for (i = 0; object_prototype_names[i].init; i++) { + atom = StdNameToAtom(cx, &object_prototype_names[i]); + if (!atom) + return JS_FALSE; + if (idstr == ATOM_TO_STRING(atom)) { + stdnm = &standard_class_names[i]; + break; + } + } + } + } + + if (stdnm) { + /* + * If this standard class is anonymous and obj advertises itself as a + * global object (in order to reserve slots for standard class object + * pointers), then we don't want to resolve by name. + * + * If inversely, either id does not name a class, or id does not name + * an anonymous class, or the global does not reserve slots for class + * objects, then we must call the init hook here. + */ + if (stdnm->clasp && + (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS) && + (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL)) { + return JS_TRUE; + } + + if (!stdnm->init(cx, obj)) + return JS_FALSE; + *resolved = JS_TRUE; + } + return JS_TRUE; +} + +static JSBool +AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom) +{ + JSScopeProperty *sprop; + JSScope *scope; + + JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_LOCK_OBJ(cx, obj); + scope = OBJ_SCOPE(obj); + sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom)); + JS_UNLOCK_SCOPE(cx, scope); + return sprop != NULL; +} + +JS_PUBLIC_API(JSBool) +JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj) +{ + JSRuntime *rt; + JSAtom *atom; + uintN i; + + CHECK_REQUEST(cx); + rt = cx->runtime; + + /* Check whether we need to bind 'undefined' and define it if so. */ + atom = rt->atomState.typeAtoms[JSTYPE_VOID]; + if (!AlreadyHasOwnProperty(cx, obj, atom) && + !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID, + NULL, NULL, JSPROP_PERMANENT, NULL)) { + return JS_FALSE; + } + + /* Initialize any classes that have not been resolved yet. */ + for (i = 0; standard_class_atoms[i].init; i++) { + atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset); + if (!AlreadyHasOwnProperty(cx, obj, atom) && + !standard_class_atoms[i].init(cx, obj)) { + return JS_FALSE; + } + } + + return JS_TRUE; +} + +static JSIdArray * +NewIdArray(JSContext *cx, jsint length) +{ + JSIdArray *ida; + + ida = (JSIdArray *) + JS_malloc(cx, offsetof(JSIdArray, vector) + length * sizeof(jsval)); + if (ida) + ida->length = length; + return ida; +} + +/* + * Unlike realloc(3), this function frees ida on failure. + */ +static JSIdArray * +SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length) +{ + JSIdArray *rida; + + rida = (JSIdArray *) + JS_realloc(cx, ida, + offsetof(JSIdArray, vector) + length * sizeof(jsval)); + if (!rida) + JS_DestroyIdArray(cx, ida); + else + rida->length = length; + return rida; +} + +static JSIdArray * +AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip) +{ + jsint i, length; + + i = *ip; + length = ida->length; + if (i >= length) { + ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8)); + if (!ida) + return NULL; + JS_ASSERT(i < ida->length); + } + ida->vector[i] = ATOM_TO_JSID(atom); + *ip = i + 1; + return ida; +} + +static JSIdArray * +EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida, + jsint *ip, JSBool *foundp) +{ + *foundp = AlreadyHasOwnProperty(cx, obj, atom); + if (*foundp) + ida = AddAtomToArray(cx, atom, ida, ip); + return ida; +} + +JS_PUBLIC_API(JSIdArray *) +JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, + JSIdArray *ida) +{ + JSRuntime *rt; + jsint i, j, k; + JSAtom *atom; + JSBool found; + JSObjectOp init; + + CHECK_REQUEST(cx); + rt = cx->runtime; + if (ida) { + i = ida->length; + } else { + ida = NewIdArray(cx, 8); + if (!ida) + return NULL; + i = 0; + } + + /* Check whether 'undefined' has been resolved and enumerate it if so. */ + atom = rt->atomState.typeAtoms[JSTYPE_VOID]; + ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found); + if (!ida) + return NULL; + + /* Enumerate only classes that *have* been resolved. */ + for (j = 0; standard_class_atoms[j].init; j++) { + atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset); + ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found); + if (!ida) + return NULL; + + if (found) { + init = standard_class_atoms[j].init; + + for (k = 0; standard_class_names[k].init; k++) { + if (standard_class_names[k].init == init) { + atom = StdNameToAtom(cx, &standard_class_names[k]); + ida = AddAtomToArray(cx, atom, ida, &i); + if (!ida) + return NULL; + } + } + + if (init == js_InitObjectClass) { + for (k = 0; object_prototype_names[k].init; k++) { + atom = StdNameToAtom(cx, &object_prototype_names[k]); + ida = AddAtomToArray(cx, atom, ida, &i); + if (!ida) + return NULL; + } + } + } + } + + /* Trim to exact length. */ + return SetIdArrayLength(cx, ida, i); +} + +#undef CLASP +#undef EAGER_ATOM +#undef EAGER_CLASS_ATOM +#undef EAGER_ATOM_CLASP +#undef LAZY_ATOM + +JS_PUBLIC_API(JSBool) +JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, + JSObject **objp) +{ + CHECK_REQUEST(cx); + return js_GetClassObject(cx, obj, key, objp); +} + +JS_PUBLIC_API(JSObject *) +JS_GetScopeChain(JSContext *cx) +{ + JSStackFrame *fp; + + CHECK_REQUEST(cx); + fp = cx->fp; + if (!fp) { + /* + * There is no code active on this context. In place of an actual + * scope chain, use the context's global object, which is set in + * js_InitFunctionAndObjectClasses, and which represents the default + * scope chain for the embedding. See also js_FindClassObject. + * + * For embeddings that use the inner and outer object hooks, the inner + * object represents the ultimate global object, with the outer object + * acting as a stand-in. + */ + JSObject *obj = cx->globalObject; + if (!obj) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE); + return NULL; + } + + OBJ_TO_INNER_OBJECT(cx, obj); + return obj; + } + return js_GetScopeChain(cx, fp); +} + +JS_PUBLIC_API(JSObject *) +JS_GetGlobalForObject(JSContext *cx, JSObject *obj) +{ + JSObject *parent; + + while ((parent = OBJ_GET_PARENT(cx, obj)) != NULL) + obj = parent; + return obj; +} + +JS_PUBLIC_API(jsval) +JS_ComputeThis(JSContext *cx, jsval *vp) +{ + if (!js_ComputeThis(cx, JS_FALSE, vp + 2)) + return JSVAL_NULL; + return vp[1]; +} + +JS_PUBLIC_API(void *) +JS_malloc(JSContext *cx, size_t nbytes) +{ + void *p; + + JS_ASSERT(nbytes != 0); + JS_COUNT_OPERATION(cx, JSOW_ALLOCATION); + if (nbytes == 0) + nbytes = 1; + + p = malloc(nbytes); + if (!p) { + JS_ReportOutOfMemory(cx); + return NULL; + } + js_UpdateMallocCounter(cx, nbytes); + + return p; +} + +JS_PUBLIC_API(void *) +JS_realloc(JSContext *cx, void *p, size_t nbytes) +{ + JS_COUNT_OPERATION(cx, JSOW_ALLOCATION); + p = realloc(p, nbytes); + if (!p) + JS_ReportOutOfMemory(cx); + return p; +} + +JS_PUBLIC_API(void) +JS_free(JSContext *cx, void *p) +{ + if (p) + free(p); +} + +JS_PUBLIC_API(char *) +JS_strdup(JSContext *cx, const char *s) +{ + size_t n; + void *p; + + n = strlen(s) + 1; + p = JS_malloc(cx, n); + if (!p) + return NULL; + return (char *)memcpy(p, s, n); +} + +JS_PUBLIC_API(jsdouble *) +JS_NewDouble(JSContext *cx, jsdouble d) +{ + CHECK_REQUEST(cx); + return js_NewWeaklyRootedDouble(cx, d); +} + +JS_PUBLIC_API(JSBool) +JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval) +{ + jsdouble *dp; + + CHECK_REQUEST(cx); + dp = js_NewWeaklyRootedDouble(cx, d); + if (!dp) + return JS_FALSE; + *rval = DOUBLE_TO_JSVAL(dp); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval) +{ + jsint i; + + CHECK_REQUEST(cx); + if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) { + *rval = INT_TO_JSVAL(i); + return JS_TRUE; + } + return JS_NewDoubleValue(cx, d, rval); +} + +#undef JS_AddRoot +JS_PUBLIC_API(JSBool) +JS_AddRoot(JSContext *cx, void *rp) +{ + CHECK_REQUEST(cx); + return js_AddRoot(cx, rp, NULL); +} + +JS_PUBLIC_API(JSBool) +JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name) +{ + return js_AddRootRT(rt, rp, name); +} + +JS_PUBLIC_API(JSBool) +JS_RemoveRoot(JSContext *cx, void *rp) +{ + CHECK_REQUEST(cx); + return js_RemoveRoot(cx->runtime, rp); +} + +JS_PUBLIC_API(JSBool) +JS_RemoveRootRT(JSRuntime *rt, void *rp) +{ + return js_RemoveRoot(rt, rp); +} + +JS_PUBLIC_API(JSBool) +JS_AddNamedRoot(JSContext *cx, void *rp, const char *name) +{ + CHECK_REQUEST(cx); + return js_AddRoot(cx, rp, name); +} + +JS_PUBLIC_API(void) +JS_ClearNewbornRoots(JSContext *cx) +{ + JS_CLEAR_WEAK_ROOTS(&cx->weakRoots); +} + +JS_PUBLIC_API(JSBool) +JS_EnterLocalRootScope(JSContext *cx) +{ + CHECK_REQUEST(cx); + return js_EnterLocalRootScope(cx); +} + +JS_PUBLIC_API(void) +JS_LeaveLocalRootScope(JSContext *cx) +{ + CHECK_REQUEST(cx); + js_LeaveLocalRootScope(cx); +} + +JS_PUBLIC_API(void) +JS_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval) +{ + CHECK_REQUEST(cx); + js_LeaveLocalRootScopeWithResult(cx, rval); +} + +JS_PUBLIC_API(void) +JS_ForgetLocalRoot(JSContext *cx, void *thing) +{ + CHECK_REQUEST(cx); + js_ForgetLocalRoot(cx, (jsval) thing); +} + +#ifdef DEBUG + +JS_PUBLIC_API(void) +JS_DumpNamedRoots(JSRuntime *rt, + void (*dump)(const char *name, void *rp, void *data), + void *data) +{ + js_DumpNamedRoots(rt, dump, data); +} + +#endif /* DEBUG */ + +JS_PUBLIC_API(uint32) +JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data) +{ + return js_MapGCRoots(rt, map, data); +} + +JS_PUBLIC_API(JSBool) +JS_LockGCThing(JSContext *cx, void *thing) +{ + JSBool ok; + + CHECK_REQUEST(cx); + ok = js_LockGCThingRT(cx->runtime, thing); + if (!ok) + JS_ReportOutOfMemory(cx); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_LockGCThingRT(JSRuntime *rt, void *thing) +{ + return js_LockGCThingRT(rt, thing); +} + +JS_PUBLIC_API(JSBool) +JS_UnlockGCThing(JSContext *cx, void *thing) +{ + JSBool ok; + + CHECK_REQUEST(cx); + ok = js_UnlockGCThingRT(cx->runtime, thing); + if (!ok) + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_UnlockGCThingRT(JSRuntime *rt, void *thing) +{ + return js_UnlockGCThingRT(rt, thing); +} + +JS_PUBLIC_API(void) +JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data) +{ + rt->gcExtraRootsTraceOp = traceOp; + rt->gcExtraRootsData = data; +} + +JS_PUBLIC_API(void) +JS_TraceRuntime(JSTracer *trc) +{ + JSBool allAtoms = trc->context->runtime->gcKeepAtoms != 0; + + js_TraceRuntime(trc, allAtoms); +} + +#ifdef DEBUG + +#ifdef HAVE_XPCONNECT +#include "dump_xpc.h" +#endif + +JS_PUBLIC_API(void) +JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, + void *thing, uint32 kind, JSBool details) +{ + const char *name; + size_t n; + + if (bufsize == 0) + return; + + switch (kind) { + case JSTRACE_OBJECT: + { + JSObject *obj = (JSObject *)thing; + JSClass *clasp = STOBJ_GET_CLASS(obj); + + name = clasp->name; +#ifdef HAVE_XPCONNECT + if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) { + jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE); + + JS_ASSERT(clasp->flags & JSCLASS_HAS_PRIVATE); + if (!JSVAL_IS_VOID(privateValue)) { + void *privateThing = JSVAL_TO_PRIVATE(privateValue); + const char *xpcClassName = GetXPCObjectClassName(privateThing); + + if (xpcClassName) + name = xpcClassName; + } + } +#endif + break; + } + + case JSTRACE_STRING: + name = JSSTRING_IS_DEPENDENT((JSString *)thing) + ? "substring" + : "string"; + break; + + case JSTRACE_DOUBLE: + name = "double"; + break; + +#if JS_HAS_XML_SUPPORT + case JSTRACE_XML: + name = "xml"; + break; +#endif + default: + JS_ASSERT(0); + return; + break; + } + + n = strlen(name); + if (n > bufsize - 1) + n = bufsize - 1; + memcpy(buf, name, n + 1); + buf += n; + bufsize -= n; + + if (details && bufsize > 2) { + *buf++ = ' '; + bufsize--; + + switch (kind) { + case JSTRACE_OBJECT: + { + JSObject *obj = (JSObject *)thing; + JSClass *clasp = STOBJ_GET_CLASS(obj); + if (clasp == &js_FunctionClass) { + JSFunction *fun = (JSFunction *) + JS_GetPrivate(trc->context, obj); + + if (!fun) { + JS_snprintf(buf, bufsize, ""); + } else if (FUN_OBJECT(fun) != obj) { + JS_snprintf(buf, bufsize, "%p", fun); + } else { + if (fun->atom && ATOM_IS_STRING(fun->atom)) + js_PutEscapedString(buf, bufsize, + ATOM_TO_STRING(fun->atom), 0); + } + } else if (clasp->flags & JSCLASS_HAS_PRIVATE) { + jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE); + void *privateThing = JSVAL_IS_VOID(privateValue) + ? NULL + : JSVAL_TO_PRIVATE(privateValue); + + JS_snprintf(buf, bufsize, "%p", privateThing); + } else { + JS_snprintf(buf, bufsize, ""); + } + break; + } + + case JSTRACE_STRING: + js_PutEscapedString(buf, bufsize, (JSString *)thing, 0); + break; + + case JSTRACE_DOUBLE: + JS_snprintf(buf, bufsize, "%g", *(jsdouble *)thing); + break; + +#if JS_HAS_XML_SUPPORT + case JSTRACE_XML: + { + extern const char *js_xml_class_str[]; + JSXML *xml = (JSXML *)thing; + + JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]); + break; + } +#endif + default: + JS_ASSERT(0); + break; + } + } + buf[bufsize - 1] = '\0'; +} + +typedef struct JSHeapDumpNode JSHeapDumpNode; + +struct JSHeapDumpNode { + void *thing; + uint32 kind; + JSHeapDumpNode *next; /* next sibling */ + JSHeapDumpNode *parent; /* node with the thing that refer to thing + from this node */ + char edgeName[1]; /* name of the edge from parent->thing + into thing */ +}; + +typedef struct JSDumpingTracer { + JSTracer base; + JSDHashTable visited; + JSBool ok; + void *startThing; + void *thingToFind; + void *thingToIgnore; + JSHeapDumpNode *parentNode; + JSHeapDumpNode **lastNodep; + char buffer[200]; +} JSDumpingTracer; + +static void +DumpNotify(JSTracer *trc, void *thing, uint32 kind) +{ + JSDumpingTracer *dtrc; + JSContext *cx; + JSDHashEntryStub *entry; + JSHeapDumpNode *node; + const char *edgeName; + size_t edgeNameSize; + + JS_ASSERT(trc->callback == DumpNotify); + dtrc = (JSDumpingTracer *)trc; + + if (!dtrc->ok || thing == dtrc->thingToIgnore) + return; + + cx = trc->context; + + /* + * Check if we have already seen thing unless it is thingToFind to include + * it to the graph each time we reach it and print all live things that + * refer to thingToFind. + * + * This does not print all possible paths leading to thingToFind since + * when a thing A refers directly or indirectly to thingToFind and A is + * present several times in the graph, we will print only the first path + * leading to A and thingToFind, other ways to reach A will be ignored. + */ + if (dtrc->thingToFind != thing) { + /* + * The startThing check allows to avoid putting startThing into the + * hash table before tracing startThing in JS_DumpHeap. + */ + if (thing == dtrc->startThing) + return; + entry = (JSDHashEntryStub *) + JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD); + if (!entry) { + JS_ReportOutOfMemory(cx); + dtrc->ok = JS_FALSE; + return; + } + if (entry->key) + return; + entry->key = thing; + } + + if (dtrc->base.debugPrinter) { + dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer)); + edgeName = dtrc->buffer; + } else if (dtrc->base.debugPrintIndex != (size_t)-1) { + JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]", + (const char *)dtrc->base.debugPrintArg, + dtrc->base.debugPrintIndex); + edgeName = dtrc->buffer; + } else { + edgeName = (const char*)dtrc->base.debugPrintArg; + } + + edgeNameSize = strlen(edgeName) + 1; + node = (JSHeapDumpNode *) + JS_malloc(cx, offsetof(JSHeapDumpNode, edgeName) + edgeNameSize); + if (!node) { + dtrc->ok = JS_FALSE; + return; + } + + node->thing = thing; + node->kind = kind; + node->next = NULL; + node->parent = dtrc->parentNode; + memcpy(node->edgeName, edgeName, edgeNameSize); + + JS_ASSERT(!*dtrc->lastNodep); + *dtrc->lastNodep = node; + dtrc->lastNodep = &node->next; +} + +/* Dump node and the chain that leads to thing it contains. */ +static JSBool +DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node) +{ + JSHeapDumpNode *prev, *following; + size_t chainLimit; + JSBool ok; + enum { MAX_PARENTS_TO_PRINT = 10 }; + + JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer, + &dtrc->base, node->thing, node->kind, JS_TRUE); + if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0) + return JS_FALSE; + + /* + * We need to print the parent chain in the reverse order. To do it in + * O(N) time where N is the chain length we first reverse the chain while + * searching for the top and then print each node while restoring the + * chain order. + */ + chainLimit = MAX_PARENTS_TO_PRINT; + prev = NULL; + for (;;) { + following = node->parent; + node->parent = prev; + prev = node; + node = following; + if (!node) + break; + if (chainLimit == 0) { + if (fputs("...", fp) < 0) + return JS_FALSE; + break; + } + --chainLimit; + } + + node = prev; + prev = following; + ok = JS_TRUE; + do { + /* Loop must continue even when !ok to restore the parent chain. */ + if (ok) { + if (!prev) { + /* Print edge from some runtime root or startThing. */ + if (fputs(node->edgeName, fp) < 0) + ok = JS_FALSE; + } else { + JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer, + &dtrc->base, prev->thing, prev->kind, + JS_FALSE); + if (fprintf(fp, "(%p %s).%s", + prev->thing, dtrc->buffer, node->edgeName) < 0) { + ok = JS_FALSE; + } + } + } + following = node->parent; + node->parent = prev; + prev = node; + node = following; + } while (node); + + return ok && putc('\n', fp) >= 0; +} + +JS_PUBLIC_API(JSBool) +JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind, + void *thingToFind, size_t maxDepth, void *thingToIgnore) +{ + JSDumpingTracer dtrc; + JSHeapDumpNode *node, *children, *next, *parent; + size_t depth; + JSBool thingToFindWasTraced; + + if (maxDepth == 0) + return JS_TRUE; + + JS_TRACER_INIT(&dtrc.base, cx, DumpNotify); + if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(), + NULL, sizeof(JSDHashEntryStub), + JS_DHASH_DEFAULT_CAPACITY(100))) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + dtrc.ok = JS_TRUE; + dtrc.startThing = startThing; + dtrc.thingToFind = thingToFind; + dtrc.thingToIgnore = thingToIgnore; + dtrc.parentNode = NULL; + node = NULL; + dtrc.lastNodep = &node; + if (!startThing) { + JS_ASSERT(startKind == 0); + JS_TraceRuntime(&dtrc.base); + } else { + JS_TraceChildren(&dtrc.base, startThing, startKind); + } + + depth = 1; + if (!node) + goto dump_out; + + thingToFindWasTraced = thingToFind && thingToFind == startThing; + for (;;) { + /* + * Loop must continue even when !dtrc.ok to free all nodes allocated + * so far. + */ + if (dtrc.ok) { + if (thingToFind == NULL || thingToFind == node->thing) + dtrc.ok = DumpNode(&dtrc, fp, node); + + /* Descend into children. */ + if (dtrc.ok && + depth < maxDepth && + (thingToFind != node->thing || !thingToFindWasTraced)) { + dtrc.parentNode = node; + children = NULL; + dtrc.lastNodep = &children; + JS_TraceChildren(&dtrc.base, node->thing, node->kind); + if (thingToFind == node->thing) + thingToFindWasTraced = JS_TRUE; + if (children != NULL) { + ++depth; + node = children; + continue; + } + } + } + + /* Move to next or parents next and free the node. */ + for (;;) { + next = node->next; + parent = node->parent; + JS_free(cx, node); + node = next; + if (node) + break; + if (!parent) + goto dump_out; + JS_ASSERT(depth > 1); + --depth; + node = parent; + } + } + + dump_out: + JS_ASSERT(depth == 1); + JS_DHashTableFinish(&dtrc.visited); + return dtrc.ok; +} + +#endif /* DEBUG */ + +JS_PUBLIC_API(void) +JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg) +{ + JSTracer *trc; + + trc = (JSTracer *)arg; + if (!trc) + trc = cx->runtime->gcMarkingTracer; + else + JS_ASSERT(trc == cx->runtime->gcMarkingTracer); + +#ifdef JS_THREADSAFE + JS_ASSERT(cx->runtime->gcThread == trc->context->thread); +#endif + JS_SET_TRACING_NAME(trc, name ? name : "unknown"); + js_CallValueTracerIfGCThing(trc, (jsval)thing); +} + +extern JS_PUBLIC_API(JSBool) +JS_IsGCMarkingTracer(JSTracer *trc) +{ + return IS_GC_MARKING_TRACER(trc); +} + +JS_PUBLIC_API(void) +JS_GC(JSContext *cx) +{ + /* Don't nuke active arenas if executing or compiling. */ + if (cx->stackPool.current == &cx->stackPool.first) + JS_FinishArenaPool(&cx->stackPool); + if (cx->tempPool.current == &cx->tempPool.first) + JS_FinishArenaPool(&cx->tempPool); + js_GC(cx, GC_NORMAL); +} + +JS_PUBLIC_API(void) +JS_MaybeGC(JSContext *cx) +{ + JSRuntime *rt; + uint32 bytes, lastBytes; + + rt = cx->runtime; + +#ifdef JS_GC_ZEAL + if (rt->gcZeal > 0) { + JS_GC(cx); + return; + } +#endif + + bytes = rt->gcBytes; + lastBytes = rt->gcLastBytes; + + /* + * We run the GC if we used all available free GC cells and had to + * allocate extra 1/3 of GC arenas since the last run of GC, or if + * we have malloc'd more bytes through JS_malloc than we were told + * to allocate by JS_NewRuntime. + * + * The reason for + * bytes > 4/3 lastBytes + * condition is the following. Bug 312238 changed bytes and lastBytes + * to mean the total amount of memory that the GC uses now and right + * after the last GC. + * + * Before the bug the variables meant the size of allocated GC things + * now and right after the last GC. That size did not include the + * memory taken by free GC cells and the condition was + * bytes > 3/2 lastBytes. + * That is, we run the GC if we have half again as many bytes of + * GC-things as the last time we GC'd. To be compatible we need to + * express that condition through the new meaning of bytes and + * lastBytes. + * + * We write the original condition as + * B*(1-F) > 3/2 Bl*(1-Fl) + * where B is the total memory size allocated by GC and F is the free + * cell density currently and Sl and Fl are the size and the density + * right after GC. The density by definition is memory taken by free + * cells divided by total amount of memory. In other words, B and Bl + * are bytes and lastBytes with the new meaning and B*(1-F) and + * Bl*(1-Fl) are bytes and lastBytes with the original meaning. + * + * Our task is to exclude F and Fl from the last statement. According + * to the stats from bug 331966 comment 23, Fl is about 10-25% for a + * typical run of the browser. It means that the original condition + * implied that we did not run GC unless we exhausted the pool of + * free cells. Indeed if we still have free cells, then B == Bl since + * we did not yet allocated any new arenas and the condition means + * 1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F + * That implies 3/2 Fl > 1/2 or Fl > 1/3. That can not be fulfilled + * for the state described by the stats. So we can write the original + * condition as: + * F == 0 && B > 3/2 Bl(1-Fl) + * Again using the stats we see that Fl is about 11% when the browser + * starts up and when we are far from hitting rt->gcMaxBytes. With + * this F we have + * F == 0 && B > 3/2 Bl(1-0.11) + * or approximately F == 0 && B > 4/3 Bl. + */ + if ((bytes > 8192 && bytes > lastBytes + lastBytes / 3) || + rt->gcMallocBytes >= rt->gcMaxMallocBytes) { + JS_GC(cx); + } +} + +JS_PUBLIC_API(JSGCCallback) +JS_SetGCCallback(JSContext *cx, JSGCCallback cb) +{ + CHECK_REQUEST(cx); + return JS_SetGCCallbackRT(cx->runtime, cb); +} + +JS_PUBLIC_API(JSGCCallback) +JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb) +{ + JSGCCallback oldcb; + + oldcb = rt->gcCallback; + rt->gcCallback = cb; + return oldcb; +} + +JS_PUBLIC_API(JSBool) +JS_IsAboutToBeFinalized(JSContext *cx, void *thing) +{ + JS_ASSERT(thing); + return js_IsAboutToBeFinalized(cx, thing); +} + +JS_PUBLIC_API(void) +JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value) +{ + switch (key) { + case JSGC_MAX_BYTES: + rt->gcMaxBytes = value; + break; + case JSGC_MAX_MALLOC_BYTES: + rt->gcMaxMallocBytes = value; + break; + case JSGC_STACKPOOL_LIFESPAN: + rt->gcEmptyArenaPoolLifespan = value; + break; + } +} + +JS_PUBLIC_API(intN) +JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer) +{ + return js_ChangeExternalStringFinalizer(NULL, finalizer); +} + +JS_PUBLIC_API(intN) +JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer) +{ + return js_ChangeExternalStringFinalizer(finalizer, NULL); +} + +JS_PUBLIC_API(JSString *) +JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type) +{ + JSString *str; + + CHECK_REQUEST(cx); + JS_ASSERT((uintN) type < (uintN) (GCX_NTYPES - GCX_EXTERNAL_STRING)); + + str = (JSString *) js_NewGCThing(cx, (uintN) type + GCX_EXTERNAL_STRING, + sizeof(JSString)); + if (!str) + return NULL; + JSFLATSTR_INIT(str, chars, length); + return str; +} + +JS_PUBLIC_API(intN) +JS_GetExternalStringGCType(JSRuntime *rt, JSString *str) +{ + return js_GetExternalStringGCType(str); +} + +JS_PUBLIC_API(void) +JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr) +{ +#if JS_STACK_GROWTH_DIRECTION > 0 + if (limitAddr == 0) + limitAddr = (jsuword)-1; +#endif + cx->stackLimit = limitAddr; +} + +JS_PUBLIC_API(void) +JS_SetScriptStackQuota(JSContext *cx, size_t quota) +{ + cx->scriptStackQuota = quota; +} + +/************************************************************************/ + +JS_PUBLIC_API(void) +JS_DestroyIdArray(JSContext *cx, JSIdArray *ida) +{ + JS_free(cx, ida); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToId(JSContext *cx, jsval v, jsid *idp) +{ + CHECK_REQUEST(cx); + if (JSVAL_IS_INT(v)) + *idp = INT_JSVAL_TO_JSID(v); +#if JS_HAS_XML_SUPPORT + else if (!JSVAL_IS_PRIMITIVE(v)) + *idp = OBJECT_JSVAL_TO_JSID(v); +#endif + else + return js_ValueToStringId(cx, v, idp); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_IdToValue(JSContext *cx, jsid id, jsval *vp) +{ + CHECK_REQUEST(cx); + *vp = ID_TO_VALUE(id); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_EnumerateStub(JSContext *cx, JSObject *obj) +{ + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id) +{ + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp) +{ + return js_TryValueOf(cx, obj, type, vp); +} + +JS_PUBLIC_API(void) +JS_FinalizeStub(JSContext *cx, JSObject *obj) +{ +} + +JS_PUBLIC_API(JSObject *) +JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, + JSClass *clasp, JSNative constructor, uintN nargs, + JSPropertySpec *ps, JSFunctionSpec *fs, + JSPropertySpec *static_ps, JSFunctionSpec *static_fs) +{ + JSAtom *atom; + JSProtoKey key; + JSObject *proto, *ctor; + JSTempValueRooter tvr; + jsval cval, rval; + JSBool named; + JSFunction *fun; + + CHECK_REQUEST(cx); + atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0); + if (!atom) + return NULL; + + /* + * When initializing a standard class, if no parent_proto (grand-proto of + * instances of the class, parent-proto of the class's prototype object) + * is given, we must use Object.prototype if it is available. Otherwise, + * we could look up the wrong binding for a class name in obj. Example: + * + * String = Array; + * print("hi there".join); + * + * should print undefined, not Array.prototype.join. This is required by + * ECMA-262, alas. It might have been better to make String readonly and + * permanent in the global object, instead -- but that's too big a change + * to swallow at this point. + */ + key = JSCLASS_CACHED_PROTO_KEY(clasp); + if (key != JSProto_Null && + !parent_proto && + !js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object), + &parent_proto)) { + return NULL; + } + + /* Create a prototype object for this class. */ + proto = js_NewObject(cx, clasp, parent_proto, obj, 0); + if (!proto) + return NULL; + + /* After this point, control must exit via label bad or out. */ + JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr); + + if (!constructor) { + /* + * Lacking a constructor, name the prototype (e.g., Math) unless this + * class (a) is anonymous, i.e. for internal use only; (b) the class + * of obj (the global object) is has a reserved slot indexed by key; + * and (c) key is not the null key. + */ + if ((clasp->flags & JSCLASS_IS_ANONYMOUS) && + (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) && + key != JSProto_Null) { + named = JS_FALSE; + } else { + named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), + OBJECT_TO_JSVAL(proto), + JS_PropertyStub, JS_PropertyStub, + (clasp->flags & JSCLASS_IS_ANONYMOUS) + ? JSPROP_READONLY | JSPROP_PERMANENT + : 0, + NULL); + if (!named) + goto bad; + } + + ctor = proto; + } else { + /* Define the constructor function in obj's scope. */ + fun = js_DefineFunction(cx, obj, atom, constructor, nargs, + JSFUN_STUB_GSOPS); + named = (fun != NULL); + if (!fun) + goto bad; + + /* + * Remember the class this function is a constructor for so that + * we know to create an object of this class when we call the + * constructor. + */ + FUN_CLASP(fun) = clasp; + + /* + * Optionally construct the prototype object, before the class has + * been fully initialized. Allow the ctor to replace proto with a + * different object, as is done for operator new -- and as at least + * XML support requires. + */ + ctor = FUN_OBJECT(fun); + if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) { + cval = OBJECT_TO_JSVAL(ctor); + if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval)) + goto bad; + if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto) + proto = JSVAL_TO_OBJECT(rval); + } + + /* Connect constructor and prototype by named properties. */ + if (!js_SetClassPrototype(cx, ctor, proto, + JSPROP_READONLY | JSPROP_PERMANENT)) { + goto bad; + } + + /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */ + if (OBJ_GET_CLASS(cx, ctor) == clasp) { + OBJ_SET_PROTO(cx, ctor, proto); + } + } + + /* Add properties and methods to the prototype and the constructor. */ + if ((ps && !JS_DefineProperties(cx, proto, ps)) || + (fs && !JS_DefineFunctions(cx, proto, fs)) || + (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) || + (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) { + goto bad; + } + + /* If this is a standard class, cache its prototype. */ + if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor)) + goto bad; + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return proto; + +bad: + if (named) + (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval); + proto = NULL; + goto out; +} + +#ifdef JS_THREADSAFE +JS_PUBLIC_API(JSClass *) +JS_GetClass(JSContext *cx, JSObject *obj) +{ + return OBJ_GET_CLASS(cx, obj); +} +#else +JS_PUBLIC_API(JSClass *) +JS_GetClass(JSObject *obj) +{ + return LOCKED_OBJ_GET_CLASS(obj); +} +#endif + +JS_PUBLIC_API(JSBool) +JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv) +{ + JSFunction *fun; + + CHECK_REQUEST(cx); + if (obj && OBJ_GET_CLASS(cx, obj) == clasp) + return JS_TRUE; + if (argv) { + fun = js_ValueToFunction(cx, &argv[-2], 0); + if (fun) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_PROTO, + clasp->name, JS_GetFunctionName(fun), + obj + ? OBJ_GET_CLASS(cx, obj)->name + : js_null_str); + } + } + return JS_FALSE; +} + +JS_PUBLIC_API(JSBool) +JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +{ + return js_HasInstance(cx, obj, v, bp); +} + +JS_PUBLIC_API(void *) +JS_GetPrivate(JSContext *cx, JSObject *obj) +{ + jsval v; + + JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE); + v = obj->fslots[JSSLOT_PRIVATE]; + if (!JSVAL_IS_INT(v)) + return NULL; + return JSVAL_TO_PRIVATE(v); +} + +JS_PUBLIC_API(JSBool) +JS_SetPrivate(JSContext *cx, JSObject *obj, void *data) +{ + JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE); + obj->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(data); + return JS_TRUE; +} + +JS_PUBLIC_API(void *) +JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, + jsval *argv) +{ + if (!JS_InstanceOf(cx, obj, clasp, argv)) + return NULL; + return JS_GetPrivate(cx, obj); +} + +JS_PUBLIC_API(JSObject *) +JS_GetPrototype(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + + CHECK_REQUEST(cx); + proto = OBJ_GET_PROTO(cx, obj); + + /* Beware ref to dead object (we may be called from obj's finalizer). */ + return proto && proto->map ? proto : NULL; +} + +JS_PUBLIC_API(JSBool) +JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto) +{ + CHECK_REQUEST(cx); + JS_ASSERT(obj != proto); +#ifdef DEBUG + /* + * FIXME: bug 408416. The cycle-detection required for script-writeable + * __proto__ lives in js_SetProtoOrParent over in jsobj.c, also known as + * js_ObjectOps.setProto. This hook must detect cycles, to prevent scripts + * from ilooping SpiderMonkey trivially. But the overhead of detecting + * cycles is high enough, and the threat from JS-API-calling C++ code is + * low enough, that it's not worth burdening the non-DEBUG callers. Same + * goes for JS_SetParent, below. + */ + if (obj->map->ops->setProto) + return obj->map->ops->setProto(cx, obj, JSSLOT_PROTO, proto); +#else + if (OBJ_IS_NATIVE(obj)) { + JS_LOCK_OBJ(cx, obj); + if (!js_GetMutableScope(cx, obj)) { + JS_UNLOCK_OBJ(cx, obj); + return JS_FALSE; + } + LOCKED_OBJ_SET_PROTO(obj, proto); + JS_UNLOCK_OBJ(cx, obj); + return JS_TRUE; + } +#endif + OBJ_SET_PROTO(cx, obj, proto); + return JS_TRUE; +} + +JS_PUBLIC_API(JSObject *) +JS_GetParent(JSContext *cx, JSObject *obj) +{ + JSObject *parent; + + parent = OBJ_GET_PARENT(cx, obj); + + /* Beware ref to dead object (we may be called from obj's finalizer). */ + return parent && parent->map ? parent : NULL; +} + +JS_PUBLIC_API(JSBool) +JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent) +{ + CHECK_REQUEST(cx); + JS_ASSERT(obj != parent); +#ifdef DEBUG + /* FIXME: bug 408416, see JS_SetPrototype just above. */ + if (obj->map->ops->setParent) + return obj->map->ops->setParent(cx, obj, JSSLOT_PARENT, parent); +#endif + OBJ_SET_PARENT(cx, obj, parent); + return JS_TRUE; +} + +JS_PUBLIC_API(JSObject *) +JS_GetConstructor(JSContext *cx, JSObject *proto) +{ + jsval cval; + + CHECK_REQUEST(cx); + { + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + + if (!OBJ_GET_PROPERTY(cx, proto, + ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), + &cval)) { + return NULL; + } + } + if (!VALUE_IS_FUNCTION(cx, cval)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR, + OBJ_GET_CLASS(cx, proto)->name); + return NULL; + } + return JSVAL_TO_OBJECT(cval); +} + +JS_PUBLIC_API(JSBool) +JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp) +{ + JS_ASSERT(JSID_IS_OBJECT(obj)); + *idp = OBJECT_TO_JSID(obj); + return JS_TRUE; +} + +JS_PUBLIC_API(JSObject *) +JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent) +{ + CHECK_REQUEST(cx); + if (!clasp) + clasp = &js_ObjectClass; /* default class is Object */ + return js_NewObject(cx, clasp, proto, parent, 0); +} + +JS_PUBLIC_API(JSObject *) +JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent) +{ + CHECK_REQUEST(cx); + if (!clasp) + clasp = &js_ObjectClass; /* default class is Object */ + return js_NewObjectWithGivenProto(cx, clasp, proto, parent, 0); +} + +JS_PUBLIC_API(JSBool) +JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep) +{ + JSScope *scope; + JSIdArray *ida; + uint32 nslots, i; + jsval v; + + if (!OBJ_IS_NATIVE(obj)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_SEAL_OBJECT, + OBJ_GET_CLASS(cx, obj)->name); + return JS_FALSE; + } + + scope = OBJ_SCOPE(obj); + +#if defined JS_THREADSAFE && defined DEBUG + /* Insist on scope being used exclusively by cx's thread. */ + if (scope->title.ownercx != cx) { + JS_LOCK_OBJ(cx, obj); + JS_ASSERT(OBJ_SCOPE(obj) == scope); + JS_ASSERT(scope->title.ownercx == cx); + JS_UNLOCK_SCOPE(cx, scope); + } +#endif + + /* Nothing to do if obj's scope is already sealed. */ + if (SCOPE_IS_SEALED(scope)) + return JS_TRUE; + + /* XXX Enumerate lazy properties now, as they can't be added later. */ + ida = JS_Enumerate(cx, obj); + if (!ida) + return JS_FALSE; + JS_DestroyIdArray(cx, ida); + + /* Ensure that obj has its own, mutable scope, and seal that scope. */ + JS_LOCK_OBJ(cx, obj); + scope = js_GetMutableScope(cx, obj); + if (scope) { + SCOPE_SET_SEALED(scope); + SCOPE_MAKE_UNIQUE_SHAPE(cx, scope); + } + JS_UNLOCK_OBJ(cx, obj); + if (!scope) + return JS_FALSE; + + /* If we are not sealing an entire object graph, we're done. */ + if (!deep) + return JS_TRUE; + + /* Walk slots in obj and if any value is a non-null object, seal it. */ + nslots = scope->map.freeslot; + for (i = 0; i != nslots; ++i) { + v = STOBJ_GET_SLOT(obj, i); + if (JSVAL_IS_PRIMITIVE(v)) + continue; + if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep)) + return JS_FALSE; + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSObject *) +JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent) +{ + CHECK_REQUEST(cx); + if (!clasp) + clasp = &js_ObjectClass; /* default class is Object */ + return js_ConstructObject(cx, clasp, proto, parent, 0, NULL); +} + +JS_PUBLIC_API(JSObject *) +JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent, uintN argc, jsval *argv) +{ + CHECK_REQUEST(cx); + if (!clasp) + clasp = &js_ObjectClass; /* default class is Object */ + return js_ConstructObject(cx, clasp, proto, parent, argc, argv); +} + +static JSBool +DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + uintN flags, intN tinyid) +{ + if (flags != 0 && OBJ_IS_NATIVE(obj)) { + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); + return js_DefineNativeProperty(cx, obj, id, value, getter, setter, + attrs, flags, tinyid, NULL); + } + return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs, + NULL); +} + +static JSBool +DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + uintN flags, intN tinyid) +{ + jsid id; + JSAtom *atom; + + if (attrs & JSPROP_INDEX) { + id = INT_TO_JSID(JS_PTR_TO_INT32(name)); + atom = NULL; + attrs &= ~JSPROP_INDEX; + } else { + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + id = ATOM_TO_JSID(atom); + } + return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, + flags, tinyid); +} + +#define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n)) + +static JSBool +DefineUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + uintN flags, intN tinyid) +{ + JSAtom *atom; + + atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + if (!atom) + return JS_FALSE; + if (flags != 0 && OBJ_IS_NATIVE(obj)) { + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); + return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value, + getter, setter, attrs, flags, tinyid, + NULL); + } + return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value, + getter, setter, attrs, NULL); +} + +JS_PUBLIC_API(JSObject *) +JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp, + JSObject *proto, uintN attrs) +{ + JSObject *nobj; + + CHECK_REQUEST(cx); + if (!clasp) + clasp = &js_ObjectClass; /* default class is Object */ + nobj = js_NewObject(cx, clasp, proto, obj, 0); + if (!nobj) + return NULL; + if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs, + 0, 0)) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + return NULL; + } + return nobj; +} + +JS_PUBLIC_API(JSBool) +JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds) +{ + JSBool ok; + jsval value; + uintN attrs; + + CHECK_REQUEST(cx); + for (ok = JS_TRUE; cds->name; cds++) { + ok = js_NewNumberInRootedValue(cx, cds->dval, &value); + if (!ok) + break; + attrs = cds->flags; + if (!attrs) + attrs = JSPROP_READONLY | JSPROP_PERMANENT; + ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0); + if (!ok) + break; + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps) +{ + JSBool ok; + + CHECK_REQUEST(cx); + for (ok = JS_TRUE; ps->name; ps++) { + ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID, + ps->getter, ps->setter, ps->flags, + SPROP_HAS_SHORTID, ps->tinyid); + if (!ok) + break; + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs) +{ + CHECK_REQUEST(cx); + return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0); +} + +JS_PUBLIC_API(JSBool) +JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs) +{ + CHECK_REQUEST(cx); + return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0); +} + +JS_PUBLIC_API(JSBool) +JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, + int8 tinyid, jsval value, + JSPropertyOp getter, JSPropertyOp setter, + uintN attrs) +{ + CHECK_REQUEST(cx); + return DefineProperty(cx, obj, name, value, getter, setter, attrs, + SPROP_HAS_SHORTID, tinyid); +} + +static JSBool +LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp, JSProperty **propp) +{ + JSAutoResolveFlags rf(cx, flags); + return OBJ_LOOKUP_PROPERTY(cx, obj, id, objp, propp); +} + +static JSBool +LookupProperty(JSContext *cx, JSObject *obj, const char *name, uintN flags, + JSObject **objp, JSProperty **propp) +{ + JSAtom *atom; + + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + return LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), flags, objp, propp); +} + +static JSBool +LookupUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, uintN flags, + JSObject **objp, JSProperty **propp) +{ + JSAtom *atom; + + atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + if (!atom) + return JS_FALSE; + return LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), flags, objp, propp); +} + +JS_PUBLIC_API(JSBool) +JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, + const char *alias) +{ + JSObject *obj2; + JSProperty *prop; + JSAtom *atom; + JSBool ok; + JSScopeProperty *sprop; + + CHECK_REQUEST(cx); + if (!LookupProperty(cx, obj, name, JSRESOLVE_QUALIFIED, &obj2, &prop)) + return JS_FALSE; + if (!prop) { + js_ReportIsNotDefined(cx, name); + return JS_FALSE; + } + if (obj2 != obj || !OBJ_IS_NATIVE(obj)) { + OBJ_DROP_PROPERTY(cx, obj2, prop); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS, + alias, name, OBJ_GET_CLASS(cx, obj2)->name); + return JS_FALSE; + } + atom = js_Atomize(cx, alias, strlen(alias), 0); + if (!atom) { + ok = JS_FALSE; + } else { + sprop = (JSScopeProperty *)prop; + ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom), + sprop->getter, sprop->setter, sprop->slot, + sprop->attrs, sprop->flags | SPROP_IS_ALIAS, + sprop->shortid) + != NULL); + } + OBJ_DROP_PROPERTY(cx, obj, prop); + return ok; +} + +static jsval +LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop) +{ + JSScopeProperty *sprop; + jsval rval; + + if (!prop) { + /* XXX bad API: no way to tell "not defined" from "void value" */ + return JSVAL_VOID; + } + if (OBJ_IS_NATIVE(obj2)) { + /* Peek at the native property's slot value, without doing a Get. */ + sprop = (JSScopeProperty *)prop; + rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2)) + ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot) + : JSVAL_TRUE; + } else { + /* XXX bad API: no way to return "defined but value unknown" */ + rval = JSVAL_TRUE; + } + OBJ_DROP_PROPERTY(cx, obj2, prop); + return rval; +} + +static JSBool +GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, JSPropertyOp *setterp) +{ + JSObject *obj2; + JSProperty *prop; + JSBool ok; + + if (!atom) + return JS_FALSE; + if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, + &obj2, &prop)) { + return JS_FALSE; + } + + if (!prop || obj != obj2) { + *attrsp = 0; + *foundp = JS_FALSE; + if (getterp) + *getterp = NULL; + if (setterp) + *setterp = NULL; + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + return JS_TRUE; + } + + *foundp = JS_TRUE; + ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, attrsp); + if (ok && OBJ_IS_NATIVE(obj)) { + JSScopeProperty *sprop = (JSScopeProperty *) prop; + + if (getterp) + *getterp = sprop->getter; + if (setterp) + *setterp = sprop->setter; + } + OBJ_DROP_PROPERTY(cx, obj, prop); + return ok; +} + +static JSBool +SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom, + uintN attrs, JSBool *foundp) +{ + JSObject *obj2; + JSProperty *prop; + JSBool ok; + + if (!atom) + return JS_FALSE; + if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, + &obj2, &prop)) { + return JS_FALSE; + } + if (!prop || obj != obj2) { + *foundp = JS_FALSE; + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + return JS_TRUE; + } + + *foundp = JS_TRUE; + ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs); + OBJ_DROP_PROPERTY(cx, obj, prop); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name, + uintN *attrsp, JSBool *foundp) +{ + CHECK_REQUEST(cx); + return GetPropertyAttributes(cx, obj, + js_Atomize(cx, name, strlen(name), 0), + attrsp, foundp, NULL, NULL); +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, + const char *name, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, + JSPropertyOp *setterp) +{ + CHECK_REQUEST(cx); + return GetPropertyAttributes(cx, obj, + js_Atomize(cx, name, strlen(name), 0), + attrsp, foundp, getterp, setterp); +} + +JS_PUBLIC_API(JSBool) +JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name, + uintN attrs, JSBool *foundp) +{ + CHECK_REQUEST(cx); + return SetPropertyAttributes(cx, obj, + js_Atomize(cx, name, strlen(name), 0), + attrs, foundp); +} + +static JSBool +AlreadyHasOwnPropertyHelper(JSContext *cx, JSObject *obj, jsid id, + JSBool *foundp) +{ + JSScope *scope; + + if (!OBJ_IS_NATIVE(obj)) { + JSObject *obj2; + JSProperty *prop; + + if (!LookupPropertyById(cx, obj, id, + JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING, + &obj2, &prop)) { + return JS_FALSE; + } + *foundp = (obj == obj2); + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + return JS_TRUE; + } + + JS_LOCK_OBJ(cx, obj); + scope = OBJ_SCOPE(obj); + *foundp = (scope->object == obj && SCOPE_GET_PROPERTY(scope, id)); + JS_UNLOCK_SCOPE(cx, scope); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, + JSBool *foundp) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + return AlreadyHasOwnPropertyHelper(cx, obj, ATOM_TO_JSID(atom), foundp); +} + +JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, + JSBool *foundp) +{ + CHECK_REQUEST(cx); + return AlreadyHasOwnPropertyHelper(cx, obj, id, foundp); +} + +JS_PUBLIC_API(JSBool) +JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp) +{ + JSBool ok; + JSObject *obj2; + JSProperty *prop; + + CHECK_REQUEST(cx); + ok = LookupProperty(cx, obj, name, + JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING, + &obj2, &prop); + if (ok) { + *foundp = (prop != NULL); + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp) +{ + JSBool ok; + JSObject *obj2; + JSProperty *prop; + + CHECK_REQUEST(cx); + ok = LookupPropertyById(cx, obj, id, + JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING, + &obj2, &prop); + if (ok) { + *foundp = (prop != NULL); + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp) +{ + JSBool ok; + JSObject *obj2; + JSProperty *prop; + + CHECK_REQUEST(cx); + ok = LookupProperty(cx, obj, name, JSRESOLVE_QUALIFIED, &obj2, &prop); + if (ok) + *vp = LookupResult(cx, obj, obj2, prop); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + JSBool ok; + JSObject *obj2; + JSProperty *prop; + + CHECK_REQUEST(cx); + ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop); + if (ok) + *vp = LookupResult(cx, obj, obj2, prop); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, + uintN flags, jsval *vp) +{ + JSAtom *atom; + JSObject *obj2; + + atom = js_Atomize(cx, name, strlen(name), 0); + return atom && + JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, + &obj2, vp); +} + +JS_PUBLIC_API(JSBool) +JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, + uintN flags, JSObject **objp, jsval *vp) +{ + JSBool ok; + JSProperty *prop; + + CHECK_REQUEST(cx); + ok = OBJ_IS_NATIVE(obj) + ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0 + : OBJ_LOOKUP_PROPERTY(cx, obj, id, objp, &prop); + if (ok) + *vp = LookupResult(cx, obj, *objp, prop); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp); +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + CHECK_REQUEST(cx); + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + return OBJ_GET_PROPERTY(cx, obj, id, vp); +} + +JS_PUBLIC_API(JSBool) +JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + jsval *vp) +{ + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + + CHECK_REQUEST(cx); +#if JS_HAS_XML_SUPPORT + if (OBJECT_IS_XML(cx, obj)) { + JSXMLObjectOps *ops; + + ops = (JSXMLObjectOps *) obj->map->ops; + obj = ops->getMethod(cx, obj, id, vp); + if (!obj) + return JS_FALSE; + } else +#endif + { + if (!OBJ_GET_PROPERTY(cx, obj, id, vp)) + return JS_FALSE; + } + + *objp = obj; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, + jsval *vp) +{ + JSAtom *atom; + + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + return JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp); +} + +JS_PUBLIC_API(JSBool) +JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); + return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp); +} + +JS_PUBLIC_API(JSBool) +JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + CHECK_REQUEST(cx); + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); + return OBJ_SET_PROPERTY(cx, obj, id, vp); +} + +JS_PUBLIC_API(JSBool) +JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name) +{ + jsval junk; + + return JS_DeleteProperty2(cx, obj, name, &junk); +} + +JS_PUBLIC_API(JSBool) +JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, + jsval *rval) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval); +} + +JS_PUBLIC_API(JSBool) +JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id) +{ + jsval junk; + + return JS_DeletePropertyById2(cx, obj, id, &junk); +} + +JS_PUBLIC_API(JSBool) +JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval) +{ + CHECK_REQUEST(cx); + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + return OBJ_DELETE_PROPERTY(cx, obj, id, rval); +} + +JS_PUBLIC_API(JSBool) +JS_DefineUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, jsval value, + JSPropertyOp getter, JSPropertyOp setter, + uintN attrs) +{ + CHECK_REQUEST(cx); + return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, + attrs, 0, 0); +} + +JS_PUBLIC_API(JSBool) +JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + uintN *attrsp, JSBool *foundp) +{ + CHECK_REQUEST(cx); + return GetPropertyAttributes(cx, obj, + js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0), + attrsp, foundp, NULL, NULL); +} + +JS_PUBLIC_API(JSBool) +JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, + JSPropertyOp *setterp) +{ + CHECK_REQUEST(cx); + return GetPropertyAttributes(cx, obj, + js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0), + attrsp, foundp, getterp, setterp); +} + +JS_PUBLIC_API(JSBool) +JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + uintN attrs, JSBool *foundp) +{ + CHECK_REQUEST(cx); + return SetPropertyAttributes(cx, obj, + js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0), + attrs, foundp); +} + +JS_PUBLIC_API(JSBool) +JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + int8 tinyid, jsval value, + JSPropertyOp getter, JSPropertyOp setter, + uintN attrs) +{ + CHECK_REQUEST(cx); + return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, + attrs, SPROP_HAS_SHORTID, tinyid); +} + +JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + JSBool *foundp) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + if (!atom) + return JS_FALSE; + return AlreadyHasOwnPropertyHelper(cx, obj, ATOM_TO_JSID(atom), foundp); +} + +JS_PUBLIC_API(JSBool) +JS_HasUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + JSBool *vp) +{ + JSBool ok; + JSObject *obj2; + JSProperty *prop; + + CHECK_REQUEST(cx); + ok = LookupUCProperty(cx, obj, name, namelen, + JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING, + &obj2, &prop); + if (ok) { + *vp = (prop != NULL); + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_LookupUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *vp) +{ + JSBool ok; + JSObject *obj2; + JSProperty *prop; + + CHECK_REQUEST(cx); + ok = LookupUCProperty(cx, obj, name, namelen, JSRESOLVE_QUALIFIED, + &obj2, &prop); + if (ok) + *vp = LookupResult(cx, obj, obj2, prop); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_GetUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *vp) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + if (!atom) + return JS_FALSE; + + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp); +} + +JS_PUBLIC_API(JSBool) +JS_SetUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *vp) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + if (!atom) + return JS_FALSE; + + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); + return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp); +} + +JS_PUBLIC_API(JSBool) +JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *rval) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + if (!atom) + return JS_FALSE; + + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval); +} + +JS_PUBLIC_API(JSObject *) +JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector) +{ + CHECK_REQUEST(cx); + /* NB: jsuint cast does ToUint32. */ + return js_NewArrayObject(cx, (jsuint)length, vector); +} + +JS_PUBLIC_API(JSBool) +JS_IsArrayObject(JSContext *cx, JSObject *obj) +{ + return OBJ_IS_ARRAY(cx, obj); +} + +JS_PUBLIC_API(JSBool) +JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp) +{ + CHECK_REQUEST(cx); + return js_GetLengthProperty(cx, obj, lengthp); +} + +JS_PUBLIC_API(JSBool) +JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length) +{ + CHECK_REQUEST(cx); + return js_SetLengthProperty(cx, obj, length); +} + +JS_PUBLIC_API(JSBool) +JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp) +{ + CHECK_REQUEST(cx); + return js_HasLengthProperty(cx, obj, lengthp); +} + +JS_PUBLIC_API(JSBool) +JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs) +{ + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); + + CHECK_REQUEST(cx); + return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(index), value, + getter, setter, attrs, NULL); +} + +JS_PUBLIC_API(JSBool) +JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias) +{ + JSObject *obj2; + JSProperty *prop; + JSScopeProperty *sprop; + JSBool ok; + + CHECK_REQUEST(cx); + if (!LookupProperty(cx, obj, name, JSRESOLVE_QUALIFIED, &obj2, &prop)) + return JS_FALSE; + if (!prop) { + js_ReportIsNotDefined(cx, name); + return JS_FALSE; + } + if (obj2 != obj || !OBJ_IS_NATIVE(obj)) { + char numBuf[12]; + OBJ_DROP_PROPERTY(cx, obj2, prop); + JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS, + numBuf, name, OBJ_GET_CLASS(cx, obj2)->name); + return JS_FALSE; + } + sprop = (JSScopeProperty *)prop; + ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias), + sprop->getter, sprop->setter, sprop->slot, + sprop->attrs, sprop->flags | SPROP_IS_ALIAS, + sprop->shortid) + != NULL); + OBJ_DROP_PROPERTY(cx, obj, prop); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, + JSBool *foundp) +{ + return AlreadyHasOwnPropertyHelper(cx, obj, INT_TO_JSID(index), foundp); +} + +JS_PUBLIC_API(JSBool) +JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp) +{ + JSBool ok; + JSObject *obj2; + JSProperty *prop; + + CHECK_REQUEST(cx); + ok = LookupPropertyById(cx, obj, INT_TO_JSID(index), + JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING, + &obj2, &prop); + if (ok) { + *foundp = (prop != NULL); + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp) +{ + JSBool ok; + JSObject *obj2; + JSProperty *prop; + + CHECK_REQUEST(cx); + ok = LookupPropertyById(cx, obj, INT_TO_JSID(index), JSRESOLVE_QUALIFIED, + &obj2, &prop); + if (ok) + *vp = LookupResult(cx, obj, obj2, prop); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp) +{ + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + + CHECK_REQUEST(cx); + return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(index), vp); +} + +JS_PUBLIC_API(JSBool) +JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp) +{ + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); + + CHECK_REQUEST(cx); + return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(index), vp); +} + +JS_PUBLIC_API(JSBool) +JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index) +{ + jsval junk; + + return JS_DeleteElement2(cx, obj, index, &junk); +} + +JS_PUBLIC_API(JSBool) +JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval) +{ + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + + CHECK_REQUEST(cx); + return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSID(index), rval); +} + +JS_PUBLIC_API(void) +JS_ClearScope(JSContext *cx, JSObject *obj) +{ + CHECK_REQUEST(cx); + + if (obj->map->ops->clear) + obj->map->ops->clear(cx, obj); + + /* Clear cached class objects on the global object. */ + if (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) { + int key; + + for (key = JSProto_Null; key < JSProto_LIMIT; key++) + JS_SetReservedSlot(cx, obj, key, JSVAL_VOID); + } +} + +JS_PUBLIC_API(JSIdArray *) +JS_Enumerate(JSContext *cx, JSObject *obj) +{ + jsint i, n; + jsval iter_state, num_properties; + jsid id; + JSIdArray *ida; + jsval *vector; + + CHECK_REQUEST(cx); + + ida = NULL; + iter_state = JSVAL_NULL; + + /* Get the number of properties to enumerate. */ + if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties)) + goto error; + if (!JSVAL_IS_INT(num_properties)) { + JS_ASSERT(0); + goto error; + } + + /* Grow as needed if we don't know the exact amount ahead of time. */ + n = JSVAL_TO_INT(num_properties); + if (n <= 0) + n = 8; + + /* Create an array of jsids large enough to hold all the properties */ + ida = NewIdArray(cx, n); + if (!ida) + goto error; + + i = 0; + vector = &ida->vector[0]; + for (;;) { + if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id)) + goto error; + + /* No more jsid's to enumerate ? */ + if (iter_state == JSVAL_NULL) + break; + + if (i == ida->length) { + ida = SetIdArrayLength(cx, ida, ida->length * 2); + if (!ida) + goto error; + vector = &ida->vector[0]; + } + vector[i++] = id; + } + return SetIdArrayLength(cx, ida, i); + +error: + if (iter_state != JSVAL_NULL) + OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0); + if (ida) + JS_DestroyIdArray(cx, ida); + return NULL; +} + +/* + * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's + * prop_iterator_class somehow... + * + preserve the OBJ_ENUMERATE API while optimizing the native object case + * + native case here uses a JSScopeProperty *, but that iterates in reverse! + * + so we make non-native match, by reverse-iterating after JS_Enumerating + */ +#define JSSLOT_ITER_INDEX (JSSLOT_PRIVATE + 1) + +#if JSSLOT_ITER_INDEX >= JS_INITIAL_NSLOTS +# error "JSSLOT_ITER_INDEX botch!" +#endif + +static void +prop_iter_finalize(JSContext *cx, JSObject *obj) +{ + jsval v; + jsint i; + JSIdArray *ida; + + v = obj->fslots[JSSLOT_ITER_INDEX]; + if (JSVAL_IS_VOID(v)) + return; + + i = JSVAL_TO_INT(v); + if (i >= 0) { + /* Non-native case: destroy the ida enumerated when obj was created. */ + ida = (JSIdArray *) JS_GetPrivate(cx, obj); + if (ida) + JS_DestroyIdArray(cx, ida); + } +} + +static void +prop_iter_trace(JSTracer *trc, JSObject *obj) +{ + jsval v; + jsint i, n; + JSScopeProperty *sprop; + JSIdArray *ida; + jsid id; + + v = obj->fslots[JSSLOT_PRIVATE]; + JS_ASSERT(!JSVAL_IS_VOID(v)); + + i = JSVAL_TO_INT(obj->fslots[JSSLOT_ITER_INDEX]); + if (i < 0) { + /* Native case: just mark the next property to visit. */ + sprop = (JSScopeProperty *) JSVAL_TO_PRIVATE(v); + if (sprop) + TRACE_SCOPE_PROPERTY(trc, sprop); + } else { + /* Non-native case: mark each id in the JSIdArray private. */ + ida = (JSIdArray *) JSVAL_TO_PRIVATE(v); + for (i = 0, n = ida->length; i < n; i++) { + id = ida->vector[i]; + TRACE_ID(trc, id); + } + } +} + +static JSClass prop_iter_class = { + "PropertyIterator", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | + JSCLASS_MARK_IS_TRACE, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iter_finalize, + NULL, NULL, NULL, NULL, + NULL, NULL, JS_CLASS_TRACE(prop_iter_trace), NULL +}; + +JS_PUBLIC_API(JSObject *) +JS_NewPropertyIterator(JSContext *cx, JSObject *obj) +{ + JSObject *iterobj; + JSScope *scope; + void *pdata; + jsint index; + JSIdArray *ida; + + CHECK_REQUEST(cx); + iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj, 0); + if (!iterobj) + return NULL; + + if (OBJ_IS_NATIVE(obj)) { + /* Native case: start with the last property in obj's own scope. */ + scope = OBJ_SCOPE(obj); + pdata = (scope->object == obj) ? scope->lastProp : NULL; + index = -1; + } else { + JSTempValueRooter tvr; + + /* + * Non-native case: enumerate a JSIdArray and keep it via private. + * + * Note: we have to make sure that we root obj around the call to + * JS_Enumerate to protect against multiple allocations under it. + */ + JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(iterobj), &tvr); + ida = JS_Enumerate(cx, obj); + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ida) + goto bad; + pdata = ida; + index = ida->length; + } + + /* iterobj can not escape to other threads here. */ + STOBJ_SET_SLOT(iterobj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(pdata)); + STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(index)); + return iterobj; + +bad: + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + return NULL; +} + +JS_PUBLIC_API(JSBool) +JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp) +{ + jsint i; + JSObject *obj; + JSScope *scope; + JSScopeProperty *sprop; + JSIdArray *ida; + + CHECK_REQUEST(cx); + i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX)); + if (i < 0) { + /* Native case: private data is a property tree node pointer. */ + obj = OBJ_GET_PARENT(cx, iterobj); + JS_ASSERT(OBJ_IS_NATIVE(obj)); + scope = OBJ_SCOPE(obj); + JS_ASSERT(scope->object == obj); + sprop = (JSScopeProperty *) JS_GetPrivate(cx, iterobj); + + /* + * If the next property mapped by scope in the property tree ancestor + * line is not enumerable, or it's an alias, or one or more properties + * were deleted from the "middle" of the scope-mapped ancestor line + * and the next property was among those deleted, skip it and keep on + * trying to find an enumerable property that is still in scope. + */ + while (sprop && + (!(sprop->attrs & JSPROP_ENUMERATE) || + (sprop->flags & SPROP_IS_ALIAS) || + (SCOPE_HAD_MIDDLE_DELETE(scope) && + !SCOPE_HAS_PROPERTY(scope, sprop)))) { + sprop = sprop->parent; + } + + if (!sprop) { + *idp = JSVAL_VOID; + } else { + if (!JS_SetPrivate(cx, iterobj, sprop->parent)) + return JS_FALSE; + *idp = sprop->id; + } + } else { + /* Non-native case: use the ida enumerated when iterobj was created. */ + ida = (JSIdArray *) JS_GetPrivate(cx, iterobj); + JS_ASSERT(i <= ida->length); + if (i == 0) { + *idp = JSVAL_VOID; + } else { + *idp = ida->vector[--i]; + STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i)); + } + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + jsval *vp, uintN *attrsp) +{ + CHECK_REQUEST(cx); + return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp); +} + +static JSBool +ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp, + uint32 index, uint32 limit) +{ + /* Check the computed, possibly per-instance, upper bound. */ + if (clasp->reserveSlots) + JS_LOCK_OBJ_VOID(cx, obj, limit += clasp->reserveSlots(cx, obj)); + if (index >= limit) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_RESERVED_SLOT_RANGE); + return JS_FALSE; + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp) +{ + JSClass *clasp; + uint32 limit, slot; + + CHECK_REQUEST(cx); + clasp = OBJ_GET_CLASS(cx, obj); + limit = JSCLASS_RESERVED_SLOTS(clasp); + if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit)) + return JS_FALSE; + slot = JSSLOT_START(clasp) + index; + *vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v) +{ + JSClass *clasp; + uint32 limit, slot; + + CHECK_REQUEST(cx); + clasp = OBJ_GET_CLASS(cx, obj); + limit = JSCLASS_RESERVED_SLOTS(clasp); + if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit)) + return JS_FALSE; + slot = JSSLOT_START(clasp) + index; + return OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v); +} + +#ifdef JS_THREADSAFE +JS_PUBLIC_API(jsrefcount) +JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals) +{ + return JS_ATOMIC_INCREMENT(&principals->refcount); +} + +JS_PUBLIC_API(jsrefcount) +JS_DropPrincipals(JSContext *cx, JSPrincipals *principals) +{ + jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount); + if (rc == 0) + principals->destroy(cx, principals); + return rc; +} +#endif + +JS_PUBLIC_API(JSSecurityCallbacks *) +JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks) +{ + JSSecurityCallbacks *oldcallbacks; + + oldcallbacks = rt->securityCallbacks; + rt->securityCallbacks = callbacks; + return oldcallbacks; +} + +JS_PUBLIC_API(JSSecurityCallbacks *) +JS_GetRuntimeSecurityCallbacks(JSRuntime *rt) +{ + return rt->securityCallbacks; +} + +JS_PUBLIC_API(JSSecurityCallbacks *) +JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks) +{ + JSSecurityCallbacks *oldcallbacks; + + oldcallbacks = cx->securityCallbacks; + cx->securityCallbacks = callbacks; + return oldcallbacks; +} + +JS_PUBLIC_API(JSSecurityCallbacks *) +JS_GetSecurityCallbacks(JSContext *cx) +{ + return cx->securityCallbacks + ? cx->securityCallbacks + : cx->runtime->securityCallbacks; +} + +JS_PUBLIC_API(JSFunction *) +JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags, + JSObject *parent, const char *name) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + + if (!name) { + atom = NULL; + } else { + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return NULL; + } + return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom); +} + +JS_PUBLIC_API(JSObject *) +JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent) +{ + CHECK_REQUEST(cx); + if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) { + /* Indicate we cannot clone this object. */ + return funobj; + } + return js_CloneFunctionObject(cx, GET_FUNCTION_PRIVATE(cx, funobj), parent); +} + +JS_PUBLIC_API(JSObject *) +JS_GetFunctionObject(JSFunction *fun) +{ + return FUN_OBJECT(fun); +} + +JS_PUBLIC_API(const char *) +JS_GetFunctionName(JSFunction *fun) +{ + return fun->atom + ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom)) + : js_anonymous_str; +} + +JS_PUBLIC_API(JSString *) +JS_GetFunctionId(JSFunction *fun) +{ + return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL; +} + +JS_PUBLIC_API(uintN) +JS_GetFunctionFlags(JSFunction *fun) +{ +#ifdef MOZILLA_1_8_BRANCH + uintN flags = fun->flags; + + return JSFUN_DISJOINT_FLAGS(flags) | + (JSFUN_GETTER_TEST(flags) ? JSFUN_GETTER : 0) | + (JSFUN_SETTER_TEST(flags) ? JSFUN_SETTER : 0) | + (JSFUN_BOUND_METHOD_TEST(flags) ? JSFUN_BOUND_METHOD : 0) | + (JSFUN_HEAVYWEIGHT_TEST(flags) ? JSFUN_HEAVYWEIGHT : 0); +#else + return fun->flags; +#endif +} + +JS_PUBLIC_API(uint16) +JS_GetFunctionArity(JSFunction *fun) +{ + return fun->nargs; +} + +JS_PUBLIC_API(JSBool) +JS_ObjectIsFunction(JSContext *cx, JSObject *obj) +{ + return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass; +} + +JS_BEGIN_EXTERN_C +static JSBool +js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, jsval *vp) +{ + jsval fsv; + JSFunctionSpec *fs; + JSObject *tmp; + JSFastNative native; + + if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(*vp), 0, &fsv)) + return JS_FALSE; + fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv); + JS_ASSERT((~fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == 0); + + /* + * We know that vp[2] is valid because JS_DefineFunctions, which is our + * only (indirect) referrer, defined us as requiring at least one argument + * (notice how it passes fs->nargs + 1 as the next-to-last argument to + * JS_DefineFunction). + */ + if (JSVAL_IS_PRIMITIVE(vp[2])) { + /* + * Make sure that this is an object or null, as required by the generic + * functions. + */ + if (!js_ValueToObject(cx, vp[2], &tmp)) + return JS_FALSE; + vp[2] = OBJECT_TO_JSVAL(tmp); + } + + /* + * Copy all actual (argc) arguments down over our |this| parameter, vp[1], + * which is almost always the class constructor object, e.g. Array. Then + * call the corresponding prototype native method with our first argument + * passed as |this|. + */ + memmove(vp + 1, vp + 2, argc * sizeof(jsval)); + + /* + * Follow Function.prototype.apply and .call by using the global object as + * the 'this' param if no args. + */ + if (!js_ComputeThis(cx, JS_FALSE, vp + 2)) + return JS_FALSE; + /* + * Protect against argc underflowing. By calling js_ComputeThis, we made + * it as if the static was called with one parameter, the explicit |this| + * object. + */ + if (argc != 0) + --argc; + + native = +#ifdef JS_TRACER + (fs->flags & JSFUN_TRACEABLE) + ? ((JSTraceableNative *) fs->call)->native + : +#endif + (JSFastNative) fs->call; + return native(cx, argc, vp); +} + +static JSBool +js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + jsval fsv; + JSFunctionSpec *fs; + JSObject *tmp; + + if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv)) + return JS_FALSE; + fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv); + JS_ASSERT((fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == + JSFUN_GENERIC_NATIVE); + + /* + * We know that argv[0] is valid because JS_DefineFunctions, which is our + * only (indirect) referrer, defined us as requiring at least one argument + * (notice how it passes fs->nargs + 1 as the next-to-last argument to + * JS_DefineFunction). + */ + if (JSVAL_IS_PRIMITIVE(argv[0])) { + /* + * Make sure that this is an object or null, as required by the generic + * functions. + */ + if (!js_ValueToObject(cx, argv[0], &tmp)) + return JS_FALSE; + argv[0] = OBJECT_TO_JSVAL(tmp); + } + + /* + * Copy all actual (argc) arguments down over our |this| parameter, + * argv[-1], which is almost always the class constructor object, e.g. + * Array. Then call the corresponding prototype native method with our + * first argument passed as |this|. + */ + memmove(argv - 1, argv, argc * sizeof(jsval)); + + /* + * Follow Function.prototype.apply and .call by using the global object as + * the 'this' param if no args. + */ + JS_ASSERT(cx->fp->argv == argv); + if (!js_ComputeThis(cx, JS_TRUE, argv)) + return JS_FALSE; + cx->fp->thisp = JSVAL_TO_OBJECT(argv[-1]); + + /* + * Protect against argc underflowing. By calling js_ComputeThis, we made + * it as if the static was called with one parameter, the explicit |this| + * object. + */ + if (argc != 0) + --argc; + + return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc, argv, rval); +} +JS_END_EXTERN_C + +JS_PUBLIC_API(JSBool) +JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) +{ + uintN flags; + JSObject *ctor; + JSFunction *fun; + + CHECK_REQUEST(cx); + ctor = NULL; + for (; fs->name; fs++) { + flags = fs->flags; + + /* + * Define a generic arity N+1 static method for the arity N prototype + * method if flags contains JSFUN_GENERIC_NATIVE. + */ + if (flags & JSFUN_GENERIC_NATIVE) { + if (!ctor) { + ctor = JS_GetConstructor(cx, obj); + if (!ctor) + return JS_FALSE; + } + + flags &= ~JSFUN_GENERIC_NATIVE; + fun = JS_DefineFunction(cx, ctor, fs->name, + (flags & JSFUN_FAST_NATIVE) + ? (JSNative) + js_generic_fast_native_method_dispatcher + : js_generic_native_method_dispatcher, + fs->nargs + 1, + flags & ~JSFUN_TRACEABLE); + if (!fun) + return JS_FALSE; + fun->u.n.extra = (uint16)fs->extra; + + /* + * As jsapi.h notes, fs must point to storage that lives as long + * as fun->object lives. + */ + if (!JS_SetReservedSlot(cx, FUN_OBJECT(fun), 0, PRIVATE_TO_JSVAL(fs))) + return JS_FALSE; + } + + JS_ASSERT(!(flags & JSFUN_FAST_NATIVE) || + (uint16)(fs->extra >> 16) <= fs->nargs); + fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags); + if (!fun) + return JS_FALSE; + fun->u.n.extra = (uint16)fs->extra; + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSFunction *) +JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call, + uintN nargs, uintN attrs) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return NULL; + return js_DefineFunction(cx, obj, atom, call, nargs, attrs); +} + +JS_PUBLIC_API(JSFunction *) +JS_DefineUCFunction(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, JSNative call, + uintN nargs, uintN attrs) +{ + JSAtom *atom; + + atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + if (!atom) + return NULL; + return js_DefineFunction(cx, obj, atom, call, nargs, attrs); +} + +JS_PUBLIC_API(JSScript *) +JS_CompileScript(JSContext *cx, JSObject *obj, + const char *bytes, size_t length, + const char *filename, uintN lineno) +{ + jschar *chars; + JSScript *script; + + CHECK_REQUEST(cx); + chars = js_InflateString(cx, bytes, &length); + if (!chars) + return NULL; + script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno); + JS_free(cx, chars); + return script; +} + +JS_PUBLIC_API(JSScript *) +JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const char *bytes, size_t length, + const char *filename, uintN lineno) +{ + jschar *chars; + JSScript *script; + + CHECK_REQUEST(cx); + chars = js_InflateString(cx, bytes, &length); + if (!chars) + return NULL; + script = JS_CompileUCScriptForPrincipals(cx, obj, principals, + chars, length, filename, lineno); + JS_free(cx, chars); + return script; +} + +JS_PUBLIC_API(JSScript *) +JS_CompileUCScript(JSContext *cx, JSObject *obj, + const jschar *chars, size_t length, + const char *filename, uintN lineno) +{ + CHECK_REQUEST(cx); + return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length, + filename, lineno); +} + +#define LAST_FRAME_EXCEPTION_CHECK(cx,result) \ + JS_BEGIN_MACRO \ + if (!(result) && !((cx)->options & JSOPTION_DONT_REPORT_UNCAUGHT)) \ + js_ReportUncaughtException(cx); \ + JS_END_MACRO + +#define LAST_FRAME_CHECKS(cx,result) \ + JS_BEGIN_MACRO \ + if (!(cx)->fp) { \ + (cx)->weakRoots.lastInternalResult = JSVAL_NULL; \ + LAST_FRAME_EXCEPTION_CHECK(cx, result); \ + } \ + JS_END_MACRO + +#define JS_OPTIONS_TO_TCFLAGS(cx) \ + ((((cx)->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) | \ + (((cx)->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0)) + +JS_PUBLIC_API(JSScript *) +JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, size_t length, + const char *filename, uintN lineno) +{ + uint32 tcflags; + JSScript *script; + + CHECK_REQUEST(cx); + tcflags = JS_OPTIONS_TO_TCFLAGS(cx); + script = js_CompileScript(cx, obj, NULL, principals, tcflags, + chars, length, NULL, filename, lineno); + LAST_FRAME_CHECKS(cx, script); + return script; +} + +JS_PUBLIC_API(JSBool) +JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, + const char *bytes, size_t length) +{ + jschar *chars; + JSBool result; + JSExceptionState *exnState; + JSParseContext pc; + JSErrorReporter older; + + CHECK_REQUEST(cx); + chars = js_InflateString(cx, bytes, &length); + if (!chars) + return JS_TRUE; + + /* + * Return true on any out-of-memory error, so our caller doesn't try to + * collect more buffered source. + */ + result = JS_TRUE; + exnState = JS_SaveExceptionState(cx); + if (js_InitParseContext(cx, &pc, NULL, NULL, chars, length, NULL, NULL, + 1)) { + older = JS_SetErrorReporter(cx, NULL); + if (!js_ParseScript(cx, obj, &pc) && + (pc.tokenStream.flags & TSF_UNEXPECTED_EOF)) { + /* + * We ran into an error. If it was because we ran out of source, + * we return false, so our caller will know to try to collect more + * buffered source. + */ + result = JS_FALSE; + } + JS_SetErrorReporter(cx, older); + js_FinishParseContext(cx, &pc); + } + JS_free(cx, chars); + JS_RestoreExceptionState(cx, exnState); + return result; +} + +JS_PUBLIC_API(JSScript *) +JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename) +{ + FILE *fp; + uint32 tcflags; + JSScript *script; + + CHECK_REQUEST(cx); + if (!filename || strcmp(filename, "-") == 0) { + fp = stdin; + } else { + fp = fopen(filename, "r"); + if (!fp) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN, + filename, "No such file or directory"); + return NULL; + } + } + + tcflags = JS_OPTIONS_TO_TCFLAGS(cx); + script = js_CompileScript(cx, obj, NULL, NULL, tcflags, + NULL, 0, fp, filename, 1); + if (fp != stdin) + fclose(fp); + LAST_FRAME_CHECKS(cx, script); + return script; +} + +JS_PUBLIC_API(JSScript *) +JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, + FILE *file) +{ + return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL); +} + +JS_PUBLIC_API(JSScript *) +JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, + const char *filename, FILE *file, + JSPrincipals *principals) +{ + uint32 tcflags; + JSScript *script; + + CHECK_REQUEST(cx); + tcflags = JS_OPTIONS_TO_TCFLAGS(cx); + script = js_CompileScript(cx, obj, NULL, principals, tcflags, + NULL, 0, file, filename, 1); + LAST_FRAME_CHECKS(cx, script); + return script; +} + +JS_PUBLIC_API(JSObject *) +JS_NewScriptObject(JSContext *cx, JSScript *script) +{ + JSTempValueRooter tvr; + JSObject *obj; + + CHECK_REQUEST(cx); + if (!script) + return js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0); + + JS_ASSERT(!script->u.object); + + JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); + obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0); + if (obj) { + JS_SetPrivate(cx, obj, script); + script->u.object = obj; +#ifdef CHECK_SCRIPT_OWNER + script->owner = NULL; +#endif + } + JS_POP_TEMP_ROOT(cx, &tvr); + return obj; +} + +JS_PUBLIC_API(JSObject *) +JS_GetScriptObject(JSScript *script) +{ + return script->u.object; +} + +JS_PUBLIC_API(void) +JS_DestroyScript(JSContext *cx, JSScript *script) +{ + CHECK_REQUEST(cx); + js_DestroyScript(cx, script); +} + +JS_PUBLIC_API(JSFunction *) +JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name, + uintN nargs, const char **argnames, + const char *bytes, size_t length, + const char *filename, uintN lineno) +{ + jschar *chars; + JSFunction *fun; + + CHECK_REQUEST(cx); + chars = js_InflateString(cx, bytes, &length); + if (!chars) + return NULL; + fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length, + filename, lineno); + JS_free(cx, chars); + return fun; +} + +JS_PUBLIC_API(JSFunction *) +JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const char *bytes, size_t length, + const char *filename, uintN lineno) +{ + jschar *chars; + JSFunction *fun; + + CHECK_REQUEST(cx); + chars = js_InflateString(cx, bytes, &length); + if (!chars) + return NULL; + fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name, + nargs, argnames, chars, length, + filename, lineno); + JS_free(cx, chars); + return fun; +} + +JS_PUBLIC_API(JSFunction *) +JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno) +{ + CHECK_REQUEST(cx); + return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name, + nargs, argnames, + chars, length, + filename, lineno); +} + +JS_PUBLIC_API(JSFunction *) +JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno) +{ + JSFunction *fun; + JSTempValueRooter tvr; + JSAtom *funAtom, *argAtom; + uintN i; + + CHECK_REQUEST(cx); + if (!name) { + funAtom = NULL; + } else { + funAtom = js_Atomize(cx, name, strlen(name), 0); + if (!funAtom) { + fun = NULL; + goto out2; + } + } + fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom); + if (!fun) + goto out2; + + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr); + for (i = 0; i < nargs; i++) { + argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); + if (!argAtom) { + fun = NULL; + goto out; + } + if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) { + fun = NULL; + goto out; + } + } + + if (!js_CompileFunctionBody(cx, fun, principals, chars, length, + filename, lineno)) { + fun = NULL; + goto out; + } + + if (obj && + funAtom && + !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom), + OBJECT_TO_JSVAL(FUN_OBJECT(fun)), + NULL, NULL, JSPROP_ENUMERATE, NULL)) { + fun = NULL; + } + +#ifdef JS_SCOPE_DEPTH_METER + if (fun && obj) { + JSObject *pobj = obj; + uintN depth = 1; + + while ((pobj = OBJ_GET_PARENT(cx, pobj)) != NULL) + ++depth; + JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); + } +#endif + + out: + cx->weakRoots.newborn[JSTRACE_OBJECT] = FUN_OBJECT(fun); + JS_POP_TEMP_ROOT(cx, &tvr); + + out2: + LAST_FRAME_CHECKS(cx, fun); + return fun; +} + +JS_PUBLIC_API(JSString *) +JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, + uintN indent) +{ + JSPrinter *jp; + JSString *str; + + CHECK_REQUEST(cx); + jp = JS_NEW_PRINTER(cx, name, NULL, + indent & ~JS_DONT_PRETTY_PRINT, + !(indent & JS_DONT_PRETTY_PRINT)); + if (!jp) + return NULL; + if (js_DecompileScript(jp, script)) + str = js_GetPrinterOutput(jp); + else + str = NULL; + js_DestroyPrinter(jp); + return str; +} + +JS_PUBLIC_API(JSString *) +JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent) +{ + JSPrinter *jp; + JSString *str; + + CHECK_REQUEST(cx); + jp = JS_NEW_PRINTER(cx, "JS_DecompileFunction", fun, + indent & ~JS_DONT_PRETTY_PRINT, + !(indent & JS_DONT_PRETTY_PRINT)); + if (!jp) + return NULL; + if (js_DecompileFunction(jp)) + str = js_GetPrinterOutput(jp); + else + str = NULL; + js_DestroyPrinter(jp); + return str; +} + +JS_PUBLIC_API(JSString *) +JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent) +{ + JSPrinter *jp; + JSString *str; + + CHECK_REQUEST(cx); + jp = JS_NEW_PRINTER(cx, "JS_DecompileFunctionBody", fun, + indent & ~JS_DONT_PRETTY_PRINT, + !(indent & JS_DONT_PRETTY_PRINT)); + if (!jp) + return NULL; + if (js_DecompileFunctionBody(jp)) + str = js_GetPrinterOutput(jp); + else + str = NULL; + js_DestroyPrinter(jp); + return str; +} + +JS_PUBLIC_API(JSBool) +JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval) +{ + JSBool ok; + + CHECK_REQUEST(cx); + ok = js_Execute(cx, obj, script, NULL, 0, rval); + LAST_FRAME_CHECKS(cx, ok); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script, + JSExecPart part, jsval *rval) +{ + JSScript tmp; + JSDebugHooks *hooks; + JSBool ok; + + /* Make a temporary copy of the JSScript structure and farble it a bit. */ + tmp = *script; + if (part == JSEXEC_PROLOG) { + tmp.length = PTRDIFF(tmp.main, tmp.code, jsbytecode); + } else { + tmp.length -= PTRDIFF(tmp.main, tmp.code, jsbytecode); + tmp.code = tmp.main; + } + + /* Tell the debugger about our temporary copy of the script structure. */ + hooks = cx->debugHooks; + if (hooks->newScriptHook) { + hooks->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL, + hooks->newScriptHookData); + } + + /* Execute the farbled struct and tell the debugger to forget about it. */ + ok = JS_ExecuteScript(cx, obj, &tmp, rval); + if (hooks->destroyScriptHook) + hooks->destroyScriptHook(cx, &tmp, hooks->destroyScriptHookData); + return ok; +} + +/* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */ +JS_PUBLIC_API(JSBool) +JS_EvaluateScript(JSContext *cx, JSObject *obj, + const char *bytes, uintN nbytes, + const char *filename, uintN lineno, + jsval *rval) +{ + size_t length = nbytes; + jschar *chars; + JSBool ok; + + CHECK_REQUEST(cx); + chars = js_InflateString(cx, bytes, &length); + if (!chars) + return JS_FALSE; + ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval); + JS_free(cx, chars); + return ok; +} + +/* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */ +JS_PUBLIC_API(JSBool) +JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const char *bytes, uintN nbytes, + const char *filename, uintN lineno, + jsval *rval) +{ + size_t length = nbytes; + jschar *chars; + JSBool ok; + + CHECK_REQUEST(cx); + chars = js_InflateString(cx, bytes, &length); + if (!chars) + return JS_FALSE; + ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length, + filename, lineno, rval); + JS_free(cx, chars); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_EvaluateUCScript(JSContext *cx, JSObject *obj, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval) +{ + CHECK_REQUEST(cx); + return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length, + filename, lineno, rval); +} + +JS_PUBLIC_API(JSBool) +JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval) +{ + JSScript *script; + JSBool ok; + + CHECK_REQUEST(cx); + script = js_CompileScript(cx, obj, NULL, principals, + !rval + ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL + : TCF_COMPILE_N_GO, + chars, length, NULL, filename, lineno); + if (!script) { + LAST_FRAME_CHECKS(cx, script); + return JS_FALSE; + } + ok = js_Execute(cx, obj, script, NULL, 0, rval); + LAST_FRAME_CHECKS(cx, ok); + JS_DestroyScript(cx, script); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, + jsval *argv, jsval *rval) +{ + JSBool ok; + + CHECK_REQUEST(cx); + ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(FUN_OBJECT(fun)), argc, argv, + rval); + LAST_FRAME_CHECKS(cx, ok); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, + jsval *argv, jsval *rval) +{ + JSBool ok; + jsval fval; + + CHECK_REQUEST(cx); +#if JS_HAS_XML_SUPPORT + if (OBJECT_IS_XML(cx, obj)) { + JSXMLObjectOps *ops; + JSAtom *atom; + + ops = (JSXMLObjectOps *) obj->map->ops; + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + obj = ops->getMethod(cx, obj, ATOM_TO_JSID(atom), &fval); + if (!obj) + return JS_FALSE; + } else +#endif + if (!JS_GetProperty(cx, obj, name, &fval)) + return JS_FALSE; + ok = js_InternalCall(cx, obj, fval, argc, argv, rval); + LAST_FRAME_CHECKS(cx, ok); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, + jsval *argv, jsval *rval) +{ + JSBool ok; + + CHECK_REQUEST(cx); + ok = js_InternalCall(cx, obj, fval, argc, argv, rval); + LAST_FRAME_CHECKS(cx, ok); + return ok; +} + +JS_PUBLIC_API(void) +JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback, + uint32 operationLimit) +{ + JS_ASSERT(callback); + JS_ASSERT(operationLimit <= JS_MAX_OPERATION_LIMIT); + JS_ASSERT(operationLimit > 0); + + cx->operationCount = (int32) operationLimit; + cx->operationLimit = operationLimit; + cx->operationCallbackIsSet = 1; + cx->operationCallback = callback; +} + +JS_PUBLIC_API(void) +JS_ClearOperationCallback(JSContext *cx) +{ + cx->operationCount = (int32) JS_MAX_OPERATION_LIMIT; + cx->operationLimit = JS_MAX_OPERATION_LIMIT; + cx->operationCallbackIsSet = 0; + cx->operationCallback = NULL; +} + +JS_PUBLIC_API(JSOperationCallback) +JS_GetOperationCallback(JSContext *cx) +{ + JS_ASSERT(cx->operationCallbackIsSet || !cx->operationCallback); + return cx->operationCallback; +} + +JS_PUBLIC_API(uint32) +JS_GetOperationLimit(JSContext *cx) +{ + JS_ASSERT(cx->operationCallbackIsSet); + return cx->operationLimit; +} + +JS_PUBLIC_API(void) +JS_SetOperationLimit(JSContext *cx, uint32 operationLimit) +{ + JS_ASSERT(operationLimit <= JS_MAX_OPERATION_LIMIT); + JS_ASSERT(operationLimit > 0); + JS_ASSERT(cx->operationCallbackIsSet); + + cx->operationLimit = operationLimit; + if (cx->operationCount > (int32) operationLimit) + cx->operationCount = (int32) operationLimit; +} + +JS_PUBLIC_API(JSBranchCallback) +JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb) +{ + JSBranchCallback oldcb; + + if (cx->operationCallbackIsSet) { +#ifdef DEBUG + fprintf(stderr, +"JS API usage error: call to JS_SetOperationCallback is followed by\n" +"invocation of deprecated JS_SetBranchCallback\n"); + JS_ASSERT(0); +#endif + cx->operationCallbackIsSet = 0; + oldcb = NULL; + } else { + oldcb = (JSBranchCallback) cx->operationCallback; + } + if (cb) { + cx->operationCount = JSOW_SCRIPT_JUMP; + cx->operationLimit = JSOW_SCRIPT_JUMP; + cx->operationCallback = (JSOperationCallback) cb; + } else { + JS_ClearOperationCallback(cx); + } + return oldcb; +} + +JS_PUBLIC_API(JSBool) +JS_IsRunning(JSContext *cx) +{ + return cx->fp != NULL; +} + +JS_PUBLIC_API(JSBool) +JS_IsConstructing(JSContext *cx) +{ + return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING); +} + +JS_FRIEND_API(JSBool) +JS_IsAssigning(JSContext *cx) +{ + JSStackFrame *fp; + + for (fp = cx->fp; fp && !fp->script; fp = fp->down) + continue; + if (!fp || !fp->regs) + return JS_FALSE; + return (js_CodeSpec[*fp->regs->pc].format & JOF_ASSIGNING) != 0; +} + +JS_PUBLIC_API(void) +JS_SetCallReturnValue2(JSContext *cx, jsval v) +{ +#if JS_HAS_LVALUE_RETURN + cx->rval2 = v; + cx->rval2set = JS_TRUE; +#endif +} + +JS_PUBLIC_API(JSStackFrame *) +JS_SaveFrameChain(JSContext *cx) +{ + JSStackFrame *fp; + + fp = cx->fp; + if (!fp) + return fp; + + JS_ASSERT(!fp->dormantNext); + fp->dormantNext = cx->dormantFrameChain; + cx->dormantFrameChain = fp; + cx->fp = NULL; + return fp; +} + +JS_PUBLIC_API(void) +JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp) +{ + JS_ASSERT(!cx->fp); + if (!fp) + return; + + JS_ASSERT(fp == cx->dormantFrameChain); + cx->fp = fp; + cx->dormantFrameChain = fp->dormantNext; + fp->dormantNext = NULL; +} + +/************************************************************************/ + +JS_PUBLIC_API(JSString *) +JS_NewString(JSContext *cx, char *bytes, size_t nbytes) +{ + size_t length = nbytes; + jschar *chars; + JSString *str; + + CHECK_REQUEST(cx); + + /* Make a UTF-16 vector from the 8-bit char codes in bytes. */ + chars = js_InflateString(cx, bytes, &length); + if (!chars) + return NULL; + + /* Free chars (but not bytes, which caller frees on error) if we fail. */ + str = js_NewString(cx, chars, length); + if (!str) { + JS_free(cx, chars); + return NULL; + } + + /* Hand off bytes to the deflated string cache, if possible. */ + if (!js_SetStringBytes(cx, str, bytes, nbytes)) + JS_free(cx, bytes); + return str; +} + +JS_PUBLIC_API(JSString *) +JS_NewStringCopyN(JSContext *cx, const char *s, size_t n) +{ + jschar *js; + JSString *str; + + CHECK_REQUEST(cx); + js = js_InflateString(cx, s, &n); + if (!js) + return NULL; + str = js_NewString(cx, js, n); + if (!str) + JS_free(cx, js); + return str; +} + +JS_PUBLIC_API(JSString *) +JS_NewStringCopyZ(JSContext *cx, const char *s) +{ + size_t n; + jschar *js; + JSString *str; + + CHECK_REQUEST(cx); + if (!s) + return cx->runtime->emptyString; + n = strlen(s); + js = js_InflateString(cx, s, &n); + if (!js) + return NULL; + str = js_NewString(cx, js, n); + if (!str) + JS_free(cx, js); + return str; +} + +JS_PUBLIC_API(JSString *) +JS_InternString(JSContext *cx, const char *s) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED); + if (!atom) + return NULL; + return ATOM_TO_STRING(atom); +} + +JS_PUBLIC_API(JSString *) +JS_NewUCString(JSContext *cx, jschar *chars, size_t length) +{ + CHECK_REQUEST(cx); + return js_NewString(cx, chars, length); +} + +JS_PUBLIC_API(JSString *) +JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n) +{ + CHECK_REQUEST(cx); + return js_NewStringCopyN(cx, s, n); +} + +JS_PUBLIC_API(JSString *) +JS_NewUCStringCopyZ(JSContext *cx, const jschar *s) +{ + CHECK_REQUEST(cx); + if (!s) + return cx->runtime->emptyString; + return js_NewStringCopyZ(cx, s); +} + +JS_PUBLIC_API(JSString *) +JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED); + if (!atom) + return NULL; + return ATOM_TO_STRING(atom); +} + +JS_PUBLIC_API(JSString *) +JS_InternUCString(JSContext *cx, const jschar *s) +{ + return JS_InternUCStringN(cx, s, js_strlen(s)); +} + +JS_PUBLIC_API(char *) +JS_GetStringBytes(JSString *str) +{ + const char *bytes; + + bytes = js_GetStringBytes(NULL, str); + return (char *)(bytes ? bytes : ""); +} + +JS_PUBLIC_API(jschar *) +JS_GetStringChars(JSString *str) +{ + size_t n, size; + jschar *s; + + /* + * API botch (again, shades of JS_GetStringBytes): we have no cx to report + * out-of-memory when undepending strings, so we replace js_UndependString + * with explicit malloc call and ignore its errors. + * + * If we fail to convert a dependent string into an independent one, our + * caller will not be guaranteed a \u0000 terminator as a backstop. This + * may break some clients who already misbehave on embedded NULs. + * + * The gain of dependent strings, which cure quadratic and cubic growth + * rate bugs in string concatenation, is worth this slight loss in API + * compatibility. + */ + if (JSSTRING_IS_DEPENDENT(str)) { + n = JSSTRDEP_LENGTH(str); + size = (n + 1) * sizeof(jschar); + s = (jschar *) malloc(size); + if (s) { + memcpy(s, JSSTRDEP_CHARS(str), n * sizeof *s); + s[n] = 0; + JSFLATSTR_INIT(str, s, n); + } else { + s = JSSTRDEP_CHARS(str); + } + } else { + JSFLATSTR_CLEAR_MUTABLE(str); + s = JSFLATSTR_CHARS(str); + } + return s; +} + +JS_PUBLIC_API(size_t) +JS_GetStringLength(JSString *str) +{ + return JSSTRING_LENGTH(str); +} + +JS_PUBLIC_API(intN) +JS_CompareStrings(JSString *str1, JSString *str2) +{ + return js_CompareStrings(str1, str2); +} + +JS_PUBLIC_API(JSString *) +JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length) +{ + JSString *str; + + CHECK_REQUEST(cx); + str = js_NewString(cx, chars, length); + if (!str) + return str; + JSFLATSTR_SET_MUTABLE(str); + return str; +} + +JS_PUBLIC_API(JSString *) +JS_NewDependentString(JSContext *cx, JSString *str, size_t start, + size_t length) +{ + CHECK_REQUEST(cx); + return js_NewDependentString(cx, str, start, length); +} + +JS_PUBLIC_API(JSString *) +JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right) +{ + CHECK_REQUEST(cx); + return js_ConcatStrings(cx, left, right); +} + +JS_PUBLIC_API(const jschar *) +JS_UndependString(JSContext *cx, JSString *str) +{ + CHECK_REQUEST(cx); + return js_UndependString(cx, str); +} + +JS_PUBLIC_API(JSBool) +JS_MakeStringImmutable(JSContext *cx, JSString *str) +{ + CHECK_REQUEST(cx); + return js_MakeStringImmutable(cx, str); +} + +JS_PUBLIC_API(JSBool) +JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, + size_t *dstlenp) +{ + size_t n; + + if (!dst) { + n = js_GetDeflatedStringLength(cx, src, srclen); + if (n == (size_t)-1) { + *dstlenp = 0; + return JS_FALSE; + } + *dstlenp = n; + return JS_TRUE; + } + + return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp); +} + +JS_PUBLIC_API(JSBool) +JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, + size_t *dstlenp) +{ + return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp); +} + +JS_PUBLIC_API(char *) +JS_EncodeString(JSContext *cx, JSString *str) +{ + return js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str)); +} + +JS_PUBLIC_API(JSBool) +JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, + JSONWriteCallback callback, void *data) +{ + CHECK_REQUEST(cx); + return js_Stringify(cx, vp, replacer, callback, data, 0); +} + +JS_PUBLIC_API(JSBool) +JS_TryJSON(JSContext *cx, jsval *vp) +{ + CHECK_REQUEST(cx); + return js_TryJSON(cx, vp); +} + +JS_PUBLIC_API(JSONParser *) +JS_BeginJSONParse(JSContext *cx, jsval *vp) +{ + CHECK_REQUEST(cx); + return js_BeginJSONParse(cx, vp); +} + +JS_PUBLIC_API(JSBool) +JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len) +{ + CHECK_REQUEST(cx); + return js_ConsumeJSONText(cx, jp, data, len); +} + +JS_PUBLIC_API(JSBool) +JS_FinishJSONParse(JSContext *cx, JSONParser *jp) +{ + CHECK_REQUEST(cx); + return js_FinishJSONParse(cx, jp); +} + +/* + * The following determines whether C Strings are to be treated as UTF-8 + * or ISO-8859-1. For correct operation, it must be set prior to the + * first call to JS_NewRuntime. + */ +#ifndef JS_C_STRINGS_ARE_UTF8 +JSBool js_CStringsAreUTF8 = JS_FALSE; +#endif + +JS_PUBLIC_API(JSBool) +JS_CStringsAreUTF8() +{ + return js_CStringsAreUTF8; +} + +JS_PUBLIC_API(void) +JS_SetCStringsAreUTF8() +{ + JS_ASSERT(!js_NewRuntimeWasCalled); + +#ifndef JS_C_STRINGS_ARE_UTF8 + js_CStringsAreUTF8 = JS_TRUE; +#endif +} + +/************************************************************************/ + +JS_PUBLIC_API(void) +JS_ReportError(JSContext *cx, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap); + va_end(ap); +} + +JS_PUBLIC_API(void) +JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback, + void *userRef, const uintN errorNumber, ...) +{ + va_list ap; + + va_start(ap, errorNumber); + js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef, + errorNumber, JS_TRUE, ap); + va_end(ap); +} + +JS_PUBLIC_API(void) +JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback, + void *userRef, const uintN errorNumber, ...) +{ + va_list ap; + + va_start(ap, errorNumber); + js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef, + errorNumber, JS_FALSE, ap); + va_end(ap); +} + +JS_PUBLIC_API(JSBool) +JS_ReportWarning(JSContext *cx, const char *format, ...) +{ + va_list ap; + JSBool ok; + + va_start(ap, format); + ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap); + va_end(ap); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags, + JSErrorCallback errorCallback, void *userRef, + const uintN errorNumber, ...) +{ + va_list ap; + JSBool ok; + + va_start(ap, errorNumber); + ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef, + errorNumber, JS_TRUE, ap); + va_end(ap); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags, + JSErrorCallback errorCallback, void *userRef, + const uintN errorNumber, ...) +{ + va_list ap; + JSBool ok; + + va_start(ap, errorNumber); + ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef, + errorNumber, JS_FALSE, ap); + va_end(ap); + return ok; +} + +JS_PUBLIC_API(void) +JS_ReportOutOfMemory(JSContext *cx) +{ + js_ReportOutOfMemory(cx); +} + +JS_PUBLIC_API(void) +JS_ReportAllocationOverflow(JSContext *cx) +{ + js_ReportAllocationOverflow(cx); +} + +JS_PUBLIC_API(JSErrorReporter) +JS_SetErrorReporter(JSContext *cx, JSErrorReporter er) +{ + JSErrorReporter older; + + older = cx->errorReporter; + cx->errorReporter = er; + return older; +} + +/************************************************************************/ + +/* + * Regular Expressions. + */ +JS_PUBLIC_API(JSObject *) +JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags) +{ + jschar *chars; + JSObject *obj; + + CHECK_REQUEST(cx); + chars = js_InflateString(cx, bytes, &length); + if (!chars) + return NULL; + obj = js_NewRegExpObject(cx, NULL, chars, length, flags); + JS_free(cx, chars); + return obj; +} + +JS_PUBLIC_API(JSObject *) +JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags) +{ + CHECK_REQUEST(cx); + return js_NewRegExpObject(cx, NULL, chars, length, flags); +} + +JS_PUBLIC_API(void) +JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline) +{ + JSRegExpStatics *res; + + CHECK_REQUEST(cx); + /* No locking required, cx is thread-private and input must be live. */ + res = &cx->regExpStatics; + res->input = input; + res->multiline = multiline; + cx->runtime->gcPoke = JS_TRUE; +} + +JS_PUBLIC_API(void) +JS_ClearRegExpStatics(JSContext *cx) +{ + JSRegExpStatics *res; + + /* No locking required, cx is thread-private and input must be live. */ + res = &cx->regExpStatics; + res->input = NULL; + res->multiline = JS_FALSE; + res->parenCount = 0; + res->lastMatch = res->lastParen = js_EmptySubString; + res->leftContext = res->rightContext = js_EmptySubString; + cx->runtime->gcPoke = JS_TRUE; +} + +JS_PUBLIC_API(void) +JS_ClearRegExpRoots(JSContext *cx) +{ + JSRegExpStatics *res; + + /* No locking required, cx is thread-private and input must be live. */ + res = &cx->regExpStatics; + res->input = NULL; + cx->runtime->gcPoke = JS_TRUE; +} + +/* TODO: compile, execute, get/set other statics... */ + +/************************************************************************/ + +JS_PUBLIC_API(void) +JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks) +{ + cx->localeCallbacks = callbacks; +} + +JS_PUBLIC_API(JSLocaleCallbacks *) +JS_GetLocaleCallbacks(JSContext *cx) +{ + return cx->localeCallbacks; +} + +/************************************************************************/ + +JS_PUBLIC_API(JSBool) +JS_IsExceptionPending(JSContext *cx) +{ + return (JSBool) cx->throwing; +} + +JS_PUBLIC_API(JSBool) +JS_GetPendingException(JSContext *cx, jsval *vp) +{ + CHECK_REQUEST(cx); + if (!cx->throwing) + return JS_FALSE; + *vp = cx->exception; + return JS_TRUE; +} + +JS_PUBLIC_API(void) +JS_SetPendingException(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + cx->throwing = JS_TRUE; + cx->exception = v; +} + +JS_PUBLIC_API(void) +JS_ClearPendingException(JSContext *cx) +{ + cx->throwing = JS_FALSE; + cx->exception = JSVAL_VOID; +} + +JS_PUBLIC_API(JSBool) +JS_ReportPendingException(JSContext *cx) +{ + JSBool save, ok; + + CHECK_REQUEST(cx); + + /* + * Set cx->generatingError to suppress the standard error-to-exception + * conversion done by all {js,JS}_Report* functions except for OOM. The + * cx->generatingError flag was added to suppress recursive divergence + * under js_ErrorToException, but it serves for our purposes here too. + */ + save = cx->generatingError; + cx->generatingError = JS_TRUE; + ok = js_ReportUncaughtException(cx); + cx->generatingError = save; + return ok; +} + +struct JSExceptionState { + JSBool throwing; + jsval exception; +}; + +JS_PUBLIC_API(JSExceptionState *) +JS_SaveExceptionState(JSContext *cx) +{ + JSExceptionState *state; + + CHECK_REQUEST(cx); + state = (JSExceptionState *) JS_malloc(cx, sizeof(JSExceptionState)); + if (state) { + state->throwing = JS_GetPendingException(cx, &state->exception); + if (state->throwing && JSVAL_IS_GCTHING(state->exception)) + js_AddRoot(cx, &state->exception, "JSExceptionState.exception"); + } + return state; +} + +JS_PUBLIC_API(void) +JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state) +{ + CHECK_REQUEST(cx); + if (state) { + if (state->throwing) + JS_SetPendingException(cx, state->exception); + else + JS_ClearPendingException(cx); + JS_DropExceptionState(cx, state); + } +} + +JS_PUBLIC_API(void) +JS_DropExceptionState(JSContext *cx, JSExceptionState *state) +{ + CHECK_REQUEST(cx); + if (state) { + if (state->throwing && JSVAL_IS_GCTHING(state->exception)) + JS_RemoveRoot(cx, &state->exception); + JS_free(cx, state); + } +} + +JS_PUBLIC_API(JSErrorReport *) +JS_ErrorFromException(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + return js_ErrorFromException(cx, v); +} + +JS_PUBLIC_API(JSBool) +JS_ThrowReportedError(JSContext *cx, const char *message, + JSErrorReport *reportp) +{ + return cx->fp && js_ErrorToException(cx, message, reportp); +} + +JS_PUBLIC_API(JSBool) +JS_ThrowStopIteration(JSContext *cx) +{ + return js_ThrowStopIteration(cx); +} + +/* + * Get the owning thread id of a context. Returns 0 if the context is not + * owned by any thread. + */ +JS_PUBLIC_API(jsword) +JS_GetContextThread(JSContext *cx) +{ +#ifdef JS_THREADSAFE + return JS_THREAD_ID(cx); +#else + return 0; +#endif +} + +/* + * Set the current thread as the owning thread of a context. Returns the + * old owning thread id, or -1 if the operation failed. + */ +JS_PUBLIC_API(jsword) +JS_SetContextThread(JSContext *cx) +{ +#ifdef JS_THREADSAFE + jsword old = JS_THREAD_ID(cx); + if (!js_SetContextThread(cx)) + return -1; + return old; +#else + return 0; +#endif +} + +JS_PUBLIC_API(jsword) +JS_ClearContextThread(JSContext *cx) +{ +#ifdef JS_THREADSAFE + jsword old = JS_THREAD_ID(cx); + js_ClearContextThread(cx); + return old; +#else + return 0; +#endif +} + +#ifdef JS_GC_ZEAL +JS_PUBLIC_API(void) +JS_SetGCZeal(JSContext *cx, uint8 zeal) +{ + cx->runtime->gcZeal = zeal; +} +#endif + +/************************************************************************/ + +#if !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE) + +#include + +/* + * Initialization routine for the JS DLL. + */ +BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) +{ + return TRUE; +} + +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsapi.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsapi.h new file mode 100644 index 0000000..7842192 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsapi.h @@ -0,0 +1,2699 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsapi_h___ +#define jsapi_h___ +/* + * JavaScript API. + */ +#include +#include +#include "js-config.h" +#include "jspubtd.h" +#include "jsutil.h" + +JS_BEGIN_EXTERN_C + +/* + * Type tags stored in the low bits of a jsval. + */ +#define JSVAL_OBJECT 0x0 /* untagged reference to object */ +#define JSVAL_INT 0x1 /* tagged 31-bit integer value */ +#define JSVAL_DOUBLE 0x2 /* tagged reference to double */ +#define JSVAL_STRING 0x4 /* tagged reference to string */ +#define JSVAL_BOOLEAN 0x6 /* tagged boolean value */ + +/* Type tag bitfield length and derived macros. */ +#define JSVAL_TAGBITS 3 +#define JSVAL_TAGMASK JS_BITMASK(JSVAL_TAGBITS) +#define JSVAL_TAG(v) ((v) & JSVAL_TAGMASK) +#define JSVAL_SETTAG(v,t) ((v) | (t)) +#define JSVAL_CLRTAG(v) ((v) & ~(jsval)JSVAL_TAGMASK) +#define JSVAL_ALIGN JS_BIT(JSVAL_TAGBITS) + +/* Predicates for type testing. */ +#define JSVAL_IS_OBJECT(v) (JSVAL_TAG(v) == JSVAL_OBJECT) +#define JSVAL_IS_NUMBER(v) (JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v)) +#define JSVAL_IS_INT(v) ((v) & JSVAL_INT) +#define JSVAL_IS_DOUBLE(v) (JSVAL_TAG(v) == JSVAL_DOUBLE) +#define JSVAL_IS_STRING(v) (JSVAL_TAG(v) == JSVAL_STRING) +#define JSVAL_IS_BOOLEAN(v) (((v) & ~((jsval)1 << JSVAL_TAGBITS)) == \ + JSVAL_BOOLEAN) +#define JSVAL_IS_NULL(v) ((v) == JSVAL_NULL) +#define JSVAL_IS_VOID(v) ((v) == JSVAL_VOID) +#define JSVAL_IS_PRIMITIVE(v) (!JSVAL_IS_OBJECT(v) || JSVAL_IS_NULL(v)) + +/* Objects, strings, and doubles are GC'ed. */ +#define JSVAL_IS_GCTHING(v) (!((v) & JSVAL_INT) && \ + JSVAL_TAG(v) != JSVAL_BOOLEAN) +#define JSVAL_TO_GCTHING(v) ((void *)JSVAL_CLRTAG(v)) +#define JSVAL_TO_OBJECT(v) ((JSObject *)JSVAL_TO_GCTHING(v)) +#define JSVAL_TO_DOUBLE(v) ((jsdouble *)JSVAL_TO_GCTHING(v)) +#define JSVAL_TO_STRING(v) ((JSString *)JSVAL_TO_GCTHING(v)) +#define OBJECT_TO_JSVAL(obj) ((jsval)(obj)) +#define DOUBLE_TO_JSVAL(dp) JSVAL_SETTAG((jsval)(dp), JSVAL_DOUBLE) +#define STRING_TO_JSVAL(str) JSVAL_SETTAG((jsval)(str), JSVAL_STRING) + +/* Lock and unlock the GC thing held by a jsval. */ +#define JSVAL_LOCK(cx,v) (JSVAL_IS_GCTHING(v) \ + ? JS_LockGCThing(cx, JSVAL_TO_GCTHING(v)) \ + : JS_TRUE) +#define JSVAL_UNLOCK(cx,v) (JSVAL_IS_GCTHING(v) \ + ? JS_UnlockGCThing(cx, JSVAL_TO_GCTHING(v)) \ + : JS_TRUE) + +/* Domain limits for the jsval int type. */ +#define JSVAL_INT_BITS 31 +#define JSVAL_INT_POW2(n) ((jsval)1 << (n)) +#define JSVAL_INT_MIN (-JSVAL_INT_POW2(30)) +#define JSVAL_INT_MAX (JSVAL_INT_POW2(30) - 1) +#define INT_FITS_IN_JSVAL(i) ((jsuint)(i) - (jsuint)JSVAL_INT_MIN <= \ + (jsuint)(JSVAL_INT_MAX - JSVAL_INT_MIN)) +#define JSVAL_TO_INT(v) ((jsint)(v) >> 1) +#define INT_TO_JSVAL(i) (((jsval)(i) << 1) | JSVAL_INT) + +/* Convert between boolean and jsval. */ +#define JSVAL_TO_BOOLEAN(v) ((JSBool)((v) >> JSVAL_TAGBITS)) +#define BOOLEAN_TO_JSVAL(b) JSVAL_SETTAG((jsval)(b) << JSVAL_TAGBITS, \ + JSVAL_BOOLEAN) + +/* A private data pointer (2-byte-aligned) can be stored as an int jsval. */ +#define JSVAL_TO_PRIVATE(v) ((void *)((v) & ~JSVAL_INT)) +#define PRIVATE_TO_JSVAL(p) ((jsval)(p) | JSVAL_INT) + +/* Property attributes, set in JSPropertySpec and passed to API functions. */ +#define JSPROP_ENUMERATE 0x01 /* property is visible to for/in loop */ +#define JSPROP_READONLY 0x02 /* not settable: assignment is no-op */ +#define JSPROP_PERMANENT 0x04 /* property cannot be deleted */ +#define JSPROP_GETTER 0x10 /* property holds getter function */ +#define JSPROP_SETTER 0x20 /* property holds setter function */ +#define JSPROP_SHARED 0x40 /* don't allocate a value slot for this + property; don't copy the property on + set of the same-named property in an + object that delegates to a prototype + containing this property */ +#define JSPROP_INDEX 0x80 /* name is actually (jsint) index */ + +/* Function flags, set in JSFunctionSpec and passed to JS_NewFunction etc. */ +#define JSFUN_LAMBDA 0x08 /* expressed, not declared, function */ +#define JSFUN_GETTER JSPROP_GETTER +#define JSFUN_SETTER JSPROP_SETTER +#define JSFUN_BOUND_METHOD 0x40 /* bind this to fun->object's parent */ +#define JSFUN_HEAVYWEIGHT 0x80 /* activation requires a Call object */ + +#define JSFUN_DISJOINT_FLAGS(f) ((f) & 0x0f) +#define JSFUN_GSFLAGS(f) ((f) & (JSFUN_GETTER | JSFUN_SETTER)) + +#define JSFUN_GETTER_TEST(f) ((f) & JSFUN_GETTER) +#define JSFUN_SETTER_TEST(f) ((f) & JSFUN_SETTER) +#define JSFUN_BOUND_METHOD_TEST(f) ((f) & JSFUN_BOUND_METHOD) +#define JSFUN_HEAVYWEIGHT_TEST(f) ((f) & JSFUN_HEAVYWEIGHT) + +#define JSFUN_GSFLAG2ATTR(f) JSFUN_GSFLAGS(f) + +#define JSFUN_THISP_FLAGS(f) (f) +#define JSFUN_THISP_TEST(f,t) ((f) & t) + +#define JSFUN_THISP_STRING 0x0100 /* |this| may be a primitive string */ +#define JSFUN_THISP_NUMBER 0x0200 /* |this| may be a primitive number */ +#define JSFUN_THISP_BOOLEAN 0x0400 /* |this| may be a primitive boolean */ +#define JSFUN_THISP_PRIMITIVE 0x0700 /* |this| may be any primitive value */ + +#define JSFUN_FAST_NATIVE 0x0800 /* JSFastNative needs no JSStackFrame */ + +#define JSFUN_FLAGS_MASK 0x0ff8 /* overlay JSFUN_* attributes -- + note that bit #15 is used internally + to flag interpreted functions */ + +#define JSFUN_STUB_GSOPS 0x1000 /* use JS_PropertyStub getter/setter + instead of defaulting to class gsops + for property holding function */ + +/* + * Re-use JSFUN_LAMBDA, which applies only to scripted functions, for use in + * JSFunctionSpec arrays that specify generic native prototype methods, i.e., + * methods of a class prototype that are exposed as static methods taking an + * extra leading argument: the generic |this| parameter. + * + * If you set this flag in a JSFunctionSpec struct's flags initializer, then + * that struct must live at least as long as the native static method object + * created due to this flag by JS_DefineFunctions or JS_InitClass. Typically + * JSFunctionSpec structs are allocated in static arrays. + */ +#define JSFUN_GENERIC_NATIVE JSFUN_LAMBDA + +/* + * Well-known JS values. The extern'd variables are initialized when the + * first JSContext is created by JS_NewContext (see below). + */ +#define JSVAL_VOID BOOLEAN_TO_JSVAL(2) +#define JSVAL_NULL OBJECT_TO_JSVAL(0) +#define JSVAL_ZERO INT_TO_JSVAL(0) +#define JSVAL_ONE INT_TO_JSVAL(1) +#define JSVAL_FALSE BOOLEAN_TO_JSVAL(JS_FALSE) +#define JSVAL_TRUE BOOLEAN_TO_JSVAL(JS_TRUE) + +/* + * Microseconds since the epoch, midnight, January 1, 1970 UTC. See the + * comment in jstypes.h regarding safe int64 usage. + */ +extern JS_PUBLIC_API(int64) +JS_Now(void); + +/* Don't want to export data, so provide accessors for non-inline jsvals. */ +extern JS_PUBLIC_API(jsval) +JS_GetNaNValue(JSContext *cx); + +extern JS_PUBLIC_API(jsval) +JS_GetNegativeInfinityValue(JSContext *cx); + +extern JS_PUBLIC_API(jsval) +JS_GetPositiveInfinityValue(JSContext *cx); + +extern JS_PUBLIC_API(jsval) +JS_GetEmptyStringValue(JSContext *cx); + +/* + * Format is a string of the following characters (spaces are insignificant), + * specifying the tabulated type conversions: + * + * b JSBool Boolean + * c uint16/jschar ECMA uint16, Unicode char + * i int32 ECMA int32 + * u uint32 ECMA uint32 + * j int32 Rounded int32 (coordinate) + * d jsdouble IEEE double + * I jsdouble Integral IEEE double + * s char * C string + * S JSString * Unicode string, accessed by a JSString pointer + * W jschar * Unicode character vector, 0-terminated (W for wide) + * o JSObject * Object reference + * f JSFunction * Function private + * v jsval Argument value (no conversion) + * * N/A Skip this argument (no vararg) + * / N/A End of required arguments + * + * The variable argument list after format must consist of &b, &c, &s, e.g., + * where those variables have the types given above. For the pointer types + * char *, JSString *, and JSObject *, the pointed-at memory returned belongs + * to the JS runtime, not to the calling native code. The runtime promises + * to keep this memory valid so long as argv refers to allocated stack space + * (so long as the native function is active). + * + * Fewer arguments than format specifies may be passed only if there is a / + * in format after the last required argument specifier and argc is at least + * the number of required arguments. More arguments than format specifies + * may be passed without error; it is up to the caller to deal with trailing + * unconverted arguments. + */ +extern JS_PUBLIC_API(JSBool) +JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, + ...); + +#ifdef va_start +extern JS_PUBLIC_API(JSBool) +JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, + const char *format, va_list ap); +#endif + +/* + * Inverse of JS_ConvertArguments: scan format and convert trailing arguments + * into jsvals, GC-rooted if necessary by the JS stack. Return null on error, + * and a pointer to the new argument vector on success. Also return a stack + * mark on success via *markp, in which case the caller must eventually clean + * up by calling JS_PopArguments. + * + * Note that the number of actual arguments supplied is specified exclusively + * by format, so there is no argc parameter. + */ +extern JS_PUBLIC_API(jsval *) +JS_PushArguments(JSContext *cx, void **markp, const char *format, ...); + +#ifdef va_start +extern JS_PUBLIC_API(jsval *) +JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap); +#endif + +extern JS_PUBLIC_API(void) +JS_PopArguments(JSContext *cx, void *mark); + +#ifdef JS_ARGUMENT_FORMATTER_DEFINED + +/* + * Add and remove a format string handler for JS_{Convert,Push}Arguments{,VA}. + * The handler function has this signature (see jspubtd.h): + * + * JSBool MyArgumentFormatter(JSContext *cx, const char *format, + * JSBool fromJS, jsval **vpp, va_list *app); + * + * It should return true on success, and return false after reporting an error + * or detecting an already-reported error. + * + * For a given format string, for example "AA", the formatter is called from + * JS_ConvertArgumentsVA like so: + * + * formatter(cx, "AA...", JS_TRUE, &sp, &ap); + * + * sp points into the arguments array on the JS stack, while ap points into + * the stdarg.h va_list on the C stack. The JS_TRUE passed for fromJS tells + * the formatter to convert zero or more jsvals at sp to zero or more C values + * accessed via pointers-to-values at ap, updating both sp (via *vpp) and ap + * (via *app) to point past the converted arguments and their result pointers + * on the C stack. + * + * When called from JS_PushArgumentsVA, the formatter is invoked thus: + * + * formatter(cx, "AA...", JS_FALSE, &sp, &ap); + * + * where JS_FALSE for fromJS means to wrap the C values at ap according to the + * format specifier and store them at sp, updating ap and sp appropriately. + * + * The "..." after "AA" is the rest of the format string that was passed into + * JS_{Convert,Push}Arguments{,VA}. The actual format trailing substring used + * in each Convert or PushArguments call is passed to the formatter, so that + * one such function may implement several formats, in order to share code. + * + * Remove just forgets about any handler associated with format. Add does not + * copy format, it points at the string storage allocated by the caller, which + * is typically a string constant. If format is in dynamic storage, it is up + * to the caller to keep the string alive until Remove is called. + */ +extern JS_PUBLIC_API(JSBool) +JS_AddArgumentFormatter(JSContext *cx, const char *format, + JSArgumentFormatter formatter); + +extern JS_PUBLIC_API(void) +JS_RemoveArgumentFormatter(JSContext *cx, const char *format); + +#endif /* JS_ARGUMENT_FORMATTER_DEFINED */ + +extern JS_PUBLIC_API(JSBool) +JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp); + +extern JS_PUBLIC_API(JSFunction *) +JS_ValueToFunction(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(JSFunction *) +JS_ValueToConstructor(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(JSString *) +JS_ValueToString(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(JSString *) +JS_ValueToSource(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(JSBool) +JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp); + +/* + * Convert a value to a number, then to an int32, according to the ECMA rules + * for ToInt32. + */ +extern JS_PUBLIC_API(JSBool) +JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip); + +/* + * Convert a value to a number, then to a uint32, according to the ECMA rules + * for ToUint32. + */ +extern JS_PUBLIC_API(JSBool) +JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip); + +/* + * Convert a value to a number, then to an int32 if it fits by rounding to + * nearest; but failing with an error report if the double is out of range + * or unordered. + */ +extern JS_PUBLIC_API(JSBool) +JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip); + +/* + * ECMA ToUint16, for mapping a jsval to a Unicode point. + */ +extern JS_PUBLIC_API(JSBool) +JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip); + +extern JS_PUBLIC_API(JSBool) +JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp); + +extern JS_PUBLIC_API(JSType) +JS_TypeOfValue(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(const char *) +JS_GetTypeName(JSContext *cx, JSType type); + +/************************************************************************/ + +/* + * Initialization, locking, contexts, and memory allocation. + * + * It is important that the first runtime and first context be created in a + * single-threaded fashion, otherwise the behavior of the library is undefined. + * See: http://developer.mozilla.org/en/docs/Category:JSAPI_Reference + */ +#define JS_NewRuntime JS_Init +#define JS_DestroyRuntime JS_Finish +#define JS_LockRuntime JS_Lock +#define JS_UnlockRuntime JS_Unlock + +extern JS_PUBLIC_API(JSRuntime *) +JS_NewRuntime(uint32 maxbytes); + +extern JS_PUBLIC_API(void) +JS_DestroyRuntime(JSRuntime *rt); + +extern JS_PUBLIC_API(void) +JS_ShutDown(void); + +JS_PUBLIC_API(void *) +JS_GetRuntimePrivate(JSRuntime *rt); + +JS_PUBLIC_API(void) +JS_SetRuntimePrivate(JSRuntime *rt, void *data); + +extern JS_PUBLIC_API(void) +JS_BeginRequest(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_EndRequest(JSContext *cx); + +/* Yield to pending GC operations, regardless of request depth */ +extern JS_PUBLIC_API(void) +JS_YieldRequest(JSContext *cx); + +extern JS_PUBLIC_API(jsrefcount) +JS_SuspendRequest(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth); + +#ifdef __cplusplus +JS_END_EXTERN_C + +class JSAutoRequest { + public: + JSAutoRequest(JSContext *cx) : mContext(cx), mSaveDepth(0) { + JS_BeginRequest(mContext); + } + ~JSAutoRequest() { + JS_EndRequest(mContext); + } + + void suspend() { + mSaveDepth = JS_SuspendRequest(mContext); + } + void resume() { + JS_ResumeRequest(mContext, mSaveDepth); + } + + protected: + JSContext *mContext; + jsrefcount mSaveDepth; + +#if 0 + private: + static void *operator new(size_t) CPP_THROW_NEW { return 0; }; + static void operator delete(void *, size_t) { }; +#endif +}; + +class JSAutoSuspendRequest { + public: + JSAutoSuspendRequest(JSContext *cx) : mContext(cx), mSaveDepth(0) { + if (mContext) { + mSaveDepth = JS_SuspendRequest(mContext); + } + } + ~JSAutoSuspendRequest() { + resume(); + } + + void resume() { + if (mContext) { + JS_ResumeRequest(mContext, mSaveDepth); + mContext = 0; + } + } + + protected: + JSContext *mContext; + jsrefcount mSaveDepth; + +#if 0 + private: + static void *operator new(size_t) CPP_THROW_NEW { return 0; }; + static void operator delete(void *, size_t) { }; +#endif +}; + +JS_BEGIN_EXTERN_C +#endif + +extern JS_PUBLIC_API(void) +JS_Lock(JSRuntime *rt); + +extern JS_PUBLIC_API(void) +JS_Unlock(JSRuntime *rt); + +extern JS_PUBLIC_API(JSContextCallback) +JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback); + +extern JS_PUBLIC_API(JSContext *) +JS_NewContext(JSRuntime *rt, size_t stackChunkSize); + +extern JS_PUBLIC_API(void) +JS_DestroyContext(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_DestroyContextNoGC(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_DestroyContextMaybeGC(JSContext *cx); + +extern JS_PUBLIC_API(void *) +JS_GetContextPrivate(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_SetContextPrivate(JSContext *cx, void *data); + +extern JS_PUBLIC_API(JSRuntime *) +JS_GetRuntime(JSContext *cx); + +extern JS_PUBLIC_API(JSContext *) +JS_ContextIterator(JSRuntime *rt, JSContext **iterp); + +extern JS_PUBLIC_API(JSVersion) +JS_GetVersion(JSContext *cx); + +extern JS_PUBLIC_API(JSVersion) +JS_SetVersion(JSContext *cx, JSVersion version); + +extern JS_PUBLIC_API(const char *) +JS_VersionToString(JSVersion version); + +extern JS_PUBLIC_API(JSVersion) +JS_StringToVersion(const char *string); + +/* + * JS options are orthogonal to version, and may be freely composed with one + * another as well as with version. + * + * JSOPTION_VAROBJFIX is recommended -- see the comments associated with the + * prototypes for JS_ExecuteScript, JS_EvaluateScript, etc. + */ +#define JSOPTION_STRICT JS_BIT(0) /* warn on dubious practice */ +#define JSOPTION_WERROR JS_BIT(1) /* convert warning to error */ +#define JSOPTION_VAROBJFIX JS_BIT(2) /* make JS_EvaluateScript use + the last object on its 'obj' + param's scope chain as the + ECMA 'variables object' */ +#define JSOPTION_PRIVATE_IS_NSISUPPORTS \ + JS_BIT(3) /* context private data points + to an nsISupports subclass */ +#define JSOPTION_COMPILE_N_GO JS_BIT(4) /* caller of JS_Compile*Script + promises to execute compiled + script once only; enables + compile-time scope chain + resolution of consts. */ +#define JSOPTION_ATLINE JS_BIT(5) /* //@line number ["filename"] + option supported for the + XUL preprocessor and kindred + beasts. */ +#define JSOPTION_XML JS_BIT(6) /* EMCAScript for XML support: + parse as a token, + not backward compatible with + the comment-hiding hack used + in HTML script tags. */ +#define JSOPTION_NATIVE_BRANCH_CALLBACK \ + JS_BIT(7) /* the branch callback set by + JS_SetBranchCallback may be + called with a null script + parameter, by native code + that loops intensively. + Deprecated, use + JS_SetOperationCallback + instead */ +#define JSOPTION_DONT_REPORT_UNCAUGHT \ + JS_BIT(8) /* When returning from the + outermost API call, prevent + uncaught exceptions from + being converted to error + reports */ + +#define JSOPTION_RELIMIT JS_BIT(9) /* Throw exception on any + regular expression which + backtracks more than n^3 + times, where n is length + of the input string */ +#define JSOPTION_ANONFUNFIX JS_BIT(10) /* Disallow function () {} in + statement context per + ECMA-262 Edition 3. */ + +#define JSOPTION_JIT JS_BIT(11) /* Enable JIT compilation. */ + +#define JSOPTION_NO_SCRIPT_RVAL JS_BIT(12) /* A promise to the compiler + that a null rval out-param + will be passed to each call + to JS_ExecuteScript. */ + +extern JS_PUBLIC_API(uint32) +JS_GetOptions(JSContext *cx); + +extern JS_PUBLIC_API(uint32) +JS_SetOptions(JSContext *cx, uint32 options); + +extern JS_PUBLIC_API(uint32) +JS_ToggleOptions(JSContext *cx, uint32 options); + +extern JS_PUBLIC_API(const char *) +JS_GetImplementationVersion(void); + +extern JS_PUBLIC_API(JSObject *) +JS_GetGlobalObject(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_SetGlobalObject(JSContext *cx, JSObject *obj); + +/* + * Initialize standard JS class constructors, prototypes, and any top-level + * functions and constants associated with the standard classes (e.g. isNaN + * for Number). + * + * NB: This sets cx's global object to obj if it was null. + */ +extern JS_PUBLIC_API(JSBool) +JS_InitStandardClasses(JSContext *cx, JSObject *obj); + +/* + * Resolve id, which must contain either a string or an int, to a standard + * class name in obj if possible, defining the class's constructor and/or + * prototype and storing true in *resolved. If id does not name a standard + * class or a top-level property induced by initializing a standard class, + * store false in *resolved and just return true. Return false on error, + * as usual for JSBool result-typed API entry points. + * + * This API can be called directly from a global object class's resolve op, + * to define standard classes lazily. The class's enumerate op should call + * JS_EnumerateStandardClasses(cx, obj), to define eagerly during for..in + * loops any classes not yet resolved lazily. + */ +extern JS_PUBLIC_API(JSBool) +JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id, + JSBool *resolved); + +extern JS_PUBLIC_API(JSBool) +JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj); + +/* + * Enumerate any already-resolved standard class ids into ida, or into a new + * JSIdArray if ida is null. Return the augmented array on success, null on + * failure with ida (if it was non-null on entry) destroyed. + */ +extern JS_PUBLIC_API(JSIdArray *) +JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, + JSIdArray *ida); + +extern JS_PUBLIC_API(JSBool) +JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, + JSObject **objp); + +extern JS_PUBLIC_API(JSObject *) +JS_GetScopeChain(JSContext *cx); + +extern JS_PUBLIC_API(JSObject *) +JS_GetGlobalForObject(JSContext *cx, JSObject *obj); + +/* + * Macros to hide interpreter stack layout details from a JSFastNative using + * its jsval *vp parameter. The stack layout underlying invocation can't change + * without breaking source and binary compatibility (argv[-2] is well-known to + * be the callee jsval, and argv[-1] is as well known to be |this|). + * + * Note well: However, argv[-1] may be JSVAL_NULL where with slow natives it + * is the global object, so embeddings implementing fast natives *must* call + * JS_THIS or JS_THIS_OBJECT and test for failure indicated by a null return, + * which should propagate as a false return from native functions and hooks. + * + * To reduce boilerplace checks, JS_InstanceOf and JS_GetInstancePrivate now + * handle a null obj parameter by returning false (throwing a TypeError if + * given non-null argv), so most native functions that type-check their |this| + * parameter need not add null checking. + * + * NB: there is an anti-dependency between JS_CALLEE and JS_SET_RVAL: native + * methods that may inspect their callee must defer setting their return value + * until after any such possible inspection. Otherwise the return value will be + * inspected instead of the callee function object. + * + * WARNING: These are not (yet) mandatory macros, but new code outside of the + * engine should use them. In the Mozilla 2.0 milestone their definitions may + * change incompatibly. + */ +#define JS_CALLEE(cx,vp) ((vp)[0]) +#define JS_ARGV_CALLEE(argv) ((argv)[-2]) +#define JS_THIS(cx,vp) JS_ComputeThis(cx, vp) +#define JS_THIS_OBJECT(cx,vp) ((JSObject *) JS_THIS(cx,vp)) +#define JS_ARGV(cx,vp) ((vp) + 2) +#define JS_RVAL(cx,vp) (*(vp)) +#define JS_SET_RVAL(cx,vp,v) (*(vp) = (v)) + +extern JS_PUBLIC_API(jsval) +JS_ComputeThis(JSContext *cx, jsval *vp); + +extern JS_PUBLIC_API(void *) +JS_malloc(JSContext *cx, size_t nbytes); + +extern JS_PUBLIC_API(void *) +JS_realloc(JSContext *cx, void *p, size_t nbytes); + +extern JS_PUBLIC_API(void) +JS_free(JSContext *cx, void *p); + +extern JS_PUBLIC_API(char *) +JS_strdup(JSContext *cx, const char *s); + +extern JS_PUBLIC_API(jsdouble *) +JS_NewDouble(JSContext *cx, jsdouble d); + +extern JS_PUBLIC_API(JSBool) +JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval); + +/* + * A JS GC root is a pointer to a JSObject *, JSString *, or jsdouble * that + * itself points into the GC heap (more recently, we support this extension: + * a root may be a pointer to a jsval v for which JSVAL_IS_GCTHING(v) is true). + * + * Therefore, you never pass JSObject *obj to JS_AddRoot(cx, obj). You always + * call JS_AddRoot(cx, &obj), passing obj by reference. And later, before obj + * or the structure it is embedded within goes out of scope or is freed, you + * must call JS_RemoveRoot(cx, &obj). + * + * Also, use JS_AddNamedRoot(cx, &structPtr->memberObj, "structPtr->memberObj") + * in preference to JS_AddRoot(cx, &structPtr->memberObj), in order to identify + * roots by their source callsites. This way, you can find the callsite while + * debugging if you should fail to do JS_RemoveRoot(cx, &structPtr->memberObj) + * before freeing structPtr's memory. + */ +extern JS_PUBLIC_API(JSBool) +JS_AddRoot(JSContext *cx, void *rp); + +#ifdef NAME_ALL_GC_ROOTS +#define JS_DEFINE_TO_TOKEN(def) #def +#define JS_DEFINE_TO_STRING(def) JS_DEFINE_TO_TOKEN(def) +#define JS_AddRoot(cx,rp) JS_AddNamedRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__)) +#endif + +extern JS_PUBLIC_API(JSBool) +JS_AddNamedRoot(JSContext *cx, void *rp, const char *name); + +extern JS_PUBLIC_API(JSBool) +JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name); + +extern JS_PUBLIC_API(JSBool) +JS_RemoveRoot(JSContext *cx, void *rp); + +extern JS_PUBLIC_API(JSBool) +JS_RemoveRootRT(JSRuntime *rt, void *rp); + +/* + * The last GC thing of each type (object, string, double, external string + * types) created on a given context is kept alive until another thing of the + * same type is created, using a newborn root in the context. These newborn + * roots help native code protect newly-created GC-things from GC invocations + * activated before those things can be rooted using local or global roots. + * + * However, the newborn roots can also entrain great gobs of garbage, so the + * JS_GC entry point clears them for the context on which GC is being forced. + * Embeddings may need to do likewise for all contexts. + * + * See the scoped local root API immediately below for a better way to manage + * newborns in cases where native hooks (functions, getters, setters, etc.) + * create many GC-things, potentially without connecting them to predefined + * local roots such as *rval or argv[i] in an active native function. Using + * JS_EnterLocalRootScope disables updating of the context's per-gc-thing-type + * newborn roots, until control flow unwinds and leaves the outermost nesting + * local root scope. + */ +extern JS_PUBLIC_API(void) +JS_ClearNewbornRoots(JSContext *cx); + +/* + * Scoped local root management allows native functions, getter/setters, etc. + * to avoid worrying about the newborn root pigeon-holes, overloading local + * roots allocated in argv and *rval, or ending up having to call JS_Add*Root + * and JS_RemoveRoot to manage global roots temporarily. + * + * Instead, calling JS_EnterLocalRootScope and JS_LeaveLocalRootScope around + * the body of the native hook causes the engine to allocate a local root for + * each newborn created in between the two API calls, using a local root stack + * associated with cx. For example: + * + * JSBool + * my_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) + * { + * JSBool ok; + * + * if (!JS_EnterLocalRootScope(cx)) + * return JS_FALSE; + * ok = my_GetPropertyBody(cx, obj, id, vp); + * JS_LeaveLocalRootScope(cx); + * return ok; + * } + * + * NB: JS_LeaveLocalRootScope must be called once for every prior successful + * call to JS_EnterLocalRootScope. If JS_EnterLocalRootScope fails, you must + * not make the matching JS_LeaveLocalRootScope call. + * + * JS_LeaveLocalRootScopeWithResult(cx, rval) is an alternative way to leave + * a local root scope that protects a result or return value, by effectively + * pushing it in the caller's local root scope. + * + * In case a native hook allocates many objects or other GC-things, but the + * native protects some of those GC-things by storing them as property values + * in an object that is itself protected, the hook can call JS_ForgetLocalRoot + * to free the local root automatically pushed for the now-protected GC-thing. + * + * JS_ForgetLocalRoot works on any GC-thing allocated in the current local + * root scope, but it's more time-efficient when called on references to more + * recently created GC-things. Calling it successively on other than the most + * recently allocated GC-thing will tend to average the time inefficiency, and + * may risk O(n^2) growth rate, but in any event, you shouldn't allocate too + * many local roots if you can root as you go (build a tree of objects from + * the top down, forgetting each latest-allocated GC-thing immediately upon + * linking it to its parent). + */ +extern JS_PUBLIC_API(JSBool) +JS_EnterLocalRootScope(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_LeaveLocalRootScope(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval); + +extern JS_PUBLIC_API(void) +JS_ForgetLocalRoot(JSContext *cx, void *thing); + +#ifdef __cplusplus +JS_END_EXTERN_C + +class JSAutoLocalRootScope { + public: + JSAutoLocalRootScope(JSContext *cx) : mContext(cx) { + JS_EnterLocalRootScope(mContext); + } + ~JSAutoLocalRootScope() { + JS_LeaveLocalRootScope(mContext); + } + + void forget(void *thing) { + JS_ForgetLocalRoot(mContext, thing); + } + + protected: + JSContext *mContext; + +#if 0 + private: + static void *operator new(size_t) CPP_THROW_NEW { return 0; }; + static void operator delete(void *, size_t) { }; +#endif +}; + +JS_BEGIN_EXTERN_C +#endif + +#ifdef DEBUG +extern JS_PUBLIC_API(void) +JS_DumpNamedRoots(JSRuntime *rt, + void (*dump)(const char *name, void *rp, void *data), + void *data); +#endif + +/* + * Call JS_MapGCRoots to map the GC's roots table using map(rp, name, data). + * The root is pointed at by rp; if the root is unnamed, name is null; data is + * supplied from the third parameter to JS_MapGCRoots. + * + * The map function should return JS_MAP_GCROOT_REMOVE to cause the currently + * enumerated root to be removed. To stop enumeration, set JS_MAP_GCROOT_STOP + * in the return value. To keep on mapping, return JS_MAP_GCROOT_NEXT. These + * constants are flags; you can OR them together. + * + * This function acquires and releases rt's GC lock around the mapping of the + * roots table, so the map function should run to completion in as few cycles + * as possible. Of course, map cannot call JS_GC, JS_MaybeGC, JS_BeginRequest, + * or any JS API entry point that acquires locks, without double-tripping or + * deadlocking on the GC lock. + * + * JS_MapGCRoots returns the count of roots that were successfully mapped. + */ +#define JS_MAP_GCROOT_NEXT 0 /* continue mapping entries */ +#define JS_MAP_GCROOT_STOP 1 /* stop mapping entries */ +#define JS_MAP_GCROOT_REMOVE 2 /* remove and free the current entry */ + +typedef intN +(* JSGCRootMapFun)(void *rp, const char *name, void *data); + +extern JS_PUBLIC_API(uint32) +JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data); + +extern JS_PUBLIC_API(JSBool) +JS_LockGCThing(JSContext *cx, void *thing); + +extern JS_PUBLIC_API(JSBool) +JS_LockGCThingRT(JSRuntime *rt, void *thing); + +extern JS_PUBLIC_API(JSBool) +JS_UnlockGCThing(JSContext *cx, void *thing); + +extern JS_PUBLIC_API(JSBool) +JS_UnlockGCThingRT(JSRuntime *rt, void *thing); + +/* + * Register externally maintained GC roots. + * + * traceOp: the trace operation. For each root the implementation should call + * JS_CallTracer whenever the root contains a traceable thing. + * data: the data argument to pass to each invocation of traceOp. + */ +extern JS_PUBLIC_API(void) +JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data); + +/* + * For implementors of JSMarkOp. All new code should implement JSTraceOp + * instead. + */ +extern JS_PUBLIC_API(void) +JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg); + +/* + * JS_CallTracer API and related macros for implementors of JSTraceOp, to + * enumerate all references to traceable things reachable via a property or + * other strong ref identified for debugging purposes by name or index or + * a naming callback. + * + * By definition references to traceable things include non-null pointers + * to JSObject, JSString and jsdouble and corresponding jsvals. + * + * See the JSTraceOp typedef in jspubtd.h. + */ + +/* Trace kinds to pass to JS_Tracing. */ +#define JSTRACE_OBJECT 0 +#define JSTRACE_DOUBLE 1 +#define JSTRACE_STRING 2 + +/* + * Use the following macros to check if a particular jsval is a traceable + * thing and to extract the thing and its kind to pass to JS_CallTracer. + */ +#define JSVAL_IS_TRACEABLE(v) (JSVAL_IS_GCTHING(v) && !JSVAL_IS_NULL(v)) +#define JSVAL_TO_TRACEABLE(v) (JSVAL_TO_GCTHING(v)) +#define JSVAL_TRACE_KIND(v) (JSVAL_TAG(v) >> 1) + +JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_OBJECT) == JSTRACE_OBJECT); +JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_DOUBLE) == JSTRACE_DOUBLE); +JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_STRING) == JSTRACE_STRING); + +struct JSTracer { + JSContext *context; + JSTraceCallback callback; +#ifdef DEBUG + JSTraceNamePrinter debugPrinter; + const void *debugPrintArg; + size_t debugPrintIndex; +#endif +}; + +/* + * The method to call on each reference to a traceable thing stored in a + * particular JSObject or other runtime structure. With DEBUG defined the + * caller before calling JS_CallTracer must initialize JSTracer fields + * describing the reference using the macros below. + */ +extern JS_PUBLIC_API(void) +JS_CallTracer(JSTracer *trc, void *thing, uint32 kind); + +/* + * Set debugging information about a reference to a traceable thing to prepare + * for the following call to JS_CallTracer. + * + * When printer is null, arg must be const char * or char * C string naming + * the reference and index must be either (size_t)-1 indicating that the name + * alone describes the reference or it must be an index into some array vector + * that stores the reference. + * + * When printer callback is not null, the arg and index arguments are + * available to the callback as debugPrinterArg and debugPrintIndex fields + * of JSTracer. + * + * The storage for name or callback's arguments needs to live only until + * the following call to JS_CallTracer returns. + */ +#ifdef DEBUG +# define JS_SET_TRACING_DETAILS(trc, printer, arg, index) \ + JS_BEGIN_MACRO \ + (trc)->debugPrinter = (printer); \ + (trc)->debugPrintArg = (arg); \ + (trc)->debugPrintIndex = (index); \ + JS_END_MACRO +#else +# define JS_SET_TRACING_DETAILS(trc, printer, arg, index) \ + JS_BEGIN_MACRO \ + JS_END_MACRO +#endif + +/* + * Convenience macro to describe the argument of JS_CallTracer using C string + * and index. + */ +# define JS_SET_TRACING_INDEX(trc, name, index) \ + JS_SET_TRACING_DETAILS(trc, NULL, name, index) + +/* + * Convenience macro to describe the argument of JS_CallTracer using C string. + */ +# define JS_SET_TRACING_NAME(trc, name) \ + JS_SET_TRACING_DETAILS(trc, NULL, name, (size_t)-1) + +/* + * Convenience macro to invoke JS_CallTracer using C string as the name for + * the reference to a traceable thing. + */ +# define JS_CALL_TRACER(trc, thing, kind, name) \ + JS_BEGIN_MACRO \ + JS_SET_TRACING_NAME(trc, name); \ + JS_CallTracer((trc), (thing), (kind)); \ + JS_END_MACRO + +/* + * Convenience macros to invoke JS_CallTracer when jsval represents a + * reference to a traceable thing. + */ +#define JS_CALL_VALUE_TRACER(trc, val, name) \ + JS_BEGIN_MACRO \ + if (JSVAL_IS_TRACEABLE(val)) { \ + JS_CALL_TRACER((trc), JSVAL_TO_GCTHING(val), \ + JSVAL_TRACE_KIND(val), name); \ + } \ + JS_END_MACRO + +#define JS_CALL_OBJECT_TRACER(trc, object, name) \ + JS_BEGIN_MACRO \ + JSObject *obj_ = (object); \ + JS_ASSERT(obj_); \ + JS_CALL_TRACER((trc), obj_, JSTRACE_OBJECT, name); \ + JS_END_MACRO + +#define JS_CALL_STRING_TRACER(trc, string, name) \ + JS_BEGIN_MACRO \ + JSString *str_ = (string); \ + JS_ASSERT(str_); \ + JS_CALL_TRACER((trc), str_, JSTRACE_STRING, name); \ + JS_END_MACRO + +#define JS_CALL_DOUBLE_TRACER(trc, number, name) \ + JS_BEGIN_MACRO \ + jsdouble *num_ = (number); \ + JS_ASSERT(num_); \ + JS_CALL_TRACER((trc), num_, JSTRACE_DOUBLE, name); \ + JS_END_MACRO + +/* + * API for JSTraceCallback implementations. + */ +# define JS_TRACER_INIT(trc, cx_, callback_) \ + JS_BEGIN_MACRO \ + (trc)->context = (cx_); \ + (trc)->callback = (callback_); \ + JS_SET_TRACING_DETAILS(trc, NULL, NULL, (size_t)-1); \ + JS_END_MACRO + +extern JS_PUBLIC_API(void) +JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind); + +extern JS_PUBLIC_API(void) +JS_TraceRuntime(JSTracer *trc); + +#ifdef DEBUG + +extern JS_PUBLIC_API(void) +JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, + void *thing, uint32 kind, JSBool includeDetails); + +/* + * DEBUG-only method to dump the object graph of heap-allocated things. + * + * fp: file for the dump output. + * start: when non-null, dump only things reachable from start + * thing. Otherwise dump all things reachable from the + * runtime roots. + * startKind: trace kind of start if start is not null. Must be 0 when + * start is null. + * thingToFind: dump only paths in the object graph leading to thingToFind + * when non-null. + * maxDepth: the upper bound on the number of edges to descend from the + * graph roots. + * thingToIgnore: thing to ignore during the graph traversal when non-null. + */ +extern JS_PUBLIC_API(JSBool) +JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind, + void *thingToFind, size_t maxDepth, void *thingToIgnore); + +#endif + +/* + * Garbage collector API. + */ +extern JS_PUBLIC_API(void) +JS_GC(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_MaybeGC(JSContext *cx); + +extern JS_PUBLIC_API(JSGCCallback) +JS_SetGCCallback(JSContext *cx, JSGCCallback cb); + +extern JS_PUBLIC_API(JSGCCallback) +JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb); + +extern JS_PUBLIC_API(JSBool) +JS_IsGCMarkingTracer(JSTracer *trc); + +extern JS_PUBLIC_API(JSBool) +JS_IsAboutToBeFinalized(JSContext *cx, void *thing); + +typedef enum JSGCParamKey { + /* Maximum nominal heap before last ditch GC. */ + JSGC_MAX_BYTES = 0, + + /* Number of JS_malloc bytes before last ditch GC. */ + JSGC_MAX_MALLOC_BYTES = 1, + + /* Hoard stackPools for this long, in ms, default is 30 seconds. */ + JSGC_STACKPOOL_LIFESPAN = 2 +} JSGCParamKey; + +extern JS_PUBLIC_API(void) +JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value); + +/* + * Add a finalizer for external strings created by JS_NewExternalString (see + * below) using a type-code returned from this function, and that understands + * how to free or release the memory pointed at by JS_GetStringChars(str). + * + * Return a nonnegative type index if there is room for finalizer in the + * global GC finalizers table, else return -1. If the engine is compiled + * JS_THREADSAFE and used in a multi-threaded environment, this function must + * be invoked on the primordial thread only, at startup -- or else the entire + * program must single-thread itself while loading a module that calls this + * function. + */ +extern JS_PUBLIC_API(intN) +JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer); + +/* + * Remove finalizer from the global GC finalizers table, returning its type + * code if found, -1 if not found. + * + * As with JS_AddExternalStringFinalizer, there is a threading restriction + * if you compile the engine JS_THREADSAFE: this function may be called for a + * given finalizer pointer on only one thread; different threads may call to + * remove distinct finalizers safely. + * + * You must ensure that all strings with finalizer's type have been collected + * before calling this function. Otherwise, string data will be leaked by the + * GC, for want of a finalizer to call. + */ +extern JS_PUBLIC_API(intN) +JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer); + +/* + * Create a new JSString whose chars member refers to external memory, i.e., + * memory requiring special, type-specific finalization. The type code must + * be a nonnegative return value from JS_AddExternalStringFinalizer. + */ +extern JS_PUBLIC_API(JSString *) +JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type); + +/* + * Returns the external-string finalizer index for this string, or -1 if it is + * an "internal" (native to JS engine) string. + */ +extern JS_PUBLIC_API(intN) +JS_GetExternalStringGCType(JSRuntime *rt, JSString *str); + +/* + * Sets maximum (if stack grows upward) or minimum (downward) legal stack byte + * address in limitAddr for the thread or process stack used by cx. To disable + * stack size checking, pass 0 for limitAddr. + */ +extern JS_PUBLIC_API(void) +JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr); + +/* + * Set the quota on the number of bytes that stack-like data structures can + * use when the runtime compiles and executes scripts. These structures + * consume heap space, so JS_SetThreadStackLimit does not bound their size. + * The default quota is 32MB which is quite generous. + * + * The function must be called before any script compilation or execution API + * calls, i.e. either immediately after JS_NewContext or from JSCONTEXT_NEW + * context callback. + */ +extern JS_PUBLIC_API(void) +JS_SetScriptStackQuota(JSContext *cx, size_t quota); + +#define JS_DEFAULT_SCRIPT_STACK_QUOTA ((size_t) 0x2000000) + +/************************************************************************/ + +/* + * Classes, objects, and properties. + */ + +/* For detailed comments on the function pointer types, see jspubtd.h. */ +struct JSClass { + const char *name; + uint32 flags; + + /* Mandatory non-null function pointer members. */ + JSPropertyOp addProperty; + JSPropertyOp delProperty; + JSPropertyOp getProperty; + JSPropertyOp setProperty; + JSEnumerateOp enumerate; + JSResolveOp resolve; + JSConvertOp convert; + JSFinalizeOp finalize; + + /* Optionally non-null members start here. */ + JSGetObjectOps getObjectOps; + JSCheckAccessOp checkAccess; + JSNative call; + JSNative construct; + JSXDRObjectOp xdrObject; + JSHasInstanceOp hasInstance; + JSMarkOp mark; + JSReserveSlotsOp reserveSlots; +}; + +struct JSExtendedClass { + JSClass base; + JSEqualityOp equality; + JSObjectOp outerObject; + JSObjectOp innerObject; + JSIteratorOp iteratorObject; + JSObjectOp wrappedObject; /* NB: infallible, null + returns are treated as + the original object */ + void (*reserved0)(void); + void (*reserved1)(void); + void (*reserved2)(void); +}; + +#define JSCLASS_HAS_PRIVATE (1<<0) /* objects have private slot */ +#define JSCLASS_NEW_ENUMERATE (1<<1) /* has JSNewEnumerateOp hook */ +#define JSCLASS_NEW_RESOLVE (1<<2) /* has JSNewResolveOp hook */ +#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) /* private is (nsISupports *) */ +#define JSCLASS_SHARE_ALL_PROPERTIES (1<<4) /* all properties are SHARED */ +#define JSCLASS_NEW_RESOLVE_GETS_START (1<<5) /* JSNewResolveOp gets starting + object in prototype chain + passed in via *objp in/out + parameter */ +#define JSCLASS_CONSTRUCT_PROTOTYPE (1<<6) /* call constructor on class + prototype */ +#define JSCLASS_DOCUMENT_OBSERVER (1<<7) /* DOM document observer */ + +/* + * To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or + * JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where + * n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1. + */ +#define JSCLASS_RESERVED_SLOTS_SHIFT 8 /* room for 8 flags below */ +#define JSCLASS_RESERVED_SLOTS_WIDTH 8 /* and 16 above this field */ +#define JSCLASS_RESERVED_SLOTS_MASK JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH) +#define JSCLASS_HAS_RESERVED_SLOTS(n) (((n) & JSCLASS_RESERVED_SLOTS_MASK) \ + << JSCLASS_RESERVED_SLOTS_SHIFT) +#define JSCLASS_RESERVED_SLOTS(clasp) (((clasp)->flags \ + >> JSCLASS_RESERVED_SLOTS_SHIFT) \ + & JSCLASS_RESERVED_SLOTS_MASK) + +#define JSCLASS_HIGH_FLAGS_SHIFT (JSCLASS_RESERVED_SLOTS_SHIFT + \ + JSCLASS_RESERVED_SLOTS_WIDTH) + +/* True if JSClass is really a JSExtendedClass. */ +#define JSCLASS_IS_EXTENDED (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0)) +#define JSCLASS_IS_ANONYMOUS (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1)) +#define JSCLASS_IS_GLOBAL (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2)) + +/* Indicates that JSClass.mark is a tracer with JSTraceOp type. */ +#define JSCLASS_MARK_IS_TRACE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3)) + +/* + * ECMA-262 requires that most constructors used internally create objects + * with "the original Foo.prototype value" as their [[Prototype]] (__proto__) + * member initial value. The "original ... value" verbiage is there because + * in ECMA-262, global properties naming class objects are read/write and + * deleteable, for the most part. + * + * Implementing this efficiently requires that global objects have classes + * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS won't break + * anything except the ECMA-262 "original prototype value" behavior, which was + * broken for years in SpiderMonkey. In other words, without these flags you + * get backward compatibility. + */ +#define JSCLASS_GLOBAL_FLAGS \ + (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSProto_LIMIT)) + +/* Fast access to the original value of each standard class's prototype. */ +#define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 8) +#define JSCLASS_CACHED_PROTO_WIDTH 8 +#define JSCLASS_CACHED_PROTO_MASK JS_BITMASK(JSCLASS_CACHED_PROTO_WIDTH) +#define JSCLASS_HAS_CACHED_PROTO(key) ((key) << JSCLASS_CACHED_PROTO_SHIFT) +#define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey) \ + (((clasp)->flags \ + >> JSCLASS_CACHED_PROTO_SHIFT) \ + & JSCLASS_CACHED_PROTO_MASK)) + +/* Initializer for unused members of statically initialized JSClass structs. */ +#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,0 +#define JSCLASS_NO_RESERVED_MEMBERS 0,0,0 + +/* For detailed comments on these function pointer types, see jspubtd.h. */ +struct JSObjectOps { + /* Mandatory non-null function pointer members. */ + JSNewObjectMapOp newObjectMap; + JSObjectMapOp destroyObjectMap; + JSLookupPropOp lookupProperty; + JSDefinePropOp defineProperty; + JSPropertyIdOp getProperty; + JSPropertyIdOp setProperty; + JSAttributesOp getAttributes; + JSAttributesOp setAttributes; + JSPropertyIdOp deleteProperty; + JSConvertOp defaultValue; + JSNewEnumerateOp enumerate; + JSCheckAccessIdOp checkAccess; + + /* Optionally non-null members start here. */ + JSObjectOp thisObject; + JSPropertyRefOp dropProperty; + JSNative call; + JSNative construct; + JSXDRObjectOp xdrObject; + JSHasInstanceOp hasInstance; + JSSetObjectSlotOp setProto; + JSSetObjectSlotOp setParent; + JSTraceOp trace; + JSFinalizeOp clear; + JSGetRequiredSlotOp getRequiredSlot; + JSSetRequiredSlotOp setRequiredSlot; +}; + +struct JSXMLObjectOps { + JSObjectOps base; + JSGetMethodOp getMethod; + JSSetMethodOp setMethod; + JSEnumerateValuesOp enumerateValues; + JSEqualityOp equality; + JSConcatenateOp concatenate; +}; + +/* + * Classes that expose JSObjectOps via a non-null getObjectOps class hook may + * derive a property structure from this struct, return a pointer to it from + * lookupProperty and defineProperty, and use the pointer to avoid rehashing + * in getAttributes and setAttributes. + * + * The jsid type contains either an int jsval (see JSVAL_IS_INT above), or an + * internal pointer that is opaque to users of this API, but which users may + * convert from and to a jsval using JS_ValueToId and JS_IdToValue. + */ +struct JSProperty { + jsid id; +}; + +struct JSIdArray { + jsint length; + jsid vector[1]; /* actually, length jsid words */ +}; + +extern JS_PUBLIC_API(void) +JS_DestroyIdArray(JSContext *cx, JSIdArray *ida); + +extern JS_PUBLIC_API(JSBool) +JS_ValueToId(JSContext *cx, jsval v, jsid *idp); + +extern JS_PUBLIC_API(JSBool) +JS_IdToValue(JSContext *cx, jsid id, jsval *vp); + +/* + * The magic XML namespace id is int-tagged, but not a valid integer jsval. + * Global object classes in embeddings that enable JS_HAS_XML_SUPPORT (E4X) + * should handle this id specially before converting id via JSVAL_TO_INT. + */ +#define JS_DEFAULT_XML_NAMESPACE_ID ((jsid) JSVAL_VOID) + +/* + * JSNewResolveOp flag bits. + */ +#define JSRESOLVE_QUALIFIED 0x01 /* resolve a qualified property id */ +#define JSRESOLVE_ASSIGNING 0x02 /* resolve on the left of assignment */ +#define JSRESOLVE_DETECTING 0x04 /* 'if (o.p)...' or '(o.p) ?...:...' */ +#define JSRESOLVE_DECLARING 0x08 /* var, const, or function prolog op */ +#define JSRESOLVE_CLASSNAME 0x10 /* class name used when constructing */ + +extern JS_PUBLIC_API(JSBool) +JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_EnumerateStub(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id); + +extern JS_PUBLIC_API(JSBool) +JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp); + +extern JS_PUBLIC_API(void) +JS_FinalizeStub(JSContext *cx, JSObject *obj); + +struct JSConstDoubleSpec { + jsdouble dval; + const char *name; + uint8 flags; + uint8 spare[3]; +}; + +/* + * To define an array element rather than a named property member, cast the + * element's index to (const char *) and initialize name with it, and set the + * JSPROP_INDEX bit in flags. + */ +struct JSPropertySpec { + const char *name; + int8 tinyid; + uint8 flags; + JSPropertyOp getter; + JSPropertyOp setter; +}; + +struct JSFunctionSpec { + const char *name; + JSNative call; + uint16 nargs; + uint16 flags; + + /* + * extra & 0xFFFF: Number of extra argument slots for local GC roots. + * If fast native, must be zero. + * extra >> 16: Reserved for future use (must be 0). + */ + uint32 extra; +}; + +/* + * Terminating sentinel initializer to put at the end of a JSFunctionSpec array + * that's passed to JS_DefineFunctions or JS_InitClass. + */ +#define JS_FS_END JS_FS(NULL,NULL,0,0,0) + +/* + * Initializer macro for a JSFunctionSpec array element. This is the original + * kind of native function specifier initializer. Use JS_FN ("fast native", see + * JSFastNative in jspubtd.h) for all functions that do not need a stack frame + * when activated. + */ +#define JS_FS(name,call,nargs,flags,extra) \ + {name, call, nargs, flags, extra} + +/* + * "Fast native" initializer macro for a JSFunctionSpec array element. Use this + * in preference to JS_FS if the native in question does not need its own stack + * frame when activated. + */ +#define JS_FN(name,fastcall,nargs,flags) \ + {name, (JSNative)(fastcall), nargs, \ + (flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS, 0} + +extern JS_PUBLIC_API(JSObject *) +JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, + JSClass *clasp, JSNative constructor, uintN nargs, + JSPropertySpec *ps, JSFunctionSpec *fs, + JSPropertySpec *static_ps, JSFunctionSpec *static_fs); + +#ifdef JS_THREADSAFE +extern JS_PUBLIC_API(JSClass *) +JS_GetClass(JSContext *cx, JSObject *obj); + +#define JS_GET_CLASS(cx,obj) JS_GetClass(cx, obj) +#else +extern JS_PUBLIC_API(JSClass *) +JS_GetClass(JSObject *obj); + +#define JS_GET_CLASS(cx,obj) JS_GetClass(obj) +#endif + +extern JS_PUBLIC_API(JSBool) +JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv); + +extern JS_PUBLIC_API(JSBool) +JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); + +extern JS_PUBLIC_API(void *) +JS_GetPrivate(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_SetPrivate(JSContext *cx, JSObject *obj, void *data); + +extern JS_PUBLIC_API(void *) +JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, + jsval *argv); + +extern JS_PUBLIC_API(JSObject *) +JS_GetPrototype(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto); + +extern JS_PUBLIC_API(JSObject *) +JS_GetParent(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent); + +extern JS_PUBLIC_API(JSObject *) +JS_GetConstructor(JSContext *cx, JSObject *proto); + +/* + * Get a unique identifier for obj, good for the lifetime of obj (even if it + * is moved by a copying GC). Return false on failure (likely out of memory), + * and true with *idp containing the unique id on success. + */ +extern JS_PUBLIC_API(JSBool) +JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp); + +extern JS_PUBLIC_API(JSObject *) +JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent); + +/* + * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default + * proto if proto's actual parameter value is null. + */ +extern JS_PUBLIC_API(JSObject *) +JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent); + +extern JS_PUBLIC_API(JSBool) +JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep); + +extern JS_PUBLIC_API(JSObject *) +JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent); + +extern JS_PUBLIC_API(JSObject *) +JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent, uintN argc, jsval *argv); + +extern JS_PUBLIC_API(JSObject *) +JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp, + JSObject *proto, uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds); + +extern JS_PUBLIC_API(JSBool) +JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps); + +extern JS_PUBLIC_API(JSBool) +JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs); + +/* + * Determine the attributes (JSPROP_* flags) of a property on a given object. + * + * If the object does not have a property by that name, *foundp will be + * JS_FALSE and the value of *attrsp is undefined. + */ +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name, + uintN *attrsp, JSBool *foundp); + +/* + * The same, but if the property is native, return its getter and setter via + * *getterp and *setterp, respectively (and only if the out parameter pointer + * is not null). + */ +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, + const char *name, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, + JSPropertyOp *setterp); + +/* + * Set the attributes of a property on a given object. + * + * If the object does not have a property by that name, *foundp will be + * JS_FALSE and nothing will be altered. + */ +extern JS_PUBLIC_API(JSBool) +JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name, + uintN attrs, JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, + int8 tinyid, jsval value, + JSPropertyOp getter, JSPropertyOp setter, + uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, + const char *alias); + +extern JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, + JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, + JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, + uintN flags, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, + uintN flags, JSObject **objp, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, + jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name); + +extern JS_PUBLIC_API(JSBool) +JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id); + +extern JS_PUBLIC_API(JSBool) +JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_DefineUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, jsval value, + JSPropertyOp getter, JSPropertyOp setter, + uintN attrs); + +/* + * Determine the attributes (JSPROP_* flags) of a property on a given object. + * + * If the object does not have a property by that name, *foundp will be + * JS_FALSE and the value of *attrsp is undefined. + */ +extern JS_PUBLIC_API(JSBool) +JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + uintN *attrsp, JSBool *foundp); + +/* + * The same, but if the property is native, return its getter and setter via + * *getterp and *setterp, respectively (and only if the out parameter pointer + * is not null). + */ +extern JS_PUBLIC_API(JSBool) +JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, + JSPropertyOp *setterp); + +/* + * Set the attributes of a property on a given object. + * + * If the object does not have a property by that name, *foundp will be + * JS_FALSE and nothing will be altered. + */ +extern JS_PUBLIC_API(JSBool) +JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + uintN attrs, JSBool *foundp); + + +extern JS_PUBLIC_API(JSBool) +JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + int8 tinyid, jsval value, + JSPropertyOp getter, JSPropertyOp setter, + uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, + size_t namelen, JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_HasUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + JSBool *vp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_SetUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *rval); + +extern JS_PUBLIC_API(JSObject *) +JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector); + +extern JS_PUBLIC_API(JSBool) +JS_IsArrayObject(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp); + +extern JS_PUBLIC_API(JSBool) +JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length); + +extern JS_PUBLIC_API(JSBool) +JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp); + +extern JS_PUBLIC_API(JSBool) +JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias); + +extern JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, + JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index); + +extern JS_PUBLIC_API(JSBool) +JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval); + +extern JS_PUBLIC_API(void) +JS_ClearScope(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSIdArray *) +JS_Enumerate(JSContext *cx, JSObject *obj); + +/* + * Create an object to iterate over enumerable properties of obj, in arbitrary + * property definition order. NB: This differs from longstanding for..in loop + * order, which uses order of property definition in obj. + */ +extern JS_PUBLIC_API(JSObject *) +JS_NewPropertyIterator(JSContext *cx, JSObject *obj); + +/* + * Return true on success with *idp containing the id of the next enumerable + * property to visit using iterobj, or JSVAL_VOID if there is no such property + * left to visit. Return false on error. + */ +extern JS_PUBLIC_API(JSBool) +JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp); + +extern JS_PUBLIC_API(JSBool) +JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + jsval *vp, uintN *attrsp); + +extern JS_PUBLIC_API(JSBool) +JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v); + +/************************************************************************/ + +/* + * Security protocol. + */ +struct JSPrincipals { + char *codebase; + + /* XXX unspecified and unused by Mozilla code -- can we remove these? */ + void * (* getPrincipalArray)(JSContext *cx, JSPrincipals *); + JSBool (* globalPrivilegesEnabled)(JSContext *cx, JSPrincipals *); + + /* Don't call "destroy"; use reference counting macros below. */ + jsrefcount refcount; + + void (* destroy)(JSContext *cx, JSPrincipals *); + JSBool (* subsume)(JSPrincipals *, JSPrincipals *); +}; + +#ifdef JS_THREADSAFE +#define JSPRINCIPALS_HOLD(cx, principals) JS_HoldPrincipals(cx,principals) +#define JSPRINCIPALS_DROP(cx, principals) JS_DropPrincipals(cx,principals) + +extern JS_PUBLIC_API(jsrefcount) +JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals); + +extern JS_PUBLIC_API(jsrefcount) +JS_DropPrincipals(JSContext *cx, JSPrincipals *principals); + +#else +#define JSPRINCIPALS_HOLD(cx, principals) (++(principals)->refcount) +#define JSPRINCIPALS_DROP(cx, principals) \ + ((--(principals)->refcount == 0) \ + ? ((*(principals)->destroy)((cx), (principals)), 0) \ + : (principals)->refcount) +#endif + + +struct JSSecurityCallbacks { + JSCheckAccessOp checkObjectAccess; + JSPrincipalsTranscoder principalsTranscoder; + JSObjectPrincipalsFinder findObjectPrincipals; +}; + +extern JS_PUBLIC_API(JSSecurityCallbacks *) +JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks); + +extern JS_PUBLIC_API(JSSecurityCallbacks *) +JS_GetRuntimeSecurityCallbacks(JSRuntime *rt); + +extern JS_PUBLIC_API(JSSecurityCallbacks *) +JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks); + +extern JS_PUBLIC_API(JSSecurityCallbacks *) +JS_GetSecurityCallbacks(JSContext *cx); + +/************************************************************************/ + +/* + * Functions and scripts. + */ +extern JS_PUBLIC_API(JSFunction *) +JS_NewFunction(JSContext *cx, JSNative call, uintN nargs, uintN flags, + JSObject *parent, const char *name); + +extern JS_PUBLIC_API(JSObject *) +JS_GetFunctionObject(JSFunction *fun); + +/* + * Deprecated, useful only for diagnostics. Use JS_GetFunctionId instead for + * anonymous vs. "anonymous" disambiguation and Unicode fidelity. + */ +extern JS_PUBLIC_API(const char *) +JS_GetFunctionName(JSFunction *fun); + +/* + * Return the function's identifier as a JSString, or null if fun is unnamed. + * The returned string lives as long as fun, so you don't need to root a saved + * reference to it if fun is well-connected or rooted, and provided you bound + * the use of the saved reference by fun's lifetime. + * + * Prefer JS_GetFunctionId over JS_GetFunctionName because it returns null for + * truly anonymous functions, and because it doesn't chop to ISO-Latin-1 chars + * from UTF-16-ish jschars. + */ +extern JS_PUBLIC_API(JSString *) +JS_GetFunctionId(JSFunction *fun); + +/* + * Return JSFUN_* flags for fun. + */ +extern JS_PUBLIC_API(uintN) +JS_GetFunctionFlags(JSFunction *fun); + +/* + * Return the arity (length) of fun. + */ +extern JS_PUBLIC_API(uint16) +JS_GetFunctionArity(JSFunction *fun); + +/* + * Infallible predicate to test whether obj is a function object (faster than + * comparing obj's class name to "Function", but equivalent unless someone has + * overwritten the "Function" identifier with a different constructor and then + * created instances using that constructor that might be passed in as obj). + */ +extern JS_PUBLIC_API(JSBool) +JS_ObjectIsFunction(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs); + +extern JS_PUBLIC_API(JSFunction *) +JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call, + uintN nargs, uintN attrs); + +extern JS_PUBLIC_API(JSFunction *) +JS_DefineUCFunction(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, JSNative call, + uintN nargs, uintN attrs); + +extern JS_PUBLIC_API(JSObject *) +JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent); + +/* + * Given a buffer, return JS_FALSE if the buffer might become a valid + * javascript statement with the addition of more lines. Otherwise return + * JS_TRUE. The intent is to support interactive compilation - accumulate + * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to + * the compiler. + */ +extern JS_PUBLIC_API(JSBool) +JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, + const char *bytes, size_t length); + +/* + * The JSScript objects returned by the following functions refer to string and + * other kinds of literals, including doubles and RegExp objects. These + * literals are vulnerable to garbage collection; to root script objects and + * prevent literals from being collected, create a rootable object using + * JS_NewScriptObject, and root the resulting object using JS_Add[Named]Root. + */ +extern JS_PUBLIC_API(JSScript *) +JS_CompileScript(JSContext *cx, JSObject *obj, + const char *bytes, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSScript *) +JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const char *bytes, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSScript *) +JS_CompileUCScript(JSContext *cx, JSObject *obj, + const jschar *chars, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSScript *) +JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSScript *) +JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename); + +extern JS_PUBLIC_API(JSScript *) +JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, + FILE *fh); + +extern JS_PUBLIC_API(JSScript *) +JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, + const char *filename, FILE *fh, + JSPrincipals *principals); + +/* + * NB: you must use JS_NewScriptObject and root a pointer to its return value + * in order to keep a JSScript and its atoms safe from garbage collection after + * creating the script via JS_Compile* and before a JS_ExecuteScript* call. + * E.g., and without error checks: + * + * JSScript *script = JS_CompileFile(cx, global, filename); + * JSObject *scrobj = JS_NewScriptObject(cx, script); + * JS_AddNamedRoot(cx, &scrobj, "scrobj"); + * do { + * jsval result; + * JS_ExecuteScript(cx, global, script, &result); + * JS_GC(); + * } while (!JSVAL_IS_BOOLEAN(result) || JSVAL_TO_BOOLEAN(result)); + * JS_RemoveRoot(cx, &scrobj); + */ +extern JS_PUBLIC_API(JSObject *) +JS_NewScriptObject(JSContext *cx, JSScript *script); + +/* + * Infallible getter for a script's object. If JS_NewScriptObject has not been + * called on script yet, the return value will be null. + */ +extern JS_PUBLIC_API(JSObject *) +JS_GetScriptObject(JSScript *script); + +extern JS_PUBLIC_API(void) +JS_DestroyScript(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(JSFunction *) +JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name, + uintN nargs, const char **argnames, + const char *bytes, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSFunction *) +JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const char *bytes, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSFunction *) +JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSFunction *) +JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSString *) +JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, + uintN indent); + +/* + * API extension: OR this into indent to avoid pretty-printing the decompiled + * source resulting from JS_DecompileFunction{,Body}. + */ +#define JS_DONT_PRETTY_PRINT ((uintN)0x8000) + +extern JS_PUBLIC_API(JSString *) +JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent); + +extern JS_PUBLIC_API(JSString *) +JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent); + +/* + * NB: JS_ExecuteScript, JS_ExecuteScriptPart, and the JS_Evaluate*Script* + * quadruplets all use the obj parameter as the initial scope chain header, + * the 'this' keyword value, and the variables object (ECMA parlance for where + * 'var' and 'function' bind names) of the execution context for script. + * + * Using obj as the variables object is problematic if obj's parent (which is + * the scope chain link; see JS_SetParent and JS_NewObject) is not null: in + * this case, variables created by 'var x = 0', e.g., go in obj, but variables + * created by assignment to an unbound id, 'x = 0', go in the last object on + * the scope chain linked by parent. + * + * ECMA calls that last scoping object the "global object", but note that many + * embeddings have several such objects. ECMA requires that "global code" be + * executed with the variables object equal to this global object. But these + * JS API entry points provide freedom to execute code against a "sub-global", + * i.e., a parented or scoped object, in which case the variables object will + * differ from the last object on the scope chain, resulting in confusing and + * non-ECMA explicit vs. implicit variable creation. + * + * Caveat embedders: unless you already depend on this buggy variables object + * binding behavior, you should call JS_SetOptions(cx, JSOPTION_VAROBJFIX) or + * JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_VAROBJFIX) -- the latter if + * someone may have set other options on cx already -- for each context in the + * application, if you pass parented objects as the obj parameter, or may ever + * pass such objects in the future. + * + * Why a runtime option? The alternative is to add six or so new API entry + * points with signatures matching the following six, and that doesn't seem + * worth the code bloat cost. Such new entry points would probably have less + * obvious names, too, so would not tend to be used. The JS_SetOption call, + * OTOH, can be more easily hacked into existing code that does not depend on + * the bug; such code can continue to use the familiar JS_EvaluateScript, + * etc., entry points. + */ +extern JS_PUBLIC_API(JSBool) +JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval); + +/* + * Execute either the function-defining prolog of a script, or the script's + * main body, but not both. + */ +typedef enum JSExecPart { JSEXEC_PROLOG, JSEXEC_MAIN } JSExecPart; + +extern JS_PUBLIC_API(JSBool) +JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script, + JSExecPart part, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateScript(JSContext *cx, JSObject *obj, + const char *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const char *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateUCScript(JSContext *cx, JSObject *obj, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, + jsval *argv, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, + jsval *argv, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, + jsval *argv, jsval *rval); + +/* + * The maximum value of the operation limit to pass to JS_SetOperationCallback + * and JS_SetOperationLimit. + */ +#define JS_MAX_OPERATION_LIMIT ((uint32) 0x7FFFFFFF) + +#define JS_OPERATION_WEIGHT_BASE 4096 + +/* + * Set the operation callback that the engine calls periodically after + * the internal operation count reaches the specified limit. + * + * When operationLimit is JS_OPERATION_WEIGHT_BASE, the callback will be + * called at least after each backward jump in the interpreter. To minimize + * the overhead of the callback invocation we suggest at least + * + * 100 * JS_OPERATION_WEIGHT_BASE + * + * as a value for operationLimit. + */ +extern JS_PUBLIC_API(void) +JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback, + uint32 operationLimit); + +extern JS_PUBLIC_API(void) +JS_ClearOperationCallback(JSContext *cx); + +extern JS_PUBLIC_API(JSOperationCallback) +JS_GetOperationCallback(JSContext *cx); + +/* + * Get the operation limit associated with the operation callback. This API + * function may be called only when the result of JS_GetOperationCallback(cx) + * is not null. + */ +extern JS_PUBLIC_API(uint32) +JS_GetOperationLimit(JSContext *cx); + +/* + * Change the operation limit associated with the operation callback. This API + * function may be called only when the result of JS_GetOperationCallback(cx) + * is not null. + */ +extern JS_PUBLIC_API(void) +JS_SetOperationLimit(JSContext *cx, uint32 operationLimit); + +/* + * Note well: JS_SetBranchCallback is deprecated. It is similar to + * + * JS_SetOperationCallback(cx, callback, 4096, NULL); + * + * except that the callback will not be called from a long-running native + * function when JSOPTION_NATIVE_BRANCH_CALLBACK is not set and the top-most + * frame is native. + */ +extern JS_PUBLIC_API(JSBranchCallback) +JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb); + +extern JS_PUBLIC_API(JSBool) +JS_IsRunning(JSContext *cx); + +extern JS_PUBLIC_API(JSBool) +JS_IsConstructing(JSContext *cx); + +/* + * Returns true if a script is executing and its current bytecode is a set + * (assignment) operation, even if there are native (no script) stack frames + * between the script and the caller to JS_IsAssigning. + */ +extern JS_FRIEND_API(JSBool) +JS_IsAssigning(JSContext *cx); + +/* + * Set the second return value, which should be a string or int jsval that + * identifies a property in the returned object, to form an ECMA reference + * type value (obj, id). Only native methods can return reference types, + * and if the returned value is used on the left-hand side of an assignment + * op, the identified property will be set. If the return value is in an + * r-value, the interpreter just gets obj[id]'s value. + */ +extern JS_PUBLIC_API(void) +JS_SetCallReturnValue2(JSContext *cx, jsval v); + +/* + * Saving and restoring frame chains. + * + * These two functions are used to set aside cx's call stack while that stack + * is inactive. After a call to JS_SaveFrameChain, it looks as if there is no + * code running on cx. Before calling JS_RestoreFrameChain, cx's call stack + * must be balanced and all nested calls to JS_SaveFrameChain must have had + * matching JS_RestoreFrameChain calls. + * + * JS_SaveFrameChain deals with cx not having any code running on it. A null + * return does not signify an error, and JS_RestoreFrameChain handles a null + * frame pointer argument safely. + */ +extern JS_PUBLIC_API(JSStackFrame *) +JS_SaveFrameChain(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp); + +/************************************************************************/ + +/* + * Strings. + * + * NB: JS_NewString takes ownership of bytes on success, avoiding a copy; but + * on error (signified by null return), it leaves bytes owned by the caller. + * So the caller must free bytes in the error case, if it has no use for them. + * In contrast, all the JS_New*StringCopy* functions do not take ownership of + * the character memory passed to them -- they copy it. + */ +extern JS_PUBLIC_API(JSString *) +JS_NewString(JSContext *cx, char *bytes, size_t length); + +extern JS_PUBLIC_API(JSString *) +JS_NewStringCopyN(JSContext *cx, const char *s, size_t n); + +extern JS_PUBLIC_API(JSString *) +JS_NewStringCopyZ(JSContext *cx, const char *s); + +extern JS_PUBLIC_API(JSString *) +JS_InternString(JSContext *cx, const char *s); + +extern JS_PUBLIC_API(JSString *) +JS_NewUCString(JSContext *cx, jschar *chars, size_t length); + +extern JS_PUBLIC_API(JSString *) +JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n); + +extern JS_PUBLIC_API(JSString *) +JS_NewUCStringCopyZ(JSContext *cx, const jschar *s); + +extern JS_PUBLIC_API(JSString *) +JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length); + +extern JS_PUBLIC_API(JSString *) +JS_InternUCString(JSContext *cx, const jschar *s); + +extern JS_PUBLIC_API(char *) +JS_GetStringBytes(JSString *str); + +extern JS_PUBLIC_API(jschar *) +JS_GetStringChars(JSString *str); + +extern JS_PUBLIC_API(size_t) +JS_GetStringLength(JSString *str); + +extern JS_PUBLIC_API(intN) +JS_CompareStrings(JSString *str1, JSString *str2); + +/* + * Mutable string support. A string's characters are never mutable in this JS + * implementation, but a growable string has a buffer that can be reallocated, + * and a dependent string is a substring of another (growable, dependent, or + * immutable) string. The direct data members of the (opaque to API clients) + * JSString struct may be changed in a single-threaded way for growable and + * dependent strings. + * + * Therefore mutable strings cannot be used by more than one thread at a time. + * You may call JS_MakeStringImmutable to convert the string from a mutable + * (growable or dependent) string to an immutable (and therefore thread-safe) + * string. The engine takes care of converting growable and dependent strings + * to immutable for you if you store strings in multi-threaded objects using + * JS_SetProperty or kindred API entry points. + * + * If you store a JSString pointer in a native data structure that is (safely) + * accessible to multiple threads, you must call JS_MakeStringImmutable before + * retiring the store. + */ +extern JS_PUBLIC_API(JSString *) +JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length); + +/* + * Create a dependent string, i.e., a string that owns no character storage, + * but that refers to a slice of another string's chars. Dependent strings + * are mutable by definition, so the thread safety comments above apply. + */ +extern JS_PUBLIC_API(JSString *) +JS_NewDependentString(JSContext *cx, JSString *str, size_t start, + size_t length); + +/* + * Concatenate two strings, resulting in a new growable string. If you create + * the left string and pass it to JS_ConcatStrings on a single thread, try to + * use JS_NewGrowableString to create the left string -- doing so helps Concat + * avoid allocating a new buffer for the result and copying left's chars into + * the new buffer. See above for thread safety comments. + */ +extern JS_PUBLIC_API(JSString *) +JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right); + +/* + * Convert a dependent string into an independent one. This function does not + * change the string's mutability, so the thread safety comments above apply. + */ +extern JS_PUBLIC_API(const jschar *) +JS_UndependString(JSContext *cx, JSString *str); + +/* + * Convert a mutable string (either growable or dependent) into an immutable, + * thread-safe one. + */ +extern JS_PUBLIC_API(JSBool) +JS_MakeStringImmutable(JSContext *cx, JSString *str); + +/* + * Return JS_TRUE if C (char []) strings passed via the API and internally + * are UTF-8. + */ +JS_PUBLIC_API(JSBool) +JS_CStringsAreUTF8(void); + +/* + * Update the value to be returned by JS_CStringsAreUTF8(). Once set, it + * can never be changed. This API must be called before the first call to + * JS_NewRuntime. + */ +JS_PUBLIC_API(void) +JS_SetCStringsAreUTF8(void); + +/* + * Character encoding support. + * + * For both JS_EncodeCharacters and JS_DecodeBytes, set *dstlenp to the size + * of the destination buffer before the call; on return, *dstlenp contains the + * number of bytes (JS_EncodeCharacters) or jschars (JS_DecodeBytes) actually + * stored. To determine the necessary destination buffer size, make a sizing + * call that passes NULL for dst. + * + * On errors, the functions report the error. In that case, *dstlenp contains + * the number of characters or bytes transferred so far. If cx is NULL, no + * error is reported on failure, and the functions simply return JS_FALSE. + * + * NB: Neither function stores an additional zero byte or jschar after the + * transcoded string. + * + * If JS_CStringsAreUTF8() is true then JS_EncodeCharacters encodes to + * UTF-8, and JS_DecodeBytes decodes from UTF-8, which may create additional + * errors if the character sequence is malformed. If UTF-8 support is + * disabled, the functions deflate and inflate, respectively. + */ +JS_PUBLIC_API(JSBool) +JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, + size_t *dstlenp); + +JS_PUBLIC_API(JSBool) +JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, + size_t *dstlenp); + +/* + * A variation on JS_EncodeCharacters where a null terminated string is + * returned that you are expected to call JS_free on when done. + */ +JS_PUBLIC_API(char *) +JS_EncodeString(JSContext *cx, JSString *str); + +/************************************************************************/ +/* + * JSON functions + */ +typedef JSBool (* JSONWriteCallback)(const jschar *buf, uint32 len, void *data); + +/* + * JSON.stringify as specificed by ES3.1 (draft) + */ +JS_PUBLIC_API(JSBool) +JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, + JSONWriteCallback callback, void *data); + +/* + * Retrieve a toJSON function. If found, set vp to its result. + */ +JS_PUBLIC_API(JSBool) +JS_TryJSON(JSContext *cx, jsval *vp); + +/* + * JSON.parse as specificed by ES3.1 (draft) + */ +JS_PUBLIC_API(JSONParser *) +JS_BeginJSONParse(JSContext *cx, jsval *vp); + +JS_PUBLIC_API(JSBool) +JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len); + +JS_PUBLIC_API(JSBool) +JS_FinishJSONParse(JSContext *cx, JSONParser *jp); + +/************************************************************************/ + +/* + * Locale specific string conversion and error message callbacks. + */ +struct JSLocaleCallbacks { + JSLocaleToUpperCase localeToUpperCase; + JSLocaleToLowerCase localeToLowerCase; + JSLocaleCompare localeCompare; + JSLocaleToUnicode localeToUnicode; + JSErrorCallback localeGetErrorMessage; +}; + +/* + * Establish locale callbacks. The pointer must persist as long as the + * JSContext. Passing NULL restores the default behaviour. + */ +extern JS_PUBLIC_API(void) +JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks); + +/* + * Return the address of the current locale callbacks struct, which may + * be NULL. + */ +extern JS_PUBLIC_API(JSLocaleCallbacks *) +JS_GetLocaleCallbacks(JSContext *cx); + +/************************************************************************/ + +/* + * Error reporting. + */ + +/* + * Report an exception represented by the sprintf-like conversion of format + * and its arguments. This exception message string is passed to a pre-set + * JSErrorReporter function (set by JS_SetErrorReporter; see jspubtd.h for + * the JSErrorReporter typedef). + */ +extern JS_PUBLIC_API(void) +JS_ReportError(JSContext *cx, const char *format, ...); + +/* + * Use an errorNumber to retrieve the format string, args are char * + */ +extern JS_PUBLIC_API(void) +JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback, + void *userRef, const uintN errorNumber, ...); + +/* + * Use an errorNumber to retrieve the format string, args are jschar * + */ +extern JS_PUBLIC_API(void) +JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback, + void *userRef, const uintN errorNumber, ...); + +/* + * As above, but report a warning instead (JSREPORT_IS_WARNING(report.flags)). + * Return true if there was no error trying to issue the warning, and if the + * warning was not converted into an error due to the JSOPTION_WERROR option + * being set, false otherwise. + */ +extern JS_PUBLIC_API(JSBool) +JS_ReportWarning(JSContext *cx, const char *format, ...); + +extern JS_PUBLIC_API(JSBool) +JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags, + JSErrorCallback errorCallback, void *userRef, + const uintN errorNumber, ...); + +extern JS_PUBLIC_API(JSBool) +JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags, + JSErrorCallback errorCallback, void *userRef, + const uintN errorNumber, ...); + +/* + * Complain when out of memory. + */ +extern JS_PUBLIC_API(void) +JS_ReportOutOfMemory(JSContext *cx); + +/* + * Complain when an allocation size overflows the maximum supported limit. + */ +extern JS_PUBLIC_API(void) +JS_ReportAllocationOverflow(JSContext *cx); + +struct JSErrorReport { + const char *filename; /* source file name, URL, etc., or null */ + uintN lineno; /* source line number */ + const char *linebuf; /* offending source line without final \n */ + const char *tokenptr; /* pointer to error token in linebuf */ + const jschar *uclinebuf; /* unicode (original) line buffer */ + const jschar *uctokenptr; /* unicode (original) token pointer */ + uintN flags; /* error/warning, etc. */ + uintN errorNumber; /* the error number, e.g. see js.msg */ + const jschar *ucmessage; /* the (default) error message */ + const jschar **messageArgs; /* arguments for the error message */ +}; + +/* + * JSErrorReport flag values. These may be freely composed. + */ +#define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */ +#define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */ +#define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ +#define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ + +/* + * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception + * has been thrown for this runtime error, and the host should ignore it. + * Exception-aware hosts should also check for JS_IsExceptionPending if + * JS_ExecuteScript returns failure, and signal or propagate the exception, as + * appropriate. + */ +#define JSREPORT_IS_WARNING(flags) (((flags) & JSREPORT_WARNING) != 0) +#define JSREPORT_IS_EXCEPTION(flags) (((flags) & JSREPORT_EXCEPTION) != 0) +#define JSREPORT_IS_STRICT(flags) (((flags) & JSREPORT_STRICT) != 0) + +extern JS_PUBLIC_API(JSErrorReporter) +JS_SetErrorReporter(JSContext *cx, JSErrorReporter er); + +/************************************************************************/ + +/* + * Regular Expressions. + */ +#define JSREG_FOLD 0x01 /* fold uppercase to lowercase */ +#define JSREG_GLOB 0x02 /* global exec, creates array of matches */ +#define JSREG_MULTILINE 0x04 /* treat ^ and $ as begin and end of line */ +#define JSREG_STICKY 0x08 /* only match starting at lastIndex */ + +extern JS_PUBLIC_API(JSObject *) +JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags); + +extern JS_PUBLIC_API(JSObject *) +JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags); + +extern JS_PUBLIC_API(void) +JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline); + +extern JS_PUBLIC_API(void) +JS_ClearRegExpStatics(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_ClearRegExpRoots(JSContext *cx); + +/* TODO: compile, exec, get/set other statics... */ + +/************************************************************************/ + +extern JS_PUBLIC_API(JSBool) +JS_IsExceptionPending(JSContext *cx); + +extern JS_PUBLIC_API(JSBool) +JS_GetPendingException(JSContext *cx, jsval *vp); + +extern JS_PUBLIC_API(void) +JS_SetPendingException(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(void) +JS_ClearPendingException(JSContext *cx); + +extern JS_PUBLIC_API(JSBool) +JS_ReportPendingException(JSContext *cx); + +/* + * Save the current exception state. This takes a snapshot of cx's current + * exception state without making any change to that state. + * + * The returned state pointer MUST be passed later to JS_RestoreExceptionState + * (to restore that saved state, overriding any more recent state) or else to + * JS_DropExceptionState (to free the state struct in case it is not correct + * or desirable to restore it). Both Restore and Drop free the state struct, + * so callers must stop using the pointer returned from Save after calling the + * Release or Drop API. + */ +extern JS_PUBLIC_API(JSExceptionState *) +JS_SaveExceptionState(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state); + +extern JS_PUBLIC_API(void) +JS_DropExceptionState(JSContext *cx, JSExceptionState *state); + +/* + * If the given value is an exception object that originated from an error, + * the exception will contain an error report struct, and this API will return + * the address of that struct. Otherwise, it returns NULL. The lifetime of + * the error report struct that might be returned is the same as the lifetime + * of the exception object. + */ +extern JS_PUBLIC_API(JSErrorReport *) +JS_ErrorFromException(JSContext *cx, jsval v); + +/* + * Given a reported error's message and JSErrorReport struct pointer, throw + * the corresponding exception on cx. + */ +extern JS_PUBLIC_API(JSBool) +JS_ThrowReportedError(JSContext *cx, const char *message, + JSErrorReport *reportp); + +/* + * Throws a StopIteration exception on cx. + */ +extern JS_PUBLIC_API(JSBool) +JS_ThrowStopIteration(JSContext *cx); + +/* + * Associate the current thread with the given context. This is done + * implicitly by JS_NewContext. + * + * Returns the old thread id for this context, which should be treated as + * an opaque value. This value is provided for comparison to 0, which + * indicates that ClearContextThread has been called on this context + * since the last SetContextThread, or non-0, which indicates the opposite. + */ +extern JS_PUBLIC_API(jsword) +JS_GetContextThread(JSContext *cx); + +extern JS_PUBLIC_API(jsword) +JS_SetContextThread(JSContext *cx); + +extern JS_PUBLIC_API(jsword) +JS_ClearContextThread(JSContext *cx); + +/************************************************************************/ + +#ifdef DEBUG +#define JS_GC_ZEAL 1 +#endif + +#ifdef JS_GC_ZEAL +extern JS_PUBLIC_API(void) +JS_SetGCZeal(JSContext *cx, uint8 zeal); +#endif + +JS_END_EXTERN_C + +#endif /* jsapi_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarena.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarena.cpp new file mode 100644 index 0000000..f632552 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarena.cpp @@ -0,0 +1,450 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Lifetime-based fast allocation, inspired by much prior art, including + * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" + * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). + */ +#include "jsstddef.h" +#include +#include +#include "jstypes.h" +#include "jsbit.h" +#include "jsarena.h" /* Added by JSIFY */ +#include "jsutil.h" /* Added by JSIFY */ + +#ifdef JS_ARENAMETER +static JSArenaStats *arena_stats_list; + +#define COUNT(pool,what) (pool)->stats.what++ +#else +#define COUNT(pool,what) /* nothing */ +#endif + +#define JS_ARENA_DEFAULT_ALIGN sizeof(double) + +JS_PUBLIC_API(void) +JS_INIT_NAMED_ARENA_POOL(JSArenaPool *pool, const char *name, size_t size, + size_t align, size_t *quotap) +{ + if (align == 0) + align = JS_ARENA_DEFAULT_ALIGN; + pool->mask = JS_BITMASK(JS_CeilingLog2(align)); + pool->first.next = NULL; + pool->first.base = pool->first.avail = pool->first.limit = + JS_ARENA_ALIGN(pool, &pool->first + 1); + pool->current = &pool->first; + pool->arenasize = size; + pool->quotap = quotap; +#ifdef JS_ARENAMETER + memset(&pool->stats, 0, sizeof pool->stats); + pool->stats.name = strdup(name); + pool->stats.next = arena_stats_list; + arena_stats_list = &pool->stats; +#endif +} + +/* + * An allocation that consumes more than pool->arenasize also has a header + * pointing back to its previous arena's next member. This header is not + * included in [a->base, a->limit), so its space can't be wrongly claimed. + * + * As the header is a pointer, it must be well-aligned. If pool->mask is + * greater than or equal to POINTER_MASK, the header just preceding a->base + * for an oversized arena a is well-aligned, because a->base is well-aligned. + * However, we may need to add more space to pad the JSArena ** back-pointer + * so that it lies just behind a->base, because a might not be aligned such + * that (jsuword)(a + 1) is on a pointer boundary. + * + * By how much must we pad? Let M be the alignment modulus for pool and P + * the modulus for a pointer. Given M >= P, the base of an oversized arena + * that satisfies M is well-aligned for P. + * + * On the other hand, if M < P, we must include enough space in the header + * size to align the back-pointer on a P boundary so that it can be found by + * subtracting P from a->base. This means a->base must be on a P boundary, + * even though subsequent allocations from a may be aligned on a lesser (M) + * boundary. Given powers of two M and P as above, the extra space needed + * when M < P is P-M or POINTER_MASK - pool->mask. + * + * The size of a header including padding is given by the HEADER_SIZE macro, + * below, for any pool (for any value of M). + * + * The mask to align a->base for any pool is (pool->mask | POINTER_MASK), or + * HEADER_BASE_MASK(pool). + * + * PTR_TO_HEADER computes the address of the back-pointer, given an oversized + * allocation at p. By definition, p must be a->base for the arena a that + * contains p. GET_HEADER and SET_HEADER operate on an oversized arena a, in + * the case of SET_HEADER with back-pointer ap. + */ +#define POINTER_MASK ((jsuword)(JS_ALIGN_OF_POINTER - 1)) +#define HEADER_SIZE(pool) (sizeof(JSArena **) \ + + (((pool)->mask < POINTER_MASK) \ + ? POINTER_MASK - (pool)->mask \ + : 0)) +#define HEADER_BASE_MASK(pool) ((pool)->mask | POINTER_MASK) +#define PTR_TO_HEADER(pool,p) (JS_ASSERT(((jsuword)(p) \ + & HEADER_BASE_MASK(pool)) \ + == 0), \ + (JSArena ***)(p) - 1) +#define GET_HEADER(pool,a) (*PTR_TO_HEADER(pool, (a)->base)) +#define SET_HEADER(pool,a,ap) (*PTR_TO_HEADER(pool, (a)->base) = (ap)) + +JS_PUBLIC_API(void *) +JS_ArenaAllocate(JSArenaPool *pool, size_t nb) +{ + JSArena **ap, *a, *b; + jsuword extra, hdrsz, gross; + void *p; + + /* + * Search pool from current forward till we find or make enough space. + * + * NB: subtract nb from a->limit in the loop condition, instead of adding + * nb to a->avail, to avoid overflowing a 32-bit address space (possible + * when running a 32-bit program on a 64-bit system where the kernel maps + * the heap up against the top of the 32-bit address space). + * + * Thanks to Juergen Kreileder , who brought this up in + * https://bugzilla.mozilla.org/show_bug.cgi?id=279273. + */ + JS_ASSERT((nb & pool->mask) == 0); + for (a = pool->current; nb > a->limit || a->avail > a->limit - nb; + pool->current = a) { + ap = &a->next; + if (!*ap) { + /* Not enough space in pool, so we must malloc. */ + extra = (nb > pool->arenasize) ? HEADER_SIZE(pool) : 0; + hdrsz = sizeof *a + extra + pool->mask; + gross = hdrsz + JS_MAX(nb, pool->arenasize); + if (gross < nb) + return NULL; + if (pool->quotap) { + if (gross > *pool->quotap) + return NULL; + b = (JSArena *) malloc(gross); + if (!b) + return NULL; + *pool->quotap -= gross; + } else { + b = (JSArena *) malloc(gross); + if (!b) + return NULL; + } + + b->next = NULL; + b->limit = (jsuword)b + gross; + JS_COUNT_ARENA(pool,++); + COUNT(pool, nmallocs); + + /* If oversized, store ap in the header, just before a->base. */ + *ap = a = b; + JS_ASSERT(gross <= JS_UPTRDIFF(a->limit, a)); + if (extra) { + a->base = a->avail = + ((jsuword)a + hdrsz) & ~HEADER_BASE_MASK(pool); + SET_HEADER(pool, a, ap); + } else { + a->base = a->avail = JS_ARENA_ALIGN(pool, a + 1); + } + continue; + } + a = *ap; /* move to next arena */ + } + + p = (void *)a->avail; + a->avail += nb; + JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); + return p; +} + +JS_PUBLIC_API(void *) +JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr) +{ + JSArena **ap, *a, *b; + jsuword boff, aoff, extra, hdrsz, gross, growth; + + /* + * Use the oversized-single-allocation header to avoid searching for ap. + * See JS_ArenaAllocate, the SET_HEADER call. + */ + if (size > pool->arenasize) { + ap = *PTR_TO_HEADER(pool, p); + a = *ap; + } else { + ap = &pool->first.next; + while ((a = *ap) != pool->current) + ap = &a->next; + } + + JS_ASSERT(a->base == (jsuword)p); + boff = JS_UPTRDIFF(a->base, a); + aoff = JS_ARENA_ALIGN(pool, size + incr); + JS_ASSERT(aoff > pool->arenasize); + extra = HEADER_SIZE(pool); /* oversized header holds ap */ + hdrsz = sizeof *a + extra + pool->mask; /* header and alignment slop */ + gross = hdrsz + aoff; + JS_ASSERT(gross > aoff); + if (pool->quotap) { + growth = gross - (a->limit - (jsuword) a); + if (growth > *pool->quotap) + return NULL; + a = (JSArena *) realloc(a, gross); + if (!a) + return NULL; + *pool->quotap -= growth; + } else { + a = (JSArena *) realloc(a, gross); + if (!a) + return NULL; + } +#ifdef JS_ARENAMETER + pool->stats.nreallocs++; +#endif + + if (a != *ap) { + /* Oops, realloc moved the allocation: update other pointers to a. */ + if (pool->current == *ap) + pool->current = a; + b = a->next; + if (b && b->avail - b->base > pool->arenasize) { + JS_ASSERT(GET_HEADER(pool, b) == &(*ap)->next); + SET_HEADER(pool, b, &a->next); + } + + /* Now update *ap, the next link of the arena before a. */ + *ap = a; + } + + a->base = ((jsuword)a + hdrsz) & ~HEADER_BASE_MASK(pool); + a->limit = (jsuword)a + gross; + a->avail = a->base + aoff; + JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); + + /* Check whether realloc aligned differently, and copy if necessary. */ + if (boff != JS_UPTRDIFF(a->base, a)) + memmove((void *)a->base, (char *)a + boff, size); + + /* Store ap in the oversized-load arena header. */ + SET_HEADER(pool, a, ap); + return (void *)a->base; +} + +JS_PUBLIC_API(void *) +JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr) +{ + void *newp; + + /* + * If p points to an oversized allocation, it owns an entire arena, so we + * can simply realloc the arena. + */ + if (size > pool->arenasize) + return JS_ArenaRealloc(pool, p, size, incr); + + JS_ARENA_ALLOCATE(newp, pool, size + incr); + if (newp) + memcpy(newp, p, size); + return newp; +} + +/* + * Free tail arenas linked after head, which may not be the true list head. + * Reset pool->current to point to head in case it pointed at a tail arena. + */ +static void +FreeArenaList(JSArenaPool *pool, JSArena *head) +{ + JSArena **ap, *a; + + ap = &head->next; + a = *ap; + if (!a) + return; + +#ifdef DEBUG + do { + JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); + a->avail = a->base; + JS_CLEAR_UNUSED(a); + } while ((a = a->next) != NULL); + a = *ap; +#endif + + do { + *ap = a->next; + if (pool->quotap) + *pool->quotap += a->limit - (jsuword) a; + JS_CLEAR_ARENA(a); + JS_COUNT_ARENA(pool,--); + free(a); + } while ((a = *ap) != NULL); + + pool->current = head; +} + +JS_PUBLIC_API(void) +JS_ArenaRelease(JSArenaPool *pool, char *mark) +{ + JSArena *a; + + for (a = &pool->first; a; a = a->next) { + JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); + + if (JS_ARENA_MARK_MATCH(a, mark)) { + a->avail = JS_ARENA_ALIGN(pool, mark); + JS_ASSERT(a->avail <= a->limit); + FreeArenaList(pool, a); + return; + } + } +} + +JS_PUBLIC_API(void) +JS_FreeArenaPool(JSArenaPool *pool) +{ + FreeArenaList(pool, &pool->first); + COUNT(pool, ndeallocs); +} + +JS_PUBLIC_API(void) +JS_FinishArenaPool(JSArenaPool *pool) +{ + FreeArenaList(pool, &pool->first); +#ifdef JS_ARENAMETER + { + JSArenaStats *stats, **statsp; + + if (pool->stats.name) { + free(pool->stats.name); + pool->stats.name = NULL; + } + for (statsp = &arena_stats_list; (stats = *statsp) != 0; + statsp = &stats->next) { + if (stats == &pool->stats) { + *statsp = stats->next; + return; + } + } + } +#endif +} + +JS_PUBLIC_API(void) +JS_ArenaFinish() +{ +} + +JS_PUBLIC_API(void) +JS_ArenaShutDown(void) +{ +} + +#ifdef JS_ARENAMETER +JS_PUBLIC_API(void) +JS_ArenaCountAllocation(JSArenaPool *pool, size_t nb) +{ + pool->stats.nallocs++; + pool->stats.nbytes += nb; + if (nb > pool->stats.maxalloc) + pool->stats.maxalloc = nb; + pool->stats.variance += nb * nb; +} + +JS_PUBLIC_API(void) +JS_ArenaCountInplaceGrowth(JSArenaPool *pool, size_t size, size_t incr) +{ + pool->stats.ninplace++; +} + +JS_PUBLIC_API(void) +JS_ArenaCountGrowth(JSArenaPool *pool, size_t size, size_t incr) +{ + pool->stats.ngrows++; + pool->stats.nbytes += incr; + pool->stats.variance -= size * size; + size += incr; + if (size > pool->stats.maxalloc) + pool->stats.maxalloc = size; + pool->stats.variance += size * size; +} + +JS_PUBLIC_API(void) +JS_ArenaCountRelease(JSArenaPool *pool, char *mark) +{ + pool->stats.nreleases++; +} + +JS_PUBLIC_API(void) +JS_ArenaCountRetract(JSArenaPool *pool, char *mark) +{ + pool->stats.nfastrels++; +} + +#include + +JS_PUBLIC_API(void) +JS_DumpArenaStats(FILE *fp) +{ + JSArenaStats *stats; + double mean, sigma; + + for (stats = arena_stats_list; stats; stats = stats->next) { + mean = JS_MeanAndStdDev(stats->nallocs, stats->nbytes, stats->variance, + &sigma); + + fprintf(fp, "\n%s allocation statistics:\n", stats->name); + fprintf(fp, " number of arenas: %u\n", stats->narenas); + fprintf(fp, " number of allocations: %u\n", stats->nallocs); + fprintf(fp, " number of malloc calls: %u\n", stats->nmallocs); + fprintf(fp, " number of deallocations: %u\n", stats->ndeallocs); + fprintf(fp, " number of allocation growths: %u\n", stats->ngrows); + fprintf(fp, " number of in-place growths: %u\n", stats->ninplace); + fprintf(fp, " number of realloc'ing growths: %u\n", stats->nreallocs); + fprintf(fp, "number of released allocations: %u\n", stats->nreleases); + fprintf(fp, " number of fast releases: %u\n", stats->nfastrels); + fprintf(fp, " total bytes allocated: %u\n", stats->nbytes); + fprintf(fp, " mean allocation size: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sigma); + fprintf(fp, " maximum allocation size: %u\n", stats->maxalloc); + } +} +#endif /* JS_ARENAMETER */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarena.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarena.h new file mode 100644 index 0000000..8e99a74 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarena.h @@ -0,0 +1,318 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsarena_h___ +#define jsarena_h___ +/* + * Lifetime-based fast allocation, inspired by much prior art, including + * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" + * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). + * + * Also supports LIFO allocation (JS_ARENA_MARK/JS_ARENA_RELEASE). + */ +#include +#include "jstypes.h" +#include "jscompat.h" + +JS_BEGIN_EXTERN_C + +typedef struct JSArena JSArena; +typedef struct JSArenaPool JSArenaPool; + +struct JSArena { + JSArena *next; /* next arena for this lifetime */ + jsuword base; /* aligned base address, follows this header */ + jsuword limit; /* one beyond last byte in arena */ + jsuword avail; /* points to next available byte */ +}; + +#ifdef JS_ARENAMETER +typedef struct JSArenaStats JSArenaStats; + +struct JSArenaStats { + JSArenaStats *next; /* next in arenaStats list */ + char *name; /* name for debugging */ + uint32 narenas; /* number of arenas in pool */ + uint32 nallocs; /* number of JS_ARENA_ALLOCATE() calls */ + uint32 nmallocs; /* number of malloc() calls */ + uint32 ndeallocs; /* number of lifetime deallocations */ + uint32 ngrows; /* number of JS_ARENA_GROW() calls */ + uint32 ninplace; /* number of in-place growths */ + uint32 nreallocs; /* number of arena grow extending reallocs */ + uint32 nreleases; /* number of JS_ARENA_RELEASE() calls */ + uint32 nfastrels; /* number of "fast path" releases */ + size_t nbytes; /* total bytes allocated */ + size_t maxalloc; /* maximum allocation size in bytes */ + double variance; /* size variance accumulator */ +}; +#endif + +struct JSArenaPool { + JSArena first; /* first arena in pool list */ + JSArena *current; /* arena from which to allocate space */ + size_t arenasize; /* net exact size of a new arena */ + jsuword mask; /* alignment mask (power-of-2 - 1) */ + size_t *quotap; /* pointer to the quota on pool allocation + size or null if pool is unlimited */ +#ifdef JS_ARENAMETER + JSArenaStats stats; +#endif +}; + +#ifdef JS_ARENAMETER +#define JS_INIT_NAMED_ARENA_POOL(pool, name, size, align, quotap) \ + JS_InitArenaPool(pool, name, size, align, quotap) +#else +#define JS_INIT_NAMED_ARENA_POOL(pool, name, size, align, quotap) \ + JS_InitArenaPool(pool, size, align, quotap) +#endif + +/* + * If the including .c file uses only one power-of-2 alignment, it may define + * JS_ARENA_CONST_ALIGN_MASK to the alignment mask and save a few instructions + * per ALLOCATE and GROW. + */ +#ifdef JS_ARENA_CONST_ALIGN_MASK +#define JS_ARENA_ALIGN(pool, n) (((jsuword)(n) + JS_ARENA_CONST_ALIGN_MASK) \ + & ~(jsuword)JS_ARENA_CONST_ALIGN_MASK) + +#define JS_INIT_ARENA_POOL(pool, name, size, quotap) \ + JS_INIT_NAMED_ARENA_POOL(pool, name, size, JS_ARENA_CONST_ALIGN_MASK + 1, \ + quotap) + +#else +#define JS_ARENA_ALIGN(pool, n) (((jsuword)(n) + (pool)->mask) & ~(pool)->mask) + +#define JS_INIT_ARENA_POOL(pool, name, size, align, quotap) \ + JS_INIT_NAMED_ARENA_POOL(pool, name, size, align, quotap) + +#endif + +#define JS_ARENA_ALLOCATE(p, pool, nb) \ + JS_ARENA_ALLOCATE_CAST(p, void *, pool, nb) + +#define JS_ARENA_ALLOCATE_TYPE(p, type, pool) \ + JS_ARENA_ALLOCATE_COMMON(p, type *, pool, sizeof(type), 0) + +#define JS_ARENA_ALLOCATE_CAST(p, type, pool, nb) \ + JS_ARENA_ALLOCATE_COMMON(p, type, pool, nb, _nb > _a->limit) + +/* + * NB: In JS_ARENA_ALLOCATE_CAST and JS_ARENA_GROW_CAST, always subtract _nb + * from a->limit rather than adding _nb to _p, to avoid overflowing a 32-bit + * address space (possible when running a 32-bit program on a 64-bit system + * where the kernel maps the heap up against the top of the 32-bit address + * space). + * + * Thanks to Juergen Kreileder , who brought this up in + * https://bugzilla.mozilla.org/show_bug.cgi?id=279273. + */ +#define JS_ARENA_ALLOCATE_COMMON(p, type, pool, nb, guard) \ + JS_BEGIN_MACRO \ + JSArena *_a = (pool)->current; \ + size_t _nb = JS_ARENA_ALIGN(pool, nb); \ + jsuword _p = _a->avail; \ + if ((guard) || _p > _a->limit - _nb) \ + _p = (jsuword)JS_ArenaAllocate(pool, _nb); \ + else \ + _a->avail = _p + _nb; \ + p = (type) _p; \ + JS_ArenaCountAllocation(pool, nb); \ + JS_END_MACRO + +#define JS_ARENA_GROW(p, pool, size, incr) \ + JS_ARENA_GROW_CAST(p, void *, pool, size, incr) + +#define JS_ARENA_GROW_CAST(p, type, pool, size, incr) \ + JS_BEGIN_MACRO \ + JSArena *_a = (pool)->current; \ + if (_a->avail == (jsuword)(p) + JS_ARENA_ALIGN(pool, size)) { \ + size_t _nb = (size) + (incr); \ + _nb = JS_ARENA_ALIGN(pool, _nb); \ + if (_a->limit >= _nb && (jsuword)(p) <= _a->limit - _nb) { \ + _a->avail = (jsuword)(p) + _nb; \ + JS_ArenaCountInplaceGrowth(pool, size, incr); \ + } else if ((jsuword)(p) == _a->base) { \ + p = (type) JS_ArenaRealloc(pool, p, size, incr); \ + } else { \ + p = (type) JS_ArenaGrow(pool, p, size, incr); \ + } \ + } else { \ + p = (type) JS_ArenaGrow(pool, p, size, incr); \ + } \ + JS_ArenaCountGrowth(pool, size, incr); \ + JS_END_MACRO + +#define JS_ARENA_MARK(pool) ((void *) (pool)->current->avail) +#define JS_UPTRDIFF(p,q) ((jsuword)(p) - (jsuword)(q)) + +/* + * Check if the mark is inside arena's allocated area. + */ +#define JS_ARENA_MARK_MATCH(a, mark) \ + (JS_UPTRDIFF(mark, (a)->base) <= JS_UPTRDIFF((a)->avail, (a)->base)) + +#ifdef DEBUG +#define JS_FREE_PATTERN 0xDA +#define JS_CLEAR_UNUSED(a) (JS_ASSERT((a)->avail <= (a)->limit), \ + memset((void*)(a)->avail, JS_FREE_PATTERN, \ + (a)->limit - (a)->avail)) +#define JS_CLEAR_ARENA(a) memset((void*)(a), JS_FREE_PATTERN, \ + (a)->limit - (jsuword)(a)) +#else +#define JS_CLEAR_UNUSED(a) /* nothing */ +#define JS_CLEAR_ARENA(a) /* nothing */ +#endif + +#define JS_ARENA_RELEASE(pool, mark) \ + JS_BEGIN_MACRO \ + char *_m = (char *)(mark); \ + JSArena *_a = (pool)->current; \ + if (_a != &(pool)->first && JS_ARENA_MARK_MATCH(_a, _m)) { \ + _a->avail = (jsuword)JS_ARENA_ALIGN(pool, _m); \ + JS_ASSERT(_a->avail <= _a->limit); \ + JS_CLEAR_UNUSED(_a); \ + JS_ArenaCountRetract(pool, _m); \ + } else { \ + JS_ArenaRelease(pool, _m); \ + } \ + JS_ArenaCountRelease(pool, _m); \ + JS_END_MACRO + +#ifdef JS_ARENAMETER +#define JS_COUNT_ARENA(pool,op) ((pool)->stats.narenas op) +#else +#define JS_COUNT_ARENA(pool,op) +#endif + +#define JS_ARENA_DESTROY(pool, a, pnext) \ + JS_BEGIN_MACRO \ + JS_COUNT_ARENA(pool,--); \ + if ((pool)->current == (a)) (pool)->current = &(pool)->first; \ + *(pnext) = (a)->next; \ + JS_CLEAR_ARENA(a); \ + free(a); \ + (a) = NULL; \ + JS_END_MACRO + +/* + * Initialize an arena pool with a minimum size per arena of size bytes. + * Always call JS_SET_ARENA_METER_NAME before calling this or use + * JS_INIT_ARENA_POOL macro to provide a name for for debugging and metering. + */ +extern JS_PUBLIC_API(void) +JS_INIT_NAMED_ARENA_POOL(JSArenaPool *pool, const char *name, size_t size, + size_t align, size_t *quotap); + +/* + * Free the arenas in pool. The user may continue to allocate from pool + * after calling this function. There is no need to call JS_InitArenaPool() + * again unless JS_FinishArenaPool(pool) has been called. + */ +extern JS_PUBLIC_API(void) +JS_FreeArenaPool(JSArenaPool *pool); + +/* + * Free the arenas in pool and finish using it altogether. + */ +extern JS_PUBLIC_API(void) +JS_FinishArenaPool(JSArenaPool *pool); + +/* + * Deprecated do-nothing function. + */ +extern JS_PUBLIC_API(void) +JS_ArenaFinish(void); + +/* + * Deprecated do-nothing function. + */ +extern JS_PUBLIC_API(void) +JS_ArenaShutDown(void); + +/* + * Friend functions used by the JS_ARENA_*() macros. + */ +extern JS_PUBLIC_API(void *) +JS_ArenaAllocate(JSArenaPool *pool, size_t nb); + +extern JS_PUBLIC_API(void *) +JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr); + +extern JS_PUBLIC_API(void *) +JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr); + +extern JS_PUBLIC_API(void) +JS_ArenaRelease(JSArenaPool *pool, char *mark); + +#ifdef JS_ARENAMETER + +#include + +extern JS_PUBLIC_API(void) +JS_ArenaCountAllocation(JSArenaPool *pool, size_t nb); + +extern JS_PUBLIC_API(void) +JS_ArenaCountInplaceGrowth(JSArenaPool *pool, size_t size, size_t incr); + +extern JS_PUBLIC_API(void) +JS_ArenaCountGrowth(JSArenaPool *pool, size_t size, size_t incr); + +extern JS_PUBLIC_API(void) +JS_ArenaCountRelease(JSArenaPool *pool, char *mark); + +extern JS_PUBLIC_API(void) +JS_ArenaCountRetract(JSArenaPool *pool, char *mark); + +extern JS_PUBLIC_API(void) +JS_DumpArenaStats(FILE *fp); + +#else /* !JS_ARENAMETER */ + +#define JS_ArenaCountAllocation(ap, nb) /* nothing */ +#define JS_ArenaCountInplaceGrowth(ap, size, incr) /* nothing */ +#define JS_ArenaCountGrowth(ap, size, incr) /* nothing */ +#define JS_ArenaCountRelease(ap, mark) /* nothing */ +#define JS_ArenaCountRetract(ap, mark) /* nothing */ + +#endif /* !JS_ARENAMETER */ + +JS_END_EXTERN_C + +#endif /* jsarena_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarray.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarray.cpp new file mode 100644 index 0000000..d6a2d83 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarray.cpp @@ -0,0 +1,3426 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS array class. + * + * Array objects begin as "dense" arrays, optimized for numeric-only property + * access over a vector of slots (obj->dslots) with high load factor. Array + * methods optimize for denseness by testing that the object's class is + * &js_ArrayClass, and can then directly manipulate the slots for efficiency. + * + * We track these pieces of metadata for arrays in dense mode: + * - the array's length property as a uint32, in JSSLOT_ARRAY_LENGTH, + * - the number of indices that are filled (non-holes), in JSSLOT_ARRAY_COUNT, + * - the net number of slots starting at dslots (DENSELEN), in dslots[-1] if + * dslots is non-NULL. + * + * In dense mode, holes in the array are represented by JSVAL_HOLE. The final + * slot in fslots (JSSLOT_ARRAY_LOOKUP_HOLDER) is used to store the single jsid + * "in use" by a lookupProperty caller. + * + * Arrays are converted to use js_SlowArrayClass when any of these conditions + * are met: + * - the load factor (COUNT / DENSELEN) is less than 0.25, and there are + * more than MIN_SPARSE_INDEX slots total + * - a property is set that is non-numeric (and not "length"); or + * - a hole is filled below DENSELEN (possibly implicitly through methods like + * |reverse| or |splice|). + * + * In the latter two cases, property creation order is no longer index order, + * which necessitates use of a structure that keeps track of property creation + * order. (ES4, due to expectations baked into web script, requires that + * enumeration order be the order in which properties were created.) + * + * An alternative in the latter case (out-of-order index set) would be to + * maintain the scope to track property enumeration order, but still use + * the fast slot access. That would have the same memory cost as just using + * a js_SlowArrayClass, but have the same performance characteristics as + * a dense array for slot accesses, at some cost in code complexity. + */ +#include "jsstddef.h" +#include +#include +#include "jstypes.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbit.h" +#include "jsbool.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" /* for js_TraceWatchPoints */ +#include "jsdtoa.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsscope.h" +#include "jsstr.h" +#include "jsstaticcheck.h" + +/* 2^32 - 1 as a number and a string */ +#define MAXINDEX 4294967295u +#define MAXSTR "4294967295" + +/* Small arrays are dense, no matter what. */ +#define MIN_SPARSE_INDEX 32 + +#define INDEX_TOO_BIG(index) ((index) > JS_BIT(29) - 1) +#define INDEX_TOO_SPARSE(array, index) \ + (INDEX_TOO_BIG(index) || \ + ((index) > ARRAY_DENSE_LENGTH(array) && (index) >= MIN_SPARSE_INDEX && \ + (index) > (uint32)((array)->fslots[JSSLOT_ARRAY_COUNT] + 1) * 4)) + +JS_STATIC_ASSERT(sizeof(JSScopeProperty) > 4 * sizeof(jsval)); + +#define ENSURE_SLOW_ARRAY(cx, obj) \ + (OBJ_GET_CLASS(cx, obj) == &js_SlowArrayClass || js_MakeArraySlow(cx, obj)) + +/* + * Determine if the id represents an array index or an XML property index. + * + * An id is an array index according to ECMA by (15.4): + * + * "Array objects give special treatment to a certain class of property names. + * A property name P (in the form of a string value) is an array index if and + * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal + * to 2^32-1." + * + * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id) + * except that by using signed 32-bit integers we miss the top half of the + * valid range. This function checks the string representation itself; note + * that calling a standard conversion routine might allow strings such as + * "08" or "4.0" as array indices, which they are not. + */ +JSBool +js_IdIsIndex(jsval id, jsuint *indexp) +{ + JSString *str; + jschar *cp; + + if (JSVAL_IS_INT(id)) { + jsint i; + i = JSVAL_TO_INT(id); + if (i < 0) + return JS_FALSE; + *indexp = (jsuint)i; + return JS_TRUE; + } + + /* NB: id should be a string, but jsxml.c may call us with an object id. */ + if (!JSVAL_IS_STRING(id)) + return JS_FALSE; + + str = JSVAL_TO_STRING(id); + cp = JSSTRING_CHARS(str); + if (JS7_ISDEC(*cp) && JSSTRING_LENGTH(str) < sizeof(MAXSTR)) { + jsuint index = JS7_UNDEC(*cp++); + jsuint oldIndex = 0; + jsuint c = 0; + if (index != 0) { + while (JS7_ISDEC(*cp)) { + oldIndex = index; + c = JS7_UNDEC(*cp); + index = 10*index + c; + cp++; + } + } + + /* Ensure that all characters were consumed and we didn't overflow. */ + if (*cp == 0 && + (oldIndex < (MAXINDEX / 10) || + (oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10)))) + { + *indexp = index; + return JS_TRUE; + } + } + return JS_FALSE; +} + +static jsuint +ValueIsLength(JSContext *cx, jsval* vp) +{ + jsint i; + jsdouble d; + jsuint length; + + if (JSVAL_IS_INT(*vp)) { + i = JSVAL_TO_INT(*vp); + if (i < 0) + goto error; + return (jsuint) i; + } + + d = js_ValueToNumber(cx, vp); + if (JSVAL_IS_NULL(*vp)) + goto error; + + if (JSDOUBLE_IS_NaN(d)) + goto error; + length = (jsuint) d; + if (d != (jsdouble) length) + goto error; + return length; + + error: + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_ARRAY_LENGTH); + *vp = JSVAL_NULL; + return 0; +} + +JSBool +js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) +{ + JSTempValueRooter tvr; + jsid id; + JSBool ok; + jsint i; + + if (OBJ_IS_ARRAY(cx, obj)) { + *lengthp = obj->fslots[JSSLOT_ARRAY_LENGTH]; + return JS_TRUE; + } + + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + ok = OBJ_GET_PROPERTY(cx, obj, id, &tvr.u.value); + if (ok) { + if (JSVAL_IS_INT(tvr.u.value)) { + i = JSVAL_TO_INT(tvr.u.value); + *lengthp = (jsuint)i; /* jsuint cast does ToUint32 */ + } else { + *lengthp = js_ValueToECMAUint32(cx, &tvr.u.value); + ok = !JSVAL_IS_NULL(tvr.u.value); + } + } + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +static JSBool +IndexToValue(JSContext *cx, jsuint index, jsval *vp) +{ + if (index <= JSVAL_INT_MAX) { + *vp = INT_TO_JSVAL(index); + return JS_TRUE; + } + return JS_NewDoubleValue(cx, (jsdouble)index, vp); +} + +JSBool JS_FASTCALL +js_IndexToId(JSContext *cx, jsuint index, jsid *idp) +{ + JSString *str; + + if (index <= JSVAL_INT_MAX) { + *idp = INT_TO_JSID(index); + return JS_TRUE; + } + str = js_NumberToString(cx, index); + if (!str) + return JS_FALSE; + return js_ValueToStringId(cx, STRING_TO_JSVAL(str), idp); +} + +static JSBool +BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom, + jsid *idp) +{ + jschar buf[10], *start; + JSClass *clasp; + JSAtom *atom; + JS_STATIC_ASSERT((jsuint)-1 == 4294967295U); + + JS_ASSERT(index > JSVAL_INT_MAX); + + start = JS_ARRAY_END(buf); + do { + --start; + *start = (jschar)('0' + index % 10); + index /= 10; + } while (index != 0); + + /* + * Skip the atomization if the class is known to store atoms corresponding + * to big indexes together with elements. In such case we know that the + * array does not have an element at the given index if its atom does not + * exist. Fast arrays (clasp == &js_ArrayClass) don't use atoms for + * any indexes, though it would be rare to see them have a big index + * in any case. + */ + if (!createAtom && + ((clasp = OBJ_GET_CLASS(cx, obj)) == &js_SlowArrayClass || + clasp == &js_ArgumentsClass || + clasp == &js_ObjectClass)) { + atom = js_GetExistingStringAtom(cx, start, JS_ARRAY_END(buf) - start); + if (!atom) { + *idp = JSVAL_VOID; + return JS_TRUE; + } + } else { + atom = js_AtomizeChars(cx, start, JS_ARRAY_END(buf) - start, 0); + if (!atom) + return JS_FALSE; + } + + *idp = ATOM_TO_JSID(atom); + return JS_TRUE; +} + +static JSBool +ResizeSlots(JSContext *cx, JSObject *obj, uint32 oldlen, uint32 len) +{ + jsval *slots, *newslots; + + if (len == 0) { + if (obj->dslots) { + JS_free(cx, obj->dslots - 1); + obj->dslots = NULL; + } + return JS_TRUE; + } + + if (len > ~(uint32)0 / sizeof(jsval)) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + + slots = obj->dslots ? obj->dslots - 1 : NULL; + newslots = (jsval *) JS_realloc(cx, slots, sizeof (jsval) * (len + 1)); + if (!newslots) + return JS_FALSE; + + obj->dslots = newslots + 1; + ARRAY_SET_DENSE_LENGTH(obj, len); + + for (slots = obj->dslots + oldlen; slots < obj->dslots + len; slots++) + *slots = JSVAL_HOLE; + + return JS_TRUE; +} + +static JSBool +EnsureLength(JSContext *cx, JSObject *obj, uint32 len) +{ + uint32 oldlen = ARRAY_DENSE_LENGTH(obj); + + if (len > oldlen) { + return ResizeSlots(cx, obj, oldlen, + len + ARRAY_GROWBY - (len % ARRAY_GROWBY)); + } + return JS_TRUE; +} + +/* + * If the property at the given index exists, get its value into location + * pointed by vp and set *hole to false. Otherwise set *hole to true and *vp + * to JSVAL_VOID. This function assumes that the location pointed by vp is + * properly rooted and can be used as GC-protected storage for temporaries. + */ +static JSBool +GetArrayElement(JSContext *cx, JSObject *obj, jsuint index, JSBool *hole, + jsval *vp) +{ + jsid id; + JSObject *obj2; + JSProperty *prop; + + if (OBJ_IS_DENSE_ARRAY(cx, obj) && index < ARRAY_DENSE_LENGTH(obj) && + (*vp = obj->dslots[index]) != JSVAL_HOLE) { + *hole = JS_FALSE; + return JS_TRUE; + } + + if (index <= JSVAL_INT_MAX) { + id = INT_TO_JSID(index); + } else { + if (!BigIndexToId(cx, obj, index, JS_FALSE, &id)) + return JS_FALSE; + if (JSVAL_IS_VOID(id)) { + *hole = JS_TRUE; + *vp = JSVAL_VOID; + return JS_TRUE; + } + } + + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) + return JS_FALSE; + if (!prop) { + *hole = JS_TRUE; + *vp = JSVAL_VOID; + } else { + OBJ_DROP_PROPERTY(cx, obj2, prop); + if (!OBJ_GET_PROPERTY(cx, obj, id, vp)) + return JS_FALSE; + *hole = JS_FALSE; + } + return JS_TRUE; +} + +/* + * Set the value of the property at the given index to v assuming v is rooted. + */ +static JSBool +SetArrayElement(JSContext *cx, JSObject *obj, jsuint index, jsval v) +{ + jsid id; + + if (OBJ_IS_DENSE_ARRAY(cx, obj)) { + /* Predicted/prefeched code should favor the remains-dense case. */ + if (!INDEX_TOO_SPARSE(obj, index)) { + if (!EnsureLength(cx, obj, index + 1)) + return JS_FALSE; + if (index >= (uint32)obj->fslots[JSSLOT_ARRAY_LENGTH]) + obj->fslots[JSSLOT_ARRAY_LENGTH] = index + 1; + if (obj->dslots[index] == JSVAL_HOLE) + obj->fslots[JSSLOT_ARRAY_COUNT]++; + obj->dslots[index] = v; + return JS_TRUE; + } + + if (!js_MakeArraySlow(cx, obj)) + return JS_FALSE; + } + + if (index <= JSVAL_INT_MAX) { + id = INT_TO_JSID(index); + } else { + if (!BigIndexToId(cx, obj, index, JS_TRUE, &id)) + return JS_FALSE; + JS_ASSERT(!JSVAL_IS_VOID(id)); + } + return OBJ_SET_PROPERTY(cx, obj, id, &v); +} + +static JSBool +DeleteArrayElement(JSContext *cx, JSObject *obj, jsuint index) +{ + jsid id; + jsval junk; + + if (OBJ_IS_DENSE_ARRAY(cx, obj)) { + if (index < ARRAY_DENSE_LENGTH(obj)) { + if (obj->dslots[index] != JSVAL_HOLE) + obj->fslots[JSSLOT_ARRAY_COUNT]--; + obj->dslots[index] = JSVAL_HOLE; + } + return JS_TRUE; + } + + if (index <= JSVAL_INT_MAX) { + id = INT_TO_JSID(index); + } else { + if (!BigIndexToId(cx, obj, index, JS_FALSE, &id)) + return JS_FALSE; + if (JSVAL_IS_VOID(id)) + return JS_TRUE; + } + return OBJ_DELETE_PROPERTY(cx, obj, id, &junk); +} + +/* + * When hole is true, delete the property at the given index. Otherwise set + * its value to v assuming v is rooted. + */ +static JSBool +SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, jsuint index, + JSBool hole, jsval v) +{ + if (hole) { + JS_ASSERT(JSVAL_IS_VOID(v)); + return DeleteArrayElement(cx, obj, index); + } + return SetArrayElement(cx, obj, index, v); +} + +JSBool +js_SetLengthProperty(JSContext *cx, JSObject *obj, jsuint length) +{ + jsval v; + jsid id; + + if (!IndexToValue(cx, length, &v)) + return JS_FALSE; + id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + return OBJ_SET_PROPERTY(cx, obj, id, &v); +} + +JSBool +js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) +{ + JSErrorReporter older; + JSTempValueRooter tvr; + jsid id; + JSBool ok; + + older = JS_SetErrorReporter(cx, NULL); + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + ok = OBJ_GET_PROPERTY(cx, obj, id, &tvr.u.value); + JS_SetErrorReporter(cx, older); + if (ok) { + *lengthp = ValueIsLength(cx, &tvr.u.value); + ok = !JSVAL_IS_NULL(tvr.u.value); + } + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +JSBool +js_IsArrayLike(JSContext *cx, JSObject *obj, JSBool *answerp, jsuint *lengthp) +{ + JSClass *clasp; + + clasp = OBJ_GET_CLASS(cx, obj); + *answerp = (clasp == &js_ArgumentsClass || clasp == &js_ArrayClass || + clasp == &js_SlowArrayClass); + if (!*answerp) { + *lengthp = 0; + return JS_TRUE; + } + return js_GetLengthProperty(cx, obj, lengthp); +} + +/* + * The 'length' property of all native Array instances is a shared permanent + * property of Array.prototype, so it appears to be a direct property of each + * array instance delegating to that Array.prototype. It accesses the private + * slot reserved by js_ArrayClass. + * + * Since SpiderMonkey supports cross-class prototype-based delegation, we have + * to be careful about the length getter and setter being called on an object + * not of Array class. For the getter, we search obj's prototype chain for the + * array that caused this getter to be invoked. In the setter case to overcome + * the JSPROP_SHARED attribute, we must define a shadowing length property. + */ +static JSBool +array_length_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + do { + if (OBJ_IS_ARRAY(cx, obj)) + return IndexToValue(cx, obj->fslots[JSSLOT_ARRAY_LENGTH], vp); + } while ((obj = OBJ_GET_PROTO(cx, obj)) != NULL); + return JS_TRUE; +} + +static JSBool +array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + jsuint newlen, oldlen, gap, index; + jsval junk; + JSObject *iter; + JSTempValueRooter tvr; + JSBool ok; + + if (!OBJ_IS_ARRAY(cx, obj)) { + jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + + return OBJ_DEFINE_PROPERTY(cx, obj, lengthId, *vp, NULL, NULL, + JSPROP_ENUMERATE, NULL); + } + + newlen = ValueIsLength(cx, vp); + if (JSVAL_IS_NULL(*vp)) + return JS_FALSE; + oldlen = obj->fslots[JSSLOT_ARRAY_LENGTH]; + + if (oldlen == newlen) + return JS_TRUE; + + if (!IndexToValue(cx, newlen, vp)) + return JS_FALSE; + + if (oldlen < newlen) { + obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen; + return JS_TRUE; + } + + if (OBJ_IS_DENSE_ARRAY(cx, obj)) { + if (ARRAY_DENSE_LENGTH(obj) && !ResizeSlots(cx, obj, oldlen, newlen)) + return JS_FALSE; + } else if (oldlen - newlen < (1 << 24)) { + do { + --oldlen; + if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || + !DeleteArrayElement(cx, obj, oldlen)) { + return JS_FALSE; + } + } while (oldlen != newlen); + } else { + /* + * We are going to remove a lot of indexes in a presumably sparse + * array. So instead of looping through indexes between newlen and + * oldlen, we iterate through all properties and remove those that + * correspond to indexes in the half-open range [newlen, oldlen). See + * bug 322135. + */ + iter = JS_NewPropertyIterator(cx, obj); + if (!iter) + return JS_FALSE; + + /* Protect iter against GC in OBJ_DELETE_PROPERTY. */ + JS_PUSH_TEMP_ROOT_OBJECT(cx, iter, &tvr); + gap = oldlen - newlen; + for (;;) { + ok = (JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + JS_NextProperty(cx, iter, &id)); + if (!ok) + break; + if (JSVAL_IS_VOID(id)) + break; + if (js_IdIsIndex(id, &index) && index - newlen < gap) { + ok = OBJ_DELETE_PROPERTY(cx, obj, id, &junk); + if (!ok) + break; + } + } + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return JS_FALSE; + } + + obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen; + return JS_TRUE; +} + +static JSBool +array_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp) +{ + uint32 i; + union { JSProperty *p; jsval *v; } u; + + if (!OBJ_IS_DENSE_ARRAY(cx, obj)) + return js_LookupProperty(cx, obj, id, objp, propp); + + /* + * We have only indexed properties up to DENSELEN (excepting holes), plus + * the length property. For all else, we delegate to the prototype. + */ + if (id != ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) && + (!js_IdIsIndex(id, &i) || + obj->fslots[JSSLOT_ARRAY_LENGTH] == 0 || + i >= ARRAY_DENSE_LENGTH(obj) || + obj->dslots[i] == JSVAL_HOLE)) + { + JSObject *proto = STOBJ_GET_PROTO(obj); + + if (!proto) { + *objp = NULL; + *propp = NULL; + return JS_TRUE; + } + + return OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp); + } + + /* FIXME 417501: threadsafety: could race with a lookup on another thread. + * If we can only have a single lookup active per context, we could + * pigeonhole this on the context instead. */ + JS_ASSERT(JSVAL_IS_VOID(obj->fslots[JSSLOT_ARRAY_LOOKUP_HOLDER])); + obj->fslots[JSSLOT_ARRAY_LOOKUP_HOLDER] = (jsval) id; + u.v = &(obj->fslots[JSSLOT_ARRAY_LOOKUP_HOLDER]); + *propp = u.p; + *objp = obj; + return JS_TRUE; +} + +static void +array_dropProperty(JSContext *cx, JSObject *obj, JSProperty *prop) +{ + JS_ASSERT_IF(OBJ_IS_DENSE_ARRAY(cx, obj), + !JSVAL_IS_VOID(obj->fslots[JSSLOT_ARRAY_LOOKUP_HOLDER])); +#ifdef DEBUG + obj->fslots[JSSLOT_ARRAY_LOOKUP_HOLDER] = JSVAL_VOID; +#endif +} + +static JSBool +array_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + uint32 i; + + if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) + return IndexToValue(cx, obj->fslots[JSSLOT_ARRAY_LENGTH], vp); + + if (id == ATOM_TO_JSID(cx->runtime->atomState.protoAtom)) { + *vp = STOBJ_GET_SLOT(obj, JSSLOT_PROTO); + return JS_TRUE; + } + + if (!OBJ_IS_DENSE_ARRAY(cx, obj)) + return js_GetProperty(cx, obj, id, vp); + + if (!js_IdIsIndex(ID_TO_VALUE(id), &i) || i >= ARRAY_DENSE_LENGTH(obj) || + obj->dslots[i] == JSVAL_HOLE) { + JSObject *obj2; + JSProperty *prop; + JSScopeProperty *sprop; + + JSObject *proto = STOBJ_GET_PROTO(obj); + if (!proto) { + *vp = JSVAL_VOID; + return JS_TRUE; + } + + *vp = JSVAL_VOID; + if (js_LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags, + &obj2, &prop) < 0) + return JS_FALSE; + + if (prop) { + if (OBJ_IS_NATIVE(obj2)) { + sprop = (JSScopeProperty *) prop; + if (!js_NativeGet(cx, obj, obj2, sprop, vp)) + return JS_FALSE; + } + OBJ_DROP_PROPERTY(cx, obj2, prop); + } + return JS_TRUE; + } + + *vp = obj->dslots[i]; + return JS_TRUE; +} + +static JSBool +slowarray_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + jsuint index, length; + + if (!js_IdIsIndex(id, &index)) + return JS_TRUE; + length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (index >= length) + obj->fslots[JSSLOT_ARRAY_LENGTH] = index + 1; + return JS_TRUE; +} + +static void +slowarray_trace(JSTracer *trc, JSObject *obj) +{ + uint32 length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + + JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_SlowArrayClass); + + /* + * Move JSSLOT_ARRAY_LENGTH aside to prevent the GC from treating + * untagged integer values as objects or strings. + */ + obj->fslots[JSSLOT_ARRAY_LENGTH] = JSVAL_VOID; + js_TraceObject(trc, obj); + obj->fslots[JSSLOT_ARRAY_LENGTH] = length; +} + +static JSObjectOps js_SlowArrayObjectOps; + +static JSObjectOps * +slowarray_getObjectOps(JSContext *cx, JSClass *clasp) +{ + return &js_SlowArrayObjectOps; +} + +static JSBool +array_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + uint32 i; + + if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) + return array_length_setter(cx, obj, id, vp); + + if (!OBJ_IS_DENSE_ARRAY(cx, obj)) + return js_SetProperty(cx, obj, id, vp); + + if (!js_IdIsIndex(id, &i) || INDEX_TOO_SPARSE(obj, i)) { + if (!js_MakeArraySlow(cx, obj)) + return JS_FALSE; + return js_SetProperty(cx, obj, id, vp); + } + + if (!EnsureLength(cx, obj, i + 1)) + return JS_FALSE; + + if (i >= (uint32)obj->fslots[JSSLOT_ARRAY_LENGTH]) + obj->fslots[JSSLOT_ARRAY_LENGTH] = i + 1; + if (obj->dslots[i] == JSVAL_HOLE) + obj->fslots[JSSLOT_ARRAY_COUNT]++; + obj->dslots[i] = *vp; + return JS_TRUE; +} + +#ifdef JS_TRACER +JSBool FASTCALL +js_Array_dense_setelem(JSContext* cx, JSObject* obj, jsint i, jsval v) +{ + JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj)); + + do { + jsuint length = ARRAY_DENSE_LENGTH(obj); + if ((jsuint)i < length) { + if (obj->dslots[i] == JSVAL_HOLE) { + if (cx->runtime->anyArrayProtoHasElement) + break; + if (i >= obj->fslots[JSSLOT_ARRAY_LENGTH]) + obj->fslots[JSSLOT_ARRAY_LENGTH] = i + 1; + obj->fslots[JSSLOT_ARRAY_COUNT]++; + } + obj->dslots[i] = v; + return JS_TRUE; + } + } while (0); + return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(i), &v); +} +#endif + +static JSBool +array_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + JSProperty **propp) +{ + uint32 i; + JSBool isIndex; + + if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) + return JS_TRUE; + + isIndex = js_IdIsIndex(ID_TO_VALUE(id), &i); + if (!isIndex || attrs != JSPROP_ENUMERATE) { + if (!ENSURE_SLOW_ARRAY(cx, obj)) + return JS_FALSE; + if (isIndex && STOBJ_IS_DELEGATE(obj)) + cx->runtime->anyArrayProtoHasElement = JS_TRUE; + return js_DefineProperty(cx, obj, id, value, getter, setter, attrs, propp); + } + + return array_setProperty(cx, obj, id, &value); +} + +static JSBool +array_getAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp) +{ + *attrsp = id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) + ? JSPROP_PERMANENT : JSPROP_ENUMERATE; + return JS_TRUE; +} + +static JSBool +array_setAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_SET_ARRAY_ATTRS); + return JS_FALSE; +} + +static JSBool +array_deleteProperty(JSContext *cx, JSObject *obj, jsval id, jsval *rval) +{ + uint32 i; + + if (!OBJ_IS_DENSE_ARRAY(cx, obj)) + return js_DeleteProperty(cx, obj, id, rval); + + if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { + *rval = JSVAL_FALSE; + return JS_TRUE; + } + + if (js_IdIsIndex(id, &i) && i < ARRAY_DENSE_LENGTH(obj) && + obj->dslots[i] != JSVAL_HOLE) { + obj->fslots[JSSLOT_ARRAY_COUNT]--; + obj->dslots[i] = JSVAL_HOLE; + } + + *rval = JSVAL_TRUE; + return JS_TRUE; +} + +/* + * JSObjectOps.enumerate implementation. + * + * For a fast array, JSENUMERATE_INIT captures in the enumeration state both + * the length of the array and the bitmap indicating the positions of holes in + * the array. This ensures that adding or deleting array elements does not + * affect the sequence of indexes JSENUMERATE_NEXT returns. + * + * For a common case of an array without holes, to represent the state we pack + * the (nextEnumerationIndex, arrayLength) pair as a pseudo-boolean jsval. + * This is possible when length <= PACKED_UINT_PAIR_BITS. For arrays with + * greater length or holes we allocate the JSIndexIterState structure and + * store it as an int-tagged private pointer jsval. For a slow array we + * delegate the enumeration implementation to js_Enumerate in + * slowarray_enumerate. + * + * Array mutations can turn a fast array into a slow one after the enumeration + * starts. When this happens, slowarray_enumerate receives a state created + * when the array was fast. To distinguish such fast state from a slow state, + * which is an int-tagged pointer that js_Enumerate creates, we set not one + * but two lowest bits when tagging a JSIndexIterState pointer -- see + * INDEX_ITER_TAG usage below. Thus, when slowarray_enumerate receives a state + * tagged with JSVAL_BOOLEAN or with two lowest bits set, it knows that this + * is a fast state so it calls array_enumerate to continue enumerating the + * indexes present in the original fast array. + */ + +#define PACKED_UINT_PAIR_BITS 14 +#define PACKED_UINT_PAIR_MASK JS_BITMASK(PACKED_UINT_PAIR_BITS) + +#define UINT_PAIR_TO_BOOLEAN_JSVAL(i,j) \ + (JS_ASSERT((uint32) (i) <= PACKED_UINT_PAIR_MASK), \ + JS_ASSERT((uint32) (j) <= PACKED_UINT_PAIR_MASK), \ + ((jsval) (i) << (PACKED_UINT_PAIR_BITS + JSVAL_TAGBITS)) | \ + ((jsval) (j) << (JSVAL_TAGBITS)) | \ + (jsval) JSVAL_BOOLEAN) + +#define BOOLEAN_JSVAL_TO_UINT_PAIR(v,i,j) \ + (JS_ASSERT(JSVAL_TAG(v) == JSVAL_BOOLEAN), \ + (i) = (uint32) ((v) >> (PACKED_UINT_PAIR_BITS + JSVAL_TAGBITS)), \ + (j) = (uint32) ((v) >> JSVAL_TAGBITS) & PACKED_UINT_PAIR_MASK, \ + JS_ASSERT((i) <= PACKED_UINT_PAIR_MASK)) + +JS_STATIC_ASSERT(PACKED_UINT_PAIR_BITS * 2 + JSVAL_TAGBITS <= JS_BITS_PER_WORD); + +typedef struct JSIndexIterState { + uint32 index; + uint32 length; + JSBool hasHoles; + + /* + * Variable-length bitmap representing array's holes. It must not be + * accessed when hasHoles is false. + */ + jsbitmap holes[1]; +} JSIndexIterState; + +#define INDEX_ITER_TAG 3 + +JS_STATIC_ASSERT(JSVAL_INT == 1); + +static JSBool +array_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp) +{ + uint32 length, i; + JSIndexIterState *ii; + + switch (enum_op) { + case JSENUMERATE_INIT: + JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj)); + length = ARRAY_DENSE_LENGTH(obj); + if (idp) + *idp = INT_TO_JSVAL(obj->fslots[JSSLOT_ARRAY_COUNT]); + ii = NULL; + for (i = 0; i != length; ++i) { + if (obj->dslots[i] == JSVAL_HOLE) { + if (!ii) { + ii = (JSIndexIterState *) + JS_malloc(cx, offsetof(JSIndexIterState, holes) + + JS_BITMAP_SIZE(length)); + if (!ii) + return JS_FALSE; + ii->hasHoles = JS_TRUE; + memset(ii->holes, 0, JS_BITMAP_SIZE(length)); + } + JS_SET_BIT(ii->holes, i); + } + } + if (!ii) { + /* Array has no holes. */ + if (length <= PACKED_UINT_PAIR_MASK) { + *statep = UINT_PAIR_TO_BOOLEAN_JSVAL(0, length); + break; + } + ii = (JSIndexIterState *) + JS_malloc(cx, offsetof(JSIndexIterState, holes)); + if (!ii) + return JS_FALSE; + ii->hasHoles = JS_FALSE; + } + ii->index = 0; + ii->length = length; + *statep = (jsval) ii | INDEX_ITER_TAG; + JS_ASSERT(*statep & JSVAL_INT); + break; + + case JSENUMERATE_NEXT: + if (JSVAL_TAG(*statep) == JSVAL_BOOLEAN) { + BOOLEAN_JSVAL_TO_UINT_PAIR(*statep, i, length); + if (i != length) { + *idp = INT_TO_JSID(i); + *statep = UINT_PAIR_TO_BOOLEAN_JSVAL(i + 1, length); + break; + } + } else { + JS_ASSERT((*statep & INDEX_ITER_TAG) == INDEX_ITER_TAG); + ii = (JSIndexIterState *) (*statep & ~INDEX_ITER_TAG); + i = ii->index; + if (i != ii->length) { + /* Skip holes if any. */ + if (ii->hasHoles) { + while (JS_TEST_BIT(ii->holes, i) && ++i != ii->length) + continue; + } + if (i != ii->length) { + ii->index = i + 1; + return js_IndexToId(cx, i, idp); + } + } + } + /* FALL THROUGH */ + + case JSENUMERATE_DESTROY: + if (JSVAL_TAG(*statep) != JSVAL_BOOLEAN) { + JS_ASSERT((*statep & INDEX_ITER_TAG) == INDEX_ITER_TAG); + ii = (JSIndexIterState *) (*statep & ~INDEX_ITER_TAG); + JS_free(cx, ii); + } + *statep = JSVAL_NULL; + break; + } + return JS_TRUE; +} + +static JSBool +slowarray_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp) +{ + JSBool ok; + + /* Are we continuing an enumeration that started when we were dense? */ + if (enum_op != JSENUMERATE_INIT) { + if (JSVAL_TAG(*statep) == JSVAL_BOOLEAN || + (*statep & INDEX_ITER_TAG) == INDEX_ITER_TAG) { + return array_enumerate(cx, obj, enum_op, statep, idp); + } + JS_ASSERT((*statep & INDEX_ITER_TAG) == JSVAL_INT); + } + ok = js_Enumerate(cx, obj, enum_op, statep, idp); + JS_ASSERT(*statep == JSVAL_NULL || (*statep & INDEX_ITER_TAG) == JSVAL_INT); + return ok; +} + +static void +array_finalize(JSContext *cx, JSObject *obj) +{ + if (obj->dslots) + JS_free(cx, obj->dslots - 1); + obj->dslots = NULL; +} + +static void +array_trace(JSTracer *trc, JSObject *obj) +{ + uint32 length; + size_t i; + jsval v; + + JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj)); + + length = ARRAY_DENSE_LENGTH(obj); + for (i = 0; i < length; i++) { + v = obj->dslots[i]; + if (JSVAL_IS_TRACEABLE(v)) { + JS_SET_TRACING_INDEX(trc, "array_dslots", i); + JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); + } + } + + for (i = JSSLOT_PROTO; i <= JSSLOT_PARENT; ++i) { + v = STOBJ_GET_SLOT(obj, i); + if (JSVAL_IS_TRACEABLE(v)) { + JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i); + JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); + } + } +} + +static JSObjectMap * +array_newObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, + JSClass *clasp, JSObject *obj) +{ +#ifdef DEBUG + extern JSClass js_ArrayClass; + extern JSObjectOps js_ArrayObjectOps; +#endif + JSObjectMap *map = (JSObjectMap *) JS_malloc(cx, sizeof(*map)); + if (!map) + return NULL; + + map->nrefs = nrefs; + JS_ASSERT(ops == &js_ArrayObjectOps); + map->ops = ops; + JS_ASSERT(clasp == &js_ArrayClass); + map->freeslot = JSSLOT_FREE(clasp); + + return map; +} + +void +array_destroyObjectMap(JSContext *cx, JSObjectMap *map) +{ + JS_free(cx, map); +} + +JSObjectOps js_ArrayObjectOps = { + array_newObjectMap, array_destroyObjectMap, + array_lookupProperty, array_defineProperty, + array_getProperty, array_setProperty, + array_getAttributes, array_setAttributes, + array_deleteProperty, js_DefaultValue, + array_enumerate, js_CheckAccess, + NULL, array_dropProperty, + NULL, NULL, + NULL, js_HasInstance, + js_SetProtoOrParent, js_SetProtoOrParent, + array_trace, NULL, + NULL, NULL +}; + +static JSObjectOps * +array_getObjectOps(JSContext *cx, JSClass *clasp) +{ + return &js_ArrayObjectOps; +} + +JSClass js_ArrayClass = { + "Array", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | + JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_ENUMERATE, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, js_TryValueOf, array_finalize, + array_getObjectOps, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +JSClass js_SlowArrayClass = { + "Array", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array), + slowarray_addProperty, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, js_TryValueOf, JS_FinalizeStub, + slowarray_getObjectOps, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +/* + * Convert an array object from fast-and-dense to slow-and-flexible. + */ +JSBool +js_MakeArraySlow(JSContext *cx, JSObject *obj) +{ + JSObjectMap *map, *oldmap; + uint32 i, length; + + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass); + + /* Create a native scope. */ + map = js_NewObjectMap(cx, obj->map->nrefs, &js_SlowArrayObjectOps, + &js_SlowArrayClass, obj); + if (!map) + return JS_FALSE; + + length = ARRAY_DENSE_LENGTH(obj); + if (length) { + map->freeslot = STOBJ_NSLOTS(obj) + JS_INITIAL_NSLOTS; + obj->dslots[-1] = JS_INITIAL_NSLOTS + length; + } else { + map->freeslot = STOBJ_NSLOTS(obj); + } + + /* Create new properties pointing to existing values in dslots */ + for (i = 0; i < length; i++) { + jsid id; + JSScopeProperty *sprop; + + if (!JS_ValueToId(cx, INT_TO_JSVAL(i), &id)) + goto out_bad; + + if (obj->dslots[i] == JSVAL_HOLE) { + obj->dslots[i] = JSVAL_VOID; + continue; + } + + sprop = js_AddScopeProperty(cx, (JSScope *)map, id, NULL, NULL, + i + JS_INITIAL_NSLOTS, JSPROP_ENUMERATE, + 0, 0); + if (!sprop) + goto out_bad; + } + + /* + * Render our formerly-reserved count property GC-safe. If length fits in + * a jsval, set our slow/sparse COUNT to the current length as a jsval, so + * we can tell when only named properties have been added to a dense array + * to make it slow-but-not-sparse. + */ + length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + obj->fslots[JSSLOT_ARRAY_COUNT] = INT_FITS_IN_JSVAL(length) + ? INT_TO_JSVAL(length) + : JSVAL_VOID; + + /* Make sure we preserve any flags borrowing bits in classword. */ + obj->classword ^= (jsuword) &js_ArrayClass; + obj->classword |= (jsuword) &js_SlowArrayClass; + + /* Swap in our new map. */ + oldmap = obj->map; + obj->map = map; + array_destroyObjectMap(cx, oldmap); + + return JS_TRUE; + +out_bad: + js_DestroyObjectMap(cx, map); + return JS_FALSE; +} + +enum ArrayToStringOp { + TO_STRING, + TO_LOCALE_STRING, + TO_SOURCE +}; + +/* + * When op is TO_STRING or TO_LOCALE_STRING sep indicates a separator to use + * or "," when sep is NULL. + * When op is TO_SOURCE sep must be NULL. + */ +static JSBool +array_join_sub(JSContext *cx, JSObject *obj, enum ArrayToStringOp op, + JSString *sep, jsval *rval) +{ + JSBool ok, hole; + jsuint length, index; + jschar *chars, *ochars; + size_t nchars, growth, seplen, tmplen, extratail; + const jschar *sepstr; + JSString *str; + JSHashEntry *he; + JSAtom *atom; + + JS_CHECK_RECURSION(cx, return JS_FALSE); + + ok = js_GetLengthProperty(cx, obj, &length); + if (!ok) + return JS_FALSE; + + he = js_EnterSharpObject(cx, obj, NULL, &chars); + if (!he) + return JS_FALSE; +#ifdef DEBUG + growth = (size_t) -1; +#endif + + if (op == TO_SOURCE) { + if (IS_SHARP(he)) { +#if JS_HAS_SHARP_VARS + nchars = js_strlen(chars); +#else + chars[0] = '['; + chars[1] = ']'; + chars[2] = 0; + nchars = 2; +#endif + goto make_string; + } + + /* + * Always allocate 2 extra chars for closing ']' and terminating 0 + * and then preallocate 1 + extratail to include starting '['. + */ + extratail = 2; + growth = (1 + extratail) * sizeof(jschar); + if (!chars) { + nchars = 0; + chars = (jschar *) malloc(growth); + if (!chars) + goto done; + } else { + MAKE_SHARP(he); + nchars = js_strlen(chars); + growth += nchars * sizeof(jschar); + chars = (jschar *)realloc((ochars = chars), growth); + if (!chars) { + free(ochars); + goto done; + } + } + chars[nchars++] = '['; + JS_ASSERT(sep == NULL); + sepstr = NULL; /* indicates to use ", " as separator */ + seplen = 2; + } else { + /* + * Free any sharp variable definition in chars. Normally, we would + * MAKE_SHARP(he) so that only the first sharp variable annotation is + * a definition, and all the rest are references, but in the current + * case of (op != TO_SOURCE), we don't need chars at all. + */ + if (chars) + JS_free(cx, chars); + chars = NULL; + nchars = 0; + extratail = 1; /* allocate extra char for terminating 0 */ + + /* Return the empty string on a cycle as well as on empty join. */ + if (IS_BUSY(he) || length == 0) { + js_LeaveSharpObject(cx, NULL); + *rval = JS_GetEmptyStringValue(cx); + return ok; + } + + /* Flag he as BUSY so we can distinguish a cycle from a join-point. */ + MAKE_BUSY(he); + + if (sep) { + JSSTRING_CHARS_AND_LENGTH(sep, sepstr, seplen); + } else { + sepstr = NULL; /* indicates to use "," as separator */ + seplen = 1; + } + } + + /* Use rval to locally root each element value as we loop and convert. */ + for (index = 0; index < length; index++) { + ok = (JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, obj, index, &hole, rval)); + if (!ok) + goto done; + if (hole || + (op != TO_SOURCE && + (JSVAL_IS_VOID(*rval) || JSVAL_IS_NULL(*rval)))) { + str = cx->runtime->emptyString; + } else { + if (op == TO_LOCALE_STRING) { + JSObject *robj; + + atom = cx->runtime->atomState.toLocaleStringAtom; + ok = js_ValueToObject(cx, *rval, &robj); + if (ok) { + /* Re-use *rval to protect robj temporarily. */ + *rval = OBJECT_TO_JSVAL(robj); + ok = js_TryMethod(cx, robj, atom, 0, NULL, rval); + } + if (!ok) + goto done; + str = js_ValueToString(cx, *rval); + } else if (op == TO_STRING) { + str = js_ValueToString(cx, *rval); + } else { + JS_ASSERT(op == TO_SOURCE); + str = js_ValueToSource(cx, *rval); + } + if (!str) { + ok = JS_FALSE; + goto done; + } + } + + /* + * Do not append separator after the last element unless it is a hole + * and we are in toSource. In that case we append single ",". + */ + if (index + 1 == length) + seplen = (hole && op == TO_SOURCE) ? 1 : 0; + + /* Allocate 1 at end for closing bracket and zero. */ + tmplen = JSSTRING_LENGTH(str); + growth = nchars + tmplen + seplen + extratail; + if (nchars > growth || tmplen > growth || + growth > (size_t)-1 / sizeof(jschar)) { + if (chars) { + free(chars); + chars = NULL; + } + goto done; + } + growth *= sizeof(jschar); + JS_COUNT_OPERATION(cx, JSOW_ALLOCATION); + if (!chars) { + chars = (jschar *) malloc(growth); + if (!chars) + goto done; + } else { + chars = (jschar *) realloc((ochars = chars), growth); + if (!chars) { + free(ochars); + goto done; + } + } + + js_strncpy(&chars[nchars], JSSTRING_CHARS(str), tmplen); + nchars += tmplen; + + if (seplen) { + if (sepstr) { + js_strncpy(&chars[nchars], sepstr, seplen); + } else { + JS_ASSERT(seplen == 1 || seplen == 2); + chars[nchars] = ','; + if (seplen == 2) + chars[nchars + 1] = ' '; + } + nchars += seplen; + } + } + + done: + if (op == TO_SOURCE) { + if (chars) + chars[nchars++] = ']'; + } else { + CLEAR_BUSY(he); + } + js_LeaveSharpObject(cx, NULL); + if (!ok) { + if (chars) + free(chars); + return ok; + } + + make_string: + if (!chars) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + chars[nchars] = 0; + JS_ASSERT(growth == (size_t)-1 || (nchars + 1) * sizeof(jschar) == growth); + str = js_NewString(cx, chars, nchars); + if (!str) { + free(chars); + return JS_FALSE; + } + *rval = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +#if JS_HAS_TOSOURCE +static JSBool +array_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + if (OBJ_GET_CLASS(cx, obj) != &js_SlowArrayClass && + !JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) { + return JS_FALSE; + } + return array_join_sub(cx, obj, TO_SOURCE, NULL, vp); +} +#endif + +static JSBool +array_toString(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + if (OBJ_GET_CLASS(cx, obj) != &js_SlowArrayClass && + !JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) { + return JS_FALSE; + } + return array_join_sub(cx, obj, TO_STRING, NULL, vp); +} + +static JSBool +array_toLocaleString(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + if (OBJ_GET_CLASS(cx, obj) != &js_SlowArrayClass && + !JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) { + return JS_FALSE; + } + + /* + * Passing comma here as the separator. Need a way to get a + * locale-specific version. + */ + return array_join_sub(cx, obj, TO_LOCALE_STRING, NULL, vp); +} + +static JSBool +InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint end, + jsval *vector) +{ + if (OBJ_IS_DENSE_ARRAY(cx, obj)) { + if (!EnsureLength(cx, obj, end)) + return JS_FALSE; + + if (end > (uint32)obj->fslots[JSSLOT_ARRAY_LENGTH]) + obj->fslots[JSSLOT_ARRAY_LENGTH] = end; + + memcpy(obj->dslots + start, vector, sizeof(jsval) * (end - start)); + return JS_TRUE; + } + + while (start != end) { + if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || + !SetArrayElement(cx, obj, start++, *vector++)) { + return JS_FALSE; + } + } + return JS_TRUE; +} + +static JSBool +InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector, + JSBool holey = JS_FALSE) +{ + JS_ASSERT(OBJ_IS_ARRAY(cx, obj)); + + obj->fslots[JSSLOT_ARRAY_LENGTH] = length; + + if (vector) { + if (!EnsureLength(cx, obj, length)) + return JS_FALSE; + + jsuint count = length; + if (!holey) { + memcpy(obj->dslots, vector, length * sizeof (jsval)); + } else { + for (jsuint i = 0; i < length; i++) { + if (vector[i] == JSVAL_HOLE) + --count; + obj->dslots[i] = vector[i]; + } + } + obj->fslots[JSSLOT_ARRAY_COUNT] = count; + } else { + obj->fslots[JSSLOT_ARRAY_COUNT] = 0; + } + return JS_TRUE; +} + +#ifdef JS_TRACER +static JSString* FASTCALL +Array_p_join(JSContext* cx, JSObject* obj, JSString *str) +{ + jsval v; + if (!array_join_sub(cx, obj, TO_STRING, str, &v)) + return NULL; + JS_ASSERT(JSVAL_IS_STRING(v)); + return JSVAL_TO_STRING(v); +} + +static JSString* FASTCALL +Array_p_toString(JSContext* cx, JSObject* obj) +{ + jsval v; + if (!array_join_sub(cx, obj, TO_STRING, NULL, &v)) + return NULL; + JS_ASSERT(JSVAL_IS_STRING(v)); + return JSVAL_TO_STRING(v); +} +#endif + +/* + * Perl-inspired join, reverse, and sort. + */ +static JSBool +array_join(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + JSObject *obj; + + if (argc == 0 || JSVAL_IS_VOID(vp[2])) { + str = NULL; + } else { + str = js_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + vp[2] = STRING_TO_JSVAL(str); + } + obj = JS_THIS_OBJECT(cx, vp); + return obj && array_join_sub(cx, obj, TO_STRING, str, vp); +} + +static JSBool +array_reverse(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + JSTempValueRooter tvr; + jsuint len, half, i; + JSBool ok, hole, hole2; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !js_GetLengthProperty(cx, obj, &len)) + return JS_FALSE; + + ok = JS_TRUE; + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + half = len / 2; + for (i = 0; i < half; i++) { + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, obj, i, &hole, &tvr.u.value) && + GetArrayElement(cx, obj, len - i - 1, &hole2, vp) && + SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, tvr.u.value) && + SetOrDeleteArrayElement(cx, obj, i, hole2, *vp); + if (!ok) + break; + } + JS_POP_TEMP_ROOT(cx, &tvr); + + *vp = OBJECT_TO_JSVAL(obj); + return ok; +} + +typedef struct MSortArgs { + size_t elsize; + JSComparator cmp; + void *arg; + JSBool fastcopy; +} MSortArgs; + +/* Helper function for js_MergeSort. */ +static JSBool +MergeArrays(MSortArgs *msa, void *src, void *dest, size_t run1, size_t run2) +{ + void *arg, *a, *b, *c; + size_t elsize, runtotal; + int cmp_result; + JSComparator cmp; + JSBool fastcopy; + + runtotal = run1 + run2; + + elsize = msa->elsize; + cmp = msa->cmp; + arg = msa->arg; + fastcopy = msa->fastcopy; + +#define CALL_CMP(a, b) \ + if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; + + /* Copy runs already in sorted order. */ + b = (char *)src + run1 * elsize; + a = (char *)b - elsize; + CALL_CMP(a, b); + if (cmp_result <= 0) { + memcpy(dest, src, runtotal * elsize); + return JS_TRUE; + } + +#define COPY_ONE(p,q,n) \ + (fastcopy ? (void)(*(jsval*)(p) = *(jsval*)(q)) : (void)memcpy(p, q, n)) + + a = src; + c = dest; + for (; runtotal != 0; runtotal--) { + JSBool from_a = run2 == 0; + if (!from_a && run1 != 0) { + CALL_CMP(a,b); + from_a = cmp_result <= 0; + } + + if (from_a) { + COPY_ONE(c, a, elsize); + run1--; + a = (char *)a + elsize; + } else { + COPY_ONE(c, b, elsize); + run2--; + b = (char *)b + elsize; + } + c = (char *)c + elsize; + } +#undef COPY_ONE +#undef CALL_CMP + + return JS_TRUE; +} + +/* + * This sort is stable, i.e. sequence of equal elements is preserved. + * See also bug #224128. + */ +JSBool +js_MergeSort(void *src, size_t nel, size_t elsize, + JSComparator cmp, void *arg, void *tmp) +{ + void *swap, *vec1, *vec2; + MSortArgs msa; + size_t i, j, lo, hi, run; + JSBool fastcopy; + int cmp_result; + + /* Avoid memcpy overhead for word-sized and word-aligned elements. */ + fastcopy = (elsize == sizeof(jsval) && + (((jsuword) src | (jsuword) tmp) & JSVAL_ALIGN) == 0); +#define COPY_ONE(p,q,n) \ + (fastcopy ? (void)(*(jsval*)(p) = *(jsval*)(q)) : (void)memcpy(p, q, n)) +#define CALL_CMP(a, b) \ + if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; +#define INS_SORT_INT 4 + + /* + * Apply insertion sort to small chunks to reduce the number of merge + * passes needed. + */ + for (lo = 0; lo < nel; lo += INS_SORT_INT) { + hi = lo + INS_SORT_INT; + if (hi >= nel) + hi = nel; + for (i = lo + 1; i < hi; i++) { + vec1 = (char *)src + i * elsize; + vec2 = (char *)vec1 - elsize; + for (j = i; j > lo; j--) { + CALL_CMP(vec2, vec1); + /* "<=" instead of "<" insures the sort is stable */ + if (cmp_result <= 0) { + break; + } + + /* Swap elements, using "tmp" as tmp storage */ + COPY_ONE(tmp, vec2, elsize); + COPY_ONE(vec2, vec1, elsize); + COPY_ONE(vec1, tmp, elsize); + vec1 = vec2; + vec2 = (char *)vec1 - elsize; + } + } + } +#undef CALL_CMP +#undef COPY_ONE + + msa.elsize = elsize; + msa.cmp = cmp; + msa.arg = arg; + msa.fastcopy = fastcopy; + + vec1 = src; + vec2 = tmp; + for (run = INS_SORT_INT; run < nel; run *= 2) { + for (lo = 0; lo < nel; lo += 2 * run) { + hi = lo + run; + if (hi >= nel) { + memcpy((char *)vec2 + lo * elsize, (char *)vec1 + lo * elsize, + (nel - lo) * elsize); + break; + } + if (!MergeArrays(&msa, (char *)vec1 + lo * elsize, + (char *)vec2 + lo * elsize, run, + hi + run > nel ? nel - hi : run)) { + return JS_FALSE; + } + } + swap = vec1; + vec1 = vec2; + vec2 = swap; + } + if (src != vec1) + memcpy(src, tmp, nel * elsize); + + return JS_TRUE; +} + +typedef struct CompareArgs { + JSContext *context; + jsval fval; + jsval *elemroot; /* stack needed for js_Invoke */ +} CompareArgs; + +static JSBool +sort_compare(void *arg, const void *a, const void *b, int *result) +{ + jsval av = *(const jsval *)a, bv = *(const jsval *)b; + CompareArgs *ca = (CompareArgs *) arg; + JSContext *cx = ca->context; + jsval *invokevp, *sp; + jsdouble cmp; + + /** + * array_sort deals with holes and undefs on its own and they should not + * come here. + */ + JS_ASSERT(!JSVAL_IS_VOID(av)); + JS_ASSERT(!JSVAL_IS_VOID(bv)); + + if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP)) + return JS_FALSE; + + invokevp = ca->elemroot; + sp = invokevp; + *sp++ = ca->fval; + *sp++ = JSVAL_NULL; + *sp++ = av; + *sp++ = bv; + + if (!js_Invoke(cx, 2, invokevp, 0)) + return JS_FALSE; + + cmp = js_ValueToNumber(cx, invokevp); + if (JSVAL_IS_NULL(*invokevp)) + return JS_FALSE; + + /* Clamp cmp to -1, 0, 1. */ + *result = 0; + if (!JSDOUBLE_IS_NaN(cmp) && cmp != 0) + *result = cmp > 0 ? 1 : -1; + + /* + * XXX else report some kind of error here? ECMA talks about 'consistent + * compare functions' that don't return NaN, but is silent about what the + * result should be. So we currently ignore it. + */ + + return JS_TRUE; +} + +static int +sort_compare_strings(void *arg, const void *a, const void *b, int *result) +{ + jsval av = *(const jsval *)a, bv = *(const jsval *)b; + + JS_ASSERT(JSVAL_IS_STRING(av)); + JS_ASSERT(JSVAL_IS_STRING(bv)); + if (!JS_CHECK_OPERATION_LIMIT((JSContext *)arg, JSOW_JUMP)) + return JS_FALSE; + + *result = (int) js_CompareStrings(JSVAL_TO_STRING(av), JSVAL_TO_STRING(bv)); + return JS_TRUE; +} + +/* + * The array_sort function below assumes JSVAL_NULL is zero in order to + * perform initialization using memset. Other parts of SpiderMonkey likewise + * "know" that JSVAL_NULL is zero; this static assertion covers all cases. + */ +JS_STATIC_ASSERT(JSVAL_NULL == 0); + +static JSBool +array_sort(JSContext *cx, uintN argc, jsval *vp) +{ + jsval *argv, fval, *vec, *mergesort_tmp, v; + JSObject *obj; + CompareArgs ca; + jsuint len, newlen, i, undefs; + JSTempValueRooter tvr; + JSBool hole; + bool ok; + size_t elemsize; + JSString *str; + + /* + * Optimize the default compare function case if all of obj's elements + * have values of type string. + */ + JSBool all_strings; + + argv = JS_ARGV(cx, vp); + if (argc > 0) { + if (JSVAL_IS_PRIMITIVE(argv[0])) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_SORT_ARG); + return JS_FALSE; + } + fval = argv[0]; /* non-default compare function */ + } else { + fval = JSVAL_NULL; + } + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !js_GetLengthProperty(cx, obj, &len)) + return JS_FALSE; + if (len == 0) { + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; + } + + /* + * We need a temporary array of 2 * len jsvals to hold the array elements + * and the scratch space for merge sort. Check that its size does not + * overflow size_t, which would allow for indexing beyond the end of the + * malloc'd vector. + */ +#if JS_BITS_PER_WORD == 32 + if ((size_t)len > ~(size_t)0 / (2 * sizeof(jsval))) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } +#endif + vec = (jsval *) JS_malloc(cx, 2 * (size_t) len * sizeof(jsval)); + if (!vec) + return JS_FALSE; + + /* + * Initialize vec as a root. We will clear elements of vec one by + * one while increasing tvr.count when we know that the property at + * the corresponding index exists and its value must be rooted. + * + * In this way when sorting a huge mostly sparse array we will not + * access the tail of vec corresponding to properties that do not + * exist, allowing OS to avoiding committing RAM. See bug 330812. + * + * After this point control must flow through label out: to exit. + */ + JS_PUSH_TEMP_ROOT(cx, 0, vec, &tvr); + + /* + * By ECMA 262, 15.4.4.11, a property that does not exist (which we + * call a "hole") is always greater than an existing property with + * value undefined and that is always greater than any other property. + * Thus to sort holes and undefs we simply count them, sort the rest + * of elements, append undefs after them and then make holes after + * undefs. + */ + undefs = 0; + newlen = 0; + all_strings = JS_TRUE; + for (i = 0; i < len; i++) { + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP); + if (!ok) + goto out; + + /* Clear vec[newlen] before including it in the rooted set. */ + vec[newlen] = JSVAL_NULL; + tvr.count = newlen + 1; + ok = GetArrayElement(cx, obj, i, &hole, &vec[newlen]); + if (!ok) + goto out; + + if (hole) + continue; + + if (JSVAL_IS_VOID(vec[newlen])) { + ++undefs; + continue; + } + + /* We know JSVAL_IS_STRING yields 0 or 1, so avoid a branch via &=. */ + all_strings &= JSVAL_IS_STRING(vec[newlen]); + + ++newlen; + } + + if (newlen == 0) { + /* The array has only holes and undefs. */ + ok = JS_TRUE; + goto out; + } + + /* + * The first newlen elements of vec are copied from the array object + * (above). The remaining newlen positions are used as GC-rooted scratch + * space for mergesort. We must clear the space before including it to + * the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize + * initialization using memset. + */ + mergesort_tmp = vec + newlen; + memset(mergesort_tmp, 0, newlen * sizeof(jsval)); + tvr.count = newlen * 2; + + /* Here len == 2 * (newlen + undefs + number_of_holes). */ + if (fval == JSVAL_NULL) { + /* + * Sort using the default comparator converting all elements to + * strings. + */ + if (all_strings) { + elemsize = sizeof(jsval); + } else { + /* + * To avoid string conversion on each compare we do it only once + * prior to sorting. But we also need the space for the original + * values to recover the sorting result. To reuse + * sort_compare_strings we move the original values to the odd + * indexes in vec, put the string conversion results in the even + * indexes and pass 2 * sizeof(jsval) as an element size to the + * sorting function. In this way sort_compare_strings will only + * see the string values when it casts the compare arguments as + * pointers to jsval. + * + * This requires doubling the temporary storage including the + * scratch space for the merge sort. Since vec already contains + * the rooted scratch space for newlen elements at the tail, we + * can use it to rearrange and convert to strings first and try + * realloc only when we know that we successfully converted all + * the elements. + */ +#if JS_BITS_PER_WORD == 32 + if ((size_t)newlen > ~(size_t)0 / (4 * sizeof(jsval))) { + js_ReportAllocationOverflow(cx); + ok = JS_FALSE; + goto out; + } +#endif + + /* + * Rearrange and string-convert the elements of the vector from + * the tail here and, after sorting, move the results back + * starting from the start to prevent overwrite the existing + * elements. + */ + i = newlen; + do { + --i; + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP); + if (!ok) + goto out; + v = vec[i]; + str = js_ValueToString(cx, v); + if (!str) { + ok = JS_FALSE; + goto out; + } + vec[2 * i] = STRING_TO_JSVAL(str); + vec[2 * i + 1] = v; + } while (i != 0); + + JS_ASSERT(tvr.u.array == vec); + vec = (jsval *) JS_realloc(cx, vec, + 4 * (size_t) newlen * sizeof(jsval)); + if (!vec) { + vec = tvr.u.array; + ok = JS_FALSE; + goto out; + } + tvr.u.array = vec; + mergesort_tmp = vec + 2 * newlen; + memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval)); + tvr.count = newlen * 4; + elemsize = 2 * sizeof(jsval); + } + ok = js_MergeSort(vec, (size_t) newlen, elemsize, + sort_compare_strings, cx, mergesort_tmp); + if (!ok) + goto out; + if (!all_strings) { + /* + * We want to make the following loop fast and to unroot the + * cached results of toString invocations before the operation + * callback has a chance to run the GC. For this reason we do + * not call JS_CHECK_OPERATION_LIMIT in the loop. + */ + i = 0; + do { + vec[i] = vec[2 * i + 1]; + } while (++i != newlen); + } + } else { + void *mark; + + ca.context = cx; + ca.fval = fval; + ca.elemroot = js_AllocStack(cx, 2 + 2, &mark); + if (!ca.elemroot) { + ok = JS_FALSE; + goto out; + } + ok = js_MergeSort(vec, (size_t) newlen, sizeof(jsval), + sort_compare, &ca, mergesort_tmp); + js_FreeStack(cx, mark); + if (!ok) + goto out; + } + + /* + * We no longer need to root the scratch space for the merge sort, so + * unroot it now to make the job of a potential GC under InitArrayElements + * easier. + */ + tvr.count = newlen; + ok = InitArrayElements(cx, obj, 0, newlen, vec); + if (!ok) + goto out; + + out: + JS_POP_TEMP_ROOT(cx, &tvr); + JS_free(cx, vec); + if (!ok) + return JS_FALSE; + + /* Set undefs that sorted after the rest of elements. */ + while (undefs != 0) { + --undefs; + if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || + !SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) { + return JS_FALSE; + } + } + + /* Re-create any holes that sorted to the end of the array. */ + while (len > newlen) { + if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || + !DeleteArrayElement(cx, obj, --len)) { + return JS_FALSE; + } + } + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +/* + * Perl-inspired push, pop, shift, unshift, and splice methods. + */ +static JSBool +array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + jsuint length, newlength; + + if (!js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + newlength = length + argc; + if (!InitArrayElements(cx, obj, length, newlength, argv)) + return JS_FALSE; + + /* Per ECMA-262, return the new array length. */ + if (!IndexToValue(cx, newlength, rval)) + return JS_FALSE; + return js_SetLengthProperty(cx, obj, newlength); +} + +static JSBool +array_push1_dense(JSContext* cx, JSObject* obj, jsval v, jsval *rval) +{ + uint32 length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (INDEX_TOO_SPARSE(obj, length)) { + if (!js_MakeArraySlow(cx, obj)) + return JS_FALSE; + return array_push_slowly(cx, obj, 1, &v, rval); + } + + if (!EnsureLength(cx, obj, length + 1)) + return JS_FALSE; + obj->fslots[JSSLOT_ARRAY_LENGTH] = length + 1; + + JS_ASSERT(obj->dslots[length] == JSVAL_HOLE); + obj->fslots[JSSLOT_ARRAY_COUNT]++; + obj->dslots[length] = v; + return IndexToValue(cx, obj->fslots[JSSLOT_ARRAY_LENGTH], rval); +} + +#ifdef JS_TRACER +static jsval FASTCALL +Array_p_push1(JSContext* cx, JSObject* obj, jsval v) +{ + if (OBJ_IS_DENSE_ARRAY(cx, obj) + ? array_push1_dense(cx, obj, v, &v) + : array_push_slowly(cx, obj, 1, &v, &v)) { + return v; + } + return JSVAL_ERROR_COOKIE; +} +#endif + +static JSBool +array_push(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + /* Insist on one argument and obj of the expected class. */ + obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + if (argc != 1 || !OBJ_IS_DENSE_ARRAY(cx, obj)) + return array_push_slowly(cx, obj, argc, vp + 2, vp); + + return array_push1_dense(cx, obj, vp[2], vp); +} + +static JSBool +array_pop_slowly(JSContext *cx, JSObject* obj, jsval *vp) +{ + jsuint index; + JSBool hole; + + if (!js_GetLengthProperty(cx, obj, &index)) + return JS_FALSE; + if (index == 0) { + *vp = JSVAL_VOID; + } else { + index--; + + /* Get the to-be-deleted property's value into vp. */ + if (!GetArrayElement(cx, obj, index, &hole, vp)) + return JS_FALSE; + if (!hole && !DeleteArrayElement(cx, obj, index)) + return JS_FALSE; + } + return js_SetLengthProperty(cx, obj, index); +} + +static JSBool +array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp) +{ + jsuint index; + JSBool hole; + + index = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (index == 0) { + *vp = JSVAL_VOID; + return JS_TRUE; + } + index--; + if (!GetArrayElement(cx, obj, index, &hole, vp)) + return JS_FALSE; + if (!hole && !DeleteArrayElement(cx, obj, index)) + return JS_FALSE; + obj->fslots[JSSLOT_ARRAY_LENGTH] = index; + return JS_TRUE; + +} + +#ifdef JS_TRACER +static jsval FASTCALL +Array_p_pop(JSContext* cx, JSObject* obj) +{ + jsval v; + if (OBJ_IS_DENSE_ARRAY(cx, obj) + ? array_pop_dense(cx, obj, &v) + : array_pop_slowly(cx, obj, &v)) { + return v; + } + return JSVAL_ERROR_COOKIE; +} +#endif + +static JSBool +array_pop(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + if (OBJ_IS_DENSE_ARRAY(cx, obj)) + return array_pop_dense(cx, obj, vp); + return array_pop_slowly(cx, obj, vp); +} + +static JSBool +array_shift(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + jsuint length, i; + JSBool hole, ok; + JSTempValueRooter tvr; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + if (length == 0) { + *vp = JSVAL_VOID; + } else { + length--; + + /* Get the to-be-deleted property's value into vp ASAP. */ + if (!GetArrayElement(cx, obj, 0, &hole, vp)) + return JS_FALSE; + + /* Slide down the array above the first element. */ + ok = JS_TRUE; + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + for (i = 0; i != length; i++) { + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, obj, i + 1, &hole, &tvr.u.value) && + SetOrDeleteArrayElement(cx, obj, i, hole, tvr.u.value); + if (!ok) + break; + } + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return JS_FALSE; + + /* Delete the only or last element when it exist. */ + if (!hole && !DeleteArrayElement(cx, obj, length)) + return JS_FALSE; + } + return js_SetLengthProperty(cx, obj, length); +} + +static JSBool +array_unshift(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + jsval *argv; + jsuint length, last; + JSBool hole, ok; + JSTempValueRooter tvr; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + if (argc > 0) { + /* Slide up the array to make room for argc at the bottom. */ + argv = JS_ARGV(cx, vp); + if (length > 0) { + last = length; + ok = JS_TRUE; + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + do { + --last; + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, obj, last, &hole, &tvr.u.value) && + SetOrDeleteArrayElement(cx, obj, last + argc, hole, + tvr.u.value); + if (!ok) + break; + } while (last != 0); + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return JS_FALSE; + } + + /* Copy from argv to the bottom of the array. */ + if (!InitArrayElements(cx, obj, 0, argc, argv)) + return JS_FALSE; + + length += argc; + if (!js_SetLengthProperty(cx, obj, length)) + return JS_FALSE; + } + + /* Follow Perl by returning the new array length. */ + return IndexToValue(cx, length, vp); +} + +static JSBool +array_splice(JSContext *cx, uintN argc, jsval *vp) +{ + jsval *argv; + JSObject *obj; + jsuint length, begin, end, count, delta, last; + jsdouble d; + JSBool hole, ok; + JSObject *obj2; + JSTempValueRooter tvr; + + /* + * Create a new array value to return. Our ECMA v2 proposal specs + * that splice always returns an array value, even when given no + * arguments. We think this is best because it eliminates the need + * for callers to do an extra test to handle the empty splice case. + */ + obj2 = js_NewArrayObject(cx, 0, NULL); + if (!obj2) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(obj2); + + /* Nothing to do if no args. Otherwise get length. */ + if (argc == 0) + return JS_TRUE; + argv = JS_ARGV(cx, vp); + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + + /* Convert the first argument into a starting index. */ + d = js_ValueToNumber(cx, argv); + if (JSVAL_IS_NULL(*argv)) + return JS_FALSE; + d = js_DoubleToInteger(d); + if (d < 0) { + d += length; + if (d < 0) + d = 0; + } else if (d > length) { + d = length; + } + begin = (jsuint)d; /* d has been clamped to uint32 */ + argc--; + argv++; + + /* Convert the second argument from a count into a fencepost index. */ + delta = length - begin; + if (argc == 0) { + count = delta; + end = length; + } else { + d = js_ValueToNumber(cx, argv); + if (JSVAL_IS_NULL(*argv)) + return JS_FALSE; + d = js_DoubleToInteger(d); + if (d < 0) + d = 0; + else if (d > delta) + d = delta; + count = (jsuint)d; + end = begin + count; + argc--; + argv++; + } + + MUST_FLOW_THROUGH("out"); + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + + /* If there are elements to remove, put them into the return value. */ + if (count > 0) { + for (last = begin; last < end; last++) { + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, obj, last, &hole, &tvr.u.value); + if (!ok) + goto out; + + /* Copy tvr.u.value to new array unless it's a hole. */ + if (!hole) { + ok = SetArrayElement(cx, obj2, last - begin, tvr.u.value); + if (!ok) + goto out; + } + } + + ok = js_SetLengthProperty(cx, obj2, end - begin); + if (!ok) + goto out; + } + + /* Find the direction (up or down) to copy and make way for argv. */ + if (argc > count) { + delta = (jsuint)argc - count; + last = length; + /* (uint) end could be 0, so can't use vanilla >= test */ + while (last-- > end) { + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, obj, last, &hole, &tvr.u.value) && + SetOrDeleteArrayElement(cx, obj, last + delta, hole, + tvr.u.value); + if (!ok) + goto out; + } + length += delta; + } else if (argc < count) { + delta = count - (jsuint)argc; + for (last = end; last < length; last++) { + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, obj, last, &hole, &tvr.u.value) && + SetOrDeleteArrayElement(cx, obj, last - delta, hole, + tvr.u.value); + if (!ok) + goto out; + } + length -= delta; + } + + /* Copy from argv into the hole to complete the splice. */ + ok = InitArrayElements(cx, obj, begin, begin + argc, argv); + if (!ok) + goto out; + + /* Update length in case we deleted elements from the end. */ + ok = js_SetLengthProperty(cx, obj, length); + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +/* + * Python-esque sequence operations. + */ +static JSBool +array_concat(JSContext *cx, uintN argc, jsval *vp) +{ + jsval *argv, v; + JSObject *aobj, *nobj; + jsuint length, alength, slot; + uintN i; + JSBool hole, ok; + JSTempValueRooter tvr; + + /* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */ + argv = JS_ARGV(cx, vp) - 1; + JS_ASSERT(JS_THIS_OBJECT(cx, vp) == JSVAL_TO_OBJECT(argv[0])); + + /* Create a new Array object and root it using *vp. */ + aobj = JS_THIS_OBJECT(cx, vp); + if (OBJ_IS_DENSE_ARRAY(cx, aobj)) { + /* + * Clone aobj but pass the minimum of its length and capacity (aka + * "dense length"), to handle a = [1,2,3]; a.length = 10000 "dense" + * cases efficiently. In such a case we'll pass 8 (not 3) due to the + * ARRAY_GROWBY over-allocation policy, which will cause nobj to be + * over-allocated to 16. But in the normal case where length is <= + * capacity, nobj and aobj will have the same dense length. + */ + length = aobj->fslots[JSSLOT_ARRAY_LENGTH]; + jsuint capacity = ARRAY_DENSE_LENGTH(aobj); + nobj = js_NewArrayObject(cx, JS_MIN(length, capacity), aobj->dslots, + aobj->fslots[JSSLOT_ARRAY_COUNT] != + (jsval) length); + if (!nobj) + return JS_FALSE; + nobj->fslots[JSSLOT_ARRAY_LENGTH] = length; + *vp = OBJECT_TO_JSVAL(nobj); + if (argc == 0) + return JS_TRUE; + argc--; + argv++; + } else { + nobj = js_NewArrayObject(cx, 0, NULL); + if (!nobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(nobj); + length = 0; + } + + MUST_FLOW_THROUGH("out"); + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + + /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */ + for (i = 0; i <= argc; i++) { + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP); + if (!ok) + goto out; + v = argv[i]; + if (!JSVAL_IS_PRIMITIVE(v)) { + JSObject *wobj; + + aobj = JSVAL_TO_OBJECT(v); + wobj = js_GetWrappedObject(cx, aobj); + if (OBJ_IS_ARRAY(cx, wobj)) { + ok = OBJ_GET_PROPERTY(cx, aobj, + ATOM_TO_JSID(cx->runtime->atomState + .lengthAtom), + &tvr.u.value); + if (!ok) + goto out; + alength = ValueIsLength(cx, &tvr.u.value); + ok = !JSVAL_IS_NULL(tvr.u.value); + if (!ok) + goto out; + for (slot = 0; slot < alength; slot++) { + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, aobj, slot, &hole, + &tvr.u.value); + if (!ok) + goto out; + + /* + * Per ECMA 262, 15.4.4.4, step 9, ignore non-existent + * properties. + */ + if (!hole) { + ok = SetArrayElement(cx, nobj, length + slot, + tvr.u.value); + if (!ok) + goto out; + } + } + length += alength; + continue; + } + } + + ok = SetArrayElement(cx, nobj, length, v); + if (!ok) + goto out; + length++; + } + + ok = js_SetLengthProperty(cx, nobj, length); + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +static JSBool +array_slice(JSContext *cx, uintN argc, jsval *vp) +{ + jsval *argv; + JSObject *nobj, *obj; + jsuint length, begin, end, slot; + jsdouble d; + JSBool hole, ok; + JSTempValueRooter tvr; + + argv = JS_ARGV(cx, vp); + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + begin = 0; + end = length; + + if (argc > 0) { + d = js_ValueToNumber(cx, &argv[0]); + if (JSVAL_IS_NULL(argv[0])) + return JS_FALSE; + d = js_DoubleToInteger(d); + if (d < 0) { + d += length; + if (d < 0) + d = 0; + } else if (d > length) { + d = length; + } + begin = (jsuint)d; + + if (argc > 1) { + d = js_ValueToNumber(cx, &argv[1]); + if (JSVAL_IS_NULL(argv[1])) + return JS_FALSE; + d = js_DoubleToInteger(d); + if (d < 0) { + d += length; + if (d < 0) + d = 0; + } else if (d > length) { + d = length; + } + end = (jsuint)d; + } + } + + if (begin > end) + begin = end; + + if (OBJ_IS_DENSE_ARRAY(cx, obj) && end <= ARRAY_DENSE_LENGTH(obj)) { + nobj = js_NewArrayObject(cx, end - begin, obj->dslots + begin, + obj->fslots[JSSLOT_ARRAY_COUNT] != + obj->fslots[JSSLOT_ARRAY_LENGTH]); + if (!nobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(nobj); + return JS_TRUE; + } + + /* Create a new Array object and root it using *vp. */ + nobj = js_NewArrayObject(cx, 0, NULL); + if (!nobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(nobj); + + MUST_FLOW_THROUGH("out"); + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + + for (slot = begin; slot < end; slot++) { + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, obj, slot, &hole, &tvr.u.value); + if (!ok) + goto out; + if (!hole) { + ok = SetArrayElement(cx, nobj, slot - begin, tvr.u.value); + if (!ok) + goto out; + } + } + ok = js_SetLengthProperty(cx, nobj, end - begin); + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +#if JS_HAS_ARRAY_EXTRAS + +static JSBool +array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, jsval *vp) +{ + JSObject *obj; + jsuint length, i, stop; + jsval tosearch; + jsint direction; + JSBool hole; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + if (length == 0) + goto not_found; + + if (argc <= 1) { + i = isLast ? length - 1 : 0; + tosearch = (argc != 0) ? vp[2] : JSVAL_VOID; + } else { + jsdouble start; + + tosearch = vp[2]; + start = js_ValueToNumber(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return JS_FALSE; + start = js_DoubleToInteger(start); + if (start < 0) { + start += length; + if (start < 0) { + if (isLast) + goto not_found; + i = 0; + } else { + i = (jsuint)start; + } + } else if (start >= length) { + if (!isLast) + goto not_found; + i = length - 1; + } else { + i = (jsuint)start; + } + } + + if (isLast) { + stop = 0; + direction = -1; + } else { + stop = length - 1; + direction = 1; + } + + for (;;) { + if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || + !GetArrayElement(cx, obj, (jsuint)i, &hole, vp)) { + return JS_FALSE; + } + if (!hole && js_StrictlyEqual(cx, *vp, tosearch)) + return js_NewNumberInRootedValue(cx, i, vp); + if (i == stop) + goto not_found; + i += direction; + } + + not_found: + *vp = INT_TO_JSVAL(-1); + return JS_TRUE; +} + +static JSBool +array_indexOf(JSContext *cx, uintN argc, jsval *vp) +{ + return array_indexOfHelper(cx, JS_FALSE, argc, vp); +} + +static JSBool +array_lastIndexOf(JSContext *cx, uintN argc, jsval *vp) +{ + return array_indexOfHelper(cx, JS_TRUE, argc, vp); +} + +/* Order is important; extras that take a predicate funarg must follow MAP. */ +typedef enum ArrayExtraMode { + FOREACH, + REDUCE, + REDUCE_RIGHT, + MAP, + FILTER, + SOME, + EVERY +} ArrayExtraMode; + +#define REDUCE_MODE(mode) ((mode) == REDUCE || (mode) == REDUCE_RIGHT) + +static JSBool +array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) +{ + JSObject *obj; + jsuint length, newlen; + jsval *argv, *elemroot, *invokevp, *sp; + JSBool ok, cond, hole; + JSObject *callable, *thisp, *newarr; + jsint start, end, step, i; + void *mark; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + + /* + * First, get or compute our callee, so that we error out consistently + * when passed a non-callable object. + */ + if (argc == 0) { + js_ReportMissingArg(cx, vp, 0); + return JS_FALSE; + } + argv = vp + 2; + callable = js_ValueToCallableObject(cx, &argv[0], JSV2F_SEARCH_STACK); + if (!callable) + return JS_FALSE; + + /* + * Set our initial return condition, used for zero-length array cases + * (and pre-size our map return to match our known length, for all cases). + */ +#ifdef __GNUC__ /* quell GCC overwarning */ + newlen = 0; + newarr = NULL; +#endif + start = 0, end = length, step = 1; + + switch (mode) { + case REDUCE_RIGHT: + start = length - 1, end = -1, step = -1; + /* FALL THROUGH */ + case REDUCE: + if (length == 0 && argc == 1) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_EMPTY_ARRAY_REDUCE); + return JS_FALSE; + } + if (argc >= 2) { + *vp = argv[1]; + } else { + do { + if (!GetArrayElement(cx, obj, start, &hole, vp)) + return JS_FALSE; + start += step; + } while (hole && start != end); + + if (hole && start == end) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_EMPTY_ARRAY_REDUCE); + return JS_FALSE; + } + } + break; + case MAP: + case FILTER: + newlen = (mode == MAP) ? length : 0; + newarr = js_NewArrayObject(cx, newlen, NULL); + if (!newarr) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(newarr); + break; + case SOME: + *vp = JSVAL_FALSE; + break; + case EVERY: + *vp = JSVAL_TRUE; + break; + case FOREACH: + *vp = JSVAL_VOID; + break; + } + + if (length == 0) + return JS_TRUE; + + if (argc > 1 && !REDUCE_MODE(mode)) { + if (!js_ValueToObject(cx, argv[1], &thisp)) + return JS_FALSE; + argv[1] = OBJECT_TO_JSVAL(thisp); + } else { + thisp = NULL; + } + + /* + * For all but REDUCE, we call with 3 args (value, index, array). REDUCE + * requires 4 args (accum, value, index, array). + */ + argc = 3 + REDUCE_MODE(mode); + elemroot = js_AllocStack(cx, 1 + 2 + argc, &mark); + if (!elemroot) + return JS_FALSE; + + MUST_FLOW_THROUGH("out"); + ok = JS_TRUE; + invokevp = elemroot + 1; + + for (i = start; i != end; i += step) { + ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, obj, i, &hole, elemroot); + if (!ok) + goto out; + if (hole) + continue; + + /* + * Push callable and 'this', then args. We must do this for every + * iteration around the loop since js_Invoke uses spbase[0] for return + * value storage, while some native functions use spbase[1] for local + * rooting. + */ + sp = invokevp; + *sp++ = OBJECT_TO_JSVAL(callable); + *sp++ = OBJECT_TO_JSVAL(thisp); + if (REDUCE_MODE(mode)) + *sp++ = *vp; + *sp++ = *elemroot; + *sp++ = INT_TO_JSVAL(i); + *sp++ = OBJECT_TO_JSVAL(obj); + + /* Do the call. */ + ok = js_Invoke(cx, argc, invokevp, 0); + if (!ok) + break; + + if (mode > MAP) + cond = js_ValueToBoolean(*invokevp); +#ifdef __GNUC__ /* quell GCC overwarning */ + else + cond = JS_FALSE; +#endif + + switch (mode) { + case FOREACH: + break; + case REDUCE: + case REDUCE_RIGHT: + *vp = *invokevp; + break; + case MAP: + ok = SetArrayElement(cx, newarr, i, *invokevp); + if (!ok) + goto out; + break; + case FILTER: + if (!cond) + break; + /* The filter passed *elemroot, so push it onto our result. */ + ok = SetArrayElement(cx, newarr, newlen++, *elemroot); + if (!ok) + goto out; + break; + case SOME: + if (cond) { + *vp = JSVAL_TRUE; + goto out; + } + break; + case EVERY: + if (!cond) { + *vp = JSVAL_FALSE; + goto out; + } + break; + } + } + + out: + js_FreeStack(cx, mark); + if (ok && mode == FILTER) + ok = js_SetLengthProperty(cx, newarr, newlen); + return ok; +} + +static JSBool +array_forEach(JSContext *cx, uintN argc, jsval *vp) +{ + return array_extra(cx, FOREACH, argc, vp); +} + +static JSBool +array_map(JSContext *cx, uintN argc, jsval *vp) +{ + return array_extra(cx, MAP, argc, vp); +} + +static JSBool +array_reduce(JSContext *cx, uintN argc, jsval *vp) +{ + return array_extra(cx, REDUCE, argc, vp); +} + +static JSBool +array_reduceRight(JSContext *cx, uintN argc, jsval *vp) +{ + return array_extra(cx, REDUCE_RIGHT, argc, vp); +} + +static JSBool +array_filter(JSContext *cx, uintN argc, jsval *vp) +{ + return array_extra(cx, FILTER, argc, vp); +} + +static JSBool +array_some(JSContext *cx, uintN argc, jsval *vp) +{ + return array_extra(cx, SOME, argc, vp); +} + +static JSBool +array_every(JSContext *cx, uintN argc, jsval *vp) +{ + return array_extra(cx, EVERY, argc, vp); +} +#endif + +static JSPropertySpec array_props[] = { + {js_length_str, -1, JSPROP_SHARED | JSPROP_PERMANENT, + array_length_getter, array_length_setter}, + {0,0,0,0,0} +}; + +JS_DEFINE_TRCINFO_1(array_toString, + (2, (static, STRING_FAIL, Array_p_toString, CONTEXT, THIS, 0, 0))) +JS_DEFINE_TRCINFO_1(array_join, + (3, (static, STRING_FAIL, Array_p_join, CONTEXT, THIS, STRING, 0, 0))) +JS_DEFINE_TRCINFO_1(array_push, + (3, (static, JSVAL_FAIL, Array_p_push1, CONTEXT, THIS, JSVAL, 0, 0))) +JS_DEFINE_TRCINFO_1(array_pop, + (2, (static, JSVAL_FAIL, Array_p_pop, CONTEXT, THIS, 0, 0))) + +static JSFunctionSpec array_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, array_toSource, 0,0), +#endif + JS_TN(js_toString_str, array_toString, 0,0, array_toString_trcinfo), + JS_FN(js_toLocaleString_str,array_toLocaleString,0,0), + + /* Perl-ish methods. */ + JS_TN("join", array_join, 1,JSFUN_GENERIC_NATIVE, array_join_trcinfo), + JS_FN("reverse", array_reverse, 0,JSFUN_GENERIC_NATIVE), + JS_FN("sort", array_sort, 1,JSFUN_GENERIC_NATIVE), + JS_TN("push", array_push, 1,JSFUN_GENERIC_NATIVE, array_push_trcinfo), + JS_TN("pop", array_pop, 0,JSFUN_GENERIC_NATIVE, array_pop_trcinfo), + JS_FN("shift", array_shift, 0,JSFUN_GENERIC_NATIVE), + JS_FN("unshift", array_unshift, 1,JSFUN_GENERIC_NATIVE), + JS_FN("splice", array_splice, 2,JSFUN_GENERIC_NATIVE), + + /* Pythonic sequence methods. */ + JS_FN("concat", array_concat, 1,JSFUN_GENERIC_NATIVE), + JS_FN("slice", array_slice, 2,JSFUN_GENERIC_NATIVE), + +#if JS_HAS_ARRAY_EXTRAS + JS_FN("indexOf", array_indexOf, 1,JSFUN_GENERIC_NATIVE), + JS_FN("lastIndexOf", array_lastIndexOf, 1,JSFUN_GENERIC_NATIVE), + JS_FN("forEach", array_forEach, 1,JSFUN_GENERIC_NATIVE), + JS_FN("map", array_map, 1,JSFUN_GENERIC_NATIVE), + JS_FN("reduce", array_reduce, 1,JSFUN_GENERIC_NATIVE), + JS_FN("reduceRight", array_reduceRight, 1,JSFUN_GENERIC_NATIVE), + JS_FN("filter", array_filter, 1,JSFUN_GENERIC_NATIVE), + JS_FN("some", array_some, 1,JSFUN_GENERIC_NATIVE), + JS_FN("every", array_every, 1,JSFUN_GENERIC_NATIVE), +#endif + + JS_FS_END +}; + +JSBool +js_Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + jsuint length; + jsval *vector; + + /* If called without new, replace obj with a new Array object. */ + if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { + obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(obj); + } + + if (argc == 0) { + length = 0; + vector = NULL; + } else if (argc > 1) { + length = (jsuint) argc; + vector = argv; + } else if (!JSVAL_IS_NUMBER(argv[0])) { + length = 1; + vector = argv; + } else { + length = ValueIsLength(cx, &argv[0]); + if (JSVAL_IS_NULL(argv[0])) + return JS_FALSE; + vector = NULL; + } + return InitArrayObject(cx, obj, length, vector); +} + +JS_STATIC_ASSERT(JSSLOT_PRIVATE == JSSLOT_ARRAY_LENGTH); +JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH + 1 == JSSLOT_ARRAY_COUNT); + +#ifdef JS_TRACER + +JSObject* FASTCALL +js_FastNewArray(JSContext* cx, JSObject* proto) +{ + JS_ASSERT(OBJ_IS_ARRAY(cx, proto)); + + JS_ASSERT(JS_ON_TRACE(cx)); + JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject)); + if (!obj) + return NULL; + + JSClass* clasp = &js_ArrayClass; + obj->classword = jsuword(clasp); + + obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto); + obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT]; + + obj->fslots[JSSLOT_ARRAY_LENGTH] = 0; + obj->fslots[JSSLOT_ARRAY_COUNT] = 0; + for (unsigned i = JSSLOT_ARRAY_COUNT + 1; i != JS_INITIAL_NSLOTS; ++i) + obj->fslots[i] = JSVAL_VOID; + + JSObjectOps* ops = clasp->getObjectOps(cx, clasp); + obj->map = ops->newObjectMap(cx, 1, ops, clasp, obj); + if (!obj->map) + return NULL; + obj->dslots = NULL; + return obj; +} + +JSObject* FASTCALL +js_Array_1int(JSContext* cx, JSObject* proto, int32 i) +{ + JS_ASSERT(JS_ON_TRACE(cx)); + JSObject* obj = js_FastNewArray(cx, proto); + if (obj) + obj->fslots[JSSLOT_ARRAY_LENGTH] = i; + return obj; +} + +#define ARRAY_CTOR_GUTS(exact_len, newslots_code) \ + JS_ASSERT(JS_ON_TRACE(cx)); \ + JSObject* obj = js_FastNewArray(cx, proto); \ + if (obj) { \ + const uint32 len = ARRAY_GROWBY; \ + jsval* newslots = (jsval*) JS_malloc(cx, sizeof (jsval) * (len + 1)); \ + if (newslots) { \ + obj->dslots = newslots + 1; \ + ARRAY_SET_DENSE_LENGTH(obj, len); \ + {newslots_code} \ + while (++newslots < obj->dslots + len) \ + *newslots = JSVAL_HOLE; \ + obj->fslots[JSSLOT_ARRAY_LENGTH] = (exact_len); \ + return obj; \ + } \ + } \ + return NULL; + +JSObject* FASTCALL +js_Array_1str(JSContext* cx, JSObject* proto, JSString *str) +{ + ARRAY_CTOR_GUTS(1, *++newslots = STRING_TO_JSVAL(str);) +} + +JSObject* FASTCALL +js_Array_2obj(JSContext* cx, JSObject* proto, JSObject *obj1, JSObject* obj2) +{ + ARRAY_CTOR_GUTS(2, + *++newslots = OBJECT_TO_JSVAL(obj1); + *++newslots = OBJECT_TO_JSVAL(obj2);) +} + +JSObject* FASTCALL +js_Array_3num(JSContext* cx, JSObject* proto, jsdouble n1, jsdouble n2, jsdouble n3) +{ + ARRAY_CTOR_GUTS(3, + if (!js_NewDoubleInRootedValue(cx, n1, ++newslots)) + return NULL; + if (!js_NewDoubleInRootedValue(cx, n2, ++newslots)) + return NULL; + if (!js_NewDoubleInRootedValue(cx, n3, ++newslots)) + return NULL;) +} + +#endif /* JS_TRACER */ + +JSObject * +js_InitArrayClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + + /* Initialize the ops structure used by slow arrays */ + memcpy(&js_SlowArrayObjectOps, &js_ObjectOps, sizeof(JSObjectOps)); + js_SlowArrayObjectOps.trace = slowarray_trace; + js_SlowArrayObjectOps.enumerate = slowarray_enumerate; + js_SlowArrayObjectOps.call = NULL; + + proto = JS_InitClass(cx, obj, NULL, &js_ArrayClass, js_Array, 1, + array_props, array_methods, NULL, NULL); + + /* Initialize the Array prototype object so it gets a length property. */ + if (!proto || !InitArrayObject(cx, proto, 0, NULL)) + return NULL; + return proto; +} + +JSObject * +js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey) +{ + JSTempValueRooter tvr; + JSObject *obj; + + obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL, 0); + if (!obj) + return NULL; + + JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); + if (!InitArrayObject(cx, obj, length, vector, holey)) + obj = NULL; + JS_POP_TEMP_ROOT(cx, &tvr); + + /* Set/clear newborn root, in case we lost it. */ + cx->weakRoots.newborn[GCX_OBJECT] = obj; + return obj; +} + +JSObject * +js_NewSlowArrayObject(JSContext *cx) +{ + JSObject *obj = js_NewObject(cx, &js_SlowArrayClass, NULL, NULL, 0); + if (obj) + obj->fslots[JSSLOT_ARRAY_LENGTH] = 0; + return obj; +} + +#ifdef DEBUG_ARRAYS +JSBool +js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + uintN i; + JSObject *array; + + for (i = 0; i < argc; i++) { + char *bytes; + + bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, argv[i], + NULL); + if (!bytes) + return JS_FALSE; + if (JSVAL_IS_PRIMITIVE(argv[i]) || + !OBJ_IS_ARRAY(cx, (array = JSVAL_TO_OBJECT(argv[i])))) { + fprintf(stderr, "%s: not array\n", bytes); + JS_free(cx, bytes); + continue; + } + fprintf(stderr, "%s: %s (len %lu", bytes, + OBJ_IS_DENSE_ARRAY(cx, array) ? "dense" : "sparse", + array->fslots[JSSLOT_ARRAY_LENGTH]); + if (OBJ_IS_DENSE_ARRAY(cx, array)) { + fprintf(stderr, ", count %lu, denselen %lu", + array->fslots[JSSLOT_ARRAY_COUNT], + ARRAY_DENSE_LENGTH(array)); + } + fputs(")\n", stderr); + JS_free(cx, bytes); + } + return JS_TRUE; +} +#endif + +JS_FRIEND_API(JSBool) +js_ArrayToJSUint8Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSUint8 *dest) +{ + uint32 length; + + if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj)) + return JS_FALSE; + + length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (length < offset + count) + return JS_FALSE; + + jsval v; + jsint vi; + + JSUint8 *dp = dest; + for (uintN i = offset; i < offset+count; i++) { + v = obj->dslots[i]; + if (!JSVAL_IS_INT(v) || (vi = JSVAL_TO_INT(v)) < 0) + return JS_FALSE; + + *dp++ = (JSUint8) vi; + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_ArrayToJSUint16Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSUint16 *dest) +{ + uint32 length; + + if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj)) + return JS_FALSE; + + length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (length < offset + count) + return JS_FALSE; + + jsval v; + jsint vi; + + JSUint16 *dp = dest; + for (uintN i = offset; i < offset+count; i++) { + v = obj->dslots[i]; + if (!JSVAL_IS_INT(v) || (vi = JSVAL_TO_INT(v)) < 0) + return JS_FALSE; + + *dp++ = (JSUint16) vi; + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_ArrayToJSUint32Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSUint32 *dest) +{ + uint32 length; + + if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj)) + return JS_FALSE; + + length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (length < offset + count) + return JS_FALSE; + + jsval v; + jsint vi; + + JSUint32 *dp = dest; + for (uintN i = offset; i < offset+count; i++) { + v = obj->dslots[i]; + if (!JSVAL_IS_INT(v) || (vi = JSVAL_TO_INT(v)) < 0) + return JS_FALSE; + + *dp++ = (JSUint32) vi; + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_ArrayToJSInt8Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSInt8 *dest) +{ + uint32 length; + + if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj)) + return JS_FALSE; + + length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (length < offset + count) + return JS_FALSE; + + jsval v; + JSInt8 *dp = dest; + for (uintN i = offset; i < offset+count; i++) { + v = obj->dslots[i]; + if (!JSVAL_IS_INT(v)) + return JS_FALSE; + + *dp++ = (JSInt8) JSVAL_TO_INT(v); + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_ArrayToJSInt16Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSInt16 *dest) +{ + uint32 length; + + if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj)) + return JS_FALSE; + + length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (length < offset + count) + return JS_FALSE; + + jsval v; + JSInt16 *dp = dest; + for (uintN i = offset; i < offset+count; i++) { + v = obj->dslots[i]; + if (!JSVAL_IS_INT(v)) + return JS_FALSE; + + *dp++ = (JSInt16) JSVAL_TO_INT(v); + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_ArrayToJSInt32Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSInt32 *dest) +{ + uint32 length; + + if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj)) + return JS_FALSE; + + length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (length < offset + count) + return JS_FALSE; + + jsval v; + JSInt32 *dp = dest; + for (uintN i = offset; i < offset+count; i++) { + v = obj->dslots[i]; + if (!JSVAL_IS_INT(v)) + return JS_FALSE; + + *dp++ = (JSInt32) JSVAL_TO_INT(v); + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_ArrayToJSDoubleBuffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + jsdouble *dest) +{ + uint32 length; + + if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj)) + return JS_FALSE; + + length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (length < offset + count) + return JS_FALSE; + + jsval v; + jsdouble *dp = dest; + for (uintN i = offset; i < offset+count; i++) { + v = obj->dslots[i]; + if (JSVAL_IS_INT(v)) + *dp++ = (jsdouble) JSVAL_TO_INT(v); + else if (JSVAL_IS_DOUBLE(v)) + *dp++ = *(JSVAL_TO_DOUBLE(v)); + else + return JS_FALSE; + } + + return JS_TRUE; +} + +JS_DEFINE_CALLINFO_4(extern, BOOL, js_Array_dense_setelem, CONTEXT, OBJECT, INT32, JSVAL, 0, 0) +JS_DEFINE_CALLINFO_2(extern, OBJECT, js_FastNewArray, CONTEXT, OBJECT, 0, 0) +JS_DEFINE_CALLINFO_3(extern, OBJECT, js_Array_1int, CONTEXT, OBJECT, INT32, 0, 0) +JS_DEFINE_CALLINFO_3(extern, OBJECT, js_Array_1str, CONTEXT, OBJECT, STRING, 0, 0) +JS_DEFINE_CALLINFO_4(extern, OBJECT, js_Array_2obj, CONTEXT, OBJECT, OBJECT, OBJECT, 0, 0) +JS_DEFINE_CALLINFO_5(extern, OBJECT, js_Array_3num, CONTEXT, OBJECT, DOUBLE, DOUBLE, DOUBLE, 0, 0) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarray.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarray.h new file mode 100644 index 0000000..ef10316 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsarray.h @@ -0,0 +1,191 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsarray_h___ +#define jsarray_h___ +/* + * JS Array interface. + */ +#include "jsprvtd.h" +#include "jspubtd.h" + +JS_BEGIN_EXTERN_C + +/* Generous sanity-bound on length (in elements) of array initialiser. */ +#define ARRAY_INIT_LIMIT JS_BIT(24) + +extern JSBool +js_IdIsIndex(jsval id, jsuint *indexp); + +extern JSClass js_ArrayClass, js_SlowArrayClass; + +#define OBJ_IS_DENSE_ARRAY(cx,obj) (OBJ_GET_CLASS(cx, obj) == &js_ArrayClass) + +#define OBJ_IS_ARRAY(cx,obj) (OBJ_IS_DENSE_ARRAY(cx, obj) || \ + OBJ_GET_CLASS(cx, obj) == &js_SlowArrayClass) + +extern JSObject * +js_InitArrayClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, + JSBool holey = JS_FALSE); + +/* Create an array object that starts out already made slow/sparse. */ +extern JSObject * +js_NewSlowArrayObject(JSContext *cx); + +extern JSBool +js_MakeArraySlow(JSContext *cx, JSObject *obj); + +#define JSSLOT_ARRAY_LENGTH JSSLOT_PRIVATE +#define JSSLOT_ARRAY_COUNT (JSSLOT_ARRAY_LENGTH + 1) +#define JSSLOT_ARRAY_LOOKUP_HOLDER (JSSLOT_ARRAY_COUNT + 1) + +#define ARRAY_DENSE_LENGTH(obj) \ + (JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj)), \ + (obj)->dslots ? (uint32)(obj)->dslots[-1] : 0) + +#define ARRAY_SET_DENSE_LENGTH(obj, max) \ + (JS_ASSERT((obj)->dslots), (obj)->dslots[-1] = (jsval)(max)) + +#define ARRAY_GROWBY 8 + +extern JSBool +js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp); + +extern JSBool +js_SetLengthProperty(JSContext *cx, JSObject *obj, jsuint length); + +extern JSBool +js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp); + +extern JSBool JS_FASTCALL +js_IndexToId(JSContext *cx, jsuint index, jsid *idp); + +/* + * Test whether an object is "array-like". Currently this means whether obj + * is an Array or an arguments object. We would like an API, and probably a + * way in the language, to bless other objects as array-like: having indexed + * properties, and a 'length' property of uint32 value equal to one more than + * the greatest index. + */ +extern JSBool +js_IsArrayLike(JSContext *cx, JSObject *obj, JSBool *answerp, jsuint *lengthp); + +/* + * JS-specific merge sort function. + */ +typedef JSBool (*JSComparator)(void *arg, const void *a, const void *b, + int *result); +/* + * NB: vec is the array to be sorted, tmp is temporary space at least as big + * as vec. Both should be GC-rooted if appropriate. + * + * The sorted result is in vec. vec may be in an inconsistent state if the + * comparator function cmp returns an error inside a comparison, so remember + * to check the return value of this function. + */ +extern JSBool +js_MergeSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, + void *arg, void *tmp); + +#ifdef DEBUG_ARRAYS +extern JSBool +js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +#endif + +/* + * Fast dense-array-to-buffer conversions. + * + * If the array is a dense array, fill [offset..offset+count] values + * into destination, assuming that types are consistent. Return + * JS_TRUE if successful, otherwise JS_FALSE -- note that the + * destination buffer may be modified even if JS_FALSE is returned + * (e.g. due to finding an inappropriate type later on in the array). + * If JS_FALSE is returned, no error conditions or exceptions are set + * on the context. + * + * For ArrayToJSUint8, ArrayToJSUint16, and ArrayToJSUint32, each element + * in the array a) must be an integer; b) must be >= 0. Integers + * are clamped to fit in the destination size. Only JSVAL_IS_INT values + * are considered to be valid, so for JSUint32, the maximum value that + * can be fast-converted is less than the full unsigned 32-bit range. + * + * For ArrayToJSInt8, ArrayToJSInt16, ArrayToJSInt32, each element in + * the array must be an integer. Integers are clamped to fit in the + * destination size. Only JSVAL_IS_INT values are considered to be + * valid, so for JSInt32, the maximum value that can be + * fast-converted is less than the full signed 32-bit range. + * + * For ArrayToJSDouble, each element in the array must be an + * integer -or- a double (JSVAL_IS_NUMBER). + */ + +JS_FRIEND_API(JSBool) +js_ArrayToJSUint8Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSUint8 *dest); + +JS_FRIEND_API(JSBool) +js_ArrayToJSUint16Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSUint16 *dest); + +JS_FRIEND_API(JSBool) +js_ArrayToJSUint32Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSUint32 *dest); + +JS_FRIEND_API(JSBool) +js_ArrayToJSInt8Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSInt8 *dest); + +JS_FRIEND_API(JSBool) +js_ArrayToJSInt16Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSInt16 *dest); + +JS_FRIEND_API(JSBool) +js_ArrayToJSInt32Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + JSInt32 *dest); + +JS_FRIEND_API(JSBool) +js_ArrayToJSDoubleBuffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count, + jsdouble *dest); + +JS_END_EXTERN_C + +#endif /* jsarray_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsatom.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsatom.cpp new file mode 100644 index 0000000..7bcfeca --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsatom.cpp @@ -0,0 +1,1064 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS atom table. + */ +#include "jsstddef.h" +#include +#include +#include "jstypes.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jshash.h" /* Added by JSIFY */ +#include "jsprf.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsgc.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsscan.h" +#include "jsstr.h" + +const char * +js_AtomToPrintableString(JSContext *cx, JSAtom *atom) +{ + return js_ValueToPrintableString(cx, ATOM_KEY(atom)); +} + +#define JS_PROTO(name,code,init) const char js_##name##_str[] = #name; +#include "jsproto.tbl" +#undef JS_PROTO + +/* + * String constants for common atoms defined in JSAtomState starting from + * JSAtomState.emptyAtom until JSAtomState.lazy. + * + * The elements of the array after the first empty string define strings + * corresponding to the two boolean literals, false and true, followed by the + * JSType enumerators from jspubtd.h starting with "undefined" for JSTYPE_VOID + * (which is pseudo-boolean 2) and continuing as initialized below. The static + * asserts check these relations. + */ +JS_STATIC_ASSERT(JSTYPE_LIMIT == 8); +JS_STATIC_ASSERT(JSVAL_TO_BOOLEAN(JSVAL_VOID) == 2); +JS_STATIC_ASSERT(JSTYPE_VOID == 0); + +const char *const js_common_atom_names[] = { + "", /* emptyAtom */ + js_false_str, /* booleanAtoms[0] */ + js_true_str, /* booleanAtoms[1] */ + js_undefined_str, /* typeAtoms[JSTYPE_VOID] */ + js_object_str, /* typeAtoms[JSTYPE_OBJECT] */ + js_function_str, /* typeAtoms[JSTYPE_FUNCTION] */ + "string", /* typeAtoms[JSTYPE_STRING] */ + "number", /* typeAtoms[JSTYPE_NUMBER] */ + "boolean", /* typeAtoms[JSTYPE_BOOLEAN] */ + js_null_str, /* typeAtoms[JSTYPE_NULL] */ + "xml", /* typeAtoms[JSTYPE_XML] */ + js_null_str, /* nullAtom */ + +#define JS_PROTO(name,code,init) js_##name##_str, +#include "jsproto.tbl" +#undef JS_PROTO + + js_anonymous_str, /* anonymousAtom */ + js_apply_str, /* applyAtom */ + js_arguments_str, /* argumentsAtom */ + js_arity_str, /* arityAtom */ + js_call_str, /* callAtom */ + js_callee_str, /* calleeAtom */ + js_caller_str, /* callerAtom */ + js_class_prototype_str, /* classPrototypeAtom */ + js_constructor_str, /* constructorAtom */ + js_count_str, /* countAtom */ + js_each_str, /* eachAtom */ + js_eval_str, /* evalAtom */ + js_fileName_str, /* fileNameAtom */ + js_get_str, /* getAtom */ + js_getter_str, /* getterAtom */ + js_index_str, /* indexAtom */ + js_input_str, /* inputAtom */ + js_iterator_str, /* iteratorAtom */ + js_length_str, /* lengthAtom */ + js_lineNumber_str, /* lineNumberAtom */ + js_message_str, /* messageAtom */ + js_name_str, /* nameAtom */ + js_next_str, /* nextAtom */ + js_noSuchMethod_str, /* noSuchMethodAtom */ + js_parent_str, /* parentAtom */ + js_proto_str, /* protoAtom */ + js_set_str, /* setAtom */ + js_setter_str, /* setterAtom */ + js_stack_str, /* stackAtom */ + js_toLocaleString_str, /* toLocaleStringAtom */ + js_toSource_str, /* toSourceAtom */ + js_toString_str, /* toStringAtom */ + js_valueOf_str, /* valueOfAtom */ + js_toJSON_str, /* toJSONAtom */ + "(void 0)", /* void0Atom */ + +#if JS_HAS_XML_SUPPORT + js_etago_str, /* etagoAtom */ + js_namespace_str, /* namespaceAtom */ + js_ptagc_str, /* ptagcAtom */ + js_qualifier_str, /* qualifierAtom */ + js_space_str, /* spaceAtom */ + js_stago_str, /* stagoAtom */ + js_star_str, /* starAtom */ + js_starQualifier_str, /* starQualifierAtom */ + js_tagc_str, /* tagcAtom */ + js_xml_str, /* xmlAtom */ +#endif + +#ifdef NARCISSUS + js___call___str, /* __call__Atom */ + js___construct___str, /* __construct__Atom */ + js___hasInstance___str, /* __hasInstance__Atom */ + js_ExecutionContext_str, /* ExecutionContextAtom */ + js_current_str, /* currentAtom */ +#endif +}; + +JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) == + LAZY_ATOM_OFFSET_START - ATOM_OFFSET_START); + +/* + * Interpreter macros called by the trace recorder assume common atom indexes + * fit in one byte of immediate operand. + */ +JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) < 256); + +const size_t js_common_atom_count = JS_ARRAY_LENGTH(js_common_atom_names); + +const char js_anonymous_str[] = "anonymous"; +const char js_apply_str[] = "apply"; +const char js_arguments_str[] = "arguments"; +const char js_arity_str[] = "arity"; +const char js_call_str[] = "call"; +const char js_callee_str[] = "callee"; +const char js_caller_str[] = "caller"; +const char js_class_prototype_str[] = "prototype"; +const char js_constructor_str[] = "constructor"; +const char js_count_str[] = "__count__"; +const char js_each_str[] = "each"; +const char js_eval_str[] = "eval"; +const char js_fileName_str[] = "fileName"; +const char js_get_str[] = "get"; +const char js_getter_str[] = "getter"; +const char js_index_str[] = "index"; +const char js_input_str[] = "input"; +const char js_iterator_str[] = "__iterator__"; +const char js_length_str[] = "length"; +const char js_lineNumber_str[] = "lineNumber"; +const char js_message_str[] = "message"; +const char js_name_str[] = "name"; +const char js_next_str[] = "next"; +const char js_noSuchMethod_str[] = "__noSuchMethod__"; +const char js_object_str[] = "object"; +const char js_parent_str[] = "__parent__"; +const char js_proto_str[] = "__proto__"; +const char js_setter_str[] = "setter"; +const char js_set_str[] = "set"; +const char js_stack_str[] = "stack"; +const char js_toSource_str[] = "toSource"; +const char js_toString_str[] = "toString"; +const char js_toLocaleString_str[] = "toLocaleString"; +const char js_undefined_str[] = "undefined"; +const char js_valueOf_str[] = "valueOf"; +const char js_toJSON_str[] = "toJSON"; + +#if JS_HAS_XML_SUPPORT +const char js_etago_str[] = ""; +const char js_qualifier_str[] = "::"; +const char js_space_str[] = " "; +const char js_stago_str[] = "<"; +const char js_star_str[] = "*"; +const char js_starQualifier_str[] = "*::"; +const char js_tagc_str[] = ">"; +const char js_xml_str[] = "xml"; +#endif + +#if JS_HAS_GENERATORS +const char js_close_str[] = "close"; +const char js_send_str[] = "send"; +#endif + +#ifdef NARCISSUS +const char js___call___str[] = "__call__"; +const char js___construct___str[] = "__construct__"; +const char js___hasInstance___str[] = "__hasInstance__"; +const char js_ExecutionContext_str[] = "ExecutionContext"; +const char js_current_str[] = "current"; +#endif + +/* + * JSAtomState.doubleAtoms and JSAtomState.stringAtoms hashtable entry. To + * support pinned and interned string atoms, we use the lowest bits of the + * keyAndFlags field to store ATOM_PINNED and ATOM_INTERNED flags. + */ +typedef struct JSAtomHashEntry { + JSDHashEntryHdr hdr; + jsuword keyAndFlags; +} JSAtomHashEntry; + +#define ATOM_ENTRY_FLAG_MASK (ATOM_PINNED | ATOM_INTERNED) + +JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JSVAL_ALIGN); + +/* + * Helper macros to access and modify JSAtomHashEntry. + */ +#define TO_ATOM_ENTRY(hdr) ((JSAtomHashEntry *) hdr) +#define ATOM_ENTRY_KEY(entry) \ + ((void *)((entry)->keyAndFlags & ~ATOM_ENTRY_FLAG_MASK)) +#define ATOM_ENTRY_FLAGS(entry) \ + ((uintN)((entry)->keyAndFlags & ATOM_ENTRY_FLAG_MASK)) +#define INIT_ATOM_ENTRY(entry, key) \ + ((void)((entry)->keyAndFlags = (jsuword)(key))) +#define ADD_ATOM_ENTRY_FLAGS(entry, flags) \ + ((void)((entry)->keyAndFlags |= (jsuword)(flags))) +#define CLEAR_ATOM_ENTRY_FLAGS(entry, flags) \ + ((void)((entry)->keyAndFlags &= ~(jsuword)(flags))) + +static JSDHashNumber +HashDouble(JSDHashTable *table, const void *key); + +static JSBool +MatchDouble(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key); + +static JSDHashNumber +HashString(JSDHashTable *table, const void *key); + +static JSBool +MatchString(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key); + +static const JSDHashTableOps DoubleHashOps = { + JS_DHashAllocTable, + JS_DHashFreeTable, + HashDouble, + MatchDouble, + JS_DHashMoveEntryStub, + JS_DHashClearEntryStub, + JS_DHashFinalizeStub, + NULL +}; + +static const JSDHashTableOps StringHashOps = { + JS_DHashAllocTable, + JS_DHashFreeTable, + HashString, + MatchString, + JS_DHashMoveEntryStub, + JS_DHashClearEntryStub, + JS_DHashFinalizeStub, + NULL +}; + +#define IS_DOUBLE_TABLE(table) ((table)->ops == &DoubleHashOps) +#define IS_STRING_TABLE(table) ((table)->ops == &StringHashOps) + +#define IS_INITIALIZED_STATE(state) IS_DOUBLE_TABLE(&(state)->doubleAtoms) + +static JSDHashNumber +HashDouble(JSDHashTable *table, const void *key) +{ + jsdouble d; + + JS_ASSERT(IS_DOUBLE_TABLE(table)); + d = *(jsdouble *)key; + return JSDOUBLE_HI32(d) ^ JSDOUBLE_LO32(d); +} + +static JSDHashNumber +HashString(JSDHashTable *table, const void *key) +{ + JS_ASSERT(IS_STRING_TABLE(table)); + return js_HashString((JSString *)key); +} + +static JSBool +MatchDouble(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key) +{ + JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr); + jsdouble d1, d2; + + JS_ASSERT(IS_DOUBLE_TABLE(table)); + if (entry->keyAndFlags == 0) { + /* See comments in MatchString. */ + return JS_FALSE; + } + + d1 = *(jsdouble *)ATOM_ENTRY_KEY(entry); + d2 = *(jsdouble *)key; + if (JSDOUBLE_IS_NaN(d1)) + return JSDOUBLE_IS_NaN(d2); +#if defined(XP_WIN) + /* XXX MSVC miscompiles such that (NaN == 0) */ + if (JSDOUBLE_IS_NaN(d2)) + return JS_FALSE; +#endif + return d1 == d2; +} + +static JSBool +MatchString(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key) +{ + JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr); + + JS_ASSERT(IS_STRING_TABLE(table)); + if (entry->keyAndFlags == 0) { + /* + * This happens when js_AtomizeString adds a new hash entry and + * releases the lock but before it takes the lock the second time to + * initialize keyAndFlags for the entry. + * + * We always return false for such entries so JS_DHashTableOperate + * never finds them. We clean them during GC's sweep phase. + * + * It means that with a contested lock or when GC is triggered outside + * the lock we may end up adding two entries, but this is a price for + * simpler code. + */ + return JS_FALSE; + } + return js_EqualStrings((JSString *)ATOM_ENTRY_KEY(entry), (JSString *)key); +} + +/* + * For a browser build from 2007-08-09 after the browser starts up there are + * just 55 double atoms, but over 15000 string atoms. Not to penalize more + * economical embeddings allocating too much memory initially we initialize + * atomized strings with just 1K entries. + */ +#define JS_STRING_HASH_COUNT 1024 +#define JS_DOUBLE_HASH_COUNT 64 + +JSBool +js_InitAtomState(JSRuntime *rt) +{ + JSAtomState *state = &rt->atomState; + + /* + * The caller must zero the state before calling this function. + */ + JS_ASSERT(!state->stringAtoms.ops); + JS_ASSERT(!state->doubleAtoms.ops); + + if (!JS_DHashTableInit(&state->stringAtoms, &StringHashOps, + NULL, sizeof(JSAtomHashEntry), + JS_DHASH_DEFAULT_CAPACITY(JS_STRING_HASH_COUNT))) { + state->stringAtoms.ops = NULL; + return JS_FALSE; + } + JS_ASSERT(IS_STRING_TABLE(&state->stringAtoms)); + + if (!JS_DHashTableInit(&state->doubleAtoms, &DoubleHashOps, + NULL, sizeof(JSAtomHashEntry), + JS_DHASH_DEFAULT_CAPACITY(JS_DOUBLE_HASH_COUNT))) { + state->doubleAtoms.ops = NULL; + JS_DHashTableFinish(&state->stringAtoms); + state->stringAtoms.ops = NULL; + return JS_FALSE; + } + JS_ASSERT(IS_DOUBLE_TABLE(&state->doubleAtoms)); + +#ifdef JS_THREADSAFE + js_InitLock(&state->lock); +#endif + JS_ASSERT(IS_INITIALIZED_STATE(state)); + return JS_TRUE; +} + +static JSDHashOperator +js_string_uninterner(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr); + JSRuntime *rt = (JSRuntime *)arg; + JSString *str; + + /* + * Any string entry that remains at this point must be initialized, as the + * last GC should clean any uninitialized ones. + */ + JS_ASSERT(IS_STRING_TABLE(table)); + JS_ASSERT(entry->keyAndFlags != 0); + str = (JSString *)ATOM_ENTRY_KEY(entry); + + /* Pass null as context. */ + js_FinalizeStringRT(rt, str, js_GetExternalStringGCType(str), NULL); + return JS_DHASH_NEXT; +} + +void +js_FinishAtomState(JSRuntime *rt) +{ + JSAtomState *state = &rt->atomState; + + if (!IS_INITIALIZED_STATE(state)) { + /* + * We are called with uninitialized state when JS_NewRuntime fails and + * calls JS_DestroyRuntime on a partially initialized runtime. + */ + return; + } + + JS_DHashTableEnumerate(&state->stringAtoms, js_string_uninterner, rt); + JS_DHashTableFinish(&state->stringAtoms); + JS_DHashTableFinish(&state->doubleAtoms); + +#ifdef JS_THREADSAFE + js_FinishLock(&state->lock); +#endif +#ifdef DEBUG + memset(state, JS_FREE_PATTERN, sizeof *state); +#endif +} + +JSBool +js_InitCommonAtoms(JSContext *cx) +{ + JSAtomState *state = &cx->runtime->atomState; + uintN i; + JSAtom **atoms; + + atoms = COMMON_ATOMS_START(state); + for (i = 0; i < JS_ARRAY_LENGTH(js_common_atom_names); i++, atoms++) { + *atoms = js_Atomize(cx, js_common_atom_names[i], + strlen(js_common_atom_names[i]), ATOM_PINNED); + if (!*atoms) + return JS_FALSE; + } + JS_ASSERT((uint8 *)atoms - (uint8 *)state == LAZY_ATOM_OFFSET_START); + memset(atoms, 0, ATOM_OFFSET_LIMIT - LAZY_ATOM_OFFSET_START); + + return JS_TRUE; +} + +static JSDHashOperator +js_atom_unpinner(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + JS_ASSERT(IS_STRING_TABLE(table)); + CLEAR_ATOM_ENTRY_FLAGS(TO_ATOM_ENTRY(hdr), ATOM_PINNED); + return JS_DHASH_NEXT; +} + +void +js_FinishCommonAtoms(JSContext *cx) +{ + JSAtomState *state = &cx->runtime->atomState; + + JS_DHashTableEnumerate(&state->stringAtoms, js_atom_unpinner, NULL); +#ifdef DEBUG + memset(COMMON_ATOMS_START(state), JS_FREE_PATTERN, + ATOM_OFFSET_LIMIT - ATOM_OFFSET_START); +#endif +} + +static JSDHashOperator +js_locked_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr); + JSTracer *trc = (JSTracer *)arg; + + if (entry->keyAndFlags == 0) { + /* Ignore uninitialized entries during tracing. */ + return JS_DHASH_NEXT; + } + JS_SET_TRACING_INDEX(trc, "locked_atom", (size_t)number); + JS_CallTracer(trc, ATOM_ENTRY_KEY(entry), + IS_STRING_TABLE(table) ? JSTRACE_STRING : JSTRACE_DOUBLE); + return JS_DHASH_NEXT; +} + +static JSDHashOperator +js_pinned_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr); + JSTracer *trc = (JSTracer *)arg; + uintN flags = ATOM_ENTRY_FLAGS(entry); + + JS_ASSERT(IS_STRING_TABLE(table)); + if (flags & (ATOM_PINNED | ATOM_INTERNED)) { + JS_SET_TRACING_INDEX(trc, + flags & ATOM_PINNED + ? "pinned_atom" + : "interned_atom", + (size_t)number); + JS_CallTracer(trc, ATOM_ENTRY_KEY(entry), JSTRACE_STRING); + } + return JS_DHASH_NEXT; +} + +void +js_TraceAtomState(JSTracer *trc, JSBool allAtoms) +{ + JSAtomState *state; + + state = &trc->context->runtime->atomState; + if (allAtoms) { + JS_DHashTableEnumerate(&state->doubleAtoms, js_locked_atom_tracer, trc); + JS_DHashTableEnumerate(&state->stringAtoms, js_locked_atom_tracer, trc); + } else { + JS_DHashTableEnumerate(&state->stringAtoms, js_pinned_atom_tracer, trc); + } +} + +static JSDHashOperator +js_atom_sweeper(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr); + JSContext *cx = (JSContext *)arg; + + /* Remove uninitialized entries. */ + if (entry->keyAndFlags == 0) + return JS_DHASH_REMOVE; + + if (ATOM_ENTRY_FLAGS(entry) & (ATOM_PINNED | ATOM_INTERNED)) { + /* Pinned or interned key cannot be finalized. */ + JS_ASSERT(!js_IsAboutToBeFinalized(cx, ATOM_ENTRY_KEY(entry))); + } else if (js_IsAboutToBeFinalized(cx, ATOM_ENTRY_KEY(entry))) { + /* Remove entries with things about to be GC'ed. */ + return JS_DHASH_REMOVE; + } + return JS_DHASH_NEXT; +} + +void +js_SweepAtomState(JSContext *cx) +{ + JSAtomState *state = &cx->runtime->atomState; + + JS_DHashTableEnumerate(&state->doubleAtoms, js_atom_sweeper, cx); + JS_DHashTableEnumerate(&state->stringAtoms, js_atom_sweeper, cx); + + /* + * Optimize for simplicity and mutate table generation numbers even if the + * sweeper has not removed any entries. + */ + state->doubleAtoms.generation++; + state->stringAtoms.generation++; +} + +JSAtom * +js_AtomizeDouble(JSContext *cx, jsdouble d) +{ + JSAtomState *state; + JSDHashTable *table; + JSAtomHashEntry *entry; + uint32 gen; + jsdouble *key; + jsval v; + + state = &cx->runtime->atomState; + table = &state->doubleAtoms; + + JS_LOCK(cx, &state->lock); + entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, &d, JS_DHASH_ADD)); + if (!entry) + goto failed_hash_add; + if (entry->keyAndFlags == 0) { + gen = ++table->generation; + JS_UNLOCK(cx, &state->lock); + + key = js_NewWeaklyRootedDouble(cx, d); + if (!key) + return NULL; + + JS_LOCK(cx, &state->lock); + if (table->generation == gen) { + JS_ASSERT(entry->keyAndFlags == 0); + } else { + entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key, + JS_DHASH_ADD)); + if (!entry) + goto failed_hash_add; + if (entry->keyAndFlags != 0) + goto finish; + ++table->generation; + } + INIT_ATOM_ENTRY(entry, key); + } + + finish: + v = DOUBLE_TO_JSVAL((jsdouble *)ATOM_ENTRY_KEY(entry)); + cx->weakRoots.lastAtom = v; + JS_UNLOCK(cx, &state->lock); + + return (JSAtom *)v; + + failed_hash_add: + JS_UNLOCK(cx, &state->lock); + JS_ReportOutOfMemory(cx); + return NULL; +} + +JSAtom * +js_AtomizeString(JSContext *cx, JSString *str, uintN flags) +{ + jsval v; + JSAtomState *state; + JSDHashTable *table; + JSAtomHashEntry *entry; + JSString *key; + uint32 gen; + + JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY))); + JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR); + + state = &cx->runtime->atomState; + table = &state->stringAtoms; + + JS_LOCK(cx, &state->lock); + entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, str, JS_DHASH_ADD)); + if (!entry) + goto failed_hash_add; + if (entry->keyAndFlags != 0) { + key = (JSString *)ATOM_ENTRY_KEY(entry); + } else { + /* + * We created a new hashtable entry. Unless str is already allocated + * from the GC heap and flat, we have to release state->lock as + * string construction is a complex operation. For example, it can + * trigger GC which may rehash the table and make the entry invalid. + */ + ++table->generation; + if (!(flags & ATOM_TMPSTR) && JSSTRING_IS_FLAT(str)) { + JSFLATSTR_CLEAR_MUTABLE(str); + key = str; + } else { + gen = table->generation; + JS_UNLOCK(cx, &state->lock); + + if (flags & ATOM_TMPSTR) { + if (flags & ATOM_NOCOPY) { + key = js_NewString(cx, JSFLATSTR_CHARS(str), + JSFLATSTR_LENGTH(str)); + if (!key) + return NULL; + + /* Finish handing off chars to the GC'ed key string. */ + str->u.chars = NULL; + } else { + key = js_NewStringCopyN(cx, JSFLATSTR_CHARS(str), + JSFLATSTR_LENGTH(str)); + if (!key) + return NULL; + } + } else { + JS_ASSERT(JSSTRING_IS_DEPENDENT(str)); + if (!js_UndependString(cx, str)) + return NULL; + key = str; + } + + JS_LOCK(cx, &state->lock); + if (table->generation == gen) { + JS_ASSERT(entry->keyAndFlags == 0); + } else { + entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key, + JS_DHASH_ADD)); + if (!entry) + goto failed_hash_add; + if (entry->keyAndFlags != 0) { + key = (JSString *)ATOM_ENTRY_KEY(entry); + goto finish; + } + ++table->generation; + } + } + INIT_ATOM_ENTRY(entry, key); + JSFLATSTR_SET_ATOMIZED(key); + } + + finish: + ADD_ATOM_ENTRY_FLAGS(entry, flags & (ATOM_PINNED | ATOM_INTERNED)); + JS_ASSERT(JSSTRING_IS_ATOMIZED(key)); + v = STRING_TO_JSVAL(key); + cx->weakRoots.lastAtom = v; + JS_UNLOCK(cx, &state->lock); + return (JSAtom *)v; + + failed_hash_add: + JS_UNLOCK(cx, &state->lock); + JS_ReportOutOfMemory(cx); + return NULL; +} + +JSAtom * +js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags) +{ + jschar *chars; + JSString str; + JSAtom *atom; + + /* + * Avoiding the malloc in js_InflateString on shorter strings saves us + * over 20,000 malloc calls on mozilla browser startup. This compares to + * only 131 calls where the string is longer than a 31 char (net) buffer. + * The vast majority of atomized strings are already in the hashtable. So + * js_AtomizeString rarely has to copy the temp string we make. + */ +#define ATOMIZE_BUF_MAX 32 + jschar inflated[ATOMIZE_BUF_MAX]; + size_t inflatedLength = ATOMIZE_BUF_MAX - 1; + + if (length < ATOMIZE_BUF_MAX) { + js_InflateStringToBuffer(cx, bytes, length, inflated, &inflatedLength); + inflated[inflatedLength] = 0; + chars = inflated; + } else { + inflatedLength = length; + chars = js_InflateString(cx, bytes, &inflatedLength); + if (!chars) + return NULL; + flags |= ATOM_NOCOPY; + } + + JSFLATSTR_INIT(&str, (jschar *)chars, inflatedLength); + atom = js_AtomizeString(cx, &str, ATOM_TMPSTR | flags); + if (chars != inflated && str.u.chars) + JS_free(cx, chars); + return atom; +} + +JSAtom * +js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags) +{ + JSString str; + + JSFLATSTR_INIT(&str, (jschar *)chars, length); + return js_AtomizeString(cx, &str, ATOM_TMPSTR | flags); +} + +JSAtom * +js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length) +{ + JSString str, *str2; + JSAtomState *state; + JSDHashEntryHdr *hdr; + + JSFLATSTR_INIT(&str, (jschar *)chars, length); + state = &cx->runtime->atomState; + + JS_LOCK(cx, &state->lock); + hdr = JS_DHashTableOperate(&state->stringAtoms, &str, JS_DHASH_LOOKUP); + str2 = JS_DHASH_ENTRY_IS_BUSY(hdr) + ? (JSString *)ATOM_ENTRY_KEY(TO_ATOM_ENTRY(hdr)) + : NULL; + JS_UNLOCK(cx, &state->lock); + + return str2 ? (JSAtom *)STRING_TO_JSVAL(str2) : NULL; +} + +JSBool +js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp) +{ + JSAtom *atom; + + if (JSVAL_IS_STRING(v)) { + atom = js_AtomizeString(cx, JSVAL_TO_STRING(v), 0); + if (!atom) + return JS_FALSE; + } else if (JSVAL_IS_DOUBLE(v)) { + atom = js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(v)); + if (!atom) + return JS_FALSE; + } else { + JS_ASSERT(JSVAL_IS_INT(v) || JSVAL_IS_BOOLEAN(v) || + JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)); + atom = (JSAtom *)v; + } + *atomp = atom; + return JS_TRUE; +} + +JSBool +js_ValueToStringId(JSContext *cx, jsval v, jsid *idp) +{ + JSString *str; + JSAtom *atom; + + /* + * Optimize for the common case where v is an already-atomized string. The + * comment in jsstr.h before the JSSTRING_SET_ATOMIZED macro's definition + * explains why this is thread-safe. The extra rooting via lastAtom (which + * would otherwise be done in js_js_AtomizeString) ensures the caller that + * the resulting id at is least weakly rooted. + */ + if (JSVAL_IS_STRING(v)) { + str = JSVAL_TO_STRING(v); + if (JSSTRING_IS_ATOMIZED(str)) { + cx->weakRoots.lastAtom = v; + *idp = ATOM_TO_JSID((JSAtom *) v); + return JS_TRUE; + } + } else { + str = js_ValueToString(cx, v); + if (!str) + return JS_FALSE; + } + atom = js_AtomizeString(cx, str, 0); + if (!atom) + return JS_FALSE; + *idp = ATOM_TO_JSID(atom); + return JS_TRUE; +} + +#ifdef DEBUG + +static JSDHashOperator +atom_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr); + FILE *fp = (FILE *)arg; + void *key; + uintN flags; + + fprintf(fp, "%3u %08x ", number, (uintN)entry->hdr.keyHash); + if (entry->keyAndFlags == 0) { + fputs("", fp); + } else { + key = ATOM_ENTRY_KEY(entry); + if (IS_DOUBLE_TABLE(table)) { + fprintf(fp, "%.16g", *(jsdouble *)key); + } else { + JS_ASSERT(IS_STRING_TABLE(table)); + js_FileEscapedString(fp, (JSString *)key, '"'); + } + flags = ATOM_ENTRY_FLAGS(entry); + if (flags != 0) { + fputs((flags & (ATOM_PINNED | ATOM_INTERNED)) + ? " pinned | interned" + : (flags & ATOM_PINNED) ? " pinned" : " interned", + fp); + } + } + putc('\n', fp); + return JS_DHASH_NEXT; +} + +JS_FRIEND_API(void) +js_DumpAtoms(JSContext *cx, FILE *fp) +{ + JSAtomState *state = &cx->runtime->atomState; + + fprintf(fp, "stringAtoms table contents:\n"); + JS_DHashTableEnumerate(&state->stringAtoms, atom_dumper, fp); +#ifdef JS_DHASHMETER + JS_DHashTableDumpMeter(&state->stringAtoms, atom_dumper, fp); +#endif + putc('\n', fp); + + fprintf(fp, "doubleAtoms table contents:\n"); + JS_DHashTableEnumerate(&state->doubleAtoms, atom_dumper, fp); +#ifdef JS_DHASHMETER + JS_DHashTableDumpMeter(&state->doubleAtoms, atom_dumper, fp); +#endif + putc('\n', fp); +} + +#endif + +static JSHashNumber +js_hash_atom_ptr(const void *key) +{ + const JSAtom *atom = (const JSAtom *) key; + return ATOM_HASH(atom); +} + +static void * +js_alloc_temp_space(void *priv, size_t size) +{ + JSContext *cx = (JSContext *) priv; + void *space; + + JS_ARENA_ALLOCATE(space, &cx->tempPool, size); + if (!space) + js_ReportOutOfScriptQuota(cx); + return space; +} + +static void +js_free_temp_space(void *priv, void *item) +{ +} + +static JSHashEntry * +js_alloc_temp_entry(void *priv, const void *key) +{ + JSContext *cx = (JSContext *) priv; + JSAtomListElement *ale; + + JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &cx->tempPool); + if (!ale) { + js_ReportOutOfScriptQuota(cx); + return NULL; + } + return &ale->entry; +} + +static void +js_free_temp_entry(void *priv, JSHashEntry *he, uintN flag) +{ +} + +static JSHashAllocOps temp_alloc_ops = { + js_alloc_temp_space, js_free_temp_space, + js_alloc_temp_entry, js_free_temp_entry +}; + +JSAtomListElement * +js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al) +{ + JSAtomListElement *ale, *ale2, *next; + JSHashEntry **hep; + + ATOM_LIST_LOOKUP(ale, hep, al, atom); + if (!ale) { + if (al->count < 10) { + /* Few enough for linear search, no hash table needed. */ + JS_ASSERT(!al->table); + ale = (JSAtomListElement *)js_alloc_temp_entry(cx, atom); + if (!ale) + return NULL; + ALE_SET_ATOM(ale, atom); + ale->entry.next = al->list; + al->list = &ale->entry; + } else { + /* We want to hash. Have we already made a hash table? */ + if (!al->table) { + /* No hash table yet, so hep had better be null! */ + JS_ASSERT(!hep); + al->table = JS_NewHashTable(al->count + 1, js_hash_atom_ptr, + JS_CompareValues, JS_CompareValues, + &temp_alloc_ops, cx); + if (!al->table) + return NULL; + + /* + * Set ht->nentries explicitly, because we are moving entries + * from al to ht, not calling JS_HashTable(Raw|)Add. + */ + al->table->nentries = al->count; + + /* Insert each ale on al->list into the new hash table. */ + for (ale2 = (JSAtomListElement *)al->list; ale2; ale2 = next) { + next = ALE_NEXT(ale2); + ale2->entry.keyHash = ATOM_HASH(ALE_ATOM(ale2)); + hep = JS_HashTableRawLookup(al->table, ale2->entry.keyHash, + ale2->entry.key); + ale2->entry.next = *hep; + *hep = &ale2->entry; + } + al->list = NULL; + + /* Set hep for insertion of atom's ale, immediately below. */ + hep = JS_HashTableRawLookup(al->table, ATOM_HASH(atom), atom); + } + + /* Finally, add an entry for atom into the hash bucket at hep. */ + ale = (JSAtomListElement *) + JS_HashTableRawAdd(al->table, hep, ATOM_HASH(atom), atom, + NULL); + if (!ale) + return NULL; + } + + ALE_SET_INDEX(ale, al->count++); + } + return ale; +} + +static intN +js_map_atom(JSHashEntry *he, intN i, void *arg) +{ + JSAtomListElement *ale = (JSAtomListElement *)he; + JSAtom **vector = (JSAtom **) arg; + + vector[ALE_INDEX(ale)] = ALE_ATOM(ale); + return HT_ENUMERATE_NEXT; +} + +#ifdef DEBUG +static jsrefcount js_atom_map_count; +static jsrefcount js_atom_map_hash_table_count; +#endif + +void +js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al) +{ + JSAtom **vector; + JSAtomListElement *ale; + uint32 count; + + /* Map length must already be initialized. */ + JS_ASSERT(al->count == map->length); +#ifdef DEBUG + JS_ATOMIC_INCREMENT(&js_atom_map_count); +#endif + ale = (JSAtomListElement *)al->list; + if (!ale && !al->table) { + JS_ASSERT(!map->vector); + return; + } + + count = al->count; + vector = map->vector; + if (al->table) { +#ifdef DEBUG + JS_ATOMIC_INCREMENT(&js_atom_map_hash_table_count); +#endif + JS_HashTableEnumerateEntries(al->table, js_map_atom, vector); + } else { + do { + vector[ALE_INDEX(ale)] = ALE_ATOM(ale); + } while ((ale = ALE_NEXT(ale)) != NULL); + } + ATOM_LIST_INIT(al); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsatom.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsatom.h new file mode 100644 index 0000000..76dd5c4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsatom.h @@ -0,0 +1,458 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsatom_h___ +#define jsatom_h___ +/* + * JS atom table. + */ +#include +#include "jsversion.h" +#include "jstypes.h" +#include "jshash.h" /* Added by JSIFY */ +#include "jsdhash.h" +#include "jsapi.h" +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jslock.h" + +JS_BEGIN_EXTERN_C + +#define ATOM_PINNED 0x1 /* atom is pinned against GC */ +#define ATOM_INTERNED 0x2 /* pinned variant for JS_Intern* API */ +#define ATOM_NOCOPY 0x4 /* don't copy atom string bytes */ +#define ATOM_TMPSTR 0x8 /* internal, to avoid extra string */ + +#define ATOM_KEY(atom) ((jsval)(atom)) +#define ATOM_IS_DOUBLE(atom) JSVAL_IS_DOUBLE(ATOM_KEY(atom)) +#define ATOM_TO_DOUBLE(atom) JSVAL_TO_DOUBLE(ATOM_KEY(atom)) +#define ATOM_IS_STRING(atom) JSVAL_IS_STRING(ATOM_KEY(atom)) +#define ATOM_TO_STRING(atom) JSVAL_TO_STRING(ATOM_KEY(atom)) + +JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4); +JS_STATIC_ASSERT(sizeof(JSAtom *) == JS_BYTES_PER_WORD); + +#if JS_BYTES_PER_WORD == 4 +# define ATOM_HASH(atom) ((JSHashNumber)(atom) >> 2) +#elif JS_BYTES_PER_WORD == 8 +# define ATOM_HASH(atom) (((JSHashNumber)(jsuword)(atom) >> 3) ^ \ + (JSHashNumber)((jsuword)(atom) >> 32)) +#else +# error "Unsupported configuration" +#endif + +/* + * Return a printable, lossless char[] representation of a string-type atom. + * The lifetime of the result extends at least until the next GC activation, + * longer if cx's string newborn root is not overwritten. + */ +extern const char * +js_AtomToPrintableString(JSContext *cx, JSAtom *atom); + +struct JSAtomListElement { + JSHashEntry entry; +}; + +#define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key) +#define ALE_INDEX(ale) ((jsatomid) JS_PTR_TO_UINT32((ale)->entry.value)) +#define ALE_JSOP(ale) ((JSOp) JS_PTR_TO_UINT32((ale)->entry.value)) +#define ALE_VALUE(ale) ((jsval) (ale)->entry.value) +#define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next) + +#define ALE_SET_ATOM(ale,atom) ((ale)->entry.key = (const void *)(atom)) +#define ALE_SET_INDEX(ale,index)((ale)->entry.value = JS_UINT32_TO_PTR(index)) +#define ALE_SET_JSOP(ale,op) ((ale)->entry.value = JS_UINT32_TO_PTR(op)) +#define ALE_SET_VALUE(ale, v) ((ale)->entry.value = (void *)(v)) + +struct JSAtomList { + JSHashEntry *list; /* literals indexed for mapping */ + JSHashTable *table; /* hash table if list gets too long */ + jsuint count; /* count of indexed literals */ +}; + +#define ATOM_LIST_INIT(al) ((al)->list = NULL, (al)->table = NULL, \ + (al)->count = 0) + +#define ATOM_LIST_SEARCH(_ale,_al,_atom) \ + JS_BEGIN_MACRO \ + JSHashEntry **_hep; \ + ATOM_LIST_LOOKUP(_ale, _hep, _al, _atom); \ + JS_END_MACRO + +#define ATOM_LIST_LOOKUP(_ale,_hep,_al,_atom) \ + JS_BEGIN_MACRO \ + if ((_al)->table) { \ + _hep = JS_HashTableRawLookup((_al)->table, ATOM_HASH(_atom), \ + _atom); \ + _ale = *_hep ? (JSAtomListElement *) *_hep : NULL; \ + } else { \ + JSHashEntry **_alep = &(_al)->list; \ + _hep = NULL; \ + while ((_ale = (JSAtomListElement *)*_alep) != NULL) { \ + if (ALE_ATOM(_ale) == (_atom)) { \ + /* Hit, move atom's element to the front of the list. */ \ + *_alep = (_ale)->entry.next; \ + (_ale)->entry.next = (_al)->list; \ + (_al)->list = &_ale->entry; \ + break; \ + } \ + _alep = &_ale->entry.next; \ + } \ + } \ + JS_END_MACRO + +struct JSAtomMap { + JSAtom **vector; /* array of ptrs to indexed atoms */ + jsatomid length; /* count of (to-be-)indexed atoms */ +}; + +struct JSAtomState { + JSDHashTable stringAtoms; /* hash table with shared strings */ + JSDHashTable doubleAtoms; /* hash table with shared doubles */ +#ifdef JS_THREADSAFE + JSThinLock lock; +#endif + + /* + * From this point until the end of struct definition the struct must + * contain only JSAtom fields. We use this to access the storage occupied + * by the common atoms in js_FinishCommonAtoms. + * + * js_common_atom_names defined in jsatom.c contains C strings for atoms + * in the order of atom fields here. Therefore you must update that array + * if you change member order here. + */ + + /* The rt->emptyString atom, see jsstr.c's js_InitRuntimeStringState. */ + JSAtom *emptyAtom; + + /* + * Literal value and type names. + * NB: booleanAtoms must come right before typeAtoms! + */ + JSAtom *booleanAtoms[2]; + JSAtom *typeAtoms[JSTYPE_LIMIT]; + JSAtom *nullAtom; + + /* Standard class constructor or prototype names. */ + JSAtom *classAtoms[JSProto_LIMIT]; + + /* Various built-in or commonly-used atoms, pinned on first context. */ + JSAtom *anonymousAtom; + JSAtom *applyAtom; + JSAtom *argumentsAtom; + JSAtom *arityAtom; + JSAtom *callAtom; + JSAtom *calleeAtom; + JSAtom *callerAtom; + JSAtom *classPrototypeAtom; + JSAtom *constructorAtom; + JSAtom *countAtom; + JSAtom *eachAtom; + JSAtom *evalAtom; + JSAtom *fileNameAtom; + JSAtom *getAtom; + JSAtom *getterAtom; + JSAtom *indexAtom; + JSAtom *inputAtom; + JSAtom *iteratorAtom; + JSAtom *lengthAtom; + JSAtom *lineNumberAtom; + JSAtom *messageAtom; + JSAtom *nameAtom; + JSAtom *nextAtom; + JSAtom *noSuchMethodAtom; + JSAtom *parentAtom; + JSAtom *protoAtom; + JSAtom *setAtom; + JSAtom *setterAtom; + JSAtom *stackAtom; + JSAtom *toLocaleStringAtom; + JSAtom *toSourceAtom; + JSAtom *toStringAtom; + JSAtom *valueOfAtom; + JSAtom *toJSONAtom; + JSAtom *void0Atom; + +#if JS_HAS_XML_SUPPORT + JSAtom *etagoAtom; + JSAtom *namespaceAtom; + JSAtom *ptagcAtom; + JSAtom *qualifierAtom; + JSAtom *spaceAtom; + JSAtom *stagoAtom; + JSAtom *starAtom; + JSAtom *starQualifierAtom; + JSAtom *tagcAtom; + JSAtom *xmlAtom; +#endif + +#ifdef NARCISSUS + JSAtom *__call__Atom; + JSAtom *__construct__Atom; + JSAtom *__hasInstance__Atom; + JSAtom *ExecutionContextAtom; + JSAtom *currentAtom; +#endif + + /* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */ + struct { + JSAtom *InfinityAtom; + JSAtom *NaNAtom; + JSAtom *XMLListAtom; + JSAtom *decodeURIAtom; + JSAtom *decodeURIComponentAtom; + JSAtom *defineGetterAtom; + JSAtom *defineSetterAtom; + JSAtom *encodeURIAtom; + JSAtom *encodeURIComponentAtom; + JSAtom *escapeAtom; + JSAtom *functionNamespaceURIAtom; + JSAtom *hasOwnPropertyAtom; + JSAtom *isFiniteAtom; + JSAtom *isNaNAtom; + JSAtom *isPrototypeOfAtom; + JSAtom *isXMLNameAtom; + JSAtom *lookupGetterAtom; + JSAtom *lookupSetterAtom; + JSAtom *parseFloatAtom; + JSAtom *parseIntAtom; + JSAtom *propertyIsEnumerableAtom; + JSAtom *unescapeAtom; + JSAtom *unevalAtom; + JSAtom *unwatchAtom; + JSAtom *watchAtom; + } lazy; +}; + +#define ATOM_OFFSET_START offsetof(JSAtomState, emptyAtom) +#define LAZY_ATOM_OFFSET_START offsetof(JSAtomState, lazy) +#define ATOM_OFFSET_LIMIT (sizeof(JSAtomState)) + +#define COMMON_ATOMS_START(state) \ + ((JSAtom **)((uint8 *)(state) + ATOM_OFFSET_START)) +#define COMMON_ATOM_INDEX(name) \ + ((offsetof(JSAtomState, name##Atom) - ATOM_OFFSET_START) \ + / sizeof(JSAtom*)) +#define COMMON_TYPE_ATOM_INDEX(type) \ + ((offsetof(JSAtomState, typeAtoms[type]) - ATOM_OFFSET_START) \ + / sizeof(JSAtom*)) + +/* Start and limit offsets should correspond to atoms. */ +JS_STATIC_ASSERT(ATOM_OFFSET_START % sizeof(JSAtom *) == 0); +JS_STATIC_ASSERT(ATOM_OFFSET_LIMIT % sizeof(JSAtom *) == 0); + +#define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom) +#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off))) +#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name]) + +#define CLASS_ATOM(cx,name) \ + ((cx)->runtime->atomState.classAtoms[JSProto_##name]) + +extern const char *const js_common_atom_names[]; +extern const size_t js_common_atom_count; + +/* + * Macros to access C strings for JSType and boolean literals together with + * checks that boolean names start from index 1 and type names from 1+2. + */ +#define JS_BOOLEAN_STR(type) (js_common_atom_names[1 + (type)]) +#define JS_TYPE_STR(type) (js_common_atom_names[1 + 2 + (type)]) + +JS_STATIC_ASSERT(1 * sizeof(JSAtom *) == + offsetof(JSAtomState, booleanAtoms) - ATOM_OFFSET_START); +JS_STATIC_ASSERT((1 + 2) * sizeof(JSAtom *) == + offsetof(JSAtomState, typeAtoms) - ATOM_OFFSET_START); + +/* Well-known predefined C strings. */ +#define JS_PROTO(name,code,init) extern const char js_##name##_str[]; +#include "jsproto.tbl" +#undef JS_PROTO + +extern const char js_anonymous_str[]; +extern const char js_apply_str[]; +extern const char js_arguments_str[]; +extern const char js_arity_str[]; +extern const char js_call_str[]; +extern const char js_callee_str[]; +extern const char js_caller_str[]; +extern const char js_class_prototype_str[]; +extern const char js_close_str[]; +extern const char js_constructor_str[]; +extern const char js_count_str[]; +extern const char js_etago_str[]; +extern const char js_each_str[]; +extern const char js_eval_str[]; +extern const char js_fileName_str[]; +extern const char js_get_str[]; +extern const char js_getter_str[]; +extern const char js_index_str[]; +extern const char js_input_str[]; +extern const char js_iterator_str[]; +extern const char js_length_str[]; +extern const char js_lineNumber_str[]; +extern const char js_message_str[]; +extern const char js_name_str[]; +extern const char js_namespace_str[]; +extern const char js_next_str[]; +extern const char js_noSuchMethod_str[]; +extern const char js_object_str[]; +extern const char js_parent_str[]; +extern const char js_proto_str[]; +extern const char js_ptagc_str[]; +extern const char js_qualifier_str[]; +extern const char js_send_str[]; +extern const char js_setter_str[]; +extern const char js_set_str[]; +extern const char js_space_str[]; +extern const char js_stack_str[]; +extern const char js_stago_str[]; +extern const char js_star_str[]; +extern const char js_starQualifier_str[]; +extern const char js_tagc_str[]; +extern const char js_toSource_str[]; +extern const char js_toString_str[]; +extern const char js_toLocaleString_str[]; +extern const char js_undefined_str[]; +extern const char js_valueOf_str[]; +extern const char js_toJSON_str[]; +extern const char js_xml_str[]; + +#ifdef NARCISSUS +extern const char js___call___str[]; +extern const char js___construct___str[]; +extern const char js___hasInstance___str[]; +extern const char js_ExecutionContext_str[]; +extern const char js_current_str[]; +#endif + +/* + * Initialize atom state. Return true on success, false on failure to allocate + * memory. The caller must zero rt->atomState before calling this function and + * only call it after js_InitGC successfully returns. + */ +extern JSBool +js_InitAtomState(JSRuntime *rt); + +/* + * Free and clear atom state including any interned string atoms. This + * function must be called before js_FinishGC. + */ +extern void +js_FinishAtomState(JSRuntime *rt); + +/* + * Atom tracing and garbage collection hooks. + */ + +extern void +js_TraceAtomState(JSTracer *trc, JSBool allAtoms); + +extern void +js_SweepAtomState(JSContext *cx); + +extern JSBool +js_InitCommonAtoms(JSContext *cx); + +extern void +js_FinishCommonAtoms(JSContext *cx); + +/* + * Find or create the atom for a double value. Return null on failure to + * allocate memory. + */ +extern JSAtom * +js_AtomizeDouble(JSContext *cx, jsdouble d); + +/* + * Find or create the atom for a string. Return null on failure to allocate + * memory. + */ +extern JSAtom * +js_AtomizeString(JSContext *cx, JSString *str, uintN flags); + +extern JSAtom * +js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags); + +extern JSAtom * +js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags); + +/* + * Return an existing atom for the given char array or null if the char + * sequence is currently not atomized. + */ +extern JSAtom * +js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length); + +/* + * This variant handles all primitive values. + */ +JSBool +js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp); + +/* + * Convert v to an atomized string and wrap it as an id. + */ +extern JSBool +js_ValueToStringId(JSContext *cx, jsval v, jsid *idp); + +#ifdef DEBUG + +extern JS_FRIEND_API(void) +js_DumpAtoms(JSContext *cx, FILE *fp); + +#endif + +/* + * Assign atom an index and insert it on al. + */ +extern JSAtomListElement * +js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al); + +/* + * For all unmapped atoms recorded in al, add a mapping from the atom's index + * to its address. map->length must already be set to the number of atoms in + * the list and map->vector must point to pre-allocated memory. + */ +extern void +js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al); + +JS_END_EXTERN_C + +#endif /* jsatom_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbit.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbit.h new file mode 100644 index 0000000..f54199b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbit.h @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsbit_h___ +#define jsbit_h___ + +#include "jstypes.h" +#include "jsutil.h" + +JS_BEGIN_EXTERN_C + +/* +** A jsbitmap_t is a long integer that can be used for bitmaps +*/ +typedef JSUword jsbitmap_t; /* NSPR name, a la Unix system types */ +typedef jsbitmap_t jsbitmap; /* JS-style scalar typedef name */ + +#define JS_BITMAP_SIZE(bits) (JS_HOWMANY(bits, JS_BITS_PER_WORD) * \ + sizeof(jsbitmap)) + +#define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] & \ + ((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) +#define JS_SET_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] |= \ + ((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) +#define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] &= \ + ~((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) + +/* +** Compute the log of the least power of 2 greater than or equal to n +*/ +extern JS_PUBLIC_API(JSIntn) JS_CeilingLog2(JSUint32 i); + +/* +** Compute the log of the greatest power of 2 less than or equal to n +*/ +extern JS_PUBLIC_API(JSIntn) JS_FloorLog2(JSUint32 i); + +/* + * Replace bit-scanning code sequences with CPU-specific instructions to + * speedup calculations of ceiling/floor log2. + * + * With GCC 3.4 or later we can use __builtin_clz for that, see bug 327129. + * + * SWS: Added MSVC intrinsic bitscan support. See bugs 349364 and 356856. + */ +#if defined(_WIN32) && (_MSC_VER >= 1300) && defined(_M_IX86) + +unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask); +unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask); +# pragma intrinsic(_BitScanForward,_BitScanReverse) + +__forceinline static int +__BitScanForward32(unsigned int val) +{ + unsigned long idx; + + _BitScanForward(&idx, (unsigned long)val); + return (int)idx; +} +__forceinline static int +__BitScanReverse32(unsigned int val) +{ + unsigned long idx; + + _BitScanReverse(&idx, (unsigned long)val); + return (int)(31-idx); +} +# define js_bitscan_ctz32(val) __BitScanForward32(val) +# define js_bitscan_clz32(val) __BitScanReverse32(val) +# define JS_HAS_BUILTIN_BITSCAN32 + +#elif (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + +# define js_bitscan_ctz32(val) __builtin_ctz(val) +# define js_bitscan_clz32(val) __builtin_clz(val) +# define JS_HAS_BUILTIN_BITSCAN32 +# if (JS_BYTES_PER_WORD == 8) +# define js_bitscan_ctz64(val) __builtin_ctzll(val) +# define js_bitscan_clz64(val) __builtin_clzll(val) +# define JS_HAS_BUILTIN_BITSCAN64 +# endif + +#endif + +/* +** Macro version of JS_CeilingLog2: Compute the log of the least power of +** 2 greater than or equal to _n. The result is returned in _log2. +*/ +#ifdef JS_HAS_BUILTIN_BITSCAN32 +/* + * Use intrinsic function or count-leading-zeros to calculate ceil(log2(_n)). + * The macro checks for "n <= 1" and not "n != 0" as js_bitscan_clz32(0) is + * undefined. + */ +# define JS_CEILING_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + JS_STATIC_ASSERT(sizeof(unsigned int) == sizeof(JSUint32)); \ + unsigned int j_ = (unsigned int)(_n); \ + (_log2) = (j_ <= 1 ? 0 : 32 - js_bitscan_clz32(j_ - 1)); \ + JS_END_MACRO +#else +# define JS_CEILING_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + JSUint32 j_ = (JSUint32)(_n); \ + (_log2) = 0; \ + if ((j_) & ((j_)-1)) \ + (_log2) += 1; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + JS_END_MACRO +#endif + +/* +** Macro version of JS_FloorLog2: Compute the log of the greatest power of +** 2 less than or equal to _n. The result is returned in _log2. +** +** This is equivalent to finding the highest set bit in the word. +*/ +#ifdef JS_HAS_BUILTIN_BITSCAN32 +/* + * Use js_bitscan_clz32 or count-leading-zeros to calculate floor(log2(_n)). + * Since js_bitscan_clz32(0) is undefined, the macro set the loweset bit to 1 + * to ensure 0 result when _n == 0. + */ +# define JS_FLOOR_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + JS_STATIC_ASSERT(sizeof(unsigned int) == sizeof(JSUint32)); \ + (_log2) = 31 - js_bitscan_clz32(((unsigned int)(_n)) | 1); \ + JS_END_MACRO +#else +# define JS_FLOOR_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + JSUint32 j_ = (JSUint32)(_n); \ + (_log2) = 0; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + JS_END_MACRO +#endif + +/* + * Internal function. + * Compute the log of the least power of 2 greater than or equal to n. + * This is a version of JS_CeilingLog2 that operates on jsuword with + * CPU-dependant size. + */ +#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1)) + +/* + * Internal function. + * Compute the log of the greatest power of 2 less than or equal to n. + * This is a version of JS_FloorLog2 that operates on jsuword with + * CPU-dependant size and requires that n != 0. + */ +#define JS_FLOOR_LOG2W(n) (JS_ASSERT((n) != 0), js_FloorLog2wImpl(n)) + +#if JS_BYTES_PER_WORD == 4 + +# ifdef JS_HAS_BUILTIN_BITSCAN32 +JS_STATIC_ASSERT(sizeof(unsigned) == sizeof(JSUword)); +# define js_FloorLog2wImpl(n) \ + ((JSUword)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n))) +# else +# define js_FloorLog2wImpl(n) ((JSUword)JS_FloorLog2(n)) +#endif + +#elif JS_BYTES_PER_WORD == 8 + +# ifdef JS_HAS_BUILTIN_BITSCAN64 +JS_STATIC_ASSERT(sizeof(unsigned long long) == sizeof(JSUword)); +# define js_FloorLog2wImpl(n) \ + ((JSUword)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n))) +# else +extern JSUword js_FloorLog2wImpl(JSUword n); +# endif + +#else + +# error "NOT SUPPORTED" + +#endif + +/* + * Macros for rotate left. There is no rotate operation in the C Language so + * the construct (a << 4) | (a >> 28) is used instead. Most compilers convert + * this to a rotate instruction but some versions of MSVC don't without a + * little help. To get MSVC to generate a rotate instruction, we have to use + * the _rotl intrinsic and use a pragma to make _rotl inline. + * + * MSVC in VS2005 will do an inline rotate instruction on the above construct. + */ + +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \ + defined(_M_X64)) +#include +#pragma intrinsic(_rotl) +#define JS_ROTATE_LEFT32(a, bits) _rotl(a, bits) +#else +#define JS_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits)))) +#endif + +JS_END_EXTERN_C +#endif /* jsbit_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbool.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbool.cpp new file mode 100644 index 0000000..9167fa1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbool.cpp @@ -0,0 +1,182 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS boolean implementation. + */ +#include "jsstddef.h" +#include "jstypes.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jsapi.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsstr.h" + +/* Check pseudo-booleans values. */ +JS_STATIC_ASSERT(JSVAL_VOID == JSVAL_TRUE + JSVAL_ALIGN); +JS_STATIC_ASSERT(JSVAL_HOLE == JSVAL_VOID + JSVAL_ALIGN); +JS_STATIC_ASSERT(JSVAL_ARETURN == JSVAL_HOLE + JSVAL_ALIGN); + +JSClass js_BooleanClass = { + "Boolean", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +#if JS_HAS_TOSOURCE +#include "jsprf.h" + +static JSBool +bool_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + jsval v; + char buf[32]; + JSString *str; + + if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + JS_snprintf(buf, sizeof buf, "(new %s(%s))", + js_BooleanClass.name, + JS_BOOLEAN_STR(JSVAL_TO_BOOLEAN(v))); + str = JS_NewStringCopyZ(cx, buf); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} +#endif + +static JSBool +bool_toString(JSContext *cx, uintN argc, jsval *vp) +{ + jsval v; + JSAtom *atom; + JSString *str; + + if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + atom = cx->runtime->atomState.booleanAtoms[JSVAL_TO_BOOLEAN(v) ? 1 : 0]; + str = ATOM_TO_STRING(atom); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +bool_valueOf(JSContext *cx, uintN argc, jsval *vp) +{ + return js_GetPrimitiveThis(cx, vp, &js_BooleanClass, vp); +} + +static JSFunctionSpec boolean_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, bool_toSource, 0, JSFUN_THISP_BOOLEAN), +#endif + JS_FN(js_toString_str, bool_toString, 0, JSFUN_THISP_BOOLEAN), + JS_FN(js_valueOf_str, bool_valueOf, 0, JSFUN_THISP_BOOLEAN), + JS_FN(js_toJSON_str, bool_valueOf, 0, JSFUN_THISP_BOOLEAN), + JS_FS_END +}; + +static JSBool +Boolean(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + jsval bval; + + bval = (argc != 0) + ? BOOLEAN_TO_JSVAL(js_ValueToBoolean(argv[0])) + : JSVAL_FALSE; + if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { + *rval = bval; + return JS_TRUE; + } + STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, bval); + return JS_TRUE; +} + +JSObject * +js_InitBooleanClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + + proto = JS_InitClass(cx, obj, NULL, &js_BooleanClass, Boolean, 1, + NULL, boolean_methods, NULL, NULL); + if (!proto) + return NULL; + STOBJ_SET_SLOT(proto, JSSLOT_PRIVATE, JSVAL_FALSE); + return proto; +} + +JSString * +js_BooleanToString(JSContext *cx, JSBool b) +{ + return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[b ? 1 : 0]); +} + +JSBool +js_ValueToBoolean(jsval v) +{ + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) + return JS_FALSE; + if (JSVAL_IS_OBJECT(v)) + return JS_TRUE; + if (JSVAL_IS_STRING(v)) + return JSSTRING_LENGTH(JSVAL_TO_STRING(v)) != 0; + if (JSVAL_IS_INT(v)) + return JSVAL_TO_INT(v) != 0; + if (JSVAL_IS_DOUBLE(v)) { + jsdouble d; + + d = *JSVAL_TO_DOUBLE(v); + return !JSDOUBLE_IS_NaN(d) && d != 0; + } + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + return JSVAL_TO_BOOLEAN(v); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbool.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbool.h new file mode 100644 index 0000000..f76de2e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbool.h @@ -0,0 +1,75 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsbool_h___ +#define jsbool_h___ +/* + * JS boolean interface. + */ + +JS_BEGIN_EXTERN_C + +/* + * Pseudo-booleans, not visible to script but used internally by the engine. + * + * JSVAL_HOLE is a useful value for identifying a hole in an array. It's also + * used in the interpreter to represent "no exception pending". In general it + * can be used to represent "no value". + * + * JSVAL_ARETURN is used to throw asynchronous return for generator.close(). + * + * NB: BOOLEAN_TO_JSVAL(2) is JSVAL_VOID (see jsapi.h). + */ +#define JSVAL_HOLE BOOLEAN_TO_JSVAL(3) +#define JSVAL_ARETURN BOOLEAN_TO_JSVAL(4) + +extern JSClass js_BooleanClass; + +extern JSObject * +js_InitBooleanClass(JSContext *cx, JSObject *obj); + +extern JSString * +js_BooleanToString(JSContext *cx, JSBool b); + +extern JSBool +js_ValueToBoolean(jsval v); + +JS_END_EXTERN_C + +#endif /* jsbool_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbuiltins.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbuiltins.cpp new file mode 100644 index 0000000..8a21edb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbuiltins.cpp @@ -0,0 +1,497 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Andreas Gal + * + * Contributor(s): + * Brendan Eich + * Mike Shaver + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsstddef.h" +#include + +#include "jsapi.h" +#include "jsarray.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsgc.h" +#include "jsiter.h" +#include "jslibmath.h" +#include "jsmath.h" +#include "jsnum.h" +#include "prmjtime.h" +#include "jsdate.h" +#include "jsscope.h" +#include "jsstr.h" +#include "jsbuiltins.h" +#include "jstracer.h" + +using namespace avmplus; +using namespace nanojit; + +extern jsdouble js_NaN; + +/* + * NB: bool FASTCALL is not compatible with Nanojit's calling convention usage. + * Do not use bool FASTCALL, use JSBool only! + */ + +jsdouble FASTCALL +js_dmod(jsdouble a, jsdouble b) +{ + if (b == 0.0) { + jsdpun u; + u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK; + u.s.lo = 0xffffffff; + return u.d; + } + jsdouble r; +#ifdef XP_WIN + /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */ + if (JSDOUBLE_IS_FINITE(a) && JSDOUBLE_IS_INFINITE(b)) + r = a; + else +#endif + r = fmod(a, b); + return r; +} + +int32 FASTCALL +js_imod(int32 a, int32 b) +{ + if (a < 0 || b <= 0) + return -1; + int r = a % b; + return r; +} + +/* The following boxing/unboxing primitives we can't emit inline because + they either interact with the GC and depend on Spidermonkey's 32-bit + integer representation. */ + +jsval FASTCALL +js_BoxDouble(JSContext* cx, jsdouble d) +{ + int32 i; + if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) + return INT_TO_JSVAL(i); + JS_ASSERT(JS_ON_TRACE(cx)); + jsval v; /* not rooted but ok here because we know GC won't run */ + if (!js_NewDoubleInRootedValue(cx, d, &v)) + return JSVAL_ERROR_COOKIE; + return v; +} + +jsval FASTCALL +js_BoxInt32(JSContext* cx, int32 i) +{ + if (JS_LIKELY(INT_FITS_IN_JSVAL(i))) + return INT_TO_JSVAL(i); + JS_ASSERT(JS_ON_TRACE(cx)); + jsval v; /* not rooted but ok here because we know GC won't run */ + jsdouble d = (jsdouble)i; + if (!js_NewDoubleInRootedValue(cx, d, &v)) + return JSVAL_ERROR_COOKIE; + return v; +} + +jsdouble FASTCALL +js_UnboxDouble(jsval v) +{ + if (JS_LIKELY(JSVAL_IS_INT(v))) + return (jsdouble)JSVAL_TO_INT(v); + return *JSVAL_TO_DOUBLE(v); +} + +int32 FASTCALL +js_UnboxInt32(jsval v) +{ + if (JS_LIKELY(JSVAL_IS_INT(v))) + return JSVAL_TO_INT(v); + return js_DoubleToECMAInt32(*JSVAL_TO_DOUBLE(v)); +} + +int32 FASTCALL +js_DoubleToInt32(jsdouble d) +{ + return js_DoubleToECMAInt32(d); +} + +uint32 FASTCALL +js_DoubleToUint32(jsdouble d) +{ + return js_DoubleToECMAUint32(d); +} + +jsdouble FASTCALL +js_StringToNumber(JSContext* cx, JSString* str) +{ + const jschar* bp; + const jschar* end; + const jschar* ep; + jsdouble d; + + JSSTRING_CHARS_AND_END(str, bp, end); + if ((!js_strtod(cx, bp, end, &ep, &d) || + js_SkipWhiteSpace(ep, end) != end) && + (!js_strtointeger(cx, bp, end, &ep, 0, &d) || + js_SkipWhiteSpace(ep, end) != end)) { + return js_NaN; + } + return d; +} + +int32 FASTCALL +js_StringToInt32(JSContext* cx, JSString* str) +{ + const jschar* bp; + const jschar* end; + const jschar* ep; + jsdouble d; + + JSSTRING_CHARS_AND_END(str, bp, end); + if (!js_strtod(cx, bp, end, &ep, &d) || js_SkipWhiteSpace(ep, end) != end) + return 0; + return js_DoubleToECMAInt32(d); +} + +static inline JSBool +js_Int32ToId(JSContext* cx, int32 index, jsid* id) +{ + if (index <= JSVAL_INT_MAX) { + *id = INT_TO_JSID(index); + return JS_TRUE; + } + JSString* str = js_NumberToString(cx, index); + if (!str) + return JS_FALSE; + return js_ValueToStringId(cx, STRING_TO_JSVAL(str), id); +} + +jsval FASTCALL +js_Any_getprop(JSContext* cx, JSObject* obj, JSString* idstr) +{ + jsval v; + jsid id; + + if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id)) + return JSVAL_ERROR_COOKIE; + if (!OBJ_GET_PROPERTY(cx, obj, id, &v)) + return JSVAL_ERROR_COOKIE; + return v; +} + +JSBool FASTCALL +js_Any_setprop(JSContext* cx, JSObject* obj, JSString* idstr, jsval v) +{ + jsid id; + if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id)) + return JS_FALSE; + return OBJ_SET_PROPERTY(cx, obj, id, &v); +} + +jsval FASTCALL +js_Any_getelem(JSContext* cx, JSObject* obj, int32 index) +{ + jsval v; + jsid id; + if (!js_Int32ToId(cx, index, &id)) + return JSVAL_ERROR_COOKIE; + if (!OBJ_GET_PROPERTY(cx, obj, id, &v)) + return JSVAL_ERROR_COOKIE; + return v; +} + +JSBool FASTCALL +js_Any_setelem(JSContext* cx, JSObject* obj, int32 index, jsval v) +{ + jsid id; + if (!js_Int32ToId(cx, index, &id)) + return JSVAL_ERROR_COOKIE; + return OBJ_SET_PROPERTY(cx, obj, id, &v); +} + +JSObject* FASTCALL +js_FastValueToIterator(JSContext* cx, jsuint flags, jsval v) +{ + if (!js_ValueToIterator(cx, flags, &v)) + return NULL; + return JSVAL_TO_OBJECT(v); +} + +jsval FASTCALL +js_FastCallIteratorNext(JSContext* cx, JSObject* iterobj) +{ + jsval v; + if (!js_CallIteratorNext(cx, iterobj, &v)) + return JSVAL_ERROR_COOKIE; + return v; +} + +SideExit* FASTCALL +js_CallTree(InterpState* state, Fragment* f) +{ + union { NIns *code; GuardRecord* (FASTCALL *func)(InterpState*, Fragment*); } u; + + u.code = f->code(); + JS_ASSERT(u.code); + + GuardRecord* rec; +#if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32) + SIMULATE_FASTCALL(rec, state, NULL, u.func); +#else + rec = u.func(state, NULL); +#endif + VMSideExit* lr = (VMSideExit*)rec->exit; + + if (lr->exitType == NESTED_EXIT) { + /* This only occurs once a tree call guard mismatches and we unwind the tree call stack. + We store the first (innermost) tree call guard in state and we will try to grow + the outer tree the failing call was in starting at that guard. */ + if (!state->lastTreeCallGuard) { + state->lastTreeCallGuard = lr; + FrameInfo* rp = (FrameInfo*)state->rp; + state->rpAtLastTreeCall = rp + lr->calldepth; + } + } else { + /* If the tree exits on a regular (non-nested) guard, keep updating lastTreeExitGuard + with that guard. If we mismatch on a tree call guard, this will contain the last + non-nested guard we encountered, which is the innermost loop or branch guard. */ + state->lastTreeExitGuard = lr; + } + + return lr; +} + +JSObject* FASTCALL +js_FastNewObject(JSContext* cx, JSObject* ctor) +{ + JS_ASSERT(HAS_FUNCTION_CLASS(ctor)); + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, ctor); + JSClass* clasp = (FUN_INTERPRETED(fun) || (fun->flags & JSFUN_TRACEABLE)) + ? &js_ObjectClass + : FUN_CLASP(fun); + JS_ASSERT(clasp != &js_ArrayClass); + + JS_LOCK_OBJ(cx, ctor); + JSScope *scope = OBJ_SCOPE(ctor); + JS_ASSERT(scope->object == ctor); + JSAtom* atom = cx->runtime->atomState.classPrototypeAtom; + + JSScopeProperty *sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom)); + JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, scope)); + jsval v = LOCKED_OBJ_GET_SLOT(ctor, sprop->slot); + JS_UNLOCK_SCOPE(cx, scope); + + JSObject* proto; + if (JSVAL_IS_PRIMITIVE(v)) { + if (!js_GetClassPrototype(cx, JSVAL_TO_OBJECT(ctor->fslots[JSSLOT_PARENT]), + INT_TO_JSID(JSProto_Object), &proto)) { + return NULL; + } + } else { + proto = JSVAL_TO_OBJECT(v); + } + + JS_ASSERT(JS_ON_TRACE(cx)); + JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject)); + if (!obj) + return NULL; + + obj->classword = jsuword(clasp); + obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto); + obj->fslots[JSSLOT_PARENT] = ctor->fslots[JSSLOT_PARENT]; + for (unsigned i = JSSLOT_PRIVATE; i != JS_INITIAL_NSLOTS; ++i) + obj->fslots[i] = JSVAL_VOID; + + obj->map = js_HoldObjectMap(cx, proto->map); + obj->dslots = NULL; + return obj; +} + +JSBool FASTCALL +js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop) +{ + JSScopeProperty* sprop2 = NULL; // initialize early to make MSVC happy + + JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(SPROP_HAS_STUB_SETTER(sprop)); + + JS_LOCK_OBJ(cx, obj); + JSScope* scope = OBJ_SCOPE(obj); + if (scope->object == obj) { + JS_ASSERT(!SCOPE_HAS_PROPERTY(scope, sprop)); + } else { + scope = js_GetMutableScope(cx, obj); + if (!scope) { + JS_UNLOCK_OBJ(cx, obj); + return JS_FALSE; + } + } + + uint32 slot = sprop->slot; + if (!scope->table && sprop->parent == scope->lastProp && slot == scope->map.freeslot) { + if (slot < STOBJ_NSLOTS(obj) && !OBJ_GET_CLASS(cx, obj)->reserveSlots) { + JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->map.freeslot))); + ++scope->map.freeslot; + } else { + if (!js_AllocSlot(cx, obj, &slot)) { + JS_UNLOCK_SCOPE(cx, scope); + return JS_FALSE; + } + + if (slot != sprop->slot) + goto slot_changed; + } + + SCOPE_EXTEND_SHAPE(cx, scope, sprop); + ++scope->entryCount; + scope->lastProp = sprop; + JS_UNLOCK_SCOPE(cx, scope); + return JS_TRUE; + } + + sprop2 = js_AddScopeProperty(cx, scope, sprop->id, + sprop->getter, sprop->setter, SPROP_INVALID_SLOT, + sprop->attrs, sprop->flags, sprop->shortid); + if (sprop2 == sprop) { + JS_UNLOCK_SCOPE(cx, scope); + return JS_TRUE; + } + slot = sprop2->slot; + + slot_changed: + js_FreeSlot(cx, obj, slot); + JS_UNLOCK_SCOPE(cx, scope); + return JS_FALSE; +} + +JSBool FASTCALL +js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr) +{ + jsid id; + if (!obj || !js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id)) + return JSVAL_TO_BOOLEAN(JSVAL_VOID); + + JSObject* obj2; + JSProperty* prop; + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) + return JSVAL_TO_BOOLEAN(JSVAL_VOID); + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + return prop != NULL; +} + +JSBool FASTCALL +js_HasNamedPropertyInt32(JSContext* cx, JSObject* obj, int32 index) +{ + jsid id; + if (!obj || !js_Int32ToId(cx, index, &id)) + return JSVAL_TO_BOOLEAN(JSVAL_VOID); + + JSObject* obj2; + JSProperty* prop; + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) + return JSVAL_TO_BOOLEAN(JSVAL_VOID); + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + return prop != NULL; +} + +jsval FASTCALL +js_CallGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop) +{ + JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop)); + jsval v; + if (!SPROP_GET(cx, sprop, obj, obj, &v)) + return JSVAL_ERROR_COOKIE; + return v; +} + +JSString* FASTCALL +js_TypeOfObject(JSContext* cx, JSObject* obj) +{ + JSType type = JS_TypeOfValue(cx, OBJECT_TO_JSVAL(obj)); + return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]); +} + +JSString* FASTCALL +js_TypeOfBoolean(JSContext* cx, int32 unboxed) +{ + jsval boxed = BOOLEAN_TO_JSVAL(unboxed); + JS_ASSERT(JSVAL_IS_VOID(boxed) || JSVAL_IS_BOOLEAN(boxed)); + JSType type = JS_TypeOfValue(cx, boxed); + return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]); +} + +jsdouble FASTCALL +js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed) +{ + if (unboxed == JSVAL_TO_BOOLEAN(JSVAL_VOID)) + return js_NaN; + return unboxed; +} + +JSString* FASTCALL +js_BooleanOrUndefinedToString(JSContext *cx, int32 unboxed) +{ + JS_ASSERT(uint32(unboxed) <= 2); + return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]); +} + +JSString* FASTCALL +js_ObjectToString(JSContext* cx, JSObject* obj) +{ + if (!obj) + return ATOM_TO_STRING(cx->runtime->atomState.nullAtom); + jsval v; + if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v)) + return NULL; + JS_ASSERT(JSVAL_IS_STRING(v)); + return JSVAL_TO_STRING(v); +} + +JSObject* FASTCALL +js_Arguments(JSContext* cx) +{ + return NULL; +} + +#define BUILTIN1 JS_DEFINE_CALLINFO_1 +#define BUILTIN2 JS_DEFINE_CALLINFO_2 +#define BUILTIN3 JS_DEFINE_CALLINFO_3 +#define BUILTIN4 JS_DEFINE_CALLINFO_4 +#define BUILTIN5 JS_DEFINE_CALLINFO_5 +#include "builtins.tbl" diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbuiltins.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbuiltins.h new file mode 100644 index 0000000..366d24f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsbuiltins.h @@ -0,0 +1,374 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * + * Contributor(s): + * Jason Orendorff + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsbuiltins_h___ +#define jsbuiltins_h___ + +#ifdef JS_TRACER + +#include "nanojit/nanojit.h" +#include "jstracer.h" + +enum JSTNErrType { INFALLIBLE, FAIL_NULL, FAIL_NEG, FAIL_VOID, FAIL_JSVAL }; +enum { JSTN_ERRTYPE_MASK = 7, JSTN_MORE = 8 }; + +#define JSTN_ERRTYPE(jstn) ((jstn)->flags & JSTN_ERRTYPE_MASK) + +/* + * |prefix| and |argtypes| declare what arguments should be passed to the + * native function. |prefix| can contain the following characters: + * + * 'C': a JSContext* argument + * 'T': |this| as a JSObject* argument (bails if |this| is not an object) + * 'S': |this| as a JSString* argument (bails if |this| is not a string) + * 'R': a JSRuntime* argument + * 'P': the pc as a jsbytecode* + * 'D': |this| as a number (jsdouble) + * 'f': the function being called, as a JSObject* + * 'p': the .prototype of the function, as a JSObject* + * + * The corresponding things will get passed as arguments to the builtin in + * reverse order (so TC means JSContext* as the first arg, and the + * JSObject* for |this| as the second arg). + * + * |argtypes| can contain the following characters: + * 'd': a number (double) argument + * 'i': an integer argument + * 's': a JSString* argument + * 'o': a JSObject* argument + * 'r': a JSObject* argument that is of class js_RegExpClass + * 'f': a JSObject* argument that is of class js_FunctionClass + * 'v': a jsval argument (boxing whatever value is actually being passed in) + */ +struct JSTraceableNative { + JSFastNative native; + const nanojit::CallInfo *builtin; + const char *prefix; + const char *argtypes; + uintN flags; /* JSTN_MORE | JSTNErrType */ +}; + +/* + * We use a magic boxed pointer value to represent error conditions that + * trigger a side exit. The address is so low that it should never be actually + * in use. If it is, a performance regression occurs, not an actual runtime + * error. + */ +#define JSVAL_ERROR_COOKIE OBJECT_TO_JSVAL((void*)0x10) + +/* Macros used by JS_DEFINE_CALLINFOn. */ +#ifdef DEBUG +#define _JS_CI_NAME(op) ,#op +#else +#define _JS_CI_NAME(op) +#endif + +#define _JS_I32_ARGSIZE nanojit::ARGSIZE_LO +#define _JS_I32_RETSIZE nanojit::ARGSIZE_LO +#define _JS_F64_ARGSIZE nanojit::ARGSIZE_F +#define _JS_F64_RETSIZE nanojit::ARGSIZE_F +#define _JS_PTR_ARGSIZE nanojit::ARGSIZE_LO +#if defined AVMPLUS_64BIT +# define _JS_PTR_RETSIZE nanojit::ARGSIZE_Q +#else +# define _JS_PTR_RETSIZE nanojit::ARGSIZE_LO +#endif + +/* + * Supported types for builtin functions. + * + * Types with -- for the two string fields are not permitted as argument types + * in JS_DEFINE_TRCINFO. + * + * If a traceable native can fail, the values that indicate failure are part of + * the return type: + * JSVAL_FAIL: JSVAL_ERROR_COOKIE + * BOOL_FAIL: JSVAL_TO_BOOLEAN(JSVAL_VOID) + * INT32_FAIL: any negative value + * STRING_FAIL: NULL + * OBJECT_FAIL_NULL: NULL + * OBJECT_FAIL_VOID: JSVAL_TO_OBJECT(JSVAL_VOID) + * (NULL means the function successfully returned JS null.) + * + * Special builtins known to the tracer can have their own idiosyncratic + * error codes. + * + * When a traceable native returns a value indicating failure, we fall off + * trace. If an exception is pending, it is thrown; otherwise, we assume the + * builtin had no side effects and retry the current bytecode in the + * interpreter. + * + * So a builtin must not return a value indicating failure after causing side + * effects (such as reporting an error), without setting an exception pending. + * The operation would be retried, despite the first attempt's observable + * effects. + */ +#define _JS_CTYPE(ctype, size, pch, ach, flags) (ctype, size, pch, ach, flags) +#define _JS_CTYPE_CONTEXT _JS_CTYPE(JSContext *, _JS_PTR,"C", "", INFALLIBLE) +#define _JS_CTYPE_RUNTIME _JS_CTYPE(JSRuntime *, _JS_PTR,"R", "", INFALLIBLE) +#define _JS_CTYPE_THIS _JS_CTYPE(JSObject *, _JS_PTR,"T", "", INFALLIBLE) +#define _JS_CTYPE_THIS_DOUBLE _JS_CTYPE(jsdouble, _JS_F64,"D", "", INFALLIBLE) +#define _JS_CTYPE_THIS_STRING _JS_CTYPE(JSString *, _JS_PTR,"S", "", INFALLIBLE) +#define _JS_CTYPE_PC _JS_CTYPE(jsbytecode *, _JS_PTR,"P", "", INFALLIBLE) +#define _JS_CTYPE_JSVAL _JS_CTYPE(jsval, _JS_PTR, "","v", INFALLIBLE) +#define _JS_CTYPE_JSVAL_FAIL _JS_CTYPE(jsval, _JS_PTR, --, --, FAIL_JSVAL) +#define _JS_CTYPE_BOOL _JS_CTYPE(JSBool, _JS_I32, "","i", INFALLIBLE) +#define _JS_CTYPE_BOOL_FAIL _JS_CTYPE(int32, _JS_I32, --, --, FAIL_VOID) +#define _JS_CTYPE_INT32 _JS_CTYPE(int32, _JS_I32, "","i", INFALLIBLE) +#define _JS_CTYPE_INT32_FAIL _JS_CTYPE(int32, _JS_I32, --, --, FAIL_NEG) +#define _JS_CTYPE_UINT32 _JS_CTYPE(uint32, _JS_I32, --, --, INFALLIBLE) +#define _JS_CTYPE_DOUBLE _JS_CTYPE(jsdouble, _JS_F64, "","d", INFALLIBLE) +#define _JS_CTYPE_STRING _JS_CTYPE(JSString *, _JS_PTR, "","s", INFALLIBLE) +#define _JS_CTYPE_STRING_FAIL _JS_CTYPE(JSString *, _JS_PTR, --, --, FAIL_NULL) +#define _JS_CTYPE_OBJECT _JS_CTYPE(JSObject *, _JS_PTR, "","o", INFALLIBLE) +#define _JS_CTYPE_OBJECT_FAIL_NULL _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_NULL) +#define _JS_CTYPE_OBJECT_FAIL_VOID _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_VOID) +#define _JS_CTYPE_REGEXP _JS_CTYPE(JSObject *, _JS_PTR, "","r", INFALLIBLE) +#define _JS_CTYPE_SCOPEPROP _JS_CTYPE(JSScopeProperty *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_SIDEEXIT _JS_CTYPE(SideExit *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_INTERPSTATE _JS_CTYPE(InterpState *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_FRAGMENT _JS_CTYPE(nanojit::Fragment *, _JS_PTR, --, --, INFALLIBLE) + +#define _JS_EXPAND(tokens) tokens + +#define _JS_CTYPE_TYPE2(t,s,p,a,f) t +#define _JS_CTYPE_TYPE(tyname) _JS_EXPAND(_JS_CTYPE_TYPE2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_RETSIZE2(t,s,p,a,f) s##_RETSIZE +#define _JS_CTYPE_RETSIZE(tyname) _JS_EXPAND(_JS_CTYPE_RETSIZE2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_ARGSIZE2(t,s,p,a,f) s##_ARGSIZE +#define _JS_CTYPE_ARGSIZE(tyname) _JS_EXPAND(_JS_CTYPE_ARGSIZE2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_PCH2(t,s,p,a,f) p +#define _JS_CTYPE_PCH(tyname) _JS_EXPAND(_JS_CTYPE_PCH2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_ACH2(t,s,p,a,f) a +#define _JS_CTYPE_ACH(tyname) _JS_EXPAND(_JS_CTYPE_ACH2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_FLAGS2(t,s,p,a,f) f +#define _JS_CTYPE_FLAGS(tyname) _JS_EXPAND(_JS_CTYPE_FLAGS2 _JS_CTYPE_##tyname) + +#define _JS_static_TN(t) static t +#define _JS_static_CI static +#define _JS_extern_TN(t) extern t +#define _JS_extern_CI +#define _JS_FRIEND_TN(t) extern JS_FRIEND_API(t) +#define _JS_FRIEND_CI +#define _JS_TN_LINKAGE(linkage, t) _JS_##linkage##_TN(t) +#define _JS_CI_LINKAGE(linkage) _JS_##linkage##_CI + +#define _JS_CALLINFO(name) name##_ci + +#if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32) +#define _JS_DEFINE_CALLINFO(linkage, name, crtype, cargtypes, argtypes, cse, fold) \ + _JS_TN_LINKAGE(linkage, crtype) name cargtypes; \ + _JS_CI_LINKAGE(linkage) const nanojit::CallInfo _JS_CALLINFO(name) = \ + { (intptr_t) &name, argtypes, cse, fold, nanojit::ABI_CDECL _JS_CI_NAME(name) }; +#else +#define _JS_DEFINE_CALLINFO(linkage, name, crtype, cargtypes, argtypes, cse, fold) \ + _JS_TN_LINKAGE(linkage, crtype) FASTCALL name cargtypes; \ + _JS_CI_LINKAGE(linkage) const nanojit::CallInfo _JS_CALLINFO(name) = \ + { (intptr_t) &name, argtypes, cse, fold, nanojit::ABI_FASTCALL _JS_CI_NAME(name) }; +#endif + +/* + * Declare a C function named and a CallInfo struct named _callinfo so the + * tracer can call it. |linkage| controls the visibility of both the function + * and the CallInfo global. It can be extern, static, or FRIEND, which + * specifies JS_FRIEND_API linkage for the function. + */ +#define JS_DEFINE_CALLINFO_1(linkage, rt, op, at0, cse, fold) \ + _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), (_JS_CTYPE_TYPE(at0)), \ + (_JS_CTYPE_ARGSIZE(at0) << 2) | _JS_CTYPE_RETSIZE(rt), cse, fold) +#define JS_DEFINE_CALLINFO_2(linkage, rt, op, at0, at1, cse, fold) \ + _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1)), \ + (_JS_CTYPE_ARGSIZE(at0) << 4) | (_JS_CTYPE_ARGSIZE(at1) << 2) | \ + _JS_CTYPE_RETSIZE(rt), \ + cse, fold) +#define JS_DEFINE_CALLINFO_3(linkage, rt, op, at0, at1, at2, cse, fold) \ + _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2)), \ + (_JS_CTYPE_ARGSIZE(at0) << 6) | (_JS_CTYPE_ARGSIZE(at1) << 4) | \ + (_JS_CTYPE_ARGSIZE(at2) << 2) | _JS_CTYPE_RETSIZE(rt), \ + cse, fold) +#define JS_DEFINE_CALLINFO_4(linkage, rt, op, at0, at1, at2, at3, cse, fold) \ + _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \ + _JS_CTYPE_TYPE(at3)), \ + (_JS_CTYPE_ARGSIZE(at0) << 8) | (_JS_CTYPE_ARGSIZE(at1) << 6) | \ + (_JS_CTYPE_ARGSIZE(at2) << 4) | (_JS_CTYPE_ARGSIZE(at3) << 2) | \ + _JS_CTYPE_RETSIZE(rt), \ + cse, fold) +#define JS_DEFINE_CALLINFO_5(linkage, rt, op, at0, at1, at2, at3, at4, cse, fold) \ + _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \ + _JS_CTYPE_TYPE(at3), _JS_CTYPE_TYPE(at4)), \ + (_JS_CTYPE_ARGSIZE(at0) << 10) | (_JS_CTYPE_ARGSIZE(at1) << 8) | \ + (_JS_CTYPE_ARGSIZE(at2) << 6) | (_JS_CTYPE_ARGSIZE(at3) << 4) | \ + (_JS_CTYPE_ARGSIZE(at4) << 2) | _JS_CTYPE_RETSIZE(rt), \ + cse, fold) + +#define JS_DECLARE_CALLINFO(name) extern const nanojit::CallInfo _JS_CALLINFO(name); + +#define _JS_TN_INIT_HELPER_n(n, args) _JS_TN_INIT_HELPER_##n args + +#define _JS_TN_INIT_HELPER_1(linkage, rt, op, at0, cse, fold) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at0), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_2(linkage, rt, op, at0, at1, cse, fold) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at0) _JS_CTYPE_ACH(at1), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_3(linkage, rt, op, at0, at1, at2, cse, fold) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at2) _JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at0) _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at2), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_4(linkage, rt, op, at0, at1, at2, at3, cse, fold) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at3) _JS_CTYPE_PCH(at2) _JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at0) _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at2) _JS_CTYPE_ACH(at3), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_5(linkage, rt, op, at0, at1, at2, at3, at4, cse, fold) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at4) _JS_CTYPE_PCH(at3) _JS_CTYPE_PCH(at2) _JS_CTYPE_PCH(at1) \ + _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at0) _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at2) _JS_CTYPE_ACH(at3) \ + _JS_CTYPE_ACH(at4), \ + _JS_CTYPE_FLAGS(rt) + +#define JS_DEFINE_TRCINFO_1(name, tn0) \ + _JS_DEFINE_CALLINFO_n tn0 \ + JSTraceableNative name##_trcinfo[] = { \ + { name, _JS_TN_INIT_HELPER_n tn0 } \ + }; + +#define JS_DEFINE_TRCINFO_2(name, tn0, tn1) \ + _JS_DEFINE_CALLINFO_n tn0 \ + _JS_DEFINE_CALLINFO_n tn1 \ + JSTraceableNative name##_trcinfo[] = { \ + { name, _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE }, \ + { name, _JS_TN_INIT_HELPER_n tn1 } \ + }; + +#define JS_DEFINE_TRCINFO_3(name, tn0, tn1, tn2) \ + _JS_DEFINE_CALLINFO_n tn0 \ + _JS_DEFINE_CALLINFO_n tn1 \ + _JS_DEFINE_CALLINFO_n tn2 \ + JSTraceableNative name##_trcinfo[] = { \ + { name, _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE }, \ + { name, _JS_TN_INIT_HELPER_n tn1 | JSTN_MORE }, \ + { name, _JS_TN_INIT_HELPER_n tn2 } \ + }; + +#define JS_DEFINE_TRCINFO_4(name, tn0, tn1, tn2, tn3) \ + _JS_DEFINE_CALLINFO_n tn0 \ + _JS_DEFINE_CALLINFO_n tn1 \ + _JS_DEFINE_CALLINFO_n tn2 \ + _JS_DEFINE_CALLINFO_n tn3 \ + JSTraceableNative name##_trcinfo[] = { \ + { name, _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE }, \ + { name, _JS_TN_INIT_HELPER_n tn1 | JSTN_MORE }, \ + { name, _JS_TN_INIT_HELPER_n tn2 | JSTN_MORE }, \ + { name, _JS_TN_INIT_HELPER_n tn3 } \ + }; + +#define _JS_DEFINE_CALLINFO_n(n, args) JS_DEFINE_CALLINFO_##n args + +jsdouble FASTCALL +js_StringToNumber(JSContext* cx, JSString* str); + +jsdouble FASTCALL +js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed); + +#else + +#define JS_DEFINE_CALLINFO_1(linkage, rt, op, at0, cse, fold) +#define JS_DEFINE_CALLINFO_2(linkage, rt, op, at0, at1, cse, fold) +#define JS_DEFINE_CALLINFO_3(linkage, rt, op, at0, at1, at2, cse, fold) +#define JS_DEFINE_CALLINFO_4(linkage, rt, op, at0, at1, at2, at3, cse, fold) +#define JS_DEFINE_CALLINFO_5(linkage, rt, op, at0, at1, at2, at3, at4, cse, fold) +#define JS_DECLARE_CALLINFO(name) +#define JS_DEFINE_TRCINFO_1(name, tn0) +#define JS_DEFINE_TRCINFO_2(name, tn0, tn1) +#define JS_DEFINE_TRCINFO_3(name, tn0, tn1, tn2) +#define JS_DEFINE_TRCINFO_4(name, tn0, tn1, tn2, tn3) + +#endif /* !JS_TRACER */ + +/* Defined in jsarray.cpp */ +JS_DECLARE_CALLINFO(js_Array_dense_setelem) +JS_DECLARE_CALLINFO(js_FastNewArray) +JS_DECLARE_CALLINFO(js_Array_1int) +JS_DECLARE_CALLINFO(js_Array_1str) +JS_DECLARE_CALLINFO(js_Array_2obj) +JS_DECLARE_CALLINFO(js_Array_3num) + +/* Defined in jsdate.cpp */ +JS_DECLARE_CALLINFO(js_FastNewDate) + +/* Defined in jsnum.cpp */ +JS_DECLARE_CALLINFO(js_NumberToString) + +/* Defined in jsstr.cpp */ +JS_DECLARE_CALLINFO(js_ConcatStrings) +JS_DECLARE_CALLINFO(js_String_getelem) +JS_DECLARE_CALLINFO(js_String_p_charCodeAt) +JS_DECLARE_CALLINFO(js_EqualStrings) +JS_DECLARE_CALLINFO(js_CompareStrings) + +/* Defined in jsbuiltins.cpp */ +#define BUILTIN1(linkage, rt, op, at0, cse, fold) JS_DECLARE_CALLINFO(op) +#define BUILTIN2(linkage, rt, op, at0, at1, cse, fold) JS_DECLARE_CALLINFO(op) +#define BUILTIN3(linkage, rt, op, at0, at1, at2, cse, fold) JS_DECLARE_CALLINFO(op) +#define BUILTIN4(linkage, rt, op, at0, at1, at2, at3, cse, fold) JS_DECLARE_CALLINFO(op) +#define BUILTIN5(linkage, rt, op, at0, at1, at2, at3, at4, cse, fold) JS_DECLARE_CALLINFO(op) +#include "builtins.tbl" +#undef BUILTIN +#undef BUILTIN1 +#undef BUILTIN2 +#undef BUILTIN3 +#undef BUILTIN4 +#undef BUILTIN5 + +#endif /* jsbuiltins_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsclist.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsclist.h new file mode 100644 index 0000000..604ec0e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsclist.h @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsclist_h___ +#define jsclist_h___ + +#include "jstypes.h" + +/* +** Circular linked list +*/ +typedef struct JSCListStr { + struct JSCListStr *next; + struct JSCListStr *prev; +} JSCList; + +/* +** Insert element "_e" into the list, before "_l". +*/ +#define JS_INSERT_BEFORE(_e,_l) \ + JS_BEGIN_MACRO \ + (_e)->next = (_l); \ + (_e)->prev = (_l)->prev; \ + (_l)->prev->next = (_e); \ + (_l)->prev = (_e); \ + JS_END_MACRO + +/* +** Insert element "_e" into the list, after "_l". +*/ +#define JS_INSERT_AFTER(_e,_l) \ + JS_BEGIN_MACRO \ + (_e)->next = (_l)->next; \ + (_e)->prev = (_l); \ + (_l)->next->prev = (_e); \ + (_l)->next = (_e); \ + JS_END_MACRO + +/* +** Return the element following element "_e" +*/ +#define JS_NEXT_LINK(_e) \ + ((_e)->next) +/* +** Return the element preceding element "_e" +*/ +#define JS_PREV_LINK(_e) \ + ((_e)->prev) + +/* +** Append an element "_e" to the end of the list "_l" +*/ +#define JS_APPEND_LINK(_e,_l) JS_INSERT_BEFORE(_e,_l) + +/* +** Insert an element "_e" at the head of the list "_l" +*/ +#define JS_INSERT_LINK(_e,_l) JS_INSERT_AFTER(_e,_l) + +/* Return the head/tail of the list */ +#define JS_LIST_HEAD(_l) (_l)->next +#define JS_LIST_TAIL(_l) (_l)->prev + +/* +** Remove the element "_e" from it's circular list. +*/ +#define JS_REMOVE_LINK(_e) \ + JS_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + JS_END_MACRO + +/* +** Remove the element "_e" from it's circular list. Also initializes the +** linkage. +*/ +#define JS_REMOVE_AND_INIT_LINK(_e) \ + JS_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + (_e)->next = (_e); \ + (_e)->prev = (_e); \ + JS_END_MACRO + +/* +** Return non-zero if the given circular list "_l" is empty, zero if the +** circular list is not empty +*/ +#define JS_CLIST_IS_EMPTY(_l) \ + ((_l)->next == (_l)) + +/* +** Initialize a circular list +*/ +#define JS_INIT_CLIST(_l) \ + JS_BEGIN_MACRO \ + (_l)->next = (_l); \ + (_l)->prev = (_l); \ + JS_END_MACRO + +#define JS_INIT_STATIC_CLIST(_l) \ + {(_l), (_l)} + +#endif /* jsclist_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscntxt.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscntxt.cpp new file mode 100644 index 0000000..c06a334 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscntxt.cpp @@ -0,0 +1,1394 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS execution context. + */ +#include "jsstddef.h" +#include +#include +#include +#include "jstypes.h" +#include "jsarena.h" /* Added by JSIFY */ +#include "jsutil.h" /* Added by JSIFY */ +#include "jsclist.h" +#include "jsprf.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsexn.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jstracer.h" + +#ifdef JS_THREADSAFE +#include "prtypes.h" + +/* + * The index for JSThread info, returned by PR_NewThreadPrivateIndex. The + * index value is visible and shared by all threads, but the data associated + * with it is private to each thread. + */ +static PRUintn threadTPIndex; +static JSBool tpIndexInited = JS_FALSE; + +JS_BEGIN_EXTERN_C +JSBool +js_InitThreadPrivateIndex(void (*ptr)(void *)) +{ + PRStatus status; + + if (tpIndexInited) + return JS_TRUE; + + status = PR_NewThreadPrivateIndex(&threadTPIndex, ptr); + + if (status == PR_SUCCESS) + tpIndexInited = JS_TRUE; + return status == PR_SUCCESS; +} +JS_END_EXTERN_C + +/* + * Callback function to delete a JSThread info when the thread that owns it + * is destroyed. + */ +void +js_ThreadDestructorCB(void *ptr) +{ + JSThread *thread = (JSThread *)ptr; + + if (!thread) + return; + + /* + * Check that this thread properly called either JS_DestroyContext or + * JS_ClearContextThread on each JSContext it created or used. + */ + JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList)); + GSN_CACHE_CLEAR(&thread->gsnCache); +#if defined JS_TRACER + js_FinishJIT(&thread->traceMonitor); +#endif + free(thread); +} + +/* + * Get current thread-local JSThread info, creating one if it doesn't exist. + * Each thread has a unique JSThread pointer. + * + * Since we are dealing with thread-local data, no lock is needed. + * + * Return a pointer to the thread local info, NULL if the system runs out + * of memory, or it failed to set thread private data (neither case is very + * likely; both are probably due to out-of-memory). It is up to the caller + * to report an error, if possible. + */ +JSThread * +js_GetCurrentThread(JSRuntime *rt) +{ + JSThread *thread; + + thread = (JSThread *)PR_GetThreadPrivate(threadTPIndex); + if (!thread) { + thread = (JSThread *) malloc(sizeof(JSThread)); + if (!thread) + return NULL; +#ifdef DEBUG + memset(thread, JS_FREE_PATTERN, sizeof(JSThread)); +#endif + if (PR_FAILURE == PR_SetThreadPrivate(threadTPIndex, thread)) { + free(thread); + return NULL; + } + + JS_INIT_CLIST(&thread->contextList); + thread->id = js_CurrentThreadId(); + thread->gcMallocBytes = 0; +#ifdef JS_TRACER + memset(&thread->traceMonitor, 0, sizeof(thread->traceMonitor)); + js_InitJIT(&thread->traceMonitor); +#endif + thread->scriptsToGC = NULL; + + /* + * js_SetContextThread initializes the remaining fields as necessary. + */ + } + return thread; +} + +/* + * Sets current thread as owning thread of a context by assigning the + * thread-private info to the context. If the current thread doesn't have + * private JSThread info, create one. + */ +JSBool +js_SetContextThread(JSContext *cx) +{ + JSThread *thread = js_GetCurrentThread(cx->runtime); + + if (!thread) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + /* + * Clear caches on each transition from 0 to 1 context active on the + * current thread. See bug 425828. + */ + if (JS_CLIST_IS_EMPTY(&thread->contextList)) { + memset(&thread->gsnCache, 0, sizeof(thread->gsnCache)); + memset(&thread->propertyCache, 0, sizeof(thread->propertyCache)); + } + + /* Assert that the previous cx->thread called JS_ClearContextThread(). */ + JS_ASSERT(!cx->thread || cx->thread == thread); + if (!cx->thread) + JS_APPEND_LINK(&cx->threadLinks, &thread->contextList); + cx->thread = thread; + return JS_TRUE; +} + +/* Remove the owning thread info of a context. */ +void +js_ClearContextThread(JSContext *cx) +{ + /* + * If cx is associated with a thread, this must be called only from that + * thread. If not, this is a harmless no-op. + */ + JS_ASSERT(cx->thread == js_GetCurrentThread(cx->runtime) || !cx->thread); + JS_REMOVE_AND_INIT_LINK(&cx->threadLinks); + cx->thread = NULL; +} + +#endif /* JS_THREADSAFE */ + +void +js_OnVersionChange(JSContext *cx) +{ +#ifdef DEBUG + JSVersion version = JSVERSION_NUMBER(cx); + + JS_ASSERT(version == JSVERSION_DEFAULT || version >= JSVERSION_ECMA_3); +#endif +} + +void +js_SetVersion(JSContext *cx, JSVersion version) +{ + cx->version = version; + js_OnVersionChange(cx); +} + +JSContext * +js_NewContext(JSRuntime *rt, size_t stackChunkSize) +{ + JSContext *cx; + JSBool ok, first; + JSContextCallback cxCallback; + + cx = (JSContext *) malloc(sizeof *cx); + if (!cx) + return NULL; + memset(cx, 0, sizeof *cx); + + cx->runtime = rt; + JS_ClearOperationCallback(cx); + cx->debugHooks = &rt->globalDebugHooks; +#if JS_STACK_GROWTH_DIRECTION > 0 + cx->stackLimit = (jsuword)-1; +#endif + cx->scriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA; +#ifdef JS_THREADSAFE + cx->gcLocalFreeLists = (JSGCFreeListSet *) &js_GCEmptyFreeListSet; + JS_INIT_CLIST(&cx->threadLinks); + js_SetContextThread(cx); +#endif + + JS_LOCK_GC(rt); + for (;;) { + first = (rt->contextList.next == &rt->contextList); + if (rt->state == JSRTS_UP) { + JS_ASSERT(!first); + break; + } + if (rt->state == JSRTS_DOWN) { + JS_ASSERT(first); + rt->state = JSRTS_LAUNCHING; + break; + } + JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT); + } + JS_APPEND_LINK(&cx->links, &rt->contextList); + JS_UNLOCK_GC(rt); + + /* + * First we do the infallible, every-time per-context initializations. + * Should a later, fallible initialization (js_InitRegExpStatics, e.g., + * or the stuff under 'if (first)' below) fail, at least the version + * and arena-pools will be valid and safe to use (say, from the last GC + * done by js_DestroyContext). + */ + cx->version = JSVERSION_DEFAULT; + JS_INIT_ARENA_POOL(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval), + &cx->scriptStackQuota); + + JS_INIT_ARENA_POOL(&cx->tempPool, "temp", + 1024, /* FIXME: bug 421435 */ + sizeof(jsdouble), &cx->scriptStackQuota); + + /* + * To avoid multiple allocations in InitMatch() (in jsregexp.c), the arena + * size parameter should be at least as big as: + * INITIAL_BACKTRACK + * + (sizeof(REProgState) * INITIAL_STATESTACK) + * + (offsetof(REMatchState, parens) + avgParanSize * sizeof(RECapture)) + */ + JS_INIT_ARENA_POOL(&cx->regexpPool, "regexp", + 12 * 1024 - 40, /* FIXME: bug 421435 */ + sizeof(void *), &cx->scriptStackQuota); + + if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) { + js_DestroyContext(cx, JSDCM_NEW_FAILED); + return NULL; + } + + cx->resolveFlags = 0; + + /* + * If cx is the first context on this runtime, initialize well-known atoms, + * keywords, numbers, and strings. If one of these steps should fail, the + * runtime will be left in a partially initialized state, with zeroes and + * nulls stored in the default-initialized remainder of the struct. We'll + * clean the runtime up under js_DestroyContext, because cx will be "last" + * as well as "first". + */ + if (first) { +#ifdef JS_THREADSAFE + JS_BeginRequest(cx); +#endif + ok = js_InitCommonAtoms(cx); + + /* + * scriptFilenameTable may be left over from a previous episode of + * non-zero contexts alive in rt, so don't re-init the table if it's + * not necessary. + */ + if (ok && !rt->scriptFilenameTable) + ok = js_InitRuntimeScriptState(rt); + if (ok) + ok = js_InitRuntimeNumberState(cx); + if (ok) + ok = js_InitRuntimeStringState(cx); +#ifdef JS_THREADSAFE + JS_EndRequest(cx); +#endif + if (!ok) { + js_DestroyContext(cx, JSDCM_NEW_FAILED); + return NULL; + } + + JS_LOCK_GC(rt); + rt->state = JSRTS_UP; + JS_NOTIFY_ALL_CONDVAR(rt->stateChange); + JS_UNLOCK_GC(rt); + } + + cxCallback = rt->cxCallback; + if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) { + js_DestroyContext(cx, JSDCM_NEW_FAILED); + return NULL; + } + + return cx; +} + +void +js_DestroyContext(JSContext *cx, JSDestroyContextMode mode) +{ + JSRuntime *rt; + JSContextCallback cxCallback; + JSBool last; + JSArgumentFormatMap *map; + JSLocalRootStack *lrs; + JSLocalRootChunk *lrc; + + rt = cx->runtime; + + if (mode != JSDCM_NEW_FAILED) { + cxCallback = rt->cxCallback; + if (cxCallback) { + /* + * JSCONTEXT_DESTROY callback is not allowed to fail and must + * return true. + */ +#ifdef DEBUG + JSBool callbackStatus = +#endif + cxCallback(cx, JSCONTEXT_DESTROY); + JS_ASSERT(callbackStatus); + } + } + + /* Remove cx from context list first. */ + JS_LOCK_GC(rt); + JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING); + JS_REMOVE_LINK(&cx->links); + last = (rt->contextList.next == &rt->contextList); + if (last) + rt->state = JSRTS_LANDING; +#ifdef JS_THREADSAFE + js_RevokeGCLocalFreeLists(cx); +#endif + JS_UNLOCK_GC(rt); + + if (last) { +#ifdef JS_THREADSAFE + /* + * If cx is not in a request already, begin one now so that we wait + * for any racing GC started on a not-last context to finish, before + * we plow ahead and unpin atoms. Note that even though we begin a + * request here if necessary, we end all requests on cx below before + * forcing a final GC. This lets any not-last context destruction + * racing in another thread try to force or maybe run the GC, but by + * that point, rt->state will not be JSRTS_UP, and that GC attempt + * will return early. + */ + if (cx->requestDepth == 0) + JS_BeginRequest(cx); +#endif + + /* Unlock and clear GC things held by runtime pointers. */ + js_FinishRuntimeNumberState(cx); + js_FinishRuntimeStringState(cx); + + /* Unpin all common atoms before final GC. */ + js_FinishCommonAtoms(cx); + + /* Clear debugging state to remove GC roots. */ + JS_ClearAllTraps(cx); + JS_ClearAllWatchPoints(cx); + } + + /* + * Remove more GC roots in regExpStatics, then collect garbage. + * XXX anti-modularity alert: we rely on the call to js_RemoveRoot within + * XXX this function call to wait for any racing GC to complete, in the + * XXX case where JS_DestroyContext is called outside of a request on cx + */ + js_FreeRegExpStatics(cx, &cx->regExpStatics); + +#ifdef JS_THREADSAFE + /* + * Destroying a context implicitly calls JS_EndRequest(). Also, we must + * end our request here in case we are "last" -- in that event, another + * js_DestroyContext that was not last might be waiting in the GC for our + * request to end. We'll let it run below, just before we do the truly + * final GC and then free atom state. + * + * At this point, cx must be inaccessible to other threads. It's off the + * rt->contextList, and it should not be reachable via any object private + * data structure. + */ + while (cx->requestDepth != 0) + JS_EndRequest(cx); +#endif + + if (last) { + js_GC(cx, GC_LAST_CONTEXT); + + /* + * Free the script filename table if it exists and is empty. Do this + * after the last GC to avoid finalizers tripping on free memory. + */ + if (rt->scriptFilenameTable && rt->scriptFilenameTable->nentries == 0) + js_FinishRuntimeScriptState(rt); + + /* Take the runtime down, now that it has no contexts or atoms. */ + JS_LOCK_GC(rt); + rt->state = JSRTS_DOWN; + JS_NOTIFY_ALL_CONDVAR(rt->stateChange); + JS_UNLOCK_GC(rt); + } else { + if (mode == JSDCM_FORCE_GC) + js_GC(cx, GC_NORMAL); + else if (mode == JSDCM_MAYBE_GC) + JS_MaybeGC(cx); + } + + /* Free the stuff hanging off of cx. */ + JS_FinishArenaPool(&cx->stackPool); + JS_FinishArenaPool(&cx->tempPool); + JS_FinishArenaPool(&cx->regexpPool); + + if (cx->lastMessage) + free(cx->lastMessage); + + /* Remove any argument formatters. */ + map = cx->argumentFormatMap; + while (map) { + JSArgumentFormatMap *temp = map; + map = map->next; + JS_free(cx, temp); + } + + /* Destroy the resolve recursion damper. */ + if (cx->resolvingTable) { + JS_DHashTableDestroy(cx->resolvingTable); + cx->resolvingTable = NULL; + } + + lrs = cx->localRootStack; + if (lrs) { + while ((lrc = lrs->topChunk) != &lrs->firstChunk) { + lrs->topChunk = lrc->down; + JS_free(cx, lrc); + } + JS_free(cx, lrs); + } + +#ifdef JS_THREADSAFE + js_ClearContextThread(cx); +#endif + + /* Finally, free cx itself. */ + free(cx); +} + +JSBool +js_ValidContextPointer(JSRuntime *rt, JSContext *cx) +{ + JSCList *cl; + + for (cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) { + if (cl == &cx->links) + return JS_TRUE; + } + JS_RUNTIME_METER(rt, deadContexts); + return JS_FALSE; +} + +JSContext * +js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp) +{ + JSContext *cx = *iterp; + + if (unlocked) + JS_LOCK_GC(rt); + cx = (JSContext *) (cx ? cx->links.next : rt->contextList.next); + if (&cx->links == &rt->contextList) + cx = NULL; + *iterp = cx; + if (unlocked) + JS_UNLOCK_GC(rt); + return cx; +} + +static JSDHashNumber +resolving_HashKey(JSDHashTable *table, const void *ptr) +{ + const JSResolvingKey *key = (const JSResolvingKey *)ptr; + + return ((JSDHashNumber)JS_PTR_TO_UINT32(key->obj) >> JSVAL_TAGBITS) ^ key->id; +} + +JS_PUBLIC_API(JSBool) +resolving_MatchEntry(JSDHashTable *table, + const JSDHashEntryHdr *hdr, + const void *ptr) +{ + const JSResolvingEntry *entry = (const JSResolvingEntry *)hdr; + const JSResolvingKey *key = (const JSResolvingKey *)ptr; + + return entry->key.obj == key->obj && entry->key.id == key->id; +} + +static const JSDHashTableOps resolving_dhash_ops = { + JS_DHashAllocTable, + JS_DHashFreeTable, + resolving_HashKey, + resolving_MatchEntry, + JS_DHashMoveEntryStub, + JS_DHashClearEntryStub, + JS_DHashFinalizeStub, + NULL +}; + +JSBool +js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, + JSResolvingEntry **entryp) +{ + JSDHashTable *table; + JSResolvingEntry *entry; + + table = cx->resolvingTable; + if (!table) { + table = JS_NewDHashTable(&resolving_dhash_ops, NULL, + sizeof(JSResolvingEntry), + JS_DHASH_MIN_SIZE); + if (!table) + goto outofmem; + cx->resolvingTable = table; + } + + entry = (JSResolvingEntry *) + JS_DHashTableOperate(table, key, JS_DHASH_ADD); + if (!entry) + goto outofmem; + + if (entry->flags & flag) { + /* An entry for (key, flag) exists already -- dampen recursion. */ + entry = NULL; + } else { + /* Fill in key if we were the first to add entry, then set flag. */ + if (!entry->key.obj) + entry->key = *key; + entry->flags |= flag; + } + *entryp = entry; + return JS_TRUE; + +outofmem: + JS_ReportOutOfMemory(cx); + return JS_FALSE; +} + +void +js_StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, + JSResolvingEntry *entry, uint32 generation) +{ + JSDHashTable *table; + + /* + * Clear flag from entry->flags and return early if other flags remain. + * We must take care to re-lookup entry if the table has changed since + * it was found by js_StartResolving. + */ + table = cx->resolvingTable; + if (!entry || table->generation != generation) { + entry = (JSResolvingEntry *) + JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP); + } + JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&entry->hdr)); + entry->flags &= ~flag; + if (entry->flags) + return; + + /* + * Do a raw remove only if fewer entries were removed than would cause + * alpha to be less than .5 (alpha is at most .75). Otherwise, we just + * call JS_DHashTableOperate to re-lookup the key and remove its entry, + * compressing or shrinking the table as needed. + */ + if (table->removedCount < JS_DHASH_TABLE_SIZE(table) >> 2) + JS_DHashTableRawRemove(table, &entry->hdr); + else + JS_DHashTableOperate(table, key, JS_DHASH_REMOVE); +} + +JSBool +js_EnterLocalRootScope(JSContext *cx) +{ + JSLocalRootStack *lrs; + int mark; + + lrs = cx->localRootStack; + if (!lrs) { + lrs = (JSLocalRootStack *) JS_malloc(cx, sizeof *lrs); + if (!lrs) + return JS_FALSE; + lrs->scopeMark = JSLRS_NULL_MARK; + lrs->rootCount = 0; + lrs->topChunk = &lrs->firstChunk; + lrs->firstChunk.down = NULL; + cx->localRootStack = lrs; + } + + /* Push lrs->scopeMark to save it for restore when leaving. */ + mark = js_PushLocalRoot(cx, lrs, INT_TO_JSVAL(lrs->scopeMark)); + if (mark < 0) + return JS_FALSE; + lrs->scopeMark = (uint32) mark; + return JS_TRUE; +} + +void +js_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval) +{ + JSLocalRootStack *lrs; + uint32 mark, m, n; + JSLocalRootChunk *lrc; + + /* Defend against buggy native callers. */ + lrs = cx->localRootStack; + JS_ASSERT(lrs && lrs->rootCount != 0); + if (!lrs || lrs->rootCount == 0) + return; + + mark = lrs->scopeMark; + JS_ASSERT(mark != JSLRS_NULL_MARK); + if (mark == JSLRS_NULL_MARK) + return; + + /* Free any chunks being popped by this leave operation. */ + m = mark >> JSLRS_CHUNK_SHIFT; + n = (lrs->rootCount - 1) >> JSLRS_CHUNK_SHIFT; + while (n > m) { + lrc = lrs->topChunk; + JS_ASSERT(lrc != &lrs->firstChunk); + lrs->topChunk = lrc->down; + JS_free(cx, lrc); + --n; + } + + /* + * Pop the scope, restoring lrs->scopeMark. If rval is a GC-thing, push + * it on the caller's scope, or store it in lastInternalResult if we are + * leaving the outermost scope. We don't need to allocate a new lrc + * because we can overwrite the old mark's slot with rval. + */ + lrc = lrs->topChunk; + m = mark & JSLRS_CHUNK_MASK; + lrs->scopeMark = (uint32) JSVAL_TO_INT(lrc->roots[m]); + if (JSVAL_IS_GCTHING(rval) && !JSVAL_IS_NULL(rval)) { + if (mark == 0) { + cx->weakRoots.lastInternalResult = rval; + } else { + /* + * Increment m to avoid the "else if (m == 0)" case below. If + * rval is not a GC-thing, that case would take care of freeing + * any chunk that contained only the old mark. Since rval *is* + * a GC-thing here, we want to reuse that old mark's slot. + */ + lrc->roots[m++] = rval; + ++mark; + } + } + lrs->rootCount = (uint32) mark; + + /* + * Free the stack eagerly, risking malloc churn. The alternative would + * require an lrs->entryCount member, maintained by Enter and Leave, and + * tested by the GC in addition to the cx->localRootStack non-null test. + * + * That approach would risk hoarding 264 bytes (net) per context. Right + * now it seems better to give fresh (dirty in CPU write-back cache, and + * the data is no longer needed) memory back to the malloc heap. + */ + if (mark == 0) { + cx->localRootStack = NULL; + JS_free(cx, lrs); + } else if (m == 0) { + lrs->topChunk = lrc->down; + JS_free(cx, lrc); + } +} + +void +js_ForgetLocalRoot(JSContext *cx, jsval v) +{ + JSLocalRootStack *lrs; + uint32 i, j, m, n, mark; + JSLocalRootChunk *lrc, *lrc2; + jsval top; + + lrs = cx->localRootStack; + JS_ASSERT(lrs && lrs->rootCount); + if (!lrs || lrs->rootCount == 0) + return; + + /* Prepare to pop the top-most value from the stack. */ + n = lrs->rootCount - 1; + m = n & JSLRS_CHUNK_MASK; + lrc = lrs->topChunk; + top = lrc->roots[m]; + + /* Be paranoid about calls on an empty scope. */ + mark = lrs->scopeMark; + JS_ASSERT(mark < n); + if (mark >= n) + return; + + /* If v was not the last root pushed in the top scope, find it. */ + if (top != v) { + /* Search downward in case v was recently pushed. */ + i = n; + j = m; + lrc2 = lrc; + while (--i > mark) { + if (j == 0) + lrc2 = lrc2->down; + j = i & JSLRS_CHUNK_MASK; + if (lrc2->roots[j] == v) + break; + } + + /* If we didn't find v in this scope, assert and bail out. */ + JS_ASSERT(i != mark); + if (i == mark) + return; + + /* Swap top and v so common tail code can pop v. */ + lrc2->roots[j] = top; + } + + /* Pop the last value from the stack. */ + lrc->roots[m] = JSVAL_NULL; + lrs->rootCount = n; + if (m == 0) { + JS_ASSERT(n != 0); + JS_ASSERT(lrc != &lrs->firstChunk); + lrs->topChunk = lrc->down; + JS_free(cx, lrc); + } +} + +int +js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v) +{ + uint32 n, m; + JSLocalRootChunk *lrc; + + n = lrs->rootCount; + m = n & JSLRS_CHUNK_MASK; + if (n == 0 || m != 0) { + /* + * At start of first chunk, or not at start of a non-first top chunk. + * Check for lrs->rootCount overflow. + */ + if ((uint32)(n + 1) == 0) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TOO_MANY_LOCAL_ROOTS); + return -1; + } + lrc = lrs->topChunk; + JS_ASSERT(n != 0 || lrc == &lrs->firstChunk); + } else { + /* + * After lrs->firstChunk, trying to index at a power-of-two chunk + * boundary: need a new chunk. + */ + lrc = (JSLocalRootChunk *) JS_malloc(cx, sizeof *lrc); + if (!lrc) + return -1; + lrc->down = lrs->topChunk; + lrs->topChunk = lrc; + } + lrs->rootCount = n + 1; + lrc->roots[m] = v; + return (int) n; +} + +void +js_TraceLocalRoots(JSTracer *trc, JSLocalRootStack *lrs) +{ + uint32 n, m, mark; + JSLocalRootChunk *lrc; + jsval v; + + n = lrs->rootCount; + if (n == 0) + return; + + mark = lrs->scopeMark; + lrc = lrs->topChunk; + do { + while (--n > mark) { + m = n & JSLRS_CHUNK_MASK; + v = lrc->roots[m]; + JS_ASSERT(JSVAL_IS_GCTHING(v) && v != JSVAL_NULL); + JS_SET_TRACING_INDEX(trc, "local_root", n); + js_CallValueTracerIfGCThing(trc, v); + if (m == 0) + lrc = lrc->down; + } + m = n & JSLRS_CHUNK_MASK; + mark = JSVAL_TO_INT(lrc->roots[m]); + if (m == 0) + lrc = lrc->down; + } while (n != 0); + JS_ASSERT(!lrc); +} + +static void +ReportError(JSContext *cx, const char *message, JSErrorReport *reportp) +{ + /* + * Check the error report, and set a JavaScript-catchable exception + * if the error is defined to have an associated exception. If an + * exception is thrown, then the JSREPORT_EXCEPTION flag will be set + * on the error report, and exception-aware hosts should ignore it. + */ + JS_ASSERT(reportp); + if (reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION) + reportp->flags |= JSREPORT_EXCEPTION; + + /* + * Call the error reporter only if an exception wasn't raised. + * + * If an exception was raised, then we call the debugErrorHook + * (if present) to give it a chance to see the error before it + * propagates out of scope. This is needed for compatability + * with the old scheme. + */ + if (!cx->fp || !js_ErrorToException(cx, message, reportp)) { + js_ReportErrorAgain(cx, message, reportp); + } else if (cx->debugHooks->debugErrorHook && cx->errorReporter) { + JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; + /* test local in case debugErrorHook changed on another thread */ + if (hook) + hook(cx, message, reportp, cx->debugHooks->debugErrorHookData); + } +} + +/* + * We don't post an exception in this case, since doing so runs into + * complications of pre-allocating an exception object which required + * running the Exception class initializer early etc. + * Instead we just invoke the errorReporter with an "Out Of Memory" + * type message, and then hope the process ends swiftly. + */ +void +js_ReportOutOfMemory(JSContext *cx) +{ + JSStackFrame *fp; + JSErrorReport report; + JSErrorReporter onError = cx->errorReporter; + + /* Get the message for this error, but we won't expand any arguments. */ + const JSErrorFormatString *efs = + js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY); + const char *msg = efs ? efs->format : "Out of memory"; + + /* Fill out the report, but don't do anything that requires allocation. */ + memset(&report, 0, sizeof (struct JSErrorReport)); + report.flags = JSREPORT_ERROR; + report.errorNumber = JSMSG_OUT_OF_MEMORY; + + /* + * Walk stack until we find a frame that is associated with some script + * rather than a native frame. + */ + for (fp = cx->fp; fp; fp = fp->down) { + if (fp->regs) { + report.filename = fp->script->filename; + report.lineno = js_FramePCToLineNumber(cx, fp); + break; + } + } + + /* + * If debugErrorHook is present then we give it a chance to veto sending + * the error on to the regular ErrorReporter. We also clear a pending + * exception if any now so the hooks can replace the out-of-memory error + * by a script-catchable exception. + */ + cx->throwing = JS_FALSE; + if (onError) { + JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; + if (hook && + !hook(cx, msg, &report, cx->debugHooks->debugErrorHookData)) { + onError = NULL; + } + } + + if (onError) + onError(cx, msg, &report); +} + +void +js_ReportOutOfScriptQuota(JSContext *cx) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_SCRIPT_STACK_QUOTA); +} + +void +js_ReportOverRecursed(JSContext *cx) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); +} + +void +js_ReportAllocationOverflow(JSContext *cx) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ALLOC_OVERFLOW); +} + +JSBool +js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap) +{ + char *message; + jschar *ucmessage; + size_t messagelen; + JSStackFrame *fp; + JSErrorReport report; + JSBool warning; + + if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx)) + return JS_TRUE; + + message = JS_vsmprintf(format, ap); + if (!message) + return JS_FALSE; + messagelen = strlen(message); + + memset(&report, 0, sizeof (struct JSErrorReport)); + report.flags = flags; + report.errorNumber = JSMSG_USER_DEFINED_ERROR; + report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen); + + /* Find the top-most active script frame, for best line number blame. */ + for (fp = cx->fp; fp; fp = fp->down) { + if (fp->regs) { + report.filename = fp->script->filename; + report.lineno = js_FramePCToLineNumber(cx, fp); + break; + } + } + + warning = JSREPORT_IS_WARNING(report.flags); + if (warning && JS_HAS_WERROR_OPTION(cx)) { + report.flags &= ~JSREPORT_WARNING; + warning = JS_FALSE; + } + + ReportError(cx, message, &report); + free(message); + JS_free(cx, ucmessage); + return warning; +} + +/* + * The arguments from ap need to be packaged up into an array and stored + * into the report struct. + * + * The format string addressed by the error number may contain operands + * identified by the format {N}, where N is a decimal digit. Each of these + * is to be replaced by the Nth argument from the va_list. The complete + * message is placed into reportp->ucmessage converted to a JSString. + * + * Returns true if the expansion succeeds (can fail if out of memory). + */ +JSBool +js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback, + void *userRef, const uintN errorNumber, + char **messagep, JSErrorReport *reportp, + JSBool *warningp, JSBool charArgs, va_list ap) +{ + const JSErrorFormatString *efs; + int i; + int argCount; + + *warningp = JSREPORT_IS_WARNING(reportp->flags); + if (*warningp && JS_HAS_WERROR_OPTION(cx)) { + reportp->flags &= ~JSREPORT_WARNING; + *warningp = JS_FALSE; + } + + *messagep = NULL; + + /* Most calls supply js_GetErrorMessage; if this is so, assume NULL. */ + if (!callback || callback == js_GetErrorMessage) + efs = js_GetLocalizedErrorMessage(cx, userRef, NULL, errorNumber); + else + efs = callback(userRef, NULL, errorNumber); + if (efs) { + size_t totalArgsLength = 0; + size_t argLengths[10]; /* only {0} thru {9} supported */ + argCount = efs->argCount; + JS_ASSERT(argCount <= 10); + if (argCount > 0) { + /* + * Gather the arguments into an array, and accumulate + * their sizes. We allocate 1 more than necessary and + * null it out to act as the caboose when we free the + * pointers later. + */ + reportp->messageArgs = (const jschar **) + JS_malloc(cx, sizeof(jschar *) * (argCount + 1)); + if (!reportp->messageArgs) + return JS_FALSE; + reportp->messageArgs[argCount] = NULL; + for (i = 0; i < argCount; i++) { + if (charArgs) { + char *charArg = va_arg(ap, char *); + size_t charArgLength = strlen(charArg); + reportp->messageArgs[i] + = js_InflateString(cx, charArg, &charArgLength); + if (!reportp->messageArgs[i]) + goto error; + } else { + reportp->messageArgs[i] = va_arg(ap, jschar *); + } + argLengths[i] = js_strlen(reportp->messageArgs[i]); + totalArgsLength += argLengths[i]; + } + /* NULL-terminate for easy copying. */ + reportp->messageArgs[i] = NULL; + } + /* + * Parse the error format, substituting the argument X + * for {X} in the format. + */ + if (argCount > 0) { + if (efs->format) { + jschar *buffer, *fmt, *out; + int expandedArgs = 0; + size_t expandedLength; + size_t len = strlen(efs->format); + + buffer = fmt = js_InflateString (cx, efs->format, &len); + if (!buffer) + goto error; + expandedLength = len + - (3 * argCount) /* exclude the {n} */ + + totalArgsLength; + + /* + * Note - the above calculation assumes that each argument + * is used once and only once in the expansion !!! + */ + reportp->ucmessage = out = (jschar *) + JS_malloc(cx, (expandedLength + 1) * sizeof(jschar)); + if (!out) { + JS_free (cx, buffer); + goto error; + } + while (*fmt) { + if (*fmt == '{') { + if (isdigit(fmt[1])) { + int d = JS7_UNDEC(fmt[1]); + JS_ASSERT(d < argCount); + js_strncpy(out, reportp->messageArgs[d], + argLengths[d]); + out += argLengths[d]; + fmt += 3; + expandedArgs++; + continue; + } + } + *out++ = *fmt++; + } + JS_ASSERT(expandedArgs == argCount); + *out = 0; + JS_free (cx, buffer); + *messagep = + js_DeflateString(cx, reportp->ucmessage, + (size_t)(out - reportp->ucmessage)); + if (!*messagep) + goto error; + } + } else { + /* + * Zero arguments: the format string (if it exists) is the + * entire message. + */ + if (efs->format) { + size_t len; + *messagep = JS_strdup(cx, efs->format); + if (!*messagep) + goto error; + len = strlen(*messagep); + reportp->ucmessage = js_InflateString(cx, *messagep, &len); + if (!reportp->ucmessage) + goto error; + } + } + } + if (*messagep == NULL) { + /* where's the right place for this ??? */ + const char *defaultErrorMessage + = "No error message available for error number %d"; + size_t nbytes = strlen(defaultErrorMessage) + 16; + *messagep = (char *)JS_malloc(cx, nbytes); + if (!*messagep) + goto error; + JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber); + } + return JS_TRUE; + +error: + if (reportp->messageArgs) { + /* free the arguments only if we allocated them */ + if (charArgs) { + i = 0; + while (reportp->messageArgs[i]) + JS_free(cx, (void *)reportp->messageArgs[i++]); + } + JS_free(cx, (void *)reportp->messageArgs); + reportp->messageArgs = NULL; + } + if (reportp->ucmessage) { + JS_free(cx, (void *)reportp->ucmessage); + reportp->ucmessage = NULL; + } + if (*messagep) { + JS_free(cx, (void *)*messagep); + *messagep = NULL; + } + return JS_FALSE; +} + +JSBool +js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback, + void *userRef, const uintN errorNumber, + JSBool charArgs, va_list ap) +{ + JSStackFrame *fp; + JSErrorReport report; + char *message; + JSBool warning; + + if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx)) + return JS_TRUE; + + memset(&report, 0, sizeof (struct JSErrorReport)); + report.flags = flags; + report.errorNumber = errorNumber; + + /* + * If we can't find out where the error was based on the current frame, + * see if the next frame has a script/pc combo we can use. + */ + for (fp = cx->fp; fp; fp = fp->down) { + if (fp->regs) { + report.filename = fp->script->filename; + report.lineno = js_FramePCToLineNumber(cx, fp); + break; + } + } + + if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber, + &message, &report, &warning, charArgs, ap)) { + return JS_FALSE; + } + + ReportError(cx, message, &report); + + if (message) + JS_free(cx, message); + if (report.messageArgs) { + /* + * js_ExpandErrorArguments owns its messageArgs only if it had to + * inflate the arguments (from regular |char *|s). + */ + if (charArgs) { + int i = 0; + while (report.messageArgs[i]) + JS_free(cx, (void *)report.messageArgs[i++]); + } + JS_free(cx, (void *)report.messageArgs); + } + if (report.ucmessage) + JS_free(cx, (void *)report.ucmessage); + + return warning; +} + +JS_FRIEND_API(void) +js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp) +{ + JSErrorReporter onError; + + if (!message) + return; + + if (cx->lastMessage) + free(cx->lastMessage); + cx->lastMessage = JS_strdup(cx, message); + if (!cx->lastMessage) + return; + onError = cx->errorReporter; + + /* + * If debugErrorHook is present then we give it a chance to veto + * sending the error on to the regular ErrorReporter. + */ + if (onError) { + JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; + if (hook && + !hook(cx, cx->lastMessage, reportp, + cx->debugHooks->debugErrorHookData)) { + onError = NULL; + } + } + if (onError) + onError(cx, cx->lastMessage, reportp); +} + +void +js_ReportIsNotDefined(JSContext *cx, const char *name) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name); +} + +JSBool +js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, jsval v, + JSString *fallback) +{ + char *bytes; + JSBool ok; + + bytes = js_DecompileValueGenerator(cx, spindex, v, fallback); + if (!bytes) + return JS_FALSE; + + if (strcmp(bytes, js_undefined_str) == 0 || + strcmp(bytes, js_null_str) == 0) { + ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_NO_PROPERTIES, bytes, + NULL, NULL); + } else if (JSVAL_IS_VOID(v)) { + ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_NULL_OR_UNDEFINED, bytes, + js_undefined_str, NULL); + } else { + JS_ASSERT(JSVAL_IS_NULL(v)); + ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_NULL_OR_UNDEFINED, bytes, + js_null_str, NULL); + } + + JS_free(cx, bytes); + return ok; +} + +void +js_ReportMissingArg(JSContext *cx, jsval *vp, uintN arg) +{ + char argbuf[11]; + char *bytes; + JSAtom *atom; + + JS_snprintf(argbuf, sizeof argbuf, "%u", arg); + bytes = NULL; + if (VALUE_IS_FUNCTION(cx, *vp)) { + atom = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(*vp))->atom; + bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, *vp, + ATOM_TO_STRING(atom)); + if (!bytes) + return; + } + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_MISSING_FUN_ARG, argbuf, + bytes ? bytes : ""); + JS_free(cx, bytes); +} + +JSBool +js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber, + intN spindex, jsval v, JSString *fallback, + const char *arg1, const char *arg2) +{ + char *bytes; + JSBool ok; + + JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1); + JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3); + bytes = js_DecompileValueGenerator(cx, spindex, v, fallback); + if (!bytes) + return JS_FALSE; + + ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, + NULL, errorNumber, bytes, arg1, arg2); + JS_free(cx, bytes); + return ok; +} + +#if defined DEBUG && defined XP_UNIX +/* For gdb usage. */ +void js_traceon(JSContext *cx) { cx->tracefp = stderr; } +void js_traceoff(JSContext *cx) { cx->tracefp = NULL; } +#endif + +JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = { +#define MSG_DEF(name, number, count, exception, format) \ + { format, count, exception } , +#include "js.msg" +#undef MSG_DEF +}; + +JS_FRIEND_API(const JSErrorFormatString *) +js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber) +{ + if ((errorNumber > 0) && (errorNumber < JSErr_Limit)) + return &js_ErrorFormatString[errorNumber]; + return NULL; +} + +JSBool +js_ResetOperationCount(JSContext *cx) +{ + JSScript *script; + + JS_ASSERT(cx->operationCount <= 0); + JS_ASSERT(cx->operationLimit > 0); + + cx->operationCount = (int32) cx->operationLimit; + if (cx->operationCallbackIsSet) + return cx->operationCallback(cx); + + if (cx->operationCallback) { + /* + * Invoke the deprecated branch callback. It may be called only when + * the top-most frame is scripted or JSOPTION_NATIVE_BRANCH_CALLBACK + * is set. + */ + script = cx->fp ? cx->fp->script : NULL; + if (script || JS_HAS_OPTION(cx, JSOPTION_NATIVE_BRANCH_CALLBACK)) + return ((JSBranchCallback) cx->operationCallback)(cx, script); + } + return JS_TRUE; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscntxt.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscntxt.h new file mode 100644 index 0000000..c201f1f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscntxt.h @@ -0,0 +1,1247 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jscntxt_h___ +#define jscntxt_h___ +/* + * JS execution context. + */ +#include "jsarena.h" /* Added by JSIFY */ +#include "jsclist.h" +#include "jslong.h" +#include "jsatom.h" +#include "jsversion.h" +#include "jsdhash.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsobj.h" +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsregexp.h" +#include "jsutil.h" + +JS_BEGIN_EXTERN_C + +/* + * js_GetSrcNote cache to avoid O(n^2) growth in finding a source note for a + * given pc in a script. We use the script->code pointer to tag the cache, + * instead of the script address itself, so that source notes are always found + * by offset from the bytecode with which they were generated. + */ +typedef struct JSGSNCache { + jsbytecode *code; + JSDHashTable table; +#ifdef JS_GSNMETER + uint32 hits; + uint32 misses; + uint32 fills; + uint32 clears; +# define GSN_CACHE_METER(cache,cnt) (++(cache)->cnt) +#else +# define GSN_CACHE_METER(cache,cnt) /* nothing */ +#endif +} JSGSNCache; + +#define GSN_CACHE_CLEAR(cache) \ + JS_BEGIN_MACRO \ + (cache)->code = NULL; \ + if ((cache)->table.ops) { \ + JS_DHashTableFinish(&(cache)->table); \ + (cache)->table.ops = NULL; \ + } \ + GSN_CACHE_METER(cache, clears); \ + JS_END_MACRO + +/* These helper macros take a cx as parameter and operate on its GSN cache. */ +#define JS_CLEAR_GSN_CACHE(cx) GSN_CACHE_CLEAR(&JS_GSN_CACHE(cx)) +#define JS_METER_GSN_CACHE(cx,cnt) GSN_CACHE_METER(&JS_GSN_CACHE(cx), cnt) + +#ifdef __cplusplus +namespace nanojit { + class Fragment; + class Fragmento; +} +class TraceRecorder; +extern "C++" { template class Queue; } +typedef Queue SlotList; +class TypeMap; + +# define CLS(T) T* +#else +# define CLS(T) void* +#endif + +/* + * Trace monitor. Every JSThread (if JS_THREADSAFE) or JSRuntime (if not + * JS_THREADSAFE) has an associated trace monitor that keeps track of loop + * frequencies for all JavaScript code loaded into that runtime. + */ +typedef struct JSTraceMonitor { + /* + * Flag set when running (or recording) JIT-compiled code. This prevents + * both interpreter activation and last-ditch garbage collection when up + * against our runtime's memory limits. This flag also suppresses calls to + * JS_ReportOutOfMemory when failing due to runtime limits. + */ + JSBool onTrace; + CLS(nanojit::Fragmento) fragmento; + CLS(TraceRecorder) recorder; + uint32 globalShape; + CLS(SlotList) globalSlots; + CLS(TypeMap) globalTypeMap; + jsval *recoveryDoublePool; + jsval *recoveryDoublePoolPtr; + + /* Fragmento for the regular expression compiler. This is logically + * a distinct compiler but needs to be managed in exactly the same + * way as the real tracing Fragmento. */ + CLS(nanojit::Fragmento) reFragmento; + + /* Keep a list of recorders we need to abort on cache flush. */ + CLS(TraceRecorder) abortStack; +} JSTraceMonitor; + +#ifdef JS_TRACER +# define JS_ON_TRACE(cx) (JS_TRACE_MONITOR(cx).onTrace) +#else +# define JS_ON_TRACE(cx) JS_FALSE +#endif + +#ifdef JS_THREADSAFE + +/* + * Structure uniquely representing a thread. It holds thread-private data + * that can be accessed without a global lock. + */ +struct JSThread { + /* Linked list of all contexts active on this thread. */ + JSCList contextList; + + /* Opaque thread-id, from NSPR's PR_GetCurrentThread(). */ + jsword id; + + /* + * Thread-local version of JSRuntime.gcMallocBytes to avoid taking + * locks on each JS_malloc. + */ + uint32 gcMallocBytes; + + /* + * Store the GSN cache in struct JSThread, not struct JSContext, both to + * save space and to simplify cleanup in js_GC. Any embedding (Firefox + * or another Gecko application) that uses many contexts per thread is + * unlikely to interleave js_GetSrcNote-intensive loops in the decompiler + * among two or more contexts running script in one thread. + */ + JSGSNCache gsnCache; + + /* Property cache for faster call/get/set invocation. */ + JSPropertyCache propertyCache; + + /* Trace-tree JIT recorder/interpreter state. */ + JSTraceMonitor traceMonitor; + + /* Lock-free list of scripts created by eval to garbage-collect. */ + JSScript *scriptsToGC; +}; + +#define JS_GSN_CACHE(cx) ((cx)->thread->gsnCache) +#define JS_PROPERTY_CACHE(cx) ((cx)->thread->propertyCache) +#define JS_TRACE_MONITOR(cx) ((cx)->thread->traceMonitor) +#define JS_SCRIPTS_TO_GC(cx) ((cx)->thread->scriptsToGC) + +extern void +js_ThreadDestructorCB(void *ptr); + +extern JSBool +js_SetContextThread(JSContext *cx); + +extern void +js_ClearContextThread(JSContext *cx); + +extern JSThread * +js_GetCurrentThread(JSRuntime *rt); + +#endif /* JS_THREADSAFE */ + +typedef enum JSDestroyContextMode { + JSDCM_NO_GC, + JSDCM_MAYBE_GC, + JSDCM_FORCE_GC, + JSDCM_NEW_FAILED +} JSDestroyContextMode; + +typedef enum JSRuntimeState { + JSRTS_DOWN, + JSRTS_LAUNCHING, + JSRTS_UP, + JSRTS_LANDING +} JSRuntimeState; + +typedef struct JSPropertyTreeEntry { + JSDHashEntryHdr hdr; + JSScopeProperty *child; +} JSPropertyTreeEntry; + +typedef struct JSSetSlotRequest JSSetSlotRequest; + +struct JSSetSlotRequest { + JSObject *obj; /* object containing slot to set */ + JSObject *pobj; /* new proto or parent reference */ + uint16 slot; /* which to set, proto or parent */ + uint16 errnum; /* JSMSG_NO_ERROR or error result */ + JSSetSlotRequest *next; /* next request in GC worklist */ +}; + +struct JSRuntime { + /* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */ + JSRuntimeState state; + + /* Context create/destroy callback. */ + JSContextCallback cxCallback; + + /* Garbage collector state, used by jsgc.c. */ + JSGCChunkInfo *gcChunkList; + JSGCArenaList gcArenaList[GC_NUM_FREELISTS]; + JSGCDoubleArenaList gcDoubleArenaList; + JSGCFreeListSet *gcFreeListsPool; + JSDHashTable gcRootsHash; + JSDHashTable *gcLocksHash; + jsrefcount gcKeepAtoms; + uint32 gcBytes; + uint32 gcLastBytes; + uint32 gcMaxBytes; + uint32 gcMaxMallocBytes; + uint32 gcEmptyArenaPoolLifespan; + uint32 gcLevel; + uint32 gcNumber; + JSTracer *gcMarkingTracer; + + /* + * NB: do not pack another flag here by claiming gcPadding unless the new + * flag is written only by the GC thread. Atomic updates to packed bytes + * are not guaranteed, so stores issued by one thread may be lost due to + * unsynchronized read-modify-write cycles on other threads. + */ + JSPackedBool gcPoke; + JSPackedBool gcRunning; + uint16 gcPadding; +#ifdef JS_GC_ZEAL + jsrefcount gcZeal; +#endif + + JSGCCallback gcCallback; + uint32 gcMallocBytes; + JSGCArenaInfo *gcUntracedArenaStackTop; +#ifdef DEBUG + size_t gcTraceLaterCount; +#endif + + /* + * Table for tracking iterators to ensure that we close iterator's state + * before finalizing the iterable object. + */ + JSPtrTable gcIteratorTable; + + /* + * The trace operation and its data argument to trace embedding-specific + * GC roots. + */ + JSTraceDataOp gcExtraRootsTraceOp; + void *gcExtraRootsData; + + /* + * Used to serialize cycle checks when setting __proto__ or __parent__ by + * requesting the GC handle the required cycle detection. If the GC hasn't + * been poked, it won't scan for garbage. This member is protected by + * rt->gcLock. + */ + JSSetSlotRequest *setSlotRequests; + + /* Random number generator state, used by jsmath.c. */ + JSBool rngInitialized; + int64 rngMultiplier; + int64 rngAddend; + int64 rngMask; + int64 rngSeed; + jsdouble rngDscale; + + /* Well-known numbers held for use by this runtime's contexts. */ + jsdouble *jsNaN; + jsdouble *jsNegativeInfinity; + jsdouble *jsPositiveInfinity; + +#ifdef JS_THREADSAFE + JSLock *deflatedStringCacheLock; +#endif + JSHashTable *deflatedStringCache; +#ifdef DEBUG + uint32 deflatedStringCacheBytes; +#endif + + /* + * Empty and unit-length strings held for use by this runtime's contexts. + * The unitStrings array and its elements are created on demand. + */ + JSString *emptyString; + JSString **unitStrings; + + /* List of active contexts sharing this runtime; protected by gcLock. */ + JSCList contextList; + + /* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */ + JSDebugHooks globalDebugHooks; + + /* More debugging state, see jsdbgapi.c. */ + JSCList trapList; + JSCList watchPointList; + + /* Client opaque pointers */ + void *data; + +#ifdef JS_THREADSAFE + /* These combine to interlock the GC and new requests. */ + PRLock *gcLock; + PRCondVar *gcDone; + PRCondVar *requestDone; + uint32 requestCount; + JSThread *gcThread; + + /* Lock and owning thread pointer for JS_LOCK_RUNTIME. */ + PRLock *rtLock; +#ifdef DEBUG + jsword rtLockOwner; +#endif + + /* Used to synchronize down/up state change; protected by gcLock. */ + PRCondVar *stateChange; + + /* + * State for sharing single-threaded titles, once a second thread tries to + * lock a title. The titleSharingDone condvar is protected by rt->gcLock + * to minimize number of locks taken in JS_EndRequest. + * + * The titleSharingTodo linked list is likewise "global" per runtime, not + * one-list-per-context, to conserve space over all contexts, optimizing + * for the likely case that titles become shared rarely, and among a very + * small set of threads (contexts). + */ + PRCondVar *titleSharingDone; + JSTitle *titleSharingTodo; + +/* + * Magic terminator for the rt->titleSharingTodo linked list, threaded through + * title->u.link. This hack allows us to test whether a title is on the list + * by asking whether title->u.link is non-null. We use a large, likely bogus + * pointer here to distinguish this value from any valid u.count (small int) + * value. + */ +#define NO_TITLE_SHARING_TODO ((JSTitle *) 0xfeedbeef) + + /* + * Lock serializing trapList and watchPointList accesses, and count of all + * mutations to trapList and watchPointList made by debugger threads. To + * keep the code simple, we define debuggerMutations for the thread-unsafe + * case too. + */ + PRLock *debuggerLock; +#endif /* JS_THREADSAFE */ + uint32 debuggerMutations; + + /* + * Security callbacks set on the runtime are used by each context unless + * an override is set on the context. + */ + JSSecurityCallbacks *securityCallbacks; + + /* + * Shared scope property tree, and arena-pool for allocating its nodes. + * The propertyRemovals counter is incremented for every js_ClearScope, + * and for each js_RemoveScopeProperty that frees a slot in an object. + * See js_NativeGet and js_NativeSet in jsobj.c. + */ + JSDHashTable propertyTreeHash; + JSScopeProperty *propertyFreeList; + JSArenaPool propertyArenaPool; + int32 propertyRemovals; + + /* Script filename table. */ + struct JSHashTable *scriptFilenameTable; + JSCList scriptFilenamePrefixes; +#ifdef JS_THREADSAFE + PRLock *scriptFilenameTableLock; +#endif + + /* Number localization, used by jsnum.c */ + const char *thousandsSeparator; + const char *decimalSeparator; + const char *numGrouping; + + /* + * Weak references to lazily-created, well-known XML singletons. + * + * NB: Singleton objects must be carefully disconnected from the rest of + * the object graph usually associated with a JSContext's global object, + * including the set of standard class objects. See jsxml.c for details. + */ + JSObject *anynameObject; + JSObject *functionNamespaceObject; + + /* + * A helper list for the GC, so it can mark native iterator states. See + * js_TraceNativeEnumerators for details. + */ + JSNativeEnumerator *nativeEnumerators; + +#ifndef JS_THREADSAFE + /* + * For thread-unsafe embeddings, the GSN cache lives in the runtime and + * not each context, since we expect it to be filled once when decompiling + * a longer script, then hit repeatedly as js_GetSrcNote is called during + * the decompiler activation that filled it. + */ + JSGSNCache gsnCache; + + /* Property cache for faster call/get/set invocation. */ + JSPropertyCache propertyCache; + + /* Trace-tree JIT recorder/interpreter state. */ + JSTraceMonitor traceMonitor; + + /* Lock-free list of scripts created by eval to garbage-collect. */ + JSScript *scriptsToGC; + +#define JS_GSN_CACHE(cx) ((cx)->runtime->gsnCache) +#define JS_PROPERTY_CACHE(cx) ((cx)->runtime->propertyCache) +#define JS_TRACE_MONITOR(cx) ((cx)->runtime->traceMonitor) +#define JS_SCRIPTS_TO_GC(cx) ((cx)->runtime->scriptsToGC) +#endif + + /* + * Object shape (property cache structural type) identifier generator. + * + * Type 0 stands for the empty scope, and must not be regenerated due to + * uint32 wrap-around. Since we use atomic pre-increment, the initial + * value for the first typed non-empty scope will be 1. + * + * The GC compresses live types, minimizing rt->shapeGen in the process. + * If this counter overflows into SHAPE_OVERFLOW_BIT (in jsinterp.h), the + * GC will disable property caches for all threads, to avoid aliasing two + * different types. Updated by js_GenerateShape (in jsinterp.c). + */ + uint32 shapeGen; + + /* Literal table maintained by jsatom.c functions. */ + JSAtomState atomState; + + /* + * Cache of reusable JSNativeEnumerators mapped by shape identifiers (as + * stored in scope->shape). This cache is nulled by the GC and protected + * by gcLock. + */ +#define NATIVE_ENUM_CACHE_LOG2 8 +#define NATIVE_ENUM_CACHE_MASK JS_BITMASK(NATIVE_ENUM_CACHE_LOG2) +#define NATIVE_ENUM_CACHE_SIZE JS_BIT(NATIVE_ENUM_CACHE_LOG2) + +#define NATIVE_ENUM_CACHE_HASH(shape) \ + ((((shape) >> NATIVE_ENUM_CACHE_LOG2) ^ (shape)) & NATIVE_ENUM_CACHE_MASK) + + jsuword nativeEnumCache[NATIVE_ENUM_CACHE_SIZE]; + + /* + * Runtime-wide flag set to true when any Array prototype has an indexed + * property defined on it, creating a hazard for code reading or writing + * over a hole from a dense Array instance that is not prepared to look up + * the proto chain (the writing case must involve a check for a read-only + * element, which cannot be shadowed). + */ + JSBool anyArrayProtoHasElement; + + /* + * Various metering fields are defined at the end of JSRuntime. In this + * way there is no need to recompile all the code that refers to other + * fields of JSRuntime after enabling the corresponding metering macro. + */ +#ifdef JS_DUMP_ENUM_CACHE_STATS + int32 nativeEnumProbes; + int32 nativeEnumMisses; +# define ENUM_CACHE_METER(name) JS_ATOMIC_INCREMENT(&cx->runtime->name) +#else +# define ENUM_CACHE_METER(name) ((void) 0) +#endif + +#ifdef JS_DUMP_LOOP_STATS + /* Loop statistics, to trigger trace recording and compiling. */ + JSBasicStats loopStats; +#endif + +#if defined DEBUG || defined JS_DUMP_PROPTREE_STATS + /* Function invocation metering. */ + jsrefcount inlineCalls; + jsrefcount nativeCalls; + jsrefcount nonInlineCalls; + jsrefcount constructs; + + /* Title lock and scope property metering. */ + jsrefcount claimAttempts; + jsrefcount claimedTitles; + jsrefcount deadContexts; + jsrefcount deadlocksAvoided; + jsrefcount liveScopes; + jsrefcount sharedTitles; + jsrefcount totalScopes; + jsrefcount liveScopeProps; + jsrefcount liveScopePropsPreSweep; + jsrefcount totalScopeProps; + jsrefcount livePropTreeNodes; + jsrefcount duplicatePropTreeNodes; + jsrefcount totalPropTreeNodes; + jsrefcount propTreeKidsChunks; + jsrefcount middleDeleteFixups; + + /* String instrumentation. */ + jsrefcount liveStrings; + jsrefcount totalStrings; + jsrefcount liveDependentStrings; + jsrefcount totalDependentStrings; + jsrefcount badUndependStrings; + double lengthSum; + double lengthSquaredSum; + double strdepLengthSum; + double strdepLengthSquaredSum; +#endif /* DEBUG || JS_DUMP_PROPTREE_STATS */ + +#ifdef JS_SCOPE_DEPTH_METER + /* + * Stats on runtime prototype chain lookups and scope chain depths, i.e., + * counts of objects traversed on a chain until the wanted id is found. + */ + JSBasicStats protoLookupDepthStats; + JSBasicStats scopeSearchDepthStats; + + /* + * Stats on compile-time host environment and lexical scope chain lengths + * (maximum depths). + */ + JSBasicStats hostenvScopeDepthStats; + JSBasicStats lexicalScopeDepthStats; +#endif + +#ifdef JS_GCMETER + JSGCStats gcStats; +#endif +}; + +#ifdef DEBUG +# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which) +# define JS_RUNTIME_UNMETER(rt, which) JS_ATOMIC_DECREMENT(&(rt)->which) +#else +# define JS_RUNTIME_METER(rt, which) /* nothing */ +# define JS_RUNTIME_UNMETER(rt, which) /* nothing */ +#endif + +#define JS_KEEP_ATOMS(rt) JS_ATOMIC_INCREMENT(&(rt)->gcKeepAtoms); +#define JS_UNKEEP_ATOMS(rt) JS_ATOMIC_DECREMENT(&(rt)->gcKeepAtoms); + +#ifdef JS_ARGUMENT_FORMATTER_DEFINED +/* + * Linked list mapping format strings for JS_{Convert,Push}Arguments{,VA} to + * formatter functions. Elements are sorted in non-increasing format string + * length order. + */ +struct JSArgumentFormatMap { + const char *format; + size_t length; + JSArgumentFormatter formatter; + JSArgumentFormatMap *next; +}; +#endif + +struct JSStackHeader { + uintN nslots; + JSStackHeader *down; +}; + +#define JS_STACK_SEGMENT(sh) ((jsval *)(sh) + 2) + +/* + * Key and entry types for the JSContext.resolvingTable hash table, typedef'd + * here because all consumers need to see these declarations (and not just the + * typedef names, as would be the case for an opaque pointer-to-typedef'd-type + * declaration), along with cx->resolvingTable. + */ +typedef struct JSResolvingKey { + JSObject *obj; + jsid id; +} JSResolvingKey; + +typedef struct JSResolvingEntry { + JSDHashEntryHdr hdr; + JSResolvingKey key; + uint32 flags; +} JSResolvingEntry; + +#define JSRESFLAG_LOOKUP 0x1 /* resolving id from lookup */ +#define JSRESFLAG_WATCH 0x2 /* resolving id from watch */ + +typedef struct JSLocalRootChunk JSLocalRootChunk; + +#define JSLRS_CHUNK_SHIFT 8 +#define JSLRS_CHUNK_SIZE JS_BIT(JSLRS_CHUNK_SHIFT) +#define JSLRS_CHUNK_MASK JS_BITMASK(JSLRS_CHUNK_SHIFT) + +struct JSLocalRootChunk { + jsval roots[JSLRS_CHUNK_SIZE]; + JSLocalRootChunk *down; +}; + +typedef struct JSLocalRootStack { + uint32 scopeMark; + uint32 rootCount; + JSLocalRootChunk *topChunk; + JSLocalRootChunk firstChunk; +} JSLocalRootStack; + +#define JSLRS_NULL_MARK ((uint32) -1) + +/* + * Macros to push/pop JSTempValueRooter instances to context-linked stack of + * temporary GC roots. If you need to protect a result value that flows out of + * a C function across several layers of other functions, use the + * js_LeaveLocalRootScopeWithResult internal API (see further below) instead. + * + * The macros also provide a simple way to get a single rooted pointer via + * JS_PUSH_TEMP_ROOT_(cx, NULL, &tvr). Then &tvr.u. gives the + * necessary pointer. + * + * JSTempValueRooter.count defines the type of the rooted value referenced by + * JSTempValueRooter.u union of type JSTempValueUnion. When count is positive + * or zero, u.array points to a vector of jsvals. Otherwise it must be one of + * the following constants: + */ +#define JSTVU_SINGLE (-1) /* u.value or u. is single jsval + or GC-thing */ +#define JSTVU_TRACE (-2) /* u.trace is a hook to trace a custom + * structure */ +#define JSTVU_SPROP (-3) /* u.sprop roots property tree node */ +#define JSTVU_WEAK_ROOTS (-4) /* u.weakRoots points to saved weak roots */ +#define JSTVU_PARSE_CONTEXT (-5) /* u.parseContext roots JSParseContext* */ +#define JSTVU_SCRIPT (-6) /* u.script roots JSScript* */ + +/* + * Here single JSTVU_SINGLE covers both jsval and pointers to any GC-thing via + * reinterpreting the thing as JSVAL_OBJECT. It works because the GC-thing is + * aligned on a 0 mod 8 boundary, and object has the 0 jsval tag. So any + * GC-thing may be tagged as if it were an object and untagged, if it's then + * used only as an opaque pointer until discriminated by other means than tag + * bits. This is how, for example, js_GetGCThingTraceKind uses its |thing| + * parameter -- it consults GC-thing flags stored separately from the thing to + * decide the kind of thing. + * + * The following checks that this type-punning is possible. + */ +JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval)); +JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(void *)); + +#define JS_PUSH_TEMP_ROOT_COMMON(cx,x,tvr,cnt,kind) \ + JS_BEGIN_MACRO \ + JS_ASSERT((cx)->tempValueRooters != (tvr)); \ + (tvr)->count = (cnt); \ + (tvr)->u.kind = (x); \ + (tvr)->down = (cx)->tempValueRooters; \ + (cx)->tempValueRooters = (tvr); \ + JS_END_MACRO + +#define JS_POP_TEMP_ROOT(cx,tvr) \ + JS_BEGIN_MACRO \ + JS_ASSERT((cx)->tempValueRooters == (tvr)); \ + (cx)->tempValueRooters = (tvr)->down; \ + JS_END_MACRO + +#define JS_PUSH_TEMP_ROOT(cx,cnt,arr,tvr) \ + JS_BEGIN_MACRO \ + JS_ASSERT((int)(cnt) >= 0); \ + JS_PUSH_TEMP_ROOT_COMMON(cx, arr, tvr, (ptrdiff_t) (cnt), array); \ + JS_END_MACRO + +#define JS_PUSH_SINGLE_TEMP_ROOT(cx,val,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, val, tvr, JSTVU_SINGLE, value) + +#define JS_PUSH_TEMP_ROOT_OBJECT(cx,obj,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, obj, tvr, JSTVU_SINGLE, object) + +#define JS_PUSH_TEMP_ROOT_STRING(cx,str,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, str, tvr, JSTVU_SINGLE, string) + +#define JS_PUSH_TEMP_ROOT_XML(cx,xml_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, xml_, tvr, JSTVU_SINGLE, xml) + +#define JS_PUSH_TEMP_ROOT_TRACE(cx,trace_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, trace_, tvr, JSTVU_TRACE, trace) + +#define JS_PUSH_TEMP_ROOT_SPROP(cx,sprop_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, sprop_, tvr, JSTVU_SPROP, sprop) + +#define JS_PUSH_TEMP_ROOT_WEAK_COPY(cx,weakRoots_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, weakRoots_, tvr, JSTVU_WEAK_ROOTS, weakRoots) + +#define JS_PUSH_TEMP_ROOT_PARSE_CONTEXT(cx,pc,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, pc, tvr, JSTVU_PARSE_CONTEXT, parseContext) + +#define JS_PUSH_TEMP_ROOT_SCRIPT(cx,script_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, script_, tvr, JSTVU_SCRIPT, script) + + +#define JSRESOLVE_INFER 0xffff /* infer bits from current bytecode */ + +struct JSContext { + /* JSRuntime contextList linkage. */ + JSCList links; + + /* + * Operation count. It is declared early in the structure as a frequently + * accessed field. + */ + int32 operationCount; + +#if JS_HAS_XML_SUPPORT + /* + * Bit-set formed from binary exponentials of the XML_* tiny-ids defined + * for boolean settings in jsxml.c, plus an XSF_CACHE_VALID bit. Together + * these act as a cache of the boolean XML.ignore* and XML.prettyPrinting + * property values associated with this context's global object. + */ + uint8 xmlSettingFlags; + uint8 padding; +#else + uint16 padding; +#endif + + /* + * Classic Algol "display" static link optimization. + */ +#define JS_DISPLAY_SIZE 16 + + JSStackFrame *display[JS_DISPLAY_SIZE]; + + /* Runtime version control identifier. */ + uint16 version; + + /* Per-context options. */ + uint32 options; /* see jsapi.h for JSOPTION_* */ + + /* Locale specific callbacks for string conversion. */ + JSLocaleCallbacks *localeCallbacks; + + /* + * cx->resolvingTable is non-null and non-empty if we are initializing + * standard classes lazily, or if we are otherwise recursing indirectly + * from js_LookupProperty through a JSClass.resolve hook. It is used to + * limit runaway recursion (see jsapi.c and jsobj.c). + */ + JSDHashTable *resolvingTable; + +#if JS_HAS_LVALUE_RETURN + /* + * Secondary return value from native method called on the left-hand side + * of an assignment operator. The native should store the object in which + * to set a property in *rval, and return the property's id expressed as a + * jsval by calling JS_SetCallReturnValue2(cx, idval). + */ + jsval rval2; + JSPackedBool rval2set; +#endif + + /* + * True if generating an error, to prevent runaway recursion. + * NB: generatingError packs with rval2set, #if JS_HAS_LVALUE_RETURN; + * with insideGCMarkCallback and with throwing below. + */ + JSPackedBool generatingError; + + /* Flag to indicate that we run inside gcCallback(cx, JSGC_MARK_END). */ + JSPackedBool insideGCMarkCallback; + + /* Exception state -- the exception member is a GC root by definition. */ + JSPackedBool throwing; /* is there a pending exception? */ + jsval exception; /* most-recently-thrown exception */ + + /* Limit pointer for checking native stack consumption during recursion. */ + jsuword stackLimit; + + /* Quota on the size of arenas used to compile and execute scripts. */ + size_t scriptStackQuota; + + /* Data shared by threads in an address space. */ + JSRuntime *runtime; + + /* Stack arena pool and frame pointer register. */ + JSArenaPool stackPool; + JSStackFrame *fp; + + /* Temporary arena pool used while compiling and decompiling. */ + JSArenaPool tempPool; + + /* Top-level object and pointer to top stack frame's scope chain. */ + JSObject *globalObject; + + /* Storage to root recently allocated GC things and script result. */ + JSWeakRoots weakRoots; + + /* Regular expression class statics (XXX not shared globally). */ + JSRegExpStatics regExpStatics; + + /* State for object and array toSource conversion. */ + JSSharpObjectMap sharpObjectMap; + + /* Argument formatter support for JS_{Convert,Push}Arguments{,VA}. */ + JSArgumentFormatMap *argumentFormatMap; + + /* Last message string and trace file for debugging. */ + char *lastMessage; +#ifdef DEBUG + void *tracefp; +#endif + + /* Per-context optional error reporter. */ + JSErrorReporter errorReporter; + + /* + * Flag indicating that the operation callback is set. When the flag is 0 + * but operationCallback is not null, operationCallback stores the branch + * callback. + */ + uint32 operationCallbackIsSet : 1; + uint32 operationLimit : 31; + JSOperationCallback operationCallback; + + /* Interpreter activation count. */ + uintN interpLevel; + + /* Client opaque pointers. */ + void *data; + void *data2; + + /* GC and thread-safe state. */ + JSStackFrame *dormantFrameChain; /* dormant stack frame to scan */ +#ifdef JS_THREADSAFE + JSThread *thread; + jsrefcount requestDepth; + /* Same as requestDepth but ignoring JS_SuspendRequest/JS_ResumeRequest */ + jsrefcount outstandingRequests; + JSTitle *titleToShare; /* weak reference, see jslock.c */ + JSTitle *lockedSealedTitle; /* weak ref, for low-cost sealed + title locking */ + JSCList threadLinks; /* JSThread contextList linkage */ + +#define CX_FROM_THREAD_LINKS(tl) \ + ((JSContext *)((char *)(tl) - offsetof(JSContext, threadLinks))) +#endif + + /* PDL of stack headers describing stack slots not rooted by argv, etc. */ + JSStackHeader *stackHeaders; + + /* Optional stack of heap-allocated scoped local GC roots. */ + JSLocalRootStack *localRootStack; + + /* Stack of thread-stack-allocated temporary GC roots. */ + JSTempValueRooter *tempValueRooters; + +#ifdef JS_THREADSAFE + JSGCFreeListSet *gcLocalFreeLists; +#endif + + /* List of pre-allocated doubles. */ + JSGCDoubleCell *doubleFreeList; + + /* Debug hooks associated with the current context. */ + JSDebugHooks *debugHooks; + + /* Security callbacks that override any defined on the runtime. */ + JSSecurityCallbacks *securityCallbacks; + + /* Pinned regexp pool used for regular expressions. */ + JSArenaPool regexpPool; + + /* Stored here to avoid passing it around as a parameter. */ + uintN resolveFlags; +}; + +#ifdef JS_THREADSAFE +# define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0) +#endif + +#ifdef __cplusplus +/* FIXME(bug 332648): Move this into a public header. */ +class JSAutoTempValueRooter +{ + public: + JSAutoTempValueRooter(JSContext *cx, size_t len, jsval *vec) + : mContext(cx) { + JS_PUSH_TEMP_ROOT(mContext, len, vec, &mTvr); + } + JSAutoTempValueRooter(JSContext *cx, jsval v) + : mContext(cx) { + JS_PUSH_SINGLE_TEMP_ROOT(mContext, v, &mTvr); + } + + ~JSAutoTempValueRooter() { + JS_POP_TEMP_ROOT(mContext, &mTvr); + } + + protected: + JSContext *mContext; + + private: +#ifndef AIX + static void *operator new(size_t); + static void operator delete(void *, size_t); +#endif + + JSTempValueRooter mTvr; +}; + +class JSAutoResolveFlags +{ + public: + JSAutoResolveFlags(JSContext *cx, uintN flags) + : mContext(cx), mSaved(cx->resolveFlags) { + cx->resolveFlags = flags; + } + + ~JSAutoResolveFlags() { mContext->resolveFlags = mSaved; } + + private: + JSContext *mContext; + uintN mSaved; +}; +#endif + +/* + * Slightly more readable macros for testing per-context option settings (also + * to hide bitset implementation detail). + * + * JSOPTION_XML must be handled specially in order to propagate from compile- + * to run-time (from cx->options to script->version/cx->version). To do that, + * we copy JSOPTION_XML from cx->options into cx->version as JSVERSION_HAS_XML + * whenever options are set, and preserve this XML flag across version number + * changes done via the JS_SetVersion API. + * + * But when executing a script or scripted function, the interpreter changes + * cx->version, including the XML flag, to script->version. Thus JSOPTION_XML + * is a compile-time option that causes a run-time version change during each + * activation of the compiled script. That version change has the effect of + * changing JS_HAS_XML_OPTION, so that any compiling done via eval enables XML + * support. If an XML-enabled script or function calls a non-XML function, + * the flag bit will be cleared during the callee's activation. + * + * Note that JS_SetVersion API calls never pass JSVERSION_HAS_XML or'd into + * that API's version parameter. + * + * Note also that script->version must contain this XML option flag in order + * for XDR'ed scripts to serialize and deserialize with that option preserved + * for detection at run-time. We can't copy other compile-time options into + * script->version because that would break backward compatibility (certain + * other options, e.g. JSOPTION_VAROBJFIX, are analogous to JSOPTION_XML). + */ +#define JS_HAS_OPTION(cx,option) (((cx)->options & (option)) != 0) +#define JS_HAS_STRICT_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_STRICT) +#define JS_HAS_WERROR_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_WERROR) +#define JS_HAS_COMPILE_N_GO_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_COMPILE_N_GO) +#define JS_HAS_ATLINE_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_ATLINE) + +#define JSVERSION_MASK 0x0FFF /* see JSVersion in jspubtd.h */ +#define JSVERSION_HAS_XML 0x1000 /* flag induced by XML option */ + +#define JSVERSION_NUMBER(cx) ((JSVersion)((cx)->version & \ + JSVERSION_MASK)) +#define JS_HAS_XML_OPTION(cx) ((cx)->version & JSVERSION_HAS_XML || \ + JSVERSION_NUMBER(cx) >= JSVERSION_1_6) + +/* + * Initialize a library-wide thread private data index, and remember that it + * has already been done, so that it happens only once ever. Returns true on + * success. + */ +extern JSBool +js_InitThreadPrivateIndex(void (*ptr)(void *)); + +/* + * Common subroutine of JS_SetVersion and js_SetVersion, to update per-context + * data that depends on version. + */ +extern void +js_OnVersionChange(JSContext *cx); + +/* + * Unlike the JS_SetVersion API, this function stores JSVERSION_HAS_XML and + * any future non-version-number flags induced by compiler options. + */ +extern void +js_SetVersion(JSContext *cx, JSVersion version); + +/* + * Create and destroy functions for JSContext, which is manually allocated + * and exclusively owned. + */ +extern JSContext * +js_NewContext(JSRuntime *rt, size_t stackChunkSize); + +extern void +js_DestroyContext(JSContext *cx, JSDestroyContextMode mode); + +/* + * Return true if cx points to a context in rt->contextList, else return false. + * NB: the caller (see jslock.c:ClaimTitle) must hold rt->gcLock. + */ +extern JSBool +js_ValidContextPointer(JSRuntime *rt, JSContext *cx); + +/* + * If unlocked, acquire and release rt->gcLock around *iterp update; otherwise + * the caller must be holding rt->gcLock. + */ +extern JSContext * +js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp); + +/* + * JSClass.resolve and watchpoint recursion damping machinery. + */ +extern JSBool +js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, + JSResolvingEntry **entryp); + +extern void +js_StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, + JSResolvingEntry *entry, uint32 generation); + +/* + * Local root set management. + * + * NB: the jsval parameters below may be properly tagged jsvals, or GC-thing + * pointers cast to (jsval). This relies on JSObject's tag being zero, but + * on the up side it lets us push int-jsval-encoded scopeMark values on the + * local root stack. + */ +extern JSBool +js_EnterLocalRootScope(JSContext *cx); + +#define js_LeaveLocalRootScope(cx) \ + js_LeaveLocalRootScopeWithResult(cx, JSVAL_NULL) + +extern void +js_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval); + +extern void +js_ForgetLocalRoot(JSContext *cx, jsval v); + +extern int +js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v); + +extern void +js_TraceLocalRoots(JSTracer *trc, JSLocalRootStack *lrs); + +/* + * Report an exception, which is currently realized as a printf-style format + * string and its arguments. + */ +typedef enum JSErrNum { +#define MSG_DEF(name, number, count, exception, format) \ + name = number, +#include "js.msg" +#undef MSG_DEF + JSErr_Limit +} JSErrNum; + +extern JS_FRIEND_API(const JSErrorFormatString *) +js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber); + +#ifdef va_start +extern JSBool +js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap); + +extern JSBool +js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback, + void *userRef, const uintN errorNumber, + JSBool charArgs, va_list ap); + +extern JSBool +js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback, + void *userRef, const uintN errorNumber, + char **message, JSErrorReport *reportp, + JSBool *warningp, JSBool charArgs, va_list ap); +#endif + +extern void +js_ReportOutOfMemory(JSContext *cx); + +/* + * Report that cx->scriptStackQuota is exhausted. + */ +extern void +js_ReportOutOfScriptQuota(JSContext *cx); + +extern void +js_ReportOverRecursed(JSContext *cx); + +extern void +js_ReportAllocationOverflow(JSContext *cx); + +#define JS_CHECK_RECURSION(cx, onerror) \ + JS_BEGIN_MACRO \ + int stackDummy_; \ + \ + if (!JS_CHECK_STACK_SIZE(cx, stackDummy_)) { \ + js_ReportOverRecursed(cx); \ + onerror; \ + } \ + JS_END_MACRO + +/* + * Report an exception using a previously composed JSErrorReport. + * XXXbe remove from "friend" API + */ +extern JS_FRIEND_API(void) +js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *report); + +extern void +js_ReportIsNotDefined(JSContext *cx, const char *name); + +/* + * Report an attempt to access the property of a null or undefined value (v). + */ +extern JSBool +js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, jsval v, + JSString *fallback); + +extern void +js_ReportMissingArg(JSContext *cx, jsval *vp, uintN arg); + +/* + * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as + * the first argument for the error message. If the error message has less + * then 3 arguments, use null for arg1 or arg2. + */ +extern JSBool +js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber, + intN spindex, jsval v, JSString *fallback, + const char *arg1, const char *arg2); + +#define js_ReportValueError(cx,errorNumber,spindex,v,fallback) \ + ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \ + spindex, v, fallback, NULL, NULL)) + +#define js_ReportValueError2(cx,errorNumber,spindex,v,fallback,arg1) \ + ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \ + spindex, v, fallback, arg1, NULL)) + +#define js_ReportValueError3(cx,errorNumber,spindex,v,fallback,arg1,arg2) \ + ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \ + spindex, v, fallback, arg1, arg2)) + +extern JSErrorFormatString js_ErrorFormatString[JSErr_Limit]; + +/* + * See JS_SetThreadStackLimit in jsapi.c, where we check that the stack grows + * in the expected direction. On Unix-y systems, JS_STACK_GROWTH_DIRECTION is + * computed on the build host by jscpucfg.c and written into jsautocfg.h. The + * macro is hardcoded in jscpucfg.h on Windows and Mac systems (for historical + * reasons pre-dating autoconf usage). + */ +#if JS_STACK_GROWTH_DIRECTION > 0 +# define JS_CHECK_STACK_SIZE(cx, lval) ((jsuword)&(lval) < (cx)->stackLimit) +#else +# define JS_CHECK_STACK_SIZE(cx, lval) ((jsuword)&(lval) > (cx)->stackLimit) +#endif + +/* + * Update the operation counter according to the given weight and call the + * operation callback when we reach the operation limit. To make this + * frequently executed macro faster we decrease the counter from + * JSContext.operationLimit and compare against zero to check the limit. + * + * This macro can run the full GC. Return true if it is OK to continue and + * false otherwise. + */ +#define JS_CHECK_OPERATION_LIMIT(cx, weight) \ + (JS_CHECK_OPERATION_WEIGHT(weight), \ + (((cx)->operationCount -= (weight)) > 0 || js_ResetOperationCount(cx))) + +/* + * A version of JS_CHECK_OPERATION_LIMIT that just updates the operation count + * without calling the operation callback or any other API. This macro resets + * the count to 0 when it becomes negative to prevent a wrap-around when the + * macro is called repeatably. + */ +#define JS_COUNT_OPERATION(cx, weight) \ + ((void)(JS_CHECK_OPERATION_WEIGHT(weight), \ + (cx)->operationCount = ((cx)->operationCount > 0) \ + ? (cx)->operationCount - (weight) \ + : 0)) + +/* + * The implementation of the above macros assumes that subtracting weights + * twice from a positive number does not wrap-around INT32_MIN. + */ +#define JS_CHECK_OPERATION_WEIGHT(weight) \ + (JS_ASSERT((uint32) (weight) > 0), \ + JS_ASSERT((uint32) (weight) < JS_BIT(30))) + +/* Relative operations weights. */ +#define JSOW_JUMP 1 +#define JSOW_ALLOCATION 100 +#define JSOW_LOOKUP_PROPERTY 5 +#define JSOW_GET_PROPERTY 10 +#define JSOW_SET_PROPERTY 20 +#define JSOW_NEW_PROPERTY 200 +#define JSOW_DELETE_PROPERTY 30 +#define JSOW_ENTER_SHARP JS_OPERATION_WEIGHT_BASE +#define JSOW_SCRIPT_JUMP JS_OPERATION_WEIGHT_BASE + +/* + * Reset the operation count and call the operation callback assuming that the + * operation limit is reached. + */ +extern JSBool +js_ResetOperationCount(JSContext *cx); + +JS_END_EXTERN_C + +#endif /* jscntxt_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscompat.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscompat.h new file mode 100644 index 0000000..80d8605 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscompat.h @@ -0,0 +1,57 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* -*- Mode: C; tab-width: 8 -*- + * Copyright (C) 1996-1999 Netscape Communications Corporation, All Rights Reserved. + */ +#ifndef jscompat_h___ +#define jscompat_h___ +/* + * Compatibility glue for various NSPR versions. We must always define int8, + * int16, jsword, and so on to minimize differences with js/ref, no matter what + * the NSPR typedef names may be. + */ +#include "jstypes.h" +#include "jslong.h" + +typedef JSIntn intN; +typedef JSUintn uintN; +typedef JSUword jsuword; +typedef JSWord jsword; +typedef float float32; +#define allocPriv allocPool +#endif /* jscompat_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsconfig.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsconfig.mk new file mode 100644 index 0000000..1aeb75f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsconfig.mk @@ -0,0 +1,181 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +ifndef OBJDIR + ifdef OBJDIR_NAME + OBJDIR = $(OBJDIR_NAME) + endif +endif + +NSPR_VERSION = v4.0 +NSPR_LIBSUFFIX = 4 + +NSPR_LOCAL = $(MOZ_DEPTH)/dist/$(OBJDIR)/nspr +NSPR_DIST = $(MOZ_DEPTH)/dist/$(OBJDIR) +NSPR_OBJDIR = $(OBJDIR) +ifeq ($(OS_ARCH), SunOS) + NSPR_OBJDIR := $(subst _sparc,,$(NSPR_OBJDIR)) +endif +ifeq ($(OS_ARCH), Linux) + LINUX_REL := $(shell uname -r) + ifneq (,$(findstring 2.0,$(LINUX_REL))) + NSPR_OBJDIR := $(subst _All,2.0_x86_glibc_PTH,$(NSPR_OBJDIR)) + else + NSPR_OBJDIR := $(subst _All,2.2_x86_glibc_PTH,$(NSPR_OBJDIR)) + endif +endif +ifeq ($(OS_ARCH), AIX) + NSPR_OBJDIR := $(subst 4.1,4.2,$(NSPR_OBJDIR)) +endif +ifeq ($(OS_CONFIG), IRIX6.2) + NSPR_OBJDIR := $(subst 6.2,6.2_n32_PTH,$(NSPR_OBJDIR)) +endif +ifeq ($(OS_CONFIG), IRIX6.5) + NSPR_OBJDIR := $(subst 6.5,6.5_n32_PTH,$(NSPR_OBJDIR)) +endif +ifeq ($(OS_ARCH), WINNT) + ifeq ($(OBJDIR), WIN32_D.OBJ) + NSPR_OBJDIR = WINNT4.0_DBG.OBJ + endif + ifeq ($(OBJDIR), WIN32_O.OBJ) + NSPR_OBJDIR = WINNT4.0_OPT.OBJ + endif +endif +NSPR_SHARED = /share/builds/components/nspr20/$(NSPR_VERSION)/$(NSPR_OBJDIR) +ifeq ($(OS_ARCH), WINNT) + NSPR_SHARED = nspr20/$(NSPR_VERSION)/$(NSPR_OBJDIR) +endif +NSPR_VERSIONFILE = $(NSPR_LOCAL)/Version +NSPR_CURVERSION := $(shell cat $(NSPR_VERSIONFILE) 2>/dev/null) + +get_nspr: + @echo "Grabbing NSPR component..." +ifeq ($(NSPR_VERSION), $(NSPR_CURVERSION)) + @echo "No need, NSPR is up to date in this tree (ver=$(NSPR_VERSION))." +else + mkdir -p $(NSPR_LOCAL) + mkdir -p $(NSPR_DIST) + ifneq ($(OS_ARCH), WINNT) + cp $(NSPR_SHARED)/*.jar $(NSPR_LOCAL) + else + sh $(MOZ_DEPTH)/../reltools/compftp.sh $(NSPR_SHARED) $(NSPR_LOCAL) *.jar + endif + unzip -o $(NSPR_LOCAL)/mdbinary.jar -d $(NSPR_DIST) + mkdir -p $(NSPR_DIST)/include + unzip -o $(NSPR_LOCAL)/mdheader.jar -d $(NSPR_DIST)/include + rm -rf $(NSPR_DIST)/META-INF + rm -rf $(NSPR_DIST)/include/META-INF + echo $(NSPR_VERSION) > $(NSPR_VERSIONFILE) +endif + +SHIP_DIST = $(MOZ_DEPTH)/dist/$(OBJDIR) +SHIP_DIR = $(SHIP_DIST)/SHIP + +SHIP_LIBS = libjs.$(SO_SUFFIX) libjs.a +ifdef JS_LIVECONNECT + SHIP_LIBS += libjsj.$(SO_SUFFIX) libjsj.a +endif +ifeq ($(OS_ARCH), WINNT) + SHIP_LIBS = js32.dll js32.lib + ifdef JS_LIVECONNECT + SHIP_LIBS += jsj.dll jsj.lib + endif +endif +SHIP_LIBS += $(LCJAR) +SHIP_LIBS := $(addprefix $(SHIP_DIST)/lib/, $(SHIP_LIBS)) + +SHIP_INCS = js*.h prmjtime.h resource.h *.msg *.tbl +ifdef JS_LIVECONNECT + SHIP_INCS += netscape*.h nsC*.h nsI*.h +endif +SHIP_INCS := $(addprefix $(SHIP_DIST)/include/, $(SHIP_INCS)) + +SHIP_BINS = js +ifdef JS_LIVECONNECT + SHIP_BINS += lcshell +endif +ifeq ($(OS_ARCH), WINNT) + SHIP_BINS := $(addsuffix .exe, $(SHIP_BINS)) +endif +SHIP_BINS := $(addprefix $(SHIP_DIST)/bin/, $(SHIP_BINS)) + +ifdef BUILD_OPT + JSREFJAR = jsref_opt.jar +else +ifdef BUILD_IDG + JSREFJAR = jsref_idg.jar +else + JSREFJAR = jsref_dbg.jar +endif +endif + +ship: + mkdir -p $(SHIP_DIR)/$(LIBDIR) + mkdir -p $(SHIP_DIR)/include + mkdir -p $(SHIP_DIR)/bin + cp $(SHIP_LIBS) $(SHIP_DIR)/$(LIBDIR) + cp $(SHIP_INCS) $(SHIP_DIR)/include + cp $(SHIP_BINS) $(SHIP_DIR)/bin + cd $(SHIP_DIR); \ + zip -r $(JSREFJAR) bin lib include +ifdef BUILD_SHIP + cp $(SHIP_DIR)/$(JSREFJAR) $(BUILD_SHIP) +endif + +CWD = $(shell pwd) +shipSource: $(SHIP_DIR)/jsref_src.lst .FORCE + mkdir -p $(SHIP_DIR) + cd $(MOZ_DEPTH)/.. ; \ + zip $(CWD)/$(SHIP_DIR)/jsref_src.jar -@ < $(CWD)/$(SHIP_DIR)/jsref_src.lst +ifdef BUILD_SHIP + cp $(SHIP_DIR)/jsref_src.jar $(BUILD_SHIP) +endif + +JSREFSRCDIRS := $(shell cat $(DEPTH)/SpiderMonkey.rsp) +$(SHIP_DIR)/jsref_src.lst: .FORCE + mkdir -p $(SHIP_DIR) + rm -f $@ + touch $@ + for d in $(JSREFSRCDIRS); do \ + cd $(MOZ_DEPTH)/..; \ + ls -1 -d $$d | grep -v CVS | grep -v \.OBJ >> $(CWD)/$@; \ + cd $(CWD); \ + done + +.FORCE: diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscpucfg.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscpucfg.cpp new file mode 100644 index 0000000..c41a47e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscpucfg.cpp @@ -0,0 +1,388 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Roland Mainz + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Generate CPU-specific bit-size and similar #defines. + */ +#include +#include + +#ifdef CROSS_COMPILE +#include +#define INT64 PRInt64 +#else + +/************************************************************************/ + +/* Generate cpucfg.h */ + +#if defined(XP_WIN) || defined(XP_OS2) +#ifdef WIN32 +#if defined(__GNUC__) +#define INT64 long long +#else +#define INT64 _int64 +#endif /* __GNUC__ */ +#else +#define INT64 long +#endif +#else +#if defined(HPUX) || defined(__QNX__) +#define INT64 long +#else +#define INT64 long long +#endif +#endif + +#endif /* CROSS_COMPILE */ + +#ifdef __GNUC__ +#define NS_NEVER_INLINE __attribute__((noinline)) +#else +#define NS_NEVER_INLINE +#endif + +#ifdef __SUNPRO_C +static int StackGrowthDirection(int *dummy1addr); +#pragma no_inline(StackGrowthDirection) +#endif + +typedef void *prword; + +struct align_short { + char c; + short a; +}; +struct align_int { + char c; + int a; +}; +struct align_long { + char c; + long a; +}; +struct align_int64 { + char c; + INT64 a; +}; +struct align_fakelonglong { + char c; + struct { + long hi, lo; + } a; +}; +struct align_float { + char c; + float a; +}; +struct align_double { + char c; + double a; +}; +struct align_pointer { + char c; + void *a; +}; +struct align_prword { + char c; + prword a; +}; + +#define ALIGN_OF(type) \ + (((char*)&(((struct align_##type *)0)->a)) - ((char*)0)) + +unsigned int bpb; + +static int Log2(unsigned int n) +{ + int log2 = 0; + + if (n & (n-1)) + log2++; + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; +} + +/* + * Conceivably this could actually be used, but there is lots of code out + * there with ands and shifts in it that assumes a byte is exactly 8 bits, + * so forget about porting THIS code to all those non 8 bit byte machines. + */ +static void BitsPerByte(void) +{ + bpb = 8; +} + +static int NS_NEVER_INLINE StackGrowthDirection(int *dummy1addr) +{ + int dummy2; + + return (&dummy2 < dummy1addr) ? -1 : 1; +} + +int main(int argc, char **argv) +{ + int sizeof_char, sizeof_short, sizeof_int, sizeof_int64, sizeof_long, + sizeof_float, sizeof_double, sizeof_word, sizeof_dword; + int bits_per_int64_log2, align_of_short, align_of_int, align_of_long, + align_of_int64, align_of_float, align_of_double, align_of_pointer, + align_of_word; + int dummy1; + + BitsPerByte(); + + printf("#ifndef js_cpucfg___\n"); + printf("#define js_cpucfg___\n\n"); + + printf("/* AUTOMATICALLY GENERATED - DO NOT EDIT */\n\n"); + +#ifdef CROSS_COMPILE +#if defined(IS_LITTLE_ENDIAN) + printf("#define IS_LITTLE_ENDIAN 1\n"); + printf("#undef IS_BIG_ENDIAN\n\n"); +#elif defined(IS_BIG_ENDIAN) + printf("#undef IS_LITTLE_ENDIAN\n"); + printf("#define IS_BIG_ENDIAN 1\n\n"); +#else +#error "Endianess not defined." +#endif + + sizeof_char = PR_BYTES_PER_BYTE; + sizeof_short = PR_BYTES_PER_SHORT; + sizeof_int = PR_BYTES_PER_INT; + sizeof_int64 = PR_BYTES_PER_INT64; + sizeof_long = PR_BYTES_PER_LONG; + sizeof_float = PR_BYTES_PER_FLOAT; + sizeof_double = PR_BYTES_PER_DOUBLE; + sizeof_word = PR_BYTES_PER_WORD; + sizeof_dword = PR_BYTES_PER_DWORD; + + bits_per_int64_log2 = PR_BITS_PER_INT64_LOG2; + + align_of_short = PR_ALIGN_OF_SHORT; + align_of_int = PR_ALIGN_OF_INT; + align_of_long = PR_ALIGN_OF_LONG; + align_of_int64 = PR_ALIGN_OF_INT64; + align_of_float = PR_ALIGN_OF_FLOAT; + align_of_double = PR_ALIGN_OF_DOUBLE; + align_of_pointer = PR_ALIGN_OF_POINTER; + align_of_word = PR_ALIGN_OF_WORD; + +#else /* !CROSS_COMPILE */ + + /* + * We don't handle PDP-endian or similar orders: if a short is big-endian, + * so must int and long be big-endian for us to generate the IS_BIG_ENDIAN + * #define and the IS_LITTLE_ENDIAN #undef. + */ + { + int big_endian = 0, little_endian = 0, ntests = 0; + + if (sizeof(short) == 2) { + /* force |volatile| here to get rid of any compiler optimisations + * (var in register etc.) which may be appiled to |auto| vars - + * even those in |union|s... + * (|static| is used to get the same functionality for compilers + * which do not honor |volatile|...). + */ + volatile static union { + short i; + char c[2]; + } u; + + u.i = 0x0102; + big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02); + little_endian += (u.c[0] == 0x02 && u.c[1] == 0x01); + ntests++; + } + + if (sizeof(int) == 4) { + /* force |volatile| here ... */ + volatile static union { + int i; + char c[4]; + } u; + + u.i = 0x01020304; + big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02 && + u.c[2] == 0x03 && u.c[3] == 0x04); + little_endian += (u.c[0] == 0x04 && u.c[1] == 0x03 && + u.c[2] == 0x02 && u.c[3] == 0x01); + ntests++; + } + + if (sizeof(long) == 8) { + /* force |volatile| here ... */ + volatile static union { + long i; + char c[8]; + } u; + + /* + * Write this as portably as possible: avoid 0x0102030405060708L + * and <<= 32. + */ + u.i = 0x01020304; + u.i <<= 16, u.i <<= 16; + u.i |= 0x05060708; + big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02 && + u.c[2] == 0x03 && u.c[3] == 0x04 && + u.c[4] == 0x05 && u.c[5] == 0x06 && + u.c[6] == 0x07 && u.c[7] == 0x08); + little_endian += (u.c[0] == 0x08 && u.c[1] == 0x07 && + u.c[2] == 0x06 && u.c[3] == 0x05 && + u.c[4] == 0x04 && u.c[5] == 0x03 && + u.c[6] == 0x02 && u.c[7] == 0x01); + ntests++; + } + + if (big_endian && big_endian == ntests) { + printf("#undef IS_LITTLE_ENDIAN\n"); + printf("#define IS_BIG_ENDIAN 1\n\n"); + } else if (little_endian && little_endian == ntests) { + printf("#define IS_LITTLE_ENDIAN 1\n"); + printf("#undef IS_BIG_ENDIAN\n\n"); + } else { + fprintf(stderr, "%s: unknown byte order" + "(big_endian=%d, little_endian=%d, ntests=%d)!\n", + argv[0], big_endian, little_endian, ntests); + return EXIT_FAILURE; + } + } + + sizeof_char = sizeof(char); + sizeof_short = sizeof(short); + sizeof_int = sizeof(int); + sizeof_int64 = 8; + sizeof_long = sizeof(long); + sizeof_float = sizeof(float); + sizeof_double = sizeof(double); + sizeof_word = sizeof(prword); + sizeof_dword = 8; + + bits_per_int64_log2 = 6; + + align_of_short = ALIGN_OF(short); + align_of_int = ALIGN_OF(int); + align_of_long = ALIGN_OF(long); + if (sizeof(INT64) < 8) { + /* this machine doesn't actually support int64's */ + align_of_int64 = ALIGN_OF(fakelonglong); + } else { + align_of_int64 = ALIGN_OF(int64); + } + align_of_float = ALIGN_OF(float); + align_of_double = ALIGN_OF(double); + align_of_pointer = ALIGN_OF(pointer); + align_of_word = ALIGN_OF(prword); + +#endif /* CROSS_COMPILE */ + + printf("#define JS_BYTES_PER_BYTE %dL\n", sizeof_char); + printf("#define JS_BYTES_PER_SHORT %dL\n", sizeof_short); + printf("#define JS_BYTES_PER_INT %dL\n", sizeof_int); + printf("#define JS_BYTES_PER_INT64 %dL\n", sizeof_int64); + printf("#define JS_BYTES_PER_LONG %dL\n", sizeof_long); + printf("#define JS_BYTES_PER_FLOAT %dL\n", sizeof_float); + printf("#define JS_BYTES_PER_DOUBLE %dL\n", sizeof_double); + printf("#define JS_BYTES_PER_WORD %dL\n", sizeof_word); + printf("#define JS_BYTES_PER_DWORD %dL\n", sizeof_dword); + printf("\n"); + + printf("#define JS_BITS_PER_BYTE %dL\n", bpb); + printf("#define JS_BITS_PER_SHORT %dL\n", bpb * sizeof_short); + printf("#define JS_BITS_PER_INT %dL\n", bpb * sizeof_int); + printf("#define JS_BITS_PER_INT64 %dL\n", bpb * sizeof_int64); + printf("#define JS_BITS_PER_LONG %dL\n", bpb * sizeof_long); + printf("#define JS_BITS_PER_FLOAT %dL\n", bpb * sizeof_float); + printf("#define JS_BITS_PER_DOUBLE %dL\n", bpb * sizeof_double); + printf("#define JS_BITS_PER_WORD %dL\n", bpb * sizeof_word); + printf("\n"); + + printf("#define JS_BITS_PER_BYTE_LOG2 %dL\n", Log2(bpb)); + printf("#define JS_BITS_PER_SHORT_LOG2 %dL\n", Log2(bpb * sizeof_short)); + printf("#define JS_BITS_PER_INT_LOG2 %dL\n", Log2(bpb * sizeof_int)); + printf("#define JS_BITS_PER_INT64_LOG2 %dL\n", bits_per_int64_log2); + printf("#define JS_BITS_PER_LONG_LOG2 %dL\n", Log2(bpb * sizeof_long)); + printf("#define JS_BITS_PER_FLOAT_LOG2 %dL\n", Log2(bpb * sizeof_float)); + printf("#define JS_BITS_PER_DOUBLE_LOG2 %dL\n", Log2(bpb * sizeof_double)); + printf("#define JS_BITS_PER_WORD_LOG2 %dL\n", Log2(bpb * sizeof_word)); + printf("\n"); + + printf("#define JS_ALIGN_OF_SHORT %dL\n", align_of_short); + printf("#define JS_ALIGN_OF_INT %dL\n", align_of_int); + printf("#define JS_ALIGN_OF_LONG %dL\n", align_of_long); + printf("#define JS_ALIGN_OF_INT64 %dL\n", align_of_int64); + printf("#define JS_ALIGN_OF_FLOAT %dL\n", align_of_float); + printf("#define JS_ALIGN_OF_DOUBLE %dL\n", align_of_double); + printf("#define JS_ALIGN_OF_POINTER %dL\n", align_of_pointer); + printf("#define JS_ALIGN_OF_WORD %dL\n", align_of_word); + printf("\n"); + + printf("#define JS_BYTES_PER_WORD_LOG2 %dL\n", Log2(sizeof_word)); + printf("#define JS_BYTES_PER_DWORD_LOG2 %dL\n", Log2(sizeof_dword)); + printf("#define JS_WORDS_PER_DWORD_LOG2 %dL\n", Log2(sizeof_dword/sizeof_word)); + printf("\n"); + + printf("#define JS_STACK_GROWTH_DIRECTION (%d)\n", StackGrowthDirection(&dummy1)); + printf("\n"); + + printf("#define JS_HAVE_LONG_LONG\n"); + printf("\n"); + +#if defined __GNUC__ && defined __x86_64__ + printf("#define HAVE_VA_LIST_AS_ARRAY 1\n"); + printf("\n"); +#endif + + printf("#endif /* js_cpucfg___ */\n"); + + return EXIT_SUCCESS; +} + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscpucfg.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscpucfg.h new file mode 100644 index 0000000..c745e81 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jscpucfg.h @@ -0,0 +1,212 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef js_cpucfg___ +#define js_cpucfg___ + +#define JS_HAVE_LONG_LONG + +#if defined(XP_WIN) || defined(XP_OS2) || defined(WINCE) + +#if defined(_WIN64) + +#if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define JS_BYTES_PER_BYTE 1L +#define JS_BYTES_PER_SHORT 2L +#define JS_BYTES_PER_INT 4L +#define JS_BYTES_PER_INT64 8L +#define JS_BYTES_PER_LONG 4L +#define JS_BYTES_PER_FLOAT 4L +#define JS_BYTES_PER_DOUBLE 8L +#define JS_BYTES_PER_WORD 8L +#define JS_BYTES_PER_DWORD 8L + +#define JS_BITS_PER_BYTE 8L +#define JS_BITS_PER_SHORT 16L +#define JS_BITS_PER_INT 32L +#define JS_BITS_PER_INT64 64L +#define JS_BITS_PER_LONG 32L +#define JS_BITS_PER_FLOAT 32L +#define JS_BITS_PER_DOUBLE 64L +#define JS_BITS_PER_WORD 64L + +#define JS_BITS_PER_BYTE_LOG2 3L +#define JS_BITS_PER_SHORT_LOG2 4L +#define JS_BITS_PER_INT_LOG2 5L +#define JS_BITS_PER_INT64_LOG2 6L +#define JS_BITS_PER_LONG_LOG2 5L +#define JS_BITS_PER_FLOAT_LOG2 5L +#define JS_BITS_PER_DOUBLE_LOG2 6L +#define JS_BITS_PER_WORD_LOG2 6L + +#define JS_ALIGN_OF_SHORT 2L +#define JS_ALIGN_OF_INT 4L +#define JS_ALIGN_OF_LONG 4L +#define JS_ALIGN_OF_INT64 8L +#define JS_ALIGN_OF_FLOAT 4L +#define JS_ALIGN_OF_DOUBLE 8L +#define JS_ALIGN_OF_POINTER 8L +#define JS_ALIGN_OF_WORD 8L + +#define JS_BYTES_PER_WORD_LOG2 3L +#define JS_BYTES_PER_DWORD_LOG2 3L +#define PR_WORDS_PER_DWORD_LOG2 0L +#else /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */ +#error "CPU type is unknown" +#endif /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */ + +#elif defined(_WIN32) || defined(XP_OS2) || defined(WINCE) + +#ifdef __WATCOMC__ +#define HAVE_VA_LIST_AS_ARRAY 1 +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define JS_BYTES_PER_BYTE 1L +#define JS_BYTES_PER_SHORT 2L +#define JS_BYTES_PER_INT 4L +#define JS_BYTES_PER_INT64 8L +#define JS_BYTES_PER_LONG 4L +#define JS_BYTES_PER_FLOAT 4L +#define JS_BYTES_PER_DOUBLE 8L +#define JS_BYTES_PER_WORD 4L +#define JS_BYTES_PER_DWORD 8L + +#define JS_BITS_PER_BYTE 8L +#define JS_BITS_PER_SHORT 16L +#define JS_BITS_PER_INT 32L +#define JS_BITS_PER_INT64 64L +#define JS_BITS_PER_LONG 32L +#define JS_BITS_PER_FLOAT 32L +#define JS_BITS_PER_DOUBLE 64L +#define JS_BITS_PER_WORD 32L + +#define JS_BITS_PER_BYTE_LOG2 3L +#define JS_BITS_PER_SHORT_LOG2 4L +#define JS_BITS_PER_INT_LOG2 5L +#define JS_BITS_PER_INT64_LOG2 6L +#define JS_BITS_PER_LONG_LOG2 5L +#define JS_BITS_PER_FLOAT_LOG2 5L +#define JS_BITS_PER_DOUBLE_LOG2 6L +#define JS_BITS_PER_WORD_LOG2 5L + +#define JS_ALIGN_OF_SHORT 2L +#define JS_ALIGN_OF_INT 4L +#define JS_ALIGN_OF_LONG 4L +#define JS_ALIGN_OF_INT64 8L +#define JS_ALIGN_OF_FLOAT 4L +#define JS_ALIGN_OF_DOUBLE 4L +#define JS_ALIGN_OF_POINTER 4L +#define JS_ALIGN_OF_WORD 4L + +#define JS_BYTES_PER_WORD_LOG2 2L +#define JS_BYTES_PER_DWORD_LOG2 3L +#define PR_WORDS_PER_DWORD_LOG2 1L +#endif /* _WIN32 || XP_OS2 || WINCE*/ + +#if defined(_WINDOWS) && !defined(_WIN32) /* WIN16 */ + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define JS_BYTES_PER_BYTE 1L +#define JS_BYTES_PER_SHORT 2L +#define JS_BYTES_PER_INT 2L +#define JS_BYTES_PER_INT64 8L +#define JS_BYTES_PER_LONG 4L +#define JS_BYTES_PER_FLOAT 4L +#define JS_BYTES_PER_DOUBLE 8L +#define JS_BYTES_PER_WORD 4L +#define JS_BYTES_PER_DWORD 8L + +#define JS_BITS_PER_BYTE 8L +#define JS_BITS_PER_SHORT 16L +#define JS_BITS_PER_INT 16L +#define JS_BITS_PER_INT64 64L +#define JS_BITS_PER_LONG 32L +#define JS_BITS_PER_FLOAT 32L +#define JS_BITS_PER_DOUBLE 64L +#define JS_BITS_PER_WORD 32L + +#define JS_BITS_PER_BYTE_LOG2 3L +#define JS_BITS_PER_SHORT_LOG2 4L +#define JS_BITS_PER_INT_LOG2 4L +#define JS_BITS_PER_INT64_LOG2 6L +#define JS_BITS_PER_LONG_LOG2 5L +#define JS_BITS_PER_FLOAT_LOG2 5L +#define JS_BITS_PER_DOUBLE_LOG2 6L +#define JS_BITS_PER_WORD_LOG2 5L + +#define JS_ALIGN_OF_SHORT 2L +#define JS_ALIGN_OF_INT 2L +#define JS_ALIGN_OF_LONG 2L +#define JS_ALIGN_OF_INT64 2L +#define JS_ALIGN_OF_FLOAT 2L +#define JS_ALIGN_OF_DOUBLE 2L +#define JS_ALIGN_OF_POINTER 2L +#define JS_ALIGN_OF_WORD 2L + +#define JS_BYTES_PER_WORD_LOG2 2L +#define JS_BYTES_PER_DWORD_LOG2 3L +#define PR_WORDS_PER_DWORD_LOG2 1L + +#endif /* defined(_WINDOWS) && !defined(_WIN32) */ + +#elif defined(XP_UNIX) || defined(XP_BEOS) + +#error "This file is supposed to be auto-generated on UNIX platforms, but the" +#error "static version for Mac and Windows platforms is being used." +#error "Something's probably wrong with paths/headers/dependencies/Makefiles." + +#else + +#error "Must define one of XP_BEOS, XP_OS2, XP_WIN, or XP_UNIX" + +#endif + +#ifndef JS_STACK_GROWTH_DIRECTION +#define JS_STACK_GROWTH_DIRECTION (-1) +#endif + +#endif /* js_cpucfg___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdate.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdate.cpp new file mode 100644 index 0000000..2fe7963 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdate.cpp @@ -0,0 +1,2475 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS date methods. + */ + +/* + * "For example, OS/360 devotes 26 bytes of the permanently + * resident date-turnover routine to the proper handling of + * December 31 on leap years (when it is Day 366). That + * might have been left to the operator." + * + * Frederick Brooks, 'The Second-System Effect'. + */ + +#include "jsstddef.h" +#include +#include +#include +#include +#include +#include "jstypes.h" +#include "jsprf.h" +#include "prmjtime.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jsapi.h" +#include "jsversion.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsdate.h" +#include "jsinterp.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsstr.h" + +/* + * The JS 'Date' object is patterned after the Java 'Date' object. + * Here is an script: + * + * today = new Date(); + * + * print(today.toLocaleString()); + * + * weekDay = today.getDay(); + * + * + * These Java (and ECMA-262) methods are supported: + * + * UTC + * getDate (getUTCDate) + * getDay (getUTCDay) + * getHours (getUTCHours) + * getMinutes (getUTCMinutes) + * getMonth (getUTCMonth) + * getSeconds (getUTCSeconds) + * getMilliseconds (getUTCMilliseconds) + * getTime + * getTimezoneOffset + * getYear + * getFullYear (getUTCFullYear) + * parse + * setDate (setUTCDate) + * setHours (setUTCHours) + * setMinutes (setUTCMinutes) + * setMonth (setUTCMonth) + * setSeconds (setUTCSeconds) + * setMilliseconds (setUTCMilliseconds) + * setTime + * setYear (setFullYear, setUTCFullYear) + * toGMTString (toUTCString) + * toLocaleString + * toString + * + * + * These Java methods are not supported + * + * setDay + * before + * after + * equals + * hashCode + */ + +/* + * 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language + * definition and reduce dependence on NSPR. NSPR is used to get the current + * time in milliseconds, the time zone offset, and the daylight savings time + * offset for a given time. NSPR is also used for Date.toLocaleString(), for + * locale-specific formatting, and to get a string representing the timezone. + * (Which turns out to be platform-dependent.) + * + * To do: + * (I did some performance tests by timing how long it took to run what + * I had of the js ECMA conformance tests.) + * + * - look at saving results across multiple calls to supporting + * functions; the toString functions compute some of the same values + * multiple times. Although - I took a quick stab at this, and I lost + * rather than gained. (Fractionally.) Hard to tell what compilers/processors + * are doing these days. + * + * - look at tweaking function return types to return double instead + * of int; this seems to make things run slightly faster sometimes. + * (though it could be architecture-dependent.) It'd be good to see + * how this does on win32. (Tried it on irix.) Types could use a + * general going-over. + */ + +/* + * Supporting functions - ECMA 15.9.1.* + */ + +#define HalfTimeDomain 8.64e15 +#define HoursPerDay 24.0 +#define MinutesPerDay (HoursPerDay * MinutesPerHour) +#define MinutesPerHour 60.0 +#define SecondsPerDay (MinutesPerDay * SecondsPerMinute) +#define SecondsPerHour (MinutesPerHour * SecondsPerMinute) +#define SecondsPerMinute 60.0 + +#if defined(XP_WIN) || defined(XP_OS2) +/* Work around msvc double optimization bug by making these runtime values; if + * they're available at compile time, msvc optimizes division by them by + * computing the reciprocal and multiplying instead of dividing - this loses + * when the reciprocal isn't representable in a double. + */ +static jsdouble msPerSecond = 1000.0; +static jsdouble msPerDay = SecondsPerDay * 1000.0; +static jsdouble msPerHour = SecondsPerHour * 1000.0; +static jsdouble msPerMinute = SecondsPerMinute * 1000.0; +#else +#define msPerDay (SecondsPerDay * msPerSecond) +#define msPerHour (SecondsPerHour * msPerSecond) +#define msPerMinute (SecondsPerMinute * msPerSecond) +#define msPerSecond 1000.0 +#endif + +#define Day(t) floor((t) / msPerDay) + +static jsdouble +TimeWithinDay(jsdouble t) +{ + jsdouble result; + result = fmod(t, msPerDay); + if (result < 0) + result += msPerDay; + return result; +} + +#define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \ + ? 366 : 365) + +/* math here has to be f.p, because we need + * floor((1968 - 1969) / 4) == -1 + */ +#define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \ + - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0)) +#define TimeFromYear(y) (DayFromYear(y) * msPerDay) + +static jsint +YearFromTime(jsdouble t) +{ + jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970; + jsdouble t2 = (jsdouble) TimeFromYear(y); + + if (t2 > t) { + y--; + } else { + if (t2 + msPerDay * DaysInYear(y) <= t) + y++; + } + return y; +} + +#define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366) + +#define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year))) + +/* + * The following array contains the day of year for the first day of + * each month, where index 0 is January, and day 0 is January 1. + */ +static jsdouble firstDayOfMonth[2][12] = { + {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0}, + {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0} +}; + +#define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m]; + +static intN +MonthFromTime(jsdouble t) +{ + intN d, step; + jsint year = YearFromTime(t); + d = DayWithinYear(t, year); + + if (d < (step = 31)) + return 0; + step += (InLeapYear(t) ? 29 : 28); + if (d < step) + return 1; + if (d < (step += 31)) + return 2; + if (d < (step += 30)) + return 3; + if (d < (step += 31)) + return 4; + if (d < (step += 30)) + return 5; + if (d < (step += 31)) + return 6; + if (d < (step += 31)) + return 7; + if (d < (step += 30)) + return 8; + if (d < (step += 31)) + return 9; + if (d < (step += 30)) + return 10; + return 11; +} + +static intN +DateFromTime(jsdouble t) +{ + intN d, step, next; + jsint year = YearFromTime(t); + d = DayWithinYear(t, year); + + if (d <= (next = 30)) + return d + 1; + step = next; + next += (InLeapYear(t) ? 29 : 28); + if (d <= next) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + return d - step; +} + +static intN +WeekDay(jsdouble t) +{ + jsint result; + result = (jsint) Day(t) + 4; + result = result % 7; + if (result < 0) + result += 7; + return (intN) result; +} + +#define MakeTime(hour, min, sec, ms) \ +((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms)) + +static jsdouble +MakeDay(jsdouble year, jsdouble month, jsdouble date) +{ + JSBool leap; + jsdouble yearday; + jsdouble monthday; + + year += floor(month / 12); + + month = fmod(month, 12.0); + if (month < 0) + month += 12; + + leap = (DaysInYear((jsint) year) == 366); + + yearday = floor(TimeFromYear(year) / msPerDay); + monthday = DayFromMonth(month, leap); + + return yearday + monthday + date - 1; +} + +#define MakeDate(day, time) ((day) * msPerDay + (time)) + +/* + * Years and leap years on which Jan 1 is a Sunday, Monday, etc. + * + * yearStartingWith[0][i] is an example non-leap year where + * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc. + * + * yearStartingWith[1][i] is an example leap year where + * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc. + */ +static jsint yearStartingWith[2][7] = { + {1978, 1973, 1974, 1975, 1981, 1971, 1977}, + {1984, 1996, 1980, 1992, 1976, 1988, 1972} +}; + +/* + * Find a year for which any given date will fall on the same weekday. + * + * This function should be used with caution when used other than + * for determining DST; it hasn't been proven not to produce an + * incorrect year for times near year boundaries. + */ +static jsint +EquivalentYearForDST(jsint year) +{ + jsint day; + JSBool isLeapYear; + + day = (jsint) DayFromYear(year) + 4; + day = day % 7; + if (day < 0) + day += 7; + + isLeapYear = (DaysInYear(year) == 366); + + return yearStartingWith[isLeapYear][day]; +} + +/* LocalTZA gets set by js_InitDateClass() */ +static jsdouble LocalTZA; + +static jsdouble +DaylightSavingTA(jsdouble t) +{ + volatile int64 PR_t; + int64 ms2us; + int64 offset; + jsdouble result; + + /* abort if NaN */ + if (JSDOUBLE_IS_NaN(t)) + return t; + + /* + * If earlier than 1970 or after 2038, potentially beyond the ken of + * many OSes, map it to an equivalent year before asking. + */ + if (t < 0.0 || t > 2145916800000.0) { + jsint year; + jsdouble day; + + year = EquivalentYearForDST(YearFromTime(t)); + day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); + t = MakeDate(day, TimeWithinDay(t)); + } + + /* put our t in an LL, and map it to usec for prtime */ + JSLL_D2L(PR_t, t); + JSLL_I2L(ms2us, PRMJ_USEC_PER_MSEC); + JSLL_MUL(PR_t, PR_t, ms2us); + + offset = PRMJ_DSTOffset(PR_t); + + JSLL_DIV(offset, offset, ms2us); + JSLL_L2D(result, offset); + return result; +} + + +#define AdjustTime(t) fmod(LocalTZA + DaylightSavingTA(t), msPerDay) + +#define LocalTime(t) ((t) + AdjustTime(t)) + +static jsdouble +UTC(jsdouble t) +{ + return t - AdjustTime(t - LocalTZA); +} + +static intN +HourFromTime(jsdouble t) +{ + intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay); + if (result < 0) + result += (intN)HoursPerDay; + return result; +} + +static intN +MinFromTime(jsdouble t) +{ + intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour); + if (result < 0) + result += (intN)MinutesPerHour; + return result; +} + +static intN +SecFromTime(jsdouble t) +{ + intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute); + if (result < 0) + result += (intN)SecondsPerMinute; + return result; +} + +static intN +msFromTime(jsdouble t) +{ + intN result = (intN) fmod(t, msPerSecond); + if (result < 0) + result += (intN)msPerSecond; + return result; +} + +#define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \ + && !((d < 0 ? -d : d) > HalfTimeDomain)) \ + ? js_DoubleToInteger(d + (+0.)) : *cx->runtime->jsNaN) + +/** + * end of ECMA 'support' functions + */ + +/* + * Other Support routines and definitions + */ + +/* + * We use the first reseved slot to store UTC time, and the second for caching + * the local time. The initial value of the cache entry is NaN. + */ +const uint32 JSSLOT_UTC_TIME = JSSLOT_PRIVATE; +const uint32 JSSLOT_LOCAL_TIME = JSSLOT_PRIVATE + 1; + +const uint32 DATE_RESERVED_SLOTS = 2; + +JSClass js_DateClass = { + js_Date_str, + JSCLASS_HAS_RESERVED_SLOTS(DATE_RESERVED_SLOTS) | + JSCLASS_HAS_CACHED_PROTO(JSProto_Date), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +/* for use by date_parse */ + +static const char* wtb[] = { + "am", "pm", + "monday", "tuesday", "wednesday", "thursday", "friday", + "saturday", "sunday", + "january", "february", "march", "april", "may", "june", + "july", "august", "september", "october", "november", "december", + "gmt", "ut", "utc", + "est", "edt", + "cst", "cdt", + "mst", "mdt", + "pst", "pdt" + /* time zone table needs to be expanded */ +}; + +static int ttb[] = { + -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */ + 10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */ + 10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */ + 10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */ + 10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */ +}; + +/* helper for date_parse */ +static JSBool +date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off, + int count, int ignoreCase) +{ + JSBool result = JS_FALSE; + /* return true if matches, otherwise, false */ + + while (count > 0 && s1[s1off] && s2[s2off]) { + if (ignoreCase) { + if (JS_TOLOWER((jschar)s1[s1off]) != JS_TOLOWER(s2[s2off])) { + break; + } + } else { + if ((jschar)s1[s1off] != s2[s2off]) { + break; + } + } + s1off++; + s2off++; + count--; + } + + if (count == 0) { + result = JS_TRUE; + } + + return result; +} + +/* find UTC time from given date... no 1900 correction! */ +static jsdouble +date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour, + jsdouble min, jsdouble sec, jsdouble msec) +{ + jsdouble day; + jsdouble msec_time; + jsdouble result; + + day = MakeDay(year, mon, mday); + msec_time = MakeTime(hour, min, sec, msec); + result = MakeDate(day, msec_time); + return result; +} + +/* compute the time in msec (unclipped) from the given args */ +#define MAXARGS 7 + +static JSBool +date_msecFromArgs(JSContext *cx, uintN argc, jsval *argv, jsdouble *rval) +{ + uintN loop; + jsdouble array[MAXARGS]; + jsdouble d; + jsdouble msec_time; + + for (loop = 0; loop < MAXARGS; loop++) { + if (loop < argc) { + d = js_ValueToNumber(cx, &argv[loop]); + if (JSVAL_IS_NULL(argv[loop])) + return JS_FALSE; + /* return NaN if any arg is not finite */ + if (!JSDOUBLE_IS_FINITE(d)) { + *rval = *cx->runtime->jsNaN; + return JS_TRUE; + } + array[loop] = js_DoubleToInteger(d); + } else { + if (loop == 2) { + array[loop] = 1; /* Default the date argument to 1. */ + } else { + array[loop] = 0; + } + } + } + + /* adjust 2-digit years into the 20th century */ + if (array[0] >= 0 && array[0] <= 99) + array[0] += 1900; + + msec_time = date_msecFromDate(array[0], array[1], array[2], + array[3], array[4], array[5], array[6]); + *rval = msec_time; + return JS_TRUE; +} + +/* + * See ECMA 15.9.4.[3-10]; + */ +static JSBool +date_UTC(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble msec_time; + + if (!date_msecFromArgs(cx, argc, vp + 2, &msec_time)) + return JS_FALSE; + + msec_time = TIMECLIP(msec_time); + + return js_NewNumberInRootedValue(cx, msec_time, vp); +} + +static JSBool +date_parseString(JSString *str, jsdouble *result) +{ + jsdouble msec; + + const jschar *s; + size_t limit; + size_t i = 0; + int year = -1; + int mon = -1; + int mday = -1; + int hour = -1; + int min = -1; + int sec = -1; + int c = -1; + int n = -1; + int tzoffset = -1; + int prevc = 0; + JSBool seenplusminus = JS_FALSE; + int temp; + JSBool seenmonthname = JS_FALSE; + + JSSTRING_CHARS_AND_LENGTH(str, s, limit); + if (limit == 0) + goto syntax; + while (i < limit) { + c = s[i]; + i++; + if (c <= ' ' || c == ',' || c == '-') { + if (c == '-' && '0' <= s[i] && s[i] <= '9') { + prevc = c; + } + continue; + } + if (c == '(') { /* comments) */ + int depth = 1; + while (i < limit) { + c = s[i]; + i++; + if (c == '(') depth++; + else if (c == ')') + if (--depth <= 0) + break; + } + continue; + } + if ('0' <= c && c <= '9') { + n = c - '0'; + while (i < limit && '0' <= (c = s[i]) && c <= '9') { + n = n * 10 + c - '0'; + i++; + } + + /* allow TZA before the year, so + * 'Wed Nov 05 21:49:11 GMT-0800 1997' + * works */ + + /* uses of seenplusminus allow : in TZA, so Java + * no-timezone style of GMT+4:30 works + */ + + if ((prevc == '+' || prevc == '-')/* && year>=0 */) { + /* make ':' case below change tzoffset */ + seenplusminus = JS_TRUE; + + /* offset */ + if (n < 24) + n = n * 60; /* EG. "GMT-3" */ + else + n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */ + if (prevc == '+') /* plus means east of GMT */ + n = -n; + if (tzoffset != 0 && tzoffset != -1) + goto syntax; + tzoffset = n; + } else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) { + if (c <= ' ' || c == ',' || c == '/' || i >= limit) + year = n; + else + goto syntax; + } else if (c == ':') { + if (hour < 0) + hour = /*byte*/ n; + else if (min < 0) + min = /*byte*/ n; + else + goto syntax; + } else if (c == '/') { + /* until it is determined that mon is the actual + month, keep it as 1-based rather than 0-based */ + if (mon < 0) + mon = /*byte*/ n; + else if (mday < 0) + mday = /*byte*/ n; + else + goto syntax; + } else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') { + goto syntax; + } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */ + if (tzoffset < 0) + tzoffset -= n; + else + tzoffset += n; + } else if (hour >= 0 && min < 0) { + min = /*byte*/ n; + } else if (prevc == ':' && min >= 0 && sec < 0) { + sec = /*byte*/ n; + } else if (mon < 0) { + mon = /*byte*/n; + } else if (mon >= 0 && mday < 0) { + mday = /*byte*/ n; + } else if (mon >= 0 && mday >= 0 && year < 0) { + year = n; + } else { + goto syntax; + } + prevc = 0; + } else if (c == '/' || c == ':' || c == '+' || c == '-') { + prevc = c; + } else { + size_t st = i - 1; + int k; + while (i < limit) { + c = s[i]; + if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))) + break; + i++; + } + if (i <= st + 1) + goto syntax; + for (k = JS_ARRAY_LENGTH(wtb); --k >= 0;) + if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) { + int action = ttb[k]; + if (action != 0) { + if (action < 0) { + /* + * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as + * 12:30, instead of blindly adding 12 if PM. + */ + JS_ASSERT(action == -1 || action == -2); + if (hour > 12 || hour < 0) { + goto syntax; + } else { + if (action == -1 && hour == 12) { /* am */ + hour = 0; + } else if (action == -2 && hour != 12) { /* pm */ + hour += 12; + } + } + } else if (action <= 13) { /* month! */ + /* Adjust mon to be 1-based until the final values + for mon, mday and year are adjusted below */ + if (seenmonthname) { + goto syntax; + } + seenmonthname = JS_TRUE; + temp = /*byte*/ (action - 2) + 1; + + if (mon < 0) { + mon = temp; + } else if (mday < 0) { + mday = mon; + mon = temp; + } else if (year < 0) { + year = mon; + mon = temp; + } else { + goto syntax; + } + } else { + tzoffset = action - 10000; + } + } + break; + } + if (k < 0) + goto syntax; + prevc = 0; + } + } + if (year < 0 || mon < 0 || mday < 0) + goto syntax; + /* + Case 1. The input string contains an English month name. + The form of the string can be month f l, or f month l, or + f l month which each evaluate to the same date. + If f and l are both greater than or equal to 70, or + both less than 70, the date is invalid. + The year is taken to be the greater of the values f, l. + If the year is greater than or equal to 70 and less than 100, + it is considered to be the number of years after 1900. + Case 2. The input string is of the form "f/m/l" where f, m and l are + integers, e.g. 7/16/45. + Adjust the mon, mday and year values to achieve 100% MSIE + compatibility. + a. If 0 <= f < 70, f/m/l is interpreted as month/day/year. + i. If year < 100, it is the number of years after 1900 + ii. If year >= 100, it is the number of years after 0. + b. If 70 <= f < 100 + i. If m < 70, f/m/l is interpreted as + year/month/day where year is the number of years after + 1900. + ii. If m >= 70, the date is invalid. + c. If f >= 100 + i. If m < 70, f/m/l is interpreted as + year/month/day where year is the number of years after 0. + ii. If m >= 70, the date is invalid. + */ + if (seenmonthname) { + if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) { + goto syntax; + } + if (mday > year) { + temp = year; + year = mday; + mday = temp; + } + if (year >= 70 && year < 100) { + year += 1900; + } + } else if (mon < 70) { /* (a) month/day/year */ + if (year < 100) { + year += 1900; + } + } else if (mon < 100) { /* (b) year/month/day */ + if (mday < 70) { + temp = year; + year = mon + 1900; + mon = mday; + mday = temp; + } else { + goto syntax; + } + } else { /* (c) year/month/day */ + if (mday < 70) { + temp = year; + year = mon; + mon = mday; + mday = temp; + } else { + goto syntax; + } + } + mon -= 1; /* convert month to 0-based */ + if (sec < 0) + sec = 0; + if (min < 0) + min = 0; + if (hour < 0) + hour = 0; + if (tzoffset == -1) { /* no time zone specified, have to use local */ + jsdouble msec_time; + msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0); + + *result = UTC(msec_time); + return JS_TRUE; + } + + msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0); + msec += tzoffset * msPerMinute; + *result = msec; + return JS_TRUE; + +syntax: + /* syntax error */ + *result = 0; + return JS_FALSE; +} + +static JSBool +date_parse(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + jsdouble result; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + str = js_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + vp[2] = STRING_TO_JSVAL(str); + if (!date_parseString(str, &result)) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + + result = TIMECLIP(result); + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_now(JSContext *cx, uintN argc, jsval *vp) +{ + return js_NewDoubleInRootedValue(cx, PRMJ_Now() / PRMJ_USEC_PER_MSEC, vp); +} + +#ifdef JS_TRACER +static jsdouble FASTCALL +date_now_tn(JSContext*) +{ + return PRMJ_Now() / PRMJ_USEC_PER_MSEC; +} +#endif + +/* + * Get UTC time from the date object. Returns false if the object is not + * Date type. + */ +static JSBool +GetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp) +{ + if (!JS_InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL)) + return JS_FALSE; + *dp = *JSVAL_TO_DOUBLE(obj->fslots[JSSLOT_UTC_TIME]); + return JS_TRUE; +} + +/* + * Set UTC time slot with a pointer pointing to a jsdouble. This function is + * used only for setting UTC time to some predefined values, such as NaN. + * + * It also invalidates cached local time. + */ +static JSBool +SetUTCTimePtr(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp) +{ + if (vp && !JS_InstanceOf(cx, obj, &js_DateClass, vp + 2)) + return JS_FALSE; + JS_ASSERT_IF(!vp, STOBJ_GET_CLASS(obj) == &js_DateClass); + + /* Invalidate local time cache. */ + obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + obj->fslots[JSSLOT_UTC_TIME] = DOUBLE_TO_JSVAL(dp); + return JS_TRUE; +} + +/* + * Set UTC time to a given time. + */ +static JSBool +SetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble t) +{ + jsdouble *dp = js_NewWeaklyRootedDouble(cx, t); + if (!dp) + return JS_FALSE; + return SetUTCTimePtr(cx, obj, vp, dp); +} + +/* + * Get the local time, cache it if necessary. If UTC time is not finite + * (e.g., NaN), the local time slot is set to the UTC time without conversion. + */ +static JSBool +GetAndCacheLocalTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp) +{ + jsval v; + jsdouble result; + jsdouble *cached; + + if (!obj || !JS_InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL)) + return JS_FALSE; + v = obj->fslots[JSSLOT_LOCAL_TIME]; + + result = *JSVAL_TO_DOUBLE(v); + + if (JSDOUBLE_IS_NaN(result)) { + if (!GetUTCTime(cx, obj, vp, &result)) + return JS_FALSE; + + /* if result is NaN, it couldn't be finite. */ + if (JSDOUBLE_IS_FINITE(result)) + result = LocalTime(result); + + cached = js_NewWeaklyRootedDouble(cx, result); + if (!cached) + return JS_FALSE; + + obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cached); + } + + *dp = result; + return JS_TRUE; +} + +/* + * See ECMA 15.9.5.4 thru 15.9.5.23 + */ +static JSBool +date_getTime(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + return GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result) && + js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +GetYear(JSContext *cx, JSBool fullyear, jsval *vp) +{ + jsdouble result; + + if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) { + result = YearFromTime(result); + + /* Follow ECMA-262 to the letter, contrary to IE JScript. */ + if (!fullyear) + result -= 1900; + } + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getYear(JSContext *cx, uintN argc, jsval *vp) +{ + return GetYear(cx, JS_FALSE, vp); +} + +static JSBool +date_getFullYear(JSContext *cx, uintN argc, jsval *vp) +{ + return GetYear(cx, JS_TRUE, vp); +} + +static JSBool +date_getUTCFullYear(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = YearFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getMonth(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = MonthFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getUTCMonth(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = MonthFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getDate(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = DateFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getUTCDate(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = DateFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getDay(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = WeekDay(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getUTCDay(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = WeekDay(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getHours(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = HourFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getUTCHours(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = HourFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getMinutes(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = MinFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getUTCMinutes(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = MinFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +/* Date.getSeconds is mapped to getUTCSeconds */ + +static JSBool +date_getUTCSeconds(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = SecFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +/* Date.getMilliseconds is mapped to getUTCMilliseconds */ + +static JSBool +date_getUTCMilliseconds(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(result)) + result = msFromTime(result); + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_getTimezoneOffset(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + jsdouble utctime, localtime, result; + + obj = JS_THIS_OBJECT(cx, vp); + if (!GetUTCTime(cx, obj, vp, &utctime)) + return JS_FALSE; + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime)) + return JS_FALSE; + + /* + * Return the time zone offset in minutes for the current locale that is + * appropriate for this time. This value would be a constant except for + * daylight savings time. + */ + result = (utctime - localtime) / msPerMinute; + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +SetDateToNaN(JSContext *cx, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + if (!SetUTCTimePtr(cx, obj, NULL, cx->runtime->jsNaN)) + return JS_FALSE; + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; +} + +static JSBool +date_setTime(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble result; + + if (argc == 0) + return SetDateToNaN(cx, vp); + result = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + + result = TIMECLIP(result); + + if (!SetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, result)) + return JS_FALSE; + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp) +{ + JSObject *obj; + jsval *argv; + uintN i; + jsdouble args[4], *argp, *stop; + jsdouble hour, min, sec, msec; + jsdouble lorutime; /* Local or UTC version of *date */ + + jsdouble msec_time; + jsdouble result; + + obj = JS_THIS_OBJECT(cx, vp); + if (!GetUTCTime(cx, obj, vp, &result)) + return JS_FALSE; + + /* just return NaN if the date is already NaN */ + if (!JSDOUBLE_IS_FINITE(result)) + return js_NewNumberInRootedValue(cx, result, vp); + + /* + * Satisfy the ECMA rule that if a function is called with + * fewer arguments than the specified formal arguments, the + * remaining arguments are set to undefined. Seems like all + * the Date.setWhatever functions in ECMA are only varargs + * beyond the first argument; this should be set to undefined + * if it's not given. This means that "d = new Date(); + * d.setMilliseconds()" returns NaN. Blech. + */ + if (argc == 0) + return SetDateToNaN(cx, vp); + if (argc > maxargs) + argc = maxargs; /* clamp argc */ + JS_ASSERT(argc <= 4); + + argv = vp + 2; + for (i = 0; i < argc; i++) { + args[i] = js_ValueToNumber(cx, &argv[i]); + if (JSVAL_IS_NULL(argv[i])) + return JS_FALSE; + if (!JSDOUBLE_IS_FINITE(args[i])) + return SetDateToNaN(cx, vp); + args[i] = js_DoubleToInteger(args[i]); + } + + if (local) + lorutime = LocalTime(result); + else + lorutime = result; + + argp = args; + stop = argp + argc; + if (maxargs >= 4 && argp < stop) + hour = *argp++; + else + hour = HourFromTime(lorutime); + + if (maxargs >= 3 && argp < stop) + min = *argp++; + else + min = MinFromTime(lorutime); + + if (maxargs >= 2 && argp < stop) + sec = *argp++; + else + sec = SecFromTime(lorutime); + + if (maxargs >= 1 && argp < stop) + msec = *argp; + else + msec = msFromTime(lorutime); + + msec_time = MakeTime(hour, min, sec, msec); + result = MakeDate(Day(lorutime), msec_time); + +/* fprintf(stderr, "%f\n", result); */ + + if (local) + result = UTC(result); + +/* fprintf(stderr, "%f\n", result); */ + + result = TIMECLIP(result); + if (!SetUTCTime(cx, obj, NULL, result)) + return JS_FALSE; + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_setMilliseconds(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeTime(cx, 1, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCMilliseconds(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeTime(cx, 1, JS_FALSE, argc, vp); +} + +static JSBool +date_setSeconds(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeTime(cx, 2, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCSeconds(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeTime(cx, 2, JS_FALSE, argc, vp); +} + +static JSBool +date_setMinutes(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeTime(cx, 3, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCMinutes(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeTime(cx, 3, JS_FALSE, argc, vp); +} + +static JSBool +date_setHours(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeTime(cx, 4, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCHours(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeTime(cx, 4, JS_FALSE, argc, vp); +} + +static JSBool +date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp) +{ + JSObject *obj; + jsval *argv; + uintN i; + jsdouble lorutime; /* local or UTC version of *date */ + jsdouble args[3], *argp, *stop; + jsdouble year, month, day; + jsdouble result; + + obj = JS_THIS_OBJECT(cx, vp); + if (!GetUTCTime(cx, obj, vp, &result)) + return JS_FALSE; + + /* see complaint about ECMA in date_MakeTime */ + if (argc == 0) + return SetDateToNaN(cx, vp); + if (argc > maxargs) + argc = maxargs; /* clamp argc */ + JS_ASSERT(1 <= argc && argc <= 3); + + argv = vp + 2; + for (i = 0; i < argc; i++) { + args[i] = js_ValueToNumber(cx, &argv[i]); + if (JSVAL_IS_NULL(argv[i])) + return JS_FALSE; + if (!JSDOUBLE_IS_FINITE(args[i])) + return SetDateToNaN(cx, vp); + args[i] = js_DoubleToInteger(args[i]); + } + + /* return NaN if date is NaN and we're not setting the year, + * If we are, use 0 as the time. */ + if (!(JSDOUBLE_IS_FINITE(result))) { + if (maxargs < 3) + return js_NewNumberInRootedValue(cx, result, vp); + lorutime = +0.; + } else { + lorutime = local ? LocalTime(result) : result; + } + + argp = args; + stop = argp + argc; + if (maxargs >= 3 && argp < stop) + year = *argp++; + else + year = YearFromTime(lorutime); + + if (maxargs >= 2 && argp < stop) + month = *argp++; + else + month = MonthFromTime(lorutime); + + if (maxargs >= 1 && argp < stop) + day = *argp++; + else + day = DateFromTime(lorutime); + + day = MakeDay(year, month, day); /* day within year */ + result = MakeDate(day, TimeWithinDay(lorutime)); + + if (local) + result = UTC(result); + + result = TIMECLIP(result); + if (!SetUTCTime(cx, obj, NULL, result)) + return JS_FALSE; + + return js_NewNumberInRootedValue(cx, result, vp); +} + +static JSBool +date_setDate(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeDate(cx, 1, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCDate(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeDate(cx, 1, JS_FALSE, argc, vp); +} + +static JSBool +date_setMonth(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeDate(cx, 2, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCMonth(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeDate(cx, 2, JS_FALSE, argc, vp); +} + +static JSBool +date_setFullYear(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeDate(cx, 3, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCFullYear(JSContext *cx, uintN argc, jsval *vp) +{ + return date_makeDate(cx, 3, JS_FALSE, argc, vp); +} + +static JSBool +date_setYear(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + jsdouble t; + jsdouble year; + jsdouble day; + jsdouble result; + + obj = JS_THIS_OBJECT(cx, vp); + if (!GetUTCTime(cx, obj, vp, &result)) + return JS_FALSE; + + if (argc == 0) + return SetDateToNaN(cx, vp); + year = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + if (!JSDOUBLE_IS_FINITE(year)) + return SetDateToNaN(cx, vp); + + year = js_DoubleToInteger(year); + + if (!JSDOUBLE_IS_FINITE(result)) { + t = +0.0; + } else { + t = LocalTime(result); + } + + if (year >= 0 && year <= 99) + year += 1900; + + day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); + result = MakeDate(day, TimeWithinDay(t)); + result = UTC(result); + + result = TIMECLIP(result); + if (!SetUTCTime(cx, obj, NULL, result)) + return JS_FALSE; + + return js_NewNumberInRootedValue(cx, result, vp); +} + +/* constants for toString, toUTCString */ +static char js_NaN_date_str[] = "Invalid Date"; +static const char* days[] = +{ + "Sun","Mon","Tue","Wed","Thu","Fri","Sat" +}; +static const char* months[] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + + +// Avoid dependence on PRMJ_FormatTimeUSEnglish, because it +// requires a PRMJTime... which only has 16-bit years. Sub-ECMA. +static void +print_gmt_string(char* buf, size_t size, jsdouble utctime) +{ + JS_snprintf(buf, size, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", + days[WeekDay(utctime)], + DateFromTime(utctime), + months[MonthFromTime(utctime)], + YearFromTime(utctime), + HourFromTime(utctime), + MinFromTime(utctime), + SecFromTime(utctime)); +} + +static void +print_iso_string(char* buf, size_t size, jsdouble utctime) +{ + JS_snprintf(buf, size, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ", + YearFromTime(utctime), + MonthFromTime(utctime) + 1, + DateFromTime(utctime), + HourFromTime(utctime), + MinFromTime(utctime), + SecFromTime(utctime), + msFromTime(utctime)); +} + +static JSBool +date_utc_format(JSContext *cx, jsval *vp, + void (*printFunc)(char*, size_t, jsdouble)) +{ + char buf[100]; + JSString *str; + jsdouble utctime; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) + return JS_FALSE; + + if (!JSDOUBLE_IS_FINITE(utctime)) { + JS_snprintf(buf, sizeof buf, js_NaN_date_str); + } else { + (*printFunc)(buf, sizeof buf, utctime); + } + str = JS_NewStringCopyZ(cx, buf); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +date_toGMTString(JSContext *cx, uintN argc, jsval *vp) +{ + return date_utc_format(cx, vp, print_gmt_string); +} + +static JSBool +date_toISOString(JSContext *cx, uintN argc, jsval *vp) +{ + return date_utc_format(cx, vp, print_iso_string); +} + +/* for Date.toLocaleString; interface to PRMJTime date struct. + */ +static void +new_explode(jsdouble timeval, PRMJTime *split) +{ + jsint year = YearFromTime(timeval); + + split->tm_usec = (int32) msFromTime(timeval) * 1000; + split->tm_sec = (int8) SecFromTime(timeval); + split->tm_min = (int8) MinFromTime(timeval); + split->tm_hour = (int8) HourFromTime(timeval); + split->tm_mday = (int8) DateFromTime(timeval); + split->tm_mon = (int8) MonthFromTime(timeval); + split->tm_wday = (int8) WeekDay(timeval); + split->tm_year = year; + split->tm_yday = (int16) DayWithinYear(timeval, year); + + /* not sure how this affects things, but it doesn't seem + to matter. */ + split->tm_isdst = (DaylightSavingTA(timeval) != 0); +} + +typedef enum formatspec { + FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME +} formatspec; + +/* helper function */ +static JSBool +date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval) +{ + char buf[100]; + JSString *str; + char tzbuf[100]; + JSBool usetz; + size_t i, tzlen; + PRMJTime split; + + if (!JSDOUBLE_IS_FINITE(date)) { + JS_snprintf(buf, sizeof buf, js_NaN_date_str); + } else { + jsdouble local = LocalTime(date); + + /* offset from GMT in minutes. The offset includes daylight savings, + if it applies. */ + jsint minutes = (jsint) floor(AdjustTime(date) / msPerMinute); + + /* map 510 minutes to 0830 hours */ + intN offset = (minutes / 60) * 100 + minutes % 60; + + /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is + * printed as 'GMT-0800' rather than as 'PST' to avoid + * operating-system dependence on strftime (which + * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints + * PST as 'Pacific Standard Time.' This way we always know + * what we're getting, and can parse it if we produce it. + * The OS TZA string is included as a comment. + */ + + /* get a timezone string from the OS to include as a + comment. */ + new_explode(date, &split); + if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) { + + /* Decide whether to use the resulting timezone string. + * + * Reject it if it contains any non-ASCII, non-alphanumeric + * characters. It's then likely in some other character + * encoding, and we probably won't display it correctly. + */ + usetz = JS_TRUE; + tzlen = strlen(tzbuf); + if (tzlen > 100) { + usetz = JS_FALSE; + } else { + for (i = 0; i < tzlen; i++) { + jschar c = tzbuf[i]; + if (c > 127 || + !(isalpha(c) || isdigit(c) || + c == ' ' || c == '(' || c == ')')) { + usetz = JS_FALSE; + } + } + } + + /* Also reject it if it's not parenthesized or if it's '()'. */ + if (tzbuf[0] != '(' || tzbuf[1] == ')') + usetz = JS_FALSE; + } else + usetz = JS_FALSE; + + switch (format) { + case FORMATSPEC_FULL: + /* + * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it + * requires a PRMJTime... which only has 16-bit years. Sub-ECMA. + */ + /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */ + JS_snprintf(buf, sizeof buf, + "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s", + days[WeekDay(local)], + months[MonthFromTime(local)], + DateFromTime(local), + YearFromTime(local), + HourFromTime(local), + MinFromTime(local), + SecFromTime(local), + offset, + usetz ? " " : "", + usetz ? tzbuf : ""); + break; + case FORMATSPEC_DATE: + /* Tue Oct 31 2000 */ + JS_snprintf(buf, sizeof buf, + "%s %s %.2d %.4d", + days[WeekDay(local)], + months[MonthFromTime(local)], + DateFromTime(local), + YearFromTime(local)); + break; + case FORMATSPEC_TIME: + /* 09:41:40 GMT-0800 (PST) */ + JS_snprintf(buf, sizeof buf, + "%.2d:%.2d:%.2d GMT%+.4d%s%s", + HourFromTime(local), + MinFromTime(local), + SecFromTime(local), + offset, + usetz ? " " : "", + usetz ? tzbuf : ""); + break; + } + } + + str = JS_NewStringCopyZ(cx, buf); + if (!str) + return JS_FALSE; + *rval = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +date_toLocaleHelper(JSContext *cx, const char *format, jsval *vp) +{ + JSObject *obj; + char buf[100]; + JSString *str; + PRMJTime split; + jsdouble utctime; + + obj = JS_THIS_OBJECT(cx, vp); + if (!GetUTCTime(cx, obj, vp, &utctime)) + return JS_FALSE; + + if (!JSDOUBLE_IS_FINITE(utctime)) { + JS_snprintf(buf, sizeof buf, js_NaN_date_str); + } else { + intN result_len; + jsdouble local = LocalTime(utctime); + new_explode(local, &split); + + /* let PRMJTime format it. */ + result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split); + + /* If it failed, default to toString. */ + if (result_len == 0) + return date_format(cx, utctime, FORMATSPEC_FULL, vp); + + /* Hacked check against undesired 2-digit year 00/00/00 form. */ + if (strcmp(format, "%x") == 0 && result_len >= 6 && + /* Format %x means use OS settings, which may have 2-digit yr, so + hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/ + !isdigit(buf[result_len - 3]) && + isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) && + /* ...but not if starts with 4-digit year, like 2022/3/11. */ + !(isdigit(buf[0]) && isdigit(buf[1]) && + isdigit(buf[2]) && isdigit(buf[3]))) { + JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2), + "%d", js_DateGetYear(cx, obj)); + } + + } + + if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) + return cx->localeCallbacks->localeToUnicode(cx, buf, vp); + + str = JS_NewStringCopyZ(cx, buf); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +date_toLocaleString(JSContext *cx, uintN argc, jsval *vp) +{ + /* Use '%#c' for windows, because '%c' is + * backward-compatible and non-y2k with msvc; '%#c' requests that a + * full year be used in the result string. + */ + return date_toLocaleHelper(cx, +#if defined(_WIN32) && !defined(__MWERKS__) + "%#c" +#else + "%c" +#endif + , vp); +} + +static JSBool +date_toLocaleDateString(JSContext *cx, uintN argc, jsval *vp) +{ + /* Use '%#x' for windows, because '%x' is + * backward-compatible and non-y2k with msvc; '%#x' requests that a + * full year be used in the result string. + */ + return date_toLocaleHelper(cx, +#if defined(_WIN32) && !defined(__MWERKS__) + "%#x" +#else + "%x" +#endif + , vp); +} + +static JSBool +date_toLocaleTimeString(JSContext *cx, uintN argc, jsval *vp) +{ + return date_toLocaleHelper(cx, "%X", vp); +} + +static JSBool +date_toLocaleFormat(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *fmt; + const char *fmtbytes; + + if (argc == 0) + return date_toLocaleString(cx, argc, vp); + + fmt = js_ValueToString(cx, vp[2]); + if (!fmt) + return JS_FALSE; + vp[2] = STRING_TO_JSVAL(fmt); + fmtbytes = js_GetStringBytes(cx, fmt); + if (!fmtbytes) + return JS_FALSE; + + return date_toLocaleHelper(cx, fmtbytes, vp); +} + +static JSBool +date_toTimeString(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble utctime; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) + return JS_FALSE; + return date_format(cx, utctime, FORMATSPEC_TIME, vp); +} + +static JSBool +date_toDateString(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble utctime; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) + return JS_FALSE; + return date_format(cx, utctime, FORMATSPEC_DATE, vp); +} + +#if JS_HAS_TOSOURCE +#include +#include "jsdtoa.h" + +static JSBool +date_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble utctime; + char buf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr, *bytes; + JSString *str; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) + return JS_FALSE; + + numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, utctime); + if (!numStr) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + bytes = JS_smprintf("(new %s(%s))", js_Date_str, numStr); + if (!bytes) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + str = JS_NewString(cx, bytes, strlen(bytes)); + if (!str) { + free(bytes); + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} +#endif + +static JSBool +date_toString(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble utctime; + + if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) + return JS_FALSE; + return date_format(cx, utctime, FORMATSPEC_FULL, vp); +} + +#ifdef JS_TRACER +static jsval FASTCALL +date_valueOf_tn(JSContext* cx, JSObject* obj, JSString* str) +{ + JS_ASSERT(JS_InstanceOf(cx, obj, &js_DateClass, NULL)); + jsdouble t = *JSVAL_TO_DOUBLE(obj->fslots[JSSLOT_UTC_TIME]); + + JSString* number_str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]); + jsval v; + if (js_EqualStrings(str, number_str)) { + if (!js_NewNumberInRootedValue(cx, t, &v)) + return JSVAL_ERROR_COOKIE; + } else { + if (!date_format(cx, t, FORMATSPEC_FULL, &v)) + return JSVAL_ERROR_COOKIE; + } + return v; +} +#endif + +static JSBool +date_valueOf(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str, *number_str; + + /* It is an error to call date_valueOf on a non-date object, but we don't + * need to check for that explicitly here because every path calls + * GetUTCTime, which does the check. + */ + + /* If called directly with no arguments, convert to a time number. */ + if (argc == 0) + return date_getTime(cx, argc, vp); + + /* Convert to number only if the hint was given, otherwise favor string. */ + str = js_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + number_str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]); + if (js_EqualStrings(str, number_str)) + return date_getTime(cx, argc, vp); + return date_toString(cx, argc, vp); +} + +JS_DEFINE_CALLINFO_2(extern, OBJECT, js_FastNewDate, CONTEXT, OBJECT, 0, 0) + +// Don't really need an argument here, but we don't support arg-less builtins +JS_DEFINE_TRCINFO_1(date_now, + (1, (static, DOUBLE, date_now_tn, CONTEXT, 0, 0))) + +static JSFunctionSpec date_static_methods[] = { + JS_FN("UTC", date_UTC, MAXARGS,0), + JS_FN("parse", date_parse, 1,0), + JS_TN("now", date_now, 0,0, date_now_trcinfo), + JS_FS_END +}; + +JS_DEFINE_TRCINFO_1(date_valueOf, + (3, (static, JSVAL_FAIL, date_valueOf_tn, CONTEXT, THIS, STRING, 0, 0))) + +static JSFunctionSpec date_methods[] = { + JS_FN("getTime", date_getTime, 0,0), + JS_FN("getTimezoneOffset", date_getTimezoneOffset, 0,0), + JS_FN("getYear", date_getYear, 0,0), + JS_FN("getFullYear", date_getFullYear, 0,0), + JS_FN("getUTCFullYear", date_getUTCFullYear, 0,0), + JS_FN("getMonth", date_getMonth, 0,0), + JS_FN("getUTCMonth", date_getUTCMonth, 0,0), + JS_FN("getDate", date_getDate, 0,0), + JS_FN("getUTCDate", date_getUTCDate, 0,0), + JS_FN("getDay", date_getDay, 0,0), + JS_FN("getUTCDay", date_getUTCDay, 0,0), + JS_FN("getHours", date_getHours, 0,0), + JS_FN("getUTCHours", date_getUTCHours, 0,0), + JS_FN("getMinutes", date_getMinutes, 0,0), + JS_FN("getUTCMinutes", date_getUTCMinutes, 0,0), + JS_FN("getSeconds", date_getUTCSeconds, 0,0), + JS_FN("getUTCSeconds", date_getUTCSeconds, 0,0), + JS_FN("getMilliseconds", date_getUTCMilliseconds, 0,0), + JS_FN("getUTCMilliseconds", date_getUTCMilliseconds, 0,0), + JS_FN("setTime", date_setTime, 1,0), + JS_FN("setYear", date_setYear, 1,0), + JS_FN("setFullYear", date_setFullYear, 3,0), + JS_FN("setUTCFullYear", date_setUTCFullYear, 3,0), + JS_FN("setMonth", date_setMonth, 2,0), + JS_FN("setUTCMonth", date_setUTCMonth, 2,0), + JS_FN("setDate", date_setDate, 1,0), + JS_FN("setUTCDate", date_setUTCDate, 1,0), + JS_FN("setHours", date_setHours, 4,0), + JS_FN("setUTCHours", date_setUTCHours, 4,0), + JS_FN("setMinutes", date_setMinutes, 3,0), + JS_FN("setUTCMinutes", date_setUTCMinutes, 3,0), + JS_FN("setSeconds", date_setSeconds, 2,0), + JS_FN("setUTCSeconds", date_setUTCSeconds, 2,0), + JS_FN("setMilliseconds", date_setMilliseconds, 1,0), + JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,0), + JS_FN("toUTCString", date_toGMTString, 0,0), + JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0), + JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0), + JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0), + JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0), + JS_FN("toDateString", date_toDateString, 0,0), + JS_FN("toTimeString", date_toTimeString, 0,0), + JS_FN("toISOString", date_toISOString, 0,0), + JS_FN(js_toJSON_str, date_toISOString, 0,0), + +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, date_toSource, 0,0), +#endif + JS_FN(js_toString_str, date_toString, 0,0), + JS_TN(js_valueOf_str, date_valueOf, 0,0, date_valueOf_trcinfo), + JS_FS_END +}; + +static jsdouble * +date_constructor(JSContext *cx, JSObject* obj) +{ + jsdouble *date; + + date = js_NewWeaklyRootedDouble(cx, 0.0); + if (!date) + return NULL; + + obj->fslots[JSSLOT_UTC_TIME] = DOUBLE_TO_JSVAL(date); + obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return date; +} + +JSBool +js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + jsdouble *date; + JSString *str; + jsdouble d; + + /* Date called as function. */ + if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { + return date_format(cx, PRMJ_Now() / PRMJ_USEC_PER_MSEC, + FORMATSPEC_FULL, rval); + } + + /* Date called as constructor. */ + if (argc == 0) { + date = date_constructor(cx, obj); + if (!date) + return JS_FALSE; + *date = PRMJ_Now() / PRMJ_USEC_PER_MSEC; + } else if (argc == 1) { + if (!JSVAL_IS_STRING(argv[0])) { + /* the argument is a millisecond number */ + d = js_ValueToNumber(cx, &argv[0]); + if (JSVAL_IS_NULL(argv[0])) + return JS_FALSE; + date = date_constructor(cx, obj); + if (!date) + return JS_FALSE; + *date = TIMECLIP(d); + } else { + /* the argument is a string; parse it. */ + date = date_constructor(cx, obj); + if (!date) + return JS_FALSE; + + str = js_ValueToString(cx, argv[0]); + if (!str) + return JS_FALSE; + + if (!date_parseString(str, date)) + *date = *cx->runtime->jsNaN; + *date = TIMECLIP(*date); + } + } else { + jsdouble *date; + jsdouble msec_time; + + if (!date_msecFromArgs(cx, argc, argv, &msec_time)) + return JS_FALSE; + + date = date_constructor(cx, obj); + if (!date) + return JS_FALSE; + + if (JSDOUBLE_IS_FINITE(msec_time)) { + msec_time = UTC(msec_time); + msec_time = TIMECLIP(msec_time); + } + + *date = msec_time; + } + return JS_TRUE; +} + +JS_STATIC_ASSERT(JSSLOT_PRIVATE == JSSLOT_UTC_TIME); +JS_STATIC_ASSERT(JSSLOT_UTC_TIME + 1 == JSSLOT_LOCAL_TIME); + +#ifdef JS_TRACER +JSObject* FASTCALL +js_FastNewDate(JSContext* cx, JSObject* proto) +{ + JS_ASSERT(JS_ON_TRACE(cx)); + JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject)); + if (!obj) + return NULL; + + JSClass* clasp = &js_DateClass; + obj->classword = jsuword(clasp); + + obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto); + obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT]; + + jsdouble* date = js_NewWeaklyRootedDouble(cx, 0.0); + if (!date) + return NULL; + *date = date_now_tn(cx); + obj->fslots[JSSLOT_UTC_TIME] = DOUBLE_TO_JSVAL(date); + obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + for (unsigned i = JSSLOT_LOCAL_TIME + 1; i != JS_INITIAL_NSLOTS; ++i) + obj->fslots[i] = JSVAL_VOID; + + JS_ASSERT(!clasp->getObjectOps); + JS_ASSERT(proto->map->ops == &js_ObjectOps); + obj->map = js_HoldObjectMap(cx, proto->map); + obj->dslots = NULL; + return obj; +} +#endif + +JSObject * +js_InitDateClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + jsdouble *proto_date; + + /* set static LocalTZA */ + LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond); + proto = JS_InitClass(cx, obj, NULL, &js_DateClass, js_Date, MAXARGS, + NULL, date_methods, NULL, date_static_methods); + if (!proto) + return NULL; + + /* Alias toUTCString with toGMTString. (ECMA B.2.6) */ + if (!JS_AliasProperty(cx, proto, "toUTCString", "toGMTString")) + return NULL; + + /* Set the value of the Date.prototype date to NaN */ + proto_date = date_constructor(cx, proto); + if (!proto_date) + return NULL; + *proto_date = *cx->runtime->jsNaN; + + return proto; +} + +JS_FRIEND_API(JSObject *) +js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time) +{ + JSObject *obj; + jsdouble *date; + + obj = js_NewObject(cx, &js_DateClass, NULL, NULL, 0); + if (!obj) + return NULL; + + date = date_constructor(cx, obj); + if (!date) + return NULL; + + *date = msec_time; + return obj; +} + +JS_FRIEND_API(JSObject *) +js_NewDateObject(JSContext* cx, int year, int mon, int mday, + int hour, int min, int sec) +{ + JSObject *obj; + jsdouble msec_time; + + JS_ASSERT(mon < 12); + msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0); + obj = js_NewDateObjectMsec(cx, UTC(msec_time)); + return obj; +} + +JS_FRIEND_API(JSBool) +js_DateIsValid(JSContext *cx, JSObject* obj) +{ + jsdouble utctime; + return GetUTCTime(cx, obj, NULL, &utctime) && !JSDOUBLE_IS_NaN(utctime); +} + +JS_FRIEND_API(int) +js_DateGetYear(JSContext *cx, JSObject* obj) +{ + jsdouble localtime; + + /* Preserve legacy API behavior of returning 0 for invalid dates. */ + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) || + JSDOUBLE_IS_NaN(localtime)) { + return 0; + } + + return (int) YearFromTime(localtime); +} + +JS_FRIEND_API(int) +js_DateGetMonth(JSContext *cx, JSObject* obj) +{ + jsdouble localtime; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) || + JSDOUBLE_IS_NaN(localtime)) { + return 0; + } + + return (int) MonthFromTime(localtime); +} + +JS_FRIEND_API(int) +js_DateGetDate(JSContext *cx, JSObject* obj) +{ + jsdouble localtime; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) || + JSDOUBLE_IS_NaN(localtime)) { + return 0; + } + + return (int) DateFromTime(localtime); +} + +JS_FRIEND_API(int) +js_DateGetHours(JSContext *cx, JSObject* obj) +{ + jsdouble localtime; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) || + JSDOUBLE_IS_NaN(localtime)) { + return 0; + } + + return (int) HourFromTime(localtime); +} + +JS_FRIEND_API(int) +js_DateGetMinutes(JSContext *cx, JSObject* obj) +{ + jsdouble localtime; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) || + JSDOUBLE_IS_NaN(localtime)) { + return 0; + } + + return (int) MinFromTime(localtime); +} + +JS_FRIEND_API(int) +js_DateGetSeconds(JSContext *cx, JSObject* obj) +{ + jsdouble utctime; + + if (!GetUTCTime(cx, obj, NULL, &utctime) || JSDOUBLE_IS_NaN(utctime)) + return 0; + + return (int) SecFromTime(utctime); +} + +JS_FRIEND_API(void) +js_DateSetYear(JSContext *cx, JSObject *obj, int year) +{ + jsdouble local; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &local)) + return; + + /* reset date if it was NaN */ + if (JSDOUBLE_IS_NaN(local)) + local = 0; + + local = date_msecFromDate(year, + MonthFromTime(local), + DateFromTime(local), + HourFromTime(local), + MinFromTime(local), + SecFromTime(local), + msFromTime(local)); + + /* SetUTCTime also invalidates local time cache. */ + SetUTCTime(cx, obj, NULL, UTC(local)); +} + +JS_FRIEND_API(void) +js_DateSetMonth(JSContext *cx, JSObject *obj, int month) +{ + jsdouble local; + + JS_ASSERT(month < 12); + + if (!GetAndCacheLocalTime(cx, obj, NULL, &local)) + return; + + /* bail if date was NaN */ + if (JSDOUBLE_IS_NaN(local)) + return; + + local = date_msecFromDate(YearFromTime(local), + month, + DateFromTime(local), + HourFromTime(local), + MinFromTime(local), + SecFromTime(local), + msFromTime(local)); + SetUTCTime(cx, obj, NULL, UTC(local)); +} + +JS_FRIEND_API(void) +js_DateSetDate(JSContext *cx, JSObject *obj, int date) +{ + jsdouble local; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &local)) + return; + + if (JSDOUBLE_IS_NaN(local)) + return; + + local = date_msecFromDate(YearFromTime(local), + MonthFromTime(local), + date, + HourFromTime(local), + MinFromTime(local), + SecFromTime(local), + msFromTime(local)); + SetUTCTime(cx, obj, NULL, UTC(local)); +} + +JS_FRIEND_API(void) +js_DateSetHours(JSContext *cx, JSObject *obj, int hours) +{ + jsdouble local; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &local)) + return; + + if (JSDOUBLE_IS_NaN(local)) + return; + local = date_msecFromDate(YearFromTime(local), + MonthFromTime(local), + DateFromTime(local), + hours, + MinFromTime(local), + SecFromTime(local), + msFromTime(local)); + SetUTCTime(cx, obj, NULL, UTC(local)); +} + +JS_FRIEND_API(void) +js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes) +{ + jsdouble local; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &local)) + return; + + if (JSDOUBLE_IS_NaN(local)) + return; + local = date_msecFromDate(YearFromTime(local), + MonthFromTime(local), + DateFromTime(local), + HourFromTime(local), + minutes, + SecFromTime(local), + msFromTime(local)); + SetUTCTime(cx, obj, NULL, UTC(local)); +} + +JS_FRIEND_API(void) +js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds) +{ + jsdouble local; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &local)) + return; + + if (JSDOUBLE_IS_NaN(local)) + return; + local = date_msecFromDate(YearFromTime(local), + MonthFromTime(local), + DateFromTime(local), + HourFromTime(local), + MinFromTime(local), + seconds, + msFromTime(local)); + SetUTCTime(cx, obj, NULL, UTC(local)); +} + +JS_FRIEND_API(jsdouble) +js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj) +{ + jsdouble utctime; + if (!GetUTCTime(cx, obj, NULL, &utctime)) + return 0; + return utctime; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdate.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdate.h new file mode 100644 index 0000000..6c5b3aa --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdate.h @@ -0,0 +1,124 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS Date class interface. + */ + +#ifndef jsdate_h___ +#define jsdate_h___ + +JS_BEGIN_EXTERN_C + +extern JSClass js_DateClass; + +extern JSObject * +js_InitDateClass(JSContext *cx, JSObject *obj); + +/* + * These functions provide a C interface to the date/time object + */ + +/* + * Construct a new Date Object from a time value given in milliseconds UTC + * since the epoch. + */ +extern JS_FRIEND_API(JSObject*) +js_NewDateObjectMsec(JSContext* cx, jsdouble msec_time); + +/* + * Construct a new Date Object from an exploded local time value. + * + * Assert that mon < 12 to help catch off-by-one user errors, which are common + * due to the 0-based month numbering copied into JS from Java (java.util.Date + * in 1995). js_DateSetMonth (below) likewise asserts month < 12. + */ +extern JS_FRIEND_API(JSObject*) +js_NewDateObject(JSContext* cx, int year, int mon, int mday, + int hour, int min, int sec); + +/* + * Detect whether the internal date value is NaN. (Because failure is + * out-of-band for js_DateGet*) + */ +extern JS_FRIEND_API(JSBool) +js_DateIsValid(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetYear(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetMonth(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetDate(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetHours(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetMinutes(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetSeconds(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(void) +js_DateSetYear(JSContext *cx, JSObject *obj, int year); + +extern JS_FRIEND_API(void) +js_DateSetMonth(JSContext *cx, JSObject *obj, int month); + +extern JS_FRIEND_API(void) +js_DateSetDate(JSContext *cx, JSObject *obj, int date); + +extern JS_FRIEND_API(void) +js_DateSetHours(JSContext *cx, JSObject *obj, int hours); + +extern JS_FRIEND_API(void) +js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes); + +extern JS_FRIEND_API(void) +js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds); + +extern JS_FRIEND_API(jsdouble) +js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj); + +JS_END_EXTERN_C + +#endif /* jsdate_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdbgapi.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdbgapi.cpp new file mode 100644 index 0000000..dad4590 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdbgapi.cpp @@ -0,0 +1,1954 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS debugging API. + */ +#include "jsstddef.h" +#include +#include "jstypes.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jsclist.h" +#include "jsapi.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" + +#include "jsautooplen.h" + +typedef struct JSTrap { + JSCList links; + JSScript *script; + jsbytecode *pc; + JSOp op; + JSTrapHandler handler; + void *closure; +} JSTrap; + +#define DBG_LOCK(rt) JS_ACQUIRE_LOCK((rt)->debuggerLock) +#define DBG_UNLOCK(rt) JS_RELEASE_LOCK((rt)->debuggerLock) +#define DBG_LOCK_EVAL(rt,expr) (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt)) + +/* + * NB: FindTrap must be called with rt->debuggerLock acquired. + */ +static JSTrap * +FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc) +{ + JSTrap *trap; + + for (trap = (JSTrap *)rt->trapList.next; + &trap->links != &rt->trapList; + trap = (JSTrap *)trap->links.next) { + if (trap->script == script && trap->pc == pc) + return trap; + } + return NULL; +} + +jsbytecode * +js_UntrapScriptCode(JSContext *cx, JSScript *script) +{ + jsbytecode *code; + JSRuntime *rt; + JSTrap *trap; + + code = script->code; + rt = cx->runtime; + DBG_LOCK(rt); + for (trap = (JSTrap *)rt->trapList.next; + &trap->links != + &rt->trapList; + trap = (JSTrap *)trap->links.next) { + if (trap->script == script && + (size_t)(trap->pc - script->code) < script->length) { + if (code == script->code) { + jssrcnote *sn, *notes; + size_t nbytes; + + nbytes = script->length * sizeof(jsbytecode); + notes = SCRIPT_NOTES(script); + for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) + continue; + nbytes += (sn - notes + 1) * sizeof *sn; + + code = (jsbytecode *) JS_malloc(cx, nbytes); + if (!code) + break; + memcpy(code, script->code, nbytes); + JS_CLEAR_GSN_CACHE(cx); + } + code[trap->pc - script->code] = trap->op; + } + } + DBG_UNLOCK(rt); + return code; +} + +JS_PUBLIC_API(JSBool) +JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, + JSTrapHandler handler, void *closure) +{ + JSTrap *junk, *trap, *twin; + JSRuntime *rt; + uint32 sample; + + JS_ASSERT((JSOp) *pc != JSOP_TRAP); + junk = NULL; + rt = cx->runtime; + DBG_LOCK(rt); + trap = FindTrap(rt, script, pc); + if (trap) { + JS_ASSERT(trap->script == script && trap->pc == pc); + JS_ASSERT(*pc == JSOP_TRAP); + } else { + sample = rt->debuggerMutations; + DBG_UNLOCK(rt); + trap = (JSTrap *) JS_malloc(cx, sizeof *trap); + if (!trap) + return JS_FALSE; + trap->closure = NULL; + if(!js_AddRoot(cx, &trap->closure, "trap->closure")) { + JS_free(cx, trap); + return JS_FALSE; + } + DBG_LOCK(rt); + twin = (rt->debuggerMutations != sample) + ? FindTrap(rt, script, pc) + : NULL; + if (twin) { + junk = trap; + trap = twin; + } else { + JS_APPEND_LINK(&trap->links, &rt->trapList); + ++rt->debuggerMutations; + trap->script = script; + trap->pc = pc; + trap->op = (JSOp)*pc; + *pc = JSOP_TRAP; + } + } + trap->handler = handler; + trap->closure = closure; + DBG_UNLOCK(rt); + if (junk) { + js_RemoveRoot(rt, &junk->closure); + JS_free(cx, junk); + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSOp) +JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + JSRuntime *rt; + JSTrap *trap; + JSOp op; + + rt = cx->runtime; + DBG_LOCK(rt); + trap = FindTrap(rt, script, pc); + op = trap ? trap->op : (JSOp) *pc; + DBG_UNLOCK(rt); + return op; +} + +static void +DestroyTrapAndUnlock(JSContext *cx, JSTrap *trap) +{ + ++cx->runtime->debuggerMutations; + JS_REMOVE_LINK(&trap->links); + *trap->pc = (jsbytecode)trap->op; + DBG_UNLOCK(cx->runtime); + + js_RemoveRoot(cx->runtime, &trap->closure); + JS_free(cx, trap); +} + +JS_PUBLIC_API(void) +JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc, + JSTrapHandler *handlerp, void **closurep) +{ + JSTrap *trap; + + DBG_LOCK(cx->runtime); + trap = FindTrap(cx->runtime, script, pc); + if (handlerp) + *handlerp = trap ? trap->handler : NULL; + if (closurep) + *closurep = trap ? trap->closure : NULL; + if (trap) + DestroyTrapAndUnlock(cx, trap); + else + DBG_UNLOCK(cx->runtime); +} + +JS_PUBLIC_API(void) +JS_ClearScriptTraps(JSContext *cx, JSScript *script) +{ + JSRuntime *rt; + JSTrap *trap, *next; + uint32 sample; + + rt = cx->runtime; + DBG_LOCK(rt); + for (trap = (JSTrap *)rt->trapList.next; + &trap->links != &rt->trapList; + trap = next) { + next = (JSTrap *)trap->links.next; + if (trap->script == script) { + sample = rt->debuggerMutations; + DestroyTrapAndUnlock(cx, trap); + DBG_LOCK(rt); + if (rt->debuggerMutations != sample + 1) + next = (JSTrap *)rt->trapList.next; + } + } + DBG_UNLOCK(rt); +} + +JS_PUBLIC_API(void) +JS_ClearAllTraps(JSContext *cx) +{ + JSRuntime *rt; + JSTrap *trap, *next; + uint32 sample; + + rt = cx->runtime; + DBG_LOCK(rt); + for (trap = (JSTrap *)rt->trapList.next; + &trap->links != &rt->trapList; + trap = next) { + next = (JSTrap *)trap->links.next; + sample = rt->debuggerMutations; + DestroyTrapAndUnlock(cx, trap); + DBG_LOCK(rt); + if (rt->debuggerMutations != sample + 1) + next = (JSTrap *)rt->trapList.next; + } + DBG_UNLOCK(rt); +} + +JS_PUBLIC_API(JSTrapStatus) +JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval) +{ + JSTrap *trap; + jsint op; + JSTrapStatus status; + + DBG_LOCK(cx->runtime); + trap = FindTrap(cx->runtime, script, pc); + JS_ASSERT(!trap || trap->handler); + if (!trap) { + op = (JSOp) *pc; + DBG_UNLOCK(cx->runtime); + + /* Defend against "pc for wrong script" API usage error. */ + JS_ASSERT(op != JSOP_TRAP); + +#ifdef JS_THREADSAFE + /* If the API was abused, we must fail for want of the real op. */ + if (op == JSOP_TRAP) + return JSTRAP_ERROR; + + /* Assume a race with a debugger thread and try to carry on. */ + *rval = INT_TO_JSVAL(op); + return JSTRAP_CONTINUE; +#else + /* Always fail if single-threaded (must be an API usage error). */ + return JSTRAP_ERROR; +#endif + } + DBG_UNLOCK(cx->runtime); + + /* + * It's important that we not use 'trap->' after calling the callback -- + * the callback might remove the trap! + */ + op = (jsint)trap->op; + status = trap->handler(cx, script, pc, rval, trap->closure); + if (status == JSTRAP_CONTINUE) { + /* By convention, return the true op to the interpreter in rval. */ + *rval = INT_TO_JSVAL(op); + } + return status; +} + +JS_PUBLIC_API(JSBool) +JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure) +{ + rt->globalDebugHooks.interruptHandler = handler; + rt->globalDebugHooks.interruptHandlerData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep) +{ + if (handlerp) + *handlerp = (JSTrapHandler)rt->globalDebugHooks.interruptHandler; + if (closurep) + *closurep = rt->globalDebugHooks.interruptHandlerData; + rt->globalDebugHooks.interruptHandler = 0; + rt->globalDebugHooks.interruptHandlerData = 0; + return JS_TRUE; +} + +/************************************************************************/ + +typedef struct JSWatchPoint { + JSCList links; + JSObject *object; /* weak link, see js_FinalizeObject */ + JSScopeProperty *sprop; + JSPropertyOp setter; + JSWatchPointHandler handler; + void *closure; + uintN flags; +} JSWatchPoint; + +#define JSWP_LIVE 0x1 /* live because set and not cleared */ +#define JSWP_HELD 0x2 /* held while running handler/setter */ + +/* + * NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases. + */ +static JSBool +DropWatchPointAndUnlock(JSContext *cx, JSWatchPoint *wp, uintN flag) +{ + JSBool ok, found; + JSScopeProperty *sprop; + JSScope *scope; + JSPropertyOp setter; + + ok = JS_TRUE; + wp->flags &= ~flag; + if (wp->flags != 0) { + DBG_UNLOCK(cx->runtime); + return ok; + } + + /* + * Remove wp from the list, then if there are no other watchpoints for + * wp->sprop in any scope, restore wp->sprop->setter from wp. + */ + ++cx->runtime->debuggerMutations; + JS_REMOVE_LINK(&wp->links); + sprop = wp->sprop; + + /* + * Passing null for the scope parameter tells js_GetWatchedSetter to find + * any watch point for sprop, and not to lock or unlock rt->debuggerLock. + * If js_ChangeNativePropertyAttrs fails, propagate failure after removing + * wp->closure's root and freeing wp. + */ + setter = js_GetWatchedSetter(cx->runtime, NULL, sprop); + DBG_UNLOCK(cx->runtime); + if (!setter) { + JS_LOCK_OBJ(cx, wp->object); + scope = OBJ_SCOPE(wp->object); + found = (scope->object == wp->object && + SCOPE_GET_PROPERTY(scope, sprop->id)); + JS_UNLOCK_SCOPE(cx, scope); + + /* + * If the property wasn't found on wp->object or didn't exist, then + * someone else has dealt with this sprop, and we don't need to change + * the property attributes. + */ + if (found) { + sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop, + 0, sprop->attrs, + sprop->getter, + wp->setter); + if (!sprop) + ok = JS_FALSE; + } + } + + JS_free(cx, wp); + return ok; +} + +/* + * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since + * the debugger should never be racing with the GC (i.e., the debugger must + * respect the request model). + */ +void +js_TraceWatchPoints(JSTracer *trc, JSObject *obj) +{ + JSRuntime *rt; + JSWatchPoint *wp; + + rt = trc->context->runtime; + + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = (JSWatchPoint *)wp->links.next) { + if (wp->object == obj) { + TRACE_SCOPE_PROPERTY(trc, wp->sprop); + if ((wp->sprop->attrs & JSPROP_SETTER) && wp->setter) { + JS_CALL_OBJECT_TRACER(trc, (JSObject *)wp->setter, + "wp->setter"); + } + JS_SET_TRACING_NAME(trc, "wp->closure"); + js_CallValueTracerIfGCThing(trc, (jsval) wp->closure); + } + } +} + +void +js_SweepWatchPoints(JSContext *cx) +{ + JSRuntime *rt; + JSWatchPoint *wp, *next; + uint32 sample; + + rt = cx->runtime; + DBG_LOCK(rt); + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = next) { + next = (JSWatchPoint *)wp->links.next; + if (js_IsAboutToBeFinalized(cx, wp->object)) { + sample = rt->debuggerMutations; + + /* Ignore failures. */ + DropWatchPointAndUnlock(cx, wp, JSWP_LIVE); + DBG_LOCK(rt); + if (rt->debuggerMutations != sample + 1) + next = (JSWatchPoint *)rt->watchPointList.next; + } + } + DBG_UNLOCK(rt); +} + + + +/* + * NB: FindWatchPoint must be called with rt->debuggerLock acquired. + */ +static JSWatchPoint * +FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id) +{ + JSWatchPoint *wp; + + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = (JSWatchPoint *)wp->links.next) { + if (wp->object == scope->object && wp->sprop->id == id) + return wp; + } + return NULL; +} + +JSScopeProperty * +js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id) +{ + JSWatchPoint *wp; + JSScopeProperty *sprop; + + DBG_LOCK(rt); + wp = FindWatchPoint(rt, scope, id); + sprop = wp ? wp->sprop : NULL; + DBG_UNLOCK(rt); + return sprop; +} + +/* + * Secret handshake with DropWatchPointAndUnlock: if (!scope), we know our + * caller has acquired rt->debuggerLock, so we don't have to. + */ +JSPropertyOp +js_GetWatchedSetter(JSRuntime *rt, JSScope *scope, + const JSScopeProperty *sprop) +{ + JSPropertyOp setter; + JSWatchPoint *wp; + + setter = NULL; + if (scope) + DBG_LOCK(rt); + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = (JSWatchPoint *)wp->links.next) { + if ((!scope || wp->object == scope->object) && wp->sprop == sprop) { + setter = wp->setter; + break; + } + } + if (scope) + DBG_UNLOCK(rt); + return setter; +} + +JSBool +js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSRuntime *rt; + JSWatchPoint *wp; + JSScopeProperty *sprop; + jsval propid, userid; + JSScope *scope; + JSBool ok; + + rt = cx->runtime; + DBG_LOCK(rt); + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = (JSWatchPoint *)wp->links.next) { + sprop = wp->sprop; + if (wp->object == obj && SPROP_USERID(sprop) == id && + !(wp->flags & JSWP_HELD)) { + wp->flags |= JSWP_HELD; + DBG_UNLOCK(rt); + + JS_LOCK_OBJ(cx, obj); + propid = ID_TO_VALUE(sprop->id); + userid = (sprop->flags & SPROP_HAS_SHORTID) + ? INT_TO_JSVAL(sprop->shortid) + : propid; + scope = OBJ_SCOPE(obj); + JS_UNLOCK_OBJ(cx, obj); + + /* NB: wp is held, so we can safely dereference it still. */ + ok = wp->handler(cx, obj, propid, + SPROP_HAS_VALID_SLOT(sprop, scope) + ? OBJ_GET_SLOT(cx, obj, sprop->slot) + : JSVAL_VOID, + vp, wp->closure); + if (ok) { + /* + * Create a pseudo-frame for the setter invocation so that any + * stack-walking security code under the setter will correctly + * identify the guilty party. So that the watcher appears to + * be active to obj_eval and other such code, point frame.pc + * at the JSOP_STOP at the end of the script. + * + * The pseudo-frame is not created for fast natives as they + * are treated as interpreter frame extensions and always + * trusted. + */ + JSObject *closure; + JSClass *clasp; + JSFunction *fun; + JSScript *script; + JSBool injectFrame; + uintN nslots; + jsval smallv[5]; + jsval *argv; + JSStackFrame frame; + JSFrameRegs regs; + + closure = (JSObject *) wp->closure; + clasp = OBJ_GET_CLASS(cx, closure); + if (clasp == &js_FunctionClass) { + fun = GET_FUNCTION_PRIVATE(cx, closure); + script = FUN_SCRIPT(fun); + } else if (clasp == &js_ScriptClass) { + fun = NULL; + script = (JSScript *) JS_GetPrivate(cx, closure); + } else { + fun = NULL; + script = NULL; + } + + nslots = 2; + injectFrame = JS_TRUE; + if (fun) { + nslots += FUN_MINARGS(fun); + if (!FUN_INTERPRETED(fun)) { + nslots += fun->u.n.extra; + injectFrame = !(fun->flags & JSFUN_FAST_NATIVE); + } + } + + if (injectFrame) { + if (nslots <= JS_ARRAY_LENGTH(smallv)) { + argv = smallv; + } else { + argv = (jsval *) JS_malloc(cx, nslots * sizeof(jsval)); + if (!argv) { + DBG_LOCK(rt); + DropWatchPointAndUnlock(cx, wp, JSWP_HELD); + return JS_FALSE; + } + } + + argv[0] = OBJECT_TO_JSVAL(closure); + argv[1] = JSVAL_NULL; + memset(argv + 2, 0, (nslots - 2) * sizeof(jsval)); + + memset(&frame, 0, sizeof(frame)); + frame.script = script; + frame.regs = NULL; + if (script) { + JS_ASSERT(script->length >= JSOP_STOP_LENGTH); + regs.pc = script->code + script->length + - JSOP_STOP_LENGTH; + regs.sp = NULL; + frame.regs = ®s; + } + frame.callee = closure; + frame.fun = fun; + frame.argv = argv + 2; + frame.down = cx->fp; + frame.scopeChain = OBJ_GET_PARENT(cx, closure); + + cx->fp = &frame; + } +#ifdef __GNUC__ + else + argv = NULL; /* suppress bogus gcc warnings */ +#endif + ok = !wp->setter || + ((sprop->attrs & JSPROP_SETTER) + ? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter), + 1, vp, vp) + : wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp)); + if (injectFrame) { + /* Evil code can cause us to have an arguments object. */ + if (frame.callobj) + ok &= js_PutCallObject(cx, &frame); + if (frame.argsobj) + ok &= js_PutArgsObject(cx, &frame); + + cx->fp = frame.down; + if (argv != smallv) + JS_free(cx, argv); + } + } + DBG_LOCK(rt); + return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok; + } + } + DBG_UNLOCK(rt); + return JS_TRUE; +} + +JSBool +js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + JSObject *funobj; + JSFunction *wrapper; + jsval userid; + + funobj = JSVAL_TO_OBJECT(argv[-2]); + JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass); + wrapper = GET_FUNCTION_PRIVATE(cx, funobj); + userid = ATOM_KEY(wrapper->atom); + *rval = argv[0]; + return js_watch_set(cx, obj, userid, rval); +} + +JSPropertyOp +js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter) +{ + JSAtom *atom; + JSFunction *wrapper; + + if (!(attrs & JSPROP_SETTER)) + return &js_watch_set; /* & to silence schoolmarmish MSVC */ + + if (JSID_IS_ATOM(id)) { + atom = JSID_TO_ATOM(id); + } else if (JSID_IS_INT(id)) { + if (!js_ValueToStringId(cx, INT_JSID_TO_JSVAL(id), &id)) + return NULL; + atom = JSID_TO_ATOM(id); + } else { + atom = NULL; + } + wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0, + OBJ_GET_PARENT(cx, (JSObject *)setter), + atom); + if (!wrapper) + return NULL; + return (JSPropertyOp) FUN_OBJECT(wrapper); +} + +JS_PUBLIC_API(JSBool) +JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval, + JSWatchPointHandler handler, void *closure) +{ + jsid propid; + JSObject *pobj; + JSProperty *prop; + JSScopeProperty *sprop; + JSRuntime *rt; + JSBool ok; + JSWatchPoint *wp; + JSPropertyOp watcher; + + if (!OBJ_IS_NATIVE(obj)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH, + OBJ_GET_CLASS(cx, obj)->name); + return JS_FALSE; + } + + if (JSVAL_IS_INT(idval)) + propid = INT_JSVAL_TO_JSID(idval); + else if (!js_ValueToStringId(cx, idval, &propid)) + return JS_FALSE; + + if (!js_LookupProperty(cx, obj, propid, &pobj, &prop)) + return JS_FALSE; + sprop = (JSScopeProperty *) prop; + rt = cx->runtime; + if (!sprop) { + /* Check for a deleted symbol watchpoint, which holds its property. */ + sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid); + if (!sprop) { + /* Make a new property in obj so we can watch for the first set. */ + if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID, + NULL, NULL, JSPROP_ENUMERATE, + &prop)) { + return JS_FALSE; + } + sprop = (JSScopeProperty *) prop; + } + } else if (pobj != obj) { + /* Clone the prototype property so we can watch the right object. */ + jsval value; + JSPropertyOp getter, setter; + uintN attrs, flags; + intN shortid; + + if (OBJ_IS_NATIVE(pobj)) { + value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj)) + ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot) + : JSVAL_VOID; + getter = sprop->getter; + setter = sprop->setter; + attrs = sprop->attrs; + flags = sprop->flags; + shortid = sprop->shortid; + } else { + if (!OBJ_GET_PROPERTY(cx, pobj, propid, &value) || + !OBJ_GET_ATTRIBUTES(cx, pobj, propid, prop, &attrs)) { + OBJ_DROP_PROPERTY(cx, pobj, prop); + return JS_FALSE; + } + getter = setter = NULL; + flags = 0; + shortid = 0; + } + OBJ_DROP_PROPERTY(cx, pobj, prop); + + /* Recall that obj is native, whether or not pobj is native. */ + if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter, + attrs, flags, shortid, &prop)) { + return JS_FALSE; + } + sprop = (JSScopeProperty *) prop; + } + + /* + * At this point, prop/sprop exists in obj, obj is locked, and we must + * OBJ_DROP_PROPERTY(cx, obj, prop) before returning. + */ + ok = JS_TRUE; + DBG_LOCK(rt); + wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid); + if (!wp) { + DBG_UNLOCK(rt); + watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter); + if (!watcher) { + ok = JS_FALSE; + goto out; + } + + wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp); + if (!wp) { + ok = JS_FALSE; + goto out; + } + wp->handler = NULL; + wp->closure = NULL; + wp->object = obj; + JS_ASSERT(sprop->setter != js_watch_set || pobj != obj); + wp->setter = sprop->setter; + wp->flags = JSWP_LIVE; + + /* XXXbe nest in obj lock here */ + sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs, + sprop->getter, watcher); + if (!sprop) { + /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */ + JS_INIT_CLIST(&wp->links); + DBG_LOCK(rt); + DropWatchPointAndUnlock(cx, wp, JSWP_LIVE); + ok = JS_FALSE; + goto out; + } + wp->sprop = sprop; + + /* + * Now that wp is fully initialized, append it to rt's wp list. + * Because obj is locked we know that no other thread could have added + * a watchpoint for (obj, propid). + */ + DBG_LOCK(rt); + JS_ASSERT(!FindWatchPoint(rt, OBJ_SCOPE(obj), propid)); + JS_APPEND_LINK(&wp->links, &rt->watchPointList); + ++rt->debuggerMutations; + } + wp->handler = handler; + wp->closure = closure; + DBG_UNLOCK(rt); + +out: + OBJ_DROP_PROPERTY(cx, obj, prop); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id, + JSWatchPointHandler *handlerp, void **closurep) +{ + JSRuntime *rt; + JSWatchPoint *wp; + + rt = cx->runtime; + DBG_LOCK(rt); + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = (JSWatchPoint *)wp->links.next) { + if (wp->object == obj && SPROP_USERID(wp->sprop) == id) { + if (handlerp) + *handlerp = wp->handler; + if (closurep) + *closurep = wp->closure; + return DropWatchPointAndUnlock(cx, wp, JSWP_LIVE); + } + } + DBG_UNLOCK(rt); + if (handlerp) + *handlerp = NULL; + if (closurep) + *closurep = NULL; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj) +{ + JSRuntime *rt; + JSWatchPoint *wp, *next; + uint32 sample; + + rt = cx->runtime; + DBG_LOCK(rt); + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = next) { + next = (JSWatchPoint *)wp->links.next; + if (wp->object == obj) { + sample = rt->debuggerMutations; + if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE)) + return JS_FALSE; + DBG_LOCK(rt); + if (rt->debuggerMutations != sample + 1) + next = (JSWatchPoint *)rt->watchPointList.next; + } + } + DBG_UNLOCK(rt); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ClearAllWatchPoints(JSContext *cx) +{ + JSRuntime *rt; + JSWatchPoint *wp, *next; + uint32 sample; + + rt = cx->runtime; + DBG_LOCK(rt); + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = next) { + next = (JSWatchPoint *)wp->links.next; + sample = rt->debuggerMutations; + if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE)) + return JS_FALSE; + DBG_LOCK(rt); + if (rt->debuggerMutations != sample + 1) + next = (JSWatchPoint *)rt->watchPointList.next; + } + DBG_UNLOCK(rt); + return JS_TRUE; +} + +/************************************************************************/ + +JS_PUBLIC_API(uintN) +JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + return js_PCToLineNumber(cx, script, pc); +} + +JS_PUBLIC_API(jsbytecode *) +JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno) +{ + return js_LineNumberToPC(script, lineno); +} + +JS_PUBLIC_API(JSScript *) +JS_GetFunctionScript(JSContext *cx, JSFunction *fun) +{ + return FUN_SCRIPT(fun); +} + +JS_PUBLIC_API(JSNative) +JS_GetFunctionNative(JSContext *cx, JSFunction *fun) +{ + return FUN_NATIVE(fun); +} + +JS_PUBLIC_API(JSFastNative) +JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun) +{ + return FUN_FAST_NATIVE(fun); +} + +JS_PUBLIC_API(JSPrincipals *) +JS_GetScriptPrincipals(JSContext *cx, JSScript *script) +{ + return script->principals; +} + +/************************************************************************/ + +/* + * Stack Frame Iterator + */ +JS_PUBLIC_API(JSStackFrame *) +JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp) +{ + *iteratorp = (*iteratorp == NULL) ? cx->fp : (*iteratorp)->down; + return *iteratorp; +} + +JS_PUBLIC_API(JSScript *) +JS_GetFrameScript(JSContext *cx, JSStackFrame *fp) +{ + return fp->script; +} + +JS_PUBLIC_API(jsbytecode *) +JS_GetFramePC(JSContext *cx, JSStackFrame *fp) +{ + return fp->regs ? fp->regs->pc : NULL; +} + +JS_PUBLIC_API(JSStackFrame *) +JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp) +{ + if (!fp) + fp = cx->fp; + while (fp) { + if (fp->script) + return fp; + fp = fp->down; + } + return NULL; +} + +JS_PUBLIC_API(JSPrincipals *) +JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp) +{ + JSSecurityCallbacks *callbacks; + + if (fp->fun) { + callbacks = JS_GetSecurityCallbacks(cx); + if (callbacks && callbacks->findObjectPrincipals) { + if (FUN_OBJECT(fp->fun) != fp->callee) + return callbacks->findObjectPrincipals(cx, fp->callee); + /* FALL THROUGH */ + } + } + if (fp->script) + return fp->script->principals; + return NULL; +} + +JS_PUBLIC_API(JSPrincipals *) +JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller) +{ + JSPrincipals *principals, *callerPrincipals; + JSSecurityCallbacks *callbacks; + + callbacks = JS_GetSecurityCallbacks(cx); + if (callbacks && callbacks->findObjectPrincipals) { + principals = callbacks->findObjectPrincipals(cx, fp->callee); + } else { + principals = NULL; + } + if (!caller) + return principals; + callerPrincipals = JS_StackFramePrincipals(cx, caller); + return (callerPrincipals && principals && + callerPrincipals->subsume(callerPrincipals, principals)) + ? principals + : callerPrincipals; +} + +JS_PUBLIC_API(void *) +JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp) +{ + if (fp->annotation && fp->script) { + JSPrincipals *principals = JS_StackFramePrincipals(cx, fp); + + if (principals && principals->globalPrivilegesEnabled(cx, principals)) { + /* + * Give out an annotation only if privileges have not been revoked + * or disabled globally. + */ + return fp->annotation; + } + } + + return NULL; +} + +JS_PUBLIC_API(void) +JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation) +{ + fp->annotation = annotation; +} + +JS_PUBLIC_API(void *) +JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp) +{ + JSPrincipals *principals; + + principals = JS_StackFramePrincipals(cx, fp); + if (!principals) + return NULL; + return principals->getPrincipalArray(cx, principals); +} + +JS_PUBLIC_API(JSBool) +JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp) +{ + return !fp->script; +} + +/* this is deprecated, use JS_GetFrameScopeChain instead */ +JS_PUBLIC_API(JSObject *) +JS_GetFrameObject(JSContext *cx, JSStackFrame *fp) +{ + return fp->scopeChain; +} + +JS_PUBLIC_API(JSObject *) +JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp) +{ + /* Force creation of argument and call objects if not yet created */ + (void) JS_GetFrameCallObject(cx, fp); + return js_GetScopeChain(cx, fp); +} + +JS_PUBLIC_API(JSObject *) +JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp) +{ + if (! fp->fun) + return NULL; + + /* Force creation of argument object if not yet created */ + (void) js_GetArgsObject(cx, fp); + + /* + * XXX ill-defined: null return here means error was reported, unlike a + * null returned above or in the #else + */ + return js_GetCallObject(cx, fp, NULL); +} + +JS_PUBLIC_API(JSObject *) +JS_GetFrameThis(JSContext *cx, JSStackFrame *fp) +{ + JSStackFrame *afp; + + if (fp->flags & JSFRAME_COMPUTED_THIS) + return fp->thisp; + + /* js_ComputeThis gets confused if fp != cx->fp, so set it aside. */ + if (cx->fp != fp) { + afp = cx->fp; + if (afp) { + afp->dormantNext = cx->dormantFrameChain; + cx->dormantFrameChain = afp; + cx->fp = fp; + } + } else { + afp = NULL; + } + + if (!fp->thisp && fp->argv) + fp->thisp = js_ComputeThis(cx, JS_TRUE, fp->argv); + + if (afp) { + cx->fp = afp; + cx->dormantFrameChain = afp->dormantNext; + afp->dormantNext = NULL; + } + + return fp->thisp; +} + +JS_PUBLIC_API(JSFunction *) +JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp) +{ + return fp->fun; +} + +JS_PUBLIC_API(JSObject *) +JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp) +{ + if (!fp->fun) + return NULL; + + JS_ASSERT(OBJ_GET_CLASS(cx, fp->callee) == &js_FunctionClass); + JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->callee) == fp->fun); + return fp->callee; +} + +JS_PUBLIC_API(JSBool) +JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp) +{ + return (fp->flags & JSFRAME_CONSTRUCTING) != 0; +} + +JS_PUBLIC_API(JSObject *) +JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp) +{ + return fp->callee; +} + +JS_PUBLIC_API(JSBool) +JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp) +{ + return (fp->flags & JSFRAME_DEBUGGER) != 0; +} + +JS_PUBLIC_API(jsval) +JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp) +{ + return fp->rval; +} + +JS_PUBLIC_API(void) +JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval) +{ + fp->rval = rval; +} + +/************************************************************************/ + +JS_PUBLIC_API(const char *) +JS_GetScriptFilename(JSContext *cx, JSScript *script) +{ + return script->filename; +} + +JS_PUBLIC_API(uintN) +JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script) +{ + return script->lineno; +} + +JS_PUBLIC_API(uintN) +JS_GetScriptLineExtent(JSContext *cx, JSScript *script) +{ + return js_GetScriptLineExtent(script); +} + +JS_PUBLIC_API(JSVersion) +JS_GetScriptVersion(JSContext *cx, JSScript *script) +{ + return (JSVersion) (script->version & JSVERSION_MASK); +} + +/***************************************************************************/ + +JS_PUBLIC_API(void) +JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata) +{ + rt->globalDebugHooks.newScriptHook = hook; + rt->globalDebugHooks.newScriptHookData = callerdata; +} + +JS_PUBLIC_API(void) +JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook, + void *callerdata) +{ + rt->globalDebugHooks.destroyScriptHook = hook; + rt->globalDebugHooks.destroyScriptHookData = callerdata; +} + +/***************************************************************************/ + +JS_PUBLIC_API(JSBool) +JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval) +{ + JSObject *scobj; + JSScript *script; + JSBool ok; + + scobj = JS_GetFrameScopeChain(cx, fp); + if (!scobj) + return JS_FALSE; + + script = js_CompileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp), + TCF_COMPILE_N_GO | + TCF_PUT_STATIC_DEPTH(fp->script->staticDepth + 1), + chars, length, NULL, + filename, lineno); + if (!script) + return JS_FALSE; + + ok = js_Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, + rval); + js_DestroyScript(cx, script); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp, + const char *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval) +{ + jschar *chars; + JSBool ok; + size_t len = length; + + chars = js_InflateString(cx, bytes, &len); + if (!chars) + return JS_FALSE; + length = (uintN) len; + ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno, + rval); + JS_free(cx, chars); + + return ok; +} + +/************************************************************************/ + +/* XXXbe this all needs to be reworked to avoid requiring JSScope types. */ + +JS_PUBLIC_API(JSScopeProperty *) +JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp) +{ + JSScopeProperty *sprop; + JSScope *scope; + + sprop = *iteratorp; + scope = OBJ_SCOPE(obj); + + /* XXXbe minor(?) incompatibility: iterate in reverse definition order */ + if (!sprop) { + sprop = SCOPE_LAST_PROP(scope); + } else { + while ((sprop = sprop->parent) != NULL) { + if (!SCOPE_HAD_MIDDLE_DELETE(scope)) + break; + if (SCOPE_HAS_PROPERTY(scope, sprop)) + break; + } + } + *iteratorp = sprop; + return sprop; +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, + JSPropertyDesc *pd) +{ + JSScope *scope; + JSScopeProperty *aprop; + jsval lastException; + JSBool wasThrowing; + + pd->id = ID_TO_VALUE(sprop->id); + + wasThrowing = cx->throwing; + if (wasThrowing) { + lastException = cx->exception; + if (JSVAL_IS_GCTHING(lastException) && + !js_AddRoot(cx, &lastException, "lastException")) { + return JS_FALSE; + } + cx->throwing = JS_FALSE; + } + + if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) { + if (!cx->throwing) { + pd->flags = JSPD_ERROR; + pd->value = JSVAL_VOID; + } else { + pd->flags = JSPD_EXCEPTION; + pd->value = cx->exception; + } + } else { + pd->flags = 0; + } + + cx->throwing = wasThrowing; + if (wasThrowing) { + cx->exception = lastException; + if (JSVAL_IS_GCTHING(lastException)) + js_RemoveRoot(cx->runtime, &lastException); + } + + pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0) + | ((sprop->attrs & JSPROP_READONLY) ? JSPD_READONLY : 0) + | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0); + pd->spare = 0; + if (sprop->getter == js_GetCallArg) { + pd->slot = sprop->shortid; + pd->flags |= JSPD_ARGUMENT; + } else if (sprop->getter == js_GetCallVar) { + pd->slot = sprop->shortid; + pd->flags |= JSPD_VARIABLE; + } else { + pd->slot = 0; + } + pd->alias = JSVAL_VOID; + scope = OBJ_SCOPE(obj); + if (SPROP_HAS_VALID_SLOT(sprop, scope)) { + for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) { + if (aprop != sprop && aprop->slot == sprop->slot) { + pd->alias = ID_TO_VALUE(aprop->id); + break; + } + } + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda) +{ + JSClass *clasp; + JSScope *scope; + uint32 i, n; + JSPropertyDesc *pd; + JSScopeProperty *sprop; + + clasp = OBJ_GET_CLASS(cx, obj); + if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_DESCRIBE_PROPS, clasp->name); + return JS_FALSE; + } + if (!clasp->enumerate(cx, obj)) + return JS_FALSE; + + /* have no props, or object's scope has not mutated from that of proto */ + scope = OBJ_SCOPE(obj); + if (scope->object != obj || scope->entryCount == 0) { + pda->length = 0; + pda->array = NULL; + return JS_TRUE; + } + + n = STOBJ_NSLOTS(obj); + if (n > scope->entryCount) + n = scope->entryCount; + pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc)); + if (!pd) + return JS_FALSE; + i = 0; + for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { + if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop)) + continue; + if (!js_AddRoot(cx, &pd[i].id, NULL)) + goto bad; + if (!js_AddRoot(cx, &pd[i].value, NULL)) + goto bad; + if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i])) + goto bad; + if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL)) + goto bad; + if (++i == n) + break; + } + pda->length = i; + pda->array = pd; + return JS_TRUE; + +bad: + pda->length = i + 1; + pda->array = pd; + JS_PutPropertyDescArray(cx, pda); + return JS_FALSE; +} + +JS_PUBLIC_API(void) +JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda) +{ + JSPropertyDesc *pd; + uint32 i; + + pd = pda->array; + for (i = 0; i < pda->length; i++) { + js_RemoveRoot(cx->runtime, &pd[i].id); + js_RemoveRoot(cx->runtime, &pd[i].value); + if (pd[i].flags & JSPD_ALIAS) + js_RemoveRoot(cx->runtime, &pd[i].alias); + } + JS_free(cx, pd); +} + +/************************************************************************/ + +JS_PUBLIC_API(JSBool) +JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure) +{ + rt->globalDebugHooks.debuggerHandler = handler; + rt->globalDebugHooks.debuggerHandlerData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure) +{ + rt->globalDebugHooks.sourceHandler = handler; + rt->globalDebugHooks.sourceHandlerData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) +{ + rt->globalDebugHooks.executeHook = hook; + rt->globalDebugHooks.executeHookData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) +{ + rt->globalDebugHooks.callHook = hook; + rt->globalDebugHooks.callHookData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure) +{ + rt->globalDebugHooks.objectHook = hook; + rt->globalDebugHooks.objectHookData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure) +{ + rt->globalDebugHooks.throwHook = hook; + rt->globalDebugHooks.throwHookData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure) +{ + rt->globalDebugHooks.debugErrorHook = hook; + rt->globalDebugHooks.debugErrorHookData = closure; + return JS_TRUE; +} + +/************************************************************************/ + +JS_PUBLIC_API(size_t) +JS_GetObjectTotalSize(JSContext *cx, JSObject *obj) +{ + size_t nbytes; + JSScope *scope; + + nbytes = sizeof *obj; + if (obj->dslots) { + nbytes += ((uint32)obj->dslots[-1] - JS_INITIAL_NSLOTS + 1) + * sizeof obj->dslots[0]; + } + if (OBJ_IS_NATIVE(obj)) { + scope = OBJ_SCOPE(obj); + if (scope->object == obj) { + nbytes += sizeof *scope; + nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *); + } + } + return nbytes; +} + +static size_t +GetAtomTotalSize(JSContext *cx, JSAtom *atom) +{ + size_t nbytes; + + nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub); + if (ATOM_IS_STRING(atom)) { + nbytes += sizeof(JSString); + nbytes += (JSFLATSTR_LENGTH(ATOM_TO_STRING(atom)) + 1) * sizeof(jschar); + } else if (ATOM_IS_DOUBLE(atom)) { + nbytes += sizeof(jsdouble); + } + return nbytes; +} + +JS_PUBLIC_API(size_t) +JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun) +{ + size_t nbytes; + + nbytes = sizeof *fun; + nbytes += JS_GetObjectTotalSize(cx, FUN_OBJECT(fun)); + if (FUN_INTERPRETED(fun)) + nbytes += JS_GetScriptTotalSize(cx, fun->u.i.script); + if (fun->atom) + nbytes += GetAtomTotalSize(cx, fun->atom); + return nbytes; +} + +#include "jsemit.h" + +JS_PUBLIC_API(size_t) +JS_GetScriptTotalSize(JSContext *cx, JSScript *script) +{ + size_t nbytes, pbytes; + jsatomid i; + jssrcnote *sn, *notes; + JSObjectArray *objarray; + JSPrincipals *principals; + + nbytes = sizeof *script; + if (script->u.object) + nbytes += JS_GetObjectTotalSize(cx, script->u.object); + + nbytes += script->length * sizeof script->code[0]; + nbytes += script->atomMap.length * sizeof script->atomMap.vector[0]; + for (i = 0; i < script->atomMap.length; i++) + nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]); + + if (script->filename) + nbytes += strlen(script->filename) + 1; + + notes = SCRIPT_NOTES(script); + for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) + continue; + nbytes += (sn - notes + 1) * sizeof *sn; + + if (script->objectsOffset != 0) { + objarray = JS_SCRIPT_OBJECTS(script); + i = objarray->length; + nbytes += sizeof *objarray + i * sizeof objarray->vector[0]; + do { + nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]); + } while (i != 0); + } + + if (script->regexpsOffset != 0) { + objarray = JS_SCRIPT_REGEXPS(script); + i = objarray->length; + nbytes += sizeof *objarray + i * sizeof objarray->vector[0]; + do { + nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]); + } while (i != 0); + } + + if (script->trynotesOffset != 0) { + nbytes += sizeof(JSTryNoteArray) + + JS_SCRIPT_TRYNOTES(script)->length * sizeof(JSTryNote); + } + + principals = script->principals; + if (principals) { + JS_ASSERT(principals->refcount); + pbytes = sizeof *principals; + if (principals->refcount > 1) + pbytes = JS_HOWMANY(pbytes, principals->refcount); + nbytes += pbytes; + } + + return nbytes; +} + +JS_PUBLIC_API(uint32) +JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp) +{ + if (!fp) + fp = cx->fp; + while (fp) { + if (fp->script) + return JS_GetScriptFilenameFlags(fp->script); + fp = fp->down; + } + return 0; + } + +JS_PUBLIC_API(uint32) +JS_GetScriptFilenameFlags(JSScript *script) +{ + JS_ASSERT(script); + if (!script->filename) + return JSFILENAME_NULL; + return js_GetScriptFilenameFlags(script->filename); +} + +JS_PUBLIC_API(JSBool) +JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags) +{ + if (!js_SaveScriptFilenameRT(rt, prefix, flags)) + return JS_FALSE; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_IsSystemObject(JSContext *cx, JSObject *obj) +{ + return STOBJ_IS_SYSTEM(obj); +} + +JS_PUBLIC_API(JSObject *) +JS_NewSystemObject(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent, JSBool system) +{ + JSObject *obj; + + obj = js_NewObject(cx, clasp, proto, parent, 0); + if (obj && system) + STOBJ_SET_SYSTEM(obj); + return obj; +} + +/************************************************************************/ + +JS_PUBLIC_API(JSDebugHooks *) +JS_GetGlobalDebugHooks(JSRuntime *rt) +{ + return &rt->globalDebugHooks; +} + +JS_PUBLIC_API(JSDebugHooks *) +JS_SetContextDebugHooks(JSContext *cx, JSDebugHooks *hooks) +{ + JSDebugHooks *old; + + JS_ASSERT(hooks); + old = cx->debugHooks; + cx->debugHooks = hooks; + return old; +} + +#ifdef MOZ_SHARK + +#include + +JS_PUBLIC_API(JSBool) +JS_StartChudRemote() +{ + if (chudIsRemoteAccessAcquired() && + (chudStartRemotePerfMonitor("Mozilla") == chudSuccess)) { + return JS_TRUE; + } + + return JS_FALSE; +} + +JS_PUBLIC_API(JSBool) +JS_StopChudRemote() +{ + if (chudIsRemoteAccessAcquired() && + (chudStopRemotePerfMonitor() == chudSuccess)) { + return JS_TRUE; + } + + return JS_FALSE; +} + +JS_PUBLIC_API(JSBool) +JS_ConnectShark() +{ + if (!chudIsInitialized() && (chudInitialize() != chudSuccess)) + return JS_FALSE; + + if (chudAcquireRemoteAccess() != chudSuccess) + return JS_FALSE; + + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_DisconnectShark() +{ + if (chudIsRemoteAccessAcquired() && (chudReleaseRemoteAccess() != chudSuccess)) + return JS_FALSE; + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_StartShark(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + if (!JS_StartChudRemote()) { + JS_ReportError(cx, "Error starting CHUD."); + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_StopShark(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + if (!JS_StopChudRemote()) { + JS_ReportError(cx, "Error stopping CHUD."); + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_ConnectShark(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + if (!JS_ConnectShark()) { + JS_ReportError(cx, "Error connecting to Shark."); + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_DisconnectShark(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + if (!JS_DisconnectShark()) { + JS_ReportError(cx, "Error disconnecting from Shark."); + } + + return JS_TRUE; +} + +#endif /* MOZ_SHARK */ + +#ifdef MOZ_CALLGRIND + +#include + +JS_FRIEND_API(JSBool) +js_StartCallgrind(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + CALLGRIND_START_INSTRUMENTATION; + CALLGRIND_ZERO_STATS; + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_StopCallgrind(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + CALLGRIND_STOP_INSTRUMENTATION; + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_DumpCallgrind(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + JSString *str; + char *cstr; + + if (argc > 0 && JSVAL_IS_STRING(argv[0])) { + str = JSVAL_TO_STRING(argv[0]); + cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str)); + if (cstr) { + CALLGRIND_DUMP_STATS_AT(cstr); + JS_free(cx, cstr); + return JS_TRUE; + } + } + CALLGRIND_DUMP_STATS; + + return JS_TRUE; +} + +#endif /* MOZ_CALLGRIND */ + +#ifdef MOZ_VTUNE +#include + +static const char *vtuneErrorMessages[] = { + "unknown, error #0", + "invalid 'max samples' field", + "invalid 'samples per buffer' field", + "invalid 'sample interval' field", + "invalid path", + "sample file in use", + "invalid 'number of events' field", + "unknown, error #7", + "internal error", + "bad event name", + "VTStopSampling called without calling VTStartSampling", + "no events selected for event-based sampling", + "events selected cannot be run together", + "no sampling parameters", + "sample database already exists", + "sampling already started", + "time-based sampling not supported", + "invalid 'sampling parameters size' field", + "invalid 'event size' field", + "sampling file already bound", + "invalid event path", + "invalid license", + "invalid 'global options' field", + +}; + +JS_FRIEND_API(JSBool) +js_StartVtune(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + VTUNE_EVENT events[] = { + { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" }, + { 1000000, 0, 0, 0, "INST_RETIRED.ANY" }, + }; + + U32 n_events = sizeof(events) / sizeof(VTUNE_EVENT); + char *default_filename = "mozilla-vtune.tb5"; + JSString *str; + U32 status; + + VTUNE_SAMPLING_PARAMS params = { + sizeof(VTUNE_SAMPLING_PARAMS), + sizeof(VTUNE_EVENT), + 0, 0, /* Reserved fields */ + 1, /* Initialize in "paused" state */ + 0, /* Max samples, or 0 for "continuous" */ + 4096, /* Samples per buffer */ + 0.1, /* Sampling interval in ms */ + 1, /* 1 for event-based sampling, 0 for time-based */ + + n_events, + events, + default_filename, + }; + + if (argc > 0 && JSVAL_IS_STRING(argv[0])) { + str = JSVAL_TO_STRING(argv[0]); + params.tb5Filename = js_DeflateString(cx, + JSSTRING_CHARS(str), + JSSTRING_LENGTH(str)); + } + + status = VTStartSampling(¶ms); + + if (params.tb5Filename != default_filename) + JS_free(cx, params.tb5Filename); + + if (status != 0) { + if (status == VTAPI_MULTIPLE_RUNS) + VTStopSampling(0); + if (status < sizeof(vtuneErrorMessages)) + JS_ReportError(cx, "Vtune setup error: %s", + vtuneErrorMessages[status]); + else + JS_ReportError(cx, "Vtune setup error: %d", + status); + return JS_FALSE; + } + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_StopVtune(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + U32 status = VTStopSampling(1); + if (status) { + if (status < sizeof(vtuneErrorMessages)) + JS_ReportError(cx, "Vtune shutdown error: %s", + vtuneErrorMessages[status]); + else + JS_ReportError(cx, "Vtune shutdown error: %d", + status); + return JS_FALSE; + } + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_PauseVtune(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + VTPause(); + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_ResumeVtune(JSContext *cx, JSObject *obj, + uintN argc, jsval *argv, jsval *rval) +{ + VTResume(); + return JS_TRUE; +} + +#endif /* MOZ_VTUNE */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdbgapi.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdbgapi.h new file mode 100644 index 0000000..b6855b2 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdbgapi.h @@ -0,0 +1,500 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsdbgapi_h___ +#define jsdbgapi_h___ +/* + * JS debugger API. + */ +#include "jsapi.h" +#include "jsopcode.h" +#include "jsprvtd.h" + +JS_BEGIN_EXTERN_C + +/* + * Unexported library-private helper used to unpatch all traps in a script. + * Returns script->code if script has no traps, else a JS_malloc'ed copy of + * script->code which the caller must JS_free, or null on JS_malloc OOM. + */ +extern jsbytecode * +js_UntrapScriptCode(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(JSBool) +JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, + JSTrapHandler handler, void *closure); + +extern JS_PUBLIC_API(JSOp) +JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc); + +extern JS_PUBLIC_API(void) +JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc, + JSTrapHandler *handlerp, void **closurep); + +extern JS_PUBLIC_API(void) +JS_ClearScriptTraps(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(void) +JS_ClearAllTraps(JSContext *cx); + +extern JS_PUBLIC_API(JSTrapStatus) +JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep); + +/************************************************************************/ + +extern JS_PUBLIC_API(JSBool) +JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id, + JSWatchPointHandler handler, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id, + JSWatchPointHandler *handlerp, void **closurep); + +extern JS_PUBLIC_API(JSBool) +JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_ClearAllWatchPoints(JSContext *cx); + +#ifdef JS_HAS_OBJ_WATCHPOINT +/* + * Hide these non-API function prototypes by testing whether the internal + * header file "jsversion.h" has been included. + */ +extern void +js_TraceWatchPoints(JSTracer *trc, JSObject *obj); + +extern void +js_SweepWatchPoints(JSContext *cx); + +extern JSScopeProperty * +js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id); + +/* + * NB: callers outside of jsdbgapi.c must pass non-null scope. + */ +extern JSPropertyOp +js_GetWatchedSetter(JSRuntime *rt, JSScope *scope, + const JSScopeProperty *sprop); + +extern JSBool +js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + +extern JSBool +js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JSPropertyOp +js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter); + +#endif /* JS_HAS_OBJ_WATCHPOINT */ + +/************************************************************************/ + +extern JS_PUBLIC_API(uintN) +JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc); + +extern JS_PUBLIC_API(jsbytecode *) +JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno); + +extern JS_PUBLIC_API(JSScript *) +JS_GetFunctionScript(JSContext *cx, JSFunction *fun); + +extern JS_PUBLIC_API(JSNative) +JS_GetFunctionNative(JSContext *cx, JSFunction *fun); + +extern JS_PUBLIC_API(JSFastNative) +JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun); + +extern JS_PUBLIC_API(JSPrincipals *) +JS_GetScriptPrincipals(JSContext *cx, JSScript *script); + +/* + * Stack Frame Iterator + * + * Used to iterate through the JS stack frames to extract + * information from the frames. + */ + +extern JS_PUBLIC_API(JSStackFrame *) +JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp); + +extern JS_PUBLIC_API(JSScript *) +JS_GetFrameScript(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(jsbytecode *) +JS_GetFramePC(JSContext *cx, JSStackFrame *fp); + +/* + * Get the closest scripted frame below fp. If fp is null, start from cx->fp. + */ +extern JS_PUBLIC_API(JSStackFrame *) +JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp); + +/* + * Return a weak reference to fp's principals. A null return does not denote + * an error, it means there are no principals. + */ +extern JS_PUBLIC_API(JSPrincipals *) +JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp); + +/* + * This API is like JS_StackFramePrincipals(cx, caller), except that if + * cx->runtime->findObjectPrincipals is non-null, it returns the weaker of + * the caller's principals and the object principals of fp's callee function + * object (fp->argv[-2]), which is eval, Function, or a similar eval-like + * method. The caller parameter should be JS_GetScriptedCaller(cx, fp). + * + * All eval-like methods must use JS_EvalFramePrincipals to acquire a weak + * reference to the correct principals for the eval call to be secure, given + * an embedding that calls JS_SetObjectPrincipalsFinder (see jsapi.h). + */ +extern JS_PUBLIC_API(JSPrincipals *) +JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller); + +extern JS_PUBLIC_API(void *) +JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(void) +JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation); + +extern JS_PUBLIC_API(void *) +JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSBool) +JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp); + +/* this is deprecated, use JS_GetFrameScopeChain instead */ +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameObject(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameThis(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSFunction *) +JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp); + +/* XXXrginda Initially published with typo */ +#define JS_IsContructorFrame JS_IsConstructorFrame +extern JS_PUBLIC_API(JSBool) +JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSBool) +JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(jsval) +JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(void) +JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval); + +/** + * Return fp's callee function object (fp->callee) if it has one. + */ +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp); + +/************************************************************************/ + +extern JS_PUBLIC_API(const char *) +JS_GetScriptFilename(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(uintN) +JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(uintN) +JS_GetScriptLineExtent(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(JSVersion) +JS_GetScriptVersion(JSContext *cx, JSScript *script); + +/************************************************************************/ + +/* + * Hook setters for script creation and destruction, see jsprvtd.h for the + * typedefs. These macros provide binary compatibility and newer, shorter + * synonyms. + */ +#define JS_SetNewScriptHook JS_SetNewScriptHookProc +#define JS_SetDestroyScriptHook JS_SetDestroyScriptHookProc + +extern JS_PUBLIC_API(void) +JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata); + +extern JS_PUBLIC_API(void) +JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook, + void *callerdata); + +/************************************************************************/ + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp, + const char *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +/************************************************************************/ + +typedef struct JSPropertyDesc { + jsval id; /* primary id, a string or int */ + jsval value; /* property value */ + uint8 flags; /* flags, see below */ + uint8 spare; /* unused */ + uint16 slot; /* argument/variable slot */ + jsval alias; /* alias id if JSPD_ALIAS flag */ +} JSPropertyDesc; + +#define JSPD_ENUMERATE 0x01 /* visible to for/in loop */ +#define JSPD_READONLY 0x02 /* assignment is error */ +#define JSPD_PERMANENT 0x04 /* property cannot be deleted */ +#define JSPD_ALIAS 0x08 /* property has an alias id */ +#define JSPD_ARGUMENT 0x10 /* argument to function */ +#define JSPD_VARIABLE 0x20 /* local variable in function */ +#define JSPD_EXCEPTION 0x40 /* exception occurred fetching the property, */ + /* value is exception */ +#define JSPD_ERROR 0x80 /* native getter returned JS_FALSE without */ + /* throwing an exception */ + +typedef struct JSPropertyDescArray { + uint32 length; /* number of elements in array */ + JSPropertyDesc *array; /* alloc'd by Get, freed by Put */ +} JSPropertyDescArray; + +extern JS_PUBLIC_API(JSScopeProperty *) +JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp); + +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, + JSPropertyDesc *pd); + +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda); + +extern JS_PUBLIC_API(void) +JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda); + +/************************************************************************/ + +extern JS_PUBLIC_API(JSBool) +JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure); + +/************************************************************************/ + +extern JS_PUBLIC_API(size_t) +JS_GetObjectTotalSize(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(size_t) +JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun); + +extern JS_PUBLIC_API(size_t) +JS_GetScriptTotalSize(JSContext *cx, JSScript *script); + +/* + * Get the top-most running script on cx starting from fp, or from the top of + * cx's frame stack if fp is null, and return its script filename flags. If + * the script has a null filename member, return JSFILENAME_NULL. + */ +extern JS_PUBLIC_API(uint32) +JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp); + +/* + * Get the script filename flags for the script. If the script doesn't have a + * filename, return JSFILENAME_NULL. + */ +extern JS_PUBLIC_API(uint32) +JS_GetScriptFilenameFlags(JSScript *script); + +/* + * Associate flags with a script filename prefix in rt, so that any subsequent + * script compilation will inherit those flags if the script's filename is the + * same as prefix, or if prefix is a substring of the script's filename. + * + * The API defines only one flag bit, JSFILENAME_SYSTEM, leaving the remaining + * 31 bits up to the API client to define. The union of all 32 bits must not + * be a legal combination, however, in order to preserve JSFILENAME_NULL as a + * unique value. API clients may depend on JSFILENAME_SYSTEM being a set bit + * in JSFILENAME_NULL -- a script with a null filename member is presumed to + * be a "system" script. + */ +extern JS_PUBLIC_API(JSBool) +JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags); + +#define JSFILENAME_NULL 0xffffffff /* null script filename */ +#define JSFILENAME_SYSTEM 0x00000001 /* "system" script, see below */ +#define JSFILENAME_PROTECTED 0x00000002 /* scripts need protection */ + +/* + * Return true if obj is a "system" object, that is, one created by + * JS_NewSystemObject with the system flag set and not JS_NewObject. + * + * What "system" means is up to the API client, but it can be used to implement + * access control policies based on script filenames and their prefixes, using + * JS_FlagScriptFilenamePrefix and JS_GetTopScriptFilenameFlags. + */ +extern JS_PUBLIC_API(JSBool) +JS_IsSystemObject(JSContext *cx, JSObject *obj); + +/* + * Call JS_NewObject(cx, clasp, proto, parent) and, if system is true, mark the + * result as a system object, that is an object for which JS_IsSystemObject + * returns true. + */ +extern JS_PUBLIC_API(JSObject *) +JS_NewSystemObject(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent, JSBool system); + +/************************************************************************/ + +extern JS_PUBLIC_API(JSDebugHooks *) +JS_GetGlobalDebugHooks(JSRuntime *rt); + +extern JS_PUBLIC_API(JSDebugHooks *) +JS_SetContextDebugHooks(JSContext *cx, JSDebugHooks *hooks); + +#ifdef MOZ_SHARK + +extern JS_PUBLIC_API(JSBool) +JS_StartChudRemote(); + +extern JS_PUBLIC_API(JSBool) +JS_StopChudRemote(); + +extern JS_PUBLIC_API(JSBool) +JS_ConnectShark(); + +extern JS_PUBLIC_API(JSBool) +JS_DisconnectShark(); + +extern JS_FRIEND_API(JSBool) +js_StopShark(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JS_FRIEND_API(JSBool) +js_StartShark(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JS_FRIEND_API(JSBool) +js_ConnectShark(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JS_FRIEND_API(JSBool) +js_DisconnectShark(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +#endif /* MOZ_SHARK */ + +#ifdef MOZ_CALLGRIND + +extern JS_FRIEND_API(JSBool) +js_StopCallgrind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JS_FRIEND_API(JSBool) +js_StartCallgrind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JS_FRIEND_API(JSBool) +js_DumpCallgrind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +#endif /* MOZ_CALLGRIND */ + +#ifdef MOZ_VTUNE + +extern JS_FRIEND_API(JSBool) +js_StartVtune(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JS_FRIEND_API(JSBool) +js_StopVtune(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JS_FRIEND_API(JSBool) +js_PauseVtune(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JS_FRIEND_API(JSBool) +js_ResumeVtune(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +#endif /* MOZ_VTUNE */ + +JS_END_EXTERN_C + +#endif /* jsdbgapi_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdhash.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdhash.cpp new file mode 100644 index 0000000..58cd440 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdhash.cpp @@ -0,0 +1,876 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla JavaScript code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (Original Author) + * Chris Waterson + * L. David Baron , Mozilla Corporation + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Double hashing implementation. + */ +#include +#include +#include +#include "jsbit.h" +#include "jsdhash.h" +#include "jsutil.h" /* for JS_ASSERT */ + +#ifdef JS_DHASHMETER +# if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan +# include "nsTraceMalloc.h" +# endif +# define METER(x) x +#else +# define METER(x) /* nothing */ +#endif + +/* + * The following DEBUG-only code is used to assert that calls to one of + * table->ops or to an enumerator do not cause re-entry into a call that + * can mutate the table. The recursion level is stored in additional + * space allocated at the end of the entry store to avoid changing + * JSDHashTable, which could cause issues when mixing DEBUG and + * non-DEBUG components. + */ +#ifdef DEBUG + +#define JSDHASH_ONELINE_ASSERT JS_ASSERT +#define RECURSION_LEVEL(table_) (*(uint32*)(table_->entryStore + \ + JS_DHASH_TABLE_SIZE(table_) * \ + table_->entrySize)) + +#define ENTRY_STORE_EXTRA sizeof(uint32) +#define INCREMENT_RECURSION_LEVEL(table_) \ + JS_BEGIN_MACRO \ + ++RECURSION_LEVEL(table_); \ + JS_END_MACRO +#define DECREMENT_RECURSION_LEVEL(table_) \ + JS_BEGIN_MACRO \ + JSDHASH_ONELINE_ASSERT(RECURSION_LEVEL(table_) > 0); \ + --RECURSION_LEVEL(table_); \ + JS_END_MACRO + +#else + +#define ENTRY_STORE_EXTRA 0 +#define INCREMENT_RECURSION_LEVEL(table_) JS_BEGIN_MACRO JS_END_MACRO +#define DECREMENT_RECURSION_LEVEL(table_) JS_BEGIN_MACRO JS_END_MACRO + +#endif /* defined(DEBUG) */ + +JS_PUBLIC_API(void *) +JS_DHashAllocTable(JSDHashTable *table, uint32 nbytes) +{ + return malloc(nbytes); +} + +JS_PUBLIC_API(void) +JS_DHashFreeTable(JSDHashTable *table, void *ptr) +{ + free(ptr); +} + +JS_PUBLIC_API(JSDHashNumber) +JS_DHashStringKey(JSDHashTable *table, const void *key) +{ + JSDHashNumber h; + const unsigned char *s; + + h = 0; + for (s = (const unsigned char *) key; *s != '\0'; s++) + h = JS_ROTATE_LEFT32(h, 4) ^ *s; + return h; +} + +JS_PUBLIC_API(JSDHashNumber) +JS_DHashVoidPtrKeyStub(JSDHashTable *table, const void *key) +{ + return (JSDHashNumber)(unsigned long)key >> 2; +} + +JS_PUBLIC_API(JSBool) +JS_DHashMatchEntryStub(JSDHashTable *table, + const JSDHashEntryHdr *entry, + const void *key) +{ + const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry; + + return stub->key == key; +} + +JS_PUBLIC_API(JSBool) +JS_DHashMatchStringKey(JSDHashTable *table, + const JSDHashEntryHdr *entry, + const void *key) +{ + const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry; + + /* XXX tolerate null keys on account of sloppy Mozilla callers. */ + return stub->key == key || + (stub->key && key && + strcmp((const char *) stub->key, (const char *) key) == 0); +} + +JS_PUBLIC_API(void) +JS_DHashMoveEntryStub(JSDHashTable *table, + const JSDHashEntryHdr *from, + JSDHashEntryHdr *to) +{ + memcpy(to, from, table->entrySize); +} + +JS_PUBLIC_API(void) +JS_DHashClearEntryStub(JSDHashTable *table, JSDHashEntryHdr *entry) +{ + memset(entry, 0, table->entrySize); +} + +JS_PUBLIC_API(void) +JS_DHashFreeStringKey(JSDHashTable *table, JSDHashEntryHdr *entry) +{ + const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry; + + free((void *) stub->key); + memset(entry, 0, table->entrySize); +} + +JS_PUBLIC_API(void) +JS_DHashFinalizeStub(JSDHashTable *table) +{ +} + +static const JSDHashTableOps stub_ops = { + JS_DHashAllocTable, + JS_DHashFreeTable, + JS_DHashVoidPtrKeyStub, + JS_DHashMatchEntryStub, + JS_DHashMoveEntryStub, + JS_DHashClearEntryStub, + JS_DHashFinalizeStub, + NULL +}; + +JS_PUBLIC_API(const JSDHashTableOps *) +JS_DHashGetStubOps(void) +{ + return &stub_ops; +} + +JS_PUBLIC_API(JSDHashTable *) +JS_NewDHashTable(const JSDHashTableOps *ops, void *data, uint32 entrySize, + uint32 capacity) +{ + JSDHashTable *table; + + table = (JSDHashTable *) malloc(sizeof *table); + if (!table) + return NULL; + if (!JS_DHashTableInit(table, ops, data, entrySize, capacity)) { + free(table); + return NULL; + } + return table; +} + +JS_PUBLIC_API(void) +JS_DHashTableDestroy(JSDHashTable *table) +{ + JS_DHashTableFinish(table); + free(table); +} + +JS_PUBLIC_API(JSBool) +JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data, + uint32 entrySize, uint32 capacity) +{ + int log2; + uint32 nbytes; + +#ifdef DEBUG + if (entrySize > 10 * sizeof(void *)) { + fprintf(stderr, + "jsdhash: for the table at address %p, the given entrySize" + " of %lu %s favors chaining over double hashing.\n", + (void *) table, + (unsigned long) entrySize, + (entrySize > 16 * sizeof(void*)) ? "definitely" : "probably"); + } +#endif + + table->ops = ops; + table->data = data; + if (capacity < JS_DHASH_MIN_SIZE) + capacity = JS_DHASH_MIN_SIZE; + + JS_CEILING_LOG2(log2, capacity); + + capacity = JS_BIT(log2); + if (capacity >= JS_DHASH_SIZE_LIMIT) + return JS_FALSE; + table->hashShift = JS_DHASH_BITS - log2; + table->maxAlphaFrac = (uint8)(0x100 * JS_DHASH_DEFAULT_MAX_ALPHA); + table->minAlphaFrac = (uint8)(0x100 * JS_DHASH_DEFAULT_MIN_ALPHA); + table->entrySize = entrySize; + table->entryCount = table->removedCount = 0; + table->generation = 0; + nbytes = capacity * entrySize; + + table->entryStore = (char *) ops->allocTable(table, + nbytes + ENTRY_STORE_EXTRA); + if (!table->entryStore) + return JS_FALSE; + memset(table->entryStore, 0, nbytes); + METER(memset(&table->stats, 0, sizeof table->stats)); + +#ifdef DEBUG + RECURSION_LEVEL(table) = 0; +#endif + + return JS_TRUE; +} + +/* + * Compute max and min load numbers (entry counts) from table params. + */ +#define MAX_LOAD(table, size) (((table)->maxAlphaFrac * (size)) >> 8) +#define MIN_LOAD(table, size) (((table)->minAlphaFrac * (size)) >> 8) + +JS_PUBLIC_API(void) +JS_DHashTableSetAlphaBounds(JSDHashTable *table, + float maxAlpha, + float minAlpha) +{ + uint32 size; + + /* + * Reject obviously insane bounds, rather than trying to guess what the + * buggy caller intended. + */ + JS_ASSERT(0.5 <= maxAlpha && maxAlpha < 1 && 0 <= minAlpha); + if (maxAlpha < 0.5 || 1 <= maxAlpha || minAlpha < 0) + return; + + /* + * Ensure that at least one entry will always be free. If maxAlpha at + * minimum size leaves no entries free, reduce maxAlpha based on minimum + * size and the precision limit of maxAlphaFrac's fixed point format. + */ + JS_ASSERT(JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) >= 1); + if (JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) < 1) { + maxAlpha = (float) + (JS_DHASH_MIN_SIZE - JS_MAX(JS_DHASH_MIN_SIZE / 256, 1)) + / JS_DHASH_MIN_SIZE; + } + + /* + * Ensure that minAlpha is strictly less than half maxAlpha. Take care + * not to truncate an entry's worth of alpha when storing in minAlphaFrac + * (8-bit fixed point format). + */ + JS_ASSERT(minAlpha < maxAlpha / 2); + if (minAlpha >= maxAlpha / 2) { + size = JS_DHASH_TABLE_SIZE(table); + minAlpha = (size * maxAlpha - JS_MAX(size / 256, 1)) / (2 * size); + } + + table->maxAlphaFrac = (uint8)(maxAlpha * 256); + table->minAlphaFrac = (uint8)(minAlpha * 256); +} + +/* + * Double hashing needs the second hash code to be relatively prime to table + * size, so we simply make hash2 odd. + */ +#define HASH1(hash0, shift) ((hash0) >> (shift)) +#define HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1) + +/* + * Reserve keyHash 0 for free entries and 1 for removed-entry sentinels. Note + * that a removed-entry sentinel need be stored only if the removed entry had + * a colliding entry added after it. Therefore we can use 1 as the collision + * flag in addition to the removed-entry sentinel value. Multiplicative hash + * uses the high order bits of keyHash, so this least-significant reservation + * should not hurt the hash function's effectiveness much. + * + * If you change any of these magic numbers, also update JS_DHASH_ENTRY_IS_LIVE + * in jsdhash.h. It used to be private to jsdhash.c, but then became public to + * assist iterator writers who inspect table->entryStore directly. + */ +#define COLLISION_FLAG ((JSDHashNumber) 1) +#define MARK_ENTRY_FREE(entry) ((entry)->keyHash = 0) +#define MARK_ENTRY_REMOVED(entry) ((entry)->keyHash = 1) +#define ENTRY_IS_REMOVED(entry) ((entry)->keyHash == 1) +#define ENTRY_IS_LIVE(entry) JS_DHASH_ENTRY_IS_LIVE(entry) +#define ENSURE_LIVE_KEYHASH(hash0) if (hash0 < 2) hash0 -= 2; else (void)0 + +/* Match an entry's keyHash against an unstored one computed from a key. */ +#define MATCH_ENTRY_KEYHASH(entry,hash0) \ + (((entry)->keyHash & ~COLLISION_FLAG) == (hash0)) + +/* Compute the address of the indexed entry in table. */ +#define ADDRESS_ENTRY(table, index) \ + ((JSDHashEntryHdr *)((table)->entryStore + (index) * (table)->entrySize)) + +JS_PUBLIC_API(void) +JS_DHashTableFinish(JSDHashTable *table) +{ + char *entryAddr, *entryLimit; + uint32 entrySize; + JSDHashEntryHdr *entry; + +#ifdef DEBUG_XXXbrendan + static FILE *dumpfp = NULL; + if (!dumpfp) dumpfp = fopen("/tmp/jsdhash.bigdump", "w"); + if (dumpfp) { +#ifdef MOZILLA_CLIENT + NS_TraceStack(1, dumpfp); +#endif + JS_DHashTableDumpMeter(table, NULL, dumpfp); + fputc('\n', dumpfp); + } +#endif + + INCREMENT_RECURSION_LEVEL(table); + + /* Call finalize before clearing entries, so it can enumerate them. */ + table->ops->finalize(table); + + /* Clear any remaining live entries. */ + entryAddr = table->entryStore; + entrySize = table->entrySize; + entryLimit = entryAddr + JS_DHASH_TABLE_SIZE(table) * entrySize; + while (entryAddr < entryLimit) { + entry = (JSDHashEntryHdr *)entryAddr; + if (ENTRY_IS_LIVE(entry)) { + METER(table->stats.removeEnums++); + table->ops->clearEntry(table, entry); + } + entryAddr += entrySize; + } + + DECREMENT_RECURSION_LEVEL(table); + JS_ASSERT(RECURSION_LEVEL(table) == 0); + + /* Free entry storage last. */ + table->ops->freeTable(table, table->entryStore); +} + +static JSDHashEntryHdr * JS_DHASH_FASTCALL +SearchTable(JSDHashTable *table, const void *key, JSDHashNumber keyHash, + JSDHashOperator op) +{ + JSDHashNumber hash1, hash2; + int hashShift, sizeLog2; + JSDHashEntryHdr *entry, *firstRemoved; + JSDHashMatchEntry matchEntry; + uint32 sizeMask; + + METER(table->stats.searches++); + JS_ASSERT(!(keyHash & COLLISION_FLAG)); + + /* Compute the primary hash address. */ + hashShift = table->hashShift; + hash1 = HASH1(keyHash, hashShift); + entry = ADDRESS_ENTRY(table, hash1); + + /* Miss: return space for a new entry. */ + if (JS_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return entry; + } + + /* Hit: return entry. */ + matchEntry = table->ops->matchEntry; + if (MATCH_ENTRY_KEYHASH(entry, keyHash) && matchEntry(table, entry, key)) { + METER(table->stats.hits++); + return entry; + } + + /* Collision: double hash. */ + sizeLog2 = JS_DHASH_BITS - table->hashShift; + hash2 = HASH2(keyHash, sizeLog2, hashShift); + sizeMask = JS_BITMASK(sizeLog2); + + /* Save the first removed entry pointer so JS_DHASH_ADD can recycle it. */ + firstRemoved = NULL; + + for (;;) { + if (JS_UNLIKELY(ENTRY_IS_REMOVED(entry))) { + if (!firstRemoved) + firstRemoved = entry; + } else { + if (op == JS_DHASH_ADD) + entry->keyHash |= COLLISION_FLAG; + } + + METER(table->stats.steps++); + hash1 -= hash2; + hash1 &= sizeMask; + + entry = ADDRESS_ENTRY(table, hash1); + if (JS_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return (firstRemoved && op == JS_DHASH_ADD) ? firstRemoved : entry; + } + + if (MATCH_ENTRY_KEYHASH(entry, keyHash) && + matchEntry(table, entry, key)) { + METER(table->stats.hits++); + return entry; + } + } + + /* NOTREACHED */ + return NULL; +} + +/* + * This is a copy of SearchTable, used by ChangeTable, hardcoded to + * 1. assume |op == PL_DHASH_ADD|, + * 2. assume that |key| will never match an existing entry, and + * 3. assume that no entries have been removed from the current table + * structure. + * Avoiding the need for |key| means we can avoid needing a way to map + * entries to keys, which means callers can use complex key types more + * easily. + */ +static JSDHashEntryHdr * JS_DHASH_FASTCALL +FindFreeEntry(JSDHashTable *table, JSDHashNumber keyHash) +{ + JSDHashNumber hash1, hash2; + int hashShift, sizeLog2; + JSDHashEntryHdr *entry; + uint32 sizeMask; + + METER(table->stats.searches++); + JS_ASSERT(!(keyHash & COLLISION_FLAG)); + + /* Compute the primary hash address. */ + hashShift = table->hashShift; + hash1 = HASH1(keyHash, hashShift); + entry = ADDRESS_ENTRY(table, hash1); + + /* Miss: return space for a new entry. */ + if (JS_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return entry; + } + + /* Collision: double hash. */ + sizeLog2 = JS_DHASH_BITS - table->hashShift; + hash2 = HASH2(keyHash, sizeLog2, hashShift); + sizeMask = JS_BITMASK(sizeLog2); + + for (;;) { + JS_ASSERT(!ENTRY_IS_REMOVED(entry)); + entry->keyHash |= COLLISION_FLAG; + + METER(table->stats.steps++); + hash1 -= hash2; + hash1 &= sizeMask; + + entry = ADDRESS_ENTRY(table, hash1); + if (JS_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return entry; + } + } + + /* NOTREACHED */ + return NULL; +} + +static JSBool +ChangeTable(JSDHashTable *table, int deltaLog2) +{ + int oldLog2, newLog2; + uint32 oldCapacity, newCapacity; + char *newEntryStore, *oldEntryStore, *oldEntryAddr; + uint32 entrySize, i, nbytes; + JSDHashEntryHdr *oldEntry, *newEntry; + JSDHashMoveEntry moveEntry; +#ifdef DEBUG + uint32 recursionLevel; +#endif + + /* Look, but don't touch, until we succeed in getting new entry store. */ + oldLog2 = JS_DHASH_BITS - table->hashShift; + newLog2 = oldLog2 + deltaLog2; + oldCapacity = JS_BIT(oldLog2); + newCapacity = JS_BIT(newLog2); + if (newCapacity >= JS_DHASH_SIZE_LIMIT) + return JS_FALSE; + entrySize = table->entrySize; + nbytes = newCapacity * entrySize; + + newEntryStore = (char *) table->ops->allocTable(table, + nbytes + ENTRY_STORE_EXTRA); + if (!newEntryStore) + return JS_FALSE; + + /* We can't fail from here on, so update table parameters. */ +#ifdef DEBUG + recursionLevel = RECURSION_LEVEL(table); +#endif + table->hashShift = JS_DHASH_BITS - newLog2; + table->removedCount = 0; + table->generation++; + + /* Assign the new entry store to table. */ + memset(newEntryStore, 0, nbytes); + oldEntryAddr = oldEntryStore = table->entryStore; + table->entryStore = newEntryStore; + moveEntry = table->ops->moveEntry; +#ifdef DEBUG + RECURSION_LEVEL(table) = recursionLevel; +#endif + + /* Copy only live entries, leaving removed ones behind. */ + for (i = 0; i < oldCapacity; i++) { + oldEntry = (JSDHashEntryHdr *)oldEntryAddr; + if (ENTRY_IS_LIVE(oldEntry)) { + oldEntry->keyHash &= ~COLLISION_FLAG; + newEntry = FindFreeEntry(table, oldEntry->keyHash); + JS_ASSERT(JS_DHASH_ENTRY_IS_FREE(newEntry)); + moveEntry(table, oldEntry, newEntry); + newEntry->keyHash = oldEntry->keyHash; + } + oldEntryAddr += entrySize; + } + + table->ops->freeTable(table, oldEntryStore); + return JS_TRUE; +} + +JS_PUBLIC_API(JSDHashEntryHdr *) JS_DHASH_FASTCALL +JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op) +{ + JSDHashNumber keyHash; + JSDHashEntryHdr *entry; + uint32 size; + int deltaLog2; + + JS_ASSERT(op == JS_DHASH_LOOKUP || RECURSION_LEVEL(table) == 0); + INCREMENT_RECURSION_LEVEL(table); + + keyHash = table->ops->hashKey(table, key); + keyHash *= JS_DHASH_GOLDEN_RATIO; + + /* Avoid 0 and 1 hash codes, they indicate free and removed entries. */ + ENSURE_LIVE_KEYHASH(keyHash); + keyHash &= ~COLLISION_FLAG; + + switch (op) { + case JS_DHASH_LOOKUP: + METER(table->stats.lookups++); + entry = SearchTable(table, key, keyHash, op); + break; + + case JS_DHASH_ADD: + /* + * If alpha is >= .75, grow or compress the table. If key is already + * in the table, we may grow once more than necessary, but only if we + * are on the edge of being overloaded. + */ + size = JS_DHASH_TABLE_SIZE(table); + if (table->entryCount + table->removedCount >= MAX_LOAD(table, size)) { + /* Compress if a quarter or more of all entries are removed. */ + if (table->removedCount >= size >> 2) { + METER(table->stats.compresses++); + deltaLog2 = 0; + } else { + METER(table->stats.grows++); + deltaLog2 = 1; + } + + /* + * Grow or compress table, returning null if ChangeTable fails and + * falling through might claim the last free entry. + */ + if (!ChangeTable(table, deltaLog2) && + table->entryCount + table->removedCount == size - 1) { + METER(table->stats.addFailures++); + entry = NULL; + break; + } + } + + /* + * Look for entry after possibly growing, so we don't have to add it, + * then skip it while growing the table and re-add it after. + */ + entry = SearchTable(table, key, keyHash, op); + if (!ENTRY_IS_LIVE(entry)) { + /* Initialize the entry, indicating that it's no longer free. */ + METER(table->stats.addMisses++); + if (ENTRY_IS_REMOVED(entry)) { + METER(table->stats.addOverRemoved++); + table->removedCount--; + keyHash |= COLLISION_FLAG; + } + if (table->ops->initEntry && + !table->ops->initEntry(table, entry, key)) { + /* We haven't claimed entry yet; fail with null return. */ + memset(entry + 1, 0, table->entrySize - sizeof *entry); + entry = NULL; + break; + } + entry->keyHash = keyHash; + table->entryCount++; + } + METER(else table->stats.addHits++); + break; + + case JS_DHASH_REMOVE: + entry = SearchTable(table, key, keyHash, op); + if (ENTRY_IS_LIVE(entry)) { + /* Clear this entry and mark it as "removed". */ + METER(table->stats.removeHits++); + JS_DHashTableRawRemove(table, entry); + + /* Shrink if alpha is <= .25 and table isn't too small already. */ + size = JS_DHASH_TABLE_SIZE(table); + if (size > JS_DHASH_MIN_SIZE && + table->entryCount <= MIN_LOAD(table, size)) { + METER(table->stats.shrinks++); + (void) ChangeTable(table, -1); + } + } + METER(else table->stats.removeMisses++); + entry = NULL; + break; + + default: + JS_ASSERT(0); + entry = NULL; + } + + DECREMENT_RECURSION_LEVEL(table); + + return entry; +} + +JS_PUBLIC_API(void) +JS_DHashTableRawRemove(JSDHashTable *table, JSDHashEntryHdr *entry) +{ + JSDHashNumber keyHash; /* load first in case clearEntry goofs it */ + + JS_ASSERT(JS_DHASH_ENTRY_IS_LIVE(entry)); + keyHash = entry->keyHash; + table->ops->clearEntry(table, entry); + if (keyHash & COLLISION_FLAG) { + MARK_ENTRY_REMOVED(entry); + table->removedCount++; + } else { + METER(table->stats.removeFrees++); + MARK_ENTRY_FREE(entry); + } + table->entryCount--; +} + +JS_PUBLIC_API(uint32) +JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg) +{ + char *entryAddr, *entryLimit; + uint32 i, capacity, entrySize, ceiling; + JSBool didRemove; + JSDHashEntryHdr *entry; + JSDHashOperator op; + + INCREMENT_RECURSION_LEVEL(table); + + entryAddr = table->entryStore; + entrySize = table->entrySize; + capacity = JS_DHASH_TABLE_SIZE(table); + entryLimit = entryAddr + capacity * entrySize; + i = 0; + didRemove = JS_FALSE; + while (entryAddr < entryLimit) { + entry = (JSDHashEntryHdr *)entryAddr; + if (ENTRY_IS_LIVE(entry)) { + op = etor(table, entry, i++, arg); + if (op & JS_DHASH_REMOVE) { + METER(table->stats.removeEnums++); + JS_DHashTableRawRemove(table, entry); + didRemove = JS_TRUE; + } + if (op & JS_DHASH_STOP) + break; + } + entryAddr += entrySize; + } + + JS_ASSERT(!didRemove || RECURSION_LEVEL(table) == 1); + + /* + * Shrink or compress if a quarter or more of all entries are removed, or + * if the table is underloaded according to the configured minimum alpha, + * and is not minimal-size already. Do this only if we removed above, so + * non-removing enumerations can count on stable table->entryStore until + * the next non-lookup-Operate or removing-Enumerate. + */ + if (didRemove && + (table->removedCount >= capacity >> 2 || + (capacity > JS_DHASH_MIN_SIZE && + table->entryCount <= MIN_LOAD(table, capacity)))) { + METER(table->stats.enumShrinks++); + capacity = table->entryCount; + capacity += capacity >> 1; + if (capacity < JS_DHASH_MIN_SIZE) + capacity = JS_DHASH_MIN_SIZE; + + JS_CEILING_LOG2(ceiling, capacity); + ceiling -= JS_DHASH_BITS - table->hashShift; + + (void) ChangeTable(table, ceiling); + } + + DECREMENT_RECURSION_LEVEL(table); + + return i; +} + +#ifdef JS_DHASHMETER +#include + +JS_PUBLIC_API(void) +JS_DHashTableDumpMeter(JSDHashTable *table, JSDHashEnumerator dump, FILE *fp) +{ + char *entryAddr; + uint32 entrySize, entryCount; + int hashShift, sizeLog2; + uint32 i, tableSize, sizeMask, chainLen, maxChainLen, chainCount; + JSDHashNumber hash1, hash2, saveHash1, maxChainHash1, maxChainHash2; + double sqsum, mean, variance, sigma; + JSDHashEntryHdr *entry, *probe; + + entryAddr = table->entryStore; + entrySize = table->entrySize; + hashShift = table->hashShift; + sizeLog2 = JS_DHASH_BITS - hashShift; + tableSize = JS_DHASH_TABLE_SIZE(table); + sizeMask = JS_BITMASK(sizeLog2); + chainCount = maxChainLen = 0; + hash2 = 0; + sqsum = 0; + + for (i = 0; i < tableSize; i++) { + entry = (JSDHashEntryHdr *)entryAddr; + entryAddr += entrySize; + if (!ENTRY_IS_LIVE(entry)) + continue; + hash1 = HASH1(entry->keyHash & ~COLLISION_FLAG, hashShift); + saveHash1 = hash1; + probe = ADDRESS_ENTRY(table, hash1); + chainLen = 1; + if (probe == entry) { + /* Start of a (possibly unit-length) chain. */ + chainCount++; + } else { + hash2 = HASH2(entry->keyHash & ~COLLISION_FLAG, sizeLog2, + hashShift); + do { + chainLen++; + hash1 -= hash2; + hash1 &= sizeMask; + probe = ADDRESS_ENTRY(table, hash1); + } while (probe != entry); + } + sqsum += chainLen * chainLen; + if (chainLen > maxChainLen) { + maxChainLen = chainLen; + maxChainHash1 = saveHash1; + maxChainHash2 = hash2; + } + } + + entryCount = table->entryCount; + if (entryCount && chainCount) { + mean = (double)entryCount / chainCount; + variance = chainCount * sqsum - entryCount * entryCount; + if (variance < 0 || chainCount == 1) + variance = 0; + else + variance /= chainCount * (chainCount - 1); + sigma = sqrt(variance); + } else { + mean = sigma = 0; + } + + fprintf(fp, "Double hashing statistics:\n"); + fprintf(fp, " table size (in entries): %u\n", tableSize); + fprintf(fp, " number of entries: %u\n", table->entryCount); + fprintf(fp, " number of removed entries: %u\n", table->removedCount); + fprintf(fp, " number of searches: %u\n", table->stats.searches); + fprintf(fp, " number of hits: %u\n", table->stats.hits); + fprintf(fp, " number of misses: %u\n", table->stats.misses); + fprintf(fp, " mean steps per search: %g\n", table->stats.searches ? + (double)table->stats.steps + / table->stats.searches : + 0.); + fprintf(fp, " mean hash chain length: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sigma); + fprintf(fp, " maximum hash chain length: %u\n", maxChainLen); + fprintf(fp, " number of lookups: %u\n", table->stats.lookups); + fprintf(fp, " adds that made a new entry: %u\n", table->stats.addMisses); + fprintf(fp, "adds that recycled removeds: %u\n", table->stats.addOverRemoved); + fprintf(fp, " adds that found an entry: %u\n", table->stats.addHits); + fprintf(fp, " add failures: %u\n", table->stats.addFailures); + fprintf(fp, " useful removes: %u\n", table->stats.removeHits); + fprintf(fp, " useless removes: %u\n", table->stats.removeMisses); + fprintf(fp, "removes that freed an entry: %u\n", table->stats.removeFrees); + fprintf(fp, " removes while enumerating: %u\n", table->stats.removeEnums); + fprintf(fp, " number of grows: %u\n", table->stats.grows); + fprintf(fp, " number of shrinks: %u\n", table->stats.shrinks); + fprintf(fp, " number of compresses: %u\n", table->stats.compresses); + fprintf(fp, "number of enumerate shrinks: %u\n", table->stats.enumShrinks); + + if (dump && maxChainLen && hash2) { + fputs("Maximum hash chain:\n", fp); + hash1 = maxChainHash1; + hash2 = maxChainHash2; + entry = ADDRESS_ENTRY(table, hash1); + i = 0; + do { + if (dump(table, entry, i++, fp) != JS_DHASH_NEXT) + break; + hash1 -= hash2; + hash1 &= sizeMask; + entry = ADDRESS_ENTRY(table, hash1); + } while (JS_DHASH_ENTRY_IS_BUSY(entry)); + } +} +#endif /* JS_DHASHMETER */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdhash.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdhash.h new file mode 100644 index 0000000..5e17b26 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdhash.h @@ -0,0 +1,588 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla JavaScript code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsdhash_h___ +#define jsdhash_h___ +/* + * Double hashing, a la Knuth 6. + */ +#include "jstypes.h" + +JS_BEGIN_EXTERN_C + +#if defined(__GNUC__) && defined(__i386__) && (__GNUC__ >= 3) && !defined(XP_OS2) +#define JS_DHASH_FASTCALL __attribute__ ((regparm (3),stdcall)) +#elif defined(XP_WIN) +#define JS_DHASH_FASTCALL __fastcall +#else +#define JS_DHASH_FASTCALL +#endif + +#ifdef DEBUG_XXXbrendan +#define JS_DHASHMETER 1 +#endif + +/* Table size limit, do not equal or exceed (see min&maxAlphaFrac, below). */ +#undef JS_DHASH_SIZE_LIMIT +#define JS_DHASH_SIZE_LIMIT JS_BIT(24) + +/* Minimum table size, or gross entry count (net is at most .75 loaded). */ +#ifndef JS_DHASH_MIN_SIZE +#define JS_DHASH_MIN_SIZE 16 +#elif (JS_DHASH_MIN_SIZE & (JS_DHASH_MIN_SIZE - 1)) != 0 +#error "JS_DHASH_MIN_SIZE must be a power of two!" +#endif + +/* + * Multiplicative hash uses an unsigned 32 bit integer and the golden ratio, + * expressed as a fixed-point 32-bit fraction. + */ +#define JS_DHASH_BITS 32 +#define JS_DHASH_GOLDEN_RATIO 0x9E3779B9U + +/* Primitive and forward-struct typedefs. */ +typedef uint32 JSDHashNumber; +typedef struct JSDHashEntryHdr JSDHashEntryHdr; +typedef struct JSDHashEntryStub JSDHashEntryStub; +typedef struct JSDHashTable JSDHashTable; +typedef struct JSDHashTableOps JSDHashTableOps; + +/* + * Table entry header structure. + * + * In order to allow in-line allocation of key and value, we do not declare + * either here. Instead, the API uses const void *key as a formal parameter. + * The key need not be stored in the entry; it may be part of the value, but + * need not be stored at all. + * + * Callback types are defined below and grouped into the JSDHashTableOps + * structure, for single static initialization per hash table sub-type. + * + * Each hash table sub-type should nest the JSDHashEntryHdr structure at the + * front of its particular entry type. The keyHash member contains the result + * of multiplying the hash code returned from the hashKey callback (see below) + * by JS_DHASH_GOLDEN_RATIO, then constraining the result to avoid the magic 0 + * and 1 values. The stored keyHash value is table size invariant, and it is + * maintained automatically by JS_DHashTableOperate -- users should never set + * it, and its only uses should be via the entry macros below. + * + * The JS_DHASH_ENTRY_IS_LIVE macro tests whether entry is neither free nor + * removed. An entry may be either busy or free; if busy, it may be live or + * removed. Consumers of this API should not access members of entries that + * are not live. + * + * However, use JS_DHASH_ENTRY_IS_BUSY for faster liveness testing of entries + * returned by JS_DHashTableOperate, as JS_DHashTableOperate never returns a + * non-live, busy (i.e., removed) entry pointer to its caller. See below for + * more details on JS_DHashTableOperate's calling rules. + */ +struct JSDHashEntryHdr { + JSDHashNumber keyHash; /* every entry must begin like this */ +}; + +#define JS_DHASH_ENTRY_IS_FREE(entry) ((entry)->keyHash == 0) +#define JS_DHASH_ENTRY_IS_BUSY(entry) (!JS_DHASH_ENTRY_IS_FREE(entry)) +#define JS_DHASH_ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2) + +/* + * A JSDHashTable is currently 8 words (without the JS_DHASHMETER overhead) + * on most architectures, and may be allocated on the stack or within another + * structure or class (see below for the Init and Finish functions to use). + * + * To decide whether to use double hashing vs. chaining, we need to develop a + * trade-off relation, as follows: + * + * Let alpha be the load factor, esize the entry size in words, count the + * entry count, and pow2 the power-of-two table size in entries. + * + * (JSDHashTable overhead) > (JSHashTable overhead) + * (unused table entry space) > (malloc and .next overhead per entry) + + * (buckets overhead) + * (1 - alpha) * esize * pow2 > 2 * count + pow2 + * + * Notice that alpha is by definition (count / pow2): + * + * (1 - alpha) * esize * pow2 > 2 * alpha * pow2 + pow2 + * (1 - alpha) * esize > 2 * alpha + 1 + * + * esize > (1 + 2 * alpha) / (1 - alpha) + * + * This assumes both tables must keep keyHash, key, and value for each entry, + * where key and value point to separately allocated strings or structures. + * If key and value can be combined into one pointer, then the trade-off is: + * + * esize > (1 + 3 * alpha) / (1 - alpha) + * + * If the entry value can be a subtype of JSDHashEntryHdr, rather than a type + * that must be allocated separately and referenced by an entry.value pointer + * member, and provided key's allocation can be fused with its entry's, then + * k (the words wasted per entry with chaining) is 4. + * + * To see these curves, feed gnuplot input like so: + * + * gnuplot> f(x,k) = (1 + k * x) / (1 - x) + * gnuplot> plot [0:.75] f(x,2), f(x,3), f(x,4) + * + * For k of 2 and a well-loaded table (alpha > .5), esize must be more than 4 + * words for chaining to be more space-efficient than double hashing. + * + * Solving for alpha helps us decide when to shrink an underloaded table: + * + * esize > (1 + k * alpha) / (1 - alpha) + * esize - alpha * esize > 1 + k * alpha + * esize - 1 > (k + esize) * alpha + * (esize - 1) / (k + esize) > alpha + * + * alpha < (esize - 1) / (esize + k) + * + * Therefore double hashing should keep alpha >= (esize - 1) / (esize + k), + * assuming esize is not too large (in which case, chaining should probably be + * used for any alpha). For esize=2 and k=3, we want alpha >= .2; for esize=3 + * and k=2, we want alpha >= .4. For k=4, esize could be 6, and alpha >= .5 + * would still obtain. See the JS_DHASH_MIN_ALPHA macro further below. + * + * The current implementation uses a configurable lower bound on alpha, which + * defaults to .25, when deciding to shrink the table (while still respecting + * JS_DHASH_MIN_SIZE). + * + * Note a qualitative difference between chaining and double hashing: under + * chaining, entry addresses are stable across table shrinks and grows. With + * double hashing, you can't safely hold an entry pointer and use it after an + * ADD or REMOVE operation, unless you sample table->generation before adding + * or removing, and compare the sample after, dereferencing the entry pointer + * only if table->generation has not changed. + * + * The moral of this story: there is no one-size-fits-all hash table scheme, + * but for small table entry size, and assuming entry address stability is not + * required, double hashing wins. + */ +struct JSDHashTable { + const JSDHashTableOps *ops; /* virtual operations, see below */ + void *data; /* ops- and instance-specific data */ + int16 hashShift; /* multiplicative hash shift */ + uint8 maxAlphaFrac; /* 8-bit fixed point max alpha */ + uint8 minAlphaFrac; /* 8-bit fixed point min alpha */ + uint32 entrySize; /* number of bytes in an entry */ + uint32 entryCount; /* number of entries in table */ + uint32 removedCount; /* removed entry sentinels in table */ + uint32 generation; /* entry storage generation number */ + char *entryStore; /* entry storage */ +#ifdef JS_DHASHMETER + struct JSDHashStats { + uint32 searches; /* total number of table searches */ + uint32 steps; /* hash chain links traversed */ + uint32 hits; /* searches that found key */ + uint32 misses; /* searches that didn't find key */ + uint32 lookups; /* number of JS_DHASH_LOOKUPs */ + uint32 addMisses; /* adds that miss, and do work */ + uint32 addOverRemoved; /* adds that recycled a removed entry */ + uint32 addHits; /* adds that hit an existing entry */ + uint32 addFailures; /* out-of-memory during add growth */ + uint32 removeHits; /* removes that hit, and do work */ + uint32 removeMisses; /* useless removes that miss */ + uint32 removeFrees; /* removes that freed entry directly */ + uint32 removeEnums; /* removes done by Enumerate */ + uint32 grows; /* table expansions */ + uint32 shrinks; /* table contractions */ + uint32 compresses; /* table compressions */ + uint32 enumShrinks; /* contractions after Enumerate */ + } stats; +#endif +}; + +/* + * Size in entries (gross, not net of free and removed sentinels) for table. + * We store hashShift rather than sizeLog2 to optimize the collision-free case + * in SearchTable. + */ +#define JS_DHASH_TABLE_SIZE(table) JS_BIT(JS_DHASH_BITS - (table)->hashShift) + +/* + * Table space at entryStore is allocated and freed using these callbacks. + * The allocator should return null on error only (not if called with nbytes + * equal to 0; but note that jsdhash.c code will never call with 0 nbytes). + */ +typedef void * +(* JSDHashAllocTable)(JSDHashTable *table, uint32 nbytes); + +typedef void +(* JSDHashFreeTable) (JSDHashTable *table, void *ptr); + +/* + * Compute the hash code for a given key to be looked up, added, or removed + * from table. A hash code may have any JSDHashNumber value. + */ +typedef JSDHashNumber +(* JSDHashHashKey) (JSDHashTable *table, const void *key); + +/* + * Compare the key identifying entry in table with the provided key parameter. + * Return JS_TRUE if keys match, JS_FALSE otherwise. + */ +typedef JSBool +(* JSDHashMatchEntry)(JSDHashTable *table, const JSDHashEntryHdr *entry, + const void *key); + +/* + * Copy the data starting at from to the new entry storage at to. Do not add + * reference counts for any strong references in the entry, however, as this + * is a "move" operation: the old entry storage at from will be freed without + * any reference-decrementing callback shortly. + */ +typedef void +(* JSDHashMoveEntry)(JSDHashTable *table, const JSDHashEntryHdr *from, + JSDHashEntryHdr *to); + +/* + * Clear the entry and drop any strong references it holds. This callback is + * invoked during a JS_DHASH_REMOVE operation (see below for operation codes), + * but only if the given key is found in the table. + */ +typedef void +(* JSDHashClearEntry)(JSDHashTable *table, JSDHashEntryHdr *entry); + +/* + * Called when a table (whether allocated dynamically by itself, or nested in + * a larger structure, or allocated on the stack) is finished. This callback + * allows table->ops-specific code to finalize table->data. + */ +typedef void +(* JSDHashFinalize) (JSDHashTable *table); + +/* + * Initialize a new entry, apart from keyHash. This function is called when + * JS_DHashTableOperate's JS_DHASH_ADD case finds no existing entry for the + * given key, and must add a new one. At that point, entry->keyHash is not + * set yet, to avoid claiming the last free entry in a severely overloaded + * table. + */ +typedef JSBool +(* JSDHashInitEntry)(JSDHashTable *table, JSDHashEntryHdr *entry, + const void *key); + +/* + * Finally, the "vtable" structure for JSDHashTable. The first eight hooks + * must be provided by implementations; they're called unconditionally by the + * generic jsdhash.c code. Hooks after these may be null. + * + * Summary of allocation-related hook usage with C++ placement new emphasis: + * allocTable Allocate raw bytes with malloc, no ctors run. + * freeTable Free raw bytes with free, no dtors run. + * initEntry Call placement new using default key-based ctor. + * Return JS_TRUE on success, JS_FALSE on error. + * moveEntry Call placement new using copy ctor, run dtor on old + * entry storage. + * clearEntry Run dtor on entry. + * finalize Stub unless table->data was initialized and needs to + * be finalized. + * + * Note the reason why initEntry is optional: the default hooks (stubs) clear + * entry storage: On successful JS_DHashTableOperate(tbl, key, JS_DHASH_ADD), + * the returned entry pointer addresses an entry struct whose keyHash member + * has been set non-zero, but all other entry members are still clear (null). + * JS_DHASH_ADD callers can test such members to see whether the entry was + * newly created by the JS_DHASH_ADD call that just succeeded. If placement + * new or similar initialization is required, define an initEntry hook. Of + * course, the clearEntry hook must zero or null appropriately. + * + * XXX assumes 0 is null for pointer types. + */ +struct JSDHashTableOps { + /* Mandatory hooks. All implementations must provide these. */ + JSDHashAllocTable allocTable; + JSDHashFreeTable freeTable; + JSDHashHashKey hashKey; + JSDHashMatchEntry matchEntry; + JSDHashMoveEntry moveEntry; + JSDHashClearEntry clearEntry; + JSDHashFinalize finalize; + + /* Optional hooks start here. If null, these are not called. */ + JSDHashInitEntry initEntry; +}; + +/* + * Default implementations for the above ops. + */ +extern JS_PUBLIC_API(void *) +JS_DHashAllocTable(JSDHashTable *table, uint32 nbytes); + +extern JS_PUBLIC_API(void) +JS_DHashFreeTable(JSDHashTable *table, void *ptr); + +extern JS_PUBLIC_API(JSDHashNumber) +JS_DHashStringKey(JSDHashTable *table, const void *key); + +/* A minimal entry contains a keyHash header and a void key pointer. */ +struct JSDHashEntryStub { + JSDHashEntryHdr hdr; + const void *key; +}; + +extern JS_PUBLIC_API(JSDHashNumber) +JS_DHashVoidPtrKeyStub(JSDHashTable *table, const void *key); + +extern JS_PUBLIC_API(JSBool) +JS_DHashMatchEntryStub(JSDHashTable *table, + const JSDHashEntryHdr *entry, + const void *key); + +extern JS_PUBLIC_API(JSBool) +JS_DHashMatchStringKey(JSDHashTable *table, + const JSDHashEntryHdr *entry, + const void *key); + +extern JS_PUBLIC_API(void) +JS_DHashMoveEntryStub(JSDHashTable *table, + const JSDHashEntryHdr *from, + JSDHashEntryHdr *to); + +extern JS_PUBLIC_API(void) +JS_DHashClearEntryStub(JSDHashTable *table, JSDHashEntryHdr *entry); + +extern JS_PUBLIC_API(void) +JS_DHashFreeStringKey(JSDHashTable *table, JSDHashEntryHdr *entry); + +extern JS_PUBLIC_API(void) +JS_DHashFinalizeStub(JSDHashTable *table); + +/* + * If you use JSDHashEntryStub or a subclass of it as your entry struct, and + * if your entries move via memcpy and clear via memset(0), you can use these + * stub operations. + */ +extern JS_PUBLIC_API(const JSDHashTableOps *) +JS_DHashGetStubOps(void); + +/* + * Dynamically allocate a new JSDHashTable using malloc, initialize it using + * JS_DHashTableInit, and return its address. Return null on malloc failure. + * Note that the entry storage at table->entryStore will be allocated using + * the ops->allocTable callback. + */ +extern JS_PUBLIC_API(JSDHashTable *) +JS_NewDHashTable(const JSDHashTableOps *ops, void *data, uint32 entrySize, + uint32 capacity); + +/* + * Finalize table's data, free its entry storage (via table->ops->freeTable), + * and return the memory starting at table to the malloc heap. + */ +extern JS_PUBLIC_API(void) +JS_DHashTableDestroy(JSDHashTable *table); + +/* + * Initialize table with ops, data, entrySize, and capacity. Capacity is a + * guess for the smallest table size at which the table will usually be less + * than 75% loaded (the table will grow or shrink as needed; capacity serves + * only to avoid inevitable early growth from JS_DHASH_MIN_SIZE). + */ +extern JS_PUBLIC_API(JSBool) +JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data, + uint32 entrySize, uint32 capacity); + +/* + * Set maximum and minimum alpha for table. The defaults are 0.75 and .25. + * maxAlpha must be in [0.5, 0.9375] for the default JS_DHASH_MIN_SIZE; or if + * MinSize=JS_DHASH_MIN_SIZE <= 256, in [0.5, (float)(MinSize-1)/MinSize]; or + * else in [0.5, 255.0/256]. minAlpha must be in [0, maxAlpha / 2), so that + * we don't shrink on the very next remove after growing a table upon adding + * an entry that brings entryCount past maxAlpha * tableSize. + */ +extern JS_PUBLIC_API(void) +JS_DHashTableSetAlphaBounds(JSDHashTable *table, + float maxAlpha, + float minAlpha); + +/* + * Call this macro with k, the number of pointer-sized words wasted per entry + * under chaining, to compute the minimum alpha at which double hashing still + * beats chaining. + */ +#define JS_DHASH_MIN_ALPHA(table, k) \ + ((float)((table)->entrySize / sizeof(void *) - 1) \ + / ((table)->entrySize / sizeof(void *) + (k))) + +/* + * Default max/min alpha, and macros to compute the value for the |capacity| + * parameter to JS_NewDHashTable and JS_DHashTableInit, given default or any + * max alpha, such that adding entryCount entries right after initializing the + * table will not require a reallocation (so JS_DHASH_ADD can't fail for those + * JS_DHashTableOperate calls). + * + * NB: JS_DHASH_CAP is a helper macro meant for use only in JS_DHASH_CAPACITY. + * Don't use it directly! + */ +#define JS_DHASH_DEFAULT_MAX_ALPHA 0.75 +#define JS_DHASH_DEFAULT_MIN_ALPHA 0.25 + +#define JS_DHASH_CAP(entryCount, maxAlpha) \ + ((uint32)((double)(entryCount) / (maxAlpha))) + +#define JS_DHASH_CAPACITY(entryCount, maxAlpha) \ + (JS_DHASH_CAP(entryCount, maxAlpha) + \ + (((JS_DHASH_CAP(entryCount, maxAlpha) * (uint8)(0x100 * (maxAlpha))) \ + >> 8) < (entryCount))) + +#define JS_DHASH_DEFAULT_CAPACITY(entryCount) \ + JS_DHASH_CAPACITY(entryCount, JS_DHASH_DEFAULT_MAX_ALPHA) + +/* + * Finalize table's data, free its entry storage using table->ops->freeTable, + * and leave its members unchanged from their last live values (which leaves + * pointers dangling). If you want to burn cycles clearing table, it's up to + * your code to call memset. + */ +extern JS_PUBLIC_API(void) +JS_DHashTableFinish(JSDHashTable *table); + +/* + * To consolidate keyHash computation and table grow/shrink code, we use a + * single entry point for lookup, add, and remove operations. The operation + * codes are declared here, along with codes returned by JSDHashEnumerator + * functions, which control JS_DHashTableEnumerate's behavior. + */ +typedef enum JSDHashOperator { + JS_DHASH_LOOKUP = 0, /* lookup entry */ + JS_DHASH_ADD = 1, /* add entry */ + JS_DHASH_REMOVE = 2, /* remove entry, or enumerator says remove */ + JS_DHASH_NEXT = 0, /* enumerator says continue */ + JS_DHASH_STOP = 1 /* enumerator says stop */ +} JSDHashOperator; + +/* + * To lookup a key in table, call: + * + * entry = JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP); + * + * If JS_DHASH_ENTRY_IS_BUSY(entry) is true, key was found and it identifies + * entry. If JS_DHASH_ENTRY_IS_FREE(entry) is true, key was not found. + * + * To add an entry identified by key to table, call: + * + * entry = JS_DHashTableOperate(table, key, JS_DHASH_ADD); + * + * If entry is null upon return, then either the table is severely overloaded, + * and memory can't be allocated for entry storage via table->ops->allocTable; + * Or if table->ops->initEntry is non-null, the table->ops->initEntry op may + * have returned false. + * + * Otherwise, entry->keyHash has been set so that JS_DHASH_ENTRY_IS_BUSY(entry) + * is true, and it is up to the caller to initialize the key and value parts + * of the entry sub-type, if they have not been set already (i.e. if entry was + * not already in the table, and if the optional initEntry hook was not used). + * + * To remove an entry identified by key from table, call: + * + * (void) JS_DHashTableOperate(table, key, JS_DHASH_REMOVE); + * + * If key's entry is found, it is cleared (via table->ops->clearEntry) and + * the entry is marked so that JS_DHASH_ENTRY_IS_FREE(entry). This operation + * returns null unconditionally; you should ignore its return value. + */ +extern JS_PUBLIC_API(JSDHashEntryHdr *) JS_DHASH_FASTCALL +JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op); + +/* + * Remove an entry already accessed via LOOKUP or ADD. + * + * NB: this is a "raw" or low-level routine, intended to be used only where + * the inefficiency of a full JS_DHashTableOperate (which rehashes in order + * to find the entry given its key) is not tolerable. This function does not + * shrink the table if it is underloaded. It does not update stats #ifdef + * JS_DHASHMETER, either. + */ +extern JS_PUBLIC_API(void) +JS_DHashTableRawRemove(JSDHashTable *table, JSDHashEntryHdr *entry); + +/* + * Enumerate entries in table using etor: + * + * count = JS_DHashTableEnumerate(table, etor, arg); + * + * JS_DHashTableEnumerate calls etor like so: + * + * op = etor(table, entry, number, arg); + * + * where number is a zero-based ordinal assigned to live entries according to + * their order in table->entryStore. + * + * The return value, op, is treated as a set of flags. If op is JS_DHASH_NEXT, + * then continue enumerating. If op contains JS_DHASH_REMOVE, then clear (via + * table->ops->clearEntry) and free entry. Then we check whether op contains + * JS_DHASH_STOP; if so, stop enumerating and return the number of live entries + * that were enumerated so far. Return the total number of live entries when + * enumeration completes normally. + * + * If etor calls JS_DHashTableOperate on table with op != JS_DHASH_LOOKUP, it + * must return JS_DHASH_STOP; otherwise undefined behavior results. + * + * If any enumerator returns JS_DHASH_REMOVE, table->entryStore may be shrunk + * or compressed after enumeration, but before JS_DHashTableEnumerate returns. + * Such an enumerator therefore can't safely set aside entry pointers, but an + * enumerator that never returns JS_DHASH_REMOVE can set pointers to entries + * aside, e.g., to avoid copying live entries into an array of the entry type. + * Copying entry pointers is cheaper, and safe so long as the caller of such a + * "stable" Enumerate doesn't use the set-aside pointers after any call either + * to PL_DHashTableOperate, or to an "unstable" form of Enumerate, which might + * grow or shrink entryStore. + * + * If your enumerator wants to remove certain entries, but set aside pointers + * to other entries that it retains, it can use JS_DHashTableRawRemove on the + * entries to be removed, returning JS_DHASH_NEXT to skip them. Likewise, if + * you want to remove entries, but for some reason you do not want entryStore + * to be shrunk or compressed, you can call JS_DHashTableRawRemove safely on + * the entry being enumerated, rather than returning JS_DHASH_REMOVE. + */ +typedef JSDHashOperator +(* JSDHashEnumerator)(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, + void *arg); + +extern JS_PUBLIC_API(uint32) +JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg); + +#ifdef JS_DHASHMETER +#include + +extern JS_PUBLIC_API(void) +JS_DHashTableDumpMeter(JSDHashTable *table, JSDHashEnumerator dump, FILE *fp); +#endif + +JS_END_EXTERN_C + +#endif /* jsdhash_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtoa.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtoa.cpp new file mode 100644 index 0000000..ca9176d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtoa.cpp @@ -0,0 +1,572 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Portable double to alphanumeric string and back converters. + */ +#include "jsstddef.h" +#include "jslibmath.h" +#include "jstypes.h" +#include "jsdtoa.h" +#include "jsprf.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jspubtd.h" +#include "jsnum.h" +#include "jsbit.h" + +#ifdef JS_THREADSAFE +#include "jslock.h" +#endif + +#ifdef IS_LITTLE_ENDIAN +#define IEEE_8087 +#else +#define IEEE_MC68k +#endif + +#ifndef Long +#define Long int32 +#endif + +#ifndef ULong +#define ULong uint32 +#endif + +/* +#ifndef Llong +#define Llong JSInt64 +#endif + +#ifndef ULlong +#define ULlong JSUint64 +#endif +*/ + +#ifdef JS_THREADSAFE +static PRLock *dtoalock; +static JSBool _dtoainited = JS_FALSE; + +#define LOCK_DTOA() PR_Lock(dtoalock); +#define UNLOCK_DTOA() PR_Unlock(dtoalock) +#else +#define LOCK_DTOA() +#define UNLOCK_DTOA() +#endif +#include "dtoa.c" + +JS_FRIEND_API(JSBool) +js_InitDtoa() +{ +#ifdef JS_THREADSAFE + if (!_dtoainited) { + dtoalock = PR_NewLock(); + JS_ASSERT(dtoalock); + _dtoainited = JS_TRUE; + } + + return (dtoalock != 0); +#else + return JS_TRUE; +#endif +} + +JS_FRIEND_API(void) +js_FinishDtoa() +{ +#ifdef JS_THREADSAFE + if (_dtoainited) { + PR_DestroyLock(dtoalock); + dtoalock = NULL; + _dtoainited = JS_FALSE; + } +#endif +} + +/* Mapping of JSDToStrMode -> js_dtoa mode */ +static const uint8 dtoaModes[] = { + 0, /* DTOSTR_STANDARD */ + 0, /* DTOSTR_STANDARD_EXPONENTIAL, */ + 3, /* DTOSTR_FIXED, */ + 2, /* DTOSTR_EXPONENTIAL, */ + 2}; /* DTOSTR_PRECISION */ + +JS_FRIEND_API(double) +JS_strtod(const char *s00, char **se, int *err) +{ + double retval; + if (err) + *err = 0; + LOCK_DTOA(); + retval = _strtod(s00, se); + UNLOCK_DTOA(); + return retval; +} + +JS_FRIEND_API(char *) +JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, double dinput) +{ + U d; + int decPt; /* Offset of decimal point from first digit */ + int sign; /* Nonzero if the sign bit was set in d */ + int nDigits; /* Number of significand digits returned by js_dtoa */ + char *numBegin; /* Pointer to the digits returned by js_dtoa */ + char *numEnd = 0; /* Pointer past the digits returned by js_dtoa */ + + JS_ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL + ? DTOSTR_STANDARD_BUFFER_SIZE + : DTOSTR_VARIABLE_BUFFER_SIZE(precision))); + + /* + * Change mode here rather than below because the buffer may not be large + * enough to hold a large integer. + */ + if (mode == DTOSTR_FIXED && (dinput >= 1e21 || dinput <= -1e21)) + mode = DTOSTR_STANDARD; + + LOCK_DTOA(); + dval(d) = dinput; + numBegin = dtoa(d, dtoaModes[mode], precision, &decPt, &sign, &numEnd); + if (!numBegin) { + UNLOCK_DTOA(); + return NULL; + } + + nDigits = numEnd - numBegin; + JS_ASSERT((size_t) nDigits <= bufferSize - 2); + if ((size_t) nDigits > bufferSize - 2) { + UNLOCK_DTOA(); + return NULL; + } + + memcpy(buffer + 2, numBegin, nDigits); + freedtoa(numBegin); + UNLOCK_DTOA(); + numBegin = buffer + 2; /* +2 leaves space for sign and/or decimal point */ + numEnd = numBegin + nDigits; + *numEnd = '\0'; + + /* If Infinity, -Infinity, or NaN, return the string regardless of mode. */ + if (decPt != 9999) { + JSBool exponentialNotation = JS_FALSE; + int minNDigits = 0; /* Min number of significant digits required */ + char *p; + char *q; + + switch (mode) { + case DTOSTR_STANDARD: + if (decPt < -5 || decPt > 21) + exponentialNotation = JS_TRUE; + else + minNDigits = decPt; + break; + + case DTOSTR_FIXED: + if (precision >= 0) + minNDigits = decPt + precision; + else + minNDigits = decPt; + break; + + case DTOSTR_EXPONENTIAL: + JS_ASSERT(precision > 0); + minNDigits = precision; + /* Fall through */ + case DTOSTR_STANDARD_EXPONENTIAL: + exponentialNotation = JS_TRUE; + break; + + case DTOSTR_PRECISION: + JS_ASSERT(precision > 0); + minNDigits = precision; + if (decPt < -5 || decPt > precision) + exponentialNotation = JS_TRUE; + break; + } + + /* If the number has fewer than minNDigits, end-pad it with zeros. */ + if (nDigits < minNDigits) { + p = numBegin + minNDigits; + nDigits = minNDigits; + do { + *numEnd++ = '0'; + } while (numEnd != p); + *numEnd = '\0'; + } + + if (exponentialNotation) { + /* Insert a decimal point if more than one significand digit */ + if (nDigits != 1) { + numBegin--; + numBegin[0] = numBegin[1]; + numBegin[1] = '.'; + } + JS_snprintf(numEnd, bufferSize - (numEnd - buffer), "e%+d", decPt-1); + } else if (decPt != nDigits) { + /* Some kind of a fraction in fixed notation */ + JS_ASSERT(decPt <= nDigits); + if (decPt > 0) { + /* dd...dd . dd...dd */ + p = --numBegin; + do { + *p = p[1]; + p++; + } while (--decPt); + *p = '.'; + } else { + /* 0 . 00...00dd...dd */ + p = numEnd; + numEnd += 1 - decPt; + q = numEnd; + JS_ASSERT(numEnd < buffer + bufferSize); + *numEnd = '\0'; + while (p != numBegin) + *--q = *--p; + for (p = numBegin + 1; p != q; p++) + *p = '0'; + *numBegin = '.'; + *--numBegin = '0'; + } + } + } + + /* If negative and neither -0.0 nor NaN, output a leading '-'. */ + if (sign && + !(word0(d) == Sign_bit && word1(d) == 0) && + !((word0(d) & Exp_mask) == Exp_mask && + (word1(d) || (word0(d) & Frac_mask)))) { + *--numBegin = '-'; + } + return numBegin; +} + + +/* Let b = floor(b / divisor), and return the remainder. b must be nonnegative. + * divisor must be between 1 and 65536. + * This function cannot run out of memory. */ +static uint32 +divrem(Bigint *b, uint32 divisor) +{ + int32 n = b->wds; + uint32 remainder = 0; + ULong *bx; + ULong *bp; + + JS_ASSERT(divisor > 0 && divisor <= 65536); + + if (!n) + return 0; /* b is zero */ + bx = b->x; + bp = bx + n; + do { + ULong a = *--bp; + ULong dividend = remainder << 16 | a >> 16; + ULong quotientHi = dividend / divisor; + ULong quotientLo; + + remainder = dividend - quotientHi*divisor; + JS_ASSERT(quotientHi <= 0xFFFF && remainder < divisor); + dividend = remainder << 16 | (a & 0xFFFF); + quotientLo = dividend / divisor; + remainder = dividend - quotientLo*divisor; + JS_ASSERT(quotientLo <= 0xFFFF && remainder < divisor); + *bp = quotientHi << 16 | quotientLo; + } while (bp != bx); + /* Decrease the size of the number if its most significant word is now zero. */ + if (bx[n-1] == 0) + b->wds--; + return remainder; +} + +/* Return floor(b/2^k) and set b to be the remainder. The returned quotient must be less than 2^32. */ +static uint32 quorem2(Bigint *b, int32 k) +{ + ULong mask; + ULong result; + ULong *bx, *bxe; + int32 w; + int32 n = k >> 5; + k &= 0x1F; + mask = (1<wds - n; + if (w <= 0) + return 0; + JS_ASSERT(w <= 2); + bx = b->x; + bxe = bx + n; + result = *bxe >> k; + *bxe &= mask; + if (w == 2) { + JS_ASSERT(!(bxe[1] & ~mask)); + if (k) + result |= bxe[1] << (32 - k); + } + n++; + while (!*bxe && bxe != bx) { + n--; + bxe--; + } + b->wds = n; + return result; +} + + +/* "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce, + * which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of + * the output string and malloc fewer bytes depending on d and base, but why bother? */ +#define DTOBASESTR_BUFFER_SIZE 1078 +#define BASEDIGIT(digit) ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit))) + +JS_FRIEND_API(char *) +JS_dtobasestr(int base, double dinput) +{ + U d; + char *buffer; /* The output string */ + char *p; /* Pointer to current position in the buffer */ + char *pInt; /* Pointer to the beginning of the integer part of the string */ + char *q; + uint32 digit; + U di; /* d truncated to an integer */ + U df; /* The fractional part of d */ + + JS_ASSERT(base >= 2 && base <= 36); + + dval(d) = dinput; + buffer = (char*) malloc(DTOBASESTR_BUFFER_SIZE); + if (buffer) { + p = buffer; + if (dval(d) < 0.0 +#if defined(XP_WIN) || defined(XP_OS2) + && !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) /* Visual C++ doesn't know how to compare against NaN */ +#endif + ) { + *p++ = '-'; + dval(d) = -dval(d); + } + + /* Check for Infinity and NaN */ + if ((word0(d) & Exp_mask) == Exp_mask) { + strcpy(p, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN"); + return buffer; + } + + LOCK_DTOA(); + /* Output the integer part of d with the digits in reverse order. */ + pInt = p; + dval(di) = floor(dval(d)); + if (dval(di) <= 4294967295.0) { + uint32 n = (uint32)dval(di); + if (n) + do { + uint32 m = n / base; + digit = n - m*base; + n = m; + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (n); + else *p++ = '0'; + } else { + int e; + int bits; /* Number of significant bits in di; not used. */ + Bigint *b = d2b(di, &e, &bits); + if (!b) + goto nomem1; + b = lshift(b, e); + if (!b) { + nomem1: + Bfree(b); + UNLOCK_DTOA(); + free(buffer); + return NULL; + } + do { + digit = divrem(b, base); + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (b->wds); + Bfree(b); + } + /* Reverse the digits of the integer part of d. */ + q = p-1; + while (q > pInt) { + char ch = *pInt; + *pInt++ = *q; + *q-- = ch; + } + + dval(df) = dval(d) - dval(di); + if (dval(df) != 0.0) { + /* We have a fraction. */ + int e, bbits; + int32 s2, done; + Bigint *b, *s, *mlo, *mhi; + + b = s = mlo = mhi = NULL; + + *p++ = '.'; + b = d2b(df, &e, &bbits); + if (!b) { + nomem2: + Bfree(b); + Bfree(s); + if (mlo != mhi) + Bfree(mlo); + Bfree(mhi); + UNLOCK_DTOA(); + free(buffer); + return NULL; + } + JS_ASSERT(e < 0); + /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */ + + s2 = -(int32)(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1); +#ifndef Sudden_Underflow + if (!s2) + s2 = -1; +#endif + s2 += Bias + P; + /* 1/2^s2 = (nextDouble(d) - d)/2 */ + JS_ASSERT(-s2 < e); + mlo = i2b(1); + if (!mlo) + goto nomem2; + mhi = mlo; + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & Exp_mask << 1) +#endif + ) { + /* The special case. Here we want to be within a quarter of the last input + significant digit instead of one half of it when the output string's value is less than d. */ + s2 += Log2P; + mhi = i2b(1< df = b/2^s2 > 0; + * (d - prevDouble(d))/2 = mlo/2^s2; + * (nextDouble(d) - d)/2 = mhi/2^s2. */ + + done = JS_FALSE; + do { + int32 j, j1; + Bigint *delta; + + b = multadd(b, base, 0); + if (!b) + goto nomem2; + digit = quorem2(b, s2); + if (mlo == mhi) { + mlo = mhi = multadd(mlo, base, 0); + if (!mhi) + goto nomem2; + } + else { + mlo = multadd(mlo, base, 0); + if (!mlo) + goto nomem2; + mhi = multadd(mhi, base, 0); + if (!mhi) + goto nomem2; + } + + /* Do we yet have the shortest string that will round to d? */ + j = cmp(b, mlo); + /* j is b/2^s2 compared with mlo/2^s2. */ + delta = diff(s, mhi); + if (!delta) + goto nomem2; + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); + /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */ + +#ifndef ROUND_BIASED + if (j1 == 0 && !(word1(d) & 1)) { + if (j > 0) + digit++; + done = JS_TRUE; + } else +#endif + if (j < 0 || (j == 0 +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + )) { + if (j1 > 0) { + /* Either dig or dig+1 would work here as the least significant digit. + Use whichever would produce an output value closer to d. */ + b = lshift(b, 1); + if (!b) + goto nomem2; + j1 = cmp(b, s); + if (j1 > 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output + * such as 3.5 in base 3. */ + digit++; + } + done = JS_TRUE; + } else if (j1 > 0) { + digit++; + done = JS_TRUE; + } + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (!done); + Bfree(b); + Bfree(s); + if (mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + JS_ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE); + *p = '\0'; + UNLOCK_DTOA(); + } + return buffer; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtoa.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtoa.h new file mode 100644 index 0000000..b074c9a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtoa.h @@ -0,0 +1,131 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsdtoa_h___ +#define jsdtoa_h___ +/* + * Public interface to portable double-precision floating point to string + * and back conversion package. + */ + +#include "jscompat.h" + +JS_BEGIN_EXTERN_C + +/* + * JS_strtod() returns as a double-precision floating-point number + * the value represented by the character string pointed to by + * s00. The string is scanned up to the first unrecognized + * character. + * If the value of se is not (char **)NULL, a pointer to + * the character terminating the scan is returned in the location pointed + * to by se. If no number can be formed, se is set to s00r, and + * zero is returned. + * + * *err is set to zero on success; it's set to JS_DTOA_ERANGE on range + * errors and JS_DTOA_ENOMEM on memory failure. + */ +#define JS_DTOA_ERANGE 1 +#define JS_DTOA_ENOMEM 2 +JS_FRIEND_API(double) +JS_strtod(const char *s00, char **se, int *err); + +/* + * Modes for converting floating-point numbers to strings. + * + * Some of the modes can round-trip; this means that if the number is converted to + * a string using one of these mode and then converted back to a number, the result + * will be identical to the original number (except that, due to ECMA, -0 will get converted + * to +0). These round-trip modes return the minimum number of significand digits that + * permit the round trip. + * + * Some of the modes take an integer parameter . + */ +/* NB: Keep this in sync with number_constants[]. */ +typedef enum JSDToStrMode { + DTOSTR_STANDARD, /* Either fixed or exponential format; round-trip */ + DTOSTR_STANDARD_EXPONENTIAL, /* Always exponential format; round-trip */ + DTOSTR_FIXED, /* Round to digits after the decimal point; exponential if number is large */ + DTOSTR_EXPONENTIAL, /* Always exponential format; significant digits */ + DTOSTR_PRECISION /* Either fixed or exponential format; significant digits */ +} JSDToStrMode; + + +/* Maximum number of characters (including trailing null) that a DTOSTR_STANDARD or DTOSTR_STANDARD_EXPONENTIAL + * conversion can produce. This maximum is reached for a number like -0.0000012345678901234567. */ +#define DTOSTR_STANDARD_BUFFER_SIZE 26 + +/* Maximum number of characters (including trailing null) that one of the other conversions + * can produce. This maximum is reached for TO_FIXED, which can generate up to 21 digits before the decimal point. */ +#define DTOSTR_VARIABLE_BUFFER_SIZE(precision) ((precision)+24 > DTOSTR_STANDARD_BUFFER_SIZE ? (precision)+24 : DTOSTR_STANDARD_BUFFER_SIZE) + +/* + * Convert dval according to the given mode and return a pointer to the resulting ASCII string. + * The result is held somewhere in buffer, but not necessarily at the beginning. The size of + * buffer is given in bufferSize, and must be at least as large as given by the above macros. + * + * Return NULL if out of memory. + */ +JS_FRIEND_API(char *) +JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, double dval); + +/* + * Convert d to a string in the given base. The integral part of d will be printed exactly + * in that base, regardless of how large it is, because there is no exponential notation for non-base-ten + * numbers. The fractional part will be rounded to as few digits as possible while still preserving + * the round-trip property (analogous to that of printing decimal numbers). In other words, if one were + * to read the resulting string in via a hypothetical base-number-reading routine that rounds to the nearest + * IEEE double (and to an even significand if there are two equally near doubles), then the result would + * equal d (except for -0.0, which converts to "0", and NaN, which is not equal to itself). + * + * Return NULL if out of memory. If the result is not NULL, it must be released via free(). + */ +JS_FRIEND_API(char *) +JS_dtobasestr(int base, double d); + +/* + * Clean up any persistent RAM allocated during the execution of DtoA + * routines, and remove any locks that might have been created. + */ +JS_FRIEND_API(JSBool) js_InitDtoa(void); +JS_FRIEND_API(void) js_FinishDtoa(void); + +JS_END_EXTERN_C + +#endif /* jsdtoa_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtracef.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtracef.c new file mode 100644 index 0000000..8d95b39 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtracef.c @@ -0,0 +1,318 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Copyright (C) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsapi.h" +#include "jsutil.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsdbgapi.h" +#include "jsfun.h" +#include "jsinterp.h" +#include "jsobj.h" +#include "jsscript.h" +#include "jsstr.h" + +#include "jsdtracef.h" +#include + +#define TYPEOF(cx,v) (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v)) + +static char dempty[] = ""; + +char * +jsdtrace_funcclass_name(JSFunction *fun) +{ + return (!FUN_INTERPRETED(fun) && + !(fun->flags & JSFUN_TRACEABLE) && + FUN_CLASP(fun)) + ? (char *)FUN_CLASP(fun)->name + : dempty; +} + +char * +jsdtrace_filename(JSStackFrame *fp) +{ + while (fp && fp->script == NULL) + fp = fp->down; + return (fp && fp->script && fp->script->filename) + ? (char *)fp->script->filename + : dempty; +} + +int +jsdtrace_linenumber(JSContext *cx, JSStackFrame *fp) +{ + while (fp && fp->script == NULL) + fp = fp->down; + return (fp && fp->regs) + ? (int) js_PCToLineNumber(cx, fp->script, fp->regs->pc) + : -1; +} + +/* + * This function is used to convert function arguments and return value (jsval) + * into the following based on each value's type tag: + * + * jsval returned + * ------------------- + * STRING -> char * + * INT -> int + * DOUBLE -> double * + * BOOLEAN -> int + * OBJECT -> void * + * + * All are presented as void * for DTrace consumers to use, after shifting or + * masking out the JavaScript type bits. This allows D scripts to use ints and + * booleans directly and copyinstr() for string arguments, when types are known + * beforehand. + * + * This is used by the function-args and function-rval probes, which also + * provide raw (unmasked) jsvals should type info be useful from D scripts. + */ +void * +jsdtrace_jsvaltovoid(JSContext *cx, jsval argval) +{ + JSType type = TYPEOF(cx, argval); + + switch (type) { + case JSTYPE_NULL: + case JSTYPE_VOID: + return (void *)JS_TYPE_STR(type); + + case JSTYPE_BOOLEAN: + return (void *)JSVAL_TO_BOOLEAN(argval); + + case JSTYPE_STRING: + return (void *)js_GetStringBytes(cx, JSVAL_TO_STRING(argval)); + + case JSTYPE_NUMBER: + if (JSVAL_IS_INT(argval)) + return (void *)JSVAL_TO_INT(argval); + return JSVAL_TO_DOUBLE(argval); + + default: + return JSVAL_TO_GCTHING(argval); + } + /* NOTREACHED */ +} + +char * +jsdtrace_function_name(JSContext *cx, JSStackFrame *fp, JSFunction *fun) +{ + JSAtom *atom; + JSFrameRegs *regs; + JSScript *script; + jsbytecode *pc; + char *name; + + atom = fun->atom; + if (!atom) { + if (fp->fun != fun || !fp->down) + return dempty; + + regs = fp->down->regs; + if (!regs) + return dempty; + + /* + * An anonymous function called from an active script or interpreted + * function: try to fetch the variable or property name by which the + * anonymous function was invoked. + */ + pc = regs->pc; + script = fp->down->script; + switch ((JSOp) *pc) { + case JSOP_CALL: + case JSOP_EVAL: + JS_ASSERT(fp->argv == regs->sp - (int)GET_ARGC(pc)); + + /* + * FIXME bug 422864: update this code to use the pc stack from the + * decompiler. + */ + break; + default: ; + } + + switch ((JSOp) *pc) { + case JSOP_CALLNAME: + case JSOP_CALLPROP: + case JSOP_NAME: + case JSOP_SETNAME: + case JSOP_GETPROP: + case JSOP_SETPROP: + GET_ATOM_FROM_BYTECODE(script, pc, 0, atom); + break; + + case JSOP_CALLELEM: + case JSOP_GETELEM: + case JSOP_SETELEM: + case JSOP_CALLGVAR: + case JSOP_GETGVAR: + case JSOP_SETGVAR: + case JSOP_CALLARG: + case JSOP_CALLLOCAL: + /* FIXME: try to recover a name from these ops. */ + /* FALL THROUGH */ + + default: + return dempty; + } + } + + name = (char *)js_GetStringBytes(cx, ATOM_TO_STRING(atom)); + return name ? name : dempty; +} + +/* + * These functions call the DTrace macros for the JavaScript USDT probes. + * Originally this code was inlined in the JavaScript code; however since + * a number of operations are called, these have been placed into functions + * to reduce any negative compiler optimization effect that the addition of + * a number of usually unused lines of code would cause. + */ +void +jsdtrace_function_entry(JSContext *cx, JSStackFrame *fp, JSFunction *fun) +{ + JAVASCRIPT_FUNCTION_ENTRY( + jsdtrace_filename(fp), + jsdtrace_funcclass_name(fun), + jsdtrace_function_name(cx, fp, fun) + ); +} + +void +jsdtrace_function_info(JSContext *cx, JSStackFrame *fp, JSStackFrame *dfp, + JSFunction *fun) +{ + JAVASCRIPT_FUNCTION_INFO( + jsdtrace_filename(fp), + jsdtrace_funcclass_name(fun), + jsdtrace_function_name(cx, fp, fun), + fp->script->lineno, + jsdtrace_filename(dfp), + jsdtrace_linenumber(cx, dfp) + ); +} + +void +jsdtrace_function_args(JSContext *cx, JSStackFrame *fp, JSFunction *fun) +{ + JAVASCRIPT_FUNCTION_ARGS( + jsdtrace_filename(fp), + jsdtrace_funcclass_name(fun), + jsdtrace_function_name(cx, fp, fun), + fp->argc, (void *)fp->argv, + (fp->argc > 0) ? jsdtrace_jsvaltovoid(cx, fp->argv[0]) : 0, + (fp->argc > 1) ? jsdtrace_jsvaltovoid(cx, fp->argv[1]) : 0, + (fp->argc > 2) ? jsdtrace_jsvaltovoid(cx, fp->argv[2]) : 0, + (fp->argc > 3) ? jsdtrace_jsvaltovoid(cx, fp->argv[3]) : 0, + (fp->argc > 4) ? jsdtrace_jsvaltovoid(cx, fp->argv[4]) : 0 + ); +} + +void +jsdtrace_function_rval(JSContext *cx, JSStackFrame *fp, JSFunction *fun) +{ + JAVASCRIPT_FUNCTION_RVAL( + jsdtrace_filename(fp), + jsdtrace_funcclass_name(fun), + jsdtrace_function_name(cx, fp, fun), + jsdtrace_linenumber(cx, fp), (void *)fp->rval, + jsdtrace_jsvaltovoid(cx, fp->rval) + ); +} + +void +jsdtrace_function_return(JSContext *cx, JSStackFrame *fp, JSFunction *fun) +{ + JAVASCRIPT_FUNCTION_RETURN( + jsdtrace_filename(fp), + jsdtrace_funcclass_name(fun), + jsdtrace_function_name(cx, fp, fun) + ); +} + +void +jsdtrace_object_create_start(JSStackFrame *fp, JSClass *clasp) +{ + JAVASCRIPT_OBJECT_CREATE_START(jsdtrace_filename(fp), (char *)clasp->name); +} + +void +jsdtrace_object_create_done(JSStackFrame *fp, JSClass *clasp) +{ + JAVASCRIPT_OBJECT_CREATE_DONE(jsdtrace_filename(fp), (char *)clasp->name); +} + +void +jsdtrace_object_create(JSContext *cx, JSClass *clasp, JSObject *obj) +{ + JAVASCRIPT_OBJECT_CREATE( + jsdtrace_filename(cx->fp), + (char *)clasp->name, + (uintptr_t)obj, + jsdtrace_linenumber(cx, cx->fp) + ); +} + +void +jsdtrace_object_finalize(JSObject *obj) +{ + JSClass *clasp; + + clasp = LOCKED_OBJ_GET_CLASS(obj); + + /* the first arg is NULL - reserved for future use (filename?) */ + JAVASCRIPT_OBJECT_FINALIZE(NULL, (char *)clasp->name, (uintptr_t)obj); +} + +void +jsdtrace_execute_start(JSScript *script) +{ + JAVASCRIPT_EXECUTE_START( + script->filename ? (char *)script->filename : dempty, + script->lineno + ); +} + +void +jsdtrace_execute_done(JSScript *script) +{ + JAVASCRIPT_EXECUTE_DONE( + script->filename ? (char *)script->filename : dempty, + script->lineno + ); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtracef.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtracef.h new file mode 100644 index 0000000..08f3098 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsdtracef.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Copyright (C) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "javascript-trace.h" +#include "jspubtd.h" +#include "jsprvtd.h" + +#ifndef _JSDTRACEF_H +#define _JSDTRACEF_H + +JS_BEGIN_EXTERN_C + +extern void +jsdtrace_function_entry(JSContext *cx, JSStackFrame *fp, JSFunction *fun); + +extern void +jsdtrace_function_info(JSContext *cx, JSStackFrame *fp, JSStackFrame *dfp, + JSFunction *fun); + +extern void +jsdtrace_function_args(JSContext *cx, JSStackFrame *fp, JSFunction *fun); + +extern void +jsdtrace_function_rval(JSContext *cx, JSStackFrame *fp, JSFunction *fun); + +extern void +jsdtrace_function_return(JSContext *cx, JSStackFrame *fp, JSFunction *fun); + +extern void +jsdtrace_object_create_start(JSStackFrame *fp, JSClass *clasp); + +extern void +jsdtrace_object_create_done(JSStackFrame *fp, JSClass *clasp); + +extern void +jsdtrace_object_create(JSContext *cx, JSClass *clasp, JSObject *obj); + +extern void +jsdtrace_object_finalize(JSObject *obj); + +extern void +jsdtrace_execute_start(JSScript *script); + +extern void +jsdtrace_execute_done(JSScript *script); + +JS_END_EXTERN_C + +#endif /* _JSDTRACE_H */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsemit.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsemit.cpp new file mode 100644 index 0000000..3d2269b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsemit.cpp @@ -0,0 +1,6857 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS bytecode generation. + */ +#include "jsstddef.h" +#ifdef HAVE_MEMORY_H +#include +#endif +#include +#include "jstypes.h" +#include "jsarena.h" /* Added by JSIFY */ +#include "jsutil.h" /* Added by JSIFY */ +#include "jsbit.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsnum.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsregexp.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsautooplen.h" +#include "jsstaticcheck.h" + +/* Allocation chunk counts, must be powers of two in general. */ +#define BYTECODE_CHUNK 256 /* code allocation increment */ +#define SRCNOTE_CHUNK 64 /* initial srcnote allocation increment */ +#define TRYNOTE_CHUNK 64 /* trynote allocation increment */ + +/* Macros to compute byte sizes from typed element counts. */ +#define BYTECODE_SIZE(n) ((n) * sizeof(jsbytecode)) +#define SRCNOTE_SIZE(n) ((n) * sizeof(jssrcnote)) +#define TRYNOTE_SIZE(n) ((n) * sizeof(JSTryNote)) + +static JSBool +NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, + uintN stackDepth, size_t start, size_t end); + +JS_FRIEND_API(void) +js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc, + JSArenaPool *codePool, JSArenaPool *notePool, + uintN lineno) +{ + memset(cg, 0, sizeof *cg); + TREE_CONTEXT_INIT(&cg->treeContext, pc); + cg->codePool = codePool; + cg->notePool = notePool; + cg->codeMark = JS_ARENA_MARK(codePool); + cg->noteMark = JS_ARENA_MARK(notePool); + cg->current = &cg->main; + cg->firstLine = cg->prolog.currentLine = cg->main.currentLine = lineno; + ATOM_LIST_INIT(&cg->atomList); + cg->prolog.noteMask = cg->main.noteMask = SRCNOTE_CHUNK - 1; + ATOM_LIST_INIT(&cg->constList); + ATOM_LIST_INIT(&cg->upvarList); +} + +JS_FRIEND_API(void) +js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg) +{ + TREE_CONTEXT_FINISH(cx, &cg->treeContext); + JS_ARENA_RELEASE(cg->codePool, cg->codeMark); + JS_ARENA_RELEASE(cg->notePool, cg->noteMark); + + /* NB: non-null only after OOM. */ + if (cg->spanDeps) + JS_free(cx, cg->spanDeps); + + if (cg->upvarMap.vector) + JS_free(cx, cg->upvarMap.vector); +} + +static ptrdiff_t +EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta) +{ + jsbytecode *base, *limit, *next; + ptrdiff_t offset, length; + size_t incr, size; + + base = CG_BASE(cg); + next = CG_NEXT(cg); + limit = CG_LIMIT(cg); + offset = PTRDIFF(next, base, jsbytecode); + if (next + delta > limit) { + length = offset + delta; + length = (length <= BYTECODE_CHUNK) + ? BYTECODE_CHUNK + : JS_BIT(JS_CeilingLog2(length)); + incr = BYTECODE_SIZE(length); + if (!base) { + JS_ARENA_ALLOCATE_CAST(base, jsbytecode *, cg->codePool, incr); + } else { + size = BYTECODE_SIZE(PTRDIFF(limit, base, jsbytecode)); + incr -= size; + JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr); + } + if (!base) { + js_ReportOutOfScriptQuota(cx); + return -1; + } + CG_BASE(cg) = base; + CG_LIMIT(cg) = base + length; + CG_NEXT(cg) = base + offset; + } + return offset; +} + +static void +UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) +{ + jsbytecode *pc; + JSOp op; + const JSCodeSpec *cs; + uintN depth; + intN nuses, ndefs; + + pc = CG_CODE(cg, target); + op = (JSOp) *pc; + cs = &js_CodeSpec[op]; + if (cs->format & JOF_TMPSLOT_MASK) { + depth = (uintN) cg->stackDepth + + ((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT); + if (depth > cg->maxStackDepth) + cg->maxStackDepth = depth; + } + nuses = cs->nuses; + if (nuses < 0) + nuses = js_GetVariableStackUseLength(op, pc); + cg->stackDepth -= nuses; + JS_ASSERT(cg->stackDepth >= 0); + if (cg->stackDepth < 0) { + char numBuf[12]; + JSTokenStream *ts; + + JS_snprintf(numBuf, sizeof numBuf, "%d", target); + ts = &cg->treeContext.parseContext->tokenStream; + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, + js_GetErrorMessage, NULL, + JSMSG_STACK_UNDERFLOW, + ts->filename ? ts->filename : "stdin", + numBuf); + } + ndefs = cs->ndefs; + if (ndefs < 0) { + JSObject *blockObj; + + /* We just executed IndexParsedObject */ + JS_ASSERT(op == JSOP_ENTERBLOCK); + JS_ASSERT(nuses == 0); + blockObj = cg->objectList.lastPob->object; + JS_ASSERT(STOBJ_GET_CLASS(blockObj) == &js_BlockClass); + JS_ASSERT(JSVAL_IS_VOID(blockObj->fslots[JSSLOT_BLOCK_DEPTH])); + + OBJ_SET_BLOCK_DEPTH(cx, blockObj, cg->stackDepth); + ndefs = OBJ_BLOCK_COUNT(cx, blockObj); + } + cg->stackDepth += ndefs; + if ((uintN)cg->stackDepth > cg->maxStackDepth) + cg->maxStackDepth = cg->stackDepth; +} + +ptrdiff_t +js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op) +{ + ptrdiff_t offset = EmitCheck(cx, cg, op, 1); + + if (offset >= 0) { + *CG_NEXT(cg)++ = (jsbytecode)op; + UpdateDepth(cx, cg, offset); + } + return offset; +} + +ptrdiff_t +js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1) +{ + ptrdiff_t offset = EmitCheck(cx, cg, op, 2); + + if (offset >= 0) { + jsbytecode *next = CG_NEXT(cg); + next[0] = (jsbytecode)op; + next[1] = op1; + CG_NEXT(cg) = next + 2; + UpdateDepth(cx, cg, offset); + } + return offset; +} + +ptrdiff_t +js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1, + jsbytecode op2) +{ + ptrdiff_t offset = EmitCheck(cx, cg, op, 3); + + if (offset >= 0) { + jsbytecode *next = CG_NEXT(cg); + next[0] = (jsbytecode)op; + next[1] = op1; + next[2] = op2; + CG_NEXT(cg) = next + 3; + UpdateDepth(cx, cg, offset); + } + return offset; +} + +ptrdiff_t +js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra) +{ + ptrdiff_t length = 1 + (ptrdiff_t)extra; + ptrdiff_t offset = EmitCheck(cx, cg, op, length); + + if (offset >= 0) { + jsbytecode *next = CG_NEXT(cg); + *next = (jsbytecode)op; + memset(next + 1, 0, BYTECODE_SIZE(extra)); + CG_NEXT(cg) = next + length; + + /* + * Don't UpdateDepth if op's use-count comes from the immediate + * operand yet to be stored in the extra bytes after op. + */ + if (js_CodeSpec[op].nuses >= 0) + UpdateDepth(cx, cg, offset); + } + return offset; +} + +/* XXX too many "... statement" L10N gaffes below -- fix via js.msg! */ +const char js_with_statement_str[] = "with statement"; +const char js_finally_block_str[] = "finally block"; +const char js_script_str[] = "script"; + +static const char *statementName[] = { + "label statement", /* LABEL */ + "if statement", /* IF */ + "else statement", /* ELSE */ + "destructuring body", /* BODY */ + "switch statement", /* SWITCH */ + "block", /* BLOCK */ + js_with_statement_str, /* WITH */ + "catch block", /* CATCH */ + "try block", /* TRY */ + js_finally_block_str, /* FINALLY */ + js_finally_block_str, /* SUBROUTINE */ + "do loop", /* DO_LOOP */ + "for loop", /* FOR_LOOP */ + "for/in loop", /* FOR_IN_LOOP */ + "while loop", /* WHILE_LOOP */ +}; + +JS_STATIC_ASSERT(JS_ARRAY_LENGTH(statementName) == STMT_LIMIT); + +static const char * +StatementName(JSCodeGenerator *cg) +{ + if (!cg->treeContext.topStmt) + return js_script_str; + return statementName[cg->treeContext.topStmt->type]; +} + +static void +ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET, + StatementName(cg)); +} + +/** + Span-dependent instructions in JS bytecode consist of the jump (JOF_JUMP) + and switch (JOF_LOOKUPSWITCH, JOF_TABLESWITCH) format opcodes, subdivided + into unconditional (gotos and gosubs), and conditional jumps or branches + (which pop a value, test it, and jump depending on its value). Most jumps + have just one immediate operand, a signed offset from the jump opcode's pc + to the target bytecode. The lookup and table switch opcodes may contain + many jump offsets. + + Mozilla bug #80981 (http://bugzilla.mozilla.org/show_bug.cgi?id=80981) was + fixed by adding extended "X" counterparts to the opcodes/formats (NB: X is + suffixed to prefer JSOP_ORX thereby avoiding a JSOP_XOR name collision for + the extended form of the JSOP_OR branch opcode). The unextended or short + formats have 16-bit signed immediate offset operands, the extended or long + formats have 32-bit signed immediates. The span-dependency problem consists + of selecting as few long instructions as possible, or about as few -- since + jumps can span other jumps, extending one jump may cause another to need to + be extended. + + Most JS scripts are short, so need no extended jumps. We optimize for this + case by generating short jumps until we know a long jump is needed. After + that point, we keep generating short jumps, but each jump's 16-bit immediate + offset operand is actually an unsigned index into cg->spanDeps, an array of + JSSpanDep structs. Each struct tells the top offset in the script of the + opcode, the "before" offset of the jump (which will be the same as top for + simplex jumps, but which will index further into the bytecode array for a + non-initial jump offset in a lookup or table switch), the after "offset" + adjusted during span-dependent instruction selection (initially the same + value as the "before" offset), and the jump target (more below). + + Since we generate cg->spanDeps lazily, from within js_SetJumpOffset, we must + ensure that all bytecode generated so far can be inspected to discover where + the jump offset immediate operands lie within CG_CODE(cg). But the bonus is + that we generate span-dependency records sorted by their offsets, so we can + binary-search when trying to find a JSSpanDep for a given bytecode offset, + or the nearest JSSpanDep at or above a given pc. + + To avoid limiting scripts to 64K jumps, if the cg->spanDeps index overflows + 65534, we store SPANDEP_INDEX_HUGE in the jump's immediate operand. This + tells us that we need to binary-search for the cg->spanDeps entry by the + jump opcode's bytecode offset (sd->before). + + Jump targets need to be maintained in a data structure that lets us look + up an already-known target by its address (jumps may have a common target), + and that also lets us update the addresses (script-relative, a.k.a. absolute + offsets) of targets that come after a jump target (for when a jump below + that target needs to be extended). We use an AVL tree, implemented using + recursion, but with some tricky optimizations to its height-balancing code + (see http://www.cmcrossroads.com/bradapp/ftp/src/libs/C++/AvlTrees.html). + + A final wrinkle: backpatch chains are linked by jump-to-jump offsets with + positive sign, even though they link "backward" (i.e., toward lower bytecode + address). We don't want to waste space and search time in the AVL tree for + such temporary backpatch deltas, so we use a single-bit wildcard scheme to + tag true JSJumpTarget pointers and encode untagged, signed (positive) deltas + in JSSpanDep.target pointers, depending on whether the JSSpanDep has a known + target, or is still awaiting backpatching. + + Note that backpatch chains would present a problem for BuildSpanDepTable, + which inspects bytecode to build cg->spanDeps on demand, when the first + short jump offset overflows. To solve this temporary problem, we emit a + proxy bytecode (JSOP_BACKPATCH; JSOP_BACKPATCH_POP for branch ops) whose + nuses/ndefs counts help keep the stack balanced, but whose opcode format + distinguishes its backpatch delta immediate operand from a normal jump + offset. + */ +static int +BalanceJumpTargets(JSJumpTarget **jtp) +{ + JSJumpTarget *jt, *jt2, *root; + int dir, otherDir, heightChanged; + JSBool doubleRotate; + + jt = *jtp; + JS_ASSERT(jt->balance != 0); + + if (jt->balance < -1) { + dir = JT_RIGHT; + doubleRotate = (jt->kids[JT_LEFT]->balance > 0); + } else if (jt->balance > 1) { + dir = JT_LEFT; + doubleRotate = (jt->kids[JT_RIGHT]->balance < 0); + } else { + return 0; + } + + otherDir = JT_OTHER_DIR(dir); + if (doubleRotate) { + jt2 = jt->kids[otherDir]; + *jtp = root = jt2->kids[dir]; + + jt->kids[otherDir] = root->kids[dir]; + root->kids[dir] = jt; + + jt2->kids[dir] = root->kids[otherDir]; + root->kids[otherDir] = jt2; + + heightChanged = 1; + root->kids[JT_LEFT]->balance = -JS_MAX(root->balance, 0); + root->kids[JT_RIGHT]->balance = -JS_MIN(root->balance, 0); + root->balance = 0; + } else { + *jtp = root = jt->kids[otherDir]; + jt->kids[otherDir] = root->kids[dir]; + root->kids[dir] = jt; + + heightChanged = (root->balance != 0); + jt->balance = -((dir == JT_LEFT) ? --root->balance : ++root->balance); + } + + return heightChanged; +} + +typedef struct AddJumpTargetArgs { + JSContext *cx; + JSCodeGenerator *cg; + ptrdiff_t offset; + JSJumpTarget *node; +} AddJumpTargetArgs; + +static int +AddJumpTarget(AddJumpTargetArgs *args, JSJumpTarget **jtp) +{ + JSJumpTarget *jt; + int balanceDelta; + + jt = *jtp; + if (!jt) { + JSCodeGenerator *cg = args->cg; + + jt = cg->jtFreeList; + if (jt) { + cg->jtFreeList = jt->kids[JT_LEFT]; + } else { + JS_ARENA_ALLOCATE_CAST(jt, JSJumpTarget *, &args->cx->tempPool, + sizeof *jt); + if (!jt) { + js_ReportOutOfScriptQuota(args->cx); + return 0; + } + } + jt->offset = args->offset; + jt->balance = 0; + jt->kids[JT_LEFT] = jt->kids[JT_RIGHT] = NULL; + cg->numJumpTargets++; + args->node = jt; + *jtp = jt; + return 1; + } + + if (jt->offset == args->offset) { + args->node = jt; + return 0; + } + + if (args->offset < jt->offset) + balanceDelta = -AddJumpTarget(args, &jt->kids[JT_LEFT]); + else + balanceDelta = AddJumpTarget(args, &jt->kids[JT_RIGHT]); + if (!args->node) + return 0; + + jt->balance += balanceDelta; + return (balanceDelta && jt->balance) + ? 1 - BalanceJumpTargets(jtp) + : 0; +} + +#ifdef DEBUG_brendan +static int AVLCheck(JSJumpTarget *jt) +{ + int lh, rh; + + if (!jt) return 0; + JS_ASSERT(-1 <= jt->balance && jt->balance <= 1); + lh = AVLCheck(jt->kids[JT_LEFT]); + rh = AVLCheck(jt->kids[JT_RIGHT]); + JS_ASSERT(jt->balance == rh - lh); + return 1 + JS_MAX(lh, rh); +} +#endif + +static JSBool +SetSpanDepTarget(JSContext *cx, JSCodeGenerator *cg, JSSpanDep *sd, + ptrdiff_t off) +{ + AddJumpTargetArgs args; + + if (off < JUMPX_OFFSET_MIN || JUMPX_OFFSET_MAX < off) { + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + + args.cx = cx; + args.cg = cg; + args.offset = sd->top + off; + args.node = NULL; + AddJumpTarget(&args, &cg->jumpTargets); + if (!args.node) + return JS_FALSE; + +#ifdef DEBUG_brendan + AVLCheck(cg->jumpTargets); +#endif + + SD_SET_TARGET(sd, args.node); + return JS_TRUE; +} + +#define SPANDEPS_MIN 256 +#define SPANDEPS_SIZE(n) ((n) * sizeof(JSSpanDep)) +#define SPANDEPS_SIZE_MIN SPANDEPS_SIZE(SPANDEPS_MIN) + +static JSBool +AddSpanDep(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, jsbytecode *pc2, + ptrdiff_t off) +{ + uintN index; + JSSpanDep *sdbase, *sd; + size_t size; + + index = cg->numSpanDeps; + if (index + 1 == 0) { + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + + if ((index & (index - 1)) == 0 && + (!(sdbase = cg->spanDeps) || index >= SPANDEPS_MIN)) { + size = sdbase ? SPANDEPS_SIZE(index) : SPANDEPS_SIZE_MIN / 2; + sdbase = (JSSpanDep *) JS_realloc(cx, sdbase, size + size); + if (!sdbase) + return JS_FALSE; + cg->spanDeps = sdbase; + } + + cg->numSpanDeps = index + 1; + sd = cg->spanDeps + index; + sd->top = PTRDIFF(pc, CG_BASE(cg), jsbytecode); + sd->offset = sd->before = PTRDIFF(pc2, CG_BASE(cg), jsbytecode); + + if (js_CodeSpec[*pc].format & JOF_BACKPATCH) { + /* Jump offset will be backpatched if off is a non-zero "bpdelta". */ + if (off != 0) { + JS_ASSERT(off >= 1 + JUMP_OFFSET_LEN); + if (off > BPDELTA_MAX) { + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + } + SD_SET_BPDELTA(sd, off); + } else if (off == 0) { + /* Jump offset will be patched directly, without backpatch chaining. */ + SD_SET_TARGET(sd, 0); + } else { + /* The jump offset in off is non-zero, therefore it's already known. */ + if (!SetSpanDepTarget(cx, cg, sd, off)) + return JS_FALSE; + } + + if (index > SPANDEP_INDEX_MAX) + index = SPANDEP_INDEX_HUGE; + SET_SPANDEP_INDEX(pc2, index); + return JS_TRUE; +} + +static jsbytecode * +AddSwitchSpanDeps(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc) +{ + JSOp op; + jsbytecode *pc2; + ptrdiff_t off; + jsint low, high; + uintN njumps, indexlen; + + op = (JSOp) *pc; + JS_ASSERT(op == JSOP_TABLESWITCH || op == JSOP_LOOKUPSWITCH); + pc2 = pc; + off = GET_JUMP_OFFSET(pc2); + if (!AddSpanDep(cx, cg, pc, pc2, off)) + return NULL; + pc2 += JUMP_OFFSET_LEN; + if (op == JSOP_TABLESWITCH) { + low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + njumps = (uintN) (high - low + 1); + indexlen = 0; + } else { + njumps = GET_UINT16(pc2); + pc2 += UINT16_LEN; + indexlen = INDEX_LEN; + } + while (njumps) { + --njumps; + pc2 += indexlen; + off = GET_JUMP_OFFSET(pc2); + if (!AddSpanDep(cx, cg, pc, pc2, off)) + return NULL; + pc2 += JUMP_OFFSET_LEN; + } + return 1 + pc2; +} + +static JSBool +BuildSpanDepTable(JSContext *cx, JSCodeGenerator *cg) +{ + jsbytecode *pc, *end; + JSOp op; + const JSCodeSpec *cs; + ptrdiff_t off; + + pc = CG_BASE(cg) + cg->spanDepTodo; + end = CG_NEXT(cg); + while (pc != end) { + JS_ASSERT(pc < end); + op = (JSOp)*pc; + cs = &js_CodeSpec[op]; + + switch (JOF_TYPE(cs->format)) { + case JOF_TABLESWITCH: + case JOF_LOOKUPSWITCH: + pc = AddSwitchSpanDeps(cx, cg, pc); + if (!pc) + return JS_FALSE; + break; + + case JOF_JUMP: + off = GET_JUMP_OFFSET(pc); + if (!AddSpanDep(cx, cg, pc, pc, off)) + return JS_FALSE; + /* FALL THROUGH */ + default: + pc += cs->length; + break; + } + } + + return JS_TRUE; +} + +static JSSpanDep * +GetSpanDep(JSCodeGenerator *cg, jsbytecode *pc) +{ + uintN index; + ptrdiff_t offset; + int lo, hi, mid; + JSSpanDep *sd; + + index = GET_SPANDEP_INDEX(pc); + if (index != SPANDEP_INDEX_HUGE) + return cg->spanDeps + index; + + offset = PTRDIFF(pc, CG_BASE(cg), jsbytecode); + lo = 0; + hi = cg->numSpanDeps - 1; + while (lo <= hi) { + mid = (lo + hi) / 2; + sd = cg->spanDeps + mid; + if (sd->before == offset) + return sd; + if (sd->before < offset) + lo = mid + 1; + else + hi = mid - 1; + } + + JS_ASSERT(0); + return NULL; +} + +static JSBool +SetBackPatchDelta(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, + ptrdiff_t delta) +{ + JSSpanDep *sd; + + JS_ASSERT(delta >= 1 + JUMP_OFFSET_LEN); + if (!cg->spanDeps && delta < JUMP_OFFSET_MAX) { + SET_JUMP_OFFSET(pc, delta); + return JS_TRUE; + } + + if (delta > BPDELTA_MAX) { + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + + if (!cg->spanDeps && !BuildSpanDepTable(cx, cg)) + return JS_FALSE; + + sd = GetSpanDep(cg, pc); + JS_ASSERT(SD_GET_BPDELTA(sd) == 0); + SD_SET_BPDELTA(sd, delta); + return JS_TRUE; +} + +static void +UpdateJumpTargets(JSJumpTarget *jt, ptrdiff_t pivot, ptrdiff_t delta) +{ + if (jt->offset > pivot) { + jt->offset += delta; + if (jt->kids[JT_LEFT]) + UpdateJumpTargets(jt->kids[JT_LEFT], pivot, delta); + } + if (jt->kids[JT_RIGHT]) + UpdateJumpTargets(jt->kids[JT_RIGHT], pivot, delta); +} + +static JSSpanDep * +FindNearestSpanDep(JSCodeGenerator *cg, ptrdiff_t offset, int lo, + JSSpanDep *guard) +{ + int num, hi, mid; + JSSpanDep *sdbase, *sd; + + num = cg->numSpanDeps; + JS_ASSERT(num > 0); + hi = num - 1; + sdbase = cg->spanDeps; + while (lo <= hi) { + mid = (lo + hi) / 2; + sd = sdbase + mid; + if (sd->before == offset) + return sd; + if (sd->before < offset) + lo = mid + 1; + else + hi = mid - 1; + } + if (lo == num) + return guard; + sd = sdbase + lo; + JS_ASSERT(sd->before >= offset && (lo == 0 || sd[-1].before < offset)); + return sd; +} + +static void +FreeJumpTargets(JSCodeGenerator *cg, JSJumpTarget *jt) +{ + if (jt->kids[JT_LEFT]) + FreeJumpTargets(cg, jt->kids[JT_LEFT]); + if (jt->kids[JT_RIGHT]) + FreeJumpTargets(cg, jt->kids[JT_RIGHT]); + jt->kids[JT_LEFT] = cg->jtFreeList; + cg->jtFreeList = jt; +} + +static JSBool +OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg) +{ + jsbytecode *pc, *oldpc, *base, *limit, *next; + JSSpanDep *sd, *sd2, *sdbase, *sdlimit, *sdtop, guard; + ptrdiff_t offset, growth, delta, top, pivot, span, length, target; + JSBool done; + JSOp op; + uint32 type; + size_t size, incr; + jssrcnote *sn, *snlimit; + JSSrcNoteSpec *spec; + uintN i, n, noteIndex; + JSTryNode *tryNode; +#ifdef DEBUG_brendan + int passes = 0; +#endif + + base = CG_BASE(cg); + sdbase = cg->spanDeps; + sdlimit = sdbase + cg->numSpanDeps; + offset = CG_OFFSET(cg); + growth = 0; + + do { + done = JS_TRUE; + delta = 0; + top = pivot = -1; + sdtop = NULL; + pc = NULL; + op = JSOP_NOP; + type = 0; +#ifdef DEBUG_brendan + passes++; +#endif + + for (sd = sdbase; sd < sdlimit; sd++) { + JS_ASSERT(JT_HAS_TAG(sd->target)); + sd->offset += delta; + + if (sd->top != top) { + sdtop = sd; + top = sd->top; + JS_ASSERT(top == sd->before); + pivot = sd->offset; + pc = base + top; + op = (JSOp) *pc; + type = JOF_OPTYPE(op); + if (JOF_TYPE_IS_EXTENDED_JUMP(type)) { + /* + * We already extended all the jump offset operands for + * the opcode at sd->top. Jumps and branches have only + * one jump offset operand, but switches have many, all + * of which are adjacent in cg->spanDeps. + */ + continue; + } + + JS_ASSERT(type == JOF_JUMP || + type == JOF_TABLESWITCH || + type == JOF_LOOKUPSWITCH); + } + + if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) { + span = SD_SPAN(sd, pivot); + if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) { + ptrdiff_t deltaFromTop = 0; + + done = JS_FALSE; + + switch (op) { + case JSOP_GOTO: op = JSOP_GOTOX; break; + case JSOP_IFEQ: op = JSOP_IFEQX; break; + case JSOP_IFNE: op = JSOP_IFNEX; break; + case JSOP_OR: op = JSOP_ORX; break; + case JSOP_AND: op = JSOP_ANDX; break; + case JSOP_GOSUB: op = JSOP_GOSUBX; break; + case JSOP_CASE: op = JSOP_CASEX; break; + case JSOP_DEFAULT: op = JSOP_DEFAULTX; break; + case JSOP_TABLESWITCH: op = JSOP_TABLESWITCHX; break; + case JSOP_LOOKUPSWITCH: op = JSOP_LOOKUPSWITCHX; break; + default: + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + *pc = (jsbytecode) op; + + for (sd2 = sdtop; sd2 < sdlimit && sd2->top == top; sd2++) { + if (sd2 <= sd) { + /* + * sd2->offset already includes delta as it stood + * before we entered this loop, but it must also + * include the delta relative to top due to all the + * extended jump offset immediates for the opcode + * starting at top, which we extend in this loop. + * + * If there is only one extended jump offset, then + * sd2->offset won't change and this for loop will + * iterate once only. + */ + sd2->offset += deltaFromTop; + deltaFromTop += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN; + } else { + /* + * sd2 comes after sd, and won't be revisited by + * the outer for loop, so we have to increase its + * offset by delta, not merely by deltaFromTop. + */ + sd2->offset += delta; + } + + delta += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN; + UpdateJumpTargets(cg->jumpTargets, sd2->offset, + JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN); + } + sd = sd2 - 1; + } + } + } + + growth += delta; + } while (!done); + + if (growth) { +#ifdef DEBUG_brendan + JSTokenStream *ts = &cg->treeContext.parseContext->tokenStream; + + printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n", + ts->filename ? ts->filename : "stdin", cg->firstLine, + growth / (JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN), cg->numSpanDeps, + passes, offset + growth, offset, growth); +#endif + + /* + * Ensure that we have room for the extended jumps, but don't round up + * to a power of two -- we're done generating code, so we cut to fit. + */ + limit = CG_LIMIT(cg); + length = offset + growth; + next = base + length; + if (next > limit) { + JS_ASSERT(length > BYTECODE_CHUNK); + size = BYTECODE_SIZE(PTRDIFF(limit, base, jsbytecode)); + incr = BYTECODE_SIZE(length) - size; + JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr); + if (!base) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + CG_BASE(cg) = base; + CG_LIMIT(cg) = next = base + length; + } + CG_NEXT(cg) = next; + + /* + * Set up a fake span dependency record to guard the end of the code + * being generated. This guard record is returned as a fencepost by + * FindNearestSpanDep if there is no real spandep at or above a given + * unextended code offset. + */ + guard.top = -1; + guard.offset = offset + growth; + guard.before = offset; + guard.target = NULL; + } + + /* + * Now work backwards through the span dependencies, copying chunks of + * bytecode between each extended jump toward the end of the grown code + * space, and restoring immediate offset operands for all jump bytecodes. + * The first chunk of bytecodes, starting at base and ending at the first + * extended jump offset (NB: this chunk includes the operation bytecode + * just before that immediate jump offset), doesn't need to be copied. + */ + JS_ASSERT(sd == sdlimit); + top = -1; + while (--sd >= sdbase) { + if (sd->top != top) { + top = sd->top; + op = (JSOp) base[top]; + type = JOF_OPTYPE(op); + + for (sd2 = sd - 1; sd2 >= sdbase && sd2->top == top; sd2--) + continue; + sd2++; + pivot = sd2->offset; + JS_ASSERT(top == sd2->before); + } + + oldpc = base + sd->before; + span = SD_SPAN(sd, pivot); + + /* + * If this jump didn't need to be extended, restore its span immediate + * offset operand now, overwriting the index of sd within cg->spanDeps + * that was stored temporarily after *pc when BuildSpanDepTable ran. + * + * Note that span might fit in 16 bits even for an extended jump op, + * if the op has multiple span operands, not all of which overflowed + * (e.g. JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH where some cases are in + * range for a short jump, but others are not). + */ + if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) { + JS_ASSERT(JUMP_OFFSET_MIN <= span && span <= JUMP_OFFSET_MAX); + SET_JUMP_OFFSET(oldpc, span); + continue; + } + + /* + * Set up parameters needed to copy the next run of bytecode starting + * at offset (which is a cursor into the unextended, original bytecode + * vector), down to sd->before (a cursor of the same scale as offset, + * it's the index of the original jump pc). Reuse delta to count the + * nominal number of bytes to copy. + */ + pc = base + sd->offset; + delta = offset - sd->before; + JS_ASSERT(delta >= 1 + JUMP_OFFSET_LEN); + + /* + * Don't bother copying the jump offset we're about to reset, but do + * copy the bytecode at oldpc (which comes just before its immediate + * jump offset operand), on the next iteration through the loop, by + * including it in offset's new value. + */ + offset = sd->before + 1; + size = BYTECODE_SIZE(delta - (1 + JUMP_OFFSET_LEN)); + if (size) { + memmove(pc + 1 + JUMPX_OFFSET_LEN, + oldpc + 1 + JUMP_OFFSET_LEN, + size); + } + + SET_JUMPX_OFFSET(pc, span); + } + + if (growth) { + /* + * Fix source note deltas. Don't hardwire the delta fixup adjustment, + * even though currently it must be JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN + * at each sd that moved. The future may bring different offset sizes + * for span-dependent instruction operands. However, we fix only main + * notes here, not prolog notes -- we know that prolog opcodes are not + * span-dependent, and aren't likely ever to be. + */ + offset = growth = 0; + sd = sdbase; + for (sn = cg->main.notes, snlimit = sn + cg->main.noteCount; + sn < snlimit; + sn = SN_NEXT(sn)) { + /* + * Recall that the offset of a given note includes its delta, and + * tells the offset of the annotated bytecode from the main entry + * point of the script. + */ + offset += SN_DELTA(sn); + while (sd < sdlimit && sd->before < offset) { + /* + * To compute the delta to add to sn, we need to look at the + * spandep after sd, whose offset - (before + growth) tells by + * how many bytes sd's instruction grew. + */ + sd2 = sd + 1; + if (sd2 == sdlimit) + sd2 = &guard; + delta = sd2->offset - (sd2->before + growth); + if (delta > 0) { + JS_ASSERT(delta == JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN); + sn = js_AddToSrcNoteDelta(cx, cg, sn, delta); + if (!sn) + return JS_FALSE; + snlimit = cg->main.notes + cg->main.noteCount; + growth += delta; + } + sd++; + } + + /* + * If sn has span-dependent offset operands, check whether each + * covers further span-dependencies, and increase those operands + * accordingly. Some source notes measure offset not from the + * annotated pc, but from that pc plus some small bias. NB: we + * assume that spec->offsetBias can't itself span span-dependent + * instructions! + */ + spec = &js_SrcNoteSpec[SN_TYPE(sn)]; + if (spec->isSpanDep) { + pivot = offset + spec->offsetBias; + n = spec->arity; + for (i = 0; i < n; i++) { + span = js_GetSrcNoteOffset(sn, i); + if (span == 0) + continue; + target = pivot + span * spec->isSpanDep; + sd2 = FindNearestSpanDep(cg, target, + (target >= pivot) + ? sd - sdbase + : 0, + &guard); + + /* + * Increase target by sd2's before-vs-after offset delta, + * which is absolute (i.e., relative to start of script, + * as is target). Recompute the span by subtracting its + * adjusted pivot from target. + */ + target += sd2->offset - sd2->before; + span = target - (pivot + growth); + span *= spec->isSpanDep; + noteIndex = sn - cg->main.notes; + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, i, span)) + return JS_FALSE; + sn = cg->main.notes + noteIndex; + snlimit = cg->main.notes + cg->main.noteCount; + } + } + } + cg->main.lastNoteOffset += growth; + + /* + * Fix try/catch notes (O(numTryNotes * log2(numSpanDeps)), but it's + * not clear how we can beat that). + */ + for (tryNode = cg->lastTryNode; tryNode; tryNode = tryNode->prev) { + /* + * First, look for the nearest span dependency at/above tn->start. + * There may not be any such spandep, in which case the guard will + * be returned. + */ + offset = tryNode->note.start; + sd = FindNearestSpanDep(cg, offset, 0, &guard); + delta = sd->offset - sd->before; + tryNode->note.start = offset + delta; + + /* + * Next, find the nearest spandep at/above tn->start + tn->length. + * Use its delta minus tn->start's delta to increase tn->length. + */ + length = tryNode->note.length; + sd2 = FindNearestSpanDep(cg, offset + length, sd - sdbase, &guard); + if (sd2 != sd) { + tryNode->note.length = + length + sd2->offset - sd2->before - delta; + } + } + } + +#ifdef DEBUG_brendan + { + uintN bigspans = 0; + top = -1; + for (sd = sdbase; sd < sdlimit; sd++) { + offset = sd->offset; + + /* NB: sd->top cursors into the original, unextended bytecode vector. */ + if (sd->top != top) { + JS_ASSERT(top == -1 || + !JOF_TYPE_IS_EXTENDED_JUMP(type) || + bigspans != 0); + bigspans = 0; + top = sd->top; + JS_ASSERT(top == sd->before); + op = (JSOp) base[offset]; + type = JOF_OPTYPE(op); + JS_ASSERT(type == JOF_JUMP || + type == JOF_JUMPX || + type == JOF_TABLESWITCH || + type == JOF_TABLESWITCHX || + type == JOF_LOOKUPSWITCH || + type == JOF_LOOKUPSWITCHX); + pivot = offset; + } + + pc = base + offset; + if (JOF_TYPE_IS_EXTENDED_JUMP(type)) { + span = GET_JUMPX_OFFSET(pc); + if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) { + bigspans++; + } else { + JS_ASSERT(type == JOF_TABLESWITCHX || + type == JOF_LOOKUPSWITCHX); + } + } else { + span = GET_JUMP_OFFSET(pc); + } + JS_ASSERT(SD_SPAN(sd, pivot) == span); + } + JS_ASSERT(!JOF_TYPE_IS_EXTENDED_JUMP(type) || bigspans != 0); + } +#endif + + /* + * Reset so we optimize at most once -- cg may be used for further code + * generation of successive, independent, top-level statements. No jump + * can span top-level statements, because JS lacks goto. + */ + size = SPANDEPS_SIZE(JS_BIT(JS_CeilingLog2(cg->numSpanDeps))); + JS_free(cx, cg->spanDeps); + cg->spanDeps = NULL; + FreeJumpTargets(cg, cg->jumpTargets); + cg->jumpTargets = NULL; + cg->numSpanDeps = cg->numJumpTargets = 0; + cg->spanDepTodo = CG_OFFSET(cg); + return JS_TRUE; +} + +static ptrdiff_t +EmitJump(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t off) +{ + JSBool extend; + ptrdiff_t jmp; + jsbytecode *pc; + + extend = off < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < off; + if (extend && !cg->spanDeps && !BuildSpanDepTable(cx, cg)) + return -1; + + jmp = js_Emit3(cx, cg, op, JUMP_OFFSET_HI(off), JUMP_OFFSET_LO(off)); + if (jmp >= 0 && (extend || cg->spanDeps)) { + pc = CG_CODE(cg, jmp); + if (!AddSpanDep(cx, cg, pc, pc, off)) + return -1; + } + return jmp; +} + +static ptrdiff_t +GetJumpOffset(JSCodeGenerator *cg, jsbytecode *pc) +{ + JSSpanDep *sd; + JSJumpTarget *jt; + ptrdiff_t top; + + if (!cg->spanDeps) + return GET_JUMP_OFFSET(pc); + + sd = GetSpanDep(cg, pc); + jt = sd->target; + if (!JT_HAS_TAG(jt)) + return JT_TO_BPDELTA(jt); + + top = sd->top; + while (--sd >= cg->spanDeps && sd->top == top) + continue; + sd++; + return JT_CLR_TAG(jt)->offset - sd->offset; +} + +JSBool +js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, + ptrdiff_t off) +{ + if (!cg->spanDeps) { + if (JUMP_OFFSET_MIN <= off && off <= JUMP_OFFSET_MAX) { + SET_JUMP_OFFSET(pc, off); + return JS_TRUE; + } + + if (!BuildSpanDepTable(cx, cg)) + return JS_FALSE; + } + + return SetSpanDepTarget(cx, cg, GetSpanDep(cg, pc), off); +} + +JSBool +js_InStatement(JSTreeContext *tc, JSStmtType type) +{ + JSStmtInfo *stmt; + + for (stmt = tc->topStmt; stmt; stmt = stmt->down) { + if (stmt->type == type) + return JS_TRUE; + } + return JS_FALSE; +} + +void +js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, + ptrdiff_t top) +{ + stmt->type = type; + stmt->flags = 0; + SET_STATEMENT_TOP(stmt, top); + stmt->u.label = NULL; + JS_ASSERT(!stmt->u.blockObj); + stmt->down = tc->topStmt; + tc->topStmt = stmt; + if (STMT_LINKS_SCOPE(stmt)) { + stmt->downScope = tc->topScopeStmt; + tc->topScopeStmt = stmt; + } else { + stmt->downScope = NULL; + } +} + +void +js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj, + ptrdiff_t top) +{ + + js_PushStatement(tc, stmt, STMT_BLOCK, top); + stmt->flags |= SIF_SCOPE; + STOBJ_SET_PARENT(blockObj, tc->blockChain); + stmt->downScope = tc->topScopeStmt; + tc->topScopeStmt = stmt; + tc->blockChain = blockObj; + stmt->u.blockObj = blockObj; +} + +/* + * Emit a backpatch op with offset pointing to the previous jump of this type, + * so that we can walk back up the chain fixing up the op and jump offset. + */ +static ptrdiff_t +EmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp) +{ + ptrdiff_t offset, delta; + + offset = CG_OFFSET(cg); + delta = offset - *lastp; + *lastp = offset; + JS_ASSERT(delta > 0); + return EmitJump(cx, cg, op, delta); +} + +/* + * Macro to emit a bytecode followed by a uint16 immediate operand stored in + * big-endian order, used for arg and var numbers as well as for atomIndexes. + * NB: We use cx and cg from our caller's lexical environment, and return + * false on error. + */ +#define EMIT_UINT16_IMM_OP(op, i) \ + JS_BEGIN_MACRO \ + if (js_Emit3(cx, cg, op, UINT16_HI(i), UINT16_LO(i)) < 0) \ + return JS_FALSE; \ + JS_END_MACRO + +static JSBool +FlushPops(JSContext *cx, JSCodeGenerator *cg, intN *npops) +{ + JS_ASSERT(*npops != 0); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + EMIT_UINT16_IMM_OP(JSOP_POPN, *npops); + *npops = 0; + return JS_TRUE; +} + +/* + * Emit additional bytecode(s) for non-local jumps. + */ +static JSBool +EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt) +{ + intN depth, npops; + JSStmtInfo *stmt; + + /* + * The non-local jump fixup we emit will unbalance cg->stackDepth, because + * the fixup replicates balanced code such as JSOP_LEAVEWITH emitted at the + * end of a with statement, so we save cg->stackDepth here and restore it + * just before a successful return. + */ + depth = cg->stackDepth; + npops = 0; + +#define FLUSH_POPS() if (npops && !FlushPops(cx, cg, &npops)) return JS_FALSE + + for (stmt = cg->treeContext.topStmt; stmt != toStmt; stmt = stmt->down) { + switch (stmt->type) { + case STMT_FINALLY: + FLUSH_POPS(); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(*stmt)) < 0) + return JS_FALSE; + break; + + case STMT_WITH: + /* There's a With object on the stack that we need to pop. */ + FLUSH_POPS(); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) + return JS_FALSE; + break; + + case STMT_FOR_IN_LOOP: + /* + * The iterator and the object being iterated need to be popped. + */ + FLUSH_POPS(); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_ENDITER) < 0) + return JS_FALSE; + break; + + case STMT_SUBROUTINE: + /* + * There's a [exception or hole, retsub pc-index] pair on the + * stack that we need to pop. + */ + npops += 2; + break; + + default:; + } + + if (stmt->flags & SIF_SCOPE) { + uintN i; + + /* There is a Block object with locals on the stack to pop. */ + FLUSH_POPS(); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + i = OBJ_BLOCK_COUNT(cx, stmt->u.blockObj); + EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, i); + } + } + + FLUSH_POPS(); + cg->stackDepth = depth; + return JS_TRUE; + +#undef FLUSH_POPS +} + +static ptrdiff_t +EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, + ptrdiff_t *lastp, JSAtomListElement *label, JSSrcNoteType noteType) +{ + intN index; + + if (!EmitNonLocalJumpFixup(cx, cg, toStmt)) + return -1; + + if (label) + index = js_NewSrcNote2(cx, cg, noteType, (ptrdiff_t) ALE_INDEX(label)); + else if (noteType != SRC_NULL) + index = js_NewSrcNote(cx, cg, noteType); + else + index = 0; + if (index < 0) + return -1; + + return EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, lastp); +} + +static JSBool +BackPatch(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t last, + jsbytecode *target, jsbytecode op) +{ + jsbytecode *pc, *stop; + ptrdiff_t delta, span; + + pc = CG_CODE(cg, last); + stop = CG_CODE(cg, -1); + while (pc != stop) { + delta = GetJumpOffset(cg, pc); + span = PTRDIFF(target, pc, jsbytecode); + CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, span); + + /* + * Set *pc after jump offset in case bpdelta didn't overflow, but span + * does (if so, CHECK_AND_SET_JUMP_OFFSET might call BuildSpanDepTable + * and need to see the JSOP_BACKPATCH* op at *pc). + */ + *pc = op; + pc -= delta; + } + return JS_TRUE; +} + +void +js_PopStatement(JSTreeContext *tc) +{ + JSStmtInfo *stmt; + + stmt = tc->topStmt; + tc->topStmt = stmt->down; + if (STMT_LINKS_SCOPE(stmt)) { + tc->topScopeStmt = stmt->downScope; + if (stmt->flags & SIF_SCOPE) { + tc->blockChain = STOBJ_GET_PARENT(stmt->u.blockObj); + JS_SCOPE_DEPTH_METERING(--tc->scopeDepth); + } + } +} + +JSBool +js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg) +{ + JSStmtInfo *stmt; + + stmt = cg->treeContext.topStmt; + if (!STMT_IS_TRYING(stmt) && + (!BackPatch(cx, cg, stmt->breaks, CG_NEXT(cg), JSOP_GOTO) || + !BackPatch(cx, cg, stmt->continues, CG_CODE(cg, stmt->update), + JSOP_GOTO))) { + return JS_FALSE; + } + js_PopStatement(&cg->treeContext); + return JS_TRUE; +} + +JSBool +js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, + JSParseNode *pn) +{ + jsdouble dval; + jsint ival; + JSAtom *valueAtom; + jsval v; + JSAtomListElement *ale; + + /* XXX just do numbers for now */ + if (pn->pn_type == TOK_NUMBER) { + dval = pn->pn_dval; + if (JSDOUBLE_IS_INT(dval, ival) && INT_FITS_IN_JSVAL(ival)) { + v = INT_TO_JSVAL(ival); + } else { + /* + * We atomize double to root a jsdouble instance that we wrap as + * jsval and store in cg->constList. This works because atoms are + * protected from GC during compilation. + */ + valueAtom = js_AtomizeDouble(cx, dval); + if (!valueAtom) + return JS_FALSE; + v = ATOM_KEY(valueAtom); + } + ale = js_IndexAtom(cx, atom, &cg->constList); + if (!ale) + return JS_FALSE; + ALE_SET_VALUE(ale, v); + } + return JS_TRUE; +} + +JSStmtInfo * +js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp) +{ + JSStmtInfo *stmt; + JSObject *obj; + JSScope *scope; + JSScopeProperty *sprop; + + for (stmt = tc->topScopeStmt; stmt; stmt = stmt->downScope) { + if (stmt->type == STMT_WITH) + break; + + /* Skip "maybe scope" statements that don't contain let bindings. */ + if (!(stmt->flags & SIF_SCOPE)) + continue; + + obj = stmt->u.blockObj; + JS_ASSERT(LOCKED_OBJ_GET_CLASS(obj) == &js_BlockClass); + scope = OBJ_SCOPE(obj); + sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom)); + if (sprop) { + JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID); + + if (slotp) { + JS_ASSERT(JSVAL_IS_INT(obj->fslots[JSSLOT_BLOCK_DEPTH])); + *slotp = JSVAL_TO_INT(obj->fslots[JSSLOT_BLOCK_DEPTH]) + + sprop->shortid; + } + return stmt; + } + } + + if (slotp) + *slotp = -1; + return stmt; +} + +/* + * Check if the attributes describe a property holding a compile-time constant + * or a permanent, read-only property without a getter. + */ +#define IS_CONSTANT_PROPERTY(attrs) \ + (((attrs) & (JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_GETTER)) == \ + (JSPROP_READONLY | JSPROP_PERMANENT)) + +/* + * The function sets vp to JSVAL_HOLE when the atom does not corresponds to a + * name defining a constant. + */ +static JSBool +LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, + jsval *vp) +{ + JSBool ok; + JSStmtInfo *stmt; + JSAtomListElement *ale; + JSObject *obj, *pobj; + JSProperty *prop; + uintN attrs; + + /* + * Chase down the cg stack, but only until we reach the outermost cg. + * This enables propagating consts from top-level into switch cases in a + * function compiled along with the top-level script. + */ + *vp = JSVAL_HOLE; + do { + if (cg->treeContext.flags & (TCF_IN_FUNCTION | TCF_COMPILE_N_GO)) { + /* XXX this will need revising when 'let const' is added. */ + stmt = js_LexicalLookup(&cg->treeContext, atom, NULL); + if (stmt) + return JS_TRUE; + + ATOM_LIST_SEARCH(ale, &cg->constList, atom); + if (ale) { + JS_ASSERT(ALE_VALUE(ale) != JSVAL_HOLE); + *vp = ALE_VALUE(ale); + return JS_TRUE; + } + + /* + * Try looking in the variable object for a direct property that + * is readonly and permanent. We know such a property can't be + * shadowed by another property on obj's prototype chain, or a + * with object or catch variable; nor can prop's value be changed, + * nor can prop be deleted. + */ + if (cg->treeContext.flags & TCF_IN_FUNCTION) { + if (js_LookupLocal(cx, cg->treeContext.u.fun, atom, NULL) != + JSLOCAL_NONE) { + break; + } + } else { + JS_ASSERT(cg->treeContext.flags & TCF_COMPILE_N_GO); + obj = cg->treeContext.u.scopeChain; + ok = OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &pobj, + &prop); + if (!ok) + return JS_FALSE; + if (pobj == obj) { + /* + * We're compiling code that will be executed immediately, + * not re-executed against a different scope chain and/or + * variable object. Therefore we can get constant values + * from our variable object here. + */ + ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, + &attrs); + if (ok && IS_CONSTANT_PROPERTY(attrs)) { + ok = OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp); + JS_ASSERT_IF(ok, *vp != JSVAL_HOLE); + } + } + if (prop) + OBJ_DROP_PROPERTY(cx, pobj, prop); + if (!ok) + return JS_FALSE; + if (prop) + break; + } + } + } while ((cg = cg->parent) != NULL); + return JS_TRUE; +} + +/* + * Return JSOP_NOP to indicate that index fits 2 bytes and no index segment + * reset instruction is necessary, JSOP_FALSE to indicate an error or either + * JSOP_RESETBASE0 or JSOP_RESETBASE1 to indicate the reset bytecode to issue + * after the main bytecode sequence. + */ +static JSOp +EmitBigIndexPrefix(JSContext *cx, JSCodeGenerator *cg, uintN index) +{ + uintN indexBase; + + /* + * We have max 3 bytes for indexes and check for INDEX_LIMIT overflow only + * for big indexes. + */ + JS_STATIC_ASSERT(INDEX_LIMIT <= JS_BIT(24)); + JS_STATIC_ASSERT(INDEX_LIMIT >= + (JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 2) << 16); + + if (index < JS_BIT(16)) + return JSOP_NOP; + indexBase = index >> 16; + if (indexBase <= JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 1) { + if (js_Emit1(cx, cg, (JSOp)(JSOP_INDEXBASE1 + indexBase - 1)) < 0) + return JSOP_FALSE; + return JSOP_RESETBASE0; + } + + if (index >= INDEX_LIMIT) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TOO_MANY_LITERALS); + return JSOP_FALSE; + } + + if (js_Emit2(cx, cg, JSOP_INDEXBASE, (JSOp)indexBase) < 0) + return JSOP_FALSE; + return JSOP_RESETBASE; +} + +/* + * Emit a bytecode and its 2-byte constant index immediate operand. If the + * index requires more than 2 bytes, emit a prefix op whose 8-bit immediate + * operand effectively extends the 16-bit immediate of the prefixed opcode, + * by changing index "segment" (see jsinterp.c). We optimize segments 1-3 + * with single-byte JSOP_INDEXBASE[123] codes. + * + * Such prefixing currently requires a suffix to restore the "zero segment" + * register setting, but this could be optimized further. + */ +static JSBool +EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg) +{ + JSOp bigSuffix; + + bigSuffix = EmitBigIndexPrefix(cx, cg, index); + if (bigSuffix == JSOP_FALSE) + return JS_FALSE; + EMIT_UINT16_IMM_OP(op, index); + return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0; +} + +/* + * Slight sugar for EmitIndexOp, again accessing cx and cg from the macro + * caller's lexical environment, and embedding a false return on error. + */ +#define EMIT_INDEX_OP(op, index) \ + JS_BEGIN_MACRO \ + if (!EmitIndexOp(cx, op, index, cg)) \ + return JS_FALSE; \ + JS_END_MACRO + + +static JSBool +EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +{ + JSAtomListElement *ale; + + JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); + if (op == JSOP_GETPROP && + pn->pn_atom == cx->runtime->atomState.lengthAtom) { + return js_Emit1(cx, cg, JSOP_LENGTH) >= 0; + } + ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList); + if (!ale) + return JS_FALSE; + return EmitIndexOp(cx, op, ALE_INDEX(ale), cg); +} + +static uintN +IndexParsedObject(JSParsedObjectBox *pob, JSEmittedObjectList *list); + +static JSBool +EmitObjectOp(JSContext *cx, JSParsedObjectBox *pob, JSOp op, + JSCodeGenerator *cg) +{ + JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT); + return EmitIndexOp(cx, op, IndexParsedObject(pob, &cg->objectList), cg); +} + +/* + * What good are ARGNO_LEN and SLOTNO_LEN, you ask? The answer is that, apart + * from EmitSlotIndexOp, they abstract out the detail that both are 2, and in + * other parts of the code there's no necessary relationship between the two. + * The abstraction cracks here in order to share EmitSlotIndexOp code among + * the JSOP_DEFLOCALFUN and JSOP_GET{ARG,VAR,LOCAL}PROP cases. + */ +JS_STATIC_ASSERT(ARGNO_LEN == 2); +JS_STATIC_ASSERT(SLOTNO_LEN == 2); + +static JSBool +EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index, + JSCodeGenerator *cg) +{ + JSOp bigSuffix; + ptrdiff_t off; + jsbytecode *pc; + + JS_ASSERT(JOF_OPTYPE(op) == JOF_SLOTATOM || + JOF_OPTYPE(op) == JOF_SLOTOBJECT); + bigSuffix = EmitBigIndexPrefix(cx, cg, index); + if (bigSuffix == JSOP_FALSE) + return JS_FALSE; + + /* Emit [op, slot, index]. */ + off = js_EmitN(cx, cg, op, 2 + INDEX_LEN); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_UINT16(pc, slot); + pc += 2; + SET_INDEX(pc, index); + return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0; +} + +/* + * Adjust the slot for a block local to account for the number of variables + * that share the same index space with locals. Due to the incremental code + * generation for top-level script, we do the adjustment via code patching in + * js_CompileScript; see comments there. + * + * The function returns -1 on failures. + */ +static jsint +AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot) +{ + JS_ASSERT((jsuint) slot < cg->maxStackDepth); + if (cg->treeContext.flags & TCF_IN_FUNCTION) { + slot += cg->treeContext.u.fun->u.i.nvars; + if ((uintN) slot >= SLOTNO_LIMIT) { + js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL, + JSREPORT_ERROR, + JSMSG_TOO_MANY_LOCALS); + slot = -1; + } + } + return slot; +} + +/* + * This routine tries to optimize name gets and sets to stack slot loads and + * stores, given the variables object and scope chain in cx's top frame, the + * compile-time context in tc, and a TOK_NAME node pn. It returns false on + * error, true on success. + * + * The caller can inspect pn->pn_slot for a non-negative slot number to tell + * whether optimization occurred, in which case BindNameToSlot also updated + * pn->pn_op. If pn->pn_slot is still -1 on return, pn->pn_op nevertheless + * may have been optimized, e.g., from JSOP_NAME to JSOP_ARGUMENTS. Whether + * or not pn->pn_op was modified, if this function finds an argument or local + * variable name, pn->pn_const will be true for const properties after a + * successful return. + * + * NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget + * to update the TOK_FOR (for-in) and TOK_ASSIGN (op=, e.g. +=) special cases + * in js_EmitTree. + */ +static JSBool +BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +{ + JSTreeContext *tc; + JSAtom *atom; + JSStmtInfo *stmt; + jsint slot; + JSOp op; + JSLocalKind localKind; + uintN index; + JSAtomListElement *ale; + JSBool constOp; + + JS_ASSERT(pn->pn_type == TOK_NAME); + if (pn->pn_slot >= 0 || pn->pn_op == JSOP_ARGUMENTS) + return JS_TRUE; + + /* QNAME references can never be optimized to use arg/var storage. */ + if (pn->pn_op == JSOP_QNAMEPART) + return JS_TRUE; + + /* + * We can't optimize if we are compiling a with statement and its body, + * or we're in a catch block whose exception variable has the same name + * as this node. FIXME: we should be able to optimize catch vars to be + * block-locals. + */ + tc = &cg->treeContext; + atom = pn->pn_atom; + stmt = js_LexicalLookup(tc, atom, &slot); + if (stmt) { + if (stmt->type == STMT_WITH) + return JS_TRUE; + + JS_ASSERT(stmt->flags & SIF_SCOPE); + JS_ASSERT(slot >= 0); + op = PN_OP(pn); + switch (op) { + case JSOP_NAME: op = JSOP_GETLOCAL; break; + case JSOP_SETNAME: op = JSOP_SETLOCAL; break; + case JSOP_INCNAME: op = JSOP_INCLOCAL; break; + case JSOP_NAMEINC: op = JSOP_LOCALINC; break; + case JSOP_DECNAME: op = JSOP_DECLOCAL; break; + case JSOP_NAMEDEC: op = JSOP_LOCALDEC; break; + case JSOP_FORNAME: op = JSOP_FORLOCAL; break; + case JSOP_DELNAME: op = JSOP_FALSE; break; + default: JS_ASSERT(0); + } + if (op != pn->pn_op) { + slot = AdjustBlockSlot(cx, cg, slot); + if (slot < 0) + return JS_FALSE; + pn->pn_op = op; + pn->pn_slot = slot; + } + return JS_TRUE; + } + + /* + * We can't optimize if var and closure (a local function not in a larger + * expression and not at top-level within another's body) collide. + * XXX suboptimal: keep track of colliding names and deoptimize only those + */ + if (tc->flags & TCF_FUN_CLOSURE_VS_VAR) + return JS_TRUE; + + if (!(tc->flags & TCF_IN_FUNCTION)) { + JSStackFrame *caller; + + caller = tc->parseContext->callerFrame; + if (caller) { + JS_ASSERT(tc->flags & TCF_COMPILE_N_GO); + JS_ASSERT(caller->script); + if (!caller->fun || caller->varobj != tc->u.scopeChain) + return JS_TRUE; + + /* + * We are compiling eval or debug script inside a function frame + * and the scope chain matches function's variable object. + * Optimize access to function's arguments and variable and the + * arguments object. + */ + if (PN_OP(pn) != JSOP_NAME || cg->staticDepth > JS_DISPLAY_SIZE) + goto arguments_check; + localKind = js_LookupLocal(cx, caller->fun, atom, &index); + if (localKind == JSLOCAL_NONE) + goto arguments_check; + + ATOM_LIST_SEARCH(ale, &cg->upvarList, atom); + if (!ale) { + uint32 length, *vector; + + ale = js_IndexAtom(cx, atom, &cg->upvarList); + if (!ale) + return JS_FALSE; + JS_ASSERT(ALE_INDEX(ale) == cg->upvarList.count - 1); + + length = cg->upvarMap.length; + JS_ASSERT(ALE_INDEX(ale) <= length); + if (ALE_INDEX(ale) == length) { + length = 2 * JS_MAX(2, length); + vector = (uint32 *) + JS_realloc(cx, cg->upvarMap.vector, + length * sizeof *vector); + if (!vector) + return JS_FALSE; + cg->upvarMap.vector = vector; + cg->upvarMap.length = length; + } + + if (localKind != JSLOCAL_ARG) + index += caller->fun->nargs; + if (index >= JS_BIT(16)) { + cg->treeContext.flags |= TCF_FUN_USES_NONLOCALS; + return JS_TRUE; + } + + JS_ASSERT(cg->staticDepth > caller->fun->u.i.script->staticDepth); + uintN skip = cg->staticDepth - caller->fun->u.i.script->staticDepth; + cg->upvarMap.vector[ALE_INDEX(ale)] = MAKE_UPVAR_COOKIE(skip, index); + } + + pn->pn_op = JSOP_GETUPVAR; + pn->pn_slot = ALE_INDEX(ale); + return JS_TRUE; + } + + /* + * We are optimizing global variables and there may be no pre-existing + * global property named atom. If atom was declared via const or var, + * optimize pn to access fp->vars using the appropriate JSOP_*GVAR op. + */ + ATOM_LIST_SEARCH(ale, &tc->decls, atom); + if (!ale) { + /* Use precedes declaration, or name is never declared. */ + return JS_TRUE; + } + constOp = (ALE_JSOP(ale) == JSOP_DEFCONST); + + /* Index atom so we can map fast global number to name. */ + ale = js_IndexAtom(cx, atom, &cg->atomList); + if (!ale) + return JS_FALSE; + + /* Defend against tc->ngvars 16-bit overflow. */ + slot = ALE_INDEX(ale); + if ((slot + 1) >> 16) + return JS_TRUE; + + if ((uint16)(slot + 1) > tc->ngvars) + tc->ngvars = (uint16)(slot + 1); + + op = PN_OP(pn); + switch (op) { + case JSOP_NAME: op = JSOP_GETGVAR; break; + case JSOP_SETNAME: op = JSOP_SETGVAR; break; + case JSOP_SETCONST: /* NB: no change */ break; + case JSOP_INCNAME: op = JSOP_INCGVAR; break; + case JSOP_NAMEINC: op = JSOP_GVARINC; break; + case JSOP_DECNAME: op = JSOP_DECGVAR; break; + case JSOP_NAMEDEC: op = JSOP_GVARDEC; break; + case JSOP_FORNAME: /* NB: no change */ break; + case JSOP_DELNAME: /* NB: no change */ break; + default: JS_NOT_REACHED("gvar"); + } + pn->pn_const = constOp; + if (op != pn->pn_op) { + pn->pn_op = op; + pn->pn_slot = slot; + } + return JS_TRUE; + } + + if (tc->flags & TCF_IN_FUNCTION) { + /* + * We are compiling a function body and may be able to optimize name + * to stack slot. Look for an argument or variable in the function and + * rewrite pn_op and update pn accordingly. + */ + localKind = js_LookupLocal(cx, tc->u.fun, atom, &index); + if (localKind != JSLOCAL_NONE) { + op = PN_OP(pn); + if (localKind == JSLOCAL_ARG) { + switch (op) { + case JSOP_NAME: op = JSOP_GETARG; break; + case JSOP_SETNAME: op = JSOP_SETARG; break; + case JSOP_INCNAME: op = JSOP_INCARG; break; + case JSOP_NAMEINC: op = JSOP_ARGINC; break; + case JSOP_DECNAME: op = JSOP_DECARG; break; + case JSOP_NAMEDEC: op = JSOP_ARGDEC; break; + case JSOP_FORNAME: op = JSOP_FORARG; break; + case JSOP_DELNAME: op = JSOP_FALSE; break; + default: JS_NOT_REACHED("arg"); + } + pn->pn_const = JS_FALSE; + } else { + JS_ASSERT(localKind == JSLOCAL_VAR || + localKind == JSLOCAL_CONST); + switch (op) { + case JSOP_NAME: op = JSOP_GETLOCAL; break; + case JSOP_SETNAME: op = JSOP_SETLOCAL; break; + case JSOP_SETCONST: op = JSOP_SETLOCAL; break; + case JSOP_INCNAME: op = JSOP_INCLOCAL; break; + case JSOP_NAMEINC: op = JSOP_LOCALINC; break; + case JSOP_DECNAME: op = JSOP_DECLOCAL; break; + case JSOP_NAMEDEC: op = JSOP_LOCALDEC; break; + case JSOP_FORNAME: op = JSOP_FORLOCAL; break; + case JSOP_DELNAME: op = JSOP_FALSE; break; + default: JS_NOT_REACHED("local"); + } + pn->pn_const = (localKind == JSLOCAL_CONST); + } + pn->pn_op = op; + pn->pn_slot = index; + return JS_TRUE; + } + tc->flags |= TCF_FUN_USES_NONLOCALS; + } + + arguments_check: + /* + * Here we either compiling a function body or an eval or debug script + * inside a function and couldn't optimize pn, so it's not a global or + * local slot name. We are also outside of any with blocks. Check if we + * can optimize the predefined arguments variable. + */ + JS_ASSERT((tc->flags & TCF_IN_FUNCTION) || + (tc->parseContext->callerFrame && + tc->parseContext->callerFrame->fun && + tc->parseContext->callerFrame->varobj == tc->u.scopeChain)); + if (pn->pn_op == JSOP_NAME && + atom == cx->runtime->atomState.argumentsAtom) { + pn->pn_op = JSOP_ARGUMENTS; + return JS_TRUE; + } + return JS_TRUE; +} + +/* + * If pn contains a useful expression, return true with *answer set to true. + * If pn contains a useless expression, return true with *answer set to false. + * Return false on error. + * + * The caller should initialize *answer to false and invoke this function on + * an expression statement or similar subtree to decide whether the tree could + * produce code that has any side effects. For an expression statement, we + * define useless code as code with no side effects, because the main effect, + * the value left on the stack after the code executes, will be discarded by a + * pop bytecode. + */ +static JSBool +CheckSideEffects(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, + JSBool *answer) +{ + JSBool ok; + JSFunction *fun; + JSParseNode *pn2; + + ok = JS_TRUE; + if (!pn || *answer) + return ok; + + switch (pn->pn_arity) { + case PN_FUNC: + /* + * A named function is presumed useful: we can't yet know that it is + * not called. The side effects are the creation of a scope object + * to parent this function object, and the binding of the function's + * name in that scope object. See comments at case JSOP_NAMEDFUNOBJ: + * in jsinterp.c. + */ + fun = (JSFunction *) pn->pn_funpob->object; + if (fun->atom) + *answer = JS_TRUE; + break; + + case PN_LIST: + if (pn->pn_op == JSOP_NOP || + pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND || + pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) { + /* + * Non-operators along with ||, &&, ===, and !== never invoke + * toString or valueOf. + */ + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) + ok &= CheckSideEffects(cx, cg, pn2, answer); + } else { + /* + * All invocation operations (construct: TOK_NEW, call: TOK_LP) + * are presumed to be useful, because they may have side effects + * even if their main effect (their return value) is discarded. + * + * TOK_LB binary trees of 3 or more nodes are flattened into lists + * to avoid too much recursion. All such lists must be presumed + * to be useful because each index operation could invoke a getter + * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case, + * does not apply here: arguments[i][j] might invoke a getter). + * + * Likewise, array and object initialisers may call prototype + * setters (the __defineSetter__ built-in, and writable __proto__ + * on Array.prototype create this hazard). Initialiser list nodes + * have JSOP_NEWINIT in their pn_op. + */ + *answer = JS_TRUE; + } + break; + + case PN_TERNARY: + ok = CheckSideEffects(cx, cg, pn->pn_kid1, answer) && + CheckSideEffects(cx, cg, pn->pn_kid2, answer) && + CheckSideEffects(cx, cg, pn->pn_kid3, answer); + break; + + case PN_BINARY: + if (pn->pn_type == TOK_ASSIGN) { + /* + * Assignment is presumed to be useful, even if the next operation + * is another assignment overwriting this one's ostensible effect, + * because the left operand may be a property with a setter that + * has side effects. + * + * The only exception is assignment of a useless value to a const + * declared in the function currently being compiled. + */ + pn2 = pn->pn_left; + if (pn2->pn_type != TOK_NAME) { + *answer = JS_TRUE; + } else { + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + if (!CheckSideEffects(cx, cg, pn->pn_right, answer)) + return JS_FALSE; + if (!*answer && + (pn->pn_op != JSOP_NOP || + pn2->pn_slot < 0 || + !pn2->pn_const)) { + *answer = JS_TRUE; + } + } + } else { + if (pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND || + pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) { + /* + * ||, &&, ===, and !== do not convert their operands via + * toString or valueOf method calls. + */ + ok = CheckSideEffects(cx, cg, pn->pn_left, answer) && + CheckSideEffects(cx, cg, pn->pn_right, answer); + } else { + /* + * We can't easily prove that neither operand ever denotes an + * object with a toString or valueOf method. + */ + *answer = JS_TRUE; + } + } + break; + + case PN_UNARY: + switch (pn->pn_type) { + case TOK_RP: + ok = CheckSideEffects(cx, cg, pn->pn_kid, answer); + break; + + case TOK_DELETE: + pn2 = pn->pn_kid; + switch (pn2->pn_type) { + case TOK_NAME: + case TOK_DOT: +#if JS_HAS_XML_SUPPORT + case TOK_DBLDOT: +#endif +#if JS_HAS_LVALUE_RETURN + case TOK_LP: +#endif + case TOK_LB: + /* All these delete addressing modes have effects too. */ + *answer = JS_TRUE; + break; + default: + ok = CheckSideEffects(cx, cg, pn2, answer); + break; + } + break; + + case TOK_UNARYOP: + if (pn->pn_op == JSOP_NOT) { + /* ! does not convert its operand via toString or valueOf. */ + ok = CheckSideEffects(cx, cg, pn->pn_kid, answer); + break; + } + /* FALL THROUGH */ + + default: + /* + * All of TOK_INC, TOK_DEC, TOK_THROW, TOK_YIELD, and TOK_DEFSHARP + * have direct effects. Of the remaining unary-arity node types, + * we can't easily prove that the operand never denotes an object + * with a toString or valueOf method. + */ + *answer = JS_TRUE; + break; + } + break; + + case PN_NAME: + /* + * Take care to avoid trying to bind a label name (labels, both for + * statements and property values in object initialisers, have pn_op + * defaulted to JSOP_NOP). + */ + if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) { + if (!BindNameToSlot(cx, cg, pn)) + return JS_FALSE; + if (pn->pn_slot < 0 && pn->pn_op != JSOP_ARGUMENTS) { + /* + * Not an argument or local variable use, so this expression + * could invoke a getter that has side effects. + */ + *answer = JS_TRUE; + } + } + pn2 = pn->pn_expr; + if (pn->pn_type == TOK_DOT) { + if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + if (!(pn2->pn_op == JSOP_ARGUMENTS && + pn->pn_atom == cx->runtime->atomState.lengthAtom)) { + /* + * Any dotted property reference could call a getter, except + * for arguments.length where arguments is unambiguous. + */ + *answer = JS_TRUE; + } + } + ok = CheckSideEffects(cx, cg, pn2, answer); + break; + + case PN_NULLARY: + if (pn->pn_type == TOK_DEBUGGER) + *answer = JS_TRUE; + break; + } + return ok; +} + +static JSBool +EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, + JSBool callContext) +{ + JSOp op; + + if (!BindNameToSlot(cx, cg, pn)) + return JS_FALSE; + op = PN_OP(pn); + + if (callContext) { + switch (op) { + case JSOP_NAME: + op = JSOP_CALLNAME; + break; + case JSOP_GETGVAR: + op = JSOP_CALLGVAR; + break; + case JSOP_GETARG: + op = JSOP_CALLARG; + break; + case JSOP_GETLOCAL: + op = JSOP_CALLLOCAL; + break; + case JSOP_GETUPVAR: + op = JSOP_CALLUPVAR; + break; + default: + JS_ASSERT(op == JSOP_ARGUMENTS); + break; + } + } + + if (op == JSOP_ARGUMENTS) { + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + if (callContext && js_Emit1(cx, cg, JSOP_NULL) < 0) + return JS_FALSE; + } else { + if (pn->pn_slot >= 0) { + EMIT_UINT16_IMM_OP(op, pn->pn_slot); + } else { + if (!EmitAtomOp(cx, pn, op, cg)) + return JS_FALSE; + } + } + + return JS_TRUE; +} + +#if JS_HAS_XML_SUPPORT +static JSBool +EmitXMLName(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +{ + JSParseNode *pn2; + uintN oldflags; + + JS_ASSERT(pn->pn_type == TOK_UNARYOP); + JS_ASSERT(pn->pn_op == JSOP_XMLNAME); + JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME); + + pn2 = pn->pn_kid; + oldflags = cg->treeContext.flags; + cg->treeContext.flags &= ~TCF_IN_FOR_INIT; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, + CG_OFFSET(cg) - pn2->pn_offset) < 0) { + return JS_FALSE; + } + + return js_Emit1(cx, cg, op) >= 0; +} +#endif + +static JSBool +EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg, + JSBool callContext) +{ + JSParseNode *pn2, *pndot, *pnup, *pndown; + ptrdiff_t top; + + pn2 = pn->pn_expr; + if (callContext) { + JS_ASSERT(pn->pn_type == TOK_DOT); + JS_ASSERT(op == JSOP_GETPROP); + op = JSOP_CALLPROP; + } else if (op == JSOP_GETPROP && pn->pn_type == TOK_DOT) { + if (pn2->pn_op == JSOP_THIS) { + if (pn->pn_atom != cx->runtime->atomState.lengthAtom) { + /* Fast path for gets of |this.foo|. */ + return EmitAtomOp(cx, pn, JSOP_GETTHISPROP, cg); + } + } else if (pn2->pn_type == TOK_NAME) { + /* + * Try to optimize: + * - arguments.length into JSOP_ARGCNT + * - argname.prop into JSOP_GETARGPROP + * - localname.prop into JSOP_GETLOCALPROP + * but don't do this if the property is 'length' -- prefer to emit + * JSOP_GETARG, etc., and then JSOP_LENGTH. + */ + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + if (pn->pn_atom == cx->runtime->atomState.lengthAtom) { + if (pn2->pn_op == JSOP_ARGUMENTS) + return js_Emit1(cx, cg, JSOP_ARGCNT) >= 0; + } else { + switch (pn2->pn_op) { + case JSOP_GETARG: + op = JSOP_GETARGPROP; + goto do_indexconst; + case JSOP_GETLOCAL: + op = JSOP_GETLOCALPROP; + do_indexconst: { + JSAtomListElement *ale; + jsatomid atomIndex; + + ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList); + if (!ale) + return JS_FALSE; + atomIndex = ALE_INDEX(ale); + return EmitSlotIndexOp(cx, op, pn2->pn_slot, atomIndex, cg); + } + + default:; + } + } + } + } + + /* + * If the object operand is also a dotted property reference, reverse the + * list linked via pn_expr temporarily so we can iterate over it from the + * bottom up (reversing again as we go), to avoid excessive recursion. + */ + if (pn2->pn_type == TOK_DOT) { + pndot = pn2; + pnup = NULL; + top = CG_OFFSET(cg); + for (;;) { + /* Reverse pndot->pn_expr to point up, not down. */ + pndot->pn_offset = top; + pndown = pndot->pn_expr; + pndot->pn_expr = pnup; + if (pndown->pn_type != TOK_DOT) + break; + pnup = pndot; + pndot = pndown; + } + + /* pndown is a primary expression, not a dotted property reference. */ + if (!js_EmitTree(cx, cg, pndown)) + return JS_FALSE; + + do { + /* Walk back up the list, emitting annotated name ops. */ + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, + CG_OFFSET(cg) - pndown->pn_offset) < 0) { + return JS_FALSE; + } + if (!EmitAtomOp(cx, pndot, PN_OP(pndot), cg)) + return JS_FALSE; + + /* Reverse the pn_expr link again. */ + pnup = pndot->pn_expr; + pndot->pn_expr = pndown; + pndown = pndot; + } while ((pndot = pnup) != NULL); + } else { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } + + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, + CG_OFFSET(cg) - pn2->pn_offset) < 0) { + return JS_FALSE; + } + + return EmitAtomOp(cx, pn, op, cg); +} + +static JSBool +EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +{ + ptrdiff_t top; + JSParseNode *left, *right, *next, ltmp, rtmp; + jsint slot; + + top = CG_OFFSET(cg); + if (pn->pn_arity == PN_LIST) { + /* Left-associative operator chain to avoid too much recursion. */ + JS_ASSERT(pn->pn_op == JSOP_GETELEM); + JS_ASSERT(pn->pn_count >= 3); + left = pn->pn_head; + right = PN_LAST(pn); + next = left->pn_next; + JS_ASSERT(next != right); + + /* + * Try to optimize arguments[0][j]... into JSOP_ARGSUB<0> followed by + * one or more index expression and JSOP_GETELEM op pairs. + */ + if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) { + if (!BindNameToSlot(cx, cg, left)) + return JS_FALSE; + if (left->pn_op == JSOP_ARGUMENTS && + JSDOUBLE_IS_INT(next->pn_dval, slot) && + (jsuint)slot < JS_BIT(16)) { + /* + * arguments[i]() requires arguments object as "this". + * Check that we never generates list for that usage. + */ + JS_ASSERT(op != JSOP_CALLELEM || next->pn_next); + left->pn_offset = next->pn_offset = top; + EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot); + left = next; + next = left->pn_next; + } + } + + /* + * Check whether we generated JSOP_ARGSUB, just above, and have only + * one more index expression to emit. Given arguments[0][j], we must + * skip the while loop altogether, falling through to emit code for j + * (in the subtree referenced by right), followed by the annotated op, + * at the bottom of this function. + */ + JS_ASSERT(next != right || pn->pn_count == 3); + if (left == pn->pn_head) { + if (!js_EmitTree(cx, cg, left)) + return JS_FALSE; + } + while (next != right) { + if (!js_EmitTree(cx, cg, next)) + return JS_FALSE; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_GETELEM) < 0) + return JS_FALSE; + next = next->pn_next; + } + } else { + if (pn->pn_arity == PN_NAME) { + /* + * Set left and right so pn appears to be a TOK_LB node, instead + * of a TOK_DOT node. See the TOK_FOR/IN case in js_EmitTree, and + * EmitDestructuringOps nearer below. In the destructuring case, + * the base expression (pn_expr) of the name may be null, which + * means we have to emit a JSOP_BINDNAME. + */ + left = pn->pn_expr; + if (!left) { + left = <mp; + left->pn_type = TOK_STRING; + left->pn_op = JSOP_BINDNAME; + left->pn_arity = PN_NULLARY; + left->pn_pos = pn->pn_pos; + left->pn_atom = pn->pn_atom; + } + right = &rtmp; + right->pn_type = TOK_STRING; + JS_ASSERT(ATOM_IS_STRING(pn->pn_atom)); + right->pn_op = js_IsIdentifier(ATOM_TO_STRING(pn->pn_atom)) + ? JSOP_QNAMEPART + : JSOP_STRING; + right->pn_arity = PN_NULLARY; + right->pn_pos = pn->pn_pos; + right->pn_atom = pn->pn_atom; + } else { + JS_ASSERT(pn->pn_arity == PN_BINARY); + left = pn->pn_left; + right = pn->pn_right; + } + + /* Try to optimize arguments[0] (e.g.) into JSOP_ARGSUB<0>. */ + if (op == JSOP_GETELEM && + left->pn_type == TOK_NAME && + right->pn_type == TOK_NUMBER) { + if (!BindNameToSlot(cx, cg, left)) + return JS_FALSE; + if (left->pn_op == JSOP_ARGUMENTS && + JSDOUBLE_IS_INT(right->pn_dval, slot) && + (jsuint)slot < JS_BIT(16)) { + left->pn_offset = right->pn_offset = top; + EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot); + return JS_TRUE; + } + } + + if (!js_EmitTree(cx, cg, left)) + return JS_FALSE; + } + + /* The right side of the descendant operator is implicitly quoted. */ + JS_ASSERT(op != JSOP_DESCENDANTS || right->pn_type != TOK_STRING || + right->pn_op == JSOP_QNAMEPART); + if (!js_EmitTree(cx, cg, right)) + return JS_FALSE; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return JS_FALSE; + return js_Emit1(cx, cg, op) >= 0; +} + +static JSBool +EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg) +{ + jsint ival; + uint32 u; + ptrdiff_t off; + jsbytecode *pc; + JSAtom *atom; + JSAtomListElement *ale; + + if (JSDOUBLE_IS_INT(dval, ival) && INT_FITS_IN_JSVAL(ival)) { + if (ival == 0) + return js_Emit1(cx, cg, JSOP_ZERO) >= 0; + if (ival == 1) + return js_Emit1(cx, cg, JSOP_ONE) >= 0; + if ((jsint)(int8)ival == ival) + return js_Emit2(cx, cg, JSOP_INT8, (jsbytecode)(int8)ival) >= 0; + + u = (uint32)ival; + if (u < JS_BIT(16)) { + EMIT_UINT16_IMM_OP(JSOP_UINT16, u); + } else if (u < JS_BIT(24)) { + off = js_EmitN(cx, cg, JSOP_UINT24, 3); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_UINT24(pc, u); + } else { + off = js_EmitN(cx, cg, JSOP_INT32, 4); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_INT32(pc, ival); + } + return JS_TRUE; + } + + atom = js_AtomizeDouble(cx, dval); + if (!atom) + return JS_FALSE; + + ale = js_IndexAtom(cx, atom, &cg->atomList); + if (!ale) + return JS_FALSE; + return EmitIndexOp(cx, JSOP_DOUBLE, ALE_INDEX(ale), cg); +} + +static JSBool +EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, + JSStmtInfo *stmtInfo) +{ + JSOp switchOp; + JSBool ok, hasDefault, constPropagated; + ptrdiff_t top, off, defaultOffset; + JSParseNode *pn2, *pn3, *pn4; + uint32 caseCount, tableLength; + JSParseNode **table; + jsdouble d; + jsint i, low, high; + jsval v; + JSAtom *atom; + JSAtomListElement *ale; + intN noteIndex; + size_t switchSize, tableSize; + jsbytecode *pc, *savepc; +#if JS_HAS_BLOCK_SCOPE + jsint count; +#endif + + /* Try for most optimal, fall back if not dense ints, and per ECMAv2. */ + switchOp = JSOP_TABLESWITCH; + ok = JS_TRUE; + hasDefault = constPropagated = JS_FALSE; + defaultOffset = -1; + + /* + * If the switch contains let variables scoped by its body, model the + * resulting block on the stack first, before emitting the discriminant's + * bytecode (in case the discriminant contains a stack-model dependency + * such as a let expression). + */ + pn2 = pn->pn_right; +#if JS_HAS_BLOCK_SCOPE + if (pn2->pn_type == TOK_LEXICALSCOPE) { + /* + * Push the body's block scope before discriminant code-gen for proper + * static block scope linkage in case the discriminant contains a let + * expression. The block's locals must lie under the discriminant on + * the stack so that case-dispatch bytecodes can find the discriminant + * on top of stack. + */ + count = OBJ_BLOCK_COUNT(cx, pn2->pn_pob->object); + js_PushBlockScope(&cg->treeContext, stmtInfo, pn2->pn_pob->object, -1); + stmtInfo->type = STMT_SWITCH; + + /* Emit JSOP_ENTERBLOCK before code to evaluate the discriminant. */ + if (!EmitObjectOp(cx, pn2->pn_pob, JSOP_ENTERBLOCK, cg)) + return JS_FALSE; + + /* + * Pop the switch's statement info around discriminant code-gen. Note + * how this leaves cg->treeContext.blockChain referencing the switch's + * block scope object, which is necessary for correct block parenting + * in the case where the discriminant contains a let expression. + */ + cg->treeContext.topStmt = stmtInfo->down; + cg->treeContext.topScopeStmt = stmtInfo->downScope; + } +#ifdef __GNUC__ + else { + count = 0; + } +#endif +#endif + + /* + * Emit code for the discriminant first (or nearly first, in the case of a + * switch whose body is a block scope). + */ + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + + /* Switch bytecodes run from here till end of final case. */ + top = CG_OFFSET(cg); +#if !JS_HAS_BLOCK_SCOPE + js_PushStatement(&cg->treeContext, stmtInfo, STMT_SWITCH, top); +#else + if (pn2->pn_type == TOK_LC) { + js_PushStatement(&cg->treeContext, stmtInfo, STMT_SWITCH, top); + } else { + /* Re-push the switch's statement info record. */ + cg->treeContext.topStmt = cg->treeContext.topScopeStmt = stmtInfo; + + /* Set the statement info record's idea of top. */ + stmtInfo->update = top; + + /* Advance pn2 to refer to the switch case list. */ + pn2 = pn2->pn_expr; + } +#endif + + caseCount = pn2->pn_count; + tableLength = 0; + table = NULL; + + if (caseCount == 0 || + (caseCount == 1 && + (hasDefault = (pn2->pn_head->pn_type == TOK_DEFAULT)))) { + caseCount = 0; + low = 0; + high = -1; + } else { +#define INTMAP_LENGTH 256 + jsbitmap intmap_space[INTMAP_LENGTH]; + jsbitmap *intmap = NULL; + int32 intmap_bitlen = 0; + + low = JSVAL_INT_MAX; + high = JSVAL_INT_MIN; + + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + if (pn3->pn_type == TOK_DEFAULT) { + hasDefault = JS_TRUE; + caseCount--; /* one of the "cases" was the default */ + continue; + } + + JS_ASSERT(pn3->pn_type == TOK_CASE); + if (switchOp == JSOP_CONDSWITCH) + continue; + + pn4 = pn3->pn_left; + switch (pn4->pn_type) { + case TOK_NUMBER: + d = pn4->pn_dval; + if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) { + pn3->pn_val = INT_TO_JSVAL(i); + } else { + atom = js_AtomizeDouble(cx, d); + if (!atom) { + ok = JS_FALSE; + goto release; + } + pn3->pn_val = ATOM_KEY(atom); + } + break; + case TOK_STRING: + pn3->pn_val = ATOM_KEY(pn4->pn_atom); + break; + case TOK_NAME: + if (!pn4->pn_expr) { + ok = LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &v); + if (!ok) + goto release; + if (v != JSVAL_HOLE) { + if (!JSVAL_IS_PRIMITIVE(v)) { + /* + * XXX JSOP_LOOKUPSWITCH does not support const- + * propagated object values, see bug 407186. + */ + switchOp = JSOP_CONDSWITCH; + continue; + } + pn3->pn_val = v; + constPropagated = JS_TRUE; + break; + } + } + /* FALL THROUGH */ + case TOK_PRIMARY: + if (pn4->pn_op == JSOP_TRUE) { + pn3->pn_val = JSVAL_TRUE; + break; + } + if (pn4->pn_op == JSOP_FALSE) { + pn3->pn_val = JSVAL_FALSE; + break; + } + /* FALL THROUGH */ + default: + switchOp = JSOP_CONDSWITCH; + continue; + } + + JS_ASSERT(JSVAL_IS_PRIMITIVE(pn3->pn_val)); + + if (switchOp != JSOP_TABLESWITCH) + continue; + if (!JSVAL_IS_INT(pn3->pn_val)) { + switchOp = JSOP_LOOKUPSWITCH; + continue; + } + i = JSVAL_TO_INT(pn3->pn_val); + if ((jsuint)(i + (jsint)JS_BIT(15)) >= (jsuint)JS_BIT(16)) { + switchOp = JSOP_LOOKUPSWITCH; + continue; + } + if (i < low) + low = i; + if (high < i) + high = i; + + /* + * Check for duplicates, which require a JSOP_LOOKUPSWITCH. + * We bias i by 65536 if it's negative, and hope that's a rare + * case (because it requires a malloc'd bitmap). + */ + if (i < 0) + i += JS_BIT(16); + if (i >= intmap_bitlen) { + if (!intmap && + i < (INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2)) { + intmap = intmap_space; + intmap_bitlen = INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2; + } else { + /* Just grab 8K for the worst-case bitmap. */ + intmap_bitlen = JS_BIT(16); + intmap = (jsbitmap *) + JS_malloc(cx, + (JS_BIT(16) >> JS_BITS_PER_WORD_LOG2) + * sizeof(jsbitmap)); + if (!intmap) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + } + memset(intmap, 0, intmap_bitlen >> JS_BITS_PER_BYTE_LOG2); + } + if (JS_TEST_BIT(intmap, i)) { + switchOp = JSOP_LOOKUPSWITCH; + continue; + } + JS_SET_BIT(intmap, i); + } + + release: + if (intmap && intmap != intmap_space) + JS_free(cx, intmap); + if (!ok) + return JS_FALSE; + + /* + * Compute table length and select lookup instead if overlarge or + * more than half-sparse. + */ + if (switchOp == JSOP_TABLESWITCH) { + tableLength = (uint32)(high - low + 1); + if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount) + switchOp = JSOP_LOOKUPSWITCH; + } else if (switchOp == JSOP_LOOKUPSWITCH) { + /* + * Lookup switch supports only atom indexes below 64K limit. + * Conservatively estimate the maximum possible index during + * switch generation and use conditional switch if it exceeds + * the limit. + */ + if (caseCount + cg->atomList.count > JS_BIT(16)) + switchOp = JSOP_CONDSWITCH; + } + } + + /* + * Emit a note with two offsets: first tells total switch code length, + * second tells offset to first JSOP_CASE if condswitch. + */ + noteIndex = js_NewSrcNote3(cx, cg, SRC_SWITCH, 0, 0); + if (noteIndex < 0) + return JS_FALSE; + + if (switchOp == JSOP_CONDSWITCH) { + /* + * 0 bytes of immediate for unoptimized ECMAv2 switch. + */ + switchSize = 0; + } else if (switchOp == JSOP_TABLESWITCH) { + /* + * 3 offsets (len, low, high) before the table, 1 per entry. + */ + switchSize = (size_t)(JUMP_OFFSET_LEN * (3 + tableLength)); + } else { + /* + * JSOP_LOOKUPSWITCH: + * 1 offset (len) and 1 atom index (npairs) before the table, + * 1 atom index and 1 jump offset per entry. + */ + switchSize = (size_t)(JUMP_OFFSET_LEN + INDEX_LEN + + (INDEX_LEN + JUMP_OFFSET_LEN) * caseCount); + } + + /* + * Emit switchOp followed by switchSize bytes of jump or lookup table. + * + * If switchOp is JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH, it is crucial + * to emit the immediate operand(s) by which bytecode readers such as + * BuildSpanDepTable discover the length of the switch opcode *before* + * calling js_SetJumpOffset (which may call BuildSpanDepTable). It's + * also important to zero all unknown jump offset immediate operands, + * so they can be converted to span dependencies with null targets to + * be computed later (js_EmitN zeros switchSize bytes after switchOp). + */ + if (js_EmitN(cx, cg, switchOp, switchSize) < 0) + return JS_FALSE; + + off = -1; + if (switchOp == JSOP_CONDSWITCH) { + intN caseNoteIndex = -1; + JSBool beforeCases = JS_TRUE; + + /* Emit code for evaluating cases and jumping to case statements. */ + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + pn4 = pn3->pn_left; + if (pn4 && !js_EmitTree(cx, cg, pn4)) + return JS_FALSE; + if (caseNoteIndex >= 0) { + /* off is the previous JSOP_CASE's bytecode offset. */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0, + CG_OFFSET(cg) - off)) { + return JS_FALSE; + } + } + if (!pn4) { + JS_ASSERT(pn3->pn_type == TOK_DEFAULT); + continue; + } + caseNoteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + if (caseNoteIndex < 0) + return JS_FALSE; + off = EmitJump(cx, cg, JSOP_CASE, 0); + if (off < 0) + return JS_FALSE; + pn3->pn_offset = off; + if (beforeCases) { + uintN noteCount, noteCountDelta; + + /* Switch note's second offset is to first JSOP_CASE. */ + noteCount = CG_NOTE_COUNT(cg); + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, + off - top)) { + return JS_FALSE; + } + noteCountDelta = CG_NOTE_COUNT(cg) - noteCount; + if (noteCountDelta != 0) + caseNoteIndex += noteCountDelta; + beforeCases = JS_FALSE; + } + } + + /* + * If we didn't have an explicit default (which could fall in between + * cases, preventing us from fusing this js_SetSrcNoteOffset with the + * call in the loop above), link the last case to the implicit default + * for the decompiler. + */ + if (!hasDefault && + caseNoteIndex >= 0 && + !js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0, + CG_OFFSET(cg) - off)) { + return JS_FALSE; + } + + /* Emit default even if no explicit default statement. */ + defaultOffset = EmitJump(cx, cg, JSOP_DEFAULT, 0); + if (defaultOffset < 0) + return JS_FALSE; + } else { + pc = CG_CODE(cg, top + JUMP_OFFSET_LEN); + + if (switchOp == JSOP_TABLESWITCH) { + /* Fill in switch bounds, which we know fit in 16-bit offsets. */ + SET_JUMP_OFFSET(pc, low); + pc += JUMP_OFFSET_LEN; + SET_JUMP_OFFSET(pc, high); + pc += JUMP_OFFSET_LEN; + + /* + * Use malloc to avoid arena bloat for programs with many switches. + * We free table if non-null at label out, so all control flow must + * exit this function through goto out or goto bad. + */ + if (tableLength != 0) { + tableSize = (size_t)tableLength * sizeof *table; + table = (JSParseNode **) JS_malloc(cx, tableSize); + if (!table) + return JS_FALSE; + memset(table, 0, tableSize); + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + if (pn3->pn_type == TOK_DEFAULT) + continue; + i = JSVAL_TO_INT(pn3->pn_val); + i -= low; + JS_ASSERT((uint32)i < tableLength); + table[i] = pn3; + } + } + } else { + JS_ASSERT(switchOp == JSOP_LOOKUPSWITCH); + + /* Fill in the number of cases. */ + SET_INDEX(pc, caseCount); + pc += INDEX_LEN; + } + + /* + * After this point, all control flow involving JSOP_TABLESWITCH + * must set ok and goto out to exit this function. To keep things + * simple, all switchOp cases exit that way. + */ + MUST_FLOW_THROUGH("out"); + if (cg->spanDeps) { + /* + * We have already generated at least one big jump so we must + * explicitly add span dependencies for the switch jumps. When + * called below, js_SetJumpOffset can only do it when patching + * the first big jump or when cg->spanDeps is null. + */ + if (!AddSwitchSpanDeps(cx, cg, CG_CODE(cg, top))) + goto bad; + } + + if (constPropagated) { + /* + * Skip switchOp, as we are not setting jump offsets in the two + * for loops below. We'll restore CG_NEXT(cg) from savepc after, + * unless there was an error. + */ + savepc = CG_NEXT(cg); + CG_NEXT(cg) = pc + 1; + if (switchOp == JSOP_TABLESWITCH) { + for (i = 0; i < (jsint)tableLength; i++) { + pn3 = table[i]; + if (pn3 && + (pn4 = pn3->pn_left) != NULL && + pn4->pn_type == TOK_NAME) { + /* Note a propagated constant with the const's name. */ + JS_ASSERT(!pn4->pn_expr); + ale = js_IndexAtom(cx, pn4->pn_atom, &cg->atomList); + if (!ale) + goto bad; + CG_NEXT(cg) = pc; + if (js_NewSrcNote2(cx, cg, SRC_LABEL, (ptrdiff_t) + ALE_INDEX(ale)) < 0) { + goto bad; + } + } + pc += JUMP_OFFSET_LEN; + } + } else { + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + pn4 = pn3->pn_left; + if (pn4 && pn4->pn_type == TOK_NAME) { + /* Note a propagated constant with the const's name. */ + JS_ASSERT(!pn4->pn_expr); + ale = js_IndexAtom(cx, pn4->pn_atom, &cg->atomList); + if (!ale) + goto bad; + CG_NEXT(cg) = pc; + if (js_NewSrcNote2(cx, cg, SRC_LABEL, (ptrdiff_t) + ALE_INDEX(ale)) < 0) { + goto bad; + } + } + pc += INDEX_LEN + JUMP_OFFSET_LEN; + } + } + CG_NEXT(cg) = savepc; + } + } + + /* Emit code for each case's statements, copying pn_offset up to pn3. */ + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + if (switchOp == JSOP_CONDSWITCH && pn3->pn_type != TOK_DEFAULT) + CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, pn3->pn_offset, goto bad); + pn4 = pn3->pn_right; + ok = js_EmitTree(cx, cg, pn4); + if (!ok) + goto out; + pn3->pn_offset = pn4->pn_offset; + if (pn3->pn_type == TOK_DEFAULT) + off = pn3->pn_offset - top; + } + + if (!hasDefault) { + /* If no default case, offset for default is to end of switch. */ + off = CG_OFFSET(cg) - top; + } + + /* We better have set "off" by now. */ + JS_ASSERT(off != -1); + + /* Set the default offset (to end of switch if no default). */ + if (switchOp == JSOP_CONDSWITCH) { + pc = NULL; + JS_ASSERT(defaultOffset != -1); + ok = js_SetJumpOffset(cx, cg, CG_CODE(cg, defaultOffset), + off - (defaultOffset - top)); + if (!ok) + goto out; + } else { + pc = CG_CODE(cg, top); + ok = js_SetJumpOffset(cx, cg, pc, off); + if (!ok) + goto out; + pc += JUMP_OFFSET_LEN; + } + + /* Set the SRC_SWITCH note's offset operand to tell end of switch. */ + off = CG_OFFSET(cg) - top; + ok = js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, off); + if (!ok) + goto out; + + if (switchOp == JSOP_TABLESWITCH) { + /* Skip over the already-initialized switch bounds. */ + pc += 2 * JUMP_OFFSET_LEN; + + /* Fill in the jump table, if there is one. */ + for (i = 0; i < (jsint)tableLength; i++) { + pn3 = table[i]; + off = pn3 ? pn3->pn_offset - top : 0; + ok = js_SetJumpOffset(cx, cg, pc, off); + if (!ok) + goto out; + pc += JUMP_OFFSET_LEN; + } + } else if (switchOp == JSOP_LOOKUPSWITCH) { + /* Skip over the already-initialized number of cases. */ + pc += INDEX_LEN; + + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + if (pn3->pn_type == TOK_DEFAULT) + continue; + if (!js_AtomizePrimitiveValue(cx, pn3->pn_val, &atom)) + goto bad; + ale = js_IndexAtom(cx, atom, &cg->atomList); + if (!ale) + goto bad; + SET_INDEX(pc, ALE_INDEX(ale)); + pc += INDEX_LEN; + + off = pn3->pn_offset - top; + ok = js_SetJumpOffset(cx, cg, pc, off); + if (!ok) + goto out; + pc += JUMP_OFFSET_LEN; + } + } + +out: + if (table) + JS_free(cx, table); + if (ok) { + ok = js_PopStatementCG(cx, cg); + +#if JS_HAS_BLOCK_SCOPE + if (ok && pn->pn_right->pn_type == TOK_LEXICALSCOPE) + EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, count); +#endif + } + return ok; + +bad: + ok = JS_FALSE; + goto out; +} + +JSBool +js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body) +{ + if (cg->treeContext.flags & TCF_FUN_IS_GENERATOR) { + /* JSOP_GENERATOR must be the first instruction. */ + CG_SWITCH_TO_PROLOG(cg); + JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg)); + if (js_Emit1(cx, cg, JSOP_GENERATOR) < 0) + return JS_FALSE; + CG_SWITCH_TO_MAIN(cg); + } + + return js_EmitTree(cx, cg, body) && + js_Emit1(cx, cg, JSOP_STOP) >= 0 && + js_NewScriptFromCG(cx, cg); +} + +/* A macro for inlining at the top of js_EmitTree (whence it came). */ +#define UPDATE_LINE_NUMBER_NOTES(cx, cg, pn) \ + JS_BEGIN_MACRO \ + uintN line_ = (pn)->pn_pos.begin.lineno; \ + uintN delta_ = line_ - CG_CURRENT_LINE(cg); \ + if (delta_ != 0) { \ + /* \ + * Encode any change in the current source line number by using \ + * either several SRC_NEWLINE notes or just one SRC_SETLINE note, \ + * whichever consumes less space. \ + * \ + * NB: We handle backward line number deltas (possible with for \ + * loops where the update part is emitted after the body, but its \ + * line number is <= any line number in the body) here by letting \ + * unsigned delta_ wrap to a very large number, which triggers a \ + * SRC_SETLINE. \ + */ \ + CG_CURRENT_LINE(cg) = line_; \ + if (delta_ >= (uintN)(2 + ((line_ > SN_3BYTE_OFFSET_MASK)<<1))) { \ + if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)line_) < 0)\ + return JS_FALSE; \ + } else { \ + do { \ + if (js_NewSrcNote(cx, cg, SRC_NEWLINE) < 0) \ + return JS_FALSE; \ + } while (--delta_ != 0); \ + } \ + } \ + JS_END_MACRO + +/* A function, so that we avoid macro-bloating all the other callsites. */ +static JSBool +UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +{ + UPDATE_LINE_NUMBER_NOTES(cx, cg, pn); + return JS_TRUE; +} + +static JSBool +MaybeEmitVarDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *pn, jsatomid *result) +{ + jsatomid atomIndex; + JSAtomListElement *ale; + + if (pn->pn_slot >= 0) { + atomIndex = (jsatomid) pn->pn_slot; + } else { + ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList); + if (!ale) + return JS_FALSE; + atomIndex = ALE_INDEX(ale); + } + + if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM && + (!(cg->treeContext.flags & TCF_IN_FUNCTION) || + (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT))) { + /* Emit a prolog bytecode to predefine the variable. */ + CG_SWITCH_TO_PROLOG(cg); + if (!UpdateLineNumberNotes(cx, cg, pn)) + return JS_FALSE; + EMIT_INDEX_OP(prologOp, atomIndex); + CG_SWITCH_TO_MAIN(cg); + } + + if (result) + *result = atomIndex; + return JS_TRUE; +} + +#if JS_HAS_DESTRUCTURING + +typedef JSBool +(*DestructuringDeclEmitter)(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *pn); + +static JSBool +EmitDestructuringDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *pn) +{ + JS_ASSERT(pn->pn_type == TOK_NAME); + if (!BindNameToSlot(cx, cg, pn)) + return JS_FALSE; + + JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS); + return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL); +} + +static JSBool +EmitDestructuringDecls(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *pn) +{ + JSParseNode *pn2, *pn3; + DestructuringDeclEmitter emitter; + + if (pn->pn_type == TOK_RB) { + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (pn2->pn_type == TOK_COMMA) + continue; + emitter = (pn2->pn_type == TOK_NAME) + ? EmitDestructuringDecl + : EmitDestructuringDecls; + if (!emitter(cx, cg, prologOp, pn2)) + return JS_FALSE; + } + } else { + JS_ASSERT(pn->pn_type == TOK_RC); + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + pn3 = pn2->pn_right; + emitter = (pn3->pn_type == TOK_NAME) + ? EmitDestructuringDecl + : EmitDestructuringDecls; + if (!emitter(cx, cg, prologOp, pn3)) + return JS_FALSE; + } + } + return JS_TRUE; +} + +static JSBool +EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn); + +static JSBool +EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +{ + jsuint slot; + + /* Skip any parenthesization. */ + while (pn->pn_type == TOK_RP) + pn = pn->pn_kid; + + /* + * Now emit the lvalue opcode sequence. If the lvalue is a nested + * destructuring initialiser-form, call ourselves to handle it, then + * pop the matched value. Otherwise emit an lvalue bytecode sequence + * ending with a JSOP_ENUMELEM or equivalent op. + */ + if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) { + if (!EmitDestructuringOpsHelper(cx, cg, pn)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } else { + if (pn->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn)) + return JS_FALSE; + + switch (pn->pn_op) { + case JSOP_SETNAME: + /* + * NB: pn is a PN_NAME node, not a PN_BINARY. Nevertheless, + * we want to emit JSOP_ENUMELEM, which has format JOF_ELEM. + * So here and for JSOP_ENUMCONSTELEM, we use EmitElemOp. + */ + if (!EmitElemOp(cx, pn, JSOP_ENUMELEM, cg)) + return JS_FALSE; + break; + + case JSOP_SETCONST: + if (!EmitElemOp(cx, pn, JSOP_ENUMCONSTELEM, cg)) + return JS_FALSE; + break; + + case JSOP_SETLOCAL: + slot = (jsuint) pn->pn_slot; + EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot); + break; + + case JSOP_SETARG: + case JSOP_SETGVAR: + slot = (jsuint) pn->pn_slot; + EMIT_UINT16_IMM_OP(PN_OP(pn), slot); + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + break; + + default: +#if JS_HAS_LVALUE_RETURN || JS_HAS_XML_SUPPORT + { + ptrdiff_t top; + + top = CG_OFFSET(cg); + if (!js_EmitTree(cx, cg, pn)) + return JS_FALSE; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0) + return JS_FALSE; + break; + } +#endif + case JSOP_ENUMELEM: + JS_ASSERT(0); + } + } + + return JS_TRUE; +} + +/* + * Recursive helper for EmitDestructuringOps. + * + * Given a value to destructure on the stack, walk over an object or array + * initialiser at pn, emitting bytecodes to match property values and store + * them in the lvalues identified by the matched property names. + */ +static JSBool +EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +{ + jsuint index; + JSParseNode *pn2, *pn3; + JSBool doElemOp; + +#ifdef DEBUG + intN stackDepth = cg->stackDepth; + JS_ASSERT(stackDepth != 0); + JS_ASSERT(pn->pn_arity == PN_LIST); + JS_ASSERT(pn->pn_type == TOK_RB || pn->pn_type == TOK_RC); +#endif + + if (pn->pn_count == 0) { + /* Emit a DUP;POP sequence for the decompiler. */ + return js_Emit1(cx, cg, JSOP_DUP) >= 0 && + js_Emit1(cx, cg, JSOP_POP) >= 0; + } + + index = 0; + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + /* + * Duplicate the value being destructured to use as a reference base. + */ + if (js_Emit1(cx, cg, JSOP_DUP) < 0) + return JS_FALSE; + + /* + * Now push the property name currently being matched, which is either + * the array initialiser's current index, or the current property name + * "label" on the left of a colon in the object initialiser. Set pn3 + * to the lvalue node, which is in the value-initializing position. + */ + doElemOp = JS_TRUE; + if (pn->pn_type == TOK_RB) { + if (!EmitNumberOp(cx, index, cg)) + return JS_FALSE; + pn3 = pn2; + } else { + JS_ASSERT(pn->pn_type == TOK_RC); + JS_ASSERT(pn2->pn_type == TOK_COLON); + pn3 = pn2->pn_left; + if (pn3->pn_type == TOK_NUMBER) { + /* + * If we are emitting an object destructuring initialiser, + * annotate the index op with SRC_INITPROP so we know we are + * not decompiling an array initialiser. + */ + if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0) + return JS_FALSE; + if (!EmitNumberOp(cx, pn3->pn_dval, cg)) + return JS_FALSE; + } else { + JS_ASSERT(pn3->pn_type == TOK_STRING || + pn3->pn_type == TOK_NAME); + if (!EmitAtomOp(cx, pn3, JSOP_GETPROP, cg)) + return JS_FALSE; + doElemOp = JS_FALSE; + } + pn3 = pn2->pn_right; + } + + if (doElemOp) { + /* + * Ok, get the value of the matching property name. This leaves + * that value on top of the value being destructured, so the stack + * is one deeper than when we started. + */ + if (js_Emit1(cx, cg, JSOP_GETELEM) < 0) + return JS_FALSE; + JS_ASSERT(cg->stackDepth == stackDepth + 1); + } + + /* Nullary comma node makes a hole in the array destructurer. */ + if (pn3->pn_type == TOK_COMMA && pn3->pn_arity == PN_NULLARY) { + JS_ASSERT(pn->pn_type == TOK_RB); + JS_ASSERT(pn2 == pn3); + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } else { + if (!EmitDestructuringLHS(cx, cg, pn3)) + return JS_FALSE; + } + + JS_ASSERT(cg->stackDepth == stackDepth); + ++index; + } + + return JS_TRUE; +} + +static ptrdiff_t +OpToDeclType(JSOp op) +{ + switch (op) { + case JSOP_NOP: + return SRC_DECL_LET; + case JSOP_DEFCONST: + return SRC_DECL_CONST; + case JSOP_DEFVAR: + return SRC_DECL_VAR; + default: + return SRC_DECL_NONE; + } +} + +static JSBool +EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp declOp, + JSParseNode *pn) +{ + /* + * If we're called from a variable declaration, help the decompiler by + * annotating the first JSOP_DUP that EmitDestructuringOpsHelper emits. + * If the destructuring initialiser is empty, our helper will emit a + * JSOP_DUP followed by a JSOP_POP for the decompiler. + */ + if (js_NewSrcNote2(cx, cg, SRC_DESTRUCT, OpToDeclType(declOp)) < 0) + return JS_FALSE; + + /* + * Call our recursive helper to emit the destructuring assignments and + * related stack manipulations. + */ + return EmitDestructuringOpsHelper(cx, cg, pn); +} + +static JSBool +EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp declOp, + JSParseNode *lhs, JSParseNode *rhs) +{ + jsuint depth, limit, i, nslots; + JSParseNode *pn; + + depth = limit = (uintN) cg->stackDepth; + for (pn = rhs->pn_head; pn; pn = pn->pn_next) { + if (limit == JS_BIT(16)) { + js_ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, + JSMSG_ARRAY_INIT_TOO_BIG); + return JS_FALSE; + } + + if (pn->pn_type == TOK_COMMA) { + if (js_Emit1(cx, cg, JSOP_PUSH) < 0) + return JS_FALSE; + } else { + JS_ASSERT(pn->pn_type != TOK_DEFSHARP); + if (!js_EmitTree(cx, cg, pn)) + return JS_FALSE; + } + ++limit; + } + + if (js_NewSrcNote2(cx, cg, SRC_GROUPASSIGN, OpToDeclType(declOp)) < 0) + return JS_FALSE; + + i = depth; + for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) { + if (i < limit) { + jsint slot; + + slot = AdjustBlockSlot(cx, cg, i); + if (slot < 0) + return JS_FALSE; + EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot); + } else { + if (js_Emit1(cx, cg, JSOP_PUSH) < 0) + return JS_FALSE; + } + if (pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY) { + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } else { + if (!EmitDestructuringLHS(cx, cg, pn)) + return JS_FALSE; + } + } + + nslots = limit - depth; + EMIT_UINT16_IMM_OP(JSOP_POPN, nslots); + cg->stackDepth = (uintN) depth; + return JS_TRUE; +} + +/* + * Helper called with pop out param initialized to a JSOP_POP* opcode. If we + * can emit a group assignment sequence, which results in 0 stack depth delta, + * we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop. + */ +static JSBool +MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp declOp, + JSParseNode *pn, JSOp *pop) +{ + JSParseNode *lhs, *rhs; + + JS_ASSERT(pn->pn_type == TOK_ASSIGN); + JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV); + lhs = pn->pn_left; + rhs = pn->pn_right; + if (lhs->pn_type == TOK_RB && rhs->pn_type == TOK_RB && + lhs->pn_count <= rhs->pn_count && + (rhs->pn_count == 0 || + rhs->pn_head->pn_type != TOK_DEFSHARP)) { + if (!EmitGroupAssignment(cx, cg, declOp, lhs, rhs)) + return JS_FALSE; + *pop = JSOP_NOP; + } + return JS_TRUE; +} + +#endif /* JS_HAS_DESTRUCTURING */ + +static JSBool +EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, + JSBool inLetHead, ptrdiff_t *headNoteIndex) +{ + JSTreeContext *tc; + JSBool let, forInVar; +#if JS_HAS_BLOCK_SCOPE + JSBool forInLet, popScope; + JSStmtInfo *stmt, *scopeStmt; +#endif + ptrdiff_t off, noteIndex, tmp; + JSParseNode *pn2, *pn3; + JSOp op; + jsatomid atomIndex; + uintN oldflags; + + /* Default in case of JS_HAS_BLOCK_SCOPE early return, below. */ + *headNoteIndex = -1; + + /* + * Let blocks and expressions have a parenthesized head in which the new + * scope is not yet open. Initializer evaluation uses the parent node's + * lexical scope. If popScope is true below, then we hide the top lexical + * block from any calls to BindNameToSlot hiding in pn2->pn_expr so that + * it won't find any names in the new let block. + * + * The same goes for let declarations in the head of any kind of for loop. + * Unlike a let declaration 'let x = i' within a block, where x is hoisted + * to the start of the block, a 'for (let x = i...) ...' loop evaluates i + * in the containing scope, and puts x in the loop body's scope. + */ + tc = &cg->treeContext; + let = (pn->pn_op == JSOP_NOP); + forInVar = (pn->pn_extra & PNX_FORINVAR) != 0; +#if JS_HAS_BLOCK_SCOPE + forInLet = let && forInVar; + popScope = (inLetHead || (let && (tc->flags & TCF_IN_FOR_INIT))); + JS_ASSERT(!popScope || let); +#endif + + off = noteIndex = -1; + for (pn2 = pn->pn_head; ; pn2 = pn2->pn_next) { +#if JS_HAS_DESTRUCTURING + if (pn2->pn_type != TOK_NAME) { + if (pn2->pn_type == TOK_RB || pn2->pn_type == TOK_RC) { + /* + * Emit variable binding ops, but not destructuring ops. + * The parser (see Variables, jsparse.c) has ensured that + * our caller will be the TOK_FOR/TOK_IN case in js_EmitTree, + * and that case will emit the destructuring code only after + * emitting an enumerating opcode and a branch that tests + * whether the enumeration ended. + */ + JS_ASSERT(forInVar); + JS_ASSERT(pn->pn_count == 1); + if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn2)) + return JS_FALSE; + break; + } + + /* + * A destructuring initialiser assignment preceded by var will + * never occur to the left of 'in' in a for-in loop. As with 'for + * (var x = i in o)...', this will cause the entire 'var [a, b] = + * i' to be hoisted out of the loop. + */ + JS_ASSERT(pn2->pn_type == TOK_ASSIGN); + JS_ASSERT(!forInVar); + if (pn->pn_count == 1) { + /* + * If this is the only destructuring assignment in the list, + * try to optimize to a group assignment. If we're in a let + * head, pass JSOP_POP rather than the pseudo-prolog JSOP_NOP + * in pn->pn_op, to suppress a second (and misplaced) 'let'. + */ + JS_ASSERT(noteIndex < 0 && !pn2->pn_next); + op = JSOP_POP; + if (!MaybeEmitGroupAssignment(cx, cg, + inLetHead ? JSOP_POP : PN_OP(pn), + pn2, &op)) { + return JS_FALSE; + } + if (op == JSOP_NOP) { + pn->pn_extra = (pn->pn_extra & ~PNX_POPVAR) | PNX_GROUPINIT; + break; + } + } + + pn3 = pn2->pn_left; + if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn3)) + return JS_FALSE; + + if (!js_EmitTree(cx, cg, pn2->pn_right)) + return JS_FALSE; + + /* + * Veto pn->pn_op if inLetHead to avoid emitting a SRC_DESTRUCT + * that's redundant with respect to the SRC_DECL/SRC_DECL_LET that + * we will emit at the bottom of this function. + */ + if (!EmitDestructuringOps(cx, cg, + inLetHead ? JSOP_POP : PN_OP(pn), + pn3)) { + return JS_FALSE; + } + goto emit_note_pop; + } +#else + JS_ASSERT(pn2->pn_type == TOK_NAME); +#endif + + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + JS_ASSERT(pn2->pn_slot >= 0 || !let); + + op = PN_OP(pn2); + if (op == JSOP_ARGUMENTS) { + /* JSOP_ARGUMENTS => no initializer */ + JS_ASSERT(!pn2->pn_expr && !let); + pn3 = NULL; +#ifdef __GNUC__ + atomIndex = 0; /* quell GCC overwarning */ +#endif + } else { + if (!MaybeEmitVarDecl(cx, cg, PN_OP(pn), pn2, &atomIndex)) + return JS_FALSE; + + pn3 = pn2->pn_expr; + if (pn3) { + JS_ASSERT(!forInVar); + if (op == JSOP_SETNAME) { + JS_ASSERT(!let); + EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex); + } + if (pn->pn_op == JSOP_DEFCONST && + !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom, + pn3)) { + return JS_FALSE; + } + +#if JS_HAS_BLOCK_SCOPE + /* Evaluate expr in the outer lexical scope if requested. */ + if (popScope) { + stmt = tc->topStmt; + scopeStmt = tc->topScopeStmt; + + tc->topStmt = stmt->down; + tc->topScopeStmt = scopeStmt->downScope; + } +# ifdef __GNUC__ + else stmt = scopeStmt = NULL; /* quell GCC overwarning */ +# endif +#endif + + oldflags = cg->treeContext.flags; + cg->treeContext.flags &= ~TCF_IN_FOR_INIT; + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT; + +#if JS_HAS_BLOCK_SCOPE + if (popScope) { + tc->topStmt = stmt; + tc->topScopeStmt = scopeStmt; + } +#endif + } + } + + /* + * The parser rewrites 'for (var x = i in o)' to hoist 'var x = i' -- + * likewise 'for (let x = i in o)' becomes 'i; for (let x in o)' using + * a TOK_SEQ node to make the two statements appear as one. Therefore + * if this declaration is part of a for-in loop head, we do not need to + * emit op or any source note. Our caller, the TOK_FOR/TOK_IN case in + * js_EmitTree, will annotate appropriately. + */ + JS_ASSERT(pn3 == pn2->pn_expr); + if (forInVar) { + JS_ASSERT(pn->pn_count == 1); + JS_ASSERT(!pn3); + break; + } + + if (pn2 == pn->pn_head && + !inLetHead && + js_NewSrcNote2(cx, cg, SRC_DECL, + (pn->pn_op == JSOP_DEFCONST) + ? SRC_DECL_CONST + : (pn->pn_op == JSOP_DEFVAR) + ? SRC_DECL_VAR + : SRC_DECL_LET) < 0) { + return JS_FALSE; + } + if (op == JSOP_ARGUMENTS) { + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } else if (pn2->pn_slot >= 0) { + EMIT_UINT16_IMM_OP(op, atomIndex); + } else { + EMIT_INDEX_OP(op, atomIndex); + } + +#if JS_HAS_DESTRUCTURING + emit_note_pop: +#endif + tmp = CG_OFFSET(cg); + if (noteIndex >= 0) { + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) + return JS_FALSE; + } + if (!pn2->pn_next) + break; + off = tmp; + noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } + + /* If this is a let head, emit and return a srcnote on the pop. */ + if (inLetHead) { + *headNoteIndex = js_NewSrcNote(cx, cg, SRC_DECL); + if (*headNoteIndex < 0) + return JS_FALSE; + if (!(pn->pn_extra & PNX_POPVAR)) + return js_Emit1(cx, cg, JSOP_NOP) >= 0; + } + + return !(pn->pn_extra & PNX_POPVAR) || js_Emit1(cx, cg, JSOP_POP) >= 0; +} + +#if defined DEBUG_brendanXXX || defined DEBUG_mrbkap +static JSBool +GettableNoteForNextOp(JSCodeGenerator *cg) +{ + ptrdiff_t offset, target; + jssrcnote *sn, *end; + + offset = 0; + target = CG_OFFSET(cg); + for (sn = CG_NOTES(cg), end = sn + CG_NOTE_COUNT(cg); sn < end; + sn = SN_NEXT(sn)) { + if (offset == target && SN_IS_GETTABLE(sn)) + return JS_TRUE; + offset += SN_DELTA(sn); + } + return JS_FALSE; +} +#endif + +/* Top-level named functions need a nop for decompilation. */ +static JSBool +EmitFunctionDefNop(JSContext *cx, JSCodeGenerator *cg, uintN index) +{ + return js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)index) >= 0 && + js_Emit1(cx, cg, JSOP_NOP) >= 0; +} + +/* See the SRC_FOR source note offsetBias comments later in this file. */ +JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1); +JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1); + +JSBool +js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +{ + JSBool ok, useful, wantval; + JSStmtInfo *stmt, stmtInfo; + ptrdiff_t top, off, tmp, beq, jmp; + JSParseNode *pn2, *pn3; + JSAtom *atom; + JSAtomListElement *ale; + jsatomid atomIndex; + uintN index; + ptrdiff_t noteIndex; + JSSrcNoteType noteType; + jsbytecode *pc; + JSOp op; + JSTokenType type; + uint32 argc; + + JS_CHECK_RECURSION(cx, return JS_FALSE); + + ok = JS_TRUE; + cg->emitLevel++; + pn->pn_offset = top = CG_OFFSET(cg); + + /* Emit notes to tell the current bytecode's source line number. */ + UPDATE_LINE_NUMBER_NOTES(cx, cg, pn); + + switch (pn->pn_type) { + case TOK_FUNCTION: + { + JSFunction *fun; + void *cg2mark; + JSCodeGenerator *cg2; + uintN slot; + +#if JS_HAS_XML_SUPPORT + if (pn->pn_arity == PN_NULLARY) { + if (js_Emit1(cx, cg, JSOP_GETFUNNS) < 0) + return JS_FALSE; + break; + } +#endif + + fun = (JSFunction *) pn->pn_funpob->object; + if (fun->u.i.script) { + /* + * This second pass is needed to emit JSOP_NOP with a source note + * for the already-emitted function definition prolog opcode. See + * comments in the TOK_LC case. + */ + JS_ASSERT(pn->pn_op == JSOP_NOP); + JS_ASSERT(cg->treeContext.flags & TCF_IN_FUNCTION); + JS_ASSERT(pn->pn_index != (uint32) -1); + if (!EmitFunctionDefNop(cx, cg, pn->pn_index)) + return JS_FALSE; + break; + } + + /* + * Limit static nesting depth to fit in 16 bits. See cg2->staticDepth + * assignment below. + */ + if (cg->staticDepth == JS_BITMASK(16)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_DEEP, + js_function_str); + return JS_FALSE; + } + + /* Generate code for the function's body. */ + cg2mark = JS_ARENA_MARK(cg->codePool); + JS_ARENA_ALLOCATE_TYPE(cg2, JSCodeGenerator, cg->codePool); + if (!cg2) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + js_InitCodeGenerator(cx, cg2, cg->treeContext.parseContext, + cg->codePool, cg->notePool, + pn->pn_pos.begin.lineno); + cg2->treeContext.flags = (uint16) (pn->pn_flags | TCF_IN_FUNCTION); + cg2->treeContext.u.fun = fun; + cg2->staticDepth = cg->staticDepth + 1; + cg2->parent = cg; + + /* We metered the max scope depth when parsed the function. */ + JS_SCOPE_DEPTH_METERING(cg2->treeContext.maxScopeDepth = (uintN) -1); + if (!js_EmitFunctionScript(cx, cg2, pn->pn_body)) { + pn = NULL; + } else { + /* + * We need an activation object if an inner peeks out, or if such + * inner-peeking caused one of our inners to become heavyweight. + */ + if (cg2->treeContext.flags & + (TCF_FUN_USES_NONLOCALS | TCF_FUN_HEAVYWEIGHT)) { + cg->treeContext.flags |= TCF_FUN_HEAVYWEIGHT; + } + } + + js_FinishCodeGenerator(cx, cg2); + JS_ARENA_RELEASE(cg->codePool, cg2mark); + cg2 = NULL; + if (!pn) + return JS_FALSE; + + /* Make the function object a literal in the outer script's pool. */ + index = IndexParsedObject(pn->pn_funpob, &cg->objectList); + + /* Emit a bytecode pointing to the closure object in its immediate. */ + if (pn->pn_op != JSOP_NOP) { + if ((pn->pn_flags & TCF_GENEXP_LAMBDA) && + js_NewSrcNote(cx, cg, SRC_GENEXP) < 0) { + return JS_FALSE; + } + EMIT_INDEX_OP(PN_OP(pn), index); + break; + } + + /* + * For a script we emit the code as we parse. Thus the bytecode for + * top-level functions should go in the prolog to predefine their + * names in the variable object before the already-generated main code + * is executed. This extra work for top-level scripts is not necessary + * when we emit the code for a function. It is fully parsed prior to + * invocation of the emitter and calls to js_EmitTree for function + * definitions can be scheduled before generating the rest of code. + */ + if (!(cg->treeContext.flags & TCF_IN_FUNCTION)) { + JS_ASSERT(!cg->treeContext.topStmt); + CG_SWITCH_TO_PROLOG(cg); + EMIT_INDEX_OP(JSOP_DEFFUN, index); + CG_SWITCH_TO_MAIN(cg); + + /* Emit NOP for the decompiler. */ + if (!EmitFunctionDefNop(cx, cg, index)) + return JS_FALSE; + } else { +#ifdef DEBUG + JSLocalKind localKind = +#endif + js_LookupLocal(cx, cg->treeContext.u.fun, fun->atom, &slot); + JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST); + JS_ASSERT(pn->pn_index == (uint32) -1); + pn->pn_index = index; + if (!EmitSlotIndexOp(cx, JSOP_DEFLOCALFUN, slot, index, cg)) + return JS_FALSE; + } + break; + } + + + case TOK_IF: + /* Initialize so we can detect else-if chains and avoid recursion. */ + stmtInfo.type = STMT_IF; + beq = jmp = -1; + noteIndex = -1; + + if_again: + /* Emit code for the condition before pushing stmtInfo. */ + if (!js_EmitTree(cx, cg, pn->pn_kid1)) + return JS_FALSE; + top = CG_OFFSET(cg); + if (stmtInfo.type == STMT_IF) { + js_PushStatement(&cg->treeContext, &stmtInfo, STMT_IF, top); + } else { + /* + * We came here from the goto further below that detects else-if + * chains, so we must mutate stmtInfo back into a STMT_IF record. + * Also (see below for why) we need a note offset for SRC_IF_ELSE + * to help the decompiler. Actually, we need two offsets, one for + * decompiling any else clause and the second for decompiling an + * else-if chain without bracing, overindenting, or incorrectly + * scoping let declarations. + */ + JS_ASSERT(stmtInfo.type == STMT_ELSE); + stmtInfo.type = STMT_IF; + stmtInfo.update = top; + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) + return JS_FALSE; + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 1, top - jmp)) + return JS_FALSE; + } + + /* Emit an annotated branch-if-false around the then part. */ + pn3 = pn->pn_kid3; + noteIndex = js_NewSrcNote(cx, cg, pn3 ? SRC_IF_ELSE : SRC_IF); + if (noteIndex < 0) + return JS_FALSE; + beq = EmitJump(cx, cg, JSOP_IFEQ, 0); + if (beq < 0) + return JS_FALSE; + + /* Emit code for the then and optional else parts. */ + if (!js_EmitTree(cx, cg, pn->pn_kid2)) + return JS_FALSE; + if (pn3) { + /* Modify stmtInfo so we know we're in the else part. */ + stmtInfo.type = STMT_ELSE; + + /* + * Emit a JSOP_BACKPATCH op to jump from the end of our then part + * around the else part. The js_PopStatementCG call at the bottom + * of this switch case will fix up the backpatch chain linked from + * stmtInfo.breaks. + */ + jmp = EmitGoto(cx, cg, &stmtInfo, &stmtInfo.breaks, NULL, SRC_NULL); + if (jmp < 0) + return JS_FALSE; + + /* Ensure the branch-if-false comes here, then emit the else. */ + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq); + if (pn3->pn_type == TOK_IF) { + pn = pn3; + goto if_again; + } + + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + + /* + * Annotate SRC_IF_ELSE with the offset from branch to jump, for + * the decompiler's benefit. We can't just "back up" from the pc + * of the else clause, because we don't know whether an extended + * jump was required to leap from the end of the then clause over + * the else clause. + */ + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) + return JS_FALSE; + } else { + /* No else part, fixup the branch-if-false to come here. */ + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq); + } + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_SWITCH: + /* Out of line to avoid bloating js_EmitTree's stack frame size. */ + ok = EmitSwitch(cx, cg, pn, &stmtInfo); + break; + + case TOK_WHILE: + /* + * Minimize bytecodes issued for one or more iterations by jumping to + * the condition below the body and closing the loop if the condition + * is true with a backward branch. For iteration count i: + * + * i test at the top test at the bottom + * = =============== ================== + * 0 ifeq-pass goto; ifne-fail + * 1 ifeq-fail; goto; ifne-pass goto; ifne-pass; ifne-fail + * 2 2*(ifeq-fail; goto); ifeq-pass goto; 2*ifne-pass; ifne-fail + * . . . + * N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail + * + * SpiderMonkey, pre-mozilla.org, emitted while parsing and so used + * test at the top. When JSParseNode trees were added during the ES3 + * work (1998-9), the code generation scheme was not optimized, and + * the decompiler continued to take advantage of the branch and jump + * that bracketed the body. But given the SRC_WHILE note, it is easy + * to support the more efficient scheme. + */ + js_PushStatement(&cg->treeContext, &stmtInfo, STMT_WHILE_LOOP, top); + noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE); + if (noteIndex < 0) + return JS_FALSE; + jmp = EmitJump(cx, cg, JSOP_GOTO, 0); + if (jmp < 0) + return JS_FALSE; + top = CG_OFFSET(cg); + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); + if (beq < 0) + return JS_FALSE; + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, beq - jmp)) + return JS_FALSE; + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_DO: + /* Emit an annotated nop so we know to decompile a 'do' keyword. */ + noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE); + if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0) + return JS_FALSE; + + /* Compile the loop body. */ + top = CG_OFFSET(cg); + js_PushStatement(&cg->treeContext, &stmtInfo, STMT_DO_LOOP, top); + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + + /* Set loop and enclosing label update offsets, for continue. */ + stmt = &stmtInfo; + do { + stmt->update = CG_OFFSET(cg); + } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); + + /* Compile the loop condition, now that continues know where to go. */ + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + + /* + * Since we use JSOP_IFNE for other purposes as well as for do-while + * loops, we must store 1 + (beq - top) in the SRC_WHILE note offset, + * and the decompiler must get that delta and decompile recursively. + */ + beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); + if (beq < 0) + return JS_FALSE; + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, 1 + (beq - top))) + return JS_FALSE; + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_FOR: + beq = 0; /* suppress gcc warnings */ + jmp = -1; + pn2 = pn->pn_left; + js_PushStatement(&cg->treeContext, &stmtInfo, STMT_FOR_LOOP, top); + + if (pn2->pn_type == TOK_IN) { + /* Set stmtInfo type for later testing. */ + stmtInfo.type = STMT_FOR_IN_LOOP; + + /* + * If the left part is 'var x', emit code to define x if necessary + * using a prolog opcode, but do not emit a pop. If the left part + * is 'var x = i', emit prolog code to define x if necessary; then + * emit code to evaluate i, assign the result to x, and pop the + * result off the stack. + * + * All the logic to do this is implemented in the outer switch's + * TOK_VAR case, conditioned on pn_extra flags set by the parser. + * + * In the 'for (var x = i in o) ...' case, the js_EmitTree(...pn3) + * called here will generate the proper note for the assignment + * op that sets x = i, hoisting the initialized var declaration + * out of the loop: 'var x = i; for (x in o) ...'. + * + * In the 'for (var x in o) ...' case, nothing but the prolog op + * (if needed) should be generated here, we must emit the note + * just before the JSOP_FOR* opcode in the switch on pn3->pn_type + * a bit below, so nothing is hoisted: 'for (var x in o) ...'. + * + * A 'for (let x = i in o)' loop must not be hoisted, since in + * this form the let variable is scoped by the loop body (but not + * the head). The initializer expression i must be evaluated for + * any side effects. So we hoist only i in the let case. + */ + pn3 = pn2->pn_left; + type = PN_TYPE(pn3); + cg->treeContext.flags |= TCF_IN_FOR_INIT; + if (TOKEN_TYPE_IS_DECL(type) && !js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + cg->treeContext.flags &= ~TCF_IN_FOR_INIT; + + /* Compile the object expression to the right of 'in'. */ + if (!js_EmitTree(cx, cg, pn2->pn_right)) + return JS_FALSE; + + /* + * Emit a bytecode to convert top of stack value to the iterator + * object depending on the loop variant (for-in, for-each-in, or + * destructuring for-in). + */ + JS_ASSERT(pn->pn_op == JSOP_ITER); + if (js_Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0) + return JS_FALSE; + + /* Annotate so the decompiler can find the loop-closing jump. */ + noteIndex = js_NewSrcNote(cx, cg, SRC_FOR_IN); + if (noteIndex < 0) + return JS_FALSE; + + /* + * Jump down to the loop condition to minimize overhead assuming at + * least one iteration, as the other loop forms do. + */ + jmp = EmitJump(cx, cg, JSOP_GOTO, 0); + if (jmp < 0) + return JS_FALSE; + + top = CG_OFFSET(cg); + SET_STATEMENT_TOP(&stmtInfo, top); + +#ifdef DEBUG + intN loopDepth = cg->stackDepth; +#endif + + /* + * Compile a JSOP_FOR* bytecode based on the left hand side. + * + * Initialize op to JSOP_SETNAME in case of |for ([a, b] in o)...| + * or similar, to signify assignment, rather than declaration, to + * the decompiler. EmitDestructuringOps takes a prolog bytecode + * parameter and emits the appropriate source note, defaulting to + * assignment, so JSOP_SETNAME is not critical here; many similar + * ops could be used -- just not JSOP_NOP (which means 'let'). + */ + op = JSOP_SETNAME; + switch (type) { +#if JS_HAS_BLOCK_SCOPE + case TOK_LET: +#endif + case TOK_VAR: + JS_ASSERT(pn3->pn_arity == PN_LIST && pn3->pn_count == 1); + pn3 = pn3->pn_head; +#if JS_HAS_DESTRUCTURING + if (pn3->pn_type == TOK_ASSIGN) { + pn3 = pn3->pn_left; + JS_ASSERT(pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC); + } + if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) { + op = PN_OP(pn2->pn_left); + goto destructuring_for; + } +#else + JS_ASSERT(pn3->pn_type == TOK_NAME); +#endif + /* FALL THROUGH */ + + case TOK_NAME: + /* + * Always annotate JSOP_FORLOCAL if given input of the form + * 'for (let x in * o)' -- the decompiler must not hoist the + * 'let x' out of the loop head, or x will be bound in the + * wrong scope. Likewise, but in this case only for the sake + * of higher decompilation fidelity only, do not hoist 'var x' + * when given 'for (var x in o)'. + */ + if (( +#if JS_HAS_BLOCK_SCOPE + type == TOK_LET || +#endif + (type == TOK_VAR && !pn3->pn_expr)) && + js_NewSrcNote2(cx, cg, SRC_DECL, + (type == TOK_VAR) + ? SRC_DECL_VAR + : SRC_DECL_LET) < 0) { + return JS_FALSE; + } + if (pn3->pn_slot >= 0) { + op = PN_OP(pn3); + switch (op) { + case JSOP_GETARG: /* FALL THROUGH */ + case JSOP_SETARG: op = JSOP_FORARG; break; + case JSOP_GETGVAR: /* FALL THROUGH */ + case JSOP_SETGVAR: op = JSOP_FORNAME; break; + case JSOP_GETLOCAL: /* FALL THROUGH */ + case JSOP_SETLOCAL: op = JSOP_FORLOCAL; break; + default: JS_ASSERT(0); + } + } else { + pn3->pn_op = JSOP_FORNAME; + if (!BindNameToSlot(cx, cg, pn3)) + return JS_FALSE; + op = PN_OP(pn3); + } + if (pn3->pn_slot >= 0) { + if (pn3->pn_const) { + JS_ASSERT(op == JSOP_FORLOCAL); + js_ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); + return JS_FALSE; + } + atomIndex = (jsatomid) pn3->pn_slot; + EMIT_UINT16_IMM_OP(op, atomIndex); + } else { + if (!EmitAtomOp(cx, pn3, op, cg)) + return JS_FALSE; + } + break; + + case TOK_DOT: + /* + * 'for (o.p in q)' can use JSOP_FORPROP only if evaluating 'o' + * has no side effects. + */ + useful = JS_FALSE; + if (!CheckSideEffects(cx, cg, pn3->pn_expr, &useful)) + return JS_FALSE; + if (!useful) { + if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE)) + return JS_FALSE; + break; + } + /* FALL THROUGH */ + +#if JS_HAS_DESTRUCTURING + destructuring_for: +#endif + default: + if (js_Emit1(cx, cg, JSOP_FORELEM) < 0) + return JS_FALSE; + JS_ASSERT(cg->stackDepth >= 3); + +#if JS_HAS_DESTRUCTURING + if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) { + if (!EmitDestructuringOps(cx, cg, op, pn3)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } else +#endif +#if JS_HAS_LVALUE_RETURN + if (pn3->pn_type == TOK_LP) { + JS_ASSERT(pn3->pn_op == JSOP_SETCALL); + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0) + return JS_FALSE; + } else +#endif +#if JS_HAS_XML_SUPPORT + if (pn3->pn_type == TOK_UNARYOP) { + JS_ASSERT(pn3->pn_op == JSOP_BINDXMLNAME); + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0) + return JS_FALSE; + } else +#endif + if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg)) + return JS_FALSE; + break; + } + + /* The stack should be balanced around the JSOP_FOR* opcode sequence. */ + JS_ASSERT(cg->stackDepth == loopDepth); + + /* Set the first srcnote offset so we can find the start of the loop body. */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, CG_OFFSET(cg) - jmp)) + return JS_FALSE; + + /* Emit code for the loop body. */ + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + + /* Set loop and enclosing "update" offsets, for continue. */ + stmt = &stmtInfo; + do { + stmt->update = CG_OFFSET(cg); + } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); + + /* + * Fixup the goto that starts the loop to jump down to JSOP_NEXTITER. + */ + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + if (js_Emit1(cx, cg, JSOP_NEXTITER) < 0) + return JS_FALSE; + beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); + if (beq < 0) + return JS_FALSE; + + /* Set the second srcnote offset so we can find the closing jump. */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp)) + return JS_FALSE; + } else { + /* C-style for (init; cond; update) ... loop. */ + op = JSOP_POP; + pn3 = pn2->pn_kid1; + if (!pn3) { + /* No initializer: emit an annotated nop for the decompiler. */ + op = JSOP_NOP; + } else { + cg->treeContext.flags |= TCF_IN_FOR_INIT; +#if JS_HAS_DESTRUCTURING + if (pn3->pn_type == TOK_ASSIGN && + !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) { + return JS_FALSE; + } +#endif + if (op == JSOP_POP) { + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + if (TOKEN_TYPE_IS_DECL(pn3->pn_type)) { + /* + * Check whether a destructuring-initialized var decl + * was optimized to a group assignment. If so, we do + * not need to emit a pop below, so switch to a nop, + * just for the decompiler. + */ + JS_ASSERT(pn3->pn_arity == PN_LIST); + if (pn3->pn_extra & PNX_GROUPINIT) + op = JSOP_NOP; + } + } + cg->treeContext.flags &= ~TCF_IN_FOR_INIT; + } + + /* + * NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH). + * Use tmp to hold the biased srcnote "top" offset, which differs + * from the top local variable by the length of the JSOP_GOTO{,X} + * emitted in between tmp and top if this loop has a condition. + */ + noteIndex = js_NewSrcNote(cx, cg, SRC_FOR); + if (noteIndex < 0 || js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + tmp = CG_OFFSET(cg); + + if (pn2->pn_kid2) { + /* Goto the loop condition, which branches back to iterate. */ + jmp = EmitJump(cx, cg, JSOP_GOTO, 0); + if (jmp < 0) + return JS_FALSE; + } + + top = CG_OFFSET(cg); + SET_STATEMENT_TOP(&stmtInfo, top); + + /* Emit code for the loop body. */ + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + + /* Set the second note offset so we can find the update part. */ + JS_ASSERT(noteIndex != -1); + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, + CG_OFFSET(cg) - tmp)) { + return JS_FALSE; + } + + /* Set loop and enclosing "update" offsets, for continue. */ + stmt = &stmtInfo; + do { + stmt->update = CG_OFFSET(cg); + } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); + + /* Check for update code to do before the condition (if any). */ + pn3 = pn2->pn_kid3; + if (pn3) { + op = JSOP_POP; +#if JS_HAS_DESTRUCTURING + if (pn3->pn_type == TOK_ASSIGN && + !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) { + return JS_FALSE; + } +#endif + if (op == JSOP_POP && !js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + + /* Always emit the POP or NOP, to help the decompiler. */ + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + + /* Restore the absolute line number for source note readers. */ + off = (ptrdiff_t) pn->pn_pos.end.lineno; + if (CG_CURRENT_LINE(cg) != (uintN) off) { + if (js_NewSrcNote2(cx, cg, SRC_SETLINE, off) < 0) + return JS_FALSE; + CG_CURRENT_LINE(cg) = (uintN) off; + } + } + + /* Set the first note offset so we can find the loop condition. */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, + CG_OFFSET(cg) - tmp)) { + return JS_FALSE; + } + + if (pn2->pn_kid2) { + /* Fix up the goto from top to target the loop condition. */ + JS_ASSERT(jmp >= 0); + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + + if (!js_EmitTree(cx, cg, pn2->pn_kid2)) + return JS_FALSE; + } + + /* The third note offset helps us find the loop-closing jump. */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2, + CG_OFFSET(cg) - tmp)) { + return JS_FALSE; + } + + if (pn2->pn_kid2) { + beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); + if (beq < 0) + return JS_FALSE; + } else { + /* No loop condition -- emit the loop-closing jump. */ + jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg)); + if (jmp < 0) + return JS_FALSE; + } + } + + /* Now fixup all breaks and continues (before for/in's JSOP_ENDITER). */ + if (!js_PopStatementCG(cx, cg)) + return JS_FALSE; + + if (pn2->pn_type == TOK_IN) { + /* + * JSOP_ENDITER must have a slot to save an exception thrown from + * the body of for-in loop when closing the iterator object, and + * fortunately it does: the slot that was set by JSOP_NEXTITER to + * the return value of iterator.next(). + */ + JS_ASSERT(js_CodeSpec[JSOP_ENDITER].nuses == 2); + if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) || + js_Emit1(cx, cg, JSOP_ENDITER) < 0) { + return JS_FALSE; + } + } + break; + + case TOK_BREAK: + stmt = cg->treeContext.topStmt; + atom = pn->pn_atom; + if (atom) { + ale = js_IndexAtom(cx, atom, &cg->atomList); + if (!ale) + return JS_FALSE; + while (stmt->type != STMT_LABEL || stmt->u.label != atom) + stmt = stmt->down; + noteType = SRC_BREAK2LABEL; + } else { + ale = NULL; + while (!STMT_IS_LOOP(stmt) && stmt->type != STMT_SWITCH) + stmt = stmt->down; + noteType = (stmt->type == STMT_SWITCH) ? SRC_NULL : SRC_BREAK; + } + + if (EmitGoto(cx, cg, stmt, &stmt->breaks, ale, noteType) < 0) + return JS_FALSE; + break; + + case TOK_CONTINUE: + stmt = cg->treeContext.topStmt; + atom = pn->pn_atom; + if (atom) { + /* Find the loop statement enclosed by the matching label. */ + JSStmtInfo *loop = NULL; + ale = js_IndexAtom(cx, atom, &cg->atomList); + if (!ale) + return JS_FALSE; + while (stmt->type != STMT_LABEL || stmt->u.label != atom) { + if (STMT_IS_LOOP(stmt)) + loop = stmt; + stmt = stmt->down; + } + stmt = loop; + noteType = SRC_CONT2LABEL; + } else { + ale = NULL; + while (!STMT_IS_LOOP(stmt)) + stmt = stmt->down; + noteType = SRC_CONTINUE; + } + + if (EmitGoto(cx, cg, stmt, &stmt->continues, ale, noteType) < 0) + return JS_FALSE; + break; + + case TOK_WITH: + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + js_PushStatement(&cg->treeContext, &stmtInfo, STMT_WITH, CG_OFFSET(cg)); + if (js_Emit1(cx, cg, JSOP_ENTERWITH) < 0) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) + return JS_FALSE; + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_TRY: + { + ptrdiff_t tryStart, tryEnd, catchJump, finallyStart; + intN depth; + JSParseNode *lastCatch; + + catchJump = -1; + + /* + * Push stmtInfo to track jumps-over-catches and gosubs-to-finally + * for later fixup. + * + * When a finally block is 'active' (STMT_FINALLY on the treeContext), + * non-local jumps (including jumps-over-catches) result in a GOSUB + * being written into the bytecode stream and fixed-up later (c.f. + * EmitBackPatchOp and BackPatch). + */ + js_PushStatement(&cg->treeContext, &stmtInfo, + pn->pn_kid3 ? STMT_FINALLY : STMT_TRY, + CG_OFFSET(cg)); + + /* + * Since an exception can be thrown at any place inside the try block, + * we need to restore the stack and the scope chain before we transfer + * the control to the exception handler. + * + * For that we store in a try note associated with the catch or + * finally block the stack depth upon the try entry. The interpreter + * uses this depth to properly unwind the stack and the scope chain. + */ + depth = cg->stackDepth; + + /* Mark try location for decompilation, then emit try block. */ + if (js_Emit1(cx, cg, JSOP_TRY) < 0) + return JS_FALSE; + tryStart = CG_OFFSET(cg); + if (!js_EmitTree(cx, cg, pn->pn_kid1)) + return JS_FALSE; + JS_ASSERT(depth == cg->stackDepth); + + /* GOSUB to finally, if present. */ + if (pn->pn_kid3) { + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(stmtInfo)); + if (jmp < 0) + return JS_FALSE; + } + + /* Emit (hidden) jump over catch and/or finally. */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &catchJump); + if (jmp < 0) + return JS_FALSE; + + tryEnd = CG_OFFSET(cg); + + /* If this try has a catch block, emit it. */ + pn2 = pn->pn_kid2; + lastCatch = NULL; + if (pn2) { + jsint count = 0; /* previous catch block's population */ + + /* + * The emitted code for a catch block looks like: + * + * [throwing] only if 2nd+ catch block + * [leaveblock] only if 2nd+ catch block + * enterblock with SRC_CATCH + * exception + * [dup] only if catchguard + * setlocalpop or destructuring code + * [< catchguard code >] if there's a catchguard + * [ifeq ] " " + * [pop] only if catchguard + * < catch block contents > + * leaveblock + * goto non-local; finally applies + * + * If there's no catch block without a catchguard, the last + * points to rethrow code. This + * code will [gosub] to the finally code if appropriate, and is + * also used for the catch-all trynote for capturing exceptions + * thrown from catch{} blocks. + */ + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + ptrdiff_t guardJump, catchNote; + + JS_ASSERT(cg->stackDepth == depth); + guardJump = GUARDJUMP(stmtInfo); + if (guardJump != -1) { + /* Fix up and clean up previous catch block. */ + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, guardJump); + + /* + * Account for JSOP_ENTERBLOCK (whose block object count + * is saved below) and pushed exception object that we + * still have after the jumping from the previous guard. + */ + cg->stackDepth = depth + count + 1; + + /* + * Move exception back to cx->exception to prepare for + * the next catch. We hide [throwing] from the decompiler + * since it compensates for the hidden JSOP_DUP at the + * start of the previous guarded catch. + */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit1(cx, cg, JSOP_THROWING) < 0) { + return JS_FALSE; + } + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, count); + JS_ASSERT(cg->stackDepth == depth); + } + + /* + * Annotate the JSOP_ENTERBLOCK that's about to be generated + * by the call to js_EmitTree immediately below. Save this + * source note's index in stmtInfo for use by the TOK_CATCH: + * case, where the length of the catch guard is set as the + * note's offset. + */ + catchNote = js_NewSrcNote2(cx, cg, SRC_CATCH, 0); + if (catchNote < 0) + return JS_FALSE; + CATCHNOTE(stmtInfo) = catchNote; + + /* + * Emit the lexical scope and catch body. Save the catch's + * block object population via count, for use when targeting + * guardJump at the next catch (the guard mismatch case). + */ + JS_ASSERT(pn3->pn_type == TOK_LEXICALSCOPE); + count = OBJ_BLOCK_COUNT(cx, pn3->pn_pob->object); + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + + /* gosub , if required */ + if (pn->pn_kid3) { + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, + &GOSUBS(stmtInfo)); + if (jmp < 0) + return JS_FALSE; + JS_ASSERT(cg->stackDepth == depth); + } + + /* + * Jump over the remaining catch blocks. This will get fixed + * up to jump to after catch/finally. + */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &catchJump); + if (jmp < 0) + return JS_FALSE; + + /* + * Save a pointer to the last catch node to handle try-finally + * and try-catch(guard)-finally special cases. + */ + lastCatch = pn3->pn_expr; + } + } + + /* + * Last catch guard jumps to the rethrow code sequence if none of the + * guards match. Target guardJump at the beginning of the rethrow + * sequence, just in case a guard expression throws and leaves the + * stack unbalanced. + */ + if (lastCatch && lastCatch->pn_kid2) { + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, GUARDJUMP(stmtInfo)); + + /* Sync the stack to take into account pushed exception. */ + JS_ASSERT(cg->stackDepth == depth); + cg->stackDepth = depth + 1; + + /* + * Rethrow the exception, delegating executing of finally if any + * to the exception handler. + */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit1(cx, cg, JSOP_THROW) < 0) { + return JS_FALSE; + } + } + + JS_ASSERT(cg->stackDepth == depth); + + /* Emit finally handler if any. */ + finallyStart = 0; /* to quell GCC uninitialized warnings */ + if (pn->pn_kid3) { + /* + * Fix up the gosubs that might have been emitted before non-local + * jumps to the finally code. + */ + if (!BackPatch(cx, cg, GOSUBS(stmtInfo), CG_NEXT(cg), JSOP_GOSUB)) + return JS_FALSE; + + finallyStart = CG_OFFSET(cg); + + /* Indicate that we're emitting a subroutine body. */ + stmtInfo.type = STMT_SUBROUTINE; + if (!UpdateLineNumberNotes(cx, cg, pn->pn_kid3)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_FINALLY) < 0 || + !js_EmitTree(cx, cg, pn->pn_kid3) || + js_Emit1(cx, cg, JSOP_RETSUB) < 0) { + return JS_FALSE; + } + JS_ASSERT(cg->stackDepth == depth); + } + if (!js_PopStatementCG(cx, cg)) + return JS_FALSE; + + if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 || + js_Emit1(cx, cg, JSOP_NOP) < 0) { + return JS_FALSE; + } + + /* Fix up the end-of-try/catch jumps to come here. */ + if (!BackPatch(cx, cg, catchJump, CG_NEXT(cg), JSOP_GOTO)) + return JS_FALSE; + + /* + * Add the try note last, to let post-order give us the right ordering + * (first to last for a given nesting level, inner to outer by level). + */ + if (pn->pn_kid2 && + !NewTryNote(cx, cg, JSTRY_CATCH, depth, tryStart, tryEnd)) { + return JS_FALSE; + } + + /* + * If we've got a finally, mark try+catch region with additional + * trynote to catch exceptions (re)thrown from a catch block or + * for the try{}finally{} case. + */ + if (pn->pn_kid3 && + !NewTryNote(cx, cg, JSTRY_FINALLY, depth, tryStart, finallyStart)) { + return JS_FALSE; + } + break; + } + + case TOK_CATCH: + { + ptrdiff_t catchStart, guardJump; + JSObject *blockObj; + + /* + * Morph STMT_BLOCK to STMT_CATCH, note the block entry code offset, + * and save the block object atom. + */ + stmt = cg->treeContext.topStmt; + JS_ASSERT(stmt->type == STMT_BLOCK && (stmt->flags & SIF_SCOPE)); + stmt->type = STMT_CATCH; + catchStart = stmt->update; + blockObj = stmt->u.blockObj; + + /* Go up one statement info record to the TRY or FINALLY record. */ + stmt = stmt->down; + JS_ASSERT(stmt->type == STMT_TRY || stmt->type == STMT_FINALLY); + + /* Pick up the pending exception and bind it to the catch variable. */ + if (js_Emit1(cx, cg, JSOP_EXCEPTION) < 0) + return JS_FALSE; + + /* + * Dup the exception object if there is a guard for rethrowing to use + * it later when rethrowing or in other catches. + */ + if (pn->pn_kid2 && js_Emit1(cx, cg, JSOP_DUP) < 0) + return JS_FALSE; + + pn2 = pn->pn_kid1; + switch (pn2->pn_type) { +#if JS_HAS_DESTRUCTURING + case TOK_RB: + case TOK_RC: + if (!EmitDestructuringOps(cx, cg, JSOP_NOP, pn2)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + break; +#endif + + case TOK_NAME: + /* Inline BindNameToSlot for pn2. */ + JS_ASSERT(pn2->pn_slot == -1); + pn2->pn_slot = AdjustBlockSlot(cx, cg, + OBJ_BLOCK_DEPTH(cx, blockObj)); + if (pn2->pn_slot < 0) + return JS_FALSE; + EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, pn2->pn_slot); + break; + + default: + JS_ASSERT(0); + } + + /* Emit the guard expression, if there is one. */ + if (pn->pn_kid2) { + if (!js_EmitTree(cx, cg, pn->pn_kid2)) + return JS_FALSE; + if (!js_SetSrcNoteOffset(cx, cg, CATCHNOTE(*stmt), 0, + CG_OFFSET(cg) - catchStart)) { + return JS_FALSE; + } + /* ifeq */ + guardJump = EmitJump(cx, cg, JSOP_IFEQ, 0); + if (guardJump < 0) + return JS_FALSE; + GUARDJUMP(*stmt) = guardJump; + + /* Pop duplicated exception object as we no longer need it. */ + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } + + /* Emit the catch body. */ + if (!js_EmitTree(cx, cg, pn->pn_kid3)) + return JS_FALSE; + + /* + * Annotate the JSOP_LEAVEBLOCK that will be emitted as we unwind via + * our TOK_LEXICALSCOPE parent, so the decompiler knows to pop. + */ + off = cg->stackDepth; + if (js_NewSrcNote2(cx, cg, SRC_CATCH, off) < 0) + return JS_FALSE; + break; + } + + case TOK_VAR: + if (!EmitVariables(cx, cg, pn, JS_FALSE, ¬eIndex)) + return JS_FALSE; + break; + + case TOK_RETURN: + /* Push a return value */ + pn2 = pn->pn_kid; + if (pn2) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } else { + if (js_Emit1(cx, cg, JSOP_PUSH) < 0) + return JS_FALSE; + } + + /* + * EmitNonLocalJumpFixup may add fixup bytecode to close open try + * blocks having finally clauses and to exit intermingled let blocks. + * We can't simply transfer control flow to our caller in that case, + * because we must gosub to those finally clauses from inner to outer, + * with the correct stack pointer (i.e., after popping any with, + * for/in, etc., slots nested inside the finally's try). + * + * In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an + * extra JSOP_RETRVAL after the fixups. + */ + top = CG_OFFSET(cg); + if (js_Emit1(cx, cg, JSOP_RETURN) < 0) + return JS_FALSE; + if (!EmitNonLocalJumpFixup(cx, cg, NULL)) + return JS_FALSE; + if (top + JSOP_RETURN_LENGTH != CG_OFFSET(cg)) { + CG_BASE(cg)[top] = JSOP_SETRVAL; + if (js_Emit1(cx, cg, JSOP_RETRVAL) < 0) + return JS_FALSE; + } + break; + +#if JS_HAS_GENERATORS + case TOK_YIELD: + if (!(cg->treeContext.flags & TCF_IN_FUNCTION)) { + js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, + JSMSG_BAD_RETURN_OR_YIELD, + js_yield_str); + return JS_FALSE; + } + if (pn->pn_kid) { + if (!js_EmitTree(cx, cg, pn->pn_kid)) + return JS_FALSE; + } else { + if (js_Emit1(cx, cg, JSOP_PUSH) < 0) + return JS_FALSE; + } + if (pn->pn_hidden && js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_YIELD) < 0) + return JS_FALSE; + break; +#endif + + case TOK_LC: +#if JS_HAS_XML_SUPPORT + if (pn->pn_arity == PN_UNARY) { + if (!js_EmitTree(cx, cg, pn->pn_kid)) + return JS_FALSE; + if (js_Emit1(cx, cg, PN_OP(pn)) < 0) + return JS_FALSE; + break; + } +#endif + + JS_ASSERT(pn->pn_arity == PN_LIST); + + noteIndex = -1; + tmp = CG_OFFSET(cg); + if (pn->pn_extra & PNX_NEEDBRACES) { + noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0); + if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0) + return JS_FALSE; + } + + js_PushStatement(&cg->treeContext, &stmtInfo, STMT_BLOCK, top); + if (pn->pn_extra & PNX_FUNCDEFS) { + /* + * This block contains top-level function definitions. To ensure + * that we emit the bytecode defining them prior the rest of code + * in the block we use a separate pass over functions. During the + * main pass later the emitter will add JSOP_NOP with source notes + * for the function to preserve the original functions position + * when decompiling. + * + * Currently this is used only for functions, as compile-as-we go + * mode for scripts does not allow separate emitter passes. + */ + JS_ASSERT(cg->treeContext.flags & TCF_IN_FUNCTION); + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (pn2->pn_type == TOK_FUNCTION) { + if (pn2->pn_op == JSOP_NOP) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } else { + /* + * JSOP_DEFFUN in a top-level block with function + * definitions appears, for example, when "if (true)" + * is optimized away from "if (true) function x() {}". + * See bug 428424. + */ + JS_ASSERT(pn2->pn_op == JSOP_DEFFUN); + } + } + } + } + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } + + if (noteIndex >= 0 && + !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, + CG_OFFSET(cg) - tmp)) { + return JS_FALSE; + } + + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_SEQ: + JS_ASSERT(pn->pn_arity == PN_LIST); + js_PushStatement(&cg->treeContext, &stmtInfo, STMT_SEQ, top); + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_SEMI: + pn2 = pn->pn_kid; + if (pn2) { + /* + * Top-level or called-from-a-native JS_Execute/EvaluateScript, + * debugger, and eval frames may need the value of the ultimate + * expression statement as the script's result, despite the fact + * that it appears useless to the compiler. + * + * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when + * calling JS_Compile* to suppress JSOP_POPV. + */ + useful = wantval = + !(cg->treeContext.flags & (TCF_IN_FUNCTION | TCF_NO_SCRIPT_RVAL)); + if (!useful) { + if (!CheckSideEffects(cx, cg, pn2, &useful)) + return JS_FALSE; + } + + /* + * Don't eliminate apparently useless expressions if they are + * labeled expression statements. The tc->topStmt->update test + * catches the case where we are nesting in js_EmitTree for a + * labeled compound statement. + */ + if (!useful && + (!cg->treeContext.topStmt || + cg->treeContext.topStmt->type != STMT_LABEL || + cg->treeContext.topStmt->update < CG_OFFSET(cg))) { + CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno; + if (!js_ReportCompileErrorNumber(cx, CG_TS(cg), pn2, + JSREPORT_WARNING | + JSREPORT_STRICT, + JSMSG_USELESS_EXPR)) { + return JS_FALSE; + } + } else { + op = wantval ? JSOP_POPV : JSOP_POP; +#if JS_HAS_DESTRUCTURING + if (!wantval && + pn2->pn_type == TOK_ASSIGN && + !MaybeEmitGroupAssignment(cx, cg, op, pn2, &op)) { + return JS_FALSE; + } +#endif + if (op != JSOP_NOP) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } + } + } + break; + + case TOK_COLON: + /* Emit an annotated nop so we know to decompile a label. */ + atom = pn->pn_atom; + ale = js_IndexAtom(cx, atom, &cg->atomList); + if (!ale) + return JS_FALSE; + pn2 = pn->pn_expr; + noteType = (pn2->pn_type == TOK_LC || + (pn2->pn_type == TOK_LEXICALSCOPE && + pn2->pn_expr->pn_type == TOK_LC)) + ? SRC_LABELBRACE + : SRC_LABEL; + noteIndex = js_NewSrcNote2(cx, cg, noteType, + (ptrdiff_t) ALE_INDEX(ale)); + if (noteIndex < 0 || + js_Emit1(cx, cg, JSOP_NOP) < 0) { + return JS_FALSE; + } + + /* Emit code for the labeled statement. */ + js_PushStatement(&cg->treeContext, &stmtInfo, STMT_LABEL, + CG_OFFSET(cg)); + stmtInfo.u.label = atom; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (!js_PopStatementCG(cx, cg)) + return JS_FALSE; + + /* If the statement was compound, emit a note for the end brace. */ + if (noteType == SRC_LABELBRACE) { + if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 || + js_Emit1(cx, cg, JSOP_NOP) < 0) { + return JS_FALSE; + } + } + break; + + case TOK_COMMA: + /* + * Emit SRC_PCDELTA notes on each JSOP_POP between comma operands. + * These notes help the decompiler bracket the bytecodes generated + * from each sub-expression that follows a comma. + */ + off = noteIndex = -1; + for (pn2 = pn->pn_head; ; pn2 = pn2->pn_next) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + tmp = CG_OFFSET(cg); + if (noteIndex >= 0) { + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) + return JS_FALSE; + } + if (!pn2->pn_next) + break; + off = tmp; + noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + if (noteIndex < 0 || + js_Emit1(cx, cg, JSOP_POP) < 0) { + return JS_FALSE; + } + } + break; + + case TOK_ASSIGN: + /* + * Check left operand type and generate specialized code for it. + * Specialize to avoid ECMA "reference type" values on the operand + * stack, which impose pervasive runtime "GetValue" costs. + */ + pn2 = pn->pn_left; + JS_ASSERT(pn2->pn_type != TOK_RP); + atomIndex = (jsatomid) -1; /* quell GCC overwarning */ + switch (pn2->pn_type) { + case TOK_NAME: + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + if (pn2->pn_slot >= 0) { + atomIndex = (jsatomid) pn2->pn_slot; + } else { + ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList); + if (!ale) + return JS_FALSE; + atomIndex = ALE_INDEX(ale); + EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex); + } + break; + case TOK_DOT: + if (!js_EmitTree(cx, cg, pn2->pn_expr)) + return JS_FALSE; + ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList); + if (!ale) + return JS_FALSE; + atomIndex = ALE_INDEX(ale); + break; + case TOK_LB: + JS_ASSERT(pn2->pn_arity == PN_BINARY); + if (!js_EmitTree(cx, cg, pn2->pn_left)) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn2->pn_right)) + return JS_FALSE; + break; +#if JS_HAS_DESTRUCTURING + case TOK_RB: + case TOK_RC: + break; +#endif +#if JS_HAS_LVALUE_RETURN + case TOK_LP: + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + break; +#endif +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: + JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME); + if (!js_EmitTree(cx, cg, pn2->pn_kid)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0) + return JS_FALSE; + break; +#endif + default: + JS_ASSERT(0); + } + + op = PN_OP(pn); +#if JS_HAS_GETTER_SETTER + if (op == JSOP_GETTER || op == JSOP_SETTER) { + if (pn2->pn_type == TOK_NAME && PN_OP(pn2) != JSOP_SETNAME) { + /* + * x getter = y where x is a local or let variable is not + * supported. + */ + js_ReportCompileErrorNumber(cx, + TS(cg->treeContext.parseContext), + pn2, JSREPORT_ERROR, + JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) + ? js_getter_str + : js_setter_str); + return JS_FALSE; + } + + /* We'll emit these prefix bytecodes after emitting the r.h.s. */ + } else +#endif + /* If += or similar, dup the left operand and get its value. */ + if (op != JSOP_NOP) { + switch (pn2->pn_type) { + case TOK_NAME: + if (pn2->pn_op != JSOP_SETNAME) { + EMIT_UINT16_IMM_OP((pn2->pn_op == JSOP_SETGVAR) + ? JSOP_GETGVAR + : (pn2->pn_op == JSOP_SETARG) + ? JSOP_GETARG + : JSOP_GETLOCAL, + atomIndex); + break; + } + if (js_Emit1(cx, cg, JSOP_DUP) < 0) + return JS_FALSE; + EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex); + break; + case TOK_DOT: + if (js_Emit1(cx, cg, JSOP_DUP) < 0) + return JS_FALSE; + if (pn2->pn_atom == cx->runtime->atomState.lengthAtom) { + if (js_Emit1(cx, cg, JSOP_LENGTH) < 0) + return JS_FALSE; + } else { + EMIT_INDEX_OP(JSOP_GETPROP, atomIndex); + } + break; + case TOK_LB: +#if JS_HAS_LVALUE_RETURN + case TOK_LP: +#endif +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: +#endif + if (js_Emit1(cx, cg, JSOP_DUP2) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_GETELEM) < 0) + return JS_FALSE; + break; + default:; + } + } + + /* Now emit the right operand (it may affect the namespace). */ + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + + /* If += etc., emit the binary operator with a decompiler note. */ + if (op != JSOP_NOP) { + /* + * Take care to avoid SRC_ASSIGNOP if the left-hand side is a + * const declared in a function (i.e., with non-negative pn_slot + * and when pn_const is true), as in this case (just a bit further + * below) we will avoid emitting the assignment op. + */ + if (pn2->pn_type != TOK_NAME || + pn2->pn_slot < 0 || + !pn2->pn_const) { + if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0) + return JS_FALSE; + } + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } + + /* Left parts such as a.b.c and a[b].c need a decompiler note. */ + if (pn2->pn_type != TOK_NAME && +#if JS_HAS_DESTRUCTURING + pn2->pn_type != TOK_RB && + pn2->pn_type != TOK_RC && +#endif + js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) { + return JS_FALSE; + } + + /* Finally, emit the specialized assignment bytecode. */ + switch (pn2->pn_type) { + case TOK_NAME: + if (pn2->pn_slot >= 0) { + if (!pn2->pn_const) + EMIT_UINT16_IMM_OP(PN_OP(pn2), atomIndex); + break; + } + /* FALL THROUGH */ + case TOK_DOT: + EMIT_INDEX_OP(PN_OP(pn2), atomIndex); + break; + case TOK_LB: +#if JS_HAS_LVALUE_RETURN + case TOK_LP: +#endif + if (js_Emit1(cx, cg, JSOP_SETELEM) < 0) + return JS_FALSE; + break; +#if JS_HAS_DESTRUCTURING + case TOK_RB: + case TOK_RC: + if (!EmitDestructuringOps(cx, cg, JSOP_SETNAME, pn2)) + return JS_FALSE; + break; +#endif +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: + if (js_Emit1(cx, cg, JSOP_SETXMLNAME) < 0) + return JS_FALSE; + break; +#endif + default: + JS_ASSERT(0); + } + break; + + case TOK_HOOK: + /* Emit the condition, then branch if false to the else part. */ + if (!js_EmitTree(cx, cg, pn->pn_kid1)) + return JS_FALSE; + noteIndex = js_NewSrcNote(cx, cg, SRC_COND); + if (noteIndex < 0) + return JS_FALSE; + beq = EmitJump(cx, cg, JSOP_IFEQ, 0); + if (beq < 0 || !js_EmitTree(cx, cg, pn->pn_kid2)) + return JS_FALSE; + + /* Jump around else, fixup the branch, emit else, fixup jump. */ + jmp = EmitJump(cx, cg, JSOP_GOTO, 0); + if (jmp < 0) + return JS_FALSE; + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq); + + /* + * Because each branch pushes a single value, but our stack budgeting + * analysis ignores branches, we now have to adjust cg->stackDepth to + * ignore the value pushed by the first branch. Execution will follow + * only one path, so we must decrement cg->stackDepth. + * + * Failing to do this will foil code, such as the try/catch/finally + * exception handling code generator, that samples cg->stackDepth for + * use at runtime (JSOP_SETSP), or in let expression and block code + * generation, which must use the stack depth to compute local stack + * indexes correctly. + */ + JS_ASSERT(cg->stackDepth > 0); + cg->stackDepth--; + if (!js_EmitTree(cx, cg, pn->pn_kid3)) + return JS_FALSE; + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) + return JS_FALSE; + break; + + case TOK_OR: + case TOK_AND: + /* + * JSOP_OR converts the operand on the stack to boolean, and if true, + * leaves the original operand value on the stack and jumps; otherwise + * it pops and falls into the next bytecode, which evaluates the right + * operand. The jump goes around the right operand evaluation. + * + * JSOP_AND converts the operand on the stack to boolean, and if false, + * leaves the original operand value on the stack and jumps; otherwise + * it pops and falls into the right operand's bytecode. + */ + if (pn->pn_arity == PN_BINARY) { + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0); + if (top < 0) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + off = CG_OFFSET(cg); + pc = CG_CODE(cg, top); + CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top); + *pc = pn->pn_op; + } else { + JS_ASSERT(pn->pn_arity == PN_LIST); + JS_ASSERT(pn->pn_head->pn_next->pn_next); + + /* Left-associative operator chain: avoid too much recursion. */ + pn2 = pn->pn_head; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0); + if (top < 0) + return JS_FALSE; + + /* Emit nodes between the head and the tail. */ + jmp = top; + while ((pn2 = pn2->pn_next)->pn_next) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + off = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0); + if (off < 0) + return JS_FALSE; + if (!SetBackPatchDelta(cx, cg, CG_CODE(cg, jmp), off - jmp)) + return JS_FALSE; + jmp = off; + + } + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + + pn2 = pn->pn_head; + off = CG_OFFSET(cg); + do { + pc = CG_CODE(cg, top); + tmp = GetJumpOffset(cg, pc); + CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top); + *pc = pn->pn_op; + top += tmp; + } while ((pn2 = pn2->pn_next)->pn_next); + } + break; + + case TOK_BITOR: + case TOK_BITXOR: + case TOK_BITAND: + case TOK_EQOP: + case TOK_RELOP: + case TOK_IN: + case TOK_INSTANCEOF: + case TOK_SHOP: + case TOK_PLUS: + case TOK_MINUS: + case TOK_STAR: + case TOK_DIVOP: + if (pn->pn_arity == PN_LIST) { + /* Left-associative operator chain: avoid too much recursion. */ + pn2 = pn->pn_head; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + op = PN_OP(pn); + while ((pn2 = pn2->pn_next) != NULL) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } + } else { +#if JS_HAS_XML_SUPPORT + uintN oldflags; + + case TOK_DBLCOLON: + if (pn->pn_arity == PN_NAME) { + if (!js_EmitTree(cx, cg, pn->pn_expr)) + return JS_FALSE; + if (!EmitAtomOp(cx, pn, PN_OP(pn), cg)) + return JS_FALSE; + break; + } + + /* + * Binary :: has a right operand that brackets arbitrary code, + * possibly including a let (a = b) ... expression. We must clear + * TCF_IN_FOR_INIT to avoid mis-compiling such beasts. + */ + oldflags = cg->treeContext.flags; + cg->treeContext.flags &= ~TCF_IN_FOR_INIT; +#endif + + /* Binary operators that evaluate both operands unconditionally. */ + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; +#if JS_HAS_XML_SUPPORT + cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT; +#endif + if (js_Emit1(cx, cg, PN_OP(pn)) < 0) + return JS_FALSE; + } + break; + + case TOK_THROW: +#if JS_HAS_XML_SUPPORT + case TOK_AT: + case TOK_DEFAULT: + JS_ASSERT(pn->pn_arity == PN_UNARY); + /* FALL THROUGH */ +#endif + case TOK_UNARYOP: + { + uintN oldflags; + + /* Unary op, including unary +/-. */ + op = PN_OP(pn); +#if JS_HAS_XML_SUPPORT + if (op == JSOP_XMLNAME) { + if (!EmitXMLName(cx, pn, op, cg)) + return JS_FALSE; + break; + } +#endif + pn2 = pn->pn_kid; + if (op == JSOP_TYPEOF) { + for (pn3 = pn2; pn3->pn_type == TOK_RP; pn3 = pn3->pn_kid) + continue; + if (pn3->pn_type != TOK_NAME) + op = JSOP_TYPEOFEXPR; + } + oldflags = cg->treeContext.flags; + cg->treeContext.flags &= ~TCF_IN_FOR_INIT; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + break; + } + + case TOK_INC: + case TOK_DEC: + /* Emit lvalue-specialized code for ++/-- operators. */ + pn2 = pn->pn_kid; + JS_ASSERT(pn2->pn_type != TOK_RP); + op = PN_OP(pn); + switch (pn2->pn_type) { + default: + JS_ASSERT(pn2->pn_type == TOK_NAME); + pn2->pn_op = op; + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + op = PN_OP(pn2); + if (pn2->pn_slot >= 0) { + if (pn2->pn_const) { + /* Incrementing a declared const: just get its value. */ + op = (JOF_OPTYPE(op) == JOF_ATOM) + ? JSOP_GETGVAR + : JSOP_GETLOCAL; + } + atomIndex = (jsatomid) pn2->pn_slot; + EMIT_UINT16_IMM_OP(op, atomIndex); + } else { + if (!EmitAtomOp(cx, pn2, op, cg)) + return JS_FALSE; + } + break; + case TOK_DOT: + if (!EmitPropOp(cx, pn2, op, cg, JS_FALSE)) + return JS_FALSE; + break; + case TOK_LB: + if (!EmitElemOp(cx, pn2, op, cg)) + return JS_FALSE; + break; +#if JS_HAS_LVALUE_RETURN + case TOK_LP: + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, + CG_OFFSET(cg) - pn2->pn_offset) < 0) { + return JS_FALSE; + } + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + break; +#endif +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: + JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME); + if (!js_EmitTree(cx, cg, pn2->pn_kid)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + break; +#endif + } + break; + + case TOK_DELETE: + /* + * Under ECMA 3, deleting a non-reference returns true -- but alas we + * must evaluate the operand if it appears it might have side effects. + */ + pn2 = pn->pn_kid; + switch (pn2->pn_type) { + case TOK_NAME: + pn2->pn_op = JSOP_DELNAME; + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + op = PN_OP(pn2); + if (op == JSOP_FALSE) { + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } else { + if (!EmitAtomOp(cx, pn2, op, cg)) + return JS_FALSE; + } + break; + case TOK_DOT: + if (!EmitPropOp(cx, pn2, JSOP_DELPROP, cg, JS_FALSE)) + return JS_FALSE; + break; +#if JS_HAS_XML_SUPPORT + case TOK_DBLDOT: + if (!EmitElemOp(cx, pn2, JSOP_DELDESC, cg)) + return JS_FALSE; + break; +#endif +#if JS_HAS_LVALUE_RETURN + case TOK_LP: + top = CG_OFFSET(cg); + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_DELELEM) < 0) + return JS_FALSE; + break; +#endif + case TOK_LB: + if (!EmitElemOp(cx, pn2, JSOP_DELELEM, cg)) + return JS_FALSE; + break; + default: + /* + * If useless, just emit JSOP_TRUE; otherwise convert delete foo() + * to foo(), true (a comma expression, requiring SRC_PCDELTA). + */ + useful = JS_FALSE; + if (!CheckSideEffects(cx, cg, pn2, &useful)) + return JS_FALSE; + if (!useful) { + off = noteIndex = -1; + } else { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + off = CG_OFFSET(cg); + noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } + if (js_Emit1(cx, cg, JSOP_TRUE) < 0) + return JS_FALSE; + if (noteIndex >= 0) { + tmp = CG_OFFSET(cg); + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) + return JS_FALSE; + } + } + break; + +#if JS_HAS_XML_SUPPORT + case TOK_FILTER: + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + jmp = js_Emit3(cx, cg, JSOP_FILTER, 0, 0); + if (jmp < 0) + return JS_FALSE; + top = CG_OFFSET(cg); + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + if (EmitJump(cx, cg, JSOP_ENDFILTER, top - CG_OFFSET(cg)) < 0) + return JS_FALSE; + break; +#endif + + case TOK_DOT: + /* + * Pop a stack operand, convert it to object, get a property named by + * this bytecode's immediate-indexed atom operand, and push its value + * (not a reference to it). + */ + ok = EmitPropOp(cx, pn, PN_OP(pn), cg, JS_FALSE); + break; + + case TOK_LB: +#if JS_HAS_XML_SUPPORT + case TOK_DBLDOT: +#endif + /* + * Pop two operands, convert the left one to object and the right one + * to property name (atom or tagged int), get the named property, and + * push its value. Set the "obj" register to the result of ToObject + * on the left operand. + */ + ok = EmitElemOp(cx, pn, PN_OP(pn), cg); + break; + + case TOK_NEW: + case TOK_LP: + { + uintN oldflags; + + /* + * Emit function call or operator new (constructor call) code. + * First, emit code for the left operand to evaluate the callable or + * constructable object expression. + */ + pn2 = pn->pn_head; + switch (pn2->pn_type) { + case TOK_NAME: + if (!EmitNameOp(cx, cg, pn2, JS_TRUE)) + return JS_FALSE; + break; + case TOK_DOT: + if (!EmitPropOp(cx, pn2, PN_OP(pn2), cg, JS_TRUE)) + return JS_FALSE; + break; + case TOK_LB: + JS_ASSERT(pn2->pn_op == JSOP_GETELEM); + if (!EmitElemOp(cx, pn2, JSOP_CALLELEM, cg)) + return JS_FALSE; + break; + case TOK_UNARYOP: +#if JS_HAS_XML_SUPPORT + if (pn2->pn_op == JSOP_XMLNAME) { + if (!EmitXMLName(cx, pn2, JSOP_CALLXMLNAME, cg)) + return JS_FALSE; + break; + } +#endif + /* FALL THROUGH */ + default: + /* + * Push null as a placeholder for the global object, per ECMA-262 + * 11.2.3 step 6. We use JSOP_NULLTHIS to distinguish this opcode + * from JSOP_NULL (see jstracer.cpp for one use-case). + */ + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_NULLTHIS) < 0) + return JS_FALSE; + } + + /* Remember start of callable-object bytecode for decompilation hint. */ + off = top; + + /* + * Emit code for each argument in order, then emit the JSOP_*CALL or + * JSOP_NEW bytecode with a two-byte immediate telling how many args + * were pushed on the operand stack. + */ + oldflags = cg->treeContext.flags; + cg->treeContext.flags &= ~TCF_IN_FOR_INIT; + for (pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) { + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + } + cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0) + return JS_FALSE; + + argc = pn->pn_count - 1; + if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0) + return JS_FALSE; + if (PN_OP(pn) == JSOP_EVAL) + EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno); + break; + } + + case TOK_LEXICALSCOPE: + { + JSParsedObjectBox *pob; + uintN count; + + pob = pn->pn_pob; + js_PushBlockScope(&cg->treeContext, &stmtInfo, pob->object, + CG_OFFSET(cg)); + + /* + * If this lexical scope is not for a catch block, let block or let + * expression, or any kind of for loop (where the scope starts in the + * head after the first part if for (;;), else in the body if for-in); + * and if our container is top-level but not a function body, or else + * a block statement; then emit a SRC_BRACE note. All other container + * statements get braces by default from the decompiler. + */ + noteIndex = -1; + type = PN_TYPE(pn->pn_expr); + if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR && + (!(stmt = stmtInfo.down) + ? !(cg->treeContext.flags & TCF_IN_FUNCTION) + : stmt->type == STMT_BLOCK)) { +#if defined DEBUG_brendanXXX || defined DEBUG_mrbkap + /* There must be no source note already output for the next op. */ + JS_ASSERT(CG_NOTE_COUNT(cg) == 0 || + CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) || + !GettableNoteForNextOp(cg)); +#endif + noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0); + if (noteIndex < 0) + return JS_FALSE; + } + + JS_ASSERT(CG_OFFSET(cg) == top); + if (!EmitObjectOp(cx, pob, JSOP_ENTERBLOCK, cg)) + return JS_FALSE; + + if (!js_EmitTree(cx, cg, pn->pn_expr)) + return JS_FALSE; + + op = PN_OP(pn); + if (op == JSOP_LEAVEBLOCKEXPR) { + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return JS_FALSE; + } else { + if (noteIndex >= 0 && + !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, + CG_OFFSET(cg) - top)) { + return JS_FALSE; + } + } + + /* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */ + count = OBJ_BLOCK_COUNT(cx, pob->object); + EMIT_UINT16_IMM_OP(op, count); + + ok = js_PopStatementCG(cx, cg); + break; + } + +#if JS_HAS_BLOCK_SCOPE + case TOK_LET: + /* Let statements have their variable declarations on the left. */ + if (pn->pn_arity == PN_BINARY) { + pn2 = pn->pn_right; + pn = pn->pn_left; + } else { + pn2 = NULL; + } + + /* Non-null pn2 means that pn is the variable list from a let head. */ + JS_ASSERT(pn->pn_arity == PN_LIST); + if (!EmitVariables(cx, cg, pn, pn2 != NULL, ¬eIndex)) + return JS_FALSE; + + /* Thus non-null pn2 is the body of the let block or expression. */ + tmp = CG_OFFSET(cg); + if (pn2 && !js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + + if (noteIndex >= 0 && + !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, + CG_OFFSET(cg) - tmp)) { + return JS_FALSE; + } + break; +#endif /* JS_HAS_BLOCK_SCOPE */ + +#if JS_HAS_GENERATORS + case TOK_ARRAYPUSH: { + jsint slot; + + /* + * The array object's stack index is in cg->arrayCompDepth. See below + * under the array initialiser code generator for array comprehension + * special casing. + */ + if (!js_EmitTree(cx, cg, pn->pn_kid)) + return JS_FALSE; + slot = cg->arrayCompDepth; + slot = AdjustBlockSlot(cx, cg, slot); + if (slot < 0) + return JS_FALSE; + EMIT_UINT16_IMM_OP(PN_OP(pn), slot); + break; + } +#endif + + case TOK_RB: +#if JS_HAS_GENERATORS + case TOK_ARRAYCOMP: +#endif + /* + * Emit code for [a, b, c] of the form: + * + * t = new Array; t[0] = a; t[1] = b; t[2] = c; t; + * + * but use a stack slot for t and avoid dup'ing and popping it using + * the JSOP_NEWINIT and JSOP_INITELEM bytecodes. + * + * If no sharp variable is defined and the initialiser is not for an + * array comprehension, use JSOP_NEWARRAY. + */ + pn2 = pn->pn_head; + op = JSOP_NEWINIT; // FIXME: 260106 patch disabled for now + +#if JS_HAS_SHARP_VARS + if (pn2 && pn2->pn_type == TOK_DEFSHARP) + op = JSOP_NEWINIT; +#endif +#if JS_HAS_GENERATORS + if (pn->pn_type == TOK_ARRAYCOMP) + op = JSOP_NEWINIT; +#endif + + if (op == JSOP_NEWINIT && + js_Emit2(cx, cg, op, (jsbytecode) JSProto_Array) < 0) { + return JS_FALSE; + } + +#if JS_HAS_SHARP_VARS + if (pn2 && pn2->pn_type == TOK_DEFSHARP) { + EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num); + pn2 = pn2->pn_next; + } +#endif + +#if JS_HAS_GENERATORS + if (pn->pn_type == TOK_ARRAYCOMP) { + uintN saveDepth; + + /* + * Pass the new array's stack index to the TOK_ARRAYPUSH case by + * storing it in pn->pn_extra, then simply traverse the TOK_FOR + * node and its kids under pn2 to generate this comprehension. + */ + JS_ASSERT(cg->stackDepth > 0); + saveDepth = cg->arrayCompDepth; + cg->arrayCompDepth = (uint32) (cg->stackDepth - 1); + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + cg->arrayCompDepth = saveDepth; + + /* Emit the usual op needed for decompilation. */ + if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0) + return JS_FALSE; + break; + } +#endif /* JS_HAS_GENERATORS */ + + for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) { + if (op == JSOP_NEWINIT && !EmitNumberOp(cx, atomIndex, cg)) + return JS_FALSE; + + if (pn2->pn_type == TOK_COMMA) { + if (js_Emit1(cx, cg, JSOP_HOLE) < 0) + return JS_FALSE; + } else { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } + + if (op == JSOP_NEWINIT && js_Emit1(cx, cg, JSOP_INITELEM) < 0) + return JS_FALSE; + } + + if (pn->pn_extra & PNX_ENDCOMMA) { + /* Emit a source note so we know to decompile an extra comma. */ + if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0) + return JS_FALSE; + } + + if (op == JSOP_NEWARRAY) { + JS_ASSERT(atomIndex == pn->pn_count); + off = js_EmitN(cx, cg, op, 3); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_UINT24(pc, atomIndex); + UpdateDepth(cx, cg, off); + } else { + /* Emit an op for sharp array cleanup and decompilation. */ + if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0) + return JS_FALSE; + } + break; + + case TOK_RC: +#if JS_HAS_DESTRUCTURING_SHORTHAND + if (pn->pn_extra & PNX_SHORTHAND) { + js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, + JSMSG_BAD_OBJECT_INIT); + return JS_FALSE; + } +#endif + /* + * Emit code for {p:a, '%q':b, 2:c} of the form: + * + * t = new Object; t.p = a; t['%q'] = b; t[2] = c; t; + * + * but use a stack slot for t and avoid dup'ing and popping it via + * the JSOP_NEWINIT and JSOP_INITELEM/JSOP_INITPROP bytecodes. + */ + if (js_Emit2(cx, cg, JSOP_NEWINIT, (jsbytecode) JSProto_Object) < 0) + return JS_FALSE; + + pn2 = pn->pn_head; +#if JS_HAS_SHARP_VARS + if (pn2 && pn2->pn_type == TOK_DEFSHARP) { + EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num); + pn2 = pn2->pn_next; + } +#endif + + for (; pn2; pn2 = pn2->pn_next) { + /* Emit an index for t[2], else map an atom for t.p or t['%q']. */ + pn3 = pn2->pn_left; + if (pn3->pn_type == TOK_NUMBER) { +#ifdef __GNUC__ + ale = NULL; /* quell GCC overwarning */ +#endif + if (!EmitNumberOp(cx, pn3->pn_dval, cg)) + return JS_FALSE; + } else { + JS_ASSERT(pn3->pn_type == TOK_NAME || + pn3->pn_type == TOK_STRING); + ale = js_IndexAtom(cx, pn3->pn_atom, &cg->atomList); + if (!ale) + return JS_FALSE; + } + + /* Emit code for the property initializer. */ + if (!js_EmitTree(cx, cg, pn2->pn_right)) + return JS_FALSE; + +#if JS_HAS_GETTER_SETTER + op = PN_OP(pn2); + if (op == JSOP_GETTER || op == JSOP_SETTER) { + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } +#endif + /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */ + if (pn3->pn_type == TOK_NUMBER) { + if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_INITELEM) < 0) + return JS_FALSE; + } else { + EMIT_INDEX_OP(JSOP_INITPROP, ALE_INDEX(ale)); + } + } + + /* Emit an op for sharpArray cleanup and decompilation. */ + if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0) + return JS_FALSE; + break; + +#if JS_HAS_SHARP_VARS + case TOK_DEFSHARP: + if (!js_EmitTree(cx, cg, pn->pn_kid)) + return JS_FALSE; + EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) pn->pn_num); + break; + + case TOK_USESHARP: + EMIT_UINT16_IMM_OP(JSOP_USESHARP, (jsatomid) pn->pn_num); + break; +#endif /* JS_HAS_SHARP_VARS */ + + case TOK_RP: + { + uintN oldflags; + + /* + * The node for (e) has e as its kid, enabling users who want to nest + * assignment expressions in conditions to avoid the error correction + * done by Condition (from x = y to x == y) by double-parenthesizing. + */ + oldflags = cg->treeContext.flags; + cg->treeContext.flags &= ~TCF_IN_FOR_INIT; + if (!js_EmitTree(cx, cg, pn->pn_kid)) + return JS_FALSE; + cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT; + break; + } + + case TOK_NAME: + if (!EmitNameOp(cx, cg, pn, JS_FALSE)) + return JS_FALSE; + break; + +#if JS_HAS_XML_SUPPORT + case TOK_XMLATTR: + case TOK_XMLSPACE: + case TOK_XMLTEXT: + case TOK_XMLCDATA: + case TOK_XMLCOMMENT: +#endif + case TOK_STRING: + ok = EmitAtomOp(cx, pn, PN_OP(pn), cg); + break; + + case TOK_NUMBER: + ok = EmitNumberOp(cx, pn->pn_dval, cg); + break; + + case TOK_REGEXP: + /* + * If the regexp's script is one-shot, we can avoid the extra + * fork-on-exec costs of JSOP_REGEXP by selecting JSOP_OBJECT. + * Otherwise, to avoid incorrect proto, parent, and lastIndex + * sharing among threads and sequentially across re-execution, + * select JSOP_REGEXP. + */ + JS_ASSERT(pn->pn_op == JSOP_REGEXP); + if (cg->treeContext.flags & TCF_COMPILE_N_GO) { + ok = EmitObjectOp(cx, pn->pn_pob, JSOP_OBJECT, cg); + } else { + ok = EmitIndexOp(cx, JSOP_REGEXP, + IndexParsedObject(pn->pn_pob, &cg->regexpList), + cg); + } + break; + +#if JS_HAS_XML_SUPPORT + case TOK_ANYNAME: +#endif + case TOK_PRIMARY: + if (js_Emit1(cx, cg, PN_OP(pn)) < 0) + return JS_FALSE; + break; + +#if JS_HAS_DEBUGGER_KEYWORD + case TOK_DEBUGGER: + if (js_Emit1(cx, cg, JSOP_DEBUGGER) < 0) + return JS_FALSE; + break; +#endif /* JS_HAS_DEBUGGER_KEYWORD */ + +#if JS_HAS_XML_SUPPORT + case TOK_XMLELEM: + case TOK_XMLLIST: + if (pn->pn_op == JSOP_XMLOBJECT) { + ok = EmitObjectOp(cx, pn->pn_pob, PN_OP(pn), cg); + break; + } + + JS_ASSERT(pn->pn_type == TOK_XMLLIST || pn->pn_count != 0); + switch (pn->pn_head ? pn->pn_head->pn_type : TOK_XMLLIST) { + case TOK_XMLETAGO: + JS_ASSERT(0); + /* FALL THROUGH */ + case TOK_XMLPTAGC: + case TOK_XMLSTAGO: + break; + default: + if (js_Emit1(cx, cg, JSOP_STARTXML) < 0) + return JS_FALSE; + } + + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (pn2->pn_type == TOK_LC && + js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { + return JS_FALSE; + } + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0) + return JS_FALSE; + } + + if (pn->pn_extra & PNX_XMLROOT) { + if (pn->pn_count == 0) { + JS_ASSERT(pn->pn_type == TOK_XMLLIST); + atom = cx->runtime->atomState.emptyAtom; + ale = js_IndexAtom(cx, atom, &cg->atomList); + if (!ale) + return JS_FALSE; + EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale)); + } + if (js_Emit1(cx, cg, PN_OP(pn)) < 0) + return JS_FALSE; + } +#ifdef DEBUG + else + JS_ASSERT(pn->pn_count != 0); +#endif + break; + + case TOK_XMLPTAGC: + if (pn->pn_op == JSOP_XMLOBJECT) { + ok = EmitObjectOp(cx, pn->pn_pob, PN_OP(pn), cg); + break; + } + /* FALL THROUGH */ + + case TOK_XMLSTAGO: + case TOK_XMLETAGO: + { + uint32 i; + + if (js_Emit1(cx, cg, JSOP_STARTXML) < 0) + return JS_FALSE; + + ale = js_IndexAtom(cx, + (pn->pn_type == TOK_XMLETAGO) + ? cx->runtime->atomState.etagoAtom + : cx->runtime->atomState.stagoAtom, + &cg->atomList); + if (!ale) + return JS_FALSE; + EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale)); + + JS_ASSERT(pn->pn_count != 0); + pn2 = pn->pn_head; + if (pn2->pn_type == TOK_LC && js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_ADD) < 0) + return JS_FALSE; + + for (pn2 = pn2->pn_next, i = 0; pn2; pn2 = pn2->pn_next, i++) { + if (pn2->pn_type == TOK_LC && + js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { + return JS_FALSE; + } + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if ((i & 1) && pn2->pn_type == TOK_LC) { + if (js_Emit1(cx, cg, JSOP_TOATTRVAL) < 0) + return JS_FALSE; + } + if (js_Emit1(cx, cg, + (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0) { + return JS_FALSE; + } + } + + ale = js_IndexAtom(cx, + (pn->pn_type == TOK_XMLPTAGC) + ? cx->runtime->atomState.ptagcAtom + : cx->runtime->atomState.tagcAtom, + &cg->atomList); + if (!ale) + return JS_FALSE; + EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale)); + if (js_Emit1(cx, cg, JSOP_ADD) < 0) + return JS_FALSE; + + if ((pn->pn_extra & PNX_XMLROOT) && js_Emit1(cx, cg, PN_OP(pn)) < 0) + return JS_FALSE; + break; + } + + case TOK_XMLNAME: + if (pn->pn_arity == PN_LIST) { + JS_ASSERT(pn->pn_count != 0); + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0) + return JS_FALSE; + } + } else { + JS_ASSERT(pn->pn_arity == PN_NULLARY); + ok = (pn->pn_op == JSOP_OBJECT) + ? EmitObjectOp(cx, pn->pn_pob, PN_OP(pn), cg) + : EmitAtomOp(cx, pn, PN_OP(pn), cg); + } + break; + + case TOK_XMLPI: + ale = js_IndexAtom(cx, pn->pn_atom2, &cg->atomList); + if (!ale) + return JS_FALSE; + if (!EmitIndexOp(cx, JSOP_QNAMEPART, ALE_INDEX(ale), cg)) + return JS_FALSE; + if (!EmitAtomOp(cx, pn, JSOP_XMLPI, cg)) + return JS_FALSE; + break; +#endif /* JS_HAS_XML_SUPPORT */ + + default: + JS_ASSERT(0); + } + + if (ok && --cg->emitLevel == 0 && cg->spanDeps) + ok = OptimizeSpanDeps(cx, cg); + + return ok; +} + +/* + * We should try to get rid of offsetBias (always 0 or 1, where 1 is + * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL. + */ +JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = { + {"null", 0, 0, 0}, + {"if", 0, 0, 0}, + {"if-else", 2, 0, 1}, + {"for", 3, 1, 1}, + {"while", 1, 0, 1}, + {"continue", 0, 0, 0}, + {"decl", 1, 1, 1}, + {"pcdelta", 1, 0, 1}, + {"assignop", 0, 0, 0}, + {"cond", 1, 0, 1}, + {"brace", 1, 0, 1}, + {"hidden", 0, 0, 0}, + {"pcbase", 1, 0, -1}, + {"label", 1, 0, 0}, + {"labelbrace", 1, 0, 0}, + {"endbrace", 0, 0, 0}, + {"break2label", 1, 0, 0}, + {"cont2label", 1, 0, 0}, + {"switch", 2, 0, 1}, + {"funcdef", 1, 0, 0}, + {"catch", 1, 0, 1}, + {"extended", -1, 0, 0}, + {"newline", 0, 0, 0}, + {"setline", 1, 0, 0}, + {"xdelta", 0, 0, 0}, +}; + +static intN +AllocSrcNote(JSContext *cx, JSCodeGenerator *cg) +{ + intN index; + JSArenaPool *pool; + size_t size; + + index = CG_NOTE_COUNT(cg); + if (((uintN)index & CG_NOTE_MASK(cg)) == 0) { + pool = cg->notePool; + size = SRCNOTE_SIZE(CG_NOTE_MASK(cg) + 1); + if (!CG_NOTES(cg)) { + /* Allocate the first note array lazily; leave noteMask alone. */ + JS_ARENA_ALLOCATE_CAST(CG_NOTES(cg), jssrcnote *, pool, size); + } else { + /* Grow by doubling note array size; update noteMask on success. */ + JS_ARENA_GROW_CAST(CG_NOTES(cg), jssrcnote *, pool, size, size); + if (CG_NOTES(cg)) + CG_NOTE_MASK(cg) = (CG_NOTE_MASK(cg) << 1) | 1; + } + if (!CG_NOTES(cg)) { + js_ReportOutOfScriptQuota(cx); + return -1; + } + } + + CG_NOTE_COUNT(cg) = index + 1; + return index; +} + +intN +js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type) +{ + intN index, n; + jssrcnote *sn; + ptrdiff_t offset, delta, xdelta; + + /* + * Claim a note slot in CG_NOTES(cg) by growing it if necessary and then + * incrementing CG_NOTE_COUNT(cg). + */ + index = AllocSrcNote(cx, cg); + if (index < 0) + return -1; + sn = &CG_NOTES(cg)[index]; + + /* + * Compute delta from the last annotated bytecode's offset. If it's too + * big to fit in sn, allocate one or more xdelta notes and reset sn. + */ + offset = CG_OFFSET(cg); + delta = offset - CG_LAST_NOTE_OFFSET(cg); + CG_LAST_NOTE_OFFSET(cg) = offset; + if (delta >= SN_DELTA_LIMIT) { + do { + xdelta = JS_MIN(delta, SN_XDELTA_MASK); + SN_MAKE_XDELTA(sn, xdelta); + delta -= xdelta; + index = AllocSrcNote(cx, cg); + if (index < 0) + return -1; + sn = &CG_NOTES(cg)[index]; + } while (delta >= SN_DELTA_LIMIT); + } + + /* + * Initialize type and delta, then allocate the minimum number of notes + * needed for type's arity. Usually, we won't need more, but if an offset + * does take two bytes, js_SetSrcNoteOffset will grow CG_NOTES(cg). + */ + SN_MAKE_NOTE(sn, type, delta); + for (n = (intN)js_SrcNoteSpec[type].arity; n > 0; n--) { + if (js_NewSrcNote(cx, cg, SRC_NULL) < 0) + return -1; + } + return index; +} + +intN +js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, + ptrdiff_t offset) +{ + intN index; + + index = js_NewSrcNote(cx, cg, type); + if (index >= 0) { + if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset)) + return -1; + } + return index; +} + +intN +js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, + ptrdiff_t offset1, ptrdiff_t offset2) +{ + intN index; + + index = js_NewSrcNote(cx, cg, type); + if (index >= 0) { + if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset1)) + return -1; + if (!js_SetSrcNoteOffset(cx, cg, index, 1, offset2)) + return -1; + } + return index; +} + +static JSBool +GrowSrcNotes(JSContext *cx, JSCodeGenerator *cg) +{ + JSArenaPool *pool; + size_t size; + + /* Grow by doubling note array size; update noteMask on success. */ + pool = cg->notePool; + size = SRCNOTE_SIZE(CG_NOTE_MASK(cg) + 1); + JS_ARENA_GROW_CAST(CG_NOTES(cg), jssrcnote *, pool, size, size); + if (!CG_NOTES(cg)) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + CG_NOTE_MASK(cg) = (CG_NOTE_MASK(cg) << 1) | 1; + return JS_TRUE; +} + +jssrcnote * +js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn, + ptrdiff_t delta) +{ + ptrdiff_t base, limit, newdelta, diff; + intN index; + + /* + * Called only from OptimizeSpanDeps and js_FinishTakingSrcNotes to add to + * main script note deltas, and only by a small positive amount. + */ + JS_ASSERT(cg->current == &cg->main); + JS_ASSERT((unsigned) delta < (unsigned) SN_XDELTA_LIMIT); + + base = SN_DELTA(sn); + limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT; + newdelta = base + delta; + if (newdelta < limit) { + SN_SET_DELTA(sn, newdelta); + } else { + index = sn - cg->main.notes; + if ((cg->main.noteCount & cg->main.noteMask) == 0) { + if (!GrowSrcNotes(cx, cg)) + return NULL; + sn = cg->main.notes + index; + } + diff = cg->main.noteCount - index; + cg->main.noteCount++; + memmove(sn + 1, sn, SRCNOTE_SIZE(diff)); + SN_MAKE_XDELTA(sn, delta); + sn++; + } + return sn; +} + +JS_FRIEND_API(uintN) +js_SrcNoteLength(jssrcnote *sn) +{ + uintN arity; + jssrcnote *base; + + arity = (intN)js_SrcNoteSpec[SN_TYPE(sn)].arity; + for (base = sn++; arity; sn++, arity--) { + if (*sn & SN_3BYTE_OFFSET_FLAG) + sn += 2; + } + return sn - base; +} + +JS_FRIEND_API(ptrdiff_t) +js_GetSrcNoteOffset(jssrcnote *sn, uintN which) +{ + /* Find the offset numbered which (i.e., skip exactly which offsets). */ + JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA); + JS_ASSERT((intN) which < js_SrcNoteSpec[SN_TYPE(sn)].arity); + for (sn++; which; sn++, which--) { + if (*sn & SN_3BYTE_OFFSET_FLAG) + sn += 2; + } + if (*sn & SN_3BYTE_OFFSET_FLAG) { + return (ptrdiff_t)(((uint32)(sn[0] & SN_3BYTE_OFFSET_MASK) << 16) + | (sn[1] << 8) + | sn[2]); + } + return (ptrdiff_t)*sn; +} + +JSBool +js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, + uintN which, ptrdiff_t offset) +{ + jssrcnote *sn; + ptrdiff_t diff; + + if ((jsuword)offset >= (jsuword)((ptrdiff_t)SN_3BYTE_OFFSET_FLAG << 16)) { + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + + /* Find the offset numbered which (i.e., skip exactly which offsets). */ + sn = &CG_NOTES(cg)[index]; + JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA); + JS_ASSERT((intN) which < js_SrcNoteSpec[SN_TYPE(sn)].arity); + for (sn++; which; sn++, which--) { + if (*sn & SN_3BYTE_OFFSET_FLAG) + sn += 2; + } + + /* See if the new offset requires three bytes. */ + if (offset > (ptrdiff_t)SN_3BYTE_OFFSET_MASK) { + /* Maybe this offset was already set to a three-byte value. */ + if (!(*sn & SN_3BYTE_OFFSET_FLAG)) { + /* Losing, need to insert another two bytes for this offset. */ + index = PTRDIFF(sn, CG_NOTES(cg), jssrcnote); + + /* + * Simultaneously test to see if the source note array must grow to + * accomodate either the first or second byte of additional storage + * required by this 3-byte offset. + */ + if (((CG_NOTE_COUNT(cg) + 1) & CG_NOTE_MASK(cg)) <= 1) { + if (!GrowSrcNotes(cx, cg)) + return JS_FALSE; + sn = CG_NOTES(cg) + index; + } + CG_NOTE_COUNT(cg) += 2; + + diff = CG_NOTE_COUNT(cg) - (index + 3); + JS_ASSERT(diff >= 0); + if (diff > 0) + memmove(sn + 3, sn + 1, SRCNOTE_SIZE(diff)); + } + *sn++ = (jssrcnote)(SN_3BYTE_OFFSET_FLAG | (offset >> 16)); + *sn++ = (jssrcnote)(offset >> 8); + } + *sn = (jssrcnote)offset; + return JS_TRUE; +} + +#ifdef DEBUG_notme +#define DEBUG_srcnotesize +#endif + +#ifdef DEBUG_srcnotesize +#define NBINS 10 +static uint32 hist[NBINS]; + +void DumpSrcNoteSizeHist() +{ + static FILE *fp; + int i, n; + + if (!fp) { + fp = fopen("/tmp/srcnotes.hist", "w"); + if (!fp) + return; + setvbuf(fp, NULL, _IONBF, 0); + } + fprintf(fp, "SrcNote size histogram:\n"); + for (i = 0; i < NBINS; i++) { + fprintf(fp, "%4u %4u ", JS_BIT(i), hist[i]); + for (n = (int) JS_HOWMANY(hist[i], 10); n > 0; --n) + fputc('*', fp); + fputc('\n', fp); + } + fputc('\n', fp); +} +#endif + +/* + * Fill in the storage at notes with prolog and main srcnotes; the space at + * notes was allocated using the CG_COUNT_FINAL_SRCNOTES macro from jsemit.h. + * SO DON'T CHANGE THIS FUNCTION WITHOUT AT LEAST CHECKING WHETHER jsemit.h's + * CG_COUNT_FINAL_SRCNOTES MACRO NEEDS CORRESPONDING CHANGES! + */ +JSBool +js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes) +{ + uintN prologCount, mainCount, totalCount; + ptrdiff_t offset, delta; + jssrcnote *sn; + + JS_ASSERT(cg->current == &cg->main); + + prologCount = cg->prolog.noteCount; + if (prologCount && cg->prolog.currentLine != cg->firstLine) { + CG_SWITCH_TO_PROLOG(cg); + if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)cg->firstLine) < 0) + return JS_FALSE; + prologCount = cg->prolog.noteCount; + CG_SWITCH_TO_MAIN(cg); + } else { + /* + * Either no prolog srcnotes, or no line number change over prolog. + * We don't need a SRC_SETLINE, but we may need to adjust the offset + * of the first main note, by adding to its delta and possibly even + * prepending SRC_XDELTA notes to it to account for prolog bytecodes + * that came at and after the last annotated bytecode. + */ + offset = CG_PROLOG_OFFSET(cg) - cg->prolog.lastNoteOffset; + JS_ASSERT(offset >= 0); + if (offset > 0 && cg->main.noteCount != 0) { + /* NB: Use as much of the first main note's delta as we can. */ + sn = cg->main.notes; + delta = SN_IS_XDELTA(sn) + ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK) + : SN_DELTA_MASK - (*sn & SN_DELTA_MASK); + if (offset < delta) + delta = offset; + for (;;) { + if (!js_AddToSrcNoteDelta(cx, cg, sn, delta)) + return JS_FALSE; + offset -= delta; + if (offset == 0) + break; + delta = JS_MIN(offset, SN_XDELTA_MASK); + sn = cg->main.notes; + } + } + } + + mainCount = cg->main.noteCount; + totalCount = prologCount + mainCount; + if (prologCount) + memcpy(notes, cg->prolog.notes, SRCNOTE_SIZE(prologCount)); + memcpy(notes + prologCount, cg->main.notes, SRCNOTE_SIZE(mainCount)); + SN_MAKE_TERMINATOR(¬es[totalCount]); + +#ifdef DEBUG_notme + { int bin = JS_CeilingLog2(totalCount); + if (bin >= NBINS) + bin = NBINS - 1; + ++hist[bin]; + } +#endif + return JS_TRUE; +} + +static JSBool +NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, + uintN stackDepth, size_t start, size_t end) +{ + JSTryNode *tryNode; + + JS_ASSERT((uintN)(uint16)stackDepth == stackDepth); + JS_ASSERT(start <= end); + JS_ASSERT((size_t)(uint32)start == start); + JS_ASSERT((size_t)(uint32)end == end); + + JS_ARENA_ALLOCATE_TYPE(tryNode, JSTryNode, &cx->tempPool); + if (!tryNode) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + + tryNode->note.kind = kind; + tryNode->note.stackDepth = (uint16)stackDepth; + tryNode->note.start = (uint32)start; + tryNode->note.length = (uint32)(end - start); + tryNode->prev = cg->lastTryNode; + cg->lastTryNode = tryNode; + cg->ntrynotes++; + return JS_TRUE; +} + +void +js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array) +{ + JSTryNode *tryNode; + JSTryNote *tn; + + JS_ASSERT(array->length > 0 && array->length == cg->ntrynotes); + tn = array->vector + array->length; + tryNode = cg->lastTryNode; + do { + *--tn = tryNode->note; + } while ((tryNode = tryNode->prev) != NULL); + JS_ASSERT(tn == array->vector); +} + +/* + * Find the index of the given object for code generator. + * + * Since the emitter refers to each parsed object only once, for the index we + * use the number of already indexes objects. We also add the object to a list + * to convert the list to a fixed-size array when we complete code generation, + * see FinishParsedObjects bellow. + * + * Most of the objects go to JSCodeGenerator.objectList but for regexp we use + * a separated JSCodeGenerator.regexpList. In this way the emitted index can + * be directly used to store and fetch a reference to a cloned RegExp object + * that shares the same JSRegExp private data created for the object literal + * in pob. We need clones to hold lastIndex and other direct properties that + * should not be shared among threads sharing a precompiled function or + * script. + * + * If the code being compiled is function code, allocate a reserved slot in + * the cloned function object that shares its precompiled script with other + * cloned function objects and with the compiler-created clone-parent. There + * are nregexps = JS_SCRIPT_REGEXPS(script)->length such reserved slots in each + * function object cloned from fun->object. NB: during compilation, a funobj + * slots element must never be allocated, because js_AllocSlot could hand out + * one of the slots that should be given to a regexp clone. + * + * If the code being compiled is global code, the cloned regexp are stored in + * fp->vars slot after cg->treeContext.ngvars and to protect regexp slots from + * GC we set fp->nvars to ngvars + nregexps. + * + * The slots initially contain undefined or null. We populate them lazily when + * JSOP_REGEXP is executed for the first time. + * + * Why clone regexp objects? ECMA specifies that when a regular expression + * literal is scanned, a RegExp object is created. In the spec, compilation + * and execution happen indivisibly, but in this implementation and many of + * its embeddings, code is precompiled early and re-executed in multiple + * threads, or using multiple global objects, or both, for efficiency. + * + * In such cases, naively following ECMA leads to wrongful sharing of RegExp + * objects, which makes for collisions on the lastIndex property (especially + * for global regexps) and on any ad-hoc properties. Also, __proto__ and + * __parent__ refer to the pre-compilation prototype and global objects, a + * pigeon-hole problem for instanceof tests. + */ +static uintN +IndexParsedObject(JSParsedObjectBox *pob, JSEmittedObjectList *list) +{ + JS_ASSERT(!pob->emitLink); + pob->emitLink = list->lastPob; + list->lastPob = pob; + return list->length++; +} + +void +FinishParsedObjects(JSEmittedObjectList *emittedList, JSObjectArray *array) +{ + JSObject **cursor; + JSParsedObjectBox *pob; + + JS_ASSERT(emittedList->length <= INDEX_LIMIT); + JS_ASSERT(emittedList->length == array->length); + + cursor = array->vector + array->length; + pob = emittedList->lastPob; + do { + --cursor; + JS_ASSERT(!*cursor); + *cursor = pob->object; + } while ((pob = pob->emitLink) != NULL); + JS_ASSERT(cursor == array->vector); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsemit.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsemit.h new file mode 100644 index 0000000..4e39f6c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsemit.h @@ -0,0 +1,777 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsemit_h___ +#define jsemit_h___ +/* + * JS bytecode generation. + */ + +#include "jsstddef.h" +#include "jstypes.h" +#include "jsatom.h" +#include "jsopcode.h" +#include "jsscript.h" +#include "jsprvtd.h" +#include "jspubtd.h" + +JS_BEGIN_EXTERN_C + +/* + * NB: If you add enumerators for scope statements, add them between STMT_WITH + * and STMT_CATCH, or you will break the STMT_TYPE_IS_SCOPE macro. If you add + * non-looping statement enumerators, add them before STMT_DO_LOOP or you will + * break the STMT_TYPE_IS_LOOP macro. + * + * Also remember to keep the statementName array in jsemit.c in sync. + */ +typedef enum JSStmtType { + STMT_LABEL, /* labeled statement: L: s */ + STMT_IF, /* if (then) statement */ + STMT_ELSE, /* else clause of if statement */ + STMT_SEQ, /* synthetic sequence of statements */ + STMT_BLOCK, /* compound statement: { s1[;... sN] } */ + STMT_SWITCH, /* switch statement */ + STMT_WITH, /* with statement */ + STMT_CATCH, /* catch block */ + STMT_TRY, /* try block */ + STMT_FINALLY, /* finally block */ + STMT_SUBROUTINE, /* gosub-target subroutine body */ + STMT_DO_LOOP, /* do/while loop statement */ + STMT_FOR_LOOP, /* for loop statement */ + STMT_FOR_IN_LOOP, /* for/in loop statement */ + STMT_WHILE_LOOP, /* while loop statement */ + STMT_LIMIT +} JSStmtType; + +#define STMT_TYPE_IN_RANGE(t,b,e) ((uint)((t) - (b)) <= (uintN)((e) - (b))) + +/* + * A comment on the encoding of the JSStmtType enum and type-testing macros: + * + * STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may + * become, a lexical scope. It therefore includes block and switch (the two + * low-numbered "maybe" scope types) and excludes with (with has dynamic scope + * pending the "reformed with" in ES4/JS2). It includes all try-catch-finally + * types, which are high-numbered maybe-scope types. + * + * STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly + * links to other scoping statement info records. It excludes the two early + * "maybe" types, block and switch, as well as the try and both finally types, + * since try and the other trailing maybe-scope types don't need block scope + * unless they contain let declarations. + * + * We treat WITH as a static scope because it prevents lexical binding from + * continuing further up the static scope chain. With the lost "reformed with" + * proposal for ES4, we would be able to model it statically, too. + */ +#define STMT_TYPE_MAYBE_SCOPE(type) \ + (type != STMT_WITH && \ + STMT_TYPE_IN_RANGE(type, STMT_BLOCK, STMT_SUBROUTINE)) + +#define STMT_TYPE_LINKS_SCOPE(type) \ + STMT_TYPE_IN_RANGE(type, STMT_WITH, STMT_CATCH) + +#define STMT_TYPE_IS_TRYING(type) \ + STMT_TYPE_IN_RANGE(type, STMT_TRY, STMT_SUBROUTINE) + +#define STMT_TYPE_IS_LOOP(type) ((type) >= STMT_DO_LOOP) + +#define STMT_MAYBE_SCOPE(stmt) STMT_TYPE_MAYBE_SCOPE((stmt)->type) +#define STMT_LINKS_SCOPE(stmt) (STMT_TYPE_LINKS_SCOPE((stmt)->type) || \ + ((stmt)->flags & SIF_SCOPE)) +#define STMT_IS_TRYING(stmt) STMT_TYPE_IS_TRYING((stmt)->type) +#define STMT_IS_LOOP(stmt) STMT_TYPE_IS_LOOP((stmt)->type) + +typedef struct JSStmtInfo JSStmtInfo; + +struct JSStmtInfo { + uint16 type; /* statement type */ + uint16 flags; /* flags, see below */ + ptrdiff_t update; /* loop update offset (top if none) */ + ptrdiff_t breaks; /* offset of last break in loop */ + ptrdiff_t continues; /* offset of last continue in loop */ + union { + JSAtom *label; /* name of LABEL */ + JSObject *blockObj; /* block scope object */ + } u; + JSStmtInfo *down; /* info for enclosing statement */ + JSStmtInfo *downScope; /* next enclosing lexical scope */ +}; + +#define SIF_SCOPE 0x0001 /* statement has its own lexical scope */ +#define SIF_BODY_BLOCK 0x0002 /* STMT_BLOCK type is a function body */ +#define SIF_FOR_BLOCK 0x0004 /* for (let ...) induced block scope */ + +/* + * To reuse space in JSStmtInfo, rename breaks and continues for use during + * try/catch/finally code generation and backpatching. To match most common + * use cases, the macro argument is a struct, not a struct pointer. Only a + * loop, switch, or label statement info record can have breaks and continues, + * and only a for loop has an update backpatch chain, so it's safe to overlay + * these for the "trying" JSStmtTypes. + */ +#define CATCHNOTE(stmt) ((stmt).update) +#define GOSUBS(stmt) ((stmt).breaks) +#define GUARDJUMP(stmt) ((stmt).continues) + +#define AT_TOP_LEVEL(tc) \ + (!(tc)->topStmt || ((tc)->topStmt->flags & SIF_BODY_BLOCK)) + +#define SET_STATEMENT_TOP(stmt, top) \ + ((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1)) + +struct JSTreeContext { /* tree context for semantic checks */ + uint16 flags; /* statement state flags, see below */ + uint16 ngvars; /* max. no. of global variables/regexps */ + JSStmtInfo *topStmt; /* top of statement info stack */ + JSStmtInfo *topScopeStmt; /* top lexical scope statement */ + JSObject *blockChain; /* compile time block scope chain (NB: one + deeper than the topScopeStmt/downScope + chain when in head of let block/expr) */ + JSParseNode *blockNode; /* parse node for a lexical scope. + XXX combine with blockChain? */ + JSAtomList decls; /* function, const, and var declarations */ + JSParseContext *parseContext; + + union { + + JSFunction *fun; /* function to store argument and variable + names when flags & TCF_IN_FUNCTION */ + JSObject *scopeChain; /* scope chain object for the script */ + } u; + +#ifdef JS_SCOPE_DEPTH_METER + uint16 scopeDepth; /* current lexical scope chain depth */ + uint16 maxScopeDepth; /* maximum lexical scope chain depth */ +#endif +}; + +#define TCF_IN_FUNCTION 0x01 /* parsing inside function body */ +#define TCF_RETURN_EXPR 0x02 /* function has 'return expr;' */ +#define TCF_RETURN_VOID 0x04 /* function has 'return;' */ +#define TCF_IN_FOR_INIT 0x08 /* parsing init expr of for; exclude 'in' */ +#define TCF_FUN_CLOSURE_VS_VAR 0x10 /* function and var with same name */ +#define TCF_FUN_USES_NONLOCALS 0x20 /* function refers to non-local names */ +#define TCF_FUN_HEAVYWEIGHT 0x40 /* function needs Call object per call */ +#define TCF_FUN_IS_GENERATOR 0x80 /* parsed yield statement in function */ +#define TCF_HAS_DEFXMLNS 0x100 /* default xml namespace = ...; parsed */ +#define TCF_HAS_FUNCTION_STMT 0x200 /* block contains a function statement */ +#define TCF_GENEXP_LAMBDA 0x400 /* flag lambda from generator expression */ +#define TCF_COMPILE_N_GO 0x800 /* compiler-and-go mode of script, can + optimize name references based on scope + chain */ +#define TCF_NO_SCRIPT_RVAL 0x1000 /* API caller does not want result value + from global script */ +/* + * Flags to propagate out of the blocks. + */ +#define TCF_RETURN_FLAGS (TCF_RETURN_EXPR | TCF_RETURN_VOID) + +/* + * Flags to propagate from FunctionBody. + */ +#define TCF_FUN_FLAGS (TCF_FUN_IS_GENERATOR | \ + TCF_FUN_HEAVYWEIGHT | \ + TCF_FUN_USES_NONLOCALS | \ + TCF_FUN_CLOSURE_VS_VAR) + +/* + * Flags field, not stored in JSTreeContext.flags, for passing staticDepth + * into js_CompileScript. + */ +#define TCF_STATIC_DEPTH_MASK 0xffff0000 +#define TCF_GET_STATIC_DEPTH(f) ((uint32)(f) >> 16) +#define TCF_PUT_STATIC_DEPTH(d) ((uint16)(d) << 16) + +#ifdef JS_SCOPE_DEPTH_METER +# define JS_SCOPE_DEPTH_METERING(code) ((void) (code)) +#else +# define JS_SCOPE_DEPTH_METERING(code) ((void) 0) +#endif + +#define TREE_CONTEXT_INIT(tc, pc) \ + ((tc)->flags = (tc)->ngvars = 0, \ + (tc)->topStmt = (tc)->topScopeStmt = NULL, \ + (tc)->blockChain = NULL, \ + ATOM_LIST_INIT(&(tc)->decls), \ + (tc)->blockNode = NULL, \ + (tc)->parseContext = (pc), \ + (tc)->u.scopeChain = NULL, \ + JS_SCOPE_DEPTH_METERING((tc)->scopeDepth = (tc)->maxScopeDepth = 0)) + +/* + * For functions TREE_CONTEXT_FINISH is called the second time to finish the + * extra tc created during code generation. We skip stats update in such + * cases. + */ +#define TREE_CONTEXT_FINISH(cx, tc) \ + JS_SCOPE_DEPTH_METERING( \ + (tc)->maxScopeDepth == (uintN) -1 || \ + JS_BASIC_STATS_ACCUM(&(cx)->runtime->lexicalScopeDepthStats, \ + (tc)->maxScopeDepth)) + +/* + * Span-dependent instructions are jumps whose span (from the jump bytecode to + * the jump target) may require 2 or 4 bytes of immediate operand. + */ +typedef struct JSSpanDep JSSpanDep; +typedef struct JSJumpTarget JSJumpTarget; + +struct JSSpanDep { + ptrdiff_t top; /* offset of first bytecode in an opcode */ + ptrdiff_t offset; /* offset - 1 within opcode of jump operand */ + ptrdiff_t before; /* original offset - 1 of jump operand */ + JSJumpTarget *target; /* tagged target pointer or backpatch delta */ +}; + +/* + * Jump targets are stored in an AVL tree, for O(log(n)) lookup with targets + * sorted by offset from left to right, so that targets after a span-dependent + * instruction whose jump offset operand must be extended can be found quickly + * and adjusted upward (toward higher offsets). + */ +struct JSJumpTarget { + ptrdiff_t offset; /* offset of span-dependent jump target */ + int balance; /* AVL tree balance number */ + JSJumpTarget *kids[2]; /* left and right AVL tree child pointers */ +}; + +#define JT_LEFT 0 +#define JT_RIGHT 1 +#define JT_OTHER_DIR(dir) (1 - (dir)) +#define JT_IMBALANCE(dir) (((dir) << 1) - 1) +#define JT_DIR(imbalance) (((imbalance) + 1) >> 1) + +/* + * Backpatch deltas are encoded in JSSpanDep.target if JT_TAG_BIT is clear, + * so we can maintain backpatch chains when using span dependency records to + * hold jump offsets that overflow 16 bits. + */ +#define JT_TAG_BIT ((jsword) 1) +#define JT_UNTAG_SHIFT 1 +#define JT_SET_TAG(jt) ((JSJumpTarget *)((jsword)(jt) | JT_TAG_BIT)) +#define JT_CLR_TAG(jt) ((JSJumpTarget *)((jsword)(jt) & ~JT_TAG_BIT)) +#define JT_HAS_TAG(jt) ((jsword)(jt) & JT_TAG_BIT) + +#define BITS_PER_PTRDIFF (sizeof(ptrdiff_t) * JS_BITS_PER_BYTE) +#define BITS_PER_BPDELTA (BITS_PER_PTRDIFF - 1 - JT_UNTAG_SHIFT) +#define BPDELTA_MAX (((ptrdiff_t)1 << BITS_PER_BPDELTA) - 1) +#define BPDELTA_TO_JT(bp) ((JSJumpTarget *)((bp) << JT_UNTAG_SHIFT)) +#define JT_TO_BPDELTA(jt) ((ptrdiff_t)((jsword)(jt) >> JT_UNTAG_SHIFT)) + +#define SD_SET_TARGET(sd,jt) ((sd)->target = JT_SET_TAG(jt)) +#define SD_GET_TARGET(sd) (JS_ASSERT(JT_HAS_TAG((sd)->target)), \ + JT_CLR_TAG((sd)->target)) +#define SD_SET_BPDELTA(sd,bp) ((sd)->target = BPDELTA_TO_JT(bp)) +#define SD_GET_BPDELTA(sd) (JS_ASSERT(!JT_HAS_TAG((sd)->target)), \ + JT_TO_BPDELTA((sd)->target)) + +/* Avoid asserting twice by expanding SD_GET_TARGET in the "then" clause. */ +#define SD_SPAN(sd,pivot) (SD_GET_TARGET(sd) \ + ? JT_CLR_TAG((sd)->target)->offset - (pivot) \ + : 0) + +typedef struct JSTryNode JSTryNode; + +struct JSTryNode { + JSTryNote note; + JSTryNode *prev; +}; + +typedef struct JSEmittedObjectList { + uint32 length; /* number of emitted so far objects */ + JSParsedObjectBox *lastPob; /* last emitted object */ +} JSEmittedObjectList; + +extern void +FinishParsedObjects(JSEmittedObjectList *emittedList, JSObjectArray *objectMap); + +struct JSCodeGenerator { + JSTreeContext treeContext; /* base state: statement info stack, etc. */ + + JSArenaPool *codePool; /* pointer to thread code arena pool */ + JSArenaPool *notePool; /* pointer to thread srcnote arena pool */ + void *codeMark; /* low watermark in cg->codePool */ + void *noteMark; /* low watermark in cg->notePool */ + + struct { + jsbytecode *base; /* base of JS bytecode vector */ + jsbytecode *limit; /* one byte beyond end of bytecode */ + jsbytecode *next; /* pointer to next free bytecode */ + jssrcnote *notes; /* source notes, see below */ + uintN noteCount; /* number of source notes so far */ + uintN noteMask; /* growth increment for notes */ + ptrdiff_t lastNoteOffset; /* code offset for last source note */ + uintN currentLine; /* line number for tree-based srcnote gen */ + } prolog, main, *current; + + JSAtomList atomList; /* literals indexed for mapping */ + uintN firstLine; /* first line, for js_NewScriptFromCG */ + + intN stackDepth; /* current stack depth in script frame */ + uintN maxStackDepth; /* maximum stack depth so far */ + + uintN ntrynotes; /* number of allocated so far try notes */ + JSTryNode *lastTryNode; /* the last allocated try node */ + + JSSpanDep *spanDeps; /* span dependent instruction records */ + JSJumpTarget *jumpTargets; /* AVL tree of jump target offsets */ + JSJumpTarget *jtFreeList; /* JT_LEFT-linked list of free structs */ + uintN numSpanDeps; /* number of span dependencies */ + uintN numJumpTargets; /* number of jump targets */ + ptrdiff_t spanDepTodo; /* offset from main.base of potentially + unoptimized spandeps */ + + uintN arrayCompDepth; /* stack depth of array in comprehension */ + + uintN emitLevel; /* js_EmitTree recursion level */ + JSAtomList constList; /* compile time constants */ + + JSEmittedObjectList objectList; /* list of emitted so far objects */ + JSEmittedObjectList regexpList; /* list of emitted so far regexp + that will be cloned during execution */ + + uintN staticDepth; /* static frame chain depth */ + JSAtomList upvarList; /* map of atoms to upvar indexes */ + JSUpvarArray upvarMap; /* indexed upvar pairs (JS_realloc'ed) */ + JSCodeGenerator *parent; /* enclosing function or global context */ +}; + +#define CG_TS(cg) TS((cg)->treeContext.parseContext) + +#define CG_BASE(cg) ((cg)->current->base) +#define CG_LIMIT(cg) ((cg)->current->limit) +#define CG_NEXT(cg) ((cg)->current->next) +#define CG_CODE(cg,offset) (CG_BASE(cg) + (offset)) +#define CG_OFFSET(cg) PTRDIFF(CG_NEXT(cg), CG_BASE(cg), jsbytecode) + +#define CG_NOTES(cg) ((cg)->current->notes) +#define CG_NOTE_COUNT(cg) ((cg)->current->noteCount) +#define CG_NOTE_MASK(cg) ((cg)->current->noteMask) +#define CG_LAST_NOTE_OFFSET(cg) ((cg)->current->lastNoteOffset) +#define CG_CURRENT_LINE(cg) ((cg)->current->currentLine) + +#define CG_PROLOG_BASE(cg) ((cg)->prolog.base) +#define CG_PROLOG_LIMIT(cg) ((cg)->prolog.limit) +#define CG_PROLOG_NEXT(cg) ((cg)->prolog.next) +#define CG_PROLOG_CODE(cg,poff) (CG_PROLOG_BASE(cg) + (poff)) +#define CG_PROLOG_OFFSET(cg) PTRDIFF(CG_PROLOG_NEXT(cg), CG_PROLOG_BASE(cg),\ + jsbytecode) + +#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main) +#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog) + +/* + * Initialize cg to allocate bytecode space from codePool, source note space + * from notePool, and all other arena-allocated temporaries from cx->tempPool. + */ +extern JS_FRIEND_API(void) +js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc, + JSArenaPool *codePool, JSArenaPool *notePool, + uintN lineno); + +/* + * Release cg->codePool, cg->notePool, and cx->tempPool to marks set by + * js_InitCodeGenerator. Note that cgs are magic: they own the arena pool + * "tops-of-stack" space above their codeMark, noteMark, and tempMark points. + * This means you cannot alloc from tempPool and save the pointer beyond the + * next JS_FinishCodeGenerator. + */ +extern JS_FRIEND_API(void) +js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg); + +/* + * Emit one bytecode. + */ +extern ptrdiff_t +js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op); + +/* + * Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1). + */ +extern ptrdiff_t +js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1); + +/* + * Emit three bytecodes, an opcode with two bytes of immediate operands. + */ +extern ptrdiff_t +js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1, + jsbytecode op2); + +/* + * Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand. + */ +extern ptrdiff_t +js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra); + +/* + * Unsafe macro to call js_SetJumpOffset and return false if it does. + */ +#define CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,cg,pc,off,BAD_EXIT) \ + JS_BEGIN_MACRO \ + if (!js_SetJumpOffset(cx, cg, pc, off)) { \ + BAD_EXIT; \ + } \ + JS_END_MACRO + +#define CHECK_AND_SET_JUMP_OFFSET(cx,cg,pc,off) \ + CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,cg,pc,off,return JS_FALSE) + +#define CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx,cg,off,BAD_EXIT) \ + CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx, cg, CG_CODE(cg,off), \ + CG_OFFSET(cg) - (off), BAD_EXIT) + +#define CHECK_AND_SET_JUMP_OFFSET_AT(cx,cg,off) \ + CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, off, return JS_FALSE) + +extern JSBool +js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, + ptrdiff_t off); + +/* Test whether we're in a statement of given type. */ +extern JSBool +js_InStatement(JSTreeContext *tc, JSStmtType type); + +/* Test whether we're in a with statement. */ +#define js_InWithStatement(tc) js_InStatement(tc, STMT_WITH) + +/* + * Push the C-stack-allocated struct at stmt onto the stmtInfo stack. + */ +extern void +js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, + ptrdiff_t top); + +/* + * Push a block scope statement and link blockObj into tc->blockChain. To pop + * this statement info record, use js_PopStatement as usual, or if appropriate + * (if generating code), js_PopStatementCG. + */ +extern void +js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj, + ptrdiff_t top); + +/* + * Pop tc->topStmt. If the top JSStmtInfo struct is not stack-allocated, it + * is up to the caller to free it. + */ +extern void +js_PopStatement(JSTreeContext *tc); + +/* + * Like js_PopStatement(&cg->treeContext), also patch breaks and continues + * unless the top statement info record represents a try-catch-finally suite. + * May fail if a jump offset overflows. + */ +extern JSBool +js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg); + +/* + * Define and lookup a primitive jsval associated with the const named by atom. + * js_DefineCompileTimeConstant analyzes the constant-folded initializer at pn + * and saves the const's value in cg->constList, if it can be used at compile + * time. It returns true unless an error occurred. + * + * If the initializer's value could not be saved, js_DefineCompileTimeConstant + * calls will return the undefined value. js_DefineCompileTimeConstant tries + * to find a const value memorized for atom, returning true with *vp set to a + * value other than undefined if the constant was found, true with *vp set to + * JSVAL_VOID if not found, and false on error. + */ +extern JSBool +js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, + JSParseNode *pn); + +/* + * Find a lexically scoped variable (one declared by let, catch, or an array + * comprehension) named by atom, looking in tc's compile-time scopes. + * + * If a WITH statement is reached along the scope stack, return its statement + * info record, so callers can tell that atom is ambiguous. If slotp is not + * null, then if atom is found, set *slotp to its stack slot, otherwise to -1. + * This means that if slotp is not null, all the block objects on the lexical + * scope chain must have had their depth slots computed by the code generator, + * so the caller must be under js_EmitTree. + * + * In any event, directly return the statement info record in which atom was + * found. Otherwise return null. + */ +extern JSStmtInfo * +js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp); + +/* + * Emit code into cg for the tree rooted at pn. + */ +extern JSBool +js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn); + +/* + * Emit function code using cg for the tree rooted at body. + */ +extern JSBool +js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body); + +/* + * Source notes generated along with bytecode for decompiling and debugging. + * A source note is a uint8 with 5 bits of type and 3 of offset from the pc of + * the previous note. If 3 bits of offset aren't enough, extended delta notes + * (SRC_XDELTA) consisting of 2 set high order bits followed by 6 offset bits + * are emitted before the next note. Some notes have operand offsets encoded + * immediately after them, in note bytes or byte-triples. + * + * Source Note Extended Delta + * +7-6-5-4-3+2-1-0+ +7-6-5+4-3-2-1-0+ + * |note-type|delta| |1 1| ext-delta | + * +---------+-----+ +---+-----------+ + * + * At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE, + * SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode. + * + * NB: the js_SrcNoteSpec array in jsemit.c is indexed by this enum, so its + * initializers need to match the order here. + * + * Note on adding new source notes: every pair of bytecodes (A, B) where A and + * B have disjoint sets of source notes that could apply to each bytecode may + * reuse the same note type value for two notes (snA, snB) that have the same + * arity, offsetBias, and isSpanDep initializers in js_SrcNoteSpec. This is + * why SRC_IF and SRC_INITPROP have the same value below. For bad historical + * reasons, some bytecodes below that could be overlayed have not been, but + * before using SRC_EXTENDED, consider compressing the existing note types. + * + * Don't forget to update JSXDR_BYTECODE_VERSION in jsxdrapi.h for all such + * incompatible source note or other bytecode changes. + */ +typedef enum JSSrcNoteType { + SRC_NULL = 0, /* terminates a note vector */ + SRC_IF = 1, /* JSOP_IFEQ bytecode is from an if-then */ + SRC_BREAK = 1, /* JSOP_GOTO is a break */ + SRC_INITPROP = 1, /* disjoint meaning applied to JSOP_INITELEM or + to an index label in a regular (structuring) + or a destructuring object initialiser */ + SRC_GENEXP = 1, /* JSOP_ANONFUNOBJ from generator expression */ + SRC_IF_ELSE = 2, /* JSOP_IFEQ bytecode is from an if-then-else */ + SRC_FOR_IN = 2, /* JSOP_GOTO to for-in loop condition from + before loop (same arity as SRC_IF_ELSE) */ + SRC_FOR = 3, /* JSOP_NOP or JSOP_POP in for(;;) loop head */ + SRC_WHILE = 4, /* JSOP_GOTO to for or while loop condition + from before loop, else JSOP_NOP at top of + do-while loop */ + SRC_CONTINUE = 5, /* JSOP_GOTO is a continue, not a break; + also used on JSOP_ENDINIT if extra comma + at end of array literal: [1,2,,] */ + SRC_DECL = 6, /* type of a declaration (var, const, let*) */ + SRC_DESTRUCT = 6, /* JSOP_DUP starting a destructuring assignment + operation, with SRC_DECL_* offset operand */ + SRC_PCDELTA = 7, /* distance forward from comma-operator to + next POP, or from CONDSWITCH to first CASE + opcode, etc. -- always a forward delta */ + SRC_GROUPASSIGN = 7, /* SRC_DESTRUCT variant for [a, b] = [c, d] */ + SRC_ASSIGNOP = 8, /* += or another assign-op follows */ + SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */ + SRC_BRACE = 10, /* mandatory brace, for scope or to avoid + dangling else */ + SRC_HIDDEN = 11, /* opcode shouldn't be decompiled */ + SRC_PCBASE = 12, /* distance back from annotated getprop or + setprop op to left-most obj.prop.subprop + bytecode -- always a backward delta */ + SRC_LABEL = 13, /* JSOP_NOP for label: with atomid immediate */ + SRC_LABELBRACE = 14, /* JSOP_NOP for label: {...} begin brace */ + SRC_ENDBRACE = 15, /* JSOP_NOP for label: {...} end brace */ + SRC_BREAK2LABEL = 16, /* JSOP_GOTO for 'break label' with atomid */ + SRC_CONT2LABEL = 17, /* JSOP_GOTO for 'continue label' with atomid */ + SRC_SWITCH = 18, /* JSOP_*SWITCH with offset to end of switch, + 2nd off to first JSOP_CASE if condswitch */ + SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */ + SRC_CATCH = 20, /* catch block has guard */ + SRC_EXTENDED = 21, /* extended source note, 32-159, in next byte */ + SRC_NEWLINE = 22, /* bytecode follows a source newline */ + SRC_SETLINE = 23, /* a file-absolute source line number note */ + SRC_XDELTA = 24 /* 24-31 are for extended delta notes */ +} JSSrcNoteType; + +/* + * Constants for the SRC_DECL source note. Note that span-dependent bytecode + * selection means that any SRC_DECL offset greater than SRC_DECL_LET may need + * to be adjusted, but these "offsets" are too small to span a span-dependent + * instruction, so can be used to denote distinct declaration syntaxes to the + * decompiler. + * + * NB: the var_prefix array in jsopcode.c depends on these dense indexes from + * SRC_DECL_VAR through SRC_DECL_LET. + */ +#define SRC_DECL_VAR 0 +#define SRC_DECL_CONST 1 +#define SRC_DECL_LET 2 +#define SRC_DECL_NONE 3 + +#define SN_TYPE_BITS 5 +#define SN_DELTA_BITS 3 +#define SN_XDELTA_BITS 6 +#define SN_TYPE_MASK (JS_BITMASK(SN_TYPE_BITS) << SN_DELTA_BITS) +#define SN_DELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_DELTA_BITS)) +#define SN_XDELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_XDELTA_BITS)) + +#define SN_MAKE_NOTE(sn,t,d) (*(sn) = (jssrcnote) \ + (((t) << SN_DELTA_BITS) \ + | ((d) & SN_DELTA_MASK))) +#define SN_MAKE_XDELTA(sn,d) (*(sn) = (jssrcnote) \ + ((SRC_XDELTA << SN_DELTA_BITS) \ + | ((d) & SN_XDELTA_MASK))) + +#define SN_IS_XDELTA(sn) ((*(sn) >> SN_DELTA_BITS) >= SRC_XDELTA) +#define SN_TYPE(sn) ((JSSrcNoteType)(SN_IS_XDELTA(sn) \ + ? SRC_XDELTA \ + : *(sn) >> SN_DELTA_BITS)) +#define SN_SET_TYPE(sn,type) SN_MAKE_NOTE(sn, type, SN_DELTA(sn)) +#define SN_IS_GETTABLE(sn) (SN_TYPE(sn) < SRC_NEWLINE) + +#define SN_DELTA(sn) ((ptrdiff_t)(SN_IS_XDELTA(sn) \ + ? *(sn) & SN_XDELTA_MASK \ + : *(sn) & SN_DELTA_MASK)) +#define SN_SET_DELTA(sn,delta) (SN_IS_XDELTA(sn) \ + ? SN_MAKE_XDELTA(sn, delta) \ + : SN_MAKE_NOTE(sn, SN_TYPE(sn), delta)) + +#define SN_DELTA_LIMIT ((ptrdiff_t)JS_BIT(SN_DELTA_BITS)) +#define SN_XDELTA_LIMIT ((ptrdiff_t)JS_BIT(SN_XDELTA_BITS)) + +/* + * Offset fields follow certain notes and are frequency-encoded: an offset in + * [0,0x7f] consumes one byte, an offset in [0x80,0x7fffff] takes three, and + * the high bit of the first byte is set. + */ +#define SN_3BYTE_OFFSET_FLAG 0x80 +#define SN_3BYTE_OFFSET_MASK 0x7f + +typedef struct JSSrcNoteSpec { + const char *name; /* name for disassembly/debugging output */ + int8 arity; /* number of offset operands */ + uint8 offsetBias; /* bias of offset(s) from annotated pc */ + int8 isSpanDep; /* 1 or -1 if offsets could span extended ops, + 0 otherwise; sign tells span direction */ +} JSSrcNoteSpec; + +extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[]; +extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn); + +#define SN_LENGTH(sn) ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \ + : js_SrcNoteLength(sn)) +#define SN_NEXT(sn) ((sn) + SN_LENGTH(sn)) + +/* A source note array is terminated by an all-zero element. */ +#define SN_MAKE_TERMINATOR(sn) (*(sn) = SRC_NULL) +#define SN_IS_TERMINATOR(sn) (*(sn) == SRC_NULL) + +/* + * Append a new source note of the given type (and therefore size) to cg's + * notes dynamic array, updating cg->noteCount. Return the new note's index + * within the array pointed at by cg->current->notes. Return -1 if out of + * memory. + */ +extern intN +js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type); + +extern intN +js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, + ptrdiff_t offset); + +extern intN +js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, + ptrdiff_t offset1, ptrdiff_t offset2); + +/* + * NB: this function can add at most one extra extended delta note. + */ +extern jssrcnote * +js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn, + ptrdiff_t delta); + +/* + * Get and set the offset operand identified by which (0 for the first, etc.). + */ +extern JS_FRIEND_API(ptrdiff_t) +js_GetSrcNoteOffset(jssrcnote *sn, uintN which); + +extern JSBool +js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, + uintN which, ptrdiff_t offset); + +/* + * Finish taking source notes in cx's notePool, copying final notes to the new + * stable store allocated by the caller and passed in via notes. Return false + * on malloc failure, which means this function reported an error. + * + * To compute the number of jssrcnotes to allocate and pass in via notes, use + * the CG_COUNT_FINAL_SRCNOTES macro. This macro knows a lot about details of + * js_FinishTakingSrcNotes, SO DON'T CHANGE jsemit.c's js_FinishTakingSrcNotes + * FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES! + */ +#define CG_COUNT_FINAL_SRCNOTES(cg, cnt) \ + JS_BEGIN_MACRO \ + ptrdiff_t diff_ = CG_PROLOG_OFFSET(cg) - (cg)->prolog.lastNoteOffset; \ + cnt = (cg)->prolog.noteCount + (cg)->main.noteCount + 1; \ + if ((cg)->prolog.noteCount && \ + (cg)->prolog.currentLine != (cg)->firstLine) { \ + if (diff_ > SN_DELTA_MASK) \ + cnt += JS_HOWMANY(diff_ - SN_DELTA_MASK, SN_XDELTA_MASK); \ + cnt += 2 + (((cg)->firstLine > SN_3BYTE_OFFSET_MASK) << 1); \ + } else if (diff_ > 0) { \ + if (cg->main.noteCount) { \ + jssrcnote *sn_ = (cg)->main.notes; \ + diff_ -= SN_IS_XDELTA(sn_) \ + ? SN_XDELTA_MASK - (*sn_ & SN_XDELTA_MASK) \ + : SN_DELTA_MASK - (*sn_ & SN_DELTA_MASK); \ + } \ + if (diff_ > 0) \ + cnt += JS_HOWMANY(diff_, SN_XDELTA_MASK); \ + } \ + JS_END_MACRO + +extern JSBool +js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes); + +extern void +js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array); + +JS_END_EXTERN_C + +#endif /* jsemit_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsexn.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsexn.cpp new file mode 100644 index 0000000..c61b724 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsexn.cpp @@ -0,0 +1,1376 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS standard exception implementation. + */ + +#include "jsstddef.h" +#include +#include +#include "jstypes.h" +#include "jsbit.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jsprf.h" +#include "jsapi.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsexn.h" +#include "jsfun.h" +#include "jsinterp.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstaticcheck.h" + +/* Forward declarations for js_ErrorClass's initializer. */ +static JSBool +Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +static void +exn_finalize(JSContext *cx, JSObject *obj); + +static void +exn_trace(JSTracer *trc, JSObject *obj); + +static void +exn_finalize(JSContext *cx, JSObject *obj); + +static JSBool +exn_enumerate(JSContext *cx, JSObject *obj); + +static JSBool +exn_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp); + +JSClass js_ErrorClass = { + js_Error_str, + JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_MARK_IS_TRACE | + JSCLASS_HAS_CACHED_PROTO(JSProto_Error), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + exn_enumerate, (JSResolveOp)exn_resolve, JS_ConvertStub, exn_finalize, + NULL, NULL, NULL, Exception, + NULL, NULL, JS_CLASS_TRACE(exn_trace), NULL +}; + +typedef struct JSStackTraceElem { + JSString *funName; + size_t argc; + const char *filename; + uintN ulineno; +} JSStackTraceElem; + +typedef struct JSExnPrivate { + /* A copy of the JSErrorReport originally generated. */ + JSErrorReport *errorReport; + JSString *message; + JSString *filename; + uintN lineno; + size_t stackDepth; + JSStackTraceElem stackElems[1]; +} JSExnPrivate; + +static JSString * +StackTraceToString(JSContext *cx, JSExnPrivate *priv); + +static JSErrorReport * +CopyErrorReport(JSContext *cx, JSErrorReport *report) +{ + /* + * We use a single malloc block to make a deep copy of JSErrorReport with + * the following layout: + * JSErrorReport + * array of copies of report->messageArgs + * jschar array with characters for all messageArgs + * jschar array with characters for ucmessage + * jschar array with characters for uclinebuf and uctokenptr + * char array with characters for linebuf and tokenptr + * char array with characters for filename + * Such layout together with the properties enforced by the following + * asserts does not need any extra alignment padding. + */ + JS_STATIC_ASSERT(sizeof(JSErrorReport) % sizeof(const char *) == 0); + JS_STATIC_ASSERT(sizeof(const char *) % sizeof(jschar) == 0); + + size_t filenameSize; + size_t linebufSize; + size_t uclinebufSize; + size_t ucmessageSize; + size_t i, argsArraySize, argsCopySize, argSize; + size_t mallocSize; + JSErrorReport *copy; + uint8 *cursor; + +#define JS_CHARS_SIZE(jschars) ((js_strlen(jschars) + 1) * sizeof(jschar)) + + filenameSize = report->filename ? strlen(report->filename) + 1 : 0; + linebufSize = report->linebuf ? strlen(report->linebuf) + 1 : 0; + uclinebufSize = report->uclinebuf ? JS_CHARS_SIZE(report->uclinebuf) : 0; + ucmessageSize = 0; + argsArraySize = 0; + argsCopySize = 0; + if (report->ucmessage) { + ucmessageSize = JS_CHARS_SIZE(report->ucmessage); + if (report->messageArgs) { + for (i = 0; report->messageArgs[i]; ++i) + argsCopySize += JS_CHARS_SIZE(report->messageArgs[i]); + + /* Non-null messageArgs should have at least one non-null arg. */ + JS_ASSERT(i != 0); + argsArraySize = (i + 1) * sizeof(const jschar *); + } + } + + /* + * The mallocSize can not overflow since it represents the sum of the + * sizes of already allocated objects. + */ + mallocSize = sizeof(JSErrorReport) + argsArraySize + argsCopySize + + ucmessageSize + uclinebufSize + linebufSize + filenameSize; + cursor = (uint8 *)JS_malloc(cx, mallocSize); + if (!cursor) + return NULL; + + copy = (JSErrorReport *)cursor; + memset(cursor, 0, sizeof(JSErrorReport)); + cursor += sizeof(JSErrorReport); + + if (argsArraySize != 0) { + copy->messageArgs = (const jschar **)cursor; + cursor += argsArraySize; + for (i = 0; report->messageArgs[i]; ++i) { + copy->messageArgs[i] = (const jschar *)cursor; + argSize = JS_CHARS_SIZE(report->messageArgs[i]); + memcpy(cursor, report->messageArgs[i], argSize); + cursor += argSize; + } + copy->messageArgs[i] = NULL; + JS_ASSERT(cursor == (uint8 *)copy->messageArgs[0] + argsCopySize); + } + + if (report->ucmessage) { + copy->ucmessage = (const jschar *)cursor; + memcpy(cursor, report->ucmessage, ucmessageSize); + cursor += ucmessageSize; + } + + if (report->uclinebuf) { + copy->uclinebuf = (const jschar *)cursor; + memcpy(cursor, report->uclinebuf, uclinebufSize); + cursor += uclinebufSize; + if (report->uctokenptr) { + copy->uctokenptr = copy->uclinebuf + (report->uctokenptr - + report->uclinebuf); + } + } + + if (report->linebuf) { + copy->linebuf = (const char *)cursor; + memcpy(cursor, report->linebuf, linebufSize); + cursor += linebufSize; + if (report->tokenptr) { + copy->tokenptr = copy->linebuf + (report->tokenptr - + report->linebuf); + } + } + + if (report->filename) { + copy->filename = (const char *)cursor; + memcpy(cursor, report->filename, filenameSize); + } + JS_ASSERT(cursor + filenameSize == (uint8 *)copy + mallocSize); + + /* Copy non-pointer members. */ + copy->lineno = report->lineno; + copy->errorNumber = report->errorNumber; + + /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */ + copy->flags = report->flags; + +#undef JS_CHARS_SIZE + return copy; +} + +static jsval * +GetStackTraceValueBuffer(JSExnPrivate *priv) +{ + /* + * We use extra memory after JSExnPrivateInfo.stackElems to store jsvals + * that helps to produce more informative stack traces. The following + * assert allows us to assume that no gap after stackElems is necessary to + * align the buffer properly. + */ + JS_STATIC_ASSERT(sizeof(JSStackTraceElem) % sizeof(jsval) == 0); + + return (jsval *)(priv->stackElems + priv->stackDepth); +} + +static JSBool +InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, + JSString *filename, uintN lineno, JSErrorReport *report) +{ + JSSecurityCallbacks *callbacks; + JSCheckAccessOp checkAccess; + JSErrorReporter older; + JSExceptionState *state; + jsval callerid, v; + JSStackFrame *fp, *fpstop; + size_t stackDepth, valueCount, size; + JSBool overflow; + JSExnPrivate *priv; + JSStackTraceElem *elem; + jsval *values; + + JS_ASSERT(OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass); + + /* + * Prepare stack trace data. + * + * Set aside any error reporter for cx and save its exception state + * so we can suppress any checkAccess failures. Such failures should stop + * the backtrace procedure, not result in a failure of this constructor. + */ + callbacks = JS_GetSecurityCallbacks(cx); + checkAccess = callbacks + ? callbacks->checkObjectAccess + : NULL; + older = JS_SetErrorReporter(cx, NULL); + state = JS_SaveExceptionState(cx); + + callerid = ATOM_KEY(cx->runtime->atomState.callerAtom); + stackDepth = 0; + valueCount = 0; + for (fp = cx->fp; fp; fp = fp->down) { + if (fp->fun && fp->argv) { + v = JSVAL_NULL; + if (checkAccess && + !checkAccess(cx, fp->callee, callerid, JSACC_READ, &v)) { + break; + } + valueCount += fp->argc; + } + ++stackDepth; + } + JS_RestoreExceptionState(cx, state); + JS_SetErrorReporter(cx, older); + fpstop = fp; + + size = offsetof(JSExnPrivate, stackElems); + overflow = (stackDepth > ((size_t)-1 - size) / sizeof(JSStackTraceElem)); + size += stackDepth * sizeof(JSStackTraceElem); + overflow |= (valueCount > ((size_t)-1 - size) / sizeof(jsval)); + size += valueCount * sizeof(jsval); + if (overflow) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + priv = (JSExnPrivate *)JS_malloc(cx, size); + if (!priv) + return JS_FALSE; + + /* + * We initialize errorReport with a copy of report after setting the + * private slot, to prevent GC accessing a junk value we clear the field + * here. + */ + priv->errorReport = NULL; + priv->message = message; + priv->filename = filename; + priv->lineno = lineno; + priv->stackDepth = stackDepth; + + values = GetStackTraceValueBuffer(priv); + elem = priv->stackElems; + for (fp = cx->fp; fp != fpstop; fp = fp->down) { + if (!fp->fun) { + elem->funName = NULL; + elem->argc = 0; + } else { + elem->funName = fp->fun->atom + ? ATOM_TO_STRING(fp->fun->atom) + : cx->runtime->emptyString; + elem->argc = fp->argc; + memcpy(values, fp->argv, fp->argc * sizeof(jsval)); + values += fp->argc; + } + elem->ulineno = 0; + elem->filename = NULL; + if (fp->script) { + elem->filename = fp->script->filename; + if (fp->regs) + elem->ulineno = js_FramePCToLineNumber(cx, fp); + } + ++elem; + } + JS_ASSERT(priv->stackElems + stackDepth == elem); + JS_ASSERT(GetStackTraceValueBuffer(priv) + valueCount == values); + + STOBJ_SET_SLOT(exnObject, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(priv)); + + if (report) { + /* + * Construct a new copy of the error report struct. We can't use the + * error report struct that was passed in, because it's allocated on + * the stack, and also because it may point to transient data in the + * JSTokenStream. + */ + priv->errorReport = CopyErrorReport(cx, report); + if (!priv->errorReport) { + /* The finalizer realeases priv since it is in the private slot. */ + return JS_FALSE; + } + } + + return JS_TRUE; +} + +static JSExnPrivate * +GetExnPrivate(JSContext *cx, JSObject *obj) +{ + jsval privateValue; + JSExnPrivate *priv; + + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ErrorClass); + privateValue = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); + if (JSVAL_IS_VOID(privateValue)) + return NULL; + priv = (JSExnPrivate *)JSVAL_TO_PRIVATE(privateValue); + JS_ASSERT(priv); + return priv; +} + +static void +exn_trace(JSTracer *trc, JSObject *obj) +{ + JSExnPrivate *priv; + JSStackTraceElem *elem; + size_t vcount, i; + jsval *vp, v; + + priv = GetExnPrivate(trc->context, obj); + if (priv) { + if (priv->message) + JS_CALL_STRING_TRACER(trc, priv->message, "exception message"); + if (priv->filename) + JS_CALL_STRING_TRACER(trc, priv->filename, "exception filename"); + + elem = priv->stackElems; + for (vcount = i = 0; i != priv->stackDepth; ++i, ++elem) { + if (elem->funName) { + JS_CALL_STRING_TRACER(trc, elem->funName, + "stack trace function name"); + } + if (IS_GC_MARKING_TRACER(trc) && elem->filename) + js_MarkScriptFilename(elem->filename); + vcount += elem->argc; + } + vp = GetStackTraceValueBuffer(priv); + for (i = 0; i != vcount; ++i, ++vp) { + v = *vp; + JS_CALL_VALUE_TRACER(trc, v, "stack trace argument"); + } + } +} + +static void +exn_finalize(JSContext *cx, JSObject *obj) +{ + JSExnPrivate *priv; + + priv = GetExnPrivate(cx, obj); + if (priv) { + if (priv->errorReport) + JS_free(cx, priv->errorReport); + JS_free(cx, priv); + } +} + +static JSBool +exn_enumerate(JSContext *cx, JSObject *obj) +{ + JSAtomState *atomState; + uintN i; + JSAtom *atom; + JSObject *pobj; + JSProperty *prop; + + JS_STATIC_ASSERT(sizeof(JSAtomState) <= (size_t)(uint16)-1); + static const uint16 offsets[] = { + (uint16)offsetof(JSAtomState, messageAtom), + (uint16)offsetof(JSAtomState, fileNameAtom), + (uint16)offsetof(JSAtomState, lineNumberAtom), + (uint16)offsetof(JSAtomState, stackAtom), + }; + + atomState = &cx->runtime->atomState; + for (i = 0; i != JS_ARRAY_LENGTH(offsets); ++i) { + atom = *(JSAtom **)((uint8 *)atomState + offsets[i]); + if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop)) + return JS_FALSE; + if (prop) + OBJ_DROP_PROPERTY(cx, pobj, prop); + } + return JS_TRUE; +} + +static JSBool +exn_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp) +{ + JSExnPrivate *priv; + JSString *str; + JSAtom *atom; + JSString *stack; + const char *prop; + jsval v; + + *objp = NULL; + priv = GetExnPrivate(cx, obj); + if (priv && JSVAL_IS_STRING(id)) { + str = JSVAL_TO_STRING(id); + + atom = cx->runtime->atomState.messageAtom; + if (str == ATOM_TO_STRING(atom)) { + prop = js_message_str; + v = STRING_TO_JSVAL(priv->message); + goto define; + } + + atom = cx->runtime->atomState.fileNameAtom; + if (str == ATOM_TO_STRING(atom)) { + prop = js_fileName_str; + v = STRING_TO_JSVAL(priv->filename); + goto define; + } + + atom = cx->runtime->atomState.lineNumberAtom; + if (str == ATOM_TO_STRING(atom)) { + prop = js_lineNumber_str; + v = INT_TO_JSVAL(priv->lineno); + goto define; + } + + atom = cx->runtime->atomState.stackAtom; + if (str == ATOM_TO_STRING(atom)) { + stack = StackTraceToString(cx, priv); + if (!stack) + return JS_FALSE; + + /* Allow to GC all things that were used to build stack trace. */ + priv->stackDepth = 0; + prop = js_stack_str; + v = STRING_TO_JSVAL(stack); + goto define; + } + } + return JS_TRUE; + + define: + if (!JS_DefineProperty(cx, obj, prop, v, NULL, NULL, JSPROP_ENUMERATE)) + return JS_FALSE; + *objp = obj; + return JS_TRUE; +} + +JSErrorReport * +js_ErrorFromException(JSContext *cx, jsval exn) +{ + JSObject *obj; + JSExnPrivate *priv; + + if (JSVAL_IS_PRIMITIVE(exn)) + return NULL; + obj = JSVAL_TO_OBJECT(exn); + if (OBJ_GET_CLASS(cx, obj) != &js_ErrorClass) + return NULL; + priv = GetExnPrivate(cx, obj); + if (!priv) + return NULL; + return priv->errorReport; +} + +struct JSExnSpec { + int protoIndex; + const char *name; + JSProtoKey key; + JSNative native; +}; + +/* + * All *Error constructors share the same JSClass, js_ErrorClass. But each + * constructor function for an *Error class must have a distinct native 'call' + * function pointer, in order for instanceof to work properly across multiple + * standard class sets. See jsfun.c:fun_hasInstance. + */ +#define MAKE_EXCEPTION_CTOR(name) \ +static JSBool \ +name(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) \ +{ \ + return Exception(cx, obj, argc, argv, rval); \ +} + +MAKE_EXCEPTION_CTOR(Error) +MAKE_EXCEPTION_CTOR(InternalError) +MAKE_EXCEPTION_CTOR(EvalError) +MAKE_EXCEPTION_CTOR(RangeError) +MAKE_EXCEPTION_CTOR(ReferenceError) +MAKE_EXCEPTION_CTOR(SyntaxError) +MAKE_EXCEPTION_CTOR(TypeError) +MAKE_EXCEPTION_CTOR(URIError) + +#undef MAKE_EXCEPTION_CTOR + +static struct JSExnSpec exceptions[] = { + {JSEXN_NONE, js_Error_str, JSProto_Error, Error}, + {JSEXN_ERR, js_InternalError_str, JSProto_InternalError, InternalError}, + {JSEXN_ERR, js_EvalError_str, JSProto_EvalError, EvalError}, + {JSEXN_ERR, js_RangeError_str, JSProto_RangeError, RangeError}, + {JSEXN_ERR, js_ReferenceError_str, JSProto_ReferenceError, ReferenceError}, + {JSEXN_ERR, js_SyntaxError_str, JSProto_SyntaxError, SyntaxError}, + {JSEXN_ERR, js_TypeError_str, JSProto_TypeError, TypeError}, + {JSEXN_ERR, js_URIError_str, JSProto_URIError, URIError}, + {0, NULL, JSProto_Null, NULL} +}; + +static JSString * +ValueToShortSource(JSContext *cx, jsval v) +{ + JSString *str; + + /* Avoid toSource bloat and fallibility for object types. */ + if (JSVAL_IS_PRIMITIVE(v)) { + str = js_ValueToSource(cx, v); + } else if (VALUE_IS_FUNCTION(cx, v)) { + /* + * XXX Avoid function decompilation bloat for now. + */ + str = JS_GetFunctionId(JS_ValueToFunction(cx, v)); + if (!str && !(str = js_ValueToSource(cx, v))) { + /* + * Continue to soldier on if the function couldn't be + * converted into a string. + */ + JS_ClearPendingException(cx); + str = JS_NewStringCopyZ(cx, "[unknown function]"); + } + } else { + /* + * XXX Avoid toString on objects, it takes too long and uses too much + * memory, for too many classes (see Mozilla bug 166743). + */ + char buf[100]; + JS_snprintf(buf, sizeof buf, "[object %s]", + OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v))->name); + str = JS_NewStringCopyZ(cx, buf); + } + return str; +} + +static JSString * +StackTraceToString(JSContext *cx, JSExnPrivate *priv) +{ + jschar *stackbuf; + size_t stacklen, stackmax; + JSStackTraceElem *elem, *endElem; + jsval *values; + size_t i; + JSString *str; + const char *cp; + char ulnbuf[11]; + + /* After this point, failing control flow must goto bad. */ + stackbuf = NULL; + stacklen = stackmax = 0; + +/* Limit the stackbuf length to a reasonable value to avoid overflow checks. */ +#define STACK_LENGTH_LIMIT JS_BIT(20) + +#define APPEND_CHAR_TO_STACK(c) \ + JS_BEGIN_MACRO \ + if (stacklen == stackmax) { \ + void *ptr_; \ + if (stackmax >= STACK_LENGTH_LIMIT) \ + goto done; \ + stackmax = stackmax ? 2 * stackmax : 64; \ + ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \ + if (!ptr_) \ + goto bad; \ + stackbuf = (jschar *) ptr_; \ + } \ + stackbuf[stacklen++] = (c); \ + JS_END_MACRO + +#define APPEND_STRING_TO_STACK(str) \ + JS_BEGIN_MACRO \ + JSString *str_ = str; \ + jschar *chars_; \ + size_t length_; \ + \ + JSSTRING_CHARS_AND_LENGTH(str_, chars_, length_); \ + if (length_ > stackmax - stacklen) { \ + void *ptr_; \ + if (stackmax >= STACK_LENGTH_LIMIT || \ + length_ >= STACK_LENGTH_LIMIT - stacklen) { \ + goto done; \ + } \ + stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_)); \ + ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \ + if (!ptr_) \ + goto bad; \ + stackbuf = (jschar *) ptr_; \ + } \ + js_strncpy(stackbuf + stacklen, chars_, length_); \ + stacklen += length_; \ + JS_END_MACRO + + values = GetStackTraceValueBuffer(priv); + elem = priv->stackElems; + for (endElem = elem + priv->stackDepth; elem != endElem; elem++) { + if (elem->funName) { + APPEND_STRING_TO_STACK(elem->funName); + APPEND_CHAR_TO_STACK('('); + for (i = 0; i != elem->argc; i++, values++) { + if (i > 0) + APPEND_CHAR_TO_STACK(','); + str = ValueToShortSource(cx, *values); + if (!str) + goto bad; + APPEND_STRING_TO_STACK(str); + } + APPEND_CHAR_TO_STACK(')'); + } + APPEND_CHAR_TO_STACK('@'); + if (elem->filename) { + for (cp = elem->filename; *cp; cp++) + APPEND_CHAR_TO_STACK(*cp); + } + APPEND_CHAR_TO_STACK(':'); + JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", elem->ulineno); + for (cp = ulnbuf; *cp; cp++) + APPEND_CHAR_TO_STACK(*cp); + APPEND_CHAR_TO_STACK('\n'); + } +#undef APPEND_CHAR_TO_STACK +#undef APPEND_STRING_TO_STACK +#undef STACK_LENGTH_LIMIT + + done: + if (stacklen == 0) { + JS_ASSERT(!stackbuf); + return cx->runtime->emptyString; + } + if (stacklen < stackmax) { + /* + * Realloc can fail when shrinking on some FreeBSD versions, so + * don't use JS_realloc here; simply let the oversized allocation + * be owned by the string in that rare case. + */ + void *shrunk = JS_realloc(cx, stackbuf, (stacklen+1) * sizeof(jschar)); + if (shrunk) + stackbuf = (jschar *) shrunk; + } + + stackbuf[stacklen] = 0; + str = js_NewString(cx, stackbuf, stacklen); + if (str) + return str; + + bad: + if (stackbuf) + JS_free(cx, stackbuf); + return NULL; +} + +/* XXXbe Consolidate the ugly truth that we don't treat filename as UTF-8 + with these two functions. */ +static JSString * +FilenameToString(JSContext *cx, const char *filename) +{ + return JS_NewStringCopyZ(cx, filename); +} + +static const char * +StringToFilename(JSContext *cx, JSString *str) +{ + return js_GetStringBytes(cx, str); +} + +static JSBool +Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + uint32 lineno; + JSString *message, *filename; + JSStackFrame *fp; + + if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { + /* + * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when + * called as functions, without operator new. But as we do not give + * each constructor a distinct JSClass, whose .name member is used by + * js_NewObject to find the class prototype, we must get the class + * prototype ourselves. + */ + if (!OBJ_GET_PROPERTY(cx, JSVAL_TO_OBJECT(argv[-2]), + ATOM_TO_JSID(cx->runtime->atomState + .classPrototypeAtom), + rval)) + return JS_FALSE; + obj = js_NewObject(cx, &js_ErrorClass, JSVAL_TO_OBJECT(*rval), NULL, 0); + if (!obj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(obj); + } + + /* + * If it's a new object of class Exception, then null out the private + * data so that the finalizer doesn't attempt to free it. + */ + if (OBJ_GET_CLASS(cx, obj) == &js_ErrorClass) + STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, JSVAL_VOID); + + /* Set the 'message' property. */ + if (argc != 0) { + message = js_ValueToString(cx, argv[0]); + if (!message) + return JS_FALSE; + argv[0] = STRING_TO_JSVAL(message); + } else { + message = cx->runtime->emptyString; + } + + /* Set the 'fileName' property. */ + if (argc > 1) { + filename = js_ValueToString(cx, argv[1]); + if (!filename) + return JS_FALSE; + argv[1] = STRING_TO_JSVAL(filename); + fp = NULL; + } else { + fp = JS_GetScriptedCaller(cx, NULL); + if (fp) { + filename = FilenameToString(cx, fp->script->filename); + if (!filename) + return JS_FALSE; + } else { + filename = cx->runtime->emptyString; + } + } + + /* Set the 'lineNumber' property. */ + if (argc > 2) { + lineno = js_ValueToECMAUint32(cx, &argv[2]); + if (JSVAL_IS_NULL(argv[2])) + return JS_FALSE; + } else { + if (!fp) + fp = JS_GetScriptedCaller(cx, NULL); + lineno = (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0; + } + + return (OBJ_GET_CLASS(cx, obj) != &js_ErrorClass) || + InitExnPrivate(cx, obj, message, filename, lineno, NULL); +} + +/* + * Convert to string. + * + * This method only uses JavaScript-modifiable properties name, message. It + * is left to the host to check for private data and report filename and line + * number information along with this message. + */ +static JSBool +exn_toString(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + jsval v; + JSString *name, *message, *result; + jschar *chars, *cp; + size_t name_length, message_length, length; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || + !OBJ_GET_PROPERTY(cx, obj, + ATOM_TO_JSID(cx->runtime->atomState.nameAtom), + &v)) { + return JS_FALSE; + } + name = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString; + *vp = STRING_TO_JSVAL(name); + + if (!JS_GetProperty(cx, obj, js_message_str, &v)) + return JS_FALSE; + message = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) + : cx->runtime->emptyString; + + if (JSSTRING_LENGTH(message) != 0) { + name_length = JSSTRING_LENGTH(name); + message_length = JSSTRING_LENGTH(message); + length = (name_length ? name_length + 2 : 0) + message_length; + cp = chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar)); + if (!chars) + return JS_FALSE; + + if (name_length) { + js_strncpy(cp, JSSTRING_CHARS(name), name_length); + cp += name_length; + *cp++ = ':'; *cp++ = ' '; + } + js_strncpy(cp, JSSTRING_CHARS(message), message_length); + cp += message_length; + *cp = 0; + + result = js_NewString(cx, chars, length); + if (!result) { + JS_free(cx, chars); + return JS_FALSE; + } + } else { + result = name; + } + + *vp = STRING_TO_JSVAL(result); + return JS_TRUE; +} + +#if JS_HAS_TOSOURCE +/* + * Return a string that may eval to something similar to the original object. + */ +static JSBool +exn_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + JSString *name, *message, *filename, *lineno_as_str, *result; + jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; + JSTempValueRooter tvr; + JSBool ok; + uint32 lineno; + size_t lineno_length, name_length, message_length, filename_length, length; + jschar *chars, *cp; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || + !OBJ_GET_PROPERTY(cx, obj, + ATOM_TO_JSID(cx->runtime->atomState.nameAtom), + vp)) { + return JS_FALSE; + } + name = js_ValueToString(cx, *vp); + if (!name) + return JS_FALSE; + *vp = STRING_TO_JSVAL(name); + + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr); + +#ifdef __GNUC__ + message = filename = NULL; +#endif + ok = JS_GetProperty(cx, obj, js_message_str, &localroots[0]) && + (message = js_ValueToSource(cx, localroots[0])); + if (!ok) + goto out; + localroots[0] = STRING_TO_JSVAL(message); + + ok = JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) && + (filename = js_ValueToSource(cx, localroots[1])); + if (!ok) + goto out; + localroots[1] = STRING_TO_JSVAL(filename); + + ok = JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]); + if (!ok) + goto out; + lineno = js_ValueToECMAUint32 (cx, &localroots[2]); + ok = !JSVAL_IS_NULL(localroots[2]); + if (!ok) + goto out; + + if (lineno != 0) { + lineno_as_str = js_ValueToString(cx, localroots[2]); + if (!lineno_as_str) { + ok = JS_FALSE; + goto out; + } + lineno_length = JSSTRING_LENGTH(lineno_as_str); + } else { + lineno_as_str = NULL; + lineno_length = 0; + } + + /* Magic 8, for the characters in ``(new ())''. */ + name_length = JSSTRING_LENGTH(name); + message_length = JSSTRING_LENGTH(message); + length = 8 + name_length + message_length; + + filename_length = JSSTRING_LENGTH(filename); + if (filename_length != 0) { + /* append filename as ``, {filename}'' */ + length += 2 + filename_length; + if (lineno_as_str) { + /* append lineno as ``, {lineno_as_str}'' */ + length += 2 + lineno_length; + } + } else { + if (lineno_as_str) { + /* + * no filename, but have line number, + * need to append ``, "", {lineno_as_str}'' + */ + length += 6 + lineno_length; + } + } + + cp = chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar)); + if (!chars) { + ok = JS_FALSE; + goto out; + } + + *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; + js_strncpy(cp, JSSTRING_CHARS(name), name_length); + cp += name_length; + *cp++ = '('; + if (message_length != 0) { + js_strncpy(cp, JSSTRING_CHARS(message), message_length); + cp += message_length; + } + + if (filename_length != 0) { + /* append filename as ``, {filename}'' */ + *cp++ = ','; *cp++ = ' '; + js_strncpy(cp, JSSTRING_CHARS(filename), filename_length); + cp += filename_length; + } else { + if (lineno_as_str) { + /* + * no filename, but have line number, + * need to append ``, "", {lineno_as_str}'' + */ + *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"'; + } + } + if (lineno_as_str) { + /* append lineno as ``, {lineno_as_str}'' */ + *cp++ = ','; *cp++ = ' '; + js_strncpy(cp, JSSTRING_CHARS(lineno_as_str), lineno_length); + cp += lineno_length; + } + + *cp++ = ')'; *cp++ = ')'; *cp = 0; + + result = js_NewString(cx, chars, length); + if (!result) { + JS_free(cx, chars); + ok = JS_FALSE; + goto out; + } + *vp = STRING_TO_JSVAL(result); + ok = JS_TRUE; + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} +#endif + +static JSFunctionSpec exception_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, exn_toSource, 0,0), +#endif + JS_FN(js_toString_str, exn_toString, 0,0), + JS_FS_END +}; + +JSObject * +js_InitExceptionClasses(JSContext *cx, JSObject *obj) +{ + JSObject *obj_proto, *protos[JSEXN_LIMIT]; + int i; + + /* + * If lazy class initialization occurs for any Error subclass, then all + * classes are initialized, starting with Error. To avoid reentry and + * redundant initialization, we must not pass a null proto parameter to + * js_NewObject below, when called for the Error superclass. We need to + * ensure that Object.prototype is the proto of Error.prototype. + * + * See the equivalent code to ensure that parent_proto is non-null when + * JS_InitClass calls js_NewObject, in jsapi.c. + */ + if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object), + &obj_proto)) { + return NULL; + } + + if (!js_EnterLocalRootScope(cx)) + return NULL; + + /* Initialize the prototypes first. */ + for (i = 0; exceptions[i].name != 0; i++) { + JSAtom *atom; + JSFunction *fun; + JSString *nameString; + int protoIndex = exceptions[i].protoIndex; + + /* Make the prototype for the current constructor name. */ + protos[i] = js_NewObject(cx, &js_ErrorClass, + (protoIndex != JSEXN_NONE) + ? protos[protoIndex] + : obj_proto, + obj, 0); + if (!protos[i]) + break; + + /* So exn_finalize knows whether to destroy private data. */ + STOBJ_SET_SLOT(protos[i], JSSLOT_PRIVATE, JSVAL_VOID); + + /* Make a constructor function for the current name. */ + atom = cx->runtime->atomState.classAtoms[exceptions[i].key]; + fun = js_DefineFunction(cx, obj, atom, exceptions[i].native, 3, 0); + if (!fun) + break; + + /* Make this constructor make objects of class Exception. */ + FUN_CLASP(fun) = &js_ErrorClass; + + /* Make the prototype and constructor links. */ + if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), protos[i], + JSPROP_READONLY | JSPROP_PERMANENT)) { + break; + } + + /* proto bootstrap bit from JS_InitClass omitted. */ + nameString = JS_NewStringCopyZ(cx, exceptions[i].name); + if (!nameString) + break; + + /* Add the name property to the prototype. */ + if (!JS_DefineProperty(cx, protos[i], js_name_str, + STRING_TO_JSVAL(nameString), + NULL, NULL, + JSPROP_ENUMERATE)) { + break; + } + + /* Finally, stash the constructor for later uses. */ + if (!js_SetClassObject(cx, obj, exceptions[i].key, FUN_OBJECT(fun))) + break; + } + + js_LeaveLocalRootScope(cx); + if (exceptions[i].name) + return NULL; + + /* + * Add an empty message property. (To Exception.prototype only, + * because this property will be the same for all the exception + * protos.) + */ + if (!JS_DefineProperty(cx, protos[0], js_message_str, + STRING_TO_JSVAL(cx->runtime->emptyString), + NULL, NULL, JSPROP_ENUMERATE)) { + return NULL; + } + if (!JS_DefineProperty(cx, protos[0], js_fileName_str, + STRING_TO_JSVAL(cx->runtime->emptyString), + NULL, NULL, JSPROP_ENUMERATE)) { + return NULL; + } + if (!JS_DefineProperty(cx, protos[0], js_lineNumber_str, + INT_TO_JSVAL(0), + NULL, NULL, JSPROP_ENUMERATE)) { + return NULL; + } + + /* + * Add methods only to Exception.prototype, because ostensibly all + * exception types delegate to that. + */ + if (!JS_DefineFunctions(cx, protos[0], exception_methods)) + return NULL; + + return protos[0]; +} + +const JSErrorFormatString* +js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale, + const uintN errorNumber) +{ + const JSErrorFormatString *errorString = NULL; + + if (cx->localeCallbacks && cx->localeCallbacks->localeGetErrorMessage) { + errorString = cx->localeCallbacks + ->localeGetErrorMessage(userRef, locale, errorNumber); + } + if (!errorString) + errorString = js_GetErrorMessage(userRef, locale, errorNumber); + return errorString; +} + +#if defined ( DEBUG_mccabe ) && defined ( PRINTNAMES ) +/* For use below... get character strings for error name and exception name */ +static struct exnname { char *name; char *exception; } errortoexnname[] = { +#define MSG_DEF(name, number, count, exception, format) \ + {#name, #exception}, +#include "js.msg" +#undef MSG_DEF +}; +#endif /* DEBUG */ + +JSBool +js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp) +{ + JSErrNum errorNumber; + const JSErrorFormatString *errorString; + JSExnType exn; + jsval tv[4]; + JSTempValueRooter tvr; + JSBool ok; + JSObject *errProto, *errObject; + JSString *messageStr, *filenameStr; + + /* + * Tell our caller to report immediately if this report is just a warning. + */ + JS_ASSERT(reportp); + if (JSREPORT_IS_WARNING(reportp->flags)) + return JS_FALSE; + + /* Find the exception index associated with this error. */ + errorNumber = (JSErrNum) reportp->errorNumber; + errorString = js_GetLocalizedErrorMessage(cx, NULL, NULL, errorNumber); + exn = errorString ? (JSExnType) errorString->exnType : JSEXN_NONE; + JS_ASSERT(exn < JSEXN_LIMIT); + +#if defined( DEBUG_mccabe ) && defined ( PRINTNAMES ) + /* Print the error name and the associated exception name to stderr */ + fprintf(stderr, "%s\t%s\n", + errortoexnname[errorNumber].name, + errortoexnname[errorNumber].exception); +#endif + + /* + * Return false (no exception raised) if no exception is associated + * with the given error number. + */ + if (exn == JSEXN_NONE) + return JS_FALSE; + + /* + * Prevent runaway recursion, via cx->generatingError. If an out-of-memory + * error occurs, no exception object will be created, but we don't assume + * that OOM is the only kind of error that subroutines of this function + * called below might raise. + */ + if (cx->generatingError) + return JS_FALSE; + + MUST_FLOW_THROUGH("out"); + cx->generatingError = JS_TRUE; + + /* Protect the newly-created strings below from nesting GCs. */ + memset(tv, 0, sizeof tv); + JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr); + + /* + * Try to get an appropriate prototype by looking up the corresponding + * exception constructor name in the scope chain of the current context's + * top stack frame, or in the global object if no frame is active. + */ + ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(exceptions[exn].key), + &errProto); + if (!ok) + goto out; + tv[0] = OBJECT_TO_JSVAL(errProto); + + errObject = js_NewObject(cx, &js_ErrorClass, errProto, NULL, 0); + if (!errObject) { + ok = JS_FALSE; + goto out; + } + tv[1] = OBJECT_TO_JSVAL(errObject); + + messageStr = JS_NewStringCopyZ(cx, message); + if (!messageStr) { + ok = JS_FALSE; + goto out; + } + tv[2] = STRING_TO_JSVAL(messageStr); + + filenameStr = JS_NewStringCopyZ(cx, reportp->filename); + if (!filenameStr) { + ok = JS_FALSE; + goto out; + } + tv[3] = STRING_TO_JSVAL(filenameStr); + + ok = InitExnPrivate(cx, errObject, messageStr, filenameStr, + reportp->lineno, reportp); + if (!ok) + goto out; + + JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject)); + + /* Flag the error report passed in to indicate an exception was raised. */ + reportp->flags |= JSREPORT_EXCEPTION; + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + cx->generatingError = JS_FALSE; + return ok; +} + +JSBool +js_ReportUncaughtException(JSContext *cx) +{ + jsval exn; + JSObject *exnObject; + jsval roots[5]; + JSTempValueRooter tvr; + JSErrorReport *reportp, report; + JSString *str; + const char *bytes; + JSBool ok; + + if (!JS_IsExceptionPending(cx)) + return JS_TRUE; + + if (!JS_GetPendingException(cx, &exn)) + return JS_FALSE; + + memset(roots, 0, sizeof roots); + JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); + + /* + * Because js_ValueToString below could error and an exception object + * could become unrooted, we must root exnObject. Later, if exnObject is + * non-null, we need to root other intermediates, so allocate an operand + * stack segment to protect all of these values. + */ + if (JSVAL_IS_PRIMITIVE(exn)) { + exnObject = NULL; + } else { + exnObject = JSVAL_TO_OBJECT(exn); + roots[0] = exn; + } + + JS_ClearPendingException(cx); + reportp = js_ErrorFromException(cx, exn); + + /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */ + str = js_ValueToString(cx, exn); + if (!str) { + bytes = "unknown (can't convert to string)"; + } else { + roots[1] = STRING_TO_JSVAL(str); + bytes = js_GetStringBytes(cx, str); + if (!bytes) { + ok = JS_FALSE; + goto out; + } + } + ok = JS_TRUE; + + if (!reportp && + exnObject && + OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { + const char *filename; + uint32 lineno; + + ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]); + if (!ok) + goto out; + if (JSVAL_IS_STRING(roots[2])) { + bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2])); + if (!bytes) { + ok = JS_FALSE; + goto out; + } + } + + ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]); + if (!ok) + goto out; + str = js_ValueToString(cx, roots[3]); + if (!str) { + ok = JS_FALSE; + goto out; + } + filename = StringToFilename(cx, str); + if (!filename) { + ok = JS_FALSE; + goto out; + } + + ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]); + if (!ok) + goto out; + lineno = js_ValueToECMAUint32 (cx, &roots[4]); + ok = !JSVAL_IS_NULL(roots[4]); + if (!ok) + goto out; + + reportp = &report; + memset(&report, 0, sizeof report); + report.filename = filename; + report.lineno = (uintN) lineno; + } + + if (!reportp) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_UNCAUGHT_EXCEPTION, bytes); + } else { + /* Flag the error as an exception. */ + reportp->flags |= JSREPORT_EXCEPTION; + + /* Pass the exception object. */ + JS_SetPendingException(cx, exn); + js_ReportErrorAgain(cx, bytes, reportp); + JS_ClearPendingException(cx); + } + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsexn.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsexn.h new file mode 100644 index 0000000..867586d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsexn.h @@ -0,0 +1,96 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS runtime exception classes. + */ + +#ifndef jsexn_h___ +#define jsexn_h___ + +JS_BEGIN_EXTERN_C + +extern JSClass js_ErrorClass; + +/* + * Initialize the exception constructor/prototype hierarchy. + */ +extern JSObject * +js_InitExceptionClasses(JSContext *cx, JSObject *obj); + +/* + * Given a JSErrorReport, check to see if there is an exception associated with + * the error number. If there is, then create an appropriate exception object, + * set it as the pending exception, and set the JSREPORT_EXCEPTION flag on the + * error report. Exception-aware host error reporters should probably ignore + * error reports so flagged. Returns JS_TRUE if an associated exception is + * found and set, JS_FALSE otherwise. + */ +extern JSBool +js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp); + +/* + * Called if a JS API call to js_Execute or js_InternalCall fails; calls the + * error reporter with the error report associated with any uncaught exception + * that has been raised. Returns true if there was an exception pending, and + * the error reporter was actually called. + * + * The JSErrorReport * that the error reporter is called with is currently + * associated with a JavaScript object, and is not guaranteed to persist after + * the object is collected. Any persistent uses of the JSErrorReport contents + * should make their own copy. + * + * The flags field of the JSErrorReport will have the JSREPORT_EXCEPTION flag + * set; embeddings that want to silently propagate JavaScript exceptions to + * other contexts may want to use an error reporter that ignores errors with + * this flag. + */ +extern JSBool +js_ReportUncaughtException(JSContext *cx); + +extern JSErrorReport * +js_ErrorFromException(JSContext *cx, jsval exn); + +extern const JSErrorFormatString * +js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale, + const uintN errorNumber); + +JS_END_EXTERN_C + +#endif /* jsexn_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.cpp new file mode 100644 index 0000000..c5f60ae --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.cpp @@ -0,0 +1,2736 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS File object + */ +#if JS_HAS_FILE_OBJECT + +#include "jsstddef.h" +#include "jsfile.h" + +/* ----------------- Platform-specific includes and defines ----------------- */ +#if defined(XP_WIN) || defined(XP_OS2) +# include +# include +# include +# include +# define FILESEPARATOR '\\' +# define FILESEPARATOR2 '/' +# define CURRENT_DIR "c:\\" +# define POPEN _popen +# define PCLOSE _pclose +#elif defined(XP_UNIX) || defined(XP_BEOS) +# include +# include +# include +# include +# define FILESEPARATOR '/' +# define FILESEPARATOR2 '\0' +# define CURRENT_DIR "/" +# define POPEN popen +# define PCLOSE pclose +#endif + +/* --------------- Platform-independent includes and defines ---------------- */ +#include "jsapi.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsdate.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jslock.h" +#include "jsobj.h" +#include "jsparse.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsutil.h" /* Added by JSIFY */ +#include + +/* NSPR dependencies */ +#include "prio.h" +#include "prerror.h" + +#define SPECIAL_FILE_STRING "Special File" +#define CURRENTDIR_PROPERTY "currentDir" +#define SEPARATOR_PROPERTY "separator" +#define FILE_CONSTRUCTOR "File" +#define PIPE_SYMBOL '|' + +#define ASCII 0 +#define UTF8 1 +#define UCS2 2 + +#define asciistring "text" +#define utfstring "binary" +#define unicodestring "unicode" + +#define MAX_PATH_LENGTH 1024 +#define MODE_SIZE 256 +#define NUMBER_SIZE 32 +#define MAX_LINE_LENGTH 256 +#define URL_PREFIX "file://" + +#define STDINPUT_NAME "Standard input stream" +#define STDOUTPUT_NAME "Standard output stream" +#define STDERROR_NAME "Standard error stream" + +#define RESOLVE_PATH js_canonicalPath /* js_absolutePath */ + +/* Error handling */ +typedef enum JSFileErrNum { +#define MSG_DEF(name, number, count, exception, format) \ + name = number, +#include "jsfile.msg" +#undef MSG_DEF + JSFileErr_Limit +#undef MSGDEF +} JSFileErrNum; + +#define JSFILE_HAS_DFLT_MSG_STRINGS 1 + +JSErrorFormatString JSFile_ErrorFormatString[JSFileErr_Limit] = { +#if JSFILE_HAS_DFLT_MSG_STRINGS +#define MSG_DEF(name, number, count, exception, format) \ + { format, count }, +#else +#define MSG_DEF(name, number, count, exception, format) \ + { NULL, count }, +#endif +#include "jsfile.msg" +#undef MSG_DEF +}; + +const JSErrorFormatString * +JSFile_GetErrorMessage(void *userRef, const char *locale, + const uintN errorNumber) +{ + if ((errorNumber > 0) && (errorNumber < JSFileErr_Limit)) + return &JSFile_ErrorFormatString[errorNumber]; + else + return NULL; +} + +#define JSFILE_CHECK_NATIVE(op) \ + if (file->isNative) { \ + JS_ReportWarning(cx, "Cannot call or access \"%s\" on native file %s",\ + op, file->path); \ + goto out; \ + } + +#define JSFILE_CHECK_WRITE \ + if (!file->isOpen) { \ + JS_ReportWarning(cx, \ + "File %s is closed, will open it for writing, proceeding", \ + file->path); \ + js_FileOpen(cx, obj, file, "write,append,create"); \ + } \ + if (!js_canWrite(cx, file)) { \ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \ + JSFILEMSG_CANNOT_WRITE, file->path); \ + goto out; \ + } + +#define JSFILE_CHECK_READ \ + if (!file->isOpen) { \ + JS_ReportWarning(cx, \ + "File %s is closed, will open it for reading, proceeding", \ + file->path); \ + js_FileOpen(cx, obj, file, "read"); \ + } \ + if (!js_canRead(cx, file)) { \ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \ + JSFILEMSG_CANNOT_READ, file->path); \ + goto out; \ + } + +#define JSFILE_CHECK_OPEN(op) \ + if (!file->isOpen) { \ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \ + JSFILEMSG_FILE_MUST_BE_OPEN, op); \ + goto out; \ + } + +#define JSFILE_CHECK_CLOSED(op) \ + if (file->isOpen) { \ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \ + JSFILEMSG_FILE_MUST_BE_CLOSED, op); \ + goto out; \ + } + +#define JSFILE_CHECK_ONE_ARG(op) \ + if (argc != 1) { \ + char str[NUMBER_SIZE]; \ + sprintf(str, "%d", argc); \ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \ + JSFILEMSG_EXPECTS_ONE_ARG_ERROR, op, str); \ + goto out; \ + } + + +/* + Security mechanism, should define a callback for this. + The parameters are as follows: + SECURITY_CHECK(JSContext *cx, JSPrincipals *ps, char *op_name, JSFile *file) + XXX Should this be a real function returning a JSBool result (and getting + some typesafety help from the compiler?). +*/ +#define SECURITY_CHECK(cx, ps, op, file) \ + /* Define a callback here... */ + + +/* Structure representing the file internally */ +typedef struct JSFile { + char *path; /* the path to the file. */ + JSBool isOpen; + int32 mode; /* mode used to open the file: read, write, append, create, etc.. */ + int32 type; /* Asciiz, utf, unicode */ + char byteBuffer[3]; /* bytes read in advance by js_FileRead ( UTF8 encoding ) */ + jsint nbBytesInBuf; /* number of bytes stored in the buffer above */ + jschar charBuffer; /* character read in advance by readln ( mac files only ) */ + JSBool charBufferUsed; /* flag indicating if the buffer above is being used */ + JSBool hasRandomAccess;/* can the file be randomly accessed? false for stdin, and + UTF-encoded files. */ + JSBool hasAutoflush; /* should we force a flush for each line break? */ + JSBool isNative; /* if the file is using OS-specific file FILE type */ + /* We can actually put the following two in a union since they should never be used at the same time */ + PRFileDesc *handle; /* the handle for the file, if open. */ + FILE *nativehandle; /* native handle, for stuff NSPR doesn't do. */ + JSBool isPipe; /* if the file is really an OS pipe */ +} JSFile; + +/* a few forward declarations... */ +JS_PUBLIC_API(JSObject*) js_NewFileObject(JSContext *cx, char *filename); +static JSBool file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +static JSBool file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +/* New filename manipulation procesures */ +/* assumes we don't have leading/trailing spaces */ +static JSBool +js_filenameHasAPipe(const char *filename) +{ + if (!filename) + return JS_FALSE; + + return filename[0] == PIPE_SYMBOL || + filename[strlen(filename) - 1] == PIPE_SYMBOL; +} + +static JSBool +js_isAbsolute(const char *name) +{ +#if defined(XP_WIN) || defined(XP_OS2) + return *name && name[1] == ':'; +#else + return (name[0] +# if defined(XP_UNIX) || defined(XP_BEOS) + == +# else + != +# endif + FILESEPARATOR); +#endif +} + +/* + * Concatenates base and name to produce a valid filename. + * Returned string must be freed. +*/ +static char* +js_combinePath(JSContext *cx, const char *base, const char *name) +{ + int len = strlen(base); + char* result = JS_malloc(cx, len + strlen(name) + 2); + + if (!result) + return NULL; + + strcpy(result, base); + + if (base[len - 1] != FILESEPARATOR && base[len - 1] != FILESEPARATOR2) { + result[len] = FILESEPARATOR; + result[len + 1] = '\0'; + } + strcat(result, name); + return result; +} + +/* Extract the last component from a path name. Returned string must be freed */ +static char * +js_fileBaseName(JSContext *cx, const char *pathname) +{ + jsint index, aux; + char *result; + + index = strlen(pathname)-1; + + /* Chop off trailing seperators. */ + while (index > 0 && (pathname[index]==FILESEPARATOR || + pathname[index]==FILESEPARATOR2)) { + --index; + } + + aux = index; + + /* Now find the next separator. */ + while (index >= 0 && pathname[index] != FILESEPARATOR && + pathname[index] != FILESEPARATOR2) { + --index; + } + + /* Allocate and copy. */ + result = JS_malloc(cx, aux - index + 1); + if (!result) + return NULL; + strncpy(result, pathname + index + 1, aux - index); + result[aux - index] = '\0'; + return result; +} + +/* + * Returns everything but the last component from a path name. + * Returned string must be freed. + */ +static char * +js_fileDirectoryName(JSContext *cx, const char *pathname) +{ + char *result; + const char *cp, *end; + size_t pathsize; + + end = pathname + strlen(pathname); + cp = end - 1; + + /* If this is already a directory, chop off the trailing /s. */ + while (cp >= pathname) { + if (*cp != FILESEPARATOR && *cp != FILESEPARATOR2) + break; + --cp; + } + + if (cp < pathname && end != pathname) { + /* There were just /s, return the root. */ + result = JS_malloc(cx, 1 + 1); /* The separator + trailing NUL. */ + result[0] = FILESEPARATOR; + result[1] = '\0'; + return result; + } + + /* Now chop off the last portion. */ + while (cp >= pathname) { + if (*cp == FILESEPARATOR || *cp == FILESEPARATOR2) + break; + --cp; + } + + /* Check if this is a leaf. */ + if (cp < pathname) { + /* It is, return "pathname/". */ + if (end[-1] == FILESEPARATOR || end[-1] == FILESEPARATOR2) { + /* Already has its terminating /. */ + return JS_strdup(cx, pathname); + } + + pathsize = end - pathname + 1; + result = JS_malloc(cx, pathsize + 1); + if (!result) + return NULL; + + strcpy(result, pathname); + result[pathsize - 1] = FILESEPARATOR; + result[pathsize] = '\0'; + + return result; + } + + /* Return everything up to and including the seperator. */ + pathsize = cp - pathname + 1; + result = JS_malloc(cx, pathsize + 1); + if (!result) + return NULL; + + strncpy(result, pathname, pathsize); + result[pathsize] = '\0'; + + return result; +} + +static char * +js_absolutePath(JSContext *cx, const char * path) +{ + JSObject *obj; + JSString *str; + jsval prop; + + if (js_isAbsolute(path)) { + return JS_strdup(cx, path); + } else { + obj = JS_GetGlobalObject(cx); + if (!JS_GetProperty(cx, obj, FILE_CONSTRUCTOR, &prop)) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_FILE_CONSTRUCTOR_UNDEFINED_ERROR); + return JS_strdup(cx, path); + } + + obj = JSVAL_TO_OBJECT(prop); + if (!JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, &prop)) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_FILE_CURRENTDIR_UNDEFINED_ERROR); + return JS_strdup(cx, path); + } + + str = JS_ValueToString(cx, prop); + if (!str) + return JS_strdup(cx, path); + + /* should we have an array of curr dirs indexed by drive for windows? */ + return js_combinePath(cx, JS_GetStringBytes(str), path); + } +} + +/* Side effect: will remove spaces in the beginning/end of the filename */ +static char * +js_canonicalPath(JSContext *cx, char *oldpath) +{ + char *tmp; + char *path = oldpath; + char *base, *dir, *current, *result; + jsint c; + jsint back = 0; + unsigned int i = 0, j = strlen(path)-1; + + /* This is probably optional */ + /* Remove possible spaces in the beginning and end */ + while (i < j && path[i] == ' ') + i++; + while (j >= 0 && path[j] == ' ') + j--; + + tmp = JS_malloc(cx, j-i+2); + if (!tmp) + return NULL; + + strncpy(tmp, path + i, j - i + 1); + tmp[j - i + 1] = '\0'; + + path = tmp; + + /* Pipe support. */ + if (js_filenameHasAPipe(path)) + return path; + + /* file:// support. */ + if (!strncmp(path, URL_PREFIX, strlen(URL_PREFIX))) { + tmp = js_canonicalPath(cx, path + strlen(URL_PREFIX)); + JS_free(cx, path); + return tmp; + } + + if (!js_isAbsolute(path)) { + tmp = js_absolutePath(cx, path); + if (!tmp) + return NULL; + JS_free(cx, path); + path = tmp; + } + + result = JS_strdup(cx, ""); + + current = path; + + base = js_fileBaseName(cx, current); + dir = js_fileDirectoryName(cx, current); + + while (strcmp(dir, current)) { + if (!strcmp(base, "..")) { + back++; + } else { + if (back > 0) { + back--; + } else { + tmp = result; + result = JS_malloc(cx, strlen(base) + 1 + strlen(tmp) + 1); + if (!result) + goto out; + + strcpy(result, base); + c = strlen(result); + if (*tmp) { + result[c] = FILESEPARATOR; + result[c + 1] = '\0'; + strcat(result, tmp); + } + JS_free(cx, tmp); + } + } + JS_free(cx, current); + JS_free(cx, base); + current = dir; + base = js_fileBaseName(cx, current); + dir = js_fileDirectoryName(cx, current); + } + + tmp = result; + result = JS_malloc(cx, strlen(dir)+1+strlen(tmp)+1); + if (!result) + goto out; + + strcpy(result, dir); + c = strlen(result); + if (tmp[0]!='\0') { + if ((result[c-1]!=FILESEPARATOR)&&(result[c-1]!=FILESEPARATOR2)) { + result[c] = FILESEPARATOR; + result[c+1] = '\0'; + } + strcat(result, tmp); + } + +out: + if (tmp) + JS_free(cx, tmp); + if (dir) + JS_free(cx, dir); + if (base) + JS_free(cx, base); + if (current) + JS_free(cx, current); + + return result; +} + +/* -------------------------- Text conversion ------------------------------- */ +/* The following is ripped from libi18n/unicvt.c and include files.. */ + +/* + * UTF8 defines and macros + */ +#define ONE_OCTET_BASE 0x00 /* 0xxxxxxx */ +#define ONE_OCTET_MASK 0x7F /* x1111111 */ +#define CONTINUING_OCTET_BASE 0x80 /* 10xxxxxx */ +#define CONTINUING_OCTET_MASK 0x3F /* 00111111 */ +#define TWO_OCTET_BASE 0xC0 /* 110xxxxx */ +#define TWO_OCTET_MASK 0x1F /* 00011111 */ +#define THREE_OCTET_BASE 0xE0 /* 1110xxxx */ +#define THREE_OCTET_MASK 0x0F /* 00001111 */ +#define FOUR_OCTET_BASE 0xF0 /* 11110xxx */ +#define FOUR_OCTET_MASK 0x07 /* 00000111 */ +#define FIVE_OCTET_BASE 0xF8 /* 111110xx */ +#define FIVE_OCTET_MASK 0x03 /* 00000011 */ +#define SIX_OCTET_BASE 0xFC /* 1111110x */ +#define SIX_OCTET_MASK 0x01 /* 00000001 */ + +#define IS_UTF8_1ST_OF_1(x) (( (x)&~ONE_OCTET_MASK ) == ONE_OCTET_BASE) +#define IS_UTF8_1ST_OF_2(x) (( (x)&~TWO_OCTET_MASK ) == TWO_OCTET_BASE) +#define IS_UTF8_1ST_OF_3(x) (( (x)&~THREE_OCTET_MASK) == THREE_OCTET_BASE) +#define IS_UTF8_1ST_OF_4(x) (( (x)&~FOUR_OCTET_MASK ) == FOUR_OCTET_BASE) +#define IS_UTF8_1ST_OF_5(x) (( (x)&~FIVE_OCTET_MASK ) == FIVE_OCTET_BASE) +#define IS_UTF8_1ST_OF_6(x) (( (x)&~SIX_OCTET_MASK ) == SIX_OCTET_BASE) +#define IS_UTF8_2ND_THRU_6TH(x) \ + (( (x)&~CONTINUING_OCTET_MASK ) == CONTINUING_OCTET_BASE) +#define IS_UTF8_1ST_OF_UCS2(x) \ + IS_UTF8_1ST_OF_1(x) \ + || IS_UTF8_1ST_OF_2(x) \ + || IS_UTF8_1ST_OF_3(x) + + +#define MAX_UCS2 0xFFFF +#define DEFAULT_CHAR 0x003F /* Default char is "?" */ +#define BYTE_MASK 0xBF +#define BYTE_MARK 0x80 + + +/* Function: one_ucs2_to_utf8_char + * + * Function takes one UCS-2 char and writes it to a UTF-8 buffer. + * We need a UTF-8 buffer because we don't know before this + * function how many bytes of utf-8 data will be written. It also + * takes a pointer to the end of the UTF-8 buffer so that we don't + * overwrite data. This function returns the number of UTF-8 bytes + * of data written, or -1 if the buffer would have been overrun. + */ + +#define LINE_SEPARATOR 0x2028 +#define PARAGRAPH_SEPARATOR 0x2029 +static int16 one_ucs2_to_utf8_char(unsigned char *tobufp, + unsigned char *tobufendp, + uint16 onechar) +{ + int16 numUTF8bytes = 0; + + if (onechar == LINE_SEPARATOR || onechar == PARAGRAPH_SEPARATOR) { + strcpy((char*)tobufp, "\n"); + return strlen((char*)tobufp); + } + + if (onechar < 0x80) { + numUTF8bytes = 1; + } else if (onechar < 0x800) { + numUTF8bytes = 2; + } else { + /* 0x800 >= onechar <= MAX_UCS2 */ + numUTF8bytes = 3; + } + + tobufp += numUTF8bytes; + + /* return error if we don't have space for the whole character */ + if (tobufp > tobufendp) { + return(-1); + } + + switch(numUTF8bytes) { + case 3: *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6; + *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6; + *--tobufp = onechar | THREE_OCTET_BASE; + break; + + case 2: *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6; + *--tobufp = onechar | TWO_OCTET_BASE; + break; + + case 1: *--tobufp = (unsigned char)onechar; + break; + } + + return numUTF8bytes; +} + +/* + * utf8_to_ucs2_char + * + * Convert a utf8 multibyte character to ucs2 + * + * inputs: pointer to utf8 character(s) + * length of utf8 buffer ("read" length limit) + * pointer to return ucs2 character + * + * outputs: number of bytes in the utf8 character + * -1 if not a valid utf8 character sequence + * -2 if the buffer is too short + */ +static int16 +utf8_to_ucs2_char(const unsigned char *utf8p, int16 buflen, uint16 *ucs2p) +{ + uint16 lead, cont1, cont2; + + /* + * Check for minimum buffer length + */ + if ((buflen < 1) || (utf8p == NULL)) { + return -2; + } + lead = (uint16) (*utf8p); + + /* + * Check for a one octet sequence + */ + if (IS_UTF8_1ST_OF_1(lead)) { + *ucs2p = lead & ONE_OCTET_MASK; + return 1; + } + + /* + * Check for a two octet sequence + */ + if (IS_UTF8_1ST_OF_2(*utf8p)) { + if (buflen < 2) + return -2; + cont1 = (uint16) *(utf8p+1); + if (!IS_UTF8_2ND_THRU_6TH(cont1)) + return -1; + *ucs2p = (lead & TWO_OCTET_MASK) << 6; + *ucs2p |= cont1 & CONTINUING_OCTET_MASK; + return 2; + } + + /* + * Check for a three octet sequence + */ + else if (IS_UTF8_1ST_OF_3(lead)) { + if (buflen < 3) + return -2; + cont1 = (uint16) *(utf8p+1); + cont2 = (uint16) *(utf8p+2); + if ( (!IS_UTF8_2ND_THRU_6TH(cont1)) + || (!IS_UTF8_2ND_THRU_6TH(cont2))) + return -1; + *ucs2p = (lead & THREE_OCTET_MASK) << 12; + *ucs2p |= (cont1 & CONTINUING_OCTET_MASK) << 6; + *ucs2p |= cont2 & CONTINUING_OCTET_MASK; + return 3; + } + else { /* not a valid utf8/ucs2 character */ + return -1; + } +} + +/* ----------------------------- Helper functions --------------------------- */ +/* Ripped off from lm_win.c .. */ +/* where is strcasecmp?.. for now, it's case sensitive.. + * + * strcasecmp is in strings.h, but on windows it's called _stricmp... + * will need to #ifdef this +*/ + +static int32 +js_FileHasOption(JSContext *cx, const char *oldoptions, const char *name) +{ + char *comma, *equal, *current; + char *options = JS_strdup(cx, oldoptions); + int32 found = 0; + + current = options; + for (;;) { + comma = strchr(current, ','); + if (comma) *comma = '\0'; + equal = strchr(current, '='); + if (equal) *equal = '\0'; + if (strcmp(current, name) == 0) { + if (!equal || strcmp(equal + 1, "yes") == 0) + found = 1; + else + found = atoi(equal + 1); + } + if (equal) *equal = '='; + if (comma) *comma = ','; + if (found || !comma) + break; + current = comma + 1; + } + JS_free(cx, options); + return found; +} + +/* empty the buffer */ +static void +js_ResetBuffers(JSFile * file) +{ + file->charBufferUsed = JS_FALSE; + file->nbBytesInBuf = 0; +} + +/* Reset file attributes */ +static void +js_ResetAttributes(JSFile * file) +{ + file->mode = file->type = 0; + file->isOpen = JS_FALSE; + file->handle = NULL; + file->nativehandle = NULL; + file->hasRandomAccess = JS_TRUE; /* Innocent until proven guilty. */ + file->hasAutoflush = JS_FALSE; + file->isNative = JS_FALSE; + file->isPipe = JS_FALSE; + + js_ResetBuffers(file); +} + +static JSBool +js_FileOpen(JSContext *cx, JSObject *obj, JSFile *file, char *mode){ + JSString *type, *mask; + jsval v[2]; + jsval rval; + + type = JS_InternString(cx, asciistring); + mask = JS_NewStringCopyZ(cx, mode); + v[0] = STRING_TO_JSVAL(mask); + v[1] = STRING_TO_JSVAL(type); + + if (!file_open(cx, obj, 2, v, &rval)) + return JS_FALSE; + return JS_TRUE; +} + +/* Buffered version of PR_Read. Used by js_FileRead */ +static int32 +js_BufferedRead(JSFile *f, unsigned char *buf, int32 len) +{ + int32 count = 0; + + while (f->nbBytesInBuf>0&&len>0) { + buf[0] = f->byteBuffer[0]; + f->byteBuffer[0] = f->byteBuffer[1]; + f->byteBuffer[1] = f->byteBuffer[2]; + f->nbBytesInBuf--; + len--; + buf+=1; + count++; + } + + if (len > 0) { + count += (!f->isNative) + ? PR_Read(f->handle, buf, len) + : fread(buf, 1, len, f->nativehandle); + } + return count; +} + +static int32 +js_FileRead(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode) +{ + unsigned char *aux; + int32 count = 0, i; + jsint remainder; + unsigned char utfbuf[3]; + + if (file->charBufferUsed) { + buf[0] = file->charBuffer; + buf++; + len--; + file->charBufferUsed = JS_FALSE; + } + + switch (mode) { + case ASCII: + aux = (unsigned char*)JS_malloc(cx, len); + if (!aux) + return 0; + + count = js_BufferedRead(file, aux, len); + if (count == -1) { + JS_free(cx, aux); + return 0; + } + + for (i = 0; i < len; i++) + buf[i] = (jschar)aux[i]; + + JS_free(cx, aux); + break; + + case UTF8: + remainder = 0; + for (count = 0;count0) { + file->byteBuffer[file->nbBytesInBuf] = utfbuf[0]; + file->nbBytesInBuf++; + utfbuf[0] = utfbuf[1]; + utfbuf[1] = utfbuf[2]; + remainder--; + } + break; + + case UCS2: + count = js_BufferedRead(file, (unsigned char *)buf, len * 2) >> 1; + if (count == -1) + return 0; + + break; + + default: + /* Not reached. */ + JS_ASSERT(0); + } + + if(count == -1) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "read", file->path); + } + + return count; +} + +static int32 +js_FileSeek(JSContext *cx, JSFile *file, int32 len, int32 mode) +{ + int32 count = 0, i; + jsint remainder; + unsigned char utfbuf[3]; + jschar tmp; + + switch (mode) { + case ASCII: + count = PR_Seek(file->handle, len, PR_SEEK_CUR); + break; + + case UTF8: + remainder = 0; + for (count = 0;count0) { + file->byteBuffer[file->nbBytesInBuf] = utfbuf[0]; + file->nbBytesInBuf++; + utfbuf[0] = utfbuf[1]; + utfbuf[1] = utfbuf[2]; + remainder--; + } + break; + + case UCS2: + count = PR_Seek(file->handle, len*2, PR_SEEK_CUR)/2; + break; + + default: + /* Not reached. */ + JS_ASSERT(0); + } + + if(count == -1) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "seek", file->path); + } + + return count; +} + +static int32 +js_FileWrite(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode) +{ + unsigned char *aux; + int32 count = 0, i, j; + unsigned char *utfbuf; + + switch (mode) { + case ASCII: + aux = (unsigned char*)JS_malloc(cx, len); + if (!aux) + return 0; + + for (i = 0; iisNative) + ? PR_Write(file->handle, aux, len) + : fwrite(aux, 1, len, file->nativehandle); + + if (count==-1) { + JS_free(cx, aux); + return 0; + } + + JS_free(cx, aux); + break; + + case UTF8: + utfbuf = (unsigned char*)JS_malloc(cx, len*3); + if (!utfbuf) return 0; + i = 0; + for (count = 0;countisNative) + ? PR_Write(file->handle, utfbuf, i) + : fwrite(utfbuf, 1, i, file->nativehandle); + + if (jisNative) + ? PR_Write(file->handle, buf, len*2) >> 1 + : fwrite(buf, 1, len*2, file->nativehandle) >> 1; + + if (count == -1) + return 0; + break; + + default: + /* Not reached. */ + JS_ASSERT(0); + } + + if(count == -1) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "write", file->path); + } + + return count; +} + +/* ----------------------------- Property checkers -------------------------- */ +static JSBool +js_exists(JSContext *cx, JSFile *file) +{ + if (file->isNative) { + /* It doesn't make sense for a pipe of stdstream. */ + return JS_FALSE; + } + + return PR_Access(file->path, PR_ACCESS_EXISTS) == PR_SUCCESS; +} + +static JSBool +js_canRead(JSContext *cx, JSFile *file) +{ + if (!file->isNative) { + if (file->isOpen && !(file->mode & PR_RDONLY)) + return JS_FALSE; + return PR_Access(file->path, PR_ACCESS_READ_OK) == PR_SUCCESS; + } + + if (file->isPipe) { + /* Is this pipe open for reading? */ + return file->path[0] == PIPE_SYMBOL; + } + + return !strcmp(file->path, STDINPUT_NAME); +} + +static JSBool +js_canWrite(JSContext *cx, JSFile *file) +{ + if (!file->isNative) { + if (file->isOpen && !(file->mode & PR_WRONLY)) + return JS_FALSE; + return PR_Access(file->path, PR_ACCESS_WRITE_OK) == PR_SUCCESS; + } + + if(file->isPipe) { + /* Is this pipe open for writing? */ + return file->path[strlen(file->path)-1] == PIPE_SYMBOL; + } + + return !strcmp(file->path, STDOUTPUT_NAME) || + !strcmp(file->path, STDERROR_NAME); +} + +static JSBool +js_isFile(JSContext *cx, JSFile *file) +{ + if (!file->isNative) { + PRFileInfo info; + + if (file->isOpen + ? PR_GetOpenFileInfo(file->handle, &info) + : PR_GetFileInfo(file->path, &info) != PR_SUCCESS) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path); + return JS_FALSE; + } + + return info.type == PR_FILE_FILE; + } + + /* This doesn't make sense for a pipe of stdstream. */ + return JS_FALSE; +} + +static JSBool +js_isDirectory(JSContext *cx, JSFile *file) +{ + if(!file->isNative){ + PRFileInfo info; + + /* Hack needed to get get_property to work. */ + if (!js_exists(cx, file)) + return JS_FALSE; + + if (file->isOpen + ? PR_GetOpenFileInfo(file->handle, &info) + : PR_GetFileInfo(file->path, &info) != PR_SUCCESS) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path); + return JS_FALSE; + } + + return info.type == PR_FILE_DIRECTORY; + } + + /* This doesn't make sense for a pipe of stdstream. */ + return JS_FALSE; +} + +static jsval +js_size(JSContext *cx, JSFile *file) +{ + PRFileInfo info; + + JSFILE_CHECK_NATIVE("size"); + + if (file->isOpen + ? PR_GetOpenFileInfo(file->handle, &info) + : PR_GetFileInfo(file->path, &info) != PR_SUCCESS) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path); + return JSVAL_VOID; + } + + return INT_TO_JSVAL(info.size); + +out: + return JSVAL_VOID; +} + +/* + * Return the parent object + */ +static JSBool +js_parent(JSContext *cx, JSFile *file, jsval *resultp) +{ + char *str; + + /* Since we only care about pipes and native files, return NULL. */ + if (file->isNative) { + *resultp = JSVAL_VOID; + return JS_TRUE; + } + + str = js_fileDirectoryName(cx, file->path); + if (!str) + return JS_FALSE; + + /* If the directory is equal to the original path, we're at the root. */ + if (!strcmp(file->path, str)) { + *resultp = JSVAL_NULL; + } else { + JSObject *obj = js_NewFileObject(cx, str); + if (!obj) { + JS_free(cx, str); + return JS_FALSE; + } + *resultp = OBJECT_TO_JSVAL(obj); + } + + JS_free(cx, str); + return JS_TRUE; +} + +static JSBool +js_name(JSContext *cx, JSFile *file, jsval *vp) +{ + char *name; + JSString *str; + + if (file->isPipe) { + *vp = JSVAL_VOID; + return JS_TRUE; + } + + name = js_fileBaseName(cx, file->path); + if (!name) + return JS_FALSE; + + str = JS_NewString(cx, name, strlen(name)); + if (!str) { + JS_free(cx, name); + return JS_FALSE; + } + + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +/* ------------------------------ File object methods ---------------------------- */ +static JSBool +file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + JSString *strmode, *strtype; + char *ctype, *mode; + int32 mask, type; + int len; + + mode = NULL; + + SECURITY_CHECK(cx, NULL, "open", file); + + /* A native file that is already open */ + if(file->isOpen && file->isNative) { + JS_ReportWarning(cx, "Native file %s is already open, proceeding", + file->path); + goto good; + } + + /* Close before proceeding */ + if (file->isOpen) { + JS_ReportWarning(cx, "File %s is already open, we will close it and " + "reopen, proceeding", file->path); + if(!file_close(cx, obj, 0, NULL, rval)) + goto out; + } + + if (js_isDirectory(cx, file)) { + JS_ReportWarning(cx, "%s seems to be a directory, there is no point in " + "trying to open it, proceeding", file->path); + goto good; + } + + /* Path must be defined at this point */ + len = strlen(file->path); + + /* Mode */ + if (argc >= 1) { + strmode = JS_ValueToString(cx, argv[0]); + if (!strmode) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_FIRST_ARGUMENT_OPEN_NOT_STRING_ERROR, + argv[0]); + goto out; + } + mode = JS_strdup(cx, JS_GetStringBytes(strmode)); + } else { + if(file->path[0]==PIPE_SYMBOL) { + /* pipe default mode */ + mode = JS_strdup(cx, "read"); + } else if(file->path[len-1]==PIPE_SYMBOL) { + /* pipe default mode */ + mode = JS_strdup(cx, "write"); + } else { + /* non-destructive, permissive defaults. */ + mode = JS_strdup(cx, "readWrite,append,create"); + } + } + + /* Process the mode */ + mask = 0; + /* TODO: this is pretty ugly, we walk thru the string too many times */ + mask |= js_FileHasOption(cx, mode, "read") ? PR_RDONLY : 0; + mask |= js_FileHasOption(cx, mode, "write") ? PR_WRONLY : 0; + mask |= js_FileHasOption(cx, mode, "readWrite")? PR_RDWR : 0; + mask |= js_FileHasOption(cx, mode, "append") ? PR_APPEND : 0; + mask |= js_FileHasOption(cx, mode, "create") ? PR_CREATE_FILE : 0; + mask |= js_FileHasOption(cx, mode, "replace") ? PR_TRUNCATE : 0; + + if (mask & PR_RDWR) + mask |= (PR_RDONLY | PR_WRONLY); + if ((mask & PR_RDONLY) && (mask & PR_WRONLY)) + mask |= PR_RDWR; + + file->hasAutoflush |= js_FileHasOption(cx, mode, "autoflush"); + + /* Type */ + if (argc > 1) { + strtype = JS_ValueToString(cx, argv[1]); + if (!strtype) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_SECOND_ARGUMENT_OPEN_NOT_STRING_ERROR, + argv[1]); + goto out; + } + ctype = JS_GetStringBytes(strtype); + + if(!strcmp(ctype, utfstring)) { + type = UTF8; + } else if (!strcmp(ctype, unicodestring)) { + type = UCS2; + } else { + if (strcmp(ctype, asciistring)) { + JS_ReportWarning(cx, "File type %s is not supported, using " + "'text' instead, proceeding", ctype); + } + type = ASCII; + } + } else { + type = ASCII; + } + + /* Save the relevant fields */ + file->type = type; + file->mode = mask; + file->nativehandle = NULL; + file->hasRandomAccess = (type != UTF8); + + /* + * Deal with pipes here. We can't use NSPR for pipes, so we have to use + * POPEN. + */ + if (file->path[0]==PIPE_SYMBOL || file->path[len-1]==PIPE_SYMBOL) { + if (file->path[0] == PIPE_SYMBOL && file->path[len-1] == PIPE_SYMBOL) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_BIDIRECTIONAL_PIPE_NOT_SUPPORTED); + goto out; + } else { + int i = 0; + char pipemode[3]; + SECURITY_CHECK(cx, NULL, "pipe_open", file); + + if(file->path[0] == PIPE_SYMBOL){ + if(mask & (PR_WRONLY | PR_APPEND | PR_CREATE_FILE | PR_TRUNCATE)){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OPEN_MODE_NOT_SUPPORTED_WITH_PIPES, + mode, file->path); + goto out; + } + /* open(SPOOLER, "| cat -v | lpr -h 2>/dev/null") -- pipe for writing */ + pipemode[i++] = 'r'; +#ifndef XP_UNIX + pipemode[i++] = file->type==UTF8 ? 'b' : 't'; +#endif + pipemode[i++] = '\0'; + file->nativehandle = POPEN(&file->path[1], pipemode); + } else if(file->path[len-1] == PIPE_SYMBOL) { + char *command = JS_malloc(cx, len); + + strncpy(command, file->path, len-1); + command[len-1] = '\0'; + /* open(STATUS, "netstat -an 2>&1 |") */ + pipemode[i++] = 'w'; +#ifndef XP_UNIX + pipemode[i++] = file->type==UTF8 ? 'b' : 't'; +#endif + pipemode[i++] = '\0'; + file->nativehandle = POPEN(command, pipemode); + JS_free(cx, command); + } + /* set the flags */ + file->isNative = JS_TRUE; + file->isPipe = JS_TRUE; + file->hasRandomAccess = JS_FALSE; + } + } else { + /* TODO: what about the permissions?? Java ignores the problem... */ + file->handle = PR_Open(file->path, mask, 0644); + } + + js_ResetBuffers(file); + JS_free(cx, mode); + mode = NULL; + + /* Set the open flag and return result */ + if (file->handle == NULL && file->nativehandle == NULL) { + file->isOpen = JS_FALSE; + + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "open", file->path); + goto out; + } + +good: + file->isOpen = JS_TRUE; + *rval = JSVAL_TRUE; + return JS_TRUE; + +out: + if(mode) + JS_free(cx, mode); + return JS_FALSE; +} + +static JSBool +file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + + SECURITY_CHECK(cx, NULL, "close", file); + + if(!file->isOpen){ + JS_ReportWarning(cx, "File %s is not open, can't close it, proceeding", + file->path); + goto out; + } + + if(!file->isPipe){ + if(file->isNative){ + JS_ReportWarning(cx, "Unable to close a native file, proceeding", file->path); + goto out; + }else{ + if(file->handle && PR_Close(file->handle)){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "close", file->path); + + goto out; + } + } + }else{ + if(PCLOSE(file->nativehandle)==-1){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "pclose", file->path); + goto out; + } + } + + js_ResetAttributes(file); + *rval = JSVAL_TRUE; + return JS_TRUE; + +out: + return JS_FALSE; +} + + +static JSBool +file_remove(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + + SECURITY_CHECK(cx, NULL, "remove", file); + JSFILE_CHECK_NATIVE("remove"); + JSFILE_CHECK_CLOSED("remove"); + + if ((js_isDirectory(cx, file) ? + PR_RmDir(file->path) : PR_Delete(file->path))==PR_SUCCESS) { + js_ResetAttributes(file); + *rval = JSVAL_TRUE; + return JS_TRUE; + } else { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "remove", file->path); + goto out; + } +out: + *rval = JSVAL_FALSE; + return JS_FALSE; +} + +/* Raw PR-based function. No text processing. Just raw data copying. */ +static JSBool +file_copyTo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + char *dest = NULL; + PRFileDesc *handle = NULL; + char *buffer; + jsval count, size; + JSBool fileInitiallyOpen=JS_FALSE; + + SECURITY_CHECK(cx, NULL, "copyTo", file); /* may need a second argument!*/ + JSFILE_CHECK_ONE_ARG("copyTo"); + JSFILE_CHECK_NATIVE("copyTo"); + /* remeber the state */ + fileInitiallyOpen = file->isOpen; + JSFILE_CHECK_READ; + + dest = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + + /* make sure we are not reading a file open for writing */ + if (file->isOpen && !js_canRead(cx, file)) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_COPY_FILE_OPEN_FOR_WRITING_ERROR, file->path); + goto out; + } + + if (file->handle==NULL){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "open", file->path); + goto out; + } + + handle = PR_Open(dest, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0644); + + if(!handle){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "open", dest); + goto out; + } + + if ((size=js_size(cx, file))==JSVAL_VOID) { + goto out; + } + + buffer = JS_malloc(cx, size); + + count = INT_TO_JSVAL(PR_Read(file->handle, buffer, size)); + + /* reading panic */ + if (count!=size) { + JS_free(cx, buffer); + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_COPY_READ_ERROR, file->path); + goto out; + } + + count = INT_TO_JSVAL(PR_Write(handle, buffer, JSVAL_TO_INT(size))); + + /* writing panic */ + if (count!=size) { + JS_free(cx, buffer); + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_COPY_WRITE_ERROR, file->path); + goto out; + } + + JS_free(cx, buffer); + + if(!fileInitiallyOpen){ + if(!file_close(cx, obj, 0, NULL, rval)) goto out; + } + + if(PR_Close(handle)!=PR_SUCCESS){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "close", dest); + goto out; + } + + *rval = JSVAL_TRUE; + return JS_TRUE; +out: + if(file->isOpen && !fileInitiallyOpen){ + if(PR_Close(file->handle)!=PR_SUCCESS){ + JS_ReportWarning(cx, "Can't close %s, proceeding", file->path); + } + } + + if(handle && PR_Close(handle)!=PR_SUCCESS){ + JS_ReportWarning(cx, "Can't close %s, proceeding", dest); + } + + *rval = JSVAL_FALSE; + return JS_FALSE; +} + +static JSBool +file_renameTo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + char *dest; + + SECURITY_CHECK(cx, NULL, "renameTo", file); /* may need a second argument!*/ + JSFILE_CHECK_ONE_ARG("renameTo"); + JSFILE_CHECK_NATIVE("renameTo"); + JSFILE_CHECK_CLOSED("renameTo"); + + dest = RESOLVE_PATH(cx, JS_GetStringBytes(JS_ValueToString(cx, argv[0]))); + + if (PR_Rename(file->path, dest)==PR_SUCCESS){ + /* copy the new filename */ + JS_free(cx, file->path); + file->path = dest; + *rval = JSVAL_TRUE; + return JS_TRUE; + }else{ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_RENAME_FAILED, file->path, dest); + goto out; + } +out: + *rval = JSVAL_FALSE; + return JS_FALSE; +} + +static JSBool +file_flush(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + + SECURITY_CHECK(cx, NULL, "flush", file); + JSFILE_CHECK_NATIVE("flush"); + JSFILE_CHECK_OPEN("flush"); + + if (PR_Sync(file->handle)==PR_SUCCESS){ + *rval = JSVAL_TRUE; + return JS_TRUE; + }else{ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "flush", file->path); + goto out; + } +out: + *rval = JSVAL_FALSE; + return JS_FALSE; +} + +static JSBool +file_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + JSString *str; + int32 count; + uintN i; + + SECURITY_CHECK(cx, NULL, "write", file); + JSFILE_CHECK_WRITE; + + for (i = 0; itype); + if (count==-1){ + *rval = JSVAL_FALSE; + return JS_FALSE; + } + } + + *rval = JSVAL_TRUE; + return JS_TRUE; +out: + *rval = JSVAL_FALSE; + return JS_FALSE; +} + +static JSBool +file_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + JSString *str; + + SECURITY_CHECK(cx, NULL, "writeln", file); + JSFILE_CHECK_WRITE; + + /* don't report an error here */ + if(!file_write(cx, obj, argc, argv, rval)) return JS_FALSE; + /* don't do security here -- we passed the check in file_write */ + str = JS_NewStringCopyZ(cx, "\n"); + + if (js_FileWrite(cx, file, JS_GetStringChars(str), JS_GetStringLength(str), + file->type)==-1){ + *rval = JSVAL_FALSE; + return JS_FALSE; + } + + /* eol causes flush if hasAutoflush is turned on */ + if (file->hasAutoflush) + file_flush(cx, obj, 0, NULL, rval); + + *rval = JSVAL_TRUE; + return JS_TRUE; +out: + *rval = JSVAL_FALSE; + return JS_FALSE; +} + +static JSBool +file_writeAll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + jsuint i; + jsuint limit; + JSObject *array; + JSObject *elem; + jsval elemval; + + SECURITY_CHECK(cx, NULL, "writeAll", file); + JSFILE_CHECK_ONE_ARG("writeAll"); + JSFILE_CHECK_WRITE; + + if (!JS_IsArrayObject(cx, JSVAL_TO_OBJECT(argv[0]))) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_FIRST_ARGUMENT_WRITEALL_NOT_ARRAY_ERROR); + goto out; + } + + array = JSVAL_TO_OBJECT(argv[0]); + + JS_GetArrayLength(cx, array, &limit); + + for (i = 0; i262144)?262144:want; * arbitrary size limitation */ + + buf = JS_malloc(cx, want*sizeof buf[0]); + if (!buf) goto out; + + count = js_FileRead(cx, file, buf, want, file->type); + if (count>0) { + str = JS_NewUCStringCopyN(cx, buf, count); + *rval = STRING_TO_JSVAL(str); + JS_free(cx, buf); + return JS_TRUE; + } else { + JS_free(cx, buf); + goto out; + } +out: + *rval = JSVAL_FALSE; + return JS_FALSE; +} + +static JSBool +file_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + JSString *str; + jschar *buf = NULL, *tmp; + int32 offset, read; + intN room; + jschar data, data2; + + SECURITY_CHECK(cx, NULL, "readln", file); + JSFILE_CHECK_READ; + + buf = JS_malloc(cx, MAX_LINE_LENGTH * sizeof data); + if (!buf) + return JS_FALSE; + + room = MAX_LINE_LENGTH - 1; + offset = 0; + + for (;;) { + read = js_FileRead(cx, file, &data, 1, file->type); + if (read < 0) + goto out; + if (read == 0) + goto eof; + + switch (data) { + case '\r': + read = js_FileRead(cx, file, &data2, 1, file->type); + if (read < 0) + goto out; + + if (read == 1 && data2 != '\n') { + /* We read one char too far. Buffer it. */ + file->charBuffer = data2; + file->charBufferUsed = JS_TRUE; + } + + /* Fall through. */ + case '\n': + goto done; + + default: + if (--room < 0) { + tmp = JS_realloc(cx, buf, + (offset + MAX_LINE_LENGTH) * sizeof data); + if (!tmp) + goto out; + + room = MAX_LINE_LENGTH - 1; + buf = tmp; + } + + buf[offset++] = data; + break; + } + } + +eof: + if (offset == 0) { + *rval = JSVAL_NULL; + return JS_TRUE; + } + +done: + buf[offset] = 0; + tmp = JS_realloc(cx, buf, (offset + 1) * sizeof data); + if (!tmp) + goto out; + + str = JS_NewUCString(cx, tmp, offset); + if (!str) + goto out; + + *rval = STRING_TO_JSVAL(str); + return JS_TRUE; + +out: + if (buf) + JS_free(cx, buf); + + return JS_FALSE; +} + +static JSBool +file_readAll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + JSObject *array; + jsint len; + jsval line; + JSBool lineok = JS_FALSE; + + SECURITY_CHECK(cx, NULL, "readAll", file); + JSFILE_CHECK_READ; + + array = JS_NewArrayObject(cx, 0, NULL); + if (!array) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(array); + + len = 0; + + lineok = file_readln(cx, obj, 0, NULL, &line); + while (lineok && !JSVAL_IS_NULL(line)) { + JS_SetElement(cx, array, len++, &line); + lineok = file_readln(cx, obj, 0, NULL, &line); + } + +out: + return lineok; +} + +static JSBool +file_seek(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + int32 toskip; + int32 pos; + + SECURITY_CHECK(cx, NULL, "seek", file); + JSFILE_CHECK_ONE_ARG("seek"); + JSFILE_CHECK_NATIVE("seek"); + JSFILE_CHECK_READ; + + if (!JS_ValueToInt32(cx, argv[0], &toskip)){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, "seek", argv[0]); + goto out; + } + + if(!file->hasRandomAccess){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_NO_RANDOM_ACCESS, file->path); + goto out; + } + + if(js_isDirectory(cx, file)){ + JS_ReportWarning(cx,"Seek on directories is not supported, proceeding"); + goto out; + } + + pos = js_FileSeek(cx, file, toskip, file->type); + + if (pos!=-1) { + *rval = INT_TO_JSVAL(pos); + return JS_TRUE; + } +out: + *rval = JSVAL_VOID; + return JS_FALSE; +} + +static JSBool +file_list(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + PRDir *dir; + PRDirEntry *entry; + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + JSObject *array; + JSObject *eachFile; + jsint len; + jsval v; + JSRegExp *re = NULL; + JSFunction *func = NULL; + JSString *str; + jsval args[1]; + char *filePath; + + SECURITY_CHECK(cx, NULL, "list", file); + JSFILE_CHECK_NATIVE("list"); + + if (argc==1) { + if (VALUE_IS_REGEXP(cx, argv[0])) { + re = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + }else + if (VALUE_IS_FUNCTION(cx, argv[0])) { + func = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + }else{ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_FUNCTION_OR_REGEX, argv[0]); + goto out; + } + } + + if (!js_isDirectory(cx, file)) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_DO_LIST_ON_A_FILE, file->path); + goto out; + } + + dir = PR_OpenDir(file->path); + if(!dir){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "open", file->path); + goto out; + } + + /* create JSArray here... */ + array = JS_NewArrayObject(cx, 0, NULL); + len = 0; + + while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH))!=NULL) { + /* first, check if we have a regexp */ + if (re!=NULL) { + size_t index = 0; + + str = JS_NewStringCopyZ(cx, entry->name); + if(!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &v)){ + /* don't report anything here */ + goto out; + } + /* not matched! */ + if (JSVAL_IS_NULL(v)) { + continue; + } + }else + if (func!=NULL) { + str = JS_NewStringCopyZ(cx, entry->name); + args[0] = STRING_TO_JSVAL(str); + if(!JS_CallFunction(cx, obj, func, 1, args, &v)){ + goto out; + } + + if (v==JSVAL_FALSE) { + continue; + } + } + + filePath = js_combinePath(cx, file->path, (char*)entry->name); + + eachFile = js_NewFileObject(cx, filePath); + JS_free(cx, filePath); + if (!eachFile){ + JS_ReportWarning(cx, "File %s cannot be retrieved", filePath); + continue; + } + v = OBJECT_TO_JSVAL(eachFile); + JS_SetElement(cx, array, len, &v); + JS_SetProperty(cx, array, entry->name, &v); + len++; + } + + if(PR_CloseDir(dir)!=PR_SUCCESS){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "close", file->path); + goto out; + } + *rval = OBJECT_TO_JSVAL(array); + return JS_TRUE; +out: + *rval = JSVAL_NULL; + return JS_FALSE; +} + +static JSBool +file_mkdir(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + + SECURITY_CHECK(cx, NULL, "mkdir", file); + JSFILE_CHECK_ONE_ARG("mkdir"); + JSFILE_CHECK_NATIVE("mkdir"); + + /* if the current file is not a directory, find out the directory name */ + if (!js_isDirectory(cx, file)) { + char *dir = js_fileDirectoryName(cx, file->path); + JSObject *dirObj = js_NewFileObject(cx, dir); + + JS_free(cx, dir); + + /* call file_mkdir with the right set of parameters if needed */ + if (file_mkdir(cx, dirObj, argc, argv, rval)) + return JS_TRUE; + else + goto out; + }else{ + char *dirName = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + char *fullName; + + fullName = js_combinePath(cx, file->path, dirName); + if (PR_MkDir(fullName, 0755)==PR_SUCCESS){ + *rval = JSVAL_TRUE; + JS_free(cx, fullName); + return JS_TRUE; + }else{ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "mkdir", fullName); + JS_free(cx, fullName); + goto out; + } + } +out: + *rval = JSVAL_FALSE; + return JS_FALSE; +} + +static JSBool +file_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval*rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + JSString *str; + + str = JS_NewStringCopyZ(cx, file->path); + if (!str) + return JS_FALSE; + *rval = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +file_toURL(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + char url[MAX_PATH_LENGTH]; + jschar *urlChars; + size_t len; + JSString *str; + + JSFILE_CHECK_NATIVE("toURL"); + + sprintf(url, "file://%s", file->path); + + len = strlen(url); + urlChars = js_InflateString(cx, url, &len); + if (!urlChars) + return JS_FALSE; + str = js_NewString(cx, urlChars, len); + if (!str) { + JS_free(cx, urlChars); + return JS_FALSE; + } + *rval = STRING_TO_JSVAL(str); + + /* TODO: js_escape in jsstr.h may go away at some point */ + return js_str_escape(cx, obj, 0, rval, rval); + +out: + *rval = JSVAL_VOID; + return JS_FALSE; +} + + +static void +file_finalize(JSContext *cx, JSObject *obj) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + + if(file) { + /* Close the file before exiting. */ + if(file->isOpen && !file->isNative) { + jsval vp; + file_close(cx, obj, 0, NULL, &vp); + } + + if (file->path) + JS_free(cx, file->path); + + JS_free(cx, file); + } +} + +/* + Allocates memory for the file object, sets fields to defaults. +*/ +static JSFile* +file_init(JSContext *cx, JSObject *obj, char *bytes) +{ + JSFile *file; + + file = JS_malloc(cx, sizeof *file); + if (!file) + return NULL; + memset(file, 0 , sizeof *file); + + js_ResetAttributes(file); + + file->path = RESOLVE_PATH(cx, bytes); + + if (!JS_SetPrivate(cx, obj, file)) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_SET_PRIVATE_FILE, file->path); + JS_free(cx, file); + return NULL; + } + + return file; +} + +/* Returns a JSObject. This function is globally visible */ +JS_PUBLIC_API(JSObject*) +js_NewFileObject(JSContext *cx, char *filename) +{ + JSObject *obj; + JSFile *file; + + obj = JS_NewObject(cx, &js_FileClass, NULL, NULL); + if (!obj){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OBJECT_CREATION_FAILED, "js_NewFileObject"); + return NULL; + } + file = file_init(cx, obj, filename); + if(!file) return NULL; + return obj; +} + +/* Internal function, used for cases which NSPR file support doesn't cover */ +JSObject* +js_NewFileObjectFromFILE(JSContext *cx, FILE *nativehandle, char *filename, + int32 mode, JSBool open, JSBool randomAccess) +{ + JSObject *obj; + JSFile *file; + + obj = JS_NewObject(cx, &js_FileClass, NULL, NULL); + if (!obj){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OBJECT_CREATION_FAILED, "js_NewFileObjectFromFILE"); + return NULL; + } + file = file_init(cx, obj, filename); + if(!file) return NULL; + + file->nativehandle = nativehandle; + + /* free result of RESOLVE_PATH from file_init. */ + JS_ASSERT(file->path != NULL); + JS_free(cx, file->path); + + file->path = strdup(filename); + file->isOpen = open; + file->mode = mode; + file->hasRandomAccess = randomAccess; + file->isNative = JS_TRUE; + return obj; +} + +/* + Real file constructor that is called from JavaScript. + Basically, does error processing and calls file_init. +*/ +static JSBool +file_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + JSString *str; + JSFile *file; + + if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { + /* Replace obj with a new File object. */ + obj = JS_NewObject(cx, &js_FileClass, NULL, NULL); + if (!obj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(obj); + } + + str = (argc == 0) + ? JS_InternString(cx, "") + : JS_ValueToString(cx, argv[0]); + + if (!str) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_FIRST_ARGUMENT_CONSTRUCTOR_NOT_STRING_ERROR, + argv[0]); + return JS_FALSE; + } + + file = file_init(cx, obj, JS_GetStringBytes(str)); + if (!file) + return JS_FALSE; + + SECURITY_CHECK(cx, NULL, "constructor", file); + + return JS_TRUE; +} + +/* -------------------- File methods and properties ------------------------- */ +static JSFunctionSpec file_functions[] = { + { "open", file_open, 0}, + { "close", file_close, 0}, + { "remove", file_remove, 0}, + { "copyTo", file_copyTo, 0}, + { "renameTo", file_renameTo, 0}, + { "flush", file_flush, 0}, + { "seek", file_seek, 0}, + { "read", file_read, 0}, + { "readln", file_readln, 0}, + { "readAll", file_readAll, 0}, + { "write", file_write, 0}, + { "writeln", file_writeln, 0}, + { "writeAll", file_writeAll, 0}, + { "list", file_list, 0}, + { "mkdir", file_mkdir, 0}, + { "toString", file_toString, 0}, + { "toURL", file_toURL, 0}, + {0} +}; + +enum file_tinyid { + FILE_LENGTH = -2, + FILE_PARENT = -3, + FILE_PATH = -4, + FILE_NAME = -5, + FILE_ISDIR = -6, + FILE_ISFILE = -7, + FILE_EXISTS = -8, + FILE_CANREAD = -9, + FILE_CANWRITE = -10, + FILE_OPEN = -11, + FILE_TYPE = -12, + FILE_MODE = -13, + FILE_CREATED = -14, + FILE_MODIFIED = -15, + FILE_SIZE = -16, + FILE_RANDOMACCESS = -17, + FILE_POSITION = -18, + FILE_APPEND = -19, + FILE_REPLACE = -20, + FILE_AUTOFLUSH = -21, + FILE_ISNATIVE = -22, +}; + +static JSPropertySpec file_props[] = { + {"length", FILE_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"parent", FILE_PARENT, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"path", FILE_PATH, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"name", FILE_NAME, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"isDirectory", FILE_ISDIR, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"isFile", FILE_ISFILE, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"exists", FILE_EXISTS, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"canRead", FILE_CANREAD, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"canWrite", FILE_CANWRITE, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"canAppend", FILE_APPEND, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"canReplace", FILE_REPLACE, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"isOpen", FILE_OPEN, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"type", FILE_TYPE, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"mode", FILE_MODE, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"creationTime", FILE_CREATED, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"lastModified", FILE_MODIFIED, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"size", FILE_SIZE, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"hasRandomAccess", FILE_RANDOMACCESS, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"hasAutoFlush", FILE_AUTOFLUSH, JSPROP_ENUMERATE | JSPROP_READONLY }, + {"position", FILE_POSITION, JSPROP_ENUMERATE }, + {"isNative", FILE_ISNATIVE, JSPROP_ENUMERATE | JSPROP_READONLY }, + {0} +}; + +/* ------------------------- Property getter/setter ------------------------- */ +static JSBool +file_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + char *bytes; + JSString *str; + jsint tiny; + PRFileInfo info; + JSBool flag; + PRExplodedTime expandedTime; + + tiny = JSVAL_TO_INT(id); + if (!file) + return JS_TRUE; + + switch (tiny) { + case FILE_PARENT: + SECURITY_CHECK(cx, NULL, "parent", file); + if (!js_parent(cx, file, vp)) + return JS_FALSE; + break; + case FILE_PATH: + str = JS_NewStringCopyZ(cx, file->path); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + break; + case FILE_NAME: + if (!js_name(cx, file, vp)) + return JS_FALSE; + break; + case FILE_ISDIR: + SECURITY_CHECK(cx, NULL, "isDirectory", file); + *vp = BOOLEAN_TO_JSVAL(js_isDirectory(cx, file)); + break; + case FILE_ISFILE: + SECURITY_CHECK(cx, NULL, "isFile", file); + *vp = BOOLEAN_TO_JSVAL(js_isFile(cx, file)); + break; + case FILE_EXISTS: + SECURITY_CHECK(cx, NULL, "exists", file); + *vp = BOOLEAN_TO_JSVAL(js_exists(cx, file)); + break; + case FILE_ISNATIVE: + SECURITY_CHECK(cx, NULL, "isNative", file); + *vp = BOOLEAN_TO_JSVAL(file->isNative); + break; + case FILE_CANREAD: + SECURITY_CHECK(cx, NULL, "canRead", file); + *vp = BOOLEAN_TO_JSVAL(js_canRead(cx, file)); + break; + case FILE_CANWRITE: + SECURITY_CHECK(cx, NULL, "canWrite", file); + *vp = BOOLEAN_TO_JSVAL(js_canWrite(cx, file)); + break; + case FILE_OPEN: + SECURITY_CHECK(cx, NULL, "isOpen", file); + *vp = BOOLEAN_TO_JSVAL(file->isOpen); + break; + case FILE_APPEND : + SECURITY_CHECK(cx, NULL, "canAppend", file); + JSFILE_CHECK_OPEN("canAppend"); + *vp = BOOLEAN_TO_JSVAL(!file->isNative && + (file->mode&PR_APPEND)==PR_APPEND); + break; + case FILE_REPLACE : + SECURITY_CHECK(cx, NULL, "canReplace", file); + JSFILE_CHECK_OPEN("canReplace"); + *vp = BOOLEAN_TO_JSVAL(!file->isNative && + (file->mode&PR_TRUNCATE)==PR_TRUNCATE); + break; + case FILE_AUTOFLUSH : + SECURITY_CHECK(cx, NULL, "hasAutoFlush", file); + JSFILE_CHECK_OPEN("hasAutoFlush"); + *vp = BOOLEAN_TO_JSVAL(!file->isNative && file->hasAutoflush); + break; + case FILE_TYPE: + SECURITY_CHECK(cx, NULL, "type", file); + JSFILE_CHECK_OPEN("type"); + if(js_isDirectory(cx, file)){ + *vp = JSVAL_VOID; + break; + } + + switch (file->type) { + case ASCII: + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, asciistring)); + break; + case UTF8: + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, utfstring)); + break; + case UCS2: + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, unicodestring)); + break; + default: + JS_ReportWarning(cx, "Unsupported file type %d, proceeding", + file->type); + } + break; + case FILE_MODE: + SECURITY_CHECK(cx, NULL, "mode", file); + JSFILE_CHECK_OPEN("mode"); + bytes = JS_malloc(cx, MODE_SIZE); + bytes[0] = '\0'; + flag = JS_FALSE; + + if ((file->mode&PR_RDONLY)==PR_RDONLY) { + if (flag) strcat(bytes, ","); + strcat(bytes, "read"); + flag = JS_TRUE; + } + if ((file->mode&PR_WRONLY)==PR_WRONLY) { + if (flag) strcat(bytes, ","); + strcat(bytes, "write"); + flag = JS_TRUE; + } + if ((file->mode&PR_RDWR)==PR_RDWR) { + if (flag) strcat(bytes, ","); + strcat(bytes, "readWrite"); + flag = JS_TRUE; + } + if ((file->mode&PR_APPEND)==PR_APPEND) { + if (flag) strcat(bytes, ","); + strcat(bytes, "append"); + flag = JS_TRUE; + } + if ((file->mode&PR_CREATE_FILE)==PR_CREATE_FILE) { + if (flag) strcat(bytes, ","); + strcat(bytes, "create"); + flag = JS_TRUE; + } + if ((file->mode&PR_TRUNCATE)==PR_TRUNCATE) { + if (flag) strcat(bytes, ","); + strcat(bytes, "replace"); + flag = JS_TRUE; + } + if (file->hasAutoflush) { + if (flag) strcat(bytes, ","); + strcat(bytes, "hasAutoFlush"); + flag = JS_TRUE; + } + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, bytes)); + JS_free(cx, bytes); + break; + case FILE_CREATED: + SECURITY_CHECK(cx, NULL, "creationTime", file); + JSFILE_CHECK_NATIVE("creationTime"); + if(((file->isOpen)? + PR_GetOpenFileInfo(file->handle, &info): + PR_GetFileInfo(file->path, &info))!=PR_SUCCESS){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path); + goto out; + } + + PR_ExplodeTime(info.creationTime, PR_LocalTimeParameters,&expandedTime); + *vp = OBJECT_TO_JSVAL(js_NewDateObject(cx, expandedTime.tm_year, + expandedTime.tm_month, + expandedTime.tm_mday, + expandedTime.tm_hour, + expandedTime.tm_min, + expandedTime.tm_sec)); + break; + case FILE_MODIFIED: + SECURITY_CHECK(cx, NULL, "lastModified", file); + JSFILE_CHECK_NATIVE("lastModified"); + if(((file->isOpen)? + PR_GetOpenFileInfo(file->handle, &info): + PR_GetFileInfo(file->path, &info))!=PR_SUCCESS){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path); + goto out; + } + + PR_ExplodeTime(info.modifyTime, PR_LocalTimeParameters, &expandedTime); + *vp = OBJECT_TO_JSVAL(js_NewDateObject(cx, expandedTime.tm_year, + expandedTime.tm_month, + expandedTime.tm_mday, + expandedTime.tm_hour, + expandedTime.tm_min, + expandedTime.tm_sec)); + break; + case FILE_SIZE: + SECURITY_CHECK(cx, NULL, "size", file); + *vp = js_size(cx, file); + break; + case FILE_LENGTH: + SECURITY_CHECK(cx, NULL, "length", file); + JSFILE_CHECK_NATIVE("length"); + + if (js_isDirectory(cx, file)) { /* XXX debug me */ + PRDir *dir; + PRDirEntry *entry; + jsint count = 0; + + if(!(dir = PR_OpenDir(file->path))){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_OPEN_DIR, file->path); + goto out; + } + + while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH))) { + count++; + } + + if(!PR_CloseDir(dir)){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_OP_FAILED, "close", file->path); + + goto out; + } + + *vp = INT_TO_JSVAL(count); + break; + }else{ + /* return file size */ + *vp = js_size(cx, file); + } + break; + case FILE_RANDOMACCESS: + SECURITY_CHECK(cx, NULL, "hasRandomAccess", file); + JSFILE_CHECK_OPEN("hasRandomAccess"); + *vp = BOOLEAN_TO_JSVAL(file->hasRandomAccess); + break; + case FILE_POSITION: + SECURITY_CHECK(cx, NULL, "position", file); + JSFILE_CHECK_NATIVE("position"); + JSFILE_CHECK_OPEN("position"); + + if(!file->hasRandomAccess){ + JS_ReportWarning(cx, "File %s doesn't support random access, can't report the position, proceeding"); + *vp = JSVAL_VOID; + break; + } + + if (file->isOpen && js_isFile(cx, file)) { + int pos = PR_Seek(file->handle, 0, PR_SEEK_CUR); + if(pos!=-1){ + *vp = INT_TO_JSVAL(pos); + }else{ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_REPORT_POSITION, file->path); + goto out; + } + }else { + JS_ReportWarning(cx, "File %s is closed or not a plain file," + " can't report position, proceeding"); + goto out; + } + break; + default: + SECURITY_CHECK(cx, NULL, "file_access", file); + + /* this is some other property -- try to use the dir["file"] syntax */ + if (js_isDirectory(cx, file)) { + PRDir *dir = NULL; + PRDirEntry *entry = NULL; + char *prop_name; + + str = JS_ValueToString(cx, id); + if (!str) + return JS_FALSE; + + prop_name = JS_GetStringBytes(str); + + /* no native files past this point */ + dir = PR_OpenDir(file->path); + if(!dir) { + /* This is probably not a directory */ + JS_ReportWarning(cx, "Can't open directory %s", file->path); + return JS_FALSE; + } + + while ((entry = PR_ReadDir(dir, PR_SKIP_NONE)) != NULL) { + if (!strcmp(entry->name, prop_name)){ + bytes = js_combinePath(cx, file->path, prop_name); + *vp = OBJECT_TO_JSVAL(js_NewFileObject(cx, bytes)); + PR_CloseDir(dir); + JS_free(cx, bytes); + return !JSVAL_IS_NULL(*vp); + } + } + PR_CloseDir(dir); + } + } + return JS_TRUE; + +out: + return JS_FALSE; +} + +static JSBool +file_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + jsint slot; + + if (JSVAL_IS_STRING(id)){ + return JS_TRUE; + } + + slot = JSVAL_TO_INT(id); + + switch (slot) { + /* File.position = 10 */ + case FILE_POSITION: + SECURITY_CHECK(cx, NULL, "set_position", file); + JSFILE_CHECK_NATIVE("set_position"); + + if(!file->hasRandomAccess){ + JS_ReportWarning(cx, "File %s doesn't support random access, can't " + "report the position, proceeding"); + goto out; + } + + if (file->isOpen && js_isFile(cx, file)) { + int32 pos; + int32 offset; + + if (!JS_ValueToInt32(cx, *vp, &offset)){ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, "position", *vp); + goto out; + } + + pos = PR_Seek(file->handle, offset, PR_SEEK_SET); + + if(pos!=-1){ + *vp = INT_TO_JSVAL(pos); + }else{ + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_CANNOT_SET_POSITION, file->path); + goto out; + } + } else { + JS_ReportWarning(cx, "File %s is closed or not a file, can't set " + "position, proceeding", file->path); + goto out; + } + } + + return JS_TRUE; +out: + return JS_FALSE; +} + +/* + File.currentDir = new File("D:\") or File.currentDir = "D:\" +*/ +static JSBool +file_currentDirSetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSFile *file; + + file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); + + /* Look at the rhs and extract a file object from it */ + if (JSVAL_IS_OBJECT(*vp)) { + if (JS_InstanceOf(cx, obj, &js_FileClass, NULL)) { + /* Braindamaged rhs -- just return the old value */ + if (file && (!js_exists(cx, file) || !js_isDirectory(cx, file))) { + JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, vp); + return JS_FALSE; + } else { + chdir(file->path); + return JS_TRUE; + } + } else { + return JS_FALSE; + } + } else { + JSObject *rhsObject; + char *path; + + path = JS_GetStringBytes(JS_ValueToString(cx, *vp)); + rhsObject = js_NewFileObject(cx, path); + if (!rhsObject) + return JS_FALSE; + + if (!file || !js_exists(cx, file) || !js_isDirectory(cx, file)){ + JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, vp); + } else { + *vp = OBJECT_TO_JSVAL(rhsObject); + chdir(path); + } + } + + return JS_TRUE; +} + +/* Declare class */ +JSClass js_FileClass = { + "File", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_File), + JS_PropertyStub, JS_PropertyStub, file_getProperty, file_setProperty, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, file_finalize +}; + +/* -------------------- Functions exposed to the outside -------------------- */ +JS_PUBLIC_API(JSObject*) +js_InitFileClass(JSContext *cx, JSObject* obj) +{ + JSObject *file, *ctor, *afile; + jsval vp; + char *currentdir; + char separator[2]; + + file = JS_InitClass(cx, obj, NULL, &js_FileClass, file_constructor, 1, + file_props, file_functions, NULL, NULL); + if (!file) { + JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, + JSFILEMSG_INIT_FAILED); + return NULL; + } + + ctor = JS_GetConstructor(cx, file); + if (!ctor) return NULL; + + /* Define CURRENTDIR property. We are doing this to get a + slash at the end of the current dir */ + afile = js_NewFileObject(cx, CURRENT_DIR); + currentdir = JS_malloc(cx, MAX_PATH_LENGTH); + currentdir = getcwd(currentdir, MAX_PATH_LENGTH); + afile = js_NewFileObject(cx, currentdir); + JS_free(cx, currentdir); + vp = OBJECT_TO_JSVAL(afile); + JS_DefinePropertyWithTinyId(cx, ctor, CURRENTDIR_PROPERTY, 0, vp, + JS_PropertyStub, file_currentDirSetter, + JSPROP_ENUMERATE | JSPROP_READONLY ); + + /* Define input */ + vp = OBJECT_TO_JSVAL(js_NewFileObjectFromFILE(cx, stdin, + STDINPUT_NAME, PR_RDONLY, JS_TRUE, JS_FALSE)); + JS_SetProperty(cx, ctor, "input", &vp); + + /* Define output */ + vp = OBJECT_TO_JSVAL(js_NewFileObjectFromFILE(cx, stdout, + STDOUTPUT_NAME, PR_WRONLY, JS_TRUE, JS_FALSE)); + JS_SetProperty(cx, ctor, "output", &vp); + + /* Define error */ + vp = OBJECT_TO_JSVAL(js_NewFileObjectFromFILE(cx, stderr, + STDERROR_NAME, PR_WRONLY, JS_TRUE, JS_FALSE)); + JS_SetProperty(cx, ctor, "error", &vp); + + separator[0] = FILESEPARATOR; + separator[1] = '\0'; + vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, separator)); + JS_DefinePropertyWithTinyId(cx, ctor, SEPARATOR_PROPERTY, 0, vp, + JS_PropertyStub, JS_PropertyStub, + JSPROP_ENUMERATE | JSPROP_READONLY ); + return file; +} +#endif /* JS_HAS_FILE_OBJECT */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.h new file mode 100644 index 0000000..78707e8 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.h @@ -0,0 +1,56 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _jsfile_h__ +#define _jsfile_h__ + +#if JS_HAS_FILE_OBJECT + +#include "jsobj.h" + +extern JS_PUBLIC_API(JSObject*) +js_InitFileClass(JSContext *cx, JSObject* obj); + +extern JS_PUBLIC_API(JSObject*) +js_NewFileObject(JSContext *cx, char *bytes); + +extern JSClass js_FileClass; + +#endif /* JS_HAS_FILE_OBJECT */ +#endif /* _jsfile_h__ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.msg b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.msg new file mode 100644 index 0000000..137b35d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfile.msg @@ -0,0 +1,90 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + Error messages for jsfile.c. See js.msg for format specification. +*/ + +MSG_DEF(JSFILEMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "") +MSG_DEF(JSFILEMSG_FILE_CONSTRUCTOR_UNDEFINED_ERROR, 1, 0, JSEXN_NONE, "File constructor is undefined") +MSG_DEF(JSFILEMSG_FILE_CURRENTDIR_UNDEFINED_ERROR, 2, 0, JSEXN_NONE, "File.currentDir is undefined") +MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_OPEN_NOT_STRING_ERROR, 3, 1, JSEXN_NONE, "The first argument {0} to file.open must be a string") +MSG_DEF(JSFILEMSG_SECOND_ARGUMENT_OPEN_NOT_STRING_ERROR, 4, 0, JSEXN_NONE, "The second argument to file.open must be a string") +MSG_DEF(JSFILEMSG_CANNOT_COPY_FILE_OPEN_FOR_WRITING_ERROR, 5, 1, JSEXN_NONE, "Cannot copy file {0} open for writing") +MSG_DEF(JSFILEMSG_CANNOT_ACCESS_FILE_INFO_ERROR, 6, 1, JSEXN_NONE, "Cannot access file information for {0}") +MSG_DEF(JSFILEMSG_COPY_READ_ERROR, 7, 1, JSEXN_NONE, "An error occured while attempting to read a file {0} to copy") +MSG_DEF(JSFILEMSG_COPY_WRITE_ERROR, 8, 1, JSEXN_NONE, "An error occured while attempting to copy into file {0}") +MSG_DEF(JSFILEMSG_EXPECTS_ONE_ARG_ERROR, 9, 0, JSEXN_NONE, "Operation {0} expects one argument, not {1}") +MSG_DEF(JSFILEMSG_CANNOT_FLUSH_CLOSE_FILE_ERROR, 10, 1, JSEXN_NONE, "Cannot flush closed file {0}") +MSG_DEF(JSFILEMSG_CANNOT_OPEN_WRITING_ERROR, 11, 1, JSEXN_NONE, "Cannot open file {0} for writing") +MSG_DEF(JSFILEMSG_WRITEALL_EXPECTS_ONE_ARG_ERROR, 12, 0, JSEXN_NONE, "writeAll expects one argument") +MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_WRITEALL_NOT_ARRAY_ERROR, 13, 0, JSEXN_NONE, "writeAll expects an array as an argument") +MSG_DEF(JSFILEMSG_UNUSED0, 14, 0, JSEXN_NONE, "Unused error message slot") +MSG_DEF(JSFILEMSG_CANNOT_OPEN_FILE_ERROR, 15, 1, JSEXN_NONE, "Cannot open file {0}") +MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_CONSTRUCTOR_NOT_STRING_ERROR, 16, 1, JSEXN_NONE, "The argument to the File constructor {0} must be a string") +MSG_DEF(JSFILEMSG_BIDIRECTIONAL_PIPE_NOT_SUPPORTED, 17, 0, JSEXN_NONE, "Bidirectional pipes are not supported") +MSG_DEF(JSFILEMSG_OPEN_MODE_NOT_SUPPORTED_WITH_PIPES, 18, 2, JSEXN_NONE, "The opening mode you have chosen {0} is not supported by the pipe you are trying to open: {1}") +MSG_DEF(JSFILEMSG_OPEN_FAILED, 19, 1, JSEXN_NONE, "open on file {0} failed") +MSG_DEF(JSFILEMSG_CLOSE_FAILED, 20, 1, JSEXN_NONE, "close on file {0} failed") +MSG_DEF(JSFILEMSG_PCLOSE_FAILED, 21, 1, JSEXN_NONE, "pclose on file {0} failed") +MSG_DEF(JSFILEMSG_REMOVE_FAILED, 22, 1, JSEXN_NONE, "remove on file {0} failed") +MSG_DEF(JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, 23, 1, JSEXN_NONE, "Cannot access file status for {0}") +MSG_DEF(JSFILEMSG_RENAME_FAILED, 24, 2, JSEXN_NONE, "Cannot rename {0} to {1}") +MSG_DEF(JSFILEMSG_WRITE_FAILED, 25, 1, JSEXN_NONE, "Write failed on file {0}") +MSG_DEF(JSFILEMSG_READ_FAILED, 26, 1, JSEXN_NONE, "Read failed on file {0}") +MSG_DEF(JSFILEMSG_SKIP_FAILED, 27, 1, JSEXN_NONE, "Skip failed on file {0}") +MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_FUNCTION_OR_REGEX, 28, 1, JSEXN_NONE, "The first argument to file.list must be a function or a regex") +MSG_DEF(JSFILEMSG_CANNOT_DO_LIST_ON_A_FILE, 29, 1, JSEXN_NONE, "{0} must be a directory, cannot do list") +MSG_DEF(JSFILEMSG_NATIVE_OPERATION_IS_NOT_SUPPORTED, 30, 2, JSEXN_NONE, "Native operation {0} is not supported on {1}") +MSG_DEF(JSFILEMSG_CANNOT_SET_PRIVATE_FILE, 31, 1, JSEXN_NONE, "Cannot set private data for file {0}") +MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, 32, 2, JSEXN_NONE, "First argument to {0} must be a number, not {1}") +MSG_DEF(JSFILEMSG_CANNOT_WRITE, 33, 1, JSEXN_NONE, "Cannot write to {0}, file mode is different") +MSG_DEF(JSFILEMSG_CANNOT_READ, 34, 1, JSEXN_NONE, "Cannot read from {0}, file mode is different") +MSG_DEF(JSFILEMSG_CANNOT_FLUSH, 35, 1, JSEXN_NONE, "Flush failed on {0}") +MSG_DEF(JSFILEMSG_OP_FAILED, 36, 1, JSEXN_NONE, "File operation {0} failed") +MSG_DEF(JSFILEMSG_FILE_MUST_BE_OPEN, 37, 1, JSEXN_NONE, "File must be open for {0}") +MSG_DEF(JSFILEMSG_FILE_MUST_BE_CLOSED, 38, 1, JSEXN_NONE, "File must be closed for {0}") +MSG_DEF(JSFILEMSG_NO_RANDOM_ACCESS, 39, 1, JSEXN_NONE, "File {0} doesn't allow random access") +MSG_DEF(JSFILEMSG_OBJECT_CREATION_FAILED, 40, 1, JSEXN_NONE, "Couldn't create {0}") +MSG_DEF(JSFILEMSG_CANNOT_OPEN_DIR, 41, 1, JSEXN_NONE, "Couldn't open directory {0}") +MSG_DEF(JSFILEMSG_CANNOT_REPORT_POSITION, 42, 1, JSEXN_NONE, "Couldn't report position for {0}") +MSG_DEF(JSFILEMSG_CANNOT_SET_POSITION, 43, 1, JSEXN_NONE, "Couldn't set position for {0}") +MSG_DEF(JSFILEMSG_INIT_FAILED, 44, 0, JSEXN_NONE, "File class initialization failed") + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfun.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfun.cpp new file mode 100644 index 0000000..a492bcc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfun.cpp @@ -0,0 +1,2706 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS function support. + */ +#include "jsstddef.h" +#include +#include "jstypes.h" +#include "jsbit.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsexn.h" +#include "jsstaticcheck.h" + +#if JS_HAS_GENERATORS +# include "jsiter.h" +#endif + +#if JS_HAS_XDR +# include "jsxdrapi.h" +#endif + +/* Generic function/call/arguments tinyids -- also reflected bit numbers. */ +enum { + CALL_ARGUMENTS = -1, /* predefined arguments local variable */ + ARGS_LENGTH = -2, /* number of actual args, arity if inactive */ + ARGS_CALLEE = -3, /* reference from arguments to active funobj */ + FUN_ARITY = -4, /* number of formal parameters; desired argc */ + FUN_NAME = -5, /* function name, "" if anonymous */ + FUN_CALLER = -6 /* Function.prototype.caller, backward compat */ +}; + +#if JSFRAME_OVERRIDE_BITS < 8 +# error "not enough override bits in JSStackFrame.flags!" +#endif + +#define TEST_OVERRIDE_BIT(fp, tinyid) \ + ((fp)->flags & JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1))) + +#define SET_OVERRIDE_BIT(fp, tinyid) \ + ((fp)->flags |= JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1))) + +JSBool +js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp) +{ + JSObject *argsobj; + + if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) { + JS_ASSERT(fp->callobj); + return OBJ_GET_PROPERTY(cx, fp->callobj, + ATOM_TO_JSID(cx->runtime->atomState + .argumentsAtom), + vp); + } + argsobj = js_GetArgsObject(cx, fp); + if (!argsobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(argsobj); + return JS_TRUE; +} + +static JSBool +MarkArgDeleted(JSContext *cx, JSStackFrame *fp, uintN slot) +{ + JSObject *argsobj; + jsval bmapval, bmapint; + size_t nbits, nbytes; + jsbitmap *bitmap; + + argsobj = fp->argsobj; + (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval); + nbits = fp->argc; + JS_ASSERT(slot < nbits); + if (JSVAL_IS_VOID(bmapval)) { + if (nbits <= JSVAL_INT_BITS) { + bmapint = 0; + bitmap = (jsbitmap *) &bmapint; + } else { + nbytes = JS_HOWMANY(nbits, JS_BITS_PER_WORD) * sizeof(jsbitmap); + bitmap = (jsbitmap *) JS_malloc(cx, nbytes); + if (!bitmap) + return JS_FALSE; + memset(bitmap, 0, nbytes); + bmapval = PRIVATE_TO_JSVAL(bitmap); + JS_SetReservedSlot(cx, argsobj, 0, bmapval); + } + } else { + if (nbits <= JSVAL_INT_BITS) { + bmapint = JSVAL_TO_INT(bmapval); + bitmap = (jsbitmap *) &bmapint; + } else { + bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval); + } + } + JS_SET_BIT(bitmap, slot); + if (bitmap == (jsbitmap *) &bmapint) { + bmapval = INT_TO_JSVAL(bmapint); + JS_SetReservedSlot(cx, argsobj, 0, bmapval); + } + return JS_TRUE; +} + +/* NB: Infallible predicate, false does not mean error/exception. */ +static JSBool +ArgWasDeleted(JSContext *cx, JSStackFrame *fp, uintN slot) +{ + JSObject *argsobj; + jsval bmapval, bmapint; + jsbitmap *bitmap; + + argsobj = fp->argsobj; + (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval); + if (JSVAL_IS_VOID(bmapval)) + return JS_FALSE; + if (fp->argc <= JSVAL_INT_BITS) { + bmapint = JSVAL_TO_INT(bmapval); + bitmap = (jsbitmap *) &bmapint; + } else { + bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval); + } + return JS_TEST_BIT(bitmap, slot) != 0; +} + +JSBool +js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp) +{ + jsval val; + JSObject *obj; + uintN slot; + + if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) { + JS_ASSERT(fp->callobj); + if (!OBJ_GET_PROPERTY(cx, fp->callobj, + ATOM_TO_JSID(cx->runtime->atomState + .argumentsAtom), + &val)) { + return JS_FALSE; + } + if (JSVAL_IS_PRIMITIVE(val)) { + obj = js_ValueToNonNullObject(cx, val); + if (!obj) + return JS_FALSE; + } else { + obj = JSVAL_TO_OBJECT(val); + } + return OBJ_GET_PROPERTY(cx, obj, id, vp); + } + + *vp = JSVAL_VOID; + if (JSID_IS_INT(id)) { + slot = (uintN) JSID_TO_INT(id); + if (slot < fp->argc) { + if (fp->argsobj && ArgWasDeleted(cx, fp, slot)) + return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); + *vp = fp->argv[slot]; + } else { + /* + * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share + * storage between the formal parameter and arguments[k] for all + * fp->argc <= k && k < fp->fun->nargs. For example, in + * + * function f(x) { x = 42; return arguments[0]; } + * f(); + * + * the call to f should return undefined, not 42. If fp->argsobj + * is null at this point, as it would be in the example, return + * undefined in *vp. + */ + if (fp->argsobj) + return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); + } + } else { + if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { + if (fp->argsobj && TEST_OVERRIDE_BIT(fp, ARGS_LENGTH)) + return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); + *vp = INT_TO_JSVAL((jsint) fp->argc); + } + } + return JS_TRUE; +} + +JSObject * +js_GetArgsObject(JSContext *cx, JSStackFrame *fp) +{ + JSObject *argsobj, *global, *parent; + + /* + * We must be in a function activation; the function must be lightweight + * or else fp must have a variable object. + */ + JS_ASSERT(fp->fun && (!(fp->fun->flags & JSFUN_HEAVYWEIGHT) || fp->varobj)); + + /* Skip eval and debugger frames. */ + while (fp->flags & JSFRAME_SPECIAL) + fp = fp->down; + + /* Create an arguments object for fp only if it lacks one. */ + argsobj = fp->argsobj; + if (argsobj) + return argsobj; + + /* Link the new object to fp so it can get actual argument values. */ + argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, NULL, 0); + if (!argsobj || !JS_SetPrivate(cx, argsobj, fp)) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + return NULL; + } + + /* + * Give arguments an intrinsic scope chain link to fp's global object. + * Since the arguments object lacks a prototype because js_ArgumentsClass + * is not initialized, js_NewObject won't assign a default parent to it. + * + * Therefore if arguments is used as the head of an eval scope chain (via + * a direct or indirect call to eval(program, arguments)), any reference + * to a standard class object in the program will fail to resolve due to + * js_GetClassPrototype not being able to find a global object containing + * the standard prototype by starting from arguments and following parent. + */ + global = fp->scopeChain; + while ((parent = OBJ_GET_PARENT(cx, global)) != NULL) + global = parent; + STOBJ_SET_PARENT(argsobj, global); + fp->argsobj = argsobj; + return argsobj; +} + +static JSBool +args_enumerate(JSContext *cx, JSObject *obj); + +JS_FRIEND_API(JSBool) +js_PutArgsObject(JSContext *cx, JSStackFrame *fp) +{ + JSObject *argsobj; + jsval bmapval, rval; + JSBool ok; + JSRuntime *rt; + + /* + * Reuse args_enumerate here to reflect fp's actual arguments as indexed + * elements of argsobj. Do this first, before clearing and freeing the + * deleted argument slot bitmap, because args_enumerate depends on that. + */ + argsobj = fp->argsobj; + ok = args_enumerate(cx, argsobj); + + /* + * Now clear the deleted argument number bitmap slot and free the bitmap, + * if one was actually created due to 'delete arguments[0]' or similar. + */ + (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval); + if (!JSVAL_IS_VOID(bmapval)) { + JS_SetReservedSlot(cx, argsobj, 0, JSVAL_VOID); + if (fp->argc > JSVAL_INT_BITS) + JS_free(cx, JSVAL_TO_PRIVATE(bmapval)); + } + + /* + * Now get the prototype properties so we snapshot fp->fun and fp->argc + * before fp goes away. + */ + rt = cx->runtime; + ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom), + &rval); + ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom), + &rval); + ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom), + &rval); + ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom), + &rval); + + /* + * Clear the private pointer to fp, which is about to go away (js_Invoke). + * Do this last because the args_enumerate and js_GetProperty calls above + * need to follow the private slot to find fp. + */ + ok &= JS_SetPrivate(cx, argsobj, NULL); + fp->argsobj = NULL; + return ok; +} + +static JSBool +args_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + jsint slot; + JSStackFrame *fp; + + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + fp = (JSStackFrame *) + JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); + if (!fp) + return JS_TRUE; + JS_ASSERT(fp->argsobj); + + slot = JSVAL_TO_INT(id); + switch (slot) { + case ARGS_CALLEE: + case ARGS_LENGTH: + SET_OVERRIDE_BIT(fp, slot); + break; + + default: + if ((uintN)slot < fp->argc && !MarkArgDeleted(cx, fp, slot)) + return JS_FALSE; + break; + } + return JS_TRUE; +} + +static JSBool +args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + jsint slot; + JSStackFrame *fp; + + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + fp = (JSStackFrame *) + JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); + if (!fp) + return JS_TRUE; + JS_ASSERT(fp->argsobj); + + slot = JSVAL_TO_INT(id); + switch (slot) { + case ARGS_CALLEE: + if (!TEST_OVERRIDE_BIT(fp, slot)) + *vp = OBJECT_TO_JSVAL(fp->callee); + break; + + case ARGS_LENGTH: + if (!TEST_OVERRIDE_BIT(fp, slot)) + *vp = INT_TO_JSVAL((jsint)fp->argc); + break; + + default: + if ((uintN)slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) + *vp = fp->argv[slot]; + break; + } + return JS_TRUE; +} + +static JSBool +args_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSStackFrame *fp; + jsint slot; + + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + fp = (JSStackFrame *) + JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); + if (!fp) + return JS_TRUE; + JS_ASSERT(fp->argsobj); + + slot = JSVAL_TO_INT(id); + switch (slot) { + case ARGS_CALLEE: + case ARGS_LENGTH: + SET_OVERRIDE_BIT(fp, slot); + break; + + default: + if (FUN_INTERPRETED(fp->fun) && + (uintN)slot < fp->argc && + !ArgWasDeleted(cx, fp, slot)) { + fp->argv[slot] = *vp; + } + break; + } + return JS_TRUE; +} + +static JSBool +args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp) +{ + JSStackFrame *fp; + uintN slot; + JSString *str; + JSAtom *atom; + intN tinyid; + jsval value; + + *objp = NULL; + fp = (JSStackFrame *) + JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); + if (!fp) + return JS_TRUE; + JS_ASSERT(fp->argsobj); + + if (JSVAL_IS_INT(id)) { + slot = JSVAL_TO_INT(id); + if (slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) { + /* XXX ECMA specs DontEnum, contrary to other array-like objects */ + if (!js_DefineProperty(cx, obj, INT_JSVAL_TO_JSID(id), + fp->argv[slot], + args_getProperty, args_setProperty, + 0, NULL)) { + return JS_FALSE; + } + *objp = obj; + } + } else { + str = JSVAL_TO_STRING(id); + atom = cx->runtime->atomState.lengthAtom; + if (str == ATOM_TO_STRING(atom)) { + tinyid = ARGS_LENGTH; + value = INT_TO_JSVAL(fp->argc); + } else { + atom = cx->runtime->atomState.calleeAtom; + if (str == ATOM_TO_STRING(atom)) { + tinyid = ARGS_CALLEE; + value = OBJECT_TO_JSVAL(fp->callee); + } else { + atom = NULL; + + /* Quell GCC overwarnings. */ + tinyid = 0; + value = JSVAL_NULL; + } + } + + if (atom && !TEST_OVERRIDE_BIT(fp, tinyid)) { + if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value, + args_getProperty, args_setProperty, 0, + SPROP_HAS_SHORTID, tinyid, NULL)) { + return JS_FALSE; + } + *objp = obj; + } + } + + return JS_TRUE; +} + +static JSBool +args_enumerate(JSContext *cx, JSObject *obj) +{ + JSStackFrame *fp; + JSObject *pobj; + JSProperty *prop; + uintN slot, argc; + + fp = (JSStackFrame *) + JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); + if (!fp) + return JS_TRUE; + JS_ASSERT(fp->argsobj); + + /* + * Trigger reflection with value snapshot in args_resolve using a series + * of js_LookupProperty calls. We handle length, callee, and the indexed + * argument properties. We know that args_resolve covers all these cases + * and creates direct properties of obj, but that it may fail to resolve + * length or callee if overridden. + */ + if (!js_LookupProperty(cx, obj, + ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), + &pobj, &prop)) { + return JS_FALSE; + } + if (prop) + OBJ_DROP_PROPERTY(cx, pobj, prop); + + if (!js_LookupProperty(cx, obj, + ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), + &pobj, &prop)) { + return JS_FALSE; + } + if (prop) + OBJ_DROP_PROPERTY(cx, pobj, prop); + + argc = fp->argc; + for (slot = 0; slot < argc; slot++) { + if (!js_LookupProperty(cx, obj, INT_TO_JSID((jsint)slot), &pobj, &prop)) + return JS_FALSE; + if (prop) + OBJ_DROP_PROPERTY(cx, pobj, prop); + } + return JS_TRUE; +} + +#if JS_HAS_GENERATORS +/* + * If a generator-iterator's arguments or call object escapes, it needs to + * mark its generator object. + */ +static void +args_or_call_trace(JSTracer *trc, JSObject *obj) +{ + JSStackFrame *fp; + + fp = (JSStackFrame *) JS_GetPrivate(trc->context, obj); + if (fp && (fp->flags & JSFRAME_GENERATOR)) { + JS_CALL_OBJECT_TRACER(trc, FRAME_TO_GENERATOR(fp)->obj, + "FRAME_TO_GENERATOR(fp)->obj"); + } +} +#else +# define args_or_call_trace NULL +#endif + +/* + * The Arguments class is not initialized via JS_InitClass, and must not be, + * because its name is "Object". Per ECMA, that causes instances of it to + * delegate to the object named by Object.prototype. It also ensures that + * arguments.toString() returns "[object Object]". + * + * The JSClass functions below collaborate to lazily reflect and synchronize + * actual argument values, argument count, and callee function object stored + * in a JSStackFrame with their corresponding property values in the frame's + * arguments object. + */ +JSClass js_ArgumentsClass = { + js_Object_str, + JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), + JS_PropertyStub, args_delProperty, + args_getProperty, args_setProperty, + args_enumerate, (JSResolveOp) args_resolve, + JS_ConvertStub, JS_FinalizeStub, + NULL, NULL, + NULL, NULL, + NULL, NULL, + JS_CLASS_TRACE(args_or_call_trace), NULL +}; + +#define JSSLOT_SCRIPTED_FUNCTION (JSSLOT_PRIVATE + 1) +#define JSSLOT_CALL_ARGUMENTS (JSSLOT_PRIVATE + 2) +#define CALL_CLASS_FIXED_RESERVED_SLOTS 2 + +JSObject * +js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent) +{ + JSObject *callobj, *funobj; + + /* Create a call object for fp only if it lacks one. */ + JS_ASSERT(fp->fun); + callobj = fp->callobj; + if (callobj) + return callobj; + + /* The default call parent is its function's parent (static link). */ + if (!parent) { + funobj = fp->callee; + if (funobj) + parent = OBJ_GET_PARENT(cx, funobj); + } + + /* Create the call object and link it to its stack frame. */ + callobj = js_NewObject(cx, &js_CallClass, NULL, parent, 0); + if (!callobj) + return NULL; + + JS_SetPrivate(cx, callobj, fp); + STOBJ_SET_SLOT(callobj, JSSLOT_SCRIPTED_FUNCTION, + OBJECT_TO_JSVAL(FUN_OBJECT(fp->fun))); + fp->callobj = callobj; + + /* Make callobj be the scope chain and the variables object. */ + JS_ASSERT(fp->scopeChain == parent); + fp->scopeChain = callobj; + fp->varobj = callobj; + return callobj; +} + +JSFunction * +js_GetCallObjectFunction(JSObject *obj) +{ + jsval v; + + JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass); + v = STOBJ_GET_SLOT(obj, JSSLOT_SCRIPTED_FUNCTION); + if (JSVAL_IS_VOID(v)) { + /* Newborn or prototype object. */ + return NULL; + } + JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + return (JSFunction *) JSVAL_TO_OBJECT(v); +} + +JS_FRIEND_API(JSBool) +js_PutCallObject(JSContext *cx, JSStackFrame *fp) +{ + JSObject *callobj; + JSBool ok; + JSFunction *fun; + uintN n; + JSScope *scope; + + /* + * Since for a call object all fixed slots happen to be taken, we can copy + * arguments and variables straight into JSObject.dslots. + */ + JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE == + 1 + CALL_CLASS_FIXED_RESERVED_SLOTS); + + callobj = fp->callobj; + if (!callobj) + return JS_TRUE; + + /* + * Get the arguments object to snapshot fp's actual argument values. + */ + ok = JS_TRUE; + if (fp->argsobj) { + if (!TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) { + STOBJ_SET_SLOT(callobj, JSSLOT_CALL_ARGUMENTS, + OBJECT_TO_JSVAL(fp->argsobj)); + } + ok &= js_PutArgsObject(cx, fp); + } + + fun = fp->fun; + JS_ASSERT(fun == js_GetCallObjectFunction(callobj)); + n = JS_GET_LOCAL_NAME_COUNT(fun); + if (n != 0) { + JS_LOCK_OBJ(cx, callobj); + n += JS_INITIAL_NSLOTS; + if (n > STOBJ_NSLOTS(callobj)) + ok &= js_ReallocSlots(cx, callobj, n, JS_TRUE); + scope = OBJ_SCOPE(callobj); + if (ok) { + memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval)); + memcpy(callobj->dslots + fun->nargs, fp->slots, + fun->u.i.nvars * sizeof(jsval)); + if (scope->object == callobj && n > scope->map.freeslot) + scope->map.freeslot = n; + } + JS_UNLOCK_SCOPE(cx, scope); + } + + /* + * Clear the private pointer to fp, which is about to go away (js_Invoke). + * Do this last because js_GetProperty calls above need to follow the + * private slot to find fp. + */ + JS_SetPrivate(cx, callobj, NULL); + fp->callobj = NULL; + return ok; +} + +static JSBool +call_enumerate(JSContext *cx, JSObject *obj) +{ + JSFunction *fun; + uintN n, i; + void *mark; + jsuword *names; + JSBool ok; + JSAtom *name; + JSObject *pobj; + JSProperty *prop; + + fun = js_GetCallObjectFunction(obj); + n = JS_GET_LOCAL_NAME_COUNT(fun); + if (n == 0) + return JS_TRUE; + + mark = JS_ARENA_MARK(&cx->tempPool); + + MUST_FLOW_THROUGH("out"); + names = js_GetLocalNameArray(cx, fun, &cx->tempPool); + if (!names) { + ok = JS_FALSE; + goto out; + } + + for (i = 0; i != n; ++i) { + name = JS_LOCAL_NAME_TO_ATOM(names[i]); + if (!name) + continue; + + /* + * Trigger reflection by looking up the name of the argument or + * variable. + */ + ok = js_LookupProperty(cx, obj, ATOM_TO_JSID(name), &pobj, &prop); + if (!ok) + goto out; + + /* + * At this point the call object always has a property corresponding + * to the local name because call_resolve creates the property using + * JSPROP_PERMANENT. + */ + JS_ASSERT(prop && pobj == obj); + OBJ_DROP_PROPERTY(cx, pobj, prop); + } + ok = JS_TRUE; + + out: + JS_ARENA_RELEASE(&cx->tempPool, mark); + return ok; +} + +typedef enum JSCallPropertyKind { + JSCPK_ARGUMENTS, + JSCPK_ARG, + JSCPK_VAR +} JSCallPropertyKind; + +static JSBool +CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp, + JSCallPropertyKind kind, JSBool setter) +{ + JSFunction *fun; + JSStackFrame *fp; + uintN i; + jsval *array; + + if (STOBJ_GET_CLASS(obj) != &js_CallClass) + return JS_TRUE; + + fun = js_GetCallObjectFunction(obj); + fp = (JSStackFrame *) JS_GetPrivate(cx, obj); + + if (kind == JSCPK_ARGUMENTS) { + if (setter) { + if (fp) + SET_OVERRIDE_BIT(fp, CALL_ARGUMENTS); + STOBJ_SET_SLOT(obj, JSSLOT_CALL_ARGUMENTS, *vp); + } else { + if (fp && !TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) { + JSObject *argsobj; + + argsobj = js_GetArgsObject(cx, fp); + if (!argsobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(argsobj); + } else { + *vp = STOBJ_GET_SLOT(obj, JSSLOT_CALL_ARGUMENTS); + } + } + return JS_TRUE; + } + + JS_ASSERT((int16) JSVAL_TO_INT(id) == JSVAL_TO_INT(id)); + i = (uint16) JSVAL_TO_INT(id); + JS_ASSERT_IF(kind == JSCPK_ARG, i < fun->nargs); + JS_ASSERT_IF(kind == JSCPK_VAR, i < fun->u.i.nvars); + + if (!fp) { + i += CALL_CLASS_FIXED_RESERVED_SLOTS; + if (kind == JSCPK_VAR) + i += fun->nargs; + else + JS_ASSERT(kind == JSCPK_ARG); + return setter + ? JS_SetReservedSlot(cx, obj, i, *vp) + : JS_GetReservedSlot(cx, obj, i, vp); + } + + if (kind == JSCPK_ARG) { + array = fp->argv; + } else { + JS_ASSERT(kind == JSCPK_VAR); + array = fp->slots; + } + if (setter) + array[i] = *vp; + else + *vp = array[i]; + return JS_TRUE; +} + +static JSBool +GetCallArguments(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return CallPropertyOp(cx, obj, id, vp, JSCPK_ARGUMENTS, JS_FALSE); +} + +static JSBool +SetCallArguments(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return CallPropertyOp(cx, obj, id, vp, JSCPK_ARGUMENTS, JS_TRUE); +} + +JSBool +js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, JS_FALSE); +} + +static JSBool +SetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, JS_TRUE); +} + +JSBool +js_GetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_FALSE); +} + +static JSBool +SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_TRUE); +} + +static JSBool +call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, + JSObject **objp) +{ + JSFunction *fun; + jsid id; + JSLocalKind localKind; + JSPropertyOp getter, setter; + uintN slot, attrs; + + if (!JSVAL_IS_STRING(idval)) + return JS_TRUE; + + fun = js_GetCallObjectFunction(obj); + if (!fun) + return JS_TRUE; + + if (!js_ValueToStringId(cx, idval, &id)) + return JS_FALSE; + + localKind = js_LookupLocal(cx, fun, JSID_TO_ATOM(id), &slot); + if (localKind != JSLOCAL_NONE) { + JS_ASSERT((uint16) slot == slot); + attrs = JSPROP_PERMANENT | JSPROP_SHARED; + if (localKind == JSLOCAL_ARG) { + JS_ASSERT(slot < fun->nargs); + getter = js_GetCallArg; + setter = SetCallArg; + } else { + JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST); + JS_ASSERT(slot < fun->u.i.nvars); + getter = js_GetCallVar; + setter = SetCallVar; + if (localKind == JSLOCAL_CONST) + attrs |= JSPROP_READONLY; + } + if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, getter, setter, + attrs, SPROP_HAS_SHORTID, (int16) slot, + NULL)) { + return JS_FALSE; + } + *objp = obj; + return JS_TRUE; + } + + /* + * Resolve arguments so that we never store a particular Call object's + * arguments object reference in a Call prototype's |arguments| slot. + */ + if (id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) { + if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, + GetCallArguments, SetCallArguments, + JSPROP_PERMANENT | JSPROP_SHARED, + 0, 0, NULL)) { + return JS_FALSE; + } + *objp = obj; + return JS_TRUE; + } + return JS_TRUE; +} + +static JSBool +call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) +{ + JSStackFrame *fp; + + if (type == JSTYPE_FUNCTION) { + fp = (JSStackFrame *) JS_GetPrivate(cx, obj); + if (fp) { + JS_ASSERT(fp->fun); + *vp = OBJECT_TO_JSVAL(fp->callee); + } + } + return JS_TRUE; +} + +static uint32 +call_reserveSlots(JSContext *cx, JSObject *obj) +{ + JSFunction *fun; + + fun = js_GetCallObjectFunction(obj); + return JS_GET_LOCAL_NAME_COUNT(fun); +} + +JS_FRIEND_DATA(JSClass) js_CallClass = { + js_Call_str, + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_FIXED_RESERVED_SLOTS) | + JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Call), + JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_PropertyStub, + call_enumerate, (JSResolveOp)call_resolve, + call_convert, JS_FinalizeStub, + NULL, NULL, + NULL, NULL, + NULL, NULL, + JS_CLASS_TRACE(args_or_call_trace), call_reserveSlots +}; + +static JSBool +fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + jsint slot; + JSFunction *fun; + JSStackFrame *fp; + JSSecurityCallbacks *callbacks; + + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + slot = JSVAL_TO_INT(id); + + /* + * Loop because getter and setter can be delegated from another class, + * but loop only for ARGS_LENGTH because we must pretend that f.length + * is in each function instance f, per ECMA-262, instead of only in the + * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED + * to make it appear so). + * + * This code couples tightly to the attributes for the function_props[] + * initializers above, and to js_SetProperty and js_HasOwnProperty. + * + * It's important to allow delegating objects, even though they inherit + * this getter (fun_getProperty), to override arguments, arity, caller, + * and name. If we didn't return early for slot != ARGS_LENGTH, we would + * clobber *vp with the native property value, instead of letting script + * override that value in delegating objects. + * + * Note how that clobbering is what simulates JSPROP_READONLY for all of + * the non-standard properties when the directly addressed object (obj) + * is a function object (i.e., when this loop does not iterate). + */ + while (!(fun = (JSFunction *) + JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) { + if (slot != ARGS_LENGTH) + return JS_TRUE; + obj = OBJ_GET_PROTO(cx, obj); + if (!obj) + return JS_TRUE; + } + + /* Find fun's top-most activation record. */ + for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL)); + fp = fp->down) { + continue; + } + + switch (slot) { + case CALL_ARGUMENTS: + /* Warn if strict about f.arguments or equivalent unqualified uses. */ + if (!JS_ReportErrorFlagsAndNumber(cx, + JSREPORT_WARNING | JSREPORT_STRICT, + js_GetErrorMessage, NULL, + JSMSG_DEPRECATED_USAGE, + js_arguments_str)) { + return JS_FALSE; + } + if (fp) { + if (!js_GetArgsValue(cx, fp, vp)) + return JS_FALSE; + } else { + *vp = JSVAL_NULL; + } + break; + + case ARGS_LENGTH: + case FUN_ARITY: + *vp = INT_TO_JSVAL((jsint)fun->nargs); + break; + + case FUN_NAME: + *vp = fun->atom + ? ATOM_KEY(fun->atom) + : STRING_TO_JSVAL(cx->runtime->emptyString); + break; + + case FUN_CALLER: + if (fp && fp->down && fp->down->fun) + *vp = OBJECT_TO_JSVAL(fp->down->callee); + else + *vp = JSVAL_NULL; + if (!JSVAL_IS_PRIMITIVE(*vp)) { + callbacks = JS_GetSecurityCallbacks(cx); + if (callbacks && callbacks->checkObjectAccess) { + id = ATOM_KEY(cx->runtime->atomState.callerAtom); + if (!callbacks->checkObjectAccess(cx, obj, id, JSACC_READ, vp)) + return JS_FALSE; + } + } + break; + + default: + /* XXX fun[0] and fun.arguments[0] are equivalent. */ + if (fp && fp->fun && (uintN)slot < fp->fun->nargs) + *vp = fp->argv[slot]; + break; + } + + return JS_TRUE; +} + +/* + * ECMA-262 specifies that length is a property of function object instances, + * but we can avoid that space cost by delegating to a prototype property that + * is JSPROP_PERMANENT and JSPROP_SHARED. Each fun_getProperty call computes + * a fresh length value based on the arity of the individual function object's + * private data. + * + * The extensions below other than length, i.e., the ones not in ECMA-262, + * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility + * with ECMA we must allow a delegating object to override them. Therefore to + * avoid entraining garbage in Function.prototype slots, they must be resolved + * in non-prototype function objects, wherefore the lazy_function_props table + * and fun_resolve's use of it. + */ +#define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED) + +static JSPropertySpec function_props[] = { + {js_length_str, ARGS_LENGTH, LENGTH_PROP_ATTRS, fun_getProperty, JS_PropertyStub}, + {0,0,0,0,0} +}; + +typedef struct LazyFunctionProp { + uint16 atomOffset; + int8 tinyid; + uint8 attrs; +} LazyFunctionProp; + +/* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */ +static LazyFunctionProp lazy_function_props[] = { + {ATOM_OFFSET(arguments), CALL_ARGUMENTS, JSPROP_PERMANENT}, + {ATOM_OFFSET(arity), FUN_ARITY, JSPROP_PERMANENT}, + {ATOM_OFFSET(caller), FUN_CALLER, JSPROP_PERMANENT}, + {ATOM_OFFSET(name), FUN_NAME, JSPROP_PERMANENT}, +}; + +static JSBool +fun_enumerate(JSContext *cx, JSObject *obj) +{ + jsid prototypeId; + JSObject *pobj; + JSProperty *prop; + + prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); + if (!OBJ_LOOKUP_PROPERTY(cx, obj, prototypeId, &pobj, &prop)) + return JS_FALSE; + if (prop) + OBJ_DROP_PROPERTY(cx, pobj, prop); + return JS_TRUE; +} + +static JSBool +fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp) +{ + JSFunction *fun; + JSAtom *atom; + uintN i; + + if (!JSVAL_IS_STRING(id)) + return JS_TRUE; + + fun = GET_FUNCTION_PRIVATE(cx, obj); + + /* + * No need to reflect fun.prototype in 'fun.prototype = ... '. + * + * This is not just an optimization, because we must not resolve when + * defining hidden properties during compilation. The setup code for the + * prototype and the lazy properties below eventually calls the property + * hooks for the function object. That in turn calls fun_reserveSlots to + * get the number of the reserved slots which is just the number of + * regular expressions literals in the function. When compiling, that + * number is not yet ready so we must make sure that fun_resolve does + * nothing until the code for the function is generated. + */ + if (flags & JSRESOLVE_ASSIGNING) + return JS_TRUE; + + /* + * Ok, check whether id is 'prototype' and bootstrap the function object's + * prototype property. + */ + atom = cx->runtime->atomState.classPrototypeAtom; + if (id == ATOM_KEY(atom)) { + JSObject *proto; + + /* + * Beware of the wacky case of a user function named Object -- trying + * to find a prototype for that will recur back here _ad perniciem_. + */ + if (fun->atom == CLASS_ATOM(cx, Object)) + return JS_TRUE; + + /* + * Make the prototype object to have the same parent as the function + * object itself. + */ + proto = js_NewObject(cx, &js_ObjectClass, NULL, OBJ_GET_PARENT(cx, obj), + 0); + if (!proto) + return JS_FALSE; + + /* + * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for + * user-defined functions, but DontEnum | ReadOnly | DontDelete for + * native "system" constructors such as Object or Function. So lazily + * set the former here in fun_resolve, but eagerly define the latter + * in JS_InitClass, with the right attributes. + */ + if (!js_SetClassPrototype(cx, obj, proto, + JSPROP_ENUMERATE | JSPROP_PERMANENT)) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + return JS_FALSE; + } + *objp = obj; + return JS_TRUE; + } + + for (i = 0; i < JS_ARRAY_LENGTH(lazy_function_props); i++) { + LazyFunctionProp *lfp = &lazy_function_props[i]; + + atom = OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset); + if (id == ATOM_KEY(atom)) { + if (!js_DefineNativeProperty(cx, obj, + ATOM_TO_JSID(atom), JSVAL_VOID, + fun_getProperty, JS_PropertyStub, + lfp->attrs, SPROP_HAS_SHORTID, + lfp->tinyid, NULL)) { + return JS_FALSE; + } + *objp = obj; + return JS_TRUE; + } + } + + return JS_TRUE; +} + +static JSBool +fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) +{ + switch (type) { + case JSTYPE_FUNCTION: + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; + default: + return js_TryValueOf(cx, obj, type, vp); + } +} + +#if JS_HAS_XDR + +/* XXX store parent and proto, if defined */ +static JSBool +fun_xdrObject(JSXDRState *xdr, JSObject **objp) +{ + JSContext *cx; + JSFunction *fun; + uint32 nullAtom; /* flag to indicate if fun->atom is NULL */ + uintN nargs, nvars, n; + uint32 localsword; /* word to xdr argument and variable counts */ + uint32 flagsword; /* originally only flags was JS_XDRUint8'd */ + JSTempValueRooter tvr; + JSBool ok; + + cx = xdr->cx; + if (xdr->mode == JSXDR_ENCODE) { + fun = GET_FUNCTION_PRIVATE(cx, *objp); + if (!FUN_INTERPRETED(fun)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_NOT_SCRIPTED_FUNCTION, + JS_GetFunctionName(fun)); + return JS_FALSE; + } + nullAtom = !fun->atom; + nargs = fun->nargs; + nvars = fun->u.i.nvars; + localsword = (nargs << 16) | nvars; + flagsword = fun->flags; + } else { + fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL); + if (!fun) + return JS_FALSE; + STOBJ_CLEAR_PARENT(FUN_OBJECT(fun)); + STOBJ_CLEAR_PROTO(FUN_OBJECT(fun)); +#ifdef __GNUC__ + nvars = nargs = 0; /* quell GCC uninitialized warning */ +#endif + } + + /* From here on, control flow must flow through label out. */ + JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr); + ok = JS_TRUE; + + if (!JS_XDRUint32(xdr, &nullAtom)) + goto bad; + if (!nullAtom && !js_XDRStringAtom(xdr, &fun->atom)) + goto bad; + if (!JS_XDRUint32(xdr, &localsword) || + !JS_XDRUint32(xdr, &flagsword)) { + goto bad; + } + + if (xdr->mode == JSXDR_DECODE) { + nargs = localsword >> 16; + nvars = localsword & JS_BITMASK(16); + JS_ASSERT(flagsword | JSFUN_INTERPRETED); + fun->flags = (uint16) flagsword; + } + + /* do arguments and local vars */ + n = nargs + nvars; + if (n != 0) { + void *mark; + uintN i; + uintN bitmapLength; + uint32 *bitmap; + jsuword *names; + JSAtom *name; + JSLocalKind localKind; + + mark = JS_ARENA_MARK(&xdr->cx->tempPool); + + /* + * From this point the control must flow via the label release_mark. + * + * To xdr the names we prefix the names with a bitmap descriptor and + * then xdr the names as strings. For argument names (indexes below + * nargs) the corresponding bit in the bitmap is unset when the name + * is null. Such null names are not encoded or decoded. For variable + * names (indexes starting from nargs) bitmap's bit is set when the + * name is declared as const, not as ordinary var. + * */ + bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32); + JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool, + bitmapLength * sizeof *bitmap); + if (!bitmap) { + js_ReportOutOfScriptQuota(xdr->cx); + ok = JS_FALSE; + goto release_mark; + } + if (xdr->mode == JSXDR_ENCODE) { + names = js_GetLocalNameArray(xdr->cx, fun, &xdr->cx->tempPool); + if (!names) { + ok = JS_FALSE; + goto release_mark; + } + memset(bitmap, 0, bitmapLength * sizeof *bitmap); + for (i = 0; i != n; ++i) { + if (i < fun->nargs + ? JS_LOCAL_NAME_TO_ATOM(names[i]) != NULL + : JS_LOCAL_NAME_IS_CONST(names[i])) { + bitmap[i >> JS_BITS_PER_UINT32_LOG2] |= + JS_BIT(i & (JS_BITS_PER_UINT32 - 1)); + } + } + } +#ifdef __GNUC__ + else { + names = NULL; /* quell GCC uninitialized warning */ + } +#endif + for (i = 0; i != bitmapLength; ++i) { + ok = JS_XDRUint32(xdr, &bitmap[i]); + if (!ok) + goto release_mark; + } + for (i = 0; i != n; ++i) { + if (i < nargs && + !(bitmap[i >> JS_BITS_PER_UINT32_LOG2] & + JS_BIT(i & (JS_BITS_PER_UINT32 - 1)))) { + if (xdr->mode == JSXDR_DECODE) { + ok = js_AddLocal(xdr->cx, fun, NULL, JSLOCAL_ARG); + if (!ok) + goto release_mark; + } else { + JS_ASSERT(!JS_LOCAL_NAME_TO_ATOM(names[i])); + } + continue; + } + if (xdr->mode == JSXDR_ENCODE) + name = JS_LOCAL_NAME_TO_ATOM(names[i]); + ok = js_XDRStringAtom(xdr, &name); + if (!ok) + goto release_mark; + if (xdr->mode == JSXDR_DECODE) { + localKind = (i < nargs) + ? JSLOCAL_ARG + : bitmap[i >> JS_BITS_PER_UINT32_LOG2] & + JS_BIT(i & (JS_BITS_PER_UINT32 - 1)) + ? JSLOCAL_CONST + : JSLOCAL_VAR; + ok = js_AddLocal(xdr->cx, fun, name, localKind); + if (!ok) + goto release_mark; + } + } + ok = JS_TRUE; + + release_mark: + JS_ARENA_RELEASE(&xdr->cx->tempPool, mark); + if (!ok) + goto out; + + if (xdr->mode == JSXDR_DECODE) + js_FreezeLocalNames(cx, fun); + } + + if (!js_XDRScript(xdr, &fun->u.i.script, NULL)) + goto bad; + + if (xdr->mode == JSXDR_DECODE) { + *objp = FUN_OBJECT(fun); +#ifdef CHECK_SCRIPT_OWNER + fun->u.i.script->owner = NULL; +#endif + js_CallNewScriptHook(cx, fun->u.i.script, fun); + } + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; + +bad: + ok = JS_FALSE; + goto out; +} + +#else /* !JS_HAS_XDR */ + +#define fun_xdrObject NULL + +#endif /* !JS_HAS_XDR */ + +/* + * [[HasInstance]] internal method for Function objects: fetch the .prototype + * property of its 'this' parameter, and walks the prototype chain of v (only + * if v is an object) returning true if .prototype is found. + */ +static JSBool +fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +{ + jsval pval; + + if (!OBJ_GET_PROPERTY(cx, obj, + ATOM_TO_JSID(cx->runtime->atomState + .classPrototypeAtom), + &pval)) { + return JS_FALSE; + } + + if (JSVAL_IS_PRIMITIVE(pval)) { + /* + * Throw a runtime error if instanceof is called on a function that + * has a non-object as its .prototype value. + */ + js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, + -1, OBJECT_TO_JSVAL(obj), NULL); + return JS_FALSE; + } + + return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp); +} + +static void +TraceLocalNames(JSTracer *trc, JSFunction *fun); + +static void +DestroyLocalNames(JSContext *cx, JSFunction *fun); + +static void +fun_trace(JSTracer *trc, JSObject *obj) +{ + JSFunction *fun; + + /* A newborn function object may have a not yet initialized private slot. */ + fun = (JSFunction *) JS_GetPrivate(trc->context, obj); + if (!fun) + return; + + if (FUN_OBJECT(fun) != obj) { + /* obj is cloned function object, trace the original. */ + JS_CALL_TRACER(trc, FUN_OBJECT(fun), JSTRACE_OBJECT, "private"); + return; + } + if (fun->atom) + JS_CALL_STRING_TRACER(trc, ATOM_TO_STRING(fun->atom), "atom"); + if (FUN_INTERPRETED(fun)) { + if (fun->u.i.script) + js_TraceScript(trc, fun->u.i.script); + TraceLocalNames(trc, fun); + } +} + +static void +fun_finalize(JSContext *cx, JSObject *obj) +{ + JSFunction *fun; + + /* Ignore newborn and cloned function objects. */ + fun = (JSFunction *) JS_GetPrivate(cx, obj); + if (!fun || FUN_OBJECT(fun) != obj) + return; + + /* + * Null-check of u.i.script is required since the parser sets interpreted + * very early. + */ + if (FUN_INTERPRETED(fun)) { + if (fun->u.i.script) + js_DestroyScript(cx, fun->u.i.script); + DestroyLocalNames(cx, fun); + } +} + +static uint32 +fun_reserveSlots(JSContext *cx, JSObject *obj) +{ + JSFunction *fun; + uint32 nslots; + + /* + * We use JS_GetPrivate and not GET_FUNCTION_PRIVATE because during + * js_InitFunctionClass invocation the function is called before the + * private slot of the function object is set. + */ + fun = (JSFunction *) JS_GetPrivate(cx, obj); + nslots = 0; + if (fun && FUN_INTERPRETED(fun) && fun->u.i.script) { + if (fun->u.i.script->upvarsOffset != 0) + nslots = JS_SCRIPT_UPVARS(fun->u.i.script)->length; + if (fun->u.i.script->regexpsOffset != 0) + nslots += JS_SCRIPT_REGEXPS(fun->u.i.script)->length; + } + return nslots; +} + +/* + * Reserve two slots in all function objects for XPConnect. Note that this + * does not bloat every instance, only those on which reserved slots are set, + * and those on which ad-hoc properties are defined. + */ +JS_FRIEND_DATA(JSClass) js_FunctionClass = { + js_Function_str, + JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Function), + JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_PropertyStub, + fun_enumerate, (JSResolveOp)fun_resolve, + fun_convert, fun_finalize, + NULL, NULL, + NULL, NULL, + fun_xdrObject, fun_hasInstance, + JS_CLASS_TRACE(fun_trace), fun_reserveSlots +}; + +static JSBool +fun_toStringHelper(JSContext *cx, uint32 indent, uintN argc, jsval *vp) +{ + jsval fval; + JSObject *obj; + JSFunction *fun; + JSString *str; + + fval = JS_THIS(cx, vp); + if (JSVAL_IS_NULL(fval)) + return JS_FALSE; + + if (!VALUE_IS_FUNCTION(cx, fval)) { + /* + * If we don't have a function to start off with, try converting the + * object to a function. If that doesn't work, complain. + */ + if (!JSVAL_IS_PRIMITIVE(fval)) { + obj = JSVAL_TO_OBJECT(fval); + if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, JSTYPE_FUNCTION, + &fval)) { + return JS_FALSE; + } + vp[1] = fval; + } + if (!VALUE_IS_FUNCTION(cx, fval)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_PROTO, + js_Function_str, js_toString_str, + JS_GetTypeName(cx, JS_TypeOfValue(cx, fval))); + return JS_FALSE; + } + } + + obj = JSVAL_TO_OBJECT(fval); + if (argc != 0) { + indent = js_ValueToECMAUint32(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + } + + JS_ASSERT(JS_ObjectIsFunction(cx, obj)); + fun = GET_FUNCTION_PRIVATE(cx, obj); + if (!fun) + return JS_TRUE; + str = JS_DecompileFunction(cx, fun, (uintN)indent); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +fun_toString(JSContext *cx, uintN argc, jsval *vp) +{ + return fun_toStringHelper(cx, 0, argc, vp); +} + +#if JS_HAS_TOSOURCE +static JSBool +fun_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + return fun_toStringHelper(cx, JS_DONT_PRETTY_PRINT, argc, vp); +} +#endif + +JSBool +js_fun_call(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + jsval fval, *argv, *invokevp; + JSString *str; + void *mark; + JSBool ok; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1])) + return JS_FALSE; + fval = vp[1]; + + if (!VALUE_IS_FUNCTION(cx, fval)) { + str = JS_ValueToString(cx, fval); + if (str) { + const char *bytes = js_GetStringBytes(cx, str); + + if (bytes) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_PROTO, + js_Function_str, js_call_str, + bytes); + } + } + return JS_FALSE; + } + + argv = vp + 2; + if (argc == 0) { + /* Call fun with its global object as the 'this' param if no args. */ + obj = NULL; + } else { + /* Otherwise convert the first arg to 'this' and skip over it. */ + if (!JSVAL_IS_PRIMITIVE(argv[0])) + obj = JSVAL_TO_OBJECT(argv[0]); + else if (!js_ValueToObject(cx, argv[0], &obj)) + return JS_FALSE; + argc--; + argv++; + } + + /* Allocate stack space for fval, obj, and the args. */ + invokevp = js_AllocStack(cx, 2 + argc, &mark); + if (!invokevp) + return JS_FALSE; + + /* Push fval, obj, and the args. */ + invokevp[0] = fval; + invokevp[1] = OBJECT_TO_JSVAL(obj); + memcpy(invokevp + 2, argv, argc * sizeof *argv); + + ok = js_Invoke(cx, argc, invokevp, 0); + *vp = *invokevp; + js_FreeStack(cx, mark); + return ok; +} + +JSBool +js_fun_apply(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj, *aobj; + jsval fval, *invokevp, *sp; + JSString *str; + jsuint length; + JSBool arraylike, ok; + void *mark; + uintN i; + + if (argc == 0) { + /* Will get globalObject as 'this' and no other arguments. */ + return js_fun_call(cx, argc, vp); + } + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1])) + return JS_FALSE; + fval = vp[1]; + + if (!VALUE_IS_FUNCTION(cx, fval)) { + str = JS_ValueToString(cx, fval); + if (str) { + const char *bytes = js_GetStringBytes(cx, str); + + if (bytes) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_PROTO, + js_Function_str, js_apply_str, + bytes); + } + } + return JS_FALSE; + } + + /* Quell GCC overwarnings. */ + aobj = NULL; + length = 0; + + if (argc >= 2) { + /* If the 2nd arg is null or void, call the function with 0 args. */ + if (JSVAL_IS_NULL(vp[3]) || JSVAL_IS_VOID(vp[3])) { + argc = 0; + } else { + /* The second arg must be an array (or arguments object). */ + arraylike = JS_FALSE; + if (!JSVAL_IS_PRIMITIVE(vp[3])) { + aobj = JSVAL_TO_OBJECT(vp[3]); + if (!js_IsArrayLike(cx, aobj, &arraylike, &length)) + return JS_FALSE; + } + if (!arraylike) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_APPLY_ARGS, js_apply_str); + return JS_FALSE; + } + } + } + + /* Convert the first arg to 'this' and skip over it. */ + if (!JSVAL_IS_PRIMITIVE(vp[2])) + obj = JSVAL_TO_OBJECT(vp[2]); + else if (!js_ValueToObject(cx, vp[2], &obj)) + return JS_FALSE; + + /* Allocate stack space for fval, obj, and the args. */ + argc = (uintN)JS_MIN(length, ARRAY_INIT_LIMIT - 1); + invokevp = js_AllocStack(cx, 2 + argc, &mark); + if (!invokevp) + return JS_FALSE; + + /* Push fval, obj, and aobj's elements as args. */ + sp = invokevp; + *sp++ = fval; + *sp++ = OBJECT_TO_JSVAL(obj); + for (i = 0; i < argc; i++) { + ok = JS_GetElement(cx, aobj, (jsint)i, sp); + if (!ok) + goto out; + sp++; + } + + ok = js_Invoke(cx, argc, invokevp, 0); + *vp = *invokevp; +out: + js_FreeStack(cx, mark); + return ok; +} + +#ifdef NARCISSUS +static JSBool +fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *aobj; + uintN length, i; + void *mark; + jsval *invokevp, *sp; + JSBool ok; + + if (JSVAL_IS_PRIMITIVE(vp[2]) || + (aobj = JSVAL_TO_OBJECT(vp[2]), + OBJ_GET_CLASS(cx, aobj) != &js_ArrayClass && + OBJ_GET_CLASS(cx, aobj) != &js_ArgumentsClass)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_APPLY_ARGS, "__applyConstruct__"); + return JS_FALSE; + } + + if (!js_GetLengthProperty(cx, aobj, &length)) + return JS_FALSE; + + if (length >= ARRAY_INIT_LIMIT) + length = ARRAY_INIT_LIMIT - 1; + invokevp = js_AllocStack(cx, 2 + length, &mark); + if (!invokevp) + return JS_FALSE; + + sp = invokevp; + *sp++ = vp[1]; + *sp++ = JSVAL_NULL; /* this is filled automagically */ + for (i = 0; i < length; i++) { + ok = JS_GetElement(cx, aobj, (jsint)i, sp); + if (!ok) + goto out; + sp++; + } + + ok = js_InvokeConstructor(cx, length, JS_TRUE, invokevp); + *vp = *invokevp; +out: + js_FreeStack(cx, mark); + return ok; +} +#endif + +static JSFunctionSpec function_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, fun_toSource, 0,0), +#endif + JS_FN(js_toString_str, fun_toString, 0,0), + JS_FN(js_apply_str, js_fun_apply, 2,0), + JS_FN(js_call_str, js_fun_call, 1,0), +#ifdef NARCISSUS + JS_FN("__applyConstructor__", fun_applyConstructor, 1,0), +#endif + JS_FS_END +}; + +static JSBool +Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSStackFrame *fp, *caller; + JSFunction *fun; + JSObject *parent; + uintN i, n, lineno; + JSAtom *atom; + const char *filename; + JSBool ok; + JSString *str, *arg; + JSTokenStream ts; + JSPrincipals *principals; + jschar *collected_args, *cp; + void *mark; + size_t arg_length, args_length, old_args_length; + JSTokenType tt; + + fp = cx->fp; + if (!(fp->flags & JSFRAME_CONSTRUCTING)) { + obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(obj); + } else { + /* + * The constructor is called before the private slot is initialized so + * we must use JS_GetPrivate, not GET_FUNCTION_PRIVATE here. + */ + if (JS_GetPrivate(cx, obj)) + return JS_TRUE; + } + + /* + * NB: (new Function) is not lexically closed by its caller, it's just an + * anonymous function in the top-level scope that its constructor inhabits. + * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42, + * and so would a call to f from another top-level's script or function. + * + * In older versions, before call objects, a new Function was adopted by + * its running context's globalObject, which might be different from the + * top-level reachable from scopeChain (in HTML frames, e.g.). + */ + parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2])); + + fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED, + parent, cx->runtime->atomState.anonymousAtom); + + if (!fun) + return JS_FALSE; + + /* + * Function is static and not called directly by other functions in this + * file, therefore it is callable only as a native function by js_Invoke. + * Find the scripted caller, possibly skipping other native frames such as + * are built for Function.prototype.call or .apply activations that invoke + * Function indirectly from a script. + */ + JS_ASSERT(!fp->script && fp->fun && fp->fun->u.n.native == Function); + caller = JS_GetScriptedCaller(cx, fp); + if (caller) { + principals = JS_EvalFramePrincipals(cx, fp, caller); + filename = js_ComputeFilename(cx, caller, principals, &lineno); + } else { + filename = NULL; + lineno = 0; + principals = NULL; + } + + /* Belt-and-braces: check that the caller has access to parent. */ + if (!js_CheckPrincipalsAccess(cx, parent, principals, + CLASS_ATOM(cx, Function))) { + return JS_FALSE; + } + + n = argc ? argc - 1 : 0; + if (n > 0) { + enum { OK, BAD, BAD_FORMAL } state; + + /* + * Collect the function-argument arguments into one string, separated + * by commas, then make a tokenstream from that string, and scan it to + * get the arguments. We need to throw the full scanner at the + * problem, because the argument string can legitimately contain + * comments and linefeeds. XXX It might be better to concatenate + * everything up into a function definition and pass it to the + * compiler, but doing it this way is less of a delta from the old + * code. See ECMA 15.3.2.1. + */ + state = BAD_FORMAL; + args_length = 0; + for (i = 0; i < n; i++) { + /* Collect the lengths for all the function-argument arguments. */ + arg = js_ValueToString(cx, argv[i]); + if (!arg) + return JS_FALSE; + argv[i] = STRING_TO_JSVAL(arg); + + /* + * Check for overflow. The < test works because the maximum + * JSString length fits in 2 fewer bits than size_t has. + */ + old_args_length = args_length; + args_length = old_args_length + JSSTRING_LENGTH(arg); + if (args_length < old_args_length) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + } + + /* Add 1 for each joining comma and check for overflow (two ways). */ + old_args_length = args_length; + args_length = old_args_length + n - 1; + if (args_length < old_args_length || + args_length >= ~(size_t)0 / sizeof(jschar)) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + + /* + * Allocate a string to hold the concatenated arguments, including room + * for a terminating 0. Mark cx->tempPool for later release, to free + * collected_args and its tokenstream in one swoop. + */ + mark = JS_ARENA_MARK(&cx->tempPool); + JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool, + (args_length+1) * sizeof(jschar)); + if (!cp) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + collected_args = cp; + + /* + * Concatenate the arguments into the new string, separated by commas. + */ + for (i = 0; i < n; i++) { + arg = JSVAL_TO_STRING(argv[i]); + arg_length = JSSTRING_LENGTH(arg); + (void) js_strncpy(cp, JSSTRING_CHARS(arg), arg_length); + cp += arg_length; + + /* Add separating comma or terminating 0. */ + *cp++ = (i + 1 < n) ? ',' : 0; + } + + /* Initialize a tokenstream that reads from the given string. */ + if (!js_InitTokenStream(cx, &ts, collected_args, args_length, + NULL, filename, lineno)) { + JS_ARENA_RELEASE(&cx->tempPool, mark); + return JS_FALSE; + } + + /* The argument string may be empty or contain no tokens. */ + tt = js_GetToken(cx, &ts); + if (tt != TOK_EOF) { + for (;;) { + /* + * Check that it's a name. This also implicitly guards against + * TOK_ERROR, which was already reported. + */ + if (tt != TOK_NAME) + goto after_args; + + /* + * Get the atom corresponding to the name from the token + * stream; we're assured at this point that it's a valid + * identifier. + */ + atom = CURRENT_TOKEN(&ts).t_atom; + + /* Check for a duplicate parameter name. */ + if (js_LookupLocal(cx, fun, atom, NULL) != JSLOCAL_NONE) { + const char *name; + + name = js_AtomToPrintableString(cx, atom); + ok = name && + js_ReportCompileErrorNumber(cx, &ts, NULL, + JSREPORT_WARNING | + JSREPORT_STRICT, + JSMSG_DUPLICATE_FORMAL, + name); + if (!ok) + goto after_args; + } + if (!js_AddLocal(cx, fun, atom, JSLOCAL_ARG)) + goto after_args; + + /* + * Get the next token. Stop on end of stream. Otherwise + * insist on a comma, get another name, and iterate. + */ + tt = js_GetToken(cx, &ts); + if (tt == TOK_EOF) + break; + if (tt != TOK_COMMA) + goto after_args; + tt = js_GetToken(cx, &ts); + } + } + + state = OK; + after_args: + if (state == BAD_FORMAL && !(ts.flags & TSF_ERROR)) { + /* + * Report "malformed formal parameter" iff no illegal char or + * similar scanner error was already reported. + */ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_FORMAL); + } + js_CloseTokenStream(cx, &ts); + JS_ARENA_RELEASE(&cx->tempPool, mark); + if (state != OK) + return JS_FALSE; + } + + if (argc) { + str = js_ValueToString(cx, argv[argc-1]); + if (!str) + return JS_FALSE; + argv[argc-1] = STRING_TO_JSVAL(str); + } else { + str = cx->runtime->emptyString; + } + + return js_CompileFunctionBody(cx, fun, principals, + JSSTRING_CHARS(str), JSSTRING_LENGTH(str), + filename, lineno); +} + +JSObject * +js_InitFunctionClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + JSFunction *fun; + + proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1, + function_props, function_methods, NULL, NULL); + if (!proto) + return NULL; + fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL); + if (!fun) + goto bad; + fun->u.i.script = js_NewScript(cx, 1, 1, 0, 0, 0, 0, 0); + if (!fun->u.i.script) + goto bad; + fun->u.i.script->code[0] = JSOP_STOP; + *SCRIPT_NOTES(fun->u.i.script) = SRC_NULL; +#ifdef CHECK_SCRIPT_OWNER + fun->u.i.script->owner = NULL; +#endif + return proto; + +bad: + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + return NULL; +} + +JSObject * +js_InitCallClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + + proto = JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0, + NULL, NULL, NULL, NULL); + if (!proto) + return NULL; + + /* + * Null Call.prototype's proto slot so that Object.prototype.* does not + * pollute the scope of heavyweight functions. + */ + OBJ_CLEAR_PROTO(cx, proto); + return proto; +} + +JSFunction * +js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, + uintN flags, JSObject *parent, JSAtom *atom) +{ + JSFunction *fun; + + if (funobj) { + JS_ASSERT(HAS_FUNCTION_CLASS(funobj)); + OBJ_SET_PARENT(cx, funobj, parent); + } else { + funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent, 0); + if (!funobj) + return NULL; + } + JS_ASSERT(JSVAL_IS_VOID(funobj->fslots[JSSLOT_PRIVATE])); + fun = (JSFunction *) funobj; + + /* Initialize all function members. */ + fun->nargs = nargs; + fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_INTERPRETED | JSFUN_TRACEABLE); + if (flags & JSFUN_INTERPRETED) { + JS_ASSERT(!native); + JS_ASSERT(nargs == 0); + fun->u.i.nvars = 0; + fun->u.i.nupvars = 0; + fun->u.i.script = NULL; +#ifdef DEBUG + fun->u.i.names.taggedAtom = 0; +#endif + } else { + fun->u.n.extra = 0; + fun->u.n.spare = 0; + if (flags & JSFUN_TRACEABLE) { +#ifdef JS_TRACER + JSTraceableNative *trcinfo = (JSTraceableNative *) native; + fun->u.n.native = (JSNative) trcinfo->native; + FUN_TRCINFO(fun) = trcinfo; +#else + JS_ASSERT(0); +#endif + } else { + fun->u.n.native = native; + FUN_CLASP(fun) = NULL; + } + } + fun->atom = atom; + + /* Set private to self to indicate non-cloned fully initialized function. */ + FUN_OBJECT(fun)->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun); + return fun; +} + +JSObject * +js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent) +{ + JSObject *clone; + + /* + * The cloned function object does not need the extra fields beyond + * JSObject as it points to fun via the private slot. + */ + clone = js_NewObject(cx, &js_FunctionClass, NULL, parent, + sizeof(JSObject)); + if (!clone) + return NULL; + clone->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun); + return clone; +} + +JSFunction * +js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native, + uintN nargs, uintN attrs) +{ + JSFunction *fun; + JSPropertyOp gsop; + + fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom); + if (!fun) + return NULL; + gsop = (attrs & JSFUN_STUB_GSOPS) ? JS_PropertyStub : NULL; + if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), + OBJECT_TO_JSVAL(FUN_OBJECT(fun)), + gsop, gsop, + attrs & ~JSFUN_FLAGS_MASK, NULL)) { + return NULL; + } + return fun; +} + +#if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK) +# error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!" +#endif + +JSFunction * +js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags) +{ + jsval v; + JSObject *obj; + + v = *vp; + obj = NULL; + if (JSVAL_IS_OBJECT(v)) { + obj = JSVAL_TO_OBJECT(v); + if (obj && OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) { + if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &v)) + return NULL; + obj = VALUE_IS_FUNCTION(cx, v) ? JSVAL_TO_OBJECT(v) : NULL; + } + } + if (!obj) { + js_ReportIsNotFunction(cx, vp, flags); + return NULL; + } + return GET_FUNCTION_PRIVATE(cx, obj); +} + +JSObject * +js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags) +{ + JSFunction *fun; + JSStackFrame *caller; + JSPrincipals *principals; + + if (VALUE_IS_FUNCTION(cx, *vp)) + return JSVAL_TO_OBJECT(*vp); + + fun = js_ValueToFunction(cx, vp, flags); + if (!fun) + return NULL; + *vp = OBJECT_TO_JSVAL(FUN_OBJECT(fun)); + + caller = JS_GetScriptedCaller(cx, cx->fp); + if (caller) { + principals = JS_StackFramePrincipals(cx, caller); + } else { + /* No scripted caller, don't allow access. */ + principals = NULL; + } + + if (!js_CheckPrincipalsAccess(cx, FUN_OBJECT(fun), principals, + fun->atom + ? fun->atom + : cx->runtime->atomState.anonymousAtom)) { + return NULL; + } + return FUN_OBJECT(fun); +} + +JSObject * +js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags) +{ + JSObject *callable; + + callable = JSVAL_IS_PRIMITIVE(*vp) ? NULL : JSVAL_TO_OBJECT(*vp); + if (callable && + ((callable->map->ops == &js_ObjectOps) + ? OBJ_GET_CLASS(cx, callable)->call + : callable->map->ops->call)) { + *vp = OBJECT_TO_JSVAL(callable); + } else { + callable = js_ValueToFunctionObject(cx, vp, flags); + } + return callable; +} + +void +js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) +{ + JSStackFrame *fp; + uintN error; + const char *name, *source; + JSTempValueRooter tvr; + + for (fp = cx->fp; fp && !fp->regs; fp = fp->down) + continue; + name = source = NULL; + JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr); + if (flags & JSV2F_ITERATOR) { + error = JSMSG_BAD_ITERATOR; + name = js_iterator_str; + tvr.u.string = js_ValueToSource(cx, *vp); + if (!tvr.u.string) + goto out; + tvr.u.string = js_QuoteString(cx, tvr.u.string, 0); + if (!tvr.u.string) + goto out; + source = js_GetStringBytes(cx, tvr.u.string); + if (!source) + goto out; + } else if (flags & JSV2F_CONSTRUCT) { + error = JSMSG_NOT_CONSTRUCTOR; + } else { + error = JSMSG_NOT_FUNCTION; + } + + js_ReportValueError3(cx, error, + (fp && fp->regs && + StackBase(fp) <= vp && vp < fp->regs->sp) + ? vp - fp->regs->sp + : (flags & JSV2F_SEARCH_STACK) + ? JSDVG_SEARCH_STACK + : JSDVG_IGNORE_STACK, + *vp, NULL, + name, source); + + out: + JS_POP_TEMP_ROOT(cx, &tvr); +} + +/* + * When a function has between 2 and MAX_ARRAY_LOCALS arguments and variables, + * their name are stored as the JSLocalNames.array. + */ +#define MAX_ARRAY_LOCALS 8 + +JS_STATIC_ASSERT(2 <= MAX_ARRAY_LOCALS); +JS_STATIC_ASSERT(MAX_ARRAY_LOCALS < JS_BITMASK(16)); + +/* + * We use the lowest bit of the string atom to distinguish const from var + * name when there is only single name or when names are stored as an array. + */ +JS_STATIC_ASSERT((JSVAL_STRING & 1) == 0); + +/* + * When we use a hash table to store the local names, we use a singly linked + * list to record the indexes of duplicated parameter names to preserve the + * duplicates for the decompiler. + */ +typedef struct JSNameIndexPair JSNameIndexPair; + +struct JSNameIndexPair { + JSAtom *name; + uint16 index; + JSNameIndexPair *link; +}; + +struct JSLocalNameMap { + JSDHashTable names; + JSNameIndexPair *lastdup; +}; + +typedef struct JSLocalNameHashEntry { + JSDHashEntryHdr hdr; + JSAtom *name; + uint16 index; + uint8 localKind; +} JSLocalNameHashEntry; + +static void +FreeLocalNameHash(JSContext *cx, JSLocalNameMap *map) +{ + JSNameIndexPair *dup, *next; + + for (dup = map->lastdup; dup; dup = next) { + next = dup->link; + JS_free(cx, dup); + } + JS_DHashTableFinish(&map->names); + JS_free(cx, map); +} + +static JSBool +HashLocalName(JSContext *cx, JSLocalNameMap *map, JSAtom *name, + JSLocalKind localKind, uintN index) +{ + JSLocalNameHashEntry *entry; + JSNameIndexPair *dup; + + JS_ASSERT(index <= JS_BITMASK(16)); +#if JS_HAS_DESTRUCTURING + if (!name) { + /* A destructuring pattern does not need a hash entry. */ + JS_ASSERT(localKind == JSLOCAL_ARG); + return JS_TRUE; + } +#endif + JS_ASSERT(ATOM_IS_STRING(name)); + entry = (JSLocalNameHashEntry *) + JS_DHashTableOperate(&map->names, name, JS_DHASH_ADD); + if (!entry) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + if (entry->name) { + JS_ASSERT(entry->name == name); + JS_ASSERT(entry->localKind == JSLOCAL_ARG); + dup = (JSNameIndexPair *) JS_malloc(cx, sizeof *dup); + if (!dup) + return JS_FALSE; + dup->name = entry->name; + dup->index = entry->index; + dup->link = map->lastdup; + map->lastdup = dup; + } + entry->name = name; + entry->index = (uint16) index; + entry->localKind = (uint8) localKind; + return JS_TRUE; +} + +JSBool +js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind) +{ + jsuword taggedAtom; + uint16 *indexp; + uintN n, i; + jsuword *array; + JSLocalNameMap *map; + + JS_ASSERT(FUN_INTERPRETED(fun)); + JS_ASSERT(!fun->u.i.script); + JS_ASSERT(((jsuword) atom & 1) == 0); + taggedAtom = (jsuword) atom; + if (kind == JSLOCAL_ARG) { + indexp = &fun->nargs; + } else if (kind == JSLOCAL_UPVAR) { + indexp = &fun->u.i.nupvars; + } else { + indexp = &fun->u.i.nvars; + if (kind == JSLOCAL_CONST) + taggedAtom |= 1; + else + JS_ASSERT(kind == JSLOCAL_VAR); + } + n = JS_GET_LOCAL_NAME_COUNT(fun); + if (n == 0) { + JS_ASSERT(fun->u.i.names.taggedAtom == 0); + fun->u.i.names.taggedAtom = taggedAtom; + } else if (n < MAX_ARRAY_LOCALS) { + if (n > 1) { + array = fun->u.i.names.array; + } else { + array = (jsuword *) JS_malloc(cx, MAX_ARRAY_LOCALS * sizeof *array); + if (!array) + return JS_FALSE; + array[0] = fun->u.i.names.taggedAtom; + fun->u.i.names.array = array; + } + if (kind == JSLOCAL_ARG) { + /* + * A destructuring argument pattern adds variables, not arguments, + * so for the following arguments nvars != 0. + */ +#if JS_HAS_DESTRUCTURING + if (fun->u.i.nvars != 0) { + memmove(array + fun->nargs + 1, array + fun->nargs, + fun->u.i.nvars * sizeof *array); + } +#else + JS_ASSERT(fun->u.i.nvars == 0); +#endif + array[fun->nargs] = taggedAtom; + } else { + array[n] = taggedAtom; + } + } else if (n == MAX_ARRAY_LOCALS) { + array = fun->u.i.names.array; + map = (JSLocalNameMap *) JS_malloc(cx, sizeof *map); + if (!map) + return JS_FALSE; + if (!JS_DHashTableInit(&map->names, JS_DHashGetStubOps(), + NULL, sizeof(JSLocalNameHashEntry), + JS_DHASH_DEFAULT_CAPACITY(MAX_ARRAY_LOCALS + * 2))) { + JS_ReportOutOfMemory(cx); + JS_free(cx, map); + return JS_FALSE; + } + + map->lastdup = NULL; + for (i = 0; i != MAX_ARRAY_LOCALS; ++i) { + taggedAtom = array[i]; + if (!HashLocalName(cx, map, (JSAtom *) (taggedAtom & ~1), + (i < fun->nargs) + ? JSLOCAL_ARG + : (taggedAtom & 1) ? JSLOCAL_CONST : JSLOCAL_VAR, + (i < fun->nargs) ? i : i - fun->nargs)) { + FreeLocalNameHash(cx, map); + return JS_FALSE; + } + } + if (!HashLocalName(cx, map, atom, kind, *indexp)) { + FreeLocalNameHash(cx, map); + return JS_FALSE; + } + + /* + * At this point the entry is added and we cannot fail. It is time + * to replace fun->u.i.names with the built map. + */ + fun->u.i.names.map = map; + JS_free(cx, array); + } else { + if (*indexp == JS_BITMASK(16)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + (kind == JSLOCAL_ARG) + ? JSMSG_TOO_MANY_FUN_ARGS + : JSMSG_TOO_MANY_LOCALS); + return JS_FALSE; + } + if (!HashLocalName(cx, fun->u.i.names.map, atom, kind, *indexp)) + return JS_FALSE; + } + + /* Update the argument or variable counter. */ + ++*indexp; + return JS_TRUE; +} + +JSLocalKind +js_LookupLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, uintN *indexp) +{ + uintN n, i, upvar_base; + jsuword *array; + JSLocalNameHashEntry *entry; + + JS_ASSERT(FUN_INTERPRETED(fun)); + n = JS_GET_LOCAL_NAME_COUNT(fun); + if (n == 0) + return JSLOCAL_NONE; + if (n <= MAX_ARRAY_LOCALS) { + array = (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array; + + /* Search from the tail to pick up the last duplicated name. */ + i = n; + upvar_base = JS_UPVAR_LOCAL_NAME_START(fun); + do { + --i; + if (atom == JS_LOCAL_NAME_TO_ATOM(array[i])) { + if (i < fun->nargs) { + if (indexp) + *indexp = i; + return JSLOCAL_ARG; + } + if (i >= upvar_base) { + if (indexp) + *indexp = i - upvar_base; + return JSLOCAL_UPVAR; + } + if (indexp) + *indexp = i - fun->nargs; + return JS_LOCAL_NAME_IS_CONST(array[i]) + ? JSLOCAL_CONST + : JSLOCAL_VAR; + } + } while (i != 0); + } else { + entry = (JSLocalNameHashEntry *) + JS_DHashTableOperate(&fun->u.i.names.map->names, atom, + JS_DHASH_LOOKUP); + if (JS_DHASH_ENTRY_IS_BUSY(&entry->hdr)) { + JS_ASSERT(entry->localKind != JSLOCAL_NONE); + if (indexp) + *indexp = entry->index; + return (JSLocalKind) entry->localKind; + } + } + return JSLOCAL_NONE; +} + +typedef struct JSLocalNameEnumeratorArgs { + JSFunction *fun; + jsuword *names; +#ifdef DEBUG + uintN nCopiedArgs; + uintN nCopiedVars; +#endif +} JSLocalNameEnumeratorArgs; + +static JSDHashOperator +get_local_names_enumerator(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + JSLocalNameHashEntry *entry; + JSLocalNameEnumeratorArgs *args; + uint i; + jsuword constFlag; + + entry = (JSLocalNameHashEntry *) hdr; + args = (JSLocalNameEnumeratorArgs *) arg; + JS_ASSERT(entry->name); + if (entry->localKind == JSLOCAL_ARG) { + JS_ASSERT(entry->index < args->fun->nargs); + JS_ASSERT(args->nCopiedArgs++ < args->fun->nargs); + i = entry->index; + constFlag = 0; + } else { + JS_ASSERT(entry->localKind == JSLOCAL_VAR || + entry->localKind == JSLOCAL_CONST); + JS_ASSERT(entry->index < args->fun->u.i.nvars); + JS_ASSERT(args->nCopiedVars++ < args->fun->u.i.nvars); + i = args->fun->nargs + entry->index; + constFlag = (entry->localKind == JSLOCAL_CONST); + } + args->names[i] = (jsuword) entry->name | constFlag; + return JS_DHASH_NEXT; +} + +jsuword * +js_GetLocalNameArray(JSContext *cx, JSFunction *fun, JSArenaPool *pool) +{ + uintN n; + jsuword *names; + JSLocalNameMap *map; + JSLocalNameEnumeratorArgs args; + JSNameIndexPair *dup; + + JS_ASSERT(FUN_INTERPRETED(fun)); + n = JS_GET_LOCAL_NAME_COUNT(fun); + JS_ASSERT(n != 0); + + if (n <= MAX_ARRAY_LOCALS) + return (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array; + + /* + * No need to check for overflow of the allocation size as we are making a + * copy of already allocated data. As such it must fit size_t. + */ + JS_ARENA_ALLOCATE_CAST(names, jsuword *, pool, (size_t) n * sizeof *names); + if (!names) { + js_ReportOutOfScriptQuota(cx); + return NULL; + } + +#if JS_HAS_DESTRUCTURING + /* Some parameter names can be NULL due to destructuring patterns. */ + memset(names, 0, fun->nargs * sizeof *names); +#endif + map = fun->u.i.names.map; + args.fun = fun; + args.names = names; +#ifdef DEBUG + args.nCopiedArgs = 0; + args.nCopiedVars = 0; +#endif + JS_DHashTableEnumerate(&map->names, get_local_names_enumerator, &args); + for (dup = map->lastdup; dup; dup = dup->link) { + JS_ASSERT(dup->index < fun->nargs); + JS_ASSERT(args.nCopiedArgs++ < fun->nargs); + names[dup->index] = (jsuword) dup->name; + } +#if !JS_HAS_DESTRUCTURING + JS_ASSERT(args.nCopiedArgs == fun->nargs); +#endif + JS_ASSERT(args.nCopiedVars == fun->u.i.nvars); + + return names; +} + +static JSDHashOperator +trace_local_names_enumerator(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + JSLocalNameHashEntry *entry; + JSTracer *trc; + + entry = (JSLocalNameHashEntry *) hdr; + JS_ASSERT(entry->name); + trc = (JSTracer *) arg; + JS_SET_TRACING_INDEX(trc, + entry->localKind == JSLOCAL_ARG ? "arg" : "var", + entry->index); + JS_CallTracer(trc, ATOM_TO_STRING(entry->name), JSTRACE_STRING); + return JS_DHASH_NEXT; +} + +static void +TraceLocalNames(JSTracer *trc, JSFunction *fun) +{ + uintN n, i; + JSAtom *atom; + jsuword *array; + + JS_ASSERT(FUN_INTERPRETED(fun)); + n = JS_GET_LOCAL_NAME_COUNT(fun); + if (n == 0) + return; + if (n <= MAX_ARRAY_LOCALS) { + array = (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array; + i = n; + do { + --i; + atom = (JSAtom *) (array[i] & ~1); + if (atom) { + JS_SET_TRACING_INDEX(trc, + i < fun->nargs ? "arg" : "var", + i < fun->nargs ? i : i - fun->nargs); + JS_CallTracer(trc, ATOM_TO_STRING(atom), JSTRACE_STRING); + } + } while (i != 0); + } else { + JS_DHashTableEnumerate(&fun->u.i.names.map->names, + trace_local_names_enumerator, trc); + + /* + * No need to trace the list of duplicates in map->lastdup as the + * names there are traced when enumerating the hash table. + */ + } +} + +void +DestroyLocalNames(JSContext *cx, JSFunction *fun) +{ + uintN n; + + n = fun->nargs + fun->u.i.nvars; + if (n <= 1) + return; + if (n <= MAX_ARRAY_LOCALS) + JS_free(cx, fun->u.i.names.array); + else + FreeLocalNameHash(cx, fun->u.i.names.map); +} + +void +js_FreezeLocalNames(JSContext *cx, JSFunction *fun) +{ + uintN n; + jsuword *array; + + JS_ASSERT(FUN_INTERPRETED(fun)); + JS_ASSERT(!fun->u.i.script); + n = fun->nargs + fun->u.i.nvars + fun->u.i.nupvars; + if (2 <= n && n < MAX_ARRAY_LOCALS) { + /* Shrink over-allocated array ignoring realloc failures. */ + array = (jsuword *) JS_realloc(cx, fun->u.i.names.array, + n * sizeof *array); + if (array) + fun->u.i.names.array = array; + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfun.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfun.h new file mode 100644 index 0000000..d13ccfd --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsfun.h @@ -0,0 +1,296 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsfun_h___ +#define jsfun_h___ +/* + * JS function definitions. + */ +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsobj.h" + +JS_BEGIN_EXTERN_C + +typedef struct JSLocalNameMap JSLocalNameMap; + +/* + * Depending on the number of arguments and variables in the function their + * names and attributes are stored either as a single atom or as an array of + * tagged atoms (when there are few locals) or as a hash-based map (when there + * are many locals). In the first 2 cases the lowest bit of the atom is used + * as a tag to distinguish const from var. See jsfun.c for details. + */ +typedef union JSLocalNames { + jsuword taggedAtom; + jsuword *array; + JSLocalNameMap *map; +} JSLocalNames; + +struct JSFunction { + JSObject object; /* GC'ed object header */ + uint16 nargs; /* maximum number of specified arguments, + reflected as f.length/f.arity */ + uint16 flags; /* flags, see JSFUN_* below and in jsapi.h */ + union { + struct { + uint16 extra; /* number of arg slots for local GC roots */ + uint16 spare; /* reserved for future use */ + JSNative native; /* native method pointer or null */ + union { + JSClass *clasp; /* class of objects constructed + by this function */ + JSTraceableNative *trcinfo; /* tracer metadata; can be first + element of array */ + } u; + } n; + struct { + uint16 nvars; /* number of local variables */ + uint16 nupvars; /* number of upvars (computable from script + but here for faster access) */ + JSScript *script; /* interpreted bytecode descriptor or null */ + JSLocalNames names; /* argument and variable names */ + } i; + } u; + JSAtom *atom; /* name for diagnostics and decompiling */ +}; + +#define JSFUN_TRACEABLE 0x2000 /* can trace across calls to this native + function; use FUN_TRCINFO if set, + FUN_CLASP if unset */ +#define JSFUN_EXPR_CLOSURE 0x4000 /* expression closure: function(x)x*x */ +#define JSFUN_INTERPRETED 0x8000 /* use u.i if set, u.n if unset */ + +#define JSFUN_SCRIPT_OR_FAST_NATIVE (JSFUN_INTERPRETED | JSFUN_FAST_NATIVE) + +#define FUN_OBJECT(fun) (&(fun)->object) +#define FUN_INTERPRETED(fun) ((fun)->flags & JSFUN_INTERPRETED) +#define FUN_SLOW_NATIVE(fun) (!((fun)->flags & JSFUN_SCRIPT_OR_FAST_NATIVE)) +#define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL) +#define FUN_NATIVE(fun) (FUN_SLOW_NATIVE(fun) ? (fun)->u.n.native : NULL) +#define FUN_FAST_NATIVE(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ + ? (JSFastNative) (fun)->u.n.native \ + : NULL) +#define FUN_MINARGS(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ + ? 0 \ + : (fun)->nargs) +#define FUN_CLASP(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \ + JS_ASSERT(!((fun)->flags & JSFUN_TRACEABLE)), \ + fun->u.n.u.clasp) +#define FUN_TRCINFO(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \ + JS_ASSERT((fun)->flags & JSFUN_TRACEABLE), \ + fun->u.n.u.trcinfo) + +/* + * Traceable native. This expands to a JSFunctionSpec initializer (like JS_FN + * in jsapi.h). fastcall is a JSFastNative; trcinfo is a JSTraceableNative *. + */ +#ifdef JS_TRACER +/* MSVC demands the intermediate (void *) cast here. */ +# define JS_TN(name,fastcall,nargs,flags,trcinfo) \ + {name, (JSNative)(void *)(trcinfo), nargs, \ + (flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS | JSFUN_TRACEABLE, 0} +#else +# define JS_TN(name,fastcall,nargs,flags,trcinfo) \ + JS_FN(name, fastcall, nargs, flags) +#endif + +extern JSClass js_ArgumentsClass; +extern JS_FRIEND_DATA(JSClass) js_CallClass; + +/* JS_FRIEND_DATA so that VALUE_IS_FUNCTION is callable from the shell. */ +extern JS_FRIEND_DATA(JSClass) js_FunctionClass; + +#define HAS_FUNCTION_CLASS(obj) (STOBJ_GET_CLASS(obj) == &js_FunctionClass) + +/* + * NB: jsapi.h and jsobj.h must be included before any call to this macro. + */ +#define VALUE_IS_FUNCTION(cx, v) \ + (!JSVAL_IS_PRIMITIVE(v) && HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v))) + +/* + * Macro to access the private slot of the function object after the slot is + * initialized. + */ +#define GET_FUNCTION_PRIVATE(cx, funobj) \ + (JS_ASSERT(HAS_FUNCTION_CLASS(funobj)), \ + (JSFunction *) OBJ_GET_PRIVATE(cx, funobj)) + +extern JSObject * +js_InitFunctionClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitArgumentsClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitCallClass(JSContext *cx, JSObject *obj); + +extern JSFunction * +js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, + uintN flags, JSObject *parent, JSAtom *atom); + +extern void +js_TraceFunction(JSTracer *trc, JSFunction *fun); + +extern void +js_FinalizeFunction(JSContext *cx, JSFunction *fun); + +extern JSObject * +js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent); + +extern JSBool +js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *object); + +extern JSFunction * +js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native, + uintN nargs, uintN flags); + +/* + * Flags for js_ValueToFunction and js_ReportIsNotFunction. We depend on the + * fact that JSINVOKE_CONSTRUCT (aka JSFRAME_CONSTRUCTING) is 1, and test that + * with #if/#error in jsfun.c. + */ +#define JSV2F_CONSTRUCT JSINVOKE_CONSTRUCT +#define JSV2F_ITERATOR JSINVOKE_ITERATOR +#define JSV2F_SEARCH_STACK 0x10000 + +extern JSFunction * +js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags); + +extern JSObject * +js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags); + +extern JSObject * +js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags); + +extern void +js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags); + +extern JSObject * +js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent); + +extern JS_FRIEND_API(JSBool) +js_PutCallObject(JSContext *cx, JSStackFrame *fp); + +extern JSBool +js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JSBool +js_GetCallVar(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + +extern JSBool +js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp); + +extern JSBool +js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp); + +extern JSObject * +js_GetArgsObject(JSContext *cx, JSStackFrame *fp); + +extern JS_FRIEND_API(JSBool) +js_PutArgsObject(JSContext *cx, JSStackFrame *fp); + +extern JSBool +js_XDRFunction(JSXDRState *xdr, JSObject **objp); + +typedef enum JSLocalKind { + JSLOCAL_NONE, + JSLOCAL_ARG, + JSLOCAL_VAR, + JSLOCAL_CONST, + JSLOCAL_UPVAR +} JSLocalKind; + +#define JS_UPVAR_LOCAL_NAME_START(fun) ((fun)->nargs + (fun)->u.i.nvars) +#define JS_GET_LOCAL_NAME_COUNT(fun) (JS_UPVAR_LOCAL_NAME_START(fun) + \ + (fun)->u.i.nupvars) + +extern JSBool +js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind); + +/* + * Look up an argument or variable name returning its kind when found or + * JSLOCAL_NONE when no such name exists. When indexp is not null and the name + * exists, *indexp will receive the index of the corresponding argument or + * variable. + */ +extern JSLocalKind +js_LookupLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, uintN *indexp); + +/* + * Functions to work with local names as an array of words. + * + * js_GetLocalNameArray returns the array, or null if we are out of memory. + * This function must not be called when JS_GET_LOCAL_NAME_COUNT(fun) is zero. + * + * The supplied pool is used to allocate the returned array, so the caller is + * obligated to mark and release to free it. + * + * The elements of the array with index less than fun->nargs correspond to the + * names of function formal parameters. An index >= fun->nargs addresses a var + * binding. Use JS_LOCAL_NAME_TO_ATOM to convert array's element to an atom + * pointer. This pointer can be null when the element is for a formal parameter + * corresponding to a destructuring pattern. + * + * If nameWord does not name a formal parameter, use JS_LOCAL_NAME_IS_CONST to + * check if nameWord corresponds to the const declaration. + */ +extern jsuword * +js_GetLocalNameArray(JSContext *cx, JSFunction *fun, struct JSArenaPool *pool); + +#define JS_LOCAL_NAME_TO_ATOM(nameWord) \ + ((JSAtom *) ((nameWord) & ~(jsuword) 1)) + +#define JS_LOCAL_NAME_IS_CONST(nameWord) \ + ((((nameWord) & (jsuword) 1)) != 0) + +extern void +js_FreezeLocalNames(JSContext *cx, JSFunction *fun); + +extern JSBool +js_fun_apply(JSContext *cx, uintN argc, jsval *vp); + +extern JSBool +js_fun_call(JSContext *cx, uintN argc, jsval *vp); + + +JS_END_EXTERN_C + +#endif /* jsfun_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsgc.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsgc.cpp new file mode 100644 index 0000000..ac29021 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsgc.cpp @@ -0,0 +1,3763 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS Mark-and-Sweep Garbage Collector. + * + * This GC allocates fixed-sized things with sizes up to GC_NBYTES_MAX (see + * jsgc.h). It allocates from a special GC arena pool with each arena allocated + * using malloc. It uses an ideally parallel array of flag bytes to hold the + * mark bit, finalizer type index, etc. + * + * XXX swizzle page to freelist for better locality of reference + */ +#include "jsstddef.h" +#include /* for free */ +#include +#include /* for memset used when DEBUG */ +#include "jstypes.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jshash.h" /* Added by JSIFY */ +#include "jsbit.h" +#include "jsclist.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsexn.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsparse.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jstracer.h" + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +/* + * Check if posix_memalign is available. + */ +#if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 || MOZ_MEMORY +# define HAS_POSIX_MEMALIGN 1 +#else +# define HAS_POSIX_MEMALIGN 0 +#endif + +/* + * jemalloc provides posix_memalign. + */ +#ifdef MOZ_MEMORY +extern "C" { +#include "../../memory/jemalloc/jemalloc.h" +} +#endif + +/* + * Include the headers for mmap unless we have posix_memalign and do not + * insist on mmap. + */ +#if JS_GC_USE_MMAP || (!defined JS_GC_USE_MMAP && !HAS_POSIX_MEMALIGN) +# if defined(XP_WIN) +# ifndef JS_GC_USE_MMAP +# define JS_GC_USE_MMAP 1 +# endif +# include +# else +# if defined(XP_UNIX) || defined(XP_BEOS) +# include +# endif +# if _POSIX_MAPPED_FILES > 0 +# ifndef JS_GC_USE_MMAP +# define JS_GC_USE_MMAP 1 +# endif +# include + +/* On Mac OS X MAP_ANONYMOUS is not defined. */ +# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +# endif +# else +# if JS_GC_USE_MMAP +# error "JS_GC_USE_MMAP is set when mmap is not available" +# endif +# endif +# endif +#endif + +/* + * A GC arena contains a fixed number of flag bits for each thing in its heap, + * and supports O(1) lookup of a flag given its thing's address. + * + * To implement this, we allocate things of the same size from a GC arena + * containing GC_ARENA_SIZE bytes aligned on GC_ARENA_SIZE boundary. The + * following picture shows arena's layout: + * + * +------------------------------+--------------------+---------------+ + * | allocation area for GC thing | flags of GC things | JSGCArenaInfo | + * +------------------------------+--------------------+---------------+ + * + * To find the flag bits for the thing we calculate the thing index counting + * from arena's start using: + * + * thingIndex = (thingAddress & GC_ARENA_MASK) / thingSize + * + * The details of flag's lookup depend on thing's kind. For all GC things + * except doubles we use one byte of flags where the 4 bits determine thing's + * type and the rest is used to implement GC marking, finalization and + * locking. We calculate the address of flag's byte using: + * + * flagByteAddress = + * (thingAddress | GC_ARENA_MASK) - sizeof(JSGCArenaInfo) - thingIndex + * + * where + * + * (thingAddress | GC_ARENA_MASK) - sizeof(JSGCArenaInfo) + * + * is the last byte of flags' area. + * + * This implies that the things are allocated from the start of their area and + * flags are allocated from the end. This arrangement avoids a relatively + * expensive calculation of the location of the boundary separating things and + * flags. The boundary's offset from the start of the arena is given by: + * + * thingsPerArena * thingSize + * + * where thingsPerArena is the number of things that the arena can hold: + * + * (GC_ARENA_SIZE - sizeof(JSGCArenaInfo)) / (thingSize + 1). + * + * To allocate doubles we use a specialized arena. It can contain only numbers + * so we do not need the type bits. Moreover, since the doubles do not require + * a finalizer and very few of them are locked via js_LockGCThing API, we use + * just one bit of flags per double to denote if it was marked during the + * marking phase of the GC. The locking is implemented via a hash table. Thus + * for doubles the flag area becomes a bitmap. + * + * JS_GC_USE_MMAP macro governs the choice of the aligned arena allocator. + * When it is true, a platform-dependent function like mmap is used to get + * memory aligned on CPU page boundaries. If the macro is false or undefined, + * posix_memalign is used when available. Otherwise the code uses malloc to + * over-allocate a chunk with js_gcArenasPerChunk aligned arenas. The + * approximate space overhead of this is 1/js_gcArenasPerChunk. For details, + * see NewGCChunk/DestroyGCChunk below. + * + * The code also allocates arenas in chunks when JS_GC_USE_MMAP is 1 to + * minimize the overhead of mmap/munmap. In this case js_gcArenasPerChunk can + * not be a compile-time constant as the system page size is not known until + * runtime. + */ +#if JS_GC_USE_MMAP +static uint32 js_gcArenasPerChunk = 0; +static JSBool js_gcUseMmap = JS_FALSE; +#elif HAS_POSIX_MEMALIGN +# define js_gcArenasPerChunk 1 +#else +# define js_gcArenasPerChunk 7 +#endif + +#if defined(js_gcArenasPerChunk) && js_gcArenasPerChunk == 1 +# define CHUNKED_ARENA_ALLOCATION 0 +#else +# define CHUNKED_ARENA_ALLOCATION 1 +#endif + +#define GC_ARENA_SHIFT 12 +#define GC_ARENA_MASK ((jsuword) JS_BITMASK(GC_ARENA_SHIFT)) +#define GC_ARENA_SIZE JS_BIT(GC_ARENA_SHIFT) + +/* + * JS_GC_ARENA_PAD defines the number of bytes to pad JSGCArenaInfo structure. + * It is used to improve allocation efficiency when using posix_memalign. If + * malloc's implementation uses internal headers, then calling + * + * posix_memalign(&p, GC_ARENA_SIZE, GC_ARENA_SIZE * js_gcArenasPerChunk) + * + * in a sequence leaves holes between allocations of the size GC_ARENA_SIZE + * due to the need to fit headers. JS_GC_ARENA_PAD mitigates that so the code + * calls + * + * posix_memalign(&p, GC_ARENA_SIZE, + * GC_ARENA_SIZE * js_gcArenasPerChunk - JS_GC_ARENA_PAD) + * + * When JS_GC_ARENA_PAD is equal or greater than the number of words in the + * system header, the system can pack all allocations together without holes. + * + * With JS_GC_USE_MEMALIGN we want at least 2 word pad unless posix_memalign + * comes from jemalloc that does not use any headers/trailers. + */ +#ifndef JS_GC_ARENA_PAD +# if HAS_POSIX_MEMALIGN && !MOZ_MEMORY +# define JS_GC_ARENA_PAD (2 * JS_BYTES_PER_WORD) +# else +# define JS_GC_ARENA_PAD 0 +# endif +#endif + +struct JSGCArenaInfo { + /* + * Allocation list for the arena or NULL if the arena holds double values. + */ + JSGCArenaList *list; + + /* + * Pointer to the previous arena in a linked list. The arena can either + * belong to one of JSContext.gcArenaList lists or, when it does not have + * any allocated GC things, to the list of free arenas in the chunk with + * head stored in JSGCChunkInfo.lastFreeArena. + */ + JSGCArenaInfo *prev; + +#if !CHUNKED_ARENA_ALLOCATION + jsuword prevUntracedPage; +#else + /* + * A link field for the list of arenas with marked but not yet traced + * things. The field is encoded as arena's page to share the space with + * firstArena and arenaIndex fields. + */ + jsuword prevUntracedPage : JS_BITS_PER_WORD - GC_ARENA_SHIFT; + + /* + * When firstArena is false, the index of arena in the chunk. When + * firstArena is true, the index of a free arena holding JSGCChunkInfo or + * NO_FREE_ARENAS if there are no free arenas in the chunk. + * + * GET_ARENA_INDEX and GET_CHUNK_INFO_INDEX are convenience macros to + * access either of indexes. + */ + jsuword arenaIndex : GC_ARENA_SHIFT - 1; + + /* Flag indicating if the arena is the first in the chunk. */ + jsuword firstArena : 1; +#endif + + union { + jsuword untracedThings; /* bitset for fast search of marked + but not yet traced things */ + JSBool hasMarkedDoubles; /* the arena has marked doubles */ + } u; + +#if JS_GC_ARENA_PAD != 0 + uint8 pad[JS_GC_ARENA_PAD]; +#endif +}; + +/* + * Verify that the bit fields are indeed shared and JSGCArenaInfo is as small + * as possible. The code does not rely on this check so if on a particular + * platform this does not compile, then, as a workaround, comment the assert + * out and submit a bug report. + */ +JS_STATIC_ASSERT(offsetof(JSGCArenaInfo, u) == 3 * sizeof(jsuword)); + +/* + * Macros to convert between JSGCArenaInfo, the start address of the arena and + * arena's page defined as (start address) >> GC_ARENA_SHIFT. + */ +#define ARENA_INFO_OFFSET (GC_ARENA_SIZE - (uint32) sizeof(JSGCArenaInfo)) + +#define IS_ARENA_INFO_ADDRESS(arena) \ + (((jsuword) (arena) & GC_ARENA_MASK) == ARENA_INFO_OFFSET) + +#define ARENA_START_TO_INFO(arenaStart) \ + (JS_ASSERT(((arenaStart) & (jsuword) GC_ARENA_MASK) == 0), \ + (JSGCArenaInfo *) ((arenaStart) + (jsuword) ARENA_INFO_OFFSET)) + +#define ARENA_INFO_TO_START(arena) \ + (JS_ASSERT(IS_ARENA_INFO_ADDRESS(arena)), \ + (jsuword) (arena) & ~(jsuword) GC_ARENA_MASK) + +#define ARENA_PAGE_TO_INFO(arenaPage) \ + (JS_ASSERT(arenaPage != 0), \ + JS_ASSERT(!((jsuword)(arenaPage) >> (JS_BITS_PER_WORD-GC_ARENA_SHIFT))), \ + ARENA_START_TO_INFO((arenaPage) << GC_ARENA_SHIFT)) + +#define ARENA_INFO_TO_PAGE(arena) \ + (JS_ASSERT(IS_ARENA_INFO_ADDRESS(arena)), \ + ((jsuword) (arena) >> GC_ARENA_SHIFT)) + +#define GET_ARENA_INFO(chunk, index) \ + (JS_ASSERT((index) < js_gcArenasPerChunk), \ + ARENA_START_TO_INFO(chunk + ((index) << GC_ARENA_SHIFT))) + +#if CHUNKED_ARENA_ALLOCATION +/* + * Definitions for allocating arenas in chunks. + * + * All chunks that have at least one free arena are put on the doubly-linked + * list with the head stored in JSRuntime.gcChunkList. JSGCChunkInfo contains + * the head of the chunk's free arena list together with the link fields for + * gcChunkList. + * + * Structure stored in one of chunk's free arenas. GET_CHUNK_INFO_INDEX gives + * the index of this arena. When all arenas in the chunk are used, it is + * removed from the list and the index is set to NO_FREE_ARENAS indicating + * that the chunk is not on gcChunkList and has no JSGCChunkInfo available. + */ + +struct JSGCChunkInfo { + JSGCChunkInfo **prevp; + JSGCChunkInfo *next; + JSGCArenaInfo *lastFreeArena; + uint32 numFreeArenas; +}; + +#define NO_FREE_ARENAS JS_BITMASK(GC_ARENA_SHIFT - 1) + +#ifdef js_gcArenasPerChunk +JS_STATIC_ASSERT(1 <= js_gcArenasPerChunk && + js_gcArenasPerChunk <= NO_FREE_ARENAS); +#endif + +#define GET_ARENA_CHUNK(arena, index) \ + (JS_ASSERT(GET_ARENA_INDEX(arena) == index), \ + ARENA_INFO_TO_START(arena) - ((index) << GC_ARENA_SHIFT)) + +#define GET_ARENA_INDEX(arena) \ + ((arena)->firstArena ? 0 : (uint32) (arena)->arenaIndex) + +#define GET_CHUNK_INFO_INDEX(chunk) \ + ((uint32) ARENA_START_TO_INFO(chunk)->arenaIndex) + +#define SET_CHUNK_INFO_INDEX(chunk, index) \ + (JS_ASSERT((index) < js_gcArenasPerChunk || (index) == NO_FREE_ARENAS), \ + (void) (ARENA_START_TO_INFO(chunk)->arenaIndex = (jsuword) (index))) + +#define GET_CHUNK_INFO(chunk, infoIndex) \ + (JS_ASSERT(GET_CHUNK_INFO_INDEX(chunk) == (infoIndex)), \ + JS_ASSERT((uint32) (infoIndex) < js_gcArenasPerChunk), \ + (JSGCChunkInfo *) ((chunk) + ((infoIndex) << GC_ARENA_SHIFT))) + +#define CHUNK_INFO_TO_INDEX(ci) \ + GET_ARENA_INDEX(ARENA_START_TO_INFO((jsuword)ci)) + +#endif + +/* + * Macros for GC-thing operations. + */ +#define THINGS_PER_ARENA(thingSize) \ + ((GC_ARENA_SIZE - (uint32) sizeof(JSGCArenaInfo)) / ((thingSize) + 1U)) + +#define THING_TO_ARENA(thing) \ + ((JSGCArenaInfo *)(((jsuword) (thing) | GC_ARENA_MASK) + \ + 1 - sizeof(JSGCArenaInfo))) + +#define THING_TO_INDEX(thing, thingSize) \ + ((uint32) ((jsuword) (thing) & GC_ARENA_MASK) / (uint32) (thingSize)) + +#define THING_FLAGS_END(arena) ((uint8 *)(arena)) + +#define THING_FLAGP(arena, thingIndex) \ + (JS_ASSERT((jsuword) (thingIndex) \ + < (jsuword) THINGS_PER_ARENA((arena)->list->thingSize)), \ + (uint8 *)(arena) - 1 - (thingIndex)) + +#define THING_TO_FLAGP(thing, thingSize) \ + THING_FLAGP(THING_TO_ARENA(thing), THING_TO_INDEX(thing, thingSize)) + +#define FLAGP_TO_ARENA(flagp) THING_TO_ARENA(flagp) + +#define FLAGP_TO_INDEX(flagp) \ + (JS_ASSERT(((jsuword) (flagp) & GC_ARENA_MASK) < ARENA_INFO_OFFSET), \ + (ARENA_INFO_OFFSET - 1 - (uint32) ((jsuword) (flagp) & GC_ARENA_MASK))) + +#define FLAGP_TO_THING(flagp, thingSize) \ + (JS_ASSERT(((jsuword) (flagp) & GC_ARENA_MASK) >= \ + (ARENA_INFO_OFFSET - THINGS_PER_ARENA(thingSize))), \ + (JSGCThing *)(((jsuword) (flagp) & ~GC_ARENA_MASK) + \ + (thingSize) * FLAGP_TO_INDEX(flagp))) + +/* + * Macros for the specialized arena for doubles. + * + * DOUBLES_PER_ARENA defines the maximum number of doubles that the arena can + * hold. We find it as the following. Let n be the number of doubles in the + * arena. Together with the bitmap of flags and JSGCArenaInfo they should fit + * the arena. Hence DOUBLES_PER_ARENA or n_max is the maximum value of n for + * which the following holds: + * + * n*s + ceil(n/B) <= M (1) + * + * where "/" denotes normal real division, + * ceil(r) gives the least integer not smaller than the number r, + * s is the number of words in jsdouble, + * B is number of bits per word or B == JS_BITS_PER_WORD + * M is the number of words in the arena before JSGCArenaInfo or + * M == (GC_ARENA_SIZE - sizeof(JSGCArenaInfo)) / sizeof(jsuword). + * M == ARENA_INFO_OFFSET / sizeof(jsuword) + * + * We rewrite the inequality as + * + * n*B*s/B + ceil(n/B) <= M, + * ceil(n*B*s/B + n/B) <= M, + * ceil(n*(B*s + 1)/B) <= M (2) + * + * We define a helper function e(n, s, B), + * + * e(n, s, B) := ceil(n*(B*s + 1)/B) - n*(B*s + 1)/B, 0 <= e(n, s, B) < 1. + * + * It gives: + * + * n*(B*s + 1)/B + e(n, s, B) <= M, + * n + e*B/(B*s + 1) <= M*B/(B*s + 1) + * + * We apply the floor function to both sides of the last equation, where + * floor(r) gives the biggest integer not greater than r. As a consequence we + * have: + * + * floor(n + e*B/(B*s + 1)) <= floor(M*B/(B*s + 1)), + * n + floor(e*B/(B*s + 1)) <= floor(M*B/(B*s + 1)), + * n <= floor(M*B/(B*s + 1)), (3) + * + * where floor(e*B/(B*s + 1)) is zero as e*B/(B*s + 1) < B/(B*s + 1) < 1. + * Thus any n that satisfies the original constraint (1) or its equivalent (2), + * must also satisfy (3). That is, we got an upper estimate for the maximum + * value of n. Lets show that this upper estimate, + * + * floor(M*B/(B*s + 1)), (4) + * + * also satisfies (1) and, as such, gives the required maximum value. + * Substituting it into (2) gives: + * + * ceil(floor(M*B/(B*s + 1))*(B*s + 1)/B) == ceil(floor(M/X)*X) + * + * where X == (B*s + 1)/B > 1. But then floor(M/X)*X <= M/X*X == M and + * + * ceil(floor(M/X)*X) <= ceil(M) == M. + * + * Thus the value of (4) gives the maximum n satisfying (1). + * + * For the final result we observe that in (4) + * + * M*B == ARENA_INFO_OFFSET / sizeof(jsuword) * JS_BITS_PER_WORD + * == ARENA_INFO_OFFSET * JS_BITS_PER_BYTE + * + * and + * + * B*s == JS_BITS_PER_WORD * sizeof(jsdouble) / sizeof(jsuword) + * == JS_BITS_PER_DOUBLE. + */ +#define DOUBLES_PER_ARENA \ + ((ARENA_INFO_OFFSET * JS_BITS_PER_BYTE) / (JS_BITS_PER_DOUBLE + 1)) + +/* + * Check that ARENA_INFO_OFFSET and sizeof(jsdouble) divides sizeof(jsuword). + */ +JS_STATIC_ASSERT(ARENA_INFO_OFFSET % sizeof(jsuword) == 0); +JS_STATIC_ASSERT(sizeof(jsdouble) % sizeof(jsuword) == 0); +JS_STATIC_ASSERT(sizeof(jsbitmap) == sizeof(jsuword)); + +#define DOUBLES_ARENA_BITMAP_WORDS \ + (JS_HOWMANY(DOUBLES_PER_ARENA, JS_BITS_PER_WORD)) + +/* Check that DOUBLES_PER_ARENA indeed maximises (1). */ +JS_STATIC_ASSERT(DOUBLES_PER_ARENA * sizeof(jsdouble) + + DOUBLES_ARENA_BITMAP_WORDS * sizeof(jsuword) <= + ARENA_INFO_OFFSET); + +JS_STATIC_ASSERT((DOUBLES_PER_ARENA + 1) * sizeof(jsdouble) + + sizeof(jsuword) * + JS_HOWMANY((DOUBLES_PER_ARENA + 1), JS_BITS_PER_WORD) > + ARENA_INFO_OFFSET); + +/* + * When DOUBLES_PER_ARENA % BITS_PER_DOUBLE_FLAG_UNIT != 0, some bits in the + * last byte of the occupation bitmap are unused. + */ +#define UNUSED_DOUBLE_BITMAP_BITS \ + (DOUBLES_ARENA_BITMAP_WORDS * JS_BITS_PER_WORD - DOUBLES_PER_ARENA) + +JS_STATIC_ASSERT(UNUSED_DOUBLE_BITMAP_BITS < JS_BITS_PER_WORD); + +#define DOUBLES_ARENA_BITMAP_OFFSET \ + (ARENA_INFO_OFFSET - DOUBLES_ARENA_BITMAP_WORDS * sizeof(jsuword)) + +#define CHECK_DOUBLE_ARENA_INFO(arenaInfo) \ + (JS_ASSERT(IS_ARENA_INFO_ADDRESS(arenaInfo)), \ + JS_ASSERT(!(arenaInfo)->list)) \ + +/* + * Get the start of the bitmap area containing double mark flags in the arena. + * To access the flag the code uses + * + * JS_TEST_BIT(bitmapStart, index) + * + * That is, compared with the case of arenas with non-double things, we count + * flags from the start of the bitmap area, not from the end. + */ +#define DOUBLE_ARENA_BITMAP(arenaInfo) \ + (CHECK_DOUBLE_ARENA_INFO(arenaInfo), \ + (jsbitmap *) arenaInfo - DOUBLES_ARENA_BITMAP_WORDS) + +#define DOUBLE_THING_TO_INDEX(thing) \ + (CHECK_DOUBLE_ARENA_INFO(THING_TO_ARENA(thing)), \ + JS_ASSERT(((jsuword) (thing) & GC_ARENA_MASK) < \ + DOUBLES_ARENA_BITMAP_OFFSET), \ + ((uint32) (((jsuword) (thing) & GC_ARENA_MASK) / sizeof(jsdouble)))) + +static void +ClearDoubleArenaFlags(JSGCArenaInfo *a) +{ + jsbitmap *bitmap, mask; + uintN nused; + + /* + * When some high bits in the last byte of the double occupation bitmap + * are unused, we must set them. Otherwise RefillDoubleFreeList will + * assume that they corresponds to some free cells and tries to allocate + * them. + * + * Note that the code works correctly with UNUSED_DOUBLE_BITMAP_BITS == 0. + */ + bitmap = DOUBLE_ARENA_BITMAP(a); + memset(bitmap, 0, (DOUBLES_ARENA_BITMAP_WORDS - 1) * sizeof *bitmap); + mask = ((jsbitmap) 1 << UNUSED_DOUBLE_BITMAP_BITS) - 1; + nused = JS_BITS_PER_WORD - UNUSED_DOUBLE_BITMAP_BITS; + bitmap[DOUBLES_ARENA_BITMAP_WORDS - 1] = mask << nused; +} + +static JS_ALWAYS_INLINE JSBool +IsMarkedDouble(JSGCArenaInfo *a, uint32 index) +{ + jsbitmap *bitmap; + + JS_ASSERT(a->u.hasMarkedDoubles); + bitmap = DOUBLE_ARENA_BITMAP(a); + return JS_TEST_BIT(bitmap, index); +} + +/* + * JSRuntime.gcDoubleArenaList.nextDoubleFlags points either to: + * + * 1. The next byte in the bitmap area for doubles to check for unmarked + * (or free) doubles. + * 2. Or to the end of the bitmap area when all GC cells of the arena are + * allocated. + * 3. Or to a special sentinel value indicating that there are no arenas + * to check for unmarked doubles. + * + * We set the sentinel to ARENA_INFO_OFFSET so the single check + * + * ((jsuword) nextDoubleFlags & GC_ARENA_MASK) == ARENA_INFO_OFFSET + * + * will cover both the second and the third cases. + */ +#define DOUBLE_BITMAP_SENTINEL ((jsbitmap *) ARENA_INFO_OFFSET) + +#ifdef JS_THREADSAFE +/* + * The maximum number of things to put on the local free list by taking + * several things from the global free list or from the tail of the last + * allocated arena to amortize the cost of rt->gcLock. + * + * We use number 8 based on benchmarks from bug 312238. + */ +#define MAX_THREAD_LOCAL_THINGS 8 + +#endif + +JS_STATIC_ASSERT(sizeof(JSStackHeader) >= 2 * sizeof(jsval)); + +JS_STATIC_ASSERT(sizeof(JSGCThing) >= sizeof(JSString)); +JS_STATIC_ASSERT(sizeof(JSGCThing) >= sizeof(jsdouble)); + +/* We want to use all the available GC thing space for object's slots. */ +JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(JSGCThing) == 0); + +/* + * Ensure that JSObject is allocated from a different GC-list rather than + * jsdouble and JSString so we can easily finalize JSObject before these 2 + * types of GC things. See comments in js_GC. + */ +JS_STATIC_ASSERT(GC_FREELIST_INDEX(sizeof(JSString)) != + GC_FREELIST_INDEX(sizeof(JSObject))); +JS_STATIC_ASSERT(GC_FREELIST_INDEX(sizeof(jsdouble)) != + GC_FREELIST_INDEX(sizeof(JSObject))); + +/* + * JSPtrTable capacity growth descriptor. The table grows by powers of two + * starting from capacity JSPtrTableInfo.minCapacity, but switching to linear + * growth when capacity reaches JSPtrTableInfo.linearGrowthThreshold. + */ +typedef struct JSPtrTableInfo { + uint16 minCapacity; + uint16 linearGrowthThreshold; +} JSPtrTableInfo; + +#define GC_ITERATOR_TABLE_MIN 4 +#define GC_ITERATOR_TABLE_LINEAR 1024 + +static const JSPtrTableInfo iteratorTableInfo = { + GC_ITERATOR_TABLE_MIN, + GC_ITERATOR_TABLE_LINEAR +}; + +/* Calculate table capacity based on the current value of JSPtrTable.count. */ +static size_t +PtrTableCapacity(size_t count, const JSPtrTableInfo *info) +{ + size_t linear, log, capacity; + + linear = info->linearGrowthThreshold; + JS_ASSERT(info->minCapacity <= linear); + + if (count == 0) { + capacity = 0; + } else if (count < linear) { + log = JS_CEILING_LOG2W(count); + JS_ASSERT(log != JS_BITS_PER_WORD); + capacity = (size_t)1 << log; + if (capacity < info->minCapacity) + capacity = info->minCapacity; + } else { + capacity = JS_ROUNDUP(count, linear); + } + + JS_ASSERT(capacity >= count); + return capacity; +} + +static void +FreePtrTable(JSPtrTable *table, const JSPtrTableInfo *info) +{ + if (table->array) { + JS_ASSERT(table->count > 0); + free(table->array); + table->array = NULL; + table->count = 0; + } + JS_ASSERT(table->count == 0); +} + +static JSBool +AddToPtrTable(JSContext *cx, JSPtrTable *table, const JSPtrTableInfo *info, + void *ptr) +{ + size_t count, capacity; + void **array; + + count = table->count; + capacity = PtrTableCapacity(count, info); + + if (count == capacity) { + if (capacity < info->minCapacity) { + JS_ASSERT(capacity == 0); + JS_ASSERT(!table->array); + capacity = info->minCapacity; + } else { + /* + * Simplify the overflow detection assuming pointer is bigger + * than byte. + */ + JS_STATIC_ASSERT(2 <= sizeof table->array[0]); + capacity = (capacity < info->linearGrowthThreshold) + ? 2 * capacity + : capacity + info->linearGrowthThreshold; + if (capacity > (size_t)-1 / sizeof table->array[0]) + goto bad; + } + array = (void **) realloc(table->array, + capacity * sizeof table->array[0]); + if (!array) + goto bad; +#ifdef DEBUG + memset(array + count, JS_FREE_PATTERN, + (capacity - count) * sizeof table->array[0]); +#endif + table->array = array; + } + + table->array[count] = ptr; + table->count = count + 1; + + return JS_TRUE; + + bad: + JS_ReportOutOfMemory(cx); + return JS_FALSE; +} + +static void +ShrinkPtrTable(JSPtrTable *table, const JSPtrTableInfo *info, + size_t newCount) +{ + size_t oldCapacity, capacity; + void **array; + + JS_ASSERT(newCount <= table->count); + if (newCount == table->count) + return; + + oldCapacity = PtrTableCapacity(table->count, info); + table->count = newCount; + capacity = PtrTableCapacity(newCount, info); + + if (oldCapacity != capacity) { + array = table->array; + JS_ASSERT(array); + if (capacity == 0) { + free(array); + table->array = NULL; + return; + } + array = (void **) realloc(array, capacity * sizeof array[0]); + if (array) + table->array = array; + } +#ifdef DEBUG + memset(table->array + newCount, JS_FREE_PATTERN, + (capacity - newCount) * sizeof table->array[0]); +#endif +} + +#ifdef JS_GCMETER +# define METER(x) ((void) (x)) +# define METER_IF(condition, x) ((void) ((condition) && (x))) +#else +# define METER(x) ((void) 0) +# define METER_IF(condition, x) ((void) 0) +#endif + +#define METER_UPDATE_MAX(maxLval, rval) \ + METER_IF((maxLval) < (rval), (maxLval) = (rval)) + +#if JS_GC_USE_MMAP || !HAS_POSIX_MEMALIGN + +/* + * For chunks allocated via over-sized malloc, get a pointer to store the gap + * between the malloc's result and the first arena in the chunk. + */ +static uint32 * +GetMallocedChunkGapPtr(jsuword chunk) +{ + JS_ASSERT((chunk & GC_ARENA_MASK) == 0); + + /* Use the memory after the chunk, see NewGCChunk for details. */ + return (uint32 *) (chunk + (js_gcArenasPerChunk << GC_ARENA_SHIFT)); +} + +#endif + +static jsuword +NewGCChunk(void) +{ + void *p; + +#if JS_GC_USE_MMAP + if (js_gcUseMmap) { +# if defined(XP_WIN) + p = VirtualAlloc(NULL, js_gcArenasPerChunk << GC_ARENA_SHIFT, + MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + return (jsuword) p; +# else + p = mmap(NULL, js_gcArenasPerChunk << GC_ARENA_SHIFT, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + return (p == MAP_FAILED) ? 0 : (jsuword) p; +# endif + } +#endif + +#if HAS_POSIX_MEMALIGN + if (0 != posix_memalign(&p, GC_ARENA_SIZE, + GC_ARENA_SIZE * js_gcArenasPerChunk - + JS_GC_ARENA_PAD)) { + return 0; + } + return (jsuword) p; +#else + /* + * Implement chunk allocation using oversized malloc if mmap and + * posix_memalign are not available. + * + * Since malloc allocates pointers aligned on the word boundary, to get + * js_gcArenasPerChunk aligned arenas, we need to malloc only + * + * ((js_gcArenasPerChunk + 1) << GC_ARENA_SHIFT) - sizeof(size_t) + * + * bytes. But since we stores the gap between the malloced pointer and the + * first arena in the chunk after the chunk, we need to ask for + * + * ((js_gcArenasPerChunk + 1) << GC_ARENA_SHIFT) + * + * bytes to ensure that we always have room to store the gap. + */ + p = malloc((js_gcArenasPerChunk + 1) << GC_ARENA_SHIFT); + if (!p) + return 0; + + { + jsuword chunk; + + chunk = ((jsuword) p + GC_ARENA_MASK) & ~GC_ARENA_MASK; + *GetMallocedChunkGapPtr(chunk) = (uint32) (chunk - (jsuword) p); + return chunk; + } +#endif +} + +static void +DestroyGCChunk(jsuword chunk) +{ + JS_ASSERT((chunk & GC_ARENA_MASK) == 0); +#if JS_GC_USE_MMAP + if (js_gcUseMmap) { +# if defined(XP_WIN) + VirtualFree((void *) chunk, 0, MEM_RELEASE); +# elif defined(SOLARIS) + munmap((char *) chunk, js_gcArenasPerChunk << GC_ARENA_SHIFT); +# else + munmap((void *) chunk, js_gcArenasPerChunk << GC_ARENA_SHIFT); +# endif + return; + } +#endif + +#if HAS_POSIX_MEMALIGN + free((void *) chunk); +#else + /* See comments in NewGCChunk. */ + JS_ASSERT(*GetMallocedChunkGapPtr(chunk) < GC_ARENA_SIZE); + free((void *) (chunk - *GetMallocedChunkGapPtr(chunk))); +#endif +} + +#if CHUNKED_ARENA_ALLOCATION + +static void +AddChunkToList(JSRuntime *rt, JSGCChunkInfo *ci) +{ + ci->prevp = &rt->gcChunkList; + ci->next = rt->gcChunkList; + if (rt->gcChunkList) { + JS_ASSERT(rt->gcChunkList->prevp == &rt->gcChunkList); + rt->gcChunkList->prevp = &ci->next; + } + rt->gcChunkList = ci; +} + +static void +RemoveChunkFromList(JSRuntime *rt, JSGCChunkInfo *ci) +{ + *ci->prevp = ci->next; + if (ci->next) { + JS_ASSERT(ci->next->prevp == &ci->next); + ci->next->prevp = ci->prevp; + } +} + +#endif + +static JSGCArenaInfo * +NewGCArena(JSRuntime *rt) +{ + jsuword chunk; + JSGCArenaInfo *a; + + if (rt->gcBytes >= rt->gcMaxBytes) + return NULL; + +#if CHUNKED_ARENA_ALLOCATION + if (js_gcArenasPerChunk == 1) { +#endif + chunk = NewGCChunk(); + if (chunk == 0) + return NULL; + a = ARENA_START_TO_INFO(chunk); +#if CHUNKED_ARENA_ALLOCATION + } else { + JSGCChunkInfo *ci; + uint32 i; + JSGCArenaInfo *aprev; + + ci = rt->gcChunkList; + if (!ci) { + chunk = NewGCChunk(); + if (chunk == 0) + return NULL; + JS_ASSERT((chunk & GC_ARENA_MASK) == 0); + a = GET_ARENA_INFO(chunk, 0); + a->firstArena = JS_TRUE; + a->arenaIndex = 0; + aprev = NULL; + i = 0; + do { + a->prev = aprev; + aprev = a; + ++i; + a = GET_ARENA_INFO(chunk, i); + a->firstArena = JS_FALSE; + a->arenaIndex = i; + } while (i != js_gcArenasPerChunk - 1); + ci = GET_CHUNK_INFO(chunk, 0); + ci->lastFreeArena = aprev; + ci->numFreeArenas = js_gcArenasPerChunk - 1; + AddChunkToList(rt, ci); + } else { + JS_ASSERT(ci->prevp == &rt->gcChunkList); + a = ci->lastFreeArena; + aprev = a->prev; + if (!aprev) { + JS_ASSERT(ci->numFreeArenas == 1); + JS_ASSERT(ARENA_INFO_TO_START(a) == (jsuword) ci); + RemoveChunkFromList(rt, ci); + chunk = GET_ARENA_CHUNK(a, GET_ARENA_INDEX(a)); + SET_CHUNK_INFO_INDEX(chunk, NO_FREE_ARENAS); + } else { + JS_ASSERT(ci->numFreeArenas >= 2); + JS_ASSERT(ARENA_INFO_TO_START(a) != (jsuword) ci); + ci->lastFreeArena = aprev; + ci->numFreeArenas--; + } + } + } +#endif + + rt->gcBytes += GC_ARENA_SIZE; + a->prevUntracedPage = 0; + memset(&a->u, 0, sizeof(a->u)); + + return a; +} + +static void +DestroyGCArenas(JSRuntime *rt, JSGCArenaInfo *last) +{ + JSGCArenaInfo *a; + + while (last) { + a = last; + last = last->prev; + + METER(rt->gcStats.afree++); + JS_ASSERT(rt->gcBytes >= GC_ARENA_SIZE); + rt->gcBytes -= GC_ARENA_SIZE; + +#if CHUNKED_ARENA_ALLOCATION + if (js_gcArenasPerChunk == 1) { +#endif + DestroyGCChunk(ARENA_INFO_TO_START(a)); +#if CHUNKED_ARENA_ALLOCATION + } else { + uint32 arenaIndex; + jsuword chunk; + uint32 chunkInfoIndex; + JSGCChunkInfo *ci; +# ifdef DEBUG + jsuword firstArena; + + firstArena = a->firstArena; + arenaIndex = a->arenaIndex; + memset((void *) ARENA_INFO_TO_START(a), JS_FREE_PATTERN, + GC_ARENA_SIZE - JS_GC_ARENA_PAD); + a->firstArena = firstArena; + a->arenaIndex = arenaIndex; +# endif + arenaIndex = GET_ARENA_INDEX(a); + chunk = GET_ARENA_CHUNK(a, arenaIndex); + chunkInfoIndex = GET_CHUNK_INFO_INDEX(chunk); + if (chunkInfoIndex == NO_FREE_ARENAS) { + chunkInfoIndex = arenaIndex; + SET_CHUNK_INFO_INDEX(chunk, arenaIndex); + ci = GET_CHUNK_INFO(chunk, chunkInfoIndex); + a->prev = NULL; + ci->lastFreeArena = a; + ci->numFreeArenas = 1; + AddChunkToList(rt, ci); + } else { + JS_ASSERT(chunkInfoIndex != arenaIndex); + ci = GET_CHUNK_INFO(chunk, chunkInfoIndex); + JS_ASSERT(ci->numFreeArenas != 0); + JS_ASSERT(ci->lastFreeArena); + JS_ASSERT(a != ci->lastFreeArena); + if (ci->numFreeArenas == js_gcArenasPerChunk - 1) { + RemoveChunkFromList(rt, ci); + DestroyGCChunk(chunk); + } else { + ++ci->numFreeArenas; + a->prev = ci->lastFreeArena; + ci->lastFreeArena = a; + } + } + } +# endif + } +} + +static void +InitGCArenaLists(JSRuntime *rt) +{ + uintN i, thingSize; + JSGCArenaList *arenaList; + + for (i = 0; i < GC_NUM_FREELISTS; i++) { + arenaList = &rt->gcArenaList[i]; + thingSize = GC_FREELIST_NBYTES(i); + JS_ASSERT((size_t)(uint16)thingSize == thingSize); + arenaList->last = NULL; + arenaList->lastCount = (uint16) THINGS_PER_ARENA(thingSize); + arenaList->thingSize = (uint16) thingSize; + arenaList->freeList = NULL; + } + rt->gcDoubleArenaList.first = NULL; + rt->gcDoubleArenaList.nextDoubleFlags = DOUBLE_BITMAP_SENTINEL; +} + +static void +FinishGCArenaLists(JSRuntime *rt) +{ + uintN i; + JSGCArenaList *arenaList; + + for (i = 0; i < GC_NUM_FREELISTS; i++) { + arenaList = &rt->gcArenaList[i]; + DestroyGCArenas(rt, arenaList->last); + arenaList->last = NULL; + arenaList->lastCount = THINGS_PER_ARENA(arenaList->thingSize); + arenaList->freeList = NULL; + } + DestroyGCArenas(rt, rt->gcDoubleArenaList.first); + rt->gcDoubleArenaList.first = NULL; + rt->gcDoubleArenaList.nextDoubleFlags = DOUBLE_BITMAP_SENTINEL; + + rt->gcBytes = 0; + JS_ASSERT(rt->gcChunkList == 0); +} + +/* + * This function must not be called when thing is jsdouble. + */ +static uint8 * +GetGCThingFlags(void *thing) +{ + JSGCArenaInfo *a; + uint32 index; + + a = THING_TO_ARENA(thing); + index = THING_TO_INDEX(thing, a->list->thingSize); + return THING_FLAGP(a, index); +} + +/* + * This function returns null when thing is jsdouble. + */ +static uint8 * +GetGCThingFlagsOrNull(void *thing) +{ + JSGCArenaInfo *a; + uint32 index; + + a = THING_TO_ARENA(thing); + if (!a->list) + return NULL; + index = THING_TO_INDEX(thing, a->list->thingSize); + return THING_FLAGP(a, index); +} + +intN +js_GetExternalStringGCType(JSString *str) +{ + uintN type; + + type = (uintN) *GetGCThingFlags(str) & GCF_TYPEMASK; + JS_ASSERT(type == GCX_STRING || type >= GCX_EXTERNAL_STRING); + return (type == GCX_STRING) ? -1 : (intN) (type - GCX_EXTERNAL_STRING); +} + +static uint32 +MapGCFlagsToTraceKind(uintN flags) +{ + uint32 type; + + type = flags & GCF_TYPEMASK; + JS_ASSERT(type != GCX_DOUBLE); + JS_ASSERT(type < GCX_NTYPES); + return (type < GCX_EXTERNAL_STRING) ? type : JSTRACE_STRING; +} + +JS_FRIEND_API(uint32) +js_GetGCThingTraceKind(void *thing) +{ + JSGCArenaInfo *a; + uint32 index; + + a = THING_TO_ARENA(thing); + if (!a->list) + return JSTRACE_DOUBLE; + + index = THING_TO_INDEX(thing, a->list->thingSize); + return MapGCFlagsToTraceKind(*THING_FLAGP(a, index)); +} + +JSRuntime* +js_GetGCStringRuntime(JSString *str) +{ + JSGCArenaList *list; + + list = THING_TO_ARENA(str)->list; + + JS_ASSERT(list->thingSize == sizeof(JSGCThing)); + JS_ASSERT(GC_FREELIST_INDEX(sizeof(JSGCThing)) == 0); + + return (JSRuntime *)((uint8 *)list - offsetof(JSRuntime, gcArenaList)); +} + +JSBool +js_IsAboutToBeFinalized(JSContext *cx, void *thing) +{ + JSGCArenaInfo *a; + uint32 index, flags; + + a = THING_TO_ARENA(thing); + if (!a->list) { + /* + * Check if arena has no marked doubles. In that case the bitmap with + * the mark flags contains all garbage as it is initialized only when + * marking the first double in the arena. + */ + if (!a->u.hasMarkedDoubles) + return JS_TRUE; + index = DOUBLE_THING_TO_INDEX(thing); + return !IsMarkedDouble(a, index); + } + index = THING_TO_INDEX(thing, a->list->thingSize); + flags = *THING_FLAGP(a, index); + return !(flags & (GCF_MARK | GCF_LOCK | GCF_FINAL)); +} + +/* This is compatible with JSDHashEntryStub. */ +typedef struct JSGCRootHashEntry { + JSDHashEntryHdr hdr; + void *root; + const char *name; +} JSGCRootHashEntry; + +/* Initial size of the gcRootsHash table (SWAG, small enough to amortize). */ +#define GC_ROOTS_SIZE 256 + +#if CHUNKED_ARENA_ALLOCATION + +/* + * For a CPU with extremely large pages using them for GC things wastes + * too much memory. + */ +# define GC_ARENAS_PER_CPU_PAGE_LIMIT JS_BIT(18 - GC_ARENA_SHIFT) + +JS_STATIC_ASSERT(GC_ARENAS_PER_CPU_PAGE_LIMIT <= NO_FREE_ARENAS); + +#endif + +JSBool +js_InitGC(JSRuntime *rt, uint32 maxbytes) +{ +#if JS_GC_USE_MMAP + if (js_gcArenasPerChunk == 0) { + size_t cpuPageSize, arenasPerPage; +# if defined(XP_WIN) + SYSTEM_INFO si; + + GetSystemInfo(&si); + cpuPageSize = si.dwPageSize; + +# elif defined(XP_UNIX) || defined(XP_BEOS) + cpuPageSize = (size_t) sysconf(_SC_PAGESIZE); +# else +# error "Not implemented" +# endif + /* cpuPageSize is a power of 2. */ + JS_ASSERT((cpuPageSize & (cpuPageSize - 1)) == 0); + arenasPerPage = cpuPageSize >> GC_ARENA_SHIFT; +#ifdef DEBUG + if (arenasPerPage == 0) { + fprintf(stderr, +"JS engine warning: the size of the CPU page, %u bytes, is too low to use\n" +"paged allocation for the garbage collector. Please report this.\n", + (unsigned) cpuPageSize); + } +#endif + if (arenasPerPage - 1 <= (size_t) (GC_ARENAS_PER_CPU_PAGE_LIMIT - 1)) { + /* + * Use at least 4 GC arenas per paged allocation chunk to minimize + * the overhead of mmap/VirtualAlloc. + */ + js_gcUseMmap = JS_TRUE; + js_gcArenasPerChunk = JS_MAX((uint32) arenasPerPage, 4); + } else { + js_gcUseMmap = JS_FALSE; + js_gcArenasPerChunk = 7; + } + } + JS_ASSERT(1 <= js_gcArenasPerChunk && + js_gcArenasPerChunk <= NO_FREE_ARENAS); +#endif + + InitGCArenaLists(rt); + if (!JS_DHashTableInit(&rt->gcRootsHash, JS_DHashGetStubOps(), NULL, + sizeof(JSGCRootHashEntry), GC_ROOTS_SIZE)) { + rt->gcRootsHash.ops = NULL; + return JS_FALSE; + } + rt->gcLocksHash = NULL; /* create lazily */ + + /* + * Separate gcMaxMallocBytes from gcMaxBytes but initialize to maxbytes + * for default backward API compatibility. + */ + rt->gcMaxBytes = rt->gcMaxMallocBytes = maxbytes; + rt->gcEmptyArenaPoolLifespan = 30000; + + METER(memset(&rt->gcStats, 0, sizeof rt->gcStats)); + return JS_TRUE; +} + +#ifdef JS_GCMETER + +static void +UpdateArenaStats(JSGCArenaStats *st, uint32 nlivearenas, uint32 nkilledArenas, + uint32 nthings) +{ + size_t narenas; + + narenas = nlivearenas + nkilledArenas; + JS_ASSERT(narenas >= st->livearenas); + + st->newarenas = narenas - st->livearenas; + st->narenas = narenas; + st->livearenas = nlivearenas; + if (st->maxarenas < narenas) + st->maxarenas = narenas; + st->totalarenas += narenas; + + st->nthings = nthings; + if (st->maxthings < nthings) + st->maxthings = nthings; + st->totalthings += nthings; +} + +JS_FRIEND_API(void) +js_DumpGCStats(JSRuntime *rt, FILE *fp) +{ + int i; + size_t sumArenas, sumTotalArenas; + size_t sumThings, sumMaxThings; + size_t sumThingSize, sumTotalThingSize; + size_t sumArenaCapacity, sumTotalArenaCapacity; + JSGCArenaStats *st; + size_t thingSize, thingsPerArena; + size_t sumAlloc, sumLocalAlloc, sumFail, sumRetry; + + fprintf(fp, "\nGC allocation statistics:\n"); + +#define UL(x) ((unsigned long)(x)) +#define ULSTAT(x) UL(rt->gcStats.x) +#define PERCENT(x,y) (100.0 * (double) (x) / (double) (y)) + + sumArenas = 0; + sumTotalArenas = 0; + sumThings = 0; + sumMaxThings = 0; + sumThingSize = 0; + sumTotalThingSize = 0; + sumArenaCapacity = 0; + sumTotalArenaCapacity = 0; + sumAlloc = 0; + sumLocalAlloc = 0; + sumFail = 0; + sumRetry = 0; + for (i = -1; i < (int) GC_NUM_FREELISTS; i++) { + if (i == -1) { + thingSize = sizeof(jsdouble); + thingsPerArena = DOUBLES_PER_ARENA; + st = &rt->gcStats.doubleArenaStats; + fprintf(fp, + "Arena list for double values (%lu doubles per arena):", + UL(thingsPerArena)); + } else { + thingSize = rt->gcArenaList[i].thingSize; + thingsPerArena = THINGS_PER_ARENA(thingSize); + st = &rt->gcStats.arenaStats[i]; + fprintf(fp, + "Arena list %d (thing size %lu, %lu things per arena):", + i, UL(GC_FREELIST_NBYTES(i)), UL(thingsPerArena)); + } + if (st->maxarenas == 0) { + fputs(" NEVER USED\n", fp); + continue; + } + putc('\n', fp); + fprintf(fp, " arenas before GC: %lu\n", UL(st->narenas)); + fprintf(fp, " new arenas before GC: %lu (%.1f%%)\n", + UL(st->newarenas), PERCENT(st->newarenas, st->narenas)); + fprintf(fp, " arenas after GC: %lu (%.1f%%)\n", + UL(st->livearenas), PERCENT(st->livearenas, st->narenas)); + fprintf(fp, " max arenas: %lu\n", UL(st->maxarenas)); + fprintf(fp, " things: %lu\n", UL(st->nthings)); + fprintf(fp, " GC cell utilization: %.1f%%\n", + PERCENT(st->nthings, thingsPerArena * st->narenas)); + fprintf(fp, " average cell utilization: %.1f%%\n", + PERCENT(st->totalthings, thingsPerArena * st->totalarenas)); + fprintf(fp, " max things: %lu\n", UL(st->maxthings)); + fprintf(fp, " alloc attempts: %lu\n", UL(st->alloc)); + fprintf(fp, " alloc without locks: %1u (%.1f%%)\n", + UL(st->localalloc), PERCENT(st->localalloc, st->alloc)); + sumArenas += st->narenas; + sumTotalArenas += st->totalarenas; + sumThings += st->nthings; + sumMaxThings += st->maxthings; + sumThingSize += thingSize * st->nthings; + sumTotalThingSize += thingSize * st->totalthings; + sumArenaCapacity += thingSize * thingsPerArena * st->narenas; + sumTotalArenaCapacity += thingSize * thingsPerArena * st->totalarenas; + sumAlloc += st->alloc; + sumLocalAlloc += st->localalloc; + sumFail += st->fail; + sumRetry += st->retry; + } + fprintf(fp, "TOTAL STATS:\n"); + fprintf(fp, " bytes allocated: %lu\n", UL(rt->gcBytes)); + fprintf(fp, " total GC arenas: %lu\n", UL(sumArenas)); + fprintf(fp, " total GC things: %lu\n", UL(sumThings)); + fprintf(fp, " max total GC things: %lu\n", UL(sumMaxThings)); + fprintf(fp, " GC cell utilization: %.1f%%\n", + PERCENT(sumThingSize, sumArenaCapacity)); + fprintf(fp, " average cell utilization: %.1f%%\n", + PERCENT(sumTotalThingSize, sumTotalArenaCapacity)); + fprintf(fp, "allocation retries after GC: %lu\n", UL(sumRetry)); + fprintf(fp, " alloc attempts: %lu\n", UL(sumAlloc)); + fprintf(fp, " alloc without locks: %1u (%.1f%%)\n", + UL(sumLocalAlloc), PERCENT(sumLocalAlloc, sumAlloc)); + fprintf(fp, " allocation failures: %lu\n", UL(sumFail)); + fprintf(fp, " things born locked: %lu\n", ULSTAT(lockborn)); + fprintf(fp, " valid lock calls: %lu\n", ULSTAT(lock)); + fprintf(fp, " valid unlock calls: %lu\n", ULSTAT(unlock)); + fprintf(fp, " mark recursion depth: %lu\n", ULSTAT(depth)); + fprintf(fp, " maximum mark recursion: %lu\n", ULSTAT(maxdepth)); + fprintf(fp, " mark C recursion depth: %lu\n", ULSTAT(cdepth)); + fprintf(fp, " maximum mark C recursion: %lu\n", ULSTAT(maxcdepth)); + fprintf(fp, " delayed tracing calls: %lu\n", ULSTAT(untraced)); +#ifdef DEBUG + fprintf(fp, " max trace later count: %lu\n", ULSTAT(maxuntraced)); +#endif + fprintf(fp, " maximum GC nesting level: %lu\n", ULSTAT(maxlevel)); + fprintf(fp, "potentially useful GC calls: %lu\n", ULSTAT(poke)); + fprintf(fp, " thing arenas freed so far: %lu\n", ULSTAT(afree)); + fprintf(fp, " stack segments scanned: %lu\n", ULSTAT(stackseg)); + fprintf(fp, "stack segment slots scanned: %lu\n", ULSTAT(segslots)); + fprintf(fp, "reachable closeable objects: %lu\n", ULSTAT(nclose)); + fprintf(fp, " max reachable closeable: %lu\n", ULSTAT(maxnclose)); + fprintf(fp, " scheduled close hooks: %lu\n", ULSTAT(closelater)); + fprintf(fp, " max scheduled close hooks: %lu\n", ULSTAT(maxcloselater)); + +#undef UL +#undef ULSTAT +#undef PERCENT + +#ifdef JS_ARENAMETER + JS_DumpArenaStats(fp); +#endif +} +#endif + +#ifdef DEBUG +static void +CheckLeakedRoots(JSRuntime *rt); +#endif + +#ifdef JS_THREADSAFE +static void +TrimGCFreeListsPool(JSRuntime *rt, uintN keepCount); +#endif + +void +js_FinishGC(JSRuntime *rt) +{ +#ifdef JS_ARENAMETER + JS_DumpArenaStats(stdout); +#endif +#ifdef JS_GCMETER + js_DumpGCStats(rt, stdout); +#endif + + FreePtrTable(&rt->gcIteratorTable, &iteratorTableInfo); +#ifdef JS_THREADSAFE + TrimGCFreeListsPool(rt, 0); + JS_ASSERT(!rt->gcFreeListsPool); +#endif + FinishGCArenaLists(rt); + + if (rt->gcRootsHash.ops) { +#ifdef DEBUG + CheckLeakedRoots(rt); +#endif + JS_DHashTableFinish(&rt->gcRootsHash); + rt->gcRootsHash.ops = NULL; + } + if (rt->gcLocksHash) { + JS_DHashTableDestroy(rt->gcLocksHash); + rt->gcLocksHash = NULL; + } +} + +JSBool +js_AddRoot(JSContext *cx, void *rp, const char *name) +{ + JSBool ok = js_AddRootRT(cx->runtime, rp, name); + if (!ok) + JS_ReportOutOfMemory(cx); + return ok; +} + +JSBool +js_AddRootRT(JSRuntime *rt, void *rp, const char *name) +{ + JSBool ok; + JSGCRootHashEntry *rhe; + + /* + * Due to the long-standing, but now removed, use of rt->gcLock across the + * bulk of js_GC, API users have come to depend on JS_AddRoot etc. locking + * properly with a racing GC, without calling JS_AddRoot from a request. + * We have to preserve API compatibility here, now that we avoid holding + * rt->gcLock across the mark phase (including the root hashtable mark). + * + * If the GC is running and we're called on another thread, wait for this + * GC activation to finish. We can safely wait here (in the case where we + * are called within a request on another thread's context) without fear + * of deadlock because the GC doesn't set rt->gcRunning until after it has + * waited for all active requests to end. + */ + JS_LOCK_GC(rt); +#ifdef JS_THREADSAFE + JS_ASSERT(!rt->gcRunning || rt->gcLevel > 0); + if (rt->gcRunning && rt->gcThread->id != js_CurrentThreadId()) { + do { + JS_AWAIT_GC_DONE(rt); + } while (rt->gcLevel > 0); + } +#endif + rhe = (JSGCRootHashEntry *) + JS_DHashTableOperate(&rt->gcRootsHash, rp, JS_DHASH_ADD); + if (rhe) { + rhe->root = rp; + rhe->name = name; + ok = JS_TRUE; + } else { + ok = JS_FALSE; + } + JS_UNLOCK_GC(rt); + return ok; +} + +JSBool +js_RemoveRoot(JSRuntime *rt, void *rp) +{ + /* + * Due to the JS_RemoveRootRT API, we may be called outside of a request. + * Same synchronization drill as above in js_AddRoot. + */ + JS_LOCK_GC(rt); +#ifdef JS_THREADSAFE + JS_ASSERT(!rt->gcRunning || rt->gcLevel > 0); + if (rt->gcRunning && rt->gcThread->id != js_CurrentThreadId()) { + do { + JS_AWAIT_GC_DONE(rt); + } while (rt->gcLevel > 0); + } +#endif + (void) JS_DHashTableOperate(&rt->gcRootsHash, rp, JS_DHASH_REMOVE); + rt->gcPoke = JS_TRUE; + JS_UNLOCK_GC(rt); + return JS_TRUE; +} + +#ifdef DEBUG + +static JSDHashOperator +js_root_printer(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 i, void *arg) +{ + uint32 *leakedroots = (uint32 *)arg; + JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr; + + (*leakedroots)++; + fprintf(stderr, + "JS engine warning: leaking GC root \'%s\' at %p\n", + rhe->name ? (char *)rhe->name : "", rhe->root); + + return JS_DHASH_NEXT; +} + +static void +CheckLeakedRoots(JSRuntime *rt) +{ + uint32 leakedroots = 0; + + /* Warn (but don't assert) debug builds of any remaining roots. */ + JS_DHashTableEnumerate(&rt->gcRootsHash, js_root_printer, + &leakedroots); + if (leakedroots > 0) { + if (leakedroots == 1) { + fprintf(stderr, +"JS engine warning: 1 GC root remains after destroying the JSRuntime at %p.\n" +" This root may point to freed memory. Objects reachable\n" +" through it have not been finalized.\n", + (void *) rt); + } else { + fprintf(stderr, +"JS engine warning: %lu GC roots remain after destroying the JSRuntime at %p.\n" +" These roots may point to freed memory. Objects reachable\n" +" through them have not been finalized.\n", + (unsigned long) leakedroots, (void *) rt); + } + } +} + +typedef struct NamedRootDumpArgs { + void (*dump)(const char *name, void *rp, void *data); + void *data; +} NamedRootDumpArgs; + +static JSDHashOperator +js_named_root_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, + void *arg) +{ + NamedRootDumpArgs *args = (NamedRootDumpArgs *) arg; + JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr; + + if (rhe->name) + args->dump(rhe->name, rhe->root, args->data); + return JS_DHASH_NEXT; +} + +JS_BEGIN_EXTERN_C +void +js_DumpNamedRoots(JSRuntime *rt, + void (*dump)(const char *name, void *rp, void *data), + void *data) +{ + NamedRootDumpArgs args; + + args.dump = dump; + args.data = data; + JS_DHashTableEnumerate(&rt->gcRootsHash, js_named_root_dumper, &args); +} +JS_END_EXTERN_C + +#endif /* DEBUG */ + +typedef struct GCRootMapArgs { + JSGCRootMapFun map; + void *data; +} GCRootMapArgs; + +static JSDHashOperator +js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, + void *arg) +{ + GCRootMapArgs *args = (GCRootMapArgs *) arg; + JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr; + intN mapflags; + int op; + + mapflags = args->map(rhe->root, rhe->name, args->data); + +#if JS_MAP_GCROOT_NEXT == JS_DHASH_NEXT && \ + JS_MAP_GCROOT_STOP == JS_DHASH_STOP && \ + JS_MAP_GCROOT_REMOVE == JS_DHASH_REMOVE + op = (JSDHashOperator)mapflags; +#else + op = JS_DHASH_NEXT; + if (mapflags & JS_MAP_GCROOT_STOP) + op |= JS_DHASH_STOP; + if (mapflags & JS_MAP_GCROOT_REMOVE) + op |= JS_DHASH_REMOVE; +#endif + + return (JSDHashOperator) op; +} + +uint32 +js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data) +{ + GCRootMapArgs args; + uint32 rv; + + args.map = map; + args.data = data; + JS_LOCK_GC(rt); + rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args); + JS_UNLOCK_GC(rt); + return rv; +} + +JSBool +js_RegisterCloseableIterator(JSContext *cx, JSObject *obj) +{ + JSRuntime *rt; + JSBool ok; + + rt = cx->runtime; + JS_ASSERT(!rt->gcRunning); + + JS_LOCK_GC(rt); + ok = AddToPtrTable(cx, &rt->gcIteratorTable, &iteratorTableInfo, obj); + JS_UNLOCK_GC(rt); + return ok; +} + +static void +CloseNativeIterators(JSContext *cx) +{ + JSRuntime *rt; + size_t count, newCount, i; + void **array; + JSObject *obj; + + rt = cx->runtime; + count = rt->gcIteratorTable.count; + array = rt->gcIteratorTable.array; + + newCount = 0; + for (i = 0; i != count; ++i) { + obj = (JSObject *)array[i]; + if (js_IsAboutToBeFinalized(cx, obj)) + js_CloseNativeIterator(cx, obj); + else + array[newCount++] = obj; + } + ShrinkPtrTable(&rt->gcIteratorTable, &iteratorTableInfo, newCount); +} + +#if defined(DEBUG_brendan) || defined(DEBUG_timeless) +#define DEBUG_gchist +#endif + +#ifdef DEBUG_gchist +#define NGCHIST 64 + +static struct GCHist { + JSBool lastDitch; + JSGCThing *freeList; +} gchist[NGCHIST]; + +unsigned gchpos = 0; +#endif + +#ifdef JS_THREADSAFE + +const JSGCFreeListSet js_GCEmptyFreeListSet = { + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, NULL +}; + +static void +TrimGCFreeListsPool(JSRuntime *rt, uintN keepCount) +{ + JSGCFreeListSet **cursor, *freeLists, *link; + + cursor = &rt->gcFreeListsPool; + while (keepCount != 0) { + --keepCount; + freeLists = *cursor; + if (!freeLists) + return; + memset(freeLists->array, 0, sizeof freeLists->array); + cursor = &freeLists->link; + } + freeLists = *cursor; + if (freeLists) { + *cursor = NULL; + do { + link = freeLists->link; + free(freeLists); + } while ((freeLists = link) != NULL); + } +} + +void +js_RevokeGCLocalFreeLists(JSContext *cx) +{ + JS_ASSERT(!cx->gcLocalFreeLists->link); + if (cx->gcLocalFreeLists != &js_GCEmptyFreeListSet) { + cx->gcLocalFreeLists->link = cx->runtime->gcFreeListsPool; + cx->runtime->gcFreeListsPool = cx->gcLocalFreeLists; + cx->gcLocalFreeLists = (JSGCFreeListSet *) &js_GCEmptyFreeListSet; + } +} + +static JSGCFreeListSet * +EnsureLocalFreeList(JSContext *cx) +{ + JSGCFreeListSet *freeLists; + + freeLists = cx->gcLocalFreeLists; + if (freeLists != &js_GCEmptyFreeListSet) { + JS_ASSERT(freeLists); + return freeLists; + } + + freeLists = cx->runtime->gcFreeListsPool; + if (freeLists) { + cx->runtime->gcFreeListsPool = freeLists->link; + freeLists->link = NULL; + } else { + /* JS_malloc is not used as the caller reports out-of-memory itself. */ + freeLists = (JSGCFreeListSet *) calloc(1, sizeof *freeLists); + if (!freeLists) + return NULL; + } + cx->gcLocalFreeLists = freeLists; + return freeLists; +} + +#endif + +void * +js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes) +{ + JSRuntime *rt; + uintN flindex; + JSBool doGC; + JSGCThing *thing; + uint8 *flagp; + JSGCArenaList *arenaList; + JSGCArenaInfo *a; + uintN thingsLimit; + JSLocalRootStack *lrs; +#ifdef JS_GCMETER + JSGCArenaStats *astats; +#endif +#ifdef JS_THREADSAFE + JSBool gcLocked; + uintN localMallocBytes; + JSGCFreeListSet *freeLists; + JSGCThing **lastptr; + JSGCThing *tmpthing; + uint8 *tmpflagp; + uintN maxFreeThings; /* max to take from the global free list */ +#endif + + JS_ASSERT((flags & GCF_TYPEMASK) != GCX_DOUBLE); + rt = cx->runtime; + nbytes = JS_ROUNDUP(nbytes, sizeof(JSGCThing)); + flindex = GC_FREELIST_INDEX(nbytes); + + /* Updates of metering counters here may not be thread-safe. */ + METER(astats = &cx->runtime->gcStats.arenaStats[flindex]); + METER(astats->alloc++); + +#ifdef JS_THREADSAFE + gcLocked = JS_FALSE; + JS_ASSERT(cx->thread); + freeLists = cx->gcLocalFreeLists; + thing = freeLists->array[flindex]; + localMallocBytes = cx->thread->gcMallocBytes; + if (thing && rt->gcMaxMallocBytes - rt->gcMallocBytes > localMallocBytes) { + flagp = thing->flagp; + freeLists->array[flindex] = thing->next; + METER(astats->localalloc++); + goto success; + } + + JS_LOCK_GC(rt); + gcLocked = JS_TRUE; + + /* Transfer thread-local counter to global one. */ + if (localMallocBytes != 0) { + cx->thread->gcMallocBytes = 0; + if (rt->gcMaxMallocBytes - rt->gcMallocBytes < localMallocBytes) + rt->gcMallocBytes = rt->gcMaxMallocBytes; + else + rt->gcMallocBytes += localMallocBytes; + } +#endif + JS_ASSERT(!rt->gcRunning); + if (rt->gcRunning) { + METER(rt->gcStats.finalfail++); + JS_UNLOCK_GC(rt); + return NULL; + } + + doGC = (rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke); +#ifdef JS_GC_ZEAL + doGC = doGC || rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke); +#endif + + arenaList = &rt->gcArenaList[flindex]; + for (;;) { + if (doGC && !JS_ON_TRACE(cx)) { + /* + * Keep rt->gcLock across the call into js_GC so we don't starve + * and lose to racing threads who deplete the heap just after + * js_GC has replenished it (or has synchronized with a racing + * GC that collected a bunch of garbage). This unfair scheduling + * can happen on certain operating systems. For the gory details, + * see bug 162779 at https://bugzilla.mozilla.org/. + */ + js_GC(cx, GC_LAST_DITCH); + METER(astats->retry++); + } + + /* Try to get thing from the free list. */ + thing = arenaList->freeList; + if (thing) { + arenaList->freeList = thing->next; + flagp = thing->flagp; + JS_ASSERT(*flagp & GCF_FINAL); + +#ifdef JS_THREADSAFE + /* + * Refill the local free list by taking several things from the + * global free list unless we are still at rt->gcMaxMallocBytes + * barrier or the free list is already populated. The former + * happens when GC is canceled due to !gcCallback(cx, JSGC_BEGIN) + * or no gcPoke. The latter is caused via allocating new things + * in gcCallback(cx, JSGC_END). + */ + if (rt->gcMallocBytes >= rt->gcMaxMallocBytes) + break; + + freeLists = EnsureLocalFreeList(cx); + if (!freeLists) + goto fail; + if (freeLists->array[flindex]) + break; + + tmpthing = arenaList->freeList; + if (tmpthing) { + maxFreeThings = MAX_THREAD_LOCAL_THINGS; + do { + if (!tmpthing->next) + break; + tmpthing = tmpthing->next; + } while (--maxFreeThings != 0); + + freeLists->array[flindex] = arenaList->freeList; + arenaList->freeList = tmpthing->next; + tmpthing->next = NULL; + } +#endif + break; + } + + /* + * Try to allocate things from the last arena. If it is fully used, + * check if we can allocate a new one and, if we cannot, consider + * doing a "last ditch" GC unless already tried. + */ + thingsLimit = THINGS_PER_ARENA(nbytes); + if (arenaList->lastCount != thingsLimit) { + JS_ASSERT(arenaList->lastCount < thingsLimit); + a = arenaList->last; + } else { + a = NewGCArena(rt); + if (!a) { + if (doGC || JS_ON_TRACE(cx)) + goto fail; + doGC = JS_TRUE; + continue; + } + a->list = arenaList; + a->prev = arenaList->last; + a->prevUntracedPage = 0; + a->u.untracedThings = 0; + arenaList->last = a; + arenaList->lastCount = 0; + } + + flagp = THING_FLAGP(a, arenaList->lastCount); + thing = FLAGP_TO_THING(flagp, nbytes); + arenaList->lastCount++; + +#ifdef JS_THREADSAFE + /* + * Refill the local free list by taking free things from the last + * arena. Prefer to order free things by ascending address in the + * (unscientific) hope of better cache locality. + */ + if (rt->gcMallocBytes >= rt->gcMaxMallocBytes) + break; + + freeLists = EnsureLocalFreeList(cx); + if (!freeLists) + goto fail; + if (freeLists->array[flindex]) + break; + lastptr = &freeLists->array[flindex]; + maxFreeThings = thingsLimit - arenaList->lastCount; + if (maxFreeThings > MAX_THREAD_LOCAL_THINGS) + maxFreeThings = MAX_THREAD_LOCAL_THINGS; + while (maxFreeThings != 0) { + --maxFreeThings; + + tmpflagp = THING_FLAGP(a, arenaList->lastCount); + tmpthing = FLAGP_TO_THING(tmpflagp, nbytes); + arenaList->lastCount++; + tmpthing->flagp = tmpflagp; + *tmpflagp = GCF_FINAL; /* signifying that thing is free */ + + *lastptr = tmpthing; + lastptr = &tmpthing->next; + } + *lastptr = NULL; +#endif + break; + } + + /* We successfully allocated the thing. */ +#ifdef JS_THREADSAFE + success: +#endif + lrs = cx->localRootStack; + if (lrs) { + /* + * If we're in a local root scope, don't set newborn[type] at all, to + * avoid entraining garbage from it for an unbounded amount of time + * on this context. A caller will leave the local root scope and pop + * this reference, allowing thing to be GC'd if it has no other refs. + * See JS_EnterLocalRootScope and related APIs. + */ + if (js_PushLocalRoot(cx, lrs, (jsval) thing) < 0) { + /* + * When we fail for a thing allocated through the tail of the last + * arena, thing's flag byte is not initialized. So to prevent GC + * accessing the uninitialized flags during the finalization, we + * always mark the thing as final. See bug 337407. + */ + *flagp = GCF_FINAL; + goto fail; + } + } else { + /* + * No local root scope, so we're stuck with the old, fragile model of + * depending on a pigeon-hole newborn per type per context. + */ + cx->weakRoots.newborn[flags & GCF_TYPEMASK] = thing; + } + + /* We can't fail now, so update flags. */ + *flagp = (uint8)flags; + +#ifdef DEBUG_gchist + gchist[gchpos].lastDitch = doGC; + gchist[gchpos].freeList = rt->gcArenaList[flindex].freeList; + if (++gchpos == NGCHIST) + gchpos = 0; +#endif + + /* This is not thread-safe for thread-local allocations. */ + METER_IF(flags & GCF_LOCK, rt->gcStats.lockborn++); + +#ifdef JS_THREADSAFE + if (gcLocked) + JS_UNLOCK_GC(rt); +#endif + JS_COUNT_OPERATION(cx, JSOW_ALLOCATION); + return thing; + +fail: +#ifdef JS_THREADSAFE + if (gcLocked) + JS_UNLOCK_GC(rt); +#endif + METER(astats->fail++); + if (!JS_ON_TRACE(cx)) + JS_ReportOutOfMemory(cx); + return NULL; +} + +static JSGCDoubleCell * +RefillDoubleFreeList(JSContext *cx) +{ + JSRuntime *rt; + jsbitmap *doubleFlags, usedBits; + JSBool didGC = JS_FALSE; + JSGCArenaInfo *a; + uintN bit, index; + JSGCDoubleCell *cell, *list, *lastcell; + + JS_ASSERT(!cx->doubleFreeList); + + rt = cx->runtime; + JS_LOCK_GC(rt); + + JS_ASSERT(!rt->gcRunning); + if (rt->gcRunning) { + METER(rt->gcStats.finalfail++); + JS_UNLOCK_GC(rt); + return NULL; + } + + if (rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke +#ifdef JS_GC_ZEAL + && (rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke)) +#endif + ) { + goto do_gc; + } + + /* + * Loop until we find a flag bitmap byte with unset bits indicating free + * double cells, then set all bits as used and put the cells to the free + * list for the current context. + */ + doubleFlags = rt->gcDoubleArenaList.nextDoubleFlags; + for (;;) { + if (((jsuword) doubleFlags & GC_ARENA_MASK) == + ARENA_INFO_OFFSET) { + if (doubleFlags == DOUBLE_BITMAP_SENTINEL || + !((JSGCArenaInfo *) doubleFlags)->prev) { + a = NewGCArena(rt); + if (!a) { + do_gc: + if (didGC || JS_ON_TRACE(cx)) { + METER(rt->gcStats.doubleArenaStats.fail++); + JS_UNLOCK_GC(rt); + if (!JS_ON_TRACE(cx)) + JS_ReportOutOfMemory(cx); + return NULL; + } + js_GC(cx, GC_LAST_DITCH); + METER(rt->gcStats.doubleArenaStats.retry++); + doubleFlags = rt->gcDoubleArenaList.nextDoubleFlags; + didGC = JS_TRUE; + continue; + } + a->list = NULL; + a->prev = NULL; + if (doubleFlags == DOUBLE_BITMAP_SENTINEL) { + JS_ASSERT(!rt->gcDoubleArenaList.first); + rt->gcDoubleArenaList.first = a; + } else { + JS_ASSERT(rt->gcDoubleArenaList.first); + ((JSGCArenaInfo *) doubleFlags)->prev = a; + } + ClearDoubleArenaFlags(a); + doubleFlags = DOUBLE_ARENA_BITMAP(a); + break; + } + doubleFlags = + DOUBLE_ARENA_BITMAP(((JSGCArenaInfo *) doubleFlags)->prev); + } + + /* + * When doubleFlags points the last bitmap's word in the arena, its + * high bits corresponds to non-existing cells. ClearDoubleArenaFlags + * sets such bits to 1. Thus even for this last word its bit is unset + * iff the corresponding cell exists and free. + */ + if (*doubleFlags != (jsbitmap) -1) + break; + ++doubleFlags; + } + + rt->gcDoubleArenaList.nextDoubleFlags = doubleFlags + 1; + usedBits = *doubleFlags; + JS_ASSERT(usedBits != (jsbitmap) -1); + *doubleFlags = (jsbitmap) -1; + JS_UNLOCK_GC(rt); + + /* + * Find the index corresponding to the first bit in *doubleFlags. The last + * bit will have "index + JS_BITS_PER_WORD - 1". + */ + index = ((uintN) ((jsuword) doubleFlags & GC_ARENA_MASK) - + DOUBLES_ARENA_BITMAP_OFFSET) * JS_BITS_PER_BYTE; + cell = (JSGCDoubleCell *) ((jsuword) doubleFlags & ~GC_ARENA_MASK) + index; + + if (usedBits == 0) { + /* The common case when all doubles from *doubleFlags are free. */ + JS_ASSERT(index + JS_BITS_PER_WORD <= DOUBLES_PER_ARENA); + list = cell; + for (lastcell = cell + JS_BITS_PER_WORD - 1; cell != lastcell; ++cell) + cell->link = cell + 1; + lastcell->link = NULL; + } else { + /* + * Assemble the free list from free cells from *doubleFlags starting + * from the tail. In the loop + * + * index + bit >= DOUBLES_PER_ARENA + * + * when bit is one of the unused bits. We do not check for such bits + * explicitly as they must be set and the "if" check filters them out. + */ + JS_ASSERT(index + JS_BITS_PER_WORD <= + DOUBLES_PER_ARENA + UNUSED_DOUBLE_BITMAP_BITS); + bit = JS_BITS_PER_WORD; + cell += bit; + list = NULL; + do { + --bit; + --cell; + if (!(((jsbitmap) 1 << bit) & usedBits)) { + JS_ASSERT(index + bit < DOUBLES_PER_ARENA); + JS_ASSERT_IF(index + bit == DOUBLES_PER_ARENA - 1, !list); + cell->link = list; + list = cell; + } + } while (bit != 0); + } + JS_ASSERT(list); + JS_COUNT_OPERATION(cx, JSOW_ALLOCATION * JS_BITS_PER_WORD); + + /* + * We delegate assigning cx->doubleFreeList to js_NewDoubleInRootedValue as + * it immediately consumes the head of the list. + */ + return list; +} + +JSBool +js_NewDoubleInRootedValue(JSContext *cx, jsdouble d, jsval *vp) +{ +#ifdef JS_GCMETER + JSGCArenaStats *astats; +#endif + JSGCDoubleCell *cell; + + /* Updates of metering counters here are not thread-safe. */ + METER(astats = &cx->runtime->gcStats.doubleArenaStats); + METER(astats->alloc++); + cell = cx->doubleFreeList; + if (!cell) { + cell = RefillDoubleFreeList(cx); + if (!cell) { + METER(astats->fail++); + return JS_FALSE; + } + } else { + METER(astats->localalloc++); + } + cx->doubleFreeList = cell->link; + cell->number = d; + *vp = DOUBLE_TO_JSVAL(&cell->number); + return JS_TRUE; +} + +jsdouble * +js_NewWeaklyRootedDouble(JSContext *cx, jsdouble d) +{ + jsval v; + jsdouble *dp; + + if (!js_NewDoubleInRootedValue(cx, d, &v)) + return NULL; + + JS_ASSERT(JSVAL_IS_DOUBLE(v)); + dp = JSVAL_TO_DOUBLE(v); + if (cx->localRootStack) { + if (js_PushLocalRoot(cx, cx->localRootStack, v) < 0) + return NULL; + } else { + cx->weakRoots.newborn[GCX_DOUBLE] = dp; + } + return dp; +} + +JSBool +js_AddAsGCBytes(JSContext *cx, size_t sz) +{ + JSRuntime *rt; + + rt = cx->runtime; + if (rt->gcBytes >= rt->gcMaxBytes || + sz > (size_t) (rt->gcMaxBytes - rt->gcBytes) +#ifdef JS_GC_ZEAL + || rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke) +#endif + ) { + if (JS_ON_TRACE(cx)) { + JS_UNLOCK_GC(rt); + return JS_FALSE; + } + js_GC(cx, GC_LAST_DITCH); + if (rt->gcBytes >= rt->gcMaxBytes || + sz > (size_t) (rt->gcMaxBytes - rt->gcBytes)) { + JS_UNLOCK_GC(rt); + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + } + rt->gcBytes += (uint32) sz; + return JS_TRUE; +} + +void +js_RemoveAsGCBytes(JSRuntime *rt, size_t sz) +{ + JS_ASSERT((size_t) rt->gcBytes >= sz); + rt->gcBytes -= (uint32) sz; +} + +/* + * Shallow GC-things can be locked just by setting the GCF_LOCK bit, because + * they have no descendants to mark during the GC. Currently the optimization + * is only used for non-dependant strings. + */ +#define GC_THING_IS_SHALLOW(flagp, thing) \ + ((flagp) && \ + ((*(flagp) & GCF_TYPEMASK) >= GCX_EXTERNAL_STRING || \ + ((*(flagp) & GCF_TYPEMASK) == GCX_STRING && \ + !JSSTRING_IS_DEPENDENT((JSString *) (thing))))) + +/* This is compatible with JSDHashEntryStub. */ +typedef struct JSGCLockHashEntry { + JSDHashEntryHdr hdr; + const void *thing; + uint32 count; +} JSGCLockHashEntry; + +JSBool +js_LockGCThingRT(JSRuntime *rt, void *thing) +{ + JSBool shallow, ok; + uint8 *flagp; + JSGCLockHashEntry *lhe; + + if (!thing) + return JS_TRUE; + + flagp = GetGCThingFlagsOrNull(thing); + JS_LOCK_GC(rt); + shallow = GC_THING_IS_SHALLOW(flagp, thing); + + /* + * Avoid adding a rt->gcLocksHash entry for shallow things until someone + * nests a lock. + */ + if (shallow && !(*flagp & GCF_LOCK)) { + *flagp |= GCF_LOCK; + METER(rt->gcStats.lock++); + ok = JS_TRUE; + goto out; + } + + if (!rt->gcLocksHash) { + rt->gcLocksHash = JS_NewDHashTable(JS_DHashGetStubOps(), NULL, + sizeof(JSGCLockHashEntry), + GC_ROOTS_SIZE); + if (!rt->gcLocksHash) { + ok = JS_FALSE; + goto out; + } + } + + lhe = (JSGCLockHashEntry *) + JS_DHashTableOperate(rt->gcLocksHash, thing, JS_DHASH_ADD); + if (!lhe) { + ok = JS_FALSE; + goto out; + } + if (!lhe->thing) { + lhe->thing = thing; + lhe->count = 1; + } else { + JS_ASSERT(lhe->count >= 1); + lhe->count++; + } + + METER(rt->gcStats.lock++); + ok = JS_TRUE; + out: + JS_UNLOCK_GC(rt); + return ok; +} + +JSBool +js_UnlockGCThingRT(JSRuntime *rt, void *thing) +{ + uint8 *flagp; + JSBool shallow; + JSGCLockHashEntry *lhe; + + if (!thing) + return JS_TRUE; + + flagp = GetGCThingFlagsOrNull(thing); + JS_LOCK_GC(rt); + shallow = GC_THING_IS_SHALLOW(flagp, thing); + + if (shallow && !(*flagp & GCF_LOCK)) + goto out; + if (!rt->gcLocksHash || + (lhe = (JSGCLockHashEntry *) + JS_DHashTableOperate(rt->gcLocksHash, thing, + JS_DHASH_LOOKUP), + JS_DHASH_ENTRY_IS_FREE(&lhe->hdr))) { + /* Shallow entry is not in the hash -> clear its lock bit. */ + if (shallow) + *flagp &= ~GCF_LOCK; + else + goto out; + } else { + if (--lhe->count != 0) + goto out; + JS_DHashTableOperate(rt->gcLocksHash, thing, JS_DHASH_REMOVE); + } + + rt->gcPoke = JS_TRUE; + METER(rt->gcStats.unlock++); + out: + JS_UNLOCK_GC(rt); + return JS_TRUE; +} + +JS_PUBLIC_API(void) +JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind) +{ + JSObject *obj; + size_t nslots, i; + jsval v; + JSString *str; + + switch (kind) { + case JSTRACE_OBJECT: + /* If obj has no map, it must be a newborn. */ + obj = (JSObject *) thing; + if (!obj->map) + break; + if (obj->map->ops->trace) { + obj->map->ops->trace(trc, obj); + } else { + nslots = STOBJ_NSLOTS(obj); + for (i = 0; i != nslots; ++i) { + v = STOBJ_GET_SLOT(obj, i); + if (JSVAL_IS_TRACEABLE(v)) { + JS_SET_TRACING_INDEX(trc, "slot", i); + JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), + JSVAL_TRACE_KIND(v)); + } + } + } + break; + + case JSTRACE_STRING: + str = (JSString *)thing; + if (JSSTRING_IS_DEPENDENT(str)) + JS_CALL_STRING_TRACER(trc, JSSTRDEP_BASE(str), "base"); + break; + +#if JS_HAS_XML_SUPPORT + case JSTRACE_XML: + js_TraceXML(trc, (JSXML *)thing); + break; +#endif + } +} + +/* + * Number of things covered by a single bit of JSGCArenaInfo.u.untracedThings. + */ +#define THINGS_PER_UNTRACED_BIT(thingSize) \ + JS_HOWMANY(THINGS_PER_ARENA(thingSize), JS_BITS_PER_WORD) + +static void +DelayTracingChildren(JSRuntime *rt, uint8 *flagp) +{ + JSGCArenaInfo *a; + uint32 untracedBitIndex; + jsuword bit; + + /* + * Things with children to be traced later are marked with + * GCF_MARK | GCF_FINAL flags. + */ + JS_ASSERT((*flagp & (GCF_MARK | GCF_FINAL)) == GCF_MARK); + *flagp |= GCF_FINAL; + + METER(rt->gcStats.untraced++); +#ifdef DEBUG + ++rt->gcTraceLaterCount; + METER_UPDATE_MAX(rt->gcStats.maxuntraced, rt->gcTraceLaterCount); +#endif + + a = FLAGP_TO_ARENA(flagp); + untracedBitIndex = FLAGP_TO_INDEX(flagp) / + THINGS_PER_UNTRACED_BIT(a->list->thingSize); + JS_ASSERT(untracedBitIndex < JS_BITS_PER_WORD); + bit = (jsuword)1 << untracedBitIndex; + if (a->u.untracedThings != 0) { + JS_ASSERT(rt->gcUntracedArenaStackTop); + if (a->u.untracedThings & bit) { + /* bit already covers things with children to trace later. */ + return; + } + a->u.untracedThings |= bit; + } else { + /* + * The thing is the first thing with not yet traced children in the + * whole arena, so push the arena on the stack of arenas with things + * to be traced later unless the arena has already been pushed. We + * detect that through checking prevUntracedPage as the field is 0 + * only for not yet pushed arenas. To ensure that + * prevUntracedPage != 0 + * even when the stack contains one element, we make prevUntracedPage + * for the arena at the bottom to point to itself. + * + * See comments in TraceDelayedChildren. + */ + a->u.untracedThings = bit; + if (a->prevUntracedPage == 0) { + if (!rt->gcUntracedArenaStackTop) { + /* Stack was empty, mark the arena as the bottom element. */ + a->prevUntracedPage = ARENA_INFO_TO_PAGE(a); + } else { + JS_ASSERT(rt->gcUntracedArenaStackTop->prevUntracedPage != 0); + a->prevUntracedPage = + ARENA_INFO_TO_PAGE(rt->gcUntracedArenaStackTop); + } + rt->gcUntracedArenaStackTop = a; + } + } + JS_ASSERT(rt->gcUntracedArenaStackTop); +} + +static void +TraceDelayedChildren(JSTracer *trc) +{ + JSRuntime *rt; + JSGCArenaInfo *a, *aprev; + uint32 thingSize; + uint32 thingsPerUntracedBit; + uint32 untracedBitIndex, thingIndex, indexLimit, endIndex; + JSGCThing *thing; + uint8 *flagp; + + rt = trc->context->runtime; + a = rt->gcUntracedArenaStackTop; + if (!a) { + JS_ASSERT(rt->gcTraceLaterCount == 0); + return; + } + + for (;;) { + /* + * The following assert verifies that the current arena belongs to the + * untraced stack, since DelayTracingChildren ensures that even for + * stack's bottom prevUntracedPage != 0 but rather points to itself. + */ + JS_ASSERT(a->prevUntracedPage != 0); + JS_ASSERT(rt->gcUntracedArenaStackTop->prevUntracedPage != 0); + thingSize = a->list->thingSize; + indexLimit = (a == a->list->last) + ? a->list->lastCount + : THINGS_PER_ARENA(thingSize); + thingsPerUntracedBit = THINGS_PER_UNTRACED_BIT(thingSize); + + /* + * We cannot use do-while loop here as a->u.untracedThings can be zero + * before the loop as a leftover from the previous iterations. See + * comments after the loop. + */ + while (a->u.untracedThings != 0) { + untracedBitIndex = JS_FLOOR_LOG2W(a->u.untracedThings); + a->u.untracedThings &= ~((jsuword)1 << untracedBitIndex); + thingIndex = untracedBitIndex * thingsPerUntracedBit; + endIndex = thingIndex + thingsPerUntracedBit; + + /* + * endIndex can go beyond the last allocated thing as the real + * limit can be "inside" the bit. + */ + if (endIndex > indexLimit) + endIndex = indexLimit; + JS_ASSERT(thingIndex < indexLimit); + + do { + /* + * Skip free or already traced things that share the bit + * with untraced ones. + */ + flagp = THING_FLAGP(a, thingIndex); + if ((*flagp & (GCF_MARK|GCF_FINAL)) != (GCF_MARK|GCF_FINAL)) + continue; + *flagp &= ~GCF_FINAL; +#ifdef DEBUG + JS_ASSERT(rt->gcTraceLaterCount != 0); + --rt->gcTraceLaterCount; +#endif + thing = FLAGP_TO_THING(flagp, thingSize); + JS_TraceChildren(trc, thing, MapGCFlagsToTraceKind(*flagp)); + } while (++thingIndex != endIndex); + } + + /* + * We finished tracing of all things in the the arena but we can only + * pop it from the stack if the arena is the stack's top. + * + * When JS_TraceChildren from the above calls JS_CallTracer that in + * turn on low C stack calls DelayTracingChildren and the latter + * pushes new arenas to the untraced stack, we have to skip popping + * of this arena until it becomes the top of the stack again. + */ + if (a == rt->gcUntracedArenaStackTop) { + aprev = ARENA_PAGE_TO_INFO(a->prevUntracedPage); + a->prevUntracedPage = 0; + if (a == aprev) { + /* + * prevUntracedPage points to itself and we reached the + * bottom of the stack. + */ + break; + } + rt->gcUntracedArenaStackTop = a = aprev; + } else { + a = rt->gcUntracedArenaStackTop; + } + } + JS_ASSERT(rt->gcUntracedArenaStackTop); + JS_ASSERT(rt->gcUntracedArenaStackTop->prevUntracedPage == 0); + rt->gcUntracedArenaStackTop = NULL; + JS_ASSERT(rt->gcTraceLaterCount == 0); +} + +JS_PUBLIC_API(void) +JS_CallTracer(JSTracer *trc, void *thing, uint32 kind) +{ + JSContext *cx; + JSRuntime *rt; + JSGCArenaInfo *a; + uintN index; + uint8 *flagp; + + JS_ASSERT(thing); + JS_ASSERT(JS_IS_VALID_TRACE_KIND(kind)); + JS_ASSERT(trc->debugPrinter || trc->debugPrintArg); + + if (!IS_GC_MARKING_TRACER(trc)) { + trc->callback(trc, thing, kind); + goto out; + } + + cx = trc->context; + rt = cx->runtime; + JS_ASSERT(rt->gcMarkingTracer == trc); + JS_ASSERT(rt->gcLevel > 0); + + /* + * Optimize for string and double as their size is known and their tracing + * is not recursive. + */ + switch (kind) { + case JSTRACE_DOUBLE: + a = THING_TO_ARENA(thing); + JS_ASSERT(!a->list); + if (!a->u.hasMarkedDoubles) { + ClearDoubleArenaFlags(a); + a->u.hasMarkedDoubles = JS_TRUE; + } + index = DOUBLE_THING_TO_INDEX(thing); + JS_SET_BIT(DOUBLE_ARENA_BITMAP(a), index); + goto out; + + case JSTRACE_STRING: + for (;;) { + flagp = THING_TO_FLAGP(thing, sizeof(JSGCThing)); + JS_ASSERT((*flagp & GCF_FINAL) == 0); + JS_ASSERT(kind == MapGCFlagsToTraceKind(*flagp)); + if (!JSSTRING_IS_DEPENDENT((JSString *) thing)) { + *flagp |= GCF_MARK; + goto out; + } + if (*flagp & GCF_MARK) + goto out; + *flagp |= GCF_MARK; + thing = JSSTRDEP_BASE((JSString *) thing); + } + /* NOTREACHED */ + } + + flagp = GetGCThingFlags(thing); + JS_ASSERT(kind == MapGCFlagsToTraceKind(*flagp)); + if (*flagp & GCF_MARK) + goto out; + + /* + * We check for non-final flag only if mark is unset as + * DelayTracingChildren uses the flag. See comments in the function. + */ + JS_ASSERT(*flagp != GCF_FINAL); + *flagp |= GCF_MARK; + if (!cx->insideGCMarkCallback) { + /* + * With JS_GC_ASSUME_LOW_C_STACK defined the mark phase of GC always + * uses the non-recursive code that otherwise would be called only on + * a low C stack condition. + */ +#ifdef JS_GC_ASSUME_LOW_C_STACK +# define RECURSION_TOO_DEEP() JS_TRUE +#else + int stackDummy; +# define RECURSION_TOO_DEEP() (!JS_CHECK_STACK_SIZE(cx, stackDummy)) +#endif + if (RECURSION_TOO_DEEP()) + DelayTracingChildren(rt, flagp); + else + JS_TraceChildren(trc, thing, kind); + } else { + /* + * For API compatibility we allow for the callback to assume that + * after it calls JS_MarkGCThing for the last time, the callback can + * start to finalize its own objects that are only referenced by + * unmarked GC things. + * + * Since we do not know which call from inside the callback is the + * last, we ensure that children of all marked things are traced and + * call TraceDelayedChildren(trc) after tracing the thing. + * + * As TraceDelayedChildren unconditionally invokes JS_TraceChildren + * for the things with untraced children, calling DelayTracingChildren + * is useless here. Hence we always trace thing's children even with a + * low native stack. + */ + cx->insideGCMarkCallback = JS_FALSE; + JS_TraceChildren(trc, thing, kind); + TraceDelayedChildren(trc); + cx->insideGCMarkCallback = JS_TRUE; + } + + out: +#ifdef DEBUG + trc->debugPrinter = NULL; + trc->debugPrintArg = NULL; +#endif + return; /* to avoid out: right_curl when DEBUG is not defined */ +} + +void +js_CallValueTracerIfGCThing(JSTracer *trc, jsval v) +{ + void *thing; + uint32 kind; + + if (JSVAL_IS_DOUBLE(v) || JSVAL_IS_STRING(v)) { + thing = JSVAL_TO_TRACEABLE(v); + kind = JSVAL_TRACE_KIND(v); + JS_ASSERT(kind == js_GetGCThingTraceKind(JSVAL_TO_GCTHING(v))); + } else if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) { + /* v can be an arbitrary GC thing reinterpreted as an object. */ + thing = JSVAL_TO_OBJECT(v); + kind = js_GetGCThingTraceKind(thing); + } else { + return; + } + JS_CallTracer(trc, thing, kind); +} + +static JSDHashOperator +gc_root_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, + void *arg) +{ + JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr; + JSTracer *trc = (JSTracer *)arg; + jsval *rp = (jsval *)rhe->root; + jsval v = *rp; + + /* Ignore null object and scalar values. */ + if (!JSVAL_IS_NULL(v) && JSVAL_IS_GCTHING(v)) { +#ifdef DEBUG + JSBool root_points_to_gcArenaList = JS_FALSE; + jsuword thing = (jsuword) JSVAL_TO_GCTHING(v); + JSRuntime *rt; + uintN i; + JSGCArenaList *arenaList; + uint32 thingSize; + JSGCArenaInfo *a; + size_t limit; + + rt = trc->context->runtime; + for (i = 0; i < GC_NUM_FREELISTS; i++) { + arenaList = &rt->gcArenaList[i]; + thingSize = arenaList->thingSize; + limit = (size_t) arenaList->lastCount * thingSize; + for (a = arenaList->last; a; a = a->prev) { + if (thing - ARENA_INFO_TO_START(a) < limit) { + root_points_to_gcArenaList = JS_TRUE; + break; + } + limit = (size_t) THINGS_PER_ARENA(thingSize) * thingSize; + } + } + if (!root_points_to_gcArenaList) { + for (a = rt->gcDoubleArenaList.first; a; a = a->prev) { + if (thing - ARENA_INFO_TO_START(a) < + DOUBLES_PER_ARENA * sizeof(jsdouble)) { + root_points_to_gcArenaList = JS_TRUE; + break; + } + } + } + if (!root_points_to_gcArenaList && rhe->name) { + fprintf(stderr, +"JS API usage error: the address passed to JS_AddNamedRoot currently holds an\n" +"invalid jsval. This is usually caused by a missing call to JS_RemoveRoot.\n" +"The root's name is \"%s\".\n", + rhe->name); + } + JS_ASSERT(root_points_to_gcArenaList); +#endif + JS_SET_TRACING_NAME(trc, rhe->name ? rhe->name : "root"); + js_CallValueTracerIfGCThing(trc, v); + } + + return JS_DHASH_NEXT; +} + +static JSDHashOperator +gc_lock_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, + void *arg) +{ + JSGCLockHashEntry *lhe = (JSGCLockHashEntry *)hdr; + void *thing = (void *)lhe->thing; + JSTracer *trc = (JSTracer *)arg; + uint32 traceKind; + + JS_ASSERT(lhe->count >= 1); + traceKind = js_GetGCThingTraceKind(thing); + JS_CALL_TRACER(trc, thing, traceKind, "locked object"); + return JS_DHASH_NEXT; +} + +#define TRACE_JSVALS(trc, len, vec, name) \ + JS_BEGIN_MACRO \ + jsval _v, *_vp, *_end; \ + \ + for (_vp = vec, _end = _vp + len; _vp < _end; _vp++) { \ + _v = *_vp; \ + if (JSVAL_IS_TRACEABLE(_v)) { \ + JS_SET_TRACING_INDEX(trc, name, _vp - (vec)); \ + JS_CallTracer(trc, JSVAL_TO_TRACEABLE(_v), \ + JSVAL_TRACE_KIND(_v)); \ + } \ + } \ + JS_END_MACRO + +void +js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) +{ + uintN nslots, minargs, skip; + + if (fp->callobj) + JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call"); + if (fp->argsobj) + JS_CALL_OBJECT_TRACER(trc, fp->argsobj, "arguments"); + if (fp->varobj) + JS_CALL_OBJECT_TRACER(trc, fp->varobj, "variables"); + if (fp->script) { + js_TraceScript(trc, fp->script); + if (fp->regs) { + /* + * Don't mark what has not been pushed yet, or what has been + * popped already. + */ + nslots = (uintN) (fp->regs->sp - fp->slots); + TRACE_JSVALS(trc, nslots, fp->slots, "slot"); + } + } else { + JS_ASSERT(!fp->slots); + JS_ASSERT(!fp->regs); + } + + /* Allow for primitive this parameter due to JSFUN_THISP_* flags. */ + JS_ASSERT(JSVAL_IS_OBJECT((jsval)fp->thisp) || + (fp->fun && JSFUN_THISP_FLAGS(fp->fun->flags))); + JS_CALL_VALUE_TRACER(trc, (jsval)fp->thisp, "this"); + + if (fp->callee) + JS_CALL_OBJECT_TRACER(trc, fp->callee, "callee"); + + if (fp->argv) { + nslots = fp->argc; + skip = 0; + if (fp->fun) { + minargs = FUN_MINARGS(fp->fun); + if (minargs > nslots) + nslots = minargs; + if (!FUN_INTERPRETED(fp->fun)) { + JS_ASSERT(!(fp->fun->flags & JSFUN_FAST_NATIVE)); + nslots += fp->fun->u.n.extra; + } + if (fp->fun->flags & JSFRAME_ROOTED_ARGV) + skip = 2 + fp->argc; + } + TRACE_JSVALS(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand"); + } + + JS_CALL_VALUE_TRACER(trc, fp->rval, "rval"); + if (fp->scopeChain) + JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain"); + if (fp->sharpArray) + JS_CALL_OBJECT_TRACER(trc, fp->sharpArray, "sharp array"); + + if (fp->xmlNamespace) + JS_CALL_OBJECT_TRACER(trc, fp->xmlNamespace, "xmlNamespace"); +} + +static void +TraceWeakRoots(JSTracer *trc, JSWeakRoots *wr) +{ + uint32 i; + void *thing; + +#ifdef DEBUG + static const char *weakRootNames[JSTRACE_LIMIT] = { + "newborn object", + "newborn double", + "newborn string", + "newborn xml" + }; +#endif + + for (i = 0; i != JSTRACE_LIMIT; i++) { + thing = wr->newborn[i]; + if (thing) + JS_CALL_TRACER(trc, thing, i, weakRootNames[i]); + } + JS_ASSERT(i == GCX_EXTERNAL_STRING); + for (; i != GCX_NTYPES; ++i) { + thing = wr->newborn[i]; + if (thing) { + JS_SET_TRACING_INDEX(trc, "newborn external string", + i - GCX_EXTERNAL_STRING); + JS_CallTracer(trc, thing, JSTRACE_STRING); + } + } + + JS_CALL_VALUE_TRACER(trc, wr->lastAtom, "lastAtom"); + JS_SET_TRACING_NAME(trc, "lastInternalResult"); + js_CallValueTracerIfGCThing(trc, wr->lastInternalResult); +} + +JS_FRIEND_API(void) +js_TraceContext(JSTracer *trc, JSContext *acx) +{ + JSStackFrame *fp, *nextChain; + JSStackHeader *sh; + JSTempValueRooter *tvr; + + if (IS_GC_MARKING_TRACER(trc)) { + +#define FREE_OLD_ARENAS(pool) \ + JS_BEGIN_MACRO \ + int64 _age; \ + JSArena * _a = (pool).current; \ + if (_a == (pool).first.next && \ + _a->avail == _a->base + sizeof(int64)) { \ + _age = JS_Now() - *(int64 *) _a->base; \ + if (_age > (int64) acx->runtime->gcEmptyArenaPoolLifespan * \ + 1000) \ + JS_FreeArenaPool(&(pool)); \ + } \ + JS_END_MACRO + +#ifdef JS_THREADSAFE + js_RevokeGCLocalFreeLists(acx); +#endif + + /* + * Release the stackPool's arenas if the stackPool has existed for + * longer than the limit specified by gcEmptyArenaPoolLifespan. + */ + FREE_OLD_ARENAS(acx->stackPool); + + /* + * Release the regexpPool's arenas based on the same criterion as for + * the stackPool. + */ + FREE_OLD_ARENAS(acx->regexpPool); + + /* + * Clear the double free list to release all the pre-allocated doubles. + */ + acx->doubleFreeList = NULL; + } + + /* + * Iterate frame chain and dormant chains. + * + * (NB: see comment on this whole "dormant" thing in js_Execute.) + */ + fp = acx->fp; + nextChain = acx->dormantFrameChain; + if (!fp) + goto next_chain; + + /* The top frame must not be dormant. */ + JS_ASSERT(!fp->dormantNext); + for (;;) { + do { + js_TraceStackFrame(trc, fp); + } while ((fp = fp->down) != NULL); + + next_chain: + if (!nextChain) + break; + fp = nextChain; + nextChain = nextChain->dormantNext; + } + + /* Mark other roots-by-definition in acx. */ + if (acx->globalObject) + JS_CALL_OBJECT_TRACER(trc, acx->globalObject, "global object"); + TraceWeakRoots(trc, &acx->weakRoots); + if (acx->throwing) { + JS_CALL_VALUE_TRACER(trc, acx->exception, "exception"); + } else { + /* Avoid keeping GC-ed junk stored in JSContext.exception. */ + acx->exception = JSVAL_NULL; + } +#if JS_HAS_LVALUE_RETURN + if (acx->rval2set) + JS_CALL_VALUE_TRACER(trc, acx->rval2, "rval2"); +#endif + + for (sh = acx->stackHeaders; sh; sh = sh->down) { + METER(trc->context->runtime->gcStats.stackseg++); + METER(trc->context->runtime->gcStats.segslots += sh->nslots); + TRACE_JSVALS(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); + } + + if (acx->localRootStack) + js_TraceLocalRoots(trc, acx->localRootStack); + + for (tvr = acx->tempValueRooters; tvr; tvr = tvr->down) { + switch (tvr->count) { + case JSTVU_SINGLE: + JS_SET_TRACING_NAME(trc, "tvr->u.value"); + js_CallValueTracerIfGCThing(trc, tvr->u.value); + break; + case JSTVU_TRACE: + tvr->u.trace(trc, tvr); + break; + case JSTVU_SPROP: + TRACE_SCOPE_PROPERTY(trc, tvr->u.sprop); + break; + case JSTVU_WEAK_ROOTS: + TraceWeakRoots(trc, tvr->u.weakRoots); + break; + case JSTVU_PARSE_CONTEXT: + js_TraceParseContext(trc, tvr->u.parseContext); + break; + case JSTVU_SCRIPT: + js_TraceScript(trc, tvr->u.script); + break; + default: + JS_ASSERT(tvr->count >= 0); + TRACE_JSVALS(trc, tvr->count, tvr->u.array, "tvr->u.array"); + } + } + + if (acx->sharpObjectMap.depth > 0) + js_TraceSharpMap(trc, &acx->sharpObjectMap); +} + +void +js_TraceTraceMonitor(JSTracer *trc, JSTraceMonitor *tm) +{ + if (IS_GC_MARKING_TRACER(trc)) { + tm->recoveryDoublePoolPtr = tm->recoveryDoublePool; + /* Make sure the global shape changes and will force a flush + of the code cache. */ + tm->globalShape = -1; + } +} + +void +js_TraceRuntime(JSTracer *trc, JSBool allAtoms) +{ + JSRuntime *rt = trc->context->runtime; + JSContext *iter, *acx; + + JS_DHashTableEnumerate(&rt->gcRootsHash, gc_root_traversal, trc); + if (rt->gcLocksHash) + JS_DHashTableEnumerate(rt->gcLocksHash, gc_lock_traversal, trc); + js_TraceAtomState(trc, allAtoms); + js_TraceNativeEnumerators(trc); + js_TraceRuntimeNumberState(trc); + + iter = NULL; + while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) + js_TraceContext(trc, acx); + + if (rt->gcExtraRootsTraceOp) + rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData); + +#ifdef JS_THREADSAFE + /* Trace the loop table(s) which can contain pointers to code objects. */ + while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) { + if (!acx->thread) + continue; + js_TraceTraceMonitor(trc, &acx->thread->traceMonitor); + } +#else + js_TraceTraceMonitor(trc, &rt->traceMonitor); +#endif +} + +static void +ProcessSetSlotRequest(JSContext *cx, JSSetSlotRequest *ssr) +{ + JSObject *obj, *pobj; + uint32 slot; + + obj = ssr->obj; + pobj = ssr->pobj; + slot = ssr->slot; + + while (pobj) { + pobj = js_GetWrappedObject(cx, pobj); + if (pobj == obj) { + ssr->errnum = JSMSG_CYCLIC_VALUE; + return; + } + pobj = JSVAL_TO_OBJECT(STOBJ_GET_SLOT(pobj, slot)); + } + + pobj = ssr->pobj; + + if (slot == JSSLOT_PROTO && OBJ_IS_NATIVE(obj)) { + JSScope *scope, *newscope; + JSObject *oldproto; + + /* Check to see whether obj shares its prototype's scope. */ + scope = OBJ_SCOPE(obj); + oldproto = STOBJ_GET_PROTO(obj); + if (oldproto && OBJ_SCOPE(oldproto) == scope) { + /* Either obj needs a new empty scope, or it should share pobj's. */ + if (!pobj || + !OBJ_IS_NATIVE(pobj) || + OBJ_GET_CLASS(cx, pobj) != STOBJ_GET_CLASS(oldproto)) { + /* + * With no proto and no scope of its own, obj is truly empty. + * + * If pobj is not native, obj needs its own empty scope -- it + * should not continue to share oldproto's scope once oldproto + * is not on obj's prototype chain. That would put properties + * from oldproto's scope ahead of properties defined by pobj, + * in lookup order. + * + * If pobj's class differs from oldproto's, we may need a new + * scope to handle differences in private and reserved slots, + * so we suboptimally but safely make one. + */ + if (!js_GetMutableScope(cx, obj)) { + ssr->errnum = JSMSG_OUT_OF_MEMORY; + return; + } + } else if (OBJ_SCOPE(pobj) != scope) { + newscope = (JSScope *) js_HoldObjectMap(cx, pobj->map); + obj->map = &newscope->map; + js_DropObjectMap(cx, &scope->map, obj); + JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope); + } + } + + /* + * Regenerate property cache shape ids for all of the scopes along the + * old prototype chain, in case any property cache entries were filled + * by looking up starting from obj. + */ + while (oldproto && OBJ_IS_NATIVE(oldproto)) { + scope = OBJ_SCOPE(oldproto); + SCOPE_MAKE_UNIQUE_SHAPE(cx, scope); + oldproto = STOBJ_GET_PROTO(scope->object); + } + } + + /* Finally, do the deed. */ + STOBJ_SET_SLOT(obj, slot, OBJECT_TO_JSVAL(pobj)); +} + +static void +DestroyScriptsToGC(JSContext *cx, JSScript **listp) +{ + JSScript *script; + + while ((script = *listp) != NULL) { + *listp = script->u.nextToGC; + script->u.nextToGC = NULL; + js_DestroyScript(cx, script); + } +} + +/* + * The gckind flag bit GC_LOCK_HELD indicates a call from js_NewGCThing with + * rt->gcLock already held, so the lock should be kept on return. + */ +void +js_GC(JSContext *cx, JSGCInvocationKind gckind) +{ + JSRuntime *rt; + JSBool keepAtoms; + JSGCCallback callback; + uintN i, type; + JSTracer trc; + uint32 thingSize, indexLimit; + JSGCArenaInfo *a, **ap, *emptyArenas; + uint8 flags, *flagp; + JSGCThing *thing, *freeList; + JSGCArenaList *arenaList; + JSBool allClear; +#ifdef JS_THREADSAFE + uint32 requestDebit; + JSContext *acx, *iter; +#endif +#ifdef JS_GCMETER + uint32 nlivearenas, nkilledarenas, nthings; +#endif + + JS_ASSERT_IF(gckind == GC_LAST_DITCH, !JS_ON_TRACE(cx)); + rt = cx->runtime; +#ifdef JS_THREADSAFE + /* Avoid deadlock. */ + JS_ASSERT(!JS_IS_RUNTIME_LOCKED(rt)); +#endif + + if (gckind & GC_KEEP_ATOMS) { + /* + * The set slot request and last ditch GC kinds preserve all atoms and + * weak roots. + */ + keepAtoms = JS_TRUE; + } else { + /* Keep atoms when a suspended compile is running on another context. */ + keepAtoms = (rt->gcKeepAtoms != 0); + JS_CLEAR_WEAK_ROOTS(&cx->weakRoots); + } + + /* + * Don't collect garbage if the runtime isn't up, and cx is not the last + * context in the runtime. The last context must force a GC, and nothing + * should suppress that final collection or there may be shutdown leaks, + * or runtime bloat until the next context is created. + */ + if (rt->state != JSRTS_UP && gckind != GC_LAST_CONTEXT) + return; + + restart_at_beginning: + /* + * Let the API user decide to defer a GC if it wants to (unless this + * is the last context). Invoke the callback regardless. Sample the + * callback in case we are freely racing with a JS_SetGCCallback{,RT} on + * another thread. + */ + if (gckind != GC_SET_SLOT_REQUEST && (callback = rt->gcCallback)) { + JSBool ok; + + if (gckind & GC_LOCK_HELD) + JS_UNLOCK_GC(rt); + ok = callback(cx, JSGC_BEGIN); + if (gckind & GC_LOCK_HELD) + JS_LOCK_GC(rt); + if (!ok && gckind != GC_LAST_CONTEXT) { + /* + * It's possible that we've looped back to this code from the 'goto + * restart_at_beginning' below in the GC_SET_SLOT_REQUEST code and + * that rt->gcLevel is now 0. Don't return without notifying! + */ + if (rt->gcLevel == 0 && (gckind & GC_LOCK_HELD)) + JS_NOTIFY_GC_DONE(rt); + return; + } + } + + /* Lock out other GC allocator and collector invocations. */ + if (!(gckind & GC_LOCK_HELD)) + JS_LOCK_GC(rt); + + METER(rt->gcStats.poke++); + rt->gcPoke = JS_FALSE; + +#ifdef JS_THREADSAFE + JS_ASSERT(cx->thread->id == js_CurrentThreadId()); + + /* Bump gcLevel and return rather than nest on this thread. */ + if (rt->gcThread == cx->thread) { + JS_ASSERT(rt->gcLevel > 0); + rt->gcLevel++; + METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel); + if (!(gckind & GC_LOCK_HELD)) + JS_UNLOCK_GC(rt); + return; + } + + /* + * If we're in one or more requests (possibly on more than one context) + * running on the current thread, indicate, temporarily, that all these + * requests are inactive. If cx->thread is NULL, then cx is not using + * the request model, and does not contribute to rt->requestCount. + */ + requestDebit = 0; + if (cx->thread) { + JSCList *head, *link; + + /* + * Check all contexts on cx->thread->contextList for active requests, + * counting each such context against requestDebit. + */ + head = &cx->thread->contextList; + for (link = head->next; link != head; link = link->next) { + acx = CX_FROM_THREAD_LINKS(link); + JS_ASSERT(acx->thread == cx->thread); + if (acx->requestDepth) + requestDebit++; + } + } else { + /* + * We assert, but check anyway, in case someone is misusing the API. + * Avoiding the loop over all of rt's contexts is a win in the event + * that the GC runs only on request-less contexts with null threads, + * in a special thread such as might be used by the UI/DOM/Layout + * "mozilla" or "main" thread in Mozilla-the-browser. + */ + JS_ASSERT(cx->requestDepth == 0); + if (cx->requestDepth) + requestDebit = 1; + } + if (requestDebit) { + JS_ASSERT(requestDebit <= rt->requestCount); + rt->requestCount -= requestDebit; + if (rt->requestCount == 0) + JS_NOTIFY_REQUEST_DONE(rt); + } + + /* If another thread is already in GC, don't attempt GC; wait instead. */ + if (rt->gcLevel > 0) { + /* Bump gcLevel to restart the current GC, so it finds new garbage. */ + rt->gcLevel++; + METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel); + + /* Wait for the other thread to finish, then resume our request. */ + while (rt->gcLevel > 0) + JS_AWAIT_GC_DONE(rt); + if (requestDebit) + rt->requestCount += requestDebit; + if (!(gckind & GC_LOCK_HELD)) + JS_UNLOCK_GC(rt); + return; + } + + /* No other thread is in GC, so indicate that we're now in GC. */ + rt->gcLevel = 1; + rt->gcThread = cx->thread; + + /* Wait for all other requests to finish. */ + while (rt->requestCount > 0) + JS_AWAIT_REQUEST_DONE(rt); + +#else /* !JS_THREADSAFE */ + + /* Bump gcLevel and return rather than nest; the outer gc will restart. */ + rt->gcLevel++; + METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel); + if (rt->gcLevel > 1) + return; + +#endif /* !JS_THREADSAFE */ + + /* + * Set rt->gcRunning here within the GC lock, and after waiting for any + * active requests to end, so that new requests that try to JS_AddRoot, + * JS_RemoveRoot, or JS_RemoveRootRT block in JS_BeginRequest waiting for + * rt->gcLevel to drop to zero, while request-less calls to the *Root* + * APIs block in js_AddRoot or js_RemoveRoot (see above in this file), + * waiting for GC to finish. + */ + rt->gcRunning = JS_TRUE; + + if (gckind == GC_SET_SLOT_REQUEST) { + JSSetSlotRequest *ssr; + + while ((ssr = rt->setSlotRequests) != NULL) { + rt->setSlotRequests = ssr->next; + JS_UNLOCK_GC(rt); + ssr->next = NULL; + ProcessSetSlotRequest(cx, ssr); + JS_LOCK_GC(rt); + } + + /* + * We assume here that killing links to parent and prototype objects + * does not create garbage (such objects typically are long-lived and + * widely shared, e.g. global objects, Function.prototype, etc.). We + * collect garbage only if a racing thread attempted GC and is waiting + * for us to finish (gcLevel > 1) or if someone already poked us. + */ + if (rt->gcLevel == 1 && !rt->gcPoke) + goto done_running; + + rt->gcLevel = 0; + rt->gcPoke = JS_FALSE; + rt->gcRunning = JS_FALSE; +#ifdef JS_THREADSAFE + rt->gcThread = NULL; + rt->requestCount += requestDebit; +#endif + gckind = GC_LOCK_HELD; + goto restart_at_beginning; + } + + JS_UNLOCK_GC(rt); + +#ifdef JS_TRACER + if (JS_ON_TRACE(cx)) + goto out; +#endif + + /* Reset malloc counter. */ + rt->gcMallocBytes = 0; + +#ifdef JS_DUMP_SCOPE_METERS + { extern void js_DumpScopeMeters(JSRuntime *rt); + js_DumpScopeMeters(rt); + } +#endif + + /* Clear property and JIT oracle caches (only for cx->thread if JS_THREADSAFE). */ + js_FlushPropertyCache(cx); +#ifdef JS_TRACER + js_FlushJITOracle(cx); +#endif + + /* Destroy eval'ed scripts. */ + DestroyScriptsToGC(cx, &JS_SCRIPTS_TO_GC(cx)); + +#ifdef JS_THREADSAFE + /* + * Clear thread-based caches. To avoid redundant clearing we unroll the + * current thread's step. + * + * In case a JSScript wrapped within an object was finalized, we null + * acx->thread->gsnCache.script and finish the cache's hashtable. Note + * that js_DestroyScript, called from script_finalize, will have already + * cleared cx->thread->gsnCache above during finalization, so we don't + * have to here. + */ + iter = NULL; + while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) { + if (!acx->thread || acx->thread == cx->thread) + continue; + GSN_CACHE_CLEAR(&acx->thread->gsnCache); + js_FlushPropertyCache(acx); +#ifdef JS_TRACER + js_FlushJITOracle(acx); +#endif + DestroyScriptsToGC(cx, &acx->thread->scriptsToGC); + } +#else + /* The thread-unsafe case just has to clear the runtime's GSN cache. */ + GSN_CACHE_CLEAR(&rt->gsnCache); +#endif + + restart: + rt->gcNumber++; + JS_ASSERT(!rt->gcUntracedArenaStackTop); + JS_ASSERT(rt->gcTraceLaterCount == 0); + + /* Reset the property cache's type id generator so we can compress ids. */ + rt->shapeGen = 0; + + /* + * Mark phase. + */ + JS_TRACER_INIT(&trc, cx, NULL); + rt->gcMarkingTracer = &trc; + JS_ASSERT(IS_GC_MARKING_TRACER(&trc)); + + for (a = rt->gcDoubleArenaList.first; a; a = a->prev) + a->u.hasMarkedDoubles = JS_FALSE; + + js_TraceRuntime(&trc, keepAtoms); + js_MarkScriptFilenames(rt, keepAtoms); + + /* + * Mark children of things that caused too deep recursion during the above + * tracing. + */ + TraceDelayedChildren(&trc); + + JS_ASSERT(!cx->insideGCMarkCallback); + if (rt->gcCallback) { + cx->insideGCMarkCallback = JS_TRUE; + (void) rt->gcCallback(cx, JSGC_MARK_END); + JS_ASSERT(cx->insideGCMarkCallback); + cx->insideGCMarkCallback = JS_FALSE; + } + JS_ASSERT(rt->gcTraceLaterCount == 0); + + rt->gcMarkingTracer = NULL; + + /* + * Sweep phase. + * + * Finalize as we sweep, outside of rt->gcLock but with rt->gcRunning set + * so that any attempt to allocate a GC-thing from a finalizer will fail, + * rather than nest badly and leave the unmarked newborn to be swept. + * + * We first sweep atom state so we can use js_IsAboutToBeFinalized on + * JSString or jsdouble held in a hashtable to check if the hashtable + * entry can be freed. Note that even after the entry is freed, JSObject + * finalizers can continue to access the corresponding jsdouble* and + * JSString* assuming that they are unique. This works since the + * atomization API must not be called during GC. + */ + js_SweepAtomState(cx); + + /* Finalize iterator states before the objects they iterate over. */ + CloseNativeIterators(cx); + + /* Finalize watch points associated with unreachable objects. */ + js_SweepWatchPoints(cx); + +#ifdef DEBUG + /* Save the pre-sweep count of scope-mapped properties. */ + rt->liveScopePropsPreSweep = rt->liveScopeProps; +#endif + + /* + * Here we need to ensure that JSObject instances are finalized before GC- + * allocated JSString and jsdouble instances so object's finalizer can + * access them even if they will be freed. For that we simply finalize the + * list containing JSObject first since the static assert at the beginning + * of the file guarantees that JSString and jsdouble instances are + * allocated from a different list. + */ + emptyArenas = NULL; + for (i = 0; i < GC_NUM_FREELISTS; i++) { + arenaList = &rt->gcArenaList[i == 0 + ? GC_FREELIST_INDEX(sizeof(JSObject)) + : i == GC_FREELIST_INDEX(sizeof(JSObject)) + ? 0 + : i]; + ap = &arenaList->last; + if (!(a = *ap)) + continue; + + JS_ASSERT(arenaList->lastCount > 0); + arenaList->freeList = NULL; + freeList = NULL; + thingSize = arenaList->thingSize; + indexLimit = THINGS_PER_ARENA(thingSize); + flagp = THING_FLAGP(a, arenaList->lastCount - 1); + METER((nlivearenas = 0, nkilledarenas = 0, nthings = 0)); + for (;;) { + JS_ASSERT(a->prevUntracedPage == 0); + JS_ASSERT(a->u.untracedThings == 0); + allClear = JS_TRUE; + do { + flags = *flagp; + if (flags & (GCF_MARK | GCF_LOCK)) { + *flagp &= ~GCF_MARK; + allClear = JS_FALSE; + METER(nthings++); + } else { + thing = FLAGP_TO_THING(flagp, thingSize); + if (!(flags & GCF_FINAL)) { + /* + * Call the finalizer with GCF_FINAL ORed into flags. + */ + *flagp = (uint8)(flags | GCF_FINAL); + type = flags & GCF_TYPEMASK; + switch (type) { + case GCX_OBJECT: + js_FinalizeObject(cx, (JSObject *) thing); + break; + case GCX_DOUBLE: + /* Do nothing. */ + break; +#if JS_HAS_XML_SUPPORT + case GCX_XML: + js_FinalizeXML(cx, (JSXML *) thing); + break; +#endif + default: + JS_ASSERT(type == GCX_STRING || + type - GCX_EXTERNAL_STRING < + GCX_NTYPES - GCX_EXTERNAL_STRING); + js_FinalizeStringRT(rt, (JSString *) thing, + (intN) (type - + GCX_EXTERNAL_STRING), + cx); + break; + } +#ifdef DEBUG + memset(thing, JS_FREE_PATTERN, thingSize); +#endif + } + thing->flagp = flagp; + thing->next = freeList; + freeList = thing; + } + } while (++flagp != THING_FLAGS_END(a)); + + if (allClear) { + /* + * Forget just assembled free list head for the arena and + * add the arena itself to the destroy list. + */ + freeList = arenaList->freeList; + if (a == arenaList->last) + arenaList->lastCount = (uint16) indexLimit; + *ap = a->prev; + a->prev = emptyArenas; + emptyArenas = a; + METER(nkilledarenas++); + } else { + arenaList->freeList = freeList; + ap = &a->prev; + METER(nlivearenas++); + } + if (!(a = *ap)) + break; + flagp = THING_FLAGP(a, indexLimit - 1); + } + + /* + * We use arenaList - &rt->gcArenaList[0], not i, as the stat index + * due to the enumeration reorder at the beginning of the loop. + */ + METER(UpdateArenaStats(&rt->gcStats.arenaStats[arenaList - + &rt->gcArenaList[0]], + nlivearenas, nkilledarenas, nthings)); + } + +#ifdef JS_THREADSAFE + /* + * Release all but two free list sets to avoid allocating a new set in + * js_NewGCThing. + */ + TrimGCFreeListsPool(rt, 2); +#endif + + ap = &rt->gcDoubleArenaList.first; + METER((nlivearenas = 0, nkilledarenas = 0, nthings = 0)); + while ((a = *ap) != NULL) { + if (!a->u.hasMarkedDoubles) { + /* No marked double values in the arena. */ + *ap = a->prev; + a->prev = emptyArenas; + emptyArenas = a; + METER(nkilledarenas++); + } else { + ap = &a->prev; +#ifdef JS_GCMETER + for (i = 0; i != DOUBLES_PER_ARENA; ++i) { + if (IsMarkedDouble(a, index)) + METER(nthings++); + } + METER(nlivearenas++); +#endif + } + } + METER(UpdateArenaStats(&rt->gcStats.doubleArenaStats, + nlivearenas, nkilledarenas, nthings)); + rt->gcDoubleArenaList.nextDoubleFlags = + rt->gcDoubleArenaList.first + ? DOUBLE_ARENA_BITMAP(rt->gcDoubleArenaList.first) + : DOUBLE_BITMAP_SENTINEL; + + /* + * Sweep the runtime's property tree after finalizing objects, in case any + * had watchpoints referencing tree nodes. + */ + js_SweepScopeProperties(cx); + + /* + * Sweep script filenames after sweeping functions in the generic loop + * above. In this way when a scripted function's finalizer destroys the + * script and calls rt->destroyScriptHook, the hook can still access the + * script's filename. See bug 323267. + */ + js_SweepScriptFilenames(rt); + + /* + * Destroy arenas after we finished the sweeping sofinalizers can safely + * use js_IsAboutToBeFinalized(). + */ + DestroyGCArenas(rt, emptyArenas); + + if (rt->gcCallback) + (void) rt->gcCallback(cx, JSGC_FINALIZE_END); +#ifdef DEBUG_srcnotesize + { extern void DumpSrcNoteSizeHist(); + DumpSrcNoteSizeHist(); + printf("GC HEAP SIZE %lu\n", (unsigned long)rt->gcBytes); + } +#endif + +#ifdef JS_SCOPE_DEPTH_METER + { static FILE *fp; + if (!fp) + fp = fopen("/tmp/scopedepth.stats", "w"); + + if (fp) { + JS_DumpBasicStats(&rt->protoLookupDepthStats, "proto-lookup depth", fp); + JS_DumpBasicStats(&rt->scopeSearchDepthStats, "scope-search depth", fp); + JS_DumpBasicStats(&rt->hostenvScopeDepthStats, "hostenv scope depth", fp); + JS_DumpBasicStats(&rt->lexicalScopeDepthStats, "lexical scope depth", fp); + + putc('\n', fp); + fflush(fp); + } + } +#endif /* JS_SCOPE_DEPTH_METER */ + +#ifdef JS_DUMP_LOOP_STATS + { static FILE *lsfp; + if (!lsfp) + lsfp = fopen("/tmp/loopstats", "w"); + if (lsfp) { + JS_DumpBasicStats(&rt->loopStats, "loops", lsfp); + fflush(lsfp); + } + } +#endif /* JS_DUMP_LOOP_STATS */ + +#ifdef JS_TRACER +out: +#endif + JS_LOCK_GC(rt); + + /* + * We want to restart GC if js_GC was called recursively or if any of the + * finalizers called js_RemoveRoot or js_UnlockGCThingRT. + */ + if (rt->gcLevel > 1 || rt->gcPoke) { + rt->gcLevel = 1; + rt->gcPoke = JS_FALSE; + JS_UNLOCK_GC(rt); + goto restart; + } + + if (rt->shapeGen >= SHAPE_OVERFLOW_BIT - 1) { + /* + * FIXME bug 440834: The shape id space has overflowed. Currently we + * cope badly with this. Every call to js_GenerateShape does GC, and + * we never re-enable the property cache. + */ + js_DisablePropertyCache(cx); +#ifdef JS_THREADSAFE + iter = NULL; + while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) { + if (!acx->thread || acx->thread == cx->thread) + continue; + js_DisablePropertyCache(acx); + } +#endif + } + + rt->gcLastBytes = rt->gcBytes; + done_running: + rt->gcLevel = 0; + rt->gcRunning = JS_FALSE; + +#ifdef JS_THREADSAFE + /* If we were invoked during a request, pay back the temporary debit. */ + if (requestDebit) + rt->requestCount += requestDebit; + rt->gcThread = NULL; + JS_NOTIFY_GC_DONE(rt); + + /* + * Unlock unless we have GC_LOCK_HELD which requires locked GC on return. + */ + if (!(gckind & GC_LOCK_HELD)) + JS_UNLOCK_GC(rt); +#endif + + /* + * Execute JSGC_END callback outside the lock. Again, sample the callback + * pointer in case it changes, since we are outside of the GC vs. requests + * interlock mechanism here. + */ + if (gckind != GC_SET_SLOT_REQUEST && (callback = rt->gcCallback)) { + JSWeakRoots savedWeakRoots; + JSTempValueRooter tvr; + + if (gckind & GC_KEEP_ATOMS) { + /* + * We allow JSGC_END implementation to force a full GC or allocate + * new GC things. Thus we must protect the weak roots from garbage + * collection and overwrites. + */ + savedWeakRoots = cx->weakRoots; + JS_PUSH_TEMP_ROOT_WEAK_COPY(cx, &savedWeakRoots, &tvr); + JS_KEEP_ATOMS(rt); + JS_UNLOCK_GC(rt); + } + + (void) callback(cx, JSGC_END); + + if (gckind & GC_KEEP_ATOMS) { + JS_LOCK_GC(rt); + JS_UNKEEP_ATOMS(rt); + JS_POP_TEMP_ROOT(cx, &tvr); + } else if (gckind == GC_LAST_CONTEXT && rt->gcPoke) { + /* + * On shutdown iterate until JSGC_END callback stops creating + * garbage. + */ + goto restart_at_beginning; + } + } +} + +void +js_UpdateMallocCounter(JSContext *cx, size_t nbytes) +{ + uint32 *pbytes, bytes; + +#ifdef JS_THREADSAFE + pbytes = &cx->thread->gcMallocBytes; +#else + pbytes = &cx->runtime->gcMallocBytes; +#endif + bytes = *pbytes; + *pbytes = ((uint32)-1 - bytes <= nbytes) ? (uint32)-1 : bytes + nbytes; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsgc.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsgc.h new file mode 100644 index 0000000..a0634b2 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsgc.h @@ -0,0 +1,427 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsgc_h___ +#define jsgc_h___ +/* + * JS Garbage Collector. + */ +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsdhash.h" +#include "jsbit.h" +#include "jsutil.h" + +JS_BEGIN_EXTERN_C + +JS_STATIC_ASSERT(JSTRACE_STRING == 2); + +#define JSTRACE_XML 3 + +/* + * One past the maximum trace kind. + */ +#define JSTRACE_LIMIT 4 + +/* + * We use the trace kinds as the types for all GC things except external + * strings. + */ +#define GCX_OBJECT JSTRACE_OBJECT /* JSObject */ +#define GCX_DOUBLE JSTRACE_DOUBLE /* jsdouble */ +#define GCX_STRING JSTRACE_STRING /* JSString */ +#define GCX_XML JSTRACE_XML /* JSXML */ +#define GCX_EXTERNAL_STRING JSTRACE_LIMIT /* JSString with external + chars */ +/* + * The number of defined GC types. + */ +#define GCX_NTYPES (GCX_EXTERNAL_STRING + 8) + +/* + * The maximum limit for the number of GC types. + */ +#define GCX_LIMIT_LOG2 4 /* type index bits */ +#define GCX_LIMIT JS_BIT(GCX_LIMIT_LOG2) + +JS_STATIC_ASSERT(GCX_NTYPES <= GCX_LIMIT); + +/* GC flag definitions, must fit in 8 bits (type index goes in the low bits). */ +#define GCF_TYPEMASK JS_BITMASK(GCX_LIMIT_LOG2) +#define GCF_MARK JS_BIT(GCX_LIMIT_LOG2) +#define GCF_FINAL JS_BIT(GCX_LIMIT_LOG2 + 1) +#define GCF_LOCKSHIFT (GCX_LIMIT_LOG2 + 2) /* lock bit shift */ +#define GCF_LOCK JS_BIT(GCF_LOCKSHIFT) /* lock request bit in API */ + +/* + * Get the type of the external string or -1 if the string was not created + * with JS_NewExternalString. + */ +extern intN +js_GetExternalStringGCType(JSString *str); + +extern JS_FRIEND_API(uint32) +js_GetGCThingTraceKind(void *thing); + +/* + * The sole purpose of the function is to preserve public API compatibility + * in JS_GetStringBytes which takes only single JSString* argument. + */ +JSRuntime* +js_GetGCStringRuntime(JSString *str); + +#if 1 +/* + * Since we're forcing a GC from JS_GC anyway, don't bother wasting cycles + * loading oldval. XXX remove implied force, fix jsinterp.c's "second arg + * ignored", etc. + */ +#define GC_POKE(cx, oldval) ((cx)->runtime->gcPoke = JS_TRUE) +#else +#define GC_POKE(cx, oldval) ((cx)->runtime->gcPoke = JSVAL_IS_GCTHING(oldval)) +#endif + +/* + * Write barrier macro monitoring property update from oldval to newval in + * scope->object. + * + * Since oldval is used only for the branded scope case, and the oldval actual + * argument expression is typically not used otherwise by callers, performance + * benefits if oldval is *not* evaluated into a callsite temporary variable, + * and instead passed to GC_WRITE_BARRIER for conditional evaluation (we rely + * on modern compilers to do a good CSE job). Yay, C macros. + */ +#define GC_WRITE_BARRIER(cx,scope,oldval,newval) \ + JS_BEGIN_MACRO \ + if (SCOPE_IS_BRANDED(scope) && \ + (oldval) != (newval) && \ + (VALUE_IS_FUNCTION(cx,oldval) || VALUE_IS_FUNCTION(cx,newval))) { \ + SCOPE_MAKE_UNIQUE_SHAPE(cx, scope); \ + } \ + GC_POKE(cx, oldval); \ + JS_END_MACRO + +extern JSBool +js_InitGC(JSRuntime *rt, uint32 maxbytes); + +extern void +js_FinishGC(JSRuntime *rt); + +extern intN +js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop, + JSStringFinalizeOp newop); + +extern JSBool +js_AddRoot(JSContext *cx, void *rp, const char *name); + +extern JSBool +js_AddRootRT(JSRuntime *rt, void *rp, const char *name); + +extern JSBool +js_RemoveRoot(JSRuntime *rt, void *rp); + +#ifdef DEBUG +extern void +js_DumpNamedRoots(JSRuntime *rt, + void (*dump)(const char *name, void *rp, void *data), + void *data); +#endif + +extern uint32 +js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data); + +/* Table of pointers with count valid members. */ +typedef struct JSPtrTable { + size_t count; + void **array; +} JSPtrTable; + +extern JSBool +js_RegisterCloseableIterator(JSContext *cx, JSObject *obj); + +/* + * The private JSGCThing struct, which describes a gcFreeList element. + */ +struct JSGCThing { + JSGCThing *next; + uint8 *flagp; +}; + +#define GC_NBYTES_MAX (10 * sizeof(JSGCThing)) +#define GC_NUM_FREELISTS (GC_NBYTES_MAX / sizeof(JSGCThing)) +#define GC_FREELIST_NBYTES(i) (((i) + 1) * sizeof(JSGCThing)) +#define GC_FREELIST_INDEX(n) (((n) / sizeof(JSGCThing)) - 1) + +/* + * Allocates a new GC thing of the given size. After a successful allocation + * the caller must fully initialize the thing before calling any function that + * can potentially trigger GC. This will ensure that GC tracing never sees junk + * values stored in the partially initialized thing. + */ +extern void * +js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes); + +/* + * Allocate a new double jsval and store the result in *vp. vp must be a root. + * The function does not copy the result into any weak root. + */ +extern JSBool +js_NewDoubleInRootedValue(JSContext *cx, jsdouble d, jsval *vp); + +/* + * Return a pointer to a new GC-allocated and weakly-rooted jsdouble number, + * or null when the allocation fails. + */ +extern jsdouble * +js_NewWeaklyRootedDouble(JSContext *cx, jsdouble d); + +extern JSBool +js_LockGCThingRT(JSRuntime *rt, void *thing); + +extern JSBool +js_UnlockGCThingRT(JSRuntime *rt, void *thing); + +extern JSBool +js_IsAboutToBeFinalized(JSContext *cx, void *thing); + +/* + * Macro to test if a traversal is the marking phase of GC to avoid exposing + * ScriptFilenameEntry to traversal implementations. + */ +#define IS_GC_MARKING_TRACER(trc) ((trc)->callback == NULL) + +#if JS_HAS_XML_SUPPORT +# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) < JSTRACE_LIMIT) +#else +# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_STRING) +#endif + +/* + * JS_IS_VALID_TRACE_KIND assumes that JSTRACE_STRING is the last non-xml + * trace kind when JS_HAS_XML_SUPPORT is false. + */ +JS_STATIC_ASSERT(JSTRACE_STRING + 1 == JSTRACE_XML); + +/* + * Trace jsval when JSVAL_IS_OBJECT(v) can be an arbitrary GC thing casted as + * JSVAL_OBJECT and js_GetGCThingTraceKind has to be used to find the real + * type behind v. + */ +extern void +js_CallValueTracerIfGCThing(JSTracer *trc, jsval v); + +extern void +js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp); + +extern void +js_TraceRuntime(JSTracer *trc, JSBool allAtoms); + +extern JS_FRIEND_API(void) +js_TraceContext(JSTracer *trc, JSContext *acx); + +/* + * Kinds of js_GC invocation. + */ +typedef enum JSGCInvocationKind { + /* Normal invocation. */ + GC_NORMAL = 0, + + /* + * Called from js_DestroyContext for last JSContext in a JSRuntime, when + * it is imperative that rt->gcPoke gets cleared early in js_GC. + */ + GC_LAST_CONTEXT = 1, + + /* + * Flag bit telling js_GC that the caller has already acquired rt->gcLock. + * Currently, this flag is set for the invocation kinds that also preserve + * atoms and weak roots, so we don't need another bit for GC_KEEP_ATOMS. + */ + GC_LOCK_HELD = 0x10, + GC_KEEP_ATOMS = GC_LOCK_HELD, + + /* + * Called from js_SetProtoOrParent with a request to set an object's proto + * or parent slot inserted on rt->setSlotRequests. + */ + GC_SET_SLOT_REQUEST = GC_LOCK_HELD | 1, + + /* + * Called from js_NewGCThing as a last-ditch GC attempt. See comments in + * jsgc.c just before js_GC's definition for details. + */ + GC_LAST_DITCH = GC_LOCK_HELD | 2 +} JSGCInvocationKind; + +extern void +js_GC(JSContext *cx, JSGCInvocationKind gckind); + +/* Call this after succesful malloc of memory for GC-related things. */ +extern void +js_UpdateMallocCounter(JSContext *cx, size_t nbytes); + +typedef struct JSGCArenaInfo JSGCArenaInfo; +typedef struct JSGCArenaList JSGCArenaList; +typedef struct JSGCChunkInfo JSGCChunkInfo; + +struct JSGCArenaList { + JSGCArenaInfo *last; /* last allocated GC arena */ + uint16 lastCount; /* number of allocated things in the last + arena */ + uint16 thingSize; /* size of things to allocate on this list + */ + JSGCThing *freeList; /* list of free GC things */ +}; + +typedef union JSGCDoubleCell JSGCDoubleCell; + +union JSGCDoubleCell { + double number; + JSGCDoubleCell *link; +}; + +JS_STATIC_ASSERT(sizeof(JSGCDoubleCell) == sizeof(double)); + +typedef struct JSGCDoubleArenaList { + JSGCArenaInfo *first; /* first allocated GC arena */ + jsbitmap *nextDoubleFlags; /* bitmask with flags to check for free + things */ +} JSGCDoubleArenaList; + +typedef struct JSGCFreeListSet JSGCFreeListSet; + +struct JSGCFreeListSet { + JSGCThing *array[GC_NUM_FREELISTS]; + JSGCFreeListSet *link; +}; + +extern const JSGCFreeListSet js_GCEmptyFreeListSet; + +extern void +js_RevokeGCLocalFreeLists(JSContext *cx); + +struct JSWeakRoots { + /* Most recently created things by type, members of the GC's root set. */ + void *newborn[GCX_NTYPES]; + + /* Atom root for the last-looked-up atom on this context. */ + jsval lastAtom; + + /* Root for the result of the most recent js_InternalInvoke call. */ + jsval lastInternalResult; +}; + +JS_STATIC_ASSERT(JSVAL_NULL == 0); +#define JS_CLEAR_WEAK_ROOTS(wr) (memset((wr), 0, sizeof(JSWeakRoots))) + +/* + * Increase runtime->gcBytes by sz bytes to account for an allocation outside + * the GC that will be freed only after the GC is run. The function may run + * the last ditch GC to ensure that gcBytes does not exceed gcMaxBytes. It will + * fail if the latter is not possible. + * + * This function requires that runtime->gcLock is held on entry. On successful + * return the lock is still held and on failure it will be released with + * the error reported. + */ +extern JSBool +js_AddAsGCBytes(JSContext *cx, size_t sz); + +extern void +js_RemoveAsGCBytes(JSRuntime* rt, size_t sz); + +#ifdef DEBUG_notme +#define JS_GCMETER 1 +#endif + +#ifdef JS_GCMETER + +typedef struct JSGCArenaStats { + uint32 alloc; /* allocation attempts */ + uint32 localalloc; /* allocations from local lists */ + uint32 retry; /* allocation retries after running the GC */ + uint32 fail; /* allocation failures */ + uint32 nthings; /* live GC things */ + uint32 maxthings; /* maximum of live GC cells */ + double totalthings; /* live GC things the GC scanned so far */ + uint32 narenas; /* number of arena in list before the GC */ + uint32 newarenas; /* new arenas allocated before the last GC */ + uint32 livearenas; /* number of live arenas after the last GC */ + uint32 maxarenas; /* maximum of allocated arenas */ + uint32 totalarenas; /* total number of arenas with live things that + GC scanned so far */ +} JSGCArenaStats; + +typedef struct JSGCStats { + uint32 finalfail; /* finalizer calls allocator failures */ + uint32 lockborn; /* things born locked */ + uint32 lock; /* valid lock calls */ + uint32 unlock; /* valid unlock calls */ + uint32 depth; /* mark tail recursion depth */ + uint32 maxdepth; /* maximum mark tail recursion depth */ + uint32 cdepth; /* mark recursion depth of C functions */ + uint32 maxcdepth; /* maximum mark recursion depth of C functions */ + uint32 untraced; /* number of times tracing of GC thing's children were + delayed due to a low C stack */ +#ifdef DEBUG + uint32 maxuntraced;/* maximum number of things with children to trace + later */ +#endif + uint32 maxlevel; /* maximum GC nesting (indirect recursion) level */ + uint32 poke; /* number of potentially useful GC calls */ + uint32 afree; /* thing arenas freed so far */ + uint32 stackseg; /* total extraordinary stack segments scanned */ + uint32 segslots; /* total stack segment jsval slots scanned */ + uint32 nclose; /* number of objects with close hooks */ + uint32 maxnclose; /* max number of objects with close hooks */ + uint32 closelater; /* number of close hooks scheduled to run */ + uint32 maxcloselater; /* max number of close hooks scheduled to run */ + + JSGCArenaStats arenaStats[GC_NUM_FREELISTS]; + JSGCArenaStats doubleArenaStats; +} JSGCStats; + +extern JS_FRIEND_API(void) +js_DumpGCStats(JSRuntime *rt, FILE *fp); + +#endif /* JS_GCMETER */ + +JS_END_EXTERN_C + +#endif /* jsgc_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jshash.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jshash.cpp new file mode 100644 index 0000000..5fe5f78 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jshash.cpp @@ -0,0 +1,476 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * PR hash table package. + */ +#include "jsstddef.h" +#include +#include +#include "jstypes.h" +#include "jsbit.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jshash.h" /* Added by JSIFY */ + +/* Compute the number of buckets in ht */ +#define NBUCKETS(ht) JS_BIT(JS_HASH_BITS - (ht)->shift) + +/* The smallest table has 16 buckets */ +#define MINBUCKETSLOG2 4 +#define MINBUCKETS JS_BIT(MINBUCKETSLOG2) + +/* Compute the maximum entries given n buckets that we will tolerate, ~90% */ +#define OVERLOADED(n) ((n) - ((n) >> 3)) + +/* Compute the number of entries below which we shrink the table by half */ +#define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0) + +/* +** Stubs for default hash allocator ops. +*/ +static void * +DefaultAllocTable(void *pool, size_t size) +{ + return malloc(size); +} + +static void +DefaultFreeTable(void *pool, void *item) +{ + free(item); +} + +static JSHashEntry * +DefaultAllocEntry(void *pool, const void *key) +{ + return (JSHashEntry*) malloc(sizeof(JSHashEntry)); +} + +static void +DefaultFreeEntry(void *pool, JSHashEntry *he, uintN flag) +{ + if (flag == HT_FREE_ENTRY) + free(he); +} + +static JSHashAllocOps defaultHashAllocOps = { + DefaultAllocTable, DefaultFreeTable, + DefaultAllocEntry, DefaultFreeEntry +}; + +JS_PUBLIC_API(JSHashTable *) +JS_NewHashTable(uint32 n, JSHashFunction keyHash, + JSHashComparator keyCompare, JSHashComparator valueCompare, + JSHashAllocOps *allocOps, void *allocPriv) +{ + JSHashTable *ht; + size_t nb; + + if (n <= MINBUCKETS) { + n = MINBUCKETSLOG2; + } else { + n = JS_CeilingLog2(n); + if ((int32)n < 0) + return NULL; + } + + if (!allocOps) allocOps = &defaultHashAllocOps; + + ht = (JSHashTable*) allocOps->allocTable(allocPriv, sizeof *ht); + if (!ht) + return NULL; + memset(ht, 0, sizeof *ht); + ht->shift = JS_HASH_BITS - n; + n = JS_BIT(n); + nb = n * sizeof(JSHashEntry *); + ht->buckets = (JSHashEntry**) allocOps->allocTable(allocPriv, nb); + if (!ht->buckets) { + allocOps->freeTable(allocPriv, ht); + return NULL; + } + memset(ht->buckets, 0, nb); + + ht->keyHash = keyHash; + ht->keyCompare = keyCompare; + ht->valueCompare = valueCompare; + ht->allocOps = allocOps; + ht->allocPriv = allocPriv; + return ht; +} + +JS_PUBLIC_API(void) +JS_HashTableDestroy(JSHashTable *ht) +{ + uint32 i, n; + JSHashEntry *he, **hep; + JSHashAllocOps *allocOps = ht->allocOps; + void *allocPriv = ht->allocPriv; + + n = NBUCKETS(ht); + for (i = 0; i < n; i++) { + hep = &ht->buckets[i]; + while ((he = *hep) != NULL) { + *hep = he->next; + allocOps->freeEntry(allocPriv, he, HT_FREE_ENTRY); + } + } +#ifdef DEBUG + memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]); +#endif + allocOps->freeTable(allocPriv, ht->buckets); +#ifdef DEBUG + memset(ht, 0xDB, sizeof *ht); +#endif + allocOps->freeTable(allocPriv, ht); +} + +/* + * Multiplicative hash, from Knuth 6.4. + */ +#define BUCKET_HEAD(ht, keyHash) \ + (&(ht)->buckets[((keyHash) * JS_GOLDEN_RATIO) >> (ht)->shift]) + +JS_PUBLIC_API(JSHashEntry **) +JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key) +{ + JSHashEntry *he, **hep, **hep0; + +#ifdef JS_HASHMETER + ht->nlookups++; +#endif + hep = hep0 = BUCKET_HEAD(ht, keyHash); + while ((he = *hep) != NULL) { + if (he->keyHash == keyHash && ht->keyCompare(key, he->key)) { + /* Move to front of chain if not already there */ + if (hep != hep0) { + *hep = he->next; + he->next = *hep0; + *hep0 = he; + } + return hep0; + } + hep = &he->next; +#ifdef JS_HASHMETER + ht->nsteps++; +#endif + } + return hep; +} + +static JSBool +Resize(JSHashTable *ht, uint32 newshift) +{ + size_t nb, nentries, i; + JSHashEntry **oldbuckets, *he, *next, **hep; +#ifdef DEBUG + size_t nold = NBUCKETS(ht); +#endif + + JS_ASSERT(newshift < JS_HASH_BITS); + + nb = (size_t)1 << (JS_HASH_BITS - newshift); + + /* Integer overflow protection. */ + if (nb > (size_t)-1 / sizeof(JSHashEntry*)) + return JS_FALSE; + nb *= sizeof(JSHashEntry*); + + oldbuckets = ht->buckets; + ht->buckets = (JSHashEntry**)ht->allocOps->allocTable(ht->allocPriv, nb); + if (!ht->buckets) { + ht->buckets = oldbuckets; + return JS_FALSE; + } + memset(ht->buckets, 0, nb); + + ht->shift = newshift; + nentries = ht->nentries; + + for (i = 0; nentries != 0; i++) { + for (he = oldbuckets[i]; he; he = next) { + JS_ASSERT(nentries != 0); + --nentries; + next = he->next; + hep = BUCKET_HEAD(ht, he->keyHash); + + /* + * Since he comes from the old table, it must be unique and we + * simply add it to the head of bucket chain without chain lookup. + */ + he->next = *hep; + *hep = he; + } + } +#ifdef DEBUG + memset(oldbuckets, 0xDB, nold * sizeof oldbuckets[0]); +#endif + ht->allocOps->freeTable(ht->allocPriv, oldbuckets); + return JS_TRUE; +} + +JS_PUBLIC_API(JSHashEntry *) +JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **hep, + JSHashNumber keyHash, const void *key, void *value) +{ + uint32 n; + JSHashEntry *he; + + /* Grow the table if it is overloaded */ + n = NBUCKETS(ht); + if (ht->nentries >= OVERLOADED(n)) { + if (!Resize(ht, ht->shift - 1)) + return NULL; +#ifdef JS_HASHMETER + ht->ngrows++; +#endif + hep = JS_HashTableRawLookup(ht, keyHash, key); + } + + /* Make a new key value entry */ + he = ht->allocOps->allocEntry(ht->allocPriv, key); + if (!he) + return NULL; + he->keyHash = keyHash; + he->key = key; + he->value = value; + he->next = *hep; + *hep = he; + ht->nentries++; + return he; +} + +JS_PUBLIC_API(JSHashEntry *) +JS_HashTableAdd(JSHashTable *ht, const void *key, void *value) +{ + JSHashNumber keyHash; + JSHashEntry *he, **hep; + + keyHash = ht->keyHash(key); + hep = JS_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) != NULL) { + /* Hit; see if values match */ + if (ht->valueCompare(he->value, value)) { + /* key,value pair is already present in table */ + return he; + } + if (he->value) + ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_VALUE); + he->value = value; + return he; + } + return JS_HashTableRawAdd(ht, hep, keyHash, key, value); +} + +JS_PUBLIC_API(void) +JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he) +{ + uint32 n; + + *hep = he->next; + ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_ENTRY); + + /* Shrink table if it's underloaded */ + n = NBUCKETS(ht); + if (--ht->nentries < UNDERLOADED(n)) { + Resize(ht, ht->shift + 1); +#ifdef JS_HASHMETER + ht->nshrinks++; +#endif + } +} + +JS_PUBLIC_API(JSBool) +JS_HashTableRemove(JSHashTable *ht, const void *key) +{ + JSHashNumber keyHash; + JSHashEntry *he, **hep; + + keyHash = ht->keyHash(key); + hep = JS_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) == NULL) + return JS_FALSE; + + /* Hit; remove element */ + JS_HashTableRawRemove(ht, hep, he); + return JS_TRUE; +} + +JS_PUBLIC_API(void *) +JS_HashTableLookup(JSHashTable *ht, const void *key) +{ + JSHashNumber keyHash; + JSHashEntry *he, **hep; + + keyHash = ht->keyHash(key); + hep = JS_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) != NULL) { + return he->value; + } + return NULL; +} + +/* +** Iterate over the entries in the hash table calling func for each +** entry found. Stop if "f" says to (return value & JS_ENUMERATE_STOP). +** Return a count of the number of elements scanned. +*/ +JS_PUBLIC_API(int) +JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg) +{ + JSHashEntry *he, **hep, **bucket; + uint32 nlimit, n, nbuckets, newlog2; + int rv; + + nlimit = ht->nentries; + n = 0; + for (bucket = ht->buckets; n != nlimit; ++bucket) { + hep = bucket; + while ((he = *hep) != NULL) { + JS_ASSERT(n < nlimit); + rv = f(he, n, arg); + n++; + if (rv & HT_ENUMERATE_REMOVE) { + *hep = he->next; + ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_ENTRY); + --ht->nentries; + } else { + hep = &he->next; + } + if (rv & HT_ENUMERATE_STOP) { + goto out; + } + } + } + +out: + /* Shrink table if removal of entries made it underloaded */ + if (ht->nentries != nlimit) { + JS_ASSERT(ht->nentries < nlimit); + nbuckets = NBUCKETS(ht); + if (MINBUCKETS < nbuckets && ht->nentries < UNDERLOADED(nbuckets)) { + newlog2 = JS_CeilingLog2(ht->nentries); + if (newlog2 < MINBUCKETSLOG2) + newlog2 = MINBUCKETSLOG2; + + /* Check that we really shrink the table. */ + JS_ASSERT(JS_HASH_BITS - ht->shift > newlog2); + Resize(ht, JS_HASH_BITS - newlog2); + } + } + return (int)n; +} + +#ifdef JS_HASHMETER +#include + +JS_PUBLIC_API(void) +JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp) +{ + double sqsum, mean, sigma; + uint32 nchains, nbuckets; + uint32 i, n, maxChain, maxChainLen; + JSHashEntry *he; + + sqsum = 0; + nchains = 0; + maxChain = maxChainLen = 0; + nbuckets = NBUCKETS(ht); + for (i = 0; i < nbuckets; i++) { + he = ht->buckets[i]; + if (!he) + continue; + nchains++; + for (n = 0; he; he = he->next) + n++; + sqsum += n * n; + if (n > maxChainLen) { + maxChainLen = n; + maxChain = i; + } + } + + mean = JS_MeanAndStdDev(nchains, ht->nentries, sqsum, &sigma); + + fprintf(fp, "\nHash table statistics:\n"); + fprintf(fp, " number of lookups: %u\n", ht->nlookups); + fprintf(fp, " number of entries: %u\n", ht->nentries); + fprintf(fp, " number of grows: %u\n", ht->ngrows); + fprintf(fp, " number of shrinks: %u\n", ht->nshrinks); + fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps + / ht->nlookups); + fprintf(fp, "mean hash chain length: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sigma); + fprintf(fp, " max hash chain length: %u\n", maxChainLen); + fprintf(fp, " max hash chain: [%u]\n", maxChain); + + for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++) + if (dump(he, i, fp) != HT_ENUMERATE_NEXT) + break; +} +#endif /* JS_HASHMETER */ + +JS_PUBLIC_API(int) +JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp) +{ + int count; + + count = JS_HashTableEnumerateEntries(ht, dump, fp); +#ifdef JS_HASHMETER + JS_HashTableDumpMeter(ht, dump, fp); +#endif + return count; +} + +JS_PUBLIC_API(JSHashNumber) +JS_HashString(const void *key) +{ + JSHashNumber h; + const unsigned char *s; + + h = 0; + for (s = (const unsigned char *)key; *s; s++) + h = JS_ROTATE_LEFT32(h, 4) ^ *s; + return h; +} + +JS_PUBLIC_API(int) +JS_CompareValues(const void *v1, const void *v2) +{ + return v1 == v2; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jshash.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jshash.h new file mode 100644 index 0000000..defc193 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jshash.h @@ -0,0 +1,151 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jshash_h___ +#define jshash_h___ +/* + * API to portable hash table code. + */ +#include +#include +#include "jstypes.h" +#include "jscompat.h" + +JS_BEGIN_EXTERN_C + +typedef uint32 JSHashNumber; +typedef struct JSHashEntry JSHashEntry; +typedef struct JSHashTable JSHashTable; + +#define JS_HASH_BITS 32 +#define JS_GOLDEN_RATIO 0x9E3779B9U + +typedef JSHashNumber (* JSHashFunction)(const void *key); +typedef intN (* JSHashComparator)(const void *v1, const void *v2); +typedef intN (* JSHashEnumerator)(JSHashEntry *he, intN i, void *arg); + +/* Flag bits in JSHashEnumerator's return value */ +#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */ +#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */ +#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */ + +typedef struct JSHashAllocOps { + void * (*allocTable)(void *pool, size_t size); + void (*freeTable)(void *pool, void *item); + JSHashEntry * (*allocEntry)(void *pool, const void *key); + void (*freeEntry)(void *pool, JSHashEntry *he, uintN flag); +} JSHashAllocOps; + +#define HT_FREE_VALUE 0 /* just free the entry's value */ +#define HT_FREE_ENTRY 1 /* free value and entire entry */ + +struct JSHashEntry { + JSHashEntry *next; /* hash chain linkage */ + JSHashNumber keyHash; /* key hash function result */ + const void *key; /* ptr to opaque key */ + void *value; /* ptr to opaque value */ +}; + +struct JSHashTable { + JSHashEntry **buckets; /* vector of hash buckets */ + uint32 nentries; /* number of entries in table */ + uint32 shift; /* multiplicative hash shift */ + JSHashFunction keyHash; /* key hash function */ + JSHashComparator keyCompare; /* key comparison function */ + JSHashComparator valueCompare; /* value comparison function */ + JSHashAllocOps *allocOps; /* allocation operations */ + void *allocPriv; /* allocation private data */ +#ifdef JS_HASHMETER + uint32 nlookups; /* total number of lookups */ + uint32 nsteps; /* number of hash chains traversed */ + uint32 ngrows; /* number of table expansions */ + uint32 nshrinks; /* number of table contractions */ +#endif +}; + +/* + * Create a new hash table. + * If allocOps is null, use default allocator ops built on top of malloc(). + */ +extern JS_PUBLIC_API(JSHashTable *) +JS_NewHashTable(uint32 n, JSHashFunction keyHash, + JSHashComparator keyCompare, JSHashComparator valueCompare, + JSHashAllocOps *allocOps, void *allocPriv); + +extern JS_PUBLIC_API(void) +JS_HashTableDestroy(JSHashTable *ht); + +/* Low level access methods */ +extern JS_PUBLIC_API(JSHashEntry **) +JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key); + +extern JS_PUBLIC_API(JSHashEntry *) +JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **hep, JSHashNumber keyHash, + const void *key, void *value); + +extern JS_PUBLIC_API(void) +JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he); + +/* Higher level access methods */ +extern JS_PUBLIC_API(JSHashEntry *) +JS_HashTableAdd(JSHashTable *ht, const void *key, void *value); + +extern JS_PUBLIC_API(JSBool) +JS_HashTableRemove(JSHashTable *ht, const void *key); + +extern JS_PUBLIC_API(intN) +JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg); + +extern JS_PUBLIC_API(void *) +JS_HashTableLookup(JSHashTable *ht, const void *key); + +extern JS_PUBLIC_API(intN) +JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp); + +/* General-purpose C string hash function. */ +extern JS_PUBLIC_API(JSHashNumber) +JS_HashString(const void *key); + +/* Stub function just returns v1 == v2 */ +extern JS_PUBLIC_API(intN) +JS_CompareValues(const void *v1, const void *v2); + +JS_END_EXTERN_C + +#endif /* jshash_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsify.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsify.pl new file mode 100644 index 0000000..0ce2186 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsify.pl @@ -0,0 +1,483 @@ +#!/usr/local/bin/perl + +# This script modifies C code to use the hijacked NSPR routines that are +# now baked into the JavaScript engine rather than using the NSPR +# routines that they were based on, i.e. types like PRArenaPool are changed +# to JSArenaPool. +# +# This script was used in 9/98 to facilitate the incorporation of some NSPR +# code into the JS engine so as to minimize dependency on NSPR. +# + +# Command-line: jsify.pl [options] [filename]* +# +# Options: +# -r Reverse direction of transformation, i.e. JS ==> NSPR2 +# -outdir Directory in which to place output files + + +# NSPR2 symbols that will be modified to JS symbols, e.g. +# PRArena <==> JSArena + +@NSPR_symbols = ( +"PRArena", +"PRArenaPool", +"PRArenaStats", +"PR_ARENAMETER", +"PR_ARENA_", +"PR_ARENA_ALIGN", +"PR_ARENA_ALLOCATE", +"PR_ARENA_CONST_ALIGN_MASK", +"PR_ARENA_DEFAULT_ALIGN", +"PR_ARENA_DESTROY", +"PR_ARENA_GROW", +"PR_ARENA_MARK", +"PR_ARENA_RELEASE", + +"PR_smprintf", +"PR_smprintf_free", +"PR_snprintf", +"PR_sprintf_append", +"PR_sscanf", +"PR_sxprintf", +"PR_vsmprintf", +"PR_vsnprintf", +"PR_vsprintf_append", +"PR_vsxprintf", + +"PRCList", +"PRCListStr", +"PRCLists", + +"PRDestroyEventProc", +"PREvent", +"PREventFunProc", +"PREventQueue", +"PRHandleEventProc", +"PR_PostEvent", +"PR_PostSynchronousEvent", +"PR_ProcessPendingEvents", +"PR_CreateEventQueue", +"PR_DequeueEvent", +"PR_DestroyEvent", +"PR_DestroyEventQueue", +"PR_EventAvailable", +"PR_EventLoop", +"PR_GetEvent", +"PR_GetEventOwner", +"PR_GetEventQueueMonitor", +"PR_GetEventQueueSelectFD", +"PR_GetMainEventQueue", +"PR_HandleEvent", +"PR_InitEvent", +"PR_ENTER_EVENT_QUEUE_MONITOR", +"PR_EXIT_EVENT_QUEUE_MONITOR", +"PR_MapEvents", +"PR_RevokeEvents", + +"PR_cnvtf", +"PR_dtoa", +"PR_strtod", + +"PRFileDesc", + +"PR_HASH_BITS", +"PR_GOLDEN_RATIO", +"PRHashAllocOps", +"PRHashComparator", +"PRHashEntry", +"PRHashEnumerator", +"PRHashFunction", +"PRHashNumber", +"PRHashTable", +"PR_HashString", +"PR_HashTableAdd", +"PR_HashTableDestroy", +"PR_HashTableDump", +"PR_HashTableEnumerateEntries", +"PR_HashTableLookup", +"PR_HashTableRawAdd", +"PR_HashTableRawLookup", +"PR_HashTableRawRemove", +"PR_HashTableRemove", + +"PRBool", +"PRFloat64", +"PRInt16", +"PRInt32", +"PRInt64", +"PRInt8", +"PRIntn", +"PRUint16", +"PRUint32", +"PRUint64", +"PRUint8", +"PRUintn", +"PRPtrDiff", +"PRPtrdiff", +"PRUptrdiff", +"PRUword", +"PRWord", +"PRPackedBool", +"PRSize", +"PRStatus", +"pruword", +"prword", +"prword_t", + +"PR_ALIGN_OF_DOUBLE", +"PR_ALIGN_OF_FLOAT", +"PR_ALIGN_OF_INT", +"PR_ALIGN_OF_INT64", +"PR_ALIGN_OF_LONG", +"PR_ALIGN_OF_POINTER", +"PR_ALIGN_OF_SHORT", +"PR_ALIGN_OF_WORD", +"PR_BITS_PER_BYTE", +"PR_BITS_PER_BYTE_LOG2", +"PR_BITS_PER_DOUBLE", +"PR_BITS_PER_DOUBLE_LOG2", +"PR_BITS_PER_FLOAT", +"PR_BITS_PER_FLOAT_LOG2", +"PR_BITS_PER_INT", +"PR_BITS_PER_INT64", +"PR_BITS_PER_INT64_LOG2", +"PR_BITS_PER_INT_LOG2", +"PR_BITS_PER_LONG", +"PR_BITS_PER_LONG_LOG2", +"PR_BITS_PER_SHORT", +"PR_BITS_PER_SHORT_LOG2", +"PR_BITS_PER_WORD", +"PR_BITS_PER_WORD_LOG2", +"PR_BYTES_PER_BYTE", +"PR_BYTES_PER_DOUBLE", +"PR_BYTES_PER_DWORD", +"PR_BYTES_PER_DWORD_LOG2", +"PR_BYTES_PER_FLOAT", +"PR_BYTES_PER_INT", +"PR_BYTES_PER_INT64", +"PR_BYTES_PER_LONG", +"PR_BYTES_PER_SHORT", +"PR_BYTES_PER_WORD", +"PR_BYTES_PER_WORD_LOG2", + +"PRSegment", +"PRSegmentAccess", +"PRStuffFunc", +"PRThread", + +"PR_APPEND_LINK", + +"PR_ASSERT", + +"PR_ATOMIC_DWORD_LOAD", +"PR_ATOMIC_DWORD_STORE", + +"PR_Abort", + +"PR_ArenaAllocate", +"PR_ArenaCountAllocation", +"PR_ArenaCountGrowth", +"PR_ArenaCountInplaceGrowth", +"PR_ArenaCountRelease", +"PR_ArenaCountRetract", +"PR_ArenaFinish", +"PR_ArenaGrow", +"PR_ArenaRelease", +"PR_CompactArenaPool", +"PR_DumpArenaStats", +"PR_FinishArenaPool", +"PR_FreeArenaPool", +"PR_InitArenaPool", + +"PR_Assert", + +"PR_AttachThread", + +"PR_BEGIN_EXTERN_C", +"PR_BEGIN_MACRO", + +"PR_BIT", +"PR_BITMASK", + +"PR_BUFFER_OVERFLOW_ERROR", + +"PR_CALLBACK", +"PR_CALLBACK_DECL", +"PR_CALLOC", +"PR_CEILING_LOG2", +"PR_CLEAR_ARENA", +"PR_CLEAR_BIT", +"PR_CLEAR_UNUSED", +"PR_CLIST_IS_EMPTY", +"PR_COUNT_ARENA", +"PR_CURRENT_THREAD", + +"PR_GetSegmentAccess", +"PR_GetSegmentSize", +"PR_GetSegmentVaddr", +"PR_GrowSegment", +"PR_DestroySegment", +"PR_MapSegment", +"PR_NewSegment", +"PR_Segment", +"PR_Seg", +"PR_SEGMENT_NONE", +"PR_SEGMENT_RDONLY", +"PR_SEGMENT_RDWR", + +"PR_Calloc", +"PR_CeilingLog2", +"PR_CompareStrings", +"PR_CompareValues", +"PR_DELETE", +"PR_END_EXTERN_C", +"PR_END_MACRO", +"PR_ENUMERATE_STOP", +"PR_FAILURE", +"PR_FALSE", +"PR_FLOOR_LOG2", +"PR_FREEIF", +"PR_FREE_PATTERN", +"PR_FloorLog2", +"PR_FormatTime", +"PR_Free", + +"PR_GetEnv", +"PR_GetError", +"PR_INIT_ARENA_POOL", +"PR_INIT_CLIST", +"PR_INIT_STATIC_CLIST", +"PR_INLINE", +"PR_INSERT_AFTER", +"PR_INSERT_BEFORE", +"PR_INSERT_LINK", +"PR_INT32", +"PR_INTERVAL_NO_TIMEOUT", +"PR_INTERVAL_NO_WAIT", +"PR_Init", +"PR_LIST_HEAD", +"PR_LIST_TAIL", +"PR_LOG", +"PR_LOGGING", +"PR_LOG_ALWAYS", +"PR_LOG_BEGIN", +"PR_LOG_DEBUG", +"PR_LOG_DEFINE", +"PR_LOG_END", +"PR_LOG_ERROR", +"PR_LOG_MAX", +"PR_LOG_MIN", +"PR_LOG_NONE", +"PR_LOG_NOTICE", +"PR_LOG_TEST", +"PR_LOG_WARN", +"PR_LOG_WARNING", +"PR_LogFlush", +"PR_LogPrint", +"PR_MALLOC", +"PR_MAX", +"PR_MD_calloc", +"PR_MD_free", +"PR_MD_malloc", +"PR_MD_realloc", +"PR_MIN", +"PR_Malloc", +"PR_NEW", +"PR_NEWZAP", +"PR_NEXT_LINK", +"PR_NOT_REACHED", +"PR_NewCondVar", +"PR_NewHashTable", +"PR_NewLogModule", +"PR_PREV_LINK", +"PR_PUBLIC_API", +"PR_PUBLIC_DATA", +"PR_RANGE_ERROR", +"PR_REALLOC", +"PR_REMOVE_AND_INIT_LINK", +"PR_REMOVE_LINK", +"PR_ROUNDUP", +"PR_Realloc", + +"PR_SET_BIT", +"PR_STATIC_CALLBACK", +"PR_SUCCESS", +"PR_SetError", +"PR_SetLogBuffering", +"PR_SetLogFile", + +"PR_TEST_BIT", +"PR_TRUE", +"PR_UINT32", +"PR_UPTRDIFF", + +"prarena_h___", +"prbit_h___", +"prclist_h___", +"prdtoa_h___", +"prlog_h___", +"prlong_h___", +"prmacos_h___", +"prmem_h___", +"prprf_h___", +"prtypes_h___", + +"prarena", +"prbit", +"prbitmap_t", +"prclist", +"prcpucfg", +"prdtoa", +"prhash", +"plhash", +"prlong", +"prmacos", +"prmem", +"prosdep", +"protypes", +"prprf", +"prtypes" +); + +while ($ARGV[0] =~ /^-/) { + if ($ARGV[0] eq "-r") { + shift; + $reverse_conversion = 1; + } elsif ($ARGV[0] eq "-outdir") { + shift; + $outdir = shift; + } +} + +# Given an NSPR symbol compute the JS equivalent or +# vice-versa +sub subst { + local ($replacement); + local ($sym) = @_; + + $replacement = substr($sym,0,2) eq "pr" ? "js" : "JS"; + $replacement .= substr($sym, 2); + return $replacement; +} + +# Build the regular expression that will convert between the NSPR +# types and the JS types +if ($reverse_conversion) { + die "Not implemented yet"; +} else { + foreach $sym (@NSPR_symbols) { + $regexp .= $sym . "|" + } + # Get rid of the last "!" + chop $regexp; + + # Replace PR* with JS* and replace pr* with js* + $regexp = 's/(^|\\W)(' . $regexp . ')/$1 . &subst($2)/eg'; +# print $regexp; +} + +# Pre-compile a little subroutine to perform the regexp substitution +# between NSPR types and JS types +eval('sub convert_from_NSPR {($line) = @_; $line =~ ' . $regexp . ';}'); + +sub convert_mallocs { + ($line) = @_; + $line =~ s/PR_MALLOC/malloc/g; + $line =~ s/PR_REALLOC/realloc/g; + $line =~ s/PR_FREE/free/g; + return $line; +} + +sub convert_includes { + ($line) = @_; + if ($line !~ /include/) { + return $line; + } + + if ($line =~ /prlog\.h/) { + $line = '#include "jsutil.h"'. " /* Added by JSIFY */\n"; + } elsif ($line =~ /plhash\.h/) { + $line = '#include "jshash.h"'. " /* Added by JSIFY */\n"; + } elsif ($line =~ /plarena\.h/) { + $line = '#include "jsarena.h"'. " /* Added by JSIFY */\n"; + } elsif ($line =~ /prmem\.h/) { + $line = ""; + } elsif ($line =~ /jsmsg\.def/) { + $line = '#include "js.msg"' . "\n"; + } elsif ($line =~ /shellmsg\.def/) { + $line = '#include "jsshell.msg"' . "\n"; + } elsif ($line =~ /jsopcode\.def/) { + $line = '#include "jsopcode.tbl"' . "\n"; + } + return $line; +} + +sub convert_declarations { + ($line) = @_; + $line =~ s/PR_EXTERN/JS_EXTERN_API/g; + $line =~ s/PR_IMPLEMENT_DATA/JS_EXPORT_DATA/g; + $line =~ s/PR_IMPLEMENT/JS_EXPORT_API/g; + $line =~ s/PR_IMPORT/JS_IMPORT/g; + $line =~ s/PR_PUBLIC_API/JS_EXPORT_API/g; + $line =~ s/PR_PUBLIC_DATA/JS_EXPORT_DATA/g; + return $line; +} + +sub convert_long_long_macros { + ($line) = @_; + $line =~ s/\b(LL_)/JSLL_/g; + return $line; +} + +sub convert_asserts { + ($line) = @_; + $line =~ s/\bPR_ASSERT/JS_ASSERT/g; + return $line; +} + +while ($#ARGV >= 0) { + $infile = shift; + + # Change filename, e.g. prtime.h to jsprtime.h, except for legacy + # files that start with 'prmj', like prmjtime.h. + $outfile = $infile; + if ($infile !~ /^prmj/) { + $outfile =~ s/^pr/js/; + $outfile =~ s/^pl/js/; + } + + if ($outdir) { + $outfile = $outdir . '/' . $outfile; + } + + if ($infile eq $outfile) { + die "Error: refuse to overwrite $outfile, use -outdir option." + } + die "Can't open $infile" if !open(INFILE, "<$infile"); + die "Can't open $outfile for writing" if !open(OUTFILE, ">$outfile"); + + while () { + $line = $_; + + #Get rid of #include "prlog.h" + &convert_includes($line); + + # Rename PR_EXTERN, PR_IMPORT, etc. + &convert_declarations($line); + + # Convert from PR_MALLOC to malloc, etc. + &convert_mallocs($line); + + # Convert from PR_ASSERT to JS_ASSERT +# &convert_asserts($line); + + # Convert from, e.g. PRArena to JSPRArena + &convert_from_NSPR($line); + + # Change LL_* macros to JSLL_* + &convert_long_long_macros($line); + + print OUTFILE $line; + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinterp.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinterp.cpp new file mode 100644 index 0000000..3131507 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinterp.cpp @@ -0,0 +1,7225 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript bytecode interpreter. + */ +#include "jsstddef.h" +#include +#include +#include +#include "jstypes.h" +#include "jsarena.h" /* Added by JSIFY */ +#include "jsutil.h" /* Added by JSIFY */ +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsstaticcheck.h" +#include "jstracer.h" + +#ifdef INCLUDE_MOZILLA_DTRACE +#include "jsdtracef.h" +#endif + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#include "jsautooplen.h" + +/* jsinvoke_cpp___ indicates inclusion from jsinvoke.cpp. */ +#if !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___ + +uint32 +js_GenerateShape(JSContext *cx, JSBool gcLocked, JSScopeProperty *sprop) +{ + JSRuntime *rt; + uint32 shape; + JSTempValueRooter tvr; + + rt = cx->runtime; + shape = JS_ATOMIC_INCREMENT(&rt->shapeGen); + JS_ASSERT(shape != 0); + if (shape & SHAPE_OVERFLOW_BIT) { + rt->gcPoke = JS_TRUE; + if (sprop) + JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr); + js_GC(cx, gcLocked ? GC_LOCK_HELD : GC_NORMAL); + if (sprop) + JS_POP_TEMP_ROOT(cx, &tvr); + shape = JS_ATOMIC_INCREMENT(&rt->shapeGen); + JS_ASSERT(shape != 0); + JS_ASSERT_IF(shape & SHAPE_OVERFLOW_BIT, + JS_PROPERTY_CACHE(cx).disabled); + } + return shape; +} + +void +js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, + uintN scopeIndex, uintN protoIndex, + JSObject *pobj, JSScopeProperty *sprop, + JSPropCacheEntry **entryp) +{ + JSPropertyCache *cache; + jsbytecode *pc; + JSScope *scope; + JSOp op; + const JSCodeSpec *cs; + jsuword vword; + ptrdiff_t pcoff; + jsuword khash; + JSAtom *atom; + JSPropCacheEntry *entry; + + JS_ASSERT(!cx->runtime->gcRunning); + cache = &JS_PROPERTY_CACHE(cx); + pc = cx->fp->regs->pc; + if (cache->disabled || (cx->fp->flags & JSFRAME_EVAL)) { + PCMETER(cache->disfills++); + *entryp = NULL; + return; + } + + /* + * Check for fill from js_SetPropertyHelper where the setter removed sprop + * from pobj's scope (via unwatch or delete, e.g.). + */ + scope = OBJ_SCOPE(pobj); + JS_ASSERT(scope->object == pobj); + if (!SCOPE_HAS_PROPERTY(scope, sprop)) { + PCMETER(cache->oddfills++); + *entryp = NULL; + return; + } + + /* + * Check for overdeep scope and prototype chain. Because resolve, getter, + * and setter hooks can change the prototype chain using JS_SetPrototype + * after js_LookupPropertyWithFlags has returned the nominal protoIndex, + * we have to validate protoIndex if it is non-zero. If it is zero, then + * we know thanks to the SCOPE_HAS_PROPERTY test above, and from the fact + * that obj == pobj, that protoIndex is invariant. + * + * The scopeIndex can't be wrong. We require JS_SetParent calls to happen + * before any running script might consult a parent-linked scope chain. If + * this requirement is not satisfied, the fill in progress will never hit, + * but vcap vs. scope shape tests ensure nothing malfunctions. + */ + JS_ASSERT_IF(scopeIndex == 0 && protoIndex == 0, obj == pobj); + if (protoIndex != 0) { + JSObject *tmp; + + JS_ASSERT(pobj != obj); + protoIndex = 1; + tmp = obj; + for (;;) { + tmp = OBJ_GET_PROTO(cx, tmp); + if (!tmp) { + PCMETER(cache->noprotos++); + *entryp = NULL; + return; + } + if (tmp == pobj) + break; + ++protoIndex; + } + } + if (scopeIndex > PCVCAP_SCOPEMASK || protoIndex > PCVCAP_PROTOMASK) { + PCMETER(cache->longchains++); + *entryp = NULL; + return; + } + + /* + * Optimize the cached vword based on our parameters and the current pc's + * opcode format flags. + */ + op = (JSOp) *pc; + cs = &js_CodeSpec[op]; + + do { + /* + * Check for a prototype "plain old method" callee computation. What + * is a plain old method? It's a function-valued property with stub + * getter and setter, so get of a function is idempotent and set is + * transparent. + */ + if (cs->format & JOF_CALLOP) { + if (SPROP_HAS_STUB_GETTER(sprop) && + SPROP_HAS_VALID_SLOT(sprop, scope)) { + jsval v; + + v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot); + if (VALUE_IS_FUNCTION(cx, v)) { + /* + * Great, we have a function-valued prototype property + * where the getter is JS_PropertyStub. The type id in + * pobj's scope does not evolve with changes to property + * values, however. + * + * So here, on first cache fill for this method, we brand + * the scope with a new shape and set the SCOPE_BRANDED + * flag. Once this scope flag is set, any write that adds + * or deletes a function-valued plain old property in + * scope->object will result in shape being regenerated. + */ + if (!SCOPE_IS_BRANDED(scope)) { + PCMETER(cache->brandfills++); +#ifdef DEBUG_notme + fprintf(stderr, + "branding %p (%s) for funobj %p (%s), kshape %lu\n", + pobj, LOCKED_OBJ_GET_CLASS(pobj)->name, + JSVAL_TO_OBJECT(v), + JS_GetFunctionName(GET_FUNCTION_PRIVATE(cx, + JSVAL_TO_OBJECT(v))), + kshape); +#endif + SCOPE_MAKE_UNIQUE_SHAPE(cx, scope); + SCOPE_SET_BRANDED(scope); + kshape = scope->shape; + } + vword = JSVAL_OBJECT_TO_PCVAL(v); + break; + } + } + } + + /* If getting a value via a stub getter, we can cache the slot. */ + if (!(cs->format & JOF_SET) && + SPROP_HAS_STUB_GETTER(sprop) && + SPROP_HAS_VALID_SLOT(sprop, scope)) { + /* Great, let's cache sprop's slot and use it on cache hit. */ + vword = SLOT_TO_PCVAL(sprop->slot); + } else { + /* Best we can do is to cache sprop (still a nice speedup). */ + vword = SPROP_TO_PCVAL(sprop); + } + } while (0); + + /* + * Our caller preserved the scope shape prior to the js_GetPropertyHelper + * or similar call out of the interpreter. We want to cache under that + * shape if op is overtly mutating, to bias for the case where the mutator + * udpates shape predictably. + * + * Note that an apparently non-mutating op such as JSOP_NAME may still + * mutate the base object via, e.g., lazy standard class initialization, + * but that is a one-time event and we'll have to miss the old shape and + * re-fill under the new one. + */ + if (!(cs->format & (JOF_SET | JOF_INCDEC)) && obj == pobj) + kshape = scope->shape; + + khash = PROPERTY_CACHE_HASH_PC(pc, kshape); + if (obj == pobj) { + JS_ASSERT(kshape != 0 || scope->shape != 0); + JS_ASSERT(scopeIndex == 0 && protoIndex == 0); + JS_ASSERT(OBJ_SCOPE(obj)->object == obj); + } else { + if (op == JSOP_LENGTH) { + atom = cx->runtime->atomState.lengthAtom; + } else { + pcoff = (JOF_TYPE(cs->format) == JOF_SLOTATOM) ? 2 : 0; + GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom); + } + JS_ASSERT_IF(scopeIndex == 0, + protoIndex != 1 || OBJ_GET_PROTO(cx, obj) == pobj); + if (scopeIndex != 0 || protoIndex != 1) { + khash = PROPERTY_CACHE_HASH_ATOM(atom, obj, pobj); + PCMETER(if (PCVCAP_TAG(cache->table[khash].vcap) <= 1) + cache->pcrecycles++); + pc = (jsbytecode *) atom; + kshape = (jsuword) obj; + } + } + + entry = &cache->table[khash]; + PCMETER(if (entry != *entryp) cache->modfills++); + PCMETER(if (!PCVAL_IS_NULL(entry->vword)) cache->recycles++); + entry->kpc = pc; + entry->kshape = kshape; + entry->vcap = PCVCAP_MAKE(scope->shape, scopeIndex, protoIndex); + entry->vword = vword; + *entryp = entry; + + cache->empty = JS_FALSE; + PCMETER(cache->fills++); +} + +JSAtom * +js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, + JSObject **objp, JSObject **pobjp, + JSPropCacheEntry **entryp) +{ + JSOp op; + const JSCodeSpec *cs; + ptrdiff_t pcoff; + JSAtom *atom; + JSObject *obj, *pobj, *tmp; + JSPropCacheEntry *entry; + uint32 vcap; + + JS_ASSERT(uintN((cx->fp->imacpc ? cx->fp->imacpc : pc) - cx->fp->script->code) + < cx->fp->script->length); + + op = (JSOp) *pc; + cs = &js_CodeSpec[op]; + if (op == JSOP_LENGTH) { + atom = cx->runtime->atomState.lengthAtom; + } else { + pcoff = (JOF_TYPE(cs->format) == JOF_SLOTATOM) ? 2 : 0; + GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom); + } + + obj = *objp; + JS_ASSERT(OBJ_IS_NATIVE(obj)); + entry = &JS_PROPERTY_CACHE(cx).table[PROPERTY_CACHE_HASH_ATOM(atom, obj, NULL)]; + *entryp = entry; + vcap = entry->vcap; + + if (entry->kpc != (jsbytecode *) atom) { + PCMETER(JS_PROPERTY_CACHE(cx).idmisses++); + +#ifdef DEBUG_notme + entry = &JS_PROPERTY_CACHE(cx).table[PROPERTY_CACHE_HASH_PC(pc, OBJ_SHAPE(obj))]; + fprintf(stderr, + "id miss for %s from %s:%u" + " (pc %u, kpc %u, kshape %u, shape %u)\n", + js_AtomToPrintableString(cx, atom), + cx->fp->script->filename, + js_PCToLineNumber(cx, cx->fp->script, pc), + pc - cx->fp->script->code, + entry->kpc - cx->fp->script->code, + entry->kshape, + OBJ_SHAPE(obj)); + js_Disassemble1(cx, cx->fp->script, pc, + PTRDIFF(pc, cx->fp->script->code, jsbytecode), + JS_FALSE, stderr); +#endif + + return atom; + } + + if (entry->kshape != (jsuword) obj) { + PCMETER(JS_PROPERTY_CACHE(cx).komisses++); + return atom; + } + + pobj = obj; + JS_LOCK_OBJ(cx, pobj); + + if (JOF_MODE(cs->format) == JOF_NAME) { + while (vcap & (PCVCAP_SCOPEMASK << PCVCAP_PROTOBITS)) { + tmp = LOCKED_OBJ_GET_PARENT(pobj); + if (!tmp || !OBJ_IS_NATIVE(tmp)) + break; + JS_UNLOCK_OBJ(cx, pobj); + pobj = tmp; + JS_LOCK_OBJ(cx, pobj); + vcap -= PCVCAP_PROTOSIZE; + } + + *objp = pobj; + } + + while (vcap & PCVCAP_PROTOMASK) { + tmp = LOCKED_OBJ_GET_PROTO(pobj); + if (!tmp || !OBJ_IS_NATIVE(tmp)) + break; + JS_UNLOCK_OBJ(cx, pobj); + pobj = tmp; + JS_LOCK_OBJ(cx, pobj); + --vcap; + } + + if (PCVCAP_SHAPE(vcap) == OBJ_SHAPE(pobj)) { +#ifdef DEBUG + jsid id = ATOM_TO_JSID(atom); + + CHECK_FOR_STRING_INDEX(id); + JS_ASSERT(SCOPE_GET_PROPERTY(OBJ_SCOPE(pobj), id)); + JS_ASSERT(OBJ_SCOPE(pobj)->object == pobj); +#endif + *pobjp = pobj; + return NULL; + } + + PCMETER(JS_PROPERTY_CACHE(cx).vcmisses++); + JS_UNLOCK_OBJ(cx, pobj); + return atom; +} + +#ifdef DEBUG +#define ASSERT_CACHE_IS_EMPTY(cache) \ + JS_BEGIN_MACRO \ + JSPropertyCache *cache_ = (cache); \ + uintN i_; \ + JS_ASSERT(cache_->empty); \ + for (i_ = 0; i_ < PROPERTY_CACHE_SIZE; i_++) { \ + JS_ASSERT(!cache_->table[i_].kpc); \ + JS_ASSERT(!cache_->table[i_].kshape); \ + JS_ASSERT(!cache_->table[i_].vcap); \ + JS_ASSERT(!cache_->table[i_].vword); \ + } \ + JS_END_MACRO +#else +#define ASSERT_CACHE_IS_EMPTY(cache) ((void)0) +#endif + +JS_STATIC_ASSERT(PCVAL_NULL == 0); + +void +js_FlushPropertyCache(JSContext *cx) +{ + JSPropertyCache *cache; + + cache = &JS_PROPERTY_CACHE(cx); + if (cache->empty) { + ASSERT_CACHE_IS_EMPTY(cache); + return; + } + + memset(cache->table, 0, sizeof cache->table); + cache->empty = JS_TRUE; + +#ifdef JS_PROPERTY_CACHE_METERING + { static FILE *fp; + if (!fp) + fp = fopen("/tmp/propcache.stats", "w"); + if (fp) { + fputs("Property cache stats for ", fp); +#ifdef JS_THREADSAFE + fprintf(fp, "thread %lu, ", (unsigned long) cx->thread->id); +#endif + fprintf(fp, "GC %u\n", cx->runtime->gcNumber); + +# define P(mem) fprintf(fp, "%11s %10lu\n", #mem, (unsigned long)cache->mem) + P(fills); + P(nofills); + P(rofills); + P(disfills); + P(oddfills); + P(modfills); + P(brandfills); + P(noprotos); + P(longchains); + P(recycles); + P(pcrecycles); + P(tests); + P(pchits); + P(protopchits); + P(initests); + P(inipchits); + P(inipcmisses); + P(settests); + P(addpchits); + P(setpchits); + P(setpcmisses); + P(slotchanges); + P(setmisses); + P(idmisses); + P(komisses); + P(vcmisses); + P(misses); + P(flushes); + P(pcpurges); +# undef P + + fprintf(fp, "hit rates: pc %g%% (proto %g%%), set %g%%, ini %g%%, full %g%%\n", + (100. * cache->pchits) / cache->tests, + (100. * cache->protopchits) / cache->tests, + (100. * (cache->addpchits + cache->setpchits)) + / cache->settests, + (100. * cache->inipchits) / cache->initests, + (100. * (cache->tests - cache->misses)) / cache->tests); + fflush(fp); + } + } +#endif + + PCMETER(cache->flushes++); +} + +void +js_FlushPropertyCacheForScript(JSContext *cx, JSScript *script) +{ + JSPropertyCache *cache; + JSPropCacheEntry *entry; + + cache = &JS_PROPERTY_CACHE(cx); + for (entry = cache->table; entry < cache->table + PROPERTY_CACHE_SIZE; + entry++) { + if (JS_UPTRDIFF(entry->kpc, script->code) < script->length) { + entry->kpc = NULL; + entry->kshape = 0; +#ifdef DEBUG + entry->vcap = entry->vword = 0; +#endif + } + } +} + +void +js_DisablePropertyCache(JSContext *cx) +{ + JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0); + ++JS_PROPERTY_CACHE(cx).disabled; +} + +void +js_EnablePropertyCache(JSContext *cx) +{ + --JS_PROPERTY_CACHE(cx).disabled; + JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0); +} + +/* + * Check if the current arena has enough space to fit nslots after sp and, if + * so, reserve the necessary space. + */ +static JSBool +AllocateAfterSP(JSContext *cx, jsval *sp, uintN nslots) +{ + uintN surplus; + jsval *sp2; + + JS_ASSERT((jsval *) cx->stackPool.current->base <= sp); + JS_ASSERT(sp <= (jsval *) cx->stackPool.current->avail); + surplus = (jsval *) cx->stackPool.current->avail - sp; + if (nslots <= surplus) + return JS_TRUE; + + /* + * No room before current->avail, check if the arena has enough space to + * fit the missing slots before the limit. + */ + if (nslots > (size_t) ((jsval *) cx->stackPool.current->limit - sp)) + return JS_FALSE; + + JS_ARENA_ALLOCATE_CAST(sp2, jsval *, &cx->stackPool, + (nslots - surplus) * sizeof(jsval)); + JS_ASSERT(sp2 == sp + surplus); + return JS_TRUE; +} + +JS_STATIC_INTERPRET jsval * +js_AllocRawStack(JSContext *cx, uintN nslots, void **markp) +{ + jsval *sp; + + if (!cx->stackPool.first.next) { + int64 *timestamp; + + JS_ARENA_ALLOCATE_CAST(timestamp, int64 *, + &cx->stackPool, sizeof *timestamp); + if (!timestamp) { + js_ReportOutOfScriptQuota(cx); + return NULL; + } + *timestamp = JS_Now(); + } + + if (markp) + *markp = JS_ARENA_MARK(&cx->stackPool); + JS_ARENA_ALLOCATE_CAST(sp, jsval *, &cx->stackPool, nslots * sizeof(jsval)); + if (!sp) + js_ReportOutOfScriptQuota(cx); + return sp; +} + +JS_STATIC_INTERPRET void +js_FreeRawStack(JSContext *cx, void *mark) +{ + JS_ARENA_RELEASE(&cx->stackPool, mark); +} + +JS_FRIEND_API(jsval *) +js_AllocStack(JSContext *cx, uintN nslots, void **markp) +{ + jsval *sp; + JSArena *a; + JSStackHeader *sh; + + /* Callers don't check for zero nslots: we do to avoid empty segments. */ + if (nslots == 0) { + *markp = NULL; + return (jsval *) JS_ARENA_MARK(&cx->stackPool); + } + + /* Allocate 2 extra slots for the stack segment header we'll likely need. */ + sp = js_AllocRawStack(cx, 2 + nslots, markp); + if (!sp) + return NULL; + + /* Try to avoid another header if we can piggyback on the last segment. */ + a = cx->stackPool.current; + sh = cx->stackHeaders; + if (sh && JS_STACK_SEGMENT(sh) + sh->nslots == sp) { + /* Extend the last stack segment, give back the 2 header slots. */ + sh->nslots += nslots; + a->avail -= 2 * sizeof(jsval); + } else { + /* + * Need a new stack segment, so allocate and push a stack segment + * header from the 2 extra slots. + */ + sh = (JSStackHeader *)sp; + sh->nslots = nslots; + sh->down = cx->stackHeaders; + cx->stackHeaders = sh; + sp += 2; + } + + /* + * Store JSVAL_NULL using memset, to let compilers optimize as they see + * fit, in case a caller allocates and pushes GC-things one by one, which + * could nest a last-ditch GC that will scan this segment. + */ + memset(sp, 0, nslots * sizeof(jsval)); + return sp; +} + +JS_FRIEND_API(void) +js_FreeStack(JSContext *cx, void *mark) +{ + JSStackHeader *sh; + jsuword slotdiff; + + /* Check for zero nslots allocation special case. */ + if (!mark) + return; + + /* We can assert because js_FreeStack always balances js_AllocStack. */ + sh = cx->stackHeaders; + JS_ASSERT(sh); + + /* If mark is in the current segment, reduce sh->nslots, else pop sh. */ + slotdiff = JS_UPTRDIFF(mark, JS_STACK_SEGMENT(sh)) / sizeof(jsval); + if (slotdiff < (jsuword)sh->nslots) + sh->nslots = slotdiff; + else + cx->stackHeaders = sh->down; + + /* Release the stackPool space allocated since mark was set. */ + JS_ARENA_RELEASE(&cx->stackPool, mark); +} + +JSObject * +js_GetScopeChain(JSContext *cx, JSStackFrame *fp) +{ + JSObject *obj, *cursor, *clonedChild, *parent; + JSTempValueRooter tvr; + + obj = fp->blockChain; + if (!obj) { + /* + * Don't force a call object for a lightweight function call, but do + * insist that there is a call object for a heavyweight function call. + */ + JS_ASSERT(!fp->fun || + !(fp->fun->flags & JSFUN_HEAVYWEIGHT) || + fp->callobj); + JS_ASSERT(fp->scopeChain); + return fp->scopeChain; + } + + /* + * We have one or more lexical scopes to reflect into fp->scopeChain, so + * make sure there's a call object at the current head of the scope chain, + * if this frame is a call frame. + */ + if (fp->fun && !fp->callobj) { + JS_ASSERT(OBJ_GET_CLASS(cx, fp->scopeChain) != &js_BlockClass || + OBJ_GET_PRIVATE(cx, fp->scopeChain) != fp); + if (!js_GetCallObject(cx, fp, fp->scopeChain)) + return NULL; + } + + /* + * Clone the block chain. To avoid recursive cloning we set the parent of + * the cloned child after we clone the parent. In the following loop when + * clonedChild is null it indicates the first iteration when no special GC + * rooting is necessary. On the second and the following iterations we + * have to protect cloned so far chain against the GC during cloning of + * the cursor object. + */ + cursor = obj; + clonedChild = NULL; + for (;;) { + parent = OBJ_GET_PARENT(cx, cursor); + + /* + * We pass fp->scopeChain and not null even if we override the parent + * slot later as null triggers useless calculations of slot's value in + * js_NewObject that js_CloneBlockObject calls. + */ + cursor = js_CloneBlockObject(cx, cursor, fp->scopeChain, fp); + if (!cursor) { + if (clonedChild) + JS_POP_TEMP_ROOT(cx, &tvr); + return NULL; + } + if (!clonedChild) { + /* + * The first iteration. Check if other follow and root obj if so + * to protect the whole cloned chain against GC. + */ + obj = cursor; + if (!parent) + break; + JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); + } else { + /* + * Avoid OBJ_SET_PARENT overhead as clonedChild cannot escape to + * other threads. + */ + STOBJ_SET_PARENT(clonedChild, cursor); + if (!parent) { + JS_ASSERT(tvr.u.value == OBJECT_TO_JSVAL(obj)); + JS_POP_TEMP_ROOT(cx, &tvr); + break; + } + } + clonedChild = cursor; + cursor = parent; + } + fp->flags |= JSFRAME_POP_BLOCKS; + fp->scopeChain = obj; + fp->blockChain = NULL; + return obj; +} + +JSBool +js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp) +{ + jsval v; + JSObject *obj; + + v = vp[1]; + if (JSVAL_IS_OBJECT(v)) { + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, clasp, vp + 2)) + return JS_FALSE; + v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); + } + *thisvp = v; + return JS_TRUE; +} + +/* + * ECMA requires "the global object", but in embeddings such as the browser, + * which have multiple top-level objects (windows, frames, etc. in the DOM), + * we prefer fun's parent. An example that causes this code to run: + * + * // in window w1 + * function f() { return this } + * function g() { return f } + * + * // in window w2 + * var h = w1.g() + * alert(h() == w1) + * + * The alert should display "true". + */ +JS_STATIC_INTERPRET JSObject * +js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv) +{ + JSObject *thisp; + + if (JSVAL_IS_PRIMITIVE(argv[-2]) || + !OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]))) { + thisp = cx->globalObject; + } else { + JSStackFrame *fp; + jsid id; + jsval v; + uintN attrs; + JSBool ok; + JSObject *parent; + + /* + * Walk up the parent chain, first checking that the running script + * has access to the callee's parent object. Note that if lazy, the + * running script whose principals we want to check is the script + * associated with fp->down, not with fp. + * + * FIXME: 417851 -- this access check should not be required, as it + * imposes a performance penalty on all js_ComputeGlobalThis calls, + * and it represents a maintenance hazard. + */ + fp = cx->fp; /* quell GCC overwarning */ + if (lazy) { + JS_ASSERT(fp->argv == argv); + fp->dormantNext = cx->dormantFrameChain; + cx->dormantFrameChain = fp; + cx->fp = fp->down; + fp->down = NULL; + } + thisp = JSVAL_TO_OBJECT(argv[-2]); + id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom); + + ok = OBJ_CHECK_ACCESS(cx, thisp, id, JSACC_PARENT, &v, &attrs); + if (lazy) { + cx->dormantFrameChain = fp->dormantNext; + fp->dormantNext = NULL; + fp->down = cx->fp; + cx->fp = fp; + } + if (!ok) + return NULL; + + thisp = JSVAL_IS_VOID(v) + ? OBJ_GET_PARENT(cx, thisp) + : JSVAL_TO_OBJECT(v); + while ((parent = OBJ_GET_PARENT(cx, thisp)) != NULL) + thisp = parent; + } + + OBJ_TO_OUTER_OBJECT(cx, thisp); + if (!thisp) + return NULL; + argv[-1] = OBJECT_TO_JSVAL(thisp); + return thisp; +} + +static JSObject * +ComputeThis(JSContext *cx, JSBool lazy, jsval *argv) +{ + JSObject *thisp; + + JS_ASSERT(!JSVAL_IS_NULL(argv[-1])); + if (!JSVAL_IS_OBJECT(argv[-1])) { + if (!js_PrimitiveToObject(cx, &argv[-1])) + return NULL; + thisp = JSVAL_TO_OBJECT(argv[-1]); + } else { + thisp = JSVAL_TO_OBJECT(argv[-1]); + if (OBJ_GET_CLASS(cx, thisp) == &js_CallClass) + return js_ComputeGlobalThis(cx, lazy, argv); + + if (thisp->map->ops->thisObject) { + /* Some objects (e.g., With) delegate 'this' to another object. */ + thisp = thisp->map->ops->thisObject(cx, thisp); + if (!thisp) + return NULL; + } + OBJ_TO_OUTER_OBJECT(cx, thisp); + if (!thisp) + return NULL; + argv[-1] = OBJECT_TO_JSVAL(thisp); + } + return thisp; +} + +JSObject * +js_ComputeThis(JSContext *cx, JSBool lazy, jsval *argv) +{ + if (JSVAL_IS_NULL(argv[-1])) + return js_ComputeGlobalThis(cx, lazy, argv); + return ComputeThis(cx, lazy, argv); +} + +#if JS_HAS_NO_SUCH_METHOD + +#define JSSLOT_FOUND_FUNCTION JSSLOT_PRIVATE +#define JSSLOT_SAVED_ID (JSSLOT_PRIVATE + 1) + +JSClass js_NoSuchMethodClass = { + "NoSuchMethod", + JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS | + JSCLASS_HAS_CACHED_PROTO(JSProto_NoSuchMethod), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +JS_BEGIN_EXTERN_C + +JSObject* +js_InitNoSuchMethodClass(JSContext *cx, JSObject* obj); + +JS_END_EXTERN_C + +JSObject* +js_InitNoSuchMethodClass(JSContext *cx, JSObject* obj) +{ + JSObject *proto; + + proto = JS_InitClass(cx, obj, NULL, &js_NoSuchMethodClass, NULL, 0, NULL, + NULL, NULL, NULL); + if (!proto) + return NULL; + + OBJ_CLEAR_PROTO(cx, proto); + return proto; +} + +/* + * When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of + * the base object, we search for the __noSuchMethod__ method in the base. + * If it exists, we store the method and the property's id into an object of + * NoSuchMethod class and store this object into the callee's stack slot. + * Later, js_Invoke will recognise such an object and transfer control to + * NoSuchMethod that invokes the method like: + * + * this.__noSuchMethod__(id, args) + * + * where id is the name of the method that this invocation attempted to + * call by name, and args is an Array containing this invocation's actual + * parameters. + */ +JS_STATIC_INTERPRET JSBool +js_OnUnknownMethod(JSContext *cx, jsval *vp) +{ + JSObject *obj; + jsid id; + JSTempValueRooter tvr; + JSBool ok; + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1])); + obj = JSVAL_TO_OBJECT(vp[1]); + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + + MUST_FLOW_THROUGH("out"); + id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); +#if JS_HAS_XML_SUPPORT + if (OBJECT_IS_XML(cx, obj)) { + JSXMLObjectOps *ops; + + ops = (JSXMLObjectOps *) obj->map->ops; + obj = ops->getMethod(cx, obj, id, &tvr.u.value); + if (!obj) { + ok = JS_FALSE; + goto out; + } + vp[1] = OBJECT_TO_JSVAL(obj); + } else +#endif + { + ok = OBJ_GET_PROPERTY(cx, obj, id, &tvr.u.value); + if (!ok) + goto out; + } + if (JSVAL_IS_PRIMITIVE(tvr.u.value)) { + vp[0] = tvr.u.value; + } else { +#if JS_HAS_XML_SUPPORT + /* Extract the function name from function::name qname. */ + if (!JSVAL_IS_PRIMITIVE(vp[0])) { + obj = JSVAL_TO_OBJECT(vp[0]); + ok = js_IsFunctionQName(cx, obj, &id); + if (!ok) + goto out; + if (id != 0) + vp[0] = ID_TO_VALUE(id); + } +#endif + obj = js_NewObject(cx, &js_NoSuchMethodClass, NULL, NULL, 0); + if (!obj) { + ok = JS_FALSE; + goto out; + } + obj->fslots[JSSLOT_FOUND_FUNCTION] = tvr.u.value; + obj->fslots[JSSLOT_SAVED_ID] = vp[0]; + vp[0] = OBJECT_TO_JSVAL(obj); + } + ok = JS_TRUE; + + out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +static JSBool +NoSuchMethod(JSContext *cx, uintN argc, jsval *vp, uint32 flags) +{ + jsval *invokevp; + void *mark; + JSBool ok; + JSObject *obj, *argsobj; + + invokevp = js_AllocStack(cx, 2 + 2, &mark); + if (!invokevp) + return JS_FALSE; + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[0])); + JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1])); + obj = JSVAL_TO_OBJECT(vp[0]); + JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_NoSuchMethodClass); + + invokevp[0] = obj->fslots[JSSLOT_FOUND_FUNCTION]; + invokevp[1] = vp[1]; + invokevp[2] = obj->fslots[JSSLOT_SAVED_ID]; + argsobj = js_NewArrayObject(cx, argc, vp + 2); + if (!argsobj) { + ok = JS_FALSE; + } else { + invokevp[3] = OBJECT_TO_JSVAL(argsobj); + ok = (flags & JSINVOKE_CONSTRUCT) + ? js_InvokeConstructor(cx, 2, JS_TRUE, invokevp) + : js_Invoke(cx, 2, invokevp, flags); + vp[0] = invokevp[0]; + } + js_FreeStack(cx, mark); + return ok; +} + +#endif /* JS_HAS_NO_SUCH_METHOD */ + +/* + * We check if the function accepts a primitive value as |this|. For that we + * use a table that maps value's tag into the corresponding function flag. + */ +JS_STATIC_ASSERT(JSVAL_INT == 1); +JS_STATIC_ASSERT(JSVAL_DOUBLE == 2); +JS_STATIC_ASSERT(JSVAL_STRING == 4); +JS_STATIC_ASSERT(JSVAL_BOOLEAN == 6); + +const uint16 js_PrimitiveTestFlags[] = { + JSFUN_THISP_NUMBER, /* INT */ + JSFUN_THISP_NUMBER, /* DOUBLE */ + JSFUN_THISP_NUMBER, /* INT */ + JSFUN_THISP_STRING, /* STRING */ + JSFUN_THISP_NUMBER, /* INT */ + JSFUN_THISP_BOOLEAN, /* BOOLEAN */ + JSFUN_THISP_NUMBER /* INT */ +}; + +/* + * Find a function reference and its 'this' object implicit first parameter + * under argc arguments on cx's stack, and call the function. Push missing + * required arguments, allocate declared local variables, and pop everything + * when done. Then push the return value. + */ +JS_FRIEND_API(JSBool) +js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags) +{ + void *mark; + JSStackFrame frame; + jsval *sp, *argv, *newvp; + jsval v; + JSObject *funobj, *parent; + JSBool ok; + JSClass *clasp; + JSObjectOps *ops; + JSNative native; + JSFunction *fun; + JSScript *script; + uintN nslots, i; + uint32 rootedArgsFlag; + JSInterpreterHook hook; + void *hookData; + + /* [vp .. vp + 2 + argc) must belong to the last JS stack arena. */ + JS_ASSERT((jsval *) cx->stackPool.current->base <= vp); + JS_ASSERT(vp + 2 + argc <= (jsval *) cx->stackPool.current->avail); + + /* + * Mark the top of stack and load frequently-used registers. After this + * point the control should flow through label out2: to return. + */ + mark = JS_ARENA_MARK(&cx->stackPool); + v = *vp; + + if (JSVAL_IS_PRIMITIVE(v)) + goto bad; + + funobj = JSVAL_TO_OBJECT(v); + parent = OBJ_GET_PARENT(cx, funobj); + clasp = OBJ_GET_CLASS(cx, funobj); + if (clasp != &js_FunctionClass) { +#if JS_HAS_NO_SUCH_METHOD + if (clasp == &js_NoSuchMethodClass) { + ok = NoSuchMethod(cx, argc, vp, flags); + goto out2; + } +#endif + + /* Function is inlined, all other classes use object ops. */ + ops = funobj->map->ops; + + /* + * XXX this makes no sense -- why convert to function if clasp->call? + * XXX better to call that hook without converting + * XXX the only thing that needs fixing is liveconnect + * + * Try converting to function, for closure and API compatibility. + * We attempt the conversion under all circumstances for 1.2, but + * only if there is a call op defined otherwise. + */ + if ((ops == &js_ObjectOps) ? clasp->call : ops->call) { + ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v); + if (!ok) + goto out2; + + if (VALUE_IS_FUNCTION(cx, v)) { + /* Make vp refer to funobj to keep it available as argv[-2]. */ + *vp = v; + funobj = JSVAL_TO_OBJECT(v); + parent = OBJ_GET_PARENT(cx, funobj); + goto have_fun; + } + } + fun = NULL; + script = NULL; + nslots = 0; + + /* Try a call or construct native object op. */ + if (flags & JSINVOKE_CONSTRUCT) { + if (!JSVAL_IS_OBJECT(vp[1])) { + ok = js_PrimitiveToObject(cx, &vp[1]); + if (!ok) + goto out2; + } + native = ops->construct; + } else { + native = ops->call; + } + if (!native) + goto bad; + } else { +have_fun: + /* Get private data and set derived locals from it. */ + fun = GET_FUNCTION_PRIVATE(cx, funobj); + nslots = FUN_MINARGS(fun); + nslots = (nslots > argc) ? nslots - argc : 0; + if (FUN_INTERPRETED(fun)) { + native = NULL; + script = fun->u.i.script; + } else { + native = fun->u.n.native; + script = NULL; + nslots += fun->u.n.extra; + } + + if (JSFUN_BOUND_METHOD_TEST(fun->flags)) { + /* Handle bound method special case. */ + vp[1] = OBJECT_TO_JSVAL(parent); + } else if (!JSVAL_IS_OBJECT(vp[1])) { + JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT)); + if (PRIMITIVE_THIS_TEST(fun, vp[1])) + goto start_call; + } + } + + if (flags & JSINVOKE_CONSTRUCT) { + JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1])); + } else { + /* + * We must call js_ComputeThis in case we are not called from the + * interpreter, where a prior bytecode has computed an appropriate + * |this| already. + * + * But we need to compute |this| eagerly only for so-called "slow" + * (i.e., not fast) native functions. Fast natives must use either + * JS_THIS or JS_THIS_OBJECT, and scripted functions will go through + * the appropriate this-computing bytecode, e.g., JSOP_THIS. + */ + if (native && (!fun || !(fun->flags & JSFUN_FAST_NATIVE))) { + if (!js_ComputeThis(cx, JS_FALSE, vp + 2)) { + ok = JS_FALSE; + goto out2; + } + flags |= JSFRAME_COMPUTED_THIS; + } + } + + start_call: + if (native && fun && (fun->flags & JSFUN_FAST_NATIVE)) { +#ifdef DEBUG_NOT_THROWING + JSBool alreadyThrowing = cx->throwing; +#endif + JS_ASSERT(nslots == 0); +#if JS_HAS_LVALUE_RETURN + /* Set by JS_SetCallReturnValue2, used to return reference types. */ + cx->rval2set = JS_FALSE; +#endif + ok = ((JSFastNative) native)(cx, argc, vp); + JS_RUNTIME_METER(cx->runtime, nativeCalls); +#ifdef DEBUG_NOT_THROWING + if (ok && !alreadyThrowing) + ASSERT_NOT_THROWING(cx); +#endif + goto out2; + } + + argv = vp + 2; + sp = argv + argc; + + rootedArgsFlag = JSFRAME_ROOTED_ARGV; + if (nslots != 0) { + /* + * The extra slots required by the function continue with argument + * slots. Thus, when the last stack pool arena does not have room to + * fit nslots right after sp and AllocateAfterSP fails, we have to copy + * [vp..vp+2+argc) slots and clear rootedArgsFlag to root the copy. + */ + if (!AllocateAfterSP(cx, sp, nslots)) { + rootedArgsFlag = 0; + newvp = js_AllocRawStack(cx, 2 + argc + nslots, NULL); + if (!newvp) { + ok = JS_FALSE; + goto out2; + } + memcpy(newvp, vp, (2 + argc) * sizeof(jsval)); + argv = newvp + 2; + sp = argv + argc; + } + + /* Push void to initialize missing args. */ + i = nslots; + do { + *sp++ = JSVAL_VOID; + } while (--i != 0); + } + + /* Allocate space for local variables and stack of interpreted function. */ + if (script && script->nslots != 0) { + if (!AllocateAfterSP(cx, sp, script->nslots)) { + /* NB: Discontinuity between argv and slots, stack slots. */ + sp = js_AllocRawStack(cx, script->nslots, NULL); + if (!sp) { + ok = JS_FALSE; + goto out2; + } + } + + /* Push void to initialize local variables. */ + for (jsval *end = sp + fun->u.i.nvars; sp != end; ++sp) + *sp = JSVAL_VOID; + } + + /* + * Initialize the frame. + * + * To set thisp we use an explicit cast and not JSVAL_TO_OBJECT, as vp[1] + * can be a primitive value here for those native functions specified with + * JSFUN_THISP_(NUMBER|STRING|BOOLEAN) flags. + */ + frame.thisp = (JSObject *)vp[1]; + frame.varobj = NULL; + frame.callobj = frame.argsobj = NULL; + frame.script = script; + frame.callee = funobj; + frame.fun = fun; + frame.argc = argc; + frame.argv = argv; + + /* Default return value for a constructor is the new object. */ + frame.rval = (flags & JSINVOKE_CONSTRUCT) ? vp[1] : JSVAL_VOID; + frame.down = cx->fp; + frame.annotation = NULL; + frame.scopeChain = NULL; /* set below for real, after cx->fp is set */ + frame.regs = NULL; + frame.imacpc = NULL; + frame.slots = NULL; + frame.sharpDepth = 0; + frame.sharpArray = NULL; + frame.flags = flags | rootedArgsFlag; + frame.dormantNext = NULL; + frame.xmlNamespace = NULL; + frame.blockChain = NULL; + + MUST_FLOW_THROUGH("out"); + cx->fp = &frame; + + /* Init these now in case we goto out before first hook call. */ + hook = cx->debugHooks->callHook; + hookData = NULL; + + /* call the hook if present */ + if (hook && (native || script)) + hookData = hook(cx, &frame, JS_TRUE, 0, cx->debugHooks->callHookData); + + /* Call the function, either a native method or an interpreted script. */ + if (native) { +#ifdef DEBUG_NOT_THROWING + JSBool alreadyThrowing = cx->throwing; +#endif + +#if JS_HAS_LVALUE_RETURN + /* Set by JS_SetCallReturnValue2, used to return reference types. */ + cx->rval2set = JS_FALSE; +#endif + + /* If native, use caller varobj and scopeChain for eval. */ + JS_ASSERT(!frame.varobj); + JS_ASSERT(!frame.scopeChain); + if (frame.down) { + frame.varobj = frame.down->varobj; + frame.scopeChain = frame.down->scopeChain; + } + + /* But ensure that we have a scope chain. */ + if (!frame.scopeChain) + frame.scopeChain = parent; + + frame.displaySave = NULL; + ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval); + JS_RUNTIME_METER(cx->runtime, nativeCalls); +#ifdef DEBUG_NOT_THROWING + if (ok && !alreadyThrowing) + ASSERT_NOT_THROWING(cx); +#endif + } else if (script) { + /* Use parent scope so js_GetCallObject can find the right "Call". */ + frame.scopeChain = parent; + if (JSFUN_HEAVYWEIGHT_TEST(fun->flags)) { + /* Scope with a call object parented by the callee's parent. */ + if (!js_GetCallObject(cx, &frame, parent)) { + ok = JS_FALSE; + goto out; + } + } + frame.slots = sp - fun->u.i.nvars; + + ok = js_Interpret(cx); + } else { + /* fun might be onerror trying to report a syntax error in itself. */ + frame.scopeChain = NULL; + frame.displaySave = NULL; + ok = JS_TRUE; + } + +out: + if (hookData) { + hook = cx->debugHooks->callHook; + if (hook) + hook(cx, &frame, JS_FALSE, &ok, hookData); + } + + /* If frame has a call object, sync values and clear back-pointer. */ + if (frame.callobj) + ok &= js_PutCallObject(cx, &frame); + + /* If frame has an arguments object, sync values and clear back-pointer. */ + if (frame.argsobj) + ok &= js_PutArgsObject(cx, &frame); + + *vp = frame.rval; + + /* Restore cx->fp now that we're done releasing frame objects. */ + cx->fp = frame.down; + +out2: + /* Pop everything we may have allocated off the stack. */ + JS_ARENA_RELEASE(&cx->stackPool, mark); + if (!ok) + *vp = JSVAL_NULL; + return ok; + +bad: + js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS); + ok = JS_FALSE; + goto out2; +} + +JSBool +js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags, + uintN argc, jsval *argv, jsval *rval) +{ + jsval *invokevp; + void *mark; + JSBool ok; + + invokevp = js_AllocStack(cx, 2 + argc, &mark); + if (!invokevp) + return JS_FALSE; + + invokevp[0] = fval; + invokevp[1] = OBJECT_TO_JSVAL(obj); + memcpy(invokevp + 2, argv, argc * sizeof *argv); + + ok = js_Invoke(cx, argc, invokevp, flags); + if (ok) { + /* + * Store *rval in the a scoped local root if a scope is open, else in + * the lastInternalResult pigeon-hole GC root, solely so users of + * js_InternalInvoke and its direct and indirect (js_ValueToString for + * example) callers do not need to manage roots for local, temporary + * references to such results. + */ + *rval = *invokevp; + if (JSVAL_IS_GCTHING(*rval) && *rval != JSVAL_NULL) { + if (cx->localRootStack) { + if (js_PushLocalRoot(cx, cx->localRootStack, *rval) < 0) + ok = JS_FALSE; + } else { + cx->weakRoots.lastInternalResult = *rval; + } + } + } + + js_FreeStack(cx, mark); + return ok; +} + +JSBool +js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval, + JSAccessMode mode, uintN argc, jsval *argv, jsval *rval) +{ + JSSecurityCallbacks *callbacks; + + /* + * js_InternalInvoke could result in another try to get or set the same id + * again, see bug 355497. + */ + JS_CHECK_RECURSION(cx, return JS_FALSE); + + /* + * Check general (not object-ops/class-specific) access from the running + * script to obj.id only if id has a scripted getter or setter that we're + * about to invoke. If we don't check this case, nothing else will -- no + * other native code has the chance to check. + * + * Contrast this non-native (scripted) case with native getter and setter + * accesses, where the native itself must do an access check, if security + * policies requires it. We make a checkAccess or checkObjectAccess call + * back to the embedding program only in those cases where we're not going + * to call an embedding-defined native function, getter, setter, or class + * hook anyway. Where we do call such a native, there's no need for the + * engine to impose a separate access check callback on all embeddings -- + * many embeddings have no security policy at all. + */ + JS_ASSERT(mode == JSACC_READ || mode == JSACC_WRITE); + callbacks = JS_GetSecurityCallbacks(cx); + if (callbacks && + callbacks->checkObjectAccess && + VALUE_IS_FUNCTION(cx, fval) && + FUN_INTERPRETED(GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(fval))) && + !callbacks->checkObjectAccess(cx, obj, ID_TO_VALUE(id), mode, &fval)) { + return JS_FALSE; + } + + return js_InternalCall(cx, obj, fval, argc, argv, rval); +} + +JSBool +js_Execute(JSContext *cx, JSObject *chain, JSScript *script, + JSStackFrame *down, uintN flags, jsval *result) +{ + JSInterpreterHook hook; + void *hookData, *mark; + JSStackFrame *oldfp, frame; + JSObject *obj, *tmp; + JSBool ok; + +#ifdef INCLUDE_MOZILLA_DTRACE + if (JAVASCRIPT_EXECUTE_START_ENABLED()) + jsdtrace_execute_start(script); +#endif + + hook = cx->debugHooks->executeHook; + hookData = mark = NULL; + oldfp = cx->fp; + frame.script = script; + if (down) { + /* Propagate arg state for eval and the debugger API. */ + frame.callobj = down->callobj; + frame.argsobj = down->argsobj; + frame.varobj = down->varobj; + frame.callee = down->callee; + frame.fun = down->fun; + frame.thisp = down->thisp; + if (down->flags & JSFRAME_COMPUTED_THIS) + flags |= JSFRAME_COMPUTED_THIS; + frame.argc = down->argc; + frame.argv = down->argv; + frame.annotation = down->annotation; + frame.sharpArray = down->sharpArray; + JS_ASSERT(script->nfixed == 0); + } else { + frame.callobj = frame.argsobj = NULL; + obj = chain; + if (cx->options & JSOPTION_VAROBJFIX) { + while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL) + obj = tmp; + } + frame.varobj = obj; + frame.callee = NULL; + frame.fun = NULL; + frame.thisp = chain; + frame.argc = 0; + frame.argv = NULL; + frame.annotation = NULL; + frame.sharpArray = NULL; + } + + frame.imacpc = NULL; + if (script->nslots != 0) { + frame.slots = js_AllocRawStack(cx, script->nslots, &mark); + if (!frame.slots) { + ok = JS_FALSE; + goto out; + } + memset(frame.slots, 0, script->nfixed * sizeof(jsval)); + } else { + frame.slots = NULL; + } + + frame.rval = JSVAL_VOID; + frame.down = down; + frame.scopeChain = chain; + frame.regs = NULL; + frame.sharpDepth = 0; + frame.flags = flags; + frame.dormantNext = NULL; + frame.xmlNamespace = NULL; + frame.blockChain = NULL; + + /* + * Here we wrap the call to js_Interpret with code to (conditionally) + * save and restore the old stack frame chain into a chain of 'dormant' + * frame chains. Since we are replacing cx->fp, we were running into + * the problem that if GC was called under this frame, some of the GC + * things associated with the old frame chain (available here only in + * the C variable 'oldfp') were not rooted and were being collected. + * + * So, now we preserve the links to these 'dormant' frame chains in cx + * before calling js_Interpret and cleanup afterwards. The GC walks + * these dormant chains and marks objects in the same way that it marks + * objects in the primary cx->fp chain. + */ + if (oldfp && oldfp != down) { + JS_ASSERT(!oldfp->dormantNext); + oldfp->dormantNext = cx->dormantFrameChain; + cx->dormantFrameChain = oldfp; + } + + cx->fp = &frame; + if (!down) { + OBJ_TO_OUTER_OBJECT(cx, frame.thisp); + if (!frame.thisp) { + ok = JS_FALSE; + goto out2; + } + frame.flags |= JSFRAME_COMPUTED_THIS; + } + + if (hook) { + hookData = hook(cx, &frame, JS_TRUE, 0, + cx->debugHooks->executeHookData); + } + + ok = js_Interpret(cx); + if (result) + *result = frame.rval; + + if (hookData) { + hook = cx->debugHooks->executeHook; + if (hook) + hook(cx, &frame, JS_FALSE, &ok, hookData); + } + +out2: + if (mark) + js_FreeRawStack(cx, mark); + cx->fp = oldfp; + + if (oldfp && oldfp != down) { + JS_ASSERT(cx->dormantFrameChain == oldfp); + cx->dormantFrameChain = oldfp->dormantNext; + oldfp->dormantNext = NULL; + } + +out: +#ifdef INCLUDE_MOZILLA_DTRACE + if (JAVASCRIPT_EXECUTE_DONE_ENABLED()) + jsdtrace_execute_done(script); +#endif + return ok; +} + +JSBool +js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, + JSObject **objp, JSProperty **propp) +{ + JSObject *obj2; + JSProperty *prop; + uintN oldAttrs, report; + JSBool isFunction; + jsval value; + const char *type, *name; + + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) + return JS_FALSE; + if (propp) { + *objp = obj2; + *propp = prop; + } + if (!prop) + return JS_TRUE; + + /* + * Use prop as a speedup hint to OBJ_GET_ATTRIBUTES, but drop it on error. + * An assertion at label bad: will insist that it is null. + */ + if (!OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &oldAttrs)) { + OBJ_DROP_PROPERTY(cx, obj2, prop); +#ifdef DEBUG + prop = NULL; +#endif + goto bad; + } + + /* + * From here, return true, or else goto bad on failure to null out params. + * If our caller doesn't want prop, drop it (we don't need it any longer). + */ + if (!propp) { + OBJ_DROP_PROPERTY(cx, obj2, prop); + prop = NULL; + } + + if (attrs == JSPROP_INITIALIZER) { + /* Allow the new object to override properties. */ + if (obj2 != obj) + return JS_TRUE; + report = JSREPORT_WARNING | JSREPORT_STRICT; + } else { + /* We allow redeclaring some non-readonly properties. */ + if (((oldAttrs | attrs) & JSPROP_READONLY) == 0) { + /* + * Allow redeclaration of variables and functions, but insist that + * the new value is not a getter if the old value was, ditto for + * setters -- unless prop is impermanent (in which case anyone + * could delete it and redefine it, willy-nilly). + */ + if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER))) + return JS_TRUE; + if ((~(oldAttrs ^ attrs) & (JSPROP_GETTER | JSPROP_SETTER)) == 0) + return JS_TRUE; + if (!(oldAttrs & JSPROP_PERMANENT)) + return JS_TRUE; + } + + report = JSREPORT_ERROR; + isFunction = (oldAttrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0; + if (!isFunction) { + if (!OBJ_GET_PROPERTY(cx, obj, id, &value)) + goto bad; + isFunction = VALUE_IS_FUNCTION(cx, value); + } + } + + type = (attrs == JSPROP_INITIALIZER) + ? "property" + : (oldAttrs & attrs & JSPROP_GETTER) + ? js_getter_str + : (oldAttrs & attrs & JSPROP_SETTER) + ? js_setter_str + : (oldAttrs & JSPROP_READONLY) + ? js_const_str + : isFunction + ? js_function_str + : js_var_str; + name = js_ValueToPrintableString(cx, ID_TO_VALUE(id)); + if (!name) + goto bad; + return JS_ReportErrorFlagsAndNumber(cx, report, + js_GetErrorMessage, NULL, + JSMSG_REDECLARED_VAR, + type, name); + +bad: + if (propp) { + *objp = NULL; + *propp = NULL; + } + JS_ASSERT(!prop); + return JS_FALSE; +} + +JSBool +js_StrictlyEqual(JSContext *cx, jsval lval, jsval rval) +{ + jsval ltag = JSVAL_TAG(lval), rtag = JSVAL_TAG(rval); + jsdouble ld, rd; + + if (ltag == rtag) { + if (ltag == JSVAL_STRING) { + JSString *lstr = JSVAL_TO_STRING(lval), + *rstr = JSVAL_TO_STRING(rval); + return js_EqualStrings(lstr, rstr); + } + if (ltag == JSVAL_DOUBLE) { + ld = *JSVAL_TO_DOUBLE(lval); + rd = *JSVAL_TO_DOUBLE(rval); + return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); + } + if (ltag == JSVAL_OBJECT && + lval != rval && + !JSVAL_IS_NULL(lval) && + !JSVAL_IS_NULL(rval)) { + JSObject *lobj, *robj; + + lobj = js_GetWrappedObject(cx, JSVAL_TO_OBJECT(lval)); + robj = js_GetWrappedObject(cx, JSVAL_TO_OBJECT(rval)); + lval = OBJECT_TO_JSVAL(lobj); + rval = OBJECT_TO_JSVAL(robj); + } + return lval == rval; + } + if (ltag == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) { + ld = *JSVAL_TO_DOUBLE(lval); + rd = JSVAL_TO_INT(rval); + return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); + } + if (JSVAL_IS_INT(lval) && rtag == JSVAL_DOUBLE) { + ld = JSVAL_TO_INT(lval); + rd = *JSVAL_TO_DOUBLE(rval); + return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); + } + return lval == rval; +} + +JSBool +js_InvokeConstructor(JSContext *cx, uintN argc, JSBool clampReturn, jsval *vp) +{ + JSFunction *fun, *fun2; + JSObject *obj, *obj2, *proto, *parent; + jsval lval, rval; + JSClass *clasp; + + fun = NULL; + obj2 = NULL; + lval = *vp; + if (!JSVAL_IS_OBJECT(lval) || + (obj2 = JSVAL_TO_OBJECT(lval)) == NULL || + /* XXX clean up to avoid special cases above ObjectOps layer */ + OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass || + !obj2->map->ops->construct) + { + fun = js_ValueToFunction(cx, vp, JSV2F_CONSTRUCT); + if (!fun) + return JS_FALSE; + } + + clasp = &js_ObjectClass; + if (!obj2) { + proto = parent = NULL; + fun = NULL; + } else { + /* + * Get the constructor prototype object for this function. + * Use the nominal 'this' parameter slot, vp[1], as a local + * root to protect this prototype, in case it has no other + * strong refs. + */ + if (!OBJ_GET_PROPERTY(cx, obj2, + ATOM_TO_JSID(cx->runtime->atomState + .classPrototypeAtom), + &vp[1])) { + return JS_FALSE; + } + rval = vp[1]; + proto = JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : NULL; + parent = OBJ_GET_PARENT(cx, obj2); + + if (OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass) { + fun2 = GET_FUNCTION_PRIVATE(cx, obj2); + if (!FUN_INTERPRETED(fun2) && + !(fun2->flags & JSFUN_TRACEABLE) && + fun2->u.n.u.clasp) { + clasp = fun2->u.n.u.clasp; + } + } + } + obj = js_NewObject(cx, clasp, proto, parent, 0); + if (!obj) + return JS_FALSE; + + /* Now we have an object with a constructor method; call it. */ + vp[1] = OBJECT_TO_JSVAL(obj); + if (!js_Invoke(cx, argc, vp, JSINVOKE_CONSTRUCT)) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + return JS_FALSE; + } + + /* Check the return value and if it's primitive, force it to be obj. */ + rval = *vp; + if (clampReturn && JSVAL_IS_PRIMITIVE(rval)) { + if (!fun) { + /* native [[Construct]] returning primitive is error */ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_NEW_RESULT, + js_ValueToPrintableString(cx, rval)); + return JS_FALSE; + } + *vp = OBJECT_TO_JSVAL(obj); + } + + JS_RUNTIME_METER(cx->runtime, constructs); + return JS_TRUE; +} + +JSBool +js_InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp) +{ + JS_ASSERT(!JSVAL_IS_INT(idval)); + +#if JS_HAS_XML_SUPPORT + if (!JSVAL_IS_PRIMITIVE(idval)) { + if (OBJECT_IS_XML(cx, obj)) { + *idp = OBJECT_JSVAL_TO_JSID(idval); + return JS_TRUE; + } + if (!js_IsFunctionQName(cx, JSVAL_TO_OBJECT(idval), idp)) + return JS_FALSE; + if (*idp != 0) + return JS_TRUE; + } +#endif + + return js_ValueToStringId(cx, idval, idp); +} + +/* + * Enter the new with scope using an object at sp[-1] and associate the depth + * of the with block with sp + stackIndex. + */ +JS_STATIC_INTERPRET JSBool +js_EnterWith(JSContext *cx, jsint stackIndex) +{ + JSStackFrame *fp; + jsval *sp; + JSObject *obj, *parent, *withobj; + + fp = cx->fp; + sp = fp->regs->sp; + JS_ASSERT(stackIndex < 0); + JS_ASSERT(StackBase(fp) <= sp + stackIndex); + + if (!JSVAL_IS_PRIMITIVE(sp[-1])) { + obj = JSVAL_TO_OBJECT(sp[-1]); + } else { + obj = js_ValueToNonNullObject(cx, sp[-1]); + if (!obj) + return JS_FALSE; + sp[-1] = OBJECT_TO_JSVAL(obj); + } + + parent = js_GetScopeChain(cx, fp); + if (!parent) + return JS_FALSE; + + OBJ_TO_INNER_OBJECT(cx, obj); + if (!obj) + return JS_FALSE; + + withobj = js_NewWithObject(cx, obj, parent, + sp + stackIndex - StackBase(fp)); + if (!withobj) + return JS_FALSE; + + fp->scopeChain = withobj; + js_DisablePropertyCache(cx); + return JS_TRUE; +} + +JS_STATIC_INTERPRET void +js_LeaveWith(JSContext *cx) +{ + JSObject *withobj; + + withobj = cx->fp->scopeChain; + JS_ASSERT(OBJ_GET_CLASS(cx, withobj) == &js_WithClass); + JS_ASSERT(OBJ_GET_PRIVATE(cx, withobj) == cx->fp); + JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0); + cx->fp->scopeChain = OBJ_GET_PARENT(cx, withobj); + JS_SetPrivate(cx, withobj, NULL); + js_EnablePropertyCache(cx); +} + +JSClass * +js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth) +{ + JSClass *clasp; + + clasp = OBJ_GET_CLASS(cx, obj); + if ((clasp == &js_WithClass || clasp == &js_BlockClass) && + OBJ_GET_PRIVATE(cx, obj) == cx->fp && + OBJ_BLOCK_DEPTH(cx, obj) >= stackDepth) { + return clasp; + } + return NULL; +} + +JS_STATIC_INTERPRET jsint +js_CountWithBlocks(JSContext *cx, JSStackFrame *fp) +{ + jsint n; + JSObject *obj; + JSClass *clasp; + + n = 0; + for (obj = fp->scopeChain; + (clasp = js_IsActiveWithOrBlock(cx, obj, 0)) != NULL; + obj = OBJ_GET_PARENT(cx, obj)) { + if (clasp == &js_WithClass) + ++n; + } + return n; +} + +/* + * Unwind block and scope chains to match the given depth. The function sets + * fp->sp on return to stackDepth. + */ +JSBool +js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth, + JSBool normalUnwind) +{ + JSObject *obj; + JSClass *clasp; + + JS_ASSERT(stackDepth >= 0); + JS_ASSERT(StackBase(fp) + stackDepth <= fp->regs->sp); + + for (obj = fp->blockChain; obj; obj = OBJ_GET_PARENT(cx, obj)) { + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_BlockClass); + if (OBJ_BLOCK_DEPTH(cx, obj) < stackDepth) + break; + } + fp->blockChain = obj; + + for (;;) { + obj = fp->scopeChain; + clasp = js_IsActiveWithOrBlock(cx, obj, stackDepth); + if (!clasp) + break; + if (clasp == &js_BlockClass) { + /* Don't fail until after we've updated all stacks. */ + normalUnwind &= js_PutBlockObject(cx, normalUnwind); + } else { + js_LeaveWith(cx); + } + } + + fp->regs->sp = StackBase(fp) + stackDepth; + return normalUnwind; +} + +JS_STATIC_INTERPRET JSBool +js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2) +{ + jsval v; + jsdouble d; + + v = *vp; + if (JSVAL_IS_DOUBLE(v)) { + d = *JSVAL_TO_DOUBLE(v); + } else if (JSVAL_IS_INT(v)) { + d = JSVAL_TO_INT(v); + } else { + d = js_ValueToNumber(cx, vp); + if (JSVAL_IS_NULL(*vp)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_NUMBER(*vp) || *vp == JSVAL_TRUE); + + /* Store the result of v conversion back in vp for post increments. */ + if ((cs->format & JOF_POST) && + *vp == JSVAL_TRUE + && !js_NewNumberInRootedValue(cx, d, vp)) { + return JS_FALSE; + } + } + + (cs->format & JOF_INC) ? d++ : d--; + if (!js_NewNumberInRootedValue(cx, d, vp2)) + return JS_FALSE; + + if (!(cs->format & JOF_POST)) + *vp = *vp2; + return JS_TRUE; +} + +#ifdef DEBUG + +JS_STATIC_INTERPRET void +js_TraceOpcode(JSContext *cx, jsint len) +{ + FILE *tracefp; + JSStackFrame *fp; + JSFrameRegs *regs; + JSOp prevop; + intN ndefs, n, nuses; + jsval *siter; + JSString *str; + JSOp op; + + tracefp = (FILE *) cx->tracefp; + JS_ASSERT(tracefp); + fp = cx->fp; + regs = fp->regs; + if (len != 0) { + prevop = (JSOp) regs->pc[-len]; + ndefs = js_CodeSpec[prevop].ndefs; + if (ndefs != 0) { + for (n = -ndefs; n < 0; n++) { + char *bytes = js_DecompileValueGenerator(cx, n, regs->sp[n], + NULL); + if (bytes) { + fprintf(tracefp, "%s %s", + (n == -ndefs) ? " output:" : ",", + bytes); + JS_free(cx, bytes); + } + } + fprintf(tracefp, " @ %u\n", (uintN) (regs->sp - StackBase(fp))); + } + fprintf(tracefp, " stack: "); + for (siter = StackBase(fp); siter < regs->sp; siter++) { + str = js_ValueToString(cx, *siter); + if (!str) + fputs("", tracefp); + else + js_FileEscapedString(tracefp, str, 0); + fputc(' ', tracefp); + } + fputc('\n', tracefp); + } + + fprintf(tracefp, "%4u: ", + js_PCToLineNumber(cx, fp->script, fp->imacpc ? fp->imacpc : regs->pc)); + js_Disassemble1(cx, fp->script, regs->pc, + PTRDIFF(regs->pc, fp->script->code, jsbytecode), + JS_FALSE, tracefp); + op = (JSOp) *regs->pc; + nuses = js_CodeSpec[op].nuses; + if (nuses != 0) { + for (n = -nuses; n < 0; n++) { + char *bytes = js_DecompileValueGenerator(cx, n, regs->sp[n], + NULL); + if (bytes) { + fprintf(tracefp, "%s %s", + (n == -nuses) ? " inputs:" : ",", + bytes); + JS_free(cx, bytes); + } + } + fprintf(tracefp, " @ %u\n", (uintN) (regs->sp - StackBase(fp))); + } +} + +#endif /* DEBUG */ + +#ifdef JS_OPMETER + +# include + +# define HIST_NSLOTS 8 + +/* + * The second dimension is hardcoded at 256 because we know that many bits fit + * in a byte, and mainly to optimize away multiplying by JSOP_LIMIT to address + * any particular row. + */ +static uint32 succeeds[JSOP_LIMIT][256]; +static uint32 slot_ops[JSOP_LIMIT][HIST_NSLOTS]; + +JS_STATIC_INTERPRET void +js_MeterOpcodePair(JSOp op1, JSOp op2) +{ + if (op1 != JSOP_STOP) + ++succeeds[op1][op2]; +} + +JS_STATIC_INTERPRET void +js_MeterSlotOpcode(JSOp op, uint32 slot) +{ + if (slot < HIST_NSLOTS) + ++slot_ops[op][slot]; +} + +typedef struct Edge { + const char *from; + const char *to; + uint32 count; +} Edge; + +static int +compare_edges(const void *a, const void *b) +{ + const Edge *ea = (const Edge *) a; + const Edge *eb = (const Edge *) b; + + return (int32)eb->count - (int32)ea->count; +} + +void +js_DumpOpMeters() +{ + const char *name, *from, *style; + FILE *fp; + uint32 total, count; + uint32 i, j, nedges; + Edge *graph; + + name = getenv("JS_OPMETER_FILE"); + if (!name) + name = "/tmp/ops.dot"; + fp = fopen(name, "w"); + if (!fp) { + perror(name); + return; + } + + total = nedges = 0; + for (i = 0; i < JSOP_LIMIT; i++) { + for (j = 0; j < JSOP_LIMIT; j++) { + count = succeeds[i][j]; + if (count != 0) { + total += count; + ++nedges; + } + } + } + +# define SIGNIFICANT(count,total) (200. * (count) >= (total)) + + graph = (Edge *) calloc(nedges, sizeof graph[0]); + for (i = nedges = 0; i < JSOP_LIMIT; i++) { + from = js_CodeName[i]; + for (j = 0; j < JSOP_LIMIT; j++) { + count = succeeds[i][j]; + if (count != 0 && SIGNIFICANT(count, total)) { + graph[nedges].from = from; + graph[nedges].to = js_CodeName[j]; + graph[nedges].count = count; + ++nedges; + } + } + } + qsort(graph, nedges, sizeof(Edge), compare_edges); + +# undef SIGNIFICANT + + fputs("digraph {\n", fp); + for (i = 0, style = NULL; i < nedges; i++) { + JS_ASSERT(i == 0 || graph[i-1].count >= graph[i].count); + if (!style || graph[i-1].count != graph[i].count) { + style = (i > nedges * .75) ? "dotted" : + (i > nedges * .50) ? "dashed" : + (i > nedges * .25) ? "solid" : "bold"; + } + fprintf(fp, " %s -> %s [label=\"%lu\" style=%s]\n", + graph[i].from, graph[i].to, + (unsigned long)graph[i].count, style); + } + free(graph); + fputs("}\n", fp); + fclose(fp); + + name = getenv("JS_OPMETER_HIST"); + if (!name) + name = "/tmp/ops.hist"; + fp = fopen(name, "w"); + if (!fp) { + perror(name); + return; + } + fputs("bytecode", fp); + for (j = 0; j < HIST_NSLOTS; j++) + fprintf(fp, " slot %1u", (unsigned)j); + putc('\n', fp); + fputs("========", fp); + for (j = 0; j < HIST_NSLOTS; j++) + fputs(" =======", fp); + putc('\n', fp); + for (i = 0; i < JSOP_LIMIT; i++) { + for (j = 0; j < HIST_NSLOTS; j++) { + if (slot_ops[i][j] != 0) { + /* Reuse j in the next loop, since we break after. */ + fprintf(fp, "%-8.8s", js_CodeName[i]); + for (j = 0; j < HIST_NSLOTS; j++) + fprintf(fp, " %7lu", (unsigned long)slot_ops[i][j]); + putc('\n', fp); + break; + } + } + } + fclose(fp); +} + +#endif /* JS_OPSMETER */ + +#endif /* !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___ */ + +#ifndef jsinvoke_cpp___ + +#define PUSH(v) (*regs.sp++ = (v)) +#define PUSH_OPND(v) PUSH(v) +#define STORE_OPND(n,v) (regs.sp[n] = (v)) +#define POP() (*--regs.sp) +#define POP_OPND() POP() +#define FETCH_OPND(n) (regs.sp[n]) + +/* + * Push the jsdouble d using sp from the lexical environment. Try to convert d + * to a jsint that fits in a jsval, otherwise GC-alloc space for it and push a + * reference. + */ +#define STORE_NUMBER(cx, n, d) \ + JS_BEGIN_MACRO \ + jsint i_; \ + \ + if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_)) \ + regs.sp[n] = INT_TO_JSVAL(i_); \ + else if (!js_NewDoubleInRootedValue(cx, d, ®s.sp[n])) \ + goto error; \ + JS_END_MACRO + +#define STORE_INT(cx, n, i) \ + JS_BEGIN_MACRO \ + if (INT_FITS_IN_JSVAL(i)) \ + regs.sp[n] = INT_TO_JSVAL(i); \ + else if (!js_NewDoubleInRootedValue(cx, (jsdouble) (i), ®s.sp[n])) \ + goto error; \ + JS_END_MACRO + +#define STORE_UINT(cx, n, u) \ + JS_BEGIN_MACRO \ + if ((u) <= JSVAL_INT_MAX) \ + regs.sp[n] = INT_TO_JSVAL(u); \ + else if (!js_NewDoubleInRootedValue(cx, (jsdouble) (u), ®s.sp[n])) \ + goto error; \ + JS_END_MACRO + +#define FETCH_NUMBER(cx, n, d) \ + JS_BEGIN_MACRO \ + jsval v_; \ + \ + v_ = FETCH_OPND(n); \ + VALUE_TO_NUMBER(cx, n, v_, d); \ + JS_END_MACRO + +#define FETCH_INT(cx, n, i) \ + JS_BEGIN_MACRO \ + jsval v_; \ + \ + v_= FETCH_OPND(n); \ + if (JSVAL_IS_INT(v_)) { \ + i = JSVAL_TO_INT(v_); \ + } else { \ + i = js_ValueToECMAInt32(cx, ®s.sp[n]); \ + if (JSVAL_IS_NULL(regs.sp[n])) \ + goto error; \ + } \ + JS_END_MACRO + +#define FETCH_UINT(cx, n, ui) \ + JS_BEGIN_MACRO \ + jsval v_; \ + \ + v_= FETCH_OPND(n); \ + if (JSVAL_IS_INT(v_)) { \ + ui = (uint32) JSVAL_TO_INT(v_); \ + } else { \ + ui = js_ValueToECMAUint32(cx, ®s.sp[n]); \ + if (JSVAL_IS_NULL(regs.sp[n])) \ + goto error; \ + } \ + JS_END_MACRO + +/* + * Optimized conversion macros that test for the desired type in v before + * homing sp and calling a conversion function. + */ +#define VALUE_TO_NUMBER(cx, n, v, d) \ + JS_BEGIN_MACRO \ + JS_ASSERT(v == regs.sp[n]); \ + if (JSVAL_IS_INT(v)) { \ + d = (jsdouble)JSVAL_TO_INT(v); \ + } else if (JSVAL_IS_DOUBLE(v)) { \ + d = *JSVAL_TO_DOUBLE(v); \ + } else { \ + d = js_ValueToNumber(cx, ®s.sp[n]); \ + if (JSVAL_IS_NULL(regs.sp[n])) \ + goto error; \ + JS_ASSERT(JSVAL_IS_NUMBER(regs.sp[n]) || \ + regs.sp[n] == JSVAL_TRUE); \ + } \ + JS_END_MACRO + +#define POP_BOOLEAN(cx, v, b) \ + JS_BEGIN_MACRO \ + v = FETCH_OPND(-1); \ + if (v == JSVAL_NULL) { \ + b = JS_FALSE; \ + } else if (JSVAL_IS_BOOLEAN(v)) { \ + b = JSVAL_TO_BOOLEAN(v); \ + } else { \ + b = js_ValueToBoolean(v); \ + } \ + regs.sp--; \ + JS_END_MACRO + +#define VALUE_TO_OBJECT(cx, n, v, obj) \ + JS_BEGIN_MACRO \ + if (!JSVAL_IS_PRIMITIVE(v)) { \ + obj = JSVAL_TO_OBJECT(v); \ + } else { \ + obj = js_ValueToNonNullObject(cx, v); \ + if (!obj) \ + goto error; \ + STORE_OPND(n, OBJECT_TO_JSVAL(obj)); \ + } \ + JS_END_MACRO + +#define FETCH_OBJECT(cx, n, v, obj) \ + JS_BEGIN_MACRO \ + v = FETCH_OPND(n); \ + VALUE_TO_OBJECT(cx, n, v, obj); \ + JS_END_MACRO + +#define DEFAULT_VALUE(cx, n, hint, v) \ + JS_BEGIN_MACRO \ + JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); \ + JS_ASSERT(v == regs.sp[n]); \ + if (!OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), hint, ®s.sp[n])) \ + goto error; \ + v = regs.sp[n]; \ + JS_END_MACRO + +/* + * Quickly test if v is an int from the [-2**29, 2**29) range, that is, when + * the lowest bit of v is 1 and the bits 30 and 31 are both either 0 or 1. For + * such v we can do increment or decrement via adding or subtracting two + * without checking that the result overflows JSVAL_INT_MIN or JSVAL_INT_MAX. + */ +#define CAN_DO_FAST_INC_DEC(v) (((((v) << 1) ^ v) & 0x80000001) == 1) + +JS_STATIC_ASSERT(JSVAL_INT == 1); +JS_STATIC_ASSERT(!CAN_DO_FAST_INC_DEC(INT_TO_JSVAL(JSVAL_INT_MIN))); +JS_STATIC_ASSERT(!CAN_DO_FAST_INC_DEC(INT_TO_JSVAL(JSVAL_INT_MAX))); + +/* + * Conditional assert to detect failure to clear a pending exception that is + * suppressed (or unintentional suppression of a wanted exception). + */ +#if defined DEBUG_brendan || defined DEBUG_mrbkap || defined DEBUG_shaver +# define DEBUG_NOT_THROWING 1 +#endif + +#ifdef DEBUG_NOT_THROWING +# define ASSERT_NOT_THROWING(cx) JS_ASSERT(!(cx)->throwing) +#else +# define ASSERT_NOT_THROWING(cx) /* nothing */ +#endif + +/* + * Define JS_OPMETER to instrument bytecode succession, generating a .dot file + * on shutdown that shows the graph of significant predecessor/successor pairs + * executed, where the edge labels give the succession counts. The .dot file + * is named by the JS_OPMETER_FILE envariable, and defaults to /tmp/ops.dot. + * + * Bonus feature: JS_OPMETER also enables counters for stack-addressing ops + * such as JSOP_GETLOCAL, JSOP_INCARG, via METER_SLOT_OP. The resulting counts + * are written to JS_OPMETER_HIST, defaulting to /tmp/ops.hist. + */ +#ifndef JS_OPMETER +# define METER_OP_INIT(op) /* nothing */ +# define METER_OP_PAIR(op1,op2) /* nothing */ +# define METER_SLOT_OP(op,slot) /* nothing */ +#else + +/* + * The second dimension is hardcoded at 256 because we know that many bits fit + * in a byte, and mainly to optimize away multiplying by JSOP_LIMIT to address + * any particular row. + */ +# define METER_OP_INIT(op) ((op) = JSOP_STOP) +# define METER_OP_PAIR(op1,op2) (js_MeterOpcodePair(op1, op2)) +# define METER_SLOT_OP(op,slot) (js_MeterSlotOpcode(op, slot)) + +#endif + +#define MAX_INLINE_CALL_COUNT 3000 + +/* + * Threaded interpretation via computed goto appears to be well-supported by + * GCC 3 and higher. IBM's C compiler when run with the right options (e.g., + * -qlanglvl=extended) also supports threading. Ditto the SunPro C compiler. + * Currently it's broken for JS_VERSION < 160, though this isn't worth fixing. + * Add your compiler support macros here. + */ +#ifndef JS_THREADED_INTERP +# if JS_VERSION >= 160 && ( \ + __GNUC__ >= 3 || \ + (__IBMC__ >= 700 && defined __IBM_COMPUTED_GOTO) || \ + __SUNPRO_C >= 0x570) +# define JS_THREADED_INTERP 1 +# else +# define JS_THREADED_INTERP 0 +# endif +#endif + +/* + * Interpreter assumes the following to implement condition-free interrupt + * implementation when !JS_THREADED_INTERP. + */ +JS_STATIC_ASSERT(JSOP_INTERRUPT == 0); + +/* + * Ensure that the intrepreter switch can close call-bytecode cases in the + * same way as non-call bytecodes. + */ +JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH); +JS_STATIC_ASSERT(JSOP_GETGVAR_LENGTH == JSOP_CALLGVAR_LENGTH); +JS_STATIC_ASSERT(JSOP_GETUPVAR_LENGTH == JSOP_CALLUPVAR_LENGTH); +JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH); +JS_STATIC_ASSERT(JSOP_GETLOCAL_LENGTH == JSOP_CALLLOCAL_LENGTH); +JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH); + +/* + * Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but + * remain distinct for the decompiler. Ditto for JSOP_NULL{,THIS}. + */ +JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH); +JS_STATIC_ASSERT(JSOP_NULL_LENGTH == JSOP_NULLTHIS_LENGTH); + +/* See TRY_BRANCH_AFTER_COND. */ +JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH); +JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1); + +/* For the fastest case inder JSOP_INCNAME, etc. */ +JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_DECNAME_LENGTH); +JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEINC_LENGTH); +JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEDEC_LENGTH); + +JSBool +js_Interpret(JSContext *cx) +{ + JSRuntime *rt; + JSStackFrame *fp; + JSScript *script; + uintN inlineCallCount; + JSAtom **atoms; + JSVersion currentVersion, originalVersion; + JSFrameRegs regs; + JSObject *obj, *obj2, *parent; + JSBool ok, cond; + jsint len; + jsbytecode *endpc, *pc2; + JSOp op, op2; + jsatomid index; + JSAtom *atom; + uintN argc, attrs, flags; + uint32 slot; + jsval *vp, lval, rval, ltmp, rtmp; + jsid id; + JSProperty *prop; + JSScopeProperty *sprop; + JSString *str, *str2; + jsint i, j; + jsdouble d, d2; + JSClass *clasp; + JSFunction *fun; + JSType type; +#if JS_THREADED_INTERP + register void * const *jumpTable; +#else + register uint32 switchMask; + uintN switchOp; +#endif + jsint low, high, off, npairs; + JSBool match; +#if JS_HAS_GETTER_SETTER + JSPropertyOp getter, setter; +#endif + JSAutoResolveFlags rf(cx, JSRESOLVE_INFER); + +#ifdef __GNUC__ +# define JS_EXTENSION __extension__ +# define JS_EXTENSION_(s) __extension__ ({ s; }) +#else +# define JS_EXTENSION +# define JS_EXTENSION_(s) s +#endif + +#if JS_THREADED_INTERP + static void *const normalJumpTable[] = { +# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + JS_EXTENSION &&L_##op, +# include "jsopcode.tbl" +# undef OPDEF + }; + +#ifdef JS_TRACER + static void *const recordingJumpTable[] = { +# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + JS_EXTENSION &&R_##op, +# include "jsopcode.tbl" +# undef OPDEF + }; +#endif /* JS_TRACER */ + + static void *const interruptJumpTable[] = { +# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + JS_EXTENSION &&L_JSOP_INTERRUPT, +# include "jsopcode.tbl" +# undef OPDEF + }; + + METER_OP_INIT(op); /* to nullify first METER_OP_PAIR */ + +# ifdef JS_TRACER +# define CHECK_RECORDER() JS_BEGIN_MACRO \ + JS_ASSERT(!TRACE_RECORDER(cx) ^ \ + (jumpTable == recordingJumpTable)); \ + JS_END_MACRO +# else +# define CHECK_RECORDER() ((void)0) +# endif + +# define DO_OP() JS_BEGIN_MACRO \ + CHECK_RECORDER(); \ + JS_EXTENSION_(goto *jumpTable[op]); \ + JS_END_MACRO +# define DO_NEXT_OP(n) JS_BEGIN_MACRO \ + METER_OP_PAIR(op, regs.pc[n]); \ + op = (JSOp) *(regs.pc += (n)); \ + DO_OP(); \ + JS_END_MACRO + +# define BEGIN_CASE(OP) L_##OP: \ + CHECK_RECORDER(); +# define END_CASE(OP) DO_NEXT_OP(OP##_LENGTH); +# define END_VARLEN_CASE DO_NEXT_OP(len); +# define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP) \ + JS_ASSERT(js_CodeSpec[OP].length == 1); \ + op = (JSOp) *++regs.pc; \ + DO_OP(); + +# define END_EMPTY_CASES + +#else /* !JS_THREADED_INTERP */ + +# define DO_OP() goto do_op +# define DO_NEXT_OP(n) JS_BEGIN_MACRO \ + JS_ASSERT((n) == len); \ + goto advance_pc; \ + JS_END_MACRO + +# define BEGIN_CASE(OP) case OP: +# define END_CASE(OP) END_CASE_LEN(OP##_LENGTH) +# define END_CASE_LEN(n) END_CASE_LENX(n) +# define END_CASE_LENX(n) END_CASE_LEN##n + +/* + * To share the code for all len == 1 cases we use the specialized label with + * code that falls through to advance_pc: . + */ +# define END_CASE_LEN1 goto advance_pc_by_one; +# define END_CASE_LEN2 len = 2; goto advance_pc; +# define END_CASE_LEN3 len = 3; goto advance_pc; +# define END_CASE_LEN4 len = 4; goto advance_pc; +# define END_CASE_LEN5 len = 5; goto advance_pc; +# define END_VARLEN_CASE goto advance_pc; +# define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP) +# define END_EMPTY_CASES goto advance_pc_by_one; + +#endif /* !JS_THREADED_INTERP */ + +#ifdef JS_TRACER + /* We had better not be entering the interpreter from JIT-compiled code. */ + TraceRecorder *tr = NULL; + if (JS_ON_TRACE(cx)) { + tr = TRACE_RECORDER(cx); + SET_TRACE_RECORDER(cx, NULL); + JS_TRACE_MONITOR(cx).onTrace = JS_FALSE; + /* + * ON_TRACE means either recording or coming from traced code. + * If there's no recorder (the latter case), don't care. + */ + if (tr) { + if (tr->wasDeepAborted()) + tr->removeFragmentoReferences(); + else + tr->pushAbortStack(); + } + } +#endif + + /* Check for too deep of a native thread stack. */ + JS_CHECK_RECURSION(cx, return JS_FALSE); + + rt = cx->runtime; + + /* Set registerized frame pointer and derived script pointer. */ + fp = cx->fp; + script = fp->script; + JS_ASSERT(script->length != 0); + + /* Count of JS function calls that nest in this C js_Interpret frame. */ + inlineCallCount = 0; + + /* + * Initialize the index segment register used by LOAD_ATOM and + * GET_FULL_INDEX macros below. As a register we use a pointer based on + * the atom map to turn frequently executed LOAD_ATOM into simple array + * access. For less frequent object and regexp loads we have to recover + * the segment from atoms pointer first. + */ + atoms = script->atomMap.vector; + +#define LOAD_ATOM(PCOFF) \ + JS_BEGIN_MACRO \ + JS_ASSERT(fp->imacpc \ + ? atoms == COMMON_ATOMS_START(&rt->atomState) && \ + GET_INDEX(regs.pc + PCOFF) < js_common_atom_count \ + : (size_t)(atoms - script->atomMap.vector) < \ + (size_t)(script->atomMap.length - \ + GET_INDEX(regs.pc + PCOFF))); \ + atom = atoms[GET_INDEX(regs.pc + PCOFF)]; \ + JS_END_MACRO + +#define GET_FULL_INDEX(PCOFF) \ + (atoms - script->atomMap.vector + GET_INDEX(regs.pc + PCOFF)) + +#define LOAD_OBJECT(PCOFF) \ + JS_GET_SCRIPT_OBJECT(script, GET_FULL_INDEX(PCOFF), obj) + +#define LOAD_FUNCTION(PCOFF) \ + JS_GET_SCRIPT_FUNCTION(script, GET_FULL_INDEX(PCOFF), fun) + +#ifdef JS_TRACER + +#define MONITOR_BRANCH() \ + JS_BEGIN_MACRO \ + if (TRACING_ENABLED(cx)) { \ + ENABLE_TRACER(js_MonitorLoopEdge(cx, inlineCallCount)); \ + fp = cx->fp; \ + script = fp->script; \ + atoms = script->atomMap.vector; \ + currentVersion = (JSVersion) script->version; \ + JS_ASSERT(fp->regs == ®s); \ + if (cx->throwing) \ + goto error; \ + } \ + JS_END_MACRO + +#else /* !JS_TRACER */ + +#define MONITOR_BRANCH() ((void) 0) + +#endif /* !JS_TRACER */ + + /* + * Prepare to call a user-supplied branch handler, and abort the script + * if it returns false. + */ +#define CHECK_BRANCH() \ + JS_BEGIN_MACRO \ + if ((cx->operationCount -= JSOW_SCRIPT_JUMP) <= 0) { \ + if (!js_ResetOperationCount(cx)) \ + goto error; \ + } \ + JS_END_MACRO + +#define BRANCH(n) \ + JS_BEGIN_MACRO \ + regs.pc += n; \ + if (n <= 0) { \ + CHECK_BRANCH(); \ + MONITOR_BRANCH(); \ + } \ + op = (JSOp) *regs.pc; \ + DO_OP(); \ + JS_END_MACRO + + MUST_FLOW_THROUGH("exit"); + ++cx->interpLevel; + + /* + * Optimized Get and SetVersion for proper script language versioning. + * + * If any native method or JSClass/JSObjectOps hook calls js_SetVersion + * and changes cx->version, the effect will "stick" and we will stop + * maintaining currentVersion. This is relied upon by testsuites, for + * the most part -- web browsers select version before compiling and not + * at run-time. + */ + currentVersion = (JSVersion) script->version; + originalVersion = (JSVersion) cx->version; + if (currentVersion != originalVersion) + js_SetVersion(cx, currentVersion); + + /* Update the static-link display. */ + if (script->staticDepth < JS_DISPLAY_SIZE) { + JSStackFrame **disp = &cx->display[script->staticDepth]; + fp->displaySave = *disp; + *disp = fp; + } +#ifdef DEBUG + fp->pcDisabledSave = JS_PROPERTY_CACHE(cx).disabled; +#endif + + /* + * Load the debugger's interrupt hook here and after calling out to native + * functions (but not to getters, setters, or other native hooks), so we do + * not have to reload it each time through the interpreter loop -- we hope + * the compiler can keep it in a register when it is non-null. + */ +#if JS_THREADED_INTERP +#ifdef JS_TRACER +# define LOAD_INTERRUPT_HANDLER(cx) \ + ((void) (jumpTable = (cx)->debugHooks->interruptHandler \ + ? interruptJumpTable \ + : TRACE_RECORDER(cx) \ + ? recordingJumpTable \ + : normalJumpTable)) +# define ENABLE_TRACER(flag) \ + JS_BEGIN_MACRO \ + bool flag_ = (flag); \ + JS_ASSERT(flag_ == !!TRACE_RECORDER(cx)); \ + jumpTable = flag_ ? recordingJumpTable : normalJumpTable; \ + JS_END_MACRO +#else /* !JS_TRACER */ +# define LOAD_INTERRUPT_HANDLER(cx) \ + ((void) (jumpTable = (cx)->debugHooks->interruptHandler \ + ? interruptJumpTable \ + : normalJumpTable)) +# define ENABLE_TRACER(flag) ((void)0) +#endif /* !JS_TRACER */ +#else /* !JS_THREADED_INTERP */ +#ifdef JS_TRACER +# define LOAD_INTERRUPT_HANDLER(cx) \ + ((void) (switchMask = ((cx)->debugHooks->interruptHandler || \ + TRACE_RECORDER(cx)) ? 0 : 255)) +# define ENABLE_TRACER(flag) \ + JS_BEGIN_MACRO \ + bool flag_ = (flag); \ + JS_ASSERT(flag_ == !!TRACE_RECORDER(cx)); \ + switchMask = flag_ ? 0 : 255; \ + JS_END_MACRO +#else /* !JS_TRACER */ +# define LOAD_INTERRUPT_HANDLER(cx) \ + ((void) (switchMask = ((cx)->debugHooks->interruptHandler \ + ? 0 : 255))) +# define ENABLE_TRACER(flag) ((void)0) +#endif /* !JS_TRACER */ +#endif /* !JS_THREADED_INTERP */ + + LOAD_INTERRUPT_HANDLER(cx); + +#if !JS_HAS_GENERATORS + JS_ASSERT(!fp->regs); +#else + /* Initialize the pc and sp registers unless we're resuming a generator. */ + if (JS_LIKELY(!fp->regs)) { +#endif + ASSERT_NOT_THROWING(cx); + regs.pc = script->code; + regs.sp = StackBase(fp); + fp->regs = ®s; +#if JS_HAS_GENERATORS + } else { + JSGenerator *gen; + + JS_ASSERT(fp->flags & JSFRAME_GENERATOR); + gen = FRAME_TO_GENERATOR(fp); + JS_ASSERT(fp->regs == &gen->savedRegs); + regs = gen->savedRegs; + fp->regs = ®s; + JS_ASSERT((size_t) (regs.pc - script->code) <= script->length); + JS_ASSERT((size_t) (regs.sp - StackBase(fp)) <= StackDepth(script)); + JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0); + JS_PROPERTY_CACHE(cx).disabled += js_CountWithBlocks(cx, fp); + + /* + * To support generator_throw and to catch ignored exceptions, + * fail if cx->throwing is set. + */ + if (cx->throwing) { +#ifdef DEBUG_NOT_THROWING + if (cx->exception != JSVAL_ARETURN) { + printf("JS INTERPRETER CALLED WITH PENDING EXCEPTION %lx\n", + (unsigned long) cx->exception); + } +#endif + goto error; + } + } +#endif /* JS_HAS_GENERATORS */ + + /* + * It is important that "op" be initialized before calling DO_OP because + * it is possible for "op" to be specially assigned during the normal + * processing of an opcode while looping. We rely on DO_NEXT_OP to manage + * "op" correctly in all other cases. + */ + len = 0; + DO_NEXT_OP(len); + +#if JS_THREADED_INTERP + /* + * This is a loop, but it does not look like a loop. The loop-closing + * jump is distributed throughout goto *jumpTable[op] inside of DO_OP. + * When interrupts are enabled, jumpTable is set to interruptJumpTable + * where all jumps point to the JSOP_INTERRUPT case. The latter, after + * calling the interrupt handler, dispatches through normalJumpTable to + * continue the normal bytecode processing. + */ +#else + for (;;) { + advance_pc_by_one: + JS_ASSERT(js_CodeSpec[op].length == 1); + len = 1; + advance_pc: + regs.pc += len; + op = (JSOp) *regs.pc; +#ifdef DEBUG + if (cx->tracefp) + js_TraceOpcode(cx, len); +#endif + + do_op: + switchOp = op & switchMask; + do_switch: + switch (switchOp) { +#endif /* !JS_THREADED_INTERP */ + + BEGIN_CASE(JSOP_INTERRUPT) + { + JSTrapHandler handler; + + handler = cx->debugHooks->interruptHandler; + if (handler) { + switch (handler(cx, script, regs.pc, &rval, + cx->debugHooks->interruptHandlerData)) { + case JSTRAP_ERROR: + goto error; + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + fp->rval = rval; + ok = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->throwing = JS_TRUE; + cx->exception = rval; + goto error; + default:; + } +#if !JS_THREADED_INTERP + } else { + /* this was not a real interrupt, the tracer is trying to + record a trace */ + switchOp = op + 256; + goto do_switch; +#endif + } + LOAD_INTERRUPT_HANDLER(cx); + +#if JS_THREADED_INTERP + JS_EXTENSION_(goto *normalJumpTable[op]); +#else + switchOp = op; + goto do_switch; +#endif + } + + /* No-ops for ease of decompilation. */ + ADD_EMPTY_CASE(JSOP_NOP) + ADD_EMPTY_CASE(JSOP_CONDSWITCH) + ADD_EMPTY_CASE(JSOP_TRY) + ADD_EMPTY_CASE(JSOP_FINALLY) +#if JS_HAS_XML_SUPPORT + ADD_EMPTY_CASE(JSOP_STARTXML) + ADD_EMPTY_CASE(JSOP_STARTXMLEXPR) +#endif + END_EMPTY_CASES + + /* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */ + BEGIN_CASE(JSOP_LINENO) + END_CASE(JSOP_LINENO) + + BEGIN_CASE(JSOP_PUSH) + PUSH_OPND(JSVAL_VOID); + END_CASE(JSOP_PUSH) + + BEGIN_CASE(JSOP_POP) + regs.sp--; + END_CASE(JSOP_POP) + + BEGIN_CASE(JSOP_POPN) + regs.sp -= GET_UINT16(regs.pc); +#ifdef DEBUG + JS_ASSERT(StackBase(fp) <= regs.sp); + obj = fp->blockChain; + JS_ASSERT_IF(obj, + OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj) + <= (size_t) (regs.sp - StackBase(fp))); + for (obj = fp->scopeChain; obj; obj = OBJ_GET_PARENT(cx, obj)) { + clasp = OBJ_GET_CLASS(cx, obj); + if (clasp != &js_BlockClass && clasp != &js_WithClass) + continue; + if (OBJ_GET_PRIVATE(cx, obj) != fp) + break; + JS_ASSERT(StackBase(fp) + OBJ_BLOCK_DEPTH(cx, obj) + + ((clasp == &js_BlockClass) + ? OBJ_BLOCK_COUNT(cx, obj) + : 1) + <= regs.sp); + } +#endif + END_CASE(JSOP_POPN) + + BEGIN_CASE(JSOP_SETRVAL) + BEGIN_CASE(JSOP_POPV) + ASSERT_NOT_THROWING(cx); + fp->rval = POP_OPND(); + END_CASE(JSOP_POPV) + + BEGIN_CASE(JSOP_ENTERWITH) + if (!js_EnterWith(cx, -1)) + goto error; + + /* + * We must ensure that different "with" blocks have different + * stack depth associated with them. This allows the try handler + * search to properly recover the scope chain. Thus we must keep + * the stack at least at the current level. + * + * We set sp[-1] to the current "with" object to help asserting + * the enter/leave balance in [leavewith]. + */ + regs.sp[-1] = OBJECT_TO_JSVAL(fp->scopeChain); + END_CASE(JSOP_ENTERWITH) + + BEGIN_CASE(JSOP_LEAVEWITH) + JS_ASSERT(regs.sp[-1] == OBJECT_TO_JSVAL(fp->scopeChain)); + regs.sp--; + js_LeaveWith(cx); + END_CASE(JSOP_LEAVEWITH) + + BEGIN_CASE(JSOP_RETURN) + CHECK_BRANCH(); + fp->rval = POP_OPND(); + /* FALL THROUGH */ + + BEGIN_CASE(JSOP_RETRVAL) /* fp->rval already set */ + BEGIN_CASE(JSOP_STOP) + /* + * When the inlined frame exits with an exception or an error, ok + * will be false after the inline_return label. + */ + ASSERT_NOT_THROWING(cx); + + if (fp->imacpc) { + /* + * If we are at the end of an imacro, return to its caller in + * the current frame. + */ + JS_ASSERT(op == JSOP_STOP); + + end_imacro: + JS_ASSERT((uintN)(regs.sp - fp->slots) <= script->nslots); + regs.pc = fp->imacpc + js_CodeSpec[*fp->imacpc].length; + fp->imacpc = NULL; + atoms = script->atomMap.vector; + op = JSOp(*regs.pc); + DO_OP(); + } + + JS_ASSERT(regs.sp == StackBase(fp)); + if ((fp->flags & JSFRAME_CONSTRUCTING) && + JSVAL_IS_PRIMITIVE(fp->rval)) { + if (!fp->fun) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_NEW_RESULT, + js_ValueToPrintableString(cx, rval)); + goto error; + } + fp->rval = OBJECT_TO_JSVAL(fp->thisp); + } + ok = JS_TRUE; + if (inlineCallCount) + inline_return: + { + JSInlineFrame *ifp = (JSInlineFrame *) fp; + void *hookData = ifp->hookData; + + JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave); + JS_ASSERT(!fp->blockChain); + JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0)); + + if (script->staticDepth < JS_DISPLAY_SIZE) + cx->display[script->staticDepth] = fp->displaySave; + + if (hookData) { + JSInterpreterHook hook; + JSBool status; + + hook = cx->debugHooks->callHook; + if (hook) { + /* + * Do not pass &ok directly as exposing the address + * inhibits optimizations and uninitialised warnings. + */ + status = ok; + hook(cx, fp, JS_FALSE, &status, hookData); + ok = status; + LOAD_INTERRUPT_HANDLER(cx); + } + } + + /* + * If fp has a call object, sync values and clear the back- + * pointer. This can happen for a lightweight function if it + * calls eval unexpectedly (in a way that is hidden from the + * compiler). See bug 325540. + */ + if (fp->callobj) + ok &= js_PutCallObject(cx, fp); + + if (fp->argsobj) + ok &= js_PutArgsObject(cx, fp); + +#ifdef INCLUDE_MOZILLA_DTRACE + /* DTrace function return, inlines */ + if (JAVASCRIPT_FUNCTION_RVAL_ENABLED()) + jsdtrace_function_rval(cx, fp, fp->fun); + if (JAVASCRIPT_FUNCTION_RETURN_ENABLED()) + jsdtrace_function_return(cx, fp, fp->fun); +#endif + + /* Restore context version only if callee hasn't set version. */ + if (JS_LIKELY(cx->version == currentVersion)) { + currentVersion = ifp->callerVersion; + if (currentVersion != cx->version) + js_SetVersion(cx, currentVersion); + } + + /* + * If inline-constructing, replace primitive rval with the new + * object passed in via |this|, and instrument this constructor + * invocation + */ + if (fp->flags & JSFRAME_CONSTRUCTING) { + if (JSVAL_IS_PRIMITIVE(fp->rval)) + fp->rval = OBJECT_TO_JSVAL(fp->thisp); + JS_RUNTIME_METER(cx->runtime, constructs); + } + + /* Restore caller's registers. */ + regs = ifp->callerRegs; + + /* Store the return value in the caller's operand frame. */ + regs.sp -= 1 + (size_t) ifp->frame.argc; + regs.sp[-1] = fp->rval; + + /* Restore cx->fp and release the inline frame's space. */ + cx->fp = fp = fp->down; + JS_ASSERT(fp->regs == &ifp->callerRegs); + fp->regs = ®s; + JS_ARENA_RELEASE(&cx->stackPool, ifp->mark); + + /* Restore the calling script's interpreter registers. */ + script = fp->script; + atoms = script->atomMap.vector; + + /* Resume execution in the calling frame. */ + inlineCallCount--; + if (JS_LIKELY(ok)) { + TRACE_0(LeaveFrame); + JS_ASSERT(js_CodeSpec[*regs.pc].length == JSOP_CALL_LENGTH); + len = JSOP_CALL_LENGTH; + DO_NEXT_OP(len); + } + goto error; + } + goto exit; + + BEGIN_CASE(JSOP_DEFAULT) + (void) POP(); + /* FALL THROUGH */ + BEGIN_CASE(JSOP_GOTO) + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + END_CASE(JSOP_GOTO) + + BEGIN_CASE(JSOP_IFEQ) + POP_BOOLEAN(cx, rval, cond); + if (cond == JS_FALSE) { + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } + END_CASE(JSOP_IFEQ) + + BEGIN_CASE(JSOP_IFNE) + POP_BOOLEAN(cx, rval, cond); + if (cond != JS_FALSE) { + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } + END_CASE(JSOP_IFNE) + + BEGIN_CASE(JSOP_OR) + POP_BOOLEAN(cx, rval, cond); + if (cond == JS_TRUE) { + len = GET_JUMP_OFFSET(regs.pc); + PUSH_OPND(rval); + DO_NEXT_OP(len); + } + END_CASE(JSOP_OR) + + BEGIN_CASE(JSOP_AND) + POP_BOOLEAN(cx, rval, cond); + if (cond == JS_FALSE) { + len = GET_JUMP_OFFSET(regs.pc); + PUSH_OPND(rval); + DO_NEXT_OP(len); + } + END_CASE(JSOP_AND) + + BEGIN_CASE(JSOP_DEFAULTX) + (void) POP(); + /* FALL THROUGH */ + BEGIN_CASE(JSOP_GOTOX) + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); + END_CASE(JSOP_GOTOX); + + BEGIN_CASE(JSOP_IFEQX) + POP_BOOLEAN(cx, rval, cond); + if (cond == JS_FALSE) { + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); + } + END_CASE(JSOP_IFEQX) + + BEGIN_CASE(JSOP_IFNEX) + POP_BOOLEAN(cx, rval, cond); + if (cond != JS_FALSE) { + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); + } + END_CASE(JSOP_IFNEX) + + BEGIN_CASE(JSOP_ORX) + POP_BOOLEAN(cx, rval, cond); + if (cond == JS_TRUE) { + len = GET_JUMPX_OFFSET(regs.pc); + PUSH_OPND(rval); + DO_NEXT_OP(len); + } + END_CASE(JSOP_ORX) + + BEGIN_CASE(JSOP_ANDX) + POP_BOOLEAN(cx, rval, cond); + if (cond == JS_FALSE) { + len = GET_JUMPX_OFFSET(regs.pc); + PUSH_OPND(rval); + DO_NEXT_OP(len); + } + END_CASE(JSOP_ANDX) + +/* + * If the index value at sp[n] is not an int that fits in a jsval, it could + * be an object (an XML QName, AttributeName, or AnyName), but only if we are + * compiling with JS_HAS_XML_SUPPORT. Otherwise convert the index value to a + * string atom id. + */ +#define FETCH_ELEMENT_ID(obj, n, id) \ + JS_BEGIN_MACRO \ + jsval idval_ = FETCH_OPND(n); \ + if (JSVAL_IS_INT(idval_)) { \ + id = INT_JSVAL_TO_JSID(idval_); \ + } else { \ + if (!js_InternNonIntElementId(cx, obj, idval_, &id)) \ + goto error; \ + regs.sp[n] = ID_TO_VALUE(id); \ + } \ + JS_END_MACRO + +#define TRY_BRANCH_AFTER_COND(cond,spdec) \ + JS_BEGIN_MACRO \ + uintN diff_; \ + JS_ASSERT(js_CodeSpec[op].length == 1); \ + diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ; \ + if (diff_ <= 1) { \ + regs.sp -= spdec; \ + if (cond == (diff_ != 0)) { \ + ++regs.pc; \ + len = GET_JUMP_OFFSET(regs.pc); \ + BRANCH(len); \ + } \ + len = 1 + JSOP_IFEQ_LENGTH; \ + DO_NEXT_OP(len); \ + } \ + JS_END_MACRO + + BEGIN_CASE(JSOP_IN) + rval = FETCH_OPND(-1); + if (JSVAL_IS_PRIMITIVE(rval)) { + js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rval, NULL); + goto error; + } + obj = JSVAL_TO_OBJECT(rval); + FETCH_ELEMENT_ID(obj, -2, id); + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) + goto error; + cond = prop != NULL; + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + TRY_BRANCH_AFTER_COND(cond, 2); + regs.sp--; + STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); + END_CASE(JSOP_IN) + + BEGIN_CASE(JSOP_ITER) + JS_ASSERT(regs.sp > StackBase(fp)); + flags = regs.pc[1]; + if (!js_ValueToIterator(cx, flags, ®s.sp[-1])) + goto error; + LOAD_INTERRUPT_HANDLER(cx); + JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1])); + PUSH(JSVAL_VOID); + END_CASE(JSOP_ITER) + + BEGIN_CASE(JSOP_NEXTITER) + JS_ASSERT(regs.sp - 2 >= StackBase(fp)); + JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-2])); + if (!js_CallIteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[-2]), ®s.sp[-1])) + goto error; + LOAD_INTERRUPT_HANDLER(cx); + rval = BOOLEAN_TO_JSVAL(regs.sp[-1] != JSVAL_HOLE); + PUSH(rval); + TRACE_0(IteratorNextComplete); + END_CASE(JSOP_NEXTITER) + + BEGIN_CASE(JSOP_ENDITER) + /* + * Decrease the stack pointer even when !ok -- see comments in the + * exception capturing code for details. + */ + JS_ASSERT(regs.sp - 2 >= StackBase(fp)); + ok = js_CloseIterator(cx, regs.sp[-2]); + regs.sp -= 2; + if (!ok) + goto error; + END_CASE(JSOP_ENDITER) + + BEGIN_CASE(JSOP_FORARG) + JS_ASSERT(regs.sp - 2 >= StackBase(fp)); + slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < fp->fun->nargs); + fp->argv[slot] = regs.sp[-1]; + END_CASE(JSOP_FORARG) + + BEGIN_CASE(JSOP_FORLOCAL) + JS_ASSERT(regs.sp - 2 >= StackBase(fp)); + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < fp->script->nslots); + vp = &fp->slots[slot]; + GC_POKE(cx, *vp); + *vp = regs.sp[-1]; + END_CASE(JSOP_FORLOCAL) + + BEGIN_CASE(JSOP_FORNAME) + JS_ASSERT(regs.sp - 2 >= StackBase(fp)); + LOAD_ATOM(0); + id = ATOM_TO_JSID(atom); + if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) + goto error; + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + ok = OBJ_SET_PROPERTY(cx, obj, id, ®s.sp[-1]); + if (!ok) + goto error; + END_CASE(JSOP_FORNAME) + + BEGIN_CASE(JSOP_FORPROP) + JS_ASSERT(regs.sp - 2 >= StackBase(fp)); + LOAD_ATOM(0); + id = ATOM_TO_JSID(atom); + FETCH_OBJECT(cx, -1, lval, obj); + ok = OBJ_SET_PROPERTY(cx, obj, id, ®s.sp[-2]); + if (!ok) + goto error; + regs.sp--; + END_CASE(JSOP_FORPROP) + + BEGIN_CASE(JSOP_FORELEM) + /* + * JSOP_FORELEM simply dups the property identifier at top of stack + * and lets the subsequent JSOP_ENUMELEM opcode sequence handle the + * left-hand side expression evaluation and assignment. This opcode + * exists solely to help the decompiler. + */ + JS_ASSERT(regs.sp - 2 >= StackBase(fp)); + rval = FETCH_OPND(-1); + PUSH(rval); + END_CASE(JSOP_FORELEM) + + BEGIN_CASE(JSOP_DUP) + JS_ASSERT(regs.sp > StackBase(fp)); + rval = FETCH_OPND(-1); + PUSH(rval); + END_CASE(JSOP_DUP) + + BEGIN_CASE(JSOP_DUP2) + JS_ASSERT(regs.sp - 2 >= StackBase(fp)); + lval = FETCH_OPND(-2); + rval = FETCH_OPND(-1); + PUSH(lval); + PUSH(rval); + END_CASE(JSOP_DUP2) + + BEGIN_CASE(JSOP_SWAP) + JS_ASSERT(regs.sp - 2 >= StackBase(fp)); + lval = FETCH_OPND(-2); + rval = FETCH_OPND(-1); + STORE_OPND(-1, lval); + STORE_OPND(-2, rval); + END_CASE(JSOP_SWAP) + +#define PROPERTY_OP(n, call) \ + JS_BEGIN_MACRO \ + /* Fetch the left part and resolve it to a non-null object. */ \ + FETCH_OBJECT(cx, n, lval, obj); \ + \ + /* Get or set the property. */ \ + if (!call) \ + goto error; \ + JS_END_MACRO + +#define ELEMENT_OP(n, call) \ + JS_BEGIN_MACRO \ + /* Fetch the left part and resolve it to a non-null object. */ \ + FETCH_OBJECT(cx, n - 1, lval, obj); \ + \ + /* Fetch index and convert it to id suitable for use with obj. */ \ + FETCH_ELEMENT_ID(obj, n, id); \ + \ + /* Get or set the element. */ \ + if (!call) \ + goto error; \ + JS_END_MACRO + +#define NATIVE_GET(cx,obj,pobj,sprop,vp) \ + JS_BEGIN_MACRO \ + if (SPROP_HAS_STUB_GETTER(sprop)) { \ + /* Fast path for Object instance properties. */ \ + JS_ASSERT((sprop)->slot != SPROP_INVALID_SLOT || \ + !SPROP_HAS_STUB_SETTER(sprop)); \ + *vp = ((sprop)->slot != SPROP_INVALID_SLOT) \ + ? LOCKED_OBJ_GET_SLOT(pobj, (sprop)->slot) \ + : JSVAL_VOID; \ + } else { \ + if (!js_NativeGet(cx, obj, pobj, sprop, vp)) \ + goto error; \ + } \ + JS_END_MACRO + +#define NATIVE_SET(cx,obj,sprop,vp) \ + JS_BEGIN_MACRO \ + if (SPROP_HAS_STUB_SETTER(sprop) && \ + (sprop)->slot != SPROP_INVALID_SLOT) { \ + /* Fast path for, e.g., Object instance properties. */ \ + LOCKED_OBJ_WRITE_BARRIER(cx, obj, (sprop)->slot, *vp); \ + } else { \ + if (!js_NativeSet(cx, obj, sprop, vp)) \ + goto error; \ + } \ + JS_END_MACRO + +/* + * Deadlocks or else bad races are likely if JS_THREADSAFE, so we must rely on + * single-thread DEBUG js shell testing to verify property cache hits. + */ +#if defined DEBUG && !defined JS_THREADSAFE +# define ASSERT_VALID_PROPERTY_CACHE_HIT(pcoff,obj,pobj,entry) \ + do { \ + JSAtom *atom_; \ + JSObject *obj_, *pobj_; \ + JSProperty *prop_; \ + JSScopeProperty *sprop_; \ + uint32 sample_ = rt->gcNumber; \ + if (pcoff >= 0) \ + GET_ATOM_FROM_BYTECODE(script, regs.pc, pcoff, atom_); \ + else \ + atom_ = rt->atomState.lengthAtom; \ + if (JOF_OPMODE(*regs.pc) == JOF_NAME) { \ + ok = js_FindProperty(cx, ATOM_TO_JSID(atom_), &obj_, &pobj_, \ + &prop_); \ + } else { \ + obj_ = obj; \ + ok = js_LookupProperty(cx, obj, ATOM_TO_JSID(atom_), &pobj_, \ + &prop_); \ + } \ + if (!ok) \ + goto error; \ + if (rt->gcNumber != sample_) \ + break; \ + JS_ASSERT(prop_); \ + JS_ASSERT(pobj_ == pobj); \ + sprop_ = (JSScopeProperty *) prop_; \ + if (PCVAL_IS_SLOT(entry->vword)) { \ + JS_ASSERT(PCVAL_TO_SLOT(entry->vword) == sprop_->slot); \ + } else if (PCVAL_IS_SPROP(entry->vword)) { \ + JS_ASSERT(PCVAL_TO_SPROP(entry->vword) == sprop_); \ + } else { \ + jsval v_; \ + JS_ASSERT(PCVAL_IS_OBJECT(entry->vword)); \ + JS_ASSERT(entry->vword != PCVAL_NULL); \ + JS_ASSERT(SCOPE_IS_BRANDED(OBJ_SCOPE(pobj))); \ + JS_ASSERT(SPROP_HAS_STUB_GETTER(sprop_)); \ + JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop_, OBJ_SCOPE(pobj_))); \ + v_ = LOCKED_OBJ_GET_SLOT(pobj_, sprop_->slot); \ + JS_ASSERT(VALUE_IS_FUNCTION(cx, v_)); \ + JS_ASSERT(PCVAL_TO_OBJECT(entry->vword) == JSVAL_TO_OBJECT(v_)); \ + } \ + OBJ_DROP_PROPERTY(cx, pobj_, prop_); \ + } while (0) +#else +# define ASSERT_VALID_PROPERTY_CACHE_HIT(pcoff,obj,pobj,entry) ((void) 0) +#endif + +/* + * Skip the JSOP_POP typically found after a JSOP_SET* opcode, where oplen is + * the constant length of the SET opcode sequence, and spdec is the constant + * by which to decrease the stack pointer to pop all of the SET op's operands. + * + * NB: unlike macros that could conceivably be replaced by functions (ignoring + * goto error), where a call should not have to be braced in order to expand + * correctly (e.g., in if (cond) FOO(); else BAR()), these three macros lack + * JS_{BEGIN,END}_MACRO brackets. They are also indented so as to align with + * nearby opcode code. + */ +#define SKIP_POP_AFTER_SET(oplen,spdec) \ + if (regs.pc[oplen] == JSOP_POP) { \ + regs.sp -= spdec; \ + regs.pc += oplen + JSOP_POP_LENGTH; \ + op = (JSOp) *regs.pc; \ + DO_OP(); \ + } + +#define END_SET_CASE(OP) \ + SKIP_POP_AFTER_SET(OP##_LENGTH, 1); \ + END_CASE(OP) + +#define END_SET_CASE_STORE_RVAL(OP,spdec) \ + SKIP_POP_AFTER_SET(OP##_LENGTH, spdec); \ + rval = FETCH_OPND(-1); \ + regs.sp -= (spdec) - 1; \ + STORE_OPND(-1, rval); \ + END_CASE(OP) + + BEGIN_CASE(JSOP_SETCONST) + LOAD_ATOM(0); + obj = fp->varobj; + rval = FETCH_OPND(-1); + if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval, + JS_PropertyStub, JS_PropertyStub, + JSPROP_ENUMERATE | JSPROP_PERMANENT | + JSPROP_READONLY, + NULL)) { + goto error; + } + END_SET_CASE(JSOP_SETCONST); + +#if JS_HAS_DESTRUCTURING + BEGIN_CASE(JSOP_ENUMCONSTELEM) + rval = FETCH_OPND(-3); + FETCH_OBJECT(cx, -2, lval, obj); + FETCH_ELEMENT_ID(obj, -1, id); + if (!OBJ_DEFINE_PROPERTY(cx, obj, id, rval, + JS_PropertyStub, JS_PropertyStub, + JSPROP_ENUMERATE | JSPROP_PERMANENT | + JSPROP_READONLY, + NULL)) { + goto error; + } + regs.sp -= 3; + END_CASE(JSOP_ENUMCONSTELEM) +#endif + + BEGIN_CASE(JSOP_BINDNAME) + do { + JSPropCacheEntry *entry; + + obj = fp->scopeChain; + if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { + PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + JS_UNLOCK_OBJ(cx, obj2); + break; + } + } else { + entry = NULL; + LOAD_ATOM(0); + } + id = ATOM_TO_JSID(atom); + obj = js_FindIdentifierBase(cx, id, entry); + if (!obj) + goto error; + } while (0); + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_BINDNAME) + + BEGIN_CASE(JSOP_IMACOP) + JS_ASSERT(JS_UPTRDIFF(fp->imacpc, script->code) < script->length); + op = JSOp(*fp->imacpc); + DO_OP(); + +#define BITWISE_OP(OP) \ + JS_BEGIN_MACRO \ + FETCH_INT(cx, -2, i); \ + FETCH_INT(cx, -1, j); \ + i = i OP j; \ + regs.sp--; \ + STORE_INT(cx, -1, i); \ + JS_END_MACRO + + BEGIN_CASE(JSOP_BITOR) + BITWISE_OP(|); + END_CASE(JSOP_BITOR) + + BEGIN_CASE(JSOP_BITXOR) + BITWISE_OP(^); + END_CASE(JSOP_BITXOR) + + BEGIN_CASE(JSOP_BITAND) + BITWISE_OP(&); + END_CASE(JSOP_BITAND) + +#define RELATIONAL_OP(OP) \ + JS_BEGIN_MACRO \ + rval = FETCH_OPND(-1); \ + lval = FETCH_OPND(-2); \ + /* Optimize for two int-tagged operands (typical loop control). */ \ + if ((lval & rval) & JSVAL_INT) { \ + cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval); \ + } else { \ + if (!JSVAL_IS_PRIMITIVE(lval)) \ + DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \ + if (!JSVAL_IS_PRIMITIVE(rval)) \ + DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \ + if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) { \ + str = JSVAL_TO_STRING(lval); \ + str2 = JSVAL_TO_STRING(rval); \ + cond = js_CompareStrings(str, str2) OP 0; \ + } else { \ + VALUE_TO_NUMBER(cx, -2, lval, d); \ + VALUE_TO_NUMBER(cx, -1, rval, d2); \ + cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE); \ + } \ + } \ + TRY_BRANCH_AFTER_COND(cond, 2); \ + regs.sp--; \ + STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \ + JS_END_MACRO + +/* + * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies + * because they begin if/else chains, so callers must not put semicolons after + * the call expressions! + */ +#if JS_HAS_XML_SUPPORT +#define XML_EQUALITY_OP(OP) \ + if ((ltmp == JSVAL_OBJECT && \ + (obj2 = JSVAL_TO_OBJECT(lval)) && \ + OBJECT_IS_XML(cx, obj2)) || \ + (rtmp == JSVAL_OBJECT && \ + (obj2 = JSVAL_TO_OBJECT(rval)) && \ + OBJECT_IS_XML(cx, obj2))) { \ + JSXMLObjectOps *ops; \ + \ + ops = (JSXMLObjectOps *) obj2->map->ops; \ + if (obj2 == JSVAL_TO_OBJECT(rval)) \ + rval = lval; \ + if (!ops->equality(cx, obj2, rval, &cond)) \ + goto error; \ + cond = cond OP JS_TRUE; \ + } else + +#define EXTENDED_EQUALITY_OP(OP) \ + if (ltmp == JSVAL_OBJECT && \ + (obj2 = JSVAL_TO_OBJECT(lval)) && \ + ((clasp = OBJ_GET_CLASS(cx, obj2))->flags & JSCLASS_IS_EXTENDED)) { \ + JSExtendedClass *xclasp; \ + \ + xclasp = (JSExtendedClass *) clasp; \ + if (!xclasp->equality(cx, obj2, rval, &cond)) \ + goto error; \ + cond = cond OP JS_TRUE; \ + } else +#else +#define XML_EQUALITY_OP(OP) /* nothing */ +#define EXTENDED_EQUALITY_OP(OP) /* nothing */ +#endif + +#define EQUALITY_OP(OP, IFNAN) \ + JS_BEGIN_MACRO \ + rval = FETCH_OPND(-1); \ + lval = FETCH_OPND(-2); \ + ltmp = JSVAL_TAG(lval); \ + rtmp = JSVAL_TAG(rval); \ + XML_EQUALITY_OP(OP) \ + if (ltmp == rtmp) { \ + if (ltmp == JSVAL_STRING) { \ + str = JSVAL_TO_STRING(lval); \ + str2 = JSVAL_TO_STRING(rval); \ + cond = js_EqualStrings(str, str2) OP JS_TRUE; \ + } else if (ltmp == JSVAL_DOUBLE) { \ + d = *JSVAL_TO_DOUBLE(lval); \ + d2 = *JSVAL_TO_DOUBLE(rval); \ + cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \ + } else { \ + EXTENDED_EQUALITY_OP(OP) \ + /* Handle all undefined (=>NaN) and int combinations. */ \ + cond = lval OP rval; \ + } \ + } else { \ + if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) { \ + cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1; \ + } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) { \ + cond = 1 OP 0; \ + } else { \ + if (ltmp == JSVAL_OBJECT) { \ + DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); \ + ltmp = JSVAL_TAG(lval); \ + } else if (rtmp == JSVAL_OBJECT) { \ + DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \ + rtmp = JSVAL_TAG(rval); \ + } \ + if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) { \ + str = JSVAL_TO_STRING(lval); \ + str2 = JSVAL_TO_STRING(rval); \ + cond = js_EqualStrings(str, str2) OP JS_TRUE; \ + } else { \ + VALUE_TO_NUMBER(cx, -2, lval, d); \ + VALUE_TO_NUMBER(cx, -1, rval, d2); \ + cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \ + } \ + } \ + } \ + TRY_BRANCH_AFTER_COND(cond, 2); \ + regs.sp--; \ + STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \ + JS_END_MACRO + + BEGIN_CASE(JSOP_EQ) + EQUALITY_OP(==, JS_FALSE); + END_CASE(JSOP_EQ) + + BEGIN_CASE(JSOP_NE) + EQUALITY_OP(!=, JS_TRUE); + END_CASE(JSOP_NE) + +#define STRICT_EQUALITY_OP(OP) \ + JS_BEGIN_MACRO \ + rval = FETCH_OPND(-1); \ + lval = FETCH_OPND(-2); \ + cond = js_StrictlyEqual(cx, lval, rval) OP JS_TRUE; \ + regs.sp--; \ + STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \ + JS_END_MACRO + + BEGIN_CASE(JSOP_STRICTEQ) + STRICT_EQUALITY_OP(==); + END_CASE(JSOP_STRICTEQ) + + BEGIN_CASE(JSOP_STRICTNE) + STRICT_EQUALITY_OP(!=); + END_CASE(JSOP_STRICTNE) + + BEGIN_CASE(JSOP_CASE) + STRICT_EQUALITY_OP(==); + (void) POP(); + if (cond) { + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } + PUSH(lval); + END_CASE(JSOP_CASE) + + BEGIN_CASE(JSOP_CASEX) + STRICT_EQUALITY_OP(==); + (void) POP(); + if (cond) { + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); + } + PUSH(lval); + END_CASE(JSOP_CASEX) + + BEGIN_CASE(JSOP_LT) + RELATIONAL_OP(<); + END_CASE(JSOP_LT) + + BEGIN_CASE(JSOP_LE) + RELATIONAL_OP(<=); + END_CASE(JSOP_LE) + + BEGIN_CASE(JSOP_GT) + RELATIONAL_OP(>); + END_CASE(JSOP_GT) + + BEGIN_CASE(JSOP_GE) + RELATIONAL_OP(>=); + END_CASE(JSOP_GE) + +#undef EQUALITY_OP +#undef RELATIONAL_OP + +#define SIGNED_SHIFT_OP(OP) \ + JS_BEGIN_MACRO \ + FETCH_INT(cx, -2, i); \ + FETCH_INT(cx, -1, j); \ + i = i OP (j & 31); \ + regs.sp--; \ + STORE_INT(cx, -1, i); \ + JS_END_MACRO + + BEGIN_CASE(JSOP_LSH) + SIGNED_SHIFT_OP(<<); + END_CASE(JSOP_LSH) + + BEGIN_CASE(JSOP_RSH) + SIGNED_SHIFT_OP(>>); + END_CASE(JSOP_RSH) + + BEGIN_CASE(JSOP_URSH) + { + uint32 u; + + FETCH_UINT(cx, -2, u); + FETCH_INT(cx, -1, j); + u >>= (j & 31); + regs.sp--; + STORE_UINT(cx, -1, u); + } + END_CASE(JSOP_URSH) + +#undef BITWISE_OP +#undef SIGNED_SHIFT_OP + + BEGIN_CASE(JSOP_ADD) + rval = FETCH_OPND(-1); + lval = FETCH_OPND(-2); +#if JS_HAS_XML_SUPPORT + if (!JSVAL_IS_PRIMITIVE(lval) && + (obj2 = JSVAL_TO_OBJECT(lval), OBJECT_IS_XML(cx, obj2)) && + VALUE_IS_XML(cx, rval)) { + JSXMLObjectOps *ops; + + ops = (JSXMLObjectOps *) obj2->map->ops; + if (!ops->concatenate(cx, obj2, rval, &rval)) + goto error; + regs.sp--; + STORE_OPND(-1, rval); + } else +#endif + { + if (!JSVAL_IS_PRIMITIVE(lval)) + DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); + if (!JSVAL_IS_PRIMITIVE(rval)) + DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); + if ((cond = JSVAL_IS_STRING(lval)) || JSVAL_IS_STRING(rval)) { + if (cond) { + str = JSVAL_TO_STRING(lval); + str2 = js_ValueToString(cx, rval); + if (!str2) + goto error; + regs.sp[-1] = STRING_TO_JSVAL(str2); + } else { + str2 = JSVAL_TO_STRING(rval); + str = js_ValueToString(cx, lval); + if (!str) + goto error; + regs.sp[-2] = STRING_TO_JSVAL(str); + } + str = js_ConcatStrings(cx, str, str2); + if (!str) + goto error; + regs.sp--; + STORE_OPND(-1, STRING_TO_JSVAL(str)); + } else { + VALUE_TO_NUMBER(cx, -2, lval, d); + VALUE_TO_NUMBER(cx, -1, rval, d2); + d += d2; + regs.sp--; + STORE_NUMBER(cx, -1, d); + } + } + END_CASE(JSOP_ADD) + +#define BINARY_OP(OP) \ + JS_BEGIN_MACRO \ + FETCH_NUMBER(cx, -2, d); \ + FETCH_NUMBER(cx, -1, d2); \ + d = d OP d2; \ + regs.sp--; \ + STORE_NUMBER(cx, -1, d); \ + JS_END_MACRO + + BEGIN_CASE(JSOP_SUB) + BINARY_OP(-); + END_CASE(JSOP_SUB) + + BEGIN_CASE(JSOP_MUL) + BINARY_OP(*); + END_CASE(JSOP_MUL) + + BEGIN_CASE(JSOP_DIV) + FETCH_NUMBER(cx, -1, d2); + FETCH_NUMBER(cx, -2, d); + regs.sp--; + if (d2 == 0) { +#ifdef XP_WIN + /* XXX MSVC miscompiles such that (NaN == 0) */ + if (JSDOUBLE_IS_NaN(d2)) + rval = DOUBLE_TO_JSVAL(rt->jsNaN); + else +#endif + if (d == 0 || JSDOUBLE_IS_NaN(d)) + rval = DOUBLE_TO_JSVAL(rt->jsNaN); + else if ((JSDOUBLE_HI32(d) ^ JSDOUBLE_HI32(d2)) >> 31) + rval = DOUBLE_TO_JSVAL(rt->jsNegativeInfinity); + else + rval = DOUBLE_TO_JSVAL(rt->jsPositiveInfinity); + STORE_OPND(-1, rval); + } else { + d /= d2; + STORE_NUMBER(cx, -1, d); + } + END_CASE(JSOP_DIV) + + BEGIN_CASE(JSOP_MOD) + FETCH_NUMBER(cx, -1, d2); + FETCH_NUMBER(cx, -2, d); + regs.sp--; + if (d2 == 0) { + STORE_OPND(-1, DOUBLE_TO_JSVAL(rt->jsNaN)); + } else { +#ifdef XP_WIN + /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */ + if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2))) +#endif + d = fmod(d, d2); + STORE_NUMBER(cx, -1, d); + } + END_CASE(JSOP_MOD) + + BEGIN_CASE(JSOP_NOT) + POP_BOOLEAN(cx, rval, cond); + PUSH_OPND(BOOLEAN_TO_JSVAL(!cond)); + END_CASE(JSOP_NOT) + + BEGIN_CASE(JSOP_BITNOT) + FETCH_INT(cx, -1, i); + i = ~i; + STORE_INT(cx, -1, i); + END_CASE(JSOP_BITNOT) + + BEGIN_CASE(JSOP_NEG) + /* + * When the operand is int jsval, INT_FITS_IN_JSVAL(i) implies + * INT_FITS_IN_JSVAL(-i) unless i is 0 or JSVAL_INT_MIN when the + * results, -0.0 or JSVAL_INT_MAX + 1, are jsdouble values. + */ + rval = FETCH_OPND(-1); + if (JSVAL_IS_INT(rval) && + rval != INT_TO_JSVAL(JSVAL_INT_MIN) && + (i = JSVAL_TO_INT(rval)) != 0) { + JS_STATIC_ASSERT(!INT_FITS_IN_JSVAL(-JSVAL_INT_MIN)); + i = -i; + JS_ASSERT(INT_FITS_IN_JSVAL(i)); + regs.sp[-1] = INT_TO_JSVAL(i); + } else { + if (JSVAL_IS_DOUBLE(rval)) { + d = *JSVAL_TO_DOUBLE(rval); + } else { + d = js_ValueToNumber(cx, ®s.sp[-1]); + if (JSVAL_IS_NULL(regs.sp[-1])) + goto error; + JS_ASSERT(JSVAL_IS_NUMBER(regs.sp[-1]) || + regs.sp[-1] == JSVAL_TRUE); + } +#ifdef HPUX + /* + * Negation of a zero doesn't produce a negative + * zero on HPUX. Perform the operation by bit + * twiddling. + */ + JSDOUBLE_HI32(d) ^= JSDOUBLE_HI32_SIGNBIT; +#else + d = -d; +#endif + if (!js_NewNumberInRootedValue(cx, d, ®s.sp[-1])) + goto error; + } + END_CASE(JSOP_NEG) + + BEGIN_CASE(JSOP_POS) + rval = FETCH_OPND(-1); + if (!JSVAL_IS_NUMBER(rval)) { + d = js_ValueToNumber(cx, ®s.sp[-1]); + rval = regs.sp[-1]; + if (JSVAL_IS_NULL(rval)) + goto error; + if (rval == JSVAL_TRUE) { + if (!js_NewNumberInRootedValue(cx, d, ®s.sp[-1])) + goto error; + } else { + JS_ASSERT(JSVAL_IS_NUMBER(rval)); + } + } + END_CASE(JSOP_POS) + + BEGIN_CASE(JSOP_DELNAME) + LOAD_ATOM(0); + id = ATOM_TO_JSID(atom); + if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) + goto error; + + /* ECMA says to return true if name is undefined or inherited. */ + PUSH_OPND(JSVAL_TRUE); + if (prop) { + OBJ_DROP_PROPERTY(cx, obj2, prop); + if (!OBJ_DELETE_PROPERTY(cx, obj, id, ®s.sp[-1])) + goto error; + } + END_CASE(JSOP_DELNAME) + + BEGIN_CASE(JSOP_DELPROP) + LOAD_ATOM(0); + id = ATOM_TO_JSID(atom); + PROPERTY_OP(-1, OBJ_DELETE_PROPERTY(cx, obj, id, &rval)); + STORE_OPND(-1, rval); + END_CASE(JSOP_DELPROP) + + BEGIN_CASE(JSOP_DELELEM) + ELEMENT_OP(-1, OBJ_DELETE_PROPERTY(cx, obj, id, &rval)); + regs.sp--; + STORE_OPND(-1, rval); + END_CASE(JSOP_DELELEM) + + BEGIN_CASE(JSOP_TYPEOFEXPR) + BEGIN_CASE(JSOP_TYPEOF) + rval = FETCH_OPND(-1); + type = JS_TypeOfValue(cx, rval); + atom = rt->atomState.typeAtoms[type]; + STORE_OPND(-1, ATOM_KEY(atom)); + END_CASE(JSOP_TYPEOF) + + BEGIN_CASE(JSOP_VOID) + STORE_OPND(-1, JSVAL_VOID); + END_CASE(JSOP_VOID) + + BEGIN_CASE(JSOP_INCELEM) + BEGIN_CASE(JSOP_DECELEM) + BEGIN_CASE(JSOP_ELEMINC) + BEGIN_CASE(JSOP_ELEMDEC) + /* + * Delay fetching of id until we have the object to ensure + * the proper evaluation order. See bug 372331. + */ + id = 0; + i = -2; + goto fetch_incop_obj; + + BEGIN_CASE(JSOP_INCPROP) + BEGIN_CASE(JSOP_DECPROP) + BEGIN_CASE(JSOP_PROPINC) + BEGIN_CASE(JSOP_PROPDEC) + LOAD_ATOM(0); + id = ATOM_TO_JSID(atom); + i = -1; + + fetch_incop_obj: + FETCH_OBJECT(cx, i, lval, obj); + if (id == 0) + FETCH_ELEMENT_ID(obj, -1, id); + goto do_incop; + + BEGIN_CASE(JSOP_INCNAME) + BEGIN_CASE(JSOP_DECNAME) + BEGIN_CASE(JSOP_NAMEINC) + BEGIN_CASE(JSOP_NAMEDEC) + { + JSPropCacheEntry *entry; + + obj = fp->scopeChain; + if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { + PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + if (obj == obj2 && PCVAL_IS_SLOT(entry->vword)) { + slot = PCVAL_TO_SLOT(entry->vword); + JS_ASSERT(slot < obj->map->freeslot); + rval = LOCKED_OBJ_GET_SLOT(obj, slot); + if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { + rtmp = rval; + rval += (js_CodeSpec[op].format & JOF_INC) ? 2 : -2; + if (!(js_CodeSpec[op].format & JOF_POST)) + rtmp = rval; + LOCKED_OBJ_SET_SLOT(obj, slot, rval); + JS_UNLOCK_OBJ(cx, obj); + PUSH_OPND(rtmp); + len = JSOP_INCNAME_LENGTH; + DO_NEXT_OP(len); + } + } + JS_UNLOCK_OBJ(cx, obj2); + LOAD_ATOM(0); + } + } else { + entry = NULL; + LOAD_ATOM(0); + } + id = ATOM_TO_JSID(atom); + if (js_FindPropertyHelper(cx, id, &obj, &obj2, &prop, &entry) < 0) + goto error; + if (!prop) + goto atom_not_defined; + OBJ_DROP_PROPERTY(cx, obj2, prop); + } + + do_incop: + { + const JSCodeSpec *cs; + jsval v; + + /* + * We need a root to store the value to leave on the stack until + * we have done with OBJ_SET_PROPERTY. + */ + PUSH_OPND(JSVAL_NULL); + if (!OBJ_GET_PROPERTY(cx, obj, id, ®s.sp[-1])) + goto error; + + cs = &js_CodeSpec[op]; + JS_ASSERT(cs->ndefs == 1); + JS_ASSERT((cs->format & JOF_TMPSLOT_MASK) == JOF_TMPSLOT2); + v = regs.sp[-1]; + if (JS_LIKELY(CAN_DO_FAST_INC_DEC(v))) { + jsval incr; + + incr = (cs->format & JOF_INC) ? 2 : -2; + if (cs->format & JOF_POST) { + regs.sp[-1] = v + incr; + } else { + v += incr; + regs.sp[-1] = v; + } + fp->flags |= JSFRAME_ASSIGNING; + ok = OBJ_SET_PROPERTY(cx, obj, id, ®s.sp[-1]); + fp->flags &= ~JSFRAME_ASSIGNING; + if (!ok) + goto error; + + /* + * We must set regs.sp[-1] to v for both post and pre increments + * as the setter overwrites regs.sp[-1]. + */ + regs.sp[-1] = v; + } else { + /* We need an extra root for the result. */ + PUSH_OPND(JSVAL_NULL); + if (!js_DoIncDec(cx, cs, ®s.sp[-2], ®s.sp[-1])) + goto error; + fp->flags |= JSFRAME_ASSIGNING; + ok = OBJ_SET_PROPERTY(cx, obj, id, ®s.sp[-1]); + fp->flags &= ~JSFRAME_ASSIGNING; + if (!ok) + goto error; + regs.sp--; + } + + if (cs->nuses == 0) { + /* regs.sp[-1] already contains the result of name increment. */ + } else { + rtmp = regs.sp[-1]; + regs.sp -= cs->nuses; + regs.sp[-1] = rtmp; + } + len = cs->length; + DO_NEXT_OP(len); + } + + { + jsval incr, incr2; + + /* Position cases so the most frequent i++ does not need a jump. */ + BEGIN_CASE(JSOP_DECARG) + incr = -2; incr2 = -2; goto do_arg_incop; + BEGIN_CASE(JSOP_ARGDEC) + incr = -2; incr2 = 0; goto do_arg_incop; + BEGIN_CASE(JSOP_INCARG) + incr = 2; incr2 = 2; goto do_arg_incop; + BEGIN_CASE(JSOP_ARGINC) + incr = 2; incr2 = 0; + + do_arg_incop: + slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < fp->fun->nargs); + METER_SLOT_OP(op, slot); + vp = fp->argv + slot; + goto do_int_fast_incop; + + BEGIN_CASE(JSOP_DECLOCAL) + incr = -2; incr2 = -2; goto do_local_incop; + BEGIN_CASE(JSOP_LOCALDEC) + incr = -2; incr2 = 0; goto do_local_incop; + BEGIN_CASE(JSOP_INCLOCAL) + incr = 2; incr2 = 2; goto do_local_incop; + BEGIN_CASE(JSOP_LOCALINC) + incr = 2; incr2 = 0; + + /* + * do_local_incop comes right before do_int_fast_incop as we want to + * avoid an extra jump for variable cases as local++ is more frequent + * than arg++. + */ + do_local_incop: + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < fp->script->nslots); + vp = fp->slots + slot; + METER_SLOT_OP(op, slot); + vp = fp->slots + slot; + + do_int_fast_incop: + rval = *vp; + if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { + *vp = rval + incr; + JS_ASSERT(JSOP_INCARG_LENGTH == js_CodeSpec[op].length); + SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH, 0); + PUSH_OPND(rval + incr2); + } else { + PUSH_OPND(rval); + if (!js_DoIncDec(cx, &js_CodeSpec[op], ®s.sp[-1], vp)) + goto error; + } + len = JSOP_INCARG_LENGTH; + JS_ASSERT(len == js_CodeSpec[op].length); + DO_NEXT_OP(len); + } + +/* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */ +#define FAST_GLOBAL_INCREMENT_OP(SLOWOP,INCR,INCR2) \ + op2 = SLOWOP; \ + incr = INCR; \ + incr2 = INCR2; \ + goto do_global_incop + + { + jsval incr, incr2; + + BEGIN_CASE(JSOP_DECGVAR) + FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME, -2, -2); + BEGIN_CASE(JSOP_GVARDEC) + FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC, -2, 0); + BEGIN_CASE(JSOP_INCGVAR) + FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME, 2, 2); + BEGIN_CASE(JSOP_GVARINC) + FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC, 2, 0); + +#undef FAST_GLOBAL_INCREMENT_OP + + do_global_incop: + JS_ASSERT((js_CodeSpec[op].format & JOF_TMPSLOT_MASK) == + JOF_TMPSLOT2); + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < GlobalVarCount(fp)); + METER_SLOT_OP(op, slot); + lval = fp->slots[slot]; + if (JSVAL_IS_NULL(lval)) { + op = op2; + DO_OP(); + } + slot = JSVAL_TO_INT(lval); + rval = OBJ_GET_SLOT(cx, fp->varobj, slot); + if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { + PUSH_OPND(rval + incr2); + rval += incr; + } else { + PUSH_OPND(rval); + PUSH_OPND(JSVAL_NULL); /* Extra root */ + if (!js_DoIncDec(cx, &js_CodeSpec[op], ®s.sp[-2], ®s.sp[-1])) + goto error; + rval = regs.sp[-1]; + --regs.sp; + } + OBJ_SET_SLOT(cx, fp->varobj, slot, rval); + len = JSOP_INCGVAR_LENGTH; /* all gvar incops are same length */ + JS_ASSERT(len == js_CodeSpec[op].length); + DO_NEXT_OP(len); + } + +#define COMPUTE_THIS(cx, fp, obj) \ + JS_BEGIN_MACRO \ + if (fp->flags & JSFRAME_COMPUTED_THIS) { \ + obj = fp->thisp; \ + } else { \ + obj = js_ComputeThis(cx, JS_TRUE, fp->argv); \ + if (!obj) \ + goto error; \ + fp->thisp = obj; \ + fp->flags |= JSFRAME_COMPUTED_THIS; \ + } \ + JS_END_MACRO + + BEGIN_CASE(JSOP_THIS) + COMPUTE_THIS(cx, fp, obj); + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_THIS) + + BEGIN_CASE(JSOP_GETTHISPROP) + i = 0; + COMPUTE_THIS(cx, fp, obj); + PUSH(JSVAL_NULL); + goto do_getprop_with_obj; + +#undef COMPUTE_THIS + + BEGIN_CASE(JSOP_GETARGPROP) + i = ARGNO_LEN; + slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < fp->fun->nargs); + PUSH_OPND(fp->argv[slot]); + goto do_getprop_body; + + BEGIN_CASE(JSOP_GETLOCALPROP) + i = SLOTNO_LEN; + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + PUSH_OPND(fp->slots[slot]); + goto do_getprop_body; + + BEGIN_CASE(JSOP_GETPROP) + BEGIN_CASE(JSOP_GETXPROP) + i = 0; + + do_getprop_body: + lval = FETCH_OPND(-1); + + do_getprop_with_lval: + VALUE_TO_OBJECT(cx, -1, lval, obj); + + do_getprop_with_obj: + do { + JSObject *aobj; + JSPropCacheEntry *entry; + + aobj = OBJ_IS_DENSE_ARRAY(cx, obj) ? OBJ_GET_PROTO(cx, obj) : obj; + if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) { + PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry); + if (PCVAL_IS_OBJECT(entry->vword)) { + rval = PCVAL_OBJECT_TO_JSVAL(entry->vword); + } else if (PCVAL_IS_SLOT(entry->vword)) { + slot = PCVAL_TO_SLOT(entry->vword); + JS_ASSERT(slot < obj2->map->freeslot); + rval = LOCKED_OBJ_GET_SLOT(obj2, slot); + } else { + JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); + sprop = PCVAL_TO_SPROP(entry->vword); + NATIVE_GET(cx, obj, obj2, sprop, &rval); + } + JS_UNLOCK_OBJ(cx, obj2); + break; + } + } else { + entry = NULL; + if (i < 0) + atom = rt->atomState.lengthAtom; + else + LOAD_ATOM(i); + } + id = ATOM_TO_JSID(atom); + if (entry + ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry) + : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) { + goto error; + } + } while (0); + + STORE_OPND(-1, rval); + JS_ASSERT(JSOP_GETPROP_LENGTH + i == js_CodeSpec[op].length); + len = JSOP_GETPROP_LENGTH + i; + END_VARLEN_CASE + + BEGIN_CASE(JSOP_LENGTH) + lval = FETCH_OPND(-1); + if (JSVAL_IS_STRING(lval)) { + str = JSVAL_TO_STRING(lval); + regs.sp[-1] = INT_TO_JSVAL(JSSTRING_LENGTH(str)); + } else if (!JSVAL_IS_PRIMITIVE(lval) && + (obj = JSVAL_TO_OBJECT(lval), OBJ_IS_ARRAY(cx, obj))) { + jsuint length; + + /* + * We know that the array is created with only its 'length' + * private data in a fixed slot at JSSLOT_ARRAY_LENGTH. See + * also JSOP_ARRAYPUSH, far below. + */ + length = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (length <= JSVAL_INT_MAX) { + regs.sp[-1] = INT_TO_JSVAL(length); + } else if (!js_NewDoubleInRootedValue(cx, (jsdouble) length, + ®s.sp[-1])) { + goto error; + } + } else { + i = -2; + goto do_getprop_with_lval; + } + END_CASE(JSOP_LENGTH) + + BEGIN_CASE(JSOP_CALLPROP) + { + JSObject *aobj; + JSPropCacheEntry *entry; + + lval = FETCH_OPND(-1); + if (!JSVAL_IS_PRIMITIVE(lval)) { + obj = JSVAL_TO_OBJECT(lval); + } else { + if (JSVAL_IS_STRING(lval)) { + i = JSProto_String; + } else if (JSVAL_IS_NUMBER(lval)) { + i = JSProto_Number; + } else if (JSVAL_IS_BOOLEAN(lval)) { + i = JSProto_Boolean; + } else { + JS_ASSERT(JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)); + js_ReportIsNullOrUndefined(cx, -1, lval, NULL); + goto error; + } + + if (!js_GetClassPrototype(cx, NULL, INT_TO_JSID(i), &obj)) + goto error; + } + + aobj = OBJ_IS_DENSE_ARRAY(cx, obj) ? OBJ_GET_PROTO(cx, obj) : obj; + if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) { + PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry); + if (PCVAL_IS_OBJECT(entry->vword)) { + rval = PCVAL_OBJECT_TO_JSVAL(entry->vword); + } else if (PCVAL_IS_SLOT(entry->vword)) { + slot = PCVAL_TO_SLOT(entry->vword); + JS_ASSERT(slot < obj2->map->freeslot); + rval = LOCKED_OBJ_GET_SLOT(obj2, slot); + } else { + JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); + sprop = PCVAL_TO_SPROP(entry->vword); + NATIVE_GET(cx, obj, obj2, sprop, &rval); + } + JS_UNLOCK_OBJ(cx, obj2); + STORE_OPND(-1, rval); + PUSH_OPND(lval); + goto end_callprop; + } + } else { + entry = NULL; + LOAD_ATOM(0); + } + + /* + * Cache miss: use the immediate atom that was loaded for us under + * PROPERTY_CACHE_TEST. + */ + id = ATOM_TO_JSID(atom); + PUSH(JSVAL_NULL); + if (!JSVAL_IS_PRIMITIVE(lval)) { +#if JS_HAS_XML_SUPPORT + /* Special-case XML object method lookup, per ECMA-357. */ + if (OBJECT_IS_XML(cx, obj)) { + JSXMLObjectOps *ops; + + ops = (JSXMLObjectOps *) obj->map->ops; + obj = ops->getMethod(cx, obj, id, &rval); + if (!obj) + goto error; + } else +#endif + if (entry + ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry) + : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) { + goto error; + } + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + STORE_OPND(-2, rval); + } else { + JS_ASSERT(obj->map->ops->getProperty == js_GetProperty); + if (!js_GetPropertyHelper(cx, obj, id, &rval, &entry)) + goto error; + STORE_OPND(-1, lval); + STORE_OPND(-2, rval); + } + + end_callprop: + /* Wrap primitive lval in object clothing if necessary. */ + if (JSVAL_IS_PRIMITIVE(lval)) { + /* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=412571 */ + if (!VALUE_IS_FUNCTION(cx, rval) || + (obj = JSVAL_TO_OBJECT(rval), + fun = GET_FUNCTION_PRIVATE(cx, obj), + !PRIMITIVE_THIS_TEST(fun, lval))) { + if (!js_PrimitiveToObject(cx, ®s.sp[-1])) + goto error; + } + } +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) { + LOAD_ATOM(0); + regs.sp[-2] = ATOM_KEY(atom); + if (!js_OnUnknownMethod(cx, regs.sp - 2)) + goto error; + } +#endif + } + END_CASE(JSOP_CALLPROP) + + BEGIN_CASE(JSOP_SETNAME) + BEGIN_CASE(JSOP_SETPROP) + rval = FETCH_OPND(-1); + lval = FETCH_OPND(-2); + JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval) || op == JSOP_SETPROP); + VALUE_TO_OBJECT(cx, -2, lval, obj); + + do { + JSPropCacheEntry *entry; + + entry = NULL; + atom = NULL; + if (JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) { + JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx); + uint32 kshape = OBJ_SHAPE(obj); + + /* + * Open-code JS_PROPERTY_CACHE_TEST, specializing for two + * important set-property cases. First: + * + * function f(a, b, c) { + * var o = {p:a, q:b, r:c}; + * return o; + * } + * + * or similar real-world cases, which evolve a newborn + * native object predicatably through some bounded number + * of property additions. And second: + * + * o.p = x; + * + * in a frequently executed method or loop body, where p + * will (possibly after the first iteration) always exist + * in native object o. + */ + entry = &cache->table[PROPERTY_CACHE_HASH_PC(regs.pc, kshape)]; + PCMETER(cache->tests++); + PCMETER(cache->settests++); + if (entry->kpc == regs.pc && entry->kshape == kshape) { + JSScope *scope; + + JS_LOCK_OBJ(cx, obj); + scope = OBJ_SCOPE(obj); + if (scope->shape == kshape) { + JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); + sprop = PCVAL_TO_SPROP(entry->vword); + JS_ASSERT(!(sprop->attrs & JSPROP_READONLY)); + JS_ASSERT(!SCOPE_IS_SEALED(OBJ_SCOPE(obj))); + + if (scope->object == obj) { + /* + * Fastest path: the cached sprop is already + * in scope. Just NATIVE_SET and break to get + * out of the do-while(0). + */ + if (sprop == scope->lastProp || + SCOPE_HAS_PROPERTY(scope, sprop)) { + PCMETER(cache->pchits++); + PCMETER(cache->setpchits++); + NATIVE_SET(cx, obj, sprop, &rval); + JS_UNLOCK_SCOPE(cx, scope); + TRACE_2(SetPropHit, entry, sprop); + break; + } + } else { + scope = js_GetMutableScope(cx, obj); + if (!scope) { + JS_UNLOCK_OBJ(cx, obj); + goto error; + } + } + + if (sprop->parent == scope->lastProp && + !SCOPE_HAD_MIDDLE_DELETE(scope) && + SPROP_HAS_STUB_SETTER(sprop) && + (slot = sprop->slot) == scope->map.freeslot) { + /* + * Fast path: adding a plain old property that + * was once at the frontier of the property + * tree, whose slot is next to claim among the + * allocated slots in obj, where scope->table + * has not been created yet. + * + * We may want to remove hazard conditions + * above and inline compensation code here, + * depending on real-world workloads. + */ + JS_ASSERT(!(LOCKED_OBJ_GET_CLASS(obj)->flags & + JSCLASS_SHARE_ALL_PROPERTIES)); + + PCMETER(cache->pchits++); + PCMETER(cache->addpchits++); + + /* + * Beware classes such as Function that use + * the reserveSlots hook to allocate a number + * of reserved slots that may vary with obj. + */ + if (slot < STOBJ_NSLOTS(obj) && + !OBJ_GET_CLASS(cx, obj)->reserveSlots) { + ++scope->map.freeslot; + } else { + if (!js_AllocSlot(cx, obj, &slot)) { + JS_UNLOCK_SCOPE(cx, scope); + goto error; + } + } + + /* + * If this obj's number of reserved slots + * differed, or if something created a hash + * table for scope, we must pay the price of + * js_AddScopeProperty. + * + * If slot does not match the cached sprop's + * slot, update the cache entry in the hope + * that obj and other instances with the same + * number of reserved slots are now "hot". + */ + if (slot != sprop->slot || scope->table) { + JSScopeProperty *sprop2 = + js_AddScopeProperty(cx, scope, + sprop->id, + sprop->getter, + sprop->setter, + slot, + sprop->attrs, + sprop->flags, + sprop->shortid); + if (!sprop2) { + js_FreeSlot(cx, obj, slot); + JS_UNLOCK_SCOPE(cx, scope); + goto error; + } + if (sprop2 != sprop) { + PCMETER(cache->slotchanges++); + JS_ASSERT(slot != sprop->slot && + slot == sprop2->slot && + sprop2->id == sprop->id); + entry->vword = SPROP_TO_PCVAL(sprop2); + } + sprop = sprop2; + } else { + SCOPE_EXTEND_SHAPE(cx, scope, sprop); + ++scope->entryCount; + scope->lastProp = sprop; + } + + GC_WRITE_BARRIER(cx, scope, + LOCKED_OBJ_GET_SLOT(obj, slot), + rval); + LOCKED_OBJ_SET_SLOT(obj, slot, rval); + JS_UNLOCK_SCOPE(cx, scope); + TRACE_2(SetPropHit, entry, sprop); + break; + } + + PCMETER(cache->setpcmisses++); + atom = NULL; + } + + JS_UNLOCK_OBJ(cx, obj); + } + + atom = js_FullTestPropertyCache(cx, regs.pc, &obj, &obj2, + &entry); + if (atom) { + PCMETER(cache->misses++); + PCMETER(cache->setmisses++); + } else { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + sprop = NULL; + if (obj == obj2) { + JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); + sprop = PCVAL_TO_SPROP(entry->vword); + JS_ASSERT(!(sprop->attrs & JSPROP_READONLY)); + JS_ASSERT(!SCOPE_IS_SEALED(OBJ_SCOPE(obj2))); + NATIVE_SET(cx, obj, sprop, &rval); + } + JS_UNLOCK_OBJ(cx, obj2); + if (sprop) { + TRACE_2(SetPropHit, entry, sprop); + break; + } + } + } + + if (!atom) + LOAD_ATOM(0); + id = ATOM_TO_JSID(atom); + if (entry) { + if (!js_SetPropertyHelper(cx, obj, id, &rval, &entry)) + goto error; +#ifdef JS_TRACER + if (entry) + TRACE_1(SetPropMiss, entry); +#endif + } else { + if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) + goto error; + } +#ifdef JS_TRACER + if (!entry && TRACE_RECORDER(cx)) { + js_AbortRecording(cx, "SetPropUncached"); + ENABLE_TRACER(0); + } +#endif + } while (0); + END_SET_CASE_STORE_RVAL(JSOP_SETPROP, 2); + + BEGIN_CASE(JSOP_GETELEM) + /* Open-coded ELEMENT_OP optimized for strings and dense arrays. */ + lval = FETCH_OPND(-2); + rval = FETCH_OPND(-1); + if (JSVAL_IS_STRING(lval) && JSVAL_IS_INT(rval)) { + str = JSVAL_TO_STRING(lval); + i = JSVAL_TO_INT(rval); + if ((size_t)i < JSSTRING_LENGTH(str)) { + str = js_GetUnitString(cx, str, (size_t)i); + if (!str) + goto error; + rval = STRING_TO_JSVAL(str); + goto end_getelem; + } + } + + VALUE_TO_OBJECT(cx, -2, lval, obj); + if (JSVAL_IS_INT(rval)) { + if (OBJ_IS_DENSE_ARRAY(cx, obj)) { + jsuint length; + + length = ARRAY_DENSE_LENGTH(obj); + i = JSVAL_TO_INT(rval); + if ((jsuint)i < length && + i < obj->fslots[JSSLOT_ARRAY_LENGTH]) { + rval = obj->dslots[i]; + if (rval != JSVAL_HOLE) + goto end_getelem; + + /* Reload rval from the stack in the rare hole case. */ + rval = FETCH_OPND(-1); + } + } + id = INT_JSVAL_TO_JSID(rval); + } else { + if (!js_InternNonIntElementId(cx, obj, rval, &id)) + goto error; + } + + if (!OBJ_GET_PROPERTY(cx, obj, id, &rval)) + goto error; + end_getelem: + regs.sp--; + STORE_OPND(-1, rval); + END_CASE(JSOP_GETELEM) + + BEGIN_CASE(JSOP_CALLELEM) + /* + * FIXME: JSOP_CALLELEM should call getMethod on XML objects as + * CALLPROP does. See bug 362910. + */ + ELEMENT_OP(-1, OBJ_GET_PROPERTY(cx, obj, id, &rval)); +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) { + regs.sp[-2] = regs.sp[-1]; + regs.sp[-1] = OBJECT_TO_JSVAL(obj); + if (!js_OnUnknownMethod(cx, regs.sp - 2)) + goto error; + } else +#endif + { + STORE_OPND(-2, rval); + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + } + END_CASE(JSOP_CALLELEM) + + BEGIN_CASE(JSOP_SETELEM) + rval = FETCH_OPND(-1); + FETCH_OBJECT(cx, -3, lval, obj); + FETCH_ELEMENT_ID(obj, -2, id); + do { + if (OBJ_IS_DENSE_ARRAY(cx, obj) && JSID_IS_INT(id)) { + jsuint length; + + length = ARRAY_DENSE_LENGTH(obj); + i = JSID_TO_INT(id); + if ((jsuint)i < length) { + if (obj->dslots[i] == JSVAL_HOLE) { + if (rt->anyArrayProtoHasElement) + break; + if (i >= obj->fslots[JSSLOT_ARRAY_LENGTH]) + obj->fslots[JSSLOT_ARRAY_LENGTH] = i + 1; + obj->fslots[JSSLOT_ARRAY_COUNT]++; + } + obj->dslots[i] = rval; + goto end_setelem; + } + } + } while (0); + if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) + goto error; + end_setelem: + END_SET_CASE_STORE_RVAL(JSOP_SETELEM, 3) + + BEGIN_CASE(JSOP_ENUMELEM) + /* Funky: the value to set is under the [obj, id] pair. */ + rval = FETCH_OPND(-3); + FETCH_OBJECT(cx, -2, lval, obj); + FETCH_ELEMENT_ID(obj, -1, id); + if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) + goto error; + regs.sp -= 3; + END_CASE(JSOP_ENUMELEM) + + BEGIN_CASE(JSOP_NEW) + /* Get immediate argc and find the constructor function. */ + argc = GET_ARGC(regs.pc); + vp = regs.sp - (2 + argc); + JS_ASSERT(vp >= StackBase(fp)); + + /* + * Assign lval, obj, and fun exactly as the code at inline_call: + * expects to find them, to avoid nesting a js_Interpret call via + * js_InvokeConstructor. + */ + lval = *vp; + if (VALUE_IS_FUNCTION(cx, lval)) { + obj = JSVAL_TO_OBJECT(lval); + fun = GET_FUNCTION_PRIVATE(cx, obj); + if (FUN_INTERPRETED(fun)) { + /* Root as we go using vp[1]. */ + if (!OBJ_GET_PROPERTY(cx, obj, + ATOM_TO_JSID(cx->runtime->atomState + .classPrototypeAtom), + &vp[1])) { + goto error; + } + rval = vp[1]; + obj2 = js_NewObject(cx, &js_ObjectClass, + JSVAL_IS_OBJECT(rval) + ? JSVAL_TO_OBJECT(rval) + : NULL, + OBJ_GET_PARENT(cx, obj), + 0); + if (!obj2) + goto error; + vp[1] = OBJECT_TO_JSVAL(obj2); + flags = JSFRAME_CONSTRUCTING; + goto inline_call; + } + } + + if (!js_InvokeConstructor(cx, argc, JS_FALSE, vp)) + goto error; + regs.sp = vp + 1; + LOAD_INTERRUPT_HANDLER(cx); + END_CASE(JSOP_NEW) + + BEGIN_CASE(JSOP_APPLY) + { + argc = GET_ARGC(regs.pc); + vp = regs.sp - (argc + 2); + lval = *vp; + if (!VALUE_IS_FUNCTION(cx, lval)) + goto do_call; + obj = JSVAL_TO_OBJECT(lval); + fun = GET_FUNCTION_PRIVATE(cx, obj); + if (FUN_INTERPRETED(fun)) + goto do_call; + + bool apply = (JSFastNative)fun->u.n.native == js_fun_apply; + if (!apply && (JSFastNative)fun->u.n.native != js_fun_call) + goto do_call; + + /* + * If the second arg to apply is null or void, treat it as an empty + * array. + */ + jsuint applylen = 0; + if (apply && argc >= 2 && + !JSVAL_IS_VOID(vp[3]) && !JSVAL_IS_NULL(vp[3])) { + /* + * Fall back on js_Invoke when the array argument has a wrong + * type or when it has too many elements to fit into the + * current stack chunk. + */ + if (!JSVAL_IS_OBJECT(vp[3])) + goto do_call; + + JSBool arraylike; + JSObject* aobj = JSVAL_TO_OBJECT(vp[3]); + if (!js_IsArrayLike(cx, aobj, &arraylike, &applylen)) + goto error; + if (!arraylike || applylen > ARGC_LIMIT) + goto do_call; + + JSArena *a = cx->stackPool.current; + JS_ASSERT(jsuword(vp + 2) <= a->limit); + + /* + * We need space for applylen elements plus an extra slot to + * temporary root the array object when we unpack its elements + * using OBJ_GET_PROPERTY below. + */ + if (a->limit - jsuword(vp + 2) < (applylen + 1) * sizeof(jsval)) + goto do_call; + } + + if (!VALUE_IS_FUNCTION(cx, vp[1])) + goto do_call; + vp[0] = vp[1]; + + if (argc == 0) { + /* + * Call fun with its global object as the 'this' param if + * no args. + */ + obj = NULL; + } else { + /* Convert the first arg to 'this'. */ + if (!JSVAL_IS_PRIMITIVE(vp[2])) + obj = JSVAL_TO_OBJECT(vp[2]); + else if (!js_ValueToObject(cx, vp[2], &obj)) + goto error; + } + vp[1] = OBJECT_TO_JSVAL(obj); + + if (!apply) { + if (argc != 0) { + --argc; + memmove(vp + 2, vp + 3, argc * sizeof *vp); + } + } else if (applylen == 0) { + argc = 0; + } else { + /* + * Make room for missing arguments to the right including the + * temporary root nulling any extra stack slots for GC safety. + */ + jsval* newsp = vp + 2 + applylen + 1; + if (newsp > regs.sp) { + JSArena *a = cx->stackPool.current; + JS_ASSERT(jsuword(newsp) <= a->limit); /* see above */ + if ((jsuword) newsp > a->avail) + a->avail = (jsuword) newsp; + memset(vp + 2 + argc, 0, (applylen - argc) * sizeof(jsval)); + } + + JSObject *aobj = JSVAL_TO_OBJECT(vp[3]); + newsp[-1] = vp[3]; + regs.sp = newsp; + + /* Expand array content onto the stack. */ + for (i = 0; i < jsint(applylen); i++) { + id = INT_TO_JSID(i); + if (!OBJ_GET_PROPERTY(cx, aobj, id, &vp[2 + i])) { + /* + * There is no good way to restore the original stack + * state here, but it is in a reasonable state with + * either original elements or nulls for all arguments + * we didn't unpack yet, so we leave it at that. + */ + goto error; + } + } + argc = applylen; + } + regs.sp = vp + 2 + argc; + goto do_call_with_specified_vp_and_argc; + } + + BEGIN_CASE(JSOP_CALL) + BEGIN_CASE(JSOP_EVAL) + do_call: + argc = GET_ARGC(regs.pc); + vp = regs.sp - (argc + 2); + + do_call_with_specified_vp_and_argc: + lval = *vp; + if (VALUE_IS_FUNCTION(cx, lval)) { + obj = JSVAL_TO_OBJECT(lval); + fun = GET_FUNCTION_PRIVATE(cx, obj); + + /* Clear frame flags since this is not a constructor call. */ + flags = 0; + if (FUN_INTERPRETED(fun)) + inline_call: + { + uintN nframeslots, nvars, missing; + JSArena *a; + jsuword nbytes; + void *newmark; + jsval *newsp; + JSInlineFrame *newifp; + JSInterpreterHook hook; + + /* Restrict recursion of lightweight functions. */ + if (inlineCallCount == MAX_INLINE_CALL_COUNT) { + js_ReportOverRecursed(cx); + goto error; + } + + /* Compute the total number of stack slots needed by fun. */ + nframeslots = JS_HOWMANY(sizeof(JSInlineFrame), + sizeof(jsval)); + script = fun->u.i.script; + atoms = script->atomMap.vector; + nbytes = (nframeslots + script->nslots) * sizeof(jsval); + + /* Allocate missing expected args adjacent to actuals. */ + a = cx->stackPool.current; + newmark = (void *) a->avail; + if (fun->nargs <= argc) { + missing = 0; + } else { + newsp = vp + 2 + fun->nargs; + JS_ASSERT(newsp > regs.sp); + if ((jsuword) newsp <= a->limit) { + if ((jsuword) newsp > a->avail) + a->avail = (jsuword) newsp; + jsval *argsp = newsp; + do { + *--argsp = JSVAL_VOID; + } while (argsp != regs.sp); + missing = 0; + } else { + missing = fun->nargs - argc; + nbytes += (2 + fun->nargs) * sizeof(jsval); + } + } + + /* Allocate the inline frame with its slots and operands. */ + if (a->avail + nbytes <= a->limit) { + newsp = (jsval *) a->avail; + a->avail += nbytes; + JS_ASSERT(missing == 0); + } else { + JS_ARENA_ALLOCATE_CAST(newsp, jsval *, &cx->stackPool, + nbytes); + if (!newsp) { + js_ReportOutOfScriptQuota(cx); + goto bad_inline_call; + } + + /* + * Move args if the missing ones overflow arena a, then + * push undefined for the missing args. + */ + if (missing) { + memcpy(newsp, vp, (2 + argc) * sizeof(jsval)); + vp = newsp; + newsp = vp + 2 + argc; + do { + *newsp++ = JSVAL_VOID; + } while (--missing != 0); + } + } + + /* Claim space for the stack frame and initialize it. */ + newifp = (JSInlineFrame *) newsp; + newsp += nframeslots; + newifp->frame.callobj = NULL; + newifp->frame.argsobj = NULL; + newifp->frame.varobj = NULL; + newifp->frame.script = script; + newifp->frame.callee = obj; + newifp->frame.fun = fun; + newifp->frame.argc = argc; + newifp->frame.argv = vp + 2; + newifp->frame.rval = JSVAL_VOID; + newifp->frame.down = fp; + newifp->frame.annotation = NULL; + newifp->frame.scopeChain = parent = OBJ_GET_PARENT(cx, obj); + newifp->frame.sharpDepth = 0; + newifp->frame.sharpArray = NULL; + newifp->frame.flags = flags; + newifp->frame.dormantNext = NULL; + newifp->frame.xmlNamespace = NULL; + newifp->frame.blockChain = NULL; + if (script->staticDepth < JS_DISPLAY_SIZE) { + JSStackFrame **disp = &cx->display[script->staticDepth]; + newifp->frame.displaySave = *disp; + *disp = &newifp->frame; + } +#ifdef DEBUG + newifp->frame.pcDisabledSave = + JS_PROPERTY_CACHE(cx).disabled; +#endif + newifp->mark = newmark; + + /* Compute the 'this' parameter now that argv is set. */ + JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags)); + JS_ASSERT(JSVAL_IS_OBJECT(vp[1])); + newifp->frame.thisp = (JSObject *)vp[1]; + + newifp->frame.regs = NULL; + newifp->frame.imacpc = NULL; + newifp->frame.slots = newsp; + + /* Push void to initialize local variables. */ + nvars = fun->u.i.nvars; + while (nvars--) + *newsp++ = JSVAL_VOID; + + /* Call the debugger hook if present. */ + hook = cx->debugHooks->callHook; + if (hook) { + newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0, + cx->debugHooks->callHookData); + LOAD_INTERRUPT_HANDLER(cx); + } else { + newifp->hookData = NULL; + } + + /* Scope with a call object parented by callee's parent. */ + if (JSFUN_HEAVYWEIGHT_TEST(fun->flags) && + !js_GetCallObject(cx, &newifp->frame, parent)) { + goto bad_inline_call; + } + + /* Switch version if currentVersion wasn't overridden. */ + newifp->callerVersion = (JSVersion) cx->version; + if (JS_LIKELY(cx->version == currentVersion)) { + currentVersion = (JSVersion) script->version; + if (currentVersion != cx->version) + js_SetVersion(cx, currentVersion); + } + + /* Push the frame and set interpreter registers. */ + newifp->callerRegs = regs; + fp->regs = &newifp->callerRegs; + regs.sp = newsp; + regs.pc = script->code; + newifp->frame.regs = ®s; + cx->fp = fp = &newifp->frame; + + TRACE_0(EnterFrame); + + inlineCallCount++; + JS_RUNTIME_METER(rt, inlineCalls); + +#ifdef INCLUDE_MOZILLA_DTRACE + /* DTrace function entry, inlines */ + if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED()) + jsdtrace_function_entry(cx, fp, fun); + if (JAVASCRIPT_FUNCTION_INFO_ENABLED()) + jsdtrace_function_info(cx, fp, fp->down, fun); + if (JAVASCRIPT_FUNCTION_ARGS_ENABLED()) + jsdtrace_function_args(cx, fp, fun); +#endif + + /* Load first op and dispatch it (safe since JSOP_STOP). */ + op = (JSOp) *regs.pc; + DO_OP(); + + bad_inline_call: + JS_ASSERT(fp->regs == ®s); + script = fp->script; + atoms = script->atomMap.vector; + js_FreeRawStack(cx, newmark); + goto error; + } + +#ifdef INCLUDE_MOZILLA_DTRACE + /* DTrace function entry, non-inlines */ + if (VALUE_IS_FUNCTION(cx, lval)) { + if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED()) + jsdtrace_function_entry(cx, fp, fun); + if (JAVASCRIPT_FUNCTION_INFO_ENABLED()) + jsdtrace_function_info(cx, fp, fp, fun); + if (JAVASCRIPT_FUNCTION_ARGS_ENABLED()) + jsdtrace_function_args(cx, fp, fun); + } +#endif + + if (fun->flags & JSFUN_FAST_NATIVE) { + JS_ASSERT(fun->u.n.extra == 0); + JS_ASSERT(JSVAL_IS_OBJECT(vp[1]) || + PRIMITIVE_THIS_TEST(fun, vp[1])); + ok = ((JSFastNative) fun->u.n.native)(cx, argc, vp); +#ifdef INCLUDE_MOZILLA_DTRACE + if (VALUE_IS_FUNCTION(cx, lval)) { + if (JAVASCRIPT_FUNCTION_RVAL_ENABLED()) + jsdtrace_function_rval(cx, fp, fun); + if (JAVASCRIPT_FUNCTION_RETURN_ENABLED()) + jsdtrace_function_return(cx, fp, fun); + } +#endif + regs.sp = vp + 1; + if (!ok) + goto error; + TRACE_0(FastNativeCallComplete); + goto end_call; + } + } + + ok = js_Invoke(cx, argc, vp, 0); +#ifdef INCLUDE_MOZILLA_DTRACE + /* DTrace function return, non-inlines */ + if (VALUE_IS_FUNCTION(cx, lval)) { + if (JAVASCRIPT_FUNCTION_RVAL_ENABLED()) + jsdtrace_function_rval(cx, fp, fun); + if (JAVASCRIPT_FUNCTION_RETURN_ENABLED()) + jsdtrace_function_return(cx, fp, fun); + } +#endif + regs.sp = vp + 1; + LOAD_INTERRUPT_HANDLER(cx); + if (!ok) + goto error; + JS_RUNTIME_METER(rt, nonInlineCalls); + + end_call: +#if JS_HAS_LVALUE_RETURN + if (cx->rval2set) { + /* + * Use the stack depth we didn't claim in our budget, but that + * we know is there on account of [fun, this] already having + * been pushed, at a minimum (if no args). Those two slots + * have been popped and [rval] has been pushed, which leaves + * one more slot for rval2 before we might overflow. + * + * NB: rval2 must be the property identifier, and rval the + * object from which to get the property. The pair form an + * ECMA "reference type", which can be used on the right- or + * left-hand side of assignment ops. Note well: only native + * methods can return reference types. See JSOP_SETCALL just + * below for the left-hand-side case. + */ + PUSH_OPND(cx->rval2); + ELEMENT_OP(-1, OBJ_GET_PROPERTY(cx, obj, id, &rval)); + + regs.sp--; + STORE_OPND(-1, rval); + cx->rval2set = JS_FALSE; + } +#endif /* JS_HAS_LVALUE_RETURN */ + END_CASE(JSOP_CALL) + +#if JS_HAS_LVALUE_RETURN + BEGIN_CASE(JSOP_SETCALL) + argc = GET_ARGC(regs.pc); + vp = regs.sp - argc - 2; + ok = js_Invoke(cx, argc, vp, 0); + regs.sp = vp + 1; + LOAD_INTERRUPT_HANDLER(cx); + if (!ok) + goto error; + if (!cx->rval2set) { + op2 = (JSOp) regs.pc[JSOP_SETCALL_LENGTH]; + if (op2 != JSOP_DELELEM) { + JS_ASSERT(!(js_CodeSpec[op2].format & JOF_DEL)); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_LEFTSIDE_OF_ASS); + goto error; + } + + /* + * Store true as the result of the emulated delete of a + * non-existent property. NB: We don't METER_OP_PAIR here; + * it doesn't seem worth the code for this obscure case. + */ + *vp = JSVAL_TRUE; + regs.pc += JSOP_SETCALL_LENGTH + JSOP_DELELEM_LENGTH; + op = (JSOp) *regs.pc; + DO_OP(); + } + PUSH_OPND(cx->rval2); + cx->rval2set = JS_FALSE; + END_CASE(JSOP_SETCALL) +#endif + + BEGIN_CASE(JSOP_NAME) + BEGIN_CASE(JSOP_CALLNAME) + { + JSPropCacheEntry *entry; + + obj = fp->scopeChain; + if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { + PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + if (PCVAL_IS_OBJECT(entry->vword)) { + rval = PCVAL_OBJECT_TO_JSVAL(entry->vword); + JS_UNLOCK_OBJ(cx, obj2); + goto do_push_rval; + } + + if (PCVAL_IS_SLOT(entry->vword)) { + slot = PCVAL_TO_SLOT(entry->vword); + JS_ASSERT(slot < obj2->map->freeslot); + rval = LOCKED_OBJ_GET_SLOT(obj2, slot); + JS_UNLOCK_OBJ(cx, obj2); + goto do_push_rval; + } + + JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); + sprop = PCVAL_TO_SPROP(entry->vword); + goto do_native_get; + } + } else { + entry = NULL; + LOAD_ATOM(0); + } + + id = ATOM_TO_JSID(atom); + if (js_FindPropertyHelper(cx, id, &obj, &obj2, &prop, &entry) < 0) + goto error; + if (!prop) { + /* Kludge to allow (typeof foo == "undefined") tests. */ + endpc = script->code + script->length; + op2 = (JSOp) regs.pc[JSOP_NAME_LENGTH]; + if (op2 == JSOP_TYPEOF) { + PUSH_OPND(JSVAL_VOID); + len = JSOP_NAME_LENGTH; + DO_NEXT_OP(len); + } + goto atom_not_defined; + } + + /* Take the slow path if prop was not found in a native object. */ + if (!OBJ_IS_NATIVE(obj) || !OBJ_IS_NATIVE(obj2)) { + OBJ_DROP_PROPERTY(cx, obj2, prop); + if (!OBJ_GET_PROPERTY(cx, obj, id, &rval)) + goto error; + entry = NULL; + } else { + sprop = (JSScopeProperty *)prop; + do_native_get: + NATIVE_GET(cx, obj, obj2, sprop, &rval); + OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *) sprop); + } + + do_push_rval: + PUSH_OPND(rval); + if (op == JSOP_CALLNAME) + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + } + END_CASE(JSOP_NAME) + + BEGIN_CASE(JSOP_UINT16) + i = (jsint) GET_UINT16(regs.pc); + rval = INT_TO_JSVAL(i); + PUSH_OPND(rval); + END_CASE(JSOP_UINT16) + + BEGIN_CASE(JSOP_UINT24) + i = (jsint) GET_UINT24(regs.pc); + rval = INT_TO_JSVAL(i); + PUSH_OPND(rval); + END_CASE(JSOP_UINT24) + + BEGIN_CASE(JSOP_INT8) + i = GET_INT8(regs.pc); + rval = INT_TO_JSVAL(i); + PUSH_OPND(rval); + END_CASE(JSOP_INT8) + + BEGIN_CASE(JSOP_INT32) + i = GET_INT32(regs.pc); + rval = INT_TO_JSVAL(i); + PUSH_OPND(rval); + END_CASE(JSOP_INT32) + + BEGIN_CASE(JSOP_INDEXBASE) + /* + * Here atoms can exceed script->atomMap.length as we use atoms + * as a segment register for object literals as well. + */ + atoms += GET_INDEXBASE(regs.pc); + END_CASE(JSOP_INDEXBASE) + + BEGIN_CASE(JSOP_INDEXBASE1) + BEGIN_CASE(JSOP_INDEXBASE2) + BEGIN_CASE(JSOP_INDEXBASE3) + atoms += (op - JSOP_INDEXBASE1 + 1) << 16; + END_CASE(JSOP_INDEXBASE3) + + BEGIN_CASE(JSOP_RESETBASE0) + BEGIN_CASE(JSOP_RESETBASE) + atoms = script->atomMap.vector; + END_CASE(JSOP_RESETBASE) + + BEGIN_CASE(JSOP_DOUBLE) + BEGIN_CASE(JSOP_STRING) + LOAD_ATOM(0); + PUSH_OPND(ATOM_KEY(atom)); + END_CASE(JSOP_DOUBLE) + + BEGIN_CASE(JSOP_OBJECT) + LOAD_OBJECT(0); + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_OBJECT) + + BEGIN_CASE(JSOP_REGEXP) + { + JSObject *funobj; + + /* + * Push a regexp object for the atom mapped by the bytecode at pc, + * cloning the literal's regexp object if necessary, to simulate in + * the pre-compile/execute-later case what ECMA specifies for the + * compile-and-go case: that scanning each regexp literal creates + * a single corresponding RegExp object. + * + * To support pre-compilation transparently, we must handle the + * case where a regexp object literal is used in a different global + * at execution time from the global with which it was scanned at + * compile time. We do this by re-wrapping the JSRegExp private + * data struct with a cloned object having the right prototype and + * parent, and having its own lastIndex property value storage. + * + * Unlike JSOP_DEFFUN and other prolog bytecodes that may clone + * literal objects, we don't want to pay a script prolog execution + * price for all regexp literals in a script (many may not be used + * by a particular execution of that script, depending on control + * flow), so we initialize lazily here. + * + * XXX This code is specific to regular expression objects. If we + * need a similar op for other kinds of object literals, we should + * push cloning down under JSObjectOps and reuse code here. + */ + index = GET_FULL_INDEX(0); + JS_ASSERT(index < JS_SCRIPT_REGEXPS(script)->length); + + slot = index; + if (fp->fun) { + /* + * We're in function code, not global or eval code (in eval + * code, JSOP_REGEXP is never emitted). The cloned funobj + * contains JS_SCRIPT_REGEXPS(script)->length reserved slots + * for the cloned regexps; see fun_reserveSlots, jsfun.c. + */ + funobj = fp->callee; + slot += JSCLASS_RESERVED_SLOTS(&js_FunctionClass); + if (script->upvarsOffset != 0) + slot += JS_SCRIPT_UPVARS(script)->length; + if (!JS_GetReservedSlot(cx, funobj, slot, &rval)) + goto error; + if (JSVAL_IS_VOID(rval)) + rval = JSVAL_NULL; + } else { + /* + * We're in global code. The code generator reserved a slot + * for the regexp among script->nfixed slots. All such slots + * are initialized to null, not void, for faster testing in + * JSOP_*GVAR cases. To simplify index calculations we count + * regexps in the reverse order down from script->nslots - 1. + */ + JS_ASSERT(slot < script->nfixed); + slot = script->nfixed - slot - 1; + rval = fp->slots[slot]; +#ifdef __GNUC__ + funobj = NULL; /* suppress bogus gcc warnings */ +#endif + } + + if (JSVAL_IS_NULL(rval)) { + /* Compute the current global object in obj2. */ + obj2 = fp->scopeChain; + while ((parent = OBJ_GET_PARENT(cx, obj2)) != NULL) + obj2 = parent; + + /* + * If obj's parent is not obj2, we must clone obj so that it + * has the right parent, and therefore, the right prototype. + * + * Yes, this means we assume that the correct RegExp.prototype + * to which regexp instances (including literals) delegate can + * be distinguished solely by the instance's parent, which was + * set to the parent of the RegExp constructor function object + * when the instance was created. In other words, + * + * (/x/.__parent__ == RegExp.__parent__) implies + * (/x/.__proto__ == RegExp.prototype) + * + * (unless you assign a different object to RegExp.prototype + * at runtime, in which case, ECMA doesn't specify operation, + * and you get what you deserve). + * + * This same coupling between instance parent and constructor + * parent turns up everywhere (see jsobj.c's FindClassObject, + * js_ConstructObject, and js_NewObject). It's fundamental to + * the design of the language when you consider multiple global + * objects and separate compilation and execution, even though + * it is not specified fully in ECMA. + */ + JS_GET_SCRIPT_REGEXP(script, index, obj); + if (OBJ_GET_PARENT(cx, obj) != obj2) { + obj = js_CloneRegExpObject(cx, obj, obj2); + if (!obj) + goto error; + } + rval = OBJECT_TO_JSVAL(obj); + + /* Store the regexp object value in its cloneIndex slot. */ + if (fp->fun) { + if (!JS_SetReservedSlot(cx, funobj, slot, rval)) + goto error; + } else { + fp->slots[slot] = rval; + } + } + + PUSH_OPND(rval); + } + END_CASE(JSOP_REGEXP) + + BEGIN_CASE(JSOP_ZERO) + PUSH_OPND(JSVAL_ZERO); + END_CASE(JSOP_ZERO) + + BEGIN_CASE(JSOP_ONE) + PUSH_OPND(JSVAL_ONE); + END_CASE(JSOP_ONE) + + BEGIN_CASE(JSOP_NULL) + BEGIN_CASE(JSOP_NULLTHIS) + PUSH_OPND(JSVAL_NULL); + END_CASE(JSOP_NULL) + + BEGIN_CASE(JSOP_FALSE) + PUSH_OPND(JSVAL_FALSE); + END_CASE(JSOP_FALSE) + + BEGIN_CASE(JSOP_TRUE) + PUSH_OPND(JSVAL_TRUE); + END_CASE(JSOP_TRUE) + + BEGIN_CASE(JSOP_TABLESWITCH) + pc2 = regs.pc; + len = GET_JUMP_OFFSET(pc2); + + /* + * ECMAv2+ forbids conversion of discriminant, so we will skip to + * the default case if the discriminant isn't already an int jsval. + * (This opcode is emitted only for dense jsint-domain switches.) + */ + rval = POP_OPND(); + if (JSVAL_IS_INT(rval)) { + i = JSVAL_TO_INT(rval); + } else if (JSVAL_IS_DOUBLE(rval) && *JSVAL_TO_DOUBLE(rval) == 0) { + /* Treat -0 (double) as 0. */ + i = 0; + } else { + DO_NEXT_OP(len); + } + + pc2 += JUMP_OFFSET_LEN; + low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc2); + + i -= low; + if ((jsuint)i < (jsuint)(high - low + 1)) { + pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i; + off = (jsint) GET_JUMP_OFFSET(pc2); + if (off) + len = off; + } + END_VARLEN_CASE + + BEGIN_CASE(JSOP_TABLESWITCHX) + pc2 = regs.pc; + len = GET_JUMPX_OFFSET(pc2); + + /* + * ECMAv2+ forbids conversion of discriminant, so we will skip to + * the default case if the discriminant isn't already an int jsval. + * (This opcode is emitted only for dense jsint-domain switches.) + */ + rval = POP_OPND(); + if (JSVAL_IS_INT(rval)) { + i = JSVAL_TO_INT(rval); + } else if (JSVAL_IS_DOUBLE(rval) && *JSVAL_TO_DOUBLE(rval) == 0) { + /* Treat -0 (double) as 0. */ + i = 0; + } else { + DO_NEXT_OP(len); + } + + pc2 += JUMPX_OFFSET_LEN; + low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc2); + + i -= low; + if ((jsuint)i < (jsuint)(high - low + 1)) { + pc2 += JUMP_OFFSET_LEN + JUMPX_OFFSET_LEN * i; + off = (jsint) GET_JUMPX_OFFSET(pc2); + if (off) + len = off; + } + END_VARLEN_CASE + + BEGIN_CASE(JSOP_LOOKUPSWITCHX) + off = JUMPX_OFFSET_LEN; + goto do_lookup_switch; + + BEGIN_CASE(JSOP_LOOKUPSWITCH) + off = JUMP_OFFSET_LEN; + + do_lookup_switch: + /* + * JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if + * any atom index in it would exceed 64K limit. + */ + JS_ASSERT(atoms == script->atomMap.vector); + pc2 = regs.pc; + lval = POP_OPND(); + + if (!JSVAL_IS_NUMBER(lval) && + !JSVAL_IS_STRING(lval) && + !JSVAL_IS_BOOLEAN(lval)) { + goto end_lookup_switch; + } + + pc2 += off; + npairs = (jsint) GET_UINT16(pc2); + pc2 += UINT16_LEN; + JS_ASSERT(npairs); /* empty switch uses JSOP_TABLESWITCH */ + +#define SEARCH_PAIRS(MATCH_CODE) \ + for (;;) { \ + JS_ASSERT(GET_INDEX(pc2) < script->atomMap.length); \ + atom = atoms[GET_INDEX(pc2)]; \ + rval = ATOM_KEY(atom); \ + MATCH_CODE \ + pc2 += INDEX_LEN; \ + if (match) \ + break; \ + pc2 += off; \ + if (--npairs == 0) { \ + pc2 = regs.pc; \ + break; \ + } \ + } + if (JSVAL_IS_STRING(lval)) { + str = JSVAL_TO_STRING(lval); + SEARCH_PAIRS( + match = (JSVAL_IS_STRING(rval) && + ((str2 = JSVAL_TO_STRING(rval)) == str || + js_EqualStrings(str2, str))); + ) + } else if (JSVAL_IS_DOUBLE(lval)) { + d = *JSVAL_TO_DOUBLE(lval); + SEARCH_PAIRS( + match = (JSVAL_IS_DOUBLE(rval) && + *JSVAL_TO_DOUBLE(rval) == d); + ) + } else { + SEARCH_PAIRS( + match = (lval == rval); + ) + } +#undef SEARCH_PAIRS + + end_lookup_switch: + len = (op == JSOP_LOOKUPSWITCH) + ? GET_JUMP_OFFSET(pc2) + : GET_JUMPX_OFFSET(pc2); + END_VARLEN_CASE + + BEGIN_CASE(JSOP_TRAP) + { + JSTrapStatus status; + + status = JS_HandleTrap(cx, script, regs.pc, &rval); + switch (status) { + case JSTRAP_ERROR: + goto error; + case JSTRAP_RETURN: + fp->rval = rval; + ok = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->throwing = JS_TRUE; + cx->exception = rval; + goto error; + default:; + break; + } + JS_ASSERT(status == JSTRAP_CONTINUE); + LOAD_INTERRUPT_HANDLER(cx); + JS_ASSERT(JSVAL_IS_INT(rval)); + op = (JSOp) JSVAL_TO_INT(rval); + JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT); + DO_OP(); + } + + BEGIN_CASE(JSOP_ARGUMENTS) + if (!js_GetArgsValue(cx, fp, &rval)) + goto error; + PUSH_OPND(rval); + END_CASE(JSOP_ARGUMENTS) + + BEGIN_CASE(JSOP_ARGSUB) + id = INT_TO_JSID(GET_ARGNO(regs.pc)); + if (!js_GetArgsProperty(cx, fp, id, &rval)) + goto error; + PUSH_OPND(rval); + END_CASE(JSOP_ARGSUB) + + BEGIN_CASE(JSOP_ARGCNT) + id = ATOM_TO_JSID(rt->atomState.lengthAtom); + if (!js_GetArgsProperty(cx, fp, id, &rval)) + goto error; + PUSH_OPND(rval); + END_CASE(JSOP_ARGCNT) + + BEGIN_CASE(JSOP_GETARG) + BEGIN_CASE(JSOP_CALLARG) + slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < fp->fun->nargs); + METER_SLOT_OP(op, slot); + PUSH_OPND(fp->argv[slot]); + if (op == JSOP_CALLARG) + PUSH_OPND(JSVAL_NULL); + END_CASE(JSOP_GETARG) + + BEGIN_CASE(JSOP_SETARG) + slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < fp->fun->nargs); + METER_SLOT_OP(op, slot); + vp = &fp->argv[slot]; + GC_POKE(cx, *vp); + *vp = FETCH_OPND(-1); + END_SET_CASE(JSOP_SETARG) + + BEGIN_CASE(JSOP_GETLOCAL) + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + PUSH_OPND(fp->slots[slot]); + END_CASE(JSOP_GETLOCAL) + + BEGIN_CASE(JSOP_CALLLOCAL) + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + PUSH_OPND(fp->slots[slot]); + PUSH_OPND(JSVAL_NULL); + END_CASE(JSOP_CALLLOCAL) + + BEGIN_CASE(JSOP_SETLOCAL) + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + vp = &fp->slots[slot]; + GC_POKE(cx, *vp); + *vp = FETCH_OPND(-1); + END_SET_CASE(JSOP_SETLOCAL) + + BEGIN_CASE(JSOP_GETUPVAR) + BEGIN_CASE(JSOP_CALLUPVAR) + { + JSUpvarArray *uva; + uint32 skip; + JSStackFrame *fp2; + + index = GET_UINT16(regs.pc); + uva = JS_SCRIPT_UPVARS(script); + JS_ASSERT(index < uva->length); + skip = UPVAR_FRAME_SKIP(uva->vector[index]); + fp2 = cx->display[script->staticDepth - skip]; + JS_ASSERT(fp2->fun && fp2->script); + + slot = UPVAR_FRAME_SLOT(uva->vector[index]); + if (slot < fp2->fun->nargs) { + vp = fp2->argv; + } else { + slot -= fp2->fun->nargs; + JS_ASSERT(slot < fp2->script->nslots); + vp = fp2->slots; + } + + PUSH_OPND(vp[slot]); + if (op == JSOP_CALLUPVAR) + PUSH_OPND(JSVAL_NULL); + } + END_CASE(JSOP_GETUPVAR) + + BEGIN_CASE(JSOP_GETGVAR) + BEGIN_CASE(JSOP_CALLGVAR) + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < GlobalVarCount(fp)); + METER_SLOT_OP(op, slot); + lval = fp->slots[slot]; + if (JSVAL_IS_NULL(lval)) { + op = (op == JSOP_GETGVAR) ? JSOP_NAME : JSOP_CALLNAME; + DO_OP(); + } + obj = fp->varobj; + slot = JSVAL_TO_INT(lval); + rval = OBJ_GET_SLOT(cx, obj, slot); + PUSH_OPND(rval); + if (op == JSOP_CALLGVAR) + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_GETGVAR) + + BEGIN_CASE(JSOP_SETGVAR) + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < GlobalVarCount(fp)); + METER_SLOT_OP(op, slot); + rval = FETCH_OPND(-1); + obj = fp->varobj; + lval = fp->slots[slot]; + if (JSVAL_IS_NULL(lval)) { + /* + * Inline-clone and deoptimize JSOP_SETNAME code here because + * JSOP_SETGVAR has arity 1: [rval], not arity 2: [obj, rval] + * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME. + */ + LOAD_ATOM(0); + id = ATOM_TO_JSID(atom); + if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) + goto error; + } else { + slot = JSVAL_TO_INT(lval); + JS_LOCK_OBJ(cx, obj); + LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, rval); + JS_UNLOCK_OBJ(cx, obj); + } + END_SET_CASE(JSOP_SETGVAR) + + BEGIN_CASE(JSOP_DEFCONST) + BEGIN_CASE(JSOP_DEFVAR) + index = GET_INDEX(regs.pc); + atom = atoms[index]; + + /* + * index is relative to atoms at this point but for global var + * code below we need the absolute value. + */ + index += atoms - script->atomMap.vector; + obj = fp->varobj; + attrs = JSPROP_ENUMERATE; + if (!(fp->flags & JSFRAME_EVAL)) + attrs |= JSPROP_PERMANENT; + if (op == JSOP_DEFCONST) + attrs |= JSPROP_READONLY; + + /* Lookup id in order to check for redeclaration problems. */ + id = ATOM_TO_JSID(atom); + if (!js_CheckRedeclaration(cx, obj, id, attrs, &obj2, &prop)) + goto error; + + /* Bind a variable only if it's not yet defined. */ + if (!prop) { + if (!OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, + JS_PropertyStub, JS_PropertyStub, + attrs, &prop)) { + goto error; + } + JS_ASSERT(prop); + obj2 = obj; + } + + /* + * Try to optimize a property we either just created, or found + * directly in the global object, that is permanent, has a slot, + * and has stub getter and setter, into a "fast global" accessed + * by the JSOP_*GVAR opcodes. + */ + if (!fp->fun && + index < GlobalVarCount(fp) && + (attrs & JSPROP_PERMANENT) && + obj2 == obj && + OBJ_IS_NATIVE(obj)) { + sprop = (JSScopeProperty *) prop; + if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)) && + SPROP_HAS_STUB_GETTER(sprop) && + SPROP_HAS_STUB_SETTER(sprop)) { + /* + * Fast globals use frame variables to map the global + * name's atom index to the permanent fp->varobj slot + * number, tagged as a jsval. The atom index for the + * global's name literal is identical to its variable + * index. + */ + fp->slots[index] = INT_TO_JSVAL(sprop->slot); + } + } + + OBJ_DROP_PROPERTY(cx, obj2, prop); + END_CASE(JSOP_DEFVAR) + + BEGIN_CASE(JSOP_DEFFUN) + /* + * A top-level function defined in Global or Eval code (see + * ECMA-262 Ed. 3), or else a SpiderMonkey extension: a named + * function statement in a compound statement (not at the top + * statement level of global code, or at the top level of a + * function body). + */ + LOAD_FUNCTION(0); + + if (!fp->blockChain) { + obj2 = fp->scopeChain; + } else { + obj2 = js_GetScopeChain(cx, fp); + if (!obj2) + goto error; + } + + /* + * If static link is not current scope, clone fun's object to link + * to the current scope via parent. This clause exists to enable + * sharing of compiled functions among multiple equivalent scopes, + * splitting the cost of compilation evenly among the scopes and + * amortizing it over a number of executions. Examples include XUL + * scripts and event handlers shared among Mozilla chrome windows, + * and server-side JS user-defined functions shared among requests. + */ + obj = FUN_OBJECT(fun); + if (OBJ_GET_PARENT(cx, obj) != obj2) { + obj = js_CloneFunctionObject(cx, fun, obj2); + if (!obj) + goto error; + } + + /* + * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY. All + * paths from here must flow through the "Restore fp->scopeChain" + * code below the OBJ_DEFINE_PROPERTY call. + */ + MUST_FLOW_THROUGH("restore"); + fp->scopeChain = obj; + rval = OBJECT_TO_JSVAL(obj); + + /* + * ECMA requires functions defined when entering Eval code to be + * impermanent. + */ + attrs = (fp->flags & JSFRAME_EVAL) + ? JSPROP_ENUMERATE + : JSPROP_ENUMERATE | JSPROP_PERMANENT; + + /* + * Load function flags that are also property attributes. Getters + * and setters do not need a slot, their value is stored elsewhere + * in the property itself, not in obj slots. + */ + flags = JSFUN_GSFLAG2ATTR(fun->flags); + if (flags) { + attrs |= flags | JSPROP_SHARED; + rval = JSVAL_VOID; + } + + /* + * We define the function as a property of the variable object and + * not the current scope chain even for the case of function + * expression statements and functions defined by eval inside let + * or with blocks. + */ + parent = fp->varobj; + JS_ASSERT(parent); + + /* + * Check for a const property of the same name -- or any kind + * of property if executing with the strict option. We check + * here at runtime as well as at compile-time, to handle eval + * as well as multiple HTML script tags. + */ + id = ATOM_TO_JSID(fun->atom); + ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL); + if (ok) { + if (attrs == JSPROP_ENUMERATE) { + JS_ASSERT(fp->flags & JSFRAME_EVAL); + ok = OBJ_SET_PROPERTY(cx, parent, id, &rval); + } else { + JS_ASSERT(attrs & JSPROP_PERMANENT); + + ok = OBJ_DEFINE_PROPERTY(cx, parent, id, rval, + (flags & JSPROP_GETTER) + ? JS_EXTENSION (JSPropertyOp) obj + : JS_PropertyStub, + (flags & JSPROP_SETTER) + ? JS_EXTENSION (JSPropertyOp) obj + : JS_PropertyStub, + attrs, + NULL); + } + } + + /* Restore fp->scopeChain now that obj is defined in fp->varobj. */ + MUST_FLOW_LABEL(restore) + fp->scopeChain = obj2; + if (!ok) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + goto error; + } + END_CASE(JSOP_DEFFUN) + + BEGIN_CASE(JSOP_DEFLOCALFUN) + LOAD_FUNCTION(SLOTNO_LEN); + + /* + * Define a local function (i.e., one nested at the top level of + * another function), parented by the current scope chain, and + * stored in a local variable slot that the compiler allocated. + * This is an optimization over JSOP_DEFFUN that avoids requiring + * a call object for the outer function's activation. + */ + slot = GET_SLOTNO(regs.pc); + + parent = js_GetScopeChain(cx, fp); + if (!parent) + goto error; + + obj = FUN_OBJECT(fun); + if (OBJ_GET_PARENT(cx, obj) != parent) { + obj = js_CloneFunctionObject(cx, fun, parent); + if (!obj) + goto error; + } + + TRACE_2(DefLocalFunSetSlot, slot, obj); + + fp->slots[slot] = OBJECT_TO_JSVAL(obj); + END_CASE(JSOP_DEFLOCALFUN) + + BEGIN_CASE(JSOP_ANONFUNOBJ) + /* Load the specified function object literal. */ + LOAD_FUNCTION(0); + + /* If re-parenting, push a clone of the function object. */ + parent = js_GetScopeChain(cx, fp); + if (!parent) + goto error; + obj = FUN_OBJECT(fun); + if (OBJ_GET_PARENT(cx, obj) != parent) { + obj = js_CloneFunctionObject(cx, fun, parent); + if (!obj) + goto error; + } + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_ANONFUNOBJ) + + BEGIN_CASE(JSOP_NAMEDFUNOBJ) + LOAD_FUNCTION(0); + + /* + * ECMA ed. 3 FunctionExpression: function Identifier [etc.]. + * + * 1. Create a new object as if by the expression new Object(). + * 2. Add Result(1) to the front of the scope chain. + * + * Step 2 is achieved by making the new object's parent be the + * current scope chain, and then making the new object the parent + * of the Function object clone. + */ + obj2 = js_GetScopeChain(cx, fp); + if (!obj2) + goto error; + parent = js_NewObject(cx, &js_ObjectClass, NULL, obj2, 0); + if (!parent) + goto error; + + /* + * 3. Create a new Function object as specified in section 13.2 + * with [parameters and body specified by the function expression + * that was parsed by the compiler into a Function object, and + * saved in the script's atom map]. + * + * Protect parent from the GC. + */ + fp->scopeChain = parent; + obj = js_CloneFunctionObject(cx, fun, parent); + if (!obj) + goto error; + + /* + * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY. All + * paths from here must flow through the "Restore fp->scopeChain" + * code below the OBJ_DEFINE_PROPERTY call. + */ + MUST_FLOW_THROUGH("restore2"); + fp->scopeChain = obj; + rval = OBJECT_TO_JSVAL(obj); + + /* + * 4. Create a property in the object Result(1). The property's + * name is [fun->atom, the identifier parsed by the compiler], + * value is Result(3), and attributes are { DontDelete, ReadOnly }. + */ + attrs = JSFUN_GSFLAG2ATTR(fun->flags); + if (attrs) { + attrs |= JSPROP_SHARED; + rval = JSVAL_VOID; + } + ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval, + (attrs & JSPROP_GETTER) + ? JS_EXTENSION (JSPropertyOp) obj + : JS_PropertyStub, + (attrs & JSPROP_SETTER) + ? JS_EXTENSION (JSPropertyOp) obj + : JS_PropertyStub, + attrs | + JSPROP_ENUMERATE | JSPROP_PERMANENT | + JSPROP_READONLY, + NULL); + + /* Restore fp->scopeChain now that obj is defined in parent. */ + MUST_FLOW_LABEL(restore2) + fp->scopeChain = obj2; + if (!ok) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + goto error; + } + + /* + * 5. Remove Result(1) from the front of the scope chain [no-op]. + * 6. Return Result(3). + */ + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_NAMEDFUNOBJ) + +#if JS_HAS_GETTER_SETTER + BEGIN_CASE(JSOP_GETTER) + BEGIN_CASE(JSOP_SETTER) + do_getter_setter: + op2 = (JSOp) *++regs.pc; + switch (op2) { + case JSOP_INDEXBASE: + atoms += GET_INDEXBASE(regs.pc); + regs.pc += JSOP_INDEXBASE_LENGTH - 1; + goto do_getter_setter; + case JSOP_INDEXBASE1: + case JSOP_INDEXBASE2: + case JSOP_INDEXBASE3: + atoms += (op2 - JSOP_INDEXBASE1 + 1) << 16; + goto do_getter_setter; + + case JSOP_SETNAME: + case JSOP_SETPROP: + LOAD_ATOM(0); + id = ATOM_TO_JSID(atom); + rval = FETCH_OPND(-1); + i = -1; + goto gs_pop_lval; + + case JSOP_SETELEM: + rval = FETCH_OPND(-1); + id = 0; + i = -2; + gs_pop_lval: + FETCH_OBJECT(cx, i - 1, lval, obj); + break; + + case JSOP_INITPROP: + JS_ASSERT(regs.sp - StackBase(fp) >= 2); + rval = FETCH_OPND(-1); + i = -1; + LOAD_ATOM(0); + id = ATOM_TO_JSID(atom); + goto gs_get_lval; + + default: + JS_ASSERT(op2 == JSOP_INITELEM); + + JS_ASSERT(regs.sp - StackBase(fp) >= 3); + rval = FETCH_OPND(-1); + id = 0; + i = -2; + gs_get_lval: + lval = FETCH_OPND(i-1); + JS_ASSERT(JSVAL_IS_OBJECT(lval)); + obj = JSVAL_TO_OBJECT(lval); + break; + } + + /* Ensure that id has a type suitable for use with obj. */ + if (id == 0) + FETCH_ELEMENT_ID(obj, i, id); + + if (JS_TypeOfValue(cx, rval) != JSTYPE_FUNCTION) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) + ? js_getter_str + : js_setter_str); + goto error; + } + + /* + * Getters and setters are just like watchpoints from an access + * control point of view. + */ + if (!OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &rtmp, &attrs)) + goto error; + + if (op == JSOP_GETTER) { + getter = JS_EXTENSION (JSPropertyOp) JSVAL_TO_OBJECT(rval); + setter = JS_PropertyStub; + attrs = JSPROP_GETTER; + } else { + getter = JS_PropertyStub; + setter = JS_EXTENSION (JSPropertyOp) JSVAL_TO_OBJECT(rval); + attrs = JSPROP_SETTER; + } + attrs |= JSPROP_ENUMERATE | JSPROP_SHARED; + + /* Check for a readonly or permanent property of the same name. */ + if (!js_CheckRedeclaration(cx, obj, id, attrs, NULL, NULL)) + goto error; + + if (!OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, getter, setter, + attrs, NULL)) { + goto error; + } + + regs.sp += i; + if (js_CodeSpec[op2].ndefs) + STORE_OPND(-1, rval); + len = js_CodeSpec[op2].length; + DO_NEXT_OP(len); +#endif /* JS_HAS_GETTER_SETTER */ + + BEGIN_CASE(JSOP_HOLE) + PUSH_OPND(JSVAL_HOLE); + END_CASE(JSOP_HOLE) + + BEGIN_CASE(JSOP_NEWARRAY) + len = GET_UINT24(regs.pc); + JS_ASSERT(len <= regs.sp - StackBase(fp)); + obj = js_NewArrayObject(cx, len, regs.sp - len, JS_TRUE); + if (!obj) + goto error; + regs.sp -= len - 1; + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_NEWARRAY) + + BEGIN_CASE(JSOP_NEWINIT) + i = GET_INT8(regs.pc); + JS_ASSERT(i == JSProto_Array || i == JSProto_Object); + obj = (i == JSProto_Array) + ? js_NewArrayObject(cx, 0, NULL) + : js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0); + if (!obj) + goto error; + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + fp->sharpDepth++; + LOAD_INTERRUPT_HANDLER(cx); + END_CASE(JSOP_NEWINIT) + + BEGIN_CASE(JSOP_ENDINIT) + if (--fp->sharpDepth == 0) + fp->sharpArray = NULL; + + /* Re-set the newborn root to the top of this object tree. */ + JS_ASSERT(regs.sp - StackBase(fp) >= 1); + lval = FETCH_OPND(-1); + JS_ASSERT(JSVAL_IS_OBJECT(lval)); + cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(lval); + END_CASE(JSOP_ENDINIT) + + BEGIN_CASE(JSOP_INITPROP) + /* Load the property's initial value into rval. */ + JS_ASSERT(regs.sp - StackBase(fp) >= 2); + rval = FETCH_OPND(-1); + + /* Load the object being initialized into lval/obj. */ + lval = FETCH_OPND(-2); + obj = JSVAL_TO_OBJECT(lval); + JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(!OBJ_GET_CLASS(cx, obj)->reserveSlots); + JS_ASSERT(!(LOCKED_OBJ_GET_CLASS(obj)->flags & + JSCLASS_SHARE_ALL_PROPERTIES)); + + do { + JSScope *scope; + uint32 kshape; + JSPropertyCache *cache; + JSPropCacheEntry *entry; + + JS_LOCK_OBJ(cx, obj); + scope = OBJ_SCOPE(obj); + JS_ASSERT(!SCOPE_IS_SEALED(scope)); + kshape = scope->shape; + cache = &JS_PROPERTY_CACHE(cx); + entry = &cache->table[PROPERTY_CACHE_HASH_PC(regs.pc, kshape)]; + PCMETER(cache->tests++); + PCMETER(cache->initests++); + + if (entry->kpc == regs.pc && entry->kshape == kshape) { + PCMETER(cache->pchits++); + PCMETER(cache->inipchits++); + + JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); + sprop = PCVAL_TO_SPROP(entry->vword); + JS_ASSERT(!(sprop->attrs & JSPROP_READONLY)); + + /* + * If this property has a non-stub setter, it must be + * __proto__, __parent__, or another "shared prototype" + * built-in. Force a miss to save code size here and let + * the standard code path take care of business. + */ + if (!SPROP_HAS_STUB_SETTER(sprop)) + goto do_initprop_miss; + + if (scope->object != obj) { + scope = js_GetMutableScope(cx, obj); + if (!scope) { + JS_UNLOCK_OBJ(cx, obj); + goto error; + } + } + + /* + * Detect a repeated property name and force a miss to + * share the strict warning code and cope with complexity + * managed by js_AddScopeProperty. + */ + if (sprop->parent != scope->lastProp) + goto do_initprop_miss; + + TRACE_2(SetPropHit, entry, sprop); + + /* + * Otherwise this entry must be for a direct property of + * obj, not a proto-property, and there cannot have been + * any deletions of prior properties. + */ + JS_ASSERT(PCVCAP_MAKE(sprop->shape, 0, 0) == entry->vcap); + JS_ASSERT(!SCOPE_HAD_MIDDLE_DELETE(scope)); + JS_ASSERT(!scope->table || + !SCOPE_HAS_PROPERTY(scope, sprop)); + + slot = sprop->slot; + JS_ASSERT(slot == scope->map.freeslot); + if (slot < STOBJ_NSLOTS(obj)) { + ++scope->map.freeslot; + } else { + if (!js_AllocSlot(cx, obj, &slot)) { + JS_UNLOCK_SCOPE(cx, scope); + goto error; + } + JS_ASSERT(slot == sprop->slot); + } + + JS_ASSERT(!scope->lastProp || + scope->shape == scope->lastProp->shape); + if (scope->table) { + JSScopeProperty *sprop2 = + js_AddScopeProperty(cx, scope, sprop->id, + sprop->getter, sprop->setter, + slot, sprop->attrs, + sprop->flags, sprop->shortid); + if (!sprop2) { + js_FreeSlot(cx, obj, slot); + JS_UNLOCK_SCOPE(cx, scope); + goto error; + } + JS_ASSERT(sprop2 == sprop); + } else { + scope->shape = sprop->shape; + ++scope->entryCount; + scope->lastProp = sprop; + } + + GC_WRITE_BARRIER(cx, scope, + LOCKED_OBJ_GET_SLOT(obj, slot), + rval); + LOCKED_OBJ_SET_SLOT(obj, slot, rval); + JS_UNLOCK_SCOPE(cx, scope); + break; + } + + do_initprop_miss: + PCMETER(cache->inipcmisses++); + JS_UNLOCK_SCOPE(cx, scope); + + /* Get the immediate property name into id. */ + LOAD_ATOM(0); + id = ATOM_TO_JSID(atom); + + /* Set the property named by obj[id] to rval. */ + if (!js_CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, + NULL, NULL)) { + goto error; + } + if (!js_SetPropertyHelper(cx, obj, id, &rval, &entry)) + goto error; +#ifdef JS_TRACER + if (entry) + TRACE_1(SetPropMiss, entry); +#endif + } while (0); + + /* Common tail for property cache hit and miss cases. */ + regs.sp--; + END_CASE(JSOP_INITPROP); + + BEGIN_CASE(JSOP_INITELEM) + /* Pop the element's value into rval. */ + JS_ASSERT(regs.sp - StackBase(fp) >= 3); + rval = FETCH_OPND(-1); + + /* Find the object being initialized at top of stack. */ + lval = FETCH_OPND(-3); + JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval)); + obj = JSVAL_TO_OBJECT(lval); + + /* Fetch id now that we have obj. */ + FETCH_ELEMENT_ID(obj, -2, id); + + /* + * Check for property redeclaration strict warning (we may be in + * an object initialiser, not an array initialiser). + */ + if (!js_CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, NULL, + NULL)) { + goto error; + } + + /* + * If rval is a hole, do not call OBJ_SET_PROPERTY. In this case, + * obj must be an array, so if the current op is the last element + * initialiser, set the array length to one greater than id. + */ + if (rval == JSVAL_HOLE) { + JS_ASSERT(OBJ_IS_ARRAY(cx, obj)); + JS_ASSERT(JSID_IS_INT(id)); + JS_ASSERT((jsuint) JSID_TO_INT(id) < ARRAY_INIT_LIMIT); + if ((JSOp) regs.pc[JSOP_INITELEM_LENGTH] == JSOP_ENDINIT && + !js_SetLengthProperty(cx, obj, + (jsuint) (JSID_TO_INT(id) + 1))) { + goto error; + } + } else { + if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) + goto error; + } + regs.sp -= 2; + END_CASE(JSOP_INITELEM) + +#if JS_HAS_SHARP_VARS + BEGIN_CASE(JSOP_DEFSHARP) + obj = fp->sharpArray; + if (!obj) { + obj = js_NewArrayObject(cx, 0, NULL); + if (!obj) + goto error; + fp->sharpArray = obj; + } + i = (jsint) GET_UINT16(regs.pc); + id = INT_TO_JSID(i); + rval = FETCH_OPND(-1); + if (JSVAL_IS_PRIMITIVE(rval)) { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_SHARP_DEF, numBuf); + goto error; + } + if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) + goto error; + END_CASE(JSOP_DEFSHARP) + + BEGIN_CASE(JSOP_USESHARP) + i = (jsint) GET_UINT16(regs.pc); + id = INT_TO_JSID(i); + obj = fp->sharpArray; + if (!obj) { + rval = JSVAL_VOID; + } else { + if (!OBJ_GET_PROPERTY(cx, obj, id, &rval)) + goto error; + } + if (!JSVAL_IS_OBJECT(rval)) { + char numBuf[12]; + + JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_SHARP_USE, numBuf); + goto error; + } + PUSH_OPND(rval); + END_CASE(JSOP_USESHARP) +#endif /* JS_HAS_SHARP_VARS */ + + BEGIN_CASE(JSOP_GOSUB) + PUSH(JSVAL_FALSE); + i = PTRDIFF(regs.pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH; + PUSH(INT_TO_JSVAL(i)); + len = GET_JUMP_OFFSET(regs.pc); + END_VARLEN_CASE + + BEGIN_CASE(JSOP_GOSUBX) + PUSH(JSVAL_FALSE); + i = PTRDIFF(regs.pc, script->main, jsbytecode) + JSOP_GOSUBX_LENGTH; + len = GET_JUMPX_OFFSET(regs.pc); + PUSH(INT_TO_JSVAL(i)); + END_VARLEN_CASE + + BEGIN_CASE(JSOP_RETSUB) + /* Pop [exception or hole, retsub pc-index]. */ + rval = POP(); + lval = POP(); + JS_ASSERT(JSVAL_IS_BOOLEAN(lval)); + if (JSVAL_TO_BOOLEAN(lval)) { + /* + * Exception was pending during finally, throw it *before* we + * adjust pc, because pc indexes into script->trynotes. This + * turns out not to be necessary, but it seems clearer. And + * it points out a FIXME: 350509, due to Igor Bukanov. + */ + cx->throwing = JS_TRUE; + cx->exception = rval; + goto error; + } + JS_ASSERT(JSVAL_IS_INT(rval)); + len = JSVAL_TO_INT(rval); + regs.pc = script->main; + END_VARLEN_CASE + + BEGIN_CASE(JSOP_EXCEPTION) + JS_ASSERT(cx->throwing); + PUSH(cx->exception); + cx->throwing = JS_FALSE; + END_CASE(JSOP_EXCEPTION) + + BEGIN_CASE(JSOP_THROWING) + JS_ASSERT(!cx->throwing); + cx->throwing = JS_TRUE; + cx->exception = POP_OPND(); + END_CASE(JSOP_THROWING) + + BEGIN_CASE(JSOP_THROW) + JS_ASSERT(!cx->throwing); + cx->throwing = JS_TRUE; + cx->exception = POP_OPND(); + /* let the code at error try to catch the exception. */ + goto error; + + BEGIN_CASE(JSOP_SETLOCALPOP) + /* + * The stack must have a block with at least one local slot below + * the exception object. + */ + JS_ASSERT((size_t) (regs.sp - StackBase(fp)) >= 2); + slot = GET_UINT16(regs.pc); + JS_ASSERT(slot + 1 < script->nslots); + fp->slots[slot] = POP_OPND(); + END_CASE(JSOP_SETLOCALPOP) + + BEGIN_CASE(JSOP_INSTANCEOF) + rval = FETCH_OPND(-1); + if (JSVAL_IS_PRIMITIVE(rval) || + !(obj = JSVAL_TO_OBJECT(rval))->map->ops->hasInstance) { + js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, + -1, rval, NULL); + goto error; + } + lval = FETCH_OPND(-2); + cond = JS_FALSE; + if (!obj->map->ops->hasInstance(cx, obj, lval, &cond)) + goto error; + regs.sp--; + STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); + END_CASE(JSOP_INSTANCEOF) + +#if JS_HAS_DEBUGGER_KEYWORD + BEGIN_CASE(JSOP_DEBUGGER) + { + JSTrapHandler handler = cx->debugHooks->debuggerHandler; + if (handler) { + switch (handler(cx, script, regs.pc, &rval, + cx->debugHooks->debuggerHandlerData)) { + case JSTRAP_ERROR: + goto error; + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + fp->rval = rval; + ok = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->throwing = JS_TRUE; + cx->exception = rval; + goto error; + default:; + } + LOAD_INTERRUPT_HANDLER(cx); + } + } + END_CASE(JSOP_DEBUGGER) +#endif /* JS_HAS_DEBUGGER_KEYWORD */ + +#if JS_HAS_XML_SUPPORT + BEGIN_CASE(JSOP_DEFXMLNS) + rval = POP(); + if (!js_SetDefaultXMLNamespace(cx, rval)) + goto error; + END_CASE(JSOP_DEFXMLNS) + + BEGIN_CASE(JSOP_ANYNAME) + if (!js_GetAnyName(cx, &rval)) + goto error; + PUSH_OPND(rval); + END_CASE(JSOP_ANYNAME) + + BEGIN_CASE(JSOP_QNAMEPART) + LOAD_ATOM(0); + PUSH_OPND(ATOM_KEY(atom)); + END_CASE(JSOP_QNAMEPART) + + BEGIN_CASE(JSOP_QNAMECONST) + LOAD_ATOM(0); + rval = ATOM_KEY(atom); + lval = FETCH_OPND(-1); + obj = js_ConstructXMLQNameObject(cx, lval, rval); + if (!obj) + goto error; + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_QNAMECONST) + + BEGIN_CASE(JSOP_QNAME) + rval = FETCH_OPND(-1); + lval = FETCH_OPND(-2); + obj = js_ConstructXMLQNameObject(cx, lval, rval); + if (!obj) + goto error; + regs.sp--; + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_QNAME) + + BEGIN_CASE(JSOP_TOATTRNAME) + rval = FETCH_OPND(-1); + if (!js_ToAttributeName(cx, &rval)) + goto error; + STORE_OPND(-1, rval); + END_CASE(JSOP_TOATTRNAME) + + BEGIN_CASE(JSOP_TOATTRVAL) + rval = FETCH_OPND(-1); + JS_ASSERT(JSVAL_IS_STRING(rval)); + str = js_EscapeAttributeValue(cx, JSVAL_TO_STRING(rval), JS_FALSE); + if (!str) + goto error; + STORE_OPND(-1, STRING_TO_JSVAL(str)); + END_CASE(JSOP_TOATTRVAL) + + BEGIN_CASE(JSOP_ADDATTRNAME) + BEGIN_CASE(JSOP_ADDATTRVAL) + rval = FETCH_OPND(-1); + lval = FETCH_OPND(-2); + str = JSVAL_TO_STRING(lval); + str2 = JSVAL_TO_STRING(rval); + str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2); + if (!str) + goto error; + regs.sp--; + STORE_OPND(-1, STRING_TO_JSVAL(str)); + END_CASE(JSOP_ADDATTRNAME) + + BEGIN_CASE(JSOP_BINDXMLNAME) + lval = FETCH_OPND(-1); + if (!js_FindXMLProperty(cx, lval, &obj, &id)) + goto error; + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + PUSH_OPND(ID_TO_VALUE(id)); + END_CASE(JSOP_BINDXMLNAME) + + BEGIN_CASE(JSOP_SETXMLNAME) + obj = JSVAL_TO_OBJECT(FETCH_OPND(-3)); + rval = FETCH_OPND(-1); + FETCH_ELEMENT_ID(obj, -2, id); + if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) + goto error; + rval = FETCH_OPND(-1); + regs.sp -= 2; + STORE_OPND(-1, rval); + END_CASE(JSOP_SETXMLNAME) + + BEGIN_CASE(JSOP_CALLXMLNAME) + BEGIN_CASE(JSOP_XMLNAME) + lval = FETCH_OPND(-1); + if (!js_FindXMLProperty(cx, lval, &obj, &id)) + goto error; + if (!OBJ_GET_PROPERTY(cx, obj, id, &rval)) + goto error; + STORE_OPND(-1, rval); + if (op == JSOP_CALLXMLNAME) + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_XMLNAME) + + BEGIN_CASE(JSOP_DESCENDANTS) + BEGIN_CASE(JSOP_DELDESC) + FETCH_OBJECT(cx, -2, lval, obj); + rval = FETCH_OPND(-1); + if (!js_GetXMLDescendants(cx, obj, rval, &rval)) + goto error; + + if (op == JSOP_DELDESC) { + regs.sp[-1] = rval; /* set local root */ + if (!js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval))) + goto error; + rval = JSVAL_TRUE; /* always succeed */ + } + + regs.sp--; + STORE_OPND(-1, rval); + END_CASE(JSOP_DESCENDANTS) + + BEGIN_CASE(JSOP_FILTER) + /* + * We push the hole value before jumping to [enditer] so we can + * detect the first iteration and direct js_StepXMLListFilter to + * initialize filter's state. + */ + PUSH_OPND(JSVAL_HOLE); + len = GET_JUMP_OFFSET(regs.pc); + JS_ASSERT(len > 0); + END_VARLEN_CASE + + BEGIN_CASE(JSOP_ENDFILTER) + cond = (regs.sp[-1] != JSVAL_HOLE); + if (cond) { + /* Exit the "with" block left from the previous iteration. */ + js_LeaveWith(cx); + } + if (!js_StepXMLListFilter(cx, cond)) + goto error; + if (regs.sp[-1] != JSVAL_NULL) { + /* + * Decrease sp after EnterWith returns as we use sp[-1] there + * to root temporaries. + */ + JS_ASSERT(VALUE_IS_XML(cx, regs.sp[-1])); + if (!js_EnterWith(cx, -2)) + goto error; + regs.sp--; + len = GET_JUMP_OFFSET(regs.pc); + JS_ASSERT(len < 0); + BRANCH(len); + } + regs.sp--; + END_CASE(JSOP_ENDFILTER); + + BEGIN_CASE(JSOP_TOXML) + rval = FETCH_OPND(-1); + obj = js_ValueToXMLObject(cx, rval); + if (!obj) + goto error; + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_TOXML) + + BEGIN_CASE(JSOP_TOXMLLIST) + rval = FETCH_OPND(-1); + obj = js_ValueToXMLListObject(cx, rval); + if (!obj) + goto error; + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_TOXMLLIST) + + BEGIN_CASE(JSOP_XMLTAGEXPR) + rval = FETCH_OPND(-1); + str = js_ValueToString(cx, rval); + if (!str) + goto error; + STORE_OPND(-1, STRING_TO_JSVAL(str)); + END_CASE(JSOP_XMLTAGEXPR) + + BEGIN_CASE(JSOP_XMLELTEXPR) + rval = FETCH_OPND(-1); + if (VALUE_IS_XML(cx, rval)) { + str = js_ValueToXMLString(cx, rval); + } else { + str = js_ValueToString(cx, rval); + if (str) + str = js_EscapeElementValue(cx, str); + } + if (!str) + goto error; + STORE_OPND(-1, STRING_TO_JSVAL(str)); + END_CASE(JSOP_XMLELTEXPR) + + BEGIN_CASE(JSOP_XMLOBJECT) + LOAD_OBJECT(0); + obj = js_CloneXMLObject(cx, obj); + if (!obj) + goto error; + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_XMLOBJECT) + + BEGIN_CASE(JSOP_XMLCDATA) + LOAD_ATOM(0); + str = ATOM_TO_STRING(atom); + obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str); + if (!obj) + goto error; + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_XMLCDATA) + + BEGIN_CASE(JSOP_XMLCOMMENT) + LOAD_ATOM(0); + str = ATOM_TO_STRING(atom); + obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str); + if (!obj) + goto error; + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_XMLCOMMENT) + + BEGIN_CASE(JSOP_XMLPI) + LOAD_ATOM(0); + str = ATOM_TO_STRING(atom); + rval = FETCH_OPND(-1); + str2 = JSVAL_TO_STRING(rval); + obj = js_NewXMLSpecialObject(cx, + JSXML_CLASS_PROCESSING_INSTRUCTION, + str, str2); + if (!obj) + goto error; + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + END_CASE(JSOP_XMLPI) + + BEGIN_CASE(JSOP_GETFUNNS) + if (!js_GetFunctionNamespace(cx, &rval)) + goto error; + PUSH_OPND(rval); + END_CASE(JSOP_GETFUNNS) +#endif /* JS_HAS_XML_SUPPORT */ + + BEGIN_CASE(JSOP_ENTERBLOCK) + LOAD_OBJECT(0); + JS_ASSERT(!OBJ_IS_CLONED_BLOCK(obj)); + JS_ASSERT(StackBase(fp) + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp); + vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj); + JS_ASSERT(regs.sp < vp); + JS_ASSERT(vp <= fp->slots + script->nslots); + while (regs.sp < vp) { + STORE_OPND(0, JSVAL_VOID); + regs.sp++; + } + + /* + * If this frame had to reflect the compile-time block chain into + * the runtime scope chain, we can't optimize block scopes out of + * runtime any longer, because an outer block that parents obj has + * been cloned onto the scope chain. To avoid re-cloning such a + * parent and accumulating redundant clones via js_GetScopeChain, + * we must clone each block eagerly on entry, and push it on the + * scope chain, until this frame pops. + */ + if (fp->flags & JSFRAME_POP_BLOCKS) { + JS_ASSERT(!fp->blockChain); + obj = js_CloneBlockObject(cx, obj, fp->scopeChain, fp); + if (!obj) + goto error; + fp->scopeChain = obj; + } else { + JS_ASSERT(!fp->blockChain || + OBJ_GET_PARENT(cx, obj) == fp->blockChain); + fp->blockChain = obj; + } + END_CASE(JSOP_ENTERBLOCK) + + BEGIN_CASE(JSOP_LEAVEBLOCKEXPR) + BEGIN_CASE(JSOP_LEAVEBLOCK) + { +#ifdef DEBUG + uintN blockDepth = OBJ_BLOCK_DEPTH(cx, + fp->blockChain + ? fp->blockChain + : fp->scopeChain); + + JS_ASSERT(blockDepth <= StackDepth(script)); +#endif + if (fp->blockChain) { + JS_ASSERT(OBJ_GET_CLASS(cx, fp->blockChain) == &js_BlockClass); + fp->blockChain = OBJ_GET_PARENT(cx, fp->blockChain); + } else { + /* + * This block was cloned into fp->scopeChain, so clear its + * private data and sync its locals to their property slots. + */ + if (!js_PutBlockObject(cx, JS_TRUE)) + goto error; + } + + /* + * We will move the result of the expression to the new topmost + * stack slot. + */ + if (op == JSOP_LEAVEBLOCKEXPR) + rval = FETCH_OPND(-1); + regs.sp -= GET_UINT16(regs.pc); + if (op == JSOP_LEAVEBLOCKEXPR) { + JS_ASSERT(StackBase(fp) + blockDepth == regs.sp - 1); + STORE_OPND(-1, rval); + } else { + JS_ASSERT(StackBase(fp) + blockDepth == regs.sp); + } + } + END_CASE(JSOP_LEAVEBLOCK) + +#if JS_HAS_GENERATORS + BEGIN_CASE(JSOP_GENERATOR) + ASSERT_NOT_THROWING(cx); + regs.pc += JSOP_GENERATOR_LENGTH; + obj = js_NewGenerator(cx, fp); + if (!obj) + goto error; + JS_ASSERT(!fp->callobj && !fp->argsobj); + fp->rval = OBJECT_TO_JSVAL(obj); + ok = JS_TRUE; + if (inlineCallCount != 0) + goto inline_return; + goto exit; + + BEGIN_CASE(JSOP_YIELD) + ASSERT_NOT_THROWING(cx); + if (FRAME_TO_GENERATOR(fp)->state == JSGEN_CLOSING) { + js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, + JSDVG_SEARCH_STACK, fp->argv[-2], NULL); + goto error; + } + fp->rval = FETCH_OPND(-1); + fp->flags |= JSFRAME_YIELDING; + regs.pc += JSOP_YIELD_LENGTH; + ok = JS_TRUE; + goto exit; + + BEGIN_CASE(JSOP_ARRAYPUSH) + slot = GET_UINT16(regs.pc); + JS_ASSERT(script->nfixed <= slot); + JS_ASSERT(slot < script->nslots); + lval = fp->slots[slot]; + obj = JSVAL_TO_OBJECT(lval); + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass); + rval = FETCH_OPND(-1); + + /* + * We know that the array is created with only a 'length' private + * data slot at JSSLOT_ARRAY_LENGTH, and that previous iterations + * of the comprehension have added the only properties directly in + * the array object. + */ + i = obj->fslots[JSSLOT_ARRAY_LENGTH]; + if (i == ARRAY_INIT_LIMIT) { + JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL, + JSMSG_ARRAY_INIT_TOO_BIG); + goto error; + } + id = INT_TO_JSID(i); + if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) + goto error; + regs.sp--; + END_CASE(JSOP_ARRAYPUSH) +#endif /* JS_HAS_GENERATORS */ + +#if JS_THREADED_INTERP + L_JSOP_BACKPATCH: + L_JSOP_BACKPATCH_POP: + +# if !JS_HAS_GENERATORS + L_JSOP_GENERATOR: + L_JSOP_YIELD: + L_JSOP_ARRAYPUSH: +# endif + +# if !JS_HAS_DESTRUCTURING + L_JSOP_ENUMCONSTELEM: +# endif + +# if !JS_HAS_XML_SUPPORT + L_JSOP_CALLXMLNAME: + L_JSOP_STARTXMLEXPR: + L_JSOP_STARTXML: + L_JSOP_DELDESC: + L_JSOP_GETFUNNS: + L_JSOP_XMLPI: + L_JSOP_XMLCOMMENT: + L_JSOP_XMLCDATA: + L_JSOP_XMLOBJECT: + L_JSOP_XMLELTEXPR: + L_JSOP_XMLTAGEXPR: + L_JSOP_TOXMLLIST: + L_JSOP_TOXML: + L_JSOP_ENDFILTER: + L_JSOP_FILTER: + L_JSOP_DESCENDANTS: + L_JSOP_XMLNAME: + L_JSOP_SETXMLNAME: + L_JSOP_BINDXMLNAME: + L_JSOP_ADDATTRVAL: + L_JSOP_ADDATTRNAME: + L_JSOP_TOATTRVAL: + L_JSOP_TOATTRNAME: + L_JSOP_QNAME: + L_JSOP_QNAMECONST: + L_JSOP_QNAMEPART: + L_JSOP_ANYNAME: + L_JSOP_DEFXMLNS: +# endif + + L_JSOP_UNUSED131: + L_JSOP_UNUSED201: + L_JSOP_UNUSED202: + L_JSOP_UNUSED203: + L_JSOP_UNUSED204: + L_JSOP_UNUSED205: + L_JSOP_UNUSED206: + L_JSOP_UNUSED207: + L_JSOP_UNUSED208: + L_JSOP_UNUSED209: + L_JSOP_UNUSED219: + L_JSOP_UNUSED226: + +#else /* !JS_THREADED_INTERP */ + default: +#endif + { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%d", op); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_BYTECODE, numBuf); + goto error; + } + +#ifdef JS_TRACER + +#if JS_THREADED_INTERP +# define OPDEF(x,val,name,token,length,nuses,ndefs,prec,format) \ + R_##x: RECORD(x); goto L_##x; +#else +# define OPDEF(x,val,name,token,length,nuses,ndefs,prec,format) \ + case 256 + x: RECORD(x); op = x; switchOp = x; goto do_switch; +#endif +#include "jsopcode.tbl" +#undef OPDEF + +#endif /* JS_TRACER */ + +#if !JS_THREADED_INTERP + + } /* switch (op) */ + } +#endif /* !JS_THREADED_INTERP */ + + error: + if (fp->imacpc && cx->throwing) { + // To keep things simple, we hard-code imacro exception handlers here. + if (*fp->imacpc == JSOP_NEXTITER) { + JS_ASSERT(*regs.pc == JSOP_CALL); + if (js_ValueIsStopIteration(cx->exception)) { + cx->throwing = JS_FALSE; + cx->exception = JSVAL_VOID; + regs.sp[-1] = JSVAL_HOLE; + PUSH(JSVAL_FALSE); + goto end_imacro; + } + } + + // Handle other exceptions as if they came from the imacro-calling pc. + regs.pc = fp->imacpc; + fp->imacpc = NULL; + atoms = script->atomMap.vector; + } + + JS_ASSERT((size_t)(regs.pc - script->code) < script->length); + if (!cx->throwing) { + /* This is an error, not a catchable exception, quit the frame ASAP. */ + ok = JS_FALSE; + } else { + JSTrapHandler handler; + JSTryNote *tn, *tnlimit; + uint32 offset; + + /* Call debugger throw hook if set. */ + handler = cx->debugHooks->throwHook; + if (handler) { + switch (handler(cx, script, regs.pc, &rval, + cx->debugHooks->throwHookData)) { + case JSTRAP_ERROR: + cx->throwing = JS_FALSE; + goto error; + case JSTRAP_RETURN: + cx->throwing = JS_FALSE; + fp->rval = rval; + ok = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->exception = rval; + case JSTRAP_CONTINUE: + default:; + } + LOAD_INTERRUPT_HANDLER(cx); + } + + /* + * Look for a try block in script that can catch this exception. + */ + if (script->trynotesOffset == 0) + goto no_catch; + + offset = (uint32)(regs.pc - script->main); + tn = JS_SCRIPT_TRYNOTES(script)->vector; + tnlimit = tn + JS_SCRIPT_TRYNOTES(script)->length; + do { + if (offset - tn->start >= tn->length) + continue; + + /* + * We have a note that covers the exception pc but we must check + * whether the interpreter has already executed the corresponding + * handler. This is possible when the executed bytecode + * implements break or return from inside a for-in loop. + * + * In this case the emitter generates additional [enditer] and + * [gosub] opcodes to close all outstanding iterators and execute + * the finally blocks. If such an [enditer] throws an exception, + * its pc can still be inside several nested for-in loops and + * try-finally statements even if we have already closed the + * corresponding iterators and invoked the finally blocks. + * + * To address this, we make [enditer] always decrease the stack + * even when its implementation throws an exception. Thus already + * executed [enditer] and [gosub] opcodes will have try notes + * with the stack depth exceeding the current one and this + * condition is what we use to filter them out. + */ + if (tn->stackDepth > regs.sp - StackBase(fp)) + continue; + + /* + * Set pc to the first bytecode after the the try note to point + * to the beginning of catch or finally or to [enditer] closing + * the for-in loop. + */ + regs.pc = (script)->main + tn->start + tn->length; + + ok = js_UnwindScope(cx, fp, tn->stackDepth, JS_TRUE); + JS_ASSERT(fp->regs->sp == StackBase(fp) + tn->stackDepth); + if (!ok) { + /* + * Restart the handler search with updated pc and stack depth + * to properly notify the debugger. + */ + goto error; + } + + switch (tn->kind) { + case JSTRY_CATCH: + JS_ASSERT(*regs.pc == JSOP_ENTERBLOCK); + +#if JS_HAS_GENERATORS + /* Catch cannot intercept the closing of a generator. */ + if (JS_UNLIKELY(cx->exception == JSVAL_ARETURN)) + break; +#endif + + /* + * Don't clear cx->throwing to save cx->exception from GC + * until it is pushed to the stack via [exception] in the + * catch block. + */ + len = 0; + DO_NEXT_OP(len); + + case JSTRY_FINALLY: + /* + * Push (true, exception) pair for finally to indicate that + * [retsub] should rethrow the exception. + */ + PUSH(JSVAL_TRUE); + PUSH(cx->exception); + cx->throwing = JS_FALSE; + len = 0; + DO_NEXT_OP(len); + + case JSTRY_ITER: + /* + * This is similar to JSOP_ENDITER in the interpreter loop, + * except the code now uses the stack slot normally used by + * JSOP_NEXTITER, namely regs.sp[-1] before the regs.sp -= 2 + * adjustment and regs.sp[1] after, to save and restore the + * pending exception. + */ + JS_ASSERT(*regs.pc == JSOP_ENDITER); + regs.sp[-1] = cx->exception; + cx->throwing = JS_FALSE; + ok = js_CloseIterator(cx, regs.sp[-2]); + regs.sp -= 2; + if (!ok) + goto error; + cx->throwing = JS_TRUE; + cx->exception = regs.sp[1]; + } + } while (++tn != tnlimit); + + no_catch: + /* + * Propagate the exception or error to the caller unless the exception + * is an asynchronous return from a generator. + */ + ok = JS_FALSE; +#if JS_HAS_GENERATORS + if (JS_UNLIKELY(cx->throwing && cx->exception == JSVAL_ARETURN)) { + cx->throwing = JS_FALSE; + ok = JS_TRUE; + fp->rval = JSVAL_VOID; + } +#endif + } + + forced_return: + /* + * Unwind the scope making sure that ok stays false even when UnwindScope + * returns true. + * + * When a trap handler returns JSTRAP_RETURN, we jump here with ok set to + * true bypassing any finally blocks. + */ + ok &= js_UnwindScope(cx, fp, 0, ok || cx->throwing); + JS_ASSERT(regs.sp == StackBase(fp)); + + if (inlineCallCount) + goto inline_return; + + exit: + /* + * At this point we are inevitably leaving an interpreted function or a + * top-level script, and returning to one of: + * (a) an "out of line" call made through js_Invoke; + * (b) a js_Execute activation; + * (c) a generator (SendToGenerator, jsiter.c). + * + * We must not be in an inline frame. The check above ensures that for the + * error case and for a normal return, the code jumps directly to parent's + * frame pc. + */ + JS_ASSERT(inlineCallCount == 0); + JS_ASSERT(fp->regs == ®s); +#ifdef JS_TRACER + if (TRACE_RECORDER(cx)) + js_AbortRecording(cx, "recording out of js_Interpret"); +#endif +#if JS_HAS_GENERATORS + if (JS_UNLIKELY(fp->flags & JSFRAME_YIELDING)) { + JSGenerator *gen; + + gen = FRAME_TO_GENERATOR(fp); + gen->savedRegs = regs; + gen->frame.regs = &gen->savedRegs; + JS_PROPERTY_CACHE(cx).disabled -= js_CountWithBlocks(cx, fp); + JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0); + } else +#endif /* JS_HAS_GENERATORS */ + { + JS_ASSERT(!fp->blockChain); + JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0)); + fp->regs = NULL; + } + + /* Undo the remaining effects committed on entry to js_Interpret. */ + if (script->staticDepth < JS_DISPLAY_SIZE) + cx->display[script->staticDepth] = fp->displaySave; + JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave); + if (cx->version == currentVersion && currentVersion != originalVersion) + js_SetVersion(cx, originalVersion); + --cx->interpLevel; + +#ifdef JS_TRACER + if (tr) { + JS_TRACE_MONITOR(cx).onTrace = JS_TRUE; + SET_TRACE_RECORDER(cx, tr); + if (!tr->wasDeepAborted()) { + tr->popAbortStack(); + tr->deepAbort(); + } + } +#endif + return ok; + + atom_not_defined: + { + const char *printable; + + printable = js_AtomToPrintableString(cx, atom); + if (printable) + js_ReportIsNotDefined(cx, printable); + goto error; + } +} + +#endif /* !defined jsinvoke_cpp___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinterp.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinterp.h new file mode 100644 index 0000000..a016c47 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinterp.h @@ -0,0 +1,591 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsinterp_h___ +#define jsinterp_h___ +/* + * JS interpreter interface. + */ +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsfun.h" +#include "jsopcode.h" +#include "jsscript.h" + +JS_BEGIN_EXTERN_C + +typedef struct JSFrameRegs { + jsbytecode *pc; /* program counter */ + jsval *sp; /* stack pointer */ +} JSFrameRegs; + +/* + * JS stack frame, may be allocated on the C stack by native callers. Always + * allocated on cx->stackPool for calls from the interpreter to an interpreted + * function. + * + * NB: This struct is manually initialized in jsinterp.c and jsiter.c. If you + * add new members, update both files. But first, try to remove members. The + * sharp* and xml* members should be moved onto the stack as local variables + * with well-known slots, if possible. + */ +struct JSStackFrame { + JSFrameRegs *regs; + jsbytecode *imacpc; /* null or interpreter macro call pc */ + jsval *slots; /* variables, locals and operand stack */ + JSObject *callobj; /* lazily created Call object */ + JSObject *argsobj; /* lazily created arguments object */ + JSObject *varobj; /* variables object, where vars go */ + JSObject *callee; /* function or script object */ + JSScript *script; /* script being interpreted */ + JSFunction *fun; /* function being called or null */ + JSObject *thisp; /* "this" pointer if in method */ + uintN argc; /* actual argument count */ + jsval *argv; /* base of argument stack slots */ + jsval rval; /* function return value */ + JSStackFrame *down; /* previous frame */ + void *annotation; /* used by Java security */ + JSObject *scopeChain; /* scope chain */ + uintN sharpDepth; /* array/object initializer depth */ + JSObject *sharpArray; /* scope for #n= initializer vars */ + uint32 flags; /* frame flags -- see below */ + JSStackFrame *dormantNext; /* next dormant frame chain */ + JSObject *xmlNamespace; /* null or default xml namespace in E4X */ + JSObject *blockChain; /* active compile-time block scopes */ + JSStackFrame *displaySave; /* previous value of display entry for + script->staticDepth */ +#ifdef DEBUG + jsrefcount pcDisabledSave; /* for balanced property cache control */ +#endif +}; + +#ifdef DEBUG +#ifdef __cplusplus +static JS_INLINE uintN +FramePCOffset(JSStackFrame* fp) +{ + return uintN((fp->imacpc ? fp->imacpc : fp->regs->pc) - fp->script->code); +} +#endif +#endif + +static JS_INLINE jsval * +StackBase(JSStackFrame *fp) +{ + return fp->slots + fp->script->nfixed; +} + +static JS_INLINE uintN +GlobalVarCount(JSStackFrame *fp) +{ + uintN n; + + JS_ASSERT(!fp->fun); + n = fp->script->nfixed; + if (fp->script->regexpsOffset != 0) + n -= JS_SCRIPT_REGEXPS(fp->script)->length; + return n; +} + +typedef struct JSInlineFrame { + JSStackFrame frame; /* base struct */ + JSFrameRegs callerRegs; /* parent's frame registers */ + void *mark; /* mark before inline frame */ + void *hookData; /* debugger call hook data */ + JSVersion callerVersion; /* dynamic version of calling script */ +} JSInlineFrame; + +/* JS stack frame flags. */ +#define JSFRAME_CONSTRUCTING 0x01 /* frame is for a constructor invocation */ +#define JSFRAME_COMPUTED_THIS 0x02 /* frame.thisp was computed already */ +#define JSFRAME_ASSIGNING 0x04 /* a complex (not simplex JOF_ASSIGNING) op + is currently assigning to a property */ +#define JSFRAME_DEBUGGER 0x08 /* frame for JS_EvaluateInStackFrame */ +#define JSFRAME_EVAL 0x10 /* frame for obj_eval */ +#define JSFRAME_ROOTED_ARGV 0x20 /* frame.argv is rooted by the caller */ +#define JSFRAME_YIELDING 0x40 /* js_Interpret dispatched JSOP_YIELD */ +#define JSFRAME_ITERATOR 0x80 /* trying to get an iterator for for-in */ +#define JSFRAME_POP_BLOCKS 0x100 /* scope chain contains blocks to pop */ +#define JSFRAME_GENERATOR 0x200 /* frame belongs to generator-iterator */ +#define JSFRAME_IMACRO_START 0x400 /* imacro starting -- see jstracer.h */ + +#define JSFRAME_OVERRIDE_SHIFT 24 /* override bit-set params; see jsfun.c */ +#define JSFRAME_OVERRIDE_BITS 8 + +#define JSFRAME_SPECIAL (JSFRAME_DEBUGGER | JSFRAME_EVAL) + +/* + * Property cache with structurally typed capabilities for invalidation, for + * polymorphic callsite method/get/set speedups. + * + * See bug https://bugzilla.mozilla.org/show_bug.cgi?id=365851. + */ +#define PROPERTY_CACHE_LOG2 12 +#define PROPERTY_CACHE_SIZE JS_BIT(PROPERTY_CACHE_LOG2) +#define PROPERTY_CACHE_MASK JS_BITMASK(PROPERTY_CACHE_LOG2) + +/* + * Add kshape rather than xor it to avoid collisions between nearby bytecode + * that are evolving an object by setting successive properties, incrementing + * the object's scope->shape on each set. + */ +#define PROPERTY_CACHE_HASH(pc,kshape) \ + (((((jsuword)(pc) >> PROPERTY_CACHE_LOG2) ^ (jsuword)(pc)) + (kshape)) & \ + PROPERTY_CACHE_MASK) + +#define PROPERTY_CACHE_HASH_PC(pc,kshape) \ + PROPERTY_CACHE_HASH(pc, kshape) + +#define PROPERTY_CACHE_HASH_ATOM(atom,obj,pobj) \ + PROPERTY_CACHE_HASH((jsuword)(atom) >> 2, OBJ_SHAPE(obj)) + +/* + * Property cache value capability macros. + */ +#define PCVCAP_PROTOBITS 4 +#define PCVCAP_PROTOSIZE JS_BIT(PCVCAP_PROTOBITS) +#define PCVCAP_PROTOMASK JS_BITMASK(PCVCAP_PROTOBITS) + +#define PCVCAP_SCOPEBITS 4 +#define PCVCAP_SCOPESIZE JS_BIT(PCVCAP_SCOPEBITS) +#define PCVCAP_SCOPEMASK JS_BITMASK(PCVCAP_SCOPEBITS) + +#define PCVCAP_TAGBITS (PCVCAP_PROTOBITS + PCVCAP_SCOPEBITS) +#define PCVCAP_TAGMASK JS_BITMASK(PCVCAP_TAGBITS) +#define PCVCAP_TAG(t) ((t) & PCVCAP_TAGMASK) + +#define PCVCAP_MAKE(t,s,p) (((t) << PCVCAP_TAGBITS) | \ + ((s) << PCVCAP_PROTOBITS) | \ + (p)) +#define PCVCAP_SHAPE(t) ((t) >> PCVCAP_TAGBITS) + +#define SHAPE_OVERFLOW_BIT JS_BIT(32 - PCVCAP_TAGBITS) + +/* + * When sprop is not null and the shape generation triggers the GC due to a + * shape overflow, the functions roots sprop. + */ +extern uint32 +js_GenerateShape(JSContext *cx, JSBool gcLocked, JSScopeProperty *sprop); + +struct JSPropCacheEntry { + jsbytecode *kpc; /* pc if vcap tag is <= 1, else atom */ + jsuword kshape; /* key shape if pc, else obj for atom */ + jsuword vcap; /* value capability, see above */ + jsuword vword; /* value word, see PCVAL_* below */ +}; + +#if defined DEBUG_brendan || defined DEBUG_brendaneich +#define JS_PROPERTY_CACHE_METERING 1 +#endif + +typedef struct JSPropertyCache { + JSPropCacheEntry table[PROPERTY_CACHE_SIZE]; + JSBool empty; + jsrefcount disabled; /* signed for anti-underflow asserts */ +#ifdef JS_PROPERTY_CACHE_METERING + uint32 fills; /* number of cache entry fills */ + uint32 nofills; /* couldn't fill (e.g. default get) */ + uint32 rofills; /* set on read-only prop can't fill */ + uint32 disfills; /* fill attempts on disabled cache */ + uint32 oddfills; /* fill attempt after setter deleted */ + uint32 modfills; /* fill that rehashed to a new entry */ + uint32 brandfills; /* scope brandings to type structural + method fills */ + uint32 noprotos; /* resolve-returned non-proto pobj */ + uint32 longchains; /* overlong scope and/or proto chain */ + uint32 recycles; /* cache entries recycled by fills */ + uint32 pcrecycles; /* pc-keyed entries recycled by atom- + keyed fills */ + uint32 tests; /* cache probes */ + uint32 pchits; /* fast-path polymorphic op hits */ + uint32 protopchits; /* pchits hitting immediate prototype */ + uint32 initests; /* cache probes from JSOP_INITPROP */ + uint32 inipchits; /* init'ing next property pchit case */ + uint32 inipcmisses; /* init'ing next property pc misses */ + uint32 settests; /* cache probes from JOF_SET opcodes */ + uint32 addpchits; /* adding next property pchit case */ + uint32 setpchits; /* setting existing property pchit */ + uint32 setpcmisses; /* setting/adding property pc misses */ + uint32 slotchanges; /* clasp->reserveSlots result variance- + induced slot changes */ + uint32 setmisses; /* JSOP_SET{NAME,PROP} total misses */ + uint32 idmisses; /* slow-path key id == atom misses */ + uint32 komisses; /* slow-path key object misses */ + uint32 vcmisses; /* value capability misses */ + uint32 misses; /* cache misses */ + uint32 flushes; /* cache flushes */ + uint32 pcpurges; /* shadowing purges on proto chain */ +# define PCMETER(x) x +#else +# define PCMETER(x) ((void)0) +#endif +} JSPropertyCache; + +/* + * Property cache value tagging/untagging macros. + */ +#define PCVAL_OBJECT 0 +#define PCVAL_SLOT 1 +#define PCVAL_SPROP 2 + +#define PCVAL_TAGBITS 2 +#define PCVAL_TAGMASK JS_BITMASK(PCVAL_TAGBITS) +#define PCVAL_TAG(v) ((v) & PCVAL_TAGMASK) +#define PCVAL_CLRTAG(v) ((v) & ~(jsuword)PCVAL_TAGMASK) +#define PCVAL_SETTAG(v,t) ((jsuword)(v) | (t)) + +#define PCVAL_NULL 0 +#define PCVAL_IS_NULL(v) ((v) == PCVAL_NULL) + +#define PCVAL_IS_OBJECT(v) (PCVAL_TAG(v) == PCVAL_OBJECT) +#define PCVAL_TO_OBJECT(v) ((JSObject *) (v)) +#define OBJECT_TO_PCVAL(obj) ((jsuword) (obj)) + +#define PCVAL_OBJECT_TO_JSVAL(v) OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v)) +#define JSVAL_OBJECT_TO_PCVAL(v) OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v)) + +#define PCVAL_IS_SLOT(v) ((v) & PCVAL_SLOT) +#define PCVAL_TO_SLOT(v) ((jsuint)(v) >> 1) +#define SLOT_TO_PCVAL(i) (((jsuword)(i) << 1) | PCVAL_SLOT) + +#define PCVAL_IS_SPROP(v) (PCVAL_TAG(v) == PCVAL_SPROP) +#define PCVAL_TO_SPROP(v) ((JSScopeProperty *) PCVAL_CLRTAG(v)) +#define SPROP_TO_PCVAL(sprop) PCVAL_SETTAG(sprop, PCVAL_SPROP) + +/* + * Fill property cache entry for key cx->fp->pc, optimized value word computed + * from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj), + * 4-bit scopeIndex, and 4-bit protoIndex. + */ +extern void +js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, + uintN scopeIndex, uintN protoIndex, + JSObject *pobj, JSScopeProperty *sprop, + JSPropCacheEntry **entryp); + +/* + * Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the + * fast path in js_Interpret, so it makes "just-so" restrictions on parameters, + * e.g. pobj and obj should not be the same variable, since for JOF_PROP-mode + * opcodes, obj must not be changed because of a cache miss. + * + * On return from PROPERTY_CACHE_TEST, if atom is null then obj points to the + * scope chain element in which the property was found, pobj is locked, and + * entry is valid. If atom is non-null then no object is locked but entry is + * still set correctly for use, e.g., by js_FillPropertyCache and atom should + * be used as the id to find. + * + * We must lock pobj on a hit in order to close races with threads that might + * be deleting a property from its scope, or otherwise invalidating property + * caches (on all threads) by re-generating scope->shape. + */ +#define PROPERTY_CACHE_TEST(cx, pc, obj, pobj, entry, atom) \ + do { \ + JSPropertyCache *cache_ = &JS_PROPERTY_CACHE(cx); \ + uint32 kshape_ = (JS_ASSERT(OBJ_IS_NATIVE(obj)), OBJ_SHAPE(obj)); \ + entry = &cache_->table[PROPERTY_CACHE_HASH_PC(pc, kshape_)]; \ + PCMETER(cache_->tests++); \ + JS_ASSERT(&obj != &pobj); \ + if (entry->kpc == pc && entry->kshape == kshape_) { \ + JSObject *tmp_; \ + pobj = obj; \ + JS_LOCK_OBJ(cx, pobj); \ + JS_ASSERT(PCVCAP_TAG(entry->vcap) <= 1); \ + if (PCVCAP_TAG(entry->vcap) == 1 && \ + (tmp_ = LOCKED_OBJ_GET_PROTO(pobj)) != NULL && \ + OBJ_IS_NATIVE(tmp_)) { \ + JS_UNLOCK_OBJ(cx, pobj); \ + pobj = tmp_; \ + JS_LOCK_OBJ(cx, pobj); \ + } \ + if (PCVCAP_SHAPE(entry->vcap) == OBJ_SHAPE(pobj)) { \ + PCMETER(cache_->pchits++); \ + PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \ + pobj = OBJ_SCOPE(pobj)->object; \ + atom = NULL; \ + break; \ + } \ + JS_UNLOCK_OBJ(cx, pobj); \ + } \ + atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, &entry); \ + if (atom) \ + PCMETER(cache_->misses++); \ + } while (0) + +extern JSAtom * +js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, + JSObject **objp, JSObject **pobjp, + JSPropCacheEntry **entryp); + +extern void +js_FlushPropertyCache(JSContext *cx); + +extern void +js_FlushPropertyCacheForScript(JSContext *cx, JSScript *script); + +extern void +js_DisablePropertyCache(JSContext *cx); + +extern void +js_EnablePropertyCache(JSContext *cx); + +/* + * Interpreter stack arena-pool alloc and free functions. + */ +extern JS_FRIEND_API(jsval *) +js_AllocStack(JSContext *cx, uintN nslots, void **markp); + +extern JS_FRIEND_API(void) +js_FreeStack(JSContext *cx, void *mark); + +/* + * Refresh and return fp->scopeChain. It may be stale if block scopes are + * active but not yet reflected by objects in the scope chain. If a block + * scope contains a with, eval, XML filtering predicate, or similar such + * dynamically scoped construct, then compile-time block scope at fp->blocks + * must reflect at runtime. + */ +extern JSObject * +js_GetScopeChain(JSContext *cx, JSStackFrame *fp); + +/* + * Given a context and a vector of [callee, this, args...] for a function that + * was specified with a JSFUN_THISP_PRIMITIVE flag, get the primitive value of + * |this| into *thisvp. In doing so, if |this| is an object, insist it is an + * instance of clasp and extract its private slot value to return via *thisvp. + * + * NB: this function loads and uses *vp before storing *thisvp, so the two may + * alias the same jsval. + */ +extern JSBool +js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp); + +/* + * For a call with arguments argv including argv[-1] (nominal |this|) and + * argv[-2] (callee) replace null |this| with callee's parent, replace + * primitive values with the equivalent wrapper objects and censor activation + * objects as, per ECMA-262, they may not be referred to by |this|. argv[-1] + * must not be a JSVAL_VOID. + */ +extern JSObject * +js_ComputeThis(JSContext *cx, JSBool lazy, jsval *argv); + +extern const uint16 js_PrimitiveTestFlags[]; + +#define PRIMITIVE_THIS_TEST(fun,thisv) \ + (JS_ASSERT(!JSVAL_IS_VOID(thisv)), \ + JSFUN_THISP_TEST(JSFUN_THISP_FLAGS((fun)->flags), \ + js_PrimitiveTestFlags[JSVAL_TAG(thisv) - 1])) + +/* + * NB: js_Invoke requires that cx is currently running JS (i.e., that cx->fp + * is non-null), and that vp points to the callee, |this| parameter, and + * actual arguments of the call. [vp .. vp + 2 + argc) must belong to the last + * JS stack segment that js_AllocStack allocated. The function may use the + * space available after vp + 2 + argc in the stack segment for temporaries, + * so the caller should not use that space for values that must be preserved + * across the call. + */ +extern JS_FRIEND_API(JSBool) +js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags); + +/* + * Consolidated js_Invoke flags simply rename certain JSFRAME_* flags, so that + * we can share bits stored in JSStackFrame.flags and passed to: + * + * js_Invoke + * js_InternalInvoke + * js_ValueToFunction + * js_ValueToFunctionObject + * js_ValueToCallableObject + * js_ReportIsNotFunction + * + * See jsfun.h for the latter four and flag renaming macros. + */ +#define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING +#define JSINVOKE_ITERATOR JSFRAME_ITERATOR + +/* + * Mask to isolate construct and iterator flags for use with jsfun.h functions. + */ +#define JSINVOKE_FUNFLAGS (JSINVOKE_CONSTRUCT | JSINVOKE_ITERATOR) + +/* + * "Internal" calls may come from C or C++ code using a JSContext on which no + * JS is running (!cx->fp), so they may need to push a dummy JSStackFrame. + */ +#define js_InternalCall(cx,obj,fval,argc,argv,rval) \ + js_InternalInvoke(cx, obj, fval, 0, argc, argv, rval) + +#define js_InternalConstruct(cx,obj,fval,argc,argv,rval) \ + js_InternalInvoke(cx, obj, fval, JSINVOKE_CONSTRUCT, argc, argv, rval) + +extern JSBool +js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags, + uintN argc, jsval *argv, jsval *rval); + +extern JSBool +js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval, + JSAccessMode mode, uintN argc, jsval *argv, jsval *rval); + +extern JSBool +js_Execute(JSContext *cx, JSObject *chain, JSScript *script, + JSStackFrame *down, uintN flags, jsval *result); + +extern JSBool +js_InvokeConstructor(JSContext *cx, uintN argc, JSBool clampReturn, jsval *vp); + +extern JSBool +js_Interpret(JSContext *cx); + +#define JSPROP_INITIALIZER 0x100 /* NB: Not a valid property attribute. */ + +extern JSBool +js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, + JSObject **objp, JSProperty **propp); + +extern JSBool +js_StrictlyEqual(JSContext *cx, jsval lval, jsval rval); + +/* + * JS_LONE_INTERPRET indicates that the compiler should see just the code for + * the js_Interpret function when compiling jsinterp.cpp. The rest of the code + * from the file should be visible only when compiling jsinvoke.cpp. It allows + * platform builds to optimize selectively js_Interpret when the granularity + * of the optimizations with the given compiler is a compilation unit. + * + * JS_STATIC_INTERPRET is the modifier for functions defined in jsinterp.cpp + * that only js_Interpret calls. When JS_LONE_INTERPRET is true all such + * functions are declared below. + */ +#ifndef JS_LONE_INTERPRET +# ifdef _MSC_VER +# define JS_LONE_INTERPRET 0 +# else +# define JS_LONE_INTERPRET 1 +# endif +#endif + +#if !JS_LONE_INTERPRET +# define JS_STATIC_INTERPRET static +#else +# define JS_STATIC_INTERPRET + +extern jsval * +js_AllocRawStack(JSContext *cx, uintN nslots, void **markp); + +extern void +js_FreeRawStack(JSContext *cx, void *mark); + +/* + * ECMA requires "the global object", but in embeddings such as the browser, + * which have multiple top-level objects (windows, frames, etc. in the DOM), + * we prefer fun's parent. An example that causes this code to run: + * + * // in window w1 + * function f() { return this } + * function g() { return f } + * + * // in window w2 + * var h = w1.g() + * alert(h() == w1) + * + * The alert should display "true". + */ +extern JSObject * +js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv); + +extern JSBool +js_EnterWith(JSContext *cx, jsint stackIndex); + +extern void +js_LeaveWith(JSContext *cx); + +extern JSClass * +js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth); + +extern jsint +js_CountWithBlocks(JSContext *cx, JSStackFrame *fp); + +/* + * Unwind block and scope chains to match the given depth. The function sets + * fp->sp on return to stackDepth. + */ +extern JSBool +js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth, + JSBool normalUnwind); + +extern JSBool +js_InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp); + +extern JSBool +js_OnUnknownMethod(JSContext *cx, jsval *vp); + +/* + * Find the results of incrementing or decrementing *vp. For pre-increments, + * both *vp and *vp2 will contain the result on return. For post-increments, + * vp will contain the original value converted to a number and vp2 will get + * the result. Both vp and vp2 must be roots. + */ +extern JSBool +js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2); + +/* + * Opcode tracing helper. When len is not 0, cx->fp->regs->pc[-len] gives the + * previous opcode. + */ +extern void +js_TraceOpcode(JSContext *cx, jsint len); + +/* + * JS_OPMETER helper functions. + */ +extern void +js_MeterOpcodePair(JSOp op1, JSOp op2); + +extern void +js_MeterSlotOpcode(JSOp op, uint32 slot); + +#endif /* JS_LONE_INTERPRET */ + +JS_END_EXTERN_C + +#endif /* jsinterp_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinvoke.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinvoke.cpp new file mode 100644 index 0000000..893813e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsinvoke.cpp @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.8 code, released + * March 4, 2008. + * + * The Initial Developer of the Original Code is + * Igor Bukanov + * + * Contributor(s): + * Brendan Eich /* for memcpy */ +#include "jstypes.h" +#include "jsutil.h" +#include "jsarena.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsexn.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#if JSSLOT_ITER_FLAGS >= JS_INITIAL_NSLOTS +#error JS_INITIAL_NSLOTS must be greater than JSSLOT_ITER_FLAGS. +#endif + +#if JS_HAS_GENERATORS + +static JSBool +CloseGenerator(JSContext *cx, JSObject *genobj); + +#endif + +/* + * Shared code to close iterator's state either through an explicit call or + * when GC detects that the iterator is no longer reachable. + */ +void +js_CloseNativeIterator(JSContext *cx, JSObject *iterobj) +{ + jsval state; + JSObject *iterable; + + JS_ASSERT(STOBJ_GET_CLASS(iterobj) == &js_IteratorClass); + + /* Avoid double work if js_CloseNativeIterator was called on obj. */ + state = STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_STATE); + if (JSVAL_IS_NULL(state)) + return; + + /* Protect against failure to fully initialize obj. */ + iterable = STOBJ_GET_PARENT(iterobj); + if (iterable) { +#if JS_HAS_XML_SUPPORT + uintN flags = JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS)); + if ((flags & JSITER_FOREACH) && OBJECT_IS_XML(cx, iterable)) { + ((JSXMLObjectOps *) iterable->map->ops)-> + enumerateValues(cx, iterable, JSENUMERATE_DESTROY, &state, + NULL, NULL); + } else +#endif + OBJ_ENUMERATE(cx, iterable, JSENUMERATE_DESTROY, &state, NULL); + } + STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, JSVAL_NULL); +} + +JSClass js_IteratorClass = { + "Iterator", + JSCLASS_HAS_RESERVED_SLOTS(2) | /* slots for state and flags */ + JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSBool +InitNativeIterator(JSContext *cx, JSObject *iterobj, JSObject *obj, uintN flags) +{ + jsval state; + JSBool ok; + + JS_ASSERT(STOBJ_GET_CLASS(iterobj) == &js_IteratorClass); + + /* Initialize iterobj in case of enumerate hook failure. */ + STOBJ_SET_PARENT(iterobj, obj); + STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, JSVAL_NULL); + STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_FLAGS, INT_TO_JSVAL(flags)); + if (!js_RegisterCloseableIterator(cx, iterobj)) + return JS_FALSE; + if (!obj) + return JS_TRUE; + + ok = +#if JS_HAS_XML_SUPPORT + ((flags & JSITER_FOREACH) && OBJECT_IS_XML(cx, obj)) + ? ((JSXMLObjectOps *) obj->map->ops)-> + enumerateValues(cx, obj, JSENUMERATE_INIT, &state, NULL, NULL) + : +#endif + OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &state, NULL); + if (!ok) + return JS_FALSE; + + STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state); + if (flags & JSITER_ENUMERATE) { + /* + * The enumerating iterator needs the original object to suppress + * enumeration of deleted or shadowed prototype properties. Since the + * enumerator never escapes to scripts, we use the prototype slot to + * store the original object. + */ + JS_ASSERT(obj != iterobj); + STOBJ_SET_PROTO(iterobj, obj); + } + return JS_TRUE; +} + +static JSBool +Iterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval) +{ + JSBool keyonly; + uintN flags; + JSObject *obj; + + keyonly = js_ValueToBoolean(argv[1]); + flags = keyonly ? 0 : JSITER_FOREACH; + + if (cx->fp->flags & JSFRAME_CONSTRUCTING) { + /* XXX work around old valueOf call hidden beneath js_ValueToObject */ + if (!JSVAL_IS_PRIMITIVE(argv[0])) { + obj = JSVAL_TO_OBJECT(argv[0]); + } else { + obj = js_ValueToNonNullObject(cx, argv[0]); + if (!obj) + return JS_FALSE; + argv[0] = OBJECT_TO_JSVAL(obj); + } + return InitNativeIterator(cx, iterobj, obj, flags); + } + + *rval = argv[0]; + return js_ValueToIterator(cx, flags, rval); +} + +static JSBool +NewKeyValuePair(JSContext *cx, jsid key, jsval val, jsval *rval) +{ + jsval vec[2]; + JSTempValueRooter tvr; + JSObject *aobj; + + vec[0] = ID_TO_VALUE(key); + vec[1] = val; + + JS_PUSH_TEMP_ROOT(cx, 2, vec, &tvr); + aobj = js_NewArrayObject(cx, 2, vec); + *rval = OBJECT_TO_JSVAL(aobj); + JS_POP_TEMP_ROOT(cx, &tvr); + + return aobj != NULL; +} + +static JSBool +IteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval) +{ + JSObject *iterable; + jsval state; + uintN flags; + JSBool foreach, ok; + jsid id; + + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_IteratorClass); + + iterable = OBJ_GET_PARENT(cx, obj); + JS_ASSERT(iterable); + state = STOBJ_GET_SLOT(obj, JSSLOT_ITER_STATE); + if (JSVAL_IS_NULL(state)) + goto stop; + + flags = JSVAL_TO_INT(STOBJ_GET_SLOT(obj, JSSLOT_ITER_FLAGS)); + JS_ASSERT(!(flags & JSITER_ENUMERATE)); + foreach = (flags & JSITER_FOREACH) != 0; + ok = +#if JS_HAS_XML_SUPPORT + (foreach && OBJECT_IS_XML(cx, iterable)) + ? ((JSXMLObjectOps *) iterable->map->ops)-> + enumerateValues(cx, iterable, JSENUMERATE_NEXT, &state, + &id, rval) + : +#endif + OBJ_ENUMERATE(cx, iterable, JSENUMERATE_NEXT, &state, &id); + if (!ok) + return JS_FALSE; + + STOBJ_SET_SLOT(obj, JSSLOT_ITER_STATE, state); + if (JSVAL_IS_NULL(state)) + goto stop; + + if (foreach) { +#if JS_HAS_XML_SUPPORT + if (!OBJECT_IS_XML(cx, iterable) && + !OBJ_GET_PROPERTY(cx, iterable, id, rval)) { + return JS_FALSE; + } +#endif + if (!NewKeyValuePair(cx, id, *rval, rval)) + return JS_FALSE; + } else { + *rval = ID_TO_VALUE(id); + } + return JS_TRUE; + + stop: + JS_ASSERT(STOBJ_GET_SLOT(obj, JSSLOT_ITER_STATE) == JSVAL_NULL); + *rval = JSVAL_HOLE; + return JS_TRUE; +} + +JSBool +js_ThrowStopIteration(JSContext *cx) +{ + jsval v; + + JS_ASSERT(!JS_IsExceptionPending(cx)); + if (js_FindClassObject(cx, NULL, INT_TO_JSID(JSProto_StopIteration), &v)) + JS_SetPendingException(cx, v); + return JS_FALSE; +} + +static JSBool +iterator_next(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_IteratorClass, vp + 2)) + return JS_FALSE; + + if (!IteratorNextImpl(cx, obj, vp)) + return JS_FALSE; + + if (*vp == JSVAL_HOLE) { + *vp = JSVAL_NULL; + js_ThrowStopIteration(cx); + return JS_FALSE; + } + return JS_TRUE; +} + +static JSBool +iterator_self(JSContext *cx, uintN argc, jsval *vp) +{ + *vp = JS_THIS(cx, vp); + return !JSVAL_IS_NULL(*vp); +} + +#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT) + +static JSFunctionSpec iterator_methods[] = { + JS_FN(js_iterator_str, iterator_self, 0,JSPROP_ROPERM), + JS_FN(js_next_str, iterator_next, 0,JSPROP_ROPERM), + JS_FS_END +}; + +uintN +js_GetNativeIteratorFlags(JSContext *cx, JSObject *iterobj) +{ + if (OBJ_GET_CLASS(cx, iterobj) != &js_IteratorClass) + return 0; + return JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS)); +} + +/* + * Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists. + * Otherwise construct the default iterator. + */ +JS_FRIEND_API(JSBool) +js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) +{ + JSObject *obj; + JSTempValueRooter tvr; + JSAtom *atom; + JSClass *clasp; + JSExtendedClass *xclasp; + JSBool ok; + JSObject *iterobj; + jsval arg; + + JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | + JSITER_FOREACH | + JSITER_KEYVALUE))); + + /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ + JS_ASSERT(!(flags & JSITER_KEYVALUE) || (flags & JSITER_FOREACH)); + + /* XXX work around old valueOf call hidden beneath js_ValueToObject */ + if (!JSVAL_IS_PRIMITIVE(*vp)) { + obj = JSVAL_TO_OBJECT(*vp); + } else { + /* + * Enumerating over null and undefined gives an empty enumerator. + * This is contrary to ECMA-262 9.9 ToObject, invoked from step 3 of + * the first production in 12.6.4 and step 4 of the second production, + * but it's "web JS" compatible. + */ + if ((flags & JSITER_ENUMERATE)) { + if (!js_ValueToObject(cx, *vp, &obj)) + return JS_FALSE; + if (!obj) + goto default_iter; + } else { + obj = js_ValueToNonNullObject(cx, *vp); + if (!obj) + return JS_FALSE; + } + } + + JS_ASSERT(obj); + JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); + + clasp = OBJ_GET_CLASS(cx, obj); + if ((clasp->flags & JSCLASS_IS_EXTENDED) && + (xclasp = (JSExtendedClass *) clasp)->iteratorObject) { + iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH)); + if (!iterobj) + goto bad; + *vp = OBJECT_TO_JSVAL(iterobj); + } else { + atom = cx->runtime->atomState.iteratorAtom; +#if JS_HAS_XML_SUPPORT + if (OBJECT_IS_XML(cx, obj)) { + if (!js_GetXMLFunction(cx, obj, ATOM_TO_JSID(atom), vp)) + goto bad; + } else +#endif + { + if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp)) + goto bad; + } + + if (JSVAL_IS_VOID(*vp)) { + default_iter: + /* + * Fail over to the default enumerating native iterator. + * + * Create iterobj with a NULL parent to ensure that we use the + * correct scope chain to lookup the iterator's constructor. Since + * we use the parent slot to keep track of the iterable, we must + * fix it up after. + */ + iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL, 0); + if (!iterobj) + goto bad; + + /* Store in *vp to protect it from GC (callers must root vp). */ + *vp = OBJECT_TO_JSVAL(iterobj); + + if (!InitNativeIterator(cx, iterobj, obj, flags)) + goto bad; + } else { + arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0); + if (!js_InternalInvoke(cx, obj, *vp, JSINVOKE_ITERATOR, 1, &arg, + vp)) { + goto bad; + } + if (JSVAL_IS_PRIMITIVE(*vp)) { + const char *printable = js_AtomToPrintableString(cx, atom); + if (printable) { + js_ReportValueError2(cx, JSMSG_BAD_ITERATOR_RETURN, + JSDVG_SEARCH_STACK, *vp, NULL, + printable); + } + goto bad; + } + } + } + + ok = JS_TRUE; + out: + if (obj) + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; + bad: + ok = JS_FALSE; + goto out; +} + +JS_FRIEND_API(JSBool) JS_FASTCALL +js_CloseIterator(JSContext *cx, jsval v) +{ + JSObject *obj; + JSClass *clasp; + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + obj = JSVAL_TO_OBJECT(v); + clasp = OBJ_GET_CLASS(cx, obj); + + if (clasp == &js_IteratorClass) { + js_CloseNativeIterator(cx, obj); + } +#if JS_HAS_GENERATORS + else if (clasp == &js_GeneratorClass) { + if (!CloseGenerator(cx, obj)) + return JS_FALSE; + } +#endif + return JS_TRUE; +} + +static JSBool +CallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval) +{ + JSObject *obj, *origobj; + jsval state; + JSBool foreach; + jsid id; + JSObject *obj2; + JSBool cond; + JSClass *clasp; + JSExtendedClass *xclasp; + JSProperty *prop; + JSString *str; + + JS_ASSERT(flags & JSITER_ENUMERATE); + JS_ASSERT(STOBJ_GET_CLASS(iterobj) == &js_IteratorClass); + + obj = STOBJ_GET_PARENT(iterobj); + origobj = STOBJ_GET_PROTO(iterobj); + state = STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_STATE); + if (JSVAL_IS_NULL(state)) + goto stop; + + foreach = (flags & JSITER_FOREACH) != 0; +#if JS_HAS_XML_SUPPORT + /* + * Treat an XML object specially only when it starts the prototype chain. + * Otherwise we need to do the usual deleted and shadowed property checks. + */ + if (obj == origobj && OBJECT_IS_XML(cx, obj)) { + if (foreach) { + JSXMLObjectOps *xmlops = (JSXMLObjectOps *) obj->map->ops; + + if (!xmlops->enumerateValues(cx, obj, JSENUMERATE_NEXT, &state, + &id, rval)) { + return JS_FALSE; + } + } else { + if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &state, &id)) + return JS_FALSE; + } + STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state); + if (JSVAL_IS_NULL(state)) + goto stop; + } else +#endif + { + restart: + if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &state, &id)) + return JS_FALSE; + + STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state); + if (JSVAL_IS_NULL(state)) { +#if JS_HAS_XML_SUPPORT + if (OBJECT_IS_XML(cx, obj)) { + /* + * We just finished enumerating an XML obj that is present on + * the prototype chain of a non-XML origobj. Stop further + * prototype chain searches because XML objects don't + * enumerate prototypes. + */ + JS_ASSERT(origobj != obj); + JS_ASSERT(!OBJECT_IS_XML(cx, origobj)); + } else +#endif + { + obj = OBJ_GET_PROTO(cx, obj); + if (obj) { + STOBJ_SET_PARENT(iterobj, obj); + if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &state, NULL)) + return JS_FALSE; + STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state); + if (!JSVAL_IS_NULL(state)) + goto restart; + } + } + goto stop; + } + + /* Skip properties not in obj when looking from origobj. */ + if (!OBJ_LOOKUP_PROPERTY(cx, origobj, id, &obj2, &prop)) + return JS_FALSE; + if (!prop) + goto restart; + OBJ_DROP_PROPERTY(cx, obj2, prop); + + /* + * If the id was found in a prototype object or an unrelated object + * (specifically, not in an inner object for obj), skip it. This step + * means that all OBJ_LOOKUP_PROPERTY implementations must return an + * object further along on the prototype chain, or else possibly an + * object returned by the JSExtendedClass.outerObject optional hook. + */ + if (obj != obj2) { + cond = JS_FALSE; + clasp = OBJ_GET_CLASS(cx, obj2); + if (clasp->flags & JSCLASS_IS_EXTENDED) { + xclasp = (JSExtendedClass *) clasp; + cond = xclasp->outerObject && + xclasp->outerObject(cx, obj2) == obj; + } + if (!cond) + goto restart; + } + + if (foreach) { + /* Get property querying the original object. */ + if (!OBJ_GET_PROPERTY(cx, origobj, id, rval)) + return JS_FALSE; + } + } + + if (foreach) { + if (flags & JSITER_KEYVALUE) { + if (!NewKeyValuePair(cx, id, *rval, rval)) + return JS_FALSE; + } + } else { + /* Make rval a string for uniformity and compatibility. */ + str = js_ValueToString(cx, ID_TO_VALUE(id)); + if (!str) + return JS_FALSE; + *rval = STRING_TO_JSVAL(str); + } + return JS_TRUE; + + stop: + JS_ASSERT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_STATE) == JSVAL_NULL); + *rval = JSVAL_HOLE; + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval) +{ + uintN flags; + + /* Fast path for native iterators */ + if (OBJ_GET_CLASS(cx, iterobj) == &js_IteratorClass) { + flags = JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS)); + if (flags & JSITER_ENUMERATE) + return CallEnumeratorNext(cx, iterobj, flags, rval); + + /* + * Call next directly as all the methods of the native iterator are + * read-only and permanent. + */ + if (!IteratorNextImpl(cx, iterobj, rval)) + return JS_FALSE; + } else { + jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom); + + if (!JS_GetMethodById(cx, iterobj, id, &iterobj, rval)) + return JS_FALSE; + if (!js_InternalCall(cx, iterobj, *rval, 0, NULL, rval)) { + /* Check for StopIteration. */ + if (!cx->throwing || !js_ValueIsStopIteration(cx->exception)) + return JS_FALSE; + + /* Inline JS_ClearPendingException(cx). */ + cx->throwing = JS_FALSE; + cx->exception = JSVAL_VOID; + *rval = JSVAL_HOLE; + return JS_TRUE; + } + } + + return JS_TRUE; +} + +static JSBool +stopiter_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +{ + *bp = js_ValueIsStopIteration(v); + return JS_TRUE; +} + +JSClass js_StopIterationClass = { + js_StopIteration_str, + JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration), + JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, JS_FinalizeStub, + NULL, NULL, + NULL, NULL, + NULL, stopiter_hasInstance, + NULL, NULL +}; + +#if JS_HAS_GENERATORS + +static void +generator_finalize(JSContext *cx, JSObject *obj) +{ + JSGenerator *gen; + + gen = (JSGenerator *) JS_GetPrivate(cx, obj); + if (gen) { + /* + * gen can be open on shutdown when close hooks are ignored or when + * the embedding cancels scheduled close hooks. + */ + JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_CLOSED || + gen->state == JSGEN_OPEN); + JS_free(cx, gen); + } +} + +static void +generator_trace(JSTracer *trc, JSObject *obj) +{ + JSGenerator *gen; + + gen = (JSGenerator *) JS_GetPrivate(trc->context, obj); + if (!gen) + return; + + /* + * js_TraceStackFrame does not recursively trace the down-linked frame + * chain, so we insist that gen->frame has no parent to trace when the + * generator is not running. + */ + JS_ASSERT_IF(gen->state != JSGEN_RUNNING && gen->state != JSGEN_CLOSING, + !gen->frame.down); + + /* + * FIXME be 390950. Generator's frame is a part of the JS stack when the + * generator is running or closing. Thus tracing the frame in this case + * here duplicates the work done in js_TraceContext. + */ + js_TraceStackFrame(trc, &gen->frame); +} + +JSClass js_GeneratorClass = { + js_Generator_str, + JSCLASS_HAS_PRIVATE | JSCLASS_IS_ANONYMOUS | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, generator_finalize, + NULL, NULL, NULL, NULL, + NULL, NULL, JS_CLASS_TRACE(generator_trace), NULL +}; + +/* + * Called from the JSOP_GENERATOR case in the interpreter, with fp referring + * to the frame by which the generator function was activated. Create a new + * JSGenerator object, which contains its own JSStackFrame that we populate + * from *fp. We know that upon return, the JSOP_GENERATOR opcode will return + * from the activation in fp, so we can steal away fp->callobj and fp->argsobj + * if they are non-null. + */ +JSObject * +js_NewGenerator(JSContext *cx, JSStackFrame *fp) +{ + JSObject *obj; + uintN argc, nargs, nslots; + JSGenerator *gen; + jsval *slots; + + /* After the following return, failing control flow must goto bad. */ + obj = js_NewObject(cx, &js_GeneratorClass, NULL, NULL, 0); + if (!obj) + return NULL; + + /* Load and compute stack slot counts. */ + argc = fp->argc; + nargs = JS_MAX(argc, fp->fun->nargs); + nslots = 2 + nargs + fp->script->nslots; + + /* Allocate obj's private data struct. */ + gen = (JSGenerator *) + JS_malloc(cx, sizeof(JSGenerator) + (nslots - 1) * sizeof(jsval)); + if (!gen) + goto bad; + + gen->obj = obj; + + /* Steal away objects reflecting fp and point them at gen->frame. */ + gen->frame.callobj = fp->callobj; + if (fp->callobj) { + JS_SetPrivate(cx, fp->callobj, &gen->frame); + fp->callobj = NULL; + } + gen->frame.argsobj = fp->argsobj; + if (fp->argsobj) { + JS_SetPrivate(cx, fp->argsobj, &gen->frame); + fp->argsobj = NULL; + } + + /* These two references can be shared with fp until it goes away. */ + gen->frame.varobj = fp->varobj; + gen->frame.thisp = fp->thisp; + + /* Copy call-invariant script and function references. */ + gen->frame.script = fp->script; + gen->frame.callee = fp->callee; + gen->frame.fun = fp->fun; + + /* Use slots to carve space out of gen->slots. */ + slots = gen->slots; + gen->arena.next = NULL; + gen->arena.base = (jsuword) slots; + gen->arena.limit = gen->arena.avail = (jsuword) (slots + nslots); + + /* Copy rval, argv and vars. */ + gen->frame.rval = fp->rval; + memcpy(slots, fp->argv - 2, (2 + nargs) * sizeof(jsval)); + gen->frame.argc = nargs; + gen->frame.argv = slots + 2; + slots += 2 + nargs; + memcpy(slots, fp->slots, fp->script->nfixed * sizeof(jsval)); + + /* Initialize or copy virtual machine state. */ + gen->frame.down = NULL; + gen->frame.annotation = NULL; + gen->frame.scopeChain = fp->scopeChain; + + gen->frame.imacpc = NULL; + gen->frame.slots = slots; + JS_ASSERT(StackBase(fp) == fp->regs->sp); + gen->savedRegs.sp = slots + fp->script->nfixed; + gen->savedRegs.pc = fp->regs->pc; + gen->frame.regs = &gen->savedRegs; + + /* Copy remaining state (XXX sharp* and xml* should be local vars). */ + gen->frame.sharpDepth = 0; + gen->frame.sharpArray = NULL; + gen->frame.flags = (fp->flags & ~JSFRAME_ROOTED_ARGV) | JSFRAME_GENERATOR; + gen->frame.dormantNext = NULL; + gen->frame.xmlNamespace = NULL; + gen->frame.blockChain = NULL; + + /* Note that gen is newborn. */ + gen->state = JSGEN_NEWBORN; + + if (!JS_SetPrivate(cx, obj, gen)) { + JS_free(cx, gen); + goto bad; + } + return obj; + + bad: + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + return NULL; +} + +typedef enum JSGeneratorOp { + JSGENOP_NEXT, + JSGENOP_SEND, + JSGENOP_THROW, + JSGENOP_CLOSE +} JSGeneratorOp; + +/* + * Start newborn or restart yielding generator and perform the requested + * operation inside its frame. + */ +static JSBool +SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, + JSGenerator *gen, jsval arg) +{ + JSStackFrame *fp; + JSArena *arena; + JSBool ok; + + if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) { + js_ReportValueError(cx, JSMSG_NESTING_GENERATOR, + JSDVG_SEARCH_STACK, OBJECT_TO_JSVAL(obj), + JS_GetFunctionId(gen->frame.fun)); + return JS_FALSE; + } + + JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN); + switch (op) { + case JSGENOP_NEXT: + case JSGENOP_SEND: + if (gen->state == JSGEN_OPEN) { + /* + * Store the argument to send as the result of the yield + * expression. + */ + gen->savedRegs.sp[-1] = arg; + } + gen->state = JSGEN_RUNNING; + break; + + case JSGENOP_THROW: + JS_SetPendingException(cx, arg); + gen->state = JSGEN_RUNNING; + break; + + default: + JS_ASSERT(op == JSGENOP_CLOSE); + JS_SetPendingException(cx, JSVAL_ARETURN); + gen->state = JSGEN_CLOSING; + break; + } + + /* Extend the current stack pool with gen->arena. */ + arena = cx->stackPool.current; + JS_ASSERT(!arena->next); + JS_ASSERT(!gen->arena.next); + JS_ASSERT(cx->stackPool.current != &gen->arena); + cx->stackPool.current = arena->next = &gen->arena; + + /* Push gen->frame around the interpreter activation. */ + fp = cx->fp; + cx->fp = &gen->frame; + gen->frame.down = fp; + ok = js_Interpret(cx); + cx->fp = fp; + gen->frame.down = NULL; + + /* Retract the stack pool and sanitize gen->arena. */ + JS_ASSERT(!gen->arena.next); + JS_ASSERT(arena->next == &gen->arena); + JS_ASSERT(cx->stackPool.current == &gen->arena); + cx->stackPool.current = arena; + arena->next = NULL; + + if (gen->frame.flags & JSFRAME_YIELDING) { + /* Yield cannot fail, throw or be called on closing. */ + JS_ASSERT(ok); + JS_ASSERT(!cx->throwing); + JS_ASSERT(gen->state == JSGEN_RUNNING); + JS_ASSERT(op != JSGENOP_CLOSE); + gen->frame.flags &= ~JSFRAME_YIELDING; + gen->state = JSGEN_OPEN; + return JS_TRUE; + } + + gen->frame.rval = JSVAL_VOID; + gen->state = JSGEN_CLOSED; + if (ok) { + /* Returned, explicitly or by falling off the end. */ + if (op == JSGENOP_CLOSE) + return JS_TRUE; + return js_ThrowStopIteration(cx); + } + + /* + * An error, silent termination by operation callback or an exception. + * Propagate the condition to the caller. + */ + return JS_FALSE; +} + +static JSBool +CloseGenerator(JSContext *cx, JSObject *obj) +{ + JSGenerator *gen; + + JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_GeneratorClass); + gen = (JSGenerator *) JS_GetPrivate(cx, obj); + if (!gen) { + /* Generator prototype object. */ + return JS_TRUE; + } + + if (gen->state == JSGEN_CLOSED) + return JS_TRUE; + + return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, JSVAL_VOID); +} + +/* + * Common subroutine of generator_(next|send|throw|close) methods. + */ +static JSBool +generator_op(JSContext *cx, JSGeneratorOp op, jsval *vp, uintN argc) +{ + JSObject *obj; + JSGenerator *gen; + jsval arg; + + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_GeneratorClass, vp + 2)) + return JS_FALSE; + + gen = (JSGenerator *) JS_GetPrivate(cx, obj); + if (gen == NULL) { + /* This happens when obj is the generator prototype. See bug 352885. */ + goto closed_generator; + } + + if (gen->state == JSGEN_NEWBORN) { + switch (op) { + case JSGENOP_NEXT: + case JSGENOP_THROW: + break; + + case JSGENOP_SEND: + if (argc >= 1 && !JSVAL_IS_VOID(vp[2])) { + js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND, + JSDVG_SEARCH_STACK, vp[2], NULL); + return JS_FALSE; + } + break; + + default: + JS_ASSERT(op == JSGENOP_CLOSE); + gen->state = JSGEN_CLOSED; + return JS_TRUE; + } + } else if (gen->state == JSGEN_CLOSED) { + closed_generator: + switch (op) { + case JSGENOP_NEXT: + case JSGENOP_SEND: + return js_ThrowStopIteration(cx); + case JSGENOP_THROW: + JS_SetPendingException(cx, argc >= 1 ? vp[2] : JSVAL_VOID); + return JS_FALSE; + default: + JS_ASSERT(op == JSGENOP_CLOSE); + return JS_TRUE; + } + } + + arg = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0) + ? vp[2] + : JSVAL_VOID; + if (!SendToGenerator(cx, op, obj, gen, arg)) + return JS_FALSE; + *vp = gen->frame.rval; + return JS_TRUE; +} + +static JSBool +generator_send(JSContext *cx, uintN argc, jsval *vp) +{ + return generator_op(cx, JSGENOP_SEND, vp, argc); +} + +static JSBool +generator_next(JSContext *cx, uintN argc, jsval *vp) +{ + return generator_op(cx, JSGENOP_NEXT, vp, argc); +} + +static JSBool +generator_throw(JSContext *cx, uintN argc, jsval *vp) +{ + return generator_op(cx, JSGENOP_THROW, vp, argc); +} + +static JSBool +generator_close(JSContext *cx, uintN argc, jsval *vp) +{ + return generator_op(cx, JSGENOP_CLOSE, vp, argc); +} + +static JSFunctionSpec generator_methods[] = { + JS_FN(js_iterator_str, iterator_self, 0,JSPROP_ROPERM), + JS_FN(js_next_str, generator_next, 0,JSPROP_ROPERM), + JS_FN(js_send_str, generator_send, 1,JSPROP_ROPERM), + JS_FN(js_throw_str, generator_throw, 1,JSPROP_ROPERM), + JS_FN(js_close_str, generator_close, 0,JSPROP_ROPERM), + JS_FS_END +}; + +#endif /* JS_HAS_GENERATORS */ + +JSObject * +js_InitIteratorClasses(JSContext *cx, JSObject *obj) +{ + JSObject *proto, *stop; + + /* Idempotency required: we initialize several things, possibly lazily. */ + if (!js_GetClassObject(cx, obj, JSProto_StopIteration, &stop)) + return NULL; + if (stop) + return stop; + + proto = JS_InitClass(cx, obj, NULL, &js_IteratorClass, Iterator, 2, + NULL, iterator_methods, NULL, NULL); + if (!proto) + return NULL; + STOBJ_SET_SLOT(proto, JSSLOT_ITER_STATE, JSVAL_NULL); + +#if JS_HAS_GENERATORS + /* Initialize the generator internals if configured. */ + if (!JS_InitClass(cx, obj, NULL, &js_GeneratorClass, NULL, 0, + NULL, generator_methods, NULL, NULL)) { + return NULL; + } +#endif + + return JS_InitClass(cx, obj, NULL, &js_StopIterationClass, NULL, 0, + NULL, NULL, NULL, NULL); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsiter.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsiter.h new file mode 100644 index 0000000..2a7bb16 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsiter.h @@ -0,0 +1,140 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsiter_h___ +#define jsiter_h___ + +/* + * JavaScript iterators. + */ +#include "jsprvtd.h" +#include "jspubtd.h" + +JS_BEGIN_EXTERN_C + +/* + * NB: these flag bits are encoded into the bytecode stream in the immediate + * operand of JSOP_ITER, so don't change them without advancing jsxdrapi.h's + * JSXDR_BYTECODE_VERSION. + */ +#define JSITER_ENUMERATE 0x1 /* for-in compatible hidden default iterator */ +#define JSITER_FOREACH 0x2 /* return [key, value] pair rather than key */ +#define JSITER_KEYVALUE 0x4 /* destructuring for-in wants [key, value] */ + +/* + * Native iterator object slots, shared between jsiter.cpp and jstracer.cpp. + */ +#define JSSLOT_ITER_STATE (JSSLOT_PRIVATE) +#define JSSLOT_ITER_FLAGS (JSSLOT_PRIVATE + 1) + +/* + * Convert the value stored in *vp to its iteration object. The flags should + * contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating + * for-in semantics are required, and when the caller can guarantee that the + * iterator will never be exposed to scripts. + */ +extern JS_FRIEND_API(JSBool) +js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp); + +extern JS_FRIEND_API(JSBool) JS_FASTCALL +js_CloseIterator(JSContext *cx, jsval v); + +/* + * Given iterobj, call iterobj.next(). If the iterator stopped, set *rval to + * JSVAL_HOLE. Otherwise set it to the result of the next call. + */ +extern JS_FRIEND_API(JSBool) +js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval); + +/* + * Close iterobj, whose class must be js_IteratorClass. + */ +extern void +js_CloseNativeIterator(JSContext *cx, JSObject *iterobj); + +extern JSBool +js_ThrowStopIteration(JSContext *cx); + +#if JS_HAS_GENERATORS + +/* + * Generator state codes. + */ +typedef enum JSGeneratorState { + JSGEN_NEWBORN, /* not yet started */ + JSGEN_OPEN, /* started by a .next() or .send(undefined) call */ + JSGEN_RUNNING, /* currently executing via .next(), etc., call */ + JSGEN_CLOSING, /* close method is doing asynchronous return */ + JSGEN_CLOSED /* closed, cannot be started or closed again */ +} JSGeneratorState; + +struct JSGenerator { + JSObject *obj; + JSGeneratorState state; + JSStackFrame frame; + JSFrameRegs savedRegs; + JSArena arena; + jsval slots[1]; +}; + +#define FRAME_TO_GENERATOR(fp) \ + ((JSGenerator *) ((uint8 *)(fp) - offsetof(JSGenerator, frame))) + +extern JSObject * +js_NewGenerator(JSContext *cx, JSStackFrame *fp); + +#endif + +extern JSClass js_GeneratorClass; +extern JSClass js_IteratorClass; +extern JSClass js_StopIterationClass; + +static inline bool +js_ValueIsStopIteration(jsval v) +{ + return !JSVAL_IS_PRIMITIVE(v) && + STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v)) == &js_StopIterationClass; +} + +extern JSObject * +js_InitIteratorClasses(JSContext *cx, JSObject *obj); + +JS_END_EXTERN_C + +#endif /* jsiter_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jskeyword.tbl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jskeyword.tbl new file mode 100644 index 0000000..adcbf0e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jskeyword.tbl @@ -0,0 +1,124 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +JS_KEYWORD(break, TOK_BREAK, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(case, TOK_CASE, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(continue, TOK_CONTINUE, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(default, TOK_DEFAULT, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(delete, TOK_DELETE, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(do, TOK_DO, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(else, TOK_ELSE, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(export, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(false, TOK_PRIMARY, JSOP_FALSE, JSVERSION_DEFAULT) +JS_KEYWORD(for, TOK_FOR, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(function, TOK_FUNCTION, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(if, TOK_IF, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(in, TOK_IN, JSOP_IN, JSVERSION_DEFAULT) +JS_KEYWORD(new, TOK_NEW, JSOP_NEW, JSVERSION_DEFAULT) +JS_KEYWORD(null, TOK_PRIMARY, JSOP_NULL, JSVERSION_DEFAULT) +JS_KEYWORD(return, TOK_RETURN, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(switch, TOK_SWITCH, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(this, TOK_PRIMARY, JSOP_THIS, JSVERSION_DEFAULT) +JS_KEYWORD(true, TOK_PRIMARY, JSOP_TRUE, JSVERSION_DEFAULT) +JS_KEYWORD(typeof, TOK_UNARYOP, JSOP_TYPEOF, JSVERSION_DEFAULT) +JS_KEYWORD(var, TOK_VAR, JSOP_DEFVAR, JSVERSION_DEFAULT) +JS_KEYWORD(void, TOK_UNARYOP, JSOP_VOID, JSVERSION_DEFAULT) +JS_KEYWORD(while, TOK_WHILE, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(with, TOK_WITH, JSOP_NOP, JSVERSION_DEFAULT) +#if JS_HAS_CONST +JS_KEYWORD(const, TOK_VAR, JSOP_DEFCONST, JSVERSION_DEFAULT) +#else +JS_KEYWORD(const, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +#endif + +JS_KEYWORD(try, TOK_TRY, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(catch, TOK_CATCH, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(finally, TOK_FINALLY, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(throw, TOK_THROW, JSOP_NOP, JSVERSION_DEFAULT) + +JS_KEYWORD(instanceof, TOK_INSTANCEOF, JSOP_INSTANCEOF,JSVERSION_DEFAULT) + +#if JS_HAS_RESERVED_JAVA_KEYWORDS +JS_KEYWORD(abstract, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(boolean, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(byte, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(char, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(class, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(double, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(extends, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(final, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(float, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(goto, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(implements, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(import, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(int, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(interface, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(long, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(native, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(package, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(private, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(protected, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(public, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(short, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(static, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(super, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(synchronized,TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(throws, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(transient, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(volatile, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +#endif + +#if JS_HAS_RESERVED_ECMA_KEYWORDS +JS_KEYWORD(enum, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +#endif + +#if JS_HAS_DEBUGGER_KEYWORD +JS_KEYWORD(debugger, TOK_DEBUGGER, JSOP_NOP, JSVERSION_DEFAULT) +#elif JS_HAS_RESERVED_ECMA_KEYWORDS +JS_KEYWORD(debugger, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +#endif + +#if JS_HAS_GENERATORS +JS_KEYWORD(yield, TOK_YIELD, JSOP_NOP, JSVERSION_1_7) +#endif + +#if JS_HAS_BLOCK_SCOPE +JS_KEYWORD(let, TOK_LET, JSOP_NOP, JSVERSION_1_7) +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jskwgen.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jskwgen.cpp new file mode 100644 index 0000000..1d26c3d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jskwgen.cpp @@ -0,0 +1,460 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is String Switch Generator for JavaScript Keywords, + * released 2005-12-09. + * + * The Initial Developer of the Original Code is + * Igor Bukanov. + * Portions created by the Initial Developer are Copyright (C) 2005-2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsstddef.h" +#include +#include +#include +#include +#include +#include + +#include "jsversion.h" + +const char * const keyword_list[] = { +#define JS_KEYWORD(keyword, type, op, version) #keyword, +#include "jskeyword.tbl" +#undef JS_KEYWORD +}; + +struct gen_opt { + FILE *output; /* output file for generated source */ + unsigned use_if_threshold; /* max number of choices to generate + "if" selector instead of "switch" */ + unsigned char_tail_test_threshold; /* max number of unprocessed columns + to use inlined char compare + for remaining chars and not generic + string compare code */ + unsigned indent_level; /* current source identation level */ +}; + +static unsigned column_to_compare; + +static int +length_comparator(const void *a, const void *b) +{ + const char *str1 = keyword_list[*(unsigned *)a]; + const char *str2 = keyword_list[*(unsigned *)b]; + return (int)strlen(str1) - (int)strlen(str2); +} + +static int +column_comparator(const void *a, const void *b) +{ + const char *str1 = keyword_list[*(unsigned *)a]; + const char *str2 = keyword_list[*(unsigned *)b]; + return (int)str1[column_to_compare] - (int)str2[column_to_compare]; +} + +static unsigned +count_different_lengths(unsigned indexes[], unsigned nelem) +{ + unsigned nlength, current_length, i, l; + + current_length = 0; + nlength = 0; + for (i = 0; i != nelem; ++i) { + l = (unsigned)strlen(keyword_list[indexes[i]]); + assert(l != 0); + if (current_length != l) { + ++nlength; + current_length = l; + } + } + return nlength; +} + +static void +find_char_span_and_count(unsigned indexes[], unsigned nelem, unsigned column, + unsigned *span_result, unsigned *count_result) +{ + unsigned i, count; + unsigned char c, prev, minc, maxc; + + assert(nelem != 0); + minc = maxc = prev = (unsigned char)keyword_list[indexes[0]][column]; + count = 1; + for (i = 1; i != nelem; ++i) { + c = (unsigned char)keyword_list[indexes[i]][column]; + if (prev != c) { + prev = c; + ++count; + if (minc > c) { + minc = c; + } else if (maxc < c) { + maxc = c; + } + } + } + + *span_result = maxc - minc + 1; + *count_result = count; +} + +static unsigned +find_optimal_switch_column(struct gen_opt *opt, + unsigned indexes[], unsigned nelem, + unsigned columns[], unsigned unprocessed_columns, + int *use_if_result) +{ + unsigned i; + unsigned span, min_span, min_span_index; + unsigned nchar, min_nchar, min_nchar_index; + + assert(unprocessed_columns != 0); + i = 0; + min_nchar = min_span = (unsigned)-1; + min_nchar_index = min_span_index = 0; + do { + column_to_compare = columns[i]; + qsort(indexes, nelem, sizeof(indexes[0]), column_comparator); + find_char_span_and_count(indexes, nelem, column_to_compare, + &span, &nchar); + assert(span != 0); + if (span == 1) { + assert(nchar == 1); + *use_if_result = 1; + return 1; + } + assert(nchar != 1); + if (min_span > span) { + min_span = span; + min_span_index = i; + } + if (min_nchar > nchar) { + min_nchar = nchar; + min_nchar_index = i; + } + } while (++i != unprocessed_columns); + + if (min_nchar <= opt->use_if_threshold) { + *use_if_result = 1; + i = min_nchar_index; + } else { + *use_if_result = 0; + i = min_span_index; + } + + /* + * Restore order corresponding to i if it was destroyed by + * subsequent sort. + */ + if (i != unprocessed_columns - 1) { + column_to_compare = columns[i]; + qsort(indexes, nelem, sizeof(indexes[0]), column_comparator); + } + + return i; +} + + +static void +p(struct gen_opt *opt, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf(opt->output, format, ap); + va_end(ap); +} + +/* Size for '\xxx' where xxx is octal escape */ +#define MIN_QUOTED_CHAR_BUFFER 7 + +static char * +qchar(char c, char *quoted_buffer) +{ + char *s; + + s = quoted_buffer; + *s++ = '\''; + switch (c) { + case '\n': c = 'n'; goto one_char_escape; + case '\r': c = 'r'; goto one_char_escape; + case '\t': c = 't'; goto one_char_escape; + case '\f': c = 't'; goto one_char_escape; + case '\0': c = '0'; goto one_char_escape; + case '\'': goto one_char_escape; + one_char_escape: + *s++ = '\\'; + break; + default: + if (!isprint(c)) { + *s++ = '\\'; + *s++ = (char)('0' + (0x3 & (((unsigned char)c) >> 6))); + *s++ = (char)('0' + (0x7 & (((unsigned char)c) >> 3))); + c = (char)('0' + (0x7 & ((unsigned char)c))); + } + } + *s++ = c; + *s++ = '\''; + *s = '\0'; + assert(s + 1 <= quoted_buffer + MIN_QUOTED_CHAR_BUFFER); + return quoted_buffer; +} + +static void +nl(struct gen_opt *opt) +{ + putc('\n', opt->output); +} + +static void +indent(struct gen_opt *opt) +{ + unsigned n = opt->indent_level; + while (n != 0) { + --n; + fputs(" ", opt->output); + } +} + +static void +line(struct gen_opt *opt, const char *format, ...) +{ + va_list ap; + + indent(opt); + va_start(ap, format); + vfprintf(opt->output, format, ap); + va_end(ap); + nl(opt); +} + +static void +generate_letter_switch_r(struct gen_opt *opt, + unsigned indexes[], unsigned nelem, + unsigned columns[], unsigned unprocessed_columns) +{ + char qbuf[MIN_QUOTED_CHAR_BUFFER]; + + assert(nelem != 0); + if (nelem == 1) { + unsigned kw_index = indexes[0]; + const char *keyword = keyword_list[kw_index]; + + if (unprocessed_columns == 0) { + line(opt, "JSKW_GOT_MATCH(%u) /* %s */", kw_index, keyword); + } else if (unprocessed_columns > opt->char_tail_test_threshold) { + line(opt, "JSKW_TEST_GUESS(%u) /* %s */", kw_index, keyword); + } else { + unsigned i, column; + + indent(opt); p(opt, "if ("); + for (i = 0; i != unprocessed_columns; ++i) { + column = columns[i]; + qchar(keyword[column], qbuf); + p(opt, "%sJSKW_AT(%u)==%s", (i == 0) ? "" : " && ", + column, qbuf); + } + p(opt, ") {"); nl(opt); + ++opt->indent_level; + line(opt, "JSKW_GOT_MATCH(%u) /* %s */", kw_index, keyword); + --opt->indent_level; + line(opt, "}"); + line(opt, "JSKW_NO_MATCH()"); + } + } else { + unsigned optimal_column_index, optimal_column; + unsigned i; + int use_if; + char current; + + assert(unprocessed_columns != 0); + optimal_column_index = find_optimal_switch_column(opt, indexes, nelem, + columns, + unprocessed_columns, + &use_if); + optimal_column = columns[optimal_column_index]; + columns[optimal_column_index] = columns[unprocessed_columns - 1]; + + if (!use_if) + line(opt, "switch (JSKW_AT(%u)) {", optimal_column); + + current = keyword_list[indexes[0]][optimal_column]; + for (i = 0; i != nelem;) { + unsigned same_char_begin = i; + char next = current; + + for (++i; i != nelem; ++i) { + next = keyword_list[indexes[i]][optimal_column]; + if (next != current) + break; + } + qchar(current, qbuf); + if (use_if) { + line(opt, "if (JSKW_AT(%u) == %s) {", optimal_column, qbuf); + } else { + line(opt, " case %s:", qbuf); + } + ++opt->indent_level; + generate_letter_switch_r(opt, indexes + same_char_begin, + i - same_char_begin, + columns, unprocessed_columns - 1); + --opt->indent_level; + if (use_if) { + line(opt, "}"); + } + current = next; + } + + if (!use_if) { + line(opt, "}"); + } + + columns[optimal_column_index] = optimal_column; + + line(opt, "JSKW_NO_MATCH()"); + } +} + +static void +generate_letter_switch(struct gen_opt *opt, + unsigned indexes[], unsigned nelem, + unsigned current_length) +{ + unsigned *columns; + unsigned i; + + columns = (unsigned *) malloc(sizeof(columns[0]) * current_length); + if (!columns) { + perror("malloc"); + exit(EXIT_FAILURE); + } + for (i = 0; i != current_length; ++i) { + columns[i] = i; + } + generate_letter_switch_r(opt, indexes, nelem, columns, current_length); + free(columns); +} + + +static void +generate_switch(struct gen_opt *opt) +{ + unsigned *indexes; + unsigned nlength; + unsigned i, current; + int use_if; + unsigned nelem; + + nelem = sizeof(keyword_list)/sizeof(keyword_list[0]); + + line(opt, "/*"); + line(opt, " * Generating switch for the list of %u entries:", nelem); + for (i = 0; i != nelem; ++i) { + line(opt, " * %s", keyword_list[i]); + } + line(opt, " */"); + + indexes = (unsigned *) malloc(sizeof(indexes[0]) * nelem); + if (!indexes) { + perror("malloc"); + exit(EXIT_FAILURE); + } + for (i = 0; i != nelem; ++i) + indexes[i] = i; + qsort(indexes, nelem, sizeof(indexes[i]), length_comparator); + nlength = count_different_lengths(indexes, nelem); + + use_if = (nlength <= opt->use_if_threshold); + + if (!use_if) + line(opt, "switch (JSKW_LENGTH()) {"); + + current = (unsigned)strlen(keyword_list[indexes[0]]); + for (i = 0; i != nelem;) { + unsigned same_length_begin = i; + unsigned next = current; + + for (++i; i != nelem; ++i) { + next = (unsigned)strlen(keyword_list[indexes[i]]); + if (next != current) + break; + } + if (use_if) { + line(opt, "if (JSKW_LENGTH() == %u) {", current); + } else { + line(opt, " case %u:", current); + } + ++opt->indent_level; + generate_letter_switch(opt, indexes + same_length_begin, + i - same_length_begin, + current); + --opt->indent_level; + if (use_if) { + line(opt, "}"); + } + current = next; + } + if (!use_if) + line(opt, "}"); + line(opt, "JSKW_NO_MATCH()"); + free(indexes); +} + +int main(int argc, char **argv) +{ + struct gen_opt opt; + + if (argc < 2) { + opt.output = stdout; + } else { + opt.output = fopen(argv[1], "w"); + if (!opt.output) { + perror("fopen"); + exit(EXIT_FAILURE); + } + } + opt.indent_level = 1; + opt.use_if_threshold = 3; + opt.char_tail_test_threshold = 4; + + generate_switch(&opt); + + if (opt.output != stdout) { + if (fclose(opt.output)) { + perror("fclose"); + exit(EXIT_FAILURE); + } + } + + return EXIT_SUCCESS; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslibmath.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslibmath.h new file mode 100644 index 0000000..d90a04c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslibmath.h @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _LIBMATH_H +#define _LIBMATH_H + +#include +#include "jsversion.h" + +/* + * Use system provided math routines. + */ + +/* The right copysign function is not always named the same thing. */ +#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define js_copysign __builtin_copysign +#elif defined WINCE +#define js_copysign _copysign +#elif defined _WIN32 +#if _MSC_VER < 1400 +/* Try to work around apparent _copysign bustage in VC6 and VC7. */ +#define js_copysign js_copysign +extern double js_copysign(double, double); +#else +#define js_copysign _copysign +#endif +#else +#define js_copysign copysign +#endif + +#endif /* _LIBMATH_H */ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslock.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslock.cpp new file mode 100644 index 0000000..f91f0ed --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslock.cpp @@ -0,0 +1,1417 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifdef JS_THREADSAFE + +/* + * JS locking stubs. + */ +#include "jsstddef.h" +#include +#include +#include "jspubtd.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jstypes.h" +#include "jsbit.h" +#include "jscntxt.h" +#include "jsdtoa.h" +#include "jsgc.h" +#include "jsfun.h" /* for VALUE_IS_FUNCTION used by *_WRITE_BARRIER */ +#include "jslock.h" +#include "jsscope.h" +#include "jsstr.h" + +#define ReadWord(W) (W) + +/* Implement NativeCompareAndSwap. */ + +#if defined(_WIN32) && defined(_M_IX86) +#pragma warning( disable : 4035 ) +JS_BEGIN_EXTERN_C +extern long __cdecl +_InterlockedCompareExchange(long *volatile dest, long exchange, long comp); +JS_END_EXTERN_C +#pragma intrinsic(_InterlockedCompareExchange) + +static JS_ALWAYS_INLINE int +NativeCompareAndSwapHelper(jsword *w, jsword ov, jsword nv) +{ + _InterlockedCompareExchange(w, nv, ov); + __asm { + sete al + } +} + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(jsword *w, jsword ov, jsword nv) +{ + return (NativeCompareAndSwapHelper(w, ov, nv) & 1); +} + +#elif defined(XP_MACOSX) || defined(DARWIN) + +#include + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(jsword *w, jsword ov, jsword nv) +{ + /* Details on these functions available in the manpage for atomic */ +#if JS_BYTES_PER_WORD == 8 && JS_BYTES_PER_LONG != 8 + return OSAtomicCompareAndSwap64Barrier(ov, nv, (int64_t*) w); +#else + return OSAtomicCompareAndSwap32Barrier(ov, nv, (int32_t*) w); +#endif +} + +#elif defined(__GNUC__) && defined(__i386__) + +/* Note: This fails on 386 cpus, cmpxchgl is a >= 486 instruction */ +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(jsword *w, jsword ov, jsword nv) +{ + unsigned int res; + + __asm__ __volatile__ ( + "lock\n" + "cmpxchgl %2, (%1)\n" + "sete %%al\n" + "andl $1, %%eax\n" + : "=a" (res) + : "r" (w), "r" (nv), "a" (ov) + : "cc", "memory"); + return (int)res; +} + +#elif defined(__GNUC__) && defined(__x86_64__) +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(jsword *w, jsword ov, jsword nv) +{ + unsigned int res; + + __asm__ __volatile__ ( + "lock\n" + "cmpxchgq %2, (%1)\n" + "sete %%al\n" + "movzbl %%al, %%eax\n" + : "=a" (res) + : "r" (w), "r" (nv), "a" (ov) + : "cc", "memory"); + return (int)res; +} + +#elif defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC) + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(jsword *w, jsword ov, jsword nv) +{ +#if defined(__GNUC__) + unsigned int res; + JS_ASSERT(ov != nv); + asm volatile ("\ +stbar\n\ +cas [%1],%2,%3\n\ +cmp %2,%3\n\ +be,a 1f\n\ +mov 1,%0\n\ +mov 0,%0\n\ +1:" + : "=r" (res) + : "r" (w), "r" (ov), "r" (nv)); + return (int)res; +#else /* !__GNUC__ */ + extern int compare_and_swap(jsword*, jsword, jsword); + JS_ASSERT(ov != nv); + return compare_and_swap(w, ov, nv); +#endif +} + +#elif defined(AIX) + +#include + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(jsword *w, jsword ov, jsword nv) +{ + return !_check_lock((atomic_p)w, ov, nv); +} + +#elif defined(USE_ARM_KUSER) + +/* See https://bugzilla.mozilla.org/show_bug.cgi?id=429387 for a + * description of this ABI; this is a function provided at a fixed + * location by the kernel in the memory space of each process. + */ +typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr); +#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) + +JS_STATIC_ASSERT(sizeof(jsword) == sizeof(int)); + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(jsword *w, jsword ov, jsword nv) +{ + volatile int *vp = (volatile int *) w; + PRInt32 failed = 1; + + /* Loop until a __kernel_cmpxchg succeeds. See bug 446169 */ + do { + failed = __kernel_cmpxchg(ov, nv, vp); + } while (failed && *vp == ov); + return !failed; +} + +#elif JS_HAS_NATIVE_COMPARE_AND_SWAP + +#error "JS_HAS_NATIVE_COMPARE_AND_SWAP should be 0 if your platform lacks a compare-and-swap instruction." + +#endif /* arch-tests */ + +#if JS_HAS_NATIVE_COMPARE_AND_SWAP + +JSBool +js_CompareAndSwap(jsword *w, jsword ov, jsword nv) +{ + return !!NativeCompareAndSwap(w, ov, nv); +} + +#elif defined(NSPR_LOCK) + +# ifdef __GNUC__ +# warning "js_CompareAndSwap is implemented using NSSP lock" +# endif + +JSBool +js_CompareAndSwap(jsword *w, jsword ov, jsword nv) +{ + int result; + static PRLock *CompareAndSwapLock = JS_NEW_LOCK(); + + JS_ACQUIRE_LOCK(CompareAndSwapLock); + result = (*w == ov); + if (result) + *w = nv; + JS_RELEASE_LOCK(CompareAndSwapLock); + return result; +} + +#else /* !defined(NSPR_LOCK) */ + +#error "NSPR_LOCK should be on when the platform lacks native compare-and-swap." + +#endif + +#ifndef NSPR_LOCK + +struct JSFatLock { + int susp; + PRLock *slock; + PRCondVar *svar; + JSFatLock *next; + JSFatLock **prevp; +}; + +typedef struct JSFatLockTable { + JSFatLock *free; + JSFatLock *taken; +} JSFatLockTable; + +#define GLOBAL_LOCK_INDEX(id) (((uint32)(jsuword)(id)>>2) & global_locks_mask) + +static void +js_Dequeue(JSThinLock *); + +static PRLock **global_locks; +static uint32 global_lock_count = 1; +static uint32 global_locks_log2 = 0; +static uint32 global_locks_mask = 0; + +static void +js_LockGlobal(void *id) +{ + uint32 i = GLOBAL_LOCK_INDEX(id); + PR_Lock(global_locks[i]); +} + +static void +js_UnlockGlobal(void *id) +{ + uint32 i = GLOBAL_LOCK_INDEX(id); + PR_Unlock(global_locks[i]); +} + +#endif /* !NSPR_LOCK */ + +void +js_InitLock(JSThinLock *tl) +{ +#ifdef NSPR_LOCK + tl->owner = 0; + tl->fat = (JSFatLock*)JS_NEW_LOCK(); +#else + memset(tl, 0, sizeof(JSThinLock)); +#endif +} + +void +js_FinishLock(JSThinLock *tl) +{ +#ifdef NSPR_LOCK + tl->owner = 0xdeadbeef; + if (tl->fat) + JS_DESTROY_LOCK(((JSLock*)tl->fat)); +#else + JS_ASSERT(tl->owner == 0); + JS_ASSERT(tl->fat == NULL); +#endif +} + +#ifdef DEBUG_SCOPE_COUNT + +#include +#include "jsdhash.h" + +static FILE *logfp; +static JSDHashTable logtbl; + +typedef struct logentry { + JSDHashEntryStub stub; + char op; + const char *file; + int line; +} logentry; + +static void +logit(JSScope *scope, char op, const char *file, int line) +{ + logentry *entry; + + if (!logfp) { + logfp = fopen("/tmp/scope.log", "w"); + if (!logfp) + return; + setvbuf(logfp, NULL, _IONBF, 0); + } + fprintf(logfp, "%p %c %s %d\n", scope, op, file, line); + + if (!logtbl.entryStore && + !JS_DHashTableInit(&logtbl, JS_DHashGetStubOps(), NULL, + sizeof(logentry), 100)) { + return; + } + entry = (logentry *) JS_DHashTableOperate(&logtbl, scope, JS_DHASH_ADD); + if (!entry) + return; + entry->stub.key = scope; + entry->op = op; + entry->file = file; + entry->line = line; +} + +void +js_unlog_scope(JSScope *scope) +{ + if (!logtbl.entryStore) + return; + (void) JS_DHashTableOperate(&logtbl, scope, JS_DHASH_REMOVE); +} + +# define LOGIT(scope,op) logit(scope, op, __FILE__, __LINE__) + +#else + +# define LOGIT(scope,op) /* nothing */ + +#endif /* DEBUG_SCOPE_COUNT */ + +/* + * Return true if scope's ownercx, or the ownercx of a single-threaded scope + * for which ownercx is waiting to become multi-threaded and shared, is cx. + * That condition implies deadlock in ClaimScope if cx's thread were to wait + * to share scope. + * + * (i) rt->gcLock held + */ +static JSBool +WillDeadlock(JSTitle *title, JSContext *cx) +{ + JSContext *ownercx; + + do { + ownercx = title->ownercx; + if (ownercx == cx) { + JS_RUNTIME_METER(cx->runtime, deadlocksAvoided); + return JS_TRUE; + } + } while (ownercx && (title = ownercx->titleToShare) != NULL); + return JS_FALSE; +} + +/* + * Make title multi-threaded, i.e. share its ownership among contexts in rt + * using a "thin" or (if necessary due to contention) "fat" lock. Called only + * from ClaimTitle, immediately below, when we detect deadlock were we to wait + * for title's lock, because its ownercx is waiting on a title owned by the + * calling cx. + * + * (i) rt->gcLock held + */ +static void +ShareTitle(JSContext *cx, JSTitle *title) +{ + JSRuntime *rt; + JSTitle **todop; + + rt = cx->runtime; + if (title->u.link) { + for (todop = &rt->titleSharingTodo; *todop != title; + todop = &(*todop)->u.link) { + JS_ASSERT(*todop != NO_TITLE_SHARING_TODO); + } + *todop = title->u.link; + title->u.link = NULL; /* null u.link for sanity ASAP */ + JS_NOTIFY_ALL_CONDVAR(rt->titleSharingDone); + } + js_InitLock(&title->lock); + title->u.count = 0; + js_FinishSharingTitle(cx, title); +} + +/* + * js_FinishSharingTitle is the tail part of ShareTitle, split out to become a + * subroutine of JS_EndRequest too. The bulk of the work here involves making + * mutable strings in the title's object's slots be immutable. We have to do + * this because such strings will soon be available to multiple threads, so + * their buffers can't be realloc'd any longer in js_ConcatStrings, and their + * members can't be modified by js_ConcatStrings, js_MinimizeDependentStrings, + * or js_UndependString. + * + * The last bit of work done by js_FinishSharingTitle nulls title->ownercx and + * updates rt->sharedTitles. + */ + +void +js_FinishSharingTitle(JSContext *cx, JSTitle *title) +{ + JSObjectMap *map; + JSScope *scope; + JSObject *obj; + uint32 nslots, i; + jsval v; + + map = TITLE_TO_MAP(title); + if (!MAP_IS_NATIVE(map)) + return; + scope = (JSScope *)map; + + obj = scope->object; + if (obj) { + nslots = scope->map.freeslot; + for (i = 0; i != nslots; ++i) { + v = STOBJ_GET_SLOT(obj, i); + if (JSVAL_IS_STRING(v) && + !js_MakeStringImmutable(cx, JSVAL_TO_STRING(v))) { + /* + * FIXME bug 363059: The following error recovery changes + * runtime execution semantics, arbitrarily and silently + * ignoring errors except out-of-memory, which should have been + * reported through JS_ReportOutOfMemory at this point. + */ + STOBJ_SET_SLOT(obj, i, JSVAL_VOID); + } + } + } + + title->ownercx = NULL; /* NB: set last, after lock init */ + JS_RUNTIME_METER(cx->runtime, sharedTitles); +} + +/* + * Given a title with apparently non-null ownercx different from cx, try to + * set ownercx to cx, claiming exclusive (single-threaded) ownership of title. + * If we claim ownership, return true. Otherwise, we wait for ownercx to be + * set to null (indicating that title is multi-threaded); or if waiting would + * deadlock, we set ownercx to null ourselves via ShareTitle. In any case, + * once ownercx is null we return false. + */ +static JSBool +ClaimTitle(JSTitle *title, JSContext *cx) +{ + JSRuntime *rt; + JSContext *ownercx; + jsrefcount saveDepth; + PRStatus stat; + + rt = cx->runtime; + JS_RUNTIME_METER(rt, claimAttempts); + JS_LOCK_GC(rt); + + /* Reload in case ownercx went away while we blocked on the lock. */ + while ((ownercx = title->ownercx) != NULL) { + /* + * Avoid selflock if ownercx is dead, or is not running a request, or + * has the same thread as cx. Set title->ownercx to cx so that the + * matching JS_UNLOCK_SCOPE or JS_UNLOCK_OBJ macro call will take the + * fast path around the corresponding js_UnlockTitle or js_UnlockObj + * function call. + * + * If title->u.link is non-null, title has already been inserted on + * the rt->titleSharingTodo list, because another thread's context + * already wanted to lock title while ownercx was running a request. + * We can't claim any title whose u.link is non-null at this point, + * even if ownercx->requestDepth is 0 (see below where we suspend our + * request before waiting on rt->titleSharingDone). + */ + if (!title->u.link && + (!js_ValidContextPointer(rt, ownercx) || + !ownercx->requestDepth || + ownercx->thread == cx->thread)) { + JS_ASSERT(title->u.count == 0); + title->ownercx = cx; + JS_UNLOCK_GC(rt); + JS_RUNTIME_METER(rt, claimedTitles); + return JS_TRUE; + } + + /* + * Avoid deadlock if title's owner context is waiting on a title that + * we own, by revoking title's ownership. This approach to deadlock + * avoidance works because the engine never nests title locks. + * + * If cx could hold locks on ownercx->titleToShare, or if ownercx could + * hold locks on title, we would need to keep reentrancy counts for all + * such "flyweight" (ownercx != NULL) locks, so that control would + * unwind properly once these locks became "thin" or "fat". The engine + * promotes a title from exclusive to shared access only when locking, + * never when holding or unlocking. + * + * Avoid deadlock before any of this title/context cycle detection if + * cx is on the active GC's thread, because in that case, no requests + * will run until the GC completes. Any title wanted by the GC (from + * a finalizer) that can't be claimed must become shared. + */ + if (rt->gcThread == cx->thread || + (ownercx->titleToShare && + WillDeadlock(ownercx->titleToShare, cx))) { + ShareTitle(cx, title); + break; + } + + /* + * Thanks to the non-zero NO_TITLE_SHARING_TODO link terminator, we + * can decide whether title is on rt->titleSharingTodo with a single + * non-null test, and avoid double-insertion bugs. + */ + if (!title->u.link) { + title->u.link = rt->titleSharingTodo; + rt->titleSharingTodo = title; + js_HoldObjectMap(cx, TITLE_TO_MAP(title)); + } + + /* + * Inline JS_SuspendRequest before we wait on rt->titleSharingDone, + * saving and clearing cx->requestDepth so we don't deadlock if the + * GC needs to run on ownercx. + * + * Unlike JS_SuspendRequest and JS_EndRequest, we must take care not + * to decrement rt->requestCount if cx is active on the GC's thread, + * because the GC has already reduced rt->requestCount to exclude all + * such such contexts. + */ + saveDepth = cx->requestDepth; + if (saveDepth) { + cx->requestDepth = 0; + if (rt->gcThread != cx->thread) { + JS_ASSERT(rt->requestCount > 0); + rt->requestCount--; + if (rt->requestCount == 0) + JS_NOTIFY_REQUEST_DONE(rt); + } + } + + /* + * We know that some other thread's context owns title, which is now + * linked onto rt->titleSharingTodo, awaiting the end of that other + * thread's request. So it is safe to wait on rt->titleSharingDone. + */ + cx->titleToShare = title; + stat = PR_WaitCondVar(rt->titleSharingDone, PR_INTERVAL_NO_TIMEOUT); + JS_ASSERT(stat != PR_FAILURE); + + /* + * Inline JS_ResumeRequest after waiting on rt->titleSharingDone, + * restoring cx->requestDepth. Same note as above for the inlined, + * specialized JS_SuspendRequest code: beware rt->gcThread. + */ + if (saveDepth) { + if (rt->gcThread != cx->thread) { + while (rt->gcLevel > 0) + JS_AWAIT_GC_DONE(rt); + rt->requestCount++; + } + cx->requestDepth = saveDepth; + } + + /* + * Don't clear cx->titleToShare until after we're through waiting on + * all condition variables protected by rt->gcLock -- that includes + * rt->titleSharingDone *and* rt->gcDone (hidden in JS_AWAIT_GC_DONE, + * in the inlined JS_ResumeRequest code immediately above). + * + * Otherwise, the GC could easily deadlock with another thread that + * owns a title wanted by a finalizer. By keeping cx->titleToShare + * set till here, we ensure that such deadlocks are detected, which + * results in the finalized object's title being shared (it must, of + * course, have other, live objects sharing it). + */ + cx->titleToShare = NULL; + } + + JS_UNLOCK_GC(rt); + return JS_FALSE; +} + +/* Exported to js.c, which calls it via OBJ_GET_* and JSVAL_IS_* macros. */ +JS_FRIEND_API(jsval) +js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot) +{ + jsval v; + JSScope *scope; + JSTitle *title; +#ifndef NSPR_LOCK + JSThinLock *tl; + jsword me; +#endif + + /* + * We handle non-native objects via JSObjectOps.getRequiredSlot, treating + * all slots starting from 0 as required slots. A property definition or + * some prior arrangement must have allocated slot. + * + * Note once again (see jspubtd.h, before JSGetRequiredSlotOp's typedef) + * the crucial distinction between a |required slot number| that's passed + * to the get/setRequiredSlot JSObjectOps, and a |reserved slot index| + * passed to the JS_Get/SetReservedSlot APIs. + */ + if (!OBJ_IS_NATIVE(obj)) + return OBJ_GET_REQUIRED_SLOT(cx, obj, slot); + + /* + * Native object locking is inlined here to optimize the single-threaded + * and contention-free multi-threaded cases. + */ + scope = OBJ_SCOPE(obj); + title = &scope->title; + JS_ASSERT(title->ownercx != cx); + JS_ASSERT(slot < obj->map->freeslot); + + /* + * Avoid locking if called from the GC. Also avoid locking an object + * owning a sealed scope. If neither of those special cases applies, try + * to claim scope's flyweight lock from whatever context may have had it in + * an earlier request. + */ + if (CX_THREAD_IS_RUNNING_GC(cx) || + (SCOPE_IS_SEALED(scope) && scope->object == obj) || + (title->ownercx && ClaimTitle(title, cx))) { + return STOBJ_GET_SLOT(obj, slot); + } + +#ifndef NSPR_LOCK + tl = &title->lock; + me = CX_THINLOCK_ID(cx); + JS_ASSERT(CURRENT_THREAD_IS_ME(me)); + if (NativeCompareAndSwap(&tl->owner, 0, me)) { + /* + * Got the lock with one compare-and-swap. Even so, someone else may + * have mutated obj so it now has its own scope and lock, which would + * require either a restart from the top of this routine, or a thin + * lock release followed by fat lock acquisition. + */ + if (scope == OBJ_SCOPE(obj)) { + v = STOBJ_GET_SLOT(obj, slot); + if (!NativeCompareAndSwap(&tl->owner, me, 0)) { + /* Assert that scope locks never revert to flyweight. */ + JS_ASSERT(title->ownercx != cx); + LOGIT(scope, '1'); + title->u.count = 1; + js_UnlockObj(cx, obj); + } + return v; + } + if (!NativeCompareAndSwap(&tl->owner, me, 0)) + js_Dequeue(tl); + } + else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) { + return STOBJ_GET_SLOT(obj, slot); + } +#endif + + js_LockObj(cx, obj); + v = STOBJ_GET_SLOT(obj, slot); + + /* + * Test whether cx took ownership of obj's scope during js_LockObj. + * + * This does not mean that a given scope reverted to flyweight from "thin" + * or "fat" -- it does mean that obj's map pointer changed due to another + * thread setting a property, requiring obj to cease sharing a prototype + * object's scope (whose lock was not flyweight, else we wouldn't be here + * in the first place!). + */ + title = &OBJ_SCOPE(obj)->title; + if (title->ownercx != cx) + js_UnlockTitle(cx, title); + return v; +} + +void +js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v) +{ + JSTitle *title; + JSScope *scope; +#ifndef NSPR_LOCK + JSThinLock *tl; + jsword me; +#endif + + /* Any string stored in a thread-safe object must be immutable. */ + if (JSVAL_IS_STRING(v) && + !js_MakeStringImmutable(cx, JSVAL_TO_STRING(v))) { + /* FIXME bug 363059: See comments in js_FinishSharingScope. */ + v = JSVAL_NULL; + } + + /* + * We handle non-native objects via JSObjectOps.setRequiredSlot, as above + * for the Get case. + */ + if (!OBJ_IS_NATIVE(obj)) { + OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v); + return; + } + + /* + * Native object locking is inlined here to optimize the single-threaded + * and contention-free multi-threaded cases. + */ + scope = OBJ_SCOPE(obj); + title = &scope->title; + JS_ASSERT(title->ownercx != cx); + JS_ASSERT(slot < obj->map->freeslot); + + /* + * Avoid locking if called from the GC. Also avoid locking an object + * owning a sealed scope. If neither of those special cases applies, try + * to claim scope's flyweight lock from whatever context may have had it in + * an earlier request. + */ + if (CX_THREAD_IS_RUNNING_GC(cx) || + (SCOPE_IS_SEALED(scope) && scope->object == obj) || + (title->ownercx && ClaimTitle(title, cx))) { + LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, v); + return; + } + +#ifndef NSPR_LOCK + tl = &title->lock; + me = CX_THINLOCK_ID(cx); + JS_ASSERT(CURRENT_THREAD_IS_ME(me)); + if (NativeCompareAndSwap(&tl->owner, 0, me)) { + if (scope == OBJ_SCOPE(obj)) { + LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, v); + if (!NativeCompareAndSwap(&tl->owner, me, 0)) { + /* Assert that scope locks never revert to flyweight. */ + JS_ASSERT(title->ownercx != cx); + LOGIT(scope, '1'); + title->u.count = 1; + js_UnlockObj(cx, obj); + } + return; + } + if (!NativeCompareAndSwap(&tl->owner, me, 0)) + js_Dequeue(tl); + } + else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) { + LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, v); + return; + } +#endif + + js_LockObj(cx, obj); + LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, v); + + /* + * Same drill as above, in js_GetSlotThreadSafe. + */ + title = &OBJ_SCOPE(obj)->title; + if (title->ownercx != cx) + js_UnlockTitle(cx, title); +} + +#ifndef NSPR_LOCK + +static JSFatLock * +NewFatlock() +{ + JSFatLock *fl = (JSFatLock *)malloc(sizeof(JSFatLock)); /* for now */ + if (!fl) return NULL; + fl->susp = 0; + fl->next = NULL; + fl->prevp = NULL; + fl->slock = PR_NewLock(); + fl->svar = PR_NewCondVar(fl->slock); + return fl; +} + +static void +DestroyFatlock(JSFatLock *fl) +{ + PR_DestroyLock(fl->slock); + PR_DestroyCondVar(fl->svar); + free(fl); +} + +static JSFatLock * +ListOfFatlocks(int listc) +{ + JSFatLock *m; + JSFatLock *m0; + int i; + + JS_ASSERT(listc>0); + m0 = m = NewFatlock(); + for (i=1; inext = NewFatlock(); + m = m->next; + } + return m0; +} + +static void +DeleteListOfFatlocks(JSFatLock *m) +{ + JSFatLock *m0; + for (; m; m=m0) { + m0 = m->next; + DestroyFatlock(m); + } +} + +static JSFatLockTable *fl_list_table = NULL; +static uint32 fl_list_table_len = 0; +static uint32 fl_list_chunk_len = 0; + +static JSFatLock * +GetFatlock(void *id) +{ + JSFatLock *m; + + uint32 i = GLOBAL_LOCK_INDEX(id); + if (fl_list_table[i].free == NULL) { +#ifdef DEBUG + if (fl_list_table[i].taken) + printf("Ran out of fat locks!\n"); +#endif + fl_list_table[i].free = ListOfFatlocks(fl_list_chunk_len); + } + m = fl_list_table[i].free; + fl_list_table[i].free = m->next; + m->susp = 0; + m->next = fl_list_table[i].taken; + m->prevp = &fl_list_table[i].taken; + if (fl_list_table[i].taken) + fl_list_table[i].taken->prevp = &m->next; + fl_list_table[i].taken = m; + return m; +} + +static void +PutFatlock(JSFatLock *m, void *id) +{ + uint32 i; + if (m == NULL) + return; + + /* Unlink m from fl_list_table[i].taken. */ + *m->prevp = m->next; + if (m->next) + m->next->prevp = m->prevp; + + /* Insert m in fl_list_table[i].free. */ + i = GLOBAL_LOCK_INDEX(id); + m->next = fl_list_table[i].free; + fl_list_table[i].free = m; +} + +#endif /* !NSPR_LOCK */ + +JSBool +js_SetupLocks(int listc, int globc) +{ +#ifndef NSPR_LOCK + uint32 i; + + if (global_locks) + return JS_TRUE; +#ifdef DEBUG + if (listc > 10000 || listc < 0) /* listc == fat lock list chunk length */ + printf("Bad number %d in js_SetupLocks()!\n", listc); + if (globc > 100 || globc < 0) /* globc == number of global locks */ + printf("Bad number %d in js_SetupLocks()!\n", listc); +#endif + global_locks_log2 = JS_CeilingLog2(globc); + global_locks_mask = JS_BITMASK(global_locks_log2); + global_lock_count = JS_BIT(global_locks_log2); + global_locks = (PRLock **) malloc(global_lock_count * sizeof(PRLock*)); + if (!global_locks) + return JS_FALSE; + for (i = 0; i < global_lock_count; i++) { + global_locks[i] = PR_NewLock(); + if (!global_locks[i]) { + global_lock_count = i; + js_CleanupLocks(); + return JS_FALSE; + } + } + fl_list_table = (JSFatLockTable *) malloc(i * sizeof(JSFatLockTable)); + if (!fl_list_table) { + js_CleanupLocks(); + return JS_FALSE; + } + fl_list_table_len = global_lock_count; + for (i = 0; i < global_lock_count; i++) + fl_list_table[i].free = fl_list_table[i].taken = NULL; + fl_list_chunk_len = listc; +#endif /* !NSPR_LOCK */ + return JS_TRUE; +} + +void +js_CleanupLocks() +{ +#ifndef NSPR_LOCK + uint32 i; + + if (global_locks) { + for (i = 0; i < global_lock_count; i++) + PR_DestroyLock(global_locks[i]); + free(global_locks); + global_locks = NULL; + global_lock_count = 1; + global_locks_log2 = 0; + global_locks_mask = 0; + } + if (fl_list_table) { + for (i = 0; i < fl_list_table_len; i++) { + DeleteListOfFatlocks(fl_list_table[i].free); + fl_list_table[i].free = NULL; + DeleteListOfFatlocks(fl_list_table[i].taken); + fl_list_table[i].taken = NULL; + } + free(fl_list_table); + fl_list_table = NULL; + fl_list_table_len = 0; + } +#endif /* !NSPR_LOCK */ +} + +#ifdef NSPR_LOCK + +static JS_ALWAYS_INLINE void +ThinLock(JSThinLock *tl, jsword me) +{ + JS_ACQUIRE_LOCK((JSLock *) tl->fat); + tl->owner = me; +} + +static JS_ALWAYS_INLINE void +ThinUnlock(JSThinLock *tl, jsword /*me*/) +{ + tl->owner = 0; + JS_RELEASE_LOCK((JSLock *) tl->fat); +} + +#else + +/* + * Fast locking and unlocking is implemented by delaying the allocation of a + * system lock (fat lock) until contention. As long as a locking thread A + * runs uncontended, the lock is represented solely by storing A's identity in + * the object being locked. + * + * If another thread B tries to lock the object currently locked by A, B is + * enqueued into a fat lock structure (which might have to be allocated and + * pointed to by the object), and suspended using NSPR conditional variables + * (wait). A wait bit (Bacon bit) is set in the lock word of the object, + * signalling to A that when releasing the lock, B must be dequeued and + * notified. + * + * The basic operation of the locking primitives (js_Lock, js_Unlock, + * js_Enqueue, and js_Dequeue) is compare-and-swap. Hence, when locking into + * the word pointed at by p, compare-and-swap(p, 0, A) success implies that p + * is unlocked. Similarly, when unlocking p, if compare-and-swap(p, A, 0) + * succeeds this implies that p is uncontended (no one is waiting because the + * wait bit is not set). + * + * When dequeueing, the lock is released, and one of the threads suspended on + * the lock is notified. If other threads still are waiting, the wait bit is + * kept (in js_Enqueue), and if not, the fat lock is deallocated. + * + * The functions js_Enqueue, js_Dequeue, js_SuspendThread, and js_ResumeThread + * are serialized using a global lock. For scalability, a hashtable of global + * locks is used, which is indexed modulo the thin lock pointer. + */ + +/* + * Invariants: + * (i) global lock is held + * (ii) fl->susp >= 0 + */ +static int +js_SuspendThread(JSThinLock *tl) +{ + JSFatLock *fl; + PRStatus stat; + + if (tl->fat == NULL) + fl = tl->fat = GetFatlock(tl); + else + fl = tl->fat; + JS_ASSERT(fl->susp >= 0); + fl->susp++; + PR_Lock(fl->slock); + js_UnlockGlobal(tl); + stat = PR_WaitCondVar(fl->svar, PR_INTERVAL_NO_TIMEOUT); + JS_ASSERT(stat != PR_FAILURE); + PR_Unlock(fl->slock); + js_LockGlobal(tl); + fl->susp--; + if (fl->susp == 0) { + PutFatlock(fl, tl); + tl->fat = NULL; + } + return tl->fat == NULL; +} + +/* + * (i) global lock is held + * (ii) fl->susp > 0 + */ +static void +js_ResumeThread(JSThinLock *tl) +{ + JSFatLock *fl = tl->fat; + PRStatus stat; + + JS_ASSERT(fl != NULL); + JS_ASSERT(fl->susp > 0); + PR_Lock(fl->slock); + js_UnlockGlobal(tl); + stat = PR_NotifyCondVar(fl->svar); + JS_ASSERT(stat != PR_FAILURE); + PR_Unlock(fl->slock); +} + +static void +js_Enqueue(JSThinLock *tl, jsword me) +{ + jsword o, n; + + js_LockGlobal(tl); + for (;;) { + o = ReadWord(tl->owner); + n = Thin_SetWait(o); + if (o != 0 && NativeCompareAndSwap(&tl->owner, o, n)) { + if (js_SuspendThread(tl)) + me = Thin_RemoveWait(me); + else + me = Thin_SetWait(me); + } + else if (NativeCompareAndSwap(&tl->owner, 0, me)) { + js_UnlockGlobal(tl); + return; + } + } +} + +static void +js_Dequeue(JSThinLock *tl) +{ + jsword o; + + js_LockGlobal(tl); + o = ReadWord(tl->owner); + JS_ASSERT(Thin_GetWait(o) != 0); + JS_ASSERT(tl->fat != NULL); + if (!NativeCompareAndSwap(&tl->owner, o, 0)) /* release it */ + JS_ASSERT(0); + js_ResumeThread(tl); +} + +static JS_ALWAYS_INLINE void +ThinLock(JSThinLock *tl, jsword me) +{ + JS_ASSERT(CURRENT_THREAD_IS_ME(me)); + if (NativeCompareAndSwap(&tl->owner, 0, me)) + return; + if (Thin_RemoveWait(ReadWord(tl->owner)) != me) + js_Enqueue(tl, me); +#ifdef DEBUG + else + JS_ASSERT(0); +#endif +} + +static JS_ALWAYS_INLINE void +ThinUnlock(JSThinLock *tl, jsword me) +{ + JS_ASSERT(CURRENT_THREAD_IS_ME(me)); + + /* + * Since we can race with the NativeCompareAndSwap in js_Enqueue, we need + * to use a C_A_S here as well -- Arjan van de Ven 30/1/08 + */ + if (NativeCompareAndSwap(&tl->owner, me, 0)) + return; + + JS_ASSERT(Thin_GetWait(tl->owner)); + if (Thin_RemoveWait(ReadWord(tl->owner)) == me) + js_Dequeue(tl); +#ifdef DEBUG + else + JS_ASSERT(0); /* unbalanced unlock */ +#endif +} + +#endif /* !NSPR_LOCK */ + +void +js_Lock(JSContext *cx, JSThinLock *tl) +{ + ThinLock(tl, CX_THINLOCK_ID(cx)); +} + +void +js_Unlock(JSContext *cx, JSThinLock *tl) +{ + ThinUnlock(tl, CX_THINLOCK_ID(cx)); +} + +void +js_LockRuntime(JSRuntime *rt) +{ + PR_Lock(rt->rtLock); +#ifdef DEBUG + rt->rtLockOwner = js_CurrentThreadId(); +#endif +} + +void +js_UnlockRuntime(JSRuntime *rt) +{ +#ifdef DEBUG + rt->rtLockOwner = 0; +#endif + PR_Unlock(rt->rtLock); +} + +void +js_LockTitle(JSContext *cx, JSTitle *title) +{ + jsword me = CX_THINLOCK_ID(cx); + + JS_ASSERT(CURRENT_THREAD_IS_ME(me)); + JS_ASSERT(title->ownercx != cx); + if (CX_THREAD_IS_RUNNING_GC(cx)) + return; + if (title->ownercx && ClaimTitle(title, cx)) + return; + + if (Thin_RemoveWait(ReadWord(title->lock.owner)) == me) { + JS_ASSERT(title->u.count > 0); + LOGIT(scope, '+'); + title->u.count++; + } else { + ThinLock(&title->lock, me); + JS_ASSERT(title->u.count == 0); + LOGIT(scope, '1'); + title->u.count = 1; + } +} + +void +js_UnlockTitle(JSContext *cx, JSTitle *title) +{ + jsword me = CX_THINLOCK_ID(cx); + + /* We hope compilers use me instead of reloading cx->thread in the macro. */ + if (CX_THREAD_IS_RUNNING_GC(cx)) + return; + if (cx->lockedSealedTitle == title) { + cx->lockedSealedTitle = NULL; + return; + } + + /* + * If title->ownercx is not null, it's likely that two contexts not using + * requests nested locks for title. The first context, cx here, claimed + * title; the second, title->ownercx here, re-claimed it because the first + * was not in a request, or was on the same thread. We don't want to keep + * track of such nesting, because it penalizes the common non-nested case. + * Instead of asserting here and silently coping, we simply re-claim title + * for cx and return. + * + * See http://bugzilla.mozilla.org/show_bug.cgi?id=229200 for a real world + * case where an asymmetric thread model (Mozilla's main thread is known + * to be the only thread that runs the GC) combined with multiple contexts + * per thread has led to such request-less nesting. + */ + if (title->ownercx) { + JS_ASSERT(title->u.count == 0); + JS_ASSERT(title->lock.owner == 0); + title->ownercx = cx; + return; + } + + JS_ASSERT(title->u.count > 0); + if (Thin_RemoveWait(ReadWord(title->lock.owner)) != me) { + JS_ASSERT(0); /* unbalanced unlock */ + return; + } + LOGIT(scope, '-'); + if (--title->u.count == 0) + ThinUnlock(&title->lock, me); +} + +/* + * NB: oldtitle may be null if our caller is js_GetMutableScope and it just + * dropped the last reference to oldtitle. + */ +void +js_TransferTitle(JSContext *cx, JSTitle *oldtitle, JSTitle *newtitle) +{ + JS_ASSERT(JS_IS_TITLE_LOCKED(cx, newtitle)); + + /* + * If the last reference to oldtitle went away, newtitle needs no lock + * state update. + */ + if (!oldtitle) + return; + JS_ASSERT(JS_IS_TITLE_LOCKED(cx, oldtitle)); + + /* + * Special case in js_LockTitle and js_UnlockTitle for the GC calling + * code that locks, unlocks, or mutates. Nothing to do in these cases, + * because title and newtitle were "locked" by the GC thread, so neither + * was actually locked. + */ + if (CX_THREAD_IS_RUNNING_GC(cx)) + return; + + /* + * Special case in js_LockObj and js_UnlockTitle for locking the sealed + * scope of an object that owns that scope (the prototype or mutated obj + * for which OBJ_SCOPE(obj)->object == obj), and unlocking it. + */ + JS_ASSERT(cx->lockedSealedTitle != newtitle); + if (cx->lockedSealedTitle == oldtitle) { + JS_ASSERT(newtitle->ownercx == cx || + (!newtitle->ownercx && newtitle->u.count == 1)); + cx->lockedSealedTitle = NULL; + return; + } + + /* + * If oldtitle is single-threaded, there's nothing to do. + */ + if (oldtitle->ownercx) { + JS_ASSERT(oldtitle->ownercx == cx); + JS_ASSERT(newtitle->ownercx == cx || + (!newtitle->ownercx && newtitle->u.count == 1)); + return; + } + + /* + * We transfer oldtitle->u.count only if newtitle is not single-threaded. + * Flow unwinds from here through some number of JS_UNLOCK_TITLE and/or + * JS_UNLOCK_OBJ macro calls, which will decrement newtitle->u.count only + * if they find newtitle->ownercx != cx. + */ + if (newtitle->ownercx != cx) { + JS_ASSERT(!newtitle->ownercx); + newtitle->u.count = oldtitle->u.count; + } + + /* + * Reset oldtitle's lock state so that it is completely unlocked. + */ + LOGIT(oldscope, '0'); + oldtitle->u.count = 0; + ThinUnlock(&oldtitle->lock, CX_THINLOCK_ID(cx)); +} + +void +js_LockObj(JSContext *cx, JSObject *obj) +{ + JSScope *scope; + JSTitle *title; + + JS_ASSERT(OBJ_IS_NATIVE(obj)); + + /* + * We must test whether the GC is calling and return without mutating any + * state, especially cx->lockedSealedScope. Note asymmetry with respect to + * js_UnlockObj, which is a thin-layer on top of js_UnlockTitle. + */ + if (CX_THREAD_IS_RUNNING_GC(cx)) + return; + + for (;;) { + scope = OBJ_SCOPE(obj); + title = &scope->title; + if (SCOPE_IS_SEALED(scope) && scope->object == obj && + !cx->lockedSealedTitle) { + cx->lockedSealedTitle = title; + return; + } + + js_LockTitle(cx, title); + + /* If obj still has this scope, we're done. */ + if (scope == OBJ_SCOPE(obj)) + return; + + /* Lost a race with a mutator; retry with obj's new scope. */ + js_UnlockTitle(cx, title); + } +} + +void +js_UnlockObj(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(OBJ_IS_NATIVE(obj)); + js_UnlockTitle(cx, &OBJ_SCOPE(obj)->title); +} + +void +js_InitTitle(JSContext *cx, JSTitle *title) +{ +#ifdef JS_THREADSAFE + title->ownercx = cx; + memset(&title->lock, 0, sizeof title->lock); + + /* + * Set u.link = NULL, not u.count = 0, in case the target architecture's + * null pointer has a non-zero integer representation. + */ + title->u.link = NULL; + +#ifdef JS_DEBUG_TITLE_LOCKS + title->file[0] = title->file[1] = title->file[2] = title->file[3] = NULL; + title->line[0] = title->line[1] = title->line[2] = title->line[3] = 0; +#endif +#endif +} + +void +js_FinishTitle(JSContext *cx, JSTitle *title) +{ +#ifdef JS_THREADSAFE + /* Title must be single-threaded at this point, so set ownercx. */ + JS_ASSERT(title->u.count == 0); + title->ownercx = cx; + js_FinishLock(&title->lock); +#endif +} + +#ifdef DEBUG + +JSBool +js_IsRuntimeLocked(JSRuntime *rt) +{ + return js_CurrentThreadId() == rt->rtLockOwner; +} + +JSBool +js_IsObjLocked(JSContext *cx, JSObject *obj) +{ + JSScope *scope = OBJ_SCOPE(obj); + + return MAP_IS_NATIVE(&scope->map) && js_IsTitleLocked(cx, &scope->title); +} + +JSBool +js_IsTitleLocked(JSContext *cx, JSTitle *title) +{ + /* Special case: the GC locking any object's title, see js_LockTitle. */ + if (CX_THREAD_IS_RUNNING_GC(cx)) + return JS_TRUE; + + /* Special case: locked object owning a sealed scope, see js_LockObj. */ + if (cx->lockedSealedTitle == title) + return JS_TRUE; + + /* + * General case: the title is either exclusively owned (by cx), or it has + * a thin or fat lock to cope with shared (concurrent) ownership. + */ + if (title->ownercx) { + JS_ASSERT(title->ownercx == cx || title->ownercx->thread == cx->thread); + return JS_TRUE; + } + return js_CurrentThreadId() == + ((JSThread *)Thin_RemoveWait(ReadWord(title->lock.owner)))->id; +} + +#ifdef JS_DEBUG_TITLE_LOCKS +void +js_SetScopeInfo(JSScope *scope, const char *file, int line) +{ + JSTitle *title = &scope->title; + if (!title->ownercx) { + jsrefcount count = title->u.count; + JS_ASSERT_IF(!SCOPE_IS_SEALED(scope), count > 0); + JS_ASSERT(count <= 4); + title->file[count - 1] = file; + title->line[count - 1] = line; + } +} +#endif /* JS_DEBUG_TITLE_LOCKS */ +#endif /* DEBUG */ +#endif /* JS_THREADSAFE */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslock.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslock.h new file mode 100644 index 0000000..548e082 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslock.h @@ -0,0 +1,311 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef jslock_h__ +#define jslock_h__ + +#include "jstypes.h" +#include "jsprvtd.h" /* for JSScope, etc. */ +#include "jspubtd.h" /* for JSRuntime, etc. */ + +#ifdef JS_THREADSAFE +# include "pratom.h" +# include "prlock.h" +# include "prcvar.h" +# include "prthread.h" +#endif + +JS_BEGIN_EXTERN_C + +#ifdef JS_THREADSAFE + +#if (defined(_WIN32) && defined(_M_IX86)) || \ + (defined(__GNUC__) && defined(__i386__)) || \ + (defined(__GNUC__) && defined(__x86_64__)) || \ + (defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC)) || \ + defined(AIX) || \ + defined(USE_ARM_KUSER) +# define JS_HAS_NATIVE_COMPARE_AND_SWAP 1 +#else +# define JS_HAS_NATIVE_COMPARE_AND_SWAP 0 +#endif + +#if defined(JS_USE_ONLY_NSPR_LOCKS) || !JS_HAS_NATIVE_COMPARE_AND_SWAP +# define NSPR_LOCK 1 +#else +# undef NSPR_LOCK +#endif + +#define Thin_GetWait(W) ((jsword)(W) & 0x1) +#define Thin_SetWait(W) ((jsword)(W) | 0x1) +#define Thin_RemoveWait(W) ((jsword)(W) & ~0x1) + +typedef struct JSFatLock JSFatLock; + +typedef struct JSThinLock { + jsword owner; + JSFatLock *fat; +} JSThinLock; + +#define CX_THINLOCK_ID(cx) ((jsword)(cx)->thread) +#define CURRENT_THREAD_IS_ME(me) (((JSThread *)me)->id == js_CurrentThreadId()) + +typedef PRLock JSLock; + +typedef struct JSTitle JSTitle; + +struct JSTitle { + JSContext *ownercx; /* creating context, NULL if shared */ + JSThinLock lock; /* binary semaphore protecting title */ + union { /* union lockful and lock-free state: */ + jsrefcount count; /* lock entry count for reentrancy */ + JSTitle *link; /* next link in rt->titleSharingTodo */ + } u; +#ifdef JS_DEBUG_TITLE_LOCKS + const char *file[4]; /* file where lock was (re-)taken */ + unsigned int line[4]; /* line where lock was (re-)taken */ +#endif +}; + +/* + * Title structures must be immediately preceded by JSObjectMap structures for + * maps that use titles for threadsafety. This is enforced by assertion in + * jsscope.h; see bug 408416 for future remedies to this somewhat fragile + * architecture. + */ + +#define TITLE_TO_MAP(title) \ + ((JSObjectMap *)((char *)(title) - sizeof(JSObjectMap))) + +/* + * Atomic increment and decrement for a reference counter, given jsrefcount *p. + * NB: jsrefcount is int32, aka PRInt32, so that pratom.h functions work. + */ +#define JS_ATOMIC_INCREMENT(p) PR_AtomicIncrement((PRInt32 *)(p)) +#define JS_ATOMIC_DECREMENT(p) PR_AtomicDecrement((PRInt32 *)(p)) +#define JS_ATOMIC_ADD(p,v) PR_AtomicAdd((PRInt32 *)(p), (PRInt32)(v)) + +#define js_CurrentThreadId() (jsword)PR_GetCurrentThread() +#define JS_NEW_LOCK() PR_NewLock() +#define JS_DESTROY_LOCK(l) PR_DestroyLock(l) +#define JS_ACQUIRE_LOCK(l) PR_Lock(l) +#define JS_RELEASE_LOCK(l) PR_Unlock(l) + +#define JS_NEW_CONDVAR(l) PR_NewCondVar(l) +#define JS_DESTROY_CONDVAR(cv) PR_DestroyCondVar(cv) +#define JS_WAIT_CONDVAR(cv,to) PR_WaitCondVar(cv,to) +#define JS_NO_TIMEOUT PR_INTERVAL_NO_TIMEOUT +#define JS_NOTIFY_CONDVAR(cv) PR_NotifyCondVar(cv) +#define JS_NOTIFY_ALL_CONDVAR(cv) PR_NotifyAllCondVar(cv) + +#ifdef JS_DEBUG_TITLE_LOCKS + +#define SET_OBJ_INFO(obj_, file_, line_) \ + SET_SCOPE_INFO(OBJ_SCOPE(obj_), file_, line_) + +#define SET_SCOPE_INFO(scope_, file_, line_) \ + js_SetScopeInfo(scope_, file_, line_) + +#endif + +#define JS_LOCK(cx, tl) js_Lock(cx, tl) +#define JS_UNLOCK(cx, tl) js_Unlock(cx, tl) + +#define JS_LOCK_RUNTIME(rt) js_LockRuntime(rt) +#define JS_UNLOCK_RUNTIME(rt) js_UnlockRuntime(rt) + +/* + * NB: The JS_LOCK_OBJ and JS_UNLOCK_OBJ macros work *only* on native objects + * (objects for which OBJ_IS_NATIVE returns true). All uses of these macros in + * the engine are predicated on OBJ_IS_NATIVE or equivalent checks. These uses + * are for optimizations above the JSObjectOps layer, under which object locks + * normally hide. + */ +#define JS_LOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->title.ownercx == (cx)) \ + ? (void)0 \ + : (js_LockObj(cx, obj), \ + SET_OBJ_INFO(obj,__FILE__,__LINE__))) +#define JS_UNLOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->title.ownercx == (cx)) \ + ? (void)0 : js_UnlockObj(cx, obj)) + +#define JS_LOCK_TITLE(cx,title) \ + ((title)->ownercx == (cx) ? (void)0 \ + : (js_LockTitle(cx, (title)), \ + SET_TITLE_INFO(title,__FILE__,__LINE__))) + +#define JS_UNLOCK_TITLE(cx,title) ((title)->ownercx == (cx) ? (void)0 \ + : js_UnlockTitle(cx, title)) + +#define JS_LOCK_SCOPE(cx,scope) JS_LOCK_TITLE(cx,&(scope)->title) +#define JS_UNLOCK_SCOPE(cx,scope) JS_UNLOCK_TITLE(cx,&(scope)->title) + +#define JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope) \ + js_TransferTitle(cx, &scope->title, &newscope->title) + + +extern void js_Lock(JSContext *cx, JSThinLock *tl); +extern void js_Unlock(JSContext *cx, JSThinLock *tl); +extern void js_LockRuntime(JSRuntime *rt); +extern void js_UnlockRuntime(JSRuntime *rt); +extern void js_LockObj(JSContext *cx, JSObject *obj); +extern void js_UnlockObj(JSContext *cx, JSObject *obj); +extern void js_InitTitle(JSContext *cx, JSTitle *title); +extern void js_FinishTitle(JSContext *cx, JSTitle *title); +extern void js_LockTitle(JSContext *cx, JSTitle *title); +extern void js_UnlockTitle(JSContext *cx, JSTitle *title); +extern int js_SetupLocks(int,int); +extern void js_CleanupLocks(); +extern void js_TransferTitle(JSContext *, JSTitle *, JSTitle *); +extern JS_FRIEND_API(jsval) +js_GetSlotThreadSafe(JSContext *, JSObject *, uint32); +extern void js_SetSlotThreadSafe(JSContext *, JSObject *, uint32, jsval); +extern void js_InitLock(JSThinLock *); +extern void js_FinishLock(JSThinLock *); +extern void js_FinishSharingTitle(JSContext *cx, JSTitle *title); + +#ifdef DEBUG + +#define JS_IS_RUNTIME_LOCKED(rt) js_IsRuntimeLocked(rt) +#define JS_IS_OBJ_LOCKED(cx,obj) js_IsObjLocked(cx,obj) +#define JS_IS_TITLE_LOCKED(cx,title) js_IsTitleLocked(cx,title) + +extern JSBool js_IsRuntimeLocked(JSRuntime *rt); +extern JSBool js_IsObjLocked(JSContext *cx, JSObject *obj); +extern JSBool js_IsTitleLocked(JSContext *cx, JSTitle *title); +#ifdef JS_DEBUG_TITLE_LOCKS +extern void js_SetScopeInfo(JSScope *scope, const char *file, int line); +#endif + +#else + +#define JS_IS_RUNTIME_LOCKED(rt) 0 +#define JS_IS_OBJ_LOCKED(cx,obj) 1 +#define JS_IS_TITLE_LOCKED(cx,title) 1 + +#endif /* DEBUG */ + +#define JS_LOCK_OBJ_VOID(cx, obj, e) \ + JS_BEGIN_MACRO \ + JS_LOCK_OBJ(cx, obj); \ + e; \ + JS_UNLOCK_OBJ(cx, obj); \ + JS_END_MACRO + +#define JS_LOCK_VOID(cx, e) \ + JS_BEGIN_MACRO \ + JSRuntime *_rt = (cx)->runtime; \ + JS_LOCK_RUNTIME_VOID(_rt, e); \ + JS_END_MACRO + +#else /* !JS_THREADSAFE */ + +#define JS_ATOMIC_INCREMENT(p) (++*(p)) +#define JS_ATOMIC_DECREMENT(p) (--*(p)) +#define JS_ATOMIC_ADD(p,v) (*(p) += (v)) + +#define JS_CurrentThreadId() 0 +#define JS_NEW_LOCK() NULL +#define JS_DESTROY_LOCK(l) ((void)0) +#define JS_ACQUIRE_LOCK(l) ((void)0) +#define JS_RELEASE_LOCK(l) ((void)0) +#define JS_LOCK(cx, tl) ((void)0) +#define JS_UNLOCK(cx, tl) ((void)0) + +#define JS_NEW_CONDVAR(l) NULL +#define JS_DESTROY_CONDVAR(cv) ((void)0) +#define JS_WAIT_CONDVAR(cv,to) ((void)0) +#define JS_NOTIFY_CONDVAR(cv) ((void)0) +#define JS_NOTIFY_ALL_CONDVAR(cv) ((void)0) + +#define JS_LOCK_RUNTIME(rt) ((void)0) +#define JS_UNLOCK_RUNTIME(rt) ((void)0) +#define JS_LOCK_OBJ(cx,obj) ((void)0) +#define JS_UNLOCK_OBJ(cx,obj) ((void)0) +#define JS_LOCK_OBJ_VOID(cx,obj,e) (e) +#define JS_LOCK_SCOPE(cx,scope) ((void)0) +#define JS_UNLOCK_SCOPE(cx,scope) ((void)0) +#define JS_TRANSFER_SCOPE_LOCK(c,o,n) ((void)0) + +#define JS_IS_RUNTIME_LOCKED(rt) 1 +#define JS_IS_OBJ_LOCKED(cx,obj) 1 +#define JS_IS_TITLE_LOCKED(cx,title) 1 +#define JS_LOCK_VOID(cx, e) JS_LOCK_RUNTIME_VOID((cx)->runtime, e) + +#endif /* !JS_THREADSAFE */ + +#define JS_LOCK_RUNTIME_VOID(rt,e) \ + JS_BEGIN_MACRO \ + JS_LOCK_RUNTIME(rt); \ + e; \ + JS_UNLOCK_RUNTIME(rt); \ + JS_END_MACRO + +#define JS_LOCK_GC(rt) JS_ACQUIRE_LOCK((rt)->gcLock) +#define JS_UNLOCK_GC(rt) JS_RELEASE_LOCK((rt)->gcLock) +#define JS_LOCK_GC_VOID(rt,e) (JS_LOCK_GC(rt), (e), JS_UNLOCK_GC(rt)) +#define JS_AWAIT_GC_DONE(rt) JS_WAIT_CONDVAR((rt)->gcDone, JS_NO_TIMEOUT) +#define JS_NOTIFY_GC_DONE(rt) JS_NOTIFY_ALL_CONDVAR((rt)->gcDone) +#define JS_AWAIT_REQUEST_DONE(rt) JS_WAIT_CONDVAR((rt)->requestDone, \ + JS_NO_TIMEOUT) +#define JS_NOTIFY_REQUEST_DONE(rt) JS_NOTIFY_CONDVAR((rt)->requestDone) + +#ifndef SET_OBJ_INFO +#define SET_OBJ_INFO(obj,f,l) ((void)0) +#endif +#ifndef SET_TITLE_INFO +#define SET_TITLE_INFO(title,f,l) ((void)0) +#endif + +#ifdef JS_THREADSAFE + +extern JSBool +js_CompareAndSwap(jsword *w, jsword ov, jsword nv); + +#else + +static inline JSBool +js_CompareAndSwap(jsword *w, jsword ov, jsword nv) +{ + return (*w == ov) ? *w = nv, JS_TRUE : JS_FALSE; +} + +#endif + +JS_END_EXTERN_C + +#endif /* jslock_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslocko.asm b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslocko.asm new file mode 100644 index 0000000..95353ba --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslocko.asm @@ -0,0 +1,60 @@ +; -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*- + +; ***** BEGIN LICENSE BLOCK ***** +; Version: MPL 1.1/GPL 2.0/LGPL 2.1 +; +; The contents of this file are subject to the Mozilla Public License Version +; 1.1 (the "License"); you may not use this file except in compliance with +; the License. You may obtain a copy of the License at +; http://www.mozilla.org/MPL/ +; +; Software distributed under the License is distributed on an "AS IS" basis, +; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +; for the specific language governing rights and limitations under the +; License. +; +; The Original Code is an OS/2 implementation of js_CompareAndSwap in assembly. +; +; The Initial Developer of the Original Code is +; IBM Corporation. +; Portions created by the Initial Developer are Copyright (C) 2001 +; the Initial Developer. All Rights Reserved. +; +; Contributor(s): +; +; Alternatively, the contents of this file may be used under the terms of +; either the GNU General Public License Version 2 or later (the "GPL"), or +; the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +; in which case the provisions of the GPL or the LGPL are applicable instead +; of those above. If you wish to allow use of your version of this file only +; under the terms of either the GPL or the LGPL, and not to allow others to +; use your version of this file under the terms of the MPL, indicate your +; decision by deleting the provisions above and replace them with the notice +; and other provisions required by the GPL or the LGPL. If you do not delete +; the provisions above, a recipient may use your version of this file under +; the terms of any one of the MPL, the GPL or the LGPL. +; +; ***** END LICENSE BLOCK ***** + + .486P + .MODEL FLAT, OPTLINK + .STACK + + .CODE + +;;;--------------------------------------------------------------------- +;;; int _Optlink js_CompareAndSwap(jsword *w, jsword ov, jsword nv) +;;;--------------------------------------------------------------------- +js_CompareAndSwap PROC OPTLINK EXPORT + push ebx + mov ebx, eax + mov eax, edx + mov edx, ebx + lock cmpxchg [ebx], ecx + sete al + and eax, 1h + pop ebx + ret +js_CompareAndSwap endp + + END diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslog2.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslog2.cpp new file mode 100644 index 0000000..84f4f51 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslog2.cpp @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsstddef.h" +#include "jsbit.h" +#include "jsutil.h" + +/* +** Compute the log of the least power of 2 greater than or equal to n +*/ +JS_PUBLIC_API(JSIntn) JS_CeilingLog2(JSUint32 n) +{ + JSIntn log2; + + JS_CEILING_LOG2(log2, n); + return log2; +} + +/* +** Compute the log of the greatest power of 2 less than or equal to n. +** This really just finds the highest set bit in the word. +*/ +JS_PUBLIC_API(JSIntn) JS_FloorLog2(JSUint32 n) +{ + JSIntn log2; + + JS_FLOOR_LOG2(log2, n); + return log2; +} + +/* + * js_FloorLog2wImpl has to be defined only for 64-bit non-GCC case. + */ +#if !defined(JS_HAS_BUILTIN_BITSCAN64) && JS_BYTES_PER_WORD == 8 + +JSUword +js_FloorLog2wImpl(JSUword n) +{ + JSUword log2, m; + + JS_ASSERT(n != 0); + + log2 = 0; + m = n >> 32; + if (m != 0) { n = m; log2 = 32; } + m = n >> 16; + if (m != 0) { n = m; log2 |= 16; } + m = n >> 8; + if (m != 0) { n = m; log2 |= 8; } + m = n >> 4; + if (m != 0) { n = m; log2 |= 4; } + m = n >> 2; + if (m != 0) { n = m; log2 |= 2; } + log2 |= (n >> 1); + + return log2; +} + +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslong.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslong.cpp new file mode 100644 index 0000000..71dd06d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslong.cpp @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsstddef.h" +#include "jstypes.h" +#include "jslong.h" + +#ifndef JS_HAVE_LONG_LONG +/* +** Divide 64-bit a by 32-bit b, which must be normalized so its high bit is 1. +*/ +static void norm_udivmod32(JSUint32 *qp, JSUint32 *rp, JSUint64 a, JSUint32 b) +{ + JSUint32 d1, d0, q1, q0; + JSUint32 r1, r0, m; + + d1 = jshi16(b); + d0 = jslo16(b); + r1 = a.hi % d1; + q1 = a.hi / d1; + m = q1 * d0; + r1 = (r1 << 16) | jshi16(a.lo); + if (r1 < m) { + q1--, r1 += b; + if (r1 >= b /* i.e., we didn't get a carry when adding to r1 */ + && r1 < m) { + q1--, r1 += b; + } + } + r1 -= m; + r0 = r1 % d1; + q0 = r1 / d1; + m = q0 * d0; + r0 = (r0 << 16) | jslo16(a.lo); + if (r0 < m) { + q0--, r0 += b; + if (r0 >= b + && r0 < m) { + q0--, r0 += b; + } + } + *qp = (q1 << 16) | q0; + *rp = r0 - m; +} + +static JSUint32 CountLeadingZeros(JSUint32 a) +{ + JSUint32 t; + JSUint32 r = 32; + + if ((t = a >> 16) != 0) + r -= 16, a = t; + if ((t = a >> 8) != 0) + r -= 8, a = t; + if ((t = a >> 4) != 0) + r -= 4, a = t; + if ((t = a >> 2) != 0) + r -= 2, a = t; + if ((t = a >> 1) != 0) + r -= 1, a = t; + if (a & 1) + r--; + return r; +} + +JS_PUBLIC_API(void) jsll_udivmod(JSUint64 *qp, JSUint64 *rp, JSUint64 a, JSUint64 b) +{ + JSUint32 n0, n1, n2; + JSUint32 q0, q1; + JSUint32 rsh, lsh; + + n0 = a.lo; + n1 = a.hi; + + if (b.hi == 0) { + if (b.lo > n1) { + /* (0 q0) = (n1 n0) / (0 D0) */ + + lsh = CountLeadingZeros(b.lo); + + if (lsh) { + /* + * Normalize, i.e. make the most significant bit of the + * denominator be set. + */ + b.lo = b.lo << lsh; + n1 = (n1 << lsh) | (n0 >> (32 - lsh)); + n0 = n0 << lsh; + } + + a.lo = n0, a.hi = n1; + norm_udivmod32(&q0, &n0, a, b.lo); + q1 = 0; + + /* remainder is in n0 >> lsh */ + } else { + /* (q1 q0) = (n1 n0) / (0 d0) */ + + if (b.lo == 0) /* user wants to divide by zero! */ + b.lo = 1 / b.lo; /* so go ahead and crash */ + + lsh = CountLeadingZeros(b.lo); + + if (lsh == 0) { + /* + * From (n1 >= b.lo) + * && (the most significant bit of b.lo is set), + * conclude that + * (the most significant bit of n1 is set) + * && (the leading quotient digit q1 = 1). + * + * This special case is necessary, not an optimization + * (Shifts counts of 32 are undefined). + */ + n1 -= b.lo; + q1 = 1; + } else { + /* + * Normalize. + */ + rsh = 32 - lsh; + + b.lo = b.lo << lsh; + n2 = n1 >> rsh; + n1 = (n1 << lsh) | (n0 >> rsh); + n0 = n0 << lsh; + + a.lo = n1, a.hi = n2; + norm_udivmod32(&q1, &n1, a, b.lo); + } + + /* n1 != b.lo... */ + + a.lo = n0, a.hi = n1; + norm_udivmod32(&q0, &n0, a, b.lo); + + /* remainder in n0 >> lsh */ + } + + if (rp) { + rp->lo = n0 >> lsh; + rp->hi = 0; + } + } else { + if (b.hi > n1) { + /* (0 0) = (n1 n0) / (D1 d0) */ + + q0 = 0; + q1 = 0; + + /* remainder in (n1 n0) */ + if (rp) { + rp->lo = n0; + rp->hi = n1; + } + } else { + /* (0 q0) = (n1 n0) / (d1 d0) */ + + lsh = CountLeadingZeros(b.hi); + if (lsh == 0) { + /* + * From (n1 >= b.hi) + * && (the most significant bit of b.hi is set), + * conclude that + * (the most significant bit of n1 is set) + * && (the quotient digit q0 = 0 or 1). + * + * This special case is necessary, not an optimization. + */ + + /* + * The condition on the next line takes advantage of that + * n1 >= b.hi (true due to control flow). + */ + if (n1 > b.hi || n0 >= b.lo) { + q0 = 1; + a.lo = n0, a.hi = n1; + JSLL_SUB(a, a, b); + } else { + q0 = 0; + } + q1 = 0; + + if (rp) { + rp->lo = n0; + rp->hi = n1; + } + } else { + JSInt64 m; + + /* + * Normalize. + */ + rsh = 32 - lsh; + + b.hi = (b.hi << lsh) | (b.lo >> rsh); + b.lo = b.lo << lsh; + n2 = n1 >> rsh; + n1 = (n1 << lsh) | (n0 >> rsh); + n0 = n0 << lsh; + + a.lo = n1, a.hi = n2; + norm_udivmod32(&q0, &n1, a, b.hi); + JSLL_MUL32(m, q0, b.lo); + + if ((m.hi > n1) || ((m.hi == n1) && (m.lo > n0))) { + q0--; + JSLL_SUB(m, m, b); + } + + q1 = 0; + + /* Remainder is ((n1 n0) - (m1 m0)) >> lsh */ + if (rp) { + a.lo = n0, a.hi = n1; + JSLL_SUB(a, a, m); + rp->lo = (a.hi << rsh) | (a.lo >> lsh); + rp->hi = a.hi >> lsh; + } + } + } + } + + if (qp) { + qp->lo = q0; + qp->hi = q1; + } +} +#endif /* !JS_HAVE_LONG_LONG */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslong.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslong.h new file mode 100644 index 0000000..e5bd4d0 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jslong.h @@ -0,0 +1,412 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: jslong.h +** Description: Portable access to 64 bit numerics +** +** Long-long (64-bit signed integer type) support. Some C compilers +** don't support 64 bit integers yet, so we use these macros to +** support both machines that do and don't. +**/ +#ifndef jslong_h___ +#define jslong_h___ + +#include "jstypes.h" + +JS_BEGIN_EXTERN_C + +#ifdef JS_HAVE_LONG_LONG + +#if JS_BYTES_PER_LONG == 8 +#define JSLL_INIT(hi, lo) ((hi ## L << 32) + lo ## L) +#elif (defined(WIN32) || defined(WIN16)) && !defined(__GNUC__) +#define JSLL_INIT(hi, lo) ((hi ## i64 << 32) + lo ## i64) +#else +#define JSLL_INIT(hi, lo) ((hi ## LL << 32) + lo ## LL) +#endif + +/*********************************************************************** +** MACROS: JSLL_* +** DESCRIPTION: +** The following macros define portable access to the 64 bit +** math facilities. +** +***********************************************************************/ + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_IS_ZERO Test for zero +** JSLL_EQ Test for equality +** JSLL_NE Test for inequality +** JSLL_GE_ZERO Test for zero or positive +** JSLL_CMP Compare two values +***********************************************************************/ +#define JSLL_IS_ZERO(a) ((a) == 0) +#define JSLL_EQ(a, b) ((a) == (b)) +#define JSLL_NE(a, b) ((a) != (b)) +#define JSLL_GE_ZERO(a) ((a) >= 0) +#define JSLL_CMP(a, op, b) ((JSInt64)(a) op (JSInt64)(b)) +#define JSLL_UCMP(a, op, b) ((JSUint64)(a) op (JSUint64)(b)) + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_AND Logical and +** JSLL_OR Logical or +** JSLL_XOR Logical exclusion +** JSLL_OR2 A disgusting deviation +** JSLL_NOT Negation (one's compliment) +***********************************************************************/ +#define JSLL_AND(r, a, b) ((r) = (a) & (b)) +#define JSLL_OR(r, a, b) ((r) = (a) | (b)) +#define JSLL_XOR(r, a, b) ((r) = (a) ^ (b)) +#define JSLL_OR2(r, a) ((r) = (r) | (a)) +#define JSLL_NOT(r, a) ((r) = ~(a)) + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_NEG Negation (two's compliment) +** JSLL_ADD Summation (two's compliment) +** JSLL_SUB Difference (two's compliment) +***********************************************************************/ +#define JSLL_NEG(r, a) ((r) = -(a)) +#define JSLL_ADD(r, a, b) ((r) = (a) + (b)) +#define JSLL_SUB(r, a, b) ((r) = (a) - (b)) + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_MUL Product (two's compliment) +** JSLL_DIV Quotient (two's compliment) +** JSLL_MOD Modulus (two's compliment) +***********************************************************************/ +#define JSLL_MUL(r, a, b) ((r) = (a) * (b)) +#define JSLL_DIV(r, a, b) ((r) = (a) / (b)) +#define JSLL_MOD(r, a, b) ((r) = (a) % (b)) + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_SHL Shift left [0..64] bits +** JSLL_SHR Shift right [0..64] bits with sign extension +** JSLL_USHR Unsigned shift right [0..64] bits +** JSLL_ISHL Signed shift left [0..64] bits +***********************************************************************/ +#define JSLL_SHL(r, a, b) ((r) = (JSInt64)(a) << (b)) +#define JSLL_SHR(r, a, b) ((r) = (JSInt64)(a) >> (b)) +#define JSLL_USHR(r, a, b) ((r) = (JSUint64)(a) >> (b)) +#define JSLL_ISHL(r, a, b) ((r) = (JSInt64)(a) << (b)) + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_L2I Convert to signed 32 bit +** JSLL_L2UI Convert to unsigned 32 bit +** JSLL_L2F Convert to floating point +** JSLL_L2D Convert to floating point +** JSLL_I2L Convert signed to 64 bit +** JSLL_UI2L Convert unsigned to 64 bit +** JSLL_F2L Convert float to 64 bit +** JSLL_D2L Convert float to 64 bit +***********************************************************************/ +#define JSLL_L2I(i, l) ((i) = (JSInt32)(l)) +#define JSLL_L2UI(ui, l) ((ui) = (JSUint32)(l)) +#define JSLL_L2F(f, l) ((f) = (JSFloat64)(l)) +#define JSLL_L2D(d, l) ((d) = (JSFloat64)(l)) + +#define JSLL_I2L(l, i) ((l) = (JSInt64)(i)) +#define JSLL_UI2L(l, ui) ((l) = (JSInt64)(ui)) +#define JSLL_F2L(l, f) ((l) = (JSInt64)(f)) +#define JSLL_D2L(l, d) ((l) = (JSInt64)(d)) + +/*********************************************************************** +** MACROS: JSLL_UDIVMOD +** DESCRIPTION: +** Produce both a quotient and a remainder given an unsigned +** INPUTS: JSUint64 a: The dividend of the operation +** JSUint64 b: The quotient of the operation +** OUTPUTS: JSUint64 *qp: pointer to quotient +** JSUint64 *rp: pointer to remainder +***********************************************************************/ +#define JSLL_UDIVMOD(qp, rp, a, b) \ + (*(qp) = ((JSUint64)(a) / (b)), \ + *(rp) = ((JSUint64)(a) % (b))) + +#else /* !JS_HAVE_LONG_LONG */ + +#ifdef IS_LITTLE_ENDIAN +#define JSLL_INIT(hi, lo) {JS_INT32(lo), JS_INT32(hi)} +#else +#define JSLL_INIT(hi, lo) {JS_INT32(hi), JS_INT32(lo)} +#endif + +#define JSLL_IS_ZERO(a) (((a).hi == 0) && ((a).lo == 0)) +#define JSLL_EQ(a, b) (((a).hi == (b).hi) && ((a).lo == (b).lo)) +#define JSLL_NE(a, b) (((a).hi != (b).hi) || ((a).lo != (b).lo)) +#define JSLL_GE_ZERO(a) (((a).hi >> 31) == 0) + +#ifdef DEBUG +#define JSLL_CMP(a, op, b) (JS_ASSERT((#op)[1] != '='), JSLL_REAL_CMP(a, op, b)) +#define JSLL_UCMP(a, op, b) (JS_ASSERT((#op)[1] != '='), JSLL_REAL_UCMP(a, op, b)) +#else +#define JSLL_CMP(a, op, b) JSLL_REAL_CMP(a, op, b) +#define JSLL_UCMP(a, op, b) JSLL_REAL_UCMP(a, op, b) +#endif + +#define JSLL_REAL_CMP(a,op,b) (((JSInt32)(a).hi op (JSInt32)(b).hi) || \ + (((a).hi == (b).hi) && ((a).lo op (b).lo))) +#define JSLL_REAL_UCMP(a,op,b) (((a).hi op (b).hi) || \ + (((a).hi == (b).hi) && ((a).lo op (b).lo))) + +#define JSLL_AND(r, a, b) ((r).lo = (a).lo & (b).lo, \ + (r).hi = (a).hi & (b).hi) +#define JSLL_OR(r, a, b) ((r).lo = (a).lo | (b).lo, \ + (r).hi = (a).hi | (b).hi) +#define JSLL_XOR(r, a, b) ((r).lo = (a).lo ^ (b).lo, \ + (r).hi = (a).hi ^ (b).hi) +#define JSLL_OR2(r, a) ((r).lo = (r).lo | (a).lo, \ + (r).hi = (r).hi | (a).hi) +#define JSLL_NOT(r, a) ((r).lo = ~(a).lo, \ + (r).hi = ~(a).hi) + +#define JSLL_NEG(r, a) ((r).lo = -(JSInt32)(a).lo, \ + (r).hi = -(JSInt32)(a).hi - ((r).lo != 0)) +#define JSLL_ADD(r, a, b) { \ + JSInt64 _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo + _b.lo; \ + (r).hi = _a.hi + _b.hi + ((r).lo < _b.lo); \ +} + +#define JSLL_SUB(r, a, b) { \ + JSInt64 _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo - _b.lo; \ + (r).hi = _a.hi - _b.hi - (_a.lo < _b.lo); \ +} + +#define JSLL_MUL(r, a, b) { \ + JSInt64 _a, _b; \ + _a = a; _b = b; \ + JSLL_MUL32(r, _a.lo, _b.lo); \ + (r).hi += _a.hi * _b.lo + _a.lo * _b.hi; \ +} + +#define jslo16(a) ((a) & JS_BITMASK(16)) +#define jshi16(a) ((a) >> 16) + +#define JSLL_MUL32(r, a, b) { \ + JSUint32 _a1, _a0, _b1, _b0, _y0, _y1, _y2, _y3; \ + _a1 = jshi16(a), _a0 = jslo16(a); \ + _b1 = jshi16(b), _b0 = jslo16(b); \ + _y0 = _a0 * _b0; \ + _y1 = _a0 * _b1; \ + _y2 = _a1 * _b0; \ + _y3 = _a1 * _b1; \ + _y1 += jshi16(_y0); /* can't carry */ \ + _y1 += _y2; /* might carry */ \ + if (_y1 < _y2) \ + _y3 += (JSUint32)(JS_BIT(16)); /* propagate */ \ + (r).lo = (jslo16(_y1) << 16) + jslo16(_y0); \ + (r).hi = _y3 + jshi16(_y1); \ +} + +#define JSLL_UDIVMOD(qp, rp, a, b) jsll_udivmod(qp, rp, a, b) + +extern JS_PUBLIC_API(void) jsll_udivmod(JSUint64 *qp, JSUint64 *rp, JSUint64 a, JSUint64 b); + +#define JSLL_DIV(r, a, b) { \ + JSInt64 _a, _b; \ + JSUint32 _negative = (JSInt32)(a).hi < 0; \ + if (_negative) { \ + JSLL_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((JSInt32)(b).hi < 0) { \ + _negative ^= 1; \ + JSLL_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + JSLL_UDIVMOD(&(r), 0, _a, _b); \ + if (_negative) \ + JSLL_NEG(r, r); \ +} + +#define JSLL_MOD(r, a, b) { \ + JSInt64 _a, _b; \ + JSUint32 _negative = (JSInt32)(a).hi < 0; \ + if (_negative) { \ + JSLL_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((JSInt32)(b).hi < 0) { \ + JSLL_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + JSLL_UDIVMOD(0, &(r), _a, _b); \ + if (_negative) \ + JSLL_NEG(r, r); \ +} + +#define JSLL_SHL(r, a, b) { \ + if (b) { \ + JSInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = _a.lo << ((b) & 31); \ + (r).hi = (_a.hi << ((b) & 31)) | (_a.lo >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = _a.lo << ((b) & 31); \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +/* a is an JSInt32, b is JSInt32, r is JSInt64 */ +#define JSLL_ISHL(r, a, b) { \ + if (b) { \ + JSInt64 _a; \ + _a.lo = (a); \ + _a.hi = 0; \ + if ((b) < 32) { \ + (r).lo = (a) << ((b) & 31); \ + (r).hi = ((a) >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = (a) << ((b) & 31); \ + } \ + } else { \ + (r).lo = (a); \ + (r).hi = 0; \ + } \ +} + +#define JSLL_SHR(r, a, b) { \ + if (b) { \ + JSInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \ + (r).hi = (JSInt32)_a.hi >> ((b) & 31); \ + } else { \ + (r).lo = (JSInt32)_a.hi >> ((b) & 31); \ + (r).hi = (JSInt32)_a.hi >> 31; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define JSLL_USHR(r, a, b) { \ + if (b) { \ + JSInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \ + (r).hi = _a.hi >> ((b) & 31); \ + } else { \ + (r).lo = _a.hi >> ((b) & 31); \ + (r).hi = 0; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define JSLL_L2I(i, l) ((i) = (l).lo) +#define JSLL_L2UI(ui, l) ((ui) = (l).lo) +#define JSLL_L2F(f, l) { double _d; JSLL_L2D(_d, l); (f) = (JSFloat64)_d; } + +#define JSLL_L2D(d, l) { \ + int _negative; \ + JSInt64 _absval; \ + \ + _negative = (l).hi >> 31; \ + if (_negative) { \ + JSLL_NEG(_absval, l); \ + } else { \ + _absval = l; \ + } \ + (d) = (double)_absval.hi * 4.294967296e9 + _absval.lo; \ + if (_negative) \ + (d) = -(d); \ +} + +#define JSLL_I2L(l, i) { JSInt32 _i = (i) >> 31; (l).lo = (i); (l).hi = _i; } +#define JSLL_UI2L(l, ui) ((l).lo = (ui), (l).hi = 0) +#define JSLL_F2L(l, f) { double _d = (double)f; JSLL_D2L(l, _d); } + +#define JSLL_D2L(l, d) { \ + int _negative; \ + double _absval, _d_hi; \ + JSInt64 _lo_d; \ + \ + _negative = ((d) < 0); \ + _absval = _negative ? -(d) : (d); \ + \ + (l).hi = _absval / 4.294967296e9; \ + (l).lo = 0; \ + JSLL_L2D(_d_hi, l); \ + _absval -= _d_hi; \ + _lo_d.hi = 0; \ + if (_absval < 0) { \ + _lo_d.lo = -_absval; \ + JSLL_SUB(l, l, _lo_d); \ + } else { \ + _lo_d.lo = _absval; \ + JSLL_ADD(l, l, _lo_d); \ + } \ + \ + if (_negative) \ + JSLL_NEG(l, l); \ +} + +#endif /* !JS_HAVE_LONG_LONG */ + +JS_END_EXTERN_C + +#endif /* jslong_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsmath.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsmath.cpp new file mode 100644 index 0000000..75fa900 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsmath.cpp @@ -0,0 +1,721 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS math package. + */ +#include "jsstddef.h" +#include "jslibmath.h" +#include +#include "jstypes.h" +#include "jslong.h" +#include "prmjtime.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jslock.h" +#include "jsmath.h" +#include "jsnum.h" +#include "jsobj.h" + +extern jsdouble js_NaN; + +#ifndef M_E +#define M_E 2.7182818284590452354 +#endif +#ifndef M_LOG2E +#define M_LOG2E 1.4426950408889634074 +#endif +#ifndef M_LOG10E +#define M_LOG10E 0.43429448190325182765 +#endif +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.70710678118654752440 +#endif + +static JSConstDoubleSpec math_constants[] = { + {M_E, "E", 0, {0,0,0}}, + {M_LOG2E, "LOG2E", 0, {0,0,0}}, + {M_LOG10E, "LOG10E", 0, {0,0,0}}, + {M_LN2, "LN2", 0, {0,0,0}}, + {M_LN10, "LN10", 0, {0,0,0}}, + {M_PI, "PI", 0, {0,0,0}}, + {M_SQRT2, "SQRT2", 0, {0,0,0}}, + {M_SQRT1_2, "SQRT1_2", 0, {0,0,0}}, + {0,0,0,{0,0,0}} +}; + +JSClass js_MathClass = { + js_Math_str, + JSCLASS_HAS_CACHED_PROTO(JSProto_Math), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSBool +math_abs(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + z = fabs(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_acos(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; +#if defined(SOLARIS) && defined(__GNUC__) + if (x < -1 || 1 < x) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } +#endif + z = acos(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_asin(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; +#if defined(SOLARIS) && defined(__GNUC__) + if (x < -1 || 1 < x) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } +#endif + z = asin(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_atan(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + z = atan(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_atan2(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, y, z; + + if (argc <= 1) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + y = js_ValueToNumber(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return JS_FALSE; +#if defined(_MSC_VER) + /* + * MSVC's atan2 does not yield the result demanded by ECMA when both x + * and y are infinite. + * - The result is a multiple of pi/4. + * - The sign of x determines the sign of the result. + * - The sign of y determines the multiplicator, 1 or 3. + */ + if (JSDOUBLE_IS_INFINITE(x) && JSDOUBLE_IS_INFINITE(y)) { + z = js_copysign(M_PI / 4, x); + if (y < 0) + z *= 3; + return js_NewDoubleInRootedValue(cx, z, vp); + } +#endif + +#if defined(SOLARIS) && defined(__GNUC__) + if (x == 0) { + if (JSDOUBLE_IS_NEGZERO(y)) { + z = js_copysign(M_PI, x); + return js_NewDoubleInRootedValue(cx, z, vp); + } + if (y == 0) { + z = x; + return js_NewDoubleInRootedValue(cx, z, vp); + } + } +#endif + z = atan2(x, y); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_ceil(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + z = ceil(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_cos(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + z = cos(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_exp(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; +#ifdef _WIN32 + if (!JSDOUBLE_IS_NaN(x)) { + if (x == *cx->runtime->jsPositiveInfinity) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity); + return JS_TRUE; + } + if (x == *cx->runtime->jsNegativeInfinity) { + *vp = JSVAL_ZERO; + return JS_TRUE; + } + } +#endif + z = exp(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_floor(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + z = floor(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_log(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; +#if defined(SOLARIS) && defined(__GNUC__) + if (x < 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } +#endif + z = log(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_max(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z = *cx->runtime->jsNegativeInfinity; + jsval *argv; + uintN i; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity); + return JS_TRUE; + } + argv = vp + 2; + for (i = 0; i < argc; i++) { + x = js_ValueToNumber(cx, &argv[i]); + if (JSVAL_IS_NULL(argv[i])) + return JS_FALSE; + if (JSDOUBLE_IS_NaN(x)) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + if (x == 0 && x == z) { + if (js_copysign(1.0, z) == -1) + z = x; + } else { + z = (x > z) ? x : z; + } + } + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_min(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z = *cx->runtime->jsPositiveInfinity; + jsval *argv; + uintN i; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity); + return JS_TRUE; + } + argv = vp + 2; + for (i = 0; i < argc; i++) { + x = js_ValueToNumber(cx, &argv[i]); + if (JSVAL_IS_NULL(argv[i])) + return JS_FALSE; + if (JSDOUBLE_IS_NaN(x)) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + if (x == 0 && x == z) { + if (js_copysign(1.0, x) == -1) + z = x; + } else { + z = (x < z) ? x : z; + } + } + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_pow(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, y, z; + + if (argc <= 1) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + y = js_ValueToNumber(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return JS_FALSE; + /* + * Because C99 and ECMA specify different behavior for pow(), + * we need to wrap the libm call to make it ECMA compliant. + */ + if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + /* pow(x, +-0) is always 1, even for x = NaN. */ + if (y == 0) { + *vp = JSVAL_ONE; + return JS_TRUE; + } + z = pow(x, y); + return js_NewNumberInRootedValue(cx, z, vp); +} + +/* + * Math.random() support, lifted from java.util.Random.java. + */ +static void +random_setSeed(JSRuntime *rt, int64 seed) +{ + int64 tmp; + + JSLL_I2L(tmp, 1000); + JSLL_DIV(seed, seed, tmp); + JSLL_XOR(tmp, seed, rt->rngMultiplier); + JSLL_AND(rt->rngSeed, tmp, rt->rngMask); +} + +void +js_random_init(JSRuntime *rt) +{ + int64 tmp, tmp2; + + /* Do at most once. */ + if (rt->rngInitialized) + return; + rt->rngInitialized = JS_TRUE; + + /* rt->rngMultiplier = 0x5DEECE66DL */ + JSLL_ISHL(tmp, 0x5, 32); + JSLL_UI2L(tmp2, 0xDEECE66DL); + JSLL_OR(rt->rngMultiplier, tmp, tmp2); + + /* rt->rngAddend = 0xBL */ + JSLL_I2L(rt->rngAddend, 0xBL); + + /* rt->rngMask = (1L << 48) - 1 */ + JSLL_I2L(tmp, 1); + JSLL_SHL(tmp2, tmp, 48); + JSLL_SUB(rt->rngMask, tmp2, tmp); + + /* rt->rngDscale = (jsdouble)(1L << 53) */ + JSLL_SHL(tmp2, tmp, 53); + JSLL_L2D(rt->rngDscale, tmp2); + + /* Finally, set the seed from current time. */ + random_setSeed(rt, PRMJ_Now()); +} + +static uint32 +random_next(JSRuntime *rt, int bits) +{ + int64 nextseed, tmp; + uint32 retval; + + JSLL_MUL(nextseed, rt->rngSeed, rt->rngMultiplier); + JSLL_ADD(nextseed, nextseed, rt->rngAddend); + JSLL_AND(nextseed, nextseed, rt->rngMask); + rt->rngSeed = nextseed; + JSLL_USHR(tmp, nextseed, 48 - bits); + JSLL_L2I(retval, tmp); + return retval; +} + +jsdouble +js_random_nextDouble(JSRuntime *rt) +{ + int64 tmp, tmp2; + jsdouble d; + + JSLL_ISHL(tmp, random_next(rt, 26), 27); + JSLL_UI2L(tmp2, random_next(rt, 27)); + JSLL_ADD(tmp, tmp, tmp2); + JSLL_L2D(d, tmp); + return d / rt->rngDscale; +} + +static JSBool +math_random(JSContext *cx, uintN argc, jsval *vp) +{ + JSRuntime *rt; + jsdouble z; + + rt = cx->runtime; + JS_LOCK_RUNTIME(rt); + js_random_init(rt); + z = js_random_nextDouble(rt); + JS_UNLOCK_RUNTIME(rt); + return js_NewNumberInRootedValue(cx, z, vp); +} + +#if defined _WIN32 && !defined WINCE && _MSC_VER < 1400 +/* Try to work around apparent _copysign bustage in VC6 and VC7. */ +double +js_copysign(double x, double y) +{ + jsdpun xu, yu; + + xu.d = x; + yu.d = y; + xu.s.hi &= ~JSDOUBLE_HI32_SIGNBIT; + xu.s.hi |= yu.s.hi & JSDOUBLE_HI32_SIGNBIT; + return xu.d; +} +#endif + +static JSBool +math_round(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + z = js_copysign(floor(x + 0.5), x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_sin(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + z = sin(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_sqrt(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + z = sqrt(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +static JSBool +math_tan(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x, z; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + z = tan(x); + return js_NewNumberInRootedValue(cx, z, vp); +} + +#if JS_HAS_TOSOURCE +static JSBool +math_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + *vp = ATOM_KEY(CLASS_ATOM(cx, Math)); + return JS_TRUE; +} +#endif + +#ifdef JS_TRACER + +#define MATH_BUILTIN_1(name) \ + static jsdouble FASTCALL math_##name##_tn(jsdouble d) { return name(d); } \ + JS_DEFINE_TRCINFO_1(math_##name, \ + (1, (static, DOUBLE, math_##name##_tn, DOUBLE, 1, 1))) + +MATH_BUILTIN_1(sin) +MATH_BUILTIN_1(cos) +MATH_BUILTIN_1(sqrt) +MATH_BUILTIN_1(floor) +MATH_BUILTIN_1(ceil) + +static jsdouble FASTCALL +math_abs_tn(jsdouble d) +{ + return fabs(d); +} + +static jsdouble FASTCALL +math_log_tn(jsdouble d) +{ +#if defined(SOLARIS) && defined(__GNUC__) + if (d < 0) + return js_NaN; +#endif + return log(d); +} + +static jsdouble FASTCALL +math_max_tn(jsdouble d, jsdouble p) +{ + if (JSDOUBLE_IS_NaN(d) || JSDOUBLE_IS_NaN(p)) + return js_NaN; + + if (p == 0 && p == d) { + if (js_copysign(1.0, d) == -1) + return p; + return d; + } + return (p > d) ? p : d; +} + +static jsdouble FASTCALL +math_pow_tn(jsdouble d, jsdouble p) +{ + if (!JSDOUBLE_IS_FINITE(p) && (d == 1.0 || d == -1.0)) + return js_NaN; + if (p == 0) + return 1.0; + return pow(d, p); +} + +static jsdouble FASTCALL +math_random_tn(JSRuntime* rt) +{ + JS_LOCK_RUNTIME(rt); + js_random_init(rt); + jsdouble z = js_random_nextDouble(rt); + JS_UNLOCK_RUNTIME(rt); + return z; +} + +static jsdouble FASTCALL +math_round_tn(jsdouble x) +{ + return js_copysign(floor(x + 0.5), x); +} + +JS_DEFINE_TRCINFO_1(math_abs, + (1, (static, DOUBLE, math_abs_tn, DOUBLE, 1, 1))) +JS_DEFINE_TRCINFO_1(math_log, + (1, (static, DOUBLE, math_log_tn, DOUBLE, 1, 1))) +JS_DEFINE_TRCINFO_1(math_max, + (2, (static, DOUBLE, math_max_tn, DOUBLE, DOUBLE, 1, 1))) +JS_DEFINE_TRCINFO_1(math_pow, + (2, (static, DOUBLE, math_pow_tn, DOUBLE, DOUBLE, 1, 1))) +JS_DEFINE_TRCINFO_1(math_random, + (1, (static, DOUBLE, math_random_tn, RUNTIME, 0, 0))) +JS_DEFINE_TRCINFO_1(math_round, + (1, (static, DOUBLE, math_round_tn, DOUBLE, 1, 1))) + +#endif /* JS_TRACER */ + +static JSFunctionSpec math_static_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, math_toSource, 0, 0), +#endif + JS_TN("abs", math_abs, 1, 0, math_abs_trcinfo), + JS_FN("acos", math_acos, 1, 0), + JS_FN("asin", math_asin, 1, 0), + JS_FN("atan", math_atan, 1, 0), + JS_FN("atan2", math_atan2, 2, 0), + JS_TN("ceil", math_ceil, 1, 0, math_ceil_trcinfo), + JS_TN("cos", math_cos, 1, 0, math_cos_trcinfo), + JS_FN("exp", math_exp, 1, 0), + JS_TN("floor", math_floor, 1, 0, math_floor_trcinfo), + JS_TN("log", math_log, 1, 0, math_log_trcinfo), + JS_TN("max", math_max, 2, 0, math_max_trcinfo), + JS_FN("min", math_min, 2, 0), + JS_TN("pow", math_pow, 2, 0, math_pow_trcinfo), + JS_TN("random", math_random, 0, 0, math_random_trcinfo), + JS_TN("round", math_round, 1, 0, math_round_trcinfo), + JS_TN("sin", math_sin, 1, 0, math_sin_trcinfo), + JS_TN("sqrt", math_sqrt, 1, 0, math_sqrt_trcinfo), + JS_FN("tan", math_tan, 1, 0), + JS_FS_END +}; + +JSObject * +js_InitMathClass(JSContext *cx, JSObject *obj) +{ + JSObject *Math; + + Math = JS_NewObject(cx, &js_MathClass, NULL, obj); + if (!Math) + return NULL; + if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math), + JS_PropertyStub, JS_PropertyStub, + JSPROP_READONLY | JSPROP_PERMANENT)) + return NULL; + + if (!JS_DefineFunctions(cx, Math, math_static_methods)) + return NULL; + if (!JS_DefineConstDoubles(cx, Math, math_constants)) + return NULL; + return Math; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsmath.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsmath.h new file mode 100644 index 0000000..96e1c7f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsmath.h @@ -0,0 +1,63 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* -*- Mode: C; tab-width: 8 -*- + * Copyright (C) 1998-1999 Netscape Communications Corporation, All Rights Reserved. + */ + +#ifndef jsmath_h___ +#define jsmath_h___ +/* + * JS math functions. + */ + +JS_BEGIN_EXTERN_C + +extern JSClass js_MathClass; + +extern JSObject * +js_InitMathClass(JSContext *cx, JSObject *obj); + +extern void +js_random_init(JSRuntime *rt); + +extern jsdouble +js_random_nextDouble(JSRuntime *rt); + +JS_END_EXTERN_C + +#endif /* jsmath_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsnum.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsnum.cpp new file mode 100644 index 0000000..f6c1b5f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsnum.cpp @@ -0,0 +1,1338 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS number type and wrapper class. + */ +#include "jsstddef.h" +#if defined(XP_WIN) || defined(XP_OS2) +#include +#endif +#include +#include +#include +#include +#include +#include "jstypes.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jsapi.h" +#include "jsatom.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdtoa.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsprf.h" +#include "jsscope.h" +#include "jsstr.h" + +static JSBool +num_isNaN(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x; + + if (argc == 0) { + *vp = JSVAL_TRUE; + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x)); + return JS_TRUE; +} + +static JSBool +num_isFinite(JSContext *cx, uintN argc, jsval *vp) +{ + jsdouble x; + + if (argc == 0) { + *vp = JSVAL_FALSE; + return JS_TRUE; + } + x = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x)); + return JS_TRUE; +} + +static JSBool +num_parseFloat(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + jsdouble d; + const jschar *bp, *end, *ep; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + str = js_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + JSSTRING_CHARS_AND_END(str, bp, end); + if (!js_strtod(cx, bp, end, &ep, &d)) + return JS_FALSE; + if (ep == bp) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + return js_NewNumberInRootedValue(cx, d, vp); +} + +#ifdef JS_TRACER +static jsdouble FASTCALL +ParseFloat(JSContext* cx, JSString* str) +{ + const jschar* bp; + const jschar* end; + const jschar* ep; + jsdouble d; + + JSSTRING_CHARS_AND_END(str, bp, end); + if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp) + return js_NaN; + return d; +} +#endif + +/* See ECMA 15.1.2.2. */ +static JSBool +num_parseInt(JSContext *cx, uintN argc, jsval *vp) +{ + jsint radix; + JSString *str; + jsdouble d; + const jschar *bp, *end, *ep; + + if (argc == 0) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + if (argc > 1) { + radix = js_ValueToECMAInt32(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return JS_FALSE; + } else { + radix = 0; + } + if (radix != 0 && (radix < 2 || radix > 36)) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + + if (JSVAL_IS_INT(vp[2]) && (radix == 0 || radix == 10)) { + *vp = vp[2]; + return JS_TRUE; + } + + str = js_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + JSSTRING_CHARS_AND_END(str, bp, end); + if (!js_strtointeger(cx, bp, end, &ep, radix, &d)) + return JS_FALSE; + if (ep == bp) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + return js_NewNumberInRootedValue(cx, d, vp); +} + +#ifdef JS_TRACER +static jsdouble FASTCALL +ParseInt(JSContext* cx, JSString* str) +{ + const jschar* bp; + const jschar* end; + const jschar* ep; + jsdouble d; + + JSSTRING_CHARS_AND_END(str, bp, end); + if (!js_strtointeger(cx, bp, end, &ep, 0, &d) || ep == bp) + return js_NaN; + return d; +} + +static jsdouble FASTCALL +ParseIntDouble(jsdouble d) +{ + if (!JSDOUBLE_IS_FINITE(d)) + return js_NaN; + return floor(d); +} +#endif + +const char js_Infinity_str[] = "Infinity"; +const char js_NaN_str[] = "NaN"; +const char js_isNaN_str[] = "isNaN"; +const char js_isFinite_str[] = "isFinite"; +const char js_parseFloat_str[] = "parseFloat"; +const char js_parseInt_str[] = "parseInt"; + +#ifdef JS_TRACER + +JS_DEFINE_TRCINFO_2(num_parseInt, + (2, (static, DOUBLE, ParseInt, CONTEXT, STRING, 1, 1)), + (1, (static, DOUBLE, ParseIntDouble, DOUBLE, 1, 1))) + +JS_DEFINE_TRCINFO_1(num_parseFloat, + (2, (static, DOUBLE, ParseFloat, CONTEXT, STRING, 1, 1))) + +#endif /* JS_TRACER */ + +static JSFunctionSpec number_functions[] = { + JS_FN(js_isNaN_str, num_isNaN, 1,0), + JS_FN(js_isFinite_str, num_isFinite, 1,0), + JS_TN(js_parseFloat_str, num_parseFloat, 1,0, num_parseFloat_trcinfo), + JS_TN(js_parseInt_str, num_parseInt, 2,0, num_parseInt_trcinfo), + JS_FS_END +}; + +JSClass js_NumberClass = { + js_Number_str, + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Number), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSBool +Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + jsval v; + jsdouble d; + + if (argc != 0) { + d = js_ValueToNumber(cx, &argv[0]); + v = argv[0]; + if (JSVAL_IS_NULL(v)) + return JS_FALSE; + if (v != JSVAL_TRUE) { + JS_ASSERT(JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v)); + } else { + if (!js_NewNumberInRootedValue(cx, d, &argv[0])) + return JS_FALSE; + v = argv[0]; + } + } else { + v = JSVAL_ZERO; + } + if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { + *rval = v; + return JS_TRUE; + } + STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, v); + return JS_TRUE; +} + +#if JS_HAS_TOSOURCE +static JSBool +num_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + jsval v; + jsdouble d; + char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr; + char buf[64]; + JSString *str; + + if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_NUMBER(v)); + d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); + numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d); + if (!numStr) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr); + str = JS_NewStringCopyZ(cx, buf); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} +#endif + +/* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */ +char * +js_IntToCString(jsint i, jsint base, char *buf, size_t bufSize) +{ + char *cp; + jsuint u; + + u = (i < 0) ? -i : i; + + cp = buf + bufSize; /* one past last buffer cell */ + *--cp = '\0'; /* null terminate the string to be */ + + /* + * Build the string from behind. We use multiply and subtraction + * instead of modulus because that's much faster. + */ + switch (base) { + case 10: + do { + jsuint newu = u / 10; + *--cp = (char)(u - newu * 10) + '0'; + u = newu; + } while (u != 0); + break; + case 16: + do { + jsuint newu = u / 16; + *--cp = "0123456789abcdef"[u - newu * 16]; + u = newu; + } while (u != 0); + break; + default: + JS_ASSERT(base >= 2 && base <= 36); + do { + jsuint newu = u / base; + *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[u - newu * base]; + u = newu; + } while (u != 0); + break; + } + if (i < 0) + *--cp = '-'; + + JS_ASSERT(cp >= buf); + return cp; +} + +static JSBool +num_toString(JSContext *cx, uintN argc, jsval *vp) +{ + jsval v; + jsdouble d; + jsint base; + JSString *str; + + if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_NUMBER(v)); + d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); + base = 10; + if (argc != 0 && !JSVAL_IS_VOID(vp[2])) { + base = js_ValueToECMAInt32(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + if (base < 2 || base > 36) { + char numBuf[12]; + char *numStr = js_IntToCString(base, 10, numBuf, sizeof numBuf); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX, + numStr); + return JS_FALSE; + } + } + if (base == 10) { + str = js_NumberToString(cx, d); + } else { + char *dStr = JS_dtobasestr(base, d); + if (!dStr) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + str = JS_NewStringCopyZ(cx, dStr); + free(dStr); + } + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +num_toLocaleString(JSContext *cx, uintN argc, jsval *vp) +{ + char thousandsLength, decimalLength; + const char *numGrouping, *tmpGroup; + JSRuntime *rt; + JSString *numStr, *str; + const char *num, *end, *tmpSrc; + char *buf, *tmpDest; + const char *nint; + int digits, size, remainder, nrepeat; + + /* + * Create the string, move back to bytes to make string twiddling + * a bit easier and so we can insert platform charset seperators. + */ + if (!num_toString(cx, 0, vp)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_STRING(*vp)); + numStr = JSVAL_TO_STRING(*vp); + num = js_GetStringBytes(cx, numStr); + if (!num) + return JS_FALSE; + + /* + * Find the first non-integer value, whether it be a letter as in + * 'Infinity', a decimal point, or an 'e' from exponential notation. + */ + nint = num; + if (*nint == '-') + nint++; + while (*nint >= '0' && *nint <= '9') + nint++; + digits = nint - num; + end = num + digits; + if (!digits) + return JS_TRUE; + + rt = cx->runtime; + thousandsLength = strlen(rt->thousandsSeparator); + decimalLength = strlen(rt->decimalSeparator); + + /* Figure out how long resulting string will be. */ + size = digits + (*nint ? strlen(nint + 1) + 1 : 0); + if (*nint == '.') + size += decimalLength; + + numGrouping = tmpGroup = rt->numGrouping; + remainder = digits; + if (*num == '-') + remainder--; + + while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') { + if (*tmpGroup >= remainder) + break; + size += thousandsLength; + remainder -= *tmpGroup; + tmpGroup++; + } + if (*tmpGroup == '\0' && *numGrouping != '\0') { + nrepeat = (remainder - 1) / tmpGroup[-1]; + size += thousandsLength * nrepeat; + remainder -= nrepeat * tmpGroup[-1]; + } else { + nrepeat = 0; + } + tmpGroup--; + + buf = (char *)JS_malloc(cx, size + 1); + if (!buf) + return JS_FALSE; + + tmpDest = buf; + tmpSrc = num; + + while (*tmpSrc == '-' || remainder--) + *tmpDest++ = *tmpSrc++; + while (tmpSrc < end) { + strcpy(tmpDest, rt->thousandsSeparator); + tmpDest += thousandsLength; + memcpy(tmpDest, tmpSrc, *tmpGroup); + tmpDest += *tmpGroup; + tmpSrc += *tmpGroup; + if (--nrepeat < 0) + tmpGroup--; + } + + if (*nint == '.') { + strcpy(tmpDest, rt->decimalSeparator); + tmpDest += decimalLength; + strcpy(tmpDest, nint + 1); + } else { + strcpy(tmpDest, nint); + } + + if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) + return cx->localeCallbacks->localeToUnicode(cx, buf, vp); + + str = JS_NewString(cx, buf, size); + if (!str) { + JS_free(cx, buf); + return JS_FALSE; + } + + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +num_valueOf(JSContext *cx, uintN argc, jsval *vp) +{ + jsval v; + JSObject *obj; + + v = vp[1]; + if (JSVAL_IS_NUMBER(v)) { + *vp = v; + return JS_TRUE; + } + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_NumberClass, vp + 2)) + return JS_FALSE; + *vp = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); + return JS_TRUE; +} + + +#define MAX_PRECISION 100 + +static JSBool +num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode, + jsint precisionMin, jsint precisionMax, jsint precisionOffset, + uintN argc, jsval *vp) +{ + jsval v; + jsdouble d, precision; + JSString *str; + + /* Use MAX_PRECISION+1 because precisionOffset can be 1. */ + char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)]; + char *numStr; + + if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_NUMBER(v)); + d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); + + if (argc == 0) { + precision = 0.0; + oneArgMode = zeroArgMode; + } else { + precision = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + precision = js_DoubleToInteger(precision); + if (precision < precisionMin || precision > precisionMax) { + numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision); + if (!numStr) + JS_ReportOutOfMemory(cx); + else + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr); + return JS_FALSE; + } + } + + numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d); + if (!numStr) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + str = JS_NewStringCopyZ(cx, numStr); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +/* + * In the following three implementations, we allow a larger range of precision + * than ECMA requires; this is permitted by ECMA-262. + */ +static JSBool +num_toFixed(JSContext *cx, uintN argc, jsval *vp) +{ + return num_to(cx, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0, + argc, vp); +} + +static JSBool +num_toExponential(JSContext *cx, uintN argc, jsval *vp) +{ + return num_to(cx, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, + MAX_PRECISION, 1, argc, vp); +} + +static JSBool +num_toPrecision(JSContext *cx, uintN argc, jsval *vp) +{ + if (argc == 0 || JSVAL_IS_VOID(vp[2])) + return num_toString(cx, 0, vp); + return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0, + argc, vp); +} + +#ifdef JS_TRACER + +JS_DEFINE_TRCINFO_2(num_toString, + (3, (static, STRING, NumberToStringWithBase, CONTEXT, THIS_DOUBLE, INT32, 1, 1)), + (2, (extern, STRING, js_NumberToString, CONTEXT, THIS_DOUBLE, 1, 1))) + +#endif /* JS_TRACER */ + +static JSFunctionSpec number_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, num_toSource, 0,JSFUN_THISP_NUMBER), +#endif + JS_TN(js_toString_str, num_toString, 1,JSFUN_THISP_NUMBER, + num_toString_trcinfo), + JS_FN(js_toLocaleString_str, num_toLocaleString, 0,JSFUN_THISP_NUMBER), + JS_FN(js_valueOf_str, num_valueOf, 0,JSFUN_THISP_NUMBER), + JS_FN(js_toJSON_str, num_valueOf, 0,JSFUN_THISP_NUMBER), + JS_FN("toFixed", num_toFixed, 1,JSFUN_THISP_NUMBER), + JS_FN("toExponential", num_toExponential, 1,JSFUN_THISP_NUMBER), + JS_FN("toPrecision", num_toPrecision, 1,JSFUN_THISP_NUMBER), + JS_FS_END +}; + +/* NB: Keep this in synch with number_constants[]. */ +enum nc_slot { + NC_NaN, + NC_POSITIVE_INFINITY, + NC_NEGATIVE_INFINITY, + NC_MAX_VALUE, + NC_MIN_VALUE, + NC_LIMIT +}; + +/* + * Some to most C compilers forbid spelling these at compile time, or barf + * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState + * using union jsdpun. + */ +static JSConstDoubleSpec number_constants[] = { + {0, js_NaN_str, 0,{0,0,0}}, + {0, "POSITIVE_INFINITY", 0,{0,0,0}}, + {0, "NEGATIVE_INFINITY", 0,{0,0,0}}, + {1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}}, + {0, "MIN_VALUE", 0,{0,0,0}}, + {0,0,0,{0,0,0}} +}; + +jsdouble js_NaN; + +#if (defined XP_WIN || defined XP_OS2) && \ + !defined WINCE && \ + !defined __MWERKS__ && \ + (defined _M_IX86 || \ + (defined __GNUC__ && !defined __MINGW32__)) + +/* + * Set the exception mask to mask all exceptions and set the FPU precision + * to 53 bit mantissa. + * On Alpha platform this is handled via Compiler option. + */ +#define FIX_FPU() _control87(MCW_EM | PC_53, MCW_EM | MCW_PC) + +#else + +#define FIX_FPU() ((void)0) + +#endif + +JSBool +js_InitRuntimeNumberState(JSContext *cx) +{ + JSRuntime *rt; + jsdpun u; + struct lconv *locale; + + rt = cx->runtime; + JS_ASSERT(!rt->jsNaN); + + FIX_FPU(); + + u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK; + u.s.lo = 0xffffffff; + number_constants[NC_NaN].dval = js_NaN = u.d; + rt->jsNaN = js_NewWeaklyRootedDouble(cx, js_NaN); + if (!rt->jsNaN) + return JS_FALSE; + + u.s.hi = JSDOUBLE_HI32_EXPMASK; + u.s.lo = 0x00000000; + number_constants[NC_POSITIVE_INFINITY].dval = u.d; + rt->jsPositiveInfinity = js_NewWeaklyRootedDouble(cx, u.d); + if (!rt->jsPositiveInfinity) + return JS_FALSE; + + u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK; + u.s.lo = 0x00000000; + number_constants[NC_NEGATIVE_INFINITY].dval = u.d; + rt->jsNegativeInfinity = js_NewWeaklyRootedDouble(cx, u.d); + if (!rt->jsNegativeInfinity) + return JS_FALSE; + + u.s.hi = 0; + u.s.lo = 1; + number_constants[NC_MIN_VALUE].dval = u.d; + + locale = localeconv(); + rt->thousandsSeparator = + JS_strdup(cx, locale->thousands_sep ? locale->thousands_sep : "'"); + rt->decimalSeparator = + JS_strdup(cx, locale->decimal_point ? locale->decimal_point : "."); + rt->numGrouping = + JS_strdup(cx, locale->grouping ? locale->grouping : "\3\0"); + + return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping; +} + +void +js_TraceRuntimeNumberState(JSTracer *trc) +{ + JSRuntime *rt; + + rt = trc->context->runtime; + if (rt->jsNaN) + JS_CALL_DOUBLE_TRACER(trc, rt->jsNaN, "NaN"); + if (rt->jsPositiveInfinity) + JS_CALL_DOUBLE_TRACER(trc, rt->jsPositiveInfinity, "+Infinity"); + if (rt->jsNegativeInfinity) + JS_CALL_DOUBLE_TRACER(trc, rt->jsNegativeInfinity, "-Infinity"); +} + +void +js_FinishRuntimeNumberState(JSContext *cx) +{ + JSRuntime *rt = cx->runtime; + + js_UnlockGCThingRT(rt, rt->jsNaN); + js_UnlockGCThingRT(rt, rt->jsNegativeInfinity); + js_UnlockGCThingRT(rt, rt->jsPositiveInfinity); + + rt->jsNaN = NULL; + rt->jsNegativeInfinity = NULL; + rt->jsPositiveInfinity = NULL; + + JS_free(cx, (void *)rt->thousandsSeparator); + JS_free(cx, (void *)rt->decimalSeparator); + JS_free(cx, (void *)rt->numGrouping); + rt->thousandsSeparator = rt->decimalSeparator = rt->numGrouping = NULL; +} + +JSObject * +js_InitNumberClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto, *ctor; + JSRuntime *rt; + + /* XXX must do at least once per new thread, so do it per JSContext... */ + FIX_FPU(); + + if (!JS_DefineFunctions(cx, obj, number_functions)) + return NULL; + + proto = JS_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1, + NULL, number_methods, NULL, NULL); + if (!proto || !(ctor = JS_GetConstructor(cx, proto))) + return NULL; + STOBJ_SET_SLOT(proto, JSSLOT_PRIVATE, JSVAL_ZERO); + if (!JS_DefineConstDoubles(cx, ctor, number_constants)) + return NULL; + + /* ECMA 15.1.1.1 */ + rt = cx->runtime; + if (!JS_DefineProperty(cx, obj, js_NaN_str, DOUBLE_TO_JSVAL(rt->jsNaN), + NULL, NULL, JSPROP_PERMANENT)) { + return NULL; + } + + /* ECMA 15.1.1.2 */ + if (!JS_DefineProperty(cx, obj, js_Infinity_str, + DOUBLE_TO_JSVAL(rt->jsPositiveInfinity), + NULL, NULL, JSPROP_PERMANENT)) { + return NULL; + } + return proto; +} + +JSBool +js_NewNumberInRootedValue(JSContext *cx, jsdouble d, jsval *vp) +{ + jsint i; + + if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) { + *vp = INT_TO_JSVAL(i); + return JS_TRUE; + } + return js_NewDoubleInRootedValue(cx, d, vp); +} + +char * +js_NumberToCString(JSContext *cx, jsdouble d, jsint base, char *buf, size_t bufSize) +{ + jsint i; + char *numStr; + + JS_ASSERT(bufSize >= DTOSTR_STANDARD_BUFFER_SIZE); + if (JSDOUBLE_IS_INT(d, i)) { + numStr = js_IntToCString(i, base, buf, bufSize); + } else { + if (base == 10) + numStr = JS_dtostr(buf, bufSize, DTOSTR_STANDARD, 0, d); + else + numStr = JS_dtobasestr(base, d); + if (!numStr) { + JS_ReportOutOfMemory(cx); + return NULL; + } + } + return numStr; +} + +static JSString * JS_FASTCALL +NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) +{ + char buf[DTOSTR_STANDARD_BUFFER_SIZE]; + char *numStr; + + if (base < 2 || base > 36) + return NULL; + numStr = js_NumberToCString(cx, d, base, buf, sizeof buf); + if (!numStr) + return NULL; + return JS_NewStringCopyZ(cx, numStr); +} + +JSString * JS_FASTCALL +js_NumberToString(JSContext *cx, jsdouble d) +{ + return NumberToStringWithBase(cx, d, 10); +} + +jsdouble +js_ValueToNumber(JSContext *cx, jsval *vp) +{ + jsval v; + JSString *str; + const jschar *bp, *end, *ep; + jsdouble d, *dp; + JSObject *obj; + JSTempValueRooter tvr; + + v = *vp; + for (;;) { + if (JSVAL_IS_INT(v)) + return (jsdouble) JSVAL_TO_INT(v); + if (JSVAL_IS_DOUBLE(v)) + return *JSVAL_TO_DOUBLE(v); + if (JSVAL_IS_STRING(v)) { + str = JSVAL_TO_STRING(v); + + /* + * Note that ECMA doesn't treat a string beginning with a '0' as + * an octal number here. This works because all such numbers will + * be interpreted as decimal by js_strtod and will never get + * passed to js_strtointeger (which would interpret them as + * octal). + */ + JSSTRING_CHARS_AND_END(str, bp, end); + if ((!js_strtod(cx, bp, end, &ep, &d) || + js_SkipWhiteSpace(ep, end) != end) && + (!js_strtointeger(cx, bp, end, &ep, 0, &d) || + js_SkipWhiteSpace(ep, end) != end)) { + break; + } + + /* + * JSVAL_TRUE indicates that double jsval was never constructed + * for the result. + */ + *vp = JSVAL_TRUE; + return d; + } + if (JSVAL_IS_BOOLEAN(v)) { + if (JSVAL_TO_BOOLEAN(v)) { + *vp = JSVAL_ONE; + return 1.0; + } else { + *vp = JSVAL_ZERO; + return 0.0; + } + } + if (JSVAL_IS_NULL(v)) { + *vp = JSVAL_ZERO; + return 0.0; + } + if (JSVAL_IS_VOID(v)) + break; + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + obj = JSVAL_TO_OBJECT(v); + + /* + * vp roots obj so we cannot use it as an extra root for + * OBJ_DEFAULT_VALUE result when calling the hook. + */ + JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); + if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_NUMBER, &tvr.u.value)) + obj = NULL; + else + v = *vp = tvr.u.value; + JS_POP_TEMP_ROOT(cx, &tvr); + if (!obj) { + *vp = JSVAL_NULL; + return 0.0; + } + if (!JSVAL_IS_PRIMITIVE(v)) + break; + } + + dp = cx->runtime->jsNaN; + *vp = DOUBLE_TO_JSVAL(dp); + return *dp; +} + +int32 +js_ValueToECMAInt32(JSContext *cx, jsval *vp) +{ + jsval v; + jsdouble d; + + v = *vp; + if (JSVAL_IS_INT(v)) + return JSVAL_TO_INT(v); + if (JSVAL_IS_DOUBLE(v)) { + d = *JSVAL_TO_DOUBLE(v); + *vp = JSVAL_TRUE; + } else { + d = js_ValueToNumber(cx, vp); + if (JSVAL_IS_NULL(*vp)) + return 0; + *vp = JSVAL_TRUE; + } + return js_DoubleToECMAInt32(d); +} + +int32 +js_DoubleToECMAInt32(jsdouble d) +{ + int32 i; + jsdouble two32, two31; + + if (!JSDOUBLE_IS_FINITE(d)) + return 0; + + i = (int32) d; + if ((jsdouble) i == d) + return i; + + two32 = 4294967296.0; + two31 = 2147483648.0; + d = fmod(d, two32); + d = (d >= 0) ? floor(d) : ceil(d) + two32; + return (int32) (d >= two31 ? d - two32 : d); +} + +uint32 +js_ValueToECMAUint32(JSContext *cx, jsval *vp) +{ + jsval v; + jsint i; + jsdouble d; + + v = *vp; + if (JSVAL_IS_INT(v)) { + i = JSVAL_TO_INT(v); + if (i < 0) + *vp = JSVAL_TRUE; + return (uint32) i; + } + if (JSVAL_IS_DOUBLE(v)) { + d = *JSVAL_TO_DOUBLE(v); + *vp = JSVAL_TRUE; + } else { + d = js_ValueToNumber(cx, vp); + if (JSVAL_IS_NULL(*vp)) + return 0; + *vp = JSVAL_TRUE; + } + return js_DoubleToECMAUint32(d); +} + +uint32 +js_DoubleToECMAUint32(jsdouble d) +{ + int32 i; + JSBool neg; + jsdouble two32; + + if (!JSDOUBLE_IS_FINITE(d)) + return 0; + + /* + * We check whether d fits int32, not uint32, as all but the ">>>" bit + * manipulation bytecode stores the result as int, not uint. When the + * result does not fit int jsval, it will be stored as a negative double. + */ + i = (int32) d; + if ((jsdouble) i == d) + return (int32)i; + + neg = (d < 0); + d = floor(neg ? -d : d); + d = neg ? -d : d; + + two32 = 4294967296.0; + d = fmod(d, two32); + + return (uint32) (d >= 0 ? d : d + two32); +} + +int32 +js_ValueToInt32(JSContext *cx, jsval *vp) +{ + jsval v; + jsdouble d; + + v = *vp; + if (JSVAL_IS_INT(v)) + return JSVAL_TO_INT(v); + d = js_ValueToNumber(cx, vp); + if (JSVAL_IS_NULL(*vp)) + return 0; + if (JSVAL_IS_INT(*vp)) + return JSVAL_TO_INT(*vp); + + *vp = JSVAL_TRUE; + if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) { + js_ReportValueError(cx, JSMSG_CANT_CONVERT, + JSDVG_SEARCH_STACK, v, NULL); + *vp = JSVAL_NULL; + return 0; + } + return (int32) floor(d + 0.5); /* Round to nearest */ +} + +uint16 +js_ValueToUint16(JSContext *cx, jsval *vp) +{ + jsdouble d; + uint16 u; + jsuint m; + JSBool neg; + + d = js_ValueToNumber(cx, vp); + if (JSVAL_IS_NULL(*vp)) + return 0; + + if (JSVAL_IS_INT(*vp)) { + u = (uint16) JSVAL_TO_INT(*vp); + } else if (d == 0 || !JSDOUBLE_IS_FINITE(d)) { + u = (uint16) 0; + } else { + u = (uint16) d; + if ((jsdouble) u != d) { + neg = (d < 0); + d = floor(neg ? -d : d); + d = neg ? -d : d; + m = JS_BIT(16); + d = fmod(d, (double) m); + if (d < 0) + d += m; + u = (uint16) d; + } + } + *vp = INT_TO_JSVAL(u); + return u; +} + +jsdouble +js_DoubleToInteger(jsdouble d) +{ + JSBool neg; + + if (d == 0) + return d; + if (!JSDOUBLE_IS_FINITE(d)) { + if (JSDOUBLE_IS_NaN(d)) + return 0; + return d; + } + neg = (d < 0); + d = floor(neg ? -d : d); + return neg ? -d : d; +} + +JSBool +js_strtod(JSContext *cx, const jschar *s, const jschar *send, + const jschar **ep, jsdouble *dp) +{ + const jschar *s1; + size_t length, i; + char cbuf[32]; + char *cstr, *istr, *estr; + JSBool negative; + jsdouble d; + + s1 = js_SkipWhiteSpace(s, send); + length = send - s1; + + /* Use cbuf to avoid malloc */ + if (length >= sizeof cbuf) { + cstr = (char *) JS_malloc(cx, length + 1); + if (!cstr) + return JS_FALSE; + } else { + cstr = cbuf; + } + + for (i = 0; i != length; i++) { + if (s1[i] >> 8) + break; + cstr[i] = (char)s1[i]; + } + cstr[i] = 0; + + istr = cstr; + if ((negative = (*istr == '-')) != 0 || *istr == '+') + istr++; + if (!strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) { + d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity); + estr = istr + 8; + } else { + int err; + d = JS_strtod(cstr, &estr, &err); + if (d == HUGE_VAL) + d = *cx->runtime->jsPositiveInfinity; + else if (d == -HUGE_VAL) + d = *cx->runtime->jsNegativeInfinity; +#ifdef HPUX + if (d == 0.0 && negative) { + /* + * "-0", "-1e-2000" come out as positive zero + * here on HPUX. Force a negative zero instead. + */ + JSDOUBLE_HI32(d) = JSDOUBLE_HI32_SIGNBIT; + JSDOUBLE_LO32(d) = 0; + } +#endif + } + + i = estr - cstr; + if (cstr != cbuf) + JS_free(cx, cstr); + *ep = i ? s1 + i : s; + *dp = d; + return JS_TRUE; +} + +struct BinaryDigitReader +{ + uintN base; /* Base of number; must be a power of 2 */ + uintN digit; /* Current digit value in radix given by base */ + uintN digitMask; /* Mask to extract the next bit from digit */ + const jschar *digits; /* Pointer to the remaining digits */ + const jschar *end; /* Pointer to first non-digit */ +}; + +/* Return the next binary digit from the number or -1 if done */ +static intN GetNextBinaryDigit(struct BinaryDigitReader *bdr) +{ + intN bit; + + if (bdr->digitMask == 0) { + uintN c; + + if (bdr->digits == bdr->end) + return -1; + + c = *bdr->digits++; + if ('0' <= c && c <= '9') + bdr->digit = c - '0'; + else if ('a' <= c && c <= 'z') + bdr->digit = c - 'a' + 10; + else bdr->digit = c - 'A' + 10; + bdr->digitMask = bdr->base >> 1; + } + bit = (bdr->digit & bdr->digitMask) != 0; + bdr->digitMask >>= 1; + return bit; +} + +JSBool +js_strtointeger(JSContext *cx, const jschar *s, const jschar *send, + const jschar **ep, jsint base, jsdouble *dp) +{ + const jschar *s1, *start; + JSBool negative; + jsdouble value; + + s1 = js_SkipWhiteSpace(s, send); + if (s1 == send) + goto no_digits; + if ((negative = (*s1 == '-')) != 0 || *s1 == '+') { + s1++; + if (s1 == send) + goto no_digits; + } + + if (base == 0) { + /* No base supplied, or some base that evaluated to 0. */ + if (*s1 == '0') { + /* It's either hex or octal; only increment char if str isn't '0' */ + if (s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) { + base = 16; + s1 += 2; + if (s1 == send) + goto no_digits; + } else { + base = 8; + } + } else { + base = 10; /* Default to decimal. */ + } + } else if (base == 16) { + /* If base is 16, ignore hex prefix. */ + if (*s1 == '0' && s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) { + s1 += 2; + if (s1 == send) + goto no_digits; + } + } + + /* + * Done with the preliminaries; find some prefix of the string that's + * a number in the given base. + */ + JS_ASSERT(s1 < send); + start = s1; + value = 0.0; + do { + uintN digit; + jschar c = *s1; + if ('0' <= c && c <= '9') + digit = c - '0'; + else if ('a' <= c && c <= 'z') + digit = c - 'a' + 10; + else if ('A' <= c && c <= 'Z') + digit = c - 'A' + 10; + else + break; + if (digit >= (uintN)base) + break; + value = value * base + digit; + } while (++s1 != send); + + if (value >= 9007199254740992.0) { + if (base == 10) { + /* + * If we're accumulating a decimal number and the number is >= + * 2^53, then the result from the repeated multiply-add above may + * be inaccurate. Call JS_strtod to get the correct answer. + */ + size_t i; + size_t length = s1 - start; + char *cstr = (char *) JS_malloc(cx, length + 1); + char *estr; + int err=0; + + if (!cstr) + return JS_FALSE; + for (i = 0; i != length; i++) + cstr[i] = (char)start[i]; + cstr[length] = 0; + + value = JS_strtod(cstr, &estr, &err); + if (err == JS_DTOA_ENOMEM) { + JS_ReportOutOfMemory(cx); + JS_free(cx, cstr); + return JS_FALSE; + } + if (err == JS_DTOA_ERANGE && value == HUGE_VAL) + value = *cx->runtime->jsPositiveInfinity; + JS_free(cx, cstr); + } else if ((base & (base - 1)) == 0) { + /* + * The number may also be inaccurate for power-of-two bases. This + * happens if the addition in value * base + digit causes a round- + * down to an even least significant mantissa bit when the first + * dropped bit is a one. If any of the following digits in the + * number (which haven't been added in yet) are nonzero, then the + * correct action would have been to round up instead of down. An + * example occurs when reading the number 0x1000000000000081, which + * rounds to 0x1000000000000000 instead of 0x1000000000000100. + */ + struct BinaryDigitReader bdr; + intN bit, bit2; + intN j; + + bdr.base = base; + bdr.digitMask = 0; + bdr.digits = start; + bdr.end = s1; + value = 0.0; + + /* Skip leading zeros. */ + do { + bit = GetNextBinaryDigit(&bdr); + } while (bit == 0); + + if (bit == 1) { + /* Gather the 53 significant bits (including the leading 1) */ + value = 1.0; + for (j = 52; j; j--) { + bit = GetNextBinaryDigit(&bdr); + if (bit < 0) + goto done; + value = value*2 + bit; + } + /* bit2 is the 54th bit (the first dropped from the mantissa) */ + bit2 = GetNextBinaryDigit(&bdr); + if (bit2 >= 0) { + jsdouble factor = 2.0; + intN sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */ + intN bit3; + + while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) { + sticky |= bit3; + factor *= 2; + } + value += bit2 & (bit | sticky); + value *= factor; + } + done:; + } + } + } + /* We don't worry about inaccurate numbers for any other base. */ + + if (s1 == start) { + no_digits: + *dp = 0.0; + *ep = s; + } else { + *dp = negative ? -value : value; + *ep = s1; + } + return JS_TRUE; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsnum.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsnum.h new file mode 100644 index 0000000..285e29c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsnum.h @@ -0,0 +1,287 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsnum_h___ +#define jsnum_h___ + +/* + * JS number (IEEE double) interface. + * + * JS numbers are optimistically stored in the top 31 bits of 32-bit integers, + * but floating point literals, results that overflow 31 bits, and division and + * modulus operands and results require a 64-bit IEEE double. These are GC'ed + * and pointed to by 32-bit jsvals on the stack and in object properties. + */ + +JS_BEGIN_EXTERN_C + +/* + * The ARM architecture supports two floating point models: VFP and FPA. When + * targetting FPA, doubles are mixed-endian on little endian ARMs (meaning that + * the high and low words are in big endian order). + */ +#if defined(__arm) || defined(__arm32__) || defined(__arm26__) || defined(__arm__) +#if !defined(__VFP_FP__) +#define FPU_IS_ARM_FPA +#endif +#endif + +typedef union jsdpun { + struct { +#if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA) + uint32 lo, hi; +#else + uint32 hi, lo; +#endif + } s; + uint64 u64; + jsdouble d; +} jsdpun; + +#if (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || __GNUC__ > 2 +/* + * This version of the macros is safe for the alias optimizations that gcc + * does, but uses gcc-specific extensions. + */ + +#define JSDOUBLE_HI32(x) (__extension__ ({ jsdpun u; u.d = (x); u.s.hi; })) +#define JSDOUBLE_LO32(x) (__extension__ ({ jsdpun u; u.d = (x); u.s.lo; })) +#define JSDOUBLE_SET_HI32(x, y) \ + (__extension__ ({ jsdpun u; u.d = (x); u.s.hi = (y); (x) = u.d; })) +#define JSDOUBLE_SET_LO32(x, y) \ + (__extension__ ({ jsdpun u; u.d = (x); u.s.lo = (y); (x) = u.d; })) + +#else /* not or old GNUC */ + +/* + * We don't know of any non-gcc compilers that perform alias optimization, + * so this code should work. + */ + +#if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA) +#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1]) +#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0]) +#else +#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0]) +#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1]) +#endif + +#define JSDOUBLE_SET_HI32(x, y) (JSDOUBLE_HI32(x)=(y)) +#define JSDOUBLE_SET_LO32(x, y) (JSDOUBLE_LO32(x)=(y)) + +#endif /* not or old GNUC */ + +#define JSDOUBLE_HI32_SIGNBIT 0x80000000 +#define JSDOUBLE_HI32_EXPMASK 0x7ff00000 +#define JSDOUBLE_HI32_MANTMASK 0x000fffff + +#define JSDOUBLE_IS_NaN(x) \ + ((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \ + (JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK))) + +#define JSDOUBLE_IS_INFINITE(x) \ + ((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \ + !JSDOUBLE_LO32(x)) + +#define JSDOUBLE_IS_FINITE(x) \ + ((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) != JSDOUBLE_HI32_EXPMASK) + +#define JSDOUBLE_IS_NEGZERO(d) (JSDOUBLE_HI32(d) == JSDOUBLE_HI32_SIGNBIT && \ + JSDOUBLE_LO32(d) == 0) + +/* + * JSDOUBLE_IS_INT first checks that d is neither NaN nor infinite, to avoid + * raising SIGFPE on platforms such as Alpha Linux, then (only if the cast is + * safe) leaves i as (jsint)d. This also avoid anomalous NaN floating point + * comparisons under MSVC. + */ +#define JSDOUBLE_IS_INT(d, i) (JSDOUBLE_IS_FINITE(d) \ + && !JSDOUBLE_IS_NEGZERO(d) \ + && ((d) == (i = (jsint)(d)))) + +#if defined(XP_WIN) +#define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN) \ + ((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL)) \ + ? (IFNAN) \ + : (LVAL) OP (RVAL)) +#else +#define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL)) +#endif + +extern jsdouble js_NaN; + +/* Initialize number constants and runtime state for the first context. */ +extern JSBool +js_InitRuntimeNumberState(JSContext *cx); + +extern void +js_TraceRuntimeNumberState(JSTracer *trc); + +extern void +js_FinishRuntimeNumberState(JSContext *cx); + +/* Initialize the Number class, returning its prototype object. */ +extern JSClass js_NumberClass; + +extern JSObject * +js_InitNumberClass(JSContext *cx, JSObject *obj); + +/* + * String constants for global function names, used in jsapi.c and jsnum.c. + */ +extern const char js_Infinity_str[]; +extern const char js_NaN_str[]; +extern const char js_isNaN_str[]; +extern const char js_isFinite_str[]; +extern const char js_parseFloat_str[]; +extern const char js_parseInt_str[]; + +/* + * vp must be a root. + */ +extern JSBool +js_NewNumberInRootedValue(JSContext *cx, jsdouble d, jsval *vp); + +/* Convert a number to a GC'ed string. */ +extern JSString * JS_FASTCALL +js_NumberToString(JSContext *cx, jsdouble d); + +/* + * Convert int to C string. The buf must be big enough for MIN_INT to fit + * including '-' and '\0'. + */ +char * +js_IntToCString(jsint i, jsint base, char *buf, size_t bufSize); + +/* + * Convert a number to C string. The buf must be at least + * DTOSTR_STANDARD_BUFFER_SIZE. + */ +char * +js_NumberToCString(JSContext *cx, jsdouble d, jsint base, char *buf, size_t bufSize); + +/* + * Convert a value to a number. On exit JSVAL_IS_NULL(*vp) iff there was an + * error. If on exit JSVAL_IS_NUMBER(*vp), then *vp holds the jsval that + * matches the result. Otherwise *vp is JSVAL_TRUE indicating that the jsval + * for result has to be created explicitly using, for example, the + * js_NewNumberInRootedValue function. + */ +extern jsdouble +js_ValueToNumber(JSContext *cx, jsval* vp); + +/* + * Convert a value to an int32 or uint32, according to the ECMA rules for + * ToInt32 and ToUint32. On exit JSVAL_IS_NULL(*vp) iff there was an error. If + * on exit JSVAL_IS_INT(*vp), then *vp holds the jsval matching the result. + * Otherwise *vp is JSVAL_TRUE indicating that the jsval for result has to be + * created explicitly using, for example, the js_NewNumberInRootedValue + * function. + */ +extern int32 +js_ValueToECMAInt32(JSContext *cx, jsval *vp); + +extern uint32 +js_ValueToECMAUint32(JSContext *cx, jsval *vp); + +/* + * Specialized ToInt32 and ToUint32 converters for doubles. + */ +extern int32 +js_DoubleToECMAInt32(jsdouble d); + +extern uint32 +js_DoubleToECMAUint32(jsdouble d); + +/* + * Convert a value to a number, then to an int32 if it fits by rounding to + * nearest; but failing with an error report if the double is out of range + * or unordered. On exit JSVAL_IS_NULL(*vp) iff there was an error. If on exit + * JSVAL_IS_INT(*vp), then *vp holds the jsval matching the result. Otherwise + * *vp is JSVAL_TRUE indicating that the jsval for result has to be created + * explicitly using, for example, the js_NewNumberInRootedValue function. + */ +extern int32 +js_ValueToInt32(JSContext *cx, jsval *vp); + +/* + * Convert a value to a number, then to a uint16 according to the ECMA rules + * for ToUint16. On exit JSVAL_IS_NULL(*vp) iff there was an error, otherwise + * vp is jsval matching the result. + */ +extern uint16 +js_ValueToUint16(JSContext *cx, jsval *vp); + +/* + * Convert a jsdouble to an integral number, stored in a jsdouble. + * If d is NaN, return 0. If d is an infinity, return it without conversion. + */ +extern jsdouble +js_DoubleToInteger(jsdouble d); + +/* + * Similar to strtod except that it replaces overflows with infinities of the + * correct sign, and underflows with zeros of the correct sign. Guaranteed to + * return the closest double number to the given input in dp. + * + * Also allows inputs of the form [+|-]Infinity, which produce an infinity of + * the appropriate sign. The case of the "Infinity" string must match exactly. + * If the string does not contain a number, set *ep to s and return 0.0 in dp. + * Return false if out of memory. + */ +extern JSBool +js_strtod(JSContext *cx, const jschar *s, const jschar *send, + const jschar **ep, jsdouble *dp); + +/* + * Similar to strtol except that it handles integers of arbitrary size. + * Guaranteed to return the closest double number to the given input when radix + * is 10 or a power of 2. Callers may see round-off errors for very large + * numbers of a different radix than 10 or a power of 2. + * + * If the string does not contain a number, set *ep to s and return 0.0 in dp. + * Return false if out of memory. + */ +extern JSBool +js_strtointeger(JSContext *cx, const jschar *s, const jschar *send, + const jschar **ep, jsint radix, jsdouble *dp); + +JS_END_EXTERN_C + +#endif /* jsnum_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsobj.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsobj.cpp new file mode 100644 index 0000000..4e7f80a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsobj.cpp @@ -0,0 +1,5563 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS object implementation. + */ +#include "jsstddef.h" +#include +#include +#include "jstypes.h" +#include "jsarena.h" /* Added by JSIFY */ +#include "jsbit.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jshash.h" /* Added by JSIFY */ +#include "jsdhash.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsdbgapi.h" /* whether or not JS_HAS_OBJ_WATCHPOINT */ +#include "jsstaticcheck.h" + +#if JS_HAS_GENERATORS +#include "jsiter.h" +#endif + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#if JS_HAS_XDR +#include "jsxdrapi.h" +#endif + +#ifdef INCLUDE_MOZILLA_DTRACE +#include "jsdtracef.h" +#endif + +#include "jsautooplen.h" + +#ifdef JS_THREADSAFE +#define NATIVE_DROP_PROPERTY js_DropProperty + +extern void +js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop); +#else +#define NATIVE_DROP_PROPERTY NULL +#endif + +JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = { + js_NewObjectMap, js_DestroyObjectMap, + js_LookupProperty, js_DefineProperty, + js_GetProperty, js_SetProperty, + js_GetAttributes, js_SetAttributes, + js_DeleteProperty, js_DefaultValue, + js_Enumerate, js_CheckAccess, + NULL, NATIVE_DROP_PROPERTY, + js_Call, js_Construct, + NULL, js_HasInstance, + js_SetProtoOrParent, js_SetProtoOrParent, + js_TraceObject, js_Clear, + js_GetRequiredSlot, js_SetRequiredSlot +}; + +JSClass js_ObjectClass = { + js_Object_str, + JSCLASS_HAS_CACHED_PROTO(JSProto_Object), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +#if JS_HAS_OBJ_PROTO_PROP + +static JSBool +obj_getSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + +static JSBool +obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + +static JSBool +obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + +static JSPropertySpec object_props[] = { + /* These two must come first; see object_props[slot].name usage below. */ + {js_proto_str, JSSLOT_PROTO, JSPROP_PERMANENT|JSPROP_SHARED, + obj_getSlot, obj_setSlot}, + {js_parent_str,JSSLOT_PARENT,JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED, + obj_getSlot, obj_setSlot}, + {js_count_str, 0, JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED, + obj_getCount, NULL}, + {0,0,0,0,0} +}; + +/* NB: JSSLOT_PROTO and JSSLOT_PARENT are already indexes into object_props. */ +#define JSSLOT_COUNT 2 + +static JSBool +ReportStrictSlot(JSContext *cx, uint32 slot) +{ + if (slot == JSSLOT_PROTO) + return JS_TRUE; + return JS_ReportErrorFlagsAndNumber(cx, + JSREPORT_WARNING | JSREPORT_STRICT, + js_GetErrorMessage, NULL, + JSMSG_DEPRECATED_USAGE, + object_props[slot].name); +} + +static JSBool +obj_getSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + uint32 slot; + jsid propid; + JSAccessMode mode; + uintN attrs; + JSObject *pobj; + JSClass *clasp; + JSExtendedClass *xclasp; + + slot = (uint32) JSVAL_TO_INT(id); + if (id == INT_TO_JSVAL(JSSLOT_PROTO)) { + propid = ATOM_TO_JSID(cx->runtime->atomState.protoAtom); + mode = JSACC_PROTO; + } else { + propid = ATOM_TO_JSID(cx->runtime->atomState.parentAtom); + mode = JSACC_PARENT; + } + + /* Let OBJ_CHECK_ACCESS get the slot's value, based on the access mode. */ + if (!OBJ_CHECK_ACCESS(cx, obj, propid, mode, vp, &attrs)) + return JS_FALSE; + + pobj = JSVAL_TO_OBJECT(*vp); + if (pobj) { + clasp = OBJ_GET_CLASS(cx, pobj); + if (clasp == &js_CallClass || clasp == &js_BlockClass) { + /* Censor activations and lexical scopes per ECMA-262. */ + *vp = JSVAL_NULL; + } else if (clasp->flags & JSCLASS_IS_EXTENDED) { + xclasp = (JSExtendedClass *) clasp; + if (xclasp->outerObject) { + pobj = xclasp->outerObject(cx, pobj); + if (!pobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(pobj); + } + } + } + return JS_TRUE; +} + +static JSBool +obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSObject *pobj; + uint32 slot; + jsid propid; + uintN attrs; + + if (!JSVAL_IS_OBJECT(*vp)) + return JS_TRUE; + pobj = JSVAL_TO_OBJECT(*vp); + + if (pobj) { + /* + * Innerize pobj here to avoid sticking unwanted properties on the + * outer object. This ensures that any with statements only grant + * access to the inner object. + */ + OBJ_TO_INNER_OBJECT(cx, pobj); + if (!pobj) + return JS_FALSE; + } + slot = (uint32) JSVAL_TO_INT(id); + if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, slot)) + return JS_FALSE; + + /* __parent__ is readonly and permanent, only __proto__ may be set. */ + propid = ATOM_TO_JSID(cx->runtime->atomState.protoAtom); + if (!OBJ_CHECK_ACCESS(cx, obj, propid, + (JSAccessMode)(JSACC_PROTO|JSACC_WRITE), vp, + &attrs)) { + return JS_FALSE; + } + + return js_SetProtoOrParent(cx, obj, slot, pobj); +} + +static JSBool +obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + jsval iter_state; + jsid num_properties; + JSBool ok; + + if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, JSSLOT_COUNT)) + return JS_FALSE; + + /* Get the number of properties to enumerate. */ + iter_state = JSVAL_NULL; + ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties); + if (!ok) + goto out; + + if (!JSVAL_IS_INT(num_properties)) { + JS_ASSERT(0); + *vp = JSVAL_ZERO; + goto out; + } + *vp = num_properties; + +out: + if (iter_state != JSVAL_NULL) + ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0); + return ok; +} + +#else /* !JS_HAS_OBJ_PROTO_PROP */ + +#define object_props NULL + +#endif /* !JS_HAS_OBJ_PROTO_PROP */ + +JSBool +js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj) +{ + JSSetSlotRequest ssr; + JSRuntime *rt; + + /* Optimize the null case to avoid the unnecessary overhead of js_GC. */ + if (!pobj) { + JS_LOCK_OBJ(cx, obj); + if (slot == JSSLOT_PROTO && !js_GetMutableScope(cx, obj)) { + JS_UNLOCK_OBJ(cx, obj); + return JS_FALSE; + } + LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_NULL); + JS_UNLOCK_OBJ(cx, obj); + return JS_TRUE; + } + + ssr.obj = obj; + ssr.pobj = pobj; + ssr.slot = (uint16) slot; + ssr.errnum = (uint16) JSMSG_NOT_AN_ERROR; + + rt = cx->runtime; + JS_LOCK_GC(rt); + ssr.next = rt->setSlotRequests; + rt->setSlotRequests = &ssr; + for (;;) { + js_GC(cx, GC_SET_SLOT_REQUEST); + JS_UNLOCK_GC(rt); + if (!rt->setSlotRequests) + break; + JS_LOCK_GC(rt); + } + + if (ssr.errnum != JSMSG_NOT_AN_ERROR) { + if (ssr.errnum == JSMSG_OUT_OF_MEMORY) { + JS_ReportOutOfMemory(cx); + } else { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, ssr.errnum, +#if JS_HAS_OBJ_PROTO_PROP + object_props[slot].name +#else + (slot == JSSLOT_PROTO) ? js_proto_str + : js_parent_str +#endif + ); + } + return JS_FALSE; + } + + // Maintain the "any Array prototype has indexed properties hazard" flag. + if (slot == JSSLOT_PROTO && + OBJ_IS_ARRAY(cx, pobj) && + pobj->fslots[JSSLOT_ARRAY_LENGTH] != 0) { + rt->anyArrayProtoHasElement = JS_TRUE; + } + return JS_TRUE; +} + +static JSHashNumber +js_hash_object(const void *key) +{ + return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS; +} + +static JSHashEntry * +MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) +{ + JSSharpObjectMap *map; + JSHashTable *table; + JSHashNumber hash; + JSHashEntry **hep, *he; + jsatomid sharpid; + JSIdArray *ida; + JSBool ok; + jsint i, length; + jsid id; +#if JS_HAS_GETTER_SETTER + JSObject *obj2; + JSProperty *prop; + uintN attrs; +#endif + jsval val; + + JS_CHECK_RECURSION(cx, return NULL); + + map = &cx->sharpObjectMap; + table = map->table; + hash = js_hash_object(obj); + hep = JS_HashTableRawLookup(table, hash, obj); + he = *hep; + if (!he) { + sharpid = 0; + he = JS_HashTableRawAdd(table, hep, hash, obj, + JS_UINT32_TO_PTR(sharpid)); + if (!he) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + /* + * Increment map->depth to protect js_EnterSharpObject from reentering + * itself badly. Without this fix, if we reenter the basis case where + * map->depth == 0, when unwinding the inner call we will destroy the + * newly-created hash table and crash. + */ + ++map->depth; + ida = JS_Enumerate(cx, obj); + --map->depth; + if (!ida) + return NULL; + + ok = JS_TRUE; + for (i = 0, length = ida->length; i < length; i++) { + id = ida->vector[i]; +#if JS_HAS_GETTER_SETTER + ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop); + if (!ok) + break; + if (!prop) + continue; + ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs); + if (ok) { + if (OBJ_IS_NATIVE(obj2) && + (attrs & (JSPROP_GETTER | JSPROP_SETTER))) { + val = JSVAL_NULL; + if (attrs & JSPROP_GETTER) + val = (jsval) ((JSScopeProperty*)prop)->getter; + if (attrs & JSPROP_SETTER) { + if (val != JSVAL_NULL) { + /* Mark the getter, then set val to setter. */ + ok = (MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), + NULL) + != NULL); + } + val = (jsval) ((JSScopeProperty*)prop)->setter; + } + } else { + ok = OBJ_GET_PROPERTY(cx, obj, id, &val); + } + } + OBJ_DROP_PROPERTY(cx, obj2, prop); +#else + ok = OBJ_GET_PROPERTY(cx, obj, id, &val); +#endif + if (!ok) + break; + if (!JSVAL_IS_PRIMITIVE(val) && + !MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), NULL)) { + ok = JS_FALSE; + break; + } + } + if (!ok || !idap) + JS_DestroyIdArray(cx, ida); + if (!ok) + return NULL; + } else { + sharpid = JS_PTR_TO_UINT32(he->value); + if (sharpid == 0) { + sharpid = ++map->sharpgen << SHARP_ID_SHIFT; + he->value = JS_UINT32_TO_PTR(sharpid); + } + ida = NULL; + } + if (idap) + *idap = ida; + return he; +} + +JSHashEntry * +js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, + jschar **sp) +{ + JSSharpObjectMap *map; + JSHashTable *table; + JSIdArray *ida; + JSHashNumber hash; + JSHashEntry *he, **hep; + jsatomid sharpid; + char buf[20]; + size_t len; + + if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_ENTER_SHARP)) + return NULL; + + /* Set to null in case we return an early error. */ + *sp = NULL; + map = &cx->sharpObjectMap; + table = map->table; + if (!table) { + table = JS_NewHashTable(8, js_hash_object, JS_CompareValues, + JS_CompareValues, NULL, NULL); + if (!table) { + JS_ReportOutOfMemory(cx); + return NULL; + } + map->table = table; + JS_KEEP_ATOMS(cx->runtime); + } + + /* From this point the control must flow either through out: or bad:. */ + ida = NULL; + if (map->depth == 0) { + he = MarkSharpObjects(cx, obj, &ida); + if (!he) + goto bad; + JS_ASSERT((JS_PTR_TO_UINT32(he->value) & SHARP_BIT) == 0); + if (!idap) { + JS_DestroyIdArray(cx, ida); + ida = NULL; + } + } else { + hash = js_hash_object(obj); + hep = JS_HashTableRawLookup(table, hash, obj); + he = *hep; + + /* + * It's possible that the value of a property has changed from the + * first time the object's properties are traversed (when the property + * ids are entered into the hash table) to the second (when they are + * converted to strings), i.e., the OBJ_GET_PROPERTY() call is not + * idempotent. + */ + if (!he) { + he = JS_HashTableRawAdd(table, hep, hash, obj, NULL); + if (!he) { + JS_ReportOutOfMemory(cx); + goto bad; + } + sharpid = 0; + goto out; + } + } + + sharpid = JS_PTR_TO_UINT32(he->value); + if (sharpid != 0) { + len = JS_snprintf(buf, sizeof buf, "#%u%c", + sharpid >> SHARP_ID_SHIFT, + (sharpid & SHARP_BIT) ? '#' : '='); + *sp = js_InflateString(cx, buf, &len); + if (!*sp) { + if (ida) + JS_DestroyIdArray(cx, ida); + goto bad; + } + } + +out: + JS_ASSERT(he); + if ((sharpid & SHARP_BIT) == 0) { + if (idap && !ida) { + ida = JS_Enumerate(cx, obj); + if (!ida) { + if (*sp) { + JS_free(cx, *sp); + *sp = NULL; + } + goto bad; + } + } + map->depth++; + } + + if (idap) + *idap = ida; + return he; + +bad: + /* Clean up the sharpObjectMap table on outermost error. */ + if (map->depth == 0) { + JS_UNKEEP_ATOMS(cx->runtime); + map->sharpgen = 0; + JS_HashTableDestroy(map->table); + map->table = NULL; + } + return NULL; +} + +void +js_LeaveSharpObject(JSContext *cx, JSIdArray **idap) +{ + JSSharpObjectMap *map; + JSIdArray *ida; + + map = &cx->sharpObjectMap; + JS_ASSERT(map->depth > 0); + if (--map->depth == 0) { + JS_UNKEEP_ATOMS(cx->runtime); + map->sharpgen = 0; + JS_HashTableDestroy(map->table); + map->table = NULL; + } + if (idap) { + ida = *idap; + if (ida) { + JS_DestroyIdArray(cx, ida); + *idap = NULL; + } + } +} + +static intN +gc_sharp_table_entry_marker(JSHashEntry *he, intN i, void *arg) +{ + JS_CALL_OBJECT_TRACER((JSTracer *)arg, (JSObject *)he->key, + "sharp table entry"); + return JS_DHASH_NEXT; +} + +void +js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map) +{ + JS_ASSERT(map->depth > 0); + JS_ASSERT(map->table); + + /* + * During recursive calls to MarkSharpObjects a non-native object or + * object with a custom getProperty method can potentially return an + * unrooted value or even cut from the object graph an argument of one of + * MarkSharpObjects recursive invocations. So we must protect map->table + * entries against GC. + * + * We can not simply use JSTempValueRooter to mark the obj argument of + * MarkSharpObjects during recursion as we have to protect *all* entries + * in JSSharpObjectMap including those that contains otherwise unreachable + * objects just allocated through custom getProperty. Otherwise newer + * allocations can re-use the address of an object stored in the hashtable + * confusing js_EnterSharpObject. So to address the problem we simply + * mark all objects from map->table. + * + * An alternative "proper" solution is to use JSTempValueRooter in + * MarkSharpObjects with code to remove during finalization entries + * with otherwise unreachable objects. But this is way too complex + * to justify spending efforts. + */ + JS_HashTableEnumerateEntries(map->table, gc_sharp_table_entry_marker, trc); +} + +#if JS_HAS_TOSOURCE +static JSBool +obj_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + JSBool ok, outermost; + JSObject *obj; + JSHashEntry *he; + JSIdArray *ida; + jschar *chars, *ochars, *vsharp; + const jschar *idstrchars, *vchars; + size_t nchars, idstrlength, gsoplength, vlength, vsharplength, curlen; + const char *comma; + jsint i, j, length, valcnt; + jsid id; +#if JS_HAS_GETTER_SETTER + JSObject *obj2; + JSProperty *prop; + uintN attrs; +#endif + jsval *val; + jsval localroot[4] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; + JSTempValueRooter tvr; + JSString *gsopold[2]; + JSString *gsop[2]; + JSString *idstr, *valstr, *str; + + JS_CHECK_RECURSION(cx, return JS_FALSE); + + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT(cx, 4, localroot, &tvr); + + /* If outermost, we need parentheses to be an expression, not a block. */ + outermost = (cx->sharpObjectMap.depth == 0); + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !(he = js_EnterSharpObject(cx, obj, &ida, &chars))) { + ok = JS_FALSE; + goto out; + } + if (IS_SHARP(he)) { + /* + * We didn't enter -- obj is already "sharp", meaning we've visited it + * already in our depth first search, and therefore chars contains a + * string of the form "#n#". + */ + JS_ASSERT(!ida); +#if JS_HAS_SHARP_VARS + nchars = js_strlen(chars); +#else + chars[0] = '{'; + chars[1] = '}'; + chars[2] = 0; + nchars = 2; +#endif + goto make_string; + } + JS_ASSERT(ida); + ok = JS_TRUE; + + if (!chars) { + /* If outermost, allocate 4 + 1 for "({})" and the terminator. */ + chars = (jschar *) malloc(((outermost ? 4 : 2) + 1) * sizeof(jschar)); + nchars = 0; + if (!chars) + goto error; + if (outermost) + chars[nchars++] = '('; + } else { + /* js_EnterSharpObject returned a string of the form "#n=" in chars. */ + MAKE_SHARP(he); + nchars = js_strlen(chars); + chars = (jschar *) + realloc((ochars = chars), (nchars + 2 + 1) * sizeof(jschar)); + if (!chars) { + free(ochars); + goto error; + } + if (outermost) { + /* + * No need for parentheses around the whole shebang, because #n= + * unambiguously begins an object initializer, and never a block + * statement. + */ + outermost = JS_FALSE; + } + } + + chars[nchars++] = '{'; + + comma = NULL; + + /* + * We have four local roots for cooked and raw value GC safety. Hoist the + * "localroot + 2" out of the loop using the val local, which refers to + * the raw (unconverted, "uncooked") values. + */ + val = localroot + 2; + + for (i = 0, length = ida->length; i < length; i++) { + JSBool idIsLexicalIdentifier, needOldStyleGetterSetter; + + /* Get strings for id and value and GC-root them via vp. */ + id = ida->vector[i]; + +#if JS_HAS_GETTER_SETTER + ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop); + if (!ok) + goto error; +#endif + + /* + * Convert id to a jsval and then to a string. Decide early whether we + * prefer get/set or old getter/setter syntax. + */ + idstr = js_ValueToString(cx, ID_TO_VALUE(id)); + if (!idstr) { + ok = JS_FALSE; + OBJ_DROP_PROPERTY(cx, obj2, prop); + goto error; + } + *vp = STRING_TO_JSVAL(idstr); /* local root */ + idIsLexicalIdentifier = js_IsIdentifier(idstr); + needOldStyleGetterSetter = + !idIsLexicalIdentifier || + js_CheckKeyword(JSSTRING_CHARS(idstr), + JSSTRING_LENGTH(idstr)) != TOK_EOF; + +#if JS_HAS_GETTER_SETTER + + valcnt = 0; + if (prop) { + ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs); + if (!ok) { + OBJ_DROP_PROPERTY(cx, obj2, prop); + goto error; + } + if (OBJ_IS_NATIVE(obj2) && + (attrs & (JSPROP_GETTER | JSPROP_SETTER))) { + if (attrs & JSPROP_GETTER) { + val[valcnt] = (jsval) ((JSScopeProperty *)prop)->getter; + gsopold[valcnt] = + ATOM_TO_STRING(cx->runtime->atomState.getterAtom); + gsop[valcnt] = + ATOM_TO_STRING(cx->runtime->atomState.getAtom); + + valcnt++; + } + if (attrs & JSPROP_SETTER) { + val[valcnt] = (jsval) ((JSScopeProperty *)prop)->setter; + gsopold[valcnt] = + ATOM_TO_STRING(cx->runtime->atomState.setterAtom); + gsop[valcnt] = + ATOM_TO_STRING(cx->runtime->atomState.setAtom); + + valcnt++; + } + } else { + valcnt = 1; + gsop[0] = NULL; + gsopold[0] = NULL; + ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]); + } + OBJ_DROP_PROPERTY(cx, obj2, prop); + } + +#else /* !JS_HAS_GETTER_SETTER */ + + /* + * We simplify the source code at the price of minor dead code bloat in + * the ECMA version (for testing only, see jsversion.h). The null + * default values in gsop[j] suffice to disable non-ECMA getter and + * setter code. + */ + valcnt = 1; + gsop[0] = NULL; + gsopold[0] = NULL; + ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]); + +#endif /* !JS_HAS_GETTER_SETTER */ + + if (!ok) + goto error; + + /* + * If id is a string that's not an identifier, then it needs to be + * quoted. Also, negative integer ids must be quoted. + */ + if (JSID_IS_ATOM(id) + ? !idIsLexicalIdentifier + : (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) { + idstr = js_QuoteString(cx, idstr, (jschar)'\''); + if (!idstr) { + ok = JS_FALSE; + goto error; + } + *vp = STRING_TO_JSVAL(idstr); /* local root */ + } + JSSTRING_CHARS_AND_LENGTH(idstr, idstrchars, idstrlength); + + for (j = 0; j < valcnt; j++) { + /* Convert val[j] to its canonical source form. */ + valstr = js_ValueToSource(cx, val[j]); + if (!valstr) { + ok = JS_FALSE; + goto error; + } + localroot[j] = STRING_TO_JSVAL(valstr); /* local root */ + JSSTRING_CHARS_AND_LENGTH(valstr, vchars, vlength); + + if (vchars[0] == '#') + needOldStyleGetterSetter = JS_TRUE; + + if (needOldStyleGetterSetter) + gsop[j] = gsopold[j]; + + /* If val[j] is a non-sharp object, consider sharpening it. */ + vsharp = NULL; + vsharplength = 0; +#if JS_HAS_SHARP_VARS + if (!JSVAL_IS_PRIMITIVE(val[j]) && vchars[0] != '#') { + he = js_EnterSharpObject(cx, JSVAL_TO_OBJECT(val[j]), NULL, + &vsharp); + if (!he) { + ok = JS_FALSE; + goto error; + } + if (IS_SHARP(he)) { + vchars = vsharp; + vlength = js_strlen(vchars); + needOldStyleGetterSetter = JS_TRUE; + gsop[j] = gsopold[j]; + } else { + if (vsharp) { + vsharplength = js_strlen(vsharp); + MAKE_SHARP(he); + needOldStyleGetterSetter = JS_TRUE; + gsop[j] = gsopold[j]; + } + js_LeaveSharpObject(cx, NULL); + } + } +#endif + +#ifndef OLD_GETTER_SETTER + /* + * Remove '(function ' from the beginning of valstr and ')' from the + * end so that we can put "get" in front of the function definition. + */ + if (gsop[j] && VALUE_IS_FUNCTION(cx, val[j]) && + !needOldStyleGetterSetter) { + JSFunction *fun = JS_ValueToFunction(cx, val[j]); + const jschar *start = vchars; + const jschar *end = vchars + vlength; + + uint8 parenChomp = 0; + if (vchars[0] == '(') { + vchars++; + parenChomp = 1; + } + + /* + * Try to jump "getter" or "setter" keywords, if we suspect + * they might appear here. This code can be confused by people + * defining Function.prototype.toString, so let's be cautious. + */ + if (JSFUN_GETTER_TEST(fun->flags) || + JSFUN_SETTER_TEST(fun->flags)) { /* skip "getter/setter" */ + const jschar *tmp = js_strchr_limit(vchars, ' ', end); + if (tmp) + vchars = tmp + 1; + } + + /* Try to jump "function" keyword. */ + if (vchars) + vchars = js_strchr_limit(vchars, ' ', end); + + if (vchars) { + if (*vchars == ' ') + vchars++; + vlength = end - vchars - parenChomp; + } else { + gsop[j] = NULL; + vchars = start; + } + } +#else + needOldStyleGetterSetter = JS_TRUE; + gsop[j] = gsopold[j]; +#endif + +#define SAFE_ADD(n) \ + JS_BEGIN_MACRO \ + size_t n_ = (n); \ + curlen += n_; \ + if (curlen < n_) \ + goto overflow; \ + JS_END_MACRO + + curlen = nchars; + if (comma) + SAFE_ADD(2); + SAFE_ADD(idstrlength + 1); + if (gsop[j]) + SAFE_ADD(JSSTRING_LENGTH(gsop[j]) + 1); + SAFE_ADD(vsharplength); + SAFE_ADD(vlength); + /* Account for the trailing null. */ + SAFE_ADD((outermost ? 2 : 1) + 1); +#undef SAFE_ADD + + if (curlen > (size_t)-1 / sizeof(jschar)) + goto overflow; + + /* Allocate 1 + 1 at end for closing brace and terminating 0. */ + chars = (jschar *) + realloc((ochars = chars), curlen * sizeof(jschar)); + if (!chars) { + /* Save code space on error: let JS_free ignore null vsharp. */ + JS_free(cx, vsharp); + free(ochars); + goto error; + } + + if (comma) { + chars[nchars++] = comma[0]; + chars[nchars++] = comma[1]; + } + comma = ", "; + + if (needOldStyleGetterSetter) { + js_strncpy(&chars[nchars], idstrchars, idstrlength); + nchars += idstrlength; + if (gsop[j]) { + chars[nchars++] = ' '; + gsoplength = JSSTRING_LENGTH(gsop[j]); + js_strncpy(&chars[nchars], JSSTRING_CHARS(gsop[j]), + gsoplength); + nchars += gsoplength; + } + chars[nchars++] = ':'; + } else { /* New style "decompilation" */ + if (gsop[j]) { + gsoplength = JSSTRING_LENGTH(gsop[j]); + js_strncpy(&chars[nchars], JSSTRING_CHARS(gsop[j]), + gsoplength); + nchars += gsoplength; + chars[nchars++] = ' '; + } + js_strncpy(&chars[nchars], idstrchars, idstrlength); + nchars += idstrlength; + /* Extraneous space after id here will be extracted later */ + chars[nchars++] = gsop[j] ? ' ' : ':'; + } + + if (vsharplength) { + js_strncpy(&chars[nchars], vsharp, vsharplength); + nchars += vsharplength; + } + js_strncpy(&chars[nchars], vchars, vlength); + nchars += vlength; + + if (vsharp) + JS_free(cx, vsharp); + } + } + + chars[nchars++] = '}'; + if (outermost) + chars[nchars++] = ')'; + chars[nchars] = 0; + + error: + js_LeaveSharpObject(cx, &ida); + + if (!ok) { + if (chars) + free(chars); + goto out; + } + + if (!chars) { + JS_ReportOutOfMemory(cx); + ok = JS_FALSE; + goto out; + } + make_string: + str = js_NewString(cx, chars, nchars); + if (!str) { + free(chars); + ok = JS_FALSE; + goto out; + } + *vp = STRING_TO_JSVAL(str); + ok = JS_TRUE; + out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; + + overflow: + JS_free(cx, vsharp); + free(chars); + chars = NULL; + goto error; +} +#endif /* JS_HAS_TOSOURCE */ + +static JSBool +obj_toString(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + jschar *chars; + size_t nchars; + const char *clazz, *prefix; + JSString *str; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + obj = js_GetWrappedObject(cx, obj); + clazz = OBJ_GET_CLASS(cx, obj)->name; + nchars = 9 + strlen(clazz); /* 9 for "[object ]" */ + chars = (jschar *) JS_malloc(cx, (nchars + 1) * sizeof(jschar)); + if (!chars) + return JS_FALSE; + + prefix = "[object "; + nchars = 0; + while ((chars[nchars] = (jschar)*prefix) != 0) + nchars++, prefix++; + while ((chars[nchars] = (jschar)*clazz) != 0) + nchars++, clazz++; + chars[nchars++] = ']'; + chars[nchars] = 0; + + str = js_NewString(cx, chars, nchars); + if (!str) { + JS_free(cx, chars); + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +obj_toLocaleString(JSContext *cx, uintN argc, jsval *vp) +{ + jsval thisv; + JSString *str; + + thisv = JS_THIS(cx, vp); + if (JSVAL_IS_NULL(thisv)) + return JS_FALSE; + + str = js_ValueToString(cx, thisv); + if (!str) + return JS_FALSE; + + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +obj_valueOf(JSContext *cx, uintN argc, jsval *vp) +{ + *vp = JS_THIS(cx, vp); + return !JSVAL_IS_NULL(*vp); +} + +/* + * Check whether principals subsumes scopeobj's principals, and return true + * if so (or if scopeobj has no principals, for backward compatibility with + * the JS API, which does not require principals), and false otherwise. + */ +JSBool +js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj, + JSPrincipals *principals, JSAtom *caller) +{ + JSSecurityCallbacks *callbacks; + JSPrincipals *scopePrincipals; + const char *callerstr; + + callbacks = JS_GetSecurityCallbacks(cx); + if (callbacks && callbacks->findObjectPrincipals) { + scopePrincipals = callbacks->findObjectPrincipals(cx, scopeobj); + if (!principals || !scopePrincipals || + !principals->subsume(principals, scopePrincipals)) { + callerstr = js_AtomToPrintableString(cx, caller); + if (!callerstr) + return JS_FALSE; + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_INDIRECT_CALL, callerstr); + return JS_FALSE; + } + } + return JS_TRUE; +} + +JSObject * +js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller) +{ + JSClass *clasp; + JSExtendedClass *xclasp; + JSObject *inner; + + if (!scopeobj) + goto bad; + + OBJ_TO_INNER_OBJECT(cx, scopeobj); + if (!scopeobj) + return NULL; + + inner = scopeobj; + + /* XXX This is an awful gross hack. */ + while (scopeobj) { + clasp = OBJ_GET_CLASS(cx, scopeobj); + if (clasp->flags & JSCLASS_IS_EXTENDED) { + xclasp = (JSExtendedClass*)clasp; + if (xclasp->innerObject && + xclasp->innerObject(cx, scopeobj) != scopeobj) { + goto bad; + } + } + + scopeobj = OBJ_GET_PARENT(cx, scopeobj); + } + + return inner; + +bad: + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_INDIRECT_CALL, caller); + return NULL; +} + +const char * +js_ComputeFilename(JSContext *cx, JSStackFrame *caller, + JSPrincipals *principals, uintN *linenop) +{ + uint32 flags; +#ifdef DEBUG + JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx); +#endif + + JS_ASSERT(principals || !(callbacks && callbacks->findObjectPrincipals)); + flags = JS_GetScriptFilenameFlags(caller->script); + if ((flags & JSFILENAME_PROTECTED) && + principals && + strcmp(principals->codebase, "[System Principal]")) { + *linenop = 0; + return principals->codebase; + } + + if (caller->regs && *caller->regs->pc == JSOP_EVAL) { + JS_ASSERT(caller->regs->pc[JSOP_EVAL_LENGTH] == JSOP_LINENO); + *linenop = GET_UINT16(caller->regs->pc + JSOP_EVAL_LENGTH); + } else { + *linenop = js_FramePCToLineNumber(cx, caller); + } + return caller->script->filename; +} + +static JSBool +obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSStackFrame *fp, *caller; + JSBool indirectCall; + JSObject *scopeobj; + JSString *str; + const char *file; + uintN line; + JSPrincipals *principals; + uint32 tcflags; + JSScript *script; + JSBool ok; +#if JS_HAS_EVAL_THIS_SCOPE + JSObject *callerScopeChain = NULL, *callerVarObj = NULL; + JSObject *setCallerScopeChain = NULL; + JSBool setCallerVarObj = JS_FALSE; +#endif + + fp = cx->fp; + caller = JS_GetScriptedCaller(cx, fp); + indirectCall = (caller && caller->regs && *caller->regs->pc != JSOP_EVAL); + + /* + * Ban all indirect uses of eval (global.foo = eval; global.foo(...)) and + * calls that attempt to use a non-global object as the "with" object in + * the former indirect case. + */ + scopeobj = OBJ_GET_PARENT(cx, obj); + if (scopeobj) { + scopeobj = js_GetWrappedObject(cx, obj); + scopeobj = OBJ_GET_PARENT(cx, scopeobj); + } + if (indirectCall || scopeobj) { + uintN flags = scopeobj + ? JSREPORT_ERROR + : JSREPORT_STRICT | JSREPORT_WARNING; + if (!JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, NULL, + JSMSG_BAD_INDIRECT_CALL, + js_eval_str)) { + return JS_FALSE; + } + } + + if (!JSVAL_IS_STRING(argv[0])) { + *rval = argv[0]; + return JS_TRUE; + } + + /* + * If the caller is a lightweight function and doesn't have a variables + * object, then we need to provide one for the compiler to stick any + * declared (var) variables into. + */ + if (caller && !caller->varobj && !js_GetCallObject(cx, caller, NULL)) + return JS_FALSE; + + /* eval no longer takes an optional trailing argument. */ + if (argc >= 2 && + !JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT, + js_GetErrorMessage, NULL, + JSMSG_EVAL_ARITY)) { + return JS_FALSE; + } + + /* From here on, control must exit through label out with ok set. */ + MUST_FLOW_THROUGH("out"); + if (!scopeobj) { +#if JS_HAS_EVAL_THIS_SCOPE + /* If obj.eval(str), emulate 'with (obj) eval(str)' in the caller. */ + if (indirectCall) { + callerScopeChain = js_GetScopeChain(cx, caller); + if (!callerScopeChain) { + ok = JS_FALSE; + goto out; + } + OBJ_TO_INNER_OBJECT(cx, obj); + if (!obj) { + ok = JS_FALSE; + goto out; + } + if (obj != callerScopeChain) { + ok = js_CheckPrincipalsAccess(cx, obj, + caller->script->principals, + cx->runtime->atomState.evalAtom); + if (!ok) + goto out; + + scopeobj = js_NewWithObject(cx, obj, callerScopeChain, -1); + if (!scopeobj) { + ok = JS_FALSE; + goto out; + } + + /* Set fp->scopeChain too, for the compiler. */ + caller->scopeChain = fp->scopeChain = scopeobj; + + /* Remember scopeobj so we can null its private when done. */ + setCallerScopeChain = scopeobj; + } + + callerVarObj = caller->varobj; + if (obj != callerVarObj) { + /* Set fp->varobj too, for the compiler. */ + caller->varobj = fp->varobj = obj; + setCallerVarObj = JS_TRUE; + } + } +#endif + + /* + * Compile using caller's current scope object. + * + * NB: This means that native callers (who reach this point through + * the C API) must use the two parameter form. + */ + if (caller) { + scopeobj = js_GetScopeChain(cx, caller); + if (!scopeobj) { + ok = JS_FALSE; + goto out; + } + } + } + + /* Ensure we compile this eval with the right object in the scope chain. */ + scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_eval_str); + if (!scopeobj) { + ok = JS_FALSE; + goto out; + } + + str = JSVAL_TO_STRING(argv[0]); + if (caller) { + principals = JS_EvalFramePrincipals(cx, fp, caller); + file = js_ComputeFilename(cx, caller, principals, &line); + } else { + file = NULL; + line = 0; + principals = NULL; + } + + tcflags = TCF_COMPILE_N_GO; + if (caller) + tcflags |= TCF_PUT_STATIC_DEPTH(caller->script->staticDepth + 1); + script = js_CompileScript(cx, scopeobj, caller, principals, tcflags, + JSSTRING_CHARS(str), JSSTRING_LENGTH(str), + NULL, file, line); + if (!script) { + ok = JS_FALSE; + goto out; + } + + if (argc < 2) { + /* Execute using caller's new scope object (might be a Call object). */ + if (caller) + scopeobj = caller->scopeChain; + } + + /* + * Belt-and-braces: check that the lesser of eval's principals and the + * caller's principals has access to scopeobj. + */ + ok = js_CheckPrincipalsAccess(cx, scopeobj, principals, + cx->runtime->atomState.evalAtom); + if (ok) + ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval); + + script->u.nextToGC = JS_SCRIPTS_TO_GC(cx); + JS_SCRIPTS_TO_GC(cx) = script; +#ifdef CHECK_SCRIPT_OWNER + script->owner = NULL; +#endif + +out: +#if JS_HAS_EVAL_THIS_SCOPE + /* Restore OBJ_GET_PARENT(scopeobj) not callerScopeChain in case of Call. */ + if (setCallerScopeChain) { + caller->scopeChain = callerScopeChain; + JS_ASSERT(OBJ_GET_CLASS(cx, setCallerScopeChain) == &js_WithClass); + JS_SetPrivate(cx, setCallerScopeChain, NULL); + } + if (setCallerVarObj) + caller->varobj = callerVarObj; +#endif + return ok; +} + +#if JS_HAS_OBJ_WATCHPOINT + +static JSBool +obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp, + void *closure) +{ + JSObject *callable; + JSSecurityCallbacks *callbacks; + JSStackFrame *caller; + JSPrincipals *subject, *watcher; + JSResolvingKey key; + JSResolvingEntry *entry; + uint32 generation; + jsval argv[3]; + JSBool ok; + + callable = (JSObject *) closure; + + callbacks = JS_GetSecurityCallbacks(cx); + if (callbacks && callbacks->findObjectPrincipals) { + /* Skip over any obj_watch_* frames between us and the real subject. */ + caller = JS_GetScriptedCaller(cx, cx->fp); + if (caller) { + /* + * Only call the watch handler if the watcher is allowed to watch + * the currently executing script. + */ + watcher = callbacks->findObjectPrincipals(cx, callable); + subject = JS_StackFramePrincipals(cx, caller); + + if (watcher && subject && !watcher->subsume(watcher, subject)) { + /* Silently don't call the watch handler. */ + return JS_TRUE; + } + } + } + + /* Avoid recursion on (obj, id) already being watched on cx. */ + key.obj = obj; + key.id = id; + if (!js_StartResolving(cx, &key, JSRESFLAG_WATCH, &entry)) + return JS_FALSE; + if (!entry) + return JS_TRUE; + generation = cx->resolvingTable->generation; + + argv[0] = id; + argv[1] = old; + argv[2] = *nvp; + ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(callable), 3, argv, nvp); + js_StopResolving(cx, &key, JSRESFLAG_WATCH, entry, generation); + return ok; +} + +static JSBool +obj_watch(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *callable; + jsval userid, value; + jsid propid; + JSObject *obj; + uintN attrs; + + if (argc <= 1) { + js_ReportMissingArg(cx, vp, 1); + return JS_FALSE; + } + + callable = js_ValueToCallableObject(cx, &vp[3], 0); + if (!callable) + return JS_FALSE; + + /* Compute the unique int/atom symbol id needed by js_LookupProperty. */ + userid = vp[2]; + if (!JS_ValueToId(cx, userid, &propid)) + return JS_FALSE; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !OBJ_CHECK_ACCESS(cx, obj, propid, JSACC_WATCH, &value, &attrs)) + return JS_FALSE; + if (attrs & JSPROP_READONLY) + return JS_TRUE; + *vp = JSVAL_VOID; + + if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_MakeArraySlow(cx, obj)) + return JS_FALSE; + return JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, callable); +} + +static JSBool +obj_unwatch(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + *vp = JSVAL_VOID; + return JS_ClearWatchPoint(cx, obj, argc != 0 ? vp[2] : JSVAL_VOID, + NULL, NULL); +} + +#endif /* JS_HAS_OBJ_WATCHPOINT */ + +/* + * Prototype and property query methods, to complement the 'in' and + * 'instanceof' operators. + */ + +/* Proposed ECMA 15.2.4.5. */ +static JSBool +obj_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + return obj && + js_HasOwnPropertyHelper(cx, obj->map->ops->lookupProperty, argc, vp); +} + +JSBool +js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc, + jsval *vp) +{ + jsid id; + JSObject *obj; + + if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id)) + return JS_FALSE; + obj = JS_THIS_OBJECT(cx, vp); + return obj && js_HasOwnProperty(cx, lookup, obj, id, vp); +} + +JSBool +js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id, + jsval *vp) +{ + JSObject *obj2; + JSProperty *prop; + JSScopeProperty *sprop; + + if (!lookup(cx, obj, id, &obj2, &prop)) + return JS_FALSE; + if (!prop) { + *vp = JSVAL_FALSE; + } else if (obj2 == obj) { + *vp = JSVAL_TRUE; + } else { + JSClass *clasp; + JSExtendedClass *xclasp; + JSObject *outer; + + clasp = OBJ_GET_CLASS(cx, obj2); + if (!(clasp->flags & JSCLASS_IS_EXTENDED) || + !(xclasp = (JSExtendedClass *) clasp)->outerObject) { + outer = NULL; + } else { + outer = xclasp->outerObject(cx, obj2); + if (!outer) + return JS_FALSE; + } + if (outer == obj) { + *vp = JSVAL_TRUE; + } else if (OBJ_IS_NATIVE(obj2) && OBJ_GET_CLASS(cx, obj) == clasp) { + /* + * The combination of JSPROP_SHARED and JSPROP_PERMANENT in a + * delegated property makes that property appear to be direct in + * all delegating instances of the same native class. This hack + * avoids bloating every function instance with its own 'length' + * (AKA 'arity') property. But it must not extend across class + * boundaries, to avoid making hasOwnProperty lie (bug 320854). + * + * It's not really a hack, of course: a permanent property can't + * be deleted, and JSPROP_SHARED means "don't allocate a slot in + * any instance, prototype or delegating". Without a slot, and + * without the ability to remove and recreate (with differences) + * the property, there is no way to tell whether it is directly + * owned, or indirectly delegated. + */ + sprop = (JSScopeProperty *)prop; + *vp = BOOLEAN_TO_JSVAL(SPROP_IS_SHARED_PERMANENT(sprop)); + } else { + *vp = JSVAL_FALSE; + } + } + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + return JS_TRUE; +} + +#ifdef JS_TRACER +static int32 FASTCALL +Object_p_hasOwnProperty(JSContext* cx, JSObject* obj, JSString *str) +{ + jsid id; + jsval v; + + if (!js_ValueToStringId(cx, STRING_TO_JSVAL(str), &id)) + return JSVAL_TO_BOOLEAN(JSVAL_VOID); + if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &v)) + return JSVAL_TO_BOOLEAN(JSVAL_VOID); + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + return JSVAL_TO_BOOLEAN(v); +} +#endif + +/* Proposed ECMA 15.2.4.6. */ +static JSBool +obj_isPrototypeOf(JSContext *cx, uintN argc, jsval *vp) +{ + JSBool b; + + if (!js_IsDelegate(cx, JS_THIS_OBJECT(cx, vp), + argc != 0 ? vp[2] : JSVAL_VOID, &b)) { + return JS_FALSE; + } + *vp = BOOLEAN_TO_JSVAL(b); + return JS_TRUE; +} + +/* Proposed ECMA 15.2.4.7. */ +static JSBool +obj_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp) +{ + jsid id; + JSObject *obj; + + if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id)) + return JS_FALSE; + + obj = JS_THIS_OBJECT(cx, vp); + return obj && js_PropertyIsEnumerable(cx, obj, id, vp); +} + +#ifdef JS_TRACER +static int32 FASTCALL +Object_p_propertyIsEnumerable(JSContext* cx, JSObject* obj, JSString *str) +{ + jsid id = ATOM_TO_JSID(STRING_TO_JSVAL(str)); + jsval v; + if (!js_PropertyIsEnumerable(cx, obj, id, &v)) + return JSVAL_TO_BOOLEAN(JSVAL_VOID); + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + return JSVAL_TO_BOOLEAN(v); +} +#endif + +JSBool +js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + JSObject *pobj; + uintN attrs; + JSProperty *prop; + JSBool ok; + + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) + return JS_FALSE; + + if (!prop) { + *vp = JSVAL_FALSE; + return JS_TRUE; + } + + /* + * XXX ECMA spec error compatible: return false unless hasOwnProperty. + * The ECMA spec really should be fixed so propertyIsEnumerable and the + * for..in loop agree on whether prototype properties are enumerable, + * obviously by fixing this method (not by breaking the for..in loop!). + * + * We check here for shared permanent prototype properties, which should + * be treated as if they are local to obj. They are an implementation + * technique used to satisfy ECMA requirements; users should not be able + * to distinguish a shared permanent proto-property from a local one. + */ + if (pobj != obj && + !(OBJ_IS_NATIVE(pobj) && + SPROP_IS_SHARED_PERMANENT((JSScopeProperty *)prop))) { + OBJ_DROP_PROPERTY(cx, pobj, prop); + *vp = JSVAL_FALSE; + return JS_TRUE; + } + + ok = OBJ_GET_ATTRIBUTES(cx, pobj, id, prop, &attrs); + OBJ_DROP_PROPERTY(cx, pobj, prop); + if (ok) + *vp = BOOLEAN_TO_JSVAL((attrs & JSPROP_ENUMERATE) != 0); + return ok; +} + +#if JS_HAS_GETTER_SETTER +static JSBool +obj_defineGetter(JSContext *cx, uintN argc, jsval *vp) +{ + jsval fval, junk; + jsid id; + JSObject *obj; + uintN attrs; + + if (argc <= 1 || JS_TypeOfValue(cx, vp[3]) != JSTYPE_FUNCTION) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_GETTER_OR_SETTER, + js_getter_str); + return JS_FALSE; + } + fval = vp[3]; + + if (!JS_ValueToId(cx, vp[2], &id)) + return JS_FALSE; + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !js_CheckRedeclaration(cx, obj, id, JSPROP_GETTER, NULL, NULL)) + return JS_FALSE; + /* + * Getters and setters are just like watchpoints from an access + * control point of view. + */ + if (!OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &junk, &attrs)) + return JS_FALSE; + *vp = JSVAL_VOID; + return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, + (JSPropertyOp) JSVAL_TO_OBJECT(fval), + JS_PropertyStub, + JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED, + NULL); +} + +static JSBool +obj_defineSetter(JSContext *cx, uintN argc, jsval *vp) +{ + jsval fval, junk; + jsid id; + JSObject *obj; + uintN attrs; + + if (argc <= 1 || JS_TypeOfValue(cx, vp[3]) != JSTYPE_FUNCTION) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_GETTER_OR_SETTER, + js_setter_str); + return JS_FALSE; + } + fval = vp[3]; + + if (!JS_ValueToId(cx, vp[2], &id)) + return JS_FALSE; + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !js_CheckRedeclaration(cx, obj, id, JSPROP_SETTER, NULL, NULL)) + return JS_FALSE; + /* + * Getters and setters are just like watchpoints from an access + * control point of view. + */ + if (!OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &junk, &attrs)) + return JS_FALSE; + *vp = JSVAL_VOID; + return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, + JS_PropertyStub, + (JSPropertyOp) JSVAL_TO_OBJECT(fval), + JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED, + NULL); +} + +static JSBool +obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp) +{ + jsid id; + JSObject *obj, *pobj; + JSProperty *prop; + JSScopeProperty *sprop; + + if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id)) + return JS_FALSE; + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) + return JS_FALSE; + *vp = JSVAL_VOID; + if (prop) { + if (OBJ_IS_NATIVE(pobj)) { + sprop = (JSScopeProperty *) prop; + if (sprop->attrs & JSPROP_GETTER) + *vp = OBJECT_TO_JSVAL(sprop->getter); + } + OBJ_DROP_PROPERTY(cx, pobj, prop); + } + return JS_TRUE; +} + +static JSBool +obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp) +{ + jsid id; + JSObject *obj, *pobj; + JSProperty *prop; + JSScopeProperty *sprop; + + if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id)) + return JS_FALSE; + obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) + return JS_FALSE; + *vp = JSVAL_VOID; + if (prop) { + if (OBJ_IS_NATIVE(pobj)) { + sprop = (JSScopeProperty *) prop; + if (sprop->attrs & JSPROP_SETTER) + *vp = OBJECT_TO_JSVAL(sprop->setter); + } + OBJ_DROP_PROPERTY(cx, pobj, prop); + } + return JS_TRUE; +} +#endif /* JS_HAS_GETTER_SETTER */ + +JSBool +obj_getPrototypeOf(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + uintN attrs; + + if (argc == 0) { + js_ReportMissingArg(cx, vp, 0); + return JS_FALSE; + } + + obj = js_ValueToNonNullObject(cx, vp[2]); + if (!obj) + return JS_FALSE; + vp[2] = OBJECT_TO_JSVAL(obj); + + return OBJ_CHECK_ACCESS(cx, obj, + ATOM_TO_JSID(cx->runtime->atomState.protoAtom), + JSACC_PROTO, vp, &attrs); +} + +#if JS_HAS_OBJ_WATCHPOINT +const char js_watch_str[] = "watch"; +const char js_unwatch_str[] = "unwatch"; +#endif +const char js_hasOwnProperty_str[] = "hasOwnProperty"; +const char js_isPrototypeOf_str[] = "isPrototypeOf"; +const char js_propertyIsEnumerable_str[] = "propertyIsEnumerable"; +#if JS_HAS_GETTER_SETTER +const char js_defineGetter_str[] = "__defineGetter__"; +const char js_defineSetter_str[] = "__defineSetter__"; +const char js_lookupGetter_str[] = "__lookupGetter__"; +const char js_lookupSetter_str[] = "__lookupSetter__"; +#endif + +JS_DEFINE_TRCINFO_1(obj_hasOwnProperty, + (3, (static, BOOL_FAIL, Object_p_hasOwnProperty, CONTEXT, THIS, STRING, 0, 0))) +JS_DEFINE_TRCINFO_1(obj_propertyIsEnumerable, + (3, (static, BOOL_FAIL, Object_p_propertyIsEnumerable, CONTEXT, THIS, STRING, 0, 0))) + +static JSFunctionSpec object_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, obj_toSource, 0,0), +#endif + JS_FN(js_toString_str, obj_toString, 0,0), + JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0), + JS_FN(js_valueOf_str, obj_valueOf, 0,0), +#if JS_HAS_OBJ_WATCHPOINT + JS_FN(js_watch_str, obj_watch, 2,0), + JS_FN(js_unwatch_str, obj_unwatch, 1,0), +#endif + JS_TN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0, + obj_hasOwnProperty_trcinfo), + JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0), + JS_TN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0, + obj_propertyIsEnumerable_trcinfo), +#if JS_HAS_GETTER_SETTER + JS_FN(js_defineGetter_str, obj_defineGetter, 2,0), + JS_FN(js_defineSetter_str, obj_defineSetter, 2,0), + JS_FN(js_lookupGetter_str, obj_lookupGetter, 1,0), + JS_FN(js_lookupSetter_str, obj_lookupSetter, 1,0), +#endif + JS_FS_END +}; + +static JSFunctionSpec object_static_methods[] = { + JS_FN("getPrototypeOf", obj_getPrototypeOf, 1,0), + JS_FS_END +}; + +JSBool +js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if (argc == 0) { + /* Trigger logic below to construct a blank object. */ + obj = NULL; + } else { + /* If argv[0] is null or undefined, obj comes back null. */ + if (!js_ValueToObject(cx, argv[0], &obj)) + return JS_FALSE; + } + if (!obj) { + JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0])); + if (cx->fp->flags & JSFRAME_CONSTRUCTING) + return JS_TRUE; + obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + } + *rval = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +/* + * ObjectOps and Class for with-statement stack objects. + */ +static JSBool +with_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp) +{ + JSObject *proto = OBJ_GET_PROTO(cx, obj); + if (!proto) + return js_LookupProperty(cx, obj, id, objp, propp); + return OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp); +} + +static JSBool +with_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + JSObject *proto = OBJ_GET_PROTO(cx, obj); + if (!proto) + return js_GetProperty(cx, obj, id, vp); + return OBJ_GET_PROPERTY(cx, proto, id, vp); +} + +static JSBool +with_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + JSObject *proto = OBJ_GET_PROTO(cx, obj); + if (!proto) + return js_SetProperty(cx, obj, id, vp); + return OBJ_SET_PROPERTY(cx, proto, id, vp); +} + +static JSBool +with_GetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp) +{ + JSObject *proto = OBJ_GET_PROTO(cx, obj); + if (!proto) + return js_GetAttributes(cx, obj, id, prop, attrsp); + return OBJ_GET_ATTRIBUTES(cx, proto, id, prop, attrsp); +} + +static JSBool +with_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp) +{ + JSObject *proto = OBJ_GET_PROTO(cx, obj); + if (!proto) + return js_SetAttributes(cx, obj, id, prop, attrsp); + return OBJ_SET_ATTRIBUTES(cx, proto, id, prop, attrsp); +} + +static JSBool +with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) +{ + JSObject *proto = OBJ_GET_PROTO(cx, obj); + if (!proto) + return js_DeleteProperty(cx, obj, id, rval); + return OBJ_DELETE_PROPERTY(cx, proto, id, rval); +} + +static JSBool +with_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp) +{ + JSObject *proto = OBJ_GET_PROTO(cx, obj); + if (!proto) + return js_DefaultValue(cx, obj, hint, vp); + return OBJ_DEFAULT_VALUE(cx, proto, hint, vp); +} + +static JSBool +with_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp) +{ + JSObject *proto = OBJ_GET_PROTO(cx, obj); + if (!proto) + return js_Enumerate(cx, obj, enum_op, statep, idp); + return OBJ_ENUMERATE(cx, proto, enum_op, statep, idp); +} + +static JSBool +with_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + jsval *vp, uintN *attrsp) +{ + JSObject *proto = OBJ_GET_PROTO(cx, obj); + if (!proto) + return js_CheckAccess(cx, obj, id, mode, vp, attrsp); + return OBJ_CHECK_ACCESS(cx, proto, id, mode, vp, attrsp); +} + +static JSObject * +with_ThisObject(JSContext *cx, JSObject *obj) +{ + JSObject *proto = OBJ_GET_PROTO(cx, obj); + if (!proto) + return obj; + return OBJ_THIS_OBJECT(cx, proto); +} + +JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = { + js_NewObjectMap, js_DestroyObjectMap, + with_LookupProperty, js_DefineProperty, + with_GetProperty, with_SetProperty, + with_GetAttributes, with_SetAttributes, + with_DeleteProperty, with_DefaultValue, + with_Enumerate, with_CheckAccess, + with_ThisObject, NATIVE_DROP_PROPERTY, + NULL, NULL, + NULL, NULL, + js_SetProtoOrParent, js_SetProtoOrParent, + js_TraceObject, js_Clear, + NULL, NULL +}; + +static JSObjectOps * +with_getObjectOps(JSContext *cx, JSClass *clasp) +{ + return &js_WithObjectOps; +} + +JSClass js_WithClass = { + "With", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + with_getObjectOps, + 0,0,0,0,0,0,0 +}; + +JSObject * +js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth) +{ + JSObject *obj; + + obj = js_NewObject(cx, &js_WithClass, proto, parent, 0); + if (!obj) + return NULL; + STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(cx->fp)); + OBJ_SET_BLOCK_DEPTH(cx, obj, depth); + return obj; +} + +JSObject * +js_NewBlockObject(JSContext *cx) +{ + JSObject *obj; + JSBool ok; + + /* + * Null obj's proto slot so that Object.prototype.* does not pollute block + * scopes. Make sure obj has its own scope too, since clearing proto does + * not affect OBJ_SCOPE(obj). + */ + obj = js_NewObject(cx, &js_BlockClass, NULL, NULL, 0); + if (!obj) + return NULL; + JS_LOCK_OBJ(cx, obj); + ok = js_GetMutableScope(cx, obj) != NULL; + JS_UNLOCK_OBJ(cx, obj); + if (!ok) + return NULL; + OBJ_CLEAR_PROTO(cx, obj); + return obj; +} + +JSObject * +js_CloneBlockObject(JSContext *cx, JSObject *proto, JSObject *parent, + JSStackFrame *fp) +{ + JSObject *clone; + + JS_ASSERT(STOBJ_GET_CLASS(proto) == &js_BlockClass); + JS_ASSERT(!OBJ_IS_CLONED_BLOCK(proto)); + clone = js_NewObject(cx, &js_BlockClass, proto, parent, 0); + if (!clone) + return NULL; + STOBJ_SET_SLOT(clone, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(fp)); + STOBJ_SET_SLOT(clone, JSSLOT_BLOCK_DEPTH, + OBJ_GET_SLOT(cx, proto, JSSLOT_BLOCK_DEPTH)); + JS_ASSERT(OBJ_IS_CLONED_BLOCK(clone)); + return clone; +} + +JSBool +js_PutBlockObject(JSContext *cx, JSBool normalUnwind) +{ + JSStackFrame *fp; + JSObject *obj; + uintN depth, count; + + /* Blocks have one fixed slot available for the first local.*/ + JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2); + + fp = cx->fp; + obj = fp->scopeChain; + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_BlockClass); + JS_ASSERT(OBJ_GET_PRIVATE(cx, obj) == cx->fp); + JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj)); + + /* + * Block objects should never be exposed to scripts. Thus the clone should + * not own the property map and rather always share it with the prototype + * object. This allows to skip updating OBJ_SCOPE(obj)->map.freeslot after + * we copy the stack slots into reserved slots. + */ + JS_ASSERT(OBJ_SCOPE(obj)->object != obj); + + /* Block objects should not have reserved slots before they are put. */ + JS_ASSERT(STOBJ_NSLOTS(obj) == JS_INITIAL_NSLOTS); + + /* The block and its locals must be on the current stack for GC safety. */ + depth = OBJ_BLOCK_DEPTH(cx, obj); + count = OBJ_BLOCK_COUNT(cx, obj); + JS_ASSERT(depth <= (size_t) (fp->regs->sp - StackBase(fp))); + JS_ASSERT(count <= (size_t) (fp->regs->sp - StackBase(fp) - depth)); + + /* See comments in CheckDestructuring from jsparse.c. */ + JS_ASSERT(count >= 1); + + depth += fp->script->nfixed; + obj->fslots[JSSLOT_BLOCK_DEPTH + 1] = fp->slots[depth]; + if (normalUnwind && count > 1) { + --count; + JS_LOCK_OBJ(cx, obj); + if (!js_ReallocSlots(cx, obj, JS_INITIAL_NSLOTS + count, JS_TRUE)) + normalUnwind = JS_FALSE; + else + memcpy(obj->dslots, fp->slots + depth + 1, count * sizeof(jsval)); + JS_UNLOCK_OBJ(cx, obj); + } + + /* We must clear the private slot even with errors. */ + JS_SetPrivate(cx, obj, NULL); + fp->scopeChain = OBJ_GET_PARENT(cx, obj); + return normalUnwind; +} + +static JSBool +block_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + uintN index; + JSStackFrame *fp; + + JS_ASSERT(JS_InstanceOf(cx, obj, &js_BlockClass, NULL)); + JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj)); + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + + index = (uint16) JSVAL_TO_INT(id); + fp = (JSStackFrame *) JS_GetPrivate(cx, obj); + if (fp) { + index += fp->script->nfixed + OBJ_BLOCK_DEPTH(cx, obj); + JS_ASSERT(index < fp->script->nslots); + *vp = fp->slots[index]; + return JS_TRUE; + } + + /* Reserve slots start with the first slot after the private. */ + index += JSSLOT_BLOCK_DEPTH - JSSLOT_PRIVATE; + return JS_GetReservedSlot(cx, obj, index, vp); +} + +static JSBool +block_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + uintN index; + JSStackFrame *fp; + + JS_ASSERT(JS_InstanceOf(cx, obj, &js_BlockClass, NULL)); + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + + index = (uint16) JSVAL_TO_INT(id); + fp = (JSStackFrame *) JS_GetPrivate(cx, obj); + if (fp) { + index += fp->script->nfixed + OBJ_BLOCK_DEPTH(cx, obj); + JS_ASSERT(index < fp->script->nslots); + fp->slots[index] = *vp; + return JS_TRUE; + } + + /* Reserve slots start with the first slot after the private. */ + index += JSSLOT_BLOCK_DEPTH - JSSLOT_PRIVATE; + return JS_SetReservedSlot(cx, obj, index, *vp); +} + +#if JS_HAS_XDR + +#define NO_PARENT_INDEX ((uint32)-1) + +uint32 +FindObjectIndex(JSObjectArray *array, JSObject *obj) +{ + size_t i; + + if (array) { + i = array->length; + do { + + if (array->vector[--i] == obj) + return i; + } while (i != 0); + } + + return NO_PARENT_INDEX; +} + +static JSBool +block_xdrObject(JSXDRState *xdr, JSObject **objp) +{ + JSContext *cx; + uint32 parentId; + JSObject *obj, *parent; + uint16 depth, count, i; + uint32 tmp; + JSTempValueRooter tvr; + JSScopeProperty *sprop; + jsid propid; + JSAtom *atom; + int16 shortid; + JSBool ok; + + cx = xdr->cx; +#ifdef __GNUC__ + obj = NULL; /* quell GCC overwarning */ +#endif + + if (xdr->mode == JSXDR_ENCODE) { + obj = *objp; + parent = OBJ_GET_PARENT(cx, obj); + parentId = (xdr->script->objectsOffset == 0) + ? NO_PARENT_INDEX + : FindObjectIndex(JS_SCRIPT_OBJECTS(xdr->script), parent); + depth = (uint16)OBJ_BLOCK_DEPTH(cx, obj); + count = (uint16)OBJ_BLOCK_COUNT(cx, obj); + tmp = (uint32)(depth << 16) | count; + } +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + else count = 0; +#endif + + /* First, XDR the parent atomid. */ + if (!JS_XDRUint32(xdr, &parentId)) + return JS_FALSE; + + if (xdr->mode == JSXDR_DECODE) { + obj = js_NewBlockObject(cx); + if (!obj) + return JS_FALSE; + *objp = obj; + + /* + * If there's a parent id, then get the parent out of our script's + * object array. We know that we XDR block object in outer-to-inner + * order, which means that getting the parent now will work. + */ + if (parentId == NO_PARENT_INDEX) + parent = NULL; + else + JS_GET_SCRIPT_OBJECT(xdr->script, parentId, parent); + STOBJ_SET_PARENT(obj, parent); + } + + JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(obj), &tvr); + + if (!JS_XDRUint32(xdr, &tmp)) { + JS_POP_TEMP_ROOT(cx, &tvr); + return JS_FALSE; + } + + if (xdr->mode == JSXDR_DECODE) { + depth = (uint16)(tmp >> 16); + count = (uint16)tmp; + STOBJ_SET_SLOT(obj, JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth)); + } + + /* + * XDR the block object's properties. We know that there are 'count' + * properties to XDR, stored as id/shortid pairs. We do not XDR any + * non-native properties, only those that the compiler created. + */ + sprop = NULL; + ok = JS_TRUE; + for (i = 0; i < count; i++) { + if (xdr->mode == JSXDR_ENCODE) { + /* Find a property to XDR. */ + do { + /* If sprop is NULL, this is the first property. */ + sprop = sprop ? sprop->parent : OBJ_SCOPE(obj)->lastProp; + } while (!(sprop->flags & SPROP_HAS_SHORTID)); + + JS_ASSERT(sprop->getter == js_BlockClass.getProperty); + propid = sprop->id; + JS_ASSERT(JSID_IS_ATOM(propid)); + atom = JSID_TO_ATOM(propid); + shortid = sprop->shortid; + JS_ASSERT(shortid >= 0); + } + + /* XDR the real id, then the shortid. */ + if (!js_XDRStringAtom(xdr, &atom) || + !JS_XDRUint16(xdr, (uint16 *)&shortid)) { + ok = JS_FALSE; + break; + } + + if (xdr->mode == JSXDR_DECODE) { + if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), + JSVAL_VOID, NULL, NULL, + JSPROP_ENUMERATE | JSPROP_PERMANENT, + SPROP_HAS_SHORTID, shortid, NULL)) { + ok = JS_FALSE; + break; + } + } + } + + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +#else +# define block_xdrObject NULL +#endif + +static uint32 +block_reserveSlots(JSContext *cx, JSObject *obj) +{ + return OBJ_IS_CLONED_BLOCK(obj) ? OBJ_BLOCK_COUNT(cx, obj) : 0; +} + +JSClass js_BlockClass = { + "Block", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | + JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_CACHED_PROTO(JSProto_Block), + JS_PropertyStub, JS_PropertyStub, block_getProperty, block_setProperty, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + NULL, NULL, NULL, NULL, block_xdrObject, NULL, NULL, block_reserveSlots +}; + +JSObject* +js_InitBlockClass(JSContext *cx, JSObject* obj) +{ + JSObject *proto; + + proto = JS_InitClass(cx, obj, NULL, &js_BlockClass, NULL, 0, NULL, + NULL, NULL, NULL); + if (!proto) + return NULL; + + OBJ_CLEAR_PROTO(cx, proto); + return proto; +} + +JSObject * +js_InitEval(JSContext *cx, JSObject *obj) +{ + /* ECMA (15.1.2.1) says 'eval' is a property of the global object. */ + if (!js_DefineFunction(cx, obj, cx->runtime->atomState.evalAtom, + obj_eval, 1, 0)) { + return NULL; + } + + return obj; +} + +JSObject * +js_InitObjectClass(JSContext *cx, JSObject *obj) +{ + return JS_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1, + object_props, object_methods, NULL, + object_static_methods); +} + +void +js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops, + JSClass *clasp) +{ + map->nrefs = nrefs; + map->ops = ops; + map->freeslot = JSSLOT_FREE(clasp); +} + +JSObjectMap * +js_NewObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, + JSClass *clasp, JSObject *obj) +{ + return (JSObjectMap *) js_NewScope(cx, nrefs, ops, clasp, obj); +} + +void +js_DestroyObjectMap(JSContext *cx, JSObjectMap *map) +{ + js_DestroyScope(cx, (JSScope *)map); +} + +JSObjectMap * +js_HoldObjectMap(JSContext *cx, JSObjectMap *map) +{ + JS_ASSERT(map->nrefs >= 0); + JS_ATOMIC_INCREMENT(&map->nrefs); + return map; +} + +JSObjectMap * +js_DropObjectMap(JSContext *cx, JSObjectMap *map, JSObject *obj) +{ + JS_ASSERT(map->nrefs > 0); + JS_ATOMIC_DECREMENT(&map->nrefs); + if (map->nrefs == 0) { + map->ops->destroyObjectMap(cx, map); + return NULL; + } + if (MAP_IS_NATIVE(map) && ((JSScope *)map)->object == obj) + ((JSScope *)map)->object = NULL; + return map; +} + +static void +FreeSlots(JSContext *cx, JSObject *obj) +{ + if (obj->dslots) { + JS_ASSERT((uint32)obj->dslots[-1] > JS_INITIAL_NSLOTS); + JS_free(cx, obj->dslots - 1); + obj->dslots = NULL; + } +} + +#define SLOTS_TO_DYNAMIC_WORDS(nslots) \ + (JS_ASSERT((nslots) > JS_INITIAL_NSLOTS), (nslots) + 1 - JS_INITIAL_NSLOTS) + +#define DYNAMIC_WORDS_TO_SLOTS(words) \ + (JS_ASSERT((words) > 1), (words) - 1 + JS_INITIAL_NSLOTS) + +JSBool +js_ReallocSlots(JSContext *cx, JSObject *obj, uint32 nslots, + JSBool exactAllocation) +{ + jsval *old, *slots; + uint32 oslots, nwords, owords, log, i; + + /* + * Minimal number of dynamic slots to allocate. + */ +#define MIN_DYNAMIC_WORDS 4 + + /* + * The limit to switch to linear allocation strategy from the power of 2 + * growth no to waste too much memory. + */ +#define LINEAR_GROWTH_STEP JS_BIT(16) + + old = obj->dslots; + if (nslots <= JS_INITIAL_NSLOTS) { + if (old && + (exactAllocation || + SLOTS_TO_DYNAMIC_WORDS((uint32)old[-1]) != MIN_DYNAMIC_WORDS || + nslots <= (JS_INITIAL_NSLOTS + + JSSLOT_FREE(STOBJ_GET_CLASS(obj))) / 2)) { + /* + * We do not want to free dynamic slots when allocation is a hint, + * we reached minimal allocation and almost all fixed slots are + * used. It avoids allocating dynamic slots again when properties + * are added to the object. + * + * If there were no private or reserved slots, the condition to + * free the slots would be + * + * nslots <= JS_INITIAL_NSLOTS / 2 + * + * but to account for never removed slots before JSSLOT_FREE(class) + * we need to subtract it from the slot counts which gives + * + * nslots - JSSLOT_FREE <= (JS_INITIAL_NSLOTS - JSSLOT_FREE) / 2 + * + * or + * + * nslots <= (JS_INITIAL_NSLOTS + JSSLOT_FREE) / 2 + */ + FreeSlots(cx, obj); + } + return JS_TRUE; + } + + oslots = (old) ? (uint32)*--old : JS_INITIAL_NSLOTS; + nwords = SLOTS_TO_DYNAMIC_WORDS(nslots); + + if (nslots > oslots) { + if (!exactAllocation) { + /* + * Round up nslots so the number of bytes in dslots array is power + * of 2 to ensure exponential grouth. + */ + if (nwords <= MIN_DYNAMIC_WORDS) { + nwords = MIN_DYNAMIC_WORDS; + } else if (nwords < LINEAR_GROWTH_STEP) { + JS_CEILING_LOG2(log, nwords); + nwords = JS_BIT(log); + } else { + nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP); + } + } + slots = (jsval *)JS_realloc(cx, old, nwords * sizeof(jsval)); + if (!slots) + return JS_FALSE; + } else { + JS_ASSERT(nslots < oslots); + if (!exactAllocation) { + owords = DYNAMIC_WORDS_TO_SLOTS(oslots); + if (owords <= MIN_DYNAMIC_WORDS) + return JS_TRUE; + if (owords < LINEAR_GROWTH_STEP * 2) { + /* + * Shrink only if 1/4 of slots are left and we need to grow + * the array at least twice to reach the current capacity. It + * prevents frequent capacity growth/shrinking when slots are + * often removed and added. + */ + if (nwords > owords / 4) + return JS_TRUE; + JS_CEILING_LOG2(log, nwords); + nwords = JS_BIT(log); + if (nwords < MIN_DYNAMIC_WORDS) + nwords = MIN_DYNAMIC_WORDS; + } else { + /* + * Shrink only if we free at least 2 linear allocation + * segments, to prevent growth/shrinking resonance. + */ + if (nwords > owords - LINEAR_GROWTH_STEP * 2) + return JS_TRUE; + nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP); + } + } + + /* We avoid JS_realloc not to report a failed shrink attempt. */ + slots = (jsval *)realloc(old, nwords * sizeof(jsval)); + if (!slots) + slots = old; + } + + nslots = DYNAMIC_WORDS_TO_SLOTS(nwords); + *slots++ = (jsval)nslots; + obj->dslots = slots; + + /* If we're extending an allocation, initialize free slots. */ + for (i = oslots; i < nslots; i++) + slots[i - JS_INITIAL_NSLOTS] = JSVAL_VOID; + + return JS_TRUE; + +#undef LINEAR_GROWTH_STEP +#undef MIN_DYNAMIC_WORDS +} + +extern JSBool +js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp) +{ + JSProtoKey key; + JSAtom *atom; + + key = JSCLASS_CACHED_PROTO_KEY(clasp); + if (key != JSProto_Null) { + *idp = INT_TO_JSID(key); + } else if (clasp->flags & JSCLASS_IS_ANONYMOUS) { + *idp = INT_TO_JSID(JSProto_Object); + } else { + atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0); + if (!atom) + return JS_FALSE; + *idp = ATOM_TO_JSID(atom); + } + return JS_TRUE; +} + +JSObject * +js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent, + uintN objectSize) +{ + jsid id; + + /* Bootstrap the ur-object, and make it the default prototype object. */ + if (!proto) { + if (!js_GetClassId(cx, clasp, &id)) + return NULL; + if (!js_GetClassPrototype(cx, parent, id, &proto)) + return NULL; + if (!proto && + !js_GetClassPrototype(cx, parent, INT_TO_JSID(JSProto_Object), + &proto)) { + return NULL; + } + } + + return js_NewObjectWithGivenProto(cx, clasp, proto, parent, objectSize); +} + +JSObject * +js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent, uintN objectSize) +{ + JSObject *obj; + JSObjectOps *ops; + JSObjectMap *map; + JSClass *protoclasp; + uint32 nslots, i; + JSTempValueRooter tvr; + +#ifdef INCLUDE_MOZILLA_DTRACE + if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED()) + jsdtrace_object_create_start(cx->fp, clasp); +#endif + + /* Currently only functions can have non-standard allocation size. */ + if (clasp == &js_FunctionClass) { + if (objectSize == 0) + objectSize = sizeof(JSFunction); + else + JS_ASSERT(objectSize == sizeof(JSObject)); + } else { + JS_ASSERT(objectSize == 0); + objectSize = sizeof(JSObject); + } + + /* + * Allocate an object from the GC heap and initialize all its fields before + * doing any operation that can potentially trigger GC. + */ + obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, objectSize); + if (!obj) + goto earlybad; + + obj->map = NULL; + obj->dslots = NULL; + + /* + * Set the class slot with the initial value of the system and delegate + * flags set to false. + */ + JS_ASSERT(((jsuword) clasp & 3) == 0); + obj->classword = jsuword(clasp); + JS_ASSERT(!STOBJ_IS_DELEGATE(obj)); + JS_ASSERT(!STOBJ_IS_SYSTEM(obj)); + + /* Set the proto and parent properties. */ + STOBJ_SET_PROTO(obj, proto); + STOBJ_SET_PARENT(obj, parent); + + /* Initialize the remaining fixed slots. */ + for (i = JSSLOT_PRIVATE; i != JS_INITIAL_NSLOTS; ++i) + obj->fslots[i] = JSVAL_VOID; + +#ifdef DEBUG + memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN, + objectSize - sizeof(JSObject)); +#endif + + /* + * Root obj to prevent it from being collected out from under this call to + * js_NewObject. There's a possibilty of GC under the objectHook call-out + * further below. + */ + JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); + + /* Always call the class's getObjectOps hook if it has one. */ + ops = clasp->getObjectOps + ? clasp->getObjectOps(cx, clasp) + : &js_ObjectOps; + + /* + * Default parent to the parent of the prototype, which was set from + * the parent of the prototype's constructor. + */ + if (proto && !parent) + STOBJ_SET_PARENT(obj, OBJ_GET_PARENT(cx, proto)); + + /* + * Share proto's map only if it has the same JSObjectOps, and only if + * proto's class has the same private and reserved slots as obj's map + * and class have. We assume that if prototype and object are of the + * same class, they always have the same number of computed reserved + * slots (returned via clasp->reserveSlots); otherwise, prototype and + * object classes must have the same (null or not) reserveSlots hook. + */ + if (proto && + (map = proto->map)->ops == ops && + ((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp || + (!((protoclasp->flags ^ clasp->flags) & + (JSCLASS_HAS_PRIVATE | + (JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) && + protoclasp->reserveSlots == clasp->reserveSlots))) + { + /* Share the given prototype's map. */ + obj->map = js_HoldObjectMap(cx, map); + } else { + map = ops->newObjectMap(cx, 1, ops, clasp, obj); + if (!map) + goto bad; + obj->map = map; + + /* Let ops->newObjectMap set freeslot so as to reserve slots. */ + nslots = map->freeslot; + JS_ASSERT(nslots >= JSSLOT_PRIVATE); + if (nslots > JS_INITIAL_NSLOTS && + !js_ReallocSlots(cx, obj, nslots, JS_TRUE)) { + js_DropObjectMap(cx, map, obj); + obj->map = NULL; + goto bad; + } + } + + if (cx->debugHooks->objectHook) { + JS_KEEP_ATOMS(cx->runtime); + cx->debugHooks->objectHook(cx, obj, JS_TRUE, + cx->debugHooks->objectHookData); + JS_UNKEEP_ATOMS(cx->runtime); + } + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + cx->weakRoots.newborn[GCX_OBJECT] = obj; +#ifdef INCLUDE_MOZILLA_DTRACE + if (JAVASCRIPT_OBJECT_CREATE_ENABLED()) + jsdtrace_object_create(cx, clasp, obj); + if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED()) + jsdtrace_object_create_done(cx->fp, clasp); +#endif + return obj; + +bad: + obj = NULL; + goto out; + +earlybad: +#ifdef INCLUDE_MOZILLA_DTRACE + if (JAVASCRIPT_OBJECT_CREATE_ENABLED()) + jsdtrace_object_create(cx, clasp, NULL); + if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED()) + jsdtrace_object_create_done(cx->fp, clasp); +#endif + return NULL; +} + +JS_BEGIN_EXTERN_C + +static JSObject * +js_InitNullClass(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(0); + return NULL; +} + +#define JS_PROTO(name,code,init) extern JSObject *init(JSContext *, JSObject *); +#include "jsproto.tbl" +#undef JS_PROTO + +static JSObjectOp lazy_prototype_init[JSProto_LIMIT] = { +#define JS_PROTO(name,code,init) init, +#include "jsproto.tbl" +#undef JS_PROTO +}; + +JS_END_EXTERN_C + +JSBool +js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, + JSObject **objp) +{ + JSBool ok; + JSObject *tmp, *cobj; + JSResolvingKey rkey; + JSResolvingEntry *rentry; + uint32 generation; + JSObjectOp init; + jsval v; + + while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL) + obj = tmp; + if (!(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL)) { + *objp = NULL; + return JS_TRUE; + } + + ok = JS_GetReservedSlot(cx, obj, key, &v); + if (!ok) + return JS_FALSE; + if (!JSVAL_IS_PRIMITIVE(v)) { + *objp = JSVAL_TO_OBJECT(v); + return JS_TRUE; + } + + rkey.obj = obj; + rkey.id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[key]); + if (!js_StartResolving(cx, &rkey, JSRESFLAG_LOOKUP, &rentry)) + return JS_FALSE; + if (!rentry) { + /* Already caching key in obj -- suppress recursion. */ + *objp = NULL; + return JS_TRUE; + } + generation = cx->resolvingTable->generation; + + cobj = NULL; + init = lazy_prototype_init[key]; + if (init) { + if (!init(cx, obj)) { + ok = JS_FALSE; + } else { + ok = JS_GetReservedSlot(cx, obj, key, &v); + if (ok && !JSVAL_IS_PRIMITIVE(v)) + cobj = JSVAL_TO_OBJECT(v); + } + } + + js_StopResolving(cx, &rkey, JSRESFLAG_LOOKUP, rentry, generation); + *objp = cobj; + return ok; +} + +JSBool +js_SetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject *cobj) +{ + JS_ASSERT(!OBJ_GET_PARENT(cx, obj)); + if (!(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL)) + return JS_TRUE; + + return JS_SetReservedSlot(cx, obj, key, OBJECT_TO_JSVAL(cobj)); +} + +JSBool +js_FindClassObject(JSContext *cx, JSObject *start, jsid id, jsval *vp) +{ + JSObject *obj, *cobj, *pobj; + JSProtoKey key; + JSProperty *prop; + jsval v; + JSScopeProperty *sprop; + + if (start || (cx->fp && (start = cx->fp->scopeChain) != NULL)) { + /* Find the topmost object in the scope chain. */ + do { + obj = start; + start = OBJ_GET_PARENT(cx, obj); + } while (start); + } else { + obj = cx->globalObject; + if (!obj) { + *vp = JSVAL_VOID; + return JS_TRUE; + } + } + + OBJ_TO_INNER_OBJECT(cx, obj); + if (!obj) + return JS_FALSE; + + if (JSID_IS_INT(id)) { + key = (JSProtoKey) JSID_TO_INT(id); + JS_ASSERT(key != JSProto_Null); + if (!js_GetClassObject(cx, obj, key, &cobj)) + return JS_FALSE; + if (cobj) { + *vp = OBJECT_TO_JSVAL(cobj); + return JS_TRUE; + } + id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[key]); + } + + JS_ASSERT(OBJ_IS_NATIVE(obj)); + if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME, + &pobj, &prop) < 0) { + return JS_FALSE; + } + v = JSVAL_VOID; + if (prop) { + if (OBJ_IS_NATIVE(pobj)) { + sprop = (JSScopeProperty *) prop; + if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))) { + v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot); + if (JSVAL_IS_PRIMITIVE(v)) + v = JSVAL_VOID; + } + } + OBJ_DROP_PROPERTY(cx, pobj, prop); + } + *vp = v; + return JS_TRUE; +} + +JSObject * +js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent, uintN argc, jsval *argv) +{ + jsid id; + jsval cval, rval; + JSTempValueRooter argtvr, tvr; + JSObject *obj, *ctor; + + JS_PUSH_TEMP_ROOT(cx, argc, argv, &argtvr); + + if (!js_GetClassId(cx, clasp, &id) || + !js_FindClassObject(cx, parent, id, &cval)) { + JS_POP_TEMP_ROOT(cx, &argtvr); + return NULL; + } + + if (JSVAL_IS_PRIMITIVE(cval)) { + js_ReportIsNotFunction(cx, &cval, JSV2F_CONSTRUCT | JSV2F_SEARCH_STACK); + JS_POP_TEMP_ROOT(cx, &argtvr); + return NULL; + } + + /* + * Protect cval in case a crazy getter for .prototype uproots it. After + * this point, all control flow must exit through label out with obj set. + */ + JS_PUSH_SINGLE_TEMP_ROOT(cx, cval, &tvr); + MUST_FLOW_THROUGH("out"); + + /* + * If proto or parent are NULL, set them to Constructor.prototype and/or + * Constructor.__parent__, just like JSOP_NEW does. + */ + ctor = JSVAL_TO_OBJECT(cval); + if (!parent) + parent = OBJ_GET_PARENT(cx, ctor); + if (!proto) { + if (!OBJ_GET_PROPERTY(cx, ctor, + ATOM_TO_JSID(cx->runtime->atomState + .classPrototypeAtom), + &rval)) { + obj = NULL; + goto out; + } + if (JSVAL_IS_OBJECT(rval)) + proto = JSVAL_TO_OBJECT(rval); + } + + obj = js_NewObject(cx, clasp, proto, parent, 0); + if (!obj) + goto out; + + if (!js_InternalConstruct(cx, obj, cval, argc, argv, &rval)) + goto bad; + + if (JSVAL_IS_PRIMITIVE(rval)) + goto out; + obj = JSVAL_TO_OBJECT(rval); + + /* + * If the instance's class differs from what was requested, throw a type + * error. If the given class has both the JSCLASS_HAS_PRIVATE and the + * JSCLASS_CONSTRUCT_PROTOTYPE flags, and the instance does not have its + * private data set at this point, then the constructor was replaced and + * we should throw a type error. + */ + if (OBJ_GET_CLASS(cx, obj) != clasp || + (!(~clasp->flags & (JSCLASS_HAS_PRIVATE | + JSCLASS_CONSTRUCT_PROTOTYPE)) && + !JS_GetPrivate(cx, obj))) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_WRONG_CONSTRUCTOR, clasp->name); + goto bad; + } + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + JS_POP_TEMP_ROOT(cx, &argtvr); + return obj; + +bad: + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + obj = NULL; + goto out; +} + +void +js_FinalizeObject(JSContext *cx, JSObject *obj) +{ + JSObjectMap *map; + + /* Cope with stillborn objects that have no map. */ + map = obj->map; + if (!map) + return; + + if (cx->debugHooks->objectHook) { + cx->debugHooks->objectHook(cx, obj, JS_FALSE, + cx->debugHooks->objectHookData); + } + + /* Finalize obj first, in case it needs map and slots. */ + STOBJ_GET_CLASS(obj)->finalize(cx, obj); + +#ifdef INCLUDE_MOZILLA_DTRACE + if (JAVASCRIPT_OBJECT_FINALIZE_ENABLED()) + jsdtrace_object_finalize(obj); +#endif + + /* Drop map and free slots. */ + js_DropObjectMap(cx, map, obj); + FreeSlots(cx, obj); +} + +/* XXXbe if one adds props, deletes earlier props, adds more, the last added + won't recycle the deleted props' slots. */ +JSBool +js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp) +{ + JSObjectMap *map; + JSClass *clasp; + + map = obj->map; + JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj); + clasp = LOCKED_OBJ_GET_CLASS(obj); + if (map->freeslot == JSSLOT_FREE(clasp) && clasp->reserveSlots) { + /* Adjust map->freeslot to include computed reserved slots, if any. */ + map->freeslot += clasp->reserveSlots(cx, obj); + } + + if (map->freeslot >= STOBJ_NSLOTS(obj) && + !js_ReallocSlots(cx, obj, map->freeslot + 1, JS_FALSE)) { + return JS_FALSE; + } + + /* js_ReallocSlots or js_FreeSlot should set the free slots to void. */ + JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, map->freeslot))); + *slotp = map->freeslot++; + return JS_TRUE; +} + +void +js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot) +{ + JSObjectMap *map; + + map = obj->map; + JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj); + LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_VOID); + if (map->freeslot == slot + 1) { + map->freeslot = slot; + + /* When shrinking, js_ReallocSlots always returns true. */ + js_ReallocSlots(cx, obj, slot, JS_FALSE); + } +} + +jsid +js_CheckForStringIndex(jsid id, const jschar *cp, const jschar *end, + JSBool negative) +{ + jsuint index = JS7_UNDEC(*cp++); + jsuint oldIndex = 0; + jsuint c = 0; + + if (index != 0) { + while (JS7_ISDEC(*cp)) { + oldIndex = index; + c = JS7_UNDEC(*cp); + index = 10 * index + c; + cp++; + } + } + if (cp == end && + (oldIndex < (JSVAL_INT_MAX / 10) || + (oldIndex == (JSVAL_INT_MAX / 10) && + c <= (JSVAL_INT_MAX % 10)))) { + if (negative) + index = 0 - index; + id = INT_TO_JSID((jsint)index); + } + return id; +} + +static JSBool +PurgeProtoChain(JSContext *cx, JSObject *obj, jsid id) +{ + JSScope *scope; + JSScopeProperty *sprop; + + while (obj) { + if (!OBJ_IS_NATIVE(obj)) { + obj = OBJ_GET_PROTO(cx, obj); + continue; + } + JS_LOCK_OBJ(cx, obj); + scope = OBJ_SCOPE(obj); + sprop = SCOPE_GET_PROPERTY(scope, id); + if (sprop) { + PCMETER(JS_PROPERTY_CACHE(cx).pcpurges++); + SCOPE_MAKE_UNIQUE_SHAPE(cx, scope); + JS_UNLOCK_SCOPE(cx, scope); + return JS_TRUE; + } + obj = LOCKED_OBJ_GET_PROTO(scope->object); + JS_UNLOCK_SCOPE(cx, scope); + } + return JS_FALSE; +} + +static void +PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id) +{ + if (!OBJ_IS_DELEGATE(cx, obj)) + return; + + PurgeProtoChain(cx, OBJ_GET_PROTO(cx, obj), id); + while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL) { + if (PurgeProtoChain(cx, obj, id)) + return; + } +} + +JSScopeProperty * +js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, + JSPropertyOp getter, JSPropertyOp setter, uint32 slot, + uintN attrs, uintN flags, intN shortid) +{ + JSScope *scope; + JSScopeProperty *sprop; + + /* + * Purge the property cache of now-shadowed id in obj's scope chain. Do + * this optimistically (assuming no failure below) before locking obj, so + * we can lock the shadowed scope. + */ + PurgeScopeChain(cx, obj, id); + + JS_LOCK_OBJ(cx, obj); + scope = js_GetMutableScope(cx, obj); + if (!scope) { + sprop = NULL; + } else { + /* Convert string indices to integers if appropriate. */ + CHECK_FOR_STRING_INDEX(id); + sprop = js_AddScopeProperty(cx, scope, id, getter, setter, slot, attrs, + flags, shortid); + } + JS_UNLOCK_OBJ(cx, obj); + return sprop; +} + +JSScopeProperty * +js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj, + JSScopeProperty *sprop, uintN attrs, uintN mask, + JSPropertyOp getter, JSPropertyOp setter) +{ + JSScope *scope; + + JS_LOCK_OBJ(cx, obj); + scope = js_GetMutableScope(cx, obj); + if (!scope) { + sprop = NULL; + } else { + sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop, attrs, mask, + getter, setter); + } + JS_UNLOCK_OBJ(cx, obj); + return sprop; +} + +JSBool +js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + JSProperty **propp) +{ + return js_DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, + 0, 0, propp); +} + +/* + * Backward compatibility requires allowing addProperty hooks to mutate the + * nominal initial value of a slot-full property, while GC safety wants that + * value to be stored before the call-out through the hook. Optimize to do + * both while saving cycles for classes that stub their addProperty hook. + */ +#define ADD_PROPERTY_HELPER(cx,clasp,obj,scope,sprop,vp,cleanup) \ + JS_BEGIN_MACRO \ + if ((clasp)->addProperty != JS_PropertyStub) { \ + jsval nominal_ = *(vp); \ + if (!(clasp)->addProperty(cx, obj, SPROP_USERID(sprop), vp)) { \ + cleanup; \ + } \ + if (*(vp) != nominal_) { \ + if (SPROP_HAS_VALID_SLOT(sprop, scope)) \ + LOCKED_OBJ_WRITE_BARRIER(cx, obj, (sprop)->slot, *(vp)); \ + } \ + } \ + JS_END_MACRO + +JSBool +js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + uintN flags, intN shortid, JSProperty **propp) +{ + JSClass *clasp; + JSScope *scope; + JSScopeProperty *sprop; + + /* Convert string indices to integers if appropriate. */ + CHECK_FOR_STRING_INDEX(id); + +#if JS_HAS_GETTER_SETTER + /* + * If defining a getter or setter, we must check for its counterpart and + * update the attributes and property ops. A getter or setter is really + * only half of a property. + */ + sprop = NULL; + if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { + JSObject *pobj; + JSProperty *prop; + + /* + * If JS_THREADSAFE and id is found, js_LookupProperty returns with + * sprop non-null and pobj locked. If pobj == obj, the property is + * already in obj and obj has its own (mutable) scope. So if we are + * defining a getter whose setter was already defined, or vice versa, + * finish the job via js_ChangeScopePropertyAttributes, and refresh + * the property cache line for (obj, id) to map sprop. + */ + if (!js_LookupProperty(cx, obj, id, &pobj, &prop)) + return JS_FALSE; + sprop = (JSScopeProperty *) prop; + if (sprop && + pobj == obj && + (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER))) { + sprop = js_ChangeScopePropertyAttrs(cx, OBJ_SCOPE(obj), sprop, + attrs, sprop->attrs, + (attrs & JSPROP_GETTER) + ? getter + : sprop->getter, + (attrs & JSPROP_SETTER) + ? setter + : sprop->setter); + + /* NB: obj == pobj, so we can share unlock code at the bottom. */ + if (!sprop) + goto bad; + } else if (prop) { + /* NB: call OBJ_DROP_PROPERTY, as pobj might not be native. */ + OBJ_DROP_PROPERTY(cx, pobj, prop); + prop = NULL; + sprop = NULL; + } + } +#endif /* JS_HAS_GETTER_SETTER */ + + /* + * Purge the property cache of now-shadowed id in obj's scope chain. + * Do this early, before locking obj to avoid nesting locks. + */ + PurgeScopeChain(cx, obj, id); + + /* Lock if object locking is required by this implementation. */ + JS_LOCK_OBJ(cx, obj); + + /* Use the object's class getter and setter by default. */ + clasp = LOCKED_OBJ_GET_CLASS(obj); + if (!getter) + getter = clasp->getProperty; + if (!setter) + setter = clasp->setProperty; + + /* Get obj's own scope if it has one, or create a new one for obj. */ + scope = js_GetMutableScope(cx, obj); + if (!scope) + goto bad; + + if (!sprop) { + /* Add a new property, or replace an existing one of the same id. */ + if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES) + attrs |= JSPROP_SHARED; + sprop = js_AddScopeProperty(cx, scope, id, getter, setter, + SPROP_INVALID_SLOT, attrs, flags, + shortid); + if (!sprop) + goto bad; + } + + /* Store value before calling addProperty, in case the latter GC's. */ + if (SPROP_HAS_VALID_SLOT(sprop, scope)) + LOCKED_OBJ_WRITE_BARRIER(cx, obj, sprop->slot, value); + + /* XXXbe called with lock held */ + ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, &value, + js_RemoveScopeProperty(cx, scope, id); + goto bad); + + if (propp) + *propp = (JSProperty *) sprop; + else + JS_UNLOCK_OBJ(cx, obj); + return JS_TRUE; + +bad: + JS_UNLOCK_OBJ(cx, obj); + return JS_FALSE; +} + +/* + * Given pc pointing after a property accessing bytecode, return true if the + * access is "object-detecting" in the sense used by web scripts, e.g., when + * checking whether document.all is defined. + */ +static JSBool +Detecting(JSContext *cx, jsbytecode *pc) +{ + JSScript *script; + jsbytecode *endpc; + JSOp op; + JSAtom *atom; + + if (!cx->fp) + return JS_FALSE; + script = cx->fp->script; + for (endpc = script->code + script->length; + pc < endpc; + pc += js_CodeSpec[op].length) { + /* General case: a branch or equality op follows the access. */ + op = (JSOp) *pc; + if (js_CodeSpec[op].format & JOF_DETECTING) + return JS_TRUE; + + switch (op) { + case JSOP_NULL: + /* + * Special case #1: handle (document.all == null). Don't sweat + * about JS1.2's revision of the equality operators here. + */ + if (++pc < endpc) + return *pc == JSOP_EQ || *pc == JSOP_NE; + return JS_FALSE; + + case JSOP_NAME: + /* + * Special case #2: handle (document.all == undefined). Don't + * worry about someone redefining undefined, which was added by + * Edition 3, so is read/write for backward compatibility. + */ + GET_ATOM_FROM_BYTECODE(script, pc, 0, atom); + if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] && + (pc += js_CodeSpec[op].length) < endpc) { + op = (JSOp) *pc; + return op == JSOP_EQ || op == JSOP_NE || + op == JSOP_STRICTEQ || op == JSOP_STRICTNE; + } + return JS_FALSE; + + default: + /* + * At this point, anything but an extended atom index prefix means + * we're not detecting. + */ + if (!(js_CodeSpec[op].format & JOF_INDEXBASE)) + return JS_FALSE; + break; + } + } + return JS_FALSE; +} + +JS_FRIEND_API(JSBool) +js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp) +{ + return js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, + objp, propp) >= 0; +} + +#define SCOPE_DEPTH_ACCUM(bs,val) \ + JS_SCOPE_DEPTH_METERING(JS_BASIC_STATS_ACCUM(bs, val)) + +int +js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp, JSProperty **propp) +{ + JSObject *start, *obj2, *proto; + int protoIndex; + JSScope *scope; + JSScopeProperty *sprop; + JSClass *clasp; + JSResolveOp resolve; + JSResolvingKey key; + JSResolvingEntry *entry; + uint32 generation; + JSNewResolveOp newresolve; + jsbytecode *pc; + const JSCodeSpec *cs; + uint32 format; + JSBool ok; + + /* Convert string indices to integers if appropriate. */ + CHECK_FOR_STRING_INDEX(id); + JS_COUNT_OPERATION(cx, JSOW_LOOKUP_PROPERTY); + + /* Search scopes starting with obj and following the prototype link. */ + start = obj; + for (protoIndex = 0; ; protoIndex++) { + JS_LOCK_OBJ(cx, obj); + scope = OBJ_SCOPE(obj); + if (scope->object == obj) { + sprop = SCOPE_GET_PROPERTY(scope, id); + } else { + /* Shared prototype scope: try resolve before lookup. */ + sprop = NULL; + } + + /* Try obj's class resolve hook if id was not found in obj's scope. */ + if (!sprop) { + clasp = LOCKED_OBJ_GET_CLASS(obj); + resolve = clasp->resolve; + if (resolve != JS_ResolveStub) { + /* Avoid recursion on (obj, id) already being resolved on cx. */ + key.obj = obj; + key.id = id; + + /* + * Once we have successfully added an entry for (obj, key) to + * cx->resolvingTable, control must go through cleanup: before + * returning. But note that JS_DHASH_ADD may find an existing + * entry, in which case we bail to suppress runaway recursion. + */ + if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) { + JS_UNLOCK_OBJ(cx, obj); + return -1; + } + if (!entry) { + /* Already resolving id in obj -- suppress recursion. */ + JS_UNLOCK_OBJ(cx, obj); + goto out; + } + generation = cx->resolvingTable->generation; + + /* Null *propp here so we can test it at cleanup: safely. */ + *propp = NULL; + + if (clasp->flags & JSCLASS_NEW_RESOLVE) { + newresolve = (JSNewResolveOp)resolve; + if (flags == JSRESOLVE_INFER && cx->fp && cx->fp->regs) { + flags = 0; + pc = cx->fp->regs->pc; + cs = &js_CodeSpec[*pc]; + format = cs->format; + if (JOF_MODE(format) != JOF_NAME) + flags |= JSRESOLVE_QUALIFIED; + if ((format & (JOF_SET | JOF_FOR)) || + (cx->fp->flags & JSFRAME_ASSIGNING)) { + flags |= JSRESOLVE_ASSIGNING; + } else { + pc += cs->length; + if (Detecting(cx, pc)) + flags |= JSRESOLVE_DETECTING; + } + if (format & JOF_DECLARING) + flags |= JSRESOLVE_DECLARING; + } + obj2 = (clasp->flags & JSCLASS_NEW_RESOLVE_GETS_START) + ? start + : NULL; + JS_UNLOCK_OBJ(cx, obj); + + /* Protect id and all atoms from a GC nested in resolve. */ + JS_KEEP_ATOMS(cx->runtime); + ok = newresolve(cx, obj, ID_TO_VALUE(id), flags, &obj2); + JS_UNKEEP_ATOMS(cx->runtime); + if (!ok) + goto cleanup; + + JS_LOCK_OBJ(cx, obj); + if (obj2) { + /* Resolved: juggle locks and lookup id again. */ + if (obj2 != obj) { + JS_UNLOCK_OBJ(cx, obj); + if (OBJ_IS_NATIVE(obj2)) + JS_LOCK_OBJ(cx, obj2); + } + protoIndex = 0; + for (proto = start; proto && proto != obj2; + proto = OBJ_GET_PROTO(cx, proto)) { + protoIndex++; + } + scope = OBJ_SCOPE(obj2); + if (!MAP_IS_NATIVE(&scope->map)) { + /* Whoops, newresolve handed back a foreign obj2. */ + JS_ASSERT(obj2 != obj); + ok = OBJ_LOOKUP_PROPERTY(cx, obj2, id, objp, propp); + if (!ok || *propp) + goto cleanup; + JS_LOCK_OBJ(cx, obj2); + } else { + /* + * Require that obj2 have its own scope now, as we + * do for old-style resolve. If it doesn't, then + * id was not truly resolved, and we'll find it in + * the proto chain, or miss it if obj2's proto is + * not on obj's proto chain. That last case is a + * "too bad!" case. + */ + if (scope->object == obj2) + sprop = SCOPE_GET_PROPERTY(scope, id); + } + if (sprop) { + JS_ASSERT(obj2 == scope->object); + obj = obj2; + } else if (obj2 != obj) { + if (OBJ_IS_NATIVE(obj2)) + JS_UNLOCK_OBJ(cx, obj2); + JS_LOCK_OBJ(cx, obj); + } + } + } else { + /* + * Old resolve always requires id re-lookup if obj owns + * its scope after resolve returns. + */ + JS_UNLOCK_OBJ(cx, obj); + ok = resolve(cx, obj, ID_TO_VALUE(id)); + if (!ok) + goto cleanup; + JS_LOCK_OBJ(cx, obj); + scope = OBJ_SCOPE(obj); + JS_ASSERT(MAP_IS_NATIVE(&scope->map)); + if (scope->object == obj) + sprop = SCOPE_GET_PROPERTY(scope, id); + } + + cleanup: + js_StopResolving(cx, &key, JSRESFLAG_LOOKUP, entry, generation); + if (!ok) + return -1; + if (*propp) + return protoIndex; + } + } + + if (sprop) { + SCOPE_DEPTH_ACCUM(&cx->runtime->protoLookupDepthStats, protoIndex); + JS_ASSERT(OBJ_SCOPE(obj) == scope); + *objp = scope->object; /* XXXbe hide in jsscope.[ch] */ + + *propp = (JSProperty *) sprop; + return protoIndex; + } + + proto = LOCKED_OBJ_GET_PROTO(obj); + JS_UNLOCK_OBJ(cx, obj); + if (!proto) + break; + if (!OBJ_IS_NATIVE(proto)) { + if (!OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp)) + return -1; + return protoIndex + 1; + } + obj = proto; + } + +out: + *objp = NULL; + *propp = NULL; + return protoIndex; +} + +int +js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp, + JSObject **pobjp, JSProperty **propp, + JSPropCacheEntry **entryp) +{ + JSObject *obj, *pobj, *lastobj; + uint32 shape; + int scopeIndex, protoIndex; + JSProperty *prop; + JSScopeProperty *sprop; + + obj = cx->fp->scopeChain; + shape = OBJ_SHAPE(obj); + for (scopeIndex = 0; ; scopeIndex++) { + if (obj->map->ops->lookupProperty == js_LookupProperty) { + protoIndex = + js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, + &pobj, &prop); + } else { + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) + return -1; + protoIndex = -1; + } + + if (prop) { + if (entryp) { + if (protoIndex >= 0 && OBJ_IS_NATIVE(pobj)) { + sprop = (JSScopeProperty *) prop; + js_FillPropertyCache(cx, cx->fp->scopeChain, shape, + scopeIndex, protoIndex, pobj, sprop, + entryp); + } else { + PCMETER(JS_PROPERTY_CACHE(cx).nofills++); + *entryp = NULL; + } + } + SCOPE_DEPTH_ACCUM(&rt->scopeSearchDepthStats, scopeIndex); + *objp = obj; + *pobjp = pobj; + *propp = prop; + return scopeIndex; + } + + lastobj = obj; + obj = OBJ_GET_PARENT(cx, obj); + if (!obj) + break; + } + + *objp = lastobj; + *pobjp = NULL; + *propp = NULL; + return scopeIndex; +} + +JS_FRIEND_API(JSBool) +js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp, + JSProperty **propp) +{ + return js_FindPropertyHelper(cx, id, objp, pobjp, propp, NULL) >= 0; +} + +JSObject * +js_FindIdentifierBase(JSContext *cx, jsid id, JSPropCacheEntry *entry) +{ + JSObject *obj, *pobj; + JSProperty *prop; + + /* + * Look for id's property along the "with" statement chain and the + * statically-linked scope chain. + */ + if (js_FindPropertyHelper(cx, id, &obj, &pobj, &prop, &entry) < 0) + return NULL; + if (prop) { + OBJ_DROP_PROPERTY(cx, pobj, prop); + return obj; + } + + /* + * Use the top-level scope from the scope chain, which won't end in the + * same scope as cx->globalObject for cross-context function calls. + */ + JS_ASSERT(obj); + + /* + * Property not found. Give a strict warning if binding an undeclared + * top-level variable. + */ + if (JS_HAS_STRICT_OPTION(cx)) { + JSString *str = JSVAL_TO_STRING(ID_TO_VALUE(id)); + const char *bytes = js_GetStringBytes(cx, str); + + if (!bytes || + !JS_ReportErrorFlagsAndNumber(cx, + JSREPORT_WARNING | JSREPORT_STRICT, + js_GetErrorMessage, NULL, + JSMSG_UNDECLARED_VAR, bytes)) { + return NULL; + } + } + + return obj; +} + +JSBool +js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, + JSScopeProperty *sprop, jsval *vp) +{ + JSScope *scope; + uint32 slot; + int32 sample; + JSTempValueRooter tvr; + JSBool ok; + + JS_ASSERT(OBJ_IS_NATIVE(pobj)); + JS_ASSERT(JS_IS_OBJ_LOCKED(cx, pobj)); + scope = OBJ_SCOPE(pobj); + JS_ASSERT(scope->object == pobj); + + slot = sprop->slot; + *vp = (slot != SPROP_INVALID_SLOT) + ? LOCKED_OBJ_GET_SLOT(pobj, slot) + : JSVAL_VOID; + if (SPROP_HAS_STUB_GETTER(sprop)) + return JS_TRUE; + + sample = cx->runtime->propertyRemovals; + JS_UNLOCK_SCOPE(cx, scope); + JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr); + ok = SPROP_GET(cx, sprop, obj, pobj, vp); + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return JS_FALSE; + + JS_LOCK_SCOPE(cx, scope); + JS_ASSERT(scope->object == pobj); + if (SLOT_IN_SCOPE(slot, scope) && + (JS_LIKELY(cx->runtime->propertyRemovals == sample) || + SCOPE_GET_PROPERTY(scope, sprop->id) == sprop)) { + LOCKED_OBJ_SET_SLOT(pobj, slot, *vp); + } + + return JS_TRUE; +} + +JSBool +js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp) +{ + JSScope *scope; + uint32 slot; + int32 sample; + JSTempValueRooter tvr; + bool ok; + + JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj)); + scope = OBJ_SCOPE(obj); + JS_ASSERT(scope->object == obj); + + slot = sprop->slot; + if (slot != SPROP_INVALID_SLOT) { + OBJ_CHECK_SLOT(obj, slot); + + /* If sprop has a stub setter, keep scope locked and just store *vp. */ + if (SPROP_HAS_STUB_SETTER(sprop)) + goto set_slot; + } else { + /* + * Allow API consumers to create shared properties with stub setters. + * Such properties lack value storage, so setting them is like writing + * to /dev/null. + */ + if (SPROP_HAS_STUB_SETTER(sprop)) + return JS_TRUE; + } + + sample = cx->runtime->propertyRemovals; + JS_UNLOCK_SCOPE(cx, scope); + JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr); + ok = SPROP_SET(cx, sprop, obj, obj, vp); + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return JS_FALSE; + + JS_LOCK_SCOPE(cx, scope); + JS_ASSERT(scope->object == obj); + if (SLOT_IN_SCOPE(slot, scope) && + (JS_LIKELY(cx->runtime->propertyRemovals == sample) || + SCOPE_GET_PROPERTY(scope, sprop->id) == sprop)) { + set_slot: + LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, *vp); + } + + return JS_TRUE; +} + +JSBool +js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, + JSPropCacheEntry **entryp) +{ + uint32 shape; + int protoIndex; + JSObject *obj2; + JSProperty *prop; + JSScopeProperty *sprop; + + /* Convert string indices to integers if appropriate. */ + CHECK_FOR_STRING_INDEX(id); + JS_COUNT_OPERATION(cx, JSOW_GET_PROPERTY); + + shape = OBJ_SHAPE(obj); + protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, + &obj2, &prop); + if (protoIndex < 0) + return JS_FALSE; + if (!prop) { + jsbytecode *pc; + + *vp = JSVAL_VOID; + + if (!OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, ID_TO_VALUE(id), vp)) + return JS_FALSE; + + if (entryp) { + PCMETER(JS_PROPERTY_CACHE(cx).nofills++); + *entryp = NULL; + } + + /* + * Give a strict warning if foo.bar is evaluated by a script for an + * object foo with no property named 'bar'. + */ + if (JSVAL_IS_VOID(*vp) && cx->fp && cx->fp->regs) { + JSOp op; + uintN flags; + + pc = cx->fp->regs->pc; + op = (JSOp) *pc; + if (op == JSOP_GETXPROP) { + flags = JSREPORT_ERROR; + } else { + if (!JS_HAS_STRICT_OPTION(cx) || + (op != JSOP_GETPROP && op != JSOP_GETELEM)) { + return JS_TRUE; + } + + /* + * XXX do not warn about missing __iterator__ as the function + * may be called from JS_GetMethodById. See bug 355145. + */ + if (id == ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom)) + return JS_TRUE; + + /* Kludge to allow (typeof foo == "undefined") tests. */ + JS_ASSERT(cx->fp->script); + pc += js_CodeSpec[op].length; + if (Detecting(cx, pc)) + return JS_TRUE; + + flags = JSREPORT_WARNING | JSREPORT_STRICT; + } + + /* Ok, bad undefined property reference: whine about it. */ + if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP, + JSDVG_IGNORE_STACK, ID_TO_VALUE(id), + NULL, NULL, NULL)) { + return JS_FALSE; + } + } + return JS_TRUE; + } + + if (!OBJ_IS_NATIVE(obj2)) { + OBJ_DROP_PROPERTY(cx, obj2, prop); + return OBJ_GET_PROPERTY(cx, obj2, id, vp); + } + + sprop = (JSScopeProperty *) prop; + if (!js_NativeGet(cx, obj, obj2, sprop, vp)) + return JS_FALSE; + + if (entryp) + js_FillPropertyCache(cx, obj, shape, 0, protoIndex, obj2, sprop, entryp); + JS_UNLOCK_OBJ(cx, obj2); + return JS_TRUE; +} + +JSBool +js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return js_GetPropertyHelper(cx, obj, id, vp, NULL); +} + +JSBool +js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, + JSPropCacheEntry **entryp) +{ + uint32 shape; + int protoIndex; + JSObject *pobj; + JSProperty *prop; + JSScopeProperty *sprop; + JSScope *scope; + uintN attrs, flags; + intN shortid; + JSClass *clasp; + JSPropertyOp getter, setter; + + /* Convert string indices to integers if appropriate. */ + CHECK_FOR_STRING_INDEX(id); + JS_COUNT_OPERATION(cx, JSOW_SET_PROPERTY); + + shape = OBJ_SHAPE(obj); + protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, + &pobj, &prop); + if (protoIndex < 0) + return JS_FALSE; + + if (prop && !OBJ_IS_NATIVE(pobj)) { + OBJ_DROP_PROPERTY(cx, pobj, prop); + prop = NULL; + } + sprop = (JSScopeProperty *) prop; + + /* + * Now either sprop is null, meaning id was not found in obj or one of its + * prototypes; or sprop is non-null, meaning id was found in pobj's scope. + * If JS_THREADSAFE and sprop is non-null, then scope is locked, and sprop + * is held: we must OBJ_DROP_PROPERTY or JS_UNLOCK_SCOPE before we return + * (the two are equivalent for native objects, but we use JS_UNLOCK_SCOPE + * because it is cheaper). + */ + attrs = JSPROP_ENUMERATE; + flags = 0; + shortid = 0; + clasp = OBJ_GET_CLASS(cx, obj); + getter = clasp->getProperty; + setter = clasp->setProperty; + + if (sprop) { + /* + * Set scope for use below. It was locked by js_LookupProperty, and + * we know pobj owns it (i.e., scope->object == pobj). Therefore we + * optimize JS_UNLOCK_OBJ(cx, pobj) into JS_UNLOCK_SCOPE(cx, scope). + */ + scope = OBJ_SCOPE(pobj); + + attrs = sprop->attrs; + if ((attrs & JSPROP_READONLY) || + (SCOPE_IS_SEALED(scope) && pobj == obj)) { + JS_UNLOCK_SCOPE(cx, scope); + + /* + * Here, we'll either return true or goto read_only_error, which + * reports a strict warning or throws an error. So we redefine + * the |flags| local variable to be JSREPORT_* flags to pass to + * JS_ReportErrorFlagsAndNumberUC at label read_only_error. We + * must likewise re-task flags further below for the other 'goto + * read_only_error;' case. + */ + flags = JSREPORT_ERROR; + if (attrs & JSPROP_READONLY) { + if (!JS_HAS_STRICT_OPTION(cx)) { + /* Just return true per ECMA if not in strict mode. */ + PCMETER(!entryp || JS_PROPERTY_CACHE(cx).rofills++); + return JS_TRUE; + } + + /* Strict mode: report a read-only strict warning. */ + flags = JSREPORT_STRICT | JSREPORT_WARNING; + } + goto read_only_error; + } + + if (pobj != obj) { + /* + * We found id in a prototype object: prepare to share or shadow. + * + * NB: Thanks to the immutable, garbage-collected property tree + * maintained by jsscope.c in cx->runtime, we needn't worry about + * sprop going away behind our back after we've unlocked scope. + */ + JS_UNLOCK_SCOPE(cx, scope); + + /* + * Don't clone a shared prototype property. Don't fill it in the + * property cache either, since the JSOP_SETPROP/JSOP_SETNAME code + * in js_Interpret does not handle shared or prototype properties. + * Shared prototype properties require more hit qualification than + * the fast-path code for those ops, which is targeted on direct, + * slot-based properties. + */ + if (attrs & JSPROP_SHARED) { + if (entryp) { + PCMETER(JS_PROPERTY_CACHE(cx).nofills++); + *entryp = NULL; + } + + if (SPROP_HAS_STUB_SETTER(sprop) && + !(sprop->attrs & JSPROP_GETTER)) { + return JS_TRUE; + } + + return !!SPROP_SET(cx, sprop, obj, pobj, vp); + } + + /* Restore attrs to the ECMA default for new properties. */ + attrs = JSPROP_ENUMERATE; + + /* + * Preserve the shortid, getter, and setter when shadowing any + * property that has a shortid. An old API convention requires + * that the property's getter and setter functions receive the + * shortid, not id, when they are called on the shadow we are + * about to create in obj's scope. + */ + if (sprop->flags & SPROP_HAS_SHORTID) { + flags = SPROP_HAS_SHORTID; + shortid = sprop->shortid; + getter = sprop->getter; + setter = sprop->setter; + } + + /* + * Forget we found the proto-property now that we've copied any + * needed member values. + */ + sprop = NULL; + } +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + } else { + scope = NULL; +#endif + } + + if (!sprop) { + if (SCOPE_IS_SEALED(OBJ_SCOPE(obj)) && OBJ_SCOPE(obj)->object == obj) { + flags = JSREPORT_ERROR; + goto read_only_error; + } + + /* + * Purge the property cache of now-shadowed id in obj's scope chain. + * Do this early, before locking obj to avoid nesting locks. + */ + PurgeScopeChain(cx, obj, id); + + /* Find or make a property descriptor with the right heritage. */ + JS_LOCK_OBJ(cx, obj); + scope = js_GetMutableScope(cx, obj); + if (!scope) { + JS_UNLOCK_OBJ(cx, obj); + return JS_FALSE; + } + if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES) + attrs |= JSPROP_SHARED; + sprop = js_AddScopeProperty(cx, scope, id, getter, setter, + SPROP_INVALID_SLOT, attrs, flags, shortid); + if (!sprop) { + JS_UNLOCK_SCOPE(cx, scope); + return JS_FALSE; + } + + /* + * Initialize the new property value (passed to setter) to undefined. + * Note that we store before calling addProperty, to match the order + * in js_DefineNativeProperty. + */ + if (SPROP_HAS_VALID_SLOT(sprop, scope)) + LOCKED_OBJ_SET_SLOT(obj, sprop->slot, JSVAL_VOID); + + /* XXXbe called with obj locked */ + ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, vp, + js_RemoveScopeProperty(cx, scope, id); + JS_UNLOCK_SCOPE(cx, scope); + return JS_FALSE); + } + + if (!js_NativeSet(cx, obj, sprop, vp)) + return JS_FALSE; + + if (entryp) { + if (!(attrs & JSPROP_SHARED)) + js_FillPropertyCache(cx, obj, shape, 0, 0, obj, sprop, entryp); + else + PCMETER(JS_PROPERTY_CACHE(cx).nofills++); + } + JS_UNLOCK_SCOPE(cx, scope); + return JS_TRUE; + + read_only_error: + return js_ReportValueErrorFlags(cx, flags, JSMSG_READ_ONLY, + JSDVG_IGNORE_STACK, ID_TO_VALUE(id), NULL, + NULL, NULL); +} + +JSBool +js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return js_SetPropertyHelper(cx, obj, id, vp, NULL); +} + +JSBool +js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp) +{ + JSBool noprop, ok; + JSScopeProperty *sprop; + + noprop = !prop; + if (noprop) { + if (!js_LookupProperty(cx, obj, id, &obj, &prop)) + return JS_FALSE; + if (!prop) { + *attrsp = 0; + return JS_TRUE; + } + if (!OBJ_IS_NATIVE(obj)) { + ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, attrsp); + OBJ_DROP_PROPERTY(cx, obj, prop); + return ok; + } + } + sprop = (JSScopeProperty *)prop; + *attrsp = sprop->attrs; + if (noprop) + OBJ_DROP_PROPERTY(cx, obj, prop); + return JS_TRUE; +} + +JSBool +js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp) +{ + JSBool noprop, ok; + JSScopeProperty *sprop; + + noprop = !prop; + if (noprop) { + if (!js_LookupProperty(cx, obj, id, &obj, &prop)) + return JS_FALSE; + if (!prop) + return JS_TRUE; + if (!OBJ_IS_NATIVE(obj)) { + ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, attrsp); + OBJ_DROP_PROPERTY(cx, obj, prop); + return ok; + } + } + sprop = (JSScopeProperty *)prop; + sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, *attrsp, 0, + sprop->getter, sprop->setter); + if (noprop) + OBJ_DROP_PROPERTY(cx, obj, prop); + return (sprop != NULL); +} + +JSBool +js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) +{ + JSObject *proto; + JSProperty *prop; + JSScopeProperty *sprop; + JSScope *scope; + JSBool ok; + + *rval = JSVAL_TRUE; + + /* Convert string indices to integers if appropriate. */ + CHECK_FOR_STRING_INDEX(id); + JS_COUNT_OPERATION(cx, JSOW_DELETE_PROPERTY); + + if (!js_LookupProperty(cx, obj, id, &proto, &prop)) + return JS_FALSE; + if (!prop || proto != obj) { + /* + * If the property was found in a native prototype, check whether it's + * shared and permanent. Such a property stands for direct properties + * in all delegating objects, matching ECMA semantics without bloating + * each delegating object. + */ + if (prop) { + if (OBJ_IS_NATIVE(proto)) { + sprop = (JSScopeProperty *)prop; + if (SPROP_IS_SHARED_PERMANENT(sprop)) + *rval = JSVAL_FALSE; + } + OBJ_DROP_PROPERTY(cx, proto, prop); + if (*rval == JSVAL_FALSE) + return JS_TRUE; + } + + /* + * If no property, or the property comes unshared or impermanent from + * a prototype, call the class's delProperty hook, passing rval as the + * result parameter. + */ + return OBJ_GET_CLASS(cx, obj)->delProperty(cx, obj, ID_TO_VALUE(id), + rval); + } + + sprop = (JSScopeProperty *)prop; + if (sprop->attrs & JSPROP_PERMANENT) { + OBJ_DROP_PROPERTY(cx, obj, prop); + *rval = JSVAL_FALSE; + return JS_TRUE; + } + + /* XXXbe called with obj locked */ + if (!LOCKED_OBJ_GET_CLASS(obj)->delProperty(cx, obj, SPROP_USERID(sprop), + rval)) { + OBJ_DROP_PROPERTY(cx, obj, prop); + return JS_FALSE; + } + + scope = OBJ_SCOPE(obj); + if (SPROP_HAS_VALID_SLOT(sprop, scope)) + GC_POKE(cx, LOCKED_OBJ_GET_SLOT(obj, sprop->slot)); + + ok = js_RemoveScopeProperty(cx, scope, id); + OBJ_DROP_PROPERTY(cx, obj, prop); + return ok; +} + +JSBool +js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp) +{ + jsval v, save; + JSString *str; + + v = save = OBJECT_TO_JSVAL(obj); + switch (hint) { + case JSTYPE_STRING: + /* + * Propagate the exception if js_TryMethod finds an appropriate + * method, and calling that method returned failure. + */ + if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, + &v)) { + return JS_FALSE; + } + + if (!JSVAL_IS_PRIMITIVE(v)) { + if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, hint, &v)) + return JS_FALSE; + } + break; + + default: + if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, hint, &v)) + return JS_FALSE; + if (!JSVAL_IS_PRIMITIVE(v)) { + JSType type = JS_TypeOfValue(cx, v); + if (type == hint || + (type == JSTYPE_FUNCTION && hint == JSTYPE_OBJECT)) { + goto out; + } + if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, + NULL, &v)) { + return JS_FALSE; + } + } + break; + } + if (!JSVAL_IS_PRIMITIVE(v)) { + /* Avoid recursive death when decompiling in js_ReportValueError. */ + if (hint == JSTYPE_STRING) { + str = JS_InternString(cx, OBJ_GET_CLASS(cx, obj)->name); + if (!str) + return JS_FALSE; + } else { + str = NULL; + } + *vp = OBJECT_TO_JSVAL(obj); + js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, + JSDVG_SEARCH_STACK, save, str, + (hint == JSTYPE_VOID) + ? "primitive type" + : JS_TYPE_STR(hint)); + return JS_FALSE; + } +out: + *vp = v; + return JS_TRUE; +} + +/* + * Private type used to enumerate properties of a native JS object. It is + * allocated as necessary from JSENUMERATE_INIT and is freed when running the + * GC. The structure is not allocated when there are no enumerable properties + * in the object. Instead for the empty enumerator the code uses JSVAL_ZERO as + * the enumeration state. + * + * JSRuntime.nativeEnumCache caches the enumerators using scope's shape to + * avoid repeated scanning of scopes for enumerable properties. The cache + * entry is either JSNativeEnumerator* or, for the empty enumerator, the shape + * value itself. The latter is stored as (shape << 1) | 1 to ensure that it is + * always different from JSNativeEnumerator* values. + */ +struct JSNativeEnumerator { + /* + * The index into the ids array. It runs from the length down to 1 when + * the enumerator is running. It is 0 when the enumerator is finished and + * can be reused on a cache hit. Its type is jsword, not uint32, for + * compatibility with js_CompareAndSwap. + */ + jsword cursor; + + uint32 length; /* length of ids array */ + uint32 shape; /* "shape" number -- see jsscope.h */ + JSNativeEnumerator *next; /* list linking */ + jsid ids[1]; /* enumeration id array */ +}; + +/* The tagging of shape values requires one bit. */ +JS_STATIC_ASSERT((jsuword) SHAPE_OVERFLOW_BIT <= + ((jsuword) 1 << (JS_BITS_PER_WORD - 1))); + +static inline size_t +NativeEnumeratorSize(uint32 length) +{ + JS_ASSERT(length != 0); + return offsetof(JSNativeEnumerator, ids) + (size_t) length * sizeof(jsid); +} + +/* + * This function is used to enumerate the properties of native JSObjects + * and those host objects that do not define a JSNewEnumerateOp-style iterator + * function. + */ +JSBool +js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp) +{ + JSClass *clasp; + JSEnumerateOp enumerate; + JSNativeEnumerator *ne; + uint32 length, shape; + size_t allocated; + JSScope *scope; + jsuword *cachep, oldcache; + JSScopeProperty *sprop; + jsid *ids; + jsword newcursor; + + clasp = OBJ_GET_CLASS(cx, obj); + enumerate = clasp->enumerate; + if (clasp->flags & JSCLASS_NEW_ENUMERATE) { + JS_ASSERT(enumerate != JS_EnumerateStub); + return ((JSNewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp); + } + + switch (enum_op) { + case JSENUMERATE_INIT: + if (!enumerate(cx, obj)) + return JS_FALSE; + + /* + * The set of all property ids is pre-computed when the iterator is + * initialized to avoid problems caused by properties being deleted + * during the iteration. + * + * Use a do-while(0) loop to avoid too many nested ifs. If ne is null + * after the loop, it indicates an empty enumerator. If allocated is + * not zero after the loop, we add the newly allocated ne to the cache + * and runtime->nativeEnumerators list. + */ + ne = NULL; + length = 0; + allocated = (size_t) 0; + JS_LOCK_OBJ(cx, obj); + scope = OBJ_SCOPE(obj); + do { + /* + * If this object shares a scope with its prototype, don't + * enumerate its properties. Otherwise they will be enumerated + * a second time when the prototype object is enumerated. + */ + if (scope->object != obj) { +#ifdef __GNUC__ + cachep = NULL; /* suppress bogus gcc warnings */ +#endif + break; + } + + ENUM_CACHE_METER(nativeEnumProbes); + shape = scope->shape; + JS_ASSERT(shape < SHAPE_OVERFLOW_BIT); + cachep = &cx->runtime-> + nativeEnumCache[NATIVE_ENUM_CACHE_HASH(shape)]; + oldcache = *cachep; + if (oldcache & (jsuword) 1) { + if ((uint32) (oldcache >> 1) == shape) { + /* scope has a shape with no enumerable properties. */ + break; + } + } else if (oldcache != (jsuword) 0) { + /* + * We can safely read ne->shape without taking the GC lock as + * ne is deleted only when running the GC and ne->shape is + * read-only after initialization. + */ + ne = (JSNativeEnumerator *) *cachep; + JS_ASSERT(ne->length >= 1); + if (ne->shape == shape) { + /* + * Check that ne is not running with another enumerator + * and, if so, reuse and mark it as running from now. + */ + length = ne->length; + if (js_CompareAndSwap(&ne->cursor, 0, length)) + break; + length = 0; + } + ne = NULL; + } + ENUM_CACHE_METER(nativeEnumMisses); + + /* Count all enumerable properties in object's scope. */ + JS_ASSERT(length == 0); + for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { + if ((sprop->attrs & JSPROP_ENUMERATE) && + !(sprop->flags & SPROP_IS_ALIAS) && + (!SCOPE_HAD_MIDDLE_DELETE(scope) || + SCOPE_HAS_PROPERTY(scope, sprop))) { + length++; + } + } + if (length == 0) { + /* cache the scope without enumerable properties. */ + *cachep = ((jsuword) shape << 1) | (jsuword) 1; + break; + } + + allocated = NativeEnumeratorSize(length); + ne = (JSNativeEnumerator *) JS_malloc(cx, allocated); + if (!ne) { + JS_UNLOCK_SCOPE(cx, scope); + return JS_FALSE; + } + ne->cursor = length; + ne->length = length; + ne->shape = shape; + ids = ne->ids; + for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { + if ((sprop->attrs & JSPROP_ENUMERATE) && + !(sprop->flags & SPROP_IS_ALIAS) && + (!SCOPE_HAD_MIDDLE_DELETE(scope) || + SCOPE_HAS_PROPERTY(scope, sprop))) { + JS_ASSERT(ids < ne->ids + length); + *ids++ = sprop->id; + } + } + JS_ASSERT(ids == ne->ids + length); + } while (0); + JS_UNLOCK_SCOPE(cx, scope); + + if (!ne) { + JS_ASSERT(length == 0); + JS_ASSERT(allocated == 0); + *statep = JSVAL_ZERO; + } else { + JS_ASSERT(length != 0); + JS_ASSERT(ne->cursor == (jsword) length); + if (allocated != 0) { + JS_LOCK_GC(cx->runtime); + if (!js_AddAsGCBytes(cx, allocated)) { + /* js_AddAsGCBytes releases the GC lock on failures. */ + JS_free(cx, ne); + return JS_FALSE; + } + ne->next = cx->runtime->nativeEnumerators; + cx->runtime->nativeEnumerators = ne; + JS_ASSERT(((jsuword) ne & (jsuword) 1) == (jsuword) 0); + *cachep = (jsuword) ne; + JS_UNLOCK_GC(cx->runtime); + } + *statep = PRIVATE_TO_JSVAL(ne); + } + if (idp) + *idp = INT_TO_JSVAL(length); + break; + + case JSENUMERATE_NEXT: + case JSENUMERATE_DESTROY: + if (*statep == JSVAL_ZERO) { + *statep = JSVAL_NULL; + break; + } + ne = (JSNativeEnumerator *) JSVAL_TO_PRIVATE(*statep); + JS_ASSERT(ne->length >= 1); + JS_ASSERT(ne->cursor >= 1); + + /* + * We must not access ne->cursor when we set it to zero as it means + * that ne is free and another thread can grab it from the cache. So + * we set the state to JSVAL_ZERO in the NEXT case to avoid touching + * ne->length again in the DESTROY case. + */ + if (enum_op == JSENUMERATE_NEXT) { + newcursor = ne->cursor - 1; + *idp = ne->ids[newcursor]; + ne->cursor = newcursor; + if (newcursor == 0) + *statep = JSVAL_ZERO; + } else { + /* The enumerator has not iterated over all ids. */ + ne->cursor = 0; + } + break; + } + return JS_TRUE; +} + +void +js_TraceNativeEnumerators(JSTracer *trc) +{ + JSRuntime *rt; + JSNativeEnumerator **nep, *ne; + jsid *cursor, *end; + + /* + * Purge native enumerators cached by shape id, which we are about to + * re-number completely when tracing is done for the GC. + */ + rt = trc->context->runtime; + if (IS_GC_MARKING_TRACER(trc)) { + memset(&rt->nativeEnumCache, 0, sizeof rt->nativeEnumCache); +#ifdef JS_DUMP_ENUM_CACHE_STATS + printf("nativeEnumCache hit rate %g%%\n", + 100.0 * (rt->nativeEnumProbes - rt->nativeEnumMisses) / + rt->nativeEnumProbes); +#endif + } + + nep = &rt->nativeEnumerators; + while ((ne = *nep) != NULL) { + JS_ASSERT(ne->length != 0); + if (ne->cursor != 0) { + /* Trace ids of the running enumerator. */ + cursor = ne->ids; + end = cursor + ne->length; + do { + TRACE_ID(trc, *cursor); + } while (++cursor != end); + } else if (IS_GC_MARKING_TRACER(trc)) { + js_RemoveAsGCBytes(rt, NativeEnumeratorSize(ne->length)); + *nep = ne->next; + JS_free(trc->context, ne); + continue; + } + nep = &ne->next; + } +} + +JSBool +js_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + jsval *vp, uintN *attrsp) +{ + JSBool writing; + JSObject *pobj; + JSProperty *prop; + JSClass *clasp; + JSScopeProperty *sprop; + JSSecurityCallbacks *callbacks; + JSCheckAccessOp check; + + writing = (mode & JSACC_WRITE) != 0; + switch (mode & JSACC_TYPEMASK) { + case JSACC_PROTO: + pobj = obj; + if (!writing) + *vp = OBJECT_TO_JSVAL(OBJ_GET_PROTO(cx, obj)); + *attrsp = JSPROP_PERMANENT; + break; + + case JSACC_PARENT: + JS_ASSERT(!writing); + pobj = obj; + *vp = OBJECT_TO_JSVAL(OBJ_GET_PARENT(cx, obj)); + *attrsp = JSPROP_READONLY | JSPROP_PERMANENT; + break; + + default: + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) + return JS_FALSE; + if (!prop) { + if (!writing) + *vp = JSVAL_VOID; + *attrsp = 0; + pobj = obj; + break; + } + + if (!OBJ_IS_NATIVE(pobj)) { + OBJ_DROP_PROPERTY(cx, pobj, prop); + + /* Avoid diverging for non-natives that reuse js_CheckAccess. */ + if (pobj->map->ops->checkAccess == js_CheckAccess) { + if (!writing) { + *vp = JSVAL_VOID; + *attrsp = 0; + } + break; + } + return OBJ_CHECK_ACCESS(cx, pobj, id, mode, vp, attrsp); + } + + sprop = (JSScopeProperty *)prop; + *attrsp = sprop->attrs; + if (!writing) { + *vp = (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))) + ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot) + : JSVAL_VOID; + } + OBJ_DROP_PROPERTY(cx, pobj, prop); + } + + /* + * If obj's class has a stub (null) checkAccess hook, use the per-runtime + * checkObjectAccess callback, if configured. + * + * We don't want to require all classes to supply a checkAccess hook; we + * need that hook only for certain classes used when precompiling scripts + * and functions ("brutal sharing"). But for general safety of built-in + * magic properties such as __proto__ and __parent__, we route all access + * checks, even for classes that stub out checkAccess, through the global + * checkObjectAccess hook. This covers precompilation-based sharing and + * (possibly unintended) runtime sharing across trust boundaries. + */ + clasp = OBJ_GET_CLASS(cx, pobj); + check = clasp->checkAccess; + if (!check) { + callbacks = JS_GetSecurityCallbacks(cx); + check = callbacks ? callbacks->checkObjectAccess : NULL; + } + return !check || check(cx, pobj, ID_TO_VALUE(id), mode, vp); +} + +#ifdef JS_THREADSAFE +void +js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop) +{ + JS_UNLOCK_OBJ(cx, obj); +} +#endif + +#ifdef NARCISSUS +static JSBool +GetCurrentExecutionContext(JSContext *cx, JSObject *obj, jsval *rval) +{ + JSObject *tmp; + jsval xcval; + + while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL) + obj = tmp; + if (!OBJ_GET_PROPERTY(cx, obj, + ATOM_TO_JSID(cx->runtime->atomState + .ExecutionContextAtom), + &xcval)) { + return JS_FALSE; + } + if (JSVAL_IS_PRIMITIVE(xcval)) { + JS_ReportError(cx, "invalid ExecutionContext in global object"); + return JS_FALSE; + } + if (!OBJ_GET_PROPERTY(cx, JSVAL_TO_OBJECT(xcval), + ATOM_TO_JSID(cx->runtime->atomState.currentAtom), + rval)) { + return JS_FALSE; + } + return JS_TRUE; +} +#endif + +JSBool +js_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSClass *clasp; + + clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(argv[-2])); + if (!clasp->call) { +#ifdef NARCISSUS + JSObject *callee, *args; + jsval fval, nargv[3]; + JSBool ok; + + callee = JSVAL_TO_OBJECT(argv[-2]); + if (!OBJ_GET_PROPERTY(cx, callee, + ATOM_TO_JSID(cx->runtime->atomState.__call__Atom), + &fval)) { + return JS_FALSE; + } + if (VALUE_IS_FUNCTION(cx, fval)) { + if (!GetCurrentExecutionContext(cx, obj, &nargv[2])) + return JS_FALSE; + args = js_GetArgsObject(cx, cx->fp); + if (!args) + return JS_FALSE; + nargv[0] = OBJECT_TO_JSVAL(obj); + nargv[1] = OBJECT_TO_JSVAL(args); + return js_InternalCall(cx, callee, fval, 3, nargv, rval); + } + if (JSVAL_IS_OBJECT(fval) && JSVAL_TO_OBJECT(fval) != callee) { + argv[-2] = fval; + ok = js_Call(cx, obj, argc, argv, rval); + argv[-2] = OBJECT_TO_JSVAL(callee); + return ok; + } +#endif + js_ReportIsNotFunction(cx, &argv[-2], cx->fp->flags & JSFRAME_ITERATOR); + return JS_FALSE; + } + return clasp->call(cx, obj, argc, argv, rval); +} + +JSBool +js_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + JSClass *clasp; + + clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(argv[-2])); + if (!clasp->construct) { +#ifdef NARCISSUS + JSObject *callee, *args; + jsval cval, nargv[2]; + JSBool ok; + + callee = JSVAL_TO_OBJECT(argv[-2]); + if (!OBJ_GET_PROPERTY(cx, callee, + ATOM_TO_JSID(cx->runtime->atomState + .__construct__Atom), + &cval)) { + return JS_FALSE; + } + if (VALUE_IS_FUNCTION(cx, cval)) { + if (!GetCurrentExecutionContext(cx, obj, &nargv[1])) + return JS_FALSE; + args = js_GetArgsObject(cx, cx->fp); + if (!args) + return JS_FALSE; + nargv[0] = OBJECT_TO_JSVAL(args); + return js_InternalCall(cx, callee, cval, 2, nargv, rval); + } + if (JSVAL_IS_OBJECT(cval) && JSVAL_TO_OBJECT(cval) != callee) { + argv[-2] = cval; + ok = js_Call(cx, obj, argc, argv, rval); + argv[-2] = OBJECT_TO_JSVAL(callee); + return ok; + } +#endif + js_ReportIsNotFunction(cx, &argv[-2], JSV2F_CONSTRUCT); + return JS_FALSE; + } + return clasp->construct(cx, obj, argc, argv, rval); +} + +JSBool +js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +{ + JSClass *clasp; + + clasp = OBJ_GET_CLASS(cx, obj); + if (clasp->hasInstance) + return clasp->hasInstance(cx, obj, v, bp); +#ifdef NARCISSUS + { + jsval fval, rval; + + if (!OBJ_GET_PROPERTY(cx, obj, + ATOM_TO_JSID(cx->runtime->atomState + .__hasInstance__Atom), + &fval)) { + return JS_FALSE; + } + if (VALUE_IS_FUNCTION(cx, fval)) { + if (!js_InternalCall(cx, obj, fval, 1, &v, &rval)) + return JS_FALSE; + *bp = js_ValueToBoolean(rval); + return JS_TRUE; + } + } +#endif + js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, + JSDVG_SEARCH_STACK, OBJECT_TO_JSVAL(obj), NULL); + return JS_FALSE; +} + +JSBool +js_IsDelegate(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +{ + JSObject *obj2; + + *bp = JS_FALSE; + if (JSVAL_IS_PRIMITIVE(v)) + return JS_TRUE; + obj2 = JSVAL_TO_OBJECT(v); + while ((obj2 = OBJ_GET_PROTO(cx, obj2)) != NULL) { + if (obj2 == obj) { + *bp = JS_TRUE; + break; + } + } + return JS_TRUE; +} + +JSBool +js_GetClassPrototype(JSContext *cx, JSObject *scope, jsid id, + JSObject **protop) +{ + jsval v; + JSObject *ctor; + + if (!js_FindClassObject(cx, scope, id, &v)) + return JS_FALSE; + if (VALUE_IS_FUNCTION(cx, v)) { + ctor = JSVAL_TO_OBJECT(v); + if (!OBJ_GET_PROPERTY(cx, ctor, + ATOM_TO_JSID(cx->runtime->atomState + .classPrototypeAtom), + &v)) { + return JS_FALSE; + } + if (!JSVAL_IS_PRIMITIVE(v)) { + /* + * Set the newborn root in case v is otherwise unreferenced. + * It's ok to overwrite newborn roots here, since the getter + * called just above could have. Unlike the common GC rooting + * model, our callers do not have to protect protop thanks to + * this newborn root, since they all immediately create a new + * instance that delegates to this object, or just query the + * prototype for its class. + */ + cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(v); + } + } + *protop = JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : NULL; + return JS_TRUE; +} + +/* + * For shared precompilation of function objects, we support cloning on entry + * to an execution context in which the function declaration or expression + * should be processed as if it were not precompiled, where the precompiled + * function's scope chain does not match the execution context's. The cloned + * function object carries its execution-context scope in its parent slot; it + * links to the precompiled function (the "clone-parent") via its proto slot. + * + * Note that this prototype-based delegation leaves an unchecked access path + * from the clone to the clone-parent's 'constructor' property. If the clone + * lives in a less privileged or shared scope than the clone-parent, this is + * a security hole, a sharing hazard, or both. Therefore we check all such + * accesses with the following getter/setter pair, which we use when defining + * 'constructor' in f.prototype for all function objects f. + */ +static JSBool +CheckCtorGetAccess(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSAtom *atom; + uintN attrs; + + atom = cx->runtime->atomState.constructorAtom; + JS_ASSERT(id == ATOM_TO_JSID(atom)); + return OBJ_CHECK_ACCESS(cx, obj, ATOM_TO_JSID(atom), JSACC_READ, + vp, &attrs); +} + +static JSBool +CheckCtorSetAccess(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSAtom *atom; + uintN attrs; + + atom = cx->runtime->atomState.constructorAtom; + JS_ASSERT(id == ATOM_TO_JSID(atom)); + return OBJ_CHECK_ACCESS(cx, obj, ATOM_TO_JSID(atom), JSACC_WRITE, + vp, &attrs); +} + +JSBool +js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, + uintN attrs) +{ + /* + * Use the given attributes for the prototype property of the constructor, + * as user-defined constructors have a DontDelete prototype (which may be + * reset), while native or "system" constructors have DontEnum | ReadOnly | + * DontDelete. + */ + if (!OBJ_DEFINE_PROPERTY(cx, ctor, + ATOM_TO_JSID(cx->runtime->atomState + .classPrototypeAtom), + OBJECT_TO_JSVAL(proto), + JS_PropertyStub, JS_PropertyStub, + attrs, NULL)) { + return JS_FALSE; + } + + /* + * ECMA says that Object.prototype.constructor, or f.prototype.constructor + * for a user-defined function f, is DontEnum. + */ + return OBJ_DEFINE_PROPERTY(cx, proto, + ATOM_TO_JSID(cx->runtime->atomState + .constructorAtom), + OBJECT_TO_JSVAL(ctor), + CheckCtorGetAccess, CheckCtorSetAccess, + 0, NULL); +} + +JSBool +js_PrimitiveToObject(JSContext *cx, jsval *vp) +{ + JSClass *clasp; + JSObject *obj; + + /* Table to map primitive value's tag into the corresponding class. */ + JS_STATIC_ASSERT(JSVAL_INT == 1); + JS_STATIC_ASSERT(JSVAL_DOUBLE == 2); + JS_STATIC_ASSERT(JSVAL_STRING == 4); + JS_STATIC_ASSERT(JSVAL_BOOLEAN == 6); + static JSClass *const PrimitiveClasses[] = { + &js_NumberClass, /* INT */ + &js_NumberClass, /* DOUBLE */ + &js_NumberClass, /* INT */ + &js_StringClass, /* STRING */ + &js_NumberClass, /* INT */ + &js_BooleanClass, /* BOOLEAN */ + &js_NumberClass /* INT */ + }; + + JS_ASSERT(!JSVAL_IS_OBJECT(*vp)); + JS_ASSERT(!JSVAL_IS_VOID(*vp)); + clasp = PrimitiveClasses[JSVAL_TAG(*vp) - 1]; + obj = js_NewObject(cx, clasp, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, *vp); + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +JSBool +js_ValueToObject(JSContext *cx, jsval v, JSObject **objp) +{ + JSObject *obj; + + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { + obj = NULL; + } else if (JSVAL_IS_OBJECT(v)) { + obj = JSVAL_TO_OBJECT(v); + if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_OBJECT, &v)) + return JS_FALSE; + if (JSVAL_IS_OBJECT(v)) + obj = JSVAL_TO_OBJECT(v); + } else { + if (!js_PrimitiveToObject(cx, &v)) + return JS_FALSE; + obj = JSVAL_TO_OBJECT(v); + } + *objp = obj; + return JS_TRUE; +} + +JSObject * +js_ValueToNonNullObject(JSContext *cx, jsval v) +{ + JSObject *obj; + + if (!js_ValueToObject(cx, v, &obj)) + return NULL; + if (!obj) + js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, v, NULL); + return obj; +} + +JSBool +js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, jsval *rval) +{ + jsval argv[1]; + + argv[0] = ATOM_KEY(cx->runtime->atomState.typeAtoms[type]); + return js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom, 1, argv, + rval); +} + +JSBool +js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom, + uintN argc, jsval *argv, jsval *rval) +{ + JSErrorReporter older; + jsid id; + jsval fval; + JSBool ok; + + JS_CHECK_RECURSION(cx, return JS_FALSE); + + /* + * Report failure only if an appropriate method was found, and calling it + * returned failure. We propagate failure in this case to make exceptions + * behave properly. + */ + older = JS_SetErrorReporter(cx, NULL); + id = ATOM_TO_JSID(atom); + fval = JSVAL_VOID; +#if JS_HAS_XML_SUPPORT + if (OBJECT_IS_XML(cx, obj)) { + JSXMLObjectOps *ops; + + ops = (JSXMLObjectOps *) obj->map->ops; + obj = ops->getMethod(cx, obj, id, &fval); + ok = (obj != NULL); + } else +#endif + { + ok = OBJ_GET_PROPERTY(cx, obj, id, &fval); + } + if (!ok) + JS_ClearPendingException(cx); + JS_SetErrorReporter(cx, older); + + return JSVAL_IS_PRIMITIVE(fval) || + js_InternalCall(cx, obj, fval, argc, argv, rval); +} + +#if JS_HAS_XDR + +JSBool +js_XDRObject(JSXDRState *xdr, JSObject **objp) +{ + JSContext *cx; + JSAtom *atom; + JSClass *clasp; + uint32 classId, classDef; + JSProtoKey protoKey; + jsid classKey; + JSObject *proto; + + cx = xdr->cx; + atom = NULL; + if (xdr->mode == JSXDR_ENCODE) { + clasp = OBJ_GET_CLASS(cx, *objp); + classId = JS_XDRFindClassIdByName(xdr, clasp->name); + classDef = !classId; + if (classDef) { + if (!JS_XDRRegisterClass(xdr, clasp, &classId)) + return JS_FALSE; + protoKey = JSCLASS_CACHED_PROTO_KEY(clasp); + if (protoKey != JSProto_Null) { + classDef |= (protoKey << 1); + } else { + atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0); + if (!atom) + return JS_FALSE; + } + } + } else { + clasp = NULL; /* quell GCC overwarning */ + classDef = 0; + } + + /* + * XDR a flag word, which could be 0 for a class use, in which case no + * name follows, only the id in xdr's class registry; 1 for a class def, + * in which case the flag word is followed by the class name transferred + * from or to atom; or a value greater than 1, an odd number that when + * divided by two yields the JSProtoKey for class. In the last case, as + * in the 0 classDef case, no name is transferred via atom. + */ + if (!JS_XDRUint32(xdr, &classDef)) + return JS_FALSE; + if (classDef == 1 && !js_XDRStringAtom(xdr, &atom)) + return JS_FALSE; + + if (!JS_XDRUint32(xdr, &classId)) + return JS_FALSE; + + if (xdr->mode == JSXDR_DECODE) { + if (classDef) { + /* NB: we know that JSProto_Null is 0 here, for backward compat. */ + protoKey = (JSProtoKey) (classDef >> 1); + classKey = (protoKey != JSProto_Null) + ? INT_TO_JSID(protoKey) + : ATOM_TO_JSID(atom); + if (!js_GetClassPrototype(cx, NULL, classKey, &proto)) + return JS_FALSE; + clasp = OBJ_GET_CLASS(cx, proto); + if (!JS_XDRRegisterClass(xdr, clasp, &classId)) + return JS_FALSE; + } else { + clasp = JS_XDRFindClassById(xdr, classId); + if (!clasp) { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)classId); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_FIND_CLASS, numBuf); + return JS_FALSE; + } + } + } + + if (!clasp->xdrObject) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_XDR_CLASS, clasp->name); + return JS_FALSE; + } + return clasp->xdrObject(xdr, objp); +} + +#endif /* JS_HAS_XDR */ + +#ifdef JS_DUMP_SCOPE_METERS + +#include + +JSBasicStats js_entry_count_bs = JS_INIT_STATIC_BASIC_STATS; + +static void +MeterEntryCount(uintN count) +{ + JS_BASIC_STATS_ACCUM(&js_entry_count_bs, count); +} + +void +js_DumpScopeMeters(JSRuntime *rt) +{ + static FILE *logfp; + if (!logfp) + logfp = fopen("/tmp/scope.stats", "a"); + + { + double mean, sigma; + + mean = JS_MeanAndStdDevBS(&js_entry_count_bs, &sigma); + + fprintf(logfp, "scopes %u entries %g mean %g sigma %g max %u", + js_entry_count_bs.num, js_entry_count_bs.sum, mean, sigma, + js_entry_count_bs.max); + } + + JS_DumpHistogram(&js_entry_count_bs, logfp); + JS_BASIC_STATS_INIT(&js_entry_count_bs); + fflush(logfp); +} +#endif + +#ifdef DEBUG +void +js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize) +{ + JSObject *obj; + uint32 slot; + JSScope *scope; + jsval nval; + JSScopeProperty *sprop; + JSClass *clasp; + uint32 key; + const char *slotname; + + JS_ASSERT(trc->debugPrinter == js_PrintObjectSlotName); + obj = (JSObject *)trc->debugPrintArg; + slot = (uint32)trc->debugPrintIndex; + + if (OBJ_IS_NATIVE(obj)) { + scope = OBJ_SCOPE(obj); + sprop = SCOPE_LAST_PROP(scope); + while (sprop && sprop->slot != slot) + sprop = sprop->parent; + } else { + sprop = NULL; + } + + if (!sprop) { + switch (slot) { + case JSSLOT_PROTO: + JS_snprintf(buf, bufsize, "__proto__"); + break; + case JSSLOT_PARENT: + JS_snprintf(buf, bufsize, "__parent__"); + break; + default: + slotname = NULL; + clasp = LOCKED_OBJ_GET_CLASS(obj); + if (clasp->flags & JSCLASS_IS_GLOBAL) { + key = slot - JSSLOT_START(clasp); +#define JS_PROTO(name,code,init) \ + if ((code) == key) { slotname = js_##name##_str; goto found; } +#include "jsproto.tbl" +#undef JS_PROTO + } + found: + if (slotname) + JS_snprintf(buf, bufsize, "CLASS_OBJECT(%s)", slotname); + else + JS_snprintf(buf, bufsize, "**UNKNOWN SLOT %ld**", (long)slot); + break; + } + } else { + nval = ID_TO_VALUE(sprop->id); + if (JSVAL_IS_INT(nval)) { + JS_snprintf(buf, bufsize, "%ld", (long)JSVAL_TO_INT(nval)); + } else if (JSVAL_IS_STRING(nval)) { + js_PutEscapedString(buf, bufsize, JSVAL_TO_STRING(nval), 0); + } else { + JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**"); + } + } +} +#endif + +void +js_TraceObject(JSTracer *trc, JSObject *obj) +{ + JSContext *cx; + JSScope *scope; + JSBool traceScope; + JSScopeProperty *sprop; + JSClass *clasp; + size_t nslots, i; + jsval v; + + JS_ASSERT(OBJ_IS_NATIVE(obj)); + cx = trc->context; + scope = OBJ_SCOPE(obj); + + traceScope = (scope->object == obj); + if (!traceScope) { + JSObject *pobj = obj; + + /* + * Because obj does not own scope, we should be able to assert that an + * object on obj's prototype chain does -- or scope's properties might + * go untraced. It indeed turns out that you can disconnect an object + * from the prototype object whose scope it shares, so we may have to + * mark scope even though scope->object != obj. + */ + while ((pobj = LOCKED_OBJ_GET_PROTO(pobj)) != NULL) { + if (pobj == scope->object) + break; + } + JS_ASSERT_IF(pobj, OBJ_SCOPE(pobj) == scope); + traceScope = !pobj; + } + + if (traceScope) { +#ifdef JS_DUMP_SCOPE_METERS + MeterEntryCount(scope->entryCount); +#endif + + sprop = SCOPE_LAST_PROP(scope); + if (sprop) { + JS_ASSERT(SCOPE_HAS_PROPERTY(scope, sprop)); + + /* Regenerate property cache shape ids if GC'ing. */ + if (IS_GC_MARKING_TRACER(trc)) { + uint32 shape, oldshape; + + shape = ++cx->runtime->shapeGen; + JS_ASSERT(shape != 0); + + if (!(sprop->flags & SPROP_MARK)) { + oldshape = sprop->shape; + sprop->shape = shape; + sprop->flags |= SPROP_FLAG_SHAPE_REGEN; + if (scope->shape != oldshape) { + shape = ++cx->runtime->shapeGen; + JS_ASSERT(shape != 0); + } + } + + scope->shape = shape; + } + + /* Trace scope's property tree ancestor line. */ + do { + if (SCOPE_HAD_MIDDLE_DELETE(scope) && + !SCOPE_HAS_PROPERTY(scope, sprop)) { + continue; + } + TRACE_SCOPE_PROPERTY(trc, sprop); + } while ((sprop = sprop->parent) != NULL); + } + } + + if (!JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList)) + js_TraceWatchPoints(trc, obj); + + /* No one runs while the GC is running, so we can use LOCKED_... here. */ + clasp = LOCKED_OBJ_GET_CLASS(obj); + if (clasp->mark) { + if (clasp->flags & JSCLASS_MARK_IS_TRACE) + ((JSTraceOp) clasp->mark)(trc, obj); + else if (IS_GC_MARKING_TRACER(trc)) + (void) clasp->mark(cx, obj, trc); + } + + /* + * An unmutated object that shares a prototype object's scope. We can't + * tell how many slots are in use in obj by looking at its scope, so we + * use STOBJ_NSLOTS(obj). + * + * NB: In case clasp->mark mutates something, leave this code here -- + * don't move it up and unify it with the |if (!traceScope)| section + * above. + */ + nslots = STOBJ_NSLOTS(obj); + if (scope->object == obj && scope->map.freeslot < nslots) + nslots = scope->map.freeslot; + + for (i = 0; i != nslots; ++i) { + v = STOBJ_GET_SLOT(obj, i); + if (JSVAL_IS_TRACEABLE(v)) { + JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i); + JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); + } + } +} + +void +js_Clear(JSContext *cx, JSObject *obj) +{ + JSScope *scope; + uint32 i, n; + + /* + * Clear our scope and the property cache of all obj's properties only if + * obj owns the scope (i.e., not if obj is unmutated and therefore sharing + * its prototype's scope). NB: we do not clear any reserved slots lying + * below JSSLOT_FREE(clasp). + */ + JS_LOCK_OBJ(cx, obj); + scope = OBJ_SCOPE(obj); + if (scope->object == obj) { + /* Now that we're done using scope->lastProp/table, clear scope. */ + js_ClearScope(cx, scope); + + /* Clear slot values and reset freeslot so we're consistent. */ + i = STOBJ_NSLOTS(obj); + n = JSSLOT_FREE(LOCKED_OBJ_GET_CLASS(obj)); + while (--i >= n) + STOBJ_SET_SLOT(obj, i, JSVAL_VOID); + scope->map.freeslot = n; + } + JS_UNLOCK_OBJ(cx, obj); +} + +jsval +js_GetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot) +{ + jsval v; + + JS_LOCK_OBJ(cx, obj); + v = (slot < STOBJ_NSLOTS(obj)) ? STOBJ_GET_SLOT(obj, slot) : JSVAL_VOID; + JS_UNLOCK_OBJ(cx, obj); + return v; +} + +JSBool +js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v) +{ + JSScope *scope; + uint32 nslots; + JSClass *clasp; + + JS_LOCK_OBJ(cx, obj); + scope = OBJ_SCOPE(obj); + if (slot >= JS_INITIAL_NSLOTS && !obj->dslots) { + /* + * At this point, obj may or may not own scope. If some path calls + * js_GetMutableScope but does not add a slot-owning property, then + * scope->object == obj but obj->dslots will be null. If obj shares a + * prototype's scope, then we cannot update scope->map here. Instead + * we rely on STOBJ_NSLOTS(obj) to get the number of available slots + * in obj after we allocate dynamic slots. + * + * See js_TraceObject, before the slot tracing, where we make a special + * case for unmutated (scope->object != obj) objects. + */ + clasp = LOCKED_OBJ_GET_CLASS(obj); + nslots = JSSLOT_FREE(clasp); + if (clasp->reserveSlots) + nslots += clasp->reserveSlots(cx, obj); + JS_ASSERT(slot < nslots); + if (!js_ReallocSlots(cx, obj, nslots, JS_TRUE)) { + JS_UNLOCK_SCOPE(cx, scope); + return JS_FALSE; + } + } + + /* Whether or not we grew nslots, we may need to advance freeslot. */ + if (scope->object == obj && slot >= scope->map.freeslot) + scope->map.freeslot = slot + 1; + + STOBJ_SET_SLOT(obj, slot, v); + JS_UNLOCK_SCOPE(cx, scope); + return JS_TRUE; +} + +JSObject * +js_GetWrappedObject(JSContext *cx, JSObject *obj) +{ + JSClass *clasp; + + clasp = OBJ_GET_CLASS(cx, obj); + if (clasp->flags & JSCLASS_IS_EXTENDED) { + JSExtendedClass *xclasp; + JSObject *obj2; + + xclasp = (JSExtendedClass *)clasp; + if (xclasp->wrappedObject && (obj2 = xclasp->wrappedObject(cx, obj))) + return obj2; + } + return obj; +} + +#if DEBUG + +/* + * Routines to print out values during debugging. These are FRIEND_API to help + * the debugger find them and to support temporarily hacking js_Dump* calls + * into other code. + */ + +void +dumpChars(const jschar *s, size_t n) +{ + size_t i; + + if (n == (size_t) -1) { + while (s[++n]) ; + } + + fputc('"', stderr); + for (i = 0; i < n; i++) { + if (s[i] == '\n') + fprintf(stderr, "\\n"); + else if (s[i] == '\t') + fprintf(stderr, "\\t"); + else if (s[i] >= 32 && s[i] < 127) + fputc(s[i], stderr); + else if (s[i] <= 255) + fprintf(stderr, "\\x%02x", (unsigned int) s[i]); + else + fprintf(stderr, "\\u%04x", (unsigned int) s[i]); + } + fputc('"', stderr); +} + +JS_FRIEND_API(void) +js_DumpChars(const jschar *s, size_t n) +{ + fprintf(stderr, "jschar * (%p) = ", (void *) s); + dumpChars(s, n); + fputc('\n', stderr); +} + +void +dumpString(JSString *str) +{ + dumpChars(JSSTRING_CHARS(str), JSSTRING_LENGTH(str)); +} + +JS_FRIEND_API(void) +js_DumpString(JSString *str) +{ + fprintf(stderr, "JSString* (%p) = jschar * (%p) = ", + (void *) str, (void *) JSSTRING_CHARS(str)); + dumpString(str); + fputc('\n', stderr); +} + +JS_FRIEND_API(void) +js_DumpAtom(JSAtom *atom) +{ + fprintf(stderr, "JSAtom* (%p) = ", (void *) atom); + js_DumpValue(ATOM_KEY(atom)); +} + +void +dumpValue(jsval val) +{ + if (JSVAL_IS_NULL(val)) { + fprintf(stderr, "null"); + } else if (JSVAL_IS_VOID(val)) { + fprintf(stderr, "undefined"); + } else if (JSVAL_IS_OBJECT(val)) { + JSObject *obj = JSVAL_TO_OBJECT(val); + JSClass *cls = STOBJ_GET_CLASS(obj); + fprintf(stderr, "<%s%s at %p>", + cls->name, + cls == &js_ObjectClass ? "" : " object", + obj); + } else if (JSVAL_IS_INT(val)) { + fprintf(stderr, "%d", JSVAL_TO_INT(val)); + } else if (JSVAL_IS_STRING(val)) { + dumpString(JSVAL_TO_STRING(val)); + } else if (JSVAL_IS_DOUBLE(val)) { + fprintf(stderr, "%g", *JSVAL_TO_DOUBLE(val)); + } else if (val == JSVAL_TRUE) { + fprintf(stderr, "true"); + } else if (val == JSVAL_FALSE) { + fprintf(stderr, "false"); + } else if (val == JSVAL_HOLE) { + fprintf(stderr, "hole"); + } else { + /* jsvals are pointer-sized, and %p is portable */ + fprintf(stderr, "unrecognized jsval %p", (void *) val); + } +} + +JS_FRIEND_API(void) +js_DumpValue(jsval val) +{ + fprintf(stderr, "jsval %d (%p) = ", (int) val, (void *) val); + dumpValue(val); + fputc('\n', stderr); +} + +JS_FRIEND_API(void) +js_DumpId(jsid id) +{ + fprintf(stderr, "id %d (%p) = ", (int) id, (void *) id); + dumpValue(ID_TO_VALUE(id)); + fputc('\n', stderr); +} + +static void +dumpScopeProp(JSScopeProperty *sprop) +{ + jsid id = sprop->id; + uint8 attrs = sprop->attrs; + + fprintf(stderr, " "); + if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate "); + if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly "); + if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent "); + if (attrs & JSPROP_GETTER) fprintf(stderr, "getter "); + if (attrs & JSPROP_SETTER) fprintf(stderr, "setter "); + if (attrs & JSPROP_SHARED) fprintf(stderr, "shared "); + if (sprop->flags & SPROP_IS_ALIAS) fprintf(stderr, "alias "); + if (JSID_IS_ATOM(id)) + dumpString(JSVAL_TO_STRING(ID_TO_VALUE(id))); + else if (JSID_IS_INT(id)) + fprintf(stderr, "%d", (int) JSID_TO_INT(id)); + else + fprintf(stderr, "unknown jsid %p", (void *) id); + fprintf(stderr, ": slot %d", sprop->slot); + fprintf(stderr, "\n"); +} + +JS_FRIEND_API(void) +js_DumpObject(JSObject *obj) +{ + uint32 i, slots; + JSClass *clasp; + jsuint reservedEnd; + JSBool sharesScope = JS_FALSE; + + fprintf(stderr, "object %p\n", (void *) obj); + clasp = STOBJ_GET_CLASS(obj); + fprintf(stderr, "class %p %s\n", (void *)clasp, clasp->name); + + /* OBJ_IS_DENSE_ARRAY ignores the cx argument. */ + if (OBJ_IS_DENSE_ARRAY(BOGUS_CX, obj)) { + slots = JS_MIN((jsuint) obj->fslots[JSSLOT_ARRAY_LENGTH], + ARRAY_DENSE_LENGTH(obj)); + fprintf(stderr, "elements\n"); + for (i = 0; i < slots; i++) { + fprintf(stderr, " %3d: ", i); + dumpValue(obj->dslots[i]); + fprintf(stderr, "\n"); + fflush(stderr); + } + return; + } + + if (OBJ_IS_NATIVE(obj)) { + JSScope *scope = OBJ_SCOPE(obj); + JSObject *proto = STOBJ_GET_PROTO(obj); + + if (SCOPE_IS_SEALED(scope)) + fprintf(stderr, "sealed\n"); + + sharesScope = (scope->object != obj); + if (sharesScope) { + fprintf(stderr, "no own properties - see proto (%s at %p)\n", + STOBJ_GET_CLASS(proto)->name, proto); + } else { + fprintf(stderr, "properties:\n"); + for (JSScopeProperty *sprop = SCOPE_LAST_PROP(scope); sprop; + sprop = sprop->parent) { + if (!SCOPE_HAD_MIDDLE_DELETE(scope) || + SCOPE_HAS_PROPERTY(scope, sprop)) { + dumpScopeProp(sprop); + } + } + } + } else { + if (!OBJ_IS_NATIVE(obj)) + fprintf(stderr, "not native\n"); + } + + fprintf(stderr, "slots:\n"); + reservedEnd = JSSLOT_PRIVATE; + if (clasp->flags & JSCLASS_HAS_PRIVATE) + reservedEnd++; + reservedEnd += JSCLASS_RESERVED_SLOTS(clasp); + slots = sharesScope ? reservedEnd : obj->map->freeslot; + for (i = 0; i < slots; i++) { + fprintf(stderr, " %3d ", i); + if (i == JSSLOT_PRIVATE && (clasp->flags & JSCLASS_HAS_PRIVATE)) { + fprintf(stderr, "(private) = %p\n", + JSVAL_TO_PRIVATE(STOBJ_GET_SLOT(obj, i))); + continue; + } + if (i == JSSLOT_PROTO) + fprintf(stderr, "(proto) "); + else if (i == JSSLOT_PARENT) + fprintf(stderr, "(parent) "); + else if (i < reservedEnd) + fprintf(stderr, "(reserved) "); + fprintf(stderr, "= "); + dumpValue(STOBJ_GET_SLOT(obj, i)); + fputc('\n', stderr); + } + fputc('\n', stderr); +} + +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsobj.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsobj.h new file mode 100644 index 0000000..59a354f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsobj.h @@ -0,0 +1,735 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsobj_h___ +#define jsobj_h___ +/* + * JS object definitions. + * + * A JS object consists of a possibly-shared object descriptor containing + * ordered property names, called the map; and a dense vector of property + * values, called slots. The map/slot pointer pair is GC'ed, while the map + * is reference counted and the slot vector is malloc'ed. + */ +#include "jshash.h" /* Added by JSIFY */ +#include "jsprvtd.h" +#include "jspubtd.h" + +JS_BEGIN_EXTERN_C + +struct JSObjectMap { + jsrefcount nrefs; /* count of all referencing objects */ + JSObjectOps *ops; /* high level object operation vtable */ + uint32 freeslot; /* index of next free slot in object */ +}; + +/* Shorthand macros for frequently-made calls. */ +#define OBJ_LOOKUP_PROPERTY(cx,obj,id,objp,propp) \ + (obj)->map->ops->lookupProperty(cx,obj,id,objp,propp) +#define OBJ_DEFINE_PROPERTY(cx,obj,id,value,getter,setter,attrs,propp) \ + (obj)->map->ops->defineProperty(cx,obj,id,value,getter,setter,attrs,propp) +#define OBJ_GET_PROPERTY(cx,obj,id,vp) \ + (obj)->map->ops->getProperty(cx,obj,id,vp) +#define OBJ_SET_PROPERTY(cx,obj,id,vp) \ + (obj)->map->ops->setProperty(cx,obj,id,vp) +#define OBJ_GET_ATTRIBUTES(cx,obj,id,prop,attrsp) \ + (obj)->map->ops->getAttributes(cx,obj,id,prop,attrsp) +#define OBJ_SET_ATTRIBUTES(cx,obj,id,prop,attrsp) \ + (obj)->map->ops->setAttributes(cx,obj,id,prop,attrsp) +#define OBJ_DELETE_PROPERTY(cx,obj,id,rval) \ + (obj)->map->ops->deleteProperty(cx,obj,id,rval) +#define OBJ_DEFAULT_VALUE(cx,obj,hint,vp) \ + (obj)->map->ops->defaultValue(cx,obj,hint,vp) +#define OBJ_ENUMERATE(cx,obj,enum_op,statep,idp) \ + (obj)->map->ops->enumerate(cx,obj,enum_op,statep,idp) +#define OBJ_CHECK_ACCESS(cx,obj,id,mode,vp,attrsp) \ + (obj)->map->ops->checkAccess(cx,obj,id,mode,vp,attrsp) + +/* These four are time-optimized to avoid stub calls. */ +#define OBJ_THIS_OBJECT(cx,obj) \ + ((obj)->map->ops->thisObject \ + ? (obj)->map->ops->thisObject(cx,obj) \ + : (obj)) +#define OBJ_DROP_PROPERTY(cx,obj,prop) \ + ((obj)->map->ops->dropProperty \ + ? (obj)->map->ops->dropProperty(cx,obj,prop) \ + : (void)0) +#define OBJ_GET_REQUIRED_SLOT(cx,obj,slot) \ + ((obj)->map->ops->getRequiredSlot \ + ? (obj)->map->ops->getRequiredSlot(cx, obj, slot) \ + : JSVAL_VOID) +#define OBJ_SET_REQUIRED_SLOT(cx,obj,slot,v) \ + ((obj)->map->ops->setRequiredSlot \ + ? (obj)->map->ops->setRequiredSlot(cx, obj, slot, v) \ + : JS_TRUE) + +#define OBJ_TO_INNER_OBJECT(cx,obj) \ + JS_BEGIN_MACRO \ + JSClass *clasp_ = OBJ_GET_CLASS(cx, obj); \ + if (clasp_->flags & JSCLASS_IS_EXTENDED) { \ + JSExtendedClass *xclasp_ = (JSExtendedClass*)clasp_; \ + if (xclasp_->innerObject) \ + obj = xclasp_->innerObject(cx, obj); \ + } \ + JS_END_MACRO + +#define OBJ_TO_OUTER_OBJECT(cx,obj) \ + JS_BEGIN_MACRO \ + JSClass *clasp_ = OBJ_GET_CLASS(cx, obj); \ + if (clasp_->flags & JSCLASS_IS_EXTENDED) { \ + JSExtendedClass *xclasp_ = (JSExtendedClass*)clasp_; \ + if (xclasp_->outerObject) \ + obj = xclasp_->outerObject(cx, obj); \ + } \ + JS_END_MACRO + +#define JS_INITIAL_NSLOTS 5 + +/* + * When JSObject.dslots is not null, JSObject.dslots[-1] records the number of + * available slots. + */ +struct JSObject { + JSObjectMap *map; + jsuword classword; + jsval fslots[JS_INITIAL_NSLOTS]; + jsval *dslots; /* dynamically allocated slots */ +}; + +#define JSSLOT_PROTO 0 +#define JSSLOT_PARENT 1 +#define JSSLOT_PRIVATE 2 +#define JSSLOT_START(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \ + ? JSSLOT_PRIVATE + 1 \ + : JSSLOT_PARENT + 1) + +#define JSSLOT_FREE(clasp) (JSSLOT_START(clasp) \ + + JSCLASS_RESERVED_SLOTS(clasp)) + +/* + * STOBJ prefix means Single Threaded Object. Use the following fast macros to + * directly manipulate slots in obj when only one thread can access obj and + * when obj->map->freeslot can be inconsistent with slots. + */ + +#define STOBJ_NSLOTS(obj) \ + ((obj)->dslots ? (uint32)(obj)->dslots[-1] : (uint32)JS_INITIAL_NSLOTS) + +#define STOBJ_GET_SLOT(obj,slot) \ + ((slot) < JS_INITIAL_NSLOTS \ + ? (obj)->fslots[(slot)] \ + : (JS_ASSERT((slot) < (uint32)(obj)->dslots[-1]), \ + (obj)->dslots[(slot) - JS_INITIAL_NSLOTS])) + +#define STOBJ_SET_SLOT(obj,slot,value) \ + ((slot) < JS_INITIAL_NSLOTS \ + ? (obj)->fslots[(slot)] = (value) \ + : (JS_ASSERT((slot) < (uint32)(obj)->dslots[-1]), \ + (obj)->dslots[(slot) - JS_INITIAL_NSLOTS] = (value))) + +#define STOBJ_GET_PROTO(obj) \ + JSVAL_TO_OBJECT((obj)->fslots[JSSLOT_PROTO]) +#define STOBJ_SET_PROTO(obj,proto) \ + (void)(STOBJ_NULLSAFE_SET_DELEGATE(proto), \ + (obj)->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto)) +#define STOBJ_CLEAR_PROTO(obj) \ + ((obj)->fslots[JSSLOT_PROTO] = JSVAL_NULL) + +#define STOBJ_GET_PARENT(obj) \ + JSVAL_TO_OBJECT((obj)->fslots[JSSLOT_PARENT]) +#define STOBJ_SET_PARENT(obj,parent) \ + (void)(STOBJ_NULLSAFE_SET_DELEGATE(parent), \ + (obj)->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent)) +#define STOBJ_CLEAR_PARENT(obj) \ + ((obj)->fslots[JSSLOT_PARENT] = JSVAL_NULL) + +/* + * We use JSObject.classword to store both JSClass* and the delegate and system + * flags in the two least significant bits. We do *not* synchronize updates of + * obj->classword -- API clients must take care. + */ +#define STOBJ_GET_CLASS(obj) ((JSClass *)((obj)->classword & ~3)) +#define STOBJ_IS_DELEGATE(obj) (((obj)->classword & 1) != 0) +#define STOBJ_SET_DELEGATE(obj) ((obj)->classword |= 1) +#define STOBJ_NULLSAFE_SET_DELEGATE(obj) \ + (!(obj) || STOBJ_SET_DELEGATE((JSObject*)obj)) +#define STOBJ_IS_SYSTEM(obj) (((obj)->classword & 2) != 0) +#define STOBJ_SET_SYSTEM(obj) ((obj)->classword |= 2) + +#define STOBJ_GET_PRIVATE(obj) \ + (JS_ASSERT(JSVAL_IS_INT(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE))), \ + JSVAL_TO_PRIVATE(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE))) + +#define OBJ_CHECK_SLOT(obj,slot) \ + JS_ASSERT(slot < (obj)->map->freeslot) + +#define LOCKED_OBJ_GET_SLOT(obj,slot) \ + (OBJ_CHECK_SLOT(obj, slot), STOBJ_GET_SLOT(obj, slot)) +#define LOCKED_OBJ_SET_SLOT(obj,slot,value) \ + (OBJ_CHECK_SLOT(obj, slot), STOBJ_SET_SLOT(obj, slot, value)) + +/* + * NB: Don't call LOCKED_OBJ_SET_SLOT or STOBJ_SET_SLOT for a write to a slot + * that may contain a function reference already, or where the new value is a + * function ref, and the object's scope may be branded with a property cache + * structural type capability that distinguishes versions of the object with + * and without the function property. Instead use LOCKED_OBJ_WRITE_BARRIER or + * a fast inline equivalent (JSOP_SETNAME/JSOP_SETPROP cases in jsinterp.c). + */ +#define LOCKED_OBJ_WRITE_BARRIER(cx,obj,slot,newval) \ + JS_BEGIN_MACRO \ + JSScope *scope_ = OBJ_SCOPE(obj); \ + JS_ASSERT(scope_->object == (obj)); \ + GC_WRITE_BARRIER(cx, scope_, LOCKED_OBJ_GET_SLOT(obj, slot), newval); \ + LOCKED_OBJ_SET_SLOT(obj, slot, newval); \ + JS_END_MACRO + +#define LOCKED_OBJ_GET_PROTO(obj) \ + (OBJ_CHECK_SLOT(obj, JSSLOT_PROTO), STOBJ_GET_PROTO(obj)) +#define LOCKED_OBJ_SET_PROTO(obj,proto) \ + (OBJ_CHECK_SLOT(obj, JSSLOT_PROTO), STOBJ_SET_PROTO(obj, proto)) + +#define LOCKED_OBJ_GET_PARENT(obj) \ + (OBJ_CHECK_SLOT(obj, JSSLOT_PARENT), STOBJ_GET_PARENT(obj)) +#define LOCKED_OBJ_SET_PARENT(obj,parent) \ + (OBJ_CHECK_SLOT(obj, JSSLOT_PARENT), STOBJ_SET_PARENT(obj, parent)) + +#define LOCKED_OBJ_GET_CLASS(obj) \ + STOBJ_GET_CLASS(obj) + +#define LOCKED_OBJ_GET_PRIVATE(obj) \ + (OBJ_CHECK_SLOT(obj, JSSLOT_PRIVATE), STOBJ_GET_PRIVATE(obj)) + +#ifdef JS_THREADSAFE + +/* Thread-safe functions and wrapper macros for accessing slots in obj. */ +#define OBJ_GET_SLOT(cx,obj,slot) \ + (OBJ_CHECK_SLOT(obj, slot), \ + (OBJ_IS_NATIVE(obj) && OBJ_SCOPE(obj)->title.ownercx == cx) \ + ? LOCKED_OBJ_GET_SLOT(obj, slot) \ + : js_GetSlotThreadSafe(cx, obj, slot)) + +#define OBJ_SET_SLOT(cx,obj,slot,value) \ + JS_BEGIN_MACRO \ + OBJ_CHECK_SLOT(obj, slot); \ + if (OBJ_IS_NATIVE(obj) && OBJ_SCOPE(obj)->title.ownercx == cx) \ + LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, value); \ + else \ + js_SetSlotThreadSafe(cx, obj, slot, value); \ + JS_END_MACRO + +/* + * If thread-safe, define an OBJ_GET_SLOT wrapper that bypasses, for a native + * object, the lock-free "fast path" test of (OBJ_SCOPE(obj)->ownercx == cx), + * to avoid needlessly switching from lock-free to lock-full scope when doing + * GC on a different context from the last one to own the scope. The caller + * in this case is probably a JSClass.mark function, e.g., fun_mark, or maybe + * a finalizer. + * + * The GC runs only when all threads except the one on which the GC is active + * are suspended at GC-safe points, so calling STOBJ_GET_SLOT from the GC's + * thread is safe when rt->gcRunning is set. See jsgc.c for details. + */ +#define THREAD_IS_RUNNING_GC(rt, thread) \ + ((rt)->gcRunning && (rt)->gcThread == (thread)) + +#define CX_THREAD_IS_RUNNING_GC(cx) \ + THREAD_IS_RUNNING_GC((cx)->runtime, (cx)->thread) + +#else /* !JS_THREADSAFE */ + +#define OBJ_GET_SLOT(cx,obj,slot) LOCKED_OBJ_GET_SLOT(obj,slot) +#define OBJ_SET_SLOT(cx,obj,slot,value) LOCKED_OBJ_WRITE_BARRIER(cx,obj,slot, \ + value) + +#endif /* !JS_THREADSAFE */ + +/* Thread-safe delegate, proto, parent, and class access macros. */ +#define OBJ_IS_DELEGATE(cx,obj) STOBJ_IS_DELEGATE(obj) +#define OBJ_SET_DELEGATE(cx,obj) STOBJ_SET_DELEGATE(obj) + +#define OBJ_GET_PROTO(cx,obj) STOBJ_GET_PROTO(obj) +#define OBJ_SET_PROTO(cx,obj,proto) STOBJ_SET_PROTO(obj, proto) +#define OBJ_CLEAR_PROTO(cx,obj) STOBJ_CLEAR_PROTO(obj) + +#define OBJ_GET_PARENT(cx,obj) STOBJ_GET_PARENT(obj) +#define OBJ_SET_PARENT(cx,obj,parent) STOBJ_SET_PARENT(obj, parent) +#define OBJ_CLEAR_PARENT(cx,obj) STOBJ_CLEAR_PARENT(obj) + +/* + * Class is invariant and comes from the fixed clasp member. Thus no locking + * is necessary to read it. Same for the private slot. + */ +#define OBJ_GET_CLASS(cx,obj) STOBJ_GET_CLASS(obj) +#define OBJ_GET_PRIVATE(cx,obj) STOBJ_GET_PRIVATE(obj) + +/* Test whether a map or object is native. */ +#define MAP_IS_NATIVE(map) \ + JS_LIKELY((map)->ops == &js_ObjectOps || \ + (map)->ops->newObjectMap == js_ObjectOps.newObjectMap) + +#define OBJ_IS_NATIVE(obj) MAP_IS_NATIVE((obj)->map) + +extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps; +extern JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps; +extern JSClass js_ObjectClass; +extern JSClass js_WithClass; +extern JSClass js_BlockClass; + +/* + * Block scope object macros. The slots reserved by js_BlockClass are: + * + * JSSLOT_PRIVATE JSStackFrame * active frame pointer or null + * JSSLOT_BLOCK_DEPTH int depth of block slots in frame + * + * After JSSLOT_BLOCK_DEPTH come one or more slots for the block locals. + * + * A With object is like a Block object, in that both have one reserved slot + * telling the stack depth of the relevant slots (the slot whose value is the + * object named in the with statement, the slots containing the block's local + * variables); and both have a private slot referring to the JSStackFrame in + * whose activation they were created (or null if the with or block object + * outlives the frame). + */ +#define JSSLOT_BLOCK_DEPTH (JSSLOT_PRIVATE + 1) + +#define OBJ_IS_CLONED_BLOCK(obj) \ + (OBJ_SCOPE(obj)->object != (obj)) +#define OBJ_BLOCK_COUNT(cx,obj) \ + (OBJ_SCOPE(obj)->entryCount) +#define OBJ_BLOCK_DEPTH(cx,obj) \ + JSVAL_TO_INT(STOBJ_GET_SLOT(obj, JSSLOT_BLOCK_DEPTH)) +#define OBJ_SET_BLOCK_DEPTH(cx,obj,depth) \ + STOBJ_SET_SLOT(obj, JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth)) + +/* + * To make sure this slot is well-defined, always call js_NewWithObject to + * create a With object, don't call js_NewObject directly. When creating a + * With object that does not correspond to a stack slot, pass -1 for depth. + * + * When popping the stack across this object's "with" statement, client code + * must call JS_SetPrivate(cx, withobj, NULL). + */ +extern JSObject * +js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth); + +/* + * Create a new block scope object not linked to any proto or parent object. + * Blocks are created by the compiler to reify let blocks and comprehensions. + * Only when dynamic scope is captured do they need to be cloned and spliced + * into an active scope chain. + */ +extern JSObject * +js_NewBlockObject(JSContext *cx); + +extern JSObject * +js_CloneBlockObject(JSContext *cx, JSObject *proto, JSObject *parent, + JSStackFrame *fp); + +extern JSBool +js_PutBlockObject(JSContext *cx, JSBool normalUnwind); + +struct JSSharpObjectMap { + jsrefcount depth; + jsatomid sharpgen; + JSHashTable *table; +}; + +#define SHARP_BIT ((jsatomid) 1) +#define BUSY_BIT ((jsatomid) 2) +#define SHARP_ID_SHIFT 2 +#define IS_SHARP(he) (JS_PTR_TO_UINT32((he)->value) & SHARP_BIT) +#define MAKE_SHARP(he) ((he)->value = JS_UINT32_TO_PTR(JS_PTR_TO_UINT32((he)->value)|SHARP_BIT)) +#define IS_BUSY(he) (JS_PTR_TO_UINT32((he)->value) & BUSY_BIT) +#define MAKE_BUSY(he) ((he)->value = JS_UINT32_TO_PTR(JS_PTR_TO_UINT32((he)->value)|BUSY_BIT)) +#define CLEAR_BUSY(he) ((he)->value = JS_UINT32_TO_PTR(JS_PTR_TO_UINT32((he)->value)&~BUSY_BIT)) + +extern JSHashEntry * +js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, + jschar **sp); + +extern void +js_LeaveSharpObject(JSContext *cx, JSIdArray **idap); + +/* + * Mark objects stored in map if GC happens between js_EnterSharpObject + * and js_LeaveSharpObject. GC calls this when map->depth > 0. + */ +extern void +js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map); + +extern JSBool +js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc, + jsval *vp); + +extern JSBool +js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id, + jsval *vp); + +extern JSBool +js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JSObject * +js_InitBlockClass(JSContext *cx, JSObject* obj); + +extern JSObject * +js_InitEval(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitObjectClass(JSContext *cx, JSObject *obj); + +/* Select Object.prototype method names shared between jsapi.c and jsobj.c. */ +extern const char js_watch_str[]; +extern const char js_unwatch_str[]; +extern const char js_hasOwnProperty_str[]; +extern const char js_isPrototypeOf_str[]; +extern const char js_propertyIsEnumerable_str[]; +extern const char js_defineGetter_str[]; +extern const char js_defineSetter_str[]; +extern const char js_lookupGetter_str[]; +extern const char js_lookupSetter_str[]; + +extern void +js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops, + JSClass *clasp); + +extern JSObjectMap * +js_NewObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, + JSClass *clasp, JSObject *obj); + +extern void +js_DestroyObjectMap(JSContext *cx, JSObjectMap *map); + +extern JSObjectMap * +js_HoldObjectMap(JSContext *cx, JSObjectMap *map); + +extern JSObjectMap * +js_DropObjectMap(JSContext *cx, JSObjectMap *map, JSObject *obj); + +extern JSBool +js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp); + +extern JSObject * +js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent, + uintN objectSize); + +/* + * See jsapi.h, JS_NewObjectWithGivenProto. + * + * objectSize is either the explicit size for the allocated object or 0 + * indicating to use the default size based on object's class. + */ +extern JSObject * +js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent, uintN objectSize); + +/* + * Fast access to immutable standard objects (constructors and prototypes). + */ +extern JSBool +js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, + JSObject **objp); + +extern JSBool +js_SetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject *cobj); + +extern JSBool +js_FindClassObject(JSContext *cx, JSObject *start, jsid id, jsval *vp); + +extern JSObject * +js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent, uintN argc, jsval *argv); + +extern void +js_FinalizeObject(JSContext *cx, JSObject *obj); + +extern JSBool +js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp); + +extern void +js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot); + +/* JSVAL_INT_MAX as a string */ +#define JSVAL_INT_MAX_STRING "1073741823" + +#define CHECK_FOR_STRING_INDEX(id) \ + JS_BEGIN_MACRO \ + if (JSID_IS_ATOM(id)) { \ + JSAtom *atom_ = JSID_TO_ATOM(id); \ + JSString *str_ = ATOM_TO_STRING(atom_); \ + const jschar *s_ = JSFLATSTR_CHARS(str_); \ + JSBool negative_ = (*s_ == '-'); \ + if (negative_) s_++; \ + if (JS7_ISDEC(*s_)) { \ + size_t n_ = JSFLATSTR_LENGTH(str_) - negative_; \ + if (n_ <= sizeof(JSVAL_INT_MAX_STRING) - 1) \ + id = js_CheckForStringIndex(id, s_, s_ + n_, negative_); \ + } \ + } \ + JS_END_MACRO + +extern jsid +js_CheckForStringIndex(jsid id, const jschar *cp, const jschar *end, + JSBool negative); + +/* + * Find or create a property named by id in obj's scope, with the given getter + * and setter, slot, attributes, and other members. + */ +extern JSScopeProperty * +js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, + JSPropertyOp getter, JSPropertyOp setter, uint32 slot, + uintN attrs, uintN flags, intN shortid); + +/* + * Change sprop to have the given attrs, getter, and setter in scope, morphing + * it into a potentially new JSScopeProperty. Return a pointer to the changed + * or identical property. + */ +extern JSScopeProperty * +js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj, + JSScopeProperty *sprop, uintN attrs, uintN mask, + JSPropertyOp getter, JSPropertyOp setter); + +/* + * On error, return false. On success, if propp is non-null, return true with + * obj locked and with a held property in *propp; if propp is null, return true + * but release obj's lock first. Therefore all callers who pass non-null propp + * result parameters must later call OBJ_DROP_PROPERTY(cx, obj, *propp) both to + * drop the held property, and to release the lock on obj. + */ +extern JSBool +js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + JSProperty **propp); + +extern JSBool +js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + uintN flags, intN shortid, JSProperty **propp); + +/* + * Unlike js_DefineProperty, propp must be non-null. On success, and if id was + * found, return true with *objp non-null and locked, and with a held property + * stored in *propp. If successful but id was not found, return true with both + * *objp and *propp null. Therefore all callers who receive a non-null *propp + * must later call OBJ_DROP_PROPERTY(cx, *objp, *propp). + */ +extern JS_FRIEND_API(JSBool) +js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp); + +/* + * Specialized subroutine that allows caller to preset JSRESOLVE_* flags and + * returns the index along the prototype chain in which *propp was found, or + * the last index if not found, or -1 on error. + */ +extern int +js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp, JSProperty **propp); + +extern int +js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp, + JSObject **pobjp, JSProperty **propp, + JSPropCacheEntry **entryp); + +/* + * Return the index along the scope chain in which id was found, or the last + * index if not found, or -1 on error. + */ +extern JS_FRIEND_API(JSBool) +js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp, + JSProperty **propp); + +extern JSObject * +js_FindIdentifierBase(JSContext *cx, jsid id, JSPropCacheEntry *entry); + +extern JSObject * +js_FindVariableScope(JSContext *cx, JSFunction **funp); + +/* + * NB: js_NativeGet and js_NativeSet are called with the scope containing sprop + * (pobj's scope for Get, obj's for Set) locked, and on successful return, that + * scope is again locked. But on failure, both functions return false with the + * scope containing sprop unlocked. + */ +extern JSBool +js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, + JSScopeProperty *sprop, jsval *vp); + +extern JSBool +js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp); + +extern JSBool +js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, + JSPropCacheEntry **entryp); + +extern JSBool +js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JSBool +js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, + JSPropCacheEntry **entryp); + +extern JSBool +js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JSBool +js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp); + +extern JSBool +js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp); + +extern JSBool +js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval); + +extern JSBool +js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp); + +extern JSBool +js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp); + +extern void +js_TraceNativeEnumerators(JSTracer *trc); + +extern JSBool +js_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + jsval *vp, uintN *attrsp); + +extern JSBool +js_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +extern JSBool +js_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JSBool +js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); + +extern JSBool +js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj); + +extern JSBool +js_IsDelegate(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); + +extern JSBool +js_GetClassPrototype(JSContext *cx, JSObject *scope, jsid id, + JSObject **protop); + +extern JSBool +js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, + uintN attrs); + +/* + * Wrap boolean, number or string as Boolean, Number or String object. + * *vp must not be an object, null or undefined. + */ +extern JSBool +js_PrimitiveToObject(JSContext *cx, jsval *vp); + +extern JSBool +js_ValueToObject(JSContext *cx, jsval v, JSObject **objp); + +extern JSObject * +js_ValueToNonNullObject(JSContext *cx, jsval v); + +extern JSBool +js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, jsval *rval); + +extern JSBool +js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom, + uintN argc, jsval *argv, jsval *rval); + +extern JSBool +js_XDRObject(JSXDRState *xdr, JSObject **objp); + +extern void +js_TraceObject(JSTracer *trc, JSObject *obj); + +extern void +js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize); + +extern void +js_Clear(JSContext *cx, JSObject *obj); + +extern jsval +js_GetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot); + +extern JSBool +js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v); + +/* + * Precondition: obj must be locked. + */ +extern JSBool +js_ReallocSlots(JSContext *cx, JSObject *obj, uint32 nslots, + JSBool exactAllocation); + +extern JSObject * +js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller); + +extern JSBool +js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj, + JSPrincipals *principals, JSAtom *caller); + +/* Infallible -- returns its argument if there is no wrapped object. */ +extern JSObject * +js_GetWrappedObject(JSContext *cx, JSObject *obj); + +/* NB: Infallible. */ +extern const char * +js_ComputeFilename(JSContext *cx, JSStackFrame *caller, + JSPrincipals *principals, uintN *linenop); + +#ifdef DEBUG +JS_FRIEND_API(void) js_DumpChars(const jschar *s, size_t n); +JS_FRIEND_API(void) js_DumpString(JSString *str); +JS_FRIEND_API(void) js_DumpAtom(JSAtom *atom); +JS_FRIEND_API(void) js_DumpValue(jsval val); +JS_FRIEND_API(void) js_DumpId(jsid id); +JS_FRIEND_API(void) js_DumpObject(JSObject *obj); +#endif + +JS_END_EXTERN_C + +#endif /* jsobj_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/json.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/json.cpp new file mode 100644 index 0000000..e6cd28a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/json.cpp @@ -0,0 +1,954 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey JSON. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Sayre + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "jsapi.h" +#include "jsarena.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsdtoa.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsprf.h" +#include "jsscan.h" +#include "jsstr.h" +#include "jstypes.h" +#include "jsutil.h" + +#include "json.h" + +JSClass js_JSONClass = { + js_JSON_str, + JSCLASS_HAS_CACHED_PROTO(JSProto_JSON), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +JSBool +js_json_parse(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *s = NULL; + jsval *argv = vp + 2; + + // Must throw an Error if there isn't a first arg + if (!JS_ConvertArguments(cx, argc, argv, "S", &s)) + return JS_FALSE; + + + JSONParser *jp = js_BeginJSONParse(cx, vp); + JSBool ok = jp != NULL; + + if (ok) { + ok = js_ConsumeJSONText(cx, jp, JS_GetStringChars(s), JS_GetStringLength(s)); + ok &= js_FinishJSONParse(cx, jp); + } + + if (!ok) + JS_ReportError(cx, "Error parsing JSON"); + + return ok; +} + +class StringifyClosure : JSAutoTempValueRooter +{ +public: + StringifyClosure(JSContext *cx, size_t len, jsval *vec) + : JSAutoTempValueRooter(cx, len, vec), cx(cx), s(vec) + { + } + + JSContext *cx; + jsval *s; +}; + +static JSBool +WriteCallback(const jschar *buf, uint32 len, void *data) +{ + StringifyClosure *sc = static_cast(data); + JSString *s1 = JSVAL_TO_STRING(sc->s[0]); + JSString *s2 = js_NewStringCopyN(sc->cx, buf, len); + if (!s2) + return JS_FALSE; + + sc->s[1] = STRING_TO_JSVAL(s2); + + s1 = js_ConcatStrings(sc->cx, s1, s2); + if (!s1) + return JS_FALSE; + + sc->s[0] = STRING_TO_JSVAL(s1); + sc->s[1] = JSVAL_VOID; + + return JS_TRUE; +} + +JSBool +js_json_stringify(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + jsval *argv = vp + 2; + + // Must throw an Error if there isn't a first arg + if (!JS_ConvertArguments(cx, argc, argv, "o", &obj)) + return JS_FALSE; + + // Only use objects and arrays as the root for now + *vp = OBJECT_TO_JSVAL(obj); + + JSBool ok = js_TryJSON(cx, vp); + JSType type; + if (!ok || + JSVAL_IS_PRIMITIVE(*vp) || + ((type = JS_TypeOfValue(cx, *vp)) == JSTYPE_FUNCTION || + type == JSTYPE_XML)) { + JS_ReportError(cx, "Invalid argument"); + return JS_FALSE; + } + + JSString *s = JS_NewStringCopyN(cx, "", 0); + if (!s) + ok = JS_FALSE; + + if (ok) { + jsval vec[2] = {STRING_TO_JSVAL(s), JSVAL_VOID}; + StringifyClosure sc(cx, 2, vec); + JSAutoTempValueRooter resultTvr(cx, 1, sc.s); + ok = js_Stringify(cx, vp, NULL, &WriteCallback, &sc, 0); + *vp = *sc.s; + } + + return ok; +} + +JSBool +js_TryJSON(JSContext *cx, jsval *vp) +{ + // Checks whether the return value implements toJSON() + JSBool ok = JS_TRUE; + + if (!JSVAL_IS_PRIMITIVE(*vp)) { + JSObject *obj = JSVAL_TO_OBJECT(*vp); + ok = js_TryMethod(cx, obj, cx->runtime->atomState.toJSONAtom, 0, NULL, vp); + } + + return ok; +} + + +static const jschar quote = jschar('"'); +static const jschar backslash = jschar('\\'); +static const jschar unicodeEscape[] = {'\\', 'u', '0', '0'}; + +static JSBool +write_string(JSContext *cx, JSONWriteCallback callback, void *data, const jschar *buf, uint32 len) +{ + if (!callback("e, 1, data)) + return JS_FALSE; + + uint32 mark = 0; + uint32 i; + for (i = 0; i < len; ++i) { + if (buf[i] == quote || buf[i] == backslash) { + if (!callback(&buf[mark], i - mark, data) || !callback(&backslash, 1, data) || + !callback(&buf[i], 1, data)) { + return JS_FALSE; + } + mark = i + 1; + } else if (buf[i] <= 31 || buf[i] == 127) { + if (!callback(&buf[mark], i - mark, data) || !callback(unicodeEscape, 4, data)) + return JS_FALSE; + char ubuf[3]; + size_t len = JS_snprintf(ubuf, sizeof(ubuf), "%.2x", buf[i]); + JS_ASSERT(len == 2); + jschar wbuf[3]; + size_t wbufSize = JS_ARRAY_LENGTH(wbuf); + if (!js_InflateStringToBuffer(cx, ubuf, len, wbuf, &wbufSize) || + !callback(wbuf, wbufSize, data)) { + return JS_FALSE; + } + mark = i + 1; + } + } + + if (mark < len && !callback(&buf[mark], len - mark, data)) + return JS_FALSE; + + if (!callback("e, 1, data)) + return JS_FALSE; + + return JS_TRUE; +} + +JSBool +js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, + JSONWriteCallback callback, void *data, uint32 depth) +{ + if (depth > JSON_MAX_DEPTH) + return JS_FALSE; /* encoding error */ + + JSBool ok = JS_TRUE; + JSObject *obj = JSVAL_TO_OBJECT(*vp); + JSBool isArray = JS_IsArrayObject(cx, obj); + jschar output = jschar(isArray ? '[' : '{'); + if (!callback(&output, 1, data)) + return JS_FALSE; + + JSObject *iterObj = NULL; + jsint i = 0; + jsuint length = 0; + + if (isArray) { + if (!js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + } else { + if (!js_ValueToIterator(cx, JSITER_ENUMERATE, vp)) + return JS_FALSE; + iterObj = JSVAL_TO_OBJECT(*vp); + } + + jsval outputValue = JSVAL_VOID; + JSAutoTempValueRooter tvr(cx, 1, &outputValue); + + jsval key; + JSBool memberWritten = JS_FALSE; + do { + outputValue = JSVAL_VOID; + + if (isArray) { + if ((jsuint)i >= length) + break; + ok = OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(i), &outputValue); + i++; + } else { + ok = js_CallIteratorNext(cx, iterObj, &key); + if (!ok) + break; + if (key == JSVAL_HOLE) + break; + + JSString *ks; + if (JSVAL_IS_STRING(key)) { + ks = JSVAL_TO_STRING(key); + } else { + ks = js_ValueToString(cx, key); + if (!ks) { + ok = JS_FALSE; + break; + } + } + + ok = JS_GetUCProperty(cx, obj, JS_GetStringChars(ks), + JS_GetStringLength(ks), &outputValue); + } + + if (!ok) + break; + + // if this is an array, holes are transmitted as null + if (isArray && outputValue == JSVAL_VOID) { + outputValue = JSVAL_NULL; + } else if (JSVAL_IS_OBJECT(outputValue)) { + ok = js_TryJSON(cx, &outputValue); + if (!ok) + break; + } + + // elide undefined values + if (outputValue == JSVAL_VOID) + continue; + + // output a comma unless this is the first member to write + if (memberWritten) { + output = jschar(','); + ok = callback(&output, 1, data); + if (!ok) + break; + } + memberWritten = JS_TRUE; + + JSType type = JS_TypeOfValue(cx, outputValue); + + // Can't encode these types, so drop them + if (type == JSTYPE_FUNCTION || type == JSTYPE_XML) + break; + + // Be careful below, this string is weakly rooted. + JSString *s; + + // If this isn't an array, we need to output a key + if (!isArray) { + s = js_ValueToString(cx, key); + if (!s) { + ok = JS_FALSE; + break; + } + + ok = write_string(cx, callback, data, JS_GetStringChars(s), JS_GetStringLength(s)); + if (!ok) + break; + + output = jschar(':'); + ok = callback(&output, 1, data); + if (!ok) + break; + } + + if (!JSVAL_IS_PRIMITIVE(outputValue)) { + // recurse + ok = js_Stringify(cx, &outputValue, replacer, callback, data, depth + 1); + } else { + JSString *outputString; + s = js_ValueToString(cx, outputValue); + if (!s) { + ok = JS_FALSE; + break; + } + + if (type == JSTYPE_STRING) { + ok = write_string(cx, callback, data, JS_GetStringChars(s), JS_GetStringLength(s)); + if (!ok) + break; + + continue; + } + + if (type == JSTYPE_NUMBER) { + if (JSVAL_IS_DOUBLE(outputValue)) { + jsdouble d = *JSVAL_TO_DOUBLE(outputValue); + if (!JSDOUBLE_IS_FINITE(d)) + outputString = JS_NewStringCopyN(cx, "null", 4); + else + outputString = s; + } else { + outputString = s; + } + } else if (type == JSTYPE_BOOLEAN) { + outputString = s; + } else if (JSVAL_IS_NULL(outputValue)) { + outputString = JS_NewStringCopyN(cx, "null", 4); + } else { + ok = JS_FALSE; // encoding error + break; + } + + if (!outputString) { + ok = JS_FALSE; + break; + } + + ok = callback(JS_GetStringChars(outputString), JS_GetStringLength(outputString), data); + } + } while (ok); + + if (iterObj) { + // Always close the iterator, but make sure not to stomp on OK + ok &= js_CloseIterator(cx, *vp); + // encoding error or propagate? FIXME: Bug 408838. + } + + if (!ok) { + JS_ReportError(cx, "Error during JSON encoding"); + return JS_FALSE; + } + + output = jschar(isArray ? ']' : '}'); + ok = callback(&output, 1, data); + + return ok; +} + +// helper to determine whether a character could be part of a number +static JSBool IsNumChar(jschar c) +{ + return ((c <= '9' && c >= '0') || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E'); +} + +JSONParser * +js_BeginJSONParse(JSContext *cx, jsval *rootVal) +{ + if (!cx) + return NULL; + + JSObject *arr = js_NewArrayObject(cx, 0, NULL); + if (!arr) + return NULL; + + JSONParser *jp = (JSONParser*) JS_malloc(cx, sizeof(JSONParser)); + if (!jp) + return NULL; + jp->buffer = NULL; + + jp->objectStack = arr; + if (!js_AddRoot(cx, &jp->objectStack, "JSON parse stack")) + goto bad; + + jp->hexChar = 0; + jp->numHex = 0; + jp->statep = jp->stateStack; + *jp->statep = JSON_PARSE_STATE_INIT; + jp->rootVal = rootVal; + + jp->objectKey = (JSStringBuffer*) JS_malloc(cx, sizeof(JSStringBuffer)); + if (!jp->objectKey) + goto bad; + js_InitStringBuffer(jp->objectKey); + + jp->buffer = (JSStringBuffer*) JS_malloc(cx, sizeof(JSStringBuffer)); + if (!jp->buffer) + goto bad; + js_InitStringBuffer(jp->buffer); + + return jp; +bad: + JS_free(cx, jp->buffer); + JS_free(cx, jp); + return NULL; +} + +JSBool +js_FinishJSONParse(JSContext *cx, JSONParser *jp) +{ + if (!jp) + return JS_TRUE; + + if (jp->objectKey) + js_FinishStringBuffer(jp->objectKey); + JS_free(cx, jp->objectKey); + + if (jp->buffer) + js_FinishStringBuffer(jp->buffer); + JS_free(cx, jp->buffer); + + if (!js_RemoveRoot(cx->runtime, &jp->objectStack)) + return JS_FALSE; + JSBool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; + JS_free(cx, jp); + + return ok; +} + +static JSBool +PushState(JSONParser *jp, JSONParserState state) +{ + if (*jp->statep == JSON_PARSE_STATE_FINISHED) + return JS_FALSE; // extra input + + jp->statep++; + if ((uint32)(jp->statep - jp->stateStack) >= JS_ARRAY_LENGTH(jp->stateStack)) + return JS_FALSE; // too deep + + *jp->statep = state; + + return JS_TRUE; +} + +static JSBool +PopState(JSONParser *jp) +{ + jp->statep--; + if (jp->statep < jp->stateStack) { + jp->statep = jp->stateStack; + return JS_FALSE; + } + + if (*jp->statep == JSON_PARSE_STATE_INIT) + *jp->statep = JSON_PARSE_STATE_FINISHED; + + return JS_TRUE; +} + +static JSBool +PushValue(JSContext *cx, JSONParser *jp, JSObject *parent, jsval value) +{ + JSAutoTempValueRooter tvr(cx, 1, &value); + + JSBool ok; + if (OBJ_IS_ARRAY(cx, parent)) { + jsuint len; + ok = js_GetLengthProperty(cx, parent, &len); + if (ok) { + ok = OBJ_DEFINE_PROPERTY(cx, parent, INT_TO_JSID(len), value, + NULL, NULL, JSPROP_ENUMERATE, NULL); + } + } else { + ok = JS_DefineUCProperty(cx, parent, jp->objectKey->base, + STRING_BUFFER_OFFSET(jp->objectKey), value, + NULL, NULL, JSPROP_ENUMERATE); + js_FinishStringBuffer(jp->objectKey); + js_InitStringBuffer(jp->objectKey); + } + + return ok; +} + +static JSBool +PushObject(JSContext *cx, JSONParser *jp, JSObject *obj) +{ + jsuint len; + if (!js_GetLengthProperty(cx, jp->objectStack, &len)) + return JS_FALSE; + if (len >= JSON_MAX_DEPTH) + return JS_FALSE; // decoding error + + jsval v = OBJECT_TO_JSVAL(obj); + JSAutoTempValueRooter tvr(cx, v); + + // Check if this is the root object + if (len == 0) { + *jp->rootVal = v; + // This property must be enumerable to keep the array dense + if (!OBJ_DEFINE_PROPERTY(cx, jp->objectStack, INT_TO_JSID(0), *jp->rootVal, + NULL, NULL, JSPROP_ENUMERATE, NULL)) { + return JS_FALSE; + } + return JS_TRUE; + } + + jsval p; + if (!OBJ_GET_PROPERTY(cx, jp->objectStack, INT_TO_JSID(len - 1), &p)) + return JS_FALSE; + + JS_ASSERT(JSVAL_IS_OBJECT(p)); + JSObject *parent = JSVAL_TO_OBJECT(p); + if (!PushValue(cx, jp, parent, OBJECT_TO_JSVAL(obj))) + return JS_FALSE; + + // This property must be enumerable to keep the array dense + if (!OBJ_DEFINE_PROPERTY(cx, jp->objectStack, INT_TO_JSID(len), v, + NULL, NULL, JSPROP_ENUMERATE, NULL)) { + return JS_FALSE; + } + + return JS_TRUE; +} + +static JSObject * +GetTopOfObjectStack(JSContext *cx, JSONParser *jp) +{ + jsuint length; + if (!js_GetLengthProperty(cx, jp->objectStack, &length)) + return NULL; + + jsval o; + if (!OBJ_GET_PROPERTY(cx, jp->objectStack, INT_TO_JSID(length - 1), &o)) + return NULL; + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(o)); + return JSVAL_TO_OBJECT(o); +} + +static JSBool +OpenObject(JSContext *cx, JSONParser *jp) +{ + JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + + return PushObject(cx, jp, obj); +} + +static JSBool +OpenArray(JSContext *cx, JSONParser *jp) +{ + // Add an array to an existing array or object + JSObject *arr = js_NewArrayObject(cx, 0, NULL); + if (!arr) + return JS_FALSE; + + return PushObject(cx, jp, arr); +} + +static JSBool +CloseObject(JSContext *cx, JSONParser *jp) +{ + jsuint len; + if (!js_GetLengthProperty(cx, jp->objectStack, &len)) + return JS_FALSE; + if (!js_SetLengthProperty(cx, jp->objectStack, len - 1)) + return JS_FALSE; + + return JS_TRUE; +} + +static JSBool +CloseArray(JSContext *cx, JSONParser *jp) +{ + return CloseObject(cx, jp); +} + +static JSBool +HandleNumber(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) +{ + const jschar *ep; + double val; + if (!js_strtod(cx, buf, buf + len, &ep, &val) || ep != buf + len) + return JS_FALSE; + + JSBool ok; + jsval numVal; + JSObject *obj = GetTopOfObjectStack(cx, jp); + if (obj && JS_NewNumberValue(cx, val, &numVal)) + ok = PushValue(cx, jp, obj, numVal); + else + ok = JS_FALSE; // decode error + + return ok; +} + +static JSBool +HandleString(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) +{ + JSObject *obj = GetTopOfObjectStack(cx, jp); + JSString *str = js_NewStringCopyN(cx, buf, len); + if (!obj || !str) + return JS_FALSE; + + return PushValue(cx, jp, obj, STRING_TO_JSVAL(str)); +} + +static JSBool +HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) +{ + jsval keyword; + JSTokenType tt = js_CheckKeyword(buf, len); + if (tt != TOK_PRIMARY) + return JS_FALSE; + + if (buf[0] == 'n') + keyword = JSVAL_NULL; + else if (buf[0] == 't') + keyword = JSVAL_TRUE; + else if (buf[0] == 'f') + keyword = JSVAL_FALSE; + else + return JS_FALSE; + + JSObject *obj = GetTopOfObjectStack(cx, jp); + if (!obj) + return JS_FALSE; + + return PushValue(cx, jp, obj, keyword); +} + +static JSBool +HandleData(JSContext *cx, JSONParser *jp, JSONDataType type) +{ + JSBool ok = JS_FALSE; + + if (!STRING_BUFFER_OK(jp->buffer)) + return JS_FALSE; + + switch (type) { + case JSON_DATA_STRING: + ok = HandleString(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)); + break; + + case JSON_DATA_KEYSTRING: + js_AppendUCString(jp->objectKey, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)); + ok = STRING_BUFFER_OK(jp->objectKey); + break; + + case JSON_DATA_NUMBER: + ok = HandleNumber(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)); + break; + + case JSON_DATA_KEYWORD: + ok = HandleKeyword(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)); + break; + + default: + JS_NOT_REACHED("Should have a JSON data type"); + } + + js_FinishStringBuffer(jp->buffer); + js_InitStringBuffer(jp->buffer); + + return ok; +} + +JSBool +js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len) +{ + uint32 i; + + if (*jp->statep == JSON_PARSE_STATE_INIT) { + PushState(jp, JSON_PARSE_STATE_OBJECT_VALUE); + } + + for (i = 0; i < len; i++) { + jschar c = data[i]; + switch (*jp->statep) { + case JSON_PARSE_STATE_VALUE : + if (c == ']') { + // empty array + if (!PopState(jp)) + return JS_FALSE; + if (*jp->statep != JSON_PARSE_STATE_ARRAY) + return JS_FALSE; // unexpected char + if (!CloseArray(cx, jp) || !PopState(jp)) + return JS_FALSE; + break; + } + + if (c == '}') { + // we should only find these in OBJECT_KEY state + return JS_FALSE; // unexpected failure + } + + if (c == '"') { + *jp->statep = JSON_PARSE_STATE_STRING; + break; + } + + if (IsNumChar(c)) { + *jp->statep = JSON_PARSE_STATE_NUMBER; + js_AppendChar(jp->buffer, c); + break; + } + + if (JS7_ISLET(c)) { + *jp->statep = JSON_PARSE_STATE_KEYWORD; + js_AppendChar(jp->buffer, c); + break; + } + + // fall through in case the value is an object or array + case JSON_PARSE_STATE_OBJECT_VALUE : + if (c == '{') { + *jp->statep = JSON_PARSE_STATE_OBJECT; + if (!OpenObject(cx, jp) || !PushState(jp, JSON_PARSE_STATE_OBJECT_PAIR)) + return JS_FALSE; + } else if (c == '[') { + *jp->statep = JSON_PARSE_STATE_ARRAY; + if (!OpenArray(cx, jp) || !PushState(jp, JSON_PARSE_STATE_VALUE)) + return JS_FALSE; + } else if (!JS_ISXMLSPACE(c)) { + return JS_FALSE; // unexpected + } + break; + + case JSON_PARSE_STATE_OBJECT : + if (c == '}') { + if (!CloseObject(cx, jp) || !PopState(jp)) + return JS_FALSE; + } else if (c == ',') { + if (!PushState(jp, JSON_PARSE_STATE_OBJECT_PAIR)) + return JS_FALSE; + } else if (c == ']' || !JS_ISXMLSPACE(c)) { + return JS_FALSE; // unexpected + } + break; + + case JSON_PARSE_STATE_ARRAY : + if (c == ']') { + if (!CloseArray(cx, jp) || !PopState(jp)) + return JS_FALSE; + } else if (c == ',') { + if (!PushState(jp, JSON_PARSE_STATE_VALUE)) + return JS_FALSE; + } else if (!JS_ISXMLSPACE(c)) { + return JS_FALSE; // unexpected + } + break; + + case JSON_PARSE_STATE_OBJECT_PAIR : + if (c == '"') { + // we want to be waiting for a : when the string has been read + *jp->statep = JSON_PARSE_STATE_OBJECT_IN_PAIR; + if (!PushState(jp, JSON_PARSE_STATE_STRING)) + return JS_FALSE; + } else if (c == '}') { + // pop off the object pair state and the object state + if (!CloseObject(cx, jp) || !PopState(jp) || !PopState(jp)) + return JS_FALSE; + } else if (c == ']' || !JS_ISXMLSPACE(c)) { + return JS_FALSE; // unexpected + } + break; + + case JSON_PARSE_STATE_OBJECT_IN_PAIR: + if (c == ':') { + *jp->statep = JSON_PARSE_STATE_VALUE; + } else if (!JS_ISXMLSPACE(c)) { + return JS_FALSE; // unexpected + } + break; + + case JSON_PARSE_STATE_STRING: + if (c == '"') { + if (!PopState(jp)) + return JS_FALSE; + JSONDataType jdt; + if (*jp->statep == JSON_PARSE_STATE_OBJECT_IN_PAIR) { + jdt = JSON_DATA_KEYSTRING; + } else { + jdt = JSON_DATA_STRING; + } + if (!HandleData(cx, jp, jdt)) + return JS_FALSE; + } else if (c == '\\') { + *jp->statep = JSON_PARSE_STATE_STRING_ESCAPE; + } else { + js_AppendChar(jp->buffer, c); + } + break; + + case JSON_PARSE_STATE_STRING_ESCAPE: + switch (c) { + case '"': + case '\\': + case '/': + break; + case 'b' : c = '\b'; break; + case 'f' : c = '\f'; break; + case 'n' : c = '\n'; break; + case 'r' : c = '\r'; break; + case 't' : c = '\t'; break; + default : + if (c == 'u') { + jp->numHex = 0; + jp->hexChar = 0; + *jp->statep = JSON_PARSE_STATE_STRING_HEX; + continue; + } else { + return JS_FALSE; // unexpected + } + } + + js_AppendChar(jp->buffer, c); + *jp->statep = JSON_PARSE_STATE_STRING; + break; + + case JSON_PARSE_STATE_STRING_HEX: + if (('0' <= c) && (c <= '9')) + jp->hexChar = (jp->hexChar << 4) | (c - '0'); + else if (('a' <= c) && (c <= 'f')) + jp->hexChar = (jp->hexChar << 4) | (c - 'a' + 0x0a); + else if (('A' <= c) && (c <= 'F')) + jp->hexChar = (jp->hexChar << 4) | (c - 'A' + 0x0a); + else + return JS_FALSE; // unexpected + + if (++(jp->numHex) == 4) { + js_AppendChar(jp->buffer, jp->hexChar); + jp->hexChar = 0; + jp->numHex = 0; + *jp->statep = JSON_PARSE_STATE_STRING; + } + break; + + case JSON_PARSE_STATE_KEYWORD: + if (JS7_ISLET(c)) { + js_AppendChar(jp->buffer, c); + } else { + // this character isn't part of the keyword, process it again + i--; + if (!PopState(jp)) + return JS_FALSE; + + if (!HandleData(cx, jp, JSON_DATA_KEYWORD)) + return JS_FALSE; + } + break; + + case JSON_PARSE_STATE_NUMBER: + if (IsNumChar(c)) { + js_AppendChar(jp->buffer, c); + } else { + // this character isn't part of the number, process it again + i--; + if (!PopState(jp)) + return JS_FALSE; + if (!HandleData(cx, jp, JSON_DATA_NUMBER)) + return JS_FALSE; + } + break; + + case JSON_PARSE_STATE_FINISHED: + if (!JS_ISXMLSPACE(c)) + return JS_FALSE; // extra input + + break; + + default: + JS_NOT_REACHED("Invalid JSON parser state"); + } + } + + return JS_TRUE; +} + +#if JS_HAS_TOSOURCE +static JSBool +json_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + *vp = ATOM_KEY(CLASS_ATOM(cx, JSON)); + return JS_TRUE; +} +#endif + +static JSFunctionSpec json_static_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, json_toSource, 0, 0), +#endif + JS_FN("parse", js_json_parse, 0, 0), + JS_FN("stringify", js_json_stringify, 0, 0), + JS_FS_END +}; + +JSObject * +js_InitJSONClass(JSContext *cx, JSObject *obj) +{ + JSObject *JSON; + + JSON = JS_NewObject(cx, &js_JSONClass, NULL, obj); + if (!JSON) + return NULL; + if (!JS_DefineProperty(cx, obj, js_JSON_str, OBJECT_TO_JSVAL(JSON), + JS_PropertyStub, JS_PropertyStub, 0)) + return NULL; + + if (!JS_DefineFunctions(cx, JSON, json_static_methods)) + return NULL; + + return JSON; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/json.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/json.h new file mode 100644 index 0000000..b2fc729 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/json.h @@ -0,0 +1,107 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey JSON. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Sayre + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef json_h___ +#define json_h___ +/* + * JS JSON functions. + */ + +#define JSON_MAX_DEPTH 2048 +#define JSON_PARSER_BUFSIZE 1024 + +JS_BEGIN_EXTERN_C + +extern JSClass js_JSONClass; + +extern JSObject * +js_InitJSONClass(JSContext *cx, JSObject *obj); + +extern JSBool +js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, + JSONWriteCallback callback, void *data, uint32 depth); + +extern JSBool js_TryJSON(JSContext *cx, jsval *vp); + +enum JSONParserState { + JSON_PARSE_STATE_INIT, + JSON_PARSE_STATE_OBJECT_VALUE, + JSON_PARSE_STATE_VALUE, + JSON_PARSE_STATE_OBJECT, + JSON_PARSE_STATE_OBJECT_PAIR, + JSON_PARSE_STATE_OBJECT_IN_PAIR, + JSON_PARSE_STATE_ARRAY, + JSON_PARSE_STATE_STRING, + JSON_PARSE_STATE_STRING_ESCAPE, + JSON_PARSE_STATE_STRING_HEX, + JSON_PARSE_STATE_NUMBER, + JSON_PARSE_STATE_KEYWORD, + JSON_PARSE_STATE_FINISHED +}; + +enum JSONDataType { + JSON_DATA_STRING, + JSON_DATA_KEYSTRING, + JSON_DATA_NUMBER, + JSON_DATA_KEYWORD +}; + +struct JSONParser { + /* Used while handling \uNNNN in strings */ + jschar hexChar; + uint8 numHex; + + JSONParserState *statep; + JSONParserState stateStack[JSON_MAX_DEPTH]; + jsval *rootVal; + JSStringBuffer *objectKey; + JSStringBuffer *buffer; + JSObject *objectStack; +}; + +extern JSONParser * +js_BeginJSONParse(JSContext *cx, jsval *rootVal); + +extern JSBool +js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len); + +extern JSBool +js_FinishJSONParse(JSContext *cx, JSONParser *jp); + +JS_END_EXTERN_C + +#endif /* json_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.cpp new file mode 100644 index 0000000..a3227dc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.cpp @@ -0,0 +1,5304 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS bytecode descriptors, disassemblers, and decompilers. + */ +#include "jsstddef.h" +#ifdef HAVE_MEMORY_H +#include +#endif +#include +#include +#include +#include +#include "jstypes.h" +#include "jsarena.h" /* Added by JSIFY */ +#include "jsutil.h" /* Added by JSIFY */ +#include "jsdtoa.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsiter.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsregexp.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsstaticcheck.h" +#include "jstracer.h" + +#include "jsautooplen.h" + +/* Verify JSOP_XXX_LENGTH constant definitions. */ +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + JS_STATIC_ASSERT(op##_LENGTH == length); +#include "jsopcode.tbl" +#undef OPDEF + +static const char js_incop_strs[][3] = {"++", "--"}; +static const char js_for_each_str[] = "for each"; + +const JSCodeSpec js_CodeSpec[] = { +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + {length,nuses,ndefs,prec,format}, +#include "jsopcode.tbl" +#undef OPDEF +}; + +uintN js_NumCodeSpecs = JS_ARRAY_LENGTH(js_CodeSpec); + +/* + * Each element of the array is either a source literal associated with JS + * bytecode or null. + */ +static const char *CodeToken[] = { +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + token, +#include "jsopcode.tbl" +#undef OPDEF +}; + +#if defined(DEBUG) || defined(JS_JIT_SPEW) +/* + * Array of JS bytecode names used by DEBUG-only js_Disassemble and by + * JIT debug spew. + */ +const char *js_CodeName[] = { +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + name, +#include "jsopcode.tbl" +#undef OPDEF +}; +#endif + +/************************************************************************/ + +static ptrdiff_t +GetJumpOffset(jsbytecode *pc, jsbytecode *pc2) +{ + uint32 type; + + type = JOF_OPTYPE(*pc); + if (JOF_TYPE_IS_EXTENDED_JUMP(type)) + return GET_JUMPX_OFFSET(pc2); + return GET_JUMP_OFFSET(pc2); +} + +uintN +js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, + ptrdiff_t pcoff) +{ + JSOp op; + uintN span, base; + + op = (JSOp)*pc; + if (op == JSOP_TRAP) + op = JS_GetTrapOpcode(cx, script, pc); + JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN); + + /* + * We need to detect index base prefix. It presents when resetbase + * follows the bytecode. + */ + span = js_CodeSpec[op].length; + base = 0; + if (pc - script->code + span < script->length) { + if (pc[span] == JSOP_RESETBASE) { + base = GET_INDEXBASE(pc - JSOP_INDEXBASE_LENGTH); + } else if (pc[span] == JSOP_RESETBASE0) { + JS_ASSERT(JSOP_INDEXBASE1 <= pc[-1] || pc[-1] <= JSOP_INDEXBASE3); + base = (pc[-1] - JSOP_INDEXBASE1 + 1) << 16; + } + } + return base + GET_UINT16(pc + pcoff); +} + +uintN +js_GetVariableBytecodeLength(jsbytecode *pc) +{ + JSOp op; + uintN jmplen, ncases; + jsint low, high; + + op = (JSOp) *pc; + JS_ASSERT(js_CodeSpec[op].length == -1); + switch (op) { + case JSOP_TABLESWITCHX: + jmplen = JUMPX_OFFSET_LEN; + goto do_table; + case JSOP_TABLESWITCH: + jmplen = JUMP_OFFSET_LEN; + do_table: + /* Structure: default-jump case-low case-high case1-jump ... */ + pc += jmplen; + low = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc); + ncases = (uintN)(high - low + 1); + return 1 + jmplen + INDEX_LEN + INDEX_LEN + ncases * jmplen; + + case JSOP_LOOKUPSWITCHX: + jmplen = JUMPX_OFFSET_LEN; + goto do_lookup; + default: + JS_ASSERT(op == JSOP_LOOKUPSWITCH); + jmplen = JUMP_OFFSET_LEN; + do_lookup: + /* Structure: default-jump case-count (case1-value case1-jump) ... */ + pc += jmplen; + ncases = GET_UINT16(pc); + return 1 + jmplen + INDEX_LEN + ncases * (INDEX_LEN + jmplen); + } +} + +uintN +js_GetVariableStackUseLength(JSOp op, jsbytecode *pc) +{ + JS_ASSERT(*pc == op || *pc == JSOP_TRAP); + JS_ASSERT(js_CodeSpec[op].nuses == -1); + switch (op) { + case JSOP_POPN: + return GET_UINT16(pc); + case JSOP_LEAVEBLOCK: + return GET_UINT16(pc); + case JSOP_LEAVEBLOCKEXPR: + return GET_UINT16(pc) + 1; + case JSOP_NEWARRAY: + return GET_UINT24(pc); + default: + /* stack: fun, this, [argc arguments] */ + JS_ASSERT(op == JSOP_NEW || op == JSOP_CALL || + op == JSOP_EVAL || op == JSOP_SETCALL || + op == JSOP_APPLY); + return 2 + GET_ARGC(pc); + } +} + +#ifdef DEBUG + +JS_FRIEND_API(JSBool) +js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp) +{ + jsbytecode *pc, *end; + uintN len; + + pc = script->code; + end = pc + script->length; + while (pc < end) { + if (pc == script->main) + fputs("main:\n", fp); + len = js_Disassemble1(cx, script, pc, + PTRDIFF(pc, script->code, jsbytecode), + lines, fp); + if (!len) + return JS_FALSE; + pc += len; + } + return JS_TRUE; +} + +const char * +ToDisassemblySource(JSContext *cx, jsval v) +{ + JSObject *obj; + JSScopeProperty *sprop; + char *source; + const char *bytes; + JSString *str; + + if (!JSVAL_IS_PRIMITIVE(v)) { + obj = JSVAL_TO_OBJECT(v); + if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) { + source = JS_sprintf_append(NULL, "depth %d {", + OBJ_BLOCK_DEPTH(cx, obj)); + for (sprop = OBJ_SCOPE(obj)->lastProp; sprop; + sprop = sprop->parent) { + bytes = js_AtomToPrintableString(cx, JSID_TO_ATOM(sprop->id)); + if (!bytes) + return NULL; + source = JS_sprintf_append(source, "%s: %d%s", + bytes, sprop->shortid, + sprop->parent ? ", " : ""); + } + source = JS_sprintf_append(source, "}"); + if (!source) + return NULL; + str = JS_NewString(cx, source, strlen(source)); + if (!str) + return NULL; + return js_GetStringBytes(cx, str); + } + } + return js_ValueToPrintableSource(cx, v); +} + +JS_FRIEND_API(uintN) +js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, + uintN loc, JSBool lines, FILE *fp) +{ + JSOp op; + const JSCodeSpec *cs; + ptrdiff_t len, off, jmplen; + uint32 type; + JSAtom *atom; + uintN index; + JSObject *obj; + jsval v; + const char *bytes; + jsint i; + + op = (JSOp)*pc; + if (op >= JSOP_LIMIT) { + char numBuf1[12], numBuf2[12]; + JS_snprintf(numBuf1, sizeof numBuf1, "%d", op); + JS_snprintf(numBuf2, sizeof numBuf2, "%d", JSOP_LIMIT); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BYTECODE_TOO_BIG, numBuf1, numBuf2); + return 0; + } + cs = &js_CodeSpec[op]; + len = (ptrdiff_t) cs->length; + fprintf(fp, "%05u:", loc); + if (lines) + fprintf(fp, "%4u", JS_PCToLineNumber(cx, script, pc)); + fprintf(fp, " %s", js_CodeName[op]); + type = JOF_TYPE(cs->format); + switch (type) { + case JOF_BYTE: + if (op == JSOP_TRAP) { + op = JS_GetTrapOpcode(cx, script, pc); + len = (ptrdiff_t) js_CodeSpec[op].length; + } + break; + + case JOF_JUMP: + case JOF_JUMPX: + off = GetJumpOffset(pc, pc); + fprintf(fp, " %u (%d)", loc + (intN) off, (intN) off); + break; + + case JOF_ATOM: + case JOF_OBJECT: + case JOF_REGEXP: + index = js_GetIndexFromBytecode(cx, script, pc, 0); + if (type == JOF_ATOM) { + JS_GET_SCRIPT_ATOM(script, index, atom); + v = ATOM_KEY(atom); + } else { + if (type == JOF_OBJECT) + JS_GET_SCRIPT_OBJECT(script, index, obj); + else + JS_GET_SCRIPT_REGEXP(script, index, obj); + v = OBJECT_TO_JSVAL(obj); + } + bytes = ToDisassemblySource(cx, v); + if (!bytes) + return 0; + fprintf(fp, " %s", bytes); + break; + + case JOF_UINT16: + i = (jsint)GET_UINT16(pc); + goto print_int; + + case JOF_TABLESWITCH: + case JOF_TABLESWITCHX: + { + jsbytecode *pc2; + jsint i, low, high; + + jmplen = (type == JOF_TABLESWITCH) ? JUMP_OFFSET_LEN + : JUMPX_OFFSET_LEN; + pc2 = pc; + off = GetJumpOffset(pc, pc2); + pc2 += jmplen; + low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + fprintf(fp, " defaultOffset %d low %d high %d", (intN) off, low, high); + for (i = low; i <= high; i++) { + off = GetJumpOffset(pc, pc2); + fprintf(fp, "\n\t%d: %d", i, (intN) off); + pc2 += jmplen; + } + len = 1 + pc2 - pc; + break; + } + + case JOF_LOOKUPSWITCH: + case JOF_LOOKUPSWITCHX: + { + jsbytecode *pc2; + jsatomid npairs; + + jmplen = (type == JOF_LOOKUPSWITCH) ? JUMP_OFFSET_LEN + : JUMPX_OFFSET_LEN; + pc2 = pc; + off = GetJumpOffset(pc, pc2); + pc2 += jmplen; + npairs = GET_UINT16(pc2); + pc2 += UINT16_LEN; + fprintf(fp, " offset %d npairs %u", (intN) off, (uintN) npairs); + while (npairs) { + JS_GET_SCRIPT_ATOM(script, GET_INDEX(pc2), atom); + pc2 += INDEX_LEN; + off = GetJumpOffset(pc, pc2); + pc2 += jmplen; + + bytes = ToDisassemblySource(cx, ATOM_KEY(atom)); + if (!bytes) + return 0; + fprintf(fp, "\n\t%s: %d", bytes, (intN) off); + npairs--; + } + len = 1 + pc2 - pc; + break; + } + + case JOF_QARG: + fprintf(fp, " %u", GET_ARGNO(pc)); + break; + + case JOF_LOCAL: + fprintf(fp, " %u", GET_SLOTNO(pc)); + break; + + case JOF_SLOTATOM: + case JOF_SLOTOBJECT: + fprintf(fp, " %u", GET_SLOTNO(pc)); + index = js_GetIndexFromBytecode(cx, script, pc, SLOTNO_LEN); + if (type == JOF_SLOTATOM) { + JS_GET_SCRIPT_ATOM(script, index, atom); + v = ATOM_KEY(atom); + } else { + JS_GET_SCRIPT_OBJECT(script, index, obj); + v = OBJECT_TO_JSVAL(obj); + } + bytes = ToDisassemblySource(cx, v); + if (!bytes) + return 0; + fprintf(fp, " %s", bytes); + break; + + case JOF_UINT24: + JS_ASSERT(op == JSOP_UINT24 || op == JSOP_NEWARRAY); + i = (jsint)GET_UINT24(pc); + goto print_int; + + case JOF_UINT8: + i = pc[1]; + goto print_int; + + case JOF_INT8: + i = GET_INT8(pc); + goto print_int; + + case JOF_INT32: + JS_ASSERT(op == JSOP_INT32); + i = GET_INT32(pc); + print_int: + fprintf(fp, " %d", i); + break; + + default: { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) cs->format); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_UNKNOWN_FORMAT, numBuf); + return 0; + } + } + fputs("\n", fp); + return len; +} + +#endif /* DEBUG */ + +/************************************************************************/ + +/* + * Sprintf, but with unlimited and automatically allocated buffering. + */ +typedef struct Sprinter { + JSContext *context; /* context executing the decompiler */ + JSArenaPool *pool; /* string allocation pool */ + char *base; /* base address of buffer in pool */ + size_t size; /* size of buffer allocated at base */ + ptrdiff_t offset; /* offset of next free char in buffer */ +} Sprinter; + +#define INIT_SPRINTER(cx, sp, ap, off) \ + ((sp)->context = cx, (sp)->pool = ap, (sp)->base = NULL, (sp)->size = 0, \ + (sp)->offset = off) + +#define OFF2STR(sp,off) ((sp)->base + (off)) +#define STR2OFF(sp,str) ((str) - (sp)->base) +#define RETRACT(sp,str) ((sp)->offset = STR2OFF(sp, str)) + +static JSBool +SprintEnsureBuffer(Sprinter *sp, size_t len) +{ + ptrdiff_t nb; + char *base; + + nb = (sp->offset + len + 1) - sp->size; + if (nb < 0) + return JS_TRUE; + base = sp->base; + if (!base) { + JS_ARENA_ALLOCATE_CAST(base, char *, sp->pool, nb); + } else { + JS_ARENA_GROW_CAST(base, char *, sp->pool, sp->size, nb); + } + if (!base) { + js_ReportOutOfScriptQuota(sp->context); + return JS_FALSE; + } + sp->base = base; + sp->size += nb; + return JS_TRUE; +} + +static ptrdiff_t +SprintPut(Sprinter *sp, const char *s, size_t len) +{ + ptrdiff_t offset; + char *bp; + + /* Allocate space for s, including the '\0' at the end. */ + if (!SprintEnsureBuffer(sp, len)) + return -1; + + /* Advance offset and copy s into sp's buffer. */ + offset = sp->offset; + sp->offset += len; + bp = sp->base + offset; + memmove(bp, s, len); + bp[len] = 0; + return offset; +} + +static ptrdiff_t +SprintCString(Sprinter *sp, const char *s) +{ + return SprintPut(sp, s, strlen(s)); +} + +static ptrdiff_t +SprintString(Sprinter *sp, JSString *str) +{ + jschar *chars; + size_t length, size; + ptrdiff_t offset; + + JSSTRING_CHARS_AND_LENGTH(str, chars, length); + if (length == 0) + return sp->offset; + + size = js_GetDeflatedStringLength(sp->context, chars, length); + if (size == (size_t)-1 || !SprintEnsureBuffer(sp, size)) + return -1; + + offset = sp->offset; + sp->offset += size; + js_DeflateStringToBuffer(sp->context, chars, length, sp->base + offset, + &size); + sp->base[sp->offset] = 0; + return offset; +} + + +static ptrdiff_t +Sprint(Sprinter *sp, const char *format, ...) +{ + va_list ap; + char *bp; + ptrdiff_t offset; + + va_start(ap, format); + bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ + va_end(ap); + if (!bp) { + JS_ReportOutOfMemory(sp->context); + return -1; + } + offset = SprintCString(sp, bp); + free(bp); + return offset; +} + +const char js_EscapeMap[] = { + '\b', 'b', + '\f', 'f', + '\n', 'n', + '\r', 'r', + '\t', 't', + '\v', 'v', + '"', '"', + '\'', '\'', + '\\', '\\', + '\0', '0' +}; + +#define DONT_ESCAPE 0x10000 + +static char * +QuoteString(Sprinter *sp, JSString *str, uint32 quote) +{ + JSBool dontEscape, ok; + jschar qc, c; + ptrdiff_t off, len; + const jschar *s, *t, *z; + const char *e; + char *bp; + + /* Sample off first for later return value pointer computation. */ + dontEscape = (quote & DONT_ESCAPE) != 0; + qc = (jschar) quote; + off = sp->offset; + if (qc && Sprint(sp, "%c", (char)qc) < 0) + return NULL; + + /* Loop control variables: z points at end of string sentinel. */ + JSSTRING_CHARS_AND_END(str, s, z); + for (t = s; t < z; s = ++t) { + /* Move t forward from s past un-quote-worthy characters. */ + c = *t; + while (JS_ISPRINT(c) && c != qc && c != '\\' && c != '\t' && + !(c >> 8)) { + c = *++t; + if (t == z) + break; + } + len = PTRDIFF(t, s, jschar); + + /* Allocate space for s, including the '\0' at the end. */ + if (!SprintEnsureBuffer(sp, len)) + return NULL; + + /* Advance sp->offset and copy s into sp's buffer. */ + bp = sp->base + sp->offset; + sp->offset += len; + while (--len >= 0) + *bp++ = (char) *s++; + *bp = '\0'; + + if (t == z) + break; + + /* Use js_EscapeMap, \u, or \x only if necessary. */ + if (!(c >> 8) && (e = strchr(js_EscapeMap, (int)c)) != NULL) { + ok = dontEscape + ? Sprint(sp, "%c", (char)c) >= 0 + : Sprint(sp, "\\%c", e[1]) >= 0; + } else { + ok = Sprint(sp, (c >> 8) ? "\\u%04X" : "\\x%02X", c) >= 0; + } + if (!ok) + return NULL; + } + + /* Sprint the closing quote and return the quoted string. */ + if (qc && Sprint(sp, "%c", (char)qc) < 0) + return NULL; + + /* + * If we haven't Sprint'd anything yet, Sprint an empty string so that + * the OFF2STR below gives a valid result. + */ + if (off == sp->offset && Sprint(sp, "") < 0) + return NULL; + return OFF2STR(sp, off); +} + +JSString * +js_QuoteString(JSContext *cx, JSString *str, jschar quote) +{ + void *mark; + Sprinter sprinter; + char *bytes; + JSString *escstr; + + mark = JS_ARENA_MARK(&cx->tempPool); + INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0); + bytes = QuoteString(&sprinter, str, quote); + escstr = bytes ? JS_NewStringCopyZ(cx, bytes) : NULL; + JS_ARENA_RELEASE(&cx->tempPool, mark); + return escstr; +} + +/************************************************************************/ + +struct JSPrinter { + Sprinter sprinter; /* base class state */ + JSArenaPool pool; /* string allocation pool */ + uintN indent; /* indentation in spaces */ + JSPackedBool pretty; /* pretty-print: indent, use newlines */ + JSPackedBool grouped; /* in parenthesized expression context */ + JSScript *script; /* script being printed */ + jsbytecode *dvgfence; /* DecompileExpression fencepost */ + jsbytecode **pcstack; /* DecompileExpression modeled stack */ + JSFunction *fun; /* interpreted function */ + jsuword *localNames; /* argument and variable names */ +}; + +/* + * Hack another flag, a la JS_DONT_PRETTY_PRINT, into uintN indent parameters + * to functions such as js_DecompileFunction and js_NewPrinter. This time, as + * opposed to JS_DONT_PRETTY_PRINT back in the dark ages, we can assume that a + * uintN is at least 32 bits. + */ +#define JS_IN_GROUP_CONTEXT 0x10000 + +JSPrinter * +JS_NEW_PRINTER(JSContext *cx, const char *name, JSFunction *fun, + uintN indent, JSBool pretty) +{ + JSPrinter *jp; + + jp = (JSPrinter *) JS_malloc(cx, sizeof(JSPrinter)); + if (!jp) + return NULL; + INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0); + JS_INIT_ARENA_POOL(&jp->pool, name, 256, 1, &cx->scriptStackQuota); + jp->indent = indent & ~JS_IN_GROUP_CONTEXT; + jp->pretty = pretty; + jp->grouped = (indent & JS_IN_GROUP_CONTEXT) != 0; + jp->script = NULL; + jp->dvgfence = NULL; + jp->pcstack = NULL; + jp->fun = fun; + jp->localNames = NULL; + if (fun && FUN_INTERPRETED(fun) && JS_GET_LOCAL_NAME_COUNT(fun)) { + jp->localNames = js_GetLocalNameArray(cx, fun, &jp->pool); + if (!jp->localNames) { + js_DestroyPrinter(jp); + return NULL; + } + } + return jp; +} + +void +js_DestroyPrinter(JSPrinter *jp) +{ + JS_FinishArenaPool(&jp->pool); + JS_free(jp->sprinter.context, jp); +} + +JSString * +js_GetPrinterOutput(JSPrinter *jp) +{ + JSContext *cx; + JSString *str; + + cx = jp->sprinter.context; + if (!jp->sprinter.base) + return cx->runtime->emptyString; + str = JS_NewStringCopyZ(cx, jp->sprinter.base); + if (!str) + return NULL; + JS_FreeArenaPool(&jp->pool); + INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0); + return str; +} + +/* + * NB: Indexed by SRC_DECL_* defines from jsemit.h. + */ +static const char * const var_prefix[] = {"var ", "const ", "let "}; + +static const char * +VarPrefix(jssrcnote *sn) +{ + if (sn && (SN_TYPE(sn) == SRC_DECL || SN_TYPE(sn) == SRC_GROUPASSIGN)) { + ptrdiff_t type = js_GetSrcNoteOffset(sn, 0); + if ((uintN)type <= SRC_DECL_LET) + return var_prefix[type]; + } + return ""; +} + +int +js_printf(JSPrinter *jp, const char *format, ...) +{ + va_list ap; + char *bp, *fp; + int cc; + + if (*format == '\0') + return 0; + + va_start(ap, format); + + /* If pretty-printing, expand magic tab into a run of jp->indent spaces. */ + if (*format == '\t') { + format++; + if (jp->pretty && Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0) + return -1; + } + + /* Suppress newlines (must be once per format, at the end) if not pretty. */ + fp = NULL; + if (!jp->pretty && format[cc = strlen(format) - 1] == '\n') { + fp = JS_strdup(jp->sprinter.context, format); + if (!fp) + return -1; + fp[cc] = '\0'; + format = fp; + } + + /* Allocate temp space, convert format, and put. */ + bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ + if (fp) { + JS_free(jp->sprinter.context, fp); + format = NULL; + } + if (!bp) { + JS_ReportOutOfMemory(jp->sprinter.context); + return -1; + } + + cc = strlen(bp); + if (SprintPut(&jp->sprinter, bp, (size_t)cc) < 0) + cc = -1; + free(bp); + + va_end(ap); + return cc; +} + +JSBool +js_puts(JSPrinter *jp, const char *s) +{ + return SprintCString(&jp->sprinter, s) >= 0; +} + +/************************************************************************/ + +typedef struct SprintStack { + Sprinter sprinter; /* sprinter for postfix to infix buffering */ + ptrdiff_t *offsets; /* stack of postfix string offsets */ + jsbytecode *opcodes; /* parallel stack of JS opcodes */ + uintN top; /* top of stack index */ + uintN inArrayInit; /* array initialiser/comprehension level */ + JSBool inGenExp; /* in generator expression */ + JSPrinter *printer; /* permanent output goes here */ +} SprintStack; + +/* + * Find the depth of the operand stack when the interpreter reaches the given + * pc in script. pcstack must have space for least script->depth elements. On + * return it will contain pointers to opcodes that populated the interpreter's + * current operand stack. + * + * This function cannot raise an exception or error. However, due to a risk of + * potential bugs when modeling the stack, the function returns -1 if it + * detects an inconsistency in the model. Such an inconsistency triggers an + * assert in a debug build. + */ +static intN +ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *pc, + jsbytecode **pcstack); + +#define FAILED_EXPRESSION_DECOMPILER ((char *) 1) + +/* + * Decompile a part of expression up to the given pc. The function returns + * NULL on out-of-memory, or the FAILED_EXPRESSION_DECOMPILER sentinel when + * the decompiler fails due to a bug and/or unimplemented feature, or the + * decompiled string on success. + */ +static char * +DecompileExpression(JSContext *cx, JSScript *script, JSFunction *fun, + jsbytecode *pc); + +/* + * Get a stacked offset from ss->sprinter.base, or if the stacked value |off| + * is negative, fetch the generating pc from printer->pcstack[-2 - off] and + * decompile the code that generated the missing value. This is used when + * reporting errors, where the model stack will lack |pcdepth| non-negative + * offsets (see DecompileExpression and DecompileCode). + * + * If the stacked offset is -1, return 0 to index the NUL padding at the start + * of ss->sprinter.base. If this happens, it means there is a decompiler bug + * to fix, but it won't violate memory safety. + */ +static ptrdiff_t +GetOff(SprintStack *ss, uintN i) +{ + ptrdiff_t off; + jsbytecode *pc; + char *bytes; + + off = ss->offsets[i]; + if (off >= 0) + return off; + + JS_ASSERT(off <= -2); + JS_ASSERT(ss->printer->pcstack); + if (off < -2 && ss->printer->pcstack) { + pc = ss->printer->pcstack[-2 - off]; + bytes = DecompileExpression(ss->sprinter.context, ss->printer->script, + ss->printer->fun, pc); + if (!bytes) + return 0; + if (bytes != FAILED_EXPRESSION_DECOMPILER) { + off = SprintCString(&ss->sprinter, bytes); + if (off < 0) + off = 0; + ss->offsets[i] = off; + JS_free(ss->sprinter.context, bytes); + return off; + } + if (!ss->sprinter.base && SprintPut(&ss->sprinter, "", 0) >= 0) { + memset(ss->sprinter.base, 0, ss->sprinter.offset); + ss->offsets[i] = -1; + } + } + return 0; +} + +static const char * +GetStr(SprintStack *ss, uintN i) +{ + ptrdiff_t off; + + /* + * Must call GetOff before using ss->sprinter.base, since it may be null + * until bootstrapped by GetOff. + */ + off = GetOff(ss, i); + return OFF2STR(&ss->sprinter, off); +} + +/* + * Gap between stacked strings to allow for insertion of parens and commas + * when auto-parenthesizing expressions and decompiling array initialisers + * (see the JSOP_NEWARRAY case in Decompile). + */ +#define PAREN_SLOP (2 + 1) + +/* + * These pseudo-ops help js_DecompileValueGenerator decompile JSOP_SETNAME, + * JSOP_SETPROP, and JSOP_SETELEM, respectively. They are never stored in + * bytecode, so they don't preempt valid opcodes. + */ +#define JSOP_GETPROP2 256 +#define JSOP_GETELEM2 257 + +static void +AddParenSlop(SprintStack *ss) +{ + memset(OFF2STR(&ss->sprinter, ss->sprinter.offset), 0, PAREN_SLOP); + ss->sprinter.offset += PAREN_SLOP; +} + +static JSBool +PushOff(SprintStack *ss, ptrdiff_t off, JSOp op) +{ + uintN top; + + if (!SprintEnsureBuffer(&ss->sprinter, PAREN_SLOP)) + return JS_FALSE; + + /* ss->top points to the next free slot; be paranoid about overflow. */ + top = ss->top; + JS_ASSERT(top < StackDepth(ss->printer->script)); + if (top >= StackDepth(ss->printer->script)) { + JS_ReportOutOfMemory(ss->sprinter.context); + return JS_FALSE; + } + + /* The opcodes stack must contain real bytecodes that index js_CodeSpec. */ + ss->offsets[top] = off; + ss->opcodes[top] = (op == JSOP_GETPROP2) ? JSOP_GETPROP + : (op == JSOP_GETELEM2) ? JSOP_GETELEM + : (jsbytecode) op; + ss->top = ++top; + AddParenSlop(ss); + return JS_TRUE; +} + +static ptrdiff_t +PopOffPrec(SprintStack *ss, uint8 prec) +{ + uintN top; + const JSCodeSpec *topcs; + ptrdiff_t off; + + /* ss->top points to the next free slot; be paranoid about underflow. */ + top = ss->top; + JS_ASSERT(top != 0); + if (top == 0) + return 0; + + ss->top = --top; + off = GetOff(ss, top); + topcs = &js_CodeSpec[ss->opcodes[top]]; + if (topcs->prec != 0 && topcs->prec < prec) { + ss->sprinter.offset = ss->offsets[top] = off - 2; + off = Sprint(&ss->sprinter, "(%s)", OFF2STR(&ss->sprinter, off)); + } else { + ss->sprinter.offset = off; + } + return off; +} + +static const char * +PopStrPrec(SprintStack *ss, uint8 prec) +{ + ptrdiff_t off; + + off = PopOffPrec(ss, prec); + return OFF2STR(&ss->sprinter, off); +} + +static ptrdiff_t +PopOff(SprintStack *ss, JSOp op) +{ + return PopOffPrec(ss, js_CodeSpec[op].prec); +} + +static const char * +PopStr(SprintStack *ss, JSOp op) +{ + return PopStrPrec(ss, js_CodeSpec[op].prec); +} + +typedef struct TableEntry { + jsval key; + ptrdiff_t offset; + JSAtom *label; + jsint order; /* source order for stable tableswitch sort */ +} TableEntry; + +static JSBool +CompareOffsets(void *arg, const void *v1, const void *v2, int *result) +{ + ptrdiff_t offset_diff; + const TableEntry *te1 = (const TableEntry *) v1, + *te2 = (const TableEntry *) v2; + + offset_diff = te1->offset - te2->offset; + *result = (offset_diff == 0 ? te1->order - te2->order + : offset_diff < 0 ? -1 + : 1); + return JS_TRUE; +} + +static ptrdiff_t +SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp) +{ + jsdouble d; + ptrdiff_t todo; + char *s, buf[DTOSTR_STANDARD_BUFFER_SIZE]; + + JS_ASSERT(JSVAL_IS_DOUBLE(v)); + d = *JSVAL_TO_DOUBLE(v); + if (JSDOUBLE_IS_NEGZERO(d)) { + todo = SprintCString(sp, "-0"); + *opp = JSOP_NEG; + } else if (!JSDOUBLE_IS_FINITE(d)) { + /* Don't use Infinity and NaN, they're mutable. */ + todo = SprintCString(sp, + JSDOUBLE_IS_NaN(d) + ? "0 / 0" + : (d < 0) + ? "1 / -0" + : "1 / 0"); + *opp = JSOP_DIV; + } else { + s = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, d); + if (!s) { + JS_ReportOutOfMemory(sp->context); + return -1; + } + JS_ASSERT(strcmp(s, js_Infinity_str) && + (*s != '-' || + strcmp(s + 1, js_Infinity_str)) && + strcmp(s, js_NaN_str)); + todo = Sprint(sp, s); + } + return todo; +} + +static jsbytecode * +Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop); + +static JSBool +DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength, + jsbytecode *pc, ptrdiff_t switchLength, + ptrdiff_t defaultOffset, JSBool isCondSwitch) +{ + JSContext *cx; + JSPrinter *jp; + ptrdiff_t off, off2, diff, caseExprOff, todo; + char *lval, *rval; + uintN i; + jsval key; + JSString *str; + + cx = ss->sprinter.context; + jp = ss->printer; + + /* JSOP_CONDSWITCH doesn't pop, unlike JSOP_{LOOKUP,TABLE}SWITCH. */ + off = isCondSwitch ? GetOff(ss, ss->top-1) : PopOff(ss, JSOP_NOP); + lval = OFF2STR(&ss->sprinter, off); + + js_printf(jp, "\tswitch (%s) {\n", lval); + + if (tableLength) { + diff = table[0].offset - defaultOffset; + if (diff > 0) { + jp->indent += 2; + js_printf(jp, "\t%s:\n", js_default_str); + jp->indent += 2; + if (!Decompile(ss, pc + defaultOffset, diff, JSOP_NOP)) + return JS_FALSE; + jp->indent -= 4; + } + + caseExprOff = isCondSwitch ? JSOP_CONDSWITCH_LENGTH : 0; + + for (i = 0; i < tableLength; i++) { + off = table[i].offset; + off2 = (i + 1 < tableLength) ? table[i + 1].offset : switchLength; + + key = table[i].key; + if (isCondSwitch) { + ptrdiff_t nextCaseExprOff; + + /* + * key encodes the JSOP_CASE bytecode's offset from switchtop. + * The next case expression follows immediately, unless we are + * at the last case. + */ + nextCaseExprOff = (ptrdiff_t)JSVAL_TO_INT(key); + nextCaseExprOff += js_CodeSpec[pc[nextCaseExprOff]].length; + jp->indent += 2; + if (!Decompile(ss, pc + caseExprOff, + nextCaseExprOff - caseExprOff, JSOP_NOP)) { + return JS_FALSE; + } + caseExprOff = nextCaseExprOff; + + /* Balance the stack as if this JSOP_CASE matched. */ + --ss->top; + } else { + /* + * key comes from an atom, not the decompiler, so we need to + * quote it if it's a string literal. But if table[i].label + * is non-null, key was constant-propagated and label is the + * name of the const we should show as the case label. We set + * key to undefined so this identifier is escaped, if required + * by non-ASCII characters, but not quoted, by QuoteString. + */ + todo = -1; + if (table[i].label) { + str = ATOM_TO_STRING(table[i].label); + key = JSVAL_VOID; + } else if (JSVAL_IS_DOUBLE(key)) { + JSOp junk; + + todo = SprintDoubleValue(&ss->sprinter, key, &junk); + str = NULL; + } else { + str = js_ValueToString(cx, key); + if (!str) + return JS_FALSE; + } + if (todo >= 0) { + rval = OFF2STR(&ss->sprinter, todo); + } else { + rval = QuoteString(&ss->sprinter, str, (jschar) + (JSVAL_IS_STRING(key) ? '"' : 0)); + if (!rval) + return JS_FALSE; + } + RETRACT(&ss->sprinter, rval); + jp->indent += 2; + js_printf(jp, "\tcase %s:\n", rval); + } + + jp->indent += 2; + if (off <= defaultOffset && defaultOffset < off2) { + diff = defaultOffset - off; + if (diff != 0) { + if (!Decompile(ss, pc + off, diff, JSOP_NOP)) + return JS_FALSE; + off = defaultOffset; + } + jp->indent -= 2; + js_printf(jp, "\t%s:\n", js_default_str); + jp->indent += 2; + } + if (!Decompile(ss, pc + off, off2 - off, JSOP_NOP)) + return JS_FALSE; + jp->indent -= 4; + + /* Re-balance as if last JSOP_CASE or JSOP_DEFAULT mismatched. */ + if (isCondSwitch) + ++ss->top; + } + } + + if (defaultOffset == switchLength) { + jp->indent += 2; + js_printf(jp, "\t%s:;\n", js_default_str); + jp->indent -= 2; + } + js_printf(jp, "\t}\n"); + + /* By the end of a JSOP_CONDSWITCH, the discriminant has been popped. */ + if (isCondSwitch) + --ss->top; + return JS_TRUE; +} + +#define LOCAL_ASSERT_CUSTOM(expr, BAD_EXIT) \ + JS_BEGIN_MACRO \ + JS_ASSERT(expr); \ + if (!(expr)) { BAD_EXIT; } \ + JS_END_MACRO + +#define LOCAL_ASSERT_RV(expr, rv) \ + LOCAL_ASSERT_CUSTOM(expr, return (rv)) + +static JSAtom * +GetArgOrVarAtom(JSPrinter *jp, uintN slot) +{ + JSAtom *name; + + LOCAL_ASSERT_RV(jp->fun, NULL); + LOCAL_ASSERT_RV(slot < (uintN) JS_GET_LOCAL_NAME_COUNT(jp->fun), NULL); + name = JS_LOCAL_NAME_TO_ATOM(jp->localNames[slot]); +#if !JS_HAS_DESTRUCTURING + LOCAL_ASSERT_RV(name, NULL); +#endif + return name; +} + +const char * +GetLocal(SprintStack *ss, jsint i) +{ + ptrdiff_t off; + JSContext *cx; + JSScript *script; + jsatomid j, n; + JSAtom *atom; + JSObject *obj; + jsint depth, count; + JSScopeProperty *sprop; + const char *rval; + +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, "") + + off = ss->offsets[i]; + if (off >= 0) + return OFF2STR(&ss->sprinter, off); + + /* + * We must be called from js_DecompileValueGenerator (via Decompile) when + * dereferencing a local that's undefined or null. Search script->objects + * for the block containing this local by its stack index, i. + */ + cx = ss->sprinter.context; + script = ss->printer->script; + LOCAL_ASSERT(script->objectsOffset != 0); + for (j = 0, n = JS_SCRIPT_OBJECTS(script)->length; ; j++) { + LOCAL_ASSERT(j < n); + JS_GET_SCRIPT_OBJECT(script, j, obj); + if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) { + depth = OBJ_BLOCK_DEPTH(cx, obj); + count = OBJ_BLOCK_COUNT(cx, obj); + if ((jsuint)(i - depth) < (jsuint)count) + break; + } + } + + i -= depth; + for (sprop = OBJ_SCOPE(obj)->lastProp; sprop; sprop = sprop->parent) { + if (sprop->shortid == i) + break; + } + + LOCAL_ASSERT(sprop && JSID_IS_ATOM(sprop->id)); + atom = JSID_TO_ATOM(sprop->id); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + return rval; + +#undef LOCAL_ASSERT +} + +static JSBool +IsVarSlot(JSPrinter *jp, jsbytecode *pc, jsint *indexp) +{ + uintN slot; + + slot = GET_SLOTNO(pc); + if (slot < jp->script->nfixed) { + /* The slot refers to a variable with name stored in jp->localNames. */ + *indexp = jp->fun->nargs + slot; + return JS_TRUE; + } + + /* We have a local which index is relative to the stack base. */ + slot -= jp->script->nfixed; + JS_ASSERT(slot < StackDepth(jp->script)); + *indexp = slot; + return JS_FALSE; +} + +#if JS_HAS_DESTRUCTURING + +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, NULL) +#define LOAD_OP_DATA(pc) (oplen = (cs = &js_CodeSpec[op=(JSOp)*pc])->length) + +static jsbytecode * +DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc); + +static jsbytecode * +DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, + JSBool *hole) +{ + JSContext *cx; + JSPrinter *jp; + JSOp op; + const JSCodeSpec *cs; + uintN oplen; + jsint i; + const char *lval, *xval; + ptrdiff_t todo; + JSAtom *atom; + + *hole = JS_FALSE; + cx = ss->sprinter.context; + jp = ss->printer; + LOAD_OP_DATA(pc); + + switch (op) { + case JSOP_POP: + *hole = JS_TRUE; + todo = SprintPut(&ss->sprinter, ", ", 2); + break; + + case JSOP_DUP: + pc = DecompileDestructuring(ss, pc, endpc); + if (!pc) + return NULL; + if (pc == endpc) + return pc; + LOAD_OP_DATA(pc); + lval = PopStr(ss, JSOP_NOP); + todo = SprintCString(&ss->sprinter, lval); + if (op == JSOP_POPN) + return pc; + LOCAL_ASSERT(*pc == JSOP_POP); + break; + + case JSOP_SETARG: + case JSOP_SETGVAR: + case JSOP_SETLOCAL: + LOCAL_ASSERT(pc[oplen] == JSOP_POP || pc[oplen] == JSOP_POPN); + /* FALL THROUGH */ + + case JSOP_SETLOCALPOP: + atom = NULL; + lval = NULL; + if (op == JSOP_SETARG) { + atom = GetArgOrVarAtom(jp, GET_SLOTNO(pc)); + LOCAL_ASSERT(atom); + } else if (op == JSOP_SETGVAR) { + GET_ATOM_FROM_BYTECODE(jp->script, pc, 0, atom); + } else if (IsVarSlot(jp, pc, &i)) { + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + } else { + lval = GetLocal(ss, i); + } + if (atom) + lval = js_AtomToPrintableString(cx, atom); + LOCAL_ASSERT(lval); + todo = SprintCString(&ss->sprinter, lval); + if (op != JSOP_SETLOCALPOP) { + pc += oplen; + if (pc == endpc) + return pc; + LOAD_OP_DATA(pc); + if (op == JSOP_POPN) + return pc; + LOCAL_ASSERT(op == JSOP_POP); + } + break; + + default: + /* + * We may need to auto-parenthesize the left-most value decompiled + * here, so add back PAREN_SLOP temporarily. Then decompile until the + * opcode that would reduce the stack depth to (ss->top-1), which we + * pass to Decompile encoded as -(ss->top-1) - 1 or just -ss->top for + * the nb parameter. + */ + todo = ss->sprinter.offset; + ss->sprinter.offset = todo + PAREN_SLOP; + pc = Decompile(ss, pc, -((intN)ss->top), JSOP_NOP); + if (!pc) + return NULL; + if (pc == endpc) + return pc; + LOAD_OP_DATA(pc); + LOCAL_ASSERT(op == JSOP_ENUMELEM || op == JSOP_ENUMCONSTELEM); + xval = PopStr(ss, JSOP_NOP); + lval = PopStr(ss, JSOP_GETPROP); + ss->sprinter.offset = todo; + if (*lval == '\0') { + /* lval is from JSOP_BINDNAME, so just print xval. */ + todo = SprintCString(&ss->sprinter, xval); + } else if (*xval == '\0') { + /* xval is from JSOP_SETCALL or JSOP_BINDXMLNAME, print lval. */ + todo = SprintCString(&ss->sprinter, lval); + } else { + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(ss->opcodes[ss->top+1]) == JOF_XMLNAME) + ? "%s.%s" + : "%s[%s]", + lval, xval); + } + break; + } + + if (todo < 0) + return NULL; + + LOCAL_ASSERT(pc < endpc); + pc += oplen; + return pc; +} + +/* + * Starting with a SRC_DESTRUCT-annotated JSOP_DUP, decompile a destructuring + * left-hand side object or array initialiser, including nested destructuring + * initialisers. On successful return, the decompilation will be pushed on ss + * and the return value will point to the POP or GROUP bytecode following the + * destructuring expression. + * + * At any point, if pc is equal to endpc and would otherwise advance, we stop + * immediately and return endpc. + */ +static jsbytecode * +DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc) +{ + ptrdiff_t head; + JSContext *cx; + JSPrinter *jp; + JSOp op, saveop; + const JSCodeSpec *cs; + uintN oplen; + jsint i, lasti; + jsdouble d; + const char *lval; + JSAtom *atom; + jssrcnote *sn; + JSString *str; + JSBool hole; + + LOCAL_ASSERT(*pc == JSOP_DUP); + pc += JSOP_DUP_LENGTH; + + /* + * Set head so we can rewrite '[' to '{' as needed. Back up PAREN_SLOP + * chars so the destructuring decompilation accumulates contiguously in + * ss->sprinter starting with "[". + */ + head = SprintPut(&ss->sprinter, "[", 1); + if (head < 0 || !PushOff(ss, head, JSOP_NOP)) + return NULL; + ss->sprinter.offset -= PAREN_SLOP; + LOCAL_ASSERT(head == ss->sprinter.offset - 1); + LOCAL_ASSERT(*OFF2STR(&ss->sprinter, head) == '['); + + cx = ss->sprinter.context; + jp = ss->printer; + lasti = -1; + + while (pc < endpc) { +#if JS_HAS_DESTRUCTURING_SHORTHAND + ptrdiff_t nameoff = -1; +#endif + + LOAD_OP_DATA(pc); + saveop = op; + + switch (op) { + case JSOP_POP: + pc += oplen; + goto out; + + /* Handle the optimized number-pushing opcodes. */ + case JSOP_ZERO: d = i = 0; goto do_getelem; + case JSOP_ONE: d = i = 1; goto do_getelem; + case JSOP_UINT16: d = i = GET_UINT16(pc); goto do_getelem; + case JSOP_UINT24: d = i = GET_UINT24(pc); goto do_getelem; + case JSOP_INT8: d = i = GET_INT8(pc); goto do_getelem; + case JSOP_INT32: d = i = GET_INT32(pc); goto do_getelem; + + case JSOP_DOUBLE: + GET_ATOM_FROM_BYTECODE(jp->script, pc, 0, atom); + d = *ATOM_TO_DOUBLE(atom); + LOCAL_ASSERT(JSDOUBLE_IS_FINITE(d) && !JSDOUBLE_IS_NEGZERO(d)); + i = (jsint)d; + + do_getelem: + sn = js_GetSrcNote(jp->script, pc); + pc += oplen; + if (pc == endpc) + return pc; + LOAD_OP_DATA(pc); + LOCAL_ASSERT(op == JSOP_GETELEM); + + /* Distinguish object from array by opcode or source note. */ + if (sn && SN_TYPE(sn) == SRC_INITPROP) { + *OFF2STR(&ss->sprinter, head) = '{'; + if (Sprint(&ss->sprinter, "%g: ", d) < 0) + return NULL; + } else { + /* Sanity check for the gnarly control flow above. */ + LOCAL_ASSERT(i == d); + + /* Fill in any holes (holes at the end don't matter). */ + while (++lasti < i) { + if (SprintPut(&ss->sprinter, ", ", 2) < 0) + return NULL; + } + } + break; + + case JSOP_LENGTH: + atom = cx->runtime->atomState.lengthAtom; + goto do_destructure_atom; + + case JSOP_CALLPROP: + case JSOP_GETPROP: + GET_ATOM_FROM_BYTECODE(jp->script, pc, 0, atom); + do_destructure_atom: + *OFF2STR(&ss->sprinter, head) = '{'; + str = ATOM_TO_STRING(atom); +#if JS_HAS_DESTRUCTURING_SHORTHAND + nameoff = ss->sprinter.offset; +#endif + if (!QuoteString(&ss->sprinter, str, + js_IsIdentifier(str) ? 0 : (jschar)'\'')) { + return NULL; + } + if (SprintPut(&ss->sprinter, ": ", 2) < 0) + return NULL; + break; + + default: + LOCAL_ASSERT(0); + } + + pc += oplen; + if (pc == endpc) + return pc; + + /* + * Decompile the left-hand side expression whose bytecode starts at pc + * and continues for a bounded number of bytecodes or stack operations + * (and which in any event stops before endpc). + */ + pc = DecompileDestructuringLHS(ss, pc, endpc, &hole); + if (!pc) + return NULL; + +#if JS_HAS_DESTRUCTURING_SHORTHAND + if (nameoff >= 0) { + ptrdiff_t offset, initlen; + + offset = ss->sprinter.offset; + LOCAL_ASSERT(*OFF2STR(&ss->sprinter, offset) == '\0'); + initlen = offset - nameoff; + LOCAL_ASSERT(initlen >= 4); + + /* Early check to rule out odd "name: lval" length. */ + if (((size_t)initlen & 1) == 0) { + size_t namelen; + const char *name; + + /* + * Even "name: lval" string length: check for "x: x" and the + * like, and apply the shorthand if we can. + */ + namelen = (size_t)(initlen - 2) >> 1; + name = OFF2STR(&ss->sprinter, nameoff); + if (!strncmp(name + namelen, ": ", 2) && + !strncmp(name, name + namelen + 2, namelen)) { + offset -= namelen + 2; + *OFF2STR(&ss->sprinter, offset) = '\0'; + ss->sprinter.offset = offset; + } + } + } +#endif + + if (pc == endpc || *pc != JSOP_DUP) + break; + + /* + * Check for SRC_DESTRUCT on this JSOP_DUP, which would mean another + * destructuring initialiser abuts this one, and we should stop. This + * happens with source of the form '[a] = [b] = c'. + */ + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_DESTRUCT) + break; + + if (!hole && SprintPut(&ss->sprinter, ", ", 2) < 0) + return NULL; + + pc += JSOP_DUP_LENGTH; + } + +out: + lval = OFF2STR(&ss->sprinter, head); + if (SprintPut(&ss->sprinter, (*lval == '[') ? "]" : "}", 1) < 0) + return NULL; + return pc; +} + +static jsbytecode * +DecompileGroupAssignment(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, + jssrcnote *sn, ptrdiff_t *todop) +{ + JSOp op; + const JSCodeSpec *cs; + uintN oplen, start, end, i; + ptrdiff_t todo; + JSBool hole; + const char *rval; + + LOAD_OP_DATA(pc); + LOCAL_ASSERT(op == JSOP_PUSH || op == JSOP_GETLOCAL); + + todo = Sprint(&ss->sprinter, "%s[", VarPrefix(sn)); + if (todo < 0 || !PushOff(ss, todo, JSOP_NOP)) + return NULL; + ss->sprinter.offset -= PAREN_SLOP; + + for (;;) { + pc += oplen; + if (pc == endpc) + return pc; + pc = DecompileDestructuringLHS(ss, pc, endpc, &hole); + if (!pc) + return NULL; + if (pc == endpc) + return pc; + LOAD_OP_DATA(pc); + if (op != JSOP_PUSH && op != JSOP_GETLOCAL) + break; + if (!hole && SprintPut(&ss->sprinter, ", ", 2) < 0) + return NULL; + } + + LOCAL_ASSERT(op == JSOP_POPN); + if (SprintPut(&ss->sprinter, "] = [", 5) < 0) + return NULL; + + end = ss->top - 1; + start = end - GET_UINT16(pc); + for (i = start; i < end; i++) { + rval = GetStr(ss, i); + if (Sprint(&ss->sprinter, + (i == start) ? "%s" : ", %s", + (i == end - 1 && *rval == '\0') ? ", " : rval) < 0) { + return NULL; + } + } + + if (SprintPut(&ss->sprinter, "]", 1) < 0) + return NULL; + ss->sprinter.offset = ss->offsets[i]; + ss->top = start; + *todop = todo; + return pc; +} + +#undef LOCAL_ASSERT +#undef LOAD_OP_DATA + +#endif /* JS_HAS_DESTRUCTURING */ + +static JSBool +InitSprintStack(JSContext *cx, SprintStack *ss, JSPrinter *jp, uintN depth) +{ + size_t offsetsz, opcodesz; + void *space; + + INIT_SPRINTER(cx, &ss->sprinter, &cx->tempPool, PAREN_SLOP); + + /* Allocate the parallel (to avoid padding) offset and opcode stacks. */ + offsetsz = depth * sizeof(ptrdiff_t); + opcodesz = depth * sizeof(jsbytecode); + JS_ARENA_ALLOCATE(space, &cx->tempPool, offsetsz + opcodesz); + if (!space) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + ss->offsets = (ptrdiff_t *) space; + ss->opcodes = (jsbytecode *) ((char *)space + offsetsz); + + ss->top = ss->inArrayInit = 0; + ss->inGenExp = JS_FALSE; + ss->printer = jp; + return JS_TRUE; +} + +/* + * If nb is non-negative, decompile nb bytecodes starting at pc. Otherwise + * the decompiler starts at pc and continues until it reaches an opcode for + * which decompiling would result in the stack depth equaling -(nb + 1). + * + * The nextop parameter is either JSOP_NOP or the "next" opcode in order of + * abstract interpretation (not necessarily physically next in a bytecode + * vector). So nextop is JSOP_POP for the last operand in a comma expression, + * or JSOP_AND for the right operand of &&. + */ +static jsbytecode * +Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) +{ + JSContext *cx; + JSPrinter *jp, *jp2; + jsbytecode *startpc, *endpc, *pc2, *done; + ptrdiff_t tail, todo, len, oplen, cond, next; + JSOp op, lastop, saveop; + const JSCodeSpec *cs; + jssrcnote *sn, *sn2; + const char *lval, *rval, *xval, *fmt, *token; + jsint i, argc; + char **argv; + JSAtom *atom; + JSObject *obj; + JSFunction *fun; + JSString *str; + JSBool ok; +#if JS_HAS_XML_SUPPORT + JSBool foreach, inXML, quoteAttr; +#else +#define inXML JS_FALSE +#endif + jsval val; + + static const char exception_cookie[] = "/*EXCEPTION*/"; + static const char retsub_pc_cookie[] = "/*RETSUB_PC*/"; + static const char iter_cookie[] = "/*ITER*/"; + static const char forelem_cookie[] = "/*FORELEM*/"; + static const char with_cookie[] = "/*WITH*/"; + static const char dot_format[] = "%s.%s"; + static const char index_format[] = "%s[%s]"; + static const char predot_format[] = "%s%s.%s"; + static const char postdot_format[] = "%s.%s%s"; + static const char preindex_format[] = "%s%s[%s]"; + static const char postindex_format[] = "%s[%s]%s"; + static const char ss_format[] = "%s%s"; + static const char sss_format[] = "%s%s%s"; + + /* Argument and variables decompilation uses the following to share code. */ + JS_STATIC_ASSERT(ARGNO_LEN == SLOTNO_LEN); + +/* + * Local macros + */ +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, NULL) +#define DECOMPILE_CODE(pc,nb) if (!Decompile(ss, pc, nb, JSOP_NOP)) return NULL +#define NEXT_OP(pc) (((pc) + (len) == endpc) ? nextop : pc[len]) +#define TOP_STR() GetStr(ss, ss->top - 1) +#define POP_STR() PopStr(ss, op) +#define POP_STR_PREC(prec) PopStrPrec(ss, prec) + +/* + * Pop a condition expression for if/for/while. JSOP_IFEQ's precedence forces + * extra parens around assignment, which avoids a strict-mode warning. + */ +#define POP_COND_STR() \ + PopStr(ss, (js_CodeSpec[ss->opcodes[ss->top - 1]].format & JOF_SET) \ + ? JSOP_IFEQ \ + : JSOP_NOP) + +/* + * Callers know that ATOM_IS_STRING(atom), and we leave it to the optimizer to + * common ATOM_TO_STRING(atom) here and near the call sites. + */ +#define ATOM_IS_IDENTIFIER(atom) js_IsIdentifier(ATOM_TO_STRING(atom)) +#define ATOM_IS_KEYWORD(atom) \ + (js_CheckKeyword(JSSTRING_CHARS(ATOM_TO_STRING(atom)), \ + JSSTRING_LENGTH(ATOM_TO_STRING(atom))) != TOK_EOF) + +/* + * Given an atom already fetched from jp->script's atom map, quote/escape its + * string appropriately into rval, and select fmt from the quoted and unquoted + * alternatives. + */ +#define GET_QUOTE_AND_FMT(qfmt, ufmt, rval) \ + JS_BEGIN_MACRO \ + jschar quote_; \ + if (!ATOM_IS_IDENTIFIER(atom)) { \ + quote_ = '\''; \ + fmt = qfmt; \ + } else { \ + quote_ = 0; \ + fmt = ufmt; \ + } \ + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), quote_); \ + if (!rval) \ + return NULL; \ + JS_END_MACRO + +#define LOAD_ATOM(PCOFF) \ + GET_ATOM_FROM_BYTECODE(jp->script, pc, PCOFF, atom) + +#define LOAD_OBJECT(PCOFF) \ + GET_OBJECT_FROM_BYTECODE(jp->script, pc, PCOFF, obj) + +#define LOAD_FUNCTION(PCOFF) \ + GET_FUNCTION_FROM_BYTECODE(jp->script, pc, PCOFF, fun) + +#define LOAD_REGEXP(PCOFF) \ + GET_REGEXP_FROM_BYTECODE(jp->script, pc, PCOFF, obj) + +#define GET_SOURCE_NOTE_ATOM(sn, atom) \ + JS_BEGIN_MACRO \ + jsatomid atomIndex_ = (jsatomid) js_GetSrcNoteOffset((sn), 0); \ + \ + LOCAL_ASSERT(atomIndex_ < jp->script->atomMap.length); \ + (atom) = jp->script->atomMap.vector[atomIndex_]; \ + JS_END_MACRO + +/* + * Get atom from jp->script's atom map, quote/escape its string appropriately + * into rval, and select fmt from the quoted and unquoted alternatives. + */ +#define GET_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval) \ + JS_BEGIN_MACRO \ + LOAD_ATOM(0); \ + GET_QUOTE_AND_FMT(qfmt, ufmt, rval); \ + JS_END_MACRO + +/* + * Per spec, new x(y).z means (new x(y))).z. For example new (x(y).z) must + * decompile with the constructor parenthesized, but new x.z should not. The + * normal rules give x(y).z and x.z identical precedence: both are produced by + * JSOP_GETPROP. + * + * Therefore, we need to know in case JSOP_NEW whether the constructor + * expression contains any unparenthesized function calls. So when building a + * MemberExpression or CallExpression, we set ss->opcodes[n] to JSOP_CALL if + * this is true. x(y).z gets JSOP_CALL, not JSOP_GETPROP. + */ +#define PROPAGATE_CALLNESS() \ + JS_BEGIN_MACRO \ + if (ss->opcodes[ss->top - 1] == JSOP_CALL) \ + saveop = JSOP_CALL; \ + JS_END_MACRO + + cx = ss->sprinter.context; + JS_CHECK_RECURSION(cx, return NULL); + + jp = ss->printer; + startpc = pc; + endpc = (nb < 0) ? jp->script->code + jp->script->length : pc + nb; + tail = -1; + todo = -2; /* NB: different from Sprint() error return. */ + saveop = JSOP_NOP; + sn = NULL; + rval = NULL; +#if JS_HAS_XML_SUPPORT + foreach = inXML = quoteAttr = JS_FALSE; +#endif + + while (nb < 0 || pc < endpc) { + /* + * Move saveop to lastop so prefixed bytecodes can take special action + * while sharing maximal code. Set op and saveop to the new bytecode, + * use op in POP_STR to trigger automatic parenthesization, but push + * saveop at the bottom of the loop if this op pushes. Thus op may be + * set to nop or otherwise mutated to suppress auto-parens. + */ + lastop = saveop; + op = (JSOp) *pc; + cs = &js_CodeSpec[op]; + if (cs->format & JOF_INDEXBASE) { + /* + * The decompiler uses js_GetIndexFromBytecode to get atoms and + * objects and ignores these suffix/prefix bytecodes, thus + * simplifying code that must process JSOP_GETTER/JSOP_SETTER + * prefixes. + */ + pc += cs->length; + if (pc >= endpc) + break; + op = (JSOp) *pc; + cs = &js_CodeSpec[op]; + } + saveop = op; + len = oplen = cs->length; + + if (nb < 0 && -(nb + 1) == (intN)ss->top - cs->nuses + cs->ndefs) + return pc; + + /* + * Save source literal associated with JS now before the following + * rewrite changes op. See bug 380197. + */ + token = CodeToken[op]; + + if (pc + oplen == jp->dvgfence) { + JSStackFrame *fp; + uint32 format, mode, type; + + /* + * Rewrite non-get ops to their "get" format if the error is in + * the bytecode at pc, so we don't decompile more than the error + * expression. + */ + for (fp = cx->fp; fp && !fp->script; fp = fp->down) + continue; + format = cs->format; + if (((fp && fp->regs && pc == fp->regs->pc) || + (pc == startpc && cs->nuses != 0)) && + format & (JOF_SET|JOF_DEL|JOF_INCDEC|JOF_FOR|JOF_VARPROP)) { + mode = JOF_MODE(format); + if (mode == JOF_NAME) { + /* + * JOF_NAME does not imply JOF_ATOM, so we must check for + * the QARG and QVAR format types, and translate those to + * JSOP_GETARG or JSOP_GETLOCAL appropriately, instead of + * to JSOP_NAME. + */ + type = JOF_TYPE(format); + op = (type == JOF_QARG) + ? JSOP_GETARG + : (type == JOF_LOCAL) + ? JSOP_GETLOCAL + : JSOP_NAME; + + i = cs->nuses - js_CodeSpec[op].nuses; + while (--i >= 0) + PopOff(ss, JSOP_NOP); + } else { + /* + * We must replace the faulting pc's bytecode with a + * corresponding JSOP_GET* code. For JSOP_SET{PROP,ELEM}, + * we must use the "2nd" form of JSOP_GET{PROP,ELEM}, to + * throw away the assignment op's right-hand operand and + * decompile it as if it were a GET of its left-hand + * operand. + */ + if (mode == JOF_PROP) { + op = (JSOp) ((format & JOF_SET) + ? JSOP_GETPROP2 + : JSOP_GETPROP); + } else if (mode == JOF_ELEM) { + op = (JSOp) ((format & JOF_SET) + ? JSOP_GETELEM2 + : JSOP_GETELEM); + } else { + /* + * Unknown mode (including mode 0) means that op is + * uncategorized for our purposes, so we must write + * per-op special case code here. + */ + switch (op) { + case JSOP_ENUMELEM: + case JSOP_ENUMCONSTELEM: + op = JSOP_GETELEM; + break; +#if JS_HAS_LVALUE_RETURN + case JSOP_SETCALL: + op = JSOP_CALL; + break; +#endif + case JSOP_GETTHISPROP: + /* + * NB: JSOP_GETTHISPROP can't fail due to |this| + * being null or undefined at runtime (beware that + * this may change for ES4). Therefore any error + * resulting from this op must be due to the value + * of the property accessed via |this|, so do not + * rewrite op to JSOP_THIS. + * + * The next two cases should not change op if + * js_DecompileValueGenerator was called from the + * the property getter. They should rewrite only + * if the base object in the arg/var/local is null + * or undefined. FIXME: bug 431569. + */ + break; + case JSOP_GETARGPROP: + op = JSOP_GETARG; + break; + case JSOP_GETLOCALPROP: + op = JSOP_GETLOCAL; + break; + default: + LOCAL_ASSERT(0); + } + } + } + } + + saveop = op; + if (op >= JSOP_LIMIT) { + switch (op) { + case JSOP_GETPROP2: + saveop = JSOP_GETPROP; + break; + case JSOP_GETELEM2: + saveop = JSOP_GETELEM; + break; + default:; + } + } + LOCAL_ASSERT(js_CodeSpec[saveop].length == oplen || + JOF_TYPE(format) == JOF_SLOTATOM); + + jp->dvgfence = NULL; + } + + if (token) { + switch (cs->nuses) { + case 2: + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) { + /* + * Avoid over-parenthesizing y in x op= y based on its + * expansion: x = x op y (replace y by z = w to see the + * problem). + */ + op = (JSOp) pc[oplen]; + rval = POP_STR(); + lval = POP_STR(); + /* Print only the right operand of the assignment-op. */ + todo = SprintCString(&ss->sprinter, rval); + op = saveop; + } else if (!inXML) { + rval = POP_STR_PREC(cs->prec + !!(cs->format & JOF_LEFTASSOC)); + lval = POP_STR_PREC(cs->prec + !(cs->format & JOF_LEFTASSOC)); + todo = Sprint(&ss->sprinter, "%s %s %s", + lval, token, rval); + } else { + /* In XML, just concatenate the two operands. */ + LOCAL_ASSERT(op == JSOP_ADD); + rval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, ss_format, lval, rval); + } + break; + + case 1: + rval = POP_STR(); + todo = Sprint(&ss->sprinter, ss_format, token, rval); + break; + + case 0: + todo = SprintCString(&ss->sprinter, token); + break; + + default: + todo = -2; + break; + } + } else { + switch (op) { + case JSOP_NOP: + /* + * Check for a do-while loop, a for-loop with an empty + * initializer part, a labeled statement, a function + * definition, or try/finally. + */ + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + switch (sn ? SN_TYPE(sn) : SRC_NULL) { + case SRC_WHILE: + ++pc; + tail = js_GetSrcNoteOffset(sn, 0) - 1; + LOCAL_ASSERT(pc[tail] == JSOP_IFNE || + pc[tail] == JSOP_IFNEX); + js_printf(jp, "\tdo {\n"); + jp->indent += 4; + DECOMPILE_CODE(pc, tail); + jp->indent -= 4; + js_printf(jp, "\t} while (%s);\n", POP_COND_STR()); + pc += tail; + len = js_CodeSpec[*pc].length; + todo = -2; + break; + + case SRC_FOR: + rval = ""; + + do_forloop: + JS_ASSERT(SN_TYPE(sn) == SRC_FOR); + + /* Skip the JSOP_NOP or JSOP_POP bytecode. */ + pc += JSOP_NOP_LENGTH; + + /* Get the cond, next, and loop-closing tail offsets. */ + cond = js_GetSrcNoteOffset(sn, 0); + next = js_GetSrcNoteOffset(sn, 1); + tail = js_GetSrcNoteOffset(sn, 2); + + /* + * If this loop has a condition, then pc points at a goto + * targeting the condition. + */ + pc2 = pc; + if (cond != tail) { + LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX); + pc2 += (*pc == JSOP_GOTO) ? JSOP_GOTO_LENGTH : JSOP_GOTOX_LENGTH; + } + LOCAL_ASSERT(tail + GetJumpOffset(pc+tail, pc+tail) == pc2 - pc); + + /* Print the keyword and the possibly empty init-part. */ + js_printf(jp, "\tfor (%s;", rval); + + if (cond != tail) { + /* Decompile the loop condition. */ + DECOMPILE_CODE(pc + cond, tail - cond); + js_printf(jp, " %s", POP_STR()); + } + + /* Need a semicolon whether or not there was a cond. */ + js_puts(jp, ";"); + + if (next != cond) { + /* + * Decompile the loop updater. It may end in a JSOP_POP + * that we skip; or in a JSOP_POPN that we do not skip, + * followed by a JSOP_NOP (skipped as if it's a POP). + * We cope with the difference between these two cases + * by checking for stack imbalance and popping if there + * is an rval. + */ + uintN saveTop = ss->top; + + DECOMPILE_CODE(pc + next, cond - next - JSOP_POP_LENGTH); + LOCAL_ASSERT(ss->top - saveTop <= 1U); + rval = (ss->top == saveTop) + ? ss->sprinter.base + ss->sprinter.offset + : POP_STR(); + js_printf(jp, " %s", rval); + } + + /* Do the loop body. */ + js_printf(jp, ") {\n"); + jp->indent += 4; + next -= pc2 - pc; + DECOMPILE_CODE(pc2, next); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + + /* Set len so pc skips over the entire loop. */ + len = tail + js_CodeSpec[pc[tail]].length; + break; + + case SRC_LABEL: + GET_SOURCE_NOTE_ATOM(sn, atom); + jp->indent -= 4; + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + js_printf(jp, "\t%s:\n", rval); + jp->indent += 4; + break; + + case SRC_LABELBRACE: + GET_SOURCE_NOTE_ATOM(sn, atom); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + js_printf(jp, "\t%s: {\n", rval); + jp->indent += 4; + break; + + case SRC_ENDBRACE: + jp->indent -= 4; + js_printf(jp, "\t}\n"); + break; + + case SRC_FUNCDEF: + JS_GET_SCRIPT_FUNCTION(jp->script, + js_GetSrcNoteOffset(sn, 0), + fun); + do_function: + js_puts(jp, "\n"); + jp2 = JS_NEW_PRINTER(cx, "nested_function", fun, + jp->indent, jp->pretty); + if (!jp2) + return NULL; + ok = js_DecompileFunction(jp2); + if (ok && jp2->sprinter.base) + js_puts(jp, jp2->sprinter.base); + js_DestroyPrinter(jp2); + if (!ok) + return NULL; + js_puts(jp, "\n\n"); + break; + + case SRC_BRACE: + js_printf(jp, "\t{\n"); + jp->indent += 4; + len = js_GetSrcNoteOffset(sn, 0); + DECOMPILE_CODE(pc + oplen, len - oplen); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + break; + + default:; + } + break; + + case JSOP_PUSH: +#if JS_HAS_DESTRUCTURING + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_GROUPASSIGN) { + pc = DecompileGroupAssignment(ss, pc, endpc, sn, &todo); + if (!pc) + return NULL; + LOCAL_ASSERT(*pc == JSOP_POPN); + len = oplen = JSOP_POPN_LENGTH; + goto end_groupassignment; + } +#endif + /* FALL THROUGH */ + + case JSOP_BINDNAME: + todo = Sprint(&ss->sprinter, ""); + break; + + case JSOP_TRY: + js_printf(jp, "\ttry {\n"); + jp->indent += 4; + todo = -2; + break; + + case JSOP_FINALLY: + jp->indent -= 4; + js_printf(jp, "\t} finally {\n"); + jp->indent += 4; + + /* + * We push push the pair of exception/restsub cookies to + * simulate the effects [gosub] or control transfer during + * exception capturing on the stack. + */ + todo = Sprint(&ss->sprinter, exception_cookie); + if (todo < 0 || !PushOff(ss, todo, op)) + return NULL; + todo = Sprint(&ss->sprinter, retsub_pc_cookie); + break; + + case JSOP_RETSUB: + rval = POP_STR(); + LOCAL_ASSERT(strcmp(rval, retsub_pc_cookie) == 0); + lval = POP_STR(); + LOCAL_ASSERT(strcmp(lval, exception_cookie) == 0); + todo = -2; + break; + + case JSOP_GOSUB: + case JSOP_GOSUBX: + /* + * JSOP_GOSUB and GOSUBX have no effect on the decompiler's + * string stack because the next op in bytecode order finds + * the stack balanced by a JSOP_RETSUB executed elsewhere. + */ + todo = -2; + break; + + case JSOP_POPN: + { + uintN newtop, oldtop; + + /* + * The compiler models operand stack depth and fixes the stack + * pointer on entry to a catch clause based on its depth model. + * The decompiler must match the code generator's model, which + * is why JSOP_FINALLY pushes a cookie that JSOP_RETSUB pops. + */ + oldtop = ss->top; + newtop = oldtop - GET_UINT16(pc); + LOCAL_ASSERT(newtop <= oldtop); + todo = -2; + + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + break; +#if JS_HAS_DESTRUCTURING + if (sn && SN_TYPE(sn) == SRC_GROUPASSIGN) { + todo = Sprint(&ss->sprinter, "%s[] = [", + VarPrefix(sn)); + if (todo < 0) + return NULL; + for (uintN i = newtop; i < oldtop; i++) { + rval = OFF2STR(&ss->sprinter, ss->offsets[i]); + if (Sprint(&ss->sprinter, ss_format, + (i == newtop) ? "" : ", ", + (i == oldtop - 1 && *rval == '\0') + ? ", " : rval) < 0) { + return NULL; + } + } + if (SprintPut(&ss->sprinter, "]", 1) < 0) + return NULL; + + /* + * If this is an empty group assignment, we have no stack + * budget into which we can push our result string. Adjust + * ss->sprinter.offset so that our consumer can find the + * empty group assignment decompilation. + */ + if (newtop == oldtop) { + ss->sprinter.offset = todo; + } else { + /* + * Kill newtop before the end_groupassignment: label by + * retracting/popping early. Control will either jump + * to do_forloop: or do_letheadbody: or else break from + * our case JSOP_POPN: after the switch (*pc2) below. + */ + LOCAL_ASSERT(newtop < oldtop); + ss->sprinter.offset = GetOff(ss, newtop); + ss->top = newtop; + } + + end_groupassignment: + LOCAL_ASSERT(*pc == JSOP_POPN); + + /* + * Thread directly to the next opcode if we can, to handle + * the special cases of a group assignment in the first or + * last part of a for(;;) loop head, or in a let block or + * expression head. + * + * NB: todo at this point indexes space in ss->sprinter + * that is liable to be overwritten. The code below knows + * exactly how long rval lives, or else copies it down via + * SprintCString. + */ + rval = OFF2STR(&ss->sprinter, todo); + todo = -2; + pc2 = pc + oplen; + if (*pc2 == JSOP_NOP) { + sn = js_GetSrcNote(jp->script, pc2); + if (sn) { + if (SN_TYPE(sn) == SRC_FOR) { + op = JSOP_NOP; + pc = pc2; + goto do_forloop; + } + + if (SN_TYPE(sn) == SRC_DECL) { + if (ss->top == StackDepth(jp->script)) { + /* + * This must be an empty destructuring + * in the head of a let whose body block + * is also empty. + */ + pc = pc2 + JSOP_NOP_LENGTH; + len = js_GetSrcNoteOffset(sn, 0); + LOCAL_ASSERT(pc[len] == JSOP_LEAVEBLOCK); + js_printf(jp, "\tlet (%s) {\n", rval); + js_printf(jp, "\t}\n"); + break; + } + todo = SprintCString(&ss->sprinter, rval); + if (todo < 0 || !PushOff(ss, todo, JSOP_NOP)) + return NULL; + op = JSOP_POP; + pc = pc2 + JSOP_NOP_LENGTH; + goto do_letheadbody; + } + } else { + /* + * An unnannotated NOP following a POPN must be the + * third part of for(;;) loop head. If the POPN's + * immediate operand is 0, then we may have no slot + * on the sprint-stack in which to push our result + * string. In this case the result can be recovered + * at ss->sprinter.base + ss->sprinter.offset. + */ + if (GET_UINT16(pc) == 0) + break; + todo = SprintCString(&ss->sprinter, rval); + saveop = JSOP_NOP; + } + } + + /* + * If control flow reaches this point with todo still -2, + * just print rval as an expression statement. + */ + if (todo == -2) + js_printf(jp, "\t%s;\n", rval); + break; + } +#endif + if (newtop < oldtop) { + ss->sprinter.offset = GetOff(ss, newtop); + ss->top = newtop; + } + break; + } + + case JSOP_EXCEPTION: + /* The catch decompiler handles this op itself. */ + LOCAL_ASSERT(JS_FALSE); + break; + + case JSOP_POP: + /* + * By default, do not automatically parenthesize when popping + * a stacked expression decompilation. We auto-parenthesize + * only when JSOP_POP is annotated with SRC_PCDELTA, meaning + * comma operator. + */ + op = JSOP_POPV; + /* FALL THROUGH */ + + case JSOP_POPV: + sn = js_GetSrcNote(jp->script, pc); + switch (sn ? SN_TYPE(sn) : SRC_NULL) { + case SRC_FOR: + /* Force parens around 'in' expression at 'for' front. */ + if (ss->opcodes[ss->top-1] == JSOP_IN) + op = JSOP_LSH; + rval = POP_STR(); + todo = -2; + goto do_forloop; + + case SRC_PCDELTA: + /* Comma operator: use JSOP_POP for correct precedence. */ + op = JSOP_POP; + + /* Pop and save to avoid blowing stack depth budget. */ + lval = JS_strdup(cx, POP_STR()); + if (!lval) + return NULL; + + /* + * The offset tells distance to the end of the right-hand + * operand of the comma operator. + */ + done = pc + len; + pc += js_GetSrcNoteOffset(sn, 0); + len = 0; + + if (!Decompile(ss, done, pc - done, JSOP_POP)) { + JS_free(cx, (char *)lval); + return NULL; + } + + /* Pop Decompile result and print comma expression. */ + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s, %s", lval, rval); + JS_free(cx, (char *)lval); + break; + + case SRC_HIDDEN: + /* Hide this pop, it's from a goto in a with or for/in. */ + todo = -2; + break; + + case SRC_DECL: + /* This pop is at the end of the let block/expr head. */ + pc += JSOP_POP_LENGTH; +#if JS_HAS_DESTRUCTURING + do_letheadbody: +#endif + len = js_GetSrcNoteOffset(sn, 0); + if (pc[len] == JSOP_LEAVEBLOCK) { + js_printf(jp, "\tlet (%s) {\n", POP_STR()); + jp->indent += 4; + DECOMPILE_CODE(pc, len); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + todo = -2; + } else { + LOCAL_ASSERT(pc[len] == JSOP_LEAVEBLOCKEXPR); + + lval = JS_strdup(cx, PopStr(ss, JSOP_NOP)); + if (!lval) + return NULL; + + /* Set saveop to reflect what we will push. */ + saveop = JSOP_LEAVEBLOCKEXPR; + if (!Decompile(ss, pc, len, saveop)) { + JS_free(cx, (char *)lval); + return NULL; + } + rval = PopStr(ss, JSOP_SETNAME); + todo = Sprint(&ss->sprinter, + (*rval == '{') + ? "let (%s) (%s)" + : "let (%s) %s", + lval, rval); + JS_free(cx, (char *)lval); + } + break; + + default: + /* Turn off parens around a yield statement. */ + if (ss->opcodes[ss->top-1] == JSOP_YIELD) + op = JSOP_NOP; + + rval = POP_STR(); + + /* + * Don't emit decompiler-pushed strings that are not + * handled by other opcodes. They are pushed onto the + * stack to help model the interpreter stack and should + * not appear in the decompiler's output. + */ + if (*rval != '\0' && (rval[0] != '/' || rval[1] != '*')) { + js_printf(jp, + (*rval == '{' || + (strncmp(rval, js_function_str, 8) == 0 && + rval[8] == ' ')) + ? "\t(%s);\n" + : "\t%s;\n", + rval); + } else { + LOCAL_ASSERT(*rval == '\0' || + strcmp(rval, exception_cookie) == 0); + } + todo = -2; + break; + } + sn = NULL; + break; + + case JSOP_ENTERWITH: + LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc)); + rval = POP_STR(); + js_printf(jp, "\twith (%s) {\n", rval); + jp->indent += 4; + todo = Sprint(&ss->sprinter, with_cookie); + break; + + case JSOP_LEAVEWITH: + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + break; + rval = POP_STR(); + LOCAL_ASSERT(strcmp(rval, with_cookie) == 0); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + break; + + case JSOP_ENTERBLOCK: + { + JSAtom **atomv, *smallv[5]; + JSScopeProperty *sprop; + + LOAD_OBJECT(0); + argc = OBJ_BLOCK_COUNT(cx, obj); + if ((size_t)argc <= JS_ARRAY_LENGTH(smallv)) { + atomv = smallv; + } else { + atomv = (JSAtom **) JS_malloc(cx, argc * sizeof(JSAtom *)); + if (!atomv) + return NULL; + } + + MUST_FLOW_THROUGH("enterblock_out"); +#define LOCAL_ASSERT_OUT(expr) LOCAL_ASSERT_CUSTOM(expr, ok = JS_FALSE; \ + goto enterblock_out) + for (sprop = OBJ_SCOPE(obj)->lastProp; sprop; + sprop = sprop->parent) { + if (!(sprop->flags & SPROP_HAS_SHORTID)) + continue; + LOCAL_ASSERT_OUT(sprop->shortid < argc); + atomv[sprop->shortid] = JSID_TO_ATOM(sprop->id); + } + ok = JS_TRUE; + for (i = 0; i < argc; i++) { + atom = atomv[i]; + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval || + !PushOff(ss, STR2OFF(&ss->sprinter, rval), op)) { + ok = JS_FALSE; + goto enterblock_out; + } + } + + sn = js_GetSrcNote(jp->script, pc); + switch (sn ? SN_TYPE(sn) : SRC_NULL) { +#if JS_HAS_BLOCK_SCOPE + case SRC_BRACE: + js_printf(jp, "\t{\n"); + jp->indent += 4; + len = js_GetSrcNoteOffset(sn, 0); + ok = Decompile(ss, pc + oplen, len - oplen, JSOP_NOP) + != NULL; + if (!ok) + goto enterblock_out; + jp->indent -= 4; + js_printf(jp, "\t}\n"); + break; +#endif + + case SRC_CATCH: + jp->indent -= 4; + js_printf(jp, "\t} catch ("); + + pc2 = pc; + pc += oplen; + LOCAL_ASSERT_OUT(*pc == JSOP_EXCEPTION); + pc += JSOP_EXCEPTION_LENGTH; + todo = Sprint(&ss->sprinter, exception_cookie); + if (todo < 0 || !PushOff(ss, todo, JSOP_EXCEPTION)) { + ok = JS_FALSE; + goto enterblock_out; + } + + if (*pc == JSOP_DUP) { + sn2 = js_GetSrcNote(jp->script, pc); + if (!sn2 || SN_TYPE(sn2) != SRC_DESTRUCT) { + /* + * This is a dup to save the exception for later. + * It is emitted only when the catch head contains + * an exception guard. + */ + LOCAL_ASSERT_OUT(js_GetSrcNoteOffset(sn, 0) != 0); + pc += JSOP_DUP_LENGTH; + todo = Sprint(&ss->sprinter, exception_cookie); + if (todo < 0 || + !PushOff(ss, todo, JSOP_EXCEPTION)) { + ok = JS_FALSE; + goto enterblock_out; + } + } + } + +#if JS_HAS_DESTRUCTURING + if (*pc == JSOP_DUP) { + pc = DecompileDestructuring(ss, pc, endpc); + if (!pc) { + ok = JS_FALSE; + goto enterblock_out; + } + LOCAL_ASSERT_OUT(*pc == JSOP_POP); + pc += JSOP_POP_LENGTH; + lval = PopStr(ss, JSOP_NOP); + js_puts(jp, lval); + } else { +#endif + LOCAL_ASSERT_OUT(*pc == JSOP_SETLOCALPOP); + i = GET_SLOTNO(pc) - jp->script->nfixed; + pc += JSOP_SETLOCALPOP_LENGTH; + atom = atomv[i - OBJ_BLOCK_DEPTH(cx, obj)]; + str = ATOM_TO_STRING(atom); + if (!QuoteString(&jp->sprinter, str, 0)) { + ok = JS_FALSE; + goto enterblock_out; + } +#if JS_HAS_DESTRUCTURING + } +#endif + + /* + * Pop the exception_cookie (or its dup in the case of a + * guarded catch head) off the stack now. + */ + rval = PopStr(ss, JSOP_NOP); + LOCAL_ASSERT_OUT(strcmp(rval, exception_cookie) == 0); + + len = js_GetSrcNoteOffset(sn, 0); + if (len) { + len -= PTRDIFF(pc, pc2, jsbytecode); + LOCAL_ASSERT_OUT(len > 0); + js_printf(jp, " if "); + ok = Decompile(ss, pc, len, JSOP_NOP) != NULL; + if (!ok) + goto enterblock_out; + js_printf(jp, "%s", POP_STR()); + pc += len; + LOCAL_ASSERT_OUT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX); + pc += js_CodeSpec[*pc].length; + } + + js_printf(jp, ") {\n"); + jp->indent += 4; + len = 0; + break; + default: + break; + } + + todo = -2; + +#undef LOCAL_ASSERT_OUT + enterblock_out: + if (atomv != smallv) + JS_free(cx, atomv); + if (!ok) + return NULL; + } + break; + + case JSOP_LEAVEBLOCK: + case JSOP_LEAVEBLOCKEXPR: + { + uintN top, depth; + + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + if (op == JSOP_LEAVEBLOCKEXPR) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_PCBASE); + rval = POP_STR(); + } else if (sn) { + LOCAL_ASSERT(op == JSOP_LEAVEBLOCK); + if (SN_TYPE(sn) == SRC_HIDDEN) + break; + + /* + * This JSOP_LEAVEBLOCK must be for a catch block. If sn's + * offset does not equal the model stack depth, there must + * be a copy of the exception value on the stack due to a + * catch guard (see above, the JSOP_ENTERBLOCK + SRC_CATCH + * case code). + */ + LOCAL_ASSERT(SN_TYPE(sn) == SRC_CATCH); + if ((uintN)js_GetSrcNoteOffset(sn, 0) != ss->top) { + LOCAL_ASSERT((uintN)js_GetSrcNoteOffset(sn, 0) + == ss->top - 1); + rval = POP_STR(); + LOCAL_ASSERT(strcmp(rval, exception_cookie) == 0); + } + } + top = ss->top; + depth = GET_UINT16(pc); + LOCAL_ASSERT(top >= depth); + top -= depth; + ss->top = top; + ss->sprinter.offset = GetOff(ss, top); + if (op == JSOP_LEAVEBLOCKEXPR) + todo = SprintCString(&ss->sprinter, rval); + break; + } + + case JSOP_CALLUPVAR: + case JSOP_GETUPVAR: + + if (!jp->fun) + JS_GET_SCRIPT_FUNCTION(jp->script, 0, jp->fun); + + if (!jp->localNames) + jp->localNames = js_GetLocalNameArray(cx, jp->fun, &jp->pool); + + i = JS_UPVAR_LOCAL_NAME_START(jp->fun) + GET_UINT16(pc); + if (i >= JS_GET_LOCAL_NAME_COUNT(jp->fun)) { + JSUpvarArray *uva; +#ifdef DEBUG + /* + * We must be in an eval called from jp->fun, where + * jp->script is the eval-compiled script. + * + * However, it's possible that a js_Invoke already + * pushed a frame trying to call js_Construct on an + * object that's not a constructor, causing us to be + * called with an intervening frame on the stack. + */ + JSStackFrame *fp = cx->fp; + if (fp) { + while (!(fp->flags & JSFRAME_EVAL)) + fp = fp->down; + JS_ASSERT(fp->script == jp->script); + JS_ASSERT(fp->down->fun == jp->fun); + JS_ASSERT(FUN_INTERPRETED(jp->fun)); + JS_ASSERT(jp->script != jp->fun->u.i.script); + JS_ASSERT(jp->script->upvarsOffset != 0); + } +#endif + uva = JS_SCRIPT_UPVARS(jp->script); + i = GET_UINT16(pc); + i = UPVAR_FRAME_SLOT(uva->vector[i]); + } + atom = GetArgOrVarAtom(jp, i); + goto do_name; + + case JSOP_CALLLOCAL: + case JSOP_GETLOCAL: + if (IsVarSlot(jp, pc, &i)) { + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + goto do_name; + } + LOCAL_ASSERT((uintN)i < ss->top); + sn = js_GetSrcNote(jp->script, pc); + +#if JS_HAS_DESTRUCTURING + if (sn && SN_TYPE(sn) == SRC_GROUPASSIGN) { + pc = DecompileGroupAssignment(ss, pc, endpc, sn, &todo); + if (!pc) + return NULL; + LOCAL_ASSERT(*pc == JSOP_POPN); + len = oplen = JSOP_POPN_LENGTH; + goto end_groupassignment; + } +#endif + + rval = GetLocal(ss, i); + todo = Sprint(&ss->sprinter, ss_format, VarPrefix(sn), rval); + break; + + case JSOP_SETLOCAL: + case JSOP_SETLOCALPOP: + if (IsVarSlot(jp, pc, &i)) { + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + goto do_setname; + } + lval = GetLocal(ss, i); + rval = POP_STR(); + goto do_setlval; + + case JSOP_INCLOCAL: + case JSOP_DECLOCAL: + if (IsVarSlot(jp, pc, &i)) { + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + goto do_incatom; + } + lval = GetLocal(ss, i); + goto do_inclval; + + case JSOP_LOCALINC: + case JSOP_LOCALDEC: + if (IsVarSlot(jp, pc, &i)) { + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + goto do_atominc; + } + lval = GetLocal(ss, i); + goto do_lvalinc; + + case JSOP_RETRVAL: + todo = -2; + break; + + case JSOP_RETURN: + LOCAL_ASSERT(jp->fun); + fun = jp->fun; + if (fun->flags & JSFUN_EXPR_CLOSURE) { + /* Turn on parens around comma-expression here. */ + op = JSOP_SETNAME; + rval = POP_STR(); + js_printf(jp, (*rval == '{') ? "(%s)%s" : ss_format, + rval, + ((fun->flags & JSFUN_LAMBDA) || !fun->atom) + ? "" + : ";"); + todo = -2; + break; + } + /* FALL THROUGH */ + + case JSOP_SETRVAL: + rval = POP_STR(); + if (*rval != '\0') + js_printf(jp, "\t%s %s;\n", js_return_str, rval); + else + js_printf(jp, "\t%s;\n", js_return_str); + todo = -2; + break; + +#if JS_HAS_GENERATORS + case JSOP_YIELD: +#if JS_HAS_GENERATOR_EXPRS + if (!ss->inGenExp || !(sn = js_GetSrcNote(jp->script, pc))) +#endif + { + /* Turn off most parens. */ + op = JSOP_SETNAME; + rval = POP_STR(); + todo = (*rval != '\0') + ? Sprint(&ss->sprinter, + (strncmp(rval, js_yield_str, 5) == 0 && + (rval[5] == ' ' || rval[5] == '\0')) + ? "%s (%s)" + : "%s %s", + js_yield_str, rval) + : SprintCString(&ss->sprinter, js_yield_str); + break; + } +#if JS_HAS_GENERATOR_EXPRS + LOCAL_ASSERT(SN_TYPE(sn) == SRC_HIDDEN); + /* FALL THROUGH */ +#endif + + case JSOP_ARRAYPUSH: + { + uintN pos, forpos; + ptrdiff_t start; + + /* Turn off most parens. */ + op = JSOP_SETNAME; + + /* Pop the expression being pushed or yielded. */ + rval = POP_STR(); + + /* + * Skip the for loop head stacked by JSOP_FORLOCAL until we hit + * a block local slot (note empty destructuring patterns result + * in unit-count blocks). + */ + pos = ss->top; + while (pos != 0) { + op = (JSOp) ss->opcodes[--pos]; + if (op == JSOP_ENTERBLOCK) + break; + } + JS_ASSERT(op == JSOP_ENTERBLOCK); + + /* + * Here, forpos must index the space before the left-most |for| + * in the single string of accumulated |for| heads and optional + * final |if (condition)|. + */ + forpos = pos + 2; + LOCAL_ASSERT(forpos < ss->top); + + /* + * Now move pos downward over the block's local slots. Even an + * empty destructuring pattern has one (dummy) local. + */ + while (ss->opcodes[pos] == JSOP_ENTERBLOCK) { + if (pos == 0) + break; + --pos; + } + JS_ASSERT_IF(saveop == JSOP_ARRAYPUSH, + jp->script->nfixed + pos == GET_UINT16(pc)); + +#if JS_HAS_GENERATOR_EXPRS + if (saveop == JSOP_YIELD) { + /* + * Generator expression: decompile just rval followed by + * the string starting at forpos. Leave the result string + * in ss->offsets[0] so it can be recovered by our caller + * (the JSOP_ANONFUNOBJ with SRC_GENEXP case). Bump the + * top of stack to balance yield, which is an expression + * (so has neutral stack balance). + */ + LOCAL_ASSERT(pos == 0); + xval = OFF2STR(&ss->sprinter, ss->offsets[forpos]); + ss->sprinter.offset = PAREN_SLOP; + todo = Sprint(&ss->sprinter, ss_format, rval, xval); + if (todo < 0) + return NULL; + ss->offsets[0] = todo; + ++ss->top; + return pc; + } +#endif /* JS_HAS_GENERATOR_EXPRS */ + + /* + * Array comprehension: retract the sprinter to the beginning + * of the array initialiser and decompile "[ for ...]". + */ + LOCAL_ASSERT(ss->opcodes[pos] == JSOP_NEWINIT); + start = ss->offsets[pos]; + LOCAL_ASSERT(ss->sprinter.base[start] == '[' || + ss->sprinter.base[start] == '#'); + LOCAL_ASSERT(forpos < ss->top); + xval = OFF2STR(&ss->sprinter, ss->offsets[forpos]); + lval = OFF2STR(&ss->sprinter, start); + RETRACT(&ss->sprinter, lval); + + todo = Sprint(&ss->sprinter, sss_format, lval, rval, xval); + if (todo < 0) + return NULL; + ss->offsets[pos] = todo; + todo = -2; + break; + } +#endif + + case JSOP_THROWING: + todo = -2; + break; + + case JSOP_THROW: + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + break; + rval = POP_STR(); + js_printf(jp, "\t%s %s;\n", js_throw_str, rval); + break; + + case JSOP_ITER: + foreach = (pc[1] & (JSITER_FOREACH | JSITER_KEYVALUE)) == + JSITER_FOREACH; + todo = SprintCString(&ss->sprinter, iter_cookie); + break; + + case JSOP_NEXTITER: + JS_NOT_REACHED("JSOP_NEXTITER"); + break; + + case JSOP_ENDITER: + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + break; + (void) PopOff(ss, op); + (void) PopOff(ss, op); + break; + + case JSOP_GOTO: + case JSOP_GOTOX: + sn = js_GetSrcNote(jp->script, pc); + switch (sn ? SN_TYPE(sn) : SRC_NULL) { + case SRC_FOR_IN: + /* + * The loop back-edge carries +1 stack balance, for the + * flag processed by JSOP_IFNE. We do not decompile the + * JSOP_IFNE, and instead push the left-hand side of 'in' + * after the loop edge in this stack slot (the JSOP_FOR* + * opcodes' decompilers do this pushing). + */ + cond = GetJumpOffset(pc, pc); + next = js_GetSrcNoteOffset(sn, 0); + tail = js_GetSrcNoteOffset(sn, 1); + JS_ASSERT(pc[cond] == JSOP_NEXTITER); + DECOMPILE_CODE(pc + oplen, next - oplen); + lval = POP_STR(); + if (ss->inArrayInit || ss->inGenExp) { + (void) PopOff(ss, JSOP_NOP); + rval = TOP_STR(); + LOCAL_ASSERT(ss->top >= 2); + if (ss->opcodes[ss->top - 2] == JSOP_FORLOCAL) { + ss->sprinter.offset = ss->offsets[ss->top - 1] - PAREN_SLOP; + if (Sprint(&ss->sprinter, " %s (%s in %s)", + foreach ? js_for_each_str : js_for_str, + lval, rval) < 0) { + return NULL; + } + + /* + * Do not AddParentSlop here, as we will push the + * top-most offset again, which will add paren slop + * for us. We must push to balance the stack budget + * when nesting for heads in a comprehension. + */ + todo = ss->offsets[ss->top - 1]; + } else { + LOCAL_ASSERT(ss->opcodes[ss->top - 2] == JSOP_ENTERBLOCK); + todo = Sprint(&ss->sprinter, " %s (%s in %s)", + foreach ? js_for_each_str : js_for_str, + lval, rval); + } + if (todo < 0 || !PushOff(ss, todo, JSOP_FORLOCAL)) + return NULL; + DECOMPILE_CODE(pc + next, cond - next); + } else { + /* + * As above, rval or an extension of it must remain + * stacked during loop body decompilation. + */ + rval = GetStr(ss, ss->top - 2); + js_printf(jp, "\t%s (%s in %s) {\n", + foreach ? js_for_each_str : js_for_str, + lval, rval); + jp->indent += 4; + DECOMPILE_CODE(pc + next, cond - next); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + } + pc += tail; + LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX); + len = js_CodeSpec[*pc].length; + break; + + case SRC_WHILE: + cond = GetJumpOffset(pc, pc); + tail = js_GetSrcNoteOffset(sn, 0); + DECOMPILE_CODE(pc + cond, tail - cond); + js_printf(jp, "\twhile (%s) {\n", POP_COND_STR()); + jp->indent += 4; + DECOMPILE_CODE(pc + oplen, cond - oplen); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + pc += tail; + LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX); + len = js_CodeSpec[*pc].length; + todo = -2; + break; + + case SRC_CONT2LABEL: + GET_SOURCE_NOTE_ATOM(sn, atom); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + js_printf(jp, "\tcontinue %s;\n", rval); + break; + + case SRC_CONTINUE: + js_printf(jp, "\tcontinue;\n"); + break; + + case SRC_BREAK2LABEL: + GET_SOURCE_NOTE_ATOM(sn, atom); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + js_printf(jp, "\tbreak %s;\n", rval); + break; + + case SRC_HIDDEN: + break; + + default: + js_printf(jp, "\tbreak;\n"); + break; + } + todo = -2; + break; + + case JSOP_IFEQ: + case JSOP_IFEQX: + { + JSBool elseif = JS_FALSE; + + if_again: + len = GetJumpOffset(pc, pc); + sn = js_GetSrcNote(jp->script, pc); + + switch (sn ? SN_TYPE(sn) : SRC_NULL) { + case SRC_IF: + case SRC_IF_ELSE: + rval = POP_COND_STR(); + if (ss->inArrayInit || ss->inGenExp) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_IF); + ss->sprinter.offset -= PAREN_SLOP; + if (Sprint(&ss->sprinter, " if (%s)", rval) < 0) + return NULL; + AddParenSlop(ss); + } else { + js_printf(jp, + elseif ? " if (%s) {\n" : "\tif (%s) {\n", + rval); + jp->indent += 4; + } + + if (SN_TYPE(sn) == SRC_IF) { + DECOMPILE_CODE(pc + oplen, len - oplen); + } else { + LOCAL_ASSERT(!ss->inArrayInit && !ss->inGenExp); + tail = js_GetSrcNoteOffset(sn, 0); + DECOMPILE_CODE(pc + oplen, tail - oplen); + jp->indent -= 4; + pc += tail; + LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX); + oplen = js_CodeSpec[*pc].length; + len = GetJumpOffset(pc, pc); + js_printf(jp, "\t} else"); + + /* + * If the second offset for sn is non-zero, it tells + * the distance from the goto around the else, to the + * ifeq for the if inside the else that forms an "if + * else if" chain. Thus cond spans the condition of + * the second if, so we simply decompile it and start + * over at label if_again. + */ + cond = js_GetSrcNoteOffset(sn, 1); + if (cond != 0) { + DECOMPILE_CODE(pc + oplen, cond - oplen); + pc += cond; + elseif = JS_TRUE; + goto if_again; + } + + js_printf(jp, " {\n"); + jp->indent += 4; + DECOMPILE_CODE(pc + oplen, len - oplen); + } + + if (!ss->inArrayInit && !ss->inGenExp) { + jp->indent -= 4; + js_printf(jp, "\t}\n"); + } + todo = -2; + break; + + case SRC_COND: + xval = JS_strdup(cx, POP_STR()); + if (!xval) + return NULL; + len = js_GetSrcNoteOffset(sn, 0); + DECOMPILE_CODE(pc + oplen, len - oplen); + lval = JS_strdup(cx, POP_STR()); + if (!lval) { + JS_free(cx, (void *)xval); + return NULL; + } + pc += len; + LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX); + oplen = js_CodeSpec[*pc].length; + len = GetJumpOffset(pc, pc); + DECOMPILE_CODE(pc + oplen, len - oplen); + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s ? %s : %s", + xval, lval, rval); + JS_free(cx, (void *)xval); + JS_free(cx, (void *)lval); + break; + + default: + break; + } + break; + } + + case JSOP_IFNE: + case JSOP_IFNEX: + LOCAL_ASSERT(0); + break; + + case JSOP_OR: + case JSOP_ORX: + xval = "||"; + + do_logical_connective: + /* Top of stack is the first clause in a disjunction (||). */ + lval = JS_strdup(cx, POP_STR()); + if (!lval) + return NULL; + done = pc + GetJumpOffset(pc, pc); + pc += len; + len = PTRDIFF(done, pc, jsbytecode); + if (!Decompile(ss, pc, len, op)) { + JS_free(cx, (char *)lval); + return NULL; + } + rval = POP_STR(); + if (jp->pretty && + jp->indent + 4 + strlen(lval) + 4 + strlen(rval) > 75) { + rval = JS_strdup(cx, rval); + if (!rval) { + tail = -1; + } else { + todo = Sprint(&ss->sprinter, "%s %s\n", lval, xval); + tail = Sprint(&ss->sprinter, "%*s%s", + jp->indent + 4, "", rval); + JS_free(cx, (char *)rval); + } + if (tail < 0) + todo = -1; + } else { + todo = Sprint(&ss->sprinter, "%s %s %s", lval, xval, rval); + } + JS_free(cx, (char *)lval); + break; + + case JSOP_AND: + case JSOP_ANDX: + xval = "&&"; + goto do_logical_connective; + + case JSOP_FORARG: + sn = NULL; + i = GET_ARGNO(pc); + goto do_forvarslot; + + case JSOP_FORLOCAL: + sn = js_GetSrcNote(jp->script, pc); + if (!IsVarSlot(jp, pc, &i)) { + JS_ASSERT(op == JSOP_FORLOCAL); + todo = Sprint(&ss->sprinter, ss_format, VarPrefix(sn), GetStr(ss, i)); + break; + } + + do_forvarslot: + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + todo = SprintCString(&ss->sprinter, VarPrefix(sn)); + if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) + return NULL; + break; + + case JSOP_FORNAME: + LOAD_ATOM(0); + sn = js_GetSrcNote(jp->script, pc); + todo = SprintCString(&ss->sprinter, VarPrefix(sn)); + if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) + return NULL; + break; + + case JSOP_FORPROP: + xval = NULL; + LOAD_ATOM(0); + if (!ATOM_IS_IDENTIFIER(atom)) { + xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), + (jschar)'\''); + if (!xval) + return NULL; + } + lval = POP_STR(); + if (xval) { + JS_ASSERT(*lval); + todo = Sprint(&ss->sprinter, index_format, lval, xval); + } else { + todo = Sprint(&ss->sprinter, ss_format, lval, *lval ? "." : ""); + if (todo < 0) + return NULL; + if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) + return NULL; + } + break; + + case JSOP_FORELEM: + todo = SprintCString(&ss->sprinter, forelem_cookie); + break; + + case JSOP_ENUMELEM: + case JSOP_ENUMCONSTELEM: + /* + * The stack has the object under the (top) index expression. + * The "rval" property id is underneath those two on the stack. + * The for loop body net and gross lengths can now be adjusted + * to account for the length of the indexing expression that + * came after JSOP_FORELEM and before JSOP_ENUMELEM. + */ + atom = NULL; + op = JSOP_NOP; /* turn off parens around xval */ + xval = POP_STR(); + op = JSOP_GETELEM; /* lval must have high precedence */ + lval = POP_STR(); + op = saveop; + rval = POP_STR(); + LOCAL_ASSERT(strcmp(rval, forelem_cookie) == 0); + if (*xval == '\0') { + todo = SprintCString(&ss->sprinter, lval); + } else { + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(lastop) == JOF_XMLNAME) + ? dot_format + : index_format, + lval, xval); + } + break; + +#if JS_HAS_GETTER_SETTER + case JSOP_GETTER: + case JSOP_SETTER: + todo = -2; + break; +#endif + + case JSOP_DUP2: + rval = GetStr(ss, ss->top-2); + todo = SprintCString(&ss->sprinter, rval); + if (todo < 0 || !PushOff(ss, todo, + (JSOp) ss->opcodes[ss->top-2])) { + return NULL; + } + /* FALL THROUGH */ + + case JSOP_DUP: +#if JS_HAS_DESTRUCTURING + sn = js_GetSrcNote(jp->script, pc); + if (sn) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_DESTRUCT); + pc = DecompileDestructuring(ss, pc, endpc); + if (!pc) + return NULL; + len = 0; + lval = POP_STR(); + op = saveop = JSOP_ENUMELEM; + rval = POP_STR(); + + if (strcmp(rval, forelem_cookie) == 0) { + todo = Sprint(&ss->sprinter, ss_format, + VarPrefix(sn), lval); + + // Skip POP so the SRC_FOR_IN code can pop for itself. + if (*pc == JSOP_POP) + len = JSOP_POP_LENGTH; + } else { + todo = Sprint(&ss->sprinter, "%s%s = %s", + VarPrefix(sn), lval, rval); + } + break; + } +#endif + + rval = GetStr(ss, ss->top-1); + saveop = (JSOp) ss->opcodes[ss->top-1]; + todo = SprintCString(&ss->sprinter, rval); + break; + + case JSOP_SETARG: + atom = GetArgOrVarAtom(jp, GET_ARGNO(pc)); + LOCAL_ASSERT(atom); + goto do_setname; + + case JSOP_SETCONST: + case JSOP_SETNAME: + case JSOP_SETGVAR: + LOAD_ATOM(0); + + do_setname: + lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!lval) + return NULL; + rval = POP_STR(); + if (op == JSOP_SETNAME) + (void) PopOff(ss, op); + + do_setlval: + sn = js_GetSrcNote(jp->script, pc - 1); + if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) { + todo = Sprint(&ss->sprinter, "%s %s= %s", + lval, + (lastop == JSOP_GETTER) + ? js_getter_str + : (lastop == JSOP_SETTER) + ? js_setter_str + : CodeToken[lastop], + rval); + } else { + sn = js_GetSrcNote(jp->script, pc); + todo = Sprint(&ss->sprinter, "%s%s = %s", + VarPrefix(sn), lval, rval); + } + if (op == JSOP_SETLOCALPOP) { + if (!PushOff(ss, todo, saveop)) + return NULL; + rval = POP_STR(); + LOCAL_ASSERT(*rval != '\0'); + js_printf(jp, "\t%s;\n", rval); + todo = -2; + } + break; + + case JSOP_NEW: + case JSOP_CALL: + case JSOP_EVAL: + case JSOP_APPLY: +#if JS_HAS_LVALUE_RETURN + case JSOP_SETCALL: +#endif + /* Turn off most parens (all if there's only one argument). */ + argc = GET_ARGC(pc); + op = (argc == 1) ? JSOP_NOP : JSOP_SETNAME; + argv = (char **) + JS_malloc(cx, (size_t)(argc + 1) * sizeof *argv); + if (!argv) + return NULL; + + ok = JS_TRUE; + for (i = argc; i > 0; i--) { + argv[i] = JS_strdup(cx, POP_STR()); + if (!argv[i]) + ok = JS_FALSE; + } + + /* Skip the JSOP_PUSHOBJ-created empty string. */ + LOCAL_ASSERT(ss->top >= 2); + (void) PopOff(ss, op); + + /* + * Special case: new (x(y)(z)) must be parenthesized like so. + * Same for new (x(y).z) -- contrast with new x(y).z. + * See PROPAGATE_CALLNESS. + */ + op = (JSOp) ss->opcodes[ss->top-1]; + lval = PopStr(ss, + (saveop == JSOP_NEW && + (op == JSOP_CALL || + op == JSOP_EVAL || + op == JSOP_APPLY || + (js_CodeSpec[op].format & JOF_CALLOP))) + ? JSOP_NAME + : saveop); + op = saveop; + + argv[0] = JS_strdup(cx, lval); + if (!argv[i]) + ok = JS_FALSE; + + lval = "(", rval = ")"; + if (op == JSOP_NEW) { + if (argc == 0) + lval = rval = ""; + todo = Sprint(&ss->sprinter, "%s %s%s", + js_new_str, argv[0], lval); + } else { + todo = Sprint(&ss->sprinter, ss_format, + argv[0], lval); + } + if (todo < 0) + ok = JS_FALSE; + + for (i = 1; i <= argc; i++) { + if (!argv[i] || + Sprint(&ss->sprinter, ss_format, + argv[i], (i < argc) ? ", " : "") < 0) { + ok = JS_FALSE; + break; + } + } + if (Sprint(&ss->sprinter, rval) < 0) + ok = JS_FALSE; + + for (i = 0; i <= argc; i++) { + if (argv[i]) + JS_free(cx, argv[i]); + } + JS_free(cx, argv); + if (!ok) + return NULL; +#if JS_HAS_LVALUE_RETURN + if (op == JSOP_SETCALL) { + if (!PushOff(ss, todo, op)) + return NULL; + todo = Sprint(&ss->sprinter, ""); + } +#endif + break; + + case JSOP_DELNAME: + LOAD_ATOM(0); + lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!lval) + return NULL; + RETRACT(&ss->sprinter, lval); + do_delete_lval: + todo = Sprint(&ss->sprinter, "%s %s", js_delete_str, lval); + break; + + case JSOP_DELPROP: + GET_ATOM_QUOTE_AND_FMT("%s %s[%s]", "%s %s.%s", rval); + op = JSOP_GETPROP; + lval = POP_STR(); + todo = Sprint(&ss->sprinter, fmt, js_delete_str, lval, rval); + break; + + case JSOP_DELELEM: + op = JSOP_NOP; /* turn off parens */ + xval = POP_STR(); + op = JSOP_GETPROP; + lval = POP_STR(); + if (*xval == '\0') + goto do_delete_lval; + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(lastop) == JOF_XMLNAME) + ? "%s %s.%s" + : "%s %s[%s]", + js_delete_str, lval, xval); + break; + +#if JS_HAS_XML_SUPPORT + case JSOP_DELDESC: + xval = POP_STR(); + op = JSOP_GETPROP; + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s %s..%s", + js_delete_str, lval, xval); + break; +#endif + + case JSOP_TYPEOFEXPR: + case JSOP_TYPEOF: + case JSOP_VOID: + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s %s", + (op == JSOP_VOID) ? js_void_str : js_typeof_str, + rval); + break; + + case JSOP_INCARG: + case JSOP_DECARG: + atom = GetArgOrVarAtom(jp, GET_ARGNO(pc)); + LOCAL_ASSERT(atom); + goto do_incatom; + + case JSOP_INCNAME: + case JSOP_DECNAME: + case JSOP_INCGVAR: + case JSOP_DECGVAR: + LOAD_ATOM(0); + do_incatom: + lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!lval) + return NULL; + RETRACT(&ss->sprinter, lval); + do_inclval: + todo = Sprint(&ss->sprinter, ss_format, + js_incop_strs[!(cs->format & JOF_INC)], lval); + break; + + case JSOP_INCPROP: + case JSOP_DECPROP: + GET_ATOM_QUOTE_AND_FMT(preindex_format, predot_format, rval); + + /* + * Force precedence below the numeric literal opcodes, so that + * 42..foo or 10000..toString(16), e.g., decompile with parens + * around the left-hand side of dot. + */ + op = JSOP_GETPROP; + lval = POP_STR(); + todo = Sprint(&ss->sprinter, fmt, + js_incop_strs[!(cs->format & JOF_INC)], + lval, rval); + break; + + case JSOP_INCELEM: + case JSOP_DECELEM: + op = JSOP_NOP; /* turn off parens */ + xval = POP_STR(); + op = JSOP_GETELEM; + lval = POP_STR(); + if (*xval != '\0') { + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(lastop) == JOF_XMLNAME) + ? predot_format + : preindex_format, + js_incop_strs[!(cs->format & JOF_INC)], + lval, xval); + } else { + todo = Sprint(&ss->sprinter, ss_format, + js_incop_strs[!(cs->format & JOF_INC)], lval); + } + break; + + case JSOP_ARGINC: + case JSOP_ARGDEC: + atom = GetArgOrVarAtom(jp, GET_ARGNO(pc)); + LOCAL_ASSERT(atom); + goto do_atominc; + + case JSOP_NAMEINC: + case JSOP_NAMEDEC: + case JSOP_GVARINC: + case JSOP_GVARDEC: + LOAD_ATOM(0); + do_atominc: + lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!lval) + return NULL; + RETRACT(&ss->sprinter, lval); + do_lvalinc: + todo = Sprint(&ss->sprinter, ss_format, + lval, js_incop_strs[!(cs->format & JOF_INC)]); + break; + + case JSOP_PROPINC: + case JSOP_PROPDEC: + GET_ATOM_QUOTE_AND_FMT(postindex_format, postdot_format, rval); + + /* + * Force precedence below the numeric literal opcodes, so that + * 42..foo or 10000..toString(16), e.g., decompile with parens + * around the left-hand side of dot. + */ + op = JSOP_GETPROP; + lval = POP_STR(); + todo = Sprint(&ss->sprinter, fmt, lval, rval, + js_incop_strs[!(cs->format & JOF_INC)]); + break; + + case JSOP_ELEMINC: + case JSOP_ELEMDEC: + op = JSOP_NOP; /* turn off parens */ + xval = POP_STR(); + op = JSOP_GETELEM; + lval = POP_STR(); + if (*xval != '\0') { + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(lastop) == JOF_XMLNAME) + ? postdot_format + : postindex_format, + lval, xval, + js_incop_strs[!(cs->format & JOF_INC)]); + } else { + todo = Sprint(&ss->sprinter, ss_format, + lval, js_incop_strs[!(cs->format & JOF_INC)]); + } + break; + + case JSOP_LENGTH: + fmt = dot_format; + rval = js_length_str; + goto do_getprop_lval; + + case JSOP_GETPROP2: + op = JSOP_GETPROP; + (void) PopOff(ss, lastop); + /* FALL THROUGH */ + + case JSOP_CALLPROP: + case JSOP_GETPROP: + case JSOP_GETXPROP: + LOAD_ATOM(0); + + do_getprop: + GET_QUOTE_AND_FMT(index_format, dot_format, rval); + do_getprop_lval: + PROPAGATE_CALLNESS(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, fmt, lval, rval); + break; + + case JSOP_GETTHISPROP: + LOAD_ATOM(0); + GET_QUOTE_AND_FMT(index_format, dot_format, rval); + todo = Sprint(&ss->sprinter, fmt, js_this_str, rval); + break; + + case JSOP_GETARGPROP: + /* Get the name of the argument or variable. */ + i = GET_ARGNO(pc); + + do_getarg_prop: + atom = GetArgOrVarAtom(ss->printer, i); + LOCAL_ASSERT(atom); + LOCAL_ASSERT(ATOM_IS_STRING(atom)); + lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!lval || !PushOff(ss, STR2OFF(&ss->sprinter, lval), op)) + return NULL; + + /* Get the name of the property. */ + LOAD_ATOM(ARGNO_LEN); + goto do_getprop; + + case JSOP_GETLOCALPROP: + if (IsVarSlot(jp, pc, &i)) + goto do_getarg_prop; + LOCAL_ASSERT((uintN)i < ss->top); + lval = GetLocal(ss, i); + if (!lval) + return NULL; + todo = SprintCString(&ss->sprinter, lval); + if (todo < 0 || !PushOff(ss, todo, op)) + return NULL; + LOAD_ATOM(2); + goto do_getprop; + + case JSOP_SETPROP: + LOAD_ATOM(0); + GET_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval); + rval = POP_STR(); + + /* + * Force precedence below the numeric literal opcodes, so that + * 42..foo or 10000..toString(16), e.g., decompile with parens + * around the left-hand side of dot. + */ + op = JSOP_GETPROP; + lval = POP_STR(); + sn = js_GetSrcNote(jp->script, pc - 1); + todo = Sprint(&ss->sprinter, fmt, lval, xval, + (sn && SN_TYPE(sn) == SRC_ASSIGNOP) + ? (lastop == JSOP_GETTER) + ? js_getter_str + : (lastop == JSOP_SETTER) + ? js_setter_str + : CodeToken[lastop] + : "", + rval); + break; + + case JSOP_GETELEM2: + op = JSOP_GETELEM; + (void) PopOff(ss, lastop); + /* FALL THROUGH */ + + case JSOP_CALLELEM: + case JSOP_GETELEM: + op = JSOP_NOP; /* turn off parens */ + xval = POP_STR(); + op = saveop; + PROPAGATE_CALLNESS(); + lval = POP_STR(); + if (*xval == '\0') { + todo = Sprint(&ss->sprinter, "%s", lval); + } else { + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(lastop) == JOF_XMLNAME) + ? dot_format + : index_format, + lval, xval); + } + break; + + case JSOP_SETELEM: + rval = POP_STR(); + op = JSOP_NOP; /* turn off parens */ + xval = POP_STR(); + cs = &js_CodeSpec[ss->opcodes[ss->top]]; + op = JSOP_GETELEM; /* lval must have high precedence */ + lval = POP_STR(); + op = saveop; + if (*xval == '\0') + goto do_setlval; + sn = js_GetSrcNote(jp->script, pc - 1); + todo = Sprint(&ss->sprinter, + (JOF_MODE(cs->format) == JOF_XMLNAME) + ? "%s.%s %s= %s" + : "%s[%s] %s= %s", + lval, xval, + (sn && SN_TYPE(sn) == SRC_ASSIGNOP) + ? (lastop == JSOP_GETTER) + ? js_getter_str + : (lastop == JSOP_SETTER) + ? js_setter_str + : CodeToken[lastop] + : "", + rval); + break; + + case JSOP_ARGSUB: + i = (jsint) GET_ARGNO(pc); + todo = Sprint(&ss->sprinter, "%s[%d]", + js_arguments_str, (int) i); + break; + + case JSOP_ARGCNT: + todo = Sprint(&ss->sprinter, dot_format, + js_arguments_str, js_length_str); + break; + + case JSOP_CALLARG: + case JSOP_GETARG: + i = GET_ARGNO(pc); + atom = GetArgOrVarAtom(jp, i); +#if JS_HAS_DESTRUCTURING + if (!atom) { + todo = Sprint(&ss->sprinter, "%s[%d]", js_arguments_str, i); + break; + } +#else + LOCAL_ASSERT(atom); +#endif + goto do_name; + + case JSOP_CALLNAME: + case JSOP_NAME: + case JSOP_GETGVAR: + case JSOP_CALLGVAR: + LOAD_ATOM(0); + do_name: + lval = ""; +#if JS_HAS_XML_SUPPORT + do_qname: +#endif + sn = js_GetSrcNote(jp->script, pc); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), + inXML ? DONT_ESCAPE : 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + todo = Sprint(&ss->sprinter, sss_format, + VarPrefix(sn), lval, rval); + break; + + case JSOP_UINT16: + i = (jsint) GET_UINT16(pc); + goto do_sprint_int; + + case JSOP_UINT24: + i = (jsint) GET_UINT24(pc); + goto do_sprint_int; + + case JSOP_INT8: + i = GET_INT8(pc); + goto do_sprint_int; + + case JSOP_INT32: + i = GET_INT32(pc); + do_sprint_int: + todo = Sprint(&ss->sprinter, "%d", i); + break; + + case JSOP_DOUBLE: + LOAD_ATOM(0); + val = ATOM_KEY(atom); + LOCAL_ASSERT(JSVAL_IS_DOUBLE(val)); + todo = SprintDoubleValue(&ss->sprinter, val, &saveop); + break; + + case JSOP_STRING: + LOAD_ATOM(0); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), + inXML ? DONT_ESCAPE : '"'); + if (!rval) + return NULL; + todo = STR2OFF(&ss->sprinter, rval); + break; + + case JSOP_ANONFUNOBJ: +#if JS_HAS_GENERATOR_EXPRS + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_GENEXP) { + JSScript *inner, *outer; + void *mark; + SprintStack ss2; + + LOAD_FUNCTION(0); + inner = fun->u.i.script; + + /* + * All allocation when decompiling is LIFO, using malloc + * or, more commonly, arena-alloocating from cx->tempPool. + * After InitSprintStack succeeds, we must release to mark + * before returning. + */ + mark = JS_ARENA_MARK(&cx->tempPool); + if (!InitSprintStack(cx, &ss2, jp, StackDepth(inner))) + return NULL; + ss2.inGenExp = JS_TRUE; + + /* + * Recursively decompile this generator function as an + * un-parenthesized generator expression. The ss->inGenExp + * special case of JSOP_YIELD shares array comprehension + * decompilation code that leaves the result as the single + * string pushed on ss2. + */ + outer = jp->script; + LOCAL_ASSERT(JS_UPTRDIFF(pc, outer->code) <= outer->length); + jp->script = inner; + if (!Decompile(&ss2, inner->code, inner->length, JSOP_NOP)) { + JS_ARENA_RELEASE(&cx->tempPool, mark); + return NULL; + } + jp->script = outer; + + /* + * Advance over this op and its global |this| push, and + * arrange to advance over the call to this lambda. + */ + pc += len; + LOCAL_ASSERT(*pc == JSOP_NULL || *pc == JSOP_NULLTHIS); + pc += JSOP_NULL_LENGTH; + LOCAL_ASSERT(*pc == JSOP_CALL); + LOCAL_ASSERT(GET_ARGC(pc) == 0); + len = JSOP_CALL_LENGTH; + + /* + * Arrange to parenthesize this genexp unless: + * + * 1. It is the complete expression consumed by a control + * flow bytecode such as JSOP_TABLESWITCH whose syntax + * always parenthesizes the controlling expression. + * 2. It is the condition of a loop other than a for (;;). + * 3. It is the sole argument to a function call. + * 4. It is the condition of an if statement and not of a + * ?: expression. + * + * But (first, before anything else) always parenthesize + * if this genexp runs up against endpc and the next op is + * not a loop condition (JSOP_IFNE*) opcode. In such cases, + * this Decompile activation has been recursively called by + * a comma operator, &&, or || bytecode. + */ + pc2 = pc + len; + LOCAL_ASSERT(pc2 < endpc || + endpc < outer->code + outer->length); + LOCAL_ASSERT(ss2.top == 1); + ss2.opcodes[0] = JSOP_POP; + if (pc2 == endpc && + (JSOp) *endpc != JSOP_IFNE && + (JSOp) *endpc != JSOP_IFNEX) { + op = JSOP_SETNAME; + } else { + op = (JSOp) *pc2; + op = ((js_CodeSpec[op].format & JOF_PARENHEAD) || + ((js_CodeSpec[op].format & JOF_INVOKE) && + GET_ARGC(pc2) == 1) || + ((op == JSOP_IFEQ || op == JSOP_IFEQX) && + (sn2 = js_GetSrcNote(outer, pc2)) && + SN_TYPE(sn2) != SRC_COND)) + ? JSOP_POP + : JSOP_SETNAME; + + /* + * Stack this result as if it's a name and not an + * anonymous function, so it doesn't get decompiled as + * a generator function in a getter or setter context. + * The precedence level is the same for JSOP_NAME and + * JSOP_ANONFUNOBJ. + */ + LOCAL_ASSERT(js_CodeSpec[JSOP_NAME].prec == + js_CodeSpec[saveop].prec); + saveop = JSOP_NAME; + } + + /* + * Alas, we have to malloc a copy of the result left on + * the top of ss2 because both ss and ss2 arena-allocate + * from cx's tempPool. + */ + rval = JS_strdup(cx, PopStr(&ss2, op)); + JS_ARENA_RELEASE(&cx->tempPool, mark); + if (!rval) + return NULL; + todo = SprintCString(&ss->sprinter, rval); + JS_free(cx, (void *)rval); + break; + } +#endif /* JS_HAS_GENERATOR_EXPRS */ + /* FALL THROUGH */ + + case JSOP_NAMEDFUNOBJ: + LOAD_FUNCTION(0); + { + uintN indent = JS_DONT_PRETTY_PRINT; + + /* + * Always parenthesize expression closures. We can't force + * saveop to a low-precedence op to arrange for auto-magic + * parenthesization without confusing getter/setter code + * that checks for JSOP_ANONFUNOBJ and JSOP_NAMEDFUNOBJ. + */ + if (!(fun->flags & JSFUN_EXPR_CLOSURE)) + indent |= JS_IN_GROUP_CONTEXT; + str = JS_DecompileFunction(cx, fun, indent); + if (!str) + return NULL; + } + sprint_string: + todo = SprintString(&ss->sprinter, str); + break; + + case JSOP_OBJECT: + LOAD_OBJECT(0); + LOCAL_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass); + goto do_regexp; + + case JSOP_REGEXP: + GET_REGEXP_FROM_BYTECODE(jp->script, pc, 0, obj); + do_regexp: + if (!js_regexp_toString(cx, obj, &val)) + return NULL; + str = JSVAL_TO_STRING(val); + goto sprint_string; + + case JSOP_TABLESWITCH: + case JSOP_TABLESWITCHX: + { + ptrdiff_t jmplen, off, off2; + jsint j, n, low, high; + TableEntry *table, *tmp; + + sn = js_GetSrcNote(jp->script, pc); + LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); + len = js_GetSrcNoteOffset(sn, 0); + jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN + : JUMPX_OFFSET_LEN; + pc2 = pc; + off = GetJumpOffset(pc, pc2); + pc2 += jmplen; + low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + + n = high - low + 1; + if (n == 0) { + table = NULL; + j = 0; + ok = JS_TRUE; + } else { + table = (TableEntry *) + JS_malloc(cx, (size_t)n * sizeof *table); + if (!table) + return NULL; + for (i = j = 0; i < n; i++) { + table[j].label = NULL; + off2 = GetJumpOffset(pc, pc2); + if (off2) { + sn = js_GetSrcNote(jp->script, pc2); + if (sn) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_LABEL); + GET_SOURCE_NOTE_ATOM(sn, table[j].label); + } + table[j].key = INT_TO_JSVAL(low + i); + table[j].offset = off2; + table[j].order = j; + j++; + } + pc2 += jmplen; + } + tmp = (TableEntry *) + JS_malloc(cx, (size_t)j * sizeof *table); + if (tmp) { + ok = js_MergeSort(table, (size_t)j, sizeof(TableEntry), + CompareOffsets, NULL, tmp); + JS_free(cx, tmp); + } else { + ok = JS_FALSE; + } + } + + if (ok) { + ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off, + JS_FALSE); + } + JS_free(cx, table); + if (!ok) + return NULL; + todo = -2; + break; + } + + case JSOP_LOOKUPSWITCH: + case JSOP_LOOKUPSWITCHX: + { + ptrdiff_t jmplen, off, off2; + jsatomid npairs, k; + TableEntry *table; + + sn = js_GetSrcNote(jp->script, pc); + LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); + len = js_GetSrcNoteOffset(sn, 0); + jmplen = (op == JSOP_LOOKUPSWITCH) ? JUMP_OFFSET_LEN + : JUMPX_OFFSET_LEN; + pc2 = pc; + off = GetJumpOffset(pc, pc2); + pc2 += jmplen; + npairs = GET_UINT16(pc2); + pc2 += UINT16_LEN; + + table = (TableEntry *) + JS_malloc(cx, (size_t)npairs * sizeof *table); + if (!table) + return NULL; + for (k = 0; k < npairs; k++) { + sn = js_GetSrcNote(jp->script, pc2); + if (sn) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_LABEL); + GET_SOURCE_NOTE_ATOM(sn, table[k].label); + } else { + table[k].label = NULL; + } + JS_GET_SCRIPT_ATOM(jp->script, GET_INDEX(pc2), atom); + pc2 += INDEX_LEN; + off2 = GetJumpOffset(pc, pc2); + pc2 += jmplen; + table[k].key = ATOM_KEY(atom); + table[k].offset = off2; + } + + ok = DecompileSwitch(ss, table, (uintN)npairs, pc, len, off, + JS_FALSE); + JS_free(cx, table); + if (!ok) + return NULL; + todo = -2; + break; + } + + case JSOP_CONDSWITCH: + { + ptrdiff_t off, off2, caseOff; + jsint ncases; + TableEntry *table; + + sn = js_GetSrcNote(jp->script, pc); + LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); + len = js_GetSrcNoteOffset(sn, 0); + off = js_GetSrcNoteOffset(sn, 1); + + /* + * Count the cases using offsets from switch to first case, + * and case to case, stored in srcnote immediates. + */ + pc2 = pc; + off2 = off; + for (ncases = 0; off2 != 0; ncases++) { + pc2 += off2; + LOCAL_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT || + *pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX); + if (*pc2 == JSOP_DEFAULT || *pc2 == JSOP_DEFAULTX) { + /* End of cases, but count default as a case. */ + off2 = 0; + } else { + sn = js_GetSrcNote(jp->script, pc2); + LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_PCDELTA); + off2 = js_GetSrcNoteOffset(sn, 0); + } + } + + /* + * Allocate table and rescan the cases using their srcnotes, + * stashing each case's delta from switch top in table[i].key, + * and the distance to its statements in table[i].offset. + */ + table = (TableEntry *) + JS_malloc(cx, (size_t)ncases * sizeof *table); + if (!table) + return NULL; + pc2 = pc; + off2 = off; + for (i = 0; i < ncases; i++) { + pc2 += off2; + LOCAL_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT || + *pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX); + caseOff = pc2 - pc; + table[i].key = INT_TO_JSVAL((jsint) caseOff); + table[i].offset = caseOff + GetJumpOffset(pc2, pc2); + if (*pc2 == JSOP_CASE || *pc2 == JSOP_CASEX) { + sn = js_GetSrcNote(jp->script, pc2); + LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_PCDELTA); + off2 = js_GetSrcNoteOffset(sn, 0); + } + } + + /* + * Find offset of default code by fetching the default offset + * from the end of table. JSOP_CONDSWITCH always has a default + * case at the end. + */ + off = JSVAL_TO_INT(table[ncases-1].key); + pc2 = pc + off; + off += GetJumpOffset(pc2, pc2); + + ok = DecompileSwitch(ss, table, (uintN)ncases, pc, len, off, + JS_TRUE); + JS_free(cx, table); + if (!ok) + return NULL; + todo = -2; + break; + } + + case JSOP_CASE: + case JSOP_CASEX: + { + lval = POP_STR(); + if (!lval) + return NULL; + js_printf(jp, "\tcase %s:\n", lval); + todo = -2; + break; + } + + case JSOP_DEFFUN: + LOAD_FUNCTION(0); + todo = -2; + goto do_function; + break; + + case JSOP_TRAP: + saveop = op = JS_GetTrapOpcode(cx, jp->script, pc); + *pc = op; + cs = &js_CodeSpec[op]; + len = cs->length; + DECOMPILE_CODE(pc, len); + *pc = JSOP_TRAP; + todo = -2; + break; + + case JSOP_HOLE: + todo = SprintPut(&ss->sprinter, "", 0); + break; + + case JSOP_NEWARRAY: + { + ptrdiff_t off; + char *base, *from, *to; + + /* + * All operands are stacked and ready for in-place formatting. + * We know that PAREN_SLOP is 3 here, and take advantage of it + * to avoid strdup'ing. + */ + argc = GET_UINT24(pc); + LOCAL_ASSERT(ss->top >= (uintN) argc); + sn = js_GetSrcNote(jp->script, pc); + if (argc == 0) { + todo = Sprint(&ss->sprinter, "[%s]", + (sn && SN_TYPE(sn) == SRC_CONTINUE) + ? ", " + : ""); + } else { + ss->top -= argc; + off = GetOff(ss, ss->top); + LOCAL_ASSERT(off >= PAREN_SLOP); + base = OFF2STR(&ss->sprinter, off); + to = base + 1; + i = 0; + for (;;) { + /* Move to the next string that had been stacked. */ + from = OFF2STR(&ss->sprinter, off); + todo = strlen(from); + memmove(to, from, todo); + to += todo; + if (++i == argc && + !(sn && SN_TYPE(sn) == SRC_CONTINUE)) { + break; + } + *to++ = ','; + *to++ = ' '; + off = GetOff(ss, ss->top + i); + } + LOCAL_ASSERT(to - base < ss->sprinter.offset - PAREN_SLOP); + *base = '['; + *to++ = ']'; + *to = '\0'; + ss->sprinter.offset = STR2OFF(&ss->sprinter, to); + todo = STR2OFF(&ss->sprinter, base); + } + break; + } + + case JSOP_NEWINIT: + { + i = GET_INT8(pc); + LOCAL_ASSERT(i == JSProto_Array || i == JSProto_Object); + + todo = ss->sprinter.offset; +#if JS_HAS_SHARP_VARS + op = (JSOp)pc[len]; + if (op == JSOP_DEFSHARP) { + pc += len; + cs = &js_CodeSpec[op]; + len = cs->length; + if (Sprint(&ss->sprinter, "#%u=", + (unsigned) (jsint) GET_UINT16(pc)) < 0) + return NULL; + } +#endif /* JS_HAS_SHARP_VARS */ + if (i == JSProto_Array) { + ++ss->inArrayInit; + if (SprintCString(&ss->sprinter, "[") < 0) + return NULL; + } else { + if (SprintCString(&ss->sprinter, "{") < 0) + return NULL; + } + break; + } + + case JSOP_ENDINIT: + { + JSBool inArray; + + op = JSOP_NOP; /* turn off parens */ + rval = POP_STR(); + sn = js_GetSrcNote(jp->script, pc); + + /* Skip any #n= prefix to find the opening bracket. */ + for (xval = rval; *xval != '[' && *xval != '{'; xval++) + continue; + inArray = (*xval == '['); + if (inArray) + --ss->inArrayInit; + todo = Sprint(&ss->sprinter, "%s%s%c", + rval, + (sn && SN_TYPE(sn) == SRC_CONTINUE) ? ", " : "", + inArray ? ']' : '}'); + break; + } + + { + JSBool isFirst; + const char *maybeComma; + + case JSOP_INITELEM: + isFirst = (ss->opcodes[ss->top - 3] == JSOP_NEWINIT); + + /* Turn off most parens. */ + op = JSOP_SETNAME; + rval = POP_STR(); + + /* Turn off all parens for xval and lval, which we control. */ + op = JSOP_NOP; + xval = POP_STR(); + lval = POP_STR(); + sn = js_GetSrcNote(jp->script, pc); + + if (sn && SN_TYPE(sn) == SRC_INITPROP) { + atom = NULL; + goto do_initprop; + } + maybeComma = isFirst ? "" : ", "; + todo = Sprint(&ss->sprinter, sss_format, + lval, + maybeComma, + rval); + break; + + case JSOP_INITPROP: + LOAD_ATOM(0); + xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), + (jschar) + (ATOM_IS_IDENTIFIER(atom) ? 0 : '\'')); + if (!xval) + return NULL; + isFirst = (ss->opcodes[ss->top - 2] == JSOP_NEWINIT); + rval = POP_STR(); + lval = POP_STR(); + /* fall through */ + + do_initprop: + maybeComma = isFirst ? "" : ", "; +#ifdef OLD_GETTER_SETTER + todo = Sprint(&ss->sprinter, "%s%s%s%s%s%s%s:%s", + lval, + maybeComma, + xval, + (lastop == JSOP_GETTER || lastop == JSOP_SETTER) + ? " " : "", + (lastop == JSOP_GETTER) ? js_getter_str : + (lastop == JSOP_SETTER) ? js_setter_str : + "", + rval); +#else + if (lastop == JSOP_GETTER || lastop == JSOP_SETTER) { + if (!atom || + !ATOM_IS_STRING(atom) || + !ATOM_IS_IDENTIFIER(atom) || + ATOM_IS_KEYWORD(atom) || + (ss->opcodes[ss->top+1] != JSOP_ANONFUNOBJ && + ss->opcodes[ss->top+1] != JSOP_NAMEDFUNOBJ)) { + todo = Sprint(&ss->sprinter, "%s%s%s %s: %s", + lval, + maybeComma, + xval, + (lastop == JSOP_GETTER) ? js_getter_str : + (lastop == JSOP_SETTER) ? js_setter_str : + "", + rval); + } else { + const char *end = rval + strlen(rval); + + if (*rval == '(') + ++rval, --end; + LOCAL_ASSERT(strncmp(rval, js_function_str, 8) == 0); + LOCAL_ASSERT(rval[8] == ' '); + rval += 8 + 1; + LOCAL_ASSERT(*end ? *end == ')' : end[-1] == '}'); + todo = Sprint(&ss->sprinter, "%s%s%s %s%s%.*s", + lval, + maybeComma, + (lastop == JSOP_GETTER) + ? js_get_str : js_set_str, + xval, + (rval[0] != '(') ? " " : "", + end - rval, rval); + } + } else { + todo = Sprint(&ss->sprinter, "%s%s%s: %s", + lval, maybeComma, xval, rval); + } +#endif + break; + } + +#if JS_HAS_SHARP_VARS + case JSOP_DEFSHARP: + i = (jsint) GET_UINT16(pc); + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "#%u=%s", (unsigned) i, rval); + break; + + case JSOP_USESHARP: + i = (jsint) GET_UINT16(pc); + todo = Sprint(&ss->sprinter, "#%u#", (unsigned) i); + break; +#endif /* JS_HAS_SHARP_VARS */ + +#if JS_HAS_DEBUGGER_KEYWORD + case JSOP_DEBUGGER: + js_printf(jp, "\tdebugger;\n"); + todo = -2; + break; +#endif /* JS_HAS_DEBUGGER_KEYWORD */ + +#if JS_HAS_XML_SUPPORT + case JSOP_STARTXML: + case JSOP_STARTXMLEXPR: + inXML = op == JSOP_STARTXML; + todo = -2; + break; + + case JSOP_DEFXMLNS: + rval = POP_STR(); + js_printf(jp, "\t%s %s %s = %s;\n", + js_default_str, js_xml_str, js_namespace_str, rval); + todo = -2; + break; + + case JSOP_ANYNAME: + if (pc[JSOP_ANYNAME_LENGTH] == JSOP_TOATTRNAME) { + len += JSOP_TOATTRNAME_LENGTH; + todo = SprintPut(&ss->sprinter, "@*", 2); + } else { + todo = SprintPut(&ss->sprinter, "*", 1); + } + break; + + case JSOP_QNAMEPART: + LOAD_ATOM(0); + if (pc[JSOP_QNAMEPART_LENGTH] == JSOP_TOATTRNAME) { + saveop = JSOP_TOATTRNAME; + len += JSOP_TOATTRNAME_LENGTH; + lval = "@"; + goto do_qname; + } + goto do_name; + + case JSOP_QNAMECONST: + LOAD_ATOM(0); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s::%s", lval, rval); + break; + + case JSOP_QNAME: + rval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s::[%s]", lval, rval); + break; + + case JSOP_TOATTRNAME: + op = JSOP_NOP; /* turn off parens */ + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "@[%s]", rval); + break; + + case JSOP_TOATTRVAL: + todo = -2; + break; + + case JSOP_ADDATTRNAME: + rval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s %s", lval, rval); + /* This gets reset by all XML tag expressions. */ + quoteAttr = JS_TRUE; + break; + + case JSOP_ADDATTRVAL: + rval = POP_STR(); + lval = POP_STR(); + if (quoteAttr) + todo = Sprint(&ss->sprinter, "%s=\"%s\"", lval, rval); + else + todo = Sprint(&ss->sprinter, "%s=%s", lval, rval); + break; + + case JSOP_BINDXMLNAME: + /* Leave the name stacked and push a dummy string. */ + todo = Sprint(&ss->sprinter, ""); + break; + + case JSOP_SETXMLNAME: + /* Pop the r.h.s., the dummy string, and the name. */ + rval = POP_STR(); + (void) PopOff(ss, op); + lval = POP_STR(); + goto do_setlval; + + case JSOP_XMLELTEXPR: + case JSOP_XMLTAGEXPR: + todo = Sprint(&ss->sprinter, "{%s}", POP_STR()); + inXML = JS_TRUE; + /* If we're an attribute value, we shouldn't quote this. */ + quoteAttr = JS_FALSE; + break; + + case JSOP_TOXMLLIST: + op = JSOP_NOP; /* turn off parens */ + todo = Sprint(&ss->sprinter, "<>%s", POP_STR()); + inXML = JS_FALSE; + break; + + case JSOP_TOXML: + case JSOP_CALLXMLNAME: + case JSOP_XMLNAME: + case JSOP_FILTER: + /* These ops indicate the end of XML expressions. */ + inXML = JS_FALSE; + todo = -2; + break; + + case JSOP_ENDFILTER: + rval = POP_STR(); + PROPAGATE_CALLNESS(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s.(%s)", lval, rval); + break; + + case JSOP_DESCENDANTS: + rval = POP_STR(); + PROPAGATE_CALLNESS(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s..%s", lval, rval); + break; + + case JSOP_XMLOBJECT: + LOAD_OBJECT(0); + todo = Sprint(&ss->sprinter, "", obj); + break; + + case JSOP_XMLCDATA: + LOAD_ATOM(0); + todo = SprintPut(&ss->sprinter, "sprinter, ATOM_TO_STRING(atom), + DONT_ESCAPE)) + return NULL; + SprintPut(&ss->sprinter, "]]>", 3); + break; + + case JSOP_XMLCOMMENT: + LOAD_ATOM(0); + todo = SprintPut(&ss->sprinter, "", 3); + break; + + case JSOP_XMLPI: + LOAD_ATOM(0); + rval = JS_strdup(cx, POP_STR()); + if (!rval) + return NULL; + todo = SprintPut(&ss->sprinter, "sprinter, ATOM_TO_STRING(atom), 0) && + (*rval == '\0' || + (SprintPut(&ss->sprinter, " ", 1) >= 0 && + SprintCString(&ss->sprinter, rval))); + JS_free(cx, (char *)rval); + if (!ok) + return NULL; + SprintPut(&ss->sprinter, "?>", 2); + break; + + case JSOP_GETFUNNS: + todo = SprintPut(&ss->sprinter, js_function_str, 8); + break; +#endif /* JS_HAS_XML_SUPPORT */ + + default: + todo = -2; + break; + } + } + + if (todo < 0) { + /* -2 means "don't push", -1 means reported error. */ + if (todo == -1) + return NULL; + } else { + if (!PushOff(ss, todo, saveop)) + return NULL; + } + + if (cs->format & JOF_CALLOP) { + todo = Sprint(&ss->sprinter, ""); + if (todo < 0 || !PushOff(ss, todo, saveop)) + return NULL; + } + + pc += len; + } + +/* + * Undefine local macros. + */ +#undef inXML +#undef DECOMPILE_CODE +#undef NEXT_OP +#undef TOP_STR +#undef POP_STR +#undef POP_STR_PREC +#undef LOCAL_ASSERT +#undef ATOM_IS_IDENTIFIER +#undef GET_QUOTE_AND_FMT +#undef GET_ATOM_QUOTE_AND_FMT + + return pc; +} + +static JSBool +DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len, + uintN pcdepth) +{ + uintN depth, i; + SprintStack ss; + JSContext *cx; + void *mark; + JSBool ok; + JSScript *oldscript; + jsbytecode *oldcode, *oldmain, *code; + char *last; + + depth = StackDepth(script); + JS_ASSERT(pcdepth <= depth); + + /* Initialize a sprinter for use with the offset stack. */ + cx = jp->sprinter.context; + mark = JS_ARENA_MARK(&cx->tempPool); + ok = InitSprintStack(cx, &ss, jp, depth); + if (!ok) + goto out; + + /* + * If we are called from js_DecompileValueGenerator with a portion of + * script's bytecode that starts with a non-zero model stack depth given + * by pcdepth, attempt to initialize the missing string offsets in ss to + * |spindex| negative indexes from fp->sp for the activation fp in which + * the error arose. + * + * See js_DecompileValueGenerator for how its |spindex| parameter is used, + * and see also GetOff, which makes use of the ss.offsets[i] < -1 that are + * potentially stored below. + */ + ss.top = pcdepth; + if (pcdepth != 0) { + for (i = 0; i < pcdepth; i++) { + ss.offsets[i] = -2 - (ptrdiff_t)i; + ss.opcodes[i] = *jp->pcstack[i]; + } + } + + /* Call recursive subroutine to do the hard work. */ + oldscript = jp->script; + jp->script = script; + oldcode = jp->script->code; + oldmain = jp->script->main; + code = js_UntrapScriptCode(cx, jp->script); + if (code != oldcode) { + jp->script->code = code; + jp->script->main = code + (oldmain - oldcode); + pc = code + (pc - oldcode); + } + + ok = Decompile(&ss, pc, len, JSOP_NOP) != NULL; + if (code != oldcode) { + JS_free(cx, jp->script->code); + jp->script->code = oldcode; + jp->script->main = oldmain; + } + jp->script = oldscript; + + /* If the given code didn't empty the stack, do it now. */ + if (ok && ss.top) { + do { + last = OFF2STR(&ss.sprinter, PopOff(&ss, JSOP_POP)); + } while (ss.top > pcdepth); + js_printf(jp, "%s", last); + } + +out: + /* Free all temporary stuff allocated under this call. */ + JS_ARENA_RELEASE(&cx->tempPool, mark); + return ok; +} + +JSBool +js_DecompileScript(JSPrinter *jp, JSScript *script) +{ + return DecompileCode(jp, script, script->code, (uintN)script->length, 0); +} + +static const char native_code_str[] = "\t[native code]\n"; + +JSBool +js_DecompileFunctionBody(JSPrinter *jp) +{ + JSScript *script; + + JS_ASSERT(jp->fun); + JS_ASSERT(!jp->script); + if (!FUN_INTERPRETED(jp->fun)) { + js_printf(jp, native_code_str); + return JS_TRUE; + } + + script = jp->fun->u.i.script; + return DecompileCode(jp, script, script->code, (uintN)script->length, 0); +} + +JSBool +js_DecompileFunction(JSPrinter *jp) +{ + JSFunction *fun; + uintN i; + JSAtom *param; + jsbytecode *pc, *endpc; + ptrdiff_t len; + JSBool ok; + + fun = jp->fun; + JS_ASSERT(fun); + JS_ASSERT(!jp->script); + + /* + * If pretty, conform to ECMA-262 Edition 3, 15.3.4.2, by decompiling a + * FunctionDeclaration. Otherwise, check the JSFUN_LAMBDA flag and force + * an expression by parenthesizing. + */ + if (jp->pretty) { + js_printf(jp, "\t"); + } else { + if (!jp->grouped && (fun->flags & JSFUN_LAMBDA)) + js_puts(jp, "("); + } + if (JSFUN_GETTER_TEST(fun->flags)) + js_printf(jp, "%s ", js_getter_str); + else if (JSFUN_SETTER_TEST(fun->flags)) + js_printf(jp, "%s ", js_setter_str); + + js_printf(jp, "%s ", js_function_str); + if (fun->atom && !QuoteString(&jp->sprinter, ATOM_TO_STRING(fun->atom), 0)) + return JS_FALSE; + js_puts(jp, "("); + + if (!FUN_INTERPRETED(fun)) { + js_printf(jp, ") {\n"); + jp->indent += 4; + js_printf(jp, native_code_str); + jp->indent -= 4; + js_printf(jp, "\t}"); + } else { +#ifdef JS_HAS_DESTRUCTURING + SprintStack ss; + void *mark; +#endif + + /* Print the parameters. */ + pc = fun->u.i.script->main; + endpc = pc + fun->u.i.script->length; + ok = JS_TRUE; + +#ifdef JS_HAS_DESTRUCTURING + /* Skip JSOP_GENERATOR in case of destructuring parameters. */ + if (*pc == JSOP_GENERATOR) + pc += JSOP_GENERATOR_LENGTH; + + ss.printer = NULL; + jp->script = fun->u.i.script; + mark = JS_ARENA_MARK(&jp->sprinter.context->tempPool); +#endif + + for (i = 0; i < fun->nargs; i++) { + if (i > 0) + js_puts(jp, ", "); + + param = GetArgOrVarAtom(jp, i); + +#if JS_HAS_DESTRUCTURING +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, JS_FALSE) + + if (!param) { + ptrdiff_t todo; + const char *lval; + + LOCAL_ASSERT(*pc == JSOP_GETARG); + pc += JSOP_GETARG_LENGTH; + LOCAL_ASSERT(*pc == JSOP_DUP); + if (!ss.printer) { + ok = InitSprintStack(jp->sprinter.context, &ss, jp, + StackDepth(fun->u.i.script)); + if (!ok) + break; + } + pc = DecompileDestructuring(&ss, pc, endpc); + if (!pc) { + ok = JS_FALSE; + break; + } + LOCAL_ASSERT(*pc == JSOP_POP); + pc += JSOP_POP_LENGTH; + lval = PopStr(&ss, JSOP_NOP); + todo = SprintCString(&jp->sprinter, lval); + if (todo < 0) { + ok = JS_FALSE; + break; + } + continue; + } + +#undef LOCAL_ASSERT +#endif + + if (!QuoteString(&jp->sprinter, ATOM_TO_STRING(param), 0)) { + ok = JS_FALSE; + break; + } + } + +#ifdef JS_HAS_DESTRUCTURING + jp->script = NULL; + JS_ARENA_RELEASE(&jp->sprinter.context->tempPool, mark); +#endif + if (!ok) + return JS_FALSE; + if (fun->flags & JSFUN_EXPR_CLOSURE) { + js_printf(jp, ") "); + } else { + js_printf(jp, ") {\n"); + jp->indent += 4; + } + + len = fun->u.i.script->code + fun->u.i.script->length - pc; + ok = DecompileCode(jp, fun->u.i.script, pc, (uintN)len, 0); + if (!ok) + return JS_FALSE; + + if (!(fun->flags & JSFUN_EXPR_CLOSURE)) { + jp->indent -= 4; + js_printf(jp, "\t}"); + } + } + + if (!jp->pretty && !jp->grouped && (fun->flags & JSFUN_LAMBDA)) + js_puts(jp, ")"); + + return JS_TRUE; +} + +char * +js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, + JSString *fallback) +{ + JSStackFrame *fp; + jsbytecode *pc; + JSScript *script; + JSFrameRegs *regs; + intN pcdepth; + jsval *sp, *stackBase; + char *name; + + JS_ASSERT(spindex < 0 || + spindex == JSDVG_IGNORE_STACK || + spindex == JSDVG_SEARCH_STACK); + + for (fp = cx->fp; fp && !fp->script; fp = fp->down) + continue; + if (!fp || !fp->regs) + goto do_fallback; + + script = fp->script; + regs = fp->regs; + pc = fp->imacpc ? fp->imacpc : regs->pc; + if (pc < script->main || script->code + script->length <= pc) { + JS_NOT_REACHED("bug"); + goto do_fallback; + } + + if (spindex != JSDVG_IGNORE_STACK) { + jsbytecode **pcstack; + + /* + * Prepare computing pcstack containing pointers to opcodes that + * populated interpreter's stack with its current content. + */ + pcstack = (jsbytecode **) + JS_malloc(cx, StackDepth(script) * sizeof *pcstack); + if (!pcstack) + return NULL; + pcdepth = ReconstructPCStack(cx, script, pc, pcstack); + if (pcdepth < 0) + goto release_pcstack; + + if (spindex != JSDVG_SEARCH_STACK) { + JS_ASSERT(spindex < 0); + pcdepth += spindex; + if (pcdepth < 0) + goto release_pcstack; + pc = pcstack[pcdepth]; + } else { + /* + * We search from fp->sp to base to find the most recently + * calculated value matching v under assumption that it is + * it that caused exception, see bug 328664. + */ + stackBase = StackBase(fp); + sp = regs->sp; + do { + if (sp == stackBase) { + pcdepth = -1; + goto release_pcstack; + } + } while (*--sp != v); + + if (sp >= stackBase + pcdepth) { + /* + * The value comes from a temporary slot that the interpreter + * uses for GC roots or when JSOP_APPLY extended the stack to + * fit the argument array elements. Assume that it is the + * current PC that caused the exception. + */ + pc = fp->imacpc ? fp->imacpc : regs->pc; + } else { + pc = pcstack[sp - stackBase]; + } + } + + release_pcstack: + JS_free(cx, pcstack); + if (pcdepth < 0) + goto do_fallback; + } + + { + jsbytecode* savepc = regs->pc; + jsbytecode* imacpc = fp->imacpc; + if (imacpc) { + regs->pc = imacpc; + fp->imacpc = NULL; + } + name = DecompileExpression(cx, script, fp->fun, pc); + if (imacpc) { + regs->pc = savepc; + fp->imacpc = imacpc; + } + } + if (name != FAILED_EXPRESSION_DECOMPILER) + return name; + + do_fallback: + if (!fallback) { + fallback = js_ValueToSource(cx, v); + if (!fallback) + return NULL; + } + return js_DeflateString(cx, JSSTRING_CHARS(fallback), + JSSTRING_LENGTH(fallback)); +} + +static char * +DecompileExpression(JSContext *cx, JSScript *script, JSFunction *fun, + jsbytecode *pc) +{ + jsbytecode *code, *oldcode, *oldmain; + JSOp op; + const JSCodeSpec *cs; + jsbytecode *begin, *end; + jssrcnote *sn; + ptrdiff_t len; + jsbytecode **pcstack; + intN pcdepth; + JSPrinter *jp; + char *name; + + JS_ASSERT(script->main <= pc && pc < script->code + script->length); + + pcstack = NULL; + oldcode = script->code; + oldmain = script->main; + + MUST_FLOW_THROUGH("out"); + code = js_UntrapScriptCode(cx, script); + if (code != oldcode) { + script->code = code; + script->main = code + (oldmain - oldcode); + pc = code + (pc - oldcode); + } + + op = (JSOp) *pc; + + /* None of these stack-writing ops generates novel values. */ + JS_ASSERT(op != JSOP_CASE && op != JSOP_CASEX && + op != JSOP_DUP && op != JSOP_DUP2); + + /* + * |this| could convert to a very long object initialiser, so cite it by + * its keyword name instead. + */ + if (op == JSOP_THIS) { + name = JS_strdup(cx, js_this_str); + goto out; + } + + /* + * JSOP_BINDNAME is special: it generates a value, the base object of a + * reference. But if it is the generating op for a diagnostic produced by + * js_DecompileValueGenerator, the name being bound is irrelevant. Just + * fall back to the base object. + */ + if (op == JSOP_BINDNAME) { + name = FAILED_EXPRESSION_DECOMPILER; + goto out; + } + + /* NAME ops are self-contained, others require left or right context. */ + cs = &js_CodeSpec[op]; + begin = pc; + end = pc + cs->length; + switch (JOF_MODE(cs->format)) { + case JOF_PROP: + case JOF_ELEM: + case JOF_XMLNAME: + case 0: + sn = js_GetSrcNote(script, pc); + if (!sn) { + name = FAILED_EXPRESSION_DECOMPILER; + goto out; + } + switch (SN_TYPE(sn)) { + case SRC_PCBASE: + begin -= js_GetSrcNoteOffset(sn, 0); + break; + case SRC_PCDELTA: + end = begin + js_GetSrcNoteOffset(sn, 0); + begin += cs->length; + break; + default: + name = FAILED_EXPRESSION_DECOMPILER; + goto out; + } + break; + default:; + } + len = PTRDIFF(end, begin, jsbytecode); + if (len <= 0) { + name = FAILED_EXPRESSION_DECOMPILER; + goto out; + } + + pcstack = (jsbytecode **) + JS_malloc(cx, StackDepth(script) * sizeof *pcstack); + if (!pcstack) { + name = NULL; + goto out; + } + + MUST_FLOW_THROUGH("out"); + pcdepth = ReconstructPCStack(cx, script, begin, pcstack); + if (pcdepth < 0) { + name = FAILED_EXPRESSION_DECOMPILER; + goto out; + } + + name = NULL; + jp = JS_NEW_PRINTER(cx, "js_DecompileValueGenerator", fun, 0, JS_FALSE); + if (jp) { + jp->dvgfence = end; + jp->pcstack = pcstack; + if (DecompileCode(jp, script, begin, (uintN) len, (uintN) pcdepth)) { + name = (jp->sprinter.base) ? jp->sprinter.base : (char *) ""; + name = JS_strdup(cx, name); + } + js_DestroyPrinter(jp); + } + + out: + if (code != oldcode) { + JS_free(cx, script->code); + script->code = oldcode; + script->main = oldmain; + } + + JS_free(cx, pcstack); + return name; +} + +uintN +js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + return ReconstructPCStack(cx, script, pc, NULL); +} + +static intN +ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target, + jsbytecode **pcstack) +{ + intN pcdepth, nuses, ndefs; + jsbytecode *pc; + JSOp op; + const JSCodeSpec *cs; + ptrdiff_t oplen; + jssrcnote *sn; + intN i; + +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, -1); + + /* + * Walk forward from script->main and compute the stack depth and stack of + * operand-generating opcode PCs in pcstack. + * + * FIXME: Code to compute oplen copied from js_Disassemble1 and reduced. + * FIXME: Optimize to use last empty-stack sequence point. + */ + LOCAL_ASSERT(script->main <= target && target < script->code + script->length); + pcdepth = 0; + for (pc = script->main; pc < target; pc += oplen) { + op = (JSOp) *pc; + if (op == JSOP_TRAP) + op = JS_GetTrapOpcode(cx, script, pc); + cs = &js_CodeSpec[op]; + oplen = cs->length; + if (oplen < 0) + oplen = js_GetVariableBytecodeLength(pc); + + /* + * A (C ? T : E) expression requires skipping either T (if target is in + * E) or both T and E (if target is after the whole expression) before + * adjusting pcdepth based on the JSOP_IFEQ or JSOP_IFEQX at pc that + * tests condition C. We know that the stack depth can't change from + * what it was with C on top of stack. + */ + sn = js_GetSrcNote(script, pc); + if (sn && SN_TYPE(sn) == SRC_COND) { + ptrdiff_t jmpoff, jmplen; + + jmpoff = js_GetSrcNoteOffset(sn, 0); + if (pc + jmpoff < target) { + pc += jmpoff; + op = (JSOp) *pc; + JS_ASSERT(op == JSOP_GOTO || op == JSOP_GOTOX); + cs = &js_CodeSpec[op]; + oplen = cs->length; + JS_ASSERT(oplen > 0); + jmplen = GetJumpOffset(pc, pc); + if (pc + jmplen < target) { + oplen = (uintN) jmplen; + continue; + } + + /* + * Ok, target lies in E. Manually pop C off the model stack, + * since we have moved beyond the IFEQ now. + */ + --pcdepth; + LOCAL_ASSERT(pcdepth >= 0); + } + } + + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + continue; + + nuses = cs->nuses; + if (nuses < 0) + nuses = js_GetVariableStackUseLength(op, pc); + + ndefs = cs->ndefs; + if (ndefs < 0) { + JSObject *obj; + + JS_ASSERT(op == JSOP_ENTERBLOCK); + GET_OBJECT_FROM_BYTECODE(script, pc, 0, obj); + JS_ASSERT(OBJ_BLOCK_DEPTH(cx, obj) == pcdepth); + ndefs = OBJ_BLOCK_COUNT(cx, obj); + } + + pcdepth -= nuses; + LOCAL_ASSERT(pcdepth >= 0); + LOCAL_ASSERT((uintN)(pcdepth + ndefs) <= StackDepth(script)); + + /* + * Fill the slots that the opcode defines withs its pc unless it just + * reshuffle the stack. In the latter case we want to preserve the + * opcode that generated the original value. + */ + switch (op) { + default: + if (pcstack) { + for (i = 0; i != ndefs; ++i) + pcstack[pcdepth + i] = pc; + } + break; + + case JSOP_CASE: + case JSOP_CASEX: + /* Keep the switch value. */ + JS_ASSERT(ndefs == 1); + break; + + case JSOP_DUP: + JS_ASSERT(ndefs == 2); + if (pcstack) + pcstack[pcdepth + 1] = pcstack[pcdepth]; + break; + + case JSOP_DUP2: + JS_ASSERT(ndefs == 4); + if (pcstack) { + pcstack[pcdepth + 2] = pcstack[pcdepth]; + pcstack[pcdepth + 3] = pcstack[pcdepth + 1]; + } + break; + } + pcdepth += ndefs; + } + LOCAL_ASSERT(pc == target); + return pcdepth; + +#undef LOCAL_ASSERT +} + +#undef LOCAL_ASSERT_RV diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.h new file mode 100644 index 0000000..6ce8a40 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.h @@ -0,0 +1,404 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsopcode_h___ +#define jsopcode_h___ +/* + * JS bytecode definitions. + */ +#include +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsutil.h" + +JS_BEGIN_EXTERN_C + +/* + * JS operation bytecodes. + */ +typedef enum JSOp { +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + op = val, +#include "jsopcode.tbl" +#undef OPDEF + JSOP_LIMIT +} JSOp; + +/* + * JS bytecode formats. + */ +#define JOF_BYTE 0 /* single bytecode, no immediates */ +#define JOF_JUMP 1 /* signed 16-bit jump offset immediate */ +#define JOF_ATOM 2 /* unsigned 16-bit constant pool index */ +#define JOF_UINT16 3 /* unsigned 16-bit immediate operand */ +#define JOF_TABLESWITCH 4 /* table switch */ +#define JOF_LOOKUPSWITCH 5 /* lookup switch */ +#define JOF_QARG 6 /* quickened get/set function argument ops */ +#define JOF_LOCAL 7 /* var or block-local variable */ +#define JOF_SLOTATOM 8 /* uint16 slot index + constant pool index */ +#define JOF_JUMPX 9 /* signed 32-bit jump offset immediate */ +#define JOF_TABLESWITCHX 10 /* extended (32-bit offset) table switch */ +#define JOF_LOOKUPSWITCHX 11 /* extended (32-bit offset) lookup switch */ +#define JOF_UINT24 12 /* extended unsigned 24-bit literal (index) */ +#define JOF_UINT8 13 /* uint8 immediate, e.g. top 8 bits of 24-bit + atom index */ +#define JOF_INT32 14 /* int32 immediate operand */ +#define JOF_OBJECT 15 /* unsigned 16-bit object pool index */ +#define JOF_SLOTOBJECT 16 /* uint16 slot index + object pool index */ +#define JOF_REGEXP 17 /* unsigned 16-bit regexp pool index */ +#define JOF_INT8 18 /* int8 immediate operand */ +#define JOF_TYPEMASK 0x001f /* mask for above immediate types */ + +#define JOF_NAME (1U<<5) /* name operation */ +#define JOF_PROP (2U<<5) /* obj.prop operation */ +#define JOF_ELEM (3U<<5) /* obj[index] operation */ +#define JOF_XMLNAME (4U<<5) /* XML name: *, a::b, @a, @a::b, etc. */ +#define JOF_VARPROP (5U<<5) /* x.prop for this, arg, var, or local x */ +#define JOF_MODEMASK (7U<<5) /* mask for above addressing modes */ +#define JOF_SET (1U<<8) /* set (i.e., assignment) operation */ +#define JOF_DEL (1U<<9) /* delete operation */ +#define JOF_DEC (1U<<10) /* decrement (--, not ++) opcode */ +#define JOF_INC (2U<<10) /* increment (++, not --) opcode */ +#define JOF_INCDEC (3U<<10) /* increment or decrement opcode */ +#define JOF_POST (1U<<12) /* postorder increment or decrement */ +#define JOF_FOR (1U<<13) /* for-in property op (akin to JOF_SET) */ +#define JOF_ASSIGNING JOF_SET /* hint for JSClass.resolve, used for ops + that do simplex assignment */ +#define JOF_DETECTING (1U<<14) /* object detection for JSNewResolveOp */ +#define JOF_BACKPATCH (1U<<15) /* backpatch placeholder during codegen */ +#define JOF_LEFTASSOC (1U<<16) /* left-associative operator */ +#define JOF_DECLARING (1U<<17) /* var, const, or function declaration op */ +#define JOF_INDEXBASE (1U<<18) /* atom segment base setting prefix op */ +#define JOF_CALLOP (1U<<19) /* call operation that pushes function and + this */ +#define JOF_PARENHEAD (1U<<20) /* opcode consumes value of expression in + parenthesized statement head */ +#define JOF_INVOKE (1U<<21) /* JSOP_CALL, JSOP_NEW, JSOP_EVAL */ +#define JOF_TMPSLOT (1U<<22) /* interpreter uses extra temporary slot + to root intermediate objects besides + the slots opcode uses */ +#define JOF_TMPSLOT2 (2U<<22) /* interpreter uses extra 2 temporary slot + besides the slots opcode uses */ +#define JOF_TMPSLOT_SHIFT 22 +#define JOF_TMPSLOT_MASK (JS_BITMASK(2) << JOF_TMPSLOT_SHIFT) + +/* Shorthands for type from format and type from opcode. */ +#define JOF_TYPE(fmt) ((fmt) & JOF_TYPEMASK) +#define JOF_OPTYPE(op) JOF_TYPE(js_CodeSpec[op].format) + +/* Shorthands for mode from format and mode from opcode. */ +#define JOF_MODE(fmt) ((fmt) & JOF_MODEMASK) +#define JOF_OPMODE(op) JOF_MODE(js_CodeSpec[op].format) + +#define JOF_TYPE_IS_EXTENDED_JUMP(t) \ + ((unsigned)((t) - JOF_JUMPX) <= (unsigned)(JOF_LOOKUPSWITCHX - JOF_JUMPX)) + +/* + * Immediate operand getters, setters, and bounds. + */ + +/* Common uint16 immediate format helpers. */ +#define UINT16_LEN 2 +#define UINT16_HI(i) ((jsbytecode)((i) >> 8)) +#define UINT16_LO(i) ((jsbytecode)(i)) +#define GET_UINT16(pc) ((uintN)(((pc)[1] << 8) | (pc)[2])) +#define SET_UINT16(pc,i) ((pc)[1] = UINT16_HI(i), (pc)[2] = UINT16_LO(i)) +#define UINT16_LIMIT ((uintN)1 << 16) + +/* Short (2-byte signed offset) relative jump macros. */ +#define JUMP_OFFSET_LEN 2 +#define JUMP_OFFSET_HI(off) ((jsbytecode)((off) >> 8)) +#define JUMP_OFFSET_LO(off) ((jsbytecode)(off)) +#define GET_JUMP_OFFSET(pc) ((int16)GET_UINT16(pc)) +#define SET_JUMP_OFFSET(pc,off) ((pc)[1] = JUMP_OFFSET_HI(off), \ + (pc)[2] = JUMP_OFFSET_LO(off)) +#define JUMP_OFFSET_MIN ((int16)0x8000) +#define JUMP_OFFSET_MAX ((int16)0x7fff) + +/* + * When a short jump won't hold a relative offset, its 2-byte immediate offset + * operand is an unsigned index of a span-dependency record, maintained until + * code generation finishes -- after which some (but we hope not nearly all) + * span-dependent jumps must be extended (see OptimizeSpanDeps in jsemit.c). + * + * If the span-dependency record index overflows SPANDEP_INDEX_MAX, the jump + * offset will contain SPANDEP_INDEX_HUGE, indicating that the record must be + * found (via binary search) by its "before span-dependency optimization" pc + * offset (from script main entry point). + */ +#define GET_SPANDEP_INDEX(pc) ((uint16)GET_UINT16(pc)) +#define SET_SPANDEP_INDEX(pc,i) ((pc)[1] = JUMP_OFFSET_HI(i), \ + (pc)[2] = JUMP_OFFSET_LO(i)) +#define SPANDEP_INDEX_MAX ((uint16)0xfffe) +#define SPANDEP_INDEX_HUGE ((uint16)0xffff) + +/* Ultimately, if short jumps won't do, emit long (4-byte signed) offsets. */ +#define JUMPX_OFFSET_LEN 4 +#define JUMPX_OFFSET_B3(off) ((jsbytecode)((off) >> 24)) +#define JUMPX_OFFSET_B2(off) ((jsbytecode)((off) >> 16)) +#define JUMPX_OFFSET_B1(off) ((jsbytecode)((off) >> 8)) +#define JUMPX_OFFSET_B0(off) ((jsbytecode)(off)) +#define GET_JUMPX_OFFSET(pc) ((int32)(((pc)[1] << 24) | ((pc)[2] << 16) \ + | ((pc)[3] << 8) | (pc)[4])) +#define SET_JUMPX_OFFSET(pc,off)((pc)[1] = JUMPX_OFFSET_B3(off), \ + (pc)[2] = JUMPX_OFFSET_B2(off), \ + (pc)[3] = JUMPX_OFFSET_B1(off), \ + (pc)[4] = JUMPX_OFFSET_B0(off)) +#define JUMPX_OFFSET_MIN ((int32)0x80000000) +#define JUMPX_OFFSET_MAX ((int32)0x7fffffff) + +/* + * A literal is indexed by a per-script atom or object maps. Most scripts + * have relatively few literals, so the standard JOF_ATOM, JOF_OBJECT and + * JOF_REGEXP formats specifies a fixed 16 bits of immediate operand index. + * A script with more than 64K literals must wrap the bytecode into + * JSOP_INDEXBASE and JSOP_RESETBASE pair. + */ +#define INDEX_LEN 2 +#define INDEX_HI(i) ((jsbytecode)((i) >> 8)) +#define INDEX_LO(i) ((jsbytecode)(i)) +#define GET_INDEX(pc) GET_UINT16(pc) +#define SET_INDEX(pc,i) ((pc)[1] = INDEX_HI(i), (pc)[2] = INDEX_LO(i)) + +#define GET_INDEXBASE(pc) (JS_ASSERT(*(pc) == JSOP_INDEXBASE), \ + ((uintN)((pc)[1])) << 16) +#define INDEXBASE_LEN 1 + +#define UINT24_HI(i) ((jsbytecode)((i) >> 16)) +#define UINT24_MID(i) ((jsbytecode)((i) >> 8)) +#define UINT24_LO(i) ((jsbytecode)(i)) +#define GET_UINT24(pc) ((jsatomid)(((pc)[1] << 16) | \ + ((pc)[2] << 8) | \ + (pc)[3])) +#define SET_UINT24(pc,i) ((pc)[1] = UINT24_HI(i), \ + (pc)[2] = UINT24_MID(i), \ + (pc)[3] = UINT24_LO(i)) + +#define GET_INT8(pc) ((jsint)(int8)(pc)[1]) + +#define GET_INT32(pc) ((jsint)(((uint32)((pc)[1]) << 24) | \ + ((uint32)((pc)[2]) << 16) | \ + ((uint32)((pc)[3]) << 8) | \ + (uint32)(pc)[4])) +#define SET_INT32(pc,i) ((pc)[1] = (jsbytecode)((uint32)(i) >> 24), \ + (pc)[2] = (jsbytecode)((uint32)(i) >> 16), \ + (pc)[3] = (jsbytecode)((uint32)(i) >> 8), \ + (pc)[4] = (jsbytecode)(uint32)(i)) + +/* Index limit is determined by SN_3BYTE_OFFSET_FLAG, see jsemit.h. */ +#define INDEX_LIMIT_LOG2 23 +#define INDEX_LIMIT ((uint32)1 << INDEX_LIMIT_LOG2) + +JS_STATIC_ASSERT(sizeof(uint32) * JS_BITS_PER_BYTE >= INDEX_LIMIT_LOG2 + 1); + +/* Actual argument count operand format helpers. */ +#define ARGC_HI(argc) UINT16_HI(argc) +#define ARGC_LO(argc) UINT16_LO(argc) +#define GET_ARGC(pc) GET_UINT16(pc) +#define ARGC_LIMIT UINT16_LIMIT + +/* Synonyms for quick JOF_QARG and JOF_LOCAL bytecodes. */ +#define GET_ARGNO(pc) GET_UINT16(pc) +#define SET_ARGNO(pc,argno) SET_UINT16(pc,argno) +#define ARGNO_LEN 2 +#define ARGNO_LIMIT UINT16_LIMIT + +#define GET_SLOTNO(pc) GET_UINT16(pc) +#define SET_SLOTNO(pc,varno) SET_UINT16(pc,varno) +#define SLOTNO_LEN 2 +#define SLOTNO_LIMIT UINT16_LIMIT + +struct JSCodeSpec { + int8 length; /* length including opcode byte */ + int8 nuses; /* arity, -1 if variadic */ + int8 ndefs; /* number of stack results */ + uint8 prec; /* operator precedence */ + uint32 format; /* immediate operand format */ +}; + +extern const JSCodeSpec js_CodeSpec[]; +extern uintN js_NumCodeSpecs; +extern const char *js_CodeName[]; +extern const char js_EscapeMap[]; + +/* + * Return a GC'ed string containing the chars in str, with any non-printing + * chars or quotes (' or " as specified by the quote argument) escaped, and + * with the quote character at the beginning and end of the result string. + */ +extern JSString * +js_QuoteString(JSContext *cx, JSString *str, jschar quote); + +/* + * JSPrinter operations, for printf style message formatting. The return + * value from js_GetPrinterOutput() is the printer's cumulative output, in + * a GC'ed string. + */ + +#ifdef JS_ARENAMETER +# define JS_NEW_PRINTER(cx, name, fun, indent, pretty) \ + js_NewPrinter(cx, name, fun, indent, pretty) +#else +# define JS_NEW_PRINTER(cx, name, fun, indent, pretty) \ + js_NewPrinter(cx, fun, indent, pretty) +#endif + +extern JSPrinter * +JS_NEW_PRINTER(JSContext *cx, const char *name, JSFunction *fun, + uintN indent, JSBool pretty); + +extern void +js_DestroyPrinter(JSPrinter *jp); + +extern JSString * +js_GetPrinterOutput(JSPrinter *jp); + +extern int +js_printf(JSPrinter *jp, const char *format, ...); + +extern JSBool +js_puts(JSPrinter *jp, const char *s); + +/* + * Get index operand from the bytecode using a bytecode analysis to deduce the + * the index register. This function is infallible, in spite of taking cx as + * its first parameter; it uses only cx->runtime when calling JS_GetTrapOpcode. + * The GET_*_FROM_BYTECODE macros that call it pick up cx from their caller's + * lexical environments. + */ +uintN +js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, + ptrdiff_t pcoff); + +/* + * A slower version of GET_ATOM when the caller does not want to maintain + * the index segment register itself. + */ +#define GET_ATOM_FROM_BYTECODE(script, pc, pcoff, atom) \ + JS_BEGIN_MACRO \ + uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ + JS_GET_SCRIPT_ATOM((script), index_, atom); \ + JS_END_MACRO + +#define GET_OBJECT_FROM_BYTECODE(script, pc, pcoff, obj) \ + JS_BEGIN_MACRO \ + uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ + JS_GET_SCRIPT_OBJECT((script), index_, obj); \ + JS_END_MACRO + +#define GET_FUNCTION_FROM_BYTECODE(script, pc, pcoff, fun) \ + JS_BEGIN_MACRO \ + uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ + JS_GET_SCRIPT_FUNCTION((script), index_, fun); \ + JS_END_MACRO + +#define GET_REGEXP_FROM_BYTECODE(script, pc, pcoff, obj) \ + JS_BEGIN_MACRO \ + uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ + JS_GET_SCRIPT_REGEXP((script), index_, obj); \ + JS_END_MACRO + +/* + * Get the length of variable-length bytecode like JSOP_TABLESWITCH. + */ +extern uintN +js_GetVariableBytecodeLength(jsbytecode *pc); + +/* + * Find the number of stack slots used by a variadic opcode such as JSOP_CALL + * or JSOP_NEWARRAY (for such ops, JSCodeSpec.nuses is -1). + */ +extern uintN +js_GetVariableStackUseLength(JSOp op, jsbytecode *pc); + +#ifdef DEBUG +/* + * Disassemblers, for debugging only. + */ +#include + +extern JS_FRIEND_API(JSBool) +js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp); + +extern JS_FRIEND_API(uintN) +js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, + JSBool lines, FILE *fp); +#endif /* DEBUG */ + +/* + * Decompilers, for script, function, and expression pretty-printing. + */ +extern JSBool +js_DecompileScript(JSPrinter *jp, JSScript *script); + +extern JSBool +js_DecompileFunctionBody(JSPrinter *jp); + +extern JSBool +js_DecompileFunction(JSPrinter *jp); + +/* + * Find the source expression that resulted in v, and return a newly allocated + * C-string containing it. Fall back on v's string conversion (fallback) if we + * can't find the bytecode that generated and pushed v on the operand stack. + * + * Search the current stack frame if spindex is JSDVG_SEARCH_STACK. Don't + * look for v on the stack if spindex is JSDVG_IGNORE_STACK. Otherwise, + * spindex is the negative index of v, measured from cx->fp->sp, or from a + * lower frame's sp if cx->fp is native. + * + * The caller must call JS_free on the result after a succsesful call. + */ +extern char * +js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, + JSString *fallback); + +#define JSDVG_IGNORE_STACK 0 +#define JSDVG_SEARCH_STACK 1 + +/* + * Given bytecode address pc in script's main program code, return the operand + * stack depth just before (JSOp) *pc executes. + */ +extern uintN +js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc); + +JS_END_EXTERN_C + +#endif /* jsopcode_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.tbl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.tbl new file mode 100644 index 0000000..6392209 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsopcode.tbl @@ -0,0 +1,557 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=0 ft=C: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript operation bytecodes. If you need to allocate a bytecode, look + * for a name of the form JSOP_UNUSED* and claim it. Otherwise, always add at + * the end of the table. + * + * Includers must define an OPDEF macro of the following form: + * + * #define OPDEF(op,val,name,image,length,nuses,ndefs,prec,format) ... + * + * Selected arguments can be expanded in initializers. The op argument is + * expanded followed by comma in the JSOp enum (jsopcode.h), e.g. The value + * field must be dense for now, because jsopcode.c uses an OPDEF() expansion + * inside the js_CodeSpec[] initializer. + * + * Field Description + * op Bytecode name, which is the JSOp enumerator name + * value Bytecode value, which is the JSOp enumerator value + * name C string containing name for disassembler + * image C string containing "image" for pretty-printer, null if ugly + * length Number of bytes including any immediate operands + * nuses Number of stack slots consumed by bytecode, -1 if variadic + * ndefs Number of stack slots produced by bytecode, -1 if variadic + * prec Operator precedence, zero if not an operator + * format Bytecode plus immediate operand encoding format + * + * Precedence Operators Opcodes + * 1 yield w JSOP_YIELD + * 2 , JSOP_POP with SRC_PCDELTA, JSOP_RETURN + * 3 =, +=, etc. JSOP_SETNAME, etc. (all JOF_SET); + * let (...) ... and JSOP_LEAVEBLOCKEXPR + * 4 ?: JSOP_IFEQ, JSOP_IFEQX + * 5 || JSOP_OR, JSOP_ORX + * 6 && JSOP_AND, JSOP_ANDX + * 7 | JSOP_BITOR + * 8 ^ JSOP_BITXOR + * 9 & JSOP_BITAND + * 10 ==, !=, etc. JSOP_EQ, JSOP_NE, etc. + * 11 <, in, etc. JSOP_LT, JSOP_IN, etc. + * 12 <<, >>, >>> JSOP_LSH, JSOP_RSH, JSOP_URSH + * 13 +, -, etc. JSOP_ADD, JSOP_SUB, etc. + * 14 *, /, % JSOP_MUL, JSOP_DIV, JSOP_MOD + * 15 !, ~, delete, etc. JSOP_NOT, JSOP_BITNOT, JSOP_DEL*, etc. + * 16 3.14, 0, etc. JSOP_DOUBLE, JSOP_ZERO, etc. + * 17 new JSOP_NEW + * 18 x.y, f(), etc. JSOP_GETPROP, JSOP_CALL, etc. + * 19 x, null, JSOP_NAME, JSOP_NULL, etc.; + * function (...) ... and JSOP_ANONFUNOBJ, JSOP_NAMEDFUNOBJ + * + * The push-numeric-constant operators, JSOP_ZERO, JSOP_DOUBLE, etc., have + * lower precedence than the member operators emitted for the . operator, to + * cause the decompiler to parenthesize the . left operand, e.g. (0).foo. + * Otherwise the . could be taken as a decimal point. + * + * Let expressions are "primary" when viewed from the left, but they eat up ops + * to the right as if assignment expressions and therefore have precedence 3. + * This makes the decompiler retain the parentheses in (let (a=0) x) ? a : 0 + * but omit the superfluous ones in (let (a=0) x), a. + * + * Yield expressions must be parenthesized even in comma-expressions and + * argument lists, so they have the lowest precedence. + * + * This file is best viewed with 128 columns: +12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 + */ + +/* legend: op val name image len use def prec format */ + +/* Longstanding JavaScript bytecodes. */ +OPDEF(JSOP_INTERRUPT, 0, "interrupt", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_PUSH, 1, "push", NULL, 1, 0, 1, 0, JOF_BYTE) +OPDEF(JSOP_POPV, 2, "popv", NULL, 1, 1, 0, 2, JOF_BYTE) +OPDEF(JSOP_ENTERWITH, 3, "enterwith", NULL, 1, 1, 1, 0, JOF_BYTE|JOF_PARENHEAD) +OPDEF(JSOP_LEAVEWITH, 4, "leavewith", NULL, 1, 1, 0, 0, JOF_BYTE) +OPDEF(JSOP_RETURN, 5, "return", NULL, 1, 1, 0, 2, JOF_BYTE) +OPDEF(JSOP_GOTO, 6, "goto", NULL, 3, 0, 0, 0, JOF_JUMP) +OPDEF(JSOP_IFEQ, 7, "ifeq", NULL, 3, 1, 0, 4, JOF_JUMP|JOF_DETECTING) +OPDEF(JSOP_IFNE, 8, "ifne", NULL, 3, 1, 0, 0, JOF_JUMP|JOF_PARENHEAD) + +/* Get the arguments object for the current, lightweight function activation. */ +OPDEF(JSOP_ARGUMENTS, 9, js_arguments_str, js_arguments_str, 1, 0, 1, 18, JOF_BYTE) + +/* ECMA-compliant for-in loop with argument or local loop control. */ +OPDEF(JSOP_FORARG, 10, "forarg", NULL, 3, 2, 2, 19, JOF_QARG|JOF_NAME|JOF_FOR) +OPDEF(JSOP_FORLOCAL, 11, "forlocal", NULL, 3, 2, 2, 19, JOF_LOCAL|JOF_NAME|JOF_FOR) + +/* More longstanding bytecodes. */ +OPDEF(JSOP_DUP, 12, "dup", NULL, 1, 1, 2, 0, JOF_BYTE) +OPDEF(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, 0, JOF_BYTE) +OPDEF(JSOP_SETCONST, 14, "setconst", NULL, 3, 1, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET) +OPDEF(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, 7, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, 8, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, 9, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_EQ, 18, "eq", "==", 1, 2, 1, 10, JOF_BYTE|JOF_LEFTASSOC|JOF_DETECTING) +OPDEF(JSOP_NE, 19, "ne", "!=", 1, 2, 1, 10, JOF_BYTE|JOF_LEFTASSOC|JOF_DETECTING) +OPDEF(JSOP_LT, 20, "lt", "<", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_LE, 21, "le", "<=", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_GT, 22, "gt", ">", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_GE, 23, "ge", ">=", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_LSH, 24, "lsh", "<<", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_RSH, 25, "rsh", ">>", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_URSH, 26, "ursh", ">>>", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_ADD, 27, "add", "+", 1, 2, 1, 13, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_SUB, 28, "sub", "-", 1, 2, 1, 13, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_MUL, 29, "mul", "*", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_DIV, 30, "div", "/", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_MOD, 31, "mod", "%", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT2) +OPDEF(JSOP_NOT, 32, "not", "!", 1, 1, 1, 15, JOF_BYTE|JOF_DETECTING) +OPDEF(JSOP_BITNOT, 33, "bitnot", "~", 1, 1, 1, 15, JOF_BYTE) +OPDEF(JSOP_NEG, 34, "neg", "- ", 1, 1, 1, 15, JOF_BYTE) +OPDEF(JSOP_NEW, 35, js_new_str, NULL, 3, -1, 1, 17, JOF_UINT16|JOF_INVOKE) +OPDEF(JSOP_DELNAME, 36, "delname", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEL) +OPDEF(JSOP_DELPROP, 37, "delprop", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEL) +OPDEF(JSOP_DELELEM, 38, "delelem", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_DEL) +OPDEF(JSOP_TYPEOF, 39, js_typeof_str,NULL, 1, 1, 1, 15, JOF_BYTE|JOF_DETECTING) +OPDEF(JSOP_VOID, 40, js_void_str, NULL, 1, 1, 1, 15, JOF_BYTE) + +OPDEF(JSOP_INCNAME, 41, "incname", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT2) +OPDEF(JSOP_INCPROP, 42, "incprop", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_INC|JOF_TMPSLOT2) +OPDEF(JSOP_INCELEM, 43, "incelem", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_INC|JOF_TMPSLOT2) +OPDEF(JSOP_DECNAME, 44, "decname", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT2) +OPDEF(JSOP_DECPROP, 45, "decprop", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEC|JOF_TMPSLOT2) +OPDEF(JSOP_DECELEM, 46, "decelem", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_DEC|JOF_TMPSLOT2) +OPDEF(JSOP_NAMEINC, 47, "nameinc", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT2) +OPDEF(JSOP_PROPINC, 48, "propinc", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_INC|JOF_POST|JOF_TMPSLOT2) +OPDEF(JSOP_ELEMINC, 49, "eleminc", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_INC|JOF_POST|JOF_TMPSLOT2) +OPDEF(JSOP_NAMEDEC, 50, "namedec", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT2) +OPDEF(JSOP_PROPDEC, 51, "propdec", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEC|JOF_POST|JOF_TMPSLOT2) +OPDEF(JSOP_ELEMDEC, 52, "elemdec", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_DEC|JOF_POST|JOF_TMPSLOT2) + +OPDEF(JSOP_GETPROP, 53, "getprop", NULL, 3, 1, 1, 18, JOF_ATOM|JOF_PROP) +OPDEF(JSOP_SETPROP, 54, "setprop", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_GETELEM, 55, "getelem", NULL, 1, 2, 1, 18, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC) +OPDEF(JSOP_SETELEM, 56, "setelem", NULL, 1, 3, 1, 3, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_CALLNAME, 57, "callname", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP) +OPDEF(JSOP_CALL, 58, "call", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE) +OPDEF(JSOP_NAME, 59, "name", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME) +OPDEF(JSOP_DOUBLE, 60, "double", NULL, 3, 0, 1, 16, JOF_ATOM) +OPDEF(JSOP_STRING, 61, "string", NULL, 3, 0, 1, 19, JOF_ATOM) +OPDEF(JSOP_ZERO, 62, "zero", "0", 1, 0, 1, 16, JOF_BYTE) +OPDEF(JSOP_ONE, 63, "one", "1", 1, 0, 1, 16, JOF_BYTE) +OPDEF(JSOP_NULL, 64, js_null_str, js_null_str, 1, 0, 1, 19, JOF_BYTE) +OPDEF(JSOP_THIS, 65, js_this_str, js_this_str, 1, 0, 1, 19, JOF_BYTE) +OPDEF(JSOP_FALSE, 66, js_false_str, js_false_str, 1, 0, 1, 19, JOF_BYTE) +OPDEF(JSOP_TRUE, 67, js_true_str, js_true_str, 1, 0, 1, 19, JOF_BYTE) +OPDEF(JSOP_OR, 68, "or", NULL, 3, 1, 0, 5, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) +OPDEF(JSOP_AND, 69, "and", NULL, 3, 1, 0, 6, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) + +/* The switch bytecodes have variable length. */ +OPDEF(JSOP_TABLESWITCH, 70, "tableswitch", NULL, -1, 1, 0, 0, JOF_TABLESWITCH|JOF_DETECTING|JOF_PARENHEAD) +OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswitch", NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCH|JOF_DETECTING|JOF_PARENHEAD) + +/* New, infallible/transitive identity ops. */ +OPDEF(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC) +OPDEF(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC) + +/* Variant of JSOP_NULL for default (global) |this| parameter pushing. */ +OPDEF(JSOP_NULLTHIS, 74, js_null_str, js_null_str, 1, 0, 1, 19, JOF_BYTE) + +/* + * JSOP_ITER sets up a for-in or for-each-in loop using the JSITER_* flag bits + * in this op's uint8 immediate operand. It replaces the top of stack object + * with an iterator for that object, and pushes a slot used by JSOP_NEXTITER. + * + * JSOP_NEXTITER stores the next iterated value in the top of stack slot which + * was allocated by JSOP_ITER and pushes true, or stores JSVAL_HOLE and pushes + * false. It is followed immediately by JSOP_IFNE{,X}. + * + * JSOP_ENDITER cleans up after the loop. It uses the slot above the iterator + * for temporary GC rooting. + */ +OPDEF(JSOP_ITER, 75, "iter", NULL, 2, 1, 2, 0, JOF_UINT8) +OPDEF(JSOP_NEXTITER, 76, "nextiter", NULL, 1, 2, 3, 0, JOF_BYTE) +OPDEF(JSOP_ENDITER, 77, "enditer", NULL, 1, 2, 0, 0, JOF_BYTE) + +OPDEF(JSOP_APPLY, 78, "apply", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE) +OPDEF(JSOP_SWAP, 79, "swap", NULL, 1, 2, 2, 0, JOF_BYTE) + +/* Push object literal. */ +OPDEF(JSOP_OBJECT, 80, "object", NULL, 3, 0, 1, 19, JOF_OBJECT) + +/* Pop value and discard it. */ +OPDEF(JSOP_POP, 81, "pop", NULL, 1, 1, 0, 2, JOF_BYTE) + +/* Convert value to number, for unary +. */ +OPDEF(JSOP_POS, 82, "pos", "+ ", 1, 1, 1, 15, JOF_BYTE) + +/* Trap into debugger for breakpoint, etc. */ +OPDEF(JSOP_TRAP, 83, "trap", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* Fast get/set ops for function arguments and local variables. */ +OPDEF(JSOP_GETARG, 84, "getarg", NULL, 3, 0, 1, 19, JOF_QARG |JOF_NAME) +OPDEF(JSOP_SETARG, 85, "setarg", NULL, 3, 1, 1, 3, JOF_QARG |JOF_NAME|JOF_SET) +OPDEF(JSOP_GETLOCAL, 86,"getlocal", NULL, 3, 0, 1, 19, JOF_LOCAL|JOF_NAME) +OPDEF(JSOP_SETLOCAL, 87,"setlocal", NULL, 3, 1, 1, 3, JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING) + +/* Push unsigned 16-bit int constant. */ +OPDEF(JSOP_UINT16, 88, "uint16", NULL, 3, 0, 1, 16, JOF_UINT16) + +/* Object and array literal support. */ +OPDEF(JSOP_NEWINIT, 89, "newinit", NULL, 2, 0, 1, 19, JOF_INT8) +OPDEF(JSOP_ENDINIT, 90, "endinit", NULL, 1, 0, 0, 19, JOF_BYTE) +OPDEF(JSOP_INITPROP, 91, "initprop", NULL, 3, 1, 0, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_INITELEM, 92, "initelem", NULL, 1, 2, 0, 3, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_DEFSHARP, 93, "defsharp", NULL, 3, 0, 0, 0, JOF_UINT16) +OPDEF(JSOP_USESHARP, 94, "usesharp", NULL, 3, 0, 1, 0, JOF_UINT16) + +/* Fast inc/dec ops for args and locals. */ +OPDEF(JSOP_INCARG, 95, "incarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC) +OPDEF(JSOP_DECARG, 96, "decarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC) +OPDEF(JSOP_ARGINC, 97, "arginc", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_POST) +OPDEF(JSOP_ARGDEC, 98, "argdec", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_POST) + +OPDEF(JSOP_INCLOCAL, 99, "inclocal", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_INC) +OPDEF(JSOP_DECLOCAL, 100,"declocal", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_DEC) +OPDEF(JSOP_LOCALINC, 101,"localinc", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_INC|JOF_POST) +OPDEF(JSOP_LOCALDEC, 102,"localdec", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_POST) + +OPDEF(JSOP_IMACOP, 103,"imacop", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* ECMA-compliant for/in ops. */ +OPDEF(JSOP_FORNAME, 104,"forname", NULL, 3, 2, 2, 19, JOF_ATOM|JOF_NAME|JOF_FOR) +OPDEF(JSOP_FORPROP, 105,"forprop", NULL, 3, 3, 2, 18, JOF_ATOM|JOF_PROP|JOF_FOR) +OPDEF(JSOP_FORELEM, 106,"forelem", NULL, 1, 2, 3, 18, JOF_BYTE |JOF_ELEM|JOF_FOR) +OPDEF(JSOP_POPN, 107,"popn", NULL, 3, -1, 0, 0, JOF_UINT16) + +/* ECMA-compliant assignment ops. */ +OPDEF(JSOP_BINDNAME, 108,"bindname", NULL, 3, 0, 1, 0, JOF_ATOM|JOF_NAME|JOF_SET) +OPDEF(JSOP_SETNAME, 109,"setname", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING) + +/* Exception handling ops. */ +OPDEF(JSOP_THROW, 110,js_throw_str, NULL, 1, 1, 0, 0, JOF_BYTE) + +/* 'in' and 'instanceof' ops. */ +OPDEF(JSOP_IN, 111,js_in_str, js_in_str, 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_INSTANCEOF,112,js_instanceof_str,js_instanceof_str,1,2,1,11,JOF_BYTE|JOF_LEFTASSOC) + +/* debugger op */ +OPDEF(JSOP_DEBUGGER, 113,"debugger", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* gosub/retsub for finally handling */ +OPDEF(JSOP_GOSUB, 114,"gosub", NULL, 3, 0, 0, 0, JOF_JUMP) +OPDEF(JSOP_RETSUB, 115,"retsub", NULL, 1, 2, 0, 0, JOF_BYTE) + +/* More exception handling ops. */ +OPDEF(JSOP_EXCEPTION, 116,"exception", NULL, 1, 0, 1, 0, JOF_BYTE) + +/* Embedded lineno to speedup pc->line mapping. */ +OPDEF(JSOP_LINENO, 117,"lineno", NULL, 3, 0, 0, 0, JOF_UINT16) + +/* + * ECMA-compliant switch statement ops. + * CONDSWITCH is a decompilable NOP; CASE is ===, POP, jump if true, re-push + * lval if false; and DEFAULT is POP lval and GOTO. + */ +OPDEF(JSOP_CONDSWITCH,118,"condswitch", NULL, 1, 0, 0, 0, JOF_BYTE|JOF_PARENHEAD) +OPDEF(JSOP_CASE, 119,"case", NULL, 3, 2, 1, 0, JOF_JUMP) +OPDEF(JSOP_DEFAULT, 120,"default", NULL, 3, 1, 0, 0, JOF_JUMP) + +/* + * ECMA-compliant call to eval op + */ +OPDEF(JSOP_EVAL, 121,"eval", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE) + +/* + * ECMA-compliant helper for 'for (x[i] in o)' loops. + */ +OPDEF(JSOP_ENUMELEM, 122,"enumelem", NULL, 1, 3, 0, 3, JOF_BYTE |JOF_SET) + +/* + * Getter and setter prefix bytecodes. These modify the next bytecode, either + * an assignment or a property initializer code, which then defines a property + * getter or setter. + */ +OPDEF(JSOP_GETTER, 123,js_getter_str,NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_SETTER, 124,js_setter_str,NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Prolog bytecodes for defining function, var, and const names. + */ +OPDEF(JSOP_DEFFUN, 125,"deffun", NULL, 3, 0, 0, 0, JOF_OBJECT|JOF_DECLARING) +OPDEF(JSOP_DEFCONST, 126,"defconst", NULL, 3, 0, 0, 0, JOF_ATOM|JOF_DECLARING) +OPDEF(JSOP_DEFVAR, 127,"defvar", NULL, 3, 0, 0, 0, JOF_ATOM|JOF_DECLARING) + +/* Auto-clone (if needed due to re-parenting) and push an anonymous function. */ +OPDEF(JSOP_ANONFUNOBJ, 128, "anonfunobj", NULL, 3, 0, 1, 19, JOF_OBJECT) + +/* ECMA ed. 3 named function expression. */ +OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL, 3, 0, 1, 19, JOF_OBJECT) + +/* + * Like JSOP_SETLOCAL, but specialized to avoid requiring JSOP_POP immediately + * after to throw away the exception value. + */ +OPDEF(JSOP_SETLOCALPOP, 130, "setlocalpop", NULL, 3, 1, 0, 3, JOF_LOCAL|JOF_NAME|JOF_SET) + +/* Parenthesization opcode to help the decompiler. */ +OPDEF(JSOP_UNUSED131, 131, "unused131", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Host object extension: given 'o.item(i) = j', the left-hand side compiles + * JSOP_SETCALL, rather than JSOP_CALL. + */ +OPDEF(JSOP_SETCALL, 132, "setcall", NULL, 3, -1, 2, 18, JOF_UINT16|JOF_SET) + +/* + * Exception handling no-op, for more economical byte-coding than SRC_TRYFIN + * srcnote-annotated JSOP_NOPs and to simply stack balance handling. + */ +OPDEF(JSOP_TRY, 133,"try", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_FINALLY, 134,"finally", NULL, 1, 0, 2, 0, JOF_BYTE) + +/* + * Generic nop for the decompiler. + */ +OPDEF(JSOP_NOP, 135,"nop", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Bytecodes that avoid making an arguments object in most cases: + * JSOP_ARGSUB gets arguments[i] from fp->argv, iff i is in [0, fp->argc-1]. + * JSOP_ARGCNT returns fp->argc. + */ +OPDEF(JSOP_ARGSUB, 136,"argsub", NULL, 3, 0, 1, 18, JOF_QARG |JOF_NAME) +OPDEF(JSOP_ARGCNT, 137,"argcnt", NULL, 1, 0, 1, 18, JOF_BYTE) + +/* + * Define a local function object as a local variable. + * The local variable's slot number is the first immediate two-byte operand. + * The function object's atom index is the second immediate operand. + */ +OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL, 5, 0, 0, 0, JOF_SLOTOBJECT|JOF_DECLARING) + +/* Extended jumps. */ +OPDEF(JSOP_GOTOX, 139,"gotox", NULL, 5, 0, 0, 0, JOF_JUMPX) +OPDEF(JSOP_IFEQX, 140,"ifeqx", NULL, 5, 1, 0, 4, JOF_JUMPX|JOF_DETECTING) +OPDEF(JSOP_IFNEX, 141,"ifnex", NULL, 5, 1, 0, 0, JOF_JUMPX|JOF_PARENHEAD) +OPDEF(JSOP_ORX, 142,"orx", NULL, 5, 1, 0, 5, JOF_JUMPX|JOF_DETECTING) +OPDEF(JSOP_ANDX, 143,"andx", NULL, 5, 1, 0, 6, JOF_JUMPX|JOF_DETECTING) +OPDEF(JSOP_GOSUBX, 144,"gosubx", NULL, 5, 0, 0, 0, JOF_JUMPX) +OPDEF(JSOP_CASEX, 145,"casex", NULL, 5, 2, 1, 0, JOF_JUMPX) +OPDEF(JSOP_DEFAULTX, 146,"defaultx", NULL, 5, 1, 0, 0, JOF_JUMPX) +OPDEF(JSOP_TABLESWITCHX, 147,"tableswitchx",NULL, -1, 1, 0, 0, JOF_TABLESWITCHX|JOF_DETECTING|JOF_PARENHEAD) +OPDEF(JSOP_LOOKUPSWITCHX, 148,"lookupswitchx",NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCHX|JOF_DETECTING|JOF_PARENHEAD) + +/* Placeholders for a real jump opcode set during backpatch chain fixup. */ +OPDEF(JSOP_BACKPATCH, 149,"backpatch",NULL, 3, 0, 0, 0, JOF_JUMP|JOF_BACKPATCH) +OPDEF(JSOP_BACKPATCH_POP, 150,"backpatch_pop",NULL, 3, 1, 0, 0, JOF_JUMP|JOF_BACKPATCH) + +/* Set pending exception from the stack, to trigger rethrow. */ +OPDEF(JSOP_THROWING, 151,"throwing", NULL, 1, 1, 0, 0, JOF_BYTE) + +/* Set and get return value pseudo-register in stack frame. */ +OPDEF(JSOP_SETRVAL, 152,"setrval", NULL, 1, 1, 0, 2, JOF_BYTE) +OPDEF(JSOP_RETRVAL, 153,"retrval", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* Optimized global variable ops (we don't bother doing a JSOP_FORGVAR op). */ +OPDEF(JSOP_GETGVAR, 154,"getgvar", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME) +OPDEF(JSOP_SETGVAR, 155,"setgvar", NULL, 3, 1, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_INCGVAR, 156,"incgvar", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT2) +OPDEF(JSOP_DECGVAR, 157,"decgvar", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT2) +OPDEF(JSOP_GVARINC, 158,"gvarinc", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT2) +OPDEF(JSOP_GVARDEC, 159,"gvardec", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT2) + +/* Regular expression literal requiring special "fork on exec" handling. */ +OPDEF(JSOP_REGEXP, 160,"regexp", NULL, 3, 0, 1, 19, JOF_REGEXP) + +/* XML (ECMA-357, a.k.a. "E4X") support. */ +OPDEF(JSOP_DEFXMLNS, 161,"defxmlns", NULL, 1, 1, 0, 0, JOF_BYTE) +OPDEF(JSOP_ANYNAME, 162,"anyname", NULL, 1, 0, 1, 19, JOF_BYTE|JOF_XMLNAME) +OPDEF(JSOP_QNAMEPART, 163,"qnamepart", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_XMLNAME) +OPDEF(JSOP_QNAMECONST, 164,"qnameconst", NULL, 3, 1, 1, 19, JOF_ATOM|JOF_XMLNAME) +OPDEF(JSOP_QNAME, 165,"qname", NULL, 1, 2, 1, 0, JOF_BYTE|JOF_XMLNAME) +OPDEF(JSOP_TOATTRNAME, 166,"toattrname", NULL, 1, 1, 1, 19, JOF_BYTE|JOF_XMLNAME) +OPDEF(JSOP_TOATTRVAL, 167,"toattrval", NULL, 1, 1, 1, 19, JOF_BYTE) +OPDEF(JSOP_ADDATTRNAME, 168,"addattrname",NULL, 1, 2, 1, 13, JOF_BYTE) +OPDEF(JSOP_ADDATTRVAL, 169,"addattrval", NULL, 1, 2, 1, 13, JOF_BYTE) +OPDEF(JSOP_BINDXMLNAME, 170,"bindxmlname",NULL, 1, 1, 2, 3, JOF_BYTE|JOF_SET) +OPDEF(JSOP_SETXMLNAME, 171,"setxmlname", NULL, 1, 3, 1, 3, JOF_BYTE|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_XMLNAME, 172,"xmlname", NULL, 1, 1, 1, 19, JOF_BYTE) +OPDEF(JSOP_DESCENDANTS, 173,"descendants",NULL, 1, 2, 1, 18, JOF_BYTE) +OPDEF(JSOP_FILTER, 174,"filter", NULL, 3, 1, 1, 0, JOF_JUMP) +OPDEF(JSOP_ENDFILTER, 175,"endfilter", NULL, 3, 2, 1, 18, JOF_JUMP) +OPDEF(JSOP_TOXML, 176,"toxml", NULL, 1, 1, 1, 19, JOF_BYTE) +OPDEF(JSOP_TOXMLLIST, 177,"toxmllist", NULL, 1, 1, 1, 19, JOF_BYTE) +OPDEF(JSOP_XMLTAGEXPR, 178,"xmltagexpr", NULL, 1, 1, 1, 0, JOF_BYTE) +OPDEF(JSOP_XMLELTEXPR, 179,"xmleltexpr", NULL, 1, 1, 1, 0, JOF_BYTE) +OPDEF(JSOP_XMLOBJECT, 180,"xmlobject", NULL, 3, 0, 1, 19, JOF_OBJECT) +OPDEF(JSOP_XMLCDATA, 181,"xmlcdata", NULL, 3, 0, 1, 19, JOF_ATOM) +OPDEF(JSOP_XMLCOMMENT, 182,"xmlcomment", NULL, 3, 0, 1, 19, JOF_ATOM) +OPDEF(JSOP_XMLPI, 183,"xmlpi", NULL, 3, 1, 1, 19, JOF_ATOM) +OPDEF(JSOP_CALLPROP, 184,"callprop", NULL, 3, 1, 2, 18, JOF_ATOM|JOF_PROP|JOF_CALLOP) +OPDEF(JSOP_GETFUNNS, 185,"getfunns", NULL, 1, 0, 1, 19, JOF_BYTE) + +/* + * Get a display (free) variable from the closure's reserved slots. + */ +OPDEF(JSOP_GETUPVAR, 186,"getupvar", NULL, 3, 0, 1, 19, JOF_UINT16|JOF_NAME) + +OPDEF(JSOP_DELDESC, 187,"deldesc", NULL, 1, 2, 1, 15, JOF_BYTE|JOF_ELEM|JOF_DEL) + +/* + * Opcode to hold 24-bit immediate integer operands. + */ +OPDEF(JSOP_UINT24, 188,"uint24", NULL, 4, 0, 1, 16, JOF_UINT24) + +/* + * Opcodes to allow 24-bit atom or object indexes. Whenever an index exceeds + * the 16-bit limit, the index-accessing bytecode must be bracketed by + * JSOP_INDEXBASE and JSOP_RESETBASE to provide the upper bits of the index. + * See jsemit.c, EmitIndexOp. + */ +OPDEF(JSOP_INDEXBASE, 189,"atombase", NULL, 2, 0, 0, 0, JOF_UINT8|JOF_INDEXBASE) +OPDEF(JSOP_RESETBASE, 190,"resetbase", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_RESETBASE0, 191,"resetbase0", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Opcodes to help the decompiler deal with XML. + */ +OPDEF(JSOP_STARTXML, 192,"startxml", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_STARTXMLEXPR, 193,"startxmlexpr",NULL, 1, 0, 0, 0, JOF_BYTE) + +OPDEF(JSOP_CALLELEM, 194, "callelem", NULL, 1, 2, 2, 18, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC|JOF_CALLOP) + +/* + * Stop interpretation, emitted at end of script to save the threaded bytecode + * interpreter an extra branch test on every DO_NEXT_OP (see jsinterp.c). + */ +OPDEF(JSOP_STOP, 195,"stop", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Get an extant property value, throwing ReferenceError if the identified + * property does not exist. + */ +OPDEF(JSOP_GETXPROP, 196,"getxprop", NULL, 3, 1, 1, 18, JOF_ATOM|JOF_PROP) + +OPDEF(JSOP_CALLXMLNAME, 197, "callxmlname", NULL, 1, 1, 2, 19, JOF_BYTE|JOF_CALLOP) + +/* + * Specialized JSOP_TYPEOF to avoid reporting undefined for typeof(0, undef). + */ +OPDEF(JSOP_TYPEOFEXPR, 198,"typeofexpr", NULL, 1, 1, 1, 15, JOF_BYTE|JOF_DETECTING) + +/* + * Block-local scope support. + */ +OPDEF(JSOP_ENTERBLOCK, 199,"enterblock", NULL, 3, 0, -1, 0, JOF_OBJECT) +OPDEF(JSOP_LEAVEBLOCK, 200,"leaveblock", NULL, 3, -1, 0, 0, JOF_UINT16) +OPDEF(JSOP_UNUSED201, 201,"unused201", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED202, 202,"unused202", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED203, 203,"unused203", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED204, 204,"unused204", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED205, 205,"unused205", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED206, 206,"unused206", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED207, 207,"unused207", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED208, 208,"unused208", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED209, 209,"unused209", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Generator and array comprehension support. + */ +OPDEF(JSOP_GENERATOR, 210,"generator", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_YIELD, 211,"yield", NULL, 1, 1, 1, 1, JOF_BYTE) +OPDEF(JSOP_ARRAYPUSH, 212,"arraypush", NULL, 3, 1, 0, 3, JOF_LOCAL) + +/* + * In the forthcoming great opcode reorg, this should go next to JSOP_GETUPVAR. + */ +OPDEF(JSOP_CALLUPVAR, 213, "callupvar", NULL, 3, 0, 2, 19, JOF_UINT16|JOF_NAME|JOF_CALLOP) + +/* + * Variant of JSOP_ENUMELEM for destructuring const (const [a, b] = ...). + */ +OPDEF(JSOP_ENUMCONSTELEM, 214,"enumconstelem",NULL, 1, 3, 0, 3, JOF_BYTE|JOF_SET) + +/* + * Variant of JSOP_LEAVEBLOCK has a result on the stack above the locals, + * which must be moved down when the block pops. + */ +OPDEF(JSOP_LEAVEBLOCKEXPR,215,"leaveblockexpr",NULL, 3, -1, 1, 3, JOF_UINT16) + +/* + * Optimize common JSOP_{THIS,GET{ARG,LOCAL}} -> JSOP_GETPROP cliches. + */ +OPDEF(JSOP_GETTHISPROP, 216,"getthisprop", NULL, 3, 0, 1, 18, JOF_ATOM|JOF_VARPROP) +OPDEF(JSOP_GETARGPROP, 217,"getargprop", NULL, 5, 0, 1, 18, JOF_SLOTATOM|JOF_VARPROP) +OPDEF(JSOP_GETLOCALPROP, 218,"getlocalprop", NULL, 5, 0, 1, 18, JOF_SLOTATOM|JOF_VARPROP) +OPDEF(JSOP_UNUSED219, 219,"unused219", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Optimize atom segments 1-3. These must be followed by JSOP_RESETBASE0 after + * the opcode that they prefix. + */ +OPDEF(JSOP_INDEXBASE1, 220,"atombase1", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE) +OPDEF(JSOP_INDEXBASE2, 221,"atombase2", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE) +OPDEF(JSOP_INDEXBASE3, 222,"atombase3", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE) + +OPDEF(JSOP_CALLGVAR, 223, "callgvar", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP) +OPDEF(JSOP_CALLLOCAL, 224, "calllocal", NULL, 3, 0, 2, 19, JOF_LOCAL|JOF_NAME|JOF_CALLOP) +OPDEF(JSOP_CALLARG, 225, "callarg", NULL, 3, 0, 2, 19, JOF_QARG |JOF_NAME|JOF_CALLOP) +OPDEF(JSOP_UNUSED226, 226, "unused226", NULL, 1, 0, 1, 1, JOF_BYTE) + +/* + * Opcodes to hold 8-bit and 32-bit immediate integer operands. + */ +OPDEF(JSOP_INT8, 227, "int8", NULL, 2, 0, 1, 16, JOF_INT8) +OPDEF(JSOP_INT32, 228, "int32", NULL, 5, 0, 1, 16, JOF_INT32) + +/* + * Get the value of the 'length' property from a stacked object. + */ +OPDEF(JSOP_LENGTH, 229, "length", NULL, 1, 1, 1, 18, JOF_BYTE|JOF_PROP) + +/* + * JSOP_NEWARRAY optimizes array literal evaluation using the interpreter stack. + * JSOP_HOLE pushes a JSVAL_HOLE (used with JSOP_NEWINIT and JSOP_NEWARRAY). + */ +OPDEF(JSOP_NEWARRAY, 230, "newarray", NULL, 4, -1, 1, 19, JOF_UINT24) +OPDEF(JSOP_HOLE, 231, "hole", NULL, 1, 0, 1, 0, JOF_BYTE) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsoplengen.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsoplengen.cpp new file mode 100644 index 0000000..ecebc06 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsoplengen.cpp @@ -0,0 +1,121 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is String Switch Generator for JavaScript Keywords, + * released 2005-12-09. + * + * The Initial Developer of the Original Code is + * Igor Bukanov. + * Portions created by the Initial Developer are Copyright (C) 2005-2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include + +static const struct { + const char *name; + int length; +} pairs[] = { +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + { #op, length } , +#include "jsopcode.tbl" +#undef OPDEF +}; + +int +main(int argc, char **argv) +{ + FILE *fp; + size_t maxNameWidth, i, nameWidth, tabStop; + int lengthGap; + + static const char prefix[] = "#define "; + static const char suffix[] = "_LENGTH"; + static const size_t tabWidth = 8; + static const size_t prefixWidth = sizeof(prefix) - 1; + static const size_t suffixWidth = sizeof(suffix) - 1; + + if (argc != 2) { + fputs("Bad usage\n", stderr); + return EXIT_FAILURE; + } + + fp = fopen(argv[1], "w"); + if (!fp) { + perror("fopen"); + return EXIT_FAILURE; + } + fputs("/*\n" + " * Automatically generated header with JS opcode length constants.\n" + " *\n" + " * Do not edit it, alter jsopcode.tbl instead.\n" + " */\n", + fp); + + /* + * Print + * + * #define name_LENGTH length + * + * with all length values aligned on the same column. The column is at the + * second character position after a tab-stop with the first position + * reserved for the minus sign of variable-length opcodes. + */ + maxNameWidth = 0; + for (i = 0; i != sizeof pairs / sizeof pairs[0]; ++i) { + nameWidth = strlen(pairs[i].name); + if (maxNameWidth < nameWidth) + maxNameWidth = nameWidth; + } + + tabStop = prefixWidth + maxNameWidth + suffixWidth + 1; + tabStop = (tabStop + tabWidth - 1) / tabWidth * tabWidth; + for (i = 0; i != sizeof pairs / sizeof pairs[0]; ++i) { + lengthGap = (int) (tabStop - prefixWidth - strlen(pairs[i].name) - + suffixWidth); + fprintf(fp, "%s%s%s%*c%2d\n", + prefix, pairs[i].name, suffix, lengthGap, ' ', + pairs[i].length); + if (ferror(fp)) { + perror("fclose"); + exit(EXIT_FAILURE); + } + } + + if (fclose(fp)) { + perror("fclose"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsotypes.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsotypes.h new file mode 100644 index 0000000..ede1221 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsotypes.h @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This section typedefs the old 'native' types to the new PRs. + * These definitions are scheduled to be eliminated at the earliest + * possible time. The NSPR API is implemented and documented using + * the new definitions. + */ + +/* + * Note that we test for PROTYPES_H, not JSOTYPES_H. This is to avoid + * double-definitions of scalar types such as uint32, if NSPR's + * protypes.h is also included. + */ +#ifndef PROTYPES_H +#define PROTYPES_H + +#ifdef XP_BEOS +/* BeOS defines most int types in SupportDefs.h (int8, uint8, int16, + * uint16, int32, uint32, int64, uint64), so in the interest of + * not conflicting with other definitions elsewhere we have to skip the + * #ifdef jungle below, duplicate some definitions, and do our stuff. + */ +#include + +typedef JSUintn uintn; +#ifndef _XP_Core_ +typedef JSIntn intn; +#endif + +#else + +/* SVR4 typedef of uint is commonly found on UNIX machines. */ +#ifdef XP_UNIX +#include +#else +typedef JSUintn uint; +#endif + +typedef JSUintn uintn; +typedef JSUint64 uint64; +#if !defined(_WIN32) && !defined(XP_OS2) +typedef JSUint32 uint32; +#else +typedef unsigned long uint32; +#endif +typedef JSUint16 uint16; +typedef JSUint8 uint8; + +#ifndef _XP_Core_ +typedef JSIntn intn; +#endif + +/* + * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h, a very + * common header file) defines the types int8, int16, int32, and int64. + * So we don't define these four types here to avoid conflicts in case + * the code also includes sys/types.h. + */ +#if defined(AIX) && defined(HAVE_SYS_INTTYPES_H) +#include +#else +typedef JSInt64 int64; + +/* /usr/include/model.h on HP-UX defines int8, int16, and int32 */ +#ifdef HPUX +#include +#else +#if !defined(_WIN32) && !defined(XP_OS2) +typedef JSInt32 int32; +#else +typedef long int32; +#endif +typedef JSInt16 int16; +typedef JSInt8 int8; +#endif /* HPUX */ +#endif /* AIX && HAVE_SYS_INTTYPES_H */ + +#endif /* XP_BEOS */ + +typedef JSFloat64 float64; + +/* Re: jsbit.h */ +#define TEST_BIT JS_TEST_BIT +#define SET_BIT JS_SET_BIT +#define CLEAR_BIT JS_CLEAR_BIT + +/* Re: prarena.h->plarena.h */ +#define PRArena PLArena +#define PRArenaPool PLArenaPool +#define PRArenaStats PLArenaStats +#define PR_ARENA_ALIGN PL_ARENA_ALIGN +#define PR_INIT_ARENA_POOL PL_INIT_ARENA_POOL +#define PR_ARENA_ALLOCATE PL_ARENA_ALLOCATE +#define PR_ARENA_GROW PL_ARENA_GROW +#define PR_ARENA_MARK PL_ARENA_MARK +#define PR_CLEAR_UNUSED PL_CLEAR_UNUSED +#define PR_CLEAR_ARENA PL_CLEAR_ARENA +#define PR_ARENA_RELEASE PL_ARENA_RELEASE +#define PR_COUNT_ARENA PL_COUNT_ARENA +#define PR_ARENA_DESTROY PL_ARENA_DESTROY +#define PR_InitArenaPool PL_InitArenaPool +#define PR_FreeArenaPool PL_FreeArenaPool +#define PR_FinishArenaPool PL_FinishArenaPool +#define PR_CompactArenaPool PL_CompactArenaPool +#define PR_ArenaFinish PL_ArenaFinish +#define PR_ArenaAllocate PL_ArenaAllocate +#define PR_ArenaGrow PL_ArenaGrow +#define PR_ArenaRelease PL_ArenaRelease +#define PR_ArenaCountAllocation PL_ArenaCountAllocation +#define PR_ArenaCountInplaceGrowth PL_ArenaCountInplaceGrowth +#define PR_ArenaCountGrowth PL_ArenaCountGrowth +#define PR_ArenaCountRelease PL_ArenaCountRelease +#define PR_ArenaCountRetract PL_ArenaCountRetract + +/* Re: prevent.h->plevent.h */ +#define PREvent PLEvent +#define PREventQueue PLEventQueue +#define PR_CreateEventQueue PL_CreateEventQueue +#define PR_DestroyEventQueue PL_DestroyEventQueue +#define PR_GetEventQueueMonitor PL_GetEventQueueMonitor +#define PR_ENTER_EVENT_QUEUE_MONITOR PL_ENTER_EVENT_QUEUE_MONITOR +#define PR_EXIT_EVENT_QUEUE_MONITOR PL_EXIT_EVENT_QUEUE_MONITOR +#define PR_PostEvent PL_PostEvent +#define PR_PostSynchronousEvent PL_PostSynchronousEvent +#define PR_GetEvent PL_GetEvent +#define PR_EventAvailable PL_EventAvailable +#define PREventFunProc PLEventFunProc +#define PR_MapEvents PL_MapEvents +#define PR_RevokeEvents PL_RevokeEvents +#define PR_ProcessPendingEvents PL_ProcessPendingEvents +#define PR_WaitForEvent PL_WaitForEvent +#define PR_EventLoop PL_EventLoop +#define PR_GetEventQueueSelectFD PL_GetEventQueueSelectFD +#define PRHandleEventProc PLHandleEventProc +#define PRDestroyEventProc PLDestroyEventProc +#define PR_InitEvent PL_InitEvent +#define PR_GetEventOwner PL_GetEventOwner +#define PR_HandleEvent PL_HandleEvent +#define PR_DestroyEvent PL_DestroyEvent +#define PR_DequeueEvent PL_DequeueEvent +#define PR_GetMainEventQueue PL_GetMainEventQueue + +/* Re: prhash.h->plhash.h */ +#define PRHashEntry PLHashEntry +#define PRHashTable PLHashTable +#define PRHashNumber PLHashNumber +#define PRHashFunction PLHashFunction +#define PRHashComparator PLHashComparator +#define PRHashEnumerator PLHashEnumerator +#define PRHashAllocOps PLHashAllocOps +#define PR_NewHashTable PL_NewHashTable +#define PR_HashTableDestroy PL_HashTableDestroy +#define PR_HashTableRawLookup PL_HashTableRawLookup +#define PR_HashTableRawAdd PL_HashTableRawAdd +#define PR_HashTableRawRemove PL_HashTableRawRemove +#define PR_HashTableAdd PL_HashTableAdd +#define PR_HashTableRemove PL_HashTableRemove +#define PR_HashTableEnumerateEntries PL_HashTableEnumerateEntries +#define PR_HashTableLookup PL_HashTableLookup +#define PR_HashTableDump PL_HashTableDump +#define PR_HashString PL_HashString +#define PR_CompareStrings PL_CompareStrings +#define PR_CompareValues PL_CompareValues + +#endif /* !defined(PROTYPES_H) */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsparse.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsparse.cpp new file mode 100644 index 0000000..57da28a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsparse.cpp @@ -0,0 +1,6822 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS parser. + * + * This is a recursive-descent parser for the JavaScript language specified by + * "The JavaScript 1.5 Language Specification". It uses lexical and semantic + * feedback to disambiguate non-LL(1) structures. It generates trees of nodes + * induced by the recursive parsing (not precise syntax trees, see jsparse.h). + * After tree construction, it rewrites trees to fold constants and evaluate + * compile-time expressions. Finally, it calls js_EmitTree (see jsemit.h) to + * generate bytecode. + * + * This parser attempts no error recovery. + */ +#include "jsstddef.h" +#include +#include +#include +#include "jstypes.h" +#include "jsarena.h" /* Added by JSIFY */ +#include "jsutil.h" /* Added by JSIFY */ +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsstaticcheck.h" + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#if JS_HAS_DESTRUCTURING +#include "jsdhash.h" +#endif + +/* + * Asserts to verify assumptions behind pn_ macros. + */ +JS_STATIC_ASSERT(offsetof(JSParseNode, pn_u.name.atom) == + offsetof(JSParseNode, pn_u.apair.atom)); +JS_STATIC_ASSERT(offsetof(JSParseNode, pn_u.name.slot) == + offsetof(JSParseNode, pn_u.lexical.slot)); + +/* + * JS parsers, from lowest to highest precedence. + * + * Each parser takes a context, a token stream, and a tree context struct. + * Each returns a parse node tree or null on error. + */ + +typedef JSParseNode * +JSParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc); + +typedef JSParseNode * +JSMemberParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSBool allowCallSyntax); + +typedef JSParseNode * +JSPrimaryParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSTokenType tt, JSBool afterDot); + +typedef JSParseNode * +JSParenParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSParseNode *pn1, JSBool *genexp); + +static JSParser FunctionStmt; +static JSParser FunctionExpr; +static JSParser Statements; +static JSParser Statement; +static JSParser Variables; +static JSParser Expr; +static JSParser AssignExpr; +static JSParser CondExpr; +static JSParser OrExpr; +static JSParser AndExpr; +static JSParser BitOrExpr; +static JSParser BitXorExpr; +static JSParser BitAndExpr; +static JSParser EqExpr; +static JSParser RelExpr; +static JSParser ShiftExpr; +static JSParser AddExpr; +static JSParser MulExpr; +static JSParser UnaryExpr; +static JSMemberParser MemberExpr; +static JSPrimaryParser PrimaryExpr; +static JSParenParser ParenExpr; + +/* + * Insist that the next token be of type tt, or report errno and return null. + * NB: this macro uses cx and ts from its lexical environment. + */ +#define MUST_MATCH_TOKEN(tt, errno) \ + JS_BEGIN_MACRO \ + if (js_GetToken(cx, ts) != tt) { \ + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, errno); \ + return NULL; \ + } \ + JS_END_MACRO + +#ifdef METER_PARSENODES +static uint32 parsenodes = 0; +static uint32 maxparsenodes = 0; +static uint32 recyclednodes = 0; +#endif + +JSBool +js_InitParseContext(JSContext *cx, JSParseContext *pc, JSPrincipals *principals, + JSStackFrame *callerFrame, + const jschar *base, size_t length, + FILE *fp, const char *filename, uintN lineno) +{ + JS_ASSERT_IF(callerFrame, callerFrame->script); + + pc->tempPoolMark = JS_ARENA_MARK(&cx->tempPool); + if (!js_InitTokenStream(cx, TS(pc), base, length, fp, filename, lineno)) { + JS_ARENA_RELEASE(&cx->tempPool, pc->tempPoolMark); + return JS_FALSE; + } + if (principals) + JSPRINCIPALS_HOLD(cx, principals); + pc->principals = principals; + pc->callerFrame = callerFrame; + pc->nodeList = NULL; + pc->traceListHead = NULL; + + /* Root atoms and objects allocated for the parsed tree. */ + JS_KEEP_ATOMS(cx->runtime); + JS_PUSH_TEMP_ROOT_PARSE_CONTEXT(cx, pc, &pc->tempRoot); + return JS_TRUE; +} + +void +js_FinishParseContext(JSContext *cx, JSParseContext *pc) +{ + if (pc->principals) + JSPRINCIPALS_DROP(cx, pc->principals); + JS_ASSERT(pc->tempRoot.u.parseContext == pc); + JS_POP_TEMP_ROOT(cx, &pc->tempRoot); + JS_UNKEEP_ATOMS(cx->runtime); + js_CloseTokenStream(cx, TS(pc)); + JS_ARENA_RELEASE(&cx->tempPool, pc->tempPoolMark); +} + +void +js_InitCompilePrincipals(JSContext *cx, JSParseContext *pc, + JSPrincipals *principals) +{ + JS_ASSERT(!pc->principals); + if (principals) + JSPRINCIPALS_HOLD(cx, principals); + pc->principals = principals; +} + +JSParsedObjectBox * +js_NewParsedObjectBox(JSContext *cx, JSParseContext *pc, JSObject *obj) +{ + JSParsedObjectBox *pob; + + /* + * We use JSContext.tempPool to allocate parsed objects and place them on + * a list in JSTokenStream to ensure GC safety. Thus the tempPool arenas + * containing the entries must be alive until we are done with scanning, + * parsing and code generation for the whole script or top-level function. + */ + JS_ASSERT(obj); + JS_ARENA_ALLOCATE_TYPE(pob, JSParsedObjectBox, &cx->tempPool); + if (!pob) { + js_ReportOutOfScriptQuota(cx); + return NULL; + } + pob->traceLink = pc->traceListHead; + pob->emitLink = NULL; + pob->object = obj; + pc->traceListHead = pob; + return pob; +} + + +void +js_TraceParseContext(JSTracer *trc, JSParseContext *pc) +{ + JSParsedObjectBox *pob; + + JS_ASSERT(pc->tempRoot.u.parseContext == pc); + pob = pc->traceListHead; + while (pob) { + JS_CALL_OBJECT_TRACER(trc, pob->object, "parser.object"); + pob = pob->traceLink; + } +} + +static JSParseNode * +RecycleTree(JSParseNode *pn, JSTreeContext *tc) +{ + JSParseNode *next; + + if (!pn) + return NULL; + + /* Catch back-to-back dup recycles. */ + JS_ASSERT(pn != tc->parseContext->nodeList); + next = pn->pn_next; + pn->pn_next = tc->parseContext->nodeList; + tc->parseContext->nodeList = pn; +#ifdef METER_PARSENODES + recyclednodes++; +#endif + return next; +} + +static JSParseNode * +NewOrRecycledNode(JSContext *cx, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = tc->parseContext->nodeList; + if (!pn) { + JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool); + if (!pn) + js_ReportOutOfScriptQuota(cx); + } else { + tc->parseContext->nodeList = pn->pn_next; + + /* Recycle immediate descendents only, to save work and working set. */ + switch (pn->pn_arity) { + case PN_FUNC: + RecycleTree(pn->pn_body, tc); + break; + case PN_LIST: + if (pn->pn_head) { + /* XXX check for dup recycles in the list */ + *pn->pn_tail = tc->parseContext->nodeList; + tc->parseContext->nodeList = pn->pn_head; +#ifdef METER_PARSENODES + recyclednodes += pn->pn_count; +#endif + } + break; + case PN_TERNARY: + RecycleTree(pn->pn_kid1, tc); + RecycleTree(pn->pn_kid2, tc); + RecycleTree(pn->pn_kid3, tc); + break; + case PN_BINARY: + if (pn->pn_left != pn->pn_right) + RecycleTree(pn->pn_left, tc); + RecycleTree(pn->pn_right, tc); + break; + case PN_UNARY: + RecycleTree(pn->pn_kid, tc); + break; + case PN_NAME: + RecycleTree(pn->pn_expr, tc); + break; + case PN_NULLARY: + break; + } + } + if (pn) { +#ifdef METER_PARSENODES + parsenodes++; + if (parsenodes - recyclednodes > maxparsenodes) + maxparsenodes = parsenodes - recyclednodes; +#endif + memset(&pn->pn_u, 0, sizeof pn->pn_u); + pn->pn_next = NULL; + } + return pn; +} + +/* + * Allocate a JSParseNode from cx's temporary arena. + */ +static JSParseNode * +NewParseNode(JSContext *cx, JSTokenStream *ts, JSParseNodeArity arity, + JSTreeContext *tc) +{ + JSParseNode *pn; + JSToken *tp; + + pn = NewOrRecycledNode(cx, tc); + if (!pn) + return NULL; + tp = &CURRENT_TOKEN(ts); + pn->pn_type = tp->type; + pn->pn_pos = tp->pos; + pn->pn_op = JSOP_NOP; + pn->pn_arity = arity; + return pn; +} + +static JSParseNode * +NewBinary(JSContext *cx, JSTokenType tt, + JSOp op, JSParseNode *left, JSParseNode *right, + JSTreeContext *tc) +{ + JSParseNode *pn, *pn1, *pn2; + + if (!left || !right) + return NULL; + + /* + * Flatten a left-associative (left-heavy) tree of a given operator into + * a list, to reduce js_FoldConstants and js_EmitTree recursion. + */ + if (left->pn_type == tt && + left->pn_op == op && + (js_CodeSpec[op].format & JOF_LEFTASSOC)) { + if (left->pn_arity != PN_LIST) { + pn1 = left->pn_left, pn2 = left->pn_right; + left->pn_arity = PN_LIST; + PN_INIT_LIST_1(left, pn1); + PN_APPEND(left, pn2); + if (tt == TOK_PLUS) { + if (pn1->pn_type == TOK_STRING) + left->pn_extra |= PNX_STRCAT; + else if (pn1->pn_type != TOK_NUMBER) + left->pn_extra |= PNX_CANTFOLD; + if (pn2->pn_type == TOK_STRING) + left->pn_extra |= PNX_STRCAT; + else if (pn2->pn_type != TOK_NUMBER) + left->pn_extra |= PNX_CANTFOLD; + } + } + PN_APPEND(left, right); + left->pn_pos.end = right->pn_pos.end; + if (tt == TOK_PLUS) { + if (right->pn_type == TOK_STRING) + left->pn_extra |= PNX_STRCAT; + else if (right->pn_type != TOK_NUMBER) + left->pn_extra |= PNX_CANTFOLD; + } + return left; + } + + /* + * Fold constant addition immediately, to conserve node space and, what's + * more, so js_FoldConstants never sees mixed addition and concatenation + * operations with more than one leading non-string operand in a PN_LIST + * generated for expressions such as 1 + 2 + "pt" (which should evaluate + * to "3pt", not "12pt"). + */ + if (tt == TOK_PLUS && + left->pn_type == TOK_NUMBER && + right->pn_type == TOK_NUMBER) { + left->pn_dval += right->pn_dval; + left->pn_pos.end = right->pn_pos.end; + RecycleTree(right, tc); + return left; + } + + pn = NewOrRecycledNode(cx, tc); + if (!pn) + return NULL; + pn->pn_type = tt; + pn->pn_pos.begin = left->pn_pos.begin; + pn->pn_pos.end = right->pn_pos.end; + pn->pn_op = op; + pn->pn_arity = PN_BINARY; + pn->pn_left = left; + pn->pn_right = right; + return pn; +} + +#if JS_HAS_GETTER_SETTER +static JSTokenType +CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt) +{ + JSAtom *atom; + JSRuntime *rt; + JSOp op; + const char *name; + + JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_NAME); + atom = CURRENT_TOKEN(ts).t_atom; + rt = cx->runtime; + if (atom == rt->atomState.getterAtom) + op = JSOP_GETTER; + else if (atom == rt->atomState.setterAtom) + op = JSOP_SETTER; + else + return TOK_NAME; + if (js_PeekTokenSameLine(cx, ts) != tt) + return TOK_NAME; + (void) js_GetToken(cx, ts); + if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) + ? js_getter_str + : js_setter_str); + return TOK_ERROR; + } + CURRENT_TOKEN(ts).t_op = op; + if (JS_HAS_STRICT_OPTION(cx)) { + name = js_AtomToPrintableString(cx, atom); + if (!name || + !js_ReportCompileErrorNumber(cx, ts, NULL, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DEPRECATED_USAGE, + name)) { + return TOK_ERROR; + } + } + return tt; +} +#endif + +/* + * Parse a top-level JS script. + */ +JSParseNode * +js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc) +{ + JSTreeContext tc; + JSParseNode *pn; + + /* + * Protect atoms from being collected by a GC activation, which might + * - nest on this thread due to out of memory (the so-called "last ditch" + * GC attempted within js_NewGCThing), or + * - run for any reason on another thread if this thread is suspended on + * an object lock before it finishes generating bytecode into a script + * protected from the GC by a root or a stack frame reference. + */ + TREE_CONTEXT_INIT(&tc, pc); + tc.u.scopeChain = chain; + pn = Statements(cx, TS(pc), &tc); + if (pn) { + if (!js_MatchToken(cx, TS(pc), TOK_EOF)) { + js_ReportCompileErrorNumber(cx, TS(pc), NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); + pn = NULL; + } else { + pn->pn_type = TOK_LC; + if (!js_FoldConstants(cx, pn, &tc)) + pn = NULL; + } + } + + TREE_CONTEXT_FINISH(cx, &tc); + return pn; +} + +/* + * Compile a top-level script. + */ +extern JSScript * +js_CompileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame, + JSPrincipals *principals, uint32 tcflags, + const jschar *chars, size_t length, + FILE *file, const char *filename, uintN lineno) +{ + JSParseContext pc; + JSArenaPool codePool, notePool; + JSCodeGenerator cg; + JSTokenType tt; + JSParseNode *pn; + uint32 scriptGlobals; + JSScript *script; +#ifdef METER_PARSENODES + void *sbrk(ptrdiff_t), *before = sbrk(0); +#endif + + JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | + TCF_STATIC_DEPTH_MASK))); + + /* + * The scripted callerFrame can only be given for compile-and-go scripts + * and non-zero static depth requires callerFrame. + */ + JS_ASSERT_IF(callerFrame, tcflags & TCF_COMPILE_N_GO); + JS_ASSERT_IF(TCF_GET_STATIC_DEPTH(tcflags) != 0, callerFrame); + + if (!js_InitParseContext(cx, &pc, principals, callerFrame, chars, length, + file, filename, lineno)) { + return NULL; + } + + JS_INIT_ARENA_POOL(&codePool, "code", 1024, sizeof(jsbytecode), + &cx->scriptStackQuota); + JS_INIT_ARENA_POOL(¬ePool, "note", 1024, sizeof(jssrcnote), + &cx->scriptStackQuota); + js_InitCodeGenerator(cx, &cg, &pc, &codePool, ¬ePool, + pc.tokenStream.lineno); + + MUST_FLOW_THROUGH("out"); + cg.treeContext.flags |= (uint16) tcflags; + cg.treeContext.u.scopeChain = scopeChain; + cg.staticDepth = TCF_GET_STATIC_DEPTH(tcflags); + + if ((tcflags & TCF_COMPILE_N_GO) && callerFrame && callerFrame->fun) { + /* + * An eval script in a caller frame needs to have its enclosing function + * captured in case it uses an upvar reference, and someone wishes to + * decompile it while running. + */ + JSParsedObjectBox *pob = js_NewParsedObjectBox(cx, &pc, callerFrame->callee); + pob->emitLink = cg.objectList.lastPob; + cg.objectList.lastPob = pob; + cg.objectList.length++; + } + + /* Inline Statements() to emit as we go to save space. */ + for (;;) { + pc.tokenStream.flags |= TSF_OPERAND; + tt = js_PeekToken(cx, &pc.tokenStream); + pc.tokenStream.flags &= ~TSF_OPERAND; + if (tt <= TOK_EOF) { + if (tt == TOK_EOF) + break; + JS_ASSERT(tt == TOK_ERROR); + script = NULL; + goto out; + } + + pn = Statement(cx, &pc.tokenStream, &cg.treeContext); + if (!pn) { + script = NULL; + goto out; + } + JS_ASSERT(!cg.treeContext.blockNode); + + if (!js_FoldConstants(cx, pn, &cg.treeContext) || + !js_EmitTree(cx, &cg, pn)) { + script = NULL; + goto out; + } + RecycleTree(pn, &cg.treeContext); + } + + /* + * Global variables and regexps shares the index space with locals. Due to + * incremental code generation we need to patch the bytecode to adjust the + * local references to skip the globals. + */ + scriptGlobals = cg.treeContext.ngvars + cg.regexpList.length; + if (scriptGlobals != 0) { + jsbytecode *code, *end; + JSOp op; + const JSCodeSpec *cs; + uintN len, slot; + + if (scriptGlobals >= SLOTNO_LIMIT) + goto too_many_slots; + code = CG_BASE(&cg); + for (end = code + CG_OFFSET(&cg); code != end; code += len) { + JS_ASSERT(code < end); + op = (JSOp) *code; + cs = &js_CodeSpec[op]; + len = (cs->length > 0) + ? (uintN) cs->length + : js_GetVariableBytecodeLength(code); + if (JOF_TYPE(cs->format) == JOF_LOCAL || + (JOF_TYPE(cs->format) == JOF_SLOTATOM)) { + /* + * JSOP_GETARGPROP also has JOF_SLOTATOM type, but it may be + * emitted only for a function. + */ + JS_ASSERT((JOF_TYPE(cs->format) == JOF_SLOTATOM) == + (op == JSOP_GETLOCALPROP)); + slot = GET_SLOTNO(code); + slot += scriptGlobals; + if (slot >= SLOTNO_LIMIT) + goto too_many_slots; + SET_SLOTNO(code, slot); + } + } + } + +#ifdef METER_PARSENODES + printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n", + (char *)sbrk(0) - (char *)before, + parsenodes, + maxparsenodes, + parsenodes - recyclednodes); + before = sbrk(0); +#endif + + /* + * Nowadays the threaded interpreter needs a stop instruction, so we + * do have to emit that here. + */ + if (js_Emit1(cx, &cg, JSOP_STOP) < 0) { + script = NULL; + goto out; + } +#ifdef METER_PARSENODES + printf("Code-gen growth: %d (%u bytecodes, %u srcnotes)\n", + (char *)sbrk(0) - (char *)before, CG_OFFSET(cg), cg->noteCount); +#endif +#ifdef JS_ARENAMETER + JS_DumpArenaStats(stdout); +#endif + script = js_NewScriptFromCG(cx, &cg); + +#ifdef JS_SCOPE_DEPTH_METER + if (script) { + JSObject *obj = scopeChain; + uintN depth = 1; + while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL) + ++depth; + JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); + } +#endif + + out: + js_FinishCodeGenerator(cx, &cg); + JS_FinishArenaPool(&codePool); + JS_FinishArenaPool(¬ePool); + js_FinishParseContext(cx, &pc); + return script; + + too_many_slots: + js_ReportCompileErrorNumber(cx, &pc.tokenStream, NULL, + JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); + script = NULL; + goto out; +} + +/* + * Insist on a final return before control flows out of pn. Try to be a bit + * smart about loops: do {...; return e2;} while(0) at the end of a function + * that contains an early return e1 will get a strict warning. Similarly for + * iloops: while (true){...} is treated as though ... returns. + */ +#define ENDS_IN_OTHER 0 +#define ENDS_IN_RETURN 1 +#define ENDS_IN_BREAK 2 + +static int +HasFinalReturn(JSParseNode *pn) +{ + JSParseNode *pn2, *pn3; + uintN rv, rv2, hasDefault; + + switch (pn->pn_type) { + case TOK_LC: + if (!pn->pn_head) + return ENDS_IN_OTHER; + return HasFinalReturn(PN_LAST(pn)); + + case TOK_IF: + if (!pn->pn_kid3) + return ENDS_IN_OTHER; + return HasFinalReturn(pn->pn_kid2) & HasFinalReturn(pn->pn_kid3); + + case TOK_WHILE: + pn2 = pn->pn_left; + if (pn2->pn_type == TOK_PRIMARY && pn2->pn_op == JSOP_TRUE) + return ENDS_IN_RETURN; + if (pn2->pn_type == TOK_NUMBER && pn2->pn_dval) + return ENDS_IN_RETURN; + return ENDS_IN_OTHER; + + case TOK_DO: + pn2 = pn->pn_right; + if (pn2->pn_type == TOK_PRIMARY) { + if (pn2->pn_op == JSOP_FALSE) + return HasFinalReturn(pn->pn_left); + if (pn2->pn_op == JSOP_TRUE) + return ENDS_IN_RETURN; + } + if (pn2->pn_type == TOK_NUMBER) { + if (pn2->pn_dval == 0) + return HasFinalReturn(pn->pn_left); + return ENDS_IN_RETURN; + } + return ENDS_IN_OTHER; + + case TOK_FOR: + pn2 = pn->pn_left; + if (pn2->pn_arity == PN_TERNARY && !pn2->pn_kid2) + return ENDS_IN_RETURN; + return ENDS_IN_OTHER; + + case TOK_SWITCH: + rv = ENDS_IN_RETURN; + hasDefault = ENDS_IN_OTHER; + pn2 = pn->pn_right; + if (pn2->pn_type == TOK_LEXICALSCOPE) + pn2 = pn2->pn_expr; + for (pn2 = pn2->pn_head; rv && pn2; pn2 = pn2->pn_next) { + if (pn2->pn_type == TOK_DEFAULT) + hasDefault = ENDS_IN_RETURN; + pn3 = pn2->pn_right; + JS_ASSERT(pn3->pn_type == TOK_LC); + if (pn3->pn_head) { + rv2 = HasFinalReturn(PN_LAST(pn3)); + if (rv2 == ENDS_IN_OTHER && pn2->pn_next) + /* Falling through to next case or default. */; + else + rv &= rv2; + } + } + /* If a final switch has no default case, we judge it harshly. */ + rv &= hasDefault; + return rv; + + case TOK_BREAK: + return ENDS_IN_BREAK; + + case TOK_WITH: + return HasFinalReturn(pn->pn_right); + + case TOK_RETURN: + return ENDS_IN_RETURN; + + case TOK_COLON: + case TOK_LEXICALSCOPE: + return HasFinalReturn(pn->pn_expr); + + case TOK_THROW: + return ENDS_IN_RETURN; + + case TOK_TRY: + /* If we have a finally block that returns, we are done. */ + if (pn->pn_kid3) { + rv = HasFinalReturn(pn->pn_kid3); + if (rv == ENDS_IN_RETURN) + return rv; + } + + /* Else check the try block and any and all catch statements. */ + rv = HasFinalReturn(pn->pn_kid1); + if (pn->pn_kid2) { + JS_ASSERT(pn->pn_kid2->pn_arity == PN_LIST); + for (pn2 = pn->pn_kid2->pn_head; pn2; pn2 = pn2->pn_next) + rv &= HasFinalReturn(pn2); + } + return rv; + + case TOK_CATCH: + /* Check this catch block's body. */ + return HasFinalReturn(pn->pn_kid3); + + case TOK_LET: + /* Non-binary let statements are let declarations. */ + if (pn->pn_arity != PN_BINARY) + return ENDS_IN_OTHER; + return HasFinalReturn(pn->pn_right); + + default: + return ENDS_IN_OTHER; + } +} + +static JSBool +ReportBadReturn(JSContext *cx, JSTreeContext *tc, uintN flags, uintN errnum, + uintN anonerrnum) +{ + const char *name; + + JS_ASSERT(tc->flags & TCF_IN_FUNCTION); + if (tc->u.fun->atom) { + name = js_AtomToPrintableString(cx, tc->u.fun->atom); + } else { + errnum = anonerrnum; + name = NULL; + } + return js_ReportCompileErrorNumber(cx, TS(tc->parseContext), NULL, flags, + errnum, name); +} + +static JSBool +CheckFinalReturn(JSContext *cx, JSTreeContext *tc, JSParseNode *pn) +{ + JS_ASSERT(tc->flags & TCF_IN_FUNCTION); + return HasFinalReturn(pn) == ENDS_IN_RETURN || + ReportBadReturn(cx, tc, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE); +} + +static JSParseNode * +FunctionBody(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSStmtInfo stmtInfo; + uintN oldflags, firstLine; + JSParseNode *pn; + + JS_ASSERT(tc->flags & TCF_IN_FUNCTION); + js_PushStatement(tc, &stmtInfo, STMT_BLOCK, -1); + stmtInfo.flags = SIF_BODY_BLOCK; + + oldflags = tc->flags; + tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID); + + /* + * Save the body's first line, and store it in pn->pn_pos.begin.lineno + * later, because we may have not peeked in ts yet, so Statements won't + * acquire a valid pn->pn_pos.begin from the current token. + */ + firstLine = ts->lineno; +#if JS_HAS_EXPR_CLOSURES + if (CURRENT_TOKEN(ts).type == TOK_LC) { + pn = Statements(cx, ts, tc); + } else { + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (pn) { + pn->pn_kid = AssignExpr(cx, ts, tc); + if (!pn->pn_kid) { + pn = NULL; + } else { + if (tc->flags & TCF_FUN_IS_GENERATOR) { + ReportBadReturn(cx, tc, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_RETURN, + JSMSG_BAD_ANON_GENERATOR_RETURN); + pn = NULL; + } else { + pn->pn_type = TOK_RETURN; + pn->pn_op = JSOP_RETURN; + pn->pn_pos.end = pn->pn_kid->pn_pos.end; + } + } + } + } +#else + pn = Statements(cx, ts, tc); +#endif + + if (pn) { + js_PopStatement(tc); + pn->pn_pos.begin.lineno = firstLine; + + /* Check for falling off the end of a function that returns a value. */ + if (JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR) && + !CheckFinalReturn(cx, tc, pn)) { + pn = NULL; + } + } + + tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS)); + return pn; +} + +/* + * Compile a JS function body, which might appear as the value of an event + * handler attribute in an HTML tag. + */ +JSBool +js_CompileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals, + const jschar *chars, size_t length, + const char *filename, uintN lineno) +{ + JSParseContext pc; + JSArenaPool codePool, notePool; + JSCodeGenerator funcg; + JSParseNode *pn; + + if (!js_InitParseContext(cx, &pc, principals, NULL, chars, length, NULL, + filename, lineno)) { + return JS_FALSE; + } + + /* No early return from this point until js_FinishParseContext call. */ + JS_INIT_ARENA_POOL(&codePool, "code", 1024, sizeof(jsbytecode), + &cx->scriptStackQuota); + JS_INIT_ARENA_POOL(¬ePool, "note", 1024, sizeof(jssrcnote), + &cx->scriptStackQuota); + js_InitCodeGenerator(cx, &funcg, &pc, &codePool, ¬ePool, + pc.tokenStream.lineno); + funcg.treeContext.flags |= TCF_IN_FUNCTION; + funcg.treeContext.u.fun = fun; + + /* + * Farble the body so that it looks like a block statement to js_EmitTree, + * which is called beneath FunctionBody; see Statements, further below in + * this file. FunctionBody pushes a STMT_BLOCK record around its call to + * Statements, so Statements will not compile each statement as it loops + * to save JSParseNode space -- it will not compile at all, only build a + * JSParseNode tree. + * + * Therefore we must fold constants, allocate try notes, and generate code + * for this function, including a stop opcode at the end. + */ + CURRENT_TOKEN(&pc.tokenStream).type = TOK_LC; + pn = FunctionBody(cx, &pc.tokenStream, &funcg.treeContext); + if (pn) { + if (!js_MatchToken(cx, &pc.tokenStream, TOK_EOF)) { + js_ReportCompileErrorNumber(cx, &pc.tokenStream, NULL, + JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); + pn = NULL; + } else { + if (!js_FoldConstants(cx, pn, &funcg.treeContext) || + !js_EmitFunctionScript(cx, &funcg, pn)) { + pn = NULL; + } + } + } + + /* Restore saved state and release code generation arenas. */ + js_FinishCodeGenerator(cx, &funcg); + JS_FinishArenaPool(&codePool); + JS_FinishArenaPool(¬ePool); + js_FinishParseContext(cx, &pc); + return pn != NULL; +} + +/* + * Parameter block types for the several Binder functions. We use a common + * helper function signature in order to share code among destructuring and + * simple variable declaration parsers. In the destructuring case, the binder + * function is called indirectly from the variable declaration parser by way + * of CheckDestructuring and its friends. + */ +typedef struct BindData BindData; + +typedef JSBool +(*Binder)(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc); + +struct BindData { + JSParseNode *pn; /* error source coordinate */ + JSOp op; /* prolog bytecode or nop */ + Binder binder; /* binder, discriminates u */ + union { + struct { + uintN overflow; + } let; + } u; +}; + +static JSBool +BindArg(JSContext *cx, JSAtom *atom, JSTreeContext *tc) +{ + const char *name; + + /* + * Check for a duplicate parameter name, a "feature" required by ECMA-262. + */ + JS_ASSERT(tc->flags & TCF_IN_FUNCTION); + if (js_LookupLocal(cx, tc->u.fun, atom, NULL) != JSLOCAL_NONE) { + name = js_AtomToPrintableString(cx, atom); + if (!name || + !js_ReportCompileErrorNumber(cx, TS(tc->parseContext), NULL, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DUPLICATE_FORMAL, + name)) { + return JS_FALSE; + } + } + + return js_AddLocal(cx, tc->u.fun, atom, JSLOCAL_ARG); +} + +static JSBool +BindLocalVariable(JSContext *cx, JSFunction *fun, JSAtom *atom, + JSLocalKind localKind) +{ + JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST); + + /* + * Don't bind a variable with the hidden name 'arguments', per ECMA-262. + * Instead 'var arguments' always restates the predefined property of the + * activation objects with unhidden name 'arguments'. Assignment to such + * a variable must be handled specially. + */ + if (atom == cx->runtime->atomState.argumentsAtom) + return JS_TRUE; + + return js_AddLocal(cx, fun, atom, localKind); +} + +#if JS_HAS_DESTRUCTURING +/* + * Forward declaration to maintain top-down presentation. + */ +static JSParseNode * +DestructuringExpr(JSContext *cx, BindData *data, JSTreeContext *tc, + JSTokenType tt); + +static JSBool +BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, + JSTreeContext *tc) +{ + JSAtomListElement *ale; + const char *name; + + JS_ASSERT(tc->flags & TCF_IN_FUNCTION); + ATOM_LIST_SEARCH(ale, &tc->decls, atom); + if (!ale) { + ale = js_IndexAtom(cx, atom, &tc->decls); + if (!ale) + return JS_FALSE; + ALE_SET_JSOP(ale, data->op); + } + + if (js_LookupLocal(cx, tc->u.fun, atom, NULL) != JSLOCAL_NONE) { + name = js_AtomToPrintableString(cx, atom); + if (!name || + !js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DUPLICATE_FORMAL, + name)) { + return JS_FALSE; + } + } else { + if (!BindLocalVariable(cx, tc->u.fun, atom, JSLOCAL_VAR)) + return JS_FALSE; + } + return JS_TRUE; +} +#endif /* JS_HAS_DESTRUCTURING */ + +static JSFunction * +NewCompilerFunction(JSContext *cx, JSTreeContext *tc, JSAtom *atom, + uintN lambda) +{ + JSObject *parent; + JSFunction *fun; + + JS_ASSERT((lambda & ~JSFUN_LAMBDA) == 0); + parent = (tc->flags & TCF_IN_FUNCTION) + ? FUN_OBJECT(tc->u.fun) + : tc->u.scopeChain; + fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED | lambda, + parent, atom); + if (fun && !(tc->flags & TCF_COMPILE_N_GO)) { + STOBJ_CLEAR_PARENT(FUN_OBJECT(fun)); + STOBJ_CLEAR_PROTO(FUN_OBJECT(fun)); + } + return fun; +} + +static JSParseNode * +FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + uintN lambda) +{ + JSOp op, prevop; + JSParseNode *pn, *body, *result; + JSTokenType tt; + JSAtom *funAtom; + JSParsedObjectBox *funpob; + JSAtomListElement *ale; + JSFunction *fun; + JSTreeContext funtc; +#if JS_HAS_DESTRUCTURING + JSParseNode *item, *list = NULL; +#endif + + /* Make a TOK_FUNCTION node. */ +#if JS_HAS_GETTER_SETTER + op = CURRENT_TOKEN(ts).t_op; +#endif + pn = NewParseNode(cx, ts, PN_FUNC, tc); + if (!pn) + return NULL; +#ifdef DEBUG + pn->pn_index = (uint32) -1; +#endif + + /* Scan the optional function name into funAtom. */ + ts->flags |= TSF_KEYWORD_IS_NAME; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_KEYWORD_IS_NAME; + if (tt == TOK_NAME) { + funAtom = CURRENT_TOKEN(ts).t_atom; + } else { + if (lambda == 0 && (cx->options & JSOPTION_ANONFUNFIX)) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); + return NULL; + } + funAtom = NULL; + js_UngetToken(ts); + } + + /* + * Record names for function statements in tc->decls so we know when to + * avoid optimizing variable references that might name a function. + */ + if (lambda == 0 && funAtom) { + ATOM_LIST_SEARCH(ale, &tc->decls, funAtom); + if (ale) { + prevop = ALE_JSOP(ale); + if (JS_HAS_STRICT_OPTION(cx) || prevop == JSOP_DEFCONST) { + const char *name = js_AtomToPrintableString(cx, funAtom); + if (!name || + !js_ReportCompileErrorNumber(cx, ts, NULL, + (prevop != JSOP_DEFCONST) + ? JSREPORT_WARNING | + JSREPORT_STRICT + : JSREPORT_ERROR, + JSMSG_REDECLARED_VAR, + (prevop == JSOP_DEFFUN) + ? js_function_str + : (prevop == JSOP_DEFCONST) + ? js_const_str + : js_var_str, + name)) { + return NULL; + } + } + if (!AT_TOP_LEVEL(tc) && prevop == JSOP_DEFVAR) + tc->flags |= TCF_FUN_CLOSURE_VS_VAR; + } else { + ale = js_IndexAtom(cx, funAtom, &tc->decls); + if (!ale) + return NULL; + } + ALE_SET_JSOP(ale, JSOP_DEFFUN); + + /* + * A function nested at top level inside another's body needs only a + * local variable to bind its name to its value, and not an activation + * object property (it might also need the activation property, if the + * outer function contains with statements, e.g., but the stack slot + * wins when jsemit.c's BindNameToSlot can optimize a JSOP_NAME into a + * JSOP_GETLOCAL bytecode). + */ + if (AT_TOP_LEVEL(tc) && (tc->flags & TCF_IN_FUNCTION)) { + JSLocalKind localKind; + + /* + * Define a property on the outer function so that BindNameToSlot + * can properly optimize accesses. Note that we need a variable, + * not an argument, for the function statement. Thus we add a + * variable even if the parameter with the given name already + * exists. + */ + localKind = js_LookupLocal(cx, tc->u.fun, funAtom, NULL); + if (localKind == JSLOCAL_NONE || localKind == JSLOCAL_ARG) { + if (!js_AddLocal(cx, tc->u.fun, funAtom, JSLOCAL_VAR)) + return NULL; + } + } + } + + fun = NewCompilerFunction(cx, tc, funAtom, lambda); + if (!fun) + return NULL; + +#if JS_HAS_GETTER_SETTER + if (op != JSOP_NOP) + fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER; +#endif + + /* + * Create wrapping box for fun->object early to protect against a + * last-ditch GC. + */ + funpob = js_NewParsedObjectBox(cx, tc->parseContext, FUN_OBJECT(fun)); + if (!funpob) + return NULL; + + /* Initialize early for possible flags mutation via DestructuringExpr. */ + TREE_CONTEXT_INIT(&funtc, tc->parseContext); + funtc.flags |= TCF_IN_FUNCTION | (tc->flags & TCF_COMPILE_N_GO); + funtc.u.fun = fun; + + /* Now parse formal argument list and compute fun->nargs. */ + MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL); + if (!js_MatchToken(cx, ts, TOK_RP)) { + do { + tt = js_GetToken(cx, ts); + switch (tt) { +#if JS_HAS_DESTRUCTURING + case TOK_LB: + case TOK_LC: + { + BindData data; + JSParseNode *lhs, *rhs; + jsint slot; + + /* + * A destructuring formal parameter turns into one or more + * local variables initialized from properties of a single + * anonymous positional parameter, so here we must tweak our + * binder and its data. + */ + data.pn = NULL; + data.op = JSOP_DEFVAR; + data.binder = BindDestructuringArg; + lhs = DestructuringExpr(cx, &data, &funtc, tt); + if (!lhs) + return NULL; + + /* + * Adjust fun->nargs to count the single anonymous positional + * parameter that is to be destructured. + */ + slot = fun->nargs; + if (!js_AddLocal(cx, fun, NULL, JSLOCAL_ARG)) + return NULL; + + /* + * Synthesize a destructuring assignment from the single + * anonymous positional parameter into the destructuring + * left-hand-side expression and accumulate it in list. + */ + rhs = NewParseNode(cx, ts, PN_NAME, tc); + if (!rhs) + return NULL; + rhs->pn_type = TOK_NAME; + rhs->pn_op = JSOP_GETARG; + rhs->pn_atom = cx->runtime->atomState.emptyAtom; + rhs->pn_slot = slot; + + item = NewBinary(cx, TOK_ASSIGN, JSOP_NOP, lhs, rhs, tc); + if (!item) + return NULL; + if (!list) { + list = NewParseNode(cx, ts, PN_LIST, tc); + if (!list) + return NULL; + list->pn_type = TOK_COMMA; + PN_INIT_LIST(list); + } + PN_APPEND(list, item); + break; + } +#endif /* JS_HAS_DESTRUCTURING */ + + case TOK_NAME: + if (!BindArg(cx, CURRENT_TOKEN(ts).t_atom, &funtc)) + return NULL; + break; + + default: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_MISSING_FORMAL); + return NULL; + } + } while (js_MatchToken(cx, ts, TOK_COMMA)); + + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL); + } + +#if JS_HAS_EXPR_CLOSURES + ts->flags |= TSF_OPERAND; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt != TOK_LC) { + js_UngetToken(ts); + fun->flags |= JSFUN_EXPR_CLOSURE; + } +#else + MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY); +#endif + pn->pn_pos.begin = CURRENT_TOKEN(ts).pos.begin; + + body = FunctionBody(cx, ts, &funtc); + if (!body) + return NULL; + +#if JS_HAS_EXPR_CLOSURES + if (tt == TOK_LC) + MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY); + else if (lambda == 0) + js_MatchToken(cx, ts, TOK_SEMI); +#else + MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY); +#endif + pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + +#if JS_HAS_DESTRUCTURING + /* + * If there were destructuring formal parameters, prepend the initializing + * comma expression that we synthesized to body. If the body is a lexical + * scope node, we must make a special TOK_SEQ node, to prepend the formal + * parameter destructuring code without bracing the decompilation of the + * function body's lexical scope. + */ + if (list) { + if (body->pn_arity != PN_LIST) { + JSParseNode *block; + + block = NewParseNode(cx, ts, PN_LIST, tc); + if (!block) + return NULL; + block->pn_type = TOK_SEQ; + block->pn_pos = body->pn_pos; + PN_INIT_LIST_1(block, body); + + body = block; + } + + item = NewParseNode(cx, ts, PN_UNARY, tc); + if (!item) + return NULL; + + item->pn_type = TOK_SEMI; + item->pn_pos.begin = item->pn_pos.end = body->pn_pos.begin; + item->pn_kid = list; + item->pn_next = body->pn_head; + body->pn_head = item; + if (body->pn_tail == &body->pn_head) + body->pn_tail = &item->pn_next; + ++body->pn_count; + } +#endif + + /* + * If we collected flags that indicate nested heavyweight functions, or + * this function contains heavyweight-making statements (references to + * __parent__ or __proto__; use of with, or eval; and assignment to + * arguments), flag the function as heavyweight (requiring a call object + * per invocation). + */ + if (funtc.flags & TCF_FUN_HEAVYWEIGHT) { + fun->flags |= JSFUN_HEAVYWEIGHT; + tc->flags |= TCF_FUN_HEAVYWEIGHT; + } else { + /* + * If this function is a named statement function not at top-level + * (i.e. not a top-level function definiton or expression), then + * our enclosing function, if any, must be heavyweight. + * + * The TCF_FUN_USES_NONLOCALS flag is set only by the code generator, + * so it won't be set here. Assert that it's not. We have to check + * it later, in js_EmitTree, after js_EmitFunctionScript has traversed + * the function's body. + */ + JS_ASSERT(!(funtc.flags & TCF_FUN_USES_NONLOCALS)); + if (lambda == 0 && funAtom && !AT_TOP_LEVEL(tc)) + tc->flags |= TCF_FUN_HEAVYWEIGHT; + } + + result = pn; + if (lambda != 0) { + /* + * ECMA ed. 3 standard: function expression, possibly anonymous. + */ + op = funAtom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ; + } else if (!funAtom) { + /* + * If this anonymous function definition is *not* embedded within a + * larger expression, we treat it as an expression statement, not as + * a function declaration -- and not as a syntax error (as ECMA-262 + * Edition 3 would have it). Backward compatibility must trump all, + * unless JSOPTION_ANONFUNFIX is set. + */ + result = NewParseNode(cx, ts, PN_UNARY, tc); + if (!result) + return NULL; + result->pn_type = TOK_SEMI; + result->pn_pos = pn->pn_pos; + result->pn_kid = pn; + op = JSOP_ANONFUNOBJ; + } else if (!AT_TOP_LEVEL(tc)) { + /* + * ECMA ed. 3 extension: a function expression statement not at the + * top level, e.g., in a compound statement such as the "then" part + * of an "if" statement, binds a closure only if control reaches that + * sub-statement. + */ + op = JSOP_DEFFUN; + } else { + op = JSOP_NOP; + } + + pn->pn_funpob = funpob; + pn->pn_op = op; + pn->pn_body = body; + pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS | TCF_COMPILE_N_GO); + TREE_CONTEXT_FINISH(cx, &funtc); + return result; +} + +static JSParseNode * +FunctionStmt(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + return FunctionDef(cx, ts, tc, 0); +} + +static JSParseNode * +FunctionExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + return FunctionDef(cx, ts, tc, JSFUN_LAMBDA); +} + +/* + * Parse the statements in a block, creating a TOK_LC node that lists the + * statements' trees. If called from block-parsing code, the caller must + * match { before and } after. + */ +static JSParseNode * +Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn, *pn2, *saveBlock; + JSTokenType tt; + + JS_CHECK_RECURSION(cx, return NULL); + + pn = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn) + return NULL; + saveBlock = tc->blockNode; + tc->blockNode = pn; + PN_INIT_LIST(pn); + + for (;;) { + ts->flags |= TSF_OPERAND; + tt = js_PeekToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt <= TOK_EOF || tt == TOK_RC) { + if (tt == TOK_ERROR) + return NULL; + break; + } + pn2 = Statement(cx, ts, tc); + if (!pn2) { + if (ts->flags & TSF_EOF) + ts->flags |= TSF_UNEXPECTED_EOF; + return NULL; + } + + if (pn2->pn_type == TOK_FUNCTION) { + /* + * PNX_FUNCDEFS notifies the emitter that the block contains top- + * level function definitions that should be processed before the + * rest of nodes. + * + * TCF_HAS_FUNCTION_STMT is for the TOK_LC case in Statement. It + * is relevant only for function definitions not at top-level, + * which we call function statements. + */ + if (AT_TOP_LEVEL(tc)) + pn->pn_extra |= PNX_FUNCDEFS; + else + tc->flags |= TCF_HAS_FUNCTION_STMT; + } + PN_APPEND(pn, pn2); + } + + /* + * Handle the case where there was a let declaration under this block. If + * it replaced tc->blockNode with a new block node then we must refresh pn + * and then restore tc->blockNode. + */ + if (tc->blockNode != pn) + pn = tc->blockNode; + tc->blockNode = saveBlock; + + pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + return pn; +} + +static JSParseNode * +Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + + MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND); + pn = ParenExpr(cx, ts, tc, NULL, NULL); + if (!pn) + return NULL; + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND); + + /* + * Check for (a = b) and warn about possible (a == b) mistype iff b's + * operator has greater precedence than ==. + */ + if (pn->pn_type == TOK_ASSIGN && + pn->pn_op == JSOP_NOP && + pn->pn_right->pn_type > TOK_EQOP) + { + if (!js_ReportCompileErrorNumber(cx, ts, NULL, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_EQUAL_AS_ASSIGN, + "")) { + return NULL; + } + } + return pn; +} + +static JSBool +MatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn) +{ + JSAtom *label; + JSTokenType tt; + + tt = js_PeekTokenSameLine(cx, ts); + if (tt == TOK_ERROR) + return JS_FALSE; + if (tt == TOK_NAME) { + (void) js_GetToken(cx, ts); + label = CURRENT_TOKEN(ts).t_atom; + } else { + label = NULL; + } + pn->pn_atom = label; + return JS_TRUE; +} + +static JSBool +BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) +{ + JSObject *blockObj; + JSScopeProperty *sprop; + JSAtomListElement *ale; + uintN n; + + blockObj = tc->blockChain; + sprop = SCOPE_GET_PROPERTY(OBJ_SCOPE(blockObj), ATOM_TO_JSID(atom)); + ATOM_LIST_SEARCH(ale, &tc->decls, atom); + if (sprop || (ale && ALE_JSOP(ale) == JSOP_DEFCONST)) { + const char *name; + + if (sprop) { + JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID); + JS_ASSERT((uint16)sprop->shortid < OBJ_BLOCK_COUNT(cx, blockObj)); + } + + name = js_AtomToPrintableString(cx, atom); + if (name) { + js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn, + JSREPORT_ERROR, JSMSG_REDECLARED_VAR, + (ale && ALE_JSOP(ale) == JSOP_DEFCONST) + ? js_const_str + : "variable", + name); + } + return JS_FALSE; + } + + n = OBJ_BLOCK_COUNT(cx, blockObj); + if (n == JS_BIT(16)) { + js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn, + JSREPORT_ERROR, data->u.let.overflow); + return JS_FALSE; + } + + /* Use JSPROP_ENUMERATE to aid the disassembler. */ + return js_DefineNativeProperty(cx, blockObj, ATOM_TO_JSID(atom), + JSVAL_VOID, NULL, NULL, + JSPROP_ENUMERATE | + JSPROP_PERMANENT | + JSPROP_SHARED, + SPROP_HAS_SHORTID, (int16) n, NULL); +} + +static JSBool +BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) +{ + JSStmtInfo *stmt; + JSAtomListElement *ale; + JSOp op, prevop; + const char *name; + JSLocalKind localKind; + + stmt = js_LexicalLookup(tc, atom, NULL); + ATOM_LIST_SEARCH(ale, &tc->decls, atom); + op = data->op; + if ((stmt && stmt->type != STMT_WITH) || ale) { + prevop = ale ? ALE_JSOP(ale) : JSOP_DEFVAR; + if (JS_HAS_STRICT_OPTION(cx) + ? op != JSOP_DEFVAR || prevop != JSOP_DEFVAR + : op == JSOP_DEFCONST || prevop == JSOP_DEFCONST) { + name = js_AtomToPrintableString(cx, atom); + if (!name || + !js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn, + (op != JSOP_DEFCONST && + prevop != JSOP_DEFCONST) + ? JSREPORT_WARNING | + JSREPORT_STRICT + : JSREPORT_ERROR, + JSMSG_REDECLARED_VAR, + (prevop == JSOP_DEFFUN) + ? js_function_str + : (prevop == JSOP_DEFCONST) + ? js_const_str + : js_var_str, + name)) { + return JS_FALSE; + } + } + if (op == JSOP_DEFVAR && prevop == JSOP_DEFFUN) + tc->flags |= TCF_FUN_CLOSURE_VS_VAR; + } + if (!ale) { + ale = js_IndexAtom(cx, atom, &tc->decls); + if (!ale) + return JS_FALSE; + } + ALE_SET_JSOP(ale, op); + + if (!(tc->flags & TCF_IN_FUNCTION)) { + /* + * Don't lookup global variables or variables in an active frame at + * compile time. + */ + return JS_TRUE; + } + + localKind = js_LookupLocal(cx, tc->u.fun, atom, NULL); + if (localKind == JSLOCAL_NONE) { + /* + * Property not found in current variable scope: we have not seen this + * variable before. Define a new local variable by adding a property + * to the function's scope, allocating one slot in the function's vars + * frame. Any locals declared in with statement bodies are handled at + * runtime, by script prolog JSOP_DEFVAR opcodes generated for + * slot-less vars. + */ + localKind = (data->op == JSOP_DEFCONST) ? JSLOCAL_CONST : JSLOCAL_VAR; + if (!js_InWithStatement(tc) && + !BindLocalVariable(cx, tc->u.fun, atom, localKind)) { + return JS_FALSE; + } + } else if (localKind == JSLOCAL_ARG) { + name = js_AtomToPrintableString(cx, atom); + if (!name) + return JS_FALSE; + + if (op == JSOP_DEFCONST) { + js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn, + JSREPORT_ERROR, JSMSG_REDECLARED_PARAM, + name); + return JS_FALSE; + } + if (!js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_VAR_HIDES_ARG, name)) { + return JS_FALSE; + } + } else { + /* Not an argument, must be a redeclared local var. */ + JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST); + } + return JS_TRUE; +} + +static JSBool +MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg) +{ + JSParseNode *pn2; + + JS_ASSERT(pn->pn_arity == PN_LIST); + JS_ASSERT(pn->pn_op == JSOP_CALL || pn->pn_op == JSOP_EVAL || pn->pn_op == JSOP_APPLY); + pn2 = pn->pn_head; + if (pn2->pn_type == TOK_FUNCTION && (pn2->pn_flags & TCF_GENEXP_LAMBDA)) { + js_ReportCompileErrorNumber(cx, TS(tc->parseContext), pn, + JSREPORT_ERROR, msg); + return JS_FALSE; + } + pn->pn_op = JSOP_SETCALL; + return JS_TRUE; +} + +#if JS_HAS_DESTRUCTURING + +static JSBool +BindDestructuringVar(JSContext *cx, BindData *data, JSParseNode *pn, + JSTreeContext *tc) +{ + JSAtom *atom; + + /* + * Destructuring is a form of assignment, so just as for an initialized + * simple variable, we must check for assignment to 'arguments' and flag + * the enclosing function (if any) as heavyweight. + */ + JS_ASSERT(pn->pn_type == TOK_NAME); + atom = pn->pn_atom; + if (atom == cx->runtime->atomState.argumentsAtom) + tc->flags |= TCF_FUN_HEAVYWEIGHT; + + data->pn = pn; + if (!data->binder(cx, data, atom, tc)) + return JS_FALSE; + data->pn = NULL; + + /* + * Select the appropriate name-setting opcode, which may be specialized + * further for local variable and argument slot optimizations. At this + * point, we can't select the optimal final opcode, yet we must preserve + * the CONST bit and convey "set", not "get". + */ + if (data->op == JSOP_DEFCONST) { + pn->pn_op = JSOP_SETCONST; + pn->pn_const = JS_TRUE; + } else { + pn->pn_op = JSOP_SETNAME; + pn->pn_const = JS_FALSE; + } + return JS_TRUE; +} + +/* + * Here, we are destructuring {... P: Q, ...} = R, where P is any id, Q is any + * LHS expression except a destructuring initialiser, and R is on the stack. + * Because R is already evaluated, the usual LHS-specialized bytecodes won't + * work. After pushing R[P] we need to evaluate Q's "reference base" QB and + * then push its property name QN. At this point the stack looks like + * + * [... R, R[P], QB, QN] + * + * We need to set QB[QN] = R[P]. This is a job for JSOP_ENUMELEM, which takes + * its operands with left-hand side above right-hand side: + * + * [rval, lval, xval] + * + * and pops all three values, setting lval[xval] = rval. But we cannot select + * JSOP_ENUMELEM yet, because the LHS may turn out to be an arg or local var, + * which can be optimized further. So we select JSOP_SETNAME. + */ +static JSBool +BindDestructuringLHS(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) +{ + while (pn->pn_type == TOK_RP) + pn = pn->pn_kid; + + switch (pn->pn_type) { + case TOK_NAME: + if (pn->pn_atom == cx->runtime->atomState.argumentsAtom) + tc->flags |= TCF_FUN_HEAVYWEIGHT; + /* FALL THROUGH */ + case TOK_DOT: + case TOK_LB: + pn->pn_op = JSOP_SETNAME; + break; + +#if JS_HAS_LVALUE_RETURN + case TOK_LP: + if (!MakeSetCall(cx, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS)) + return JS_FALSE; + break; +#endif + +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: + if (pn->pn_op == JSOP_XMLNAME) { + pn->pn_op = JSOP_BINDXMLNAME; + break; + } + /* FALL THROUGH */ +#endif + + default: + js_ReportCompileErrorNumber(cx, TS(tc->parseContext), pn, + JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS); + return JS_FALSE; + } + + return JS_TRUE; +} + +typedef struct FindPropValData { + uint32 numvars; /* # of destructuring vars in left side */ + uint32 maxstep; /* max # of steps searching right side */ + JSDHashTable table; /* hash table for O(1) right side search */ +} FindPropValData; + +typedef struct FindPropValEntry { + JSDHashEntryHdr hdr; + JSParseNode *pnkey; + JSParseNode *pnval; +} FindPropValEntry; + +#define ASSERT_VALID_PROPERTY_KEY(pnkey) \ + JS_ASSERT((pnkey)->pn_arity == PN_NULLARY && \ + ((pnkey)->pn_type == TOK_NUMBER || \ + (pnkey)->pn_type == TOK_STRING || \ + (pnkey)->pn_type == TOK_NAME)) + +static JSDHashNumber +HashFindPropValKey(JSDHashTable *table, const void *key) +{ + const JSParseNode *pnkey = (const JSParseNode *)key; + + ASSERT_VALID_PROPERTY_KEY(pnkey); + return (pnkey->pn_type == TOK_NUMBER) + ? (JSDHashNumber) (JSDOUBLE_HI32(pnkey->pn_dval) ^ + JSDOUBLE_LO32(pnkey->pn_dval)) + : ATOM_HASH(pnkey->pn_atom); +} + +static JSBool +MatchFindPropValEntry(JSDHashTable *table, + const JSDHashEntryHdr *entry, + const void *key) +{ + const FindPropValEntry *fpve = (const FindPropValEntry *)entry; + const JSParseNode *pnkey = (const JSParseNode *)key; + + ASSERT_VALID_PROPERTY_KEY(pnkey); + return pnkey->pn_type == fpve->pnkey->pn_type && + ((pnkey->pn_type == TOK_NUMBER) + ? pnkey->pn_dval == fpve->pnkey->pn_dval + : pnkey->pn_atom == fpve->pnkey->pn_atom); +} + +static const JSDHashTableOps FindPropValOps = { + JS_DHashAllocTable, + JS_DHashFreeTable, + HashFindPropValKey, + MatchFindPropValEntry, + JS_DHashMoveEntryStub, + JS_DHashClearEntryStub, + JS_DHashFinalizeStub, + NULL +}; + +#define STEP_HASH_THRESHOLD 10 +#define BIG_DESTRUCTURING 5 +#define BIG_OBJECT_INIT 20 + +static JSParseNode * +FindPropertyValue(JSParseNode *pn, JSParseNode *pnid, FindPropValData *data) +{ + FindPropValEntry *entry; + JSParseNode *pnhit, *pnhead, *pnprop, *pnkey; + uint32 step; + + /* If we have a hash table, use it as the sole source of truth. */ + if (data->table.ops) { + entry = (FindPropValEntry *) + JS_DHashTableOperate(&data->table, pnid, JS_DHASH_LOOKUP); + return JS_DHASH_ENTRY_IS_BUSY(&entry->hdr) ? entry->pnval : NULL; + } + + /* If pn is not an object initialiser node, we can't do anything here. */ + if (pn->pn_type != TOK_RC) + return NULL; + + /* + * We must search all the way through pn's list, to handle the case of an + * id duplicated for two or more property initialisers. + */ + pnhit = NULL; + step = 0; + ASSERT_VALID_PROPERTY_KEY(pnid); + pnhead = pn->pn_head; + if (pnhead && pnhead->pn_type == TOK_DEFSHARP) + pnhead = pnhead->pn_next; + if (pnid->pn_type == TOK_NUMBER) { + for (pnprop = pnhead; pnprop; pnprop = pnprop->pn_next) { + JS_ASSERT(pnprop->pn_type == TOK_COLON); + if (pnprop->pn_op == JSOP_NOP) { + pnkey = pnprop->pn_left; + ASSERT_VALID_PROPERTY_KEY(pnkey); + if (pnkey->pn_type == TOK_NUMBER && + pnkey->pn_dval == pnid->pn_dval) { + pnhit = pnprop; + } + ++step; + } + } + } else { + for (pnprop = pnhead; pnprop; pnprop = pnprop->pn_next) { + JS_ASSERT(pnprop->pn_type == TOK_COLON); + if (pnprop->pn_op == JSOP_NOP) { + pnkey = pnprop->pn_left; + ASSERT_VALID_PROPERTY_KEY(pnkey); + if (pnkey->pn_type == pnid->pn_type && + pnkey->pn_atom == pnid->pn_atom) { + pnhit = pnprop; + } + ++step; + } + } + } + if (!pnhit) + return NULL; + + /* Hit via full search -- see whether it's time to create the hash table. */ + JS_ASSERT(!data->table.ops); + if (step > data->maxstep) { + data->maxstep = step; + if (step >= STEP_HASH_THRESHOLD && + data->numvars >= BIG_DESTRUCTURING && + pn->pn_count >= BIG_OBJECT_INIT && + JS_DHashTableInit(&data->table, &FindPropValOps, pn, + sizeof(FindPropValEntry), + JS_DHASH_DEFAULT_CAPACITY(pn->pn_count))) + { + for (pn = pnhead; pn; pn = pn->pn_next) { + JS_ASSERT(pnprop->pn_type == TOK_COLON); + ASSERT_VALID_PROPERTY_KEY(pn->pn_left); + entry = (FindPropValEntry *) + JS_DHashTableOperate(&data->table, pn->pn_left, + JS_DHASH_ADD); + entry->pnval = pn->pn_right; + } + } + } + return pnhit->pn_right; +} + +/* + * If data is null, the caller is AssignExpr and instead of binding variables, + * we specialize lvalues in the propery value positions of the left-hand side. + * If right is null, just check for well-formed lvalues. + */ +static JSBool +CheckDestructuring(JSContext *cx, BindData *data, + JSParseNode *left, JSParseNode *right, + JSTreeContext *tc) +{ + JSBool ok; + FindPropValData fpvd; + JSParseNode *lhs, *rhs, *pn, *pn2; + + if (left->pn_type == TOK_ARRAYCOMP) { + js_ReportCompileErrorNumber(cx, TS(tc->parseContext), left, + JSREPORT_ERROR, JSMSG_ARRAY_COMP_LEFTSIDE); + return JS_FALSE; + } + +#if JS_HAS_DESTRUCTURING_SHORTHAND + if (right && right->pn_arity == PN_LIST && (right->pn_extra & PNX_SHORTHAND)) { + js_ReportCompileErrorNumber(cx, TS(tc->parseContext), right, + JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); + return JS_FALSE; + } +#endif + + fpvd.table.ops = NULL; + lhs = left->pn_head; + if (lhs && lhs->pn_type == TOK_DEFSHARP) { + pn = lhs; + goto no_var_name; + } + + if (left->pn_type == TOK_RB) { + rhs = (right && right->pn_type == left->pn_type) + ? right->pn_head + : NULL; + + while (lhs) { + pn = lhs, pn2 = rhs; + if (!data) { + /* Skip parenthesization if not in a variable declaration. */ + while (pn->pn_type == TOK_RP) + pn = pn->pn_kid; + if (pn2) { + while (pn2->pn_type == TOK_RP) + pn2 = pn2->pn_kid; + } + } + + /* Nullary comma is an elision; binary comma is an expression.*/ + if (pn->pn_type != TOK_COMMA || pn->pn_arity != PN_NULLARY) { + if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) { + ok = CheckDestructuring(cx, data, pn, pn2, tc); + } else { + if (data) { + if (pn->pn_type != TOK_NAME) + goto no_var_name; + + ok = BindDestructuringVar(cx, data, pn, tc); + } else { + ok = BindDestructuringLHS(cx, pn, tc); + } + } + if (!ok) + goto out; + } + + lhs = lhs->pn_next; + if (rhs) + rhs = rhs->pn_next; + } + } else { + JS_ASSERT(left->pn_type == TOK_RC); + fpvd.numvars = left->pn_count; + fpvd.maxstep = 0; + rhs = NULL; + + while (lhs) { + JS_ASSERT(lhs->pn_type == TOK_COLON); + pn = lhs->pn_right; + if (!data) { + /* Skip parenthesization if not in a variable declaration. */ + while (pn->pn_type == TOK_RP) + pn = pn->pn_kid; + } + + if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) { + if (right) { + rhs = FindPropertyValue(right, lhs->pn_left, &fpvd); + if (rhs && !data) { + while (rhs->pn_type == TOK_RP) + rhs = rhs->pn_kid; + } + } + + ok = CheckDestructuring(cx, data, pn, rhs, tc); + } else if (data) { + if (pn->pn_type != TOK_NAME) + goto no_var_name; + + ok = BindDestructuringVar(cx, data, pn, tc); + } else { + ok = BindDestructuringLHS(cx, pn, tc); + } + if (!ok) + goto out; + + lhs = lhs->pn_next; + } + } + + /* + * The catch/finally handler implementation in the interpreter assumes + * that any operation that introduces a new scope (like a "let" or "with" + * block) increases the stack depth. This way, it is possible to restore + * the scope chain based on stack depth of the handler alone. "let" with + * an empty destructuring pattern like in + * + * let [] = 1; + * + * would violate this assumption as the there would be no let locals to + * store on the stack. To satisfy it we add an empty property to such + * blocks so that OBJ_BLOCK_COUNT(cx, blockObj), which gives the number of + * slots, would be always positive. + * + * Note that we add such a property even if the block has locals due to + * later let declarations in it. We optimize for code simplicity here, + * not the fastest runtime performance with empty [] or {}. + */ + if (data && + data->binder == BindLet && + OBJ_BLOCK_COUNT(cx, tc->blockChain) == 0) { + ok = js_DefineNativeProperty(cx, tc->blockChain, + ATOM_TO_JSID(cx->runtime-> + atomState.emptyAtom), + JSVAL_VOID, NULL, NULL, + JSPROP_ENUMERATE | + JSPROP_PERMANENT | + JSPROP_SHARED, + SPROP_HAS_SHORTID, 0, NULL); + if (!ok) + goto out; + } + + ok = JS_TRUE; + + out: + if (fpvd.table.ops) + JS_DHashTableFinish(&fpvd.table); + return ok; + + no_var_name: + js_ReportCompileErrorNumber(cx, TS(tc->parseContext), pn, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); + ok = JS_FALSE; + goto out; +} + +static JSParseNode * +DestructuringExpr(JSContext *cx, BindData *data, JSTreeContext *tc, + JSTokenType tt) +{ + JSParseNode *pn; + + pn = PrimaryExpr(cx, TS(tc->parseContext), tc, tt, JS_FALSE); + if (!pn) + return NULL; + if (!CheckDestructuring(cx, data, pn, NULL, tc)) + return NULL; + return pn; +} + +// Currently used only #if JS_HAS_DESTRUCTURING, in Statement's TOK_FOR case. +static JSParseNode * +CloneParseTree(JSContext *cx, JSParseNode *opn, JSTreeContext *tc) +{ + JSParseNode *pn, *pn2, *opn2; + + pn = NewOrRecycledNode(cx, tc); + if (!pn) + return NULL; + pn->pn_type = opn->pn_type; + pn->pn_pos = opn->pn_pos; + pn->pn_op = opn->pn_op; + pn->pn_arity = opn->pn_arity; + + switch (pn->pn_arity) { +#define NULLCHECK(e) JS_BEGIN_MACRO if (!(e)) return NULL; JS_END_MACRO + + case PN_FUNC: + NULLCHECK(pn->pn_funpob = + js_NewParsedObjectBox(cx, tc->parseContext, opn->pn_funpob->object)); + NULLCHECK(pn->pn_body = CloneParseTree(cx, opn->pn_body, tc)); + pn->pn_flags = opn->pn_flags; + pn->pn_index = opn->pn_index; + break; + + case PN_LIST: + PN_INIT_LIST(pn); + for (opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) { + NULLCHECK(pn2 = CloneParseTree(cx, opn2, tc)); + PN_APPEND(pn, pn2); + } + pn->pn_extra = opn->pn_extra; + break; + + case PN_TERNARY: + NULLCHECK(pn->pn_kid1 = CloneParseTree(cx, opn->pn_kid1, tc)); + NULLCHECK(pn->pn_kid2 = CloneParseTree(cx, opn->pn_kid2, tc)); + NULLCHECK(pn->pn_kid3 = CloneParseTree(cx, opn->pn_kid3, tc)); + break; + + case PN_BINARY: + NULLCHECK(pn->pn_left = CloneParseTree(cx, opn->pn_left, tc)); + if (opn->pn_right != opn->pn_left) + NULLCHECK(pn->pn_right = CloneParseTree(cx, opn->pn_right, tc)); + else + pn->pn_right = pn->pn_left; + pn->pn_val = opn->pn_val; + pn->pn_iflags = opn->pn_iflags; + break; + + case PN_UNARY: + NULLCHECK(pn->pn_kid = CloneParseTree(cx, opn->pn_kid, tc)); + pn->pn_num = opn->pn_num; + pn->pn_hidden = opn->pn_hidden; + break; + + case PN_NAME: + // PN_NAME could mean several arms in pn_u, so copy the whole thing. + pn->pn_u = opn->pn_u; + if (opn->pn_expr) + NULLCHECK(pn->pn_expr = CloneParseTree(cx, opn->pn_expr, tc)); + break; + + case PN_NULLARY: + // Even PN_NULLARY may have data (apair for E4X -- what a botch). + pn->pn_u = opn->pn_u; + break; + +#undef NULLCHECK + } + return pn; +} + +#endif /* JS_HAS_DESTRUCTURING */ + +extern const char js_with_statement_str[]; + +static JSParseNode * +ContainsStmt(JSParseNode *pn, JSTokenType tt) +{ + JSParseNode *pn2, *pnt; + + if (!pn) + return NULL; + if (pn->pn_type == tt) + return pn; + switch (pn->pn_arity) { + case PN_LIST: + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + pnt = ContainsStmt(pn2, tt); + if (pnt) + return pnt; + } + break; + case PN_TERNARY: + pnt = ContainsStmt(pn->pn_kid1, tt); + if (pnt) + return pnt; + pnt = ContainsStmt(pn->pn_kid2, tt); + if (pnt) + return pnt; + return ContainsStmt(pn->pn_kid3, tt); + case PN_BINARY: + /* + * Limit recursion if pn is a binary expression, which can't contain a + * var statement. + */ + if (pn->pn_op != JSOP_NOP) + return NULL; + pnt = ContainsStmt(pn->pn_left, tt); + if (pnt) + return pnt; + return ContainsStmt(pn->pn_right, tt); + case PN_UNARY: + if (pn->pn_op != JSOP_NOP) + return NULL; + return ContainsStmt(pn->pn_kid, tt); + case PN_NAME: + return ContainsStmt(pn->pn_expr, tt); + default:; + } + return NULL; +} + +static JSParseNode * +ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSParser operandParser) +{ + JSTokenType tt, tt2; + JSParseNode *pn, *pn2; + + tt = CURRENT_TOKEN(ts).type; + if (tt == TOK_RETURN && !(tc->flags & TCF_IN_FUNCTION)) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + return NULL; + } + + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + +#if JS_HAS_GENERATORS + if (tt == TOK_YIELD) + tc->flags |= TCF_FUN_IS_GENERATOR; +#endif + + /* This is ugly, but we don't want to require a semicolon. */ + ts->flags |= TSF_OPERAND; + tt2 = js_PeekTokenSameLine(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt2 == TOK_ERROR) + return NULL; + + if (tt2 != TOK_EOF && tt2 != TOK_EOL && tt2 != TOK_SEMI && tt2 != TOK_RC +#if JS_HAS_GENERATORS + && (tt != TOK_YIELD || + (tt2 != tt && tt2 != TOK_RB && tt2 != TOK_RP && + tt2 != TOK_COLON && tt2 != TOK_COMMA)) +#endif + ) { + pn2 = operandParser(cx, ts, tc); + if (!pn2) + return NULL; +#if JS_HAS_GENERATORS + if (tt == TOK_RETURN) +#endif + tc->flags |= TCF_RETURN_EXPR; + pn->pn_pos.end = pn2->pn_pos.end; + pn->pn_kid = pn2; + } else { +#if JS_HAS_GENERATORS + if (tt == TOK_RETURN) +#endif + tc->flags |= TCF_RETURN_VOID; + } + + if ((~tc->flags & (TCF_RETURN_EXPR | TCF_FUN_IS_GENERATOR)) == 0) { + /* As in Python (see PEP-255), disallow return v; in generators. */ + ReportBadReturn(cx, tc, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_RETURN, + JSMSG_BAD_ANON_GENERATOR_RETURN); + return NULL; + } + + if (JS_HAS_STRICT_OPTION(cx) && + (~tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == 0 && + !ReportBadReturn(cx, tc, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_NO_RETURN_VALUE, + JSMSG_ANON_NO_RETURN_VALUE)) { + return NULL; + } + + return pn; +} + +static JSParseNode * +PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSStmtInfo *stmtInfo) +{ + JSParseNode *pn; + JSObject *obj; + JSParsedObjectBox *blockpob; + + pn = NewParseNode(cx, ts, PN_NAME, tc); + if (!pn) + return NULL; + + obj = js_NewBlockObject(cx); + if (!obj) + return NULL; + + blockpob = js_NewParsedObjectBox(cx, tc->parseContext, obj); + if (!blockpob) + return NULL; + + js_PushBlockScope(tc, stmtInfo, obj, -1); + pn->pn_type = TOK_LEXICALSCOPE; + pn->pn_op = JSOP_LEAVEBLOCK; + pn->pn_pob = blockpob; + pn->pn_slot = -1; + return pn; +} + +#if JS_HAS_BLOCK_SCOPE + +static JSParseNode * +LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement) +{ + JSParseNode *pn, *pnblock, *pnlet; + JSStmtInfo stmtInfo; + + JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_LET); + + /* Create the let binary node. */ + pnlet = NewParseNode(cx, ts, PN_BINARY, tc); + if (!pnlet) + return NULL; + + MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_LET); + + /* This is a let block or expression of the form: let (a, b, c) .... */ + pnblock = PushLexicalScope(cx, ts, tc, &stmtInfo); + if (!pnblock) + return NULL; + pn = pnblock; + pn->pn_expr = pnlet; + + pnlet->pn_left = Variables(cx, ts, tc); + if (!pnlet->pn_left) + return NULL; + pnlet->pn_left->pn_extra = PNX_POPVAR; + + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET); + + ts->flags |= TSF_OPERAND; + if (statement && !js_MatchToken(cx, ts, TOK_LC)) { + /* + * If this is really an expression in let statement guise, then we + * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop + * the return value of the expression. + */ + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + pn->pn_type = TOK_SEMI; + pn->pn_num = -1; + pn->pn_kid = pnblock; + + statement = JS_FALSE; + } + ts->flags &= ~TSF_OPERAND; + + if (statement) { + pnlet->pn_right = Statements(cx, ts, tc); + if (!pnlet->pn_right) + return NULL; + MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET); + } else { + /* + * Change pnblock's opcode to the variant that propagates the last + * result down after popping the block, and clear statement. + */ + pnblock->pn_op = JSOP_LEAVEBLOCKEXPR; + pnlet->pn_right = AssignExpr(cx, ts, tc); + if (!pnlet->pn_right) + return NULL; + } + + js_PopStatement(tc); + return pn; +} + +#endif /* JS_HAS_BLOCK_SCOPE */ + +static JSParseNode * +Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSTokenType tt; + JSParseNode *pn, *pn1, *pn2, *pn3, *pn4; + JSStmtInfo stmtInfo, *stmt, *stmt2; + JSAtom *label; + + JS_CHECK_RECURSION(cx, return NULL); + + ts->flags |= TSF_OPERAND; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + +#if JS_HAS_GETTER_SETTER + if (tt == TOK_NAME) { + tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION); + if (tt == TOK_ERROR) + return NULL; + } +#endif + + switch (tt) { + case TOK_FUNCTION: +#if JS_HAS_XML_SUPPORT + ts->flags |= TSF_KEYWORD_IS_NAME; + tt = js_PeekToken(cx, ts); + ts->flags &= ~TSF_KEYWORD_IS_NAME; + if (tt == TOK_DBLCOLON) + goto expression; +#endif + return FunctionStmt(cx, ts, tc); + + case TOK_IF: + /* An IF node has three kids: condition, then, and optional else. */ + pn = NewParseNode(cx, ts, PN_TERNARY, tc); + if (!pn) + return NULL; + pn1 = Condition(cx, ts, tc); + if (!pn1) + return NULL; + js_PushStatement(tc, &stmtInfo, STMT_IF, -1); + pn2 = Statement(cx, ts, tc); + if (!pn2) + return NULL; + ts->flags |= TSF_OPERAND; + if (js_MatchToken(cx, ts, TOK_ELSE)) { + ts->flags &= ~TSF_OPERAND; + stmtInfo.type = STMT_ELSE; + pn3 = Statement(cx, ts, tc); + if (!pn3) + return NULL; + pn->pn_pos.end = pn3->pn_pos.end; + } else { + ts->flags &= ~TSF_OPERAND; + pn3 = NULL; + pn->pn_pos.end = pn2->pn_pos.end; + } + js_PopStatement(tc); + pn->pn_kid1 = pn1; + pn->pn_kid2 = pn2; + pn->pn_kid3 = pn3; + return pn; + + case TOK_SWITCH: + { + JSParseNode *pn5, *saveBlock; + JSBool seenDefault = JS_FALSE; + + pn = NewParseNode(cx, ts, PN_BINARY, tc); + if (!pn) + return NULL; + MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH); + + /* pn1 points to the switch's discriminant. */ + pn1 = ParenExpr(cx, ts, tc, NULL, NULL); + if (!pn1) + return NULL; + + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH); + MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH); + + /* pn2 is a list of case nodes. The default case has pn_left == NULL */ + pn2 = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn2) + return NULL; + saveBlock = tc->blockNode; + tc->blockNode = pn2; + PN_INIT_LIST(pn2); + + js_PushStatement(tc, &stmtInfo, STMT_SWITCH, -1); + + while ((tt = js_GetToken(cx, ts)) != TOK_RC) { + switch (tt) { + case TOK_DEFAULT: + if (seenDefault) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_TOO_MANY_DEFAULTS); + return NULL; + } + seenDefault = JS_TRUE; + /* FALL THROUGH */ + + case TOK_CASE: + pn3 = NewParseNode(cx, ts, PN_BINARY, tc); + if (!pn3) + return NULL; + if (tt == TOK_CASE) { + pn3->pn_left = Expr(cx, ts, tc); + if (!pn3->pn_left) + return NULL; + } + PN_APPEND(pn2, pn3); + if (pn2->pn_count == JS_BIT(16)) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_TOO_MANY_CASES); + return NULL; + } + break; + + case TOK_ERROR: + return NULL; + + default: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_SWITCH); + return NULL; + } + MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); + + pn4 = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn4) + return NULL; + pn4->pn_type = TOK_LC; + PN_INIT_LIST(pn4); + ts->flags |= TSF_OPERAND; + while ((tt = js_PeekToken(cx, ts)) != TOK_RC && + tt != TOK_CASE && tt != TOK_DEFAULT) { + ts->flags &= ~TSF_OPERAND; + if (tt == TOK_ERROR) + return NULL; + pn5 = Statement(cx, ts, tc); + if (!pn5) + return NULL; + pn4->pn_pos.end = pn5->pn_pos.end; + PN_APPEND(pn4, pn5); + ts->flags |= TSF_OPERAND; + } + ts->flags &= ~TSF_OPERAND; + + /* Fix the PN_LIST so it doesn't begin at the TOK_COLON. */ + if (pn4->pn_head) + pn4->pn_pos.begin = pn4->pn_head->pn_pos.begin; + pn3->pn_pos.end = pn4->pn_pos.end; + pn3->pn_right = pn4; + } + + /* + * Handle the case where there was a let declaration in any case in + * the switch body, but not within an inner block. If it replaced + * tc->blockNode with a new block node then we must refresh pn2 and + * then restore tc->blockNode. + */ + if (tc->blockNode != pn2) + pn2 = tc->blockNode; + tc->blockNode = saveBlock; + js_PopStatement(tc); + + pn->pn_pos.end = pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn->pn_left = pn1; + pn->pn_right = pn2; + return pn; + } + + case TOK_WHILE: + pn = NewParseNode(cx, ts, PN_BINARY, tc); + if (!pn) + return NULL; + js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1); + pn2 = Condition(cx, ts, tc); + if (!pn2) + return NULL; + pn->pn_left = pn2; + pn2 = Statement(cx, ts, tc); + if (!pn2) + return NULL; + js_PopStatement(tc); + pn->pn_pos.end = pn2->pn_pos.end; + pn->pn_right = pn2; + return pn; + + case TOK_DO: + pn = NewParseNode(cx, ts, PN_BINARY, tc); + if (!pn) + return NULL; + js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1); + pn2 = Statement(cx, ts, tc); + if (!pn2) + return NULL; + pn->pn_left = pn2; + MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO); + pn2 = Condition(cx, ts, tc); + if (!pn2) + return NULL; + js_PopStatement(tc); + pn->pn_pos.end = pn2->pn_pos.end; + pn->pn_right = pn2; + if (JSVERSION_NUMBER(cx) != JSVERSION_ECMA_3) { + /* + * All legacy and extended versions must do automatic semicolon + * insertion after do-while. See the testcase and discussion in + * http://bugzilla.mozilla.org/show_bug.cgi?id=238945. + */ + (void) js_MatchToken(cx, ts, TOK_SEMI); + return pn; + } + break; + + case TOK_FOR: + { + JSParseNode *pnseq = NULL; +#if JS_HAS_BLOCK_SCOPE + JSParseNode *pnlet = NULL; + JSStmtInfo blockInfo; +#endif + + /* A FOR node is binary, left is loop control and right is the body. */ + pn = NewParseNode(cx, ts, PN_BINARY, tc); + if (!pn) + return NULL; + js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1); + + pn->pn_op = JSOP_ITER; + pn->pn_iflags = 0; + if (js_MatchToken(cx, ts, TOK_NAME)) { + if (CURRENT_TOKEN(ts).t_atom == cx->runtime->atomState.eachAtom) + pn->pn_iflags = JSITER_FOREACH; + else + js_UngetToken(ts); + } + + MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); + ts->flags |= TSF_OPERAND; + tt = js_PeekToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt == TOK_SEMI) { + if (pn->pn_iflags & JSITER_FOREACH) + goto bad_for_each; + + /* No initializer -- set first kid of left sub-node to null. */ + pn1 = NULL; + } else { + /* + * Set pn1 to a var list or an initializing expression. + * + * Set the TCF_IN_FOR_INIT flag during parsing of the first clause + * of the for statement. This flag will be used by the RelExpr + * production; if it is set, then the 'in' keyword will not be + * recognized as an operator, leaving it available to be parsed as + * part of a for/in loop. + * + * A side effect of this restriction is that (unparenthesized) + * expressions involving an 'in' operator are illegal in the init + * clause of an ordinary for loop. + */ + tc->flags |= TCF_IN_FOR_INIT; + if (tt == TOK_VAR) { + (void) js_GetToken(cx, ts); + pn1 = Variables(cx, ts, tc); +#if JS_HAS_BLOCK_SCOPE + } else if (tt == TOK_LET) { + (void) js_GetToken(cx, ts); + if (js_PeekToken(cx, ts) == TOK_LP) { + pn1 = LetBlock(cx, ts, tc, JS_FALSE); + tt = TOK_LEXICALSCOPE; + } else { + pnlet = PushLexicalScope(cx, ts, tc, &blockInfo); + if (!pnlet) + return NULL; + blockInfo.flags |= SIF_FOR_BLOCK; + pn1 = Variables(cx, ts, tc); + } +#endif + } else { + pn1 = Expr(cx, ts, tc); + if (pn1) { + while (pn1->pn_type == TOK_RP) + pn1 = pn1->pn_kid; + } + } + tc->flags &= ~TCF_IN_FOR_INIT; + if (!pn1) + return NULL; + } + + /* + * We can be sure that it's a for/in loop if there's still an 'in' + * keyword here, even if JavaScript recognizes 'in' as an operator, + * as we've excluded 'in' from being parsed in RelExpr by setting + * the TCF_IN_FOR_INIT flag in our JSTreeContext. + */ + if (pn1 && js_MatchToken(cx, ts, TOK_IN)) { + pn->pn_iflags |= JSITER_ENUMERATE; + stmtInfo.type = STMT_FOR_IN_LOOP; + + /* Check that the left side of the 'in' is valid. */ + JS_ASSERT(!TOKEN_TYPE_IS_DECL(tt) || pn1->pn_type == tt); + if (TOKEN_TYPE_IS_DECL(tt) + ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST +#if JS_HAS_DESTRUCTURING + || (JSVERSION_NUMBER(cx) == JSVERSION_1_7 && + pn->pn_op == JSOP_ITER && + !(pn->pn_iflags & JSITER_FOREACH) && + (pn1->pn_head->pn_type == TOK_RC || + (pn1->pn_head->pn_type == TOK_RB && + pn1->pn_head->pn_count != 2) || + (pn1->pn_head->pn_type == TOK_ASSIGN && + (pn1->pn_head->pn_left->pn_type != TOK_RB || + pn1->pn_head->pn_left->pn_count != 2)))) +#endif + ) + : (pn1->pn_type != TOK_NAME && + pn1->pn_type != TOK_DOT && +#if JS_HAS_DESTRUCTURING + ((JSVERSION_NUMBER(cx) == JSVERSION_1_7 && + pn->pn_op == JSOP_ITER && + !(pn->pn_iflags & JSITER_FOREACH)) + ? (pn1->pn_type != TOK_RB || pn1->pn_count != 2) + : (pn1->pn_type != TOK_RB && pn1->pn_type != TOK_RC)) && +#endif +#if JS_HAS_LVALUE_RETURN + pn1->pn_type != TOK_LP && +#endif +#if JS_HAS_XML_SUPPORT + (pn1->pn_type != TOK_UNARYOP || + pn1->pn_op != JSOP_XMLNAME) && +#endif + pn1->pn_type != TOK_LB)) { + js_ReportCompileErrorNumber(cx, ts, pn1, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); + return NULL; + } + + /* pn2 points to the name or destructuring pattern on in's left. */ + pn2 = NULL; + + if (TOKEN_TYPE_IS_DECL(tt)) { + /* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */ + pn1->pn_extra |= PNX_FORINVAR; + + /* + * Rewrite 'for ( x = i in o)' where is 'let', + * 'var', or 'const' to hoist the initializer or the entire + * decl out of the loop head. TOK_VAR is the type for both + * 'var' and 'const'. + */ + pn2 = pn1->pn_head; + if (pn2->pn_type == TOK_NAME && pn2->pn_expr +#if JS_HAS_DESTRUCTURING + || pn2->pn_type == TOK_ASSIGN +#endif + ) { + pnseq = NewParseNode(cx, ts, PN_LIST, tc); + if (!pnseq) + return NULL; + pnseq->pn_type = TOK_SEQ; + pnseq->pn_pos.begin = pn->pn_pos.begin; + if (tt == TOK_LET) { + /* + * Hoist just the 'i' from 'for (let x = i in o)' to + * before the loop, glued together via pnseq. + */ + pn3 = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn3) + return NULL; + pn3->pn_type = TOK_SEMI; + pn3->pn_op = JSOP_NOP; +#if JS_HAS_DESTRUCTURING + if (pn2->pn_type == TOK_ASSIGN) { + pn4 = pn2->pn_right; + pn2 = pn1->pn_head = pn2->pn_left; + } else +#endif + { + pn4 = pn2->pn_expr; + pn2->pn_expr = NULL; + } + pn3->pn_pos = pn4->pn_pos; + pn3->pn_kid = pn4; + PN_INIT_LIST_1(pnseq, pn3); + } else { + /* + * All of 'var x = i' is hoisted above 'for (x in o)', + * so clear PNX_FORINVAR. + * + * Request JSOP_POP here since the var is for a simple + * name (it is not a destructuring binding's left-hand + * side) and it has an initializer. + */ + pn1->pn_extra &= ~PNX_FORINVAR; + pn1->pn_extra |= PNX_POPVAR; + PN_INIT_LIST_1(pnseq, pn1); + +#if JS_HAS_DESTRUCTURING + if (pn2->pn_type == TOK_ASSIGN) { + pn1 = CloneParseTree(cx, pn2->pn_left, tc); + if (!pn1) + return NULL; + } else +#endif + { + pn1 = NewParseNode(cx, ts, PN_NAME, tc); + if (!pn1) + return NULL; + pn1->pn_type = TOK_NAME; + pn1->pn_op = JSOP_NAME; + pn1->pn_pos = pn2->pn_pos; + pn1->pn_atom = pn2->pn_atom; + pn1->pn_expr = NULL; + pn1->pn_slot = -1; + pn1->pn_const = pn2->pn_const; + } + pn2 = pn1; + } + } + } + + if (!pn2) { + pn2 = pn1; +#if JS_HAS_LVALUE_RETURN + if (pn2->pn_type == TOK_LP && + !MakeSetCall(cx, pn2, tc, JSMSG_BAD_LEFTSIDE_OF_ASS)) { + return NULL; + } +#endif +#if JS_HAS_XML_SUPPORT + if (pn2->pn_type == TOK_UNARYOP) + pn2->pn_op = JSOP_BINDXMLNAME; +#endif + } + + switch (pn2->pn_type) { + case TOK_NAME: + /* Beware 'for (arguments in ...)' with or without a 'var'. */ + if (pn2->pn_atom == cx->runtime->atomState.argumentsAtom) + tc->flags |= TCF_FUN_HEAVYWEIGHT; + break; + +#if JS_HAS_DESTRUCTURING + case TOK_ASSIGN: + pn2 = pn2->pn_left; + JS_ASSERT(pn2->pn_type == TOK_RB || pn2->pn_type == TOK_RC); + /* FALL THROUGH */ + case TOK_RB: + case TOK_RC: + /* Check for valid lvalues in var-less destructuring for-in. */ + if (pn1 == pn2 && !CheckDestructuring(cx, NULL, pn2, NULL, tc)) + return NULL; + + if (JSVERSION_NUMBER(cx) == JSVERSION_1_7) { + /* + * Destructuring for-in requires [key, value] enumeration + * in JS1.7. + */ + JS_ASSERT(pn->pn_op == JSOP_ITER); + if (!(pn->pn_iflags & JSITER_FOREACH)) + pn->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE; + } + break; +#endif + + default:; + } + + /* Parse the object expression as the right operand of 'in'. */ + pn2 = NewBinary(cx, TOK_IN, JSOP_NOP, pn1, Expr(cx, ts, tc), tc); + if (!pn2) + return NULL; + pn->pn_left = pn2; + } else { + if (pn->pn_iflags & JSITER_FOREACH) + goto bad_for_each; + pn->pn_op = JSOP_NOP; + + /* Parse the loop condition or null into pn2. */ + MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT); + ts->flags |= TSF_OPERAND; + tt = js_PeekToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt == TOK_SEMI) { + pn2 = NULL; + } else { + pn2 = Expr(cx, ts, tc); + if (!pn2) + return NULL; + } + + /* Parse the update expression or null into pn3. */ + MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND); + ts->flags |= TSF_OPERAND; + tt = js_PeekToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt == TOK_RP) { + pn3 = NULL; + } else { + pn3 = Expr(cx, ts, tc); + if (!pn3) + return NULL; + } + + /* Build the FORHEAD node to use as the left kid of pn. */ + pn4 = NewParseNode(cx, ts, PN_TERNARY, tc); + if (!pn4) + return NULL; + pn4->pn_type = TOK_FORHEAD; + pn4->pn_op = JSOP_NOP; + pn4->pn_kid1 = pn1; + pn4->pn_kid2 = pn2; + pn4->pn_kid3 = pn3; + pn->pn_left = pn4; + } + + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL); + + /* Parse the loop body into pn->pn_right. */ + pn2 = Statement(cx, ts, tc); + if (!pn2) + return NULL; + pn->pn_right = pn2; + + /* Record the absolute line number for source note emission. */ + pn->pn_pos.end = pn2->pn_pos.end; + +#if JS_HAS_BLOCK_SCOPE + if (pnlet) { + js_PopStatement(tc); + pnlet->pn_expr = pn; + pn = pnlet; + } +#endif + if (pnseq) { + pnseq->pn_pos.end = pn->pn_pos.end; + PN_APPEND(pnseq, pn); + pn = pnseq; + } + js_PopStatement(tc); + return pn; + + bad_for_each: + js_ReportCompileErrorNumber(cx, ts, pn, JSREPORT_ERROR, + JSMSG_BAD_FOR_EACH_LOOP); + return NULL; + } + + case TOK_TRY: { + JSParseNode *catchList, *lastCatch; + + /* + * try nodes are ternary. + * kid1 is the try Statement + * kid2 is the catch node list or null + * kid3 is the finally Statement + * + * catch nodes are ternary. + * kid1 is the lvalue (TOK_NAME, TOK_LB, or TOK_LC) + * kid2 is the catch guard or null if no guard + * kid3 is the catch block + * + * catch lvalue nodes are either: + * TOK_NAME for a single identifier + * TOK_RB or TOK_RC for a destructuring left-hand side + * + * finally nodes are TOK_LC Statement lists. + */ + pn = NewParseNode(cx, ts, PN_TERNARY, tc); + if (!pn) + return NULL; + pn->pn_op = JSOP_NOP; + + MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY); + js_PushStatement(tc, &stmtInfo, STMT_TRY, -1); + pn->pn_kid1 = Statements(cx, ts, tc); + if (!pn->pn_kid1) + return NULL; + MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY); + js_PopStatement(tc); + + catchList = NULL; + tt = js_GetToken(cx, ts); + if (tt == TOK_CATCH) { + catchList = NewParseNode(cx, ts, PN_LIST, tc); + if (!catchList) + return NULL; + catchList->pn_type = TOK_RESERVED; + PN_INIT_LIST(catchList); + lastCatch = NULL; + + do { + JSParseNode *pnblock; + BindData data; + + /* Check for another catch after unconditional catch. */ + if (lastCatch && !lastCatch->pn_kid2) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_CATCH_AFTER_GENERAL); + return NULL; + } + + /* + * Create a lexical scope node around the whole catch clause, + * including the head. + */ + pnblock = PushLexicalScope(cx, ts, tc, &stmtInfo); + if (!pnblock) + return NULL; + stmtInfo.type = STMT_CATCH; + + /* + * Legal catch forms are: + * catch (lhs) + * catch (lhs if ) + * where lhs is a name or a destructuring left-hand side. + * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD) + */ + pn2 = NewParseNode(cx, ts, PN_TERNARY, tc); + if (!pn2) + return NULL; + pnblock->pn_expr = pn2; + MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH); + + /* + * Contrary to ECMA Ed. 3, the catch variable is lexically + * scoped, not a property of a new Object instance. This is + * an intentional change that anticipates ECMA Ed. 4. + */ + data.pn = NULL; + data.op = JSOP_NOP; + data.binder = BindLet; + data.u.let.overflow = JSMSG_TOO_MANY_CATCH_VARS; + + tt = js_GetToken(cx, ts); + switch (tt) { +#if JS_HAS_DESTRUCTURING + case TOK_LB: + case TOK_LC: + pn3 = DestructuringExpr(cx, &data, tc, tt); + if (!pn3) + return NULL; + break; +#endif + + case TOK_NAME: + label = CURRENT_TOKEN(ts).t_atom; + if (!data.binder(cx, &data, label, tc)) + return NULL; + + pn3 = NewParseNode(cx, ts, PN_NAME, tc); + if (!pn3) + return NULL; + pn3->pn_atom = label; + pn3->pn_slot = -1; + break; + + default: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_CATCH_IDENTIFIER); + return NULL; + } + + pn2->pn_kid1 = pn3; +#if JS_HAS_CATCH_GUARD + /* + * We use 'catch (x if x === 5)' (not 'catch (x : x === 5)') + * to avoid conflicting with the JS2/ECMAv4 type annotation + * catchguard syntax. + */ + if (js_MatchToken(cx, ts, TOK_IF)) { + pn2->pn_kid2 = Expr(cx, ts, tc); + if (!pn2->pn_kid2) + return NULL; + } +#endif + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH); + + MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH); + pn2->pn_kid3 = Statements(cx, ts, tc); + if (!pn2->pn_kid3) + return NULL; + MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH); + js_PopStatement(tc); + + PN_APPEND(catchList, pnblock); + lastCatch = pn2; + ts->flags |= TSF_OPERAND; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + } while (tt == TOK_CATCH); + } + pn->pn_kid2 = catchList; + + if (tt == TOK_FINALLY) { + MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY); + js_PushStatement(tc, &stmtInfo, STMT_FINALLY, -1); + pn->pn_kid3 = Statements(cx, ts, tc); + if (!pn->pn_kid3) + return NULL; + MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY); + js_PopStatement(tc); + } else { + js_UngetToken(ts); + } + if (!catchList && !pn->pn_kid3) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_CATCH_OR_FINALLY); + return NULL; + } + return pn; + } + + case TOK_THROW: + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + + /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */ + ts->flags |= TSF_OPERAND; + tt = js_PeekTokenSameLine(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt == TOK_ERROR) + return NULL; + if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); + return NULL; + } + + pn2 = Expr(cx, ts, tc); + if (!pn2) + return NULL; + pn->pn_pos.end = pn2->pn_pos.end; + pn->pn_op = JSOP_THROW; + pn->pn_kid = pn2; + break; + + /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */ + case TOK_CATCH: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_CATCH_WITHOUT_TRY); + return NULL; + + case TOK_FINALLY: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_FINALLY_WITHOUT_TRY); + return NULL; + + case TOK_BREAK: + pn = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn) + return NULL; + if (!MatchLabel(cx, ts, pn)) + return NULL; + stmt = tc->topStmt; + label = pn->pn_atom; + if (label) { + for (; ; stmt = stmt->down) { + if (!stmt) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_LABEL_NOT_FOUND); + return NULL; + } + if (stmt->type == STMT_LABEL && stmt->u.label == label) + break; + } + } else { + for (; ; stmt = stmt->down) { + if (!stmt) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_TOUGH_BREAK); + return NULL; + } + if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH) + break; + } + } + if (label) + pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + break; + + case TOK_CONTINUE: + pn = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn) + return NULL; + if (!MatchLabel(cx, ts, pn)) + return NULL; + stmt = tc->topStmt; + label = pn->pn_atom; + if (label) { + for (stmt2 = NULL; ; stmt = stmt->down) { + if (!stmt) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_LABEL_NOT_FOUND); + return NULL; + } + if (stmt->type == STMT_LABEL) { + if (stmt->u.label == label) { + if (!stmt2 || !STMT_IS_LOOP(stmt2)) { + js_ReportCompileErrorNumber(cx, ts, NULL, + JSREPORT_ERROR, + JSMSG_BAD_CONTINUE); + return NULL; + } + break; + } + } else { + stmt2 = stmt; + } + } + } else { + for (; ; stmt = stmt->down) { + if (!stmt) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_CONTINUE); + return NULL; + } + if (STMT_IS_LOOP(stmt)) + break; + } + } + if (label) + pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + break; + + case TOK_WITH: + pn = NewParseNode(cx, ts, PN_BINARY, tc); + if (!pn) + return NULL; + MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH); + pn2 = ParenExpr(cx, ts, tc, NULL, NULL); + if (!pn2) + return NULL; + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH); + pn->pn_left = pn2; + + js_PushStatement(tc, &stmtInfo, STMT_WITH, -1); + pn2 = Statement(cx, ts, tc); + if (!pn2) + return NULL; + js_PopStatement(tc); + + pn->pn_pos.end = pn2->pn_pos.end; + pn->pn_right = pn2; + tc->flags |= TCF_FUN_HEAVYWEIGHT; + return pn; + + case TOK_VAR: + pn = Variables(cx, ts, tc); + if (!pn) + return NULL; + + /* Tell js_EmitTree to generate a final POP. */ + pn->pn_extra |= PNX_POPVAR; + break; + +#if JS_HAS_BLOCK_SCOPE + case TOK_LET: + { + JSObject *obj; + JSParsedObjectBox *blockpob; + + /* Check for a let statement or let expression. */ + if (js_PeekToken(cx, ts) == TOK_LP) { + pn = LetBlock(cx, ts, tc, JS_TRUE); + if (!pn || pn->pn_op == JSOP_LEAVEBLOCK) + return pn; + + /* Let expressions require automatic semicolon insertion. */ + JS_ASSERT(pn->pn_type == TOK_SEMI || + pn->pn_op == JSOP_LEAVEBLOCKEXPR); + break; + } + + /* + * This is a let declaration. We must be directly under a block per + * the proposed ES4 specs, but not an implicit block created due to + * 'for (let ...)'. If we pass this error test, make the enclosing + * JSStmtInfo be our scope. Further let declarations in this block + * will find this scope statement and use the same block object. + * + * If we are the first let declaration in this block (i.e., when the + * enclosing maybe-scope JSStmtInfo isn't yet a scope statement) then + * we also need to set tc->blockNode to be our TOK_LEXICALSCOPE. + */ + stmt = tc->topStmt; + if (stmt && + (!STMT_MAYBE_SCOPE(stmt) || (stmt->flags & SIF_FOR_BLOCK))) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_LET_DECL_NOT_IN_BLOCK); + return NULL; + } + + if (stmt && (stmt->flags & SIF_SCOPE)) { + JS_ASSERT(tc->blockChain == stmt->u.blockObj); + obj = tc->blockChain; + } else { + if (!stmt || (stmt->flags & SIF_BODY_BLOCK)) { + /* + * ES4 specifies that let at top level and at body-block scope + * does not shadow var, so convert back to var. + */ + CURRENT_TOKEN(ts).type = TOK_VAR; + CURRENT_TOKEN(ts).t_op = JSOP_DEFVAR; + + pn = Variables(cx, ts, tc); + if (!pn) + return NULL; + pn->pn_extra |= PNX_POPVAR; + break; + } + + /* + * Some obvious assertions here, but they may help clarify the + * situation. This stmt is not yet a scope, so it must not be a + * catch block (which is a lexical scope by definition). + */ + JS_ASSERT(!(stmt->flags & SIF_SCOPE)); + JS_ASSERT(stmt != tc->topScopeStmt); + JS_ASSERT(stmt->type == STMT_BLOCK || + stmt->type == STMT_SWITCH || + stmt->type == STMT_TRY || + stmt->type == STMT_FINALLY); + JS_ASSERT(!stmt->downScope); + + /* Convert the block statement into a scope statement. */ + obj = js_NewBlockObject(cx); + if (!obj) + return NULL; + blockpob = js_NewParsedObjectBox(cx, tc->parseContext, obj); + if (!blockpob) + return NULL; + + /* + * Insert stmt on the tc->topScopeStmt/stmtInfo.downScope linked + * list stack, if it isn't already there. If it is there, but it + * lacks the SIF_SCOPE flag, it must be a try, catch, or finally + * block. + */ + stmt->flags |= SIF_SCOPE; + stmt->downScope = tc->topScopeStmt; + tc->topScopeStmt = stmt; + JS_SCOPE_DEPTH_METERING(++tc->scopeDepth > tc->maxScopeDepth && + (tc->maxScopeDepth = tc->scopeDepth)); + + STOBJ_SET_PARENT(obj, tc->blockChain); + tc->blockChain = obj; + stmt->u.blockObj = obj; + +#ifdef DEBUG + pn1 = tc->blockNode; + JS_ASSERT(!pn1 || pn1->pn_type != TOK_LEXICALSCOPE); +#endif + + /* Create a new lexical scope node for these statements. */ + pn1 = NewParseNode(cx, ts, PN_NAME, tc); + if (!pn1) + return NULL; + + pn1->pn_type = TOK_LEXICALSCOPE; + pn1->pn_op = JSOP_LEAVEBLOCK; + pn1->pn_pos = tc->blockNode->pn_pos; + pn1->pn_pob = blockpob; + pn1->pn_expr = tc->blockNode; + pn1->pn_slot = -1; + tc->blockNode = pn1; + } + + pn = Variables(cx, ts, tc); + if (!pn) + return NULL; + pn->pn_extra = PNX_POPVAR; + break; + } +#endif /* JS_HAS_BLOCK_SCOPE */ + + case TOK_RETURN: + pn = ReturnOrYield(cx, ts, tc, Expr); + if (!pn) + return NULL; + break; + + case TOK_LC: + { + uintN oldflags; + + oldflags = tc->flags; + tc->flags = oldflags & ~TCF_HAS_FUNCTION_STMT; + js_PushStatement(tc, &stmtInfo, STMT_BLOCK, -1); + pn = Statements(cx, ts, tc); + if (!pn) + return NULL; + + MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND); + js_PopStatement(tc); + + /* + * If we contain a function statement and our container is top-level + * or another block, flag pn to preserve braces when decompiling. + */ + if ((tc->flags & TCF_HAS_FUNCTION_STMT) && + (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)) { + pn->pn_extra |= PNX_NEEDBRACES; + } + tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_RETURN_FLAGS)); + return pn; + } + + case TOK_EOL: + case TOK_SEMI: + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + pn->pn_type = TOK_SEMI; + return pn; + +#if JS_HAS_DEBUGGER_KEYWORD + case TOK_DEBUGGER: + pn = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn) + return NULL; + pn->pn_type = TOK_DEBUGGER; + tc->flags |= TCF_FUN_HEAVYWEIGHT; + break; +#endif /* JS_HAS_DEBUGGER_KEYWORD */ + +#if JS_HAS_XML_SUPPORT + case TOK_DEFAULT: + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + if (!js_MatchToken(cx, ts, TOK_NAME) || + CURRENT_TOKEN(ts).t_atom != cx->runtime->atomState.xmlAtom || + !js_MatchToken(cx, ts, TOK_NAME) || + CURRENT_TOKEN(ts).t_atom != cx->runtime->atomState.namespaceAtom || + !js_MatchToken(cx, ts, TOK_ASSIGN) || + CURRENT_TOKEN(ts).t_op != JSOP_NOP) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_DEFAULT_XML_NAMESPACE); + return NULL; + } + pn2 = Expr(cx, ts, tc); + if (!pn2) + return NULL; + pn->pn_op = JSOP_DEFXMLNS; + pn->pn_pos.end = pn2->pn_pos.end; + pn->pn_kid = pn2; + tc->flags |= TCF_HAS_DEFXMLNS; + break; +#endif + + case TOK_ERROR: + return NULL; + + default: +#if JS_HAS_XML_SUPPORT + expression: +#endif + js_UngetToken(ts); + pn2 = Expr(cx, ts, tc); + if (!pn2) + return NULL; + + if (js_PeekToken(cx, ts) == TOK_COLON) { + if (pn2->pn_type != TOK_NAME) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_LABEL); + return NULL; + } + label = pn2->pn_atom; + for (stmt = tc->topStmt; stmt; stmt = stmt->down) { + if (stmt->type == STMT_LABEL && stmt->u.label == label) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_DUPLICATE_LABEL); + return NULL; + } + } + (void) js_GetToken(cx, ts); + + /* Push a label struct and parse the statement. */ + js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1); + stmtInfo.u.label = label; + pn = Statement(cx, ts, tc); + if (!pn) + return NULL; + + /* Normalize empty statement to empty block for the decompiler. */ + if (pn->pn_type == TOK_SEMI && !pn->pn_kid) { + pn->pn_type = TOK_LC; + pn->pn_arity = PN_LIST; + PN_INIT_LIST(pn); + } + + /* Pop the label, set pn_expr, and return early. */ + js_PopStatement(tc); + pn2->pn_type = TOK_COLON; + pn2->pn_pos.end = pn->pn_pos.end; + pn2->pn_expr = pn; + return pn2; + } + + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + pn->pn_type = TOK_SEMI; + pn->pn_pos = pn2->pn_pos; + pn->pn_kid = pn2; + break; + } + + /* Check termination of this primitive statement. */ + if (ON_CURRENT_LINE(ts, pn->pn_pos)) { + ts->flags |= TSF_OPERAND; + tt = js_PeekTokenSameLine(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt == TOK_ERROR) + return NULL; + if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_SEMI_BEFORE_STMNT); + return NULL; + } + } + + (void) js_MatchToken(cx, ts, TOK_SEMI); + return pn; +} + +static JSParseNode * +Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSTokenType tt; + JSBool let; + JSStmtInfo *scopeStmt; + BindData data; + JSParseNode *pn, *pn2; + JSAtom *atom; + + /* + * The three options here are: + * - TOK_LET: We are parsing a let declaration. + * - TOK_LP: We are parsing the head of a let block. + * - Otherwise, we're parsing var declarations. + */ + tt = CURRENT_TOKEN(ts).type; + let = (tt == TOK_LET || tt == TOK_LP); + JS_ASSERT(let || tt == TOK_VAR); + + /* Make sure that Statement set the tree context up correctly. */ + scopeStmt = tc->topScopeStmt; + if (let) { + while (scopeStmt && !(scopeStmt->flags & SIF_SCOPE)) { + JS_ASSERT(!STMT_MAYBE_SCOPE(scopeStmt)); + scopeStmt = scopeStmt->downScope; + } + JS_ASSERT(scopeStmt); + } + + data.pn = NULL; + data.op = let ? JSOP_NOP : CURRENT_TOKEN(ts).t_op; + pn = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn) + return NULL; + pn->pn_op = data.op; + PN_INIT_LIST(pn); + + /* + * The tricky part of this code is to create special parsenode opcodes for + * getting and setting variables (which will be stored as special slots in + * the frame). The most complicated case is an eval() inside a function. + * If the evaluated string references variables in the enclosing function, + * then we need to generate the special variable opcodes. We determine + * this by looking up the variable's id in the current variable object. + * Fortunately, we can avoid doing this for let declared variables. + */ + if (let) { + JS_ASSERT(tc->blockChain == scopeStmt->u.blockObj); + data.binder = BindLet; + data.u.let.overflow = JSMSG_TOO_MANY_LOCALS; + } else { + data.binder = BindVarOrConst; + } + + do { + tt = js_GetToken(cx, ts); +#if JS_HAS_DESTRUCTURING + if (tt == TOK_LB || tt == TOK_LC) { + pn2 = PrimaryExpr(cx, ts, tc, tt, JS_FALSE); + if (!pn2) + return NULL; + + if ((tc->flags & TCF_IN_FOR_INIT) && + js_PeekToken(cx, ts) == TOK_IN) { + if (!CheckDestructuring(cx, &data, pn2, NULL, tc)) + return NULL; + PN_APPEND(pn, pn2); + continue; + } + + MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL); + if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) + goto bad_var_init; + + pn2 = NewBinary(cx, TOK_ASSIGN, JSOP_NOP, + pn2, AssignExpr(cx, ts, tc), + tc); + if (!pn2 || + !CheckDestructuring(cx, &data, + pn2->pn_left, pn2->pn_right, + tc)) { + return NULL; + } + PN_APPEND(pn, pn2); + continue; + } +#endif + + if (tt != TOK_NAME) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); + return NULL; + } + atom = CURRENT_TOKEN(ts).t_atom; + if (!data.binder(cx, &data, atom, tc)) + return NULL; + + pn2 = NewParseNode(cx, ts, PN_NAME, tc); + if (!pn2) + return NULL; + pn2->pn_op = JSOP_NAME; + pn2->pn_atom = atom; + pn2->pn_slot = -1; + if (!let) + pn2->pn_const = (data.op == JSOP_DEFCONST); + PN_APPEND(pn, pn2); + + if (js_MatchToken(cx, ts, TOK_ASSIGN)) { + if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) + goto bad_var_init; + + pn2->pn_expr = AssignExpr(cx, ts, tc); + if (!pn2->pn_expr) + return NULL; + pn2->pn_op = (!let && data.op == JSOP_DEFCONST) + ? JSOP_SETCONST + : JSOP_SETNAME; + if (!let && atom == cx->runtime->atomState.argumentsAtom) + tc->flags |= TCF_FUN_HEAVYWEIGHT; + } + } while (js_MatchToken(cx, ts, TOK_COMMA)); + + pn->pn_pos.end = PN_LAST(pn)->pn_pos.end; + return pn; + +bad_var_init: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_VAR_INIT); + return NULL; +} + +static JSParseNode * +Expr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn, *pn2; + + pn = AssignExpr(cx, ts, tc); + if (pn && js_MatchToken(cx, ts, TOK_COMMA)) { + pn2 = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn2) + return NULL; + pn2->pn_pos.begin = pn->pn_pos.begin; + PN_INIT_LIST_1(pn2, pn); + pn = pn2; + do { +#if JS_HAS_GENERATORS + pn2 = PN_LAST(pn); + if (pn2->pn_type == TOK_YIELD) { + js_ReportCompileErrorNumber(cx, ts, pn2, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_yield_str); + return NULL; + } +#endif + pn2 = AssignExpr(cx, ts, tc); + if (!pn2) + return NULL; + PN_APPEND(pn, pn2); + } while (js_MatchToken(cx, ts, TOK_COMMA)); + pn->pn_pos.end = PN_LAST(pn)->pn_pos.end; + } + return pn; +} + +static JSParseNode * +AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn, *pn2; + JSTokenType tt; + JSOp op; + + JS_CHECK_RECURSION(cx, return NULL); + +#if JS_HAS_GENERATORS + ts->flags |= TSF_OPERAND; + if (js_MatchToken(cx, ts, TOK_YIELD)) { + ts->flags &= ~TSF_OPERAND; + return ReturnOrYield(cx, ts, tc, AssignExpr); + } + ts->flags &= ~TSF_OPERAND; +#endif + + pn = CondExpr(cx, ts, tc); + if (!pn) + return NULL; + + tt = js_GetToken(cx, ts); +#if JS_HAS_GETTER_SETTER + if (tt == TOK_NAME) { + tt = CheckGetterOrSetter(cx, ts, TOK_ASSIGN); + if (tt == TOK_ERROR) + return NULL; + } +#endif + if (tt != TOK_ASSIGN) { + js_UngetToken(ts); + return pn; + } + + op = CURRENT_TOKEN(ts).t_op; + for (pn2 = pn; pn2->pn_type == TOK_RP; pn2 = pn2->pn_kid) + continue; + switch (pn2->pn_type) { + case TOK_NAME: + pn2->pn_op = JSOP_SETNAME; + if (pn2->pn_atom == cx->runtime->atomState.argumentsAtom) + tc->flags |= TCF_FUN_HEAVYWEIGHT; + break; + case TOK_DOT: + pn2->pn_op = JSOP_SETPROP; + break; + case TOK_LB: + pn2->pn_op = JSOP_SETELEM; + break; +#if JS_HAS_DESTRUCTURING + case TOK_RB: + case TOK_RC: + if (op != JSOP_NOP) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_DESTRUCT_ASS); + return NULL; + } + pn = AssignExpr(cx, ts, tc); + if (!pn || !CheckDestructuring(cx, NULL, pn2, pn, tc)) + return NULL; + return NewBinary(cx, TOK_ASSIGN, op, pn2, pn, tc); +#endif +#if JS_HAS_LVALUE_RETURN + case TOK_LP: + if (!MakeSetCall(cx, pn2, tc, JSMSG_BAD_LEFTSIDE_OF_ASS)) + return NULL; + break; +#endif +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: + if (pn2->pn_op == JSOP_XMLNAME) { + pn2->pn_op = JSOP_SETXMLNAME; + break; + } + /* FALL THROUGH */ +#endif + default: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_LEFTSIDE_OF_ASS); + return NULL; + } + + return NewBinary(cx, TOK_ASSIGN, op, pn2, AssignExpr(cx, ts, tc), tc); +} + +static JSParseNode * +CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn, *pn1, *pn2, *pn3; + uintN oldflags; + + pn = OrExpr(cx, ts, tc); + if (pn && js_MatchToken(cx, ts, TOK_HOOK)) { + pn1 = pn; + pn = NewParseNode(cx, ts, PN_TERNARY, tc); + if (!pn) + return NULL; + /* + * Always accept the 'in' operator in the middle clause of a ternary, + * where it's unambiguous, even if we might be parsing the init of a + * for statement. + */ + oldflags = tc->flags; + tc->flags &= ~TCF_IN_FOR_INIT; + pn2 = AssignExpr(cx, ts, tc); + tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS); + + if (!pn2) + return NULL; + MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND); + pn3 = AssignExpr(cx, ts, tc); + if (!pn3) + return NULL; + pn->pn_pos.begin = pn1->pn_pos.begin; + pn->pn_pos.end = pn3->pn_pos.end; + pn->pn_kid1 = pn1; + pn->pn_kid2 = pn2; + pn->pn_kid3 = pn3; + } + return pn; +} + +static JSParseNode * +OrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = AndExpr(cx, ts, tc); + while (pn && js_MatchToken(cx, ts, TOK_OR)) + pn = NewBinary(cx, TOK_OR, JSOP_OR, pn, AndExpr(cx, ts, tc), tc); + return pn; +} + +static JSParseNode * +AndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = BitOrExpr(cx, ts, tc); + while (pn && js_MatchToken(cx, ts, TOK_AND)) + pn = NewBinary(cx, TOK_AND, JSOP_AND, pn, BitOrExpr(cx, ts, tc), tc); + return pn; +} + +static JSParseNode * +BitOrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = BitXorExpr(cx, ts, tc); + while (pn && js_MatchToken(cx, ts, TOK_BITOR)) { + pn = NewBinary(cx, TOK_BITOR, JSOP_BITOR, pn, BitXorExpr(cx, ts, tc), + tc); + } + return pn; +} + +static JSParseNode * +BitXorExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = BitAndExpr(cx, ts, tc); + while (pn && js_MatchToken(cx, ts, TOK_BITXOR)) { + pn = NewBinary(cx, TOK_BITXOR, JSOP_BITXOR, pn, BitAndExpr(cx, ts, tc), + tc); + } + return pn; +} + +static JSParseNode * +BitAndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = EqExpr(cx, ts, tc); + while (pn && js_MatchToken(cx, ts, TOK_BITAND)) + pn = NewBinary(cx, TOK_BITAND, JSOP_BITAND, pn, EqExpr(cx, ts, tc), tc); + return pn; +} + +static JSParseNode * +EqExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + JSOp op; + + pn = RelExpr(cx, ts, tc); + while (pn && js_MatchToken(cx, ts, TOK_EQOP)) { + op = CURRENT_TOKEN(ts).t_op; + pn = NewBinary(cx, TOK_EQOP, op, pn, RelExpr(cx, ts, tc), tc); + } + return pn; +} + +static JSParseNode * +RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + JSTokenType tt; + JSOp op; + uintN inForInitFlag = tc->flags & TCF_IN_FOR_INIT; + + /* + * Uses of the in operator in ShiftExprs are always unambiguous, + * so unset the flag that prohibits recognizing it. + */ + tc->flags &= ~TCF_IN_FOR_INIT; + + pn = ShiftExpr(cx, ts, tc); + while (pn && + (js_MatchToken(cx, ts, TOK_RELOP) || + /* + * Recognize the 'in' token as an operator only if we're not + * currently in the init expr of a for loop. + */ + (inForInitFlag == 0 && js_MatchToken(cx, ts, TOK_IN)) || + js_MatchToken(cx, ts, TOK_INSTANCEOF))) { + tt = CURRENT_TOKEN(ts).type; + op = CURRENT_TOKEN(ts).t_op; + pn = NewBinary(cx, tt, op, pn, ShiftExpr(cx, ts, tc), tc); + } + /* Restore previous state of inForInit flag. */ + tc->flags |= inForInitFlag; + + return pn; +} + +static JSParseNode * +ShiftExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + JSOp op; + + pn = AddExpr(cx, ts, tc); + while (pn && js_MatchToken(cx, ts, TOK_SHOP)) { + op = CURRENT_TOKEN(ts).t_op; + pn = NewBinary(cx, TOK_SHOP, op, pn, AddExpr(cx, ts, tc), tc); + } + return pn; +} + +static JSParseNode * +AddExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + JSTokenType tt; + JSOp op; + + pn = MulExpr(cx, ts, tc); + while (pn && + (js_MatchToken(cx, ts, TOK_PLUS) || + js_MatchToken(cx, ts, TOK_MINUS))) { + tt = CURRENT_TOKEN(ts).type; + op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB; + pn = NewBinary(cx, tt, op, pn, MulExpr(cx, ts, tc), tc); + } + return pn; +} + +static JSParseNode * +MulExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + JSTokenType tt; + JSOp op; + + pn = UnaryExpr(cx, ts, tc); + while (pn && + (js_MatchToken(cx, ts, TOK_STAR) || + js_MatchToken(cx, ts, TOK_DIVOP))) { + tt = CURRENT_TOKEN(ts).type; + op = CURRENT_TOKEN(ts).t_op; + pn = NewBinary(cx, tt, op, pn, UnaryExpr(cx, ts, tc), tc); + } + return pn; +} + +static JSParseNode * +SetLvalKid(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, JSParseNode *kid, + const char *name) +{ + while (kid->pn_type == TOK_RP) + kid = kid->pn_kid; + if (kid->pn_type != TOK_NAME && + kid->pn_type != TOK_DOT && +#if JS_HAS_LVALUE_RETURN + (kid->pn_type != TOK_LP || + (kid->pn_op != JSOP_CALL && kid->pn_op != JSOP_EVAL && kid->pn_op != JSOP_APPLY)) && +#endif +#if JS_HAS_XML_SUPPORT + (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) && +#endif + kid->pn_type != TOK_LB) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_OPERAND, name); + return NULL; + } + pn->pn_kid = kid; + return kid; +} + +static const char incop_name_str[][10] = {"increment", "decrement"}; + +static JSBool +SetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSParseNode *pn, JSParseNode *kid, + JSTokenType tt, JSBool preorder) +{ + JSOp op; + + kid = SetLvalKid(cx, ts, pn, kid, incop_name_str[tt == TOK_DEC]); + if (!kid) + return JS_FALSE; + switch (kid->pn_type) { + case TOK_NAME: + op = (tt == TOK_INC) + ? (preorder ? JSOP_INCNAME : JSOP_NAMEINC) + : (preorder ? JSOP_DECNAME : JSOP_NAMEDEC); + if (kid->pn_atom == cx->runtime->atomState.argumentsAtom) + tc->flags |= TCF_FUN_HEAVYWEIGHT; + break; + + case TOK_DOT: + op = (tt == TOK_INC) + ? (preorder ? JSOP_INCPROP : JSOP_PROPINC) + : (preorder ? JSOP_DECPROP : JSOP_PROPDEC); + break; + +#if JS_HAS_LVALUE_RETURN + case TOK_LP: + if (!MakeSetCall(cx, kid, tc, JSMSG_BAD_INCOP_OPERAND)) + return JS_FALSE; + /* FALL THROUGH */ +#endif +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: + if (kid->pn_op == JSOP_XMLNAME) + kid->pn_op = JSOP_SETXMLNAME; + /* FALL THROUGH */ +#endif + case TOK_LB: + op = (tt == TOK_INC) + ? (preorder ? JSOP_INCELEM : JSOP_ELEMINC) + : (preorder ? JSOP_DECELEM : JSOP_ELEMDEC); + break; + + default: + JS_ASSERT(0); + op = JSOP_NOP; + } + pn->pn_op = op; + return JS_TRUE; +} + +static JSParseNode * +UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSTokenType tt; + JSParseNode *pn, *pn2; + + JS_CHECK_RECURSION(cx, return NULL); + + ts->flags |= TSF_OPERAND; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + + switch (tt) { + case TOK_UNARYOP: + case TOK_PLUS: + case TOK_MINUS: + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + pn->pn_type = TOK_UNARYOP; /* PLUS and MINUS are binary */ + pn->pn_op = CURRENT_TOKEN(ts).t_op; + pn2 = UnaryExpr(cx, ts, tc); + if (!pn2) + return NULL; + pn->pn_pos.end = pn2->pn_pos.end; + pn->pn_kid = pn2; + break; + + case TOK_INC: + case TOK_DEC: + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + pn2 = MemberExpr(cx, ts, tc, JS_TRUE); + if (!pn2) + return NULL; + if (!SetIncOpKid(cx, ts, tc, pn, pn2, tt, JS_TRUE)) + return NULL; + pn->pn_pos.end = pn2->pn_pos.end; + break; + + case TOK_DELETE: + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + pn2 = UnaryExpr(cx, ts, tc); + if (!pn2) + return NULL; + pn->pn_pos.end = pn2->pn_pos.end; + + /* + * Under ECMA3, deleting any unary expression is valid -- it simply + * returns true. Here we strip off any parentheses and fold constants + * before checking for a call expression, in order to rule out delete + * of a generator expression. + */ + while (pn2->pn_type == TOK_RP) + pn2 = pn2->pn_kid; + if (!js_FoldConstants(cx, pn2, tc)) + return NULL; + if (pn2->pn_type == TOK_LP && + pn2->pn_op != JSOP_SETCALL && + !MakeSetCall(cx, pn2, tc, JSMSG_BAD_DELETE_OPERAND)) { + return NULL; + } + pn->pn_kid = pn2; + break; + + case TOK_ERROR: + return NULL; + + default: + js_UngetToken(ts); + pn = MemberExpr(cx, ts, tc, JS_TRUE); + if (!pn) + return NULL; + + /* Don't look across a newline boundary for a postfix incop. */ + if (ON_CURRENT_LINE(ts, pn->pn_pos)) { + ts->flags |= TSF_OPERAND; + tt = js_PeekTokenSameLine(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt == TOK_INC || tt == TOK_DEC) { + (void) js_GetToken(cx, ts); + pn2 = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn2) + return NULL; + if (!SetIncOpKid(cx, ts, tc, pn2, pn, tt, JS_FALSE)) + return NULL; + pn2->pn_pos.begin = pn->pn_pos.begin; + pn = pn2; + } + } + break; + } + return pn; +} + +#if JS_HAS_GENERATORS + +/* + * Starting from a |for| keyword after the first array initialiser element or + * an expression in an open parenthesis, parse the tail of the comprehension + * or generator expression signified by this |for| keyword in context. + * + * Return null on failure, else return the top-most parse node for the array + * comprehension or generator expression, with a unary node as the body of the + * (possibly nested) for-loop, initialized by |type, op, kid|. + */ +static JSParseNode * +ComprehensionTail(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSTokenType type, JSOp op, JSParseNode *kid) +{ + JSParseNode *pn, *pn2, *pn3, **pnp; + JSStmtInfo stmtInfo; + BindData data; + JSRuntime *rt; + JSTokenType tt; + JSAtom *atom; + + JS_ASSERT(type == TOK_SEMI || type == TOK_ARRAYPUSH); + JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_FOR); + + /* + * Make a parse-node and literal object representing the block scope of + * this array comprehension or generator expression. + */ + pn = PushLexicalScope(cx, ts, tc, &stmtInfo); + if (!pn) + return NULL; + pnp = &pn->pn_expr; + + data.pn = NULL; + data.op = JSOP_NOP; + data.binder = BindLet; + data.u.let.overflow = JSMSG_ARRAY_INIT_TOO_BIG; + + rt = cx->runtime; + do { + /* + * FOR node is binary, left is loop control and right is body. Use + * index to count each block-local let-variable on the left-hand side + * of the IN. + */ + pn2 = NewParseNode(cx, ts, PN_BINARY, tc); + if (!pn2) + return NULL; + + pn2->pn_op = JSOP_ITER; + pn2->pn_iflags = JSITER_ENUMERATE; + if (js_MatchToken(cx, ts, TOK_NAME)) { + if (CURRENT_TOKEN(ts).t_atom == rt->atomState.eachAtom) + pn2->pn_iflags |= JSITER_FOREACH; + else + js_UngetToken(ts); + } + MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); + + tt = js_GetToken(cx, ts); + switch (tt) { +#if JS_HAS_DESTRUCTURING + case TOK_LB: + case TOK_LC: + pn3 = DestructuringExpr(cx, &data, tc, tt); + if (!pn3) + return NULL; + + if (pn3->pn_type != TOK_RB || pn3->pn_count != 2) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); + return NULL; + } + + if (JSVERSION_NUMBER(cx) == JSVERSION_1_7) { + /* Destructuring requires [key, value] enumeration in JS1.7. */ + JS_ASSERT(pn2->pn_op == JSOP_ITER); + JS_ASSERT(pn2->pn_iflags & JSITER_ENUMERATE); + if (!(pn2->pn_iflags & JSITER_FOREACH)) + pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE; + } + break; +#endif + + case TOK_NAME: + atom = CURRENT_TOKEN(ts).t_atom; + if (!data.binder(cx, &data, atom, tc)) + return NULL; + + /* + * Create a name node with pn_op JSOP_NAME. We can't set pn_op to + * JSOP_GETLOCAL here, because we don't yet know the block's depth + * in the operand stack frame. The code generator computes that, + * and it tries to bind all names to slots, so we must let it do + * the deed. + */ + pn3 = NewParseNode(cx, ts, PN_NAME, tc); + if (!pn3) + return NULL; + pn3->pn_op = JSOP_NAME; + pn3->pn_atom = atom; + pn3->pn_slot = -1; + break; + + default: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); + + case TOK_ERROR: + return NULL; + } + + MUST_MATCH_TOKEN(TOK_IN, JSMSG_IN_AFTER_FOR_NAME); + pn3 = NewBinary(cx, TOK_IN, JSOP_NOP, pn3, + Expr(cx, ts, tc), tc); + if (!pn3) + return NULL; + + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL); + pn2->pn_left = pn3; + *pnp = pn2; + pnp = &pn2->pn_right; + } while (js_MatchToken(cx, ts, TOK_FOR)); + + if (js_MatchToken(cx, ts, TOK_IF)) { + pn2 = NewParseNode(cx, ts, PN_TERNARY, tc); + if (!pn2) + return NULL; + pn2->pn_kid1 = Condition(cx, ts, tc); + if (!pn2->pn_kid1) + return NULL; + *pnp = pn2; + pnp = &pn2->pn_kid2; + } + + pn2 = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn2) + return NULL; + pn2->pn_type = type; + pn2->pn_op = op; + pn2->pn_kid = kid; + *pnp = pn2; + + js_PopStatement(tc); + return pn; +} + +#if JS_HAS_GENERATOR_EXPRS + +/* + * Starting from a |for| keyword after an expression, parse the comprehension + * tail completing this generator expression. Wrap the expression at kid in a + * generator function that is immediately called to evaluate to the generator + * iterator that is the value of this generator expression. + * + * Callers pass a blank unary node via pn, which GeneratorExpr fills in as the + * yield expression, which ComprehensionTail in turn wraps in a TOK_SEMI-type + * expression-statement node that constitutes the body of the |for| loop(s) in + * the generator function. + * + * Note how unlike Python, we do not evaluate the expression to the right of + * the first |in| in the chain of |for| heads. Instead, a generator expression + * is merely sugar for a generator function expression and its application. + */ +static JSParseNode * +GeneratorExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + uintN oldflags, JSParseNode *pn, JSParseNode *kid) +{ + JSParseNode *body, *lambda; + JSFunction *fun; + + /* Initialize pn, connecting it to kid. */ + JS_ASSERT(pn->pn_arity == PN_UNARY); + pn->pn_type = TOK_YIELD; + pn->pn_op = JSOP_YIELD; + pn->pn_pos = kid->pn_pos; + pn->pn_kid = kid; + pn->pn_hidden = JS_TRUE; + + /* + * Parse the comprehension tail at hand, making pn the kid of the loop + * body's expression statement. + */ + body = ComprehensionTail(cx, ts, tc, TOK_SEMI, JSOP_NOP, pn); + if (!body) + return NULL; + body->pn_pos.begin = kid->pn_pos.begin; + + /* + * Make the generator function and flag it as interpreted ASAP (see the + * comment in FunctionBody). + */ + fun = NewCompilerFunction(cx, tc, NULL, JSFUN_LAMBDA); + if (!fun) + return NULL; + + /* + * This generator function is referenced by an anonymous function object + * node. Here is where we must take care to propagate certain tc->flags + * that may have changed from oldflags to reflect crucial facts about the + * expression on the left of |for| and in the comprehension tail after it. + */ + lambda = NewParseNode(cx, ts, PN_FUNC, tc); + if (!lambda) + return NULL; + lambda->pn_type = TOK_FUNCTION; + lambda->pn_op = JSOP_ANONFUNOBJ; + lambda->pn_pos.begin = body->pn_pos.begin; + lambda->pn_funpob = js_NewParsedObjectBox(cx, tc->parseContext, + FUN_OBJECT(fun)); + if (!lambda->pn_funpob) + return NULL; + lambda->pn_body = body; + lambda->pn_flags = TCF_FUN_IS_GENERATOR | TCF_GENEXP_LAMBDA | + ((oldflags ^ tc->flags) & TCF_FUN_FLAGS); + + /* + * Re-use pn to name the result node, a call expression invoking the + * anonymous generator function object. + */ + pn = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn) + return NULL; + pn->pn_type = TOK_LP; + pn->pn_op = JSOP_CALL; + pn->pn_pos.begin = lambda->pn_pos.begin; + PN_INIT_LIST_1(pn, lambda); + + body->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + tc->flags = oldflags; + return pn; +} + +static const char js_generator_str[] = "generator"; + +#endif /* JS_HAS_GENERATOR_EXPRS */ +#endif /* JS_HAS_GENERATORS */ + +static JSBool +ArgumentList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSParseNode *listNode) +{ + JSBool matched; + + ts->flags |= TSF_OPERAND; + matched = js_MatchToken(cx, ts, TOK_RP); + ts->flags &= ~TSF_OPERAND; + if (!matched) { + do { +#if JS_HAS_GENERATOR_EXPRS + uintN oldflags = tc->flags; +#endif + JSParseNode *argNode = AssignExpr(cx, ts, tc); + if (!argNode) + return JS_FALSE; +#if JS_HAS_GENERATORS + if (argNode->pn_type == TOK_YIELD && + js_PeekToken(cx, ts) == TOK_COMMA) { + js_ReportCompileErrorNumber(cx, ts, argNode, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_yield_str); + return JS_FALSE; + } +#endif +#if JS_HAS_GENERATOR_EXPRS + if (js_MatchToken(cx, ts, TOK_FOR)) { + JSParseNode *pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return JS_FALSE; + argNode = GeneratorExpr(cx, ts, tc, oldflags, pn, argNode); + if (!argNode) + return JS_FALSE; + if (listNode->pn_count > 1 || + js_PeekToken(cx, ts) == TOK_COMMA) { + js_ReportCompileErrorNumber(cx, ts, argNode, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_generator_str); + return JS_FALSE; + } + } +#endif + PN_APPEND(listNode, argNode); + } while (js_MatchToken(cx, ts, TOK_COMMA)); + + if (js_GetToken(cx, ts) != TOK_RP) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_PAREN_AFTER_ARGS); + return JS_FALSE; + } + } + return JS_TRUE; +} + +static JSParseNode * +MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSBool allowCallSyntax) +{ + JSParseNode *pn, *pn2, *pn3; + JSTokenType tt; + + JS_CHECK_RECURSION(cx, return NULL); + + /* Check for new expression first. */ + ts->flags |= TSF_OPERAND; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt == TOK_NEW) { + pn = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn) + return NULL; + pn2 = MemberExpr(cx, ts, tc, JS_FALSE); + if (!pn2) + return NULL; + pn->pn_op = JSOP_NEW; + PN_INIT_LIST_1(pn, pn2); + pn->pn_pos.begin = pn2->pn_pos.begin; + + if (js_MatchToken(cx, ts, TOK_LP) && !ArgumentList(cx, ts, tc, pn)) + return NULL; + if (pn->pn_count > ARGC_LIMIT) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TOO_MANY_CON_ARGS); + return NULL; + } + pn->pn_pos.end = PN_LAST(pn)->pn_pos.end; + } else { + pn = PrimaryExpr(cx, ts, tc, tt, JS_FALSE); + if (!pn) + return NULL; + + if (pn->pn_type == TOK_ANYNAME || + pn->pn_type == TOK_AT || + pn->pn_type == TOK_DBLCOLON) { + pn2 = NewOrRecycledNode(cx, tc); + if (!pn2) + return NULL; + pn2->pn_type = TOK_UNARYOP; + pn2->pn_pos = pn->pn_pos; + pn2->pn_op = JSOP_XMLNAME; + pn2->pn_arity = PN_UNARY; + pn2->pn_kid = pn; + pn = pn2; + } + } + + while ((tt = js_GetToken(cx, ts)) > TOK_EOF) { + if (tt == TOK_DOT) { + pn2 = NewParseNode(cx, ts, PN_NAME, tc); + if (!pn2) + return NULL; + pn2->pn_slot = -1; +#if JS_HAS_XML_SUPPORT + ts->flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; + tt = js_GetToken(cx, ts); + ts->flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); + pn3 = PrimaryExpr(cx, ts, tc, tt, JS_TRUE); + if (!pn3) + return NULL; + tt = PN_TYPE(pn3); + if (tt == TOK_NAME) { + pn2->pn_op = JSOP_GETPROP; + pn2->pn_expr = pn; + pn2->pn_atom = pn3->pn_atom; + RecycleTree(pn3, tc); + } else { + if (TOKEN_TYPE_IS_XML(tt)) { + pn2->pn_type = TOK_LB; + pn2->pn_op = JSOP_GETELEM; + } else if (tt == TOK_RP) { + JSParseNode *group = pn3; + + /* Recycle the useless TOK_RP node. */ + pn3 = group->pn_kid; + group->pn_kid = NULL; + RecycleTree(group, tc); + pn2->pn_type = TOK_FILTER; + pn2->pn_op = JSOP_FILTER; + + /* A filtering predicate is like a with statement. */ + tc->flags |= TCF_FUN_HEAVYWEIGHT; + } else { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_NAME_AFTER_DOT); + return NULL; + } + pn2->pn_arity = PN_BINARY; + pn2->pn_left = pn; + pn2->pn_right = pn3; + } +#else + ts->flags |= TSF_KEYWORD_IS_NAME; + MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT); + ts->flags &= ~TSF_KEYWORD_IS_NAME; + pn2->pn_op = JSOP_GETPROP; + pn2->pn_expr = pn; + pn2->pn_atom = CURRENT_TOKEN(ts).t_atom; +#endif + pn2->pn_pos.begin = pn->pn_pos.begin; + pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; +#if JS_HAS_XML_SUPPORT + } else if (tt == TOK_DBLDOT) { + pn2 = NewParseNode(cx, ts, PN_BINARY, tc); + if (!pn2) + return NULL; + ts->flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; + tt = js_GetToken(cx, ts); + ts->flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); + pn3 = PrimaryExpr(cx, ts, tc, tt, JS_TRUE); + if (!pn3) + return NULL; + tt = PN_TYPE(pn3); + if (tt == TOK_NAME) { + pn3->pn_type = TOK_STRING; + pn3->pn_arity = PN_NULLARY; + pn3->pn_op = JSOP_QNAMEPART; + } else if (!TOKEN_TYPE_IS_XML(tt)) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_NAME_AFTER_DOT); + return NULL; + } + pn2->pn_op = JSOP_DESCENDANTS; + pn2->pn_left = pn; + pn2->pn_right = pn3; + pn2->pn_pos.begin = pn->pn_pos.begin; + pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; +#endif + } else if (tt == TOK_LB) { + pn2 = NewParseNode(cx, ts, PN_BINARY, tc); + if (!pn2) + return NULL; + pn3 = Expr(cx, ts, tc); + if (!pn3) + return NULL; + + MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); + pn2->pn_pos.begin = pn->pn_pos.begin; + pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + + /* + * Optimize o['p'] to o.p by rewriting pn2, but avoid rewriting + * o['0'] to use JSOP_GETPROP, to keep fast indexing disjoint in + * the interpreter from fast property access. However, if the + * bracketed string is a uint32, we rewrite pn3 to be a number + * instead of a string. + */ + do { + if (pn3->pn_type == TOK_STRING) { + jsuint index; + + if (!js_IdIsIndex(ATOM_TO_JSID(pn3->pn_atom), &index)) { + pn2->pn_type = TOK_DOT; + pn2->pn_op = JSOP_GETPROP; + pn2->pn_arity = PN_NAME; + pn2->pn_expr = pn; + pn2->pn_atom = pn3->pn_atom; + break; + } + pn3->pn_type = TOK_NUMBER; + pn3->pn_op = JSOP_DOUBLE; + pn3->pn_dval = index; + } + pn2->pn_op = JSOP_GETELEM; + pn2->pn_left = pn; + pn2->pn_right = pn3; + } while (0); + } else if (allowCallSyntax && tt == TOK_LP) { + pn2 = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn2) + return NULL; + + pn2->pn_op = JSOP_CALL; + if (pn->pn_op == JSOP_NAME && + pn->pn_atom == cx->runtime->atomState.evalAtom) { + /* Pick JSOP_EVAL and flag tc as heavyweight if eval(...). */ + pn2->pn_op = JSOP_EVAL; + tc->flags |= TCF_FUN_HEAVYWEIGHT; + } else if (pn->pn_op == JSOP_GETPROP && + (pn->pn_atom == cx->runtime->atomState.applyAtom || + pn->pn_atom == cx->runtime->atomState.callAtom)) { + /* Pick JSOP_APPLY if apply(...). */ + pn2->pn_op = JSOP_APPLY; + } + + PN_INIT_LIST_1(pn2, pn); + pn2->pn_pos.begin = pn->pn_pos.begin; + + if (!ArgumentList(cx, ts, tc, pn2)) + return NULL; + if (pn2->pn_count > ARGC_LIMIT) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TOO_MANY_FUN_ARGS); + return NULL; + } + pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + } else { + js_UngetToken(ts); + return pn; + } + + pn = pn2; + } + if (tt == TOK_ERROR) + return NULL; + return pn; +} + +static JSParseNode * +BracketedExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + uintN oldflags; + JSParseNode *pn; + + /* + * Always accept the 'in' operator in a parenthesized expression, + * where it's unambiguous, even if we might be parsing the init of a + * for statement. + */ + oldflags = tc->flags; + tc->flags &= ~TCF_IN_FOR_INIT; + pn = Expr(cx, ts, tc); + tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS); + return pn; +} + +#if JS_HAS_XML_SUPPORT + +static JSParseNode * +EndBracketedExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = BracketedExpr(cx, ts, tc); + if (!pn) + return NULL; + + MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ATTR_EXPR); + return pn; +} + +/* + * From the ECMA-357 grammar in 11.1.1 and 11.1.2: + * + * AttributeIdentifier: + * @ PropertySelector + * @ QualifiedIdentifier + * @ [ Expression ] + * + * PropertySelector: + * Identifier + * * + * + * QualifiedIdentifier: + * PropertySelector :: PropertySelector + * PropertySelector :: [ Expression ] + * + * We adapt AttributeIdentifier and QualifiedIdentier to be LL(1), like so: + * + * AttributeIdentifier: + * @ QualifiedIdentifier + * @ [ Expression ] + * + * PropertySelector: + * Identifier + * * + * + * QualifiedIdentifier: + * PropertySelector :: PropertySelector + * PropertySelector :: [ Expression ] + * PropertySelector + * + * As PrimaryExpression: Identifier is in ECMA-262 and we want the semantics + * for that rule to result in a name node, but ECMA-357 extends the grammar + * to include PrimaryExpression: QualifiedIdentifier, we must factor further: + * + * QualifiedIdentifier: + * PropertySelector QualifiedSuffix + * + * QualifiedSuffix: + * :: PropertySelector + * :: [ Expression ] + * /nothing/ + * + * And use this production instead of PrimaryExpression: QualifiedIdentifier: + * + * PrimaryExpression: + * Identifier QualifiedSuffix + * + * We hoist the :: match into callers of QualifiedSuffix, in order to tweak + * PropertySelector vs. Identifier pn_arity, pn_op, and other members. + */ +static JSParseNode * +PropertySelector(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn) + return NULL; + if (pn->pn_type == TOK_STAR) { + pn->pn_type = TOK_ANYNAME; + pn->pn_op = JSOP_ANYNAME; + pn->pn_atom = cx->runtime->atomState.starAtom; + } else { + JS_ASSERT(pn->pn_type == TOK_NAME); + pn->pn_op = JSOP_QNAMEPART; + pn->pn_arity = PN_NAME; + pn->pn_atom = CURRENT_TOKEN(ts).t_atom; + pn->pn_slot = -1; + } + return pn; +} + +static JSParseNode * +QualifiedSuffix(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, + JSTreeContext *tc) +{ + JSParseNode *pn2, *pn3; + JSTokenType tt; + + JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_DBLCOLON); + pn2 = NewParseNode(cx, ts, PN_NAME, tc); + if (!pn2) + return NULL; + + /* Left operand of :: must be evaluated if it is an identifier. */ + if (pn->pn_op == JSOP_QNAMEPART) + pn->pn_op = JSOP_NAME; + + ts->flags |= TSF_KEYWORD_IS_NAME; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_KEYWORD_IS_NAME; + if (tt == TOK_STAR || tt == TOK_NAME) { + /* Inline and specialize PropertySelector for JSOP_QNAMECONST. */ + pn2->pn_op = JSOP_QNAMECONST; + pn2->pn_atom = (tt == TOK_STAR) + ? cx->runtime->atomState.starAtom + : CURRENT_TOKEN(ts).t_atom; + pn2->pn_expr = pn; + pn2->pn_slot = -1; + return pn2; + } + + if (tt != TOK_LB) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); + return NULL; + } + pn3 = EndBracketedExpr(cx, ts, tc); + if (!pn3) + return NULL; + + pn2->pn_op = JSOP_QNAME; + pn2->pn_arity = PN_BINARY; + pn2->pn_left = pn; + pn2->pn_right = pn3; + return pn2; +} + +static JSParseNode * +QualifiedIdentifier(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = PropertySelector(cx, ts, tc); + if (!pn) + return NULL; + if (js_MatchToken(cx, ts, TOK_DBLCOLON)) + pn = QualifiedSuffix(cx, ts, pn, tc); + return pn; +} + +static JSParseNode * +AttributeIdentifier(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn, *pn2; + JSTokenType tt; + + JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_AT); + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + pn->pn_op = JSOP_TOATTRNAME; + ts->flags |= TSF_KEYWORD_IS_NAME; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_KEYWORD_IS_NAME; + if (tt == TOK_STAR || tt == TOK_NAME) { + pn2 = QualifiedIdentifier(cx, ts, tc); + } else if (tt == TOK_LB) { + pn2 = EndBracketedExpr(cx, ts, tc); + } else { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); + return NULL; + } + if (!pn2) + return NULL; + pn->pn_kid = pn2; + return pn; +} + +/* + * Make a TOK_LC unary node whose pn_kid is an expression. + */ +static JSParseNode * +XMLExpr(JSContext *cx, JSTokenStream *ts, JSBool inTag, JSTreeContext *tc) +{ + JSParseNode *pn, *pn2; + uintN oldflags; + + JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_LC); + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + + /* + * Turn off XML tag mode, but don't restore it after parsing this braced + * expression. Instead, simply restore ts's old flags. This is required + * because XMLExpr is called both from within a tag, and from within text + * contained in an element, but outside of any start, end, or point tag. + */ + oldflags = ts->flags; + ts->flags = oldflags & ~TSF_XMLTAGMODE; + pn2 = Expr(cx, ts, tc); + if (!pn2) + return NULL; + + MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_XML_EXPR); + ts->flags = oldflags; + pn->pn_kid = pn2; + pn->pn_op = inTag ? JSOP_XMLTAGEXPR : JSOP_XMLELTEXPR; + return pn; +} + +/* + * Make a terminal node for one of TOK_XMLNAME, TOK_XMLATTR, TOK_XMLSPACE, + * TOK_XMLTEXT, TOK_XMLCDATA, TOK_XMLCOMMENT, or TOK_XMLPI. When converting + * parse tree to XML, we preserve a TOK_XMLSPACE node only if it's the sole + * child of a container tag. + */ +static JSParseNode * +XMLAtomNode(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn; + JSToken *tp; + + pn = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn) + return NULL; + tp = &CURRENT_TOKEN(ts); + pn->pn_op = tp->t_op; + pn->pn_atom = tp->t_atom; + if (tp->type == TOK_XMLPI) + pn->pn_atom2 = tp->t_atom2; + return pn; +} + +/* + * Parse the productions: + * + * XMLNameExpr: + * XMLName XMLNameExpr? + * { Expr } XMLNameExpr? + * + * Return a PN_LIST, PN_UNARY, or PN_NULLARY according as XMLNameExpr produces + * a list of names and/or expressions, a single expression, or a single name. + * If PN_LIST or PN_NULLARY, pn_type will be TOK_XMLNAME; if PN_UNARY, pn_type + * will be TOK_LC. + */ +static JSParseNode * +XMLNameExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +{ + JSParseNode *pn, *pn2, *list; + JSTokenType tt; + + pn = list = NULL; + do { + tt = CURRENT_TOKEN(ts).type; + if (tt == TOK_LC) { + pn2 = XMLExpr(cx, ts, JS_TRUE, tc); + if (!pn2) + return NULL; + } else { + JS_ASSERT(tt == TOK_XMLNAME); + pn2 = XMLAtomNode(cx, ts, tc); + if (!pn2) + return NULL; + } + + if (!pn) { + pn = pn2; + } else { + if (!list) { + list = NewParseNode(cx, ts, PN_LIST, tc); + if (!list) + return NULL; + list->pn_type = TOK_XMLNAME; + list->pn_pos.begin = pn->pn_pos.begin; + PN_INIT_LIST_1(list, pn); + list->pn_extra = PNX_CANTFOLD; + pn = list; + } + pn->pn_pos.end = pn2->pn_pos.end; + PN_APPEND(pn, pn2); + } + } while ((tt = js_GetToken(cx, ts)) == TOK_XMLNAME || tt == TOK_LC); + + js_UngetToken(ts); + return pn; +} + +/* + * Macro to test whether an XMLNameExpr or XMLTagContent node can be folded + * at compile time into a JSXML tree. + */ +#define XML_FOLDABLE(pn) ((pn)->pn_arity == PN_LIST \ + ? ((pn)->pn_extra & PNX_CANTFOLD) == 0 \ + : (pn)->pn_type != TOK_LC) + +/* + * Parse the productions: + * + * XMLTagContent: + * XMLNameExpr + * XMLTagContent S XMLNameExpr S? = S? XMLAttr + * XMLTagContent S XMLNameExpr S? = S? { Expr } + * + * Return a PN_LIST, PN_UNARY, or PN_NULLARY according to how XMLTagContent + * produces a list of name and attribute values and/or braced expressions, a + * single expression, or a single name. + * + * If PN_LIST or PN_NULLARY, pn_type will be TOK_XMLNAME for the case where + * XMLTagContent: XMLNameExpr. If pn_type is not TOK_XMLNAME but pn_arity is + * PN_LIST, pn_type will be tagtype. If PN_UNARY, pn_type will be TOK_LC and + * we parsed exactly one expression. + */ +static JSParseNode * +XMLTagContent(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSTokenType tagtype, JSAtom **namep) +{ + JSParseNode *pn, *pn2, *list; + JSTokenType tt; + + pn = XMLNameExpr(cx, ts, tc); + if (!pn) + return NULL; + *namep = (pn->pn_arity == PN_NULLARY) ? pn->pn_atom : NULL; + list = NULL; + + while (js_MatchToken(cx, ts, TOK_XMLSPACE)) { + tt = js_GetToken(cx, ts); + if (tt != TOK_XMLNAME && tt != TOK_LC) { + js_UngetToken(ts); + break; + } + + pn2 = XMLNameExpr(cx, ts, tc); + if (!pn2) + return NULL; + if (!list) { + list = NewParseNode(cx, ts, PN_LIST, tc); + if (!list) + return NULL; + list->pn_type = tagtype; + list->pn_pos.begin = pn->pn_pos.begin; + PN_INIT_LIST_1(list, pn); + pn = list; + } + PN_APPEND(pn, pn2); + if (!XML_FOLDABLE(pn2)) + pn->pn_extra |= PNX_CANTFOLD; + + js_MatchToken(cx, ts, TOK_XMLSPACE); + MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_NO_ASSIGN_IN_XML_ATTR); + js_MatchToken(cx, ts, TOK_XMLSPACE); + + tt = js_GetToken(cx, ts); + if (tt == TOK_XMLATTR) { + pn2 = XMLAtomNode(cx, ts, tc); + } else if (tt == TOK_LC) { + pn2 = XMLExpr(cx, ts, JS_TRUE, tc); + pn->pn_extra |= PNX_CANTFOLD; + } else { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_ATTR_VALUE); + return NULL; + } + if (!pn2) + return NULL; + pn->pn_pos.end = pn2->pn_pos.end; + PN_APPEND(pn, pn2); + } + + return pn; +} + +#define XML_CHECK_FOR_ERROR_AND_EOF(tt,result) \ + JS_BEGIN_MACRO \ + if ((tt) <= TOK_EOF) { \ + if ((tt) == TOK_EOF) { \ + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, \ + JSMSG_END_OF_XML_SOURCE); \ + } \ + return result; \ + } \ + JS_END_MACRO + +static JSParseNode * +XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSBool allowList); + +/* + * Consume XML element tag content, including the TOK_XMLETAGO (flags &= ~TSF_XMLTAGMODE; + for (;;) { + ts->flags |= TSF_XMLTEXTMODE; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_XMLTEXTMODE; + XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); + + JS_ASSERT(tt == TOK_XMLSPACE || tt == TOK_XMLTEXT); + textAtom = CURRENT_TOKEN(ts).t_atom; + if (textAtom) { + /* Non-zero-length XML text scanned. */ + pn2 = XMLAtomNode(cx, ts, tc); + if (!pn2) + return JS_FALSE; + pn->pn_pos.end = pn2->pn_pos.end; + PN_APPEND(pn, pn2); + } + + ts->flags |= TSF_OPERAND; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); + if (tt == TOK_XMLETAGO) + break; + + if (tt == TOK_LC) { + pn2 = XMLExpr(cx, ts, JS_FALSE, tc); + pn->pn_extra |= PNX_CANTFOLD; + } else if (tt == TOK_XMLSTAGO) { + pn2 = XMLElementOrList(cx, ts, tc, JS_FALSE); + if (pn2) { + pn2->pn_extra &= ~PNX_XMLROOT; + pn->pn_extra |= pn2->pn_extra; + } + } else { + JS_ASSERT(tt == TOK_XMLCDATA || tt == TOK_XMLCOMMENT || + tt == TOK_XMLPI); + pn2 = XMLAtomNode(cx, ts, tc); + } + if (!pn2) + return JS_FALSE; + pn->pn_pos.end = pn2->pn_pos.end; + PN_APPEND(pn, pn2); + } + + JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_XMLETAGO); + ts->flags |= TSF_XMLTAGMODE; + return JS_TRUE; +} + +/* + * Return a PN_LIST node containing an XML or XMLList Initialiser. + */ +static JSParseNode * +XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSBool allowList) +{ + JSParseNode *pn, *pn2, *list; + JSTokenType tt; + JSAtom *startAtom, *endAtom; + + JS_CHECK_RECURSION(cx, return NULL); + + JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_XMLSTAGO); + pn = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn) + return NULL; + + ts->flags |= TSF_XMLTAGMODE; + tt = js_GetToken(cx, ts); + if (tt == TOK_ERROR) + return NULL; + + if (tt == TOK_XMLNAME || tt == TOK_LC) { + /* + * XMLElement. Append the tag and its contents, if any, to pn. + */ + pn2 = XMLTagContent(cx, ts, tc, TOK_XMLSTAGO, &startAtom); + if (!pn2) + return NULL; + js_MatchToken(cx, ts, TOK_XMLSPACE); + + tt = js_GetToken(cx, ts); + if (tt == TOK_XMLPTAGC) { + /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */ + if (pn2->pn_type == TOK_XMLSTAGO) { + PN_INIT_LIST(pn); + RecycleTree(pn, tc); + pn = pn2; + } else { + JS_ASSERT(pn2->pn_type == TOK_XMLNAME || + pn2->pn_type == TOK_LC); + PN_INIT_LIST_1(pn, pn2); + if (!XML_FOLDABLE(pn2)) + pn->pn_extra |= PNX_CANTFOLD; + } + pn->pn_type = TOK_XMLPTAGC; + pn->pn_extra |= PNX_XMLROOT; + } else { + /* We had better have a tag-close (>) at this point. */ + if (tt != TOK_XMLTAGC) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); + return NULL; + } + pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + + /* Make sure pn2 is a TOK_XMLSTAGO list containing tag contents. */ + if (pn2->pn_type != TOK_XMLSTAGO) { + PN_INIT_LIST_1(pn, pn2); + if (!XML_FOLDABLE(pn2)) + pn->pn_extra |= PNX_CANTFOLD; + pn2 = pn; + pn = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn) + return NULL; + } + + /* Now make pn a nominal-root TOK_XMLELEM list containing pn2. */ + pn->pn_type = TOK_XMLELEM; + PN_INIT_LIST_1(pn, pn2); + if (!XML_FOLDABLE(pn2)) + pn->pn_extra |= PNX_CANTFOLD; + pn->pn_extra |= PNX_XMLROOT; + + /* Get element contents and delimiting end-tag-open sequence. */ + if (!XMLElementContent(cx, ts, pn, tc)) + return NULL; + + tt = js_GetToken(cx, ts); + XML_CHECK_FOR_ERROR_AND_EOF(tt, NULL); + if (tt != TOK_XMLNAME && tt != TOK_LC) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); + return NULL; + } + + /* Parse end tag; check mismatch at compile-time if we can. */ + pn2 = XMLTagContent(cx, ts, tc, TOK_XMLETAGO, &endAtom); + if (!pn2) + return NULL; + if (pn2->pn_type == TOK_XMLETAGO) { + /* Oops, end tag has attributes! */ + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); + return NULL; + } + if (endAtom && startAtom && endAtom != startAtom) { + JSString *str = ATOM_TO_STRING(startAtom); + + /* End vs. start tag name mismatch: point to the tag name. */ + js_ReportCompileErrorNumber(cx, ts, pn2, + JSREPORT_UC | JSREPORT_ERROR, + JSMSG_XML_TAG_NAME_MISMATCH, + JSSTRING_CHARS(str)); + return NULL; + } + + /* Make a TOK_XMLETAGO list with pn2 as its single child. */ + JS_ASSERT(pn2->pn_type == TOK_XMLNAME || pn2->pn_type == TOK_LC); + list = NewParseNode(cx, ts, PN_LIST, tc); + if (!list) + return NULL; + list->pn_type = TOK_XMLETAGO; + PN_INIT_LIST_1(list, pn2); + PN_APPEND(pn, list); + if (!XML_FOLDABLE(pn2)) { + list->pn_extra |= PNX_CANTFOLD; + pn->pn_extra |= PNX_CANTFOLD; + } + + js_MatchToken(cx, ts, TOK_XMLSPACE); + MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX); + } + + /* Set pn_op now that pn has been updated to its final value. */ + pn->pn_op = JSOP_TOXML; + } else if (allowList && tt == TOK_XMLTAGC) { + /* XMLList Initialiser. */ + pn->pn_type = TOK_XMLLIST; + pn->pn_op = JSOP_TOXMLLIST; + PN_INIT_LIST(pn); + pn->pn_extra |= PNX_XMLROOT; + if (!XMLElementContent(cx, ts, pn, tc)) + return NULL; + + MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_LIST_SYNTAX); + } else { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_NAME_SYNTAX); + return NULL; + } + + pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + ts->flags &= ~TSF_XMLTAGMODE; + return pn; +} + +static JSParseNode * +XMLElementOrListRoot(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSBool allowList) +{ + uint32 oldopts; + JSParseNode *pn; + + /* + * Force XML support to be enabled so that comments and CDATA literals + * are recognized, instead of ). + */ + oldopts = JS_SetOptions(cx, cx->options | JSOPTION_XML); + pn = XMLElementOrList(cx, ts, tc, allowList); + JS_SetOptions(cx, oldopts); + return pn; +} + +JS_FRIEND_API(JSParseNode *) +js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc, + JSBool allowList) +{ + JSParseNode *pn; + JSTreeContext tc; + JSTokenType tt; + + /* + * Push a compiler frame if we have no frames, or if the top frame is a + * lightweight function activation, or if its scope chain doesn't match + * the one passed to us. + */ + TREE_CONTEXT_INIT(&tc, pc); + tc.u.scopeChain = chain; + + /* Set XML-only mode to turn off special treatment of {expr} in XML. */ + TS(pc)->flags |= TSF_OPERAND | TSF_XMLONLYMODE; + tt = js_GetToken(cx, TS(pc)); + TS(pc)->flags &= ~TSF_OPERAND; + + if (tt != TOK_XMLSTAGO) { + js_ReportCompileErrorNumber(cx, TS(pc), NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_MARKUP); + pn = NULL; + } else { + pn = XMLElementOrListRoot(cx, TS(pc), &tc, allowList); + } + + TS(pc)->flags &= ~TSF_XMLONLYMODE; + TREE_CONTEXT_FINISH(cx, &tc); + return pn; +} + +#endif /* JS_HAS_XMLSUPPORT */ + +static JSParseNode * +PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSTokenType tt, JSBool afterDot) +{ + JSParseNode *pn, *pn2, *pn3; + JSOp op; +#if JS_HAS_SHARP_VARS + JSParseNode *defsharp; + JSBool notsharp; +#endif + + JS_CHECK_RECURSION(cx, return NULL); + +#if JS_HAS_SHARP_VARS + defsharp = NULL; + notsharp = JS_FALSE; + again: + /* + * Control flows here after #n= is scanned. If the following primary is + * not valid after such a "sharp variable" definition, the tt switch case + * should set notsharp. + */ +#endif + +#if JS_HAS_GETTER_SETTER + if (tt == TOK_NAME) { + tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION); + if (tt == TOK_ERROR) + return NULL; + } +#endif + + switch (tt) { + case TOK_FUNCTION: +#if JS_HAS_XML_SUPPORT + ts->flags |= TSF_KEYWORD_IS_NAME; + if (js_MatchToken(cx, ts, TOK_DBLCOLON)) { + ts->flags &= ~TSF_KEYWORD_IS_NAME; + pn2 = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn2) + return NULL; + pn2->pn_type = TOK_FUNCTION; + pn = QualifiedSuffix(cx, ts, pn2, tc); + if (!pn) + return NULL; + break; + } + ts->flags &= ~TSF_KEYWORD_IS_NAME; +#endif + pn = FunctionExpr(cx, ts, tc); + if (!pn) + return NULL; + break; + + case TOK_LB: + { + JSBool matched; + jsuint index; + + pn = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn) + return NULL; + pn->pn_type = TOK_RB; + pn->pn_op = JSOP_NEWINIT; + +#if JS_HAS_SHARP_VARS + if (defsharp) { + PN_INIT_LIST_1(pn, defsharp); + defsharp = NULL; + } else +#endif + PN_INIT_LIST(pn); + + ts->flags |= TSF_OPERAND; + matched = js_MatchToken(cx, ts, TOK_RB); + ts->flags &= ~TSF_OPERAND; + if (!matched) { + for (index = 0; ; index++) { + if (index == ARRAY_INIT_LIMIT) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_ARRAY_INIT_TOO_BIG); + return NULL; + } + + ts->flags |= TSF_OPERAND; + tt = js_PeekToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + if (tt == TOK_RB) { + pn->pn_extra |= PNX_ENDCOMMA; + break; + } + + if (tt == TOK_COMMA) { + /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */ + js_MatchToken(cx, ts, TOK_COMMA); + pn2 = NewParseNode(cx, ts, PN_NULLARY, tc); + } else { + pn2 = AssignExpr(cx, ts, tc); + } + if (!pn2) + return NULL; + PN_APPEND(pn, pn2); + + if (tt != TOK_COMMA) { + /* If we didn't already match TOK_COMMA in above case. */ + if (!js_MatchToken(cx, ts, TOK_COMMA)) + break; + } + } + +#if JS_HAS_GENERATORS + /* + * At this point, (index == 0 && pn->pn_count != 0) implies one + * element initialiser was parsed (possibly with a defsharp before + * the left bracket). + * + * An array comprehension of the form: + * + * [i * j for (i in o) for (j in p) if (i != j)] + * + * translates to roughly the following let expression: + * + * let (array = new Array, i, j) { + * for (i in o) let { + * for (j in p) + * if (i != j) + * array.push(i * j) + * } + * array + * } + * + * where array is a nameless block-local variable. The "roughly" + * means that an implementation may optimize away the array.push. + * An array comprehension opens exactly one block scope, no matter + * how many for heads it contains. + * + * Each let () {...} or for (let ...) ... compiles to: + * + * JSOP_ENTERBLOCK ... JSOP_LEAVEBLOCK + * + * where is a literal object representing the block scope, + * with properties, naming each var declared in the block. + * + * Each var declaration in a let-block binds a name in at + * compile time, and allocates a slot on the operand stack at + * runtime via JSOP_ENTERBLOCK. A block-local var is accessed + * by the JSOP_GETLOCAL and JSOP_SETLOCAL ops, and iterated with + * JSOP_FORLOCAL. These ops all have an immediate operand, the + * local slot's stack index from fp->spbase. + * + * The array comprehension iteration step, array.push(i * j) in + * the example above, is done by ; JSOP_ARRAYCOMP , + * where is the index of array's stack slot. + */ + if (index == 0 && + pn->pn_count != 0 && + js_MatchToken(cx, ts, TOK_FOR)) { + JSParseNode *pnexp, *pntop; + + /* Relabel pn as an array comprehension node. */ + pn->pn_type = TOK_ARRAYCOMP; + + /* + * Remove the comprehension expression from pn's linked list + * and save it via pnexp. We'll re-install it underneath the + * ARRAYPUSH node after we parse the rest of the comprehension. + */ + pnexp = PN_LAST(pn); + JS_ASSERT(pn->pn_count == 1 || pn->pn_count == 2); + pn->pn_tail = (--pn->pn_count == 1) + ? &pn->pn_head->pn_next + : &pn->pn_head; + *pn->pn_tail = NULL; + + pntop = ComprehensionTail(cx, ts, tc, TOK_ARRAYPUSH, + JSOP_ARRAYPUSH, pnexp); + if (!pntop) + return NULL; + PN_APPEND(pn, pntop); + } +#endif /* JS_HAS_GENERATORS */ + + MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST); + } + pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + return pn; + } + + case TOK_LC: + { + JSBool afterComma; + JSParseNode *pnval; + + pn = NewParseNode(cx, ts, PN_LIST, tc); + if (!pn) + return NULL; + pn->pn_type = TOK_RC; + pn->pn_op = JSOP_NEWINIT; + +#if JS_HAS_SHARP_VARS + if (defsharp) { + PN_INIT_LIST_1(pn, defsharp); + defsharp = NULL; + } else +#endif + PN_INIT_LIST(pn); + + afterComma = JS_FALSE; + for (;;) { + ts->flags |= TSF_KEYWORD_IS_NAME; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_KEYWORD_IS_NAME; + switch (tt) { + case TOK_NUMBER: + pn3 = NewParseNode(cx, ts, PN_NULLARY, tc); + if (pn3) + pn3->pn_dval = CURRENT_TOKEN(ts).t_dval; + break; + case TOK_NAME: +#if JS_HAS_GETTER_SETTER + { + JSAtom *atom; + + atom = CURRENT_TOKEN(ts).t_atom; + if (atom == cx->runtime->atomState.getAtom) + op = JSOP_GETTER; + else if (atom == cx->runtime->atomState.setAtom) + op = JSOP_SETTER; + else + goto property_name; + + ts->flags |= TSF_KEYWORD_IS_NAME; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_KEYWORD_IS_NAME; + if (tt != TOK_NAME) { + js_UngetToken(ts); + goto property_name; + } + pn3 = NewParseNode(cx, ts, PN_NAME, tc); + if (!pn3) + return NULL; + pn3->pn_atom = CURRENT_TOKEN(ts).t_atom; + pn3->pn_slot = -1; + + /* We have to fake a 'function' token here. */ + CURRENT_TOKEN(ts).t_op = JSOP_NOP; + CURRENT_TOKEN(ts).type = TOK_FUNCTION; + pn2 = FunctionExpr(cx, ts, tc); + pn2 = NewBinary(cx, TOK_COLON, op, pn3, pn2, tc); + goto skip; + } + property_name: +#endif + case TOK_STRING: + pn3 = NewParseNode(cx, ts, PN_NULLARY, tc); + if (pn3) + pn3->pn_atom = CURRENT_TOKEN(ts).t_atom; + break; + case TOK_RC: + if (afterComma && + !js_ReportCompileErrorNumber(cx, ts, NULL, + JSREPORT_WARNING | + JSREPORT_STRICT, + JSMSG_TRAILING_COMMA)) { + return NULL; + } + goto end_obj_init; + default: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_PROP_ID); + return NULL; + } + + tt = js_GetToken(cx, ts); +#if JS_HAS_GETTER_SETTER + if (tt == TOK_NAME) { + tt = CheckGetterOrSetter(cx, ts, TOK_COLON); + if (tt == TOK_ERROR) + return NULL; + } +#endif + + if (tt != TOK_COLON) { +#if JS_HAS_DESTRUCTURING_SHORTHAND + if (tt != TOK_COMMA && tt != TOK_RC) { +#endif + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_COLON_AFTER_ID); + return NULL; +#if JS_HAS_DESTRUCTURING_SHORTHAND + } + + /* + * Support, e.g., |var {x, y} = o| as destructuring shorthand + * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8. + */ + js_UngetToken(ts); + pn->pn_extra |= PNX_SHORTHAND; + pnval = pn3; + if (pnval->pn_type == TOK_NAME) { + pnval->pn_arity = PN_NAME; + pnval->pn_expr = NULL; + pnval->pn_slot = -1; + pnval->pn_const = JS_FALSE; + } + op = JSOP_NOP; +#endif + } else { + op = CURRENT_TOKEN(ts).t_op; + pnval = AssignExpr(cx, ts, tc); + } + + pn2 = NewBinary(cx, TOK_COLON, op, pn3, pnval, tc); +#if JS_HAS_GETTER_SETTER + skip: +#endif + if (!pn2) + return NULL; + PN_APPEND(pn, pn2); + + tt = js_GetToken(cx, ts); + if (tt == TOK_RC) + goto end_obj_init; + if (tt != TOK_COMMA) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_CURLY_AFTER_LIST); + return NULL; + } + afterComma = JS_TRUE; + } + + end_obj_init: + pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + return pn; + } + +#if JS_HAS_BLOCK_SCOPE + case TOK_LET: + pn = LetBlock(cx, ts, tc, JS_FALSE); + if (!pn) + return NULL; + break; +#endif + +#if JS_HAS_SHARP_VARS + case TOK_DEFSHARP: + if (defsharp) + goto badsharp; + defsharp = NewParseNode(cx, ts, PN_UNARY, tc); + if (!defsharp) + return NULL; + defsharp->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval; + ts->flags |= TSF_OPERAND; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_OPERAND; + goto again; + + case TOK_USESHARP: + /* Check for forward/dangling references at runtime, to allow eval. */ + pn = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn) + return NULL; + pn->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval; + notsharp = JS_TRUE; + break; +#endif /* JS_HAS_SHARP_VARS */ + + case TOK_LP: + { + JSBool genexp; + + pn = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn) + return NULL; + pn2 = ParenExpr(cx, ts, tc, pn, &genexp); + if (!pn2) + return NULL; + if (genexp) + return pn2; + + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN); + if (pn2->pn_type == TOK_RP || + (js_CodeSpec[pn2->pn_op].prec >= js_CodeSpec[JSOP_GETPROP].prec && + !afterDot)) { + /* + * Avoid redundant JSOP_GROUP opcodes, for efficiency and mainly + * to help the decompiler look ahead from a JSOP_ENDINIT to see a + * JSOP_GROUP followed by a POP or POPV. That sequence means the + * parentheses are mandatory, to disambiguate object initialisers + * as expression statements from block statements. + * + * Also drop pn if pn2 is a member or a primary expression of any + * kind. This is required to avoid generating a JSOP_GROUP that + * will null the |obj| interpreter register, causing |this| in any + * call of that member expression to bind to the global object. + */ + RecycleTree(pn, tc); + pn = pn2; + } else { + pn->pn_type = TOK_RP; + pn->pn_kid = pn2; + } + pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + break; + } + +#if JS_HAS_XML_SUPPORT + case TOK_STAR: + pn = QualifiedIdentifier(cx, ts, tc); + if (!pn) + return NULL; + notsharp = JS_TRUE; + break; + + case TOK_AT: + pn = AttributeIdentifier(cx, ts, tc); + if (!pn) + return NULL; + notsharp = JS_TRUE; + break; + + case TOK_XMLSTAGO: + pn = XMLElementOrListRoot(cx, ts, tc, JS_TRUE); + if (!pn) + return NULL; + notsharp = JS_TRUE; /* XXXbe could be sharp? */ + break; +#endif /* JS_HAS_XML_SUPPORT */ + + case TOK_STRING: +#if JS_HAS_SHARP_VARS + notsharp = JS_TRUE; + /* FALL THROUGH */ +#endif + +#if JS_HAS_XML_SUPPORT + case TOK_XMLCDATA: + case TOK_XMLCOMMENT: + case TOK_XMLPI: +#endif + case TOK_NAME: + pn = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn) + return NULL; + pn->pn_atom = CURRENT_TOKEN(ts).t_atom; +#if JS_HAS_XML_SUPPORT + if (tt == TOK_XMLPI) + pn->pn_atom2 = CURRENT_TOKEN(ts).t_atom2; + else +#endif + pn->pn_op = CURRENT_TOKEN(ts).t_op; + if (tt == TOK_NAME) { + pn->pn_arity = PN_NAME; + pn->pn_slot = -1; + +#if JS_HAS_XML_SUPPORT + if (js_MatchToken(cx, ts, TOK_DBLCOLON)) { + if (afterDot) { + JSString *str; + + /* + * Here PrimaryExpr is called after '.' or '..' and we + * just scanned .name:: or ..name:: . This is the only + * case where a keyword after '.' or '..' is not + * treated as a property name. + */ + str = ATOM_TO_STRING(pn->pn_atom); + tt = js_CheckKeyword(JSSTRING_CHARS(str), + JSSTRING_LENGTH(str)); + if (tt == TOK_FUNCTION) { + pn->pn_arity = PN_NULLARY; + pn->pn_type = TOK_FUNCTION; + } else if (tt != TOK_EOF) { + js_ReportCompileErrorNumber( + cx, ts, NULL, JSREPORT_ERROR, + JSMSG_KEYWORD_NOT_NS); + return NULL; + } + } + pn = QualifiedSuffix(cx, ts, pn, tc); + if (!pn) + return NULL; + break; + } +#endif + + /* Unqualified __parent__ and __proto__ uses require activations. */ + if (pn->pn_atom == cx->runtime->atomState.parentAtom || + pn->pn_atom == cx->runtime->atomState.protoAtom) { + tc->flags |= TCF_FUN_HEAVYWEIGHT; + } + } + break; + + case TOK_REGEXP: + { + JSObject *obj; + + pn = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn) + return NULL; + + /* Token stream ensures that tokenbuf is NUL-terminated. */ + JS_ASSERT(*ts->tokenbuf.ptr == (jschar) 0); + obj = js_NewRegExpObject(cx, ts, + ts->tokenbuf.base, + ts->tokenbuf.ptr - ts->tokenbuf.base, + CURRENT_TOKEN(ts).t_reflags); + if (!obj) + return NULL; + if (!(tc->flags & TCF_COMPILE_N_GO)) { + STOBJ_CLEAR_PARENT(obj); + STOBJ_CLEAR_PROTO(obj); + } + + pn->pn_pob = js_NewParsedObjectBox(cx, tc->parseContext, obj); + if (!pn->pn_pob) + return NULL; + + pn->pn_op = JSOP_REGEXP; + break; + } + + case TOK_NUMBER: + pn = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn) + return NULL; + pn->pn_op = JSOP_DOUBLE; + pn->pn_dval = CURRENT_TOKEN(ts).t_dval; +#if JS_HAS_SHARP_VARS + notsharp = JS_TRUE; +#endif + break; + + case TOK_PRIMARY: + pn = NewParseNode(cx, ts, PN_NULLARY, tc); + if (!pn) + return NULL; + pn->pn_op = CURRENT_TOKEN(ts).t_op; +#if JS_HAS_SHARP_VARS + notsharp = JS_TRUE; +#endif + break; + + case TOK_ERROR: + /* The scanner or one of its subroutines reported the error. */ + return NULL; + + default: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); + return NULL; + } + +#if JS_HAS_SHARP_VARS + if (defsharp) { + if (notsharp) { + badsharp: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_SHARP_VAR_DEF); + return NULL; + } + defsharp->pn_kid = pn; + return defsharp; + } +#endif + return pn; +} + +static JSParseNode * +ParenExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSParseNode *pn1, JSBool *genexp) +{ + JSTokenPtr begin; + JSParseNode *pn; +#if JS_HAS_GENERATOR_EXPRS + uintN oldflags = tc->flags; +#endif + + JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_LP); + begin = CURRENT_TOKEN(ts).pos.begin; + + if (genexp) + *genexp = JS_FALSE; + pn = BracketedExpr(cx, ts, tc); + if (!pn) + return NULL; + +#if JS_HAS_GENERATOR_EXPRS + if (js_MatchToken(cx, ts, TOK_FOR)) { + if (pn->pn_type == TOK_YIELD) { + js_ReportCompileErrorNumber(cx, ts, pn, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_yield_str); + return NULL; + } + if (pn->pn_type == TOK_COMMA) { + js_ReportCompileErrorNumber(cx, ts, PN_LAST(pn), JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_generator_str); + return NULL; + } + if (!pn1) { + pn1 = NewParseNode(cx, ts, PN_UNARY, tc); + if (!pn1) + return NULL; + } + pn->pn_pos.begin = begin; + pn = GeneratorExpr(cx, ts, tc, oldflags, pn1, pn); + if (!pn) + return NULL; + if (genexp) { + if (js_GetToken(cx, ts) != TOK_RP) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_generator_str); + return NULL; + } + pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + *genexp = JS_TRUE; + } + } +#endif /* JS_HAS_GENERATOR_EXPRS */ + + return pn; +} + +/* + * Fold from one constant type to another. + * XXX handles only strings and numbers for now + */ +static JSBool +FoldType(JSContext *cx, JSParseNode *pn, JSTokenType type) +{ + if (pn->pn_type != type) { + switch (type) { + case TOK_NUMBER: + if (pn->pn_type == TOK_STRING) { + jsdouble d; + if (!JS_ValueToNumber(cx, ATOM_KEY(pn->pn_atom), &d)) + return JS_FALSE; + pn->pn_dval = d; + pn->pn_type = TOK_NUMBER; + pn->pn_op = JSOP_DOUBLE; + } + break; + + case TOK_STRING: + if (pn->pn_type == TOK_NUMBER) { + JSString *str = js_NumberToString(cx, pn->pn_dval); + if (!str) + return JS_FALSE; + pn->pn_atom = js_AtomizeString(cx, str, 0); + if (!pn->pn_atom) + return JS_FALSE; + pn->pn_type = TOK_STRING; + pn->pn_op = JSOP_STRING; + } + break; + + default:; + } + } + return JS_TRUE; +} + +/* + * Fold two numeric constants. Beware that pn1 and pn2 are recycled, unless + * one of them aliases pn, so you can't safely fetch pn2->pn_next, e.g., after + * a successful call to this function. + */ +static JSBool +FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2, + JSParseNode *pn, JSTreeContext *tc) +{ + jsdouble d, d2; + int32 i, j; + + JS_ASSERT(pn1->pn_type == TOK_NUMBER && pn2->pn_type == TOK_NUMBER); + d = pn1->pn_dval; + d2 = pn2->pn_dval; + switch (op) { + case JSOP_LSH: + case JSOP_RSH: + i = js_DoubleToECMAInt32(d); + j = js_DoubleToECMAInt32(d2); + j &= 31; + d = (op == JSOP_LSH) ? i << j : i >> j; + break; + + case JSOP_URSH: + j = js_DoubleToECMAInt32(d2); + j &= 31; + d = js_DoubleToECMAUint32(d) >> j; + break; + + case JSOP_ADD: + d += d2; + break; + + case JSOP_SUB: + d -= d2; + break; + + case JSOP_MUL: + d *= d2; + break; + + case JSOP_DIV: + if (d2 == 0) { +#if defined(XP_WIN) + /* XXX MSVC miscompiles such that (NaN == 0) */ + if (JSDOUBLE_IS_NaN(d2)) + d = *cx->runtime->jsNaN; + else +#endif + if (d == 0 || JSDOUBLE_IS_NaN(d)) + d = *cx->runtime->jsNaN; + else if ((JSDOUBLE_HI32(d) ^ JSDOUBLE_HI32(d2)) >> 31) + d = *cx->runtime->jsNegativeInfinity; + else + d = *cx->runtime->jsPositiveInfinity; + } else { + d /= d2; + } + break; + + case JSOP_MOD: + if (d2 == 0) { + d = *cx->runtime->jsNaN; + } else { +#if defined(XP_WIN) + /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */ + if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2))) +#endif + d = fmod(d, d2); + } + break; + + default:; + } + + /* Take care to allow pn1 or pn2 to alias pn. */ + if (pn1 != pn) + RecycleTree(pn1, tc); + if (pn2 != pn) + RecycleTree(pn2, tc); + pn->pn_type = TOK_NUMBER; + pn->pn_op = JSOP_DOUBLE; + pn->pn_arity = PN_NULLARY; + pn->pn_dval = d; + return JS_TRUE; +} + +#if JS_HAS_XML_SUPPORT + +static JSBool +FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) +{ + JSTokenType tt; + JSParseNode **pnp, *pn1, *pn2; + JSString *accum, *str; + uint32 i, j; + JSTempValueRooter tvr; + + JS_ASSERT(pn->pn_arity == PN_LIST); + tt = PN_TYPE(pn); + pnp = &pn->pn_head; + pn1 = *pnp; + accum = NULL; + if ((pn->pn_extra & PNX_CANTFOLD) == 0) { + if (tt == TOK_XMLETAGO) + accum = ATOM_TO_STRING(cx->runtime->atomState.etagoAtom); + else if (tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) + accum = ATOM_TO_STRING(cx->runtime->atomState.stagoAtom); + } + + /* + * GC Rooting here is tricky: for most of the loop, |accum| is safe via + * the newborn string root. However, when |pn2->pn_type| is TOK_XMLCDATA, + * TOK_XMLCOMMENT, or TOK_XMLPI it is knocked out of the newborn root. + * Therefore, we have to add additonal protection from GC nesting under + * js_ConcatStrings. + */ + for (pn2 = pn1, i = j = 0; pn2; pn2 = pn2->pn_next, i++) { + /* The parser already rejected end-tags with attributes. */ + JS_ASSERT(tt != TOK_XMLETAGO || i == 0); + switch (pn2->pn_type) { + case TOK_XMLATTR: + if (!accum) + goto cantfold; + /* FALL THROUGH */ + case TOK_XMLNAME: + case TOK_XMLSPACE: + case TOK_XMLTEXT: + case TOK_STRING: + if (pn2->pn_arity == PN_LIST) + goto cantfold; + str = ATOM_TO_STRING(pn2->pn_atom); + break; + + case TOK_XMLCDATA: + str = js_MakeXMLCDATAString(cx, ATOM_TO_STRING(pn2->pn_atom)); + if (!str) + return JS_FALSE; + break; + + case TOK_XMLCOMMENT: + str = js_MakeXMLCommentString(cx, ATOM_TO_STRING(pn2->pn_atom)); + if (!str) + return JS_FALSE; + break; + + case TOK_XMLPI: + str = js_MakeXMLPIString(cx, ATOM_TO_STRING(pn2->pn_atom), + ATOM_TO_STRING(pn2->pn_atom2)); + if (!str) + return JS_FALSE; + break; + + cantfold: + default: + JS_ASSERT(*pnp == pn1); + if ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && + (i & 1) ^ (j & 1)) { +#ifdef DEBUG_brendanXXX + printf("1: %d, %d => ", i, j); + if (accum) + js_FileEscapedString(stdout, accum, 0); + else + fputs("NULL", stdout); + fputc('\n', stdout); +#endif + } else if (accum && pn1 != pn2) { + while (pn1->pn_next != pn2) { + pn1 = RecycleTree(pn1, tc); + --pn->pn_count; + } + pn1->pn_type = TOK_XMLTEXT; + pn1->pn_op = JSOP_STRING; + pn1->pn_arity = PN_NULLARY; + pn1->pn_atom = js_AtomizeString(cx, accum, 0); + if (!pn1->pn_atom) + return JS_FALSE; + JS_ASSERT(pnp != &pn1->pn_next); + *pnp = pn1; + } + pnp = &pn2->pn_next; + pn1 = *pnp; + accum = NULL; + continue; + } + + if (accum) { + JS_PUSH_TEMP_ROOT_STRING(cx, accum, &tvr); + str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) + ? js_AddAttributePart(cx, i & 1, accum, str) + : js_ConcatStrings(cx, accum, str); + JS_POP_TEMP_ROOT(cx, &tvr); + if (!str) + return JS_FALSE; +#ifdef DEBUG_brendanXXX + printf("2: %d, %d => ", i, j); + js_FileEscapedString(stdout, str, 0); + printf(" (%u)\n", JSSTRING_LENGTH(str)); +#endif + ++j; + } + accum = str; + } + + if (accum) { + str = NULL; + if ((pn->pn_extra & PNX_CANTFOLD) == 0) { + if (tt == TOK_XMLPTAGC) + str = ATOM_TO_STRING(cx->runtime->atomState.ptagcAtom); + else if (tt == TOK_XMLSTAGO || tt == TOK_XMLETAGO) + str = ATOM_TO_STRING(cx->runtime->atomState.tagcAtom); + } + if (str) { + accum = js_ConcatStrings(cx, accum, str); + if (!accum) + return JS_FALSE; + } + + JS_ASSERT(*pnp == pn1); + while (pn1->pn_next) { + pn1 = RecycleTree(pn1, tc); + --pn->pn_count; + } + pn1->pn_type = TOK_XMLTEXT; + pn1->pn_op = JSOP_STRING; + pn1->pn_arity = PN_NULLARY; + pn1->pn_atom = js_AtomizeString(cx, accum, 0); + if (!pn1->pn_atom) + return JS_FALSE; + JS_ASSERT(pnp != &pn1->pn_next); + *pnp = pn1; + } + + if (pn1 && pn->pn_count == 1) { + /* + * Only one node under pn, and it has been folded: move pn1 onto pn + * unless pn is an XML root (in which case we need it to tell the code + * generator to emit a JSOP_TOXML or JSOP_TOXMLLIST op). If pn is an + * XML root *and* it's a point-tag, rewrite it to TOK_XMLELEM to avoid + * extra "<" and "/>" bracketing at runtime. + */ + if (!(pn->pn_extra & PNX_XMLROOT)) { + PN_MOVE_NODE(pn, pn1); + } else if (tt == TOK_XMLPTAGC) { + pn->pn_type = TOK_XMLELEM; + pn->pn_op = JSOP_TOXML; + } + } + return JS_TRUE; +} + +#endif /* JS_HAS_XML_SUPPORT */ + +static JSBool +StartsWith(JSParseNode *pn, JSTokenType tt) +{ +#define TAIL_RECURSE(pn2) JS_BEGIN_MACRO pn = (pn2); goto recur; JS_END_MACRO + +recur: + if (pn->pn_type == tt) + return JS_TRUE; + switch (pn->pn_arity) { + case PN_FUNC: + return tt == TOK_FUNCTION; + case PN_LIST: + if (pn->pn_head) + TAIL_RECURSE(pn->pn_head); + break; + case PN_TERNARY: + if (pn->pn_kid1) + TAIL_RECURSE(pn->pn_kid1); + break; + case PN_BINARY: + if (pn->pn_left) + TAIL_RECURSE(pn->pn_left); + break; + case PN_UNARY: + /* A parenthesized expression starts with a left parenthesis. */ + if (pn->pn_type == TOK_RP) + return tt == TOK_LP; + if (pn->pn_kid) + TAIL_RECURSE(pn->pn_kid); + break; + case PN_NAME: + if (pn->pn_type == TOK_DOT || pn->pn_type == TOK_DBLDOT) + TAIL_RECURSE(pn->pn_expr); + /* FALL THROUGH */ + } + return JS_FALSE; +#undef TAIL_RECURSE +} + +static int +Boolish(JSParseNode *pn) +{ + switch (pn->pn_op) { + case JSOP_DOUBLE: + return pn->pn_dval != 0 && !JSDOUBLE_IS_NaN(pn->pn_dval); + + case JSOP_STRING: + return JSSTRING_LENGTH(ATOM_TO_STRING(pn->pn_atom)) != 0; + +#if JS_HAS_GENERATOR_EXPRS + case JSOP_CALL: + { + /* + * A generator expression as an if or loop condition has no effects, it + * simply results in a truthy object reference. This condition folding + * is needed for the decompiler. See bug 442342 and bug 443074. + */ + if (pn->pn_count != 1) + break; + JSParseNode *pn2 = pn->pn_head; + if (pn2->pn_type != TOK_FUNCTION) + break; + if (!(pn2->pn_flags & TCF_GENEXP_LAMBDA)) + break; + /* FALL THROUGH */ + } +#endif + + case JSOP_DEFFUN: + case JSOP_NAMEDFUNOBJ: + case JSOP_ANONFUNOBJ: + case JSOP_THIS: + case JSOP_TRUE: + return 1; + + case JSOP_NULL: + case JSOP_FALSE: + return 0; + + default:; + } + return -1; +} + +JSBool +js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) +{ + JSParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL; + + JS_CHECK_RECURSION(cx, return JS_FALSE); + + switch (pn->pn_arity) { + case PN_FUNC: + { + uint16 oldflags = tc->flags; + + tc->flags = (uint16) pn->pn_flags; + if (!js_FoldConstants(cx, pn->pn_body, tc)) + return JS_FALSE; + tc->flags = oldflags; + break; + } + + case PN_LIST: + { + /* Propagate inCond through logical connectives. */ + bool cond = inCond && (pn->pn_type == TOK_OR || pn->pn_type == TOK_AND); + + /* Save the list head in pn1 for later use. */ + for (pn1 = pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (!js_FoldConstants(cx, pn2, tc, cond)) + return JS_FALSE; + } + break; + } + + case PN_TERNARY: + /* Any kid may be null (e.g. for (;;)). */ + pn1 = pn->pn_kid1; + pn2 = pn->pn_kid2; + pn3 = pn->pn_kid3; + if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->pn_type == TOK_IF)) + return JS_FALSE; + if (pn2) { + if (!js_FoldConstants(cx, pn2, tc, pn->pn_type == TOK_FORHEAD)) + return JS_FALSE; + if (pn->pn_type == TOK_FORHEAD && pn2->pn_op == JSOP_TRUE) { + RecycleTree(pn2, tc); + pn->pn_kid2 = NULL; + } + } + if (pn3 && !js_FoldConstants(cx, pn3, tc)) + return JS_FALSE; + break; + + case PN_BINARY: + pn1 = pn->pn_left; + pn2 = pn->pn_right; + + /* Propagate inCond through logical connectives. */ + if (pn->pn_type == TOK_OR || pn->pn_type == TOK_AND) { + if (!js_FoldConstants(cx, pn1, tc, inCond)) + return JS_FALSE; + if (!js_FoldConstants(cx, pn2, tc, inCond)) + return JS_FALSE; + break; + } + + /* First kid may be null (for default case in switch). */ + if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->pn_type == TOK_WHILE)) + return JS_FALSE; + if (!js_FoldConstants(cx, pn2, tc, pn->pn_type == TOK_DO)) + return JS_FALSE; + break; + + case PN_UNARY: + /* Our kid may be null (e.g. return; vs. return e;). */ + pn1 = pn->pn_kid; + if (pn1 && + !js_FoldConstants(cx, pn1, tc, + (inCond && pn->pn_type == TOK_RP) || + pn->pn_op == JSOP_NOT)) { + return JS_FALSE; + } + break; + + case PN_NAME: + /* + * Skip pn1 down along a chain of dotted member expressions to avoid + * excessive recursion. Our only goal here is to fold constants (if + * any) in the primary expression operand to the left of the first + * dot in the chain. + */ + pn1 = pn->pn_expr; + while (pn1 && pn1->pn_arity == PN_NAME) + pn1 = pn1->pn_expr; + if (pn1 && !js_FoldConstants(cx, pn1, tc)) + return JS_FALSE; + break; + + case PN_NULLARY: + break; + } + + switch (pn->pn_type) { + case TOK_IF: + if (ContainsStmt(pn2, TOK_VAR) || ContainsStmt(pn3, TOK_VAR)) + break; + /* FALL THROUGH */ + + case TOK_HOOK: + /* Reduce 'if (C) T; else E' into T for true C, E for false. */ + while (pn1->pn_type == TOK_RP) + pn1 = pn1->pn_kid; + switch (pn1->pn_type) { + case TOK_NUMBER: + if (pn1->pn_dval == 0 || JSDOUBLE_IS_NaN(pn1->pn_dval)) + pn2 = pn3; + break; + case TOK_STRING: + if (JSSTRING_LENGTH(ATOM_TO_STRING(pn1->pn_atom)) == 0) + pn2 = pn3; + break; + case TOK_PRIMARY: + if (pn1->pn_op == JSOP_TRUE) + break; + if (pn1->pn_op == JSOP_FALSE || pn1->pn_op == JSOP_NULL) { + pn2 = pn3; + break; + } + /* FALL THROUGH */ + default: + /* Early return to dodge common code that copies pn2 to pn. */ + return JS_TRUE; + } + +#if JS_HAS_GENERATOR_EXPRS + /* Don't fold a trailing |if (0)| in a generator expression. */ + if (!pn2 && (tc->flags & TCF_GENEXP_LAMBDA)) + break; +#endif + + if (pn2) { + /* + * pn2 is the then- or else-statement subtree to compile. Take + * care not to expose an object initialiser, which would be parsed + * as a block, to the Statement parser via eval(uneval(e)) where e + * is '1 ? {p:2, q:3}[i] : r;' or the like. + */ + if (pn->pn_type == TOK_HOOK && StartsWith(pn2, TOK_RC)) { + pn->pn_type = TOK_RP; + pn->pn_arity = PN_UNARY; + pn->pn_kid = pn2; + if (pn3 && pn3 != pn2) + RecycleTree(pn3, tc); + break; + } + PN_MOVE_NODE(pn, pn2); + } + if (!pn2 || (pn->pn_type == TOK_SEMI && !pn->pn_kid)) { + /* + * False condition and no else, or an empty then-statement was + * moved up over pn. Either way, make pn an empty block (not an + * empty statement, which does not decompile, even when labeled). + * NB: pn must be a TOK_IF as TOK_HOOK can never have a null kid + * or an empty statement for a child. + */ + pn->pn_type = TOK_LC; + pn->pn_arity = PN_LIST; + PN_INIT_LIST(pn); + } + RecycleTree(pn2, tc); + if (pn3 && pn3 != pn2) + RecycleTree(pn3, tc); + break; + + case TOK_OR: + case TOK_AND: + if (inCond) { + if (pn->pn_arity == PN_LIST) { + JSParseNode **pnp = &pn->pn_head; + JS_ASSERT(*pnp == pn1); + do { + int cond = Boolish(pn1); + if (cond == (pn->pn_type == TOK_OR)) { + for (pn2 = pn1->pn_next; pn2; pn2 = pn3) { + pn3 = pn2->pn_next; + RecycleTree(pn2, tc); + --pn->pn_count; + } + pn1->pn_next = NULL; + break; + } + if (cond != -1) { + JS_ASSERT(cond == (pn->pn_type == TOK_AND)); + if (pn->pn_count == 1) + break; + *pnp = pn1->pn_next; + RecycleTree(pn1, tc); + --pn->pn_count; + } else { + pnp = &pn1->pn_next; + } + } while ((pn1 = *pnp) != NULL); + + // We may have to change arity from LIST to BINARY. + pn1 = pn->pn_head; + if (pn->pn_count == 2) { + pn2 = pn1->pn_next; + pn1->pn_next = NULL; + JS_ASSERT(!pn2->pn_next); + pn->pn_arity = PN_BINARY; + pn->pn_left = pn1; + pn->pn_right = pn2; + } else if (pn->pn_count == 1) { + PN_MOVE_NODE(pn, pn1); + RecycleTree(pn1, tc); + } + } else { + int cond = Boolish(pn1); + if (cond == (pn->pn_type == TOK_OR)) { + RecycleTree(pn2, tc); + PN_MOVE_NODE(pn, pn1); + } else if (cond != -1) { + JS_ASSERT(cond == (pn->pn_type == TOK_AND)); + RecycleTree(pn1, tc); + PN_MOVE_NODE(pn, pn2); + } + } + } + break; + + case TOK_ASSIGN: + /* + * Compound operators such as *= should be subject to folding, in case + * the left-hand side is constant, and so that the decompiler produces + * the same string that you get from decompiling a script or function + * compiled from that same string. As with +, += is special. + */ + if (pn->pn_op == JSOP_NOP) + break; + if (pn->pn_op != JSOP_ADD) + goto do_binary_op; + /* FALL THROUGH */ + + case TOK_PLUS: + if (pn->pn_arity == PN_LIST) { + size_t length, length2; + jschar *chars; + JSString *str, *str2; + + /* + * Any string literal term with all others number or string means + * this is a concatenation. If any term is not a string or number + * literal, we can't fold. + */ + JS_ASSERT(pn->pn_count > 2); + if (pn->pn_extra & PNX_CANTFOLD) + return JS_TRUE; + if (pn->pn_extra != PNX_STRCAT) + goto do_binary_op; + + /* Ok, we're concatenating: convert non-string constant operands. */ + length = 0; + for (pn2 = pn1; pn2; pn2 = pn2->pn_next) { + if (!FoldType(cx, pn2, TOK_STRING)) + return JS_FALSE; + /* XXX fold only if all operands convert to string */ + if (pn2->pn_type != TOK_STRING) + return JS_TRUE; + length += JSFLATSTR_LENGTH(ATOM_TO_STRING(pn2->pn_atom)); + } + + /* Allocate a new buffer and string descriptor for the result. */ + chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar)); + if (!chars) + return JS_FALSE; + str = js_NewString(cx, chars, length); + if (!str) { + JS_free(cx, chars); + return JS_FALSE; + } + + /* Fill the buffer, advancing chars and recycling kids as we go. */ + for (pn2 = pn1; pn2; pn2 = RecycleTree(pn2, tc)) { + str2 = ATOM_TO_STRING(pn2->pn_atom); + length2 = JSFLATSTR_LENGTH(str2); + js_strncpy(chars, JSFLATSTR_CHARS(str2), length2); + chars += length2; + } + *chars = 0; + + /* Atomize the result string and mutate pn to refer to it. */ + pn->pn_atom = js_AtomizeString(cx, str, 0); + if (!pn->pn_atom) + return JS_FALSE; + pn->pn_type = TOK_STRING; + pn->pn_op = JSOP_STRING; + pn->pn_arity = PN_NULLARY; + break; + } + + /* Handle a binary string concatenation. */ + JS_ASSERT(pn->pn_arity == PN_BINARY); + if (pn1->pn_type == TOK_STRING || pn2->pn_type == TOK_STRING) { + JSString *left, *right, *str; + + if (!FoldType(cx, (pn1->pn_type != TOK_STRING) ? pn1 : pn2, + TOK_STRING)) { + return JS_FALSE; + } + if (pn1->pn_type != TOK_STRING || pn2->pn_type != TOK_STRING) + return JS_TRUE; + left = ATOM_TO_STRING(pn1->pn_atom); + right = ATOM_TO_STRING(pn2->pn_atom); + str = js_ConcatStrings(cx, left, right); + if (!str) + return JS_FALSE; + pn->pn_atom = js_AtomizeString(cx, str, 0); + if (!pn->pn_atom) + return JS_FALSE; + pn->pn_type = TOK_STRING; + pn->pn_op = JSOP_STRING; + pn->pn_arity = PN_NULLARY; + RecycleTree(pn1, tc); + RecycleTree(pn2, tc); + break; + } + + /* Can't concatenate string literals, let's try numbers. */ + goto do_binary_op; + + case TOK_STAR: + case TOK_SHOP: + case TOK_MINUS: + case TOK_DIVOP: + do_binary_op: + if (pn->pn_arity == PN_LIST) { + JS_ASSERT(pn->pn_count > 2); + for (pn2 = pn1; pn2; pn2 = pn2->pn_next) { + if (!FoldType(cx, pn2, TOK_NUMBER)) + return JS_FALSE; + } + for (pn2 = pn1; pn2; pn2 = pn2->pn_next) { + /* XXX fold only if all operands convert to number */ + if (pn2->pn_type != TOK_NUMBER) + break; + } + if (!pn2) { + JSOp op = PN_OP(pn); + + pn2 = pn1->pn_next; + pn3 = pn2->pn_next; + if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn, tc)) + return JS_FALSE; + while ((pn2 = pn3) != NULL) { + pn3 = pn2->pn_next; + if (!FoldBinaryNumeric(cx, op, pn, pn2, pn, tc)) + return JS_FALSE; + } + } + } else { + JS_ASSERT(pn->pn_arity == PN_BINARY); + if (!FoldType(cx, pn1, TOK_NUMBER) || + !FoldType(cx, pn2, TOK_NUMBER)) { + return JS_FALSE; + } + if (pn1->pn_type == TOK_NUMBER && pn2->pn_type == TOK_NUMBER) { + if (!FoldBinaryNumeric(cx, PN_OP(pn), pn1, pn2, pn, tc)) + return JS_FALSE; + } + } + break; + + case TOK_UNARYOP: + while (pn1->pn_type == TOK_RP) + pn1 = pn1->pn_kid; + if (pn1->pn_type == TOK_NUMBER) { + jsdouble d; + + /* Operate on one numeric constant. */ + d = pn1->pn_dval; + switch (pn->pn_op) { + case JSOP_BITNOT: + d = ~js_DoubleToECMAInt32(d); + break; + + case JSOP_NEG: +#ifdef HPUX + /* + * Negation of a zero doesn't produce a negative + * zero on HPUX. Perform the operation by bit + * twiddling. + */ + JSDOUBLE_HI32(d) ^= JSDOUBLE_HI32_SIGNBIT; +#else + d = -d; +#endif + break; + + case JSOP_POS: + break; + + case JSOP_NOT: + pn->pn_type = TOK_PRIMARY; + pn->pn_op = (d == 0 || JSDOUBLE_IS_NaN(d)) ? JSOP_TRUE : JSOP_FALSE; + pn->pn_arity = PN_NULLARY; + /* FALL THROUGH */ + + default: + /* Return early to dodge the common TOK_NUMBER code. */ + return JS_TRUE; + } + pn->pn_type = TOK_NUMBER; + pn->pn_op = JSOP_DOUBLE; + pn->pn_arity = PN_NULLARY; + pn->pn_dval = d; + RecycleTree(pn1, tc); + } else if (pn1->pn_type == TOK_PRIMARY) { + if (pn->pn_op == JSOP_NOT && + (pn1->pn_op == JSOP_TRUE || + pn1->pn_op == JSOP_FALSE)) { + PN_MOVE_NODE(pn, pn1); + pn->pn_op = (pn->pn_op == JSOP_TRUE) ? JSOP_FALSE : JSOP_TRUE; + RecycleTree(pn1, tc); + } + } + break; + +#if JS_HAS_XML_SUPPORT + case TOK_XMLELEM: + case TOK_XMLLIST: + case TOK_XMLPTAGC: + case TOK_XMLSTAGO: + case TOK_XMLETAGO: + case TOK_XMLNAME: + if (pn->pn_arity == PN_LIST) { + JS_ASSERT(pn->pn_type == TOK_XMLLIST || pn->pn_count != 0); + if (!FoldXMLConstants(cx, pn, tc)) + return JS_FALSE; + } + break; + + case TOK_AT: + if (pn1->pn_type == TOK_XMLNAME) { + jsval v; + JSParsedObjectBox *xmlpob; + + v = ATOM_KEY(pn1->pn_atom); + if (!js_ToAttributeName(cx, &v)) + return JS_FALSE; + JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + + xmlpob = js_NewParsedObjectBox(cx, tc->parseContext, + JSVAL_TO_OBJECT(v)); + if (!xmlpob) + return JS_FALSE; + + pn->pn_type = TOK_XMLNAME; + pn->pn_op = JSOP_OBJECT; + pn->pn_arity = PN_NULLARY; + pn->pn_pob = xmlpob; + RecycleTree(pn1, tc); + } + break; +#endif /* JS_HAS_XML_SUPPORT */ + + default:; + } + + if (inCond) { + int cond = Boolish(pn); + if (cond >= 0) { + if (pn->pn_arity == PN_LIST) { + pn2 = pn->pn_head; + do { + pn3 = pn2->pn_next; + RecycleTree(pn2, tc); + } while ((pn2 = pn3) != NULL); + } + pn->pn_type = TOK_PRIMARY; + pn->pn_op = cond ? JSOP_TRUE : JSOP_FALSE; + pn->pn_arity = PN_NULLARY; + } + } + + return JS_TRUE; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsparse.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsparse.h new file mode 100644 index 0000000..90499db --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsparse.h @@ -0,0 +1,508 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsparse_h___ +#define jsparse_h___ +/* + * JS parser definitions. + */ +#include "jsversion.h" +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsscan.h" + +JS_BEGIN_EXTERN_C + +/* + * Parsing builds a tree of nodes that directs code generation. This tree is + * not a concrete syntax tree in all respects (for example, || and && are left + * associative, but (A && B && C) translates into the right-associated tree + * > so that code generation can emit a left-associative branch + * around when A is false). Nodes are labeled by token type, with a + * JSOp secondary label when needed: + * + * Label Variant Members + * ----- ------- ------- + * + * TOK_FUNCTION func pn_funpob: JSParsedObjectBox holding function + * object containing arg and var properties. We + * create the function object at parse (not emit) + * time to specialize arg and var bytecodes early. + * pn_body: TOK_LC node for function body statements + * pn_flags: TCF_FUN_* flags (see jsemit.h) collected + * while parsing the function's body + * + * + * TOK_LC list pn_head: list of pn_count statements + * TOK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null + * TOK_SWITCH binary pn_left: discriminant + * pn_right: list of TOK_CASE nodes, with at most one + * TOK_DEFAULT node, or if there are let bindings + * in the top level of the switch body's cases, a + * TOK_LEXICALSCOPE node that contains the list of + * TOK_CASE nodes. + * TOK_CASE, binary pn_left: case expr or null if TOK_DEFAULT + * TOK_DEFAULT pn_right: TOK_LC node for this case's statements + * pn_val: constant value if lookup or table switch + * TOK_WHILE binary pn_left: cond, pn_right: body + * TOK_DO binary pn_left: body, pn_right: cond + * TOK_FOR binary pn_left: either + * for/in loop: a binary TOK_IN node with + * pn_left: TOK_VAR or TOK_NAME to left of 'in' + * if TOK_VAR, its pn_extra may have PNX_POPVAR + * and PNX_FORINVAR bits set + * pn_right: object expr to right of 'in' + * for(;;) loop: a ternary TOK_RESERVED node with + * pn_kid1: init expr before first ';' + * pn_kid2: cond expr before second ';' + * pn_kid3: update expr after second ';' + * any kid may be null + * pn_right: body + * TOK_THROW unary pn_op: JSOP_THROW, pn_kid: exception + * TOK_TRY ternary pn_kid1: try block + * pn_kid2: null or TOK_RESERVED list of + * TOK_LEXICALSCOPE nodes, each with pn_expr pointing + * to a TOK_CATCH node + * pn_kid3: null or finally block + * TOK_CATCH ternary pn_kid1: TOK_NAME, TOK_RB, or TOK_RC catch var node + * (TOK_RB or TOK_RC if destructuring) + * pn_kid2: null or the catch guard expression + * pn_kid3: catch block statements + * TOK_BREAK name pn_atom: label or null + * TOK_CONTINUE name pn_atom: label or null + * TOK_WITH binary pn_left: head expr, pn_right: body + * TOK_VAR list pn_head: list of pn_count TOK_NAME nodes + * each name node has + * pn_atom: variable name + * pn_expr: initializer or null + * TOK_RETURN unary pn_kid: return expr or null + * TOK_SEMI unary pn_kid: expr or null statement + * TOK_COLON name pn_atom: label, pn_expr: labeled statement + * + * + * All left-associated binary trees of the same type are optimized into lists + * to avoid recursion when processing expression chains. + * TOK_COMMA list pn_head: list of pn_count comma-separated exprs + * TOK_ASSIGN binary pn_left: lvalue, pn_right: rvalue + * pn_op: JSOP_ADD for +=, etc. + * TOK_HOOK ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else + * TOK_OR binary pn_left: first in || chain, pn_right: rest of chain + * TOK_AND binary pn_left: first in && chain, pn_right: rest of chain + * TOK_BITOR binary pn_left: left-assoc | expr, pn_right: ^ expr + * TOK_BITXOR binary pn_left: left-assoc ^ expr, pn_right: & expr + * TOK_BITAND binary pn_left: left-assoc & expr, pn_right: EQ expr + * TOK_EQOP binary pn_left: left-assoc EQ expr, pn_right: REL expr + * pn_op: JSOP_EQ, JSOP_NE, + * JSOP_STRICTEQ, JSOP_STRICTNE + * TOK_RELOP binary pn_left: left-assoc REL expr, pn_right: SH expr + * pn_op: JSOP_LT, JSOP_LE, JSOP_GT, JSOP_GE + * TOK_SHOP binary pn_left: left-assoc SH expr, pn_right: ADD expr + * pn_op: JSOP_LSH, JSOP_RSH, JSOP_URSH + * TOK_PLUS, binary pn_left: left-assoc ADD expr, pn_right: MUL expr + * pn_extra: if a left-associated binary TOK_PLUS + * tree has been flattened into a list (see above + * under ), pn_extra will contain + * PNX_STRCAT if at least one list element is a + * string literal (TOK_STRING); if such a list has + * any non-string, non-number term, pn_extra will + * contain PNX_CANTFOLD. + * pn_ + * TOK_MINUS pn_op: JSOP_ADD, JSOP_SUB + * TOK_STAR, binary pn_left: left-assoc MUL expr, pn_right: UNARY expr + * TOK_DIVOP pn_op: JSOP_MUL, JSOP_DIV, JSOP_MOD + * TOK_UNARYOP unary pn_kid: UNARY expr, pn_op: JSOP_NEG, JSOP_POS, + * JSOP_NOT, JSOP_BITNOT, JSOP_TYPEOF, JSOP_VOID + * TOK_INC, unary pn_kid: MEMBER expr + * TOK_DEC + * TOK_NEW list pn_head: list of ctor, arg1, arg2, ... argN + * pn_count: 1 + N (where N is number of args) + * ctor is a MEMBER expr + * TOK_DELETE unary pn_kid: MEMBER expr + * TOK_DOT, name pn_expr: MEMBER expr to left of . + * TOK_DBLDOT pn_atom: name to right of . + * TOK_LB binary pn_left: MEMBER expr to left of [ + * pn_right: expr between [ and ] + * TOK_LP list pn_head: list of call, arg1, arg2, ... argN + * pn_count: 1 + N (where N is number of args) + * call is a MEMBER expr naming a callable object + * TOK_RB list pn_head: list of pn_count array element exprs + * [,,] holes are represented by TOK_COMMA nodes + * #n=[...] produces TOK_DEFSHARP at head of list + * pn_extra: PN_ENDCOMMA if extra comma at end + * TOK_RC list pn_head: list of pn_count TOK_COLON nodes where + * each has pn_left: property id, pn_right: value + * #n={...} produces TOK_DEFSHARP at head of list + * var {x} = object destructuring shorthand shares + * PN_NAME node for x on left and right of TOK_COLON + * node in TOK_RC's list, has PNX_SHORTHAND flag + * TOK_DEFSHARP unary pn_num: jsint value of n in #n= + * pn_kid: null for #n=[...] and #n={...}, primary + * if #n=primary for function, paren, name, object + * literal expressions + * TOK_USESHARP nullary pn_num: jsint value of n in #n# + * TOK_RP unary pn_kid: parenthesized expression + * TOK_NAME, name pn_atom: name, string, or object atom + * TOK_STRING, pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT, or + * JSOP_REGEXP + * TOK_REGEXP If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR + * with pn_slot >= 0 and pn_const telling const-ness + * TOK_NUMBER dval pn_dval: double value of numeric literal + * TOK_PRIMARY nullary pn_op: JSOp bytecode + * + * + * TOK_ANYNAME nullary pn_op: JSOP_ANYNAME + * pn_atom: cx->runtime->atomState.starAtom + * TOK_AT unary pn_op: JSOP_TOATTRNAME; pn_kid attribute id/expr + * TOK_DBLCOLON binary pn_op: JSOP_QNAME + * pn_left: TOK_ANYNAME or TOK_NAME node + * pn_right: TOK_STRING "*" node, or expr within [] + * name pn_op: JSOP_QNAMECONST + * pn_expr: TOK_ANYNAME or TOK_NAME left operand + * pn_atom: name on right of :: + * TOK_XMLELEM list XML element node + * pn_head: start tag, content1, ... contentN, end tag + * pn_count: 2 + N where N is number of content nodes + * N may be > x.length() if {expr} embedded + * TOK_XMLLIST list XML list node + * pn_head: content1, ... contentN + * TOK_XMLSTAGO, list XML start, end, and point tag contents + * TOK_XMLETAGC, pn_head: tag name or {expr}, ... XML attrs ... + * TOK_XMLPTAGO + * TOK_XMLNAME nullary pn_atom: XML name, with no {expr} embedded + * TOK_XMLNAME list pn_head: tag name or {expr}, ... name or {expr} + * TOK_XMLATTR, nullary pn_atom: attribute value string; pn_op: JSOP_STRING + * TOK_XMLCDATA, + * TOK_XMLCOMMENT + * TOK_XMLPI nullary pn_atom: XML processing instruction target + * pn_atom2: XML PI content, or null if no content + * TOK_XMLTEXT nullary pn_atom: marked-up text, or null if empty string + * TOK_LC unary {expr} in XML tag or content; pn_kid is expr + * + * So an XML tag with no {expr} and three attributes is a list with the form: + * + * (tagname attrname1 attrvalue1 attrname2 attrvalue2 attrname2 attrvalue3) + * + * An XML tag with embedded expressions like so: + * + * + * + * would have the form: + * + * ((name1 {expr1}) (name2 {expr2} name3) {expr3}) + * + * where () bracket a list with elements separated by spaces, and {expr} is a + * TOK_LC unary node with expr as its kid. + * + * Thus, the attribute name/value pairs occupy successive odd and even list + * locations, where pn_head is the TOK_XMLNAME node at list location 0. The + * parser builds the same sort of structures for elements: + * + * Hi there!How are you?{x + y} + * + * translates to: + * + * ((a x {x}) 'Hi there!' ((b y {y}) 'How are you?') ((answer) {x + y})) + * + * + * + * Label Variant Members + * ----- ------- ------- + * TOK_LEXICALSCOPE name pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR + * pn_pob: block object + * pn_expr: block body + * TOK_ARRAYCOMP list pn_head: list of pn_count (1 or 2) elements + * if pn_count is 2, first element is #n=[...] + * last element is block enclosing for loop(s) + * and optionally if-guarded TOK_ARRAYPUSH + * pn_extra: stack slot, used during code gen + * TOK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP + * pn_kid: array comprehension expression + */ +typedef enum JSParseNodeArity { + PN_FUNC = -3, + PN_LIST = -2, + PN_TERNARY = 3, + PN_BINARY = 2, + PN_UNARY = 1, + PN_NAME = -1, + PN_NULLARY = 0 +} JSParseNodeArity; + +struct JSParseNode { + uint16 pn_type; + uint8 pn_op; + int8 pn_arity; + JSTokenPos pn_pos; + ptrdiff_t pn_offset; /* first generated bytecode offset */ + union { + struct { /* TOK_FUNCTION node */ + JSParsedObjectBox *funpob; /* function object */ + JSParseNode *body; /* TOK_LC list of statements */ + uint16 flags; /* accumulated tree context flags */ + uint32 index; /* emitter's index */ + } func; + struct { /* list of next-linked nodes */ + JSParseNode *head; /* first node in list */ + JSParseNode **tail; /* ptr to ptr to last node in list */ + uint32 count; /* number of nodes in list */ + uint32 extra; /* extra flags, see below */ + } list; + struct { /* ternary: if, for(;;), ?: */ + JSParseNode *kid1; /* condition, discriminant, etc. */ + JSParseNode *kid2; /* then-part, case list, etc. */ + JSParseNode *kid3; /* else-part, default case, etc. */ + } ternary; + struct { /* two kids if binary */ + JSParseNode *left; + JSParseNode *right; + jsval val; /* switch case value */ + uintN iflags; /* JSITER_* flags for TOK_FOR node */ + } binary; + struct { /* one kid if unary */ + JSParseNode *kid; + jsint num; /* -1 or sharp variable number */ + JSBool hidden; /* hidden genexp-induced JSOP_YIELD */ + } unary; + struct { /* name, labeled statement, etc. */ + JSAtom *atom; /* name or label atom, null if slot */ + JSParseNode *expr; /* object or initializer */ + jsint slot; /* -1 or arg or local var slot */ + JSBool isconst; /* true for const names */ + } name; + struct { /* lexical scope. */ + JSParsedObjectBox *pob; /* block object */ + JSParseNode *expr; /* object or initializer */ + jsint slot; /* -1 or arg or local var slot */ + } lexical; + struct { + JSAtom *atom; /* first atom in pair */ + JSAtom *atom2; /* second atom in pair or null */ + } apair; + struct { /* object literal */ + JSParsedObjectBox *pob; + } object; + jsdouble dval; /* aligned numeric literal value */ + } pn_u; + JSParseNode *pn_next; /* to align dval and pn_u on RISCs */ +}; + +#define pn_funpob pn_u.func.funpob +#define pn_body pn_u.func.body +#define pn_flags pn_u.func.flags +#define pn_index pn_u.func.index +#define pn_head pn_u.list.head +#define pn_tail pn_u.list.tail +#define pn_count pn_u.list.count +#define pn_extra pn_u.list.extra +#define pn_kid1 pn_u.ternary.kid1 +#define pn_kid2 pn_u.ternary.kid2 +#define pn_kid3 pn_u.ternary.kid3 +#define pn_left pn_u.binary.left +#define pn_right pn_u.binary.right +#define pn_val pn_u.binary.val +#define pn_iflags pn_u.binary.iflags +#define pn_kid pn_u.unary.kid +#define pn_num pn_u.unary.num +#define pn_hidden pn_u.unary.hidden +#define pn_atom pn_u.name.atom +#define pn_expr pn_u.name.expr +#define pn_slot pn_u.name.slot +#define pn_const pn_u.name.isconst +#define pn_dval pn_u.dval +#define pn_atom2 pn_u.apair.atom2 +#define pn_pob pn_u.object.pob + +/* PN_LIST pn_extra flags. */ +#define PNX_STRCAT 0x01 /* TOK_PLUS list has string term */ +#define PNX_CANTFOLD 0x02 /* TOK_PLUS list has unfoldable term */ +#define PNX_POPVAR 0x04 /* TOK_VAR last result needs popping */ +#define PNX_FORINVAR 0x08 /* TOK_VAR is left kid of TOK_IN node, + which is left kid of TOK_FOR */ +#define PNX_ENDCOMMA 0x10 /* array literal has comma at end */ +#define PNX_XMLROOT 0x20 /* top-most node in XML literal tree */ +#define PNX_GROUPINIT 0x40 /* var [a, b] = [c, d]; unit list */ +#define PNX_NEEDBRACES 0x80 /* braces necessary due to closure */ +#define PNX_FUNCDEFS 0x100 /* contains top-level function + statements */ +#define PNX_SHORTHAND 0x200 /* shorthand syntax used, at present + object destructuring ({x,y}) only */ + +/* + * Move pn2 into pn, preserving pn->pn_pos and pn->pn_offset and handing off + * any kids in pn2->pn_u, by clearing pn2. + */ +#define PN_MOVE_NODE(pn, pn2) \ + JS_BEGIN_MACRO \ + (pn)->pn_type = (pn2)->pn_type; \ + (pn)->pn_op = (pn2)->pn_op; \ + (pn)->pn_arity = (pn2)->pn_arity; \ + (pn)->pn_u = (pn2)->pn_u; \ + PN_CLEAR_NODE(pn2); \ + JS_END_MACRO + +#define PN_CLEAR_NODE(pn) \ + JS_BEGIN_MACRO \ + (pn)->pn_type = TOK_EOF; \ + (pn)->pn_op = JSOP_NOP; \ + (pn)->pn_arity = PN_NULLARY; \ + JS_END_MACRO + +/* True if pn is a parsenode representing a literal constant. */ +#define PN_IS_CONSTANT(pn) \ + ((pn)->pn_type == TOK_NUMBER || \ + (pn)->pn_type == TOK_STRING || \ + ((pn)->pn_type == TOK_PRIMARY && (pn)->pn_op != JSOP_THIS)) + +#define PN_OP(pn) ((JSOp)(pn)->pn_op) +#define PN_TYPE(pn) ((JSTokenType)(pn)->pn_type) + +/* + * Compute a pointer to the last JSParseNode element in a singly-linked list. + * NB: list must be non-empty for correct PN_LAST usage! + */ +#define PN_LAST(list) \ + ((JSParseNode *)((char *)(list)->pn_tail - offsetof(JSParseNode, pn_next))) + +#define PN_INIT_LIST(list) \ + JS_BEGIN_MACRO \ + (list)->pn_head = NULL; \ + (list)->pn_tail = &(list)->pn_head; \ + (list)->pn_count = (list)->pn_extra = 0; \ + JS_END_MACRO + +#define PN_INIT_LIST_1(list, pn) \ + JS_BEGIN_MACRO \ + (list)->pn_head = (pn); \ + (list)->pn_tail = &(pn)->pn_next; \ + (list)->pn_count = 1; \ + (list)->pn_extra = 0; \ + JS_END_MACRO + +#define PN_APPEND(list, pn) \ + JS_BEGIN_MACRO \ + *(list)->pn_tail = (pn); \ + (list)->pn_tail = &(pn)->pn_next; \ + (list)->pn_count++; \ + JS_END_MACRO + +struct JSParsedObjectBox { + JSParsedObjectBox *traceLink; + JSParsedObjectBox *emitLink; + JSObject *object; +}; + +struct JSParseContext { + JSTokenStream tokenStream; + void *tempPoolMark; /* initial JSContext.tempPool mark */ + JSPrincipals *principals; /* principals associated with source */ + JSStackFrame *callerFrame; /* scripted caller frame for eval and + debug scripts */ + JSParseNode *nodeList; /* list of recyclable parse-node + structs */ + JSParsedObjectBox *traceListHead; /* list of parsed object for GC + tracing */ + JSTempValueRooter tempRoot; /* root to trace traceListHead */ +}; + +/* + * Convenience macro to access JSParseContext.tokenStream as a pointer. + */ +#define TS(pc) (&(pc)->tokenStream) + +/* + * Parse a top-level JS script. + */ +extern JSParseNode * +js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc); + +extern JSScript * +js_CompileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame, + JSPrincipals *principals, uint32 tcflags, + const jschar *chars, size_t length, + FILE *file, const char *filename, uintN lineno); + +extern JSBool +js_CompileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals, + const jschar *chars, size_t length, + const char *filename, uintN lineno); + +extern JSBool +js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, + bool inCond = false); + +#if JS_HAS_XML_SUPPORT +JS_FRIEND_API(JSParseNode *) +js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc, + JSBool allowList); +#endif + +/* + * Initialize a parse context. All parameters after pc are passed to + * js_InitTokenStream. + * + * The parse context owns the arena pool "tops-of-stack" space above the + * current JSContext.tempPool mark. This means you cannot allocate from + * tempPool and save the pointer beyond the next js_FinishParseContext. + */ +extern JSBool +js_InitParseContext(JSContext *cx, JSParseContext *pc, JSPrincipals *principals, + JSStackFrame *callerFrame, + const jschar *base, size_t length, FILE *fp, + const char *filename, uintN lineno); + +extern void +js_FinishParseContext(JSContext *cx, JSParseContext *pc); + +extern void +js_InitCompilePrincipals(JSContext *cx, JSParseContext *pc, + JSPrincipals *principals); + +/* + * Allocate a new parseed object node from cx->tempPool. + */ +extern JSParsedObjectBox * +js_NewParsedObjectBox(JSContext *cx, JSParseContext *pc, JSObject *obj); + +extern void +js_TraceParseContext(JSTracer *trc, JSParseContext *pc); + +JS_END_EXTERN_C + +#endif /* jsparse_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprf.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprf.cpp new file mode 100644 index 0000000..4285737 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprf.cpp @@ -0,0 +1,1262 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** Portable safe sprintf code. +** +** Author: Kipp E.B. Hickman +*/ +#include "jsstddef.h" +#include +#include +#include +#include +#include "jsprf.h" +#include "jslong.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jspubtd.h" +#include "jsstr.h" + +/* +** Note: on some platforms va_list is defined as an array, +** and requires array notation. +*/ +#ifdef HAVE_VA_COPY +#define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar) +#elif defined(HAVE_VA_LIST_AS_ARRAY) +#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0] +#else +#define VARARGS_ASSIGN(foo, bar) (foo) = (bar) +#endif + +/* +** WARNING: This code may *NOT* call JS_LOG (because JS_LOG calls it) +*/ + +/* +** XXX This needs to be internationalized! +*/ + +typedef struct SprintfStateStr SprintfState; + +struct SprintfStateStr { + int (*stuff)(SprintfState *ss, const char *sp, JSUint32 len); + + char *base; + char *cur; + JSUint32 maxlen; + + int (*func)(void *arg, const char *sp, JSUint32 len); + void *arg; +}; + +/* +** Numbered Arguement State +*/ +struct NumArgState{ + int type; /* type of the current ap */ + va_list ap; /* point to the corresponding position on ap */ +}; + +#define NAS_DEFAULT_NUM 20 /* default number of NumberedArgumentState array */ + + +#define TYPE_INT16 0 +#define TYPE_UINT16 1 +#define TYPE_INTN 2 +#define TYPE_UINTN 3 +#define TYPE_INT32 4 +#define TYPE_UINT32 5 +#define TYPE_INT64 6 +#define TYPE_UINT64 7 +#define TYPE_STRING 8 +#define TYPE_DOUBLE 9 +#define TYPE_INTSTR 10 +#define TYPE_WSTRING 11 +#define TYPE_UNKNOWN 20 + +#define FLAG_LEFT 0x1 +#define FLAG_SIGNED 0x2 +#define FLAG_SPACED 0x4 +#define FLAG_ZEROS 0x8 +#define FLAG_NEG 0x10 + +/* +** Fill into the buffer using the data in src +*/ +static int fill2(SprintfState *ss, const char *src, int srclen, int width, + int flags) +{ + char space = ' '; + int rv; + + width -= srclen; + if ((width > 0) && ((flags & FLAG_LEFT) == 0)) { /* Right adjusting */ + if (flags & FLAG_ZEROS) { + space = '0'; + } + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Copy out the source data */ + rv = (*ss->stuff)(ss, src, (JSUint32)srclen); + if (rv < 0) { + return rv; + } + + if ((width > 0) && ((flags & FLAG_LEFT) != 0)) { /* Left adjusting */ + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + return 0; +} + +/* +** Fill a number. The order is: optional-sign zero-filling conversion-digits +*/ +static int fill_n(SprintfState *ss, const char *src, int srclen, int width, + int prec, int type, int flags) +{ + int zerowidth = 0; + int precwidth = 0; + int signwidth = 0; + int leftspaces = 0; + int rightspaces = 0; + int cvtwidth; + int rv; + char sign; + + if ((type & 1) == 0) { + if (flags & FLAG_NEG) { + sign = '-'; + signwidth = 1; + } else if (flags & FLAG_SIGNED) { + sign = '+'; + signwidth = 1; + } else if (flags & FLAG_SPACED) { + sign = ' '; + signwidth = 1; + } + } + cvtwidth = signwidth + srclen; + + if (prec > 0) { + if (prec > srclen) { + precwidth = prec - srclen; /* Need zero filling */ + cvtwidth += precwidth; + } + } + + if ((flags & FLAG_ZEROS) && (prec < 0)) { + if (width > cvtwidth) { + zerowidth = width - cvtwidth; /* Zero filling */ + cvtwidth += zerowidth; + } + } + + if (flags & FLAG_LEFT) { + if (width > cvtwidth) { + /* Space filling on the right (i.e. left adjusting) */ + rightspaces = width - cvtwidth; + } + } else { + if (width > cvtwidth) { + /* Space filling on the left (i.e. right adjusting) */ + leftspaces = width - cvtwidth; + } + } + while (--leftspaces >= 0) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + if (signwidth) { + rv = (*ss->stuff)(ss, &sign, 1); + if (rv < 0) { + return rv; + } + } + while (--precwidth >= 0) { + rv = (*ss->stuff)(ss, "0", 1); + if (rv < 0) { + return rv; + } + } + while (--zerowidth >= 0) { + rv = (*ss->stuff)(ss, "0", 1); + if (rv < 0) { + return rv; + } + } + rv = (*ss->stuff)(ss, src, (JSUint32)srclen); + if (rv < 0) { + return rv; + } + while (--rightspaces >= 0) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + return 0; +} + +/* +** Convert a long into its printable form +*/ +static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix, + int type, int flags, const char *hexp) +{ + char cvtbuf[100]; + char *cvt; + int digits; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (num == 0)) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + cvt = cvtbuf + sizeof(cvtbuf); + digits = 0; + while (num) { + int digit = (((unsigned long)num) % radix) & 0xF; + *--cvt = hexp[digit]; + digits++; + num = (long)(((unsigned long)num) / radix); + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a 64-bit integer into its printable form +*/ +static int cvt_ll(SprintfState *ss, JSInt64 num, int width, int prec, int radix, + int type, int flags, const char *hexp) +{ + char cvtbuf[100]; + char *cvt; + int digits; + JSInt64 rad; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (JSLL_IS_ZERO(num))) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + JSLL_I2L(rad, radix); + cvt = cvtbuf + sizeof(cvtbuf); + digits = 0; + while (!JSLL_IS_ZERO(num)) { + JSInt32 digit; + JSInt64 quot, rem; + JSLL_UDIVMOD(", &rem, num, rad); + JSLL_L2I(digit, rem); + *--cvt = hexp[digit & 0xf]; + digits++; + num = quot; + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a double precision floating point number into its printable +** form. +** +** XXX stop using sprintf to convert floating point +*/ +static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1) +{ + char fin[20]; + char fout[300]; + int amount = fmt1 - fmt0; + + JS_ASSERT((amount > 0) && (amount < (int)sizeof(fin))); + if (amount >= (int)sizeof(fin)) { + /* Totally bogus % command to sprintf. Just ignore it */ + return 0; + } + memcpy(fin, fmt0, (size_t)amount); + fin[amount] = 0; + + /* Convert floating point using the native sprintf code */ +#ifdef DEBUG + { + const char *p = fin; + while (*p) { + JS_ASSERT(*p != 'L'); + p++; + } + } +#endif + sprintf(fout, fin, d); + + /* + ** This assert will catch overflow's of fout, when building with + ** debugging on. At least this way we can track down the evil piece + ** of calling code and fix it! + */ + JS_ASSERT(strlen(fout) < sizeof(fout)); + + return (*ss->stuff)(ss, fout, strlen(fout)); +} + +/* +** Convert a string into its printable form. "width" is the output +** width. "prec" is the maximum number of characters of "s" to output, +** where -1 means until NUL. +*/ +static int cvt_s(SprintfState *ss, const char *s, int width, int prec, + int flags) +{ + int slen; + + if (prec == 0) + return 0; + + /* Limit string length by precision value */ + slen = s ? strlen(s) : 6; + if (prec > 0) { + if (prec < slen) { + slen = prec; + } + } + + /* and away we go */ + return fill2(ss, s ? s : "(null)", slen, width, flags); +} + +static int cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec, + int flags) +{ + int result; + /* + * Supply NULL as the JSContext; errors are not reported, + * and malloc() is used to allocate the buffer buffer. + */ + if (ws) { + int slen = js_strlen(ws); + char *s = js_DeflateString(NULL, ws, slen); + if (!s) + return -1; /* JSStuffFunc error indicator. */ + result = cvt_s(ss, s, width, prec, flags); + free(s); + } else { + result = cvt_s(ss, NULL, width, prec, flags); + } + return result; +} + +/* +** BuildArgArray stands for Numbered Argument list Sprintf +** for example, +** fmp = "%4$i, %2$d, %3s, %1d"; +** the number must start from 1, and no gap among them +*/ + +static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArgState* nasArray ) +{ + int number = 0, cn = 0, i; + const char *p; + char c; + struct NumArgState *nas; + + + /* + ** first pass: + ** detemine how many legal % I have got, then allocate space + */ + + p = fmt; + *rv = 0; + i = 0; + while( ( c = *p++ ) != 0 ){ + if( c != '%' ) + continue; + if( ( c = *p++ ) == '%' ) /* skip %% case */ + continue; + + while( c != 0 ){ + if( c > '9' || c < '0' ){ + if( c == '$' ){ /* numbered argument csae */ + if( i > 0 ){ + *rv = -1; + return NULL; + } + number++; + } else { /* non-numbered argument case */ + if( number > 0 ){ + *rv = -1; + return NULL; + } + i = 1; + } + break; + } + + c = *p++; + } + } + + if( number == 0 ){ + return NULL; + } + + + if( number > NAS_DEFAULT_NUM ){ + nas = (struct NumArgState*)malloc( number * sizeof( struct NumArgState ) ); + if( !nas ){ + *rv = -1; + return NULL; + } + } else { + nas = nasArray; + } + + for( i = 0; i < number; i++ ){ + nas[i].type = TYPE_UNKNOWN; + } + + + /* + ** second pass: + ** set nas[].type + */ + + p = fmt; + while( ( c = *p++ ) != 0 ){ + if( c != '%' ) continue; + c = *p++; + if( c == '%' ) continue; + + cn = 0; + while( c && c != '$' ){ /* should improve error check later */ + cn = cn*10 + c - '0'; + c = *p++; + } + + if( !c || cn < 1 || cn > number ){ + *rv = -1; + break; + } + + /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */ + cn--; + if( nas[cn].type != TYPE_UNKNOWN ) + continue; + + c = *p++; + + /* width */ + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } + + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + + /* precision */ + if (c == '.') { + c = *p++; + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } + + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + } + + /* size */ + nas[cn].type = TYPE_INTN; + if (c == 'h') { + nas[cn].type = TYPE_INT16; + c = *p++; + } else if (c == 'L') { + /* XXX not quite sure here */ + nas[cn].type = TYPE_INT64; + c = *p++; + } else if (c == 'l') { + nas[cn].type = TYPE_INT32; + c = *p++; + if (c == 'l') { + nas[cn].type = TYPE_INT64; + c = *p++; + } + } + + /* format */ + switch (c) { + case 'd': + case 'c': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + break; + + case 'e': + case 'f': + case 'g': + nas[ cn ].type = TYPE_DOUBLE; + break; + + case 'p': + /* XXX should use cpp */ + if (sizeof(void *) == sizeof(JSInt32)) { + nas[ cn ].type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(JSInt64)) { + nas[ cn ].type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(JSIntn)) { + nas[ cn ].type = TYPE_UINTN; + } else { + nas[ cn ].type = TYPE_UNKNOWN; + } + break; + + case 'C': + case 'S': + case 'E': + case 'G': + /* XXX not supported I suppose */ + JS_ASSERT(0); + nas[ cn ].type = TYPE_UNKNOWN; + break; + + case 's': + nas[ cn ].type = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING; + break; + + case 'n': + nas[ cn ].type = TYPE_INTSTR; + break; + + default: + JS_ASSERT(0); + nas[ cn ].type = TYPE_UNKNOWN; + break; + } + + /* get a legal para. */ + if( nas[ cn ].type == TYPE_UNKNOWN ){ + *rv = -1; + break; + } + } + + + /* + ** third pass + ** fill the nas[cn].ap + */ + + if( *rv < 0 ){ + if( nas != nasArray ) + free( nas ); + return NULL; + } + + cn = 0; + while( cn < number ){ + if( nas[cn].type == TYPE_UNKNOWN ){ + cn++; + continue; + } + + VARARGS_ASSIGN(nas[cn].ap, ap); + + switch( nas[cn].type ){ + case TYPE_INT16: + case TYPE_UINT16: + case TYPE_INTN: + case TYPE_UINTN: (void)va_arg( ap, JSIntn ); break; + + case TYPE_INT32: (void)va_arg( ap, JSInt32 ); break; + + case TYPE_UINT32: (void)va_arg( ap, JSUint32 ); break; + + case TYPE_INT64: (void)va_arg( ap, JSInt64 ); break; + + case TYPE_UINT64: (void)va_arg( ap, JSUint64 ); break; + + case TYPE_STRING: (void)va_arg( ap, char* ); break; + + case TYPE_WSTRING: (void)va_arg( ap, jschar* ); break; + + case TYPE_INTSTR: (void)va_arg( ap, JSIntn* ); break; + + case TYPE_DOUBLE: (void)va_arg( ap, double ); break; + + default: + if( nas != nasArray ) + free( nas ); + *rv = -1; + return NULL; + } + + cn++; + } + + + return nas; +} + +/* +** The workhorse sprintf code. +*/ +static int dosprintf(SprintfState *ss, const char *fmt, va_list ap) +{ + char c; + int flags, width, prec, radix, type; + union { + char ch; + jschar wch; + int i; + long l; + JSInt64 ll; + double d; + const char *s; + const jschar* ws; + int *ip; + } u; + const char *fmt0; + static const char hex[] = "0123456789abcdef"; + static const char HEX[] = "0123456789ABCDEF"; + const char *hexp; + int rv, i; + struct NumArgState *nas = NULL; + struct NumArgState nasArray[ NAS_DEFAULT_NUM ]; + char pattern[20]; + const char *dolPt = NULL; /* in "%4$.2f", dolPt will poiont to . */ + uint8 utf8buf[6]; + int utf8len; + + /* + ** build an argument array, IF the fmt is numbered argument + ** list style, to contain the Numbered Argument list pointers + */ + + nas = BuildArgArray( fmt, ap, &rv, nasArray ); + if( rv < 0 ){ + /* the fmt contains error Numbered Argument format, jliu@netscape.com */ + JS_ASSERT(0); + return rv; + } + + while ((c = *fmt++) != 0) { + if (c != '%') { + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + fmt0 = fmt - 1; + + /* + ** Gobble up the % format string. Hopefully we have handled all + ** of the strange cases! + */ + flags = 0; + c = *fmt++; + if (c == '%') { + /* quoting a % with %% */ + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + + if( nas != NULL ){ + /* the fmt contains the Numbered Arguments feature */ + i = 0; + while( c && c != '$' ){ /* should imporve error check later */ + i = ( i * 10 ) + ( c - '0' ); + c = *fmt++; + } + + if( nas[i-1].type == TYPE_UNKNOWN ){ + if( nas && ( nas != nasArray ) ) + free( nas ); + return -1; + } + + ap = nas[i-1].ap; + dolPt = fmt; + c = *fmt++; + } + + /* + * Examine optional flags. Note that we do not implement the + * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is + * somewhat ambiguous and not ideal, which is perhaps why + * the various sprintf() implementations are inconsistent + * on this feature. + */ + while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) { + if (c == '-') flags |= FLAG_LEFT; + if (c == '+') flags |= FLAG_SIGNED; + if (c == ' ') flags |= FLAG_SPACED; + if (c == '0') flags |= FLAG_ZEROS; + c = *fmt++; + } + if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED; + if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS; + + /* width */ + if (c == '*') { + c = *fmt++; + width = va_arg(ap, int); + } else { + width = 0; + while ((c >= '0') && (c <= '9')) { + width = (width * 10) + (c - '0'); + c = *fmt++; + } + } + + /* precision */ + prec = -1; + if (c == '.') { + c = *fmt++; + if (c == '*') { + c = *fmt++; + prec = va_arg(ap, int); + } else { + prec = 0; + while ((c >= '0') && (c <= '9')) { + prec = (prec * 10) + (c - '0'); + c = *fmt++; + } + } + } + + /* size */ + type = TYPE_INTN; + if (c == 'h') { + type = TYPE_INT16; + c = *fmt++; + } else if (c == 'L') { + /* XXX not quite sure here */ + type = TYPE_INT64; + c = *fmt++; + } else if (c == 'l') { + type = TYPE_INT32; + c = *fmt++; + if (c == 'l') { + type = TYPE_INT64; + c = *fmt++; + } + } + + /* format */ + hexp = hex; + switch (c) { + case 'd': case 'i': /* decimal/integer */ + radix = 10; + goto fetch_and_convert; + + case 'o': /* octal */ + radix = 8; + type |= 1; + goto fetch_and_convert; + + case 'u': /* unsigned decimal */ + radix = 10; + type |= 1; + goto fetch_and_convert; + + case 'x': /* unsigned hex */ + radix = 16; + type |= 1; + goto fetch_and_convert; + + case 'X': /* unsigned HEX */ + radix = 16; + hexp = HEX; + type |= 1; + goto fetch_and_convert; + + fetch_and_convert: + switch (type) { + case TYPE_INT16: + u.l = va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= FLAG_NEG; + } + goto do_long; + case TYPE_UINT16: + u.l = va_arg(ap, int) & 0xffff; + goto do_long; + case TYPE_INTN: + u.l = va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= FLAG_NEG; + } + goto do_long; + case TYPE_UINTN: + u.l = (long)va_arg(ap, unsigned int); + goto do_long; + + case TYPE_INT32: + u.l = va_arg(ap, JSInt32); + if (u.l < 0) { + u.l = -u.l; + flags |= FLAG_NEG; + } + goto do_long; + case TYPE_UINT32: + u.l = (long)va_arg(ap, JSUint32); + do_long: + rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + + case TYPE_INT64: + u.ll = va_arg(ap, JSInt64); + if (!JSLL_GE_ZERO(u.ll)) { + JSLL_NEG(u.ll, u.ll); + flags |= FLAG_NEG; + } + goto do_longlong; + case TYPE_UINT64: + u.ll = va_arg(ap, JSUint64); + do_longlong: + rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + } + break; + + case 'e': + case 'E': + case 'f': + case 'g': + u.d = va_arg(ap, double); + if( nas != NULL ){ + i = fmt - dolPt; + if( i < (int)sizeof( pattern ) ){ + pattern[0] = '%'; + memcpy( &pattern[1], dolPt, (size_t)i ); + rv = cvt_f(ss, u.d, pattern, &pattern[i+1] ); + } + } else + rv = cvt_f(ss, u.d, fmt0, fmt); + + if (rv < 0) { + return rv; + } + break; + + case 'c': + if ((flags & FLAG_LEFT) == 0) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + } + switch (type) { + case TYPE_INT16: + /* Treat %hc as %c unless js_CStringsAreUTF8. */ + if (js_CStringsAreUTF8) { + u.wch = va_arg(ap, int); + utf8len = js_OneUcs4ToUtf8Char (utf8buf, u.wch); + rv = (*ss->stuff)(ss, (char *)utf8buf, utf8len); + break; + } + case TYPE_INTN: + u.ch = va_arg(ap, int); + rv = (*ss->stuff)(ss, &u.ch, 1); + break; + } + if (rv < 0) { + return rv; + } + if (flags & FLAG_LEFT) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + } + break; + + case 'p': + if (sizeof(void *) == sizeof(JSInt32)) { + type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(JSInt64)) { + type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(int)) { + type = TYPE_UINTN; + } else { + JS_ASSERT(0); + break; + } + radix = 16; + goto fetch_and_convert; + +#if 0 + case 'C': + case 'S': + case 'E': + case 'G': + /* XXX not supported I suppose */ + JS_ASSERT(0); + break; +#endif + + case 's': + if(type == TYPE_INT16) { + /* + * This would do a simple string/byte conversion + * unless js_CStringsAreUTF8. + */ + u.ws = va_arg(ap, const jschar*); + rv = cvt_ws(ss, u.ws, width, prec, flags); + } else { + u.s = va_arg(ap, const char*); + rv = cvt_s(ss, u.s, width, prec, flags); + } + if (rv < 0) { + return rv; + } + break; + + case 'n': + u.ip = va_arg(ap, int*); + if (u.ip) { + *u.ip = ss->cur - ss->base; + } + break; + + default: + /* Not a % token after all... skip it */ +#if 0 + JS_ASSERT(0); +#endif + rv = (*ss->stuff)(ss, "%", 1); + if (rv < 0) { + return rv; + } + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Stuff trailing NUL */ + rv = (*ss->stuff)(ss, "\0", 1); + + if( nas && ( nas != nasArray ) ){ + free( nas ); + } + + return rv; +} + +/************************************************************************/ + +static int FuncStuff(SprintfState *ss, const char *sp, JSUint32 len) +{ + int rv; + + rv = (*ss->func)(ss->arg, sp, len); + if (rv < 0) { + return rv; + } + ss->maxlen += len; + return 0; +} + +JS_PUBLIC_API(JSUint32) JS_sxprintf(JSStuffFunc func, void *arg, + const char *fmt, ...) +{ + va_list ap; + int rv; + + va_start(ap, fmt); + rv = JS_vsxprintf(func, arg, fmt, ap); + va_end(ap); + return rv; +} + +JS_PUBLIC_API(JSUint32) JS_vsxprintf(JSStuffFunc func, void *arg, + const char *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = FuncStuff; + ss.func = func; + ss.arg = arg; + ss.maxlen = 0; + rv = dosprintf(&ss, fmt, ap); + return (rv < 0) ? (JSUint32)-1 : ss.maxlen; +} + +/* +** Stuff routine that automatically grows the malloc'd output buffer +** before it overflows. +*/ +static int GrowStuff(SprintfState *ss, const char *sp, JSUint32 len) +{ + ptrdiff_t off; + char *newbase; + JSUint32 newlen; + + off = ss->cur - ss->base; + if (off + len >= ss->maxlen) { + /* Grow the buffer */ + newlen = ss->maxlen + ((len > 32) ? len : 32); + if (ss->base) { + newbase = (char*) realloc(ss->base, newlen); + } else { + newbase = (char*) malloc(newlen); + } + if (!newbase) { + /* Ran out of memory */ + return -1; + } + ss->base = newbase; + ss->maxlen = newlen; + ss->cur = ss->base + off; + } + + /* Copy data */ + while (len) { + --len; + *ss->cur++ = *sp++; + } + JS_ASSERT((JSUint32)(ss->cur - ss->base) <= ss->maxlen); + return 0; +} + +/* +** sprintf into a malloc'd buffer +*/ +JS_PUBLIC_API(char *) JS_smprintf(const char *fmt, ...) +{ + va_list ap; + char *rv; + + va_start(ap, fmt); + rv = JS_vsmprintf(fmt, ap); + va_end(ap); + return rv; +} + +/* +** Free memory allocated, for the caller, by JS_smprintf +*/ +JS_PUBLIC_API(void) JS_smprintf_free(char *mem) +{ + free(mem); +} + +JS_PUBLIC_API(char *) JS_vsmprintf(const char *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + free(ss.base); + } + return 0; + } + return ss.base; +} + +/* +** Stuff routine that discards overflow data +*/ +static int LimitStuff(SprintfState *ss, const char *sp, JSUint32 len) +{ + JSUint32 limit = ss->maxlen - (ss->cur - ss->base); + + if (len > limit) { + len = limit; + } + while (len) { + --len; + *ss->cur++ = *sp++; + } + return 0; +} + +/* +** sprintf into a fixed size buffer. Make sure there is a NUL at the end +** when finished. +*/ +JS_PUBLIC_API(JSUint32) JS_snprintf(char *out, JSUint32 outlen, const char *fmt, ...) +{ + va_list ap; + int rv; + + JS_ASSERT((JSInt32)outlen > 0); + if ((JSInt32)outlen <= 0) { + return 0; + } + + va_start(ap, fmt); + rv = JS_vsnprintf(out, outlen, fmt, ap); + va_end(ap); + return rv; +} + +JS_PUBLIC_API(JSUint32) JS_vsnprintf(char *out, JSUint32 outlen,const char *fmt, + va_list ap) +{ + SprintfState ss; + JSUint32 n; + + JS_ASSERT((JSInt32)outlen > 0); + if ((JSInt32)outlen <= 0) { + return 0; + } + + ss.stuff = LimitStuff; + ss.base = out; + ss.cur = out; + ss.maxlen = outlen; + (void) dosprintf(&ss, fmt, ap); + + /* If we added chars, and we didn't append a null, do it now. */ + if( (ss.cur != ss.base) && (ss.cur[-1] != '\0') ) + ss.cur[-1] = '\0'; + + n = ss.cur - ss.base; + return n ? n - 1 : n; +} + +JS_PUBLIC_API(char *) JS_sprintf_append(char *last, const char *fmt, ...) +{ + va_list ap; + char *rv; + + va_start(ap, fmt); + rv = JS_vsprintf_append(last, fmt, ap); + va_end(ap); + return rv; +} + +JS_PUBLIC_API(char *) JS_vsprintf_append(char *last, const char *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + if (last) { + int lastlen = strlen(last); + ss.base = last; + ss.cur = last + lastlen; + ss.maxlen = lastlen; + } else { + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + } + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + free(ss.base); + } + return 0; + } + return ss.base; +} + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprf.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprf.h new file mode 100644 index 0000000..1f3200d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprf.h @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsprf_h___ +#define jsprf_h___ + +/* +** API for PR printf like routines. Supports the following formats +** %d - decimal +** %u - unsigned decimal +** %x - unsigned hex +** %X - unsigned uppercase hex +** %o - unsigned octal +** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above +** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above +** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above +** %s - string +** %hs - 16-bit version of above (only available if js_CStringsAreUTF8) +** %c - character +** %hc - 16-bit version of above (only available if js_CStringsAreUTF8) +** %p - pointer (deals with machine dependent pointer size) +** %f - float +** %g - float +*/ +#include "jstypes.h" +#include +#include + +JS_BEGIN_EXTERN_C + +/* +** sprintf into a fixed size buffer. Guarantees that a NUL is at the end +** of the buffer. Returns the length of the written output, NOT including +** the NUL, or (JSUint32)-1 if an error occurs. +*/ +extern JS_PUBLIC_API(JSUint32) JS_snprintf(char *out, JSUint32 outlen, const char *fmt, ...); + +/* +** sprintf into a malloc'd buffer. Return a pointer to the malloc'd +** buffer on success, NULL on failure. Call "JS_smprintf_free" to release +** the memory returned. +*/ +extern JS_PUBLIC_API(char*) JS_smprintf(const char *fmt, ...); + +/* +** Free the memory allocated, for the caller, by JS_smprintf +*/ +extern JS_PUBLIC_API(void) JS_smprintf_free(char *mem); + +/* +** "append" sprintf into a malloc'd buffer. "last" is the last value of +** the malloc'd buffer. sprintf will append data to the end of last, +** growing it as necessary using realloc. If last is NULL, JS_sprintf_append +** will allocate the initial string. The return value is the new value of +** last for subsequent calls, or NULL if there is a malloc failure. +*/ +extern JS_PUBLIC_API(char*) JS_sprintf_append(char *last, const char *fmt, ...); + +/* +** sprintf into a function. The function "f" is called with a string to +** place into the output. "arg" is an opaque pointer used by the stuff +** function to hold any state needed to do the storage of the output +** data. The return value is a count of the number of characters fed to +** the stuff function, or (JSUint32)-1 if an error occurs. +*/ +typedef JSIntn (*JSStuffFunc)(void *arg, const char *s, JSUint32 slen); + +extern JS_PUBLIC_API(JSUint32) JS_sxprintf(JSStuffFunc f, void *arg, const char *fmt, ...); + +/* +** va_list forms of the above. +*/ +extern JS_PUBLIC_API(JSUint32) JS_vsnprintf(char *out, JSUint32 outlen, const char *fmt, va_list ap); +extern JS_PUBLIC_API(char*) JS_vsmprintf(const char *fmt, va_list ap); +extern JS_PUBLIC_API(char*) JS_vsprintf_append(char *last, const char *fmt, va_list ap); +extern JS_PUBLIC_API(JSUint32) JS_vsxprintf(JSStuffFunc f, void *arg, const char *fmt, va_list ap); + +/* +*************************************************************************** +** FUNCTION: JS_sscanf +** DESCRIPTION: +** JS_sscanf() scans the input character string, performs data +** conversions, and stores the converted values in the data objects +** pointed to by its arguments according to the format control +** string. +** +** JS_sscanf() behaves the same way as the sscanf() function in the +** Standard C Library (stdio.h), with the following exceptions: +** - JS_sscanf() handles the NSPR integer and floating point types, +** such as JSInt16, JSInt32, JSInt64, and JSFloat64, whereas +** sscanf() handles the standard C types like short, int, long, +** and double. +** - JS_sscanf() has no multibyte character support, while sscanf() +** does. +** INPUTS: +** const char *buf +** a character string holding the input to scan +** const char *fmt +** the format control string for the conversions +** ... +** variable number of arguments, each of them is a pointer to +** a data object in which the converted value will be stored +** OUTPUTS: none +** RETURNS: JSInt32 +** The number of values converted and stored. +** RESTRICTIONS: +** Multibyte characters in 'buf' or 'fmt' are not allowed. +*************************************************************************** +*/ + +extern JS_PUBLIC_API(JSInt32) JS_sscanf(const char *buf, const char *fmt, ...); + +JS_END_EXTERN_C + +#endif /* jsprf_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsproto.tbl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsproto.tbl new file mode 100644 index 0000000..e713d6f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsproto.tbl @@ -0,0 +1,129 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=80 ft=c: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey 1.7 work in progress, released + * February 14, 2006. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsversion.h" + +#if JS_HAS_SCRIPT_OBJECT +# define SCRIPT_INIT js_InitScriptClass +#else +# define SCRIPT_INIT js_InitNullClass +#endif + +#if JS_HAS_XML_SUPPORT +# define XML_INIT js_InitXMLClass +# define NAMESPACE_INIT js_InitNamespaceClass +# define QNAME_INIT js_InitQNameClass +# define ANYNAME_INIT js_InitAnyNameClass +# define ATTRIBUTE_INIT js_InitAttributeNameClass +# define XMLFILTER_INIT js_InitXMLFilterClass +#else +# define XML_INIT js_InitNullClass +# define NAMESPACE_INIT js_InitNullClass +# define QNAME_INIT js_InitNullClass +# define ANYNAME_INIT js_InitNullClass +# define ATTRIBUTE_INIT js_InitNullClass +# define XMLFILTER_INIT js_InitNullClass +#endif + +#if JS_HAS_GENERATORS +# define GENERATOR_INIT js_InitIteratorClasses +#else +# define GENERATOR_INIT js_InitNullClass +#endif + +#if JS_HAS_NO_SUCH_METHOD +# define NO_SUCH_METHOD_INIT js_InitNoSuchMethodClass +#else +# define NO_SUCH_METHOD_INIT js_InitNullClass +#endif + +#if JS_HAS_FILE_OBJECT +# define FILE_INIT js_InitFileClass +#else +# define FILE_INIT js_InitNullClass +#endif + +/* + * Enumerator codes in the second column must not change -- they are part of + * the JS XDR API. Client modules including jsproto.tbl should consider + * wrapping the inclusion with JS_BEGIN_EXTERN_C and JS_END_EXTERN_C. + */ +JS_PROTO(Null, 0, js_InitNullClass) +JS_PROTO(Object, 1, js_InitFunctionAndObjectClasses) +JS_PROTO(Function, 2, js_InitFunctionAndObjectClasses) +JS_PROTO(Array, 3, js_InitArrayClass) +JS_PROTO(Boolean, 4, js_InitBooleanClass) +JS_PROTO(Call, 5, js_InitCallClass) +JS_PROTO(Date, 6, js_InitDateClass) +JS_PROTO(Math, 7, js_InitMathClass) +JS_PROTO(Number, 8, js_InitNumberClass) +JS_PROTO(String, 9, js_InitStringClass) +JS_PROTO(RegExp, 10, js_InitRegExpClass) +JS_PROTO(Script, 11, SCRIPT_INIT) +JS_PROTO(XML, 12, XML_INIT) +JS_PROTO(Namespace, 13, NAMESPACE_INIT) +JS_PROTO(QName, 14, QNAME_INIT) +JS_PROTO(AnyName, 15, ANYNAME_INIT) +JS_PROTO(AttributeName, 16, ATTRIBUTE_INIT) +JS_PROTO(Error, 17, js_InitExceptionClasses) +JS_PROTO(InternalError, 18, js_InitExceptionClasses) +JS_PROTO(EvalError, 19, js_InitExceptionClasses) +JS_PROTO(RangeError, 20, js_InitExceptionClasses) +JS_PROTO(ReferenceError, 21, js_InitExceptionClasses) +JS_PROTO(SyntaxError, 22, js_InitExceptionClasses) +JS_PROTO(TypeError, 23, js_InitExceptionClasses) +JS_PROTO(URIError, 24, js_InitExceptionClasses) +JS_PROTO(Generator, 25, GENERATOR_INIT) +JS_PROTO(Iterator, 26, js_InitIteratorClasses) +JS_PROTO(StopIteration, 27, js_InitIteratorClasses) +JS_PROTO(UnusedProto28, 28, js_InitNullClass) +JS_PROTO(File, 29, FILE_INIT) +JS_PROTO(Block, 30, js_InitBlockClass) +JS_PROTO(XMLFilter, 31, XMLFILTER_INIT) +JS_PROTO(NoSuchMethod, 32, NO_SUCH_METHOD_INIT) +JS_PROTO(JSON, 33, js_InitJSONClass) + +#undef SCRIPT_INIT +#undef XML_INIT +#undef NAMESPACE_INIT +#undef QNAME_INIT +#undef ANYNAME_INIT +#undef ATTRIBUTE_INIT +#undef GENERATOR_INIT +#undef FILE_INIT +#undef NO_SUCH_METHOD_INIT diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprvtd.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprvtd.h new file mode 100644 index 0000000..710fa99 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsprvtd.h @@ -0,0 +1,263 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsprvtd_h___ +#define jsprvtd_h___ +/* + * JS private typename definitions. + * + * This header is included only in other .h files, for convenience and for + * simplicity of type naming. The alternative for structures is to use tags, + * which are named the same as their typedef names (legal in C/C++, and less + * noisy than suffixing the typedef name with "Struct" or "Str"). Instead, + * all .h files that include this file may use the same typedef name, whether + * declaring a pointer to struct type, or defining a member of struct type. + * + * A few fundamental scalar types are defined here too. Neither the scalar + * nor the struct typedefs should change much, therefore the nearly-global + * make dependency induced by this file should not prove painful. + */ + +#include "jspubtd.h" + +/* Internal identifier (jsid) macros. */ + +#define JSID_IS_ATOM(id) JSVAL_IS_STRING((jsval)(id)) +#define JSID_TO_ATOM(id) ((JSAtom *)(id)) +#define ATOM_TO_JSID(atom) (JS_ASSERT(ATOM_IS_STRING(atom)), \ + (jsid)(atom)) + +#define JSID_IS_INT(id) JSVAL_IS_INT((jsval)(id)) +#define JSID_TO_INT(id) JSVAL_TO_INT((jsval)(id)) +#define INT_TO_JSID(i) ((jsid)INT_TO_JSVAL(i)) +#define INT_JSVAL_TO_JSID(v) ((jsid)(v)) +#define INT_JSID_TO_JSVAL(id) ((jsval)(id)) + +#define JSID_IS_OBJECT(id) JSVAL_IS_OBJECT((jsval)(id)) +#define JSID_TO_OBJECT(id) JSVAL_TO_OBJECT((jsval)(id)) +#define OBJECT_TO_JSID(obj) ((jsid)OBJECT_TO_JSVAL(obj)) +#define OBJECT_JSVAL_TO_JSID(v) ((jsid)v) + +#define ID_TO_VALUE(id) ((jsval)(id)) + +/* + * Convenience constants. + */ +#define JS_BITS_PER_UINT32_LOG2 5 +#define JS_BITS_PER_UINT32 32 + +/* Scalar typedefs. */ +typedef uint8 jsbytecode; +typedef uint8 jssrcnote; +typedef uint32 jsatomid; + +/* Struct typedefs. */ +typedef struct JSArgumentFormatMap JSArgumentFormatMap; +typedef struct JSCodeGenerator JSCodeGenerator; +typedef struct JSGCThing JSGCThing; +typedef struct JSGenerator JSGenerator; +typedef struct JSNativeEnumerator JSNativeEnumerator; +typedef struct JSParseContext JSParseContext; +typedef struct JSParsedObjectBox JSParsedObjectBox; +typedef struct JSParseNode JSParseNode; +typedef struct JSPropCacheEntry JSPropCacheEntry; +typedef struct JSSharpObjectMap JSSharpObjectMap; +typedef struct JSTempValueRooter JSTempValueRooter; +typedef struct JSThread JSThread; +typedef struct JSToken JSToken; +typedef struct JSTokenPos JSTokenPos; +typedef struct JSTokenPtr JSTokenPtr; +typedef struct JSTokenStream JSTokenStream; +typedef struct JSTreeContext JSTreeContext; +typedef struct JSTryNote JSTryNote; +typedef struct JSWeakRoots JSWeakRoots; + +/* Friend "Advanced API" typedefs. */ +typedef struct JSAtom JSAtom; +typedef struct JSAtomList JSAtomList; +typedef struct JSAtomListElement JSAtomListElement; +typedef struct JSAtomMap JSAtomMap; +typedef struct JSAtomState JSAtomState; +typedef struct JSCodeSpec JSCodeSpec; +typedef struct JSPrinter JSPrinter; +typedef struct JSRegExp JSRegExp; +typedef struct JSRegExpStatics JSRegExpStatics; +typedef struct JSScope JSScope; +typedef struct JSScopeOps JSScopeOps; +typedef struct JSScopeProperty JSScopeProperty; +typedef struct JSStackHeader JSStackHeader; +typedef struct JSStringBuffer JSStringBuffer; +typedef struct JSSubString JSSubString; +typedef struct JSTraceableNative JSTraceableNative; +typedef struct JSXML JSXML; +typedef struct JSXMLArray JSXMLArray; +typedef struct JSXMLArrayCursor JSXMLArrayCursor; + +/* "Friend" types used by jscntxt.h and jsdbgapi.h. */ +typedef enum JSTrapStatus { + JSTRAP_ERROR, + JSTRAP_CONTINUE, + JSTRAP_RETURN, + JSTRAP_THROW, + JSTRAP_LIMIT +} JSTrapStatus; + +typedef JSTrapStatus +(* JSTrapHandler)(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, + void *closure); + +typedef JSBool +(* JSWatchPointHandler)(JSContext *cx, JSObject *obj, jsval id, jsval old, + jsval *newp, void *closure); + +/* called just after script creation */ +typedef void +(* JSNewScriptHook)(JSContext *cx, + const char *filename, /* URL of script */ + uintN lineno, /* first line */ + JSScript *script, + JSFunction *fun, + void *callerdata); + +/* called just before script destruction */ +typedef void +(* JSDestroyScriptHook)(JSContext *cx, + JSScript *script, + void *callerdata); + +typedef void +(* JSSourceHandler)(const char *filename, uintN lineno, jschar *str, + size_t length, void **listenerTSData, void *closure); + +/* + * This hook captures high level script execution and function calls (JS or + * native). It is used by JS_SetExecuteHook to hook top level scripts and by + * JS_SetCallHook to hook function calls. It will get called twice per script + * or function call: just before execution begins and just after it finishes. + * In both cases the 'current' frame is that of the executing code. + * + * The 'before' param is JS_TRUE for the hook invocation before the execution + * and JS_FALSE for the invocation after the code has run. + * + * The 'ok' param is significant only on the post execution invocation to + * signify whether or not the code completed 'normally'. + * + * The 'closure' param is as passed to JS_SetExecuteHook or JS_SetCallHook + * for the 'before'invocation, but is whatever value is returned from that + * invocation for the 'after' invocation. Thus, the hook implementor *could* + * allocate a structure in the 'before' invocation and return a pointer to that + * structure. The pointer would then be handed to the hook for the 'after' + * invocation. Alternately, the 'before' could just return the same value as + * in 'closure' to cause the 'after' invocation to be called with the same + * 'closure' value as the 'before'. + * + * Returning NULL in the 'before' hook will cause the 'after' hook *not* to + * be called. + */ +typedef void * +(* JSInterpreterHook)(JSContext *cx, JSStackFrame *fp, JSBool before, + JSBool *ok, void *closure); + +typedef void +(* JSObjectHook)(JSContext *cx, JSObject *obj, JSBool isNew, void *closure); + +typedef JSBool +(* JSDebugErrorHook)(JSContext *cx, const char *message, JSErrorReport *report, + void *closure); + +typedef struct JSDebugHooks { + JSTrapHandler interruptHandler; + void *interruptHandlerData; + JSNewScriptHook newScriptHook; + void *newScriptHookData; + JSDestroyScriptHook destroyScriptHook; + void *destroyScriptHookData; + JSTrapHandler debuggerHandler; + void *debuggerHandlerData; + JSSourceHandler sourceHandler; + void *sourceHandlerData; + JSInterpreterHook executeHook; + void *executeHookData; + JSInterpreterHook callHook; + void *callHookData; + JSObjectHook objectHook; + void *objectHookData; + JSTrapHandler throwHook; + void *throwHookData; + JSDebugErrorHook debugErrorHook; + void *debugErrorHookData; +} JSDebugHooks; + +/* + * Type definitions for temporary GC roots that register with GC local C + * variables. See jscntxt.h for details. + */ +typedef void +(* JSTempValueTrace)(JSTracer *trc, JSTempValueRooter *tvr); + +typedef union JSTempValueUnion { + jsval value; + JSObject *object; + JSString *string; + JSXML *xml; + JSTempValueTrace trace; + JSScopeProperty *sprop; + JSWeakRoots *weakRoots; + JSParseContext *parseContext; + JSScript *script; + jsval *array; +} JSTempValueUnion; + +struct JSTempValueRooter { + JSTempValueRooter *down; + ptrdiff_t count; + JSTempValueUnion u; +}; + +/* + * The following determines whether JS_EncodeCharacters and JS_DecodeBytes + * treat char[] as utf-8 or simply as bytes that need to be inflated/deflated. + */ +#ifdef JS_C_STRINGS_ARE_UTF8 +# define js_CStringsAreUTF8 JS_TRUE +#else +extern JSBool js_CStringsAreUTF8; +#endif + +#endif /* jsprvtd_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jspubtd.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jspubtd.h new file mode 100644 index 0000000..1e3f33a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jspubtd.h @@ -0,0 +1,727 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jspubtd_h___ +#define jspubtd_h___ +/* + * JS public API typedefs. + */ +#include "jstypes.h" +#include "jscompat.h" + +JS_BEGIN_EXTERN_C + +/* Scalar typedefs. */ +typedef uint16 jschar; +typedef int32 jsint; +typedef uint32 jsuint; +typedef float64 jsdouble; +typedef jsword jsval; +typedef jsword jsid; +typedef int32 jsrefcount; /* PRInt32 if JS_THREADSAFE, see jslock.h */ + +/* + * Run-time version enumeration. See jsversion.h for compile-time counterparts + * to these values that may be selected by the JS_VERSION macro, and tested by + * #if expressions. + */ +typedef enum JSVersion { + JSVERSION_1_0 = 100, + JSVERSION_1_1 = 110, + JSVERSION_1_2 = 120, + JSVERSION_1_3 = 130, + JSVERSION_1_4 = 140, + JSVERSION_ECMA_3 = 148, + JSVERSION_1_5 = 150, + JSVERSION_1_6 = 160, + JSVERSION_1_7 = 170, + JSVERSION_1_8 = 180, + JSVERSION_DEFAULT = 0, + JSVERSION_UNKNOWN = -1, + JSVERSION_LATEST = JSVERSION_1_8 +} JSVersion; + +#define JSVERSION_IS_ECMA(version) \ + ((version) == JSVERSION_DEFAULT || (version) >= JSVERSION_1_3) + +/* Result of typeof operator enumeration. */ +typedef enum JSType { + JSTYPE_VOID, /* undefined */ + JSTYPE_OBJECT, /* object */ + JSTYPE_FUNCTION, /* function */ + JSTYPE_STRING, /* string */ + JSTYPE_NUMBER, /* number */ + JSTYPE_BOOLEAN, /* boolean */ + JSTYPE_NULL, /* null */ + JSTYPE_XML, /* xml object */ + JSTYPE_LIMIT +} JSType; + +/* Dense index into cached prototypes and class atoms for standard objects. */ +typedef enum JSProtoKey { +#define JS_PROTO(name,code,init) JSProto_##name = code, +#include "jsproto.tbl" +#undef JS_PROTO + JSProto_LIMIT +} JSProtoKey; + +/* JSObjectOps.checkAccess mode enumeration. */ +typedef enum JSAccessMode { + JSACC_PROTO = 0, /* XXXbe redundant w.r.t. id */ + JSACC_PARENT = 1, /* XXXbe redundant w.r.t. id */ + + /* + * enum value #2 formerly called JSACC_IMPORT, + * gap preserved for liveconnect ABI compatibility. + */ + + JSACC_WATCH = 3, /* a watchpoint on object foo for id 'bar' */ + JSACC_READ = 4, /* a "get" of foo.bar */ + JSACC_WRITE = 8, /* a "set" of foo.bar = baz */ + JSACC_LIMIT +} JSAccessMode; + +#define JSACC_TYPEMASK (JSACC_WRITE - 1) + +/* + * This enum type is used to control the behavior of a JSObject property + * iterator function that has type JSNewEnumerate. + */ +typedef enum JSIterateOp { + JSENUMERATE_INIT, /* Create new iterator state */ + JSENUMERATE_NEXT, /* Iterate once */ + JSENUMERATE_DESTROY /* Destroy iterator state */ +} JSIterateOp; + +/* Struct typedefs. */ +typedef struct JSClass JSClass; +typedef struct JSExtendedClass JSExtendedClass; +typedef struct JSConstDoubleSpec JSConstDoubleSpec; +typedef struct JSContext JSContext; +typedef struct JSErrorReport JSErrorReport; +typedef struct JSFunction JSFunction; +typedef struct JSFunctionSpec JSFunctionSpec; +typedef struct JSTracer JSTracer; +typedef struct JSIdArray JSIdArray; +typedef struct JSProperty JSProperty; +typedef struct JSPropertySpec JSPropertySpec; +typedef struct JSObject JSObject; +typedef struct JSObjectMap JSObjectMap; +typedef struct JSObjectOps JSObjectOps; +typedef struct JSXMLObjectOps JSXMLObjectOps; +typedef struct JSRuntime JSRuntime; +typedef struct JSRuntime JSTaskState; /* XXX deprecated name */ +typedef struct JSScript JSScript; +typedef struct JSStackFrame JSStackFrame; +typedef struct JSString JSString; +typedef struct JSXDRState JSXDRState; +typedef struct JSExceptionState JSExceptionState; +typedef struct JSLocaleCallbacks JSLocaleCallbacks; +typedef struct JSSecurityCallbacks JSSecurityCallbacks; +typedef struct JSONParser JSONParser; + +/* JSClass (and JSObjectOps where appropriate) function pointer typedefs. */ + +/* + * Add, delete, get or set a property named by id in obj. Note the jsval id + * type -- id may be a string (Unicode property identifier) or an int (element + * index). The *vp out parameter, on success, is the new property value after + * an add, get, or set. After a successful delete, *vp is JSVAL_FALSE iff + * obj[id] can't be deleted (because it's permanent). + */ +typedef JSBool +(* JSPropertyOp)(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + +/* + * This function type is used for callbacks that enumerate the properties of + * a JSObject. The behavior depends on the value of enum_op: + * + * JSENUMERATE_INIT + * A new, opaque iterator state should be allocated and stored in *statep. + * (You can use PRIVATE_TO_JSVAL() to tag the pointer to be stored). + * + * The number of properties that will be enumerated should be returned as + * an integer jsval in *idp, if idp is non-null, and provided the number of + * enumerable properties is known. If idp is non-null and the number of + * enumerable properties can't be computed in advance, *idp should be set + * to JSVAL_ZERO. + * + * JSENUMERATE_NEXT + * A previously allocated opaque iterator state is passed in via statep. + * Return the next jsid in the iteration using *idp. The opaque iterator + * state pointed at by statep is destroyed and *statep is set to JSVAL_NULL + * if there are no properties left to enumerate. + * + * JSENUMERATE_DESTROY + * Destroy the opaque iterator state previously allocated in *statep by a + * call to this function when enum_op was JSENUMERATE_INIT. + * + * The return value is used to indicate success, with a value of JS_FALSE + * indicating failure. + */ +typedef JSBool +(* JSNewEnumerateOp)(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp); + +/* + * The old-style JSClass.enumerate op should define all lazy properties not + * yet reflected in obj. + */ +typedef JSBool +(* JSEnumerateOp)(JSContext *cx, JSObject *obj); + +/* + * Resolve a lazy property named by id in obj by defining it directly in obj. + * Lazy properties are those reflected from some peer native property space + * (e.g., the DOM attributes for a given node reflected as obj) on demand. + * + * JS looks for a property in an object, and if not found, tries to resolve + * the given id. If resolve succeeds, the engine looks again in case resolve + * defined obj[id]. If no such property exists directly in obj, the process + * is repeated with obj's prototype, etc. + * + * NB: JSNewResolveOp provides a cheaper way to resolve lazy properties. + */ +typedef JSBool +(* JSResolveOp)(JSContext *cx, JSObject *obj, jsval id); + +/* + * Like JSResolveOp, but flags provide contextual information as follows: + * + * JSRESOLVE_QUALIFIED a qualified property id: obj.id or obj[id], not id + * JSRESOLVE_ASSIGNING obj[id] is on the left-hand side of an assignment + * JSRESOLVE_DETECTING 'if (o.p)...' or similar detection opcode sequence + * JSRESOLVE_DECLARING var, const, or function prolog declaration opcode + * JSRESOLVE_CLASSNAME class name used when constructing + * + * The *objp out parameter, on success, should be null to indicate that id + * was not resolved; and non-null, referring to obj or one of its prototypes, + * if id was resolved. + * + * This hook instead of JSResolveOp is called via the JSClass.resolve member + * if JSCLASS_NEW_RESOLVE is set in JSClass.flags. + * + * Setting JSCLASS_NEW_RESOLVE and JSCLASS_NEW_RESOLVE_GETS_START further + * extends this hook by passing in the starting object on the prototype chain + * via *objp. Thus a resolve hook implementation may define the property id + * being resolved in the object in which the id was first sought, rather than + * in a prototype object whose class led to the resolve hook being called. + * + * When using JSCLASS_NEW_RESOLVE_GETS_START, the resolve hook must therefore + * null *objp to signify "not resolved". With only JSCLASS_NEW_RESOLVE and no + * JSCLASS_NEW_RESOLVE_GETS_START, the hook can assume *objp is null on entry. + * This is not good practice, but enough existing hook implementations count + * on it that we can't break compatibility by passing the starting object in + * *objp without a new JSClass flag. + */ +typedef JSBool +(* JSNewResolveOp)(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp); + +/* + * Convert obj to the given type, returning true with the resulting value in + * *vp on success, and returning false on error or exception. + */ +typedef JSBool +(* JSConvertOp)(JSContext *cx, JSObject *obj, JSType type, jsval *vp); + +/* + * Finalize obj, which the garbage collector has determined to be unreachable + * from other live objects or from GC roots. Obviously, finalizers must never + * store a reference to obj. + */ +typedef void +(* JSFinalizeOp)(JSContext *cx, JSObject *obj); + +/* + * Used by JS_AddExternalStringFinalizer and JS_RemoveExternalStringFinalizer + * to extend and reduce the set of string types finalized by the GC. + */ +typedef void +(* JSStringFinalizeOp)(JSContext *cx, JSString *str); + +/* + * The signature for JSClass.getObjectOps, used by JS_NewObject's internals + * to discover the set of high-level object operations to use for new objects + * of the given class. All native objects have a JSClass, which is stored as + * a private (int-tagged) pointer in obj slots. In contrast, all native and + * host objects have a JSObjectMap at obj->map, which may be shared among a + * number of objects, and which contains the JSObjectOps *ops pointer used to + * dispatch object operations from API calls. + * + * Thus JSClass (which pre-dates JSObjectOps in the API) provides a low-level + * interface to class-specific code and data, while JSObjectOps allows for a + * higher level of operation, which does not use the object's class except to + * find the class's JSObjectOps struct, by calling clasp->getObjectOps, and to + * finalize the object. + * + * If this seems backwards, that's because it is! API compatibility requires + * a JSClass *clasp parameter to JS_NewObject, etc. Most host objects do not + * need to implement the larger JSObjectOps, and can share the common JSScope + * code and data used by the native (js_ObjectOps, see jsobj.c) ops. + * + * Further extension to preserve API compatibility: if this function returns + * a pointer to JSXMLObjectOps.base, not to JSObjectOps, then the engine calls + * extended hooks needed for E4X. + */ +typedef JSObjectOps * +(* JSGetObjectOps)(JSContext *cx, JSClass *clasp); + +/* + * JSClass.checkAccess type: check whether obj[id] may be accessed per mode, + * returning false on error/exception, true on success with obj[id]'s last-got + * value in *vp, and its attributes in *attrsp. As for JSPropertyOp above, id + * is either a string or an int jsval. + * + * See JSCheckAccessIdOp, below, for the JSObjectOps counterpart, which takes + * a jsid (a tagged int or aligned, unique identifier pointer) rather than a + * jsval. The native js_ObjectOps.checkAccess simply forwards to the object's + * clasp->checkAccess, so that both JSClass and JSObjectOps implementors may + * specialize access checks. + */ +typedef JSBool +(* JSCheckAccessOp)(JSContext *cx, JSObject *obj, jsval id, JSAccessMode mode, + jsval *vp); + +/* + * Encode or decode an object, given an XDR state record representing external + * data. See jsxdrapi.h. + */ +typedef JSBool +(* JSXDRObjectOp)(JSXDRState *xdr, JSObject **objp); + +/* + * Check whether v is an instance of obj. Return false on error or exception, + * true on success with JS_TRUE in *bp if v is an instance of obj, JS_FALSE in + * *bp otherwise. + */ +typedef JSBool +(* JSHasInstanceOp)(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); + +/* + * Deprecated function type for JSClass.mark. All new code should define + * JSTraceOp instead to ensure the traversal of traceable things stored in + * the native structures. + */ +typedef uint32 +(* JSMarkOp)(JSContext *cx, JSObject *obj, void *arg); + +/* + * Function type for trace operation of the class called to enumerate all + * traceable things reachable from obj's private data structure. For each such + * thing, a trace implementation must call + * + * JS_CallTracer(trc, thing, kind); + * + * or one of its convenience macros as described in jsapi.h. + * + * JSTraceOp implementation can assume that no other threads mutates object + * state. It must not change state of the object or corresponding native + * structures. The only exception for this rule is the case when the embedding + * needs a tight integration with GC. In that case the embedding can check if + * the traversal is a part of the marking phase through calling + * JS_IsGCMarkingTracer and apply a special code like emptying caches or + * marking its native structures. + * + * To define the tracer for a JSClass, the implementation must add + * JSCLASS_MARK_IS_TRACE to class flags and use JS_CLASS_TRACE(method) + * macro below to convert JSTraceOp to JSMarkOp when initializing or + * assigning JSClass.mark field. + */ +typedef void +(* JSTraceOp)(JSTracer *trc, JSObject *obj); + +#if defined __GNUC__ && __GNUC__ >= 4 && !defined __cplusplus +# define JS_CLASS_TRACE(method) \ + (__builtin_types_compatible_p(JSTraceOp, __typeof(&(method))) \ + ? (JSMarkOp)(method) \ + : js_WrongTypeForClassTracer) + +extern JSMarkOp js_WrongTypeForClassTracer; + +#else +# define JS_CLASS_TRACE(method) ((JSMarkOp)(method)) +#endif + +/* + * Tracer callback, called for each traceable thing directly refrenced by a + * particular object or runtime structure. It is the callback responsibility + * to ensure the traversal of the full object graph via calling eventually + * JS_TraceChildren on the passed thing. In this case the callback must be + * prepared to deal with cycles in the traversal graph. + * + * kind argument is one of JSTRACE_OBJECT, JSTRACE_DOUBLE, JSTRACE_STRING or + * a tag denoting internal implementation-specific traversal kind. In the + * latter case the only operations on thing that the callback can do is to call + * JS_TraceChildren or DEBUG-only JS_PrintTraceThingInfo. + */ +typedef void +(* JSTraceCallback)(JSTracer *trc, void *thing, uint32 kind); + +/* + * DEBUG only callback that JSTraceOp implementation can provide to return + * a string describing the reference traced with JS_CallTracer. + */ +#ifdef DEBUG +typedef void +(* JSTraceNamePrinter)(JSTracer *trc, char *buf, size_t bufsize); +#endif + +/* + * The optional JSClass.reserveSlots hook allows a class to make computed + * per-instance object slots reservations, in addition to or instead of using + * JSCLASS_HAS_RESERVED_SLOTS(n) in the JSClass.flags initializer to reserve + * a constant-per-class number of slots. Implementations of this hook should + * return the number of slots to reserve, not including any reserved by using + * JSCLASS_HAS_RESERVED_SLOTS(n) in JSClass.flags. + * + * NB: called with obj locked by the JSObjectOps-specific mutual exclusion + * mechanism appropriate for obj, so don't nest other operations that might + * also lock obj. + */ +typedef uint32 +(* JSReserveSlotsOp)(JSContext *cx, JSObject *obj); + +/* JSObjectOps function pointer typedefs. */ + +/* + * Create a new subclass of JSObjectMap (see jsobj.h), with the nrefs and ops + * members initialized from the same-named parameters, and with the nslots and + * freeslot members initialized according to ops and clasp. Return null on + * error, non-null on success. + * + * JSObjectMaps are reference-counted by generic code in the engine. Usually, + * the nrefs parameter to JSObjectOps.newObjectMap will be 1, to count the ref + * returned to the caller on success. After a successful construction, some + * number of js_HoldObjectMap and js_DropObjectMap calls ensue. When nrefs + * reaches 0 due to a js_DropObjectMap call, JSObjectOps.destroyObjectMap will + * be called to dispose of the map. + */ +typedef JSObjectMap * +(* JSNewObjectMapOp)(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, + JSClass *clasp, JSObject *obj); + +/* + * Generic type for an infallible JSObjectMap operation, used currently by + * JSObjectOps.destroyObjectMap. + */ +typedef void +(* JSObjectMapOp)(JSContext *cx, JSObjectMap *map); + +/* + * Look for id in obj and its prototype chain, returning false on error or + * exception, true on success. On success, return null in *propp if id was + * not found. If id was found, return the first object searching from obj + * along its prototype chain in which id names a direct property in *objp, and + * return a non-null, opaque property pointer in *propp. + * + * If JSLookupPropOp succeeds and returns with *propp non-null, that pointer + * may be passed as the prop parameter to a JSAttributesOp, as a short-cut + * that bypasses id re-lookup. In any case, a non-null *propp result after a + * successful lookup must be dropped via JSObjectOps.dropProperty. + * + * NB: successful return with non-null *propp means the implementation may + * have locked *objp and added a reference count associated with *propp, so + * callers should not risk deadlock by nesting or interleaving other lookups + * or any obj-bearing ops before dropping *propp. + */ +typedef JSBool +(* JSLookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp); + +/* + * Define obj[id], a direct property of obj named id, having the given initial + * value, with the specified getter, setter, and attributes. If the propp out + * param is non-null, *propp on successful return contains an opaque property + * pointer usable as a speedup hint with JSAttributesOp. But note that propp + * may be null, indicating that the caller is not interested in recovering an + * opaque pointer to the newly-defined property. + * + * If propp is non-null and JSDefinePropOp succeeds, its caller must be sure + * to drop *propp using JSObjectOps.dropProperty in short order, just as with + * JSLookupPropOp. + */ +typedef JSBool +(* JSDefinePropOp)(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + JSProperty **propp); + +/* + * Get, set, or delete obj[id], returning false on error or exception, true + * on success. If getting or setting, the new value is returned in *vp on + * success. If deleting without error, *vp will be JSVAL_FALSE if obj[id] is + * permanent, and JSVAL_TRUE if id named a direct property of obj that was in + * fact deleted, or if id names no direct property of obj (id could name a + * prototype property, or no property in obj or its prototype chain). + */ +typedef JSBool +(* JSPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +/* + * Get or set attributes of the property obj[id]. Return false on error or + * exception, true with current attributes in *attrsp. If prop is non-null, + * it must come from the *propp out parameter of a prior JSDefinePropOp or + * JSLookupPropOp call. + */ +typedef JSBool +(* JSAttributesOp)(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp); + +/* + * JSObjectOps.checkAccess type: check whether obj[id] may be accessed per + * mode, returning false on error/exception, true on success with obj[id]'s + * last-got value in *vp, and its attributes in *attrsp. + */ +typedef JSBool +(* JSCheckAccessIdOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + jsval *vp, uintN *attrsp); + +/* + * A generic type for functions mapping an object to another object, or null + * if an error or exception was thrown on cx. Used by JSObjectOps.thisObject + * at present. + */ +typedef JSObject * +(* JSObjectOp)(JSContext *cx, JSObject *obj); + +/* + * Hook that creates an iterator object for a given object. Returns the + * iterator object or null if an error or exception was thrown on cx. + */ +typedef JSObject * +(* JSIteratorOp)(JSContext *cx, JSObject *obj, JSBool keysonly); + +/* + * A generic type for functions taking a context, object, and property, with + * no return value. Used by JSObjectOps.dropProperty currently (see above, + * JSDefinePropOp and JSLookupPropOp, for the object-locking protocol in which + * dropProperty participates). + */ +typedef void +(* JSPropertyRefOp)(JSContext *cx, JSObject *obj, JSProperty *prop); + +/* + * Function pointer type for JSObjectOps.setProto and JSObjectOps.setParent. + * These hooks must check for cycles without deadlocking, and otherwise take + * special steps. See jsobj.c and jsgc.c for details. + */ +typedef JSBool +(* JSSetObjectSlotOp)(JSContext *cx, JSObject *obj, uint32 slot, + JSObject *pobj); + +/* + * Get and set a required slot, one that should already have been allocated. + * These operations are infallible, so required slots must be pre-allocated, + * or implementations must suppress out-of-memory errors. The native ops + * (js_ObjectOps, see jsobj.c) access slots reserved by including a call to + * the JSCLASS_HAS_RESERVED_SLOTS(n) macro in the JSClass.flags initializer. + * + * NB: the slot parameter is a zero-based index into obj slots, unlike the + * index parameter to the JS_GetReservedSlot and JS_SetReservedSlot API entry + * points, which is a zero-based index into the JSCLASS_RESERVED_SLOTS(clasp) + * reserved slots that come after the initial well-known slots: proto, parent, + * class, and optionally, the private data slot. + */ +typedef jsval +(* JSGetRequiredSlotOp)(JSContext *cx, JSObject *obj, uint32 slot); + +typedef JSBool +(* JSSetRequiredSlotOp)(JSContext *cx, JSObject *obj, uint32 slot, jsval v); + +typedef JSObject * +(* JSGetMethodOp)(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +typedef JSBool +(* JSSetMethodOp)(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +typedef JSBool +(* JSEnumerateValuesOp)(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp, jsval *vp); + +typedef JSBool +(* JSEqualityOp)(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); + +typedef JSBool +(* JSConcatenateOp)(JSContext *cx, JSObject *obj, jsval v, jsval *vp); + +/* Typedef for native functions called by the JS VM. */ + +typedef JSBool +(* JSNative)(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +/* See jsapi.h, the JS_CALLEE, JS_THIS, etc. macros. */ +typedef JSBool +(* JSFastNative)(JSContext *cx, uintN argc, jsval *vp); + +/* Callbacks and their arguments. */ + +typedef enum JSContextOp { + JSCONTEXT_NEW, + JSCONTEXT_DESTROY +} JSContextOp; + +/* + * The possible values for contextOp when the runtime calls the callback are: + * JSCONTEXT_NEW JS_NewContext successfully created a new JSContext + * instance. The callback can initialize the instance as + * required. If the callback returns false, the instance + * will be destroyed and JS_NewContext returns null. In + * this case the callback is not called again. + * JSCONTEXT_DESTROY One of JS_DestroyContext* methods is called. The + * callback may perform its own cleanup and must always + * return true. + * Any other value For future compatibility the callback must do nothing + * and return true in this case. + */ +typedef JSBool +(* JSContextCallback)(JSContext *cx, uintN contextOp); + +typedef enum JSGCStatus { + JSGC_BEGIN, + JSGC_END, + JSGC_MARK_END, + JSGC_FINALIZE_END +} JSGCStatus; + +typedef JSBool +(* JSGCCallback)(JSContext *cx, JSGCStatus status); + +/* + * Generic trace operation that calls JS_CallTracer on each traceable thing + * stored in data. + */ +typedef void +(* JSTraceDataOp)(JSTracer *trc, void *data); + +typedef JSBool +(* JSOperationCallback)(JSContext *cx); + +/* + * Deprecated form of JSOperationCallback. + */ +typedef JSBool +(* JSBranchCallback)(JSContext *cx, JSScript *script); + +typedef void +(* JSErrorReporter)(JSContext *cx, const char *message, JSErrorReport *report); + +/* + * Possible exception types. These types are part of a JSErrorFormatString + * structure. They define which error to throw in case of a runtime error. + * JSEXN_NONE marks an unthrowable error. + */ +typedef enum JSExnType { + JSEXN_NONE = -1, + JSEXN_ERR, + JSEXN_INTERNALERR, + JSEXN_EVALERR, + JSEXN_RANGEERR, + JSEXN_REFERENCEERR, + JSEXN_SYNTAXERR, + JSEXN_TYPEERR, + JSEXN_URIERR, + JSEXN_LIMIT +} JSExnType; + +typedef struct JSErrorFormatString { + /* The error format string (UTF-8 if js_CStringsAreUTF8). */ + const char *format; + + /* The number of arguments to expand in the formatted error message. */ + uint16 argCount; + + /* One of the JSExnType constants above. */ + int16 exnType; +} JSErrorFormatString; + +typedef const JSErrorFormatString * +(* JSErrorCallback)(void *userRef, const char *locale, + const uintN errorNumber); + +#ifdef va_start +#define JS_ARGUMENT_FORMATTER_DEFINED 1 + +typedef JSBool +(* JSArgumentFormatter)(JSContext *cx, const char *format, JSBool fromJS, + jsval **vpp, va_list *app); +#endif + +typedef JSBool +(* JSLocaleToUpperCase)(JSContext *cx, JSString *src, jsval *rval); + +typedef JSBool +(* JSLocaleToLowerCase)(JSContext *cx, JSString *src, jsval *rval); + +typedef JSBool +(* JSLocaleCompare)(JSContext *cx, JSString *src1, JSString *src2, + jsval *rval); + +typedef JSBool +(* JSLocaleToUnicode)(JSContext *cx, char *src, jsval *rval); + +/* + * Security protocol types. + */ +typedef struct JSPrincipals JSPrincipals; + +/* + * XDR-encode or -decode a principals instance, based on whether xdr->mode is + * JSXDR_ENCODE, in which case *principalsp should be encoded; or JSXDR_DECODE, + * in which case implementations must return a held (via JSPRINCIPALS_HOLD), + * non-null *principalsp out parameter. Return true on success, false on any + * error, which the implementation must have reported. + */ +typedef JSBool +(* JSPrincipalsTranscoder)(JSXDRState *xdr, JSPrincipals **principalsp); + +/* + * Return a weak reference to the principals associated with obj, possibly via + * the immutable parent chain leading from obj to a top-level container (e.g., + * a window object in the DOM level 0). If there are no principals associated + * with obj, return null. Therefore null does not mean an error was reported; + * in no event should an error be reported or an exception be thrown by this + * callback's implementation. + */ +typedef JSPrincipals * +(* JSObjectPrincipalsFinder)(JSContext *cx, JSObject *obj); + +JS_END_EXTERN_C + +#endif /* jspubtd_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsregexp.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsregexp.cpp new file mode 100644 index 0000000..778f342 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsregexp.cpp @@ -0,0 +1,4772 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS regular expressions, after Perl. + */ +#include "jsstddef.h" +#include +#include +#include +#include "jstypes.h" +#include "jsarena.h" /* Added by JSIFY */ +#include "jsutil.h" /* Added by JSIFY */ +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsregexp.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsstr.h" + +#ifdef JS_TRACER +#include "jstracer.h" +using namespace avmplus; +using namespace nanojit; + +/* + * FIXME Duplicated with jstracer.cpp, doing it this way for now + * to keep it private to files that need it. + */ +#ifdef JS_JIT_SPEW +static bool verbose_debug = getenv("TRACEMONKEY") && strstr(getenv("TRACEMONKEY"), "verbose"); +#define debug_only_v(x) if (verbose_debug) { x; } +#else +#define debug_only_v(x) +#endif +#endif + +typedef enum REOp { +#define REOP_DEF(opcode, name) opcode, +#include "jsreops.tbl" +#undef REOP_DEF + REOP_LIMIT /* META: no operator >= to this */ +} REOp; + +#define REOP_IS_SIMPLE(op) ((op) <= REOP_NCLASS) + +#ifdef REGEXP_DEBUG +const char *reop_names[] = { +#define REOP_DEF(opcode, name) name, +#include "jsreops.tbl" +#undef REOP_DEF + NULL +}; +#endif + +#ifdef __GNUC__ +static int +re_debug(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); +#endif + +#ifdef REGEXP_DEBUG +static int +re_debug(const char *fmt, ...) +{ + va_list ap; + int retval; + + va_start(ap, fmt); + retval = vprintf(fmt, ap); + va_end(ap); + return retval; +} + +static void +re_debug_chars(const jschar *chrs, size_t length) +{ + int i = 0; + + printf(" \""); + while (*chrs && i++ < length) { + putchar((char)*chrs++); + } + printf("\""); +} +#else /* !REGEXP_DEBUG */ +/* This should be optimized to a no-op by our tier-1 compilers. */ +static int +re_debug(const char *fmt, ...) +{ + return 0; +} + +static void +re_debug_chars(const jschar *chrs, size_t length) +{ +} +#endif /* !REGEXP_DEBUG */ + +struct RENode { + REOp op; /* r.e. op bytecode */ + RENode *next; /* next in concatenation order */ + void *kid; /* first operand */ + union { + void *kid2; /* second operand */ + jsint num; /* could be a number */ + size_t parenIndex; /* or a parenthesis index */ + struct { /* or a quantifier range */ + uintN min; + uintN max; + JSPackedBool greedy; + } range; + struct { /* or a character class */ + size_t startIndex; + size_t kidlen; /* length of string at kid, in jschars */ + size_t index; /* index into class list */ + uint16 bmsize; /* bitmap size, based on max char code */ + JSPackedBool sense; + } ucclass; + struct { /* or a literal sequence */ + jschar chr; /* of one character */ + size_t length; /* or many (via the kid) */ + } flat; + struct { + RENode *kid2; /* second operand from ALT */ + jschar ch1; /* match char for ALTPREREQ */ + jschar ch2; /* ditto, or class index for ALTPREREQ2 */ + } altprereq; + } u; +}; + +#define RE_IS_LETTER(c) (((c >= 'A') && (c <= 'Z')) || \ + ((c >= 'a') && (c <= 'z')) ) +#define RE_IS_LINE_TERM(c) ((c == '\n') || (c == '\r') || \ + (c == LINE_SEPARATOR) || (c == PARA_SEPARATOR)) + +#define CLASS_CACHE_SIZE 4 + +typedef struct CompilerState { + JSContext *context; + JSTokenStream *tokenStream; /* For reporting errors */ + const jschar *cpbegin; + const jschar *cpend; + const jschar *cp; + size_t parenCount; + size_t classCount; /* number of [] encountered */ + size_t treeDepth; /* maximum depth of parse tree */ + size_t progLength; /* estimated bytecode length */ + RENode *result; + size_t classBitmapsMem; /* memory to hold all class bitmaps */ + struct { + const jschar *start; /* small cache of class strings */ + size_t length; /* since they're often the same */ + size_t index; + } classCache[CLASS_CACHE_SIZE]; + uint16 flags; +} CompilerState; + +typedef struct EmitStateStackEntry { + jsbytecode *altHead; /* start of REOP_ALT* opcode */ + jsbytecode *nextAltFixup; /* fixup pointer to next-alt offset */ + jsbytecode *nextTermFixup; /* fixup ptr. to REOP_JUMP offset */ + jsbytecode *endTermFixup; /* fixup ptr. to REOPT_ALTPREREQ* offset */ + RENode *continueNode; /* original REOP_ALT* node being stacked */ + jsbytecode continueOp; /* REOP_JUMP or REOP_ENDALT continuation */ + JSPackedBool jumpToJumpFlag; /* true if we've patched jump-to-jump to + avoid 16-bit unsigned offset overflow */ +} EmitStateStackEntry; + +/* + * Immediate operand sizes and getter/setters. Unlike the ones in jsopcode.h, + * the getters and setters take the pc of the offset, not of the opcode before + * the offset. + */ +#define ARG_LEN 2 +#define GET_ARG(pc) ((uint16)(((pc)[0] << 8) | (pc)[1])) +#define SET_ARG(pc, arg) ((pc)[0] = (jsbytecode) ((arg) >> 8), \ + (pc)[1] = (jsbytecode) (arg)) + +#define OFFSET_LEN ARG_LEN +#define OFFSET_MAX (JS_BIT(ARG_LEN * 8) - 1) +#define GET_OFFSET(pc) GET_ARG(pc) + +/* + * Maximum supported tree depth is maximum size of EmitStateStackEntry stack. + * For sanity, we limit it to 2^24 bytes. + */ +#define TREE_DEPTH_MAX (JS_BIT(24) / sizeof(EmitStateStackEntry)) + +/* + * The maximum memory that can be allocated for class bitmaps. + * For sanity, we limit it to 2^24 bytes. + */ +#define CLASS_BITMAPS_MEM_LIMIT JS_BIT(24) + +/* + * Functions to get size and write/read bytecode that represent small indexes + * compactly. + * Each byte in the code represent 7-bit chunk of the index. 8th bit when set + * indicates that the following byte brings more bits to the index. Otherwise + * this is the last byte in the index bytecode representing highest index bits. + */ +static size_t +GetCompactIndexWidth(size_t index) +{ + size_t width; + + for (width = 1; (index >>= 7) != 0; ++width) { } + return width; +} + +static JS_ALWAYS_INLINE jsbytecode * +WriteCompactIndex(jsbytecode *pc, size_t index) +{ + size_t next; + + while ((next = index >> 7) != 0) { + *pc++ = (jsbytecode)(index | 0x80); + index = next; + } + *pc++ = (jsbytecode)index; + return pc; +} + +static JS_ALWAYS_INLINE jsbytecode * +ReadCompactIndex(jsbytecode *pc, size_t *result) +{ + size_t nextByte; + + nextByte = *pc++; + if ((nextByte & 0x80) == 0) { + /* + * Short-circuit the most common case when compact index <= 127. + */ + *result = nextByte; + } else { + size_t shift = 7; + *result = 0x7F & nextByte; + do { + nextByte = *pc++; + *result |= (nextByte & 0x7F) << shift; + shift += 7; + } while ((nextByte & 0x80) != 0); + } + return pc; +} + +typedef struct RECapture { + ptrdiff_t index; /* start of contents, -1 for empty */ + size_t length; /* length of capture */ +} RECapture; + +typedef struct REMatchState { + const jschar *cp; + RECapture parens[1]; /* first of 're->parenCount' captures, + allocated at end of this struct */ +} REMatchState; + +struct REBackTrackData; + +typedef struct REProgState { + jsbytecode *continue_pc; /* current continuation data */ + jsbytecode continue_op; + ptrdiff_t index; /* progress in text */ + size_t parenSoFar; /* highest indexed paren started */ + union { + struct { + uintN min; /* current quantifier limits */ + uintN max; + } quantifier; + struct { + size_t top; /* backtrack stack state */ + size_t sz; + } assertion; + } u; +} REProgState; + +typedef struct REBackTrackData { + size_t sz; /* size of previous stack entry */ + jsbytecode *backtrack_pc; /* where to backtrack to */ + jsbytecode backtrack_op; + const jschar *cp; /* index in text of match at backtrack */ + size_t parenIndex; /* start index of saved paren contents */ + size_t parenCount; /* # of saved paren contents */ + size_t saveStateStackTop; /* number of parent states */ + /* saved parent states follow */ + /* saved paren contents follow */ +} REBackTrackData; + +#define INITIAL_STATESTACK 100 +#define INITIAL_BACKTRACK 8000 + +typedef struct REGlobalData { + JSContext *cx; + JSRegExp *regexp; /* the RE in execution */ + JSBool ok; /* runtime error (out_of_memory only?) */ + size_t start; /* offset to start at */ + ptrdiff_t skipped; /* chars skipped anchoring this r.e. */ + const jschar *cpbegin; /* text base address */ + const jschar *cpend; /* text limit address */ + + REProgState *stateStack; /* stack of state of current parents */ + size_t stateStackTop; + size_t stateStackLimit; + + REBackTrackData *backTrackStack;/* stack of matched-so-far positions */ + REBackTrackData *backTrackSP; + size_t backTrackStackSize; + size_t cursz; /* size of current stack entry */ + size_t backTrackCount; /* how many times we've backtracked */ + size_t backTrackLimit; /* upper limit on backtrack states */ +} REGlobalData; + +/* + * 1. If IgnoreCase is false, return ch. + * 2. Let u be ch converted to upper case as if by calling + * String.prototype.toUpperCase on the one-character string ch. + * 3. If u does not consist of a single character, return ch. + * 4. Let cu be u's character. + * 5. If ch's code point value is greater than or equal to decimal 128 and cu's + * code point value is less than decimal 128, then return ch. + * 6. Return cu. + */ +static JS_ALWAYS_INLINE uintN +upcase(uintN ch) +{ + uintN cu; + + JS_ASSERT((uintN) (jschar) ch == ch); + if (ch < 128) { + if (ch - (uintN) 'a' <= (uintN) ('z' - 'a')) + ch -= (uintN) ('a' - 'A'); + return ch; + } + + cu = JS_TOUPPER(ch); + return (cu < 128) ? ch : cu; +} + +static JS_ALWAYS_INLINE uintN +downcase(uintN ch) +{ + JS_ASSERT((uintN) (jschar) ch == ch); + if (ch < 128) { + if (ch - (uintN) 'A' <= (uintN) ('Z' - 'A')) + ch += (uintN) ('a' - 'A'); + return ch; + } + + return JS_TOLOWER(ch); +} + +/* Construct and initialize an RENode, returning NULL for out-of-memory */ +static RENode * +NewRENode(CompilerState *state, REOp op) +{ + JSContext *cx; + RENode *ren; + + cx = state->context; + JS_ARENA_ALLOCATE_CAST(ren, RENode *, &cx->tempPool, sizeof *ren); + if (!ren) { + js_ReportOutOfScriptQuota(cx); + return NULL; + } + ren->op = op; + ren->next = NULL; + ren->kid = NULL; + return ren; +} + +/* + * Validates and converts hex ascii value. + */ +static JSBool +isASCIIHexDigit(jschar c, uintN *digit) +{ + uintN cv = c; + + if (cv < '0') + return JS_FALSE; + if (cv <= '9') { + *digit = cv - '0'; + return JS_TRUE; + } + cv |= 0x20; + if (cv >= 'a' && cv <= 'f') { + *digit = cv - 'a' + 10; + return JS_TRUE; + } + return JS_FALSE; +} + + +typedef struct { + REOp op; + const jschar *errPos; + size_t parenIndex; +} REOpData; + +static JSBool +ReportRegExpErrorHelper(CompilerState *state, uintN flags, uintN errorNumber, + const jschar *arg) +{ + if (state->tokenStream) { + return js_ReportCompileErrorNumber(state->context, state->tokenStream, + NULL, JSREPORT_UC | flags, + errorNumber, arg); + } + return JS_ReportErrorFlagsAndNumberUC(state->context, flags, + js_GetErrorMessage, NULL, + errorNumber, arg); +} + +static JSBool +ReportRegExpError(CompilerState *state, uintN flags, uintN errorNumber) +{ + return ReportRegExpErrorHelper(state, flags, errorNumber, NULL); +} + +/* + * Process the op against the two top operands, reducing them to a single + * operand in the penultimate slot. Update progLength and treeDepth. + */ +static JSBool +ProcessOp(CompilerState *state, REOpData *opData, RENode **operandStack, + intN operandSP) +{ + RENode *result; + + switch (opData->op) { + case REOP_ALT: + result = NewRENode(state, REOP_ALT); + if (!result) + return JS_FALSE; + result->kid = operandStack[operandSP - 2]; + result->u.kid2 = operandStack[operandSP - 1]; + operandStack[operandSP - 2] = result; + + if (state->treeDepth == TREE_DEPTH_MAX) { + ReportRegExpError(state, JSREPORT_ERROR, JSMSG_REGEXP_TOO_COMPLEX); + return JS_FALSE; + } + ++state->treeDepth; + + /* + * Look at both alternates to see if there's a FLAT or a CLASS at + * the start of each. If so, use a prerequisite match. + */ + if (((RENode *) result->kid)->op == REOP_FLAT && + ((RENode *) result->u.kid2)->op == REOP_FLAT && + (state->flags & JSREG_FOLD) == 0) { + result->op = REOP_ALTPREREQ; + result->u.altprereq.ch1 = ((RENode *) result->kid)->u.flat.chr; + result->u.altprereq.ch2 = ((RENode *) result->u.kid2)->u.flat.chr; + /* ALTPREREQ, , uch1, uch2, , ..., + JUMP, ... ENDALT */ + state->progLength += 13; + } + else + if (((RENode *) result->kid)->op == REOP_CLASS && + ((RENode *) result->kid)->u.ucclass.index < 256 && + ((RENode *) result->u.kid2)->op == REOP_FLAT && + (state->flags & JSREG_FOLD) == 0) { + result->op = REOP_ALTPREREQ2; + result->u.altprereq.ch1 = ((RENode *) result->u.kid2)->u.flat.chr; + result->u.altprereq.ch2 = ((RENode *) result->kid)->u.ucclass.index; + /* ALTPREREQ2, , uch1, uch2, , ..., + JUMP, ... ENDALT */ + state->progLength += 13; + } + else + if (((RENode *) result->kid)->op == REOP_FLAT && + ((RENode *) result->u.kid2)->op == REOP_CLASS && + ((RENode *) result->u.kid2)->u.ucclass.index < 256 && + (state->flags & JSREG_FOLD) == 0) { + result->op = REOP_ALTPREREQ2; + result->u.altprereq.ch1 = ((RENode *) result->kid)->u.flat.chr; + result->u.altprereq.ch2 = + ((RENode *) result->u.kid2)->u.ucclass.index; + /* ALTPREREQ2, , uch1, uch2, , ..., + JUMP, ... ENDALT */ + state->progLength += 13; + } + else { + /* ALT, , ..., JUMP, ... ENDALT */ + state->progLength += 7; + } + break; + + case REOP_CONCAT: + result = operandStack[operandSP - 2]; + while (result->next) + result = result->next; + result->next = operandStack[operandSP - 1]; + break; + + case REOP_ASSERT: + case REOP_ASSERT_NOT: + case REOP_LPARENNON: + case REOP_LPAREN: + /* These should have been processed by a close paren. */ + ReportRegExpErrorHelper(state, JSREPORT_ERROR, JSMSG_MISSING_PAREN, + opData->errPos); + return JS_FALSE; + + default:; + } + return JS_TRUE; +} + +/* + * Parser forward declarations. + */ +static JSBool ParseTerm(CompilerState *state); +static JSBool ParseQuantifier(CompilerState *state); +static intN ParseMinMaxQuantifier(CompilerState *state, JSBool ignoreValues); + +/* + * Top-down regular expression grammar, based closely on Perl4. + * + * regexp: altern A regular expression is one or more + * altern '|' regexp alternatives separated by vertical bar. + */ +#define INITIAL_STACK_SIZE 128 + +static JSBool +ParseRegExp(CompilerState *state) +{ + size_t parenIndex; + RENode *operand; + REOpData *operatorStack; + RENode **operandStack; + REOp op; + intN i; + JSBool result = JS_FALSE; + + intN operatorSP = 0, operatorStackSize = INITIAL_STACK_SIZE; + intN operandSP = 0, operandStackSize = INITIAL_STACK_SIZE; + + /* Watch out for empty regexp */ + if (state->cp == state->cpend) { + state->result = NewRENode(state, REOP_EMPTY); + return (state->result != NULL); + } + + operatorStack = (REOpData *) + JS_malloc(state->context, sizeof(REOpData) * operatorStackSize); + if (!operatorStack) + return JS_FALSE; + + operandStack = (RENode **) + JS_malloc(state->context, sizeof(RENode *) * operandStackSize); + if (!operandStack) + goto out; + + for (;;) { + parenIndex = state->parenCount; + if (state->cp == state->cpend) { + /* + * If we are at the end of the regexp and we're short one or more + * operands, the regexp must have the form /x|/ or some such, with + * left parentheses making us short more than one operand. + */ + if (operatorSP >= operandSP) { + operand = NewRENode(state, REOP_EMPTY); + if (!operand) + goto out; + goto pushOperand; + } + } else { + switch (*state->cp) { + case '(': + ++state->cp; + if (state->cp + 1 < state->cpend && + *state->cp == '?' && + (state->cp[1] == '=' || + state->cp[1] == '!' || + state->cp[1] == ':')) { + switch (state->cp[1]) { + case '=': + op = REOP_ASSERT; + /* ASSERT, , ... ASSERTTEST */ + state->progLength += 4; + break; + case '!': + op = REOP_ASSERT_NOT; + /* ASSERTNOT, , ... ASSERTNOTTEST */ + state->progLength += 4; + break; + default: + op = REOP_LPARENNON; + break; + } + state->cp += 2; + } else { + op = REOP_LPAREN; + /* LPAREN, , ... RPAREN, */ + state->progLength + += 2 * (1 + GetCompactIndexWidth(parenIndex)); + state->parenCount++; + if (state->parenCount == 65535) { + ReportRegExpError(state, JSREPORT_ERROR, + JSMSG_TOO_MANY_PARENS); + goto out; + } + } + goto pushOperator; + + case ')': + /* + * If there's no stacked open parenthesis, throw syntax error. + */ + for (i = operatorSP - 1; ; i--) { + if (i < 0) { + ReportRegExpError(state, JSREPORT_ERROR, + JSMSG_UNMATCHED_RIGHT_PAREN); + goto out; + } + if (operatorStack[i].op == REOP_ASSERT || + operatorStack[i].op == REOP_ASSERT_NOT || + operatorStack[i].op == REOP_LPARENNON || + operatorStack[i].op == REOP_LPAREN) { + break; + } + } + /* FALL THROUGH */ + + case '|': + /* Expected an operand before these, so make an empty one */ + operand = NewRENode(state, REOP_EMPTY); + if (!operand) + goto out; + goto pushOperand; + + default: + if (!ParseTerm(state)) + goto out; + operand = state->result; +pushOperand: + if (operandSP == operandStackSize) { + RENode **tmp; + operandStackSize += operandStackSize; + tmp = (RENode **) + JS_realloc(state->context, operandStack, + sizeof(RENode *) * operandStackSize); + if (!tmp) + goto out; + operandStack = tmp; + } + operandStack[operandSP++] = operand; + break; + } + } + + /* At the end; process remaining operators. */ +restartOperator: + if (state->cp == state->cpend) { + while (operatorSP) { + --operatorSP; + if (!ProcessOp(state, &operatorStack[operatorSP], + operandStack, operandSP)) + goto out; + --operandSP; + } + JS_ASSERT(operandSP == 1); + state->result = operandStack[0]; + result = JS_TRUE; + goto out; + } + + switch (*state->cp) { + case '|': + /* Process any stacked 'concat' operators */ + ++state->cp; + while (operatorSP && + operatorStack[operatorSP - 1].op == REOP_CONCAT) { + --operatorSP; + if (!ProcessOp(state, &operatorStack[operatorSP], + operandStack, operandSP)) { + goto out; + } + --operandSP; + } + op = REOP_ALT; + goto pushOperator; + + case ')': + /* + * If there's no stacked open parenthesis, throw syntax error. + */ + for (i = operatorSP - 1; ; i--) { + if (i < 0) { + ReportRegExpError(state, JSREPORT_ERROR, + JSMSG_UNMATCHED_RIGHT_PAREN); + goto out; + } + if (operatorStack[i].op == REOP_ASSERT || + operatorStack[i].op == REOP_ASSERT_NOT || + operatorStack[i].op == REOP_LPARENNON || + operatorStack[i].op == REOP_LPAREN) { + break; + } + } + ++state->cp; + + /* Process everything on the stack until the open parenthesis. */ + for (;;) { + JS_ASSERT(operatorSP); + --operatorSP; + switch (operatorStack[operatorSP].op) { + case REOP_ASSERT: + case REOP_ASSERT_NOT: + case REOP_LPAREN: + operand = NewRENode(state, operatorStack[operatorSP].op); + if (!operand) + goto out; + operand->u.parenIndex = + operatorStack[operatorSP].parenIndex; + JS_ASSERT(operandSP); + operand->kid = operandStack[operandSP - 1]; + operandStack[operandSP - 1] = operand; + if (state->treeDepth == TREE_DEPTH_MAX) { + ReportRegExpError(state, JSREPORT_ERROR, + JSMSG_REGEXP_TOO_COMPLEX); + goto out; + } + ++state->treeDepth; + /* FALL THROUGH */ + + case REOP_LPARENNON: + state->result = operandStack[operandSP - 1]; + if (!ParseQuantifier(state)) + goto out; + operandStack[operandSP - 1] = state->result; + goto restartOperator; + default: + if (!ProcessOp(state, &operatorStack[operatorSP], + operandStack, operandSP)) + goto out; + --operandSP; + break; + } + } + break; + + case '{': + { + const jschar *errp = state->cp; + + if (ParseMinMaxQuantifier(state, JS_TRUE) < 0) { + /* + * This didn't even scan correctly as a quantifier, so we should + * treat it as flat. + */ + op = REOP_CONCAT; + goto pushOperator; + } + + state->cp = errp; + /* FALL THROUGH */ + } + + case '+': + case '*': + case '?': + ReportRegExpErrorHelper(state, JSREPORT_ERROR, JSMSG_BAD_QUANTIFIER, + state->cp); + result = JS_FALSE; + goto out; + + default: + /* Anything else is the start of the next term. */ + op = REOP_CONCAT; +pushOperator: + if (operatorSP == operatorStackSize) { + REOpData *tmp; + operatorStackSize += operatorStackSize; + tmp = (REOpData *) + JS_realloc(state->context, operatorStack, + sizeof(REOpData) * operatorStackSize); + if (!tmp) + goto out; + operatorStack = tmp; + } + operatorStack[operatorSP].op = op; + operatorStack[operatorSP].errPos = state->cp; + operatorStack[operatorSP++].parenIndex = parenIndex; + break; + } + } +out: + if (operatorStack) + JS_free(state->context, operatorStack); + if (operandStack) + JS_free(state->context, operandStack); + return result; +} + +/* + * Hack two bits in CompilerState.flags, for use within FindParenCount to flag + * its being on the stack, and to propagate errors to its callers. + */ +#define JSREG_FIND_PAREN_COUNT 0x8000 +#define JSREG_FIND_PAREN_ERROR 0x4000 + +/* + * Magic return value from FindParenCount and GetDecimalValue, to indicate + * overflow beyond GetDecimalValue's max parameter, or a computed maximum if + * its findMax parameter is non-null. + */ +#define OVERFLOW_VALUE ((uintN)-1) + +static uintN +FindParenCount(CompilerState *state) +{ + CompilerState temp; + int i; + + if (state->flags & JSREG_FIND_PAREN_COUNT) + return OVERFLOW_VALUE; + + /* + * Copy state into temp, flag it so we never report an invalid backref, + * and reset its members to parse the entire regexp. This is obviously + * suboptimal, but GetDecimalValue calls us only if a backref appears to + * refer to a forward parenthetical, which is rare. + */ + temp = *state; + temp.flags |= JSREG_FIND_PAREN_COUNT; + temp.cp = temp.cpbegin; + temp.parenCount = 0; + temp.classCount = 0; + temp.progLength = 0; + temp.treeDepth = 0; + temp.classBitmapsMem = 0; + for (i = 0; i < CLASS_CACHE_SIZE; i++) + temp.classCache[i].start = NULL; + + if (!ParseRegExp(&temp)) { + state->flags |= JSREG_FIND_PAREN_ERROR; + return OVERFLOW_VALUE; + } + return temp.parenCount; +} + +/* + * Extract and return a decimal value at state->cp. The initial character c + * has already been read. Return OVERFLOW_VALUE if the result exceeds max. + * Callers who pass a non-null findMax should test JSREG_FIND_PAREN_ERROR in + * state->flags to discover whether an error occurred under findMax. + */ +static uintN +GetDecimalValue(jschar c, uintN max, uintN (*findMax)(CompilerState *state), + CompilerState *state) +{ + uintN value = JS7_UNDEC(c); + JSBool overflow = (value > max && (!findMax || value > findMax(state))); + + /* The following restriction allows simpler overflow checks. */ + JS_ASSERT(max <= ((uintN)-1 - 9) / 10); + while (state->cp < state->cpend) { + c = *state->cp; + if (!JS7_ISDEC(c)) + break; + value = 10 * value + JS7_UNDEC(c); + if (!overflow && value > max && (!findMax || value > findMax(state))) + overflow = JS_TRUE; + ++state->cp; + } + return overflow ? OVERFLOW_VALUE : value; +} + +/* + * Calculate the total size of the bitmap required for a class expression. + */ +static JSBool +CalculateBitmapSize(CompilerState *state, RENode *target, const jschar *src, + const jschar *end) +{ + uintN max = 0; + JSBool inRange = JS_FALSE; + jschar c, rangeStart = 0; + uintN n, digit, nDigits, i; + + target->u.ucclass.bmsize = 0; + target->u.ucclass.sense = JS_TRUE; + + if (src == end) + return JS_TRUE; + + if (*src == '^') { + ++src; + target->u.ucclass.sense = JS_FALSE; + } + + while (src != end) { + JSBool canStartRange = JS_TRUE; + uintN localMax = 0; + + switch (*src) { + case '\\': + ++src; + c = *src++; + switch (c) { + case 'b': + localMax = 0x8; + break; + case 'f': + localMax = 0xC; + break; + case 'n': + localMax = 0xA; + break; + case 'r': + localMax = 0xD; + break; + case 't': + localMax = 0x9; + break; + case 'v': + localMax = 0xB; + break; + case 'c': + if (src < end && RE_IS_LETTER(*src)) { + localMax = (uintN) (*src++) & 0x1F; + } else { + --src; + localMax = '\\'; + } + break; + case 'x': + nDigits = 2; + goto lexHex; + case 'u': + nDigits = 4; +lexHex: + n = 0; + for (i = 0; (i < nDigits) && (src < end); i++) { + c = *src++; + if (!isASCIIHexDigit(c, &digit)) { + /* + * Back off to accepting the original + *'\' as a literal. + */ + src -= i + 1; + n = '\\'; + break; + } + n = (n << 4) | digit; + } + localMax = n; + break; + case 'd': + canStartRange = JS_FALSE; + if (inRange) { + JS_ReportErrorNumber(state->context, + js_GetErrorMessage, NULL, + JSMSG_BAD_CLASS_RANGE); + return JS_FALSE; + } + localMax = '9'; + break; + case 'D': + case 's': + case 'S': + case 'w': + case 'W': + canStartRange = JS_FALSE; + if (inRange) { + JS_ReportErrorNumber(state->context, + js_GetErrorMessage, NULL, + JSMSG_BAD_CLASS_RANGE); + return JS_FALSE; + } + max = 65535; + + /* + * If this is the start of a range, ensure that it's less than + * the end. + */ + localMax = 0; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + /* + * This is a non-ECMA extension - decimal escapes (in this + * case, octal!) are supposed to be an error inside class + * ranges, but supported here for backwards compatibility. + * + */ + n = JS7_UNDEC(c); + c = *src; + if ('0' <= c && c <= '7') { + src++; + n = 8 * n + JS7_UNDEC(c); + c = *src; + if ('0' <= c && c <= '7') { + src++; + i = 8 * n + JS7_UNDEC(c); + if (i <= 0377) + n = i; + else + src--; + } + } + localMax = n; + break; + + default: + localMax = c; + break; + } + break; + default: + localMax = *src++; + break; + } + + if (inRange) { + /* Throw a SyntaxError here, per ECMA-262, 15.10.2.15. */ + if (rangeStart > localMax) { + JS_ReportErrorNumber(state->context, + js_GetErrorMessage, NULL, + JSMSG_BAD_CLASS_RANGE); + return JS_FALSE; + } + inRange = JS_FALSE; + } else { + if (canStartRange && src < end - 1) { + if (*src == '-') { + ++src; + inRange = JS_TRUE; + rangeStart = (jschar)localMax; + continue; + } + } + if (state->flags & JSREG_FOLD) + rangeStart = localMax; /* one run of the uc/dc loop below */ + } + + if (state->flags & JSREG_FOLD) { + jschar maxch = localMax; + + for (i = rangeStart; i <= localMax; i++) { + jschar uch, dch; + + uch = upcase(i); + dch = downcase(i); + maxch = JS_MAX(maxch, uch); + maxch = JS_MAX(maxch, dch); + } + localMax = maxch; + } + + if (localMax > max) + max = localMax; + } + target->u.ucclass.bmsize = max; + return JS_TRUE; +} + +/* + * item: assertion An item is either an assertion or + * quantatom a quantified atom. + * + * assertion: '^' Assertions match beginning of string + * (or line if the class static property + * RegExp.multiline is true). + * '$' End of string (or line if the class + * static property RegExp.multiline is + * true). + * '\b' Word boundary (between \w and \W). + * '\B' Word non-boundary. + * + * quantatom: atom An unquantified atom. + * quantatom '{' n ',' m '}' + * Atom must occur between n and m times. + * quantatom '{' n ',' '}' Atom must occur at least n times. + * quantatom '{' n '}' Atom must occur exactly n times. + * quantatom '*' Zero or more times (same as {0,}). + * quantatom '+' One or more times (same as {1,}). + * quantatom '?' Zero or one time (same as {0,1}). + * + * any of which can be optionally followed by '?' for ungreedy + * + * atom: '(' regexp ')' A parenthesized regexp (what matched + * can be addressed using a backreference, + * see '\' n below). + * '.' Matches any char except '\n'. + * '[' classlist ']' A character class. + * '[' '^' classlist ']' A negated character class. + * '\f' Form Feed. + * '\n' Newline (Line Feed). + * '\r' Carriage Return. + * '\t' Horizontal Tab. + * '\v' Vertical Tab. + * '\d' A digit (same as [0-9]). + * '\D' A non-digit. + * '\w' A word character, [0-9a-z_A-Z]. + * '\W' A non-word character. + * '\s' A whitespace character, [ \b\f\n\r\t\v]. + * '\S' A non-whitespace character. + * '\' n A backreference to the nth (n decimal + * and positive) parenthesized expression. + * '\' octal An octal escape sequence (octal must be + * two or three digits long, unless it is + * 0 for the null character). + * '\x' hex A hex escape (hex must be two digits). + * '\u' unicode A unicode escape (must be four digits). + * '\c' ctrl A control character, ctrl is a letter. + * '\' literalatomchar Any character except one of the above + * that follow '\' in an atom. + * otheratomchar Any character not first among the other + * atom right-hand sides. + */ +static JSBool +ParseTerm(CompilerState *state) +{ + jschar c = *state->cp++; + uintN nDigits; + uintN num, tmp, n, i; + const jschar *termStart; + + switch (c) { + /* assertions and atoms */ + case '^': + state->result = NewRENode(state, REOP_BOL); + if (!state->result) + return JS_FALSE; + state->progLength++; + return JS_TRUE; + case '$': + state->result = NewRENode(state, REOP_EOL); + if (!state->result) + return JS_FALSE; + state->progLength++; + return JS_TRUE; + case '\\': + if (state->cp >= state->cpend) { + /* a trailing '\' is an error */ + ReportRegExpError(state, JSREPORT_ERROR, JSMSG_TRAILING_SLASH); + return JS_FALSE; + } + c = *state->cp++; + switch (c) { + /* assertion escapes */ + case 'b' : + state->result = NewRENode(state, REOP_WBDRY); + if (!state->result) + return JS_FALSE; + state->progLength++; + return JS_TRUE; + case 'B': + state->result = NewRENode(state, REOP_WNONBDRY); + if (!state->result) + return JS_FALSE; + state->progLength++; + return JS_TRUE; + /* Decimal escape */ + case '0': + /* Give a strict warning. See also the note below. */ + if (!ReportRegExpError(state, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_INVALID_BACKREF)) { + return JS_FALSE; + } + doOctal: + num = 0; + while (state->cp < state->cpend) { + c = *state->cp; + if (c < '0' || '7' < c) + break; + state->cp++; + tmp = 8 * num + (uintN)JS7_UNDEC(c); + if (tmp > 0377) + break; + num = tmp; + } + c = (jschar)num; + doFlat: + state->result = NewRENode(state, REOP_FLAT); + if (!state->result) + return JS_FALSE; + state->result->u.flat.chr = c; + state->result->u.flat.length = 1; + state->progLength += 3; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + termStart = state->cp - 1; + num = GetDecimalValue(c, state->parenCount, FindParenCount, state); + if (state->flags & JSREG_FIND_PAREN_ERROR) + return JS_FALSE; + if (num == OVERFLOW_VALUE) { + /* Give a strict mode warning. */ + if (!ReportRegExpError(state, + JSREPORT_WARNING | JSREPORT_STRICT, + (c >= '8') + ? JSMSG_INVALID_BACKREF + : JSMSG_BAD_BACKREF)) { + return JS_FALSE; + } + + /* + * Note: ECMA 262, 15.10.2.9 says that we should throw a syntax + * error here. However, for compatibility with IE, we treat the + * whole backref as flat if the first character in it is not a + * valid octal character, and as an octal escape otherwise. + */ + state->cp = termStart; + if (c >= '8') { + /* Treat this as flat. termStart - 1 is the \. */ + c = '\\'; + goto asFlat; + } + + /* Treat this as an octal escape. */ + goto doOctal; + } + JS_ASSERT(1 <= num && num <= 0x10000); + state->result = NewRENode(state, REOP_BACKREF); + if (!state->result) + return JS_FALSE; + state->result->u.parenIndex = num - 1; + state->progLength + += 1 + GetCompactIndexWidth(state->result->u.parenIndex); + break; + /* Control escape */ + case 'f': + c = 0xC; + goto doFlat; + case 'n': + c = 0xA; + goto doFlat; + case 'r': + c = 0xD; + goto doFlat; + case 't': + c = 0x9; + goto doFlat; + case 'v': + c = 0xB; + goto doFlat; + /* Control letter */ + case 'c': + if (state->cp < state->cpend && RE_IS_LETTER(*state->cp)) { + c = (jschar) (*state->cp++ & 0x1F); + } else { + /* back off to accepting the original '\' as a literal */ + --state->cp; + c = '\\'; + } + goto doFlat; + /* HexEscapeSequence */ + case 'x': + nDigits = 2; + goto lexHex; + /* UnicodeEscapeSequence */ + case 'u': + nDigits = 4; +lexHex: + n = 0; + for (i = 0; i < nDigits && state->cp < state->cpend; i++) { + uintN digit; + c = *state->cp++; + if (!isASCIIHexDigit(c, &digit)) { + /* + * Back off to accepting the original 'u' or 'x' as a + * literal. + */ + state->cp -= i + 2; + n = *state->cp++; + break; + } + n = (n << 4) | digit; + } + c = (jschar) n; + goto doFlat; + /* Character class escapes */ + case 'd': + state->result = NewRENode(state, REOP_DIGIT); +doSimple: + if (!state->result) + return JS_FALSE; + state->progLength++; + break; + case 'D': + state->result = NewRENode(state, REOP_NONDIGIT); + goto doSimple; + case 's': + state->result = NewRENode(state, REOP_SPACE); + goto doSimple; + case 'S': + state->result = NewRENode(state, REOP_NONSPACE); + goto doSimple; + case 'w': + state->result = NewRENode(state, REOP_ALNUM); + goto doSimple; + case 'W': + state->result = NewRENode(state, REOP_NONALNUM); + goto doSimple; + /* IdentityEscape */ + default: + state->result = NewRENode(state, REOP_FLAT); + if (!state->result) + return JS_FALSE; + state->result->u.flat.chr = c; + state->result->u.flat.length = 1; + state->result->kid = (void *) (state->cp - 1); + state->progLength += 3; + break; + } + break; + case '[': + state->result = NewRENode(state, REOP_CLASS); + if (!state->result) + return JS_FALSE; + termStart = state->cp; + state->result->u.ucclass.startIndex = termStart - state->cpbegin; + for (;;) { + if (state->cp == state->cpend) { + ReportRegExpErrorHelper(state, JSREPORT_ERROR, + JSMSG_UNTERM_CLASS, termStart); + + return JS_FALSE; + } + if (*state->cp == '\\') { + state->cp++; + if (state->cp != state->cpend) + state->cp++; + continue; + } + if (*state->cp == ']') { + state->result->u.ucclass.kidlen = state->cp - termStart; + break; + } + state->cp++; + } + for (i = 0; i < CLASS_CACHE_SIZE; i++) { + if (!state->classCache[i].start) { + state->classCache[i].start = termStart; + state->classCache[i].length = state->result->u.ucclass.kidlen; + state->classCache[i].index = state->classCount; + break; + } + if (state->classCache[i].length == + state->result->u.ucclass.kidlen) { + for (n = 0; ; n++) { + if (n == state->classCache[i].length) { + state->result->u.ucclass.index + = state->classCache[i].index; + goto claim; + } + if (state->classCache[i].start[n] != termStart[n]) + break; + } + } + } + state->result->u.ucclass.index = state->classCount++; + + claim: + /* + * Call CalculateBitmapSize now as we want any errors it finds + * to be reported during the parse phase, not at execution. + */ + if (!CalculateBitmapSize(state, state->result, termStart, state->cp++)) + return JS_FALSE; + /* + * Update classBitmapsMem with number of bytes to hold bmsize bits, + * which is (bitsCount + 7) / 8 or (highest_bit + 1 + 7) / 8 + * or highest_bit / 8 + 1 where highest_bit is u.ucclass.bmsize. + */ + n = (state->result->u.ucclass.bmsize >> 3) + 1; + if (n > CLASS_BITMAPS_MEM_LIMIT - state->classBitmapsMem) { + ReportRegExpError(state, JSREPORT_ERROR, JSMSG_REGEXP_TOO_COMPLEX); + return JS_FALSE; + } + state->classBitmapsMem += n; + /* CLASS, */ + state->progLength + += 1 + GetCompactIndexWidth(state->result->u.ucclass.index); + break; + + case '.': + state->result = NewRENode(state, REOP_DOT); + goto doSimple; + + case '{': + { + const jschar *errp = state->cp--; + intN err; + + err = ParseMinMaxQuantifier(state, JS_TRUE); + state->cp = errp; + + if (err < 0) + goto asFlat; + + /* FALL THROUGH */ + } + case '*': + case '+': + case '?': + ReportRegExpErrorHelper(state, JSREPORT_ERROR, + JSMSG_BAD_QUANTIFIER, state->cp - 1); + return JS_FALSE; + default: +asFlat: + state->result = NewRENode(state, REOP_FLAT); + if (!state->result) + return JS_FALSE; + state->result->u.flat.chr = c; + state->result->u.flat.length = 1; + state->result->kid = (void *) (state->cp - 1); + state->progLength += 3; + break; + } + return ParseQuantifier(state); +} + +static JSBool +ParseQuantifier(CompilerState *state) +{ + RENode *term; + term = state->result; + if (state->cp < state->cpend) { + switch (*state->cp) { + case '+': + state->result = NewRENode(state, REOP_QUANT); + if (!state->result) + return JS_FALSE; + state->result->u.range.min = 1; + state->result->u.range.max = (uintN)-1; + /* , ... */ + state->progLength += 4; + goto quantifier; + case '*': + state->result = NewRENode(state, REOP_QUANT); + if (!state->result) + return JS_FALSE; + state->result->u.range.min = 0; + state->result->u.range.max = (uintN)-1; + /* , ... */ + state->progLength += 4; + goto quantifier; + case '?': + state->result = NewRENode(state, REOP_QUANT); + if (!state->result) + return JS_FALSE; + state->result->u.range.min = 0; + state->result->u.range.max = 1; + /* , ... */ + state->progLength += 4; + goto quantifier; + case '{': /* balance '}' */ + { + intN err; + const jschar *errp = state->cp; + + err = ParseMinMaxQuantifier(state, JS_FALSE); + if (err == 0) + goto quantifier; + if (err == -1) + return JS_TRUE; + + ReportRegExpErrorHelper(state, JSREPORT_ERROR, err, errp); + return JS_FALSE; + } + default:; + } + } + return JS_TRUE; + +quantifier: + if (state->treeDepth == TREE_DEPTH_MAX) { + ReportRegExpError(state, JSREPORT_ERROR, JSMSG_REGEXP_TOO_COMPLEX); + return JS_FALSE; + } + + ++state->treeDepth; + ++state->cp; + state->result->kid = term; + if (state->cp < state->cpend && *state->cp == '?') { + ++state->cp; + state->result->u.range.greedy = JS_FALSE; + } else { + state->result->u.range.greedy = JS_TRUE; + } + return JS_TRUE; +} + +static intN +ParseMinMaxQuantifier(CompilerState *state, JSBool ignoreValues) +{ + uintN min, max; + jschar c; + const jschar *errp = state->cp++; + + c = *state->cp; + if (JS7_ISDEC(c)) { + ++state->cp; + min = GetDecimalValue(c, 0xFFFF, NULL, state); + c = *state->cp; + + if (!ignoreValues && min == OVERFLOW_VALUE) + return JSMSG_MIN_TOO_BIG; + + if (c == ',') { + c = *++state->cp; + if (JS7_ISDEC(c)) { + ++state->cp; + max = GetDecimalValue(c, 0xFFFF, NULL, state); + c = *state->cp; + if (!ignoreValues && max == OVERFLOW_VALUE) + return JSMSG_MAX_TOO_BIG; + if (!ignoreValues && min > max) + return JSMSG_OUT_OF_ORDER; + } else { + max = (uintN)-1; + } + } else { + max = min; + } + if (c == '}') { + state->result = NewRENode(state, REOP_QUANT); + if (!state->result) + return JSMSG_OUT_OF_MEMORY; + state->result->u.range.min = min; + state->result->u.range.max = max; + /* + * QUANT, , , ... + * where is written as compact(max+1) to make + * (uintN)-1 sentinel to occupy 1 byte, not width_of(max)+1. + */ + state->progLength += (1 + GetCompactIndexWidth(min) + + GetCompactIndexWidth(max + 1) + +3); + return 0; + } + } + + state->cp = errp; + return -1; +} + +static JSBool +SetForwardJumpOffset(jsbytecode *jump, jsbytecode *target) +{ + ptrdiff_t offset = target - jump; + + /* Check that target really points forward. */ + JS_ASSERT(offset >= 2); + if ((size_t)offset > OFFSET_MAX) + return JS_FALSE; + + jump[0] = JUMP_OFFSET_HI(offset); + jump[1] = JUMP_OFFSET_LO(offset); + return JS_TRUE; +} + +/* Copy the charset data from a character class node to the charset list + * in the regexp object. */ +static JS_ALWAYS_INLINE RECharSet * +InitNodeCharSet(JSRegExp *re, RENode *node) +{ + RECharSet *charSet = &re->classList[node->u.ucclass.index]; + charSet->converted = JS_FALSE; + charSet->length = node->u.ucclass.bmsize; + charSet->u.src.startIndex = node->u.ucclass.startIndex; + charSet->u.src.length = node->u.ucclass.kidlen; + charSet->sense = node->u.ucclass.sense; + return charSet; +} + +/* + * Generate bytecode for the tree rooted at t using an explicit stack instead + * of recursion. + */ +static jsbytecode * +EmitREBytecode(CompilerState *state, JSRegExp *re, size_t treeDepth, + jsbytecode *pc, RENode *t) +{ + EmitStateStackEntry *emitStateSP, *emitStateStack; + REOp op; + + if (treeDepth == 0) { + emitStateStack = NULL; + } else { + emitStateStack = + (EmitStateStackEntry *)JS_malloc(state->context, + sizeof(EmitStateStackEntry) * + treeDepth); + if (!emitStateStack) + return NULL; + } + emitStateSP = emitStateStack; + op = t->op; + JS_ASSERT(op < REOP_LIMIT); + + for (;;) { + *pc++ = op; + switch (op) { + case REOP_EMPTY: + --pc; + break; + + case REOP_ALTPREREQ2: + case REOP_ALTPREREQ: + JS_ASSERT(emitStateSP); + emitStateSP->altHead = pc - 1; + emitStateSP->endTermFixup = pc; + pc += OFFSET_LEN; + SET_ARG(pc, t->u.altprereq.ch1); + pc += ARG_LEN; + SET_ARG(pc, t->u.altprereq.ch2); + pc += ARG_LEN; + + emitStateSP->nextAltFixup = pc; /* offset to next alternate */ + pc += OFFSET_LEN; + + emitStateSP->continueNode = t; + emitStateSP->continueOp = REOP_JUMP; + emitStateSP->jumpToJumpFlag = JS_FALSE; + ++emitStateSP; + JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); + t = (RENode *) t->kid; + op = t->op; + JS_ASSERT(op < REOP_LIMIT); + continue; + + case REOP_JUMP: + emitStateSP->nextTermFixup = pc; /* offset to following term */ + pc += OFFSET_LEN; + if (!SetForwardJumpOffset(emitStateSP->nextAltFixup, pc)) + goto jump_too_big; + emitStateSP->continueOp = REOP_ENDALT; + ++emitStateSP; + JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); + t = (RENode *) t->u.kid2; + op = t->op; + JS_ASSERT(op < REOP_LIMIT); + continue; + + case REOP_ENDALT: + /* + * If we already patched emitStateSP->nextTermFixup to jump to + * a nearer jump, to avoid 16-bit immediate offset overflow, we + * are done here. + */ + if (emitStateSP->jumpToJumpFlag) + break; + + /* + * Fix up the REOP_JUMP offset to go to the op after REOP_ENDALT. + * REOP_ENDALT is executed only on successful match of the last + * alternate in a group. + */ + if (!SetForwardJumpOffset(emitStateSP->nextTermFixup, pc)) + goto jump_too_big; + if (t->op != REOP_ALT) { + if (!SetForwardJumpOffset(emitStateSP->endTermFixup, pc)) + goto jump_too_big; + } + + /* + * If the program is bigger than the REOP_JUMP offset range, then + * we must check for alternates before this one that are part of + * the same group, and fix up their jump offsets to target jumps + * close enough to fit in a 16-bit unsigned offset immediate. + */ + if ((size_t)(pc - re->program) > OFFSET_MAX && + emitStateSP > emitStateStack) { + EmitStateStackEntry *esp, *esp2; + jsbytecode *alt, *jump; + ptrdiff_t span, header; + + esp2 = emitStateSP; + alt = esp2->altHead; + for (esp = esp2 - 1; esp >= emitStateStack; --esp) { + if (esp->continueOp == REOP_ENDALT && + !esp->jumpToJumpFlag && + esp->nextTermFixup + OFFSET_LEN == alt && + (size_t)(pc - ((esp->continueNode->op != REOP_ALT) + ? esp->endTermFixup + : esp->nextTermFixup)) > OFFSET_MAX) { + alt = esp->altHead; + jump = esp->nextTermFixup; + + /* + * The span must be 1 less than the distance from + * jump offset to jump offset, so we actually jump + * to a REOP_JUMP bytecode, not to its offset! + */ + for (;;) { + JS_ASSERT(jump < esp2->nextTermFixup); + span = esp2->nextTermFixup - jump - 1; + if ((size_t)span <= OFFSET_MAX) + break; + do { + if (--esp2 == esp) + goto jump_too_big; + } while (esp2->continueOp != REOP_ENDALT); + } + + jump[0] = JUMP_OFFSET_HI(span); + jump[1] = JUMP_OFFSET_LO(span); + + if (esp->continueNode->op != REOP_ALT) { + /* + * We must patch the offset at esp->endTermFixup + * as well, for the REOP_ALTPREREQ{,2} opcodes. + * If we're unlucky and endTermFixup is more than + * OFFSET_MAX bytes from its target, we cheat by + * jumping 6 bytes to the jump whose offset is at + * esp->nextTermFixup, which has the same target. + */ + jump = esp->endTermFixup; + header = esp->nextTermFixup - jump; + span += header; + if ((size_t)span > OFFSET_MAX) + span = header; + + jump[0] = JUMP_OFFSET_HI(span); + jump[1] = JUMP_OFFSET_LO(span); + } + + esp->jumpToJumpFlag = JS_TRUE; + } + } + } + break; + + case REOP_ALT: + JS_ASSERT(emitStateSP); + emitStateSP->altHead = pc - 1; + emitStateSP->nextAltFixup = pc; /* offset to next alternate */ + pc += OFFSET_LEN; + emitStateSP->continueNode = t; + emitStateSP->continueOp = REOP_JUMP; + emitStateSP->jumpToJumpFlag = JS_FALSE; + ++emitStateSP; + JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); + t = (RENode *) t->kid; + op = t->op; + JS_ASSERT(op < REOP_LIMIT); + continue; + + case REOP_FLAT: + /* + * Coalesce FLATs if possible and if it would not increase bytecode + * beyond preallocated limit. The latter happens only when bytecode + * size for coalesced string with offset p and length 2 exceeds 6 + * bytes preallocated for 2 single char nodes, i.e. when + * 1 + GetCompactIndexWidth(p) + GetCompactIndexWidth(2) > 6 or + * GetCompactIndexWidth(p) > 4. + * Since when GetCompactIndexWidth(p) <= 4 coalescing of 3 or more + * nodes strictly decreases bytecode size, the check has to be + * done only for the first coalescing. + */ + if (t->kid && + GetCompactIndexWidth((jschar *)t->kid - state->cpbegin) <= 4) + { + while (t->next && + t->next->op == REOP_FLAT && + (jschar*)t->kid + t->u.flat.length == + (jschar*)t->next->kid) { + t->u.flat.length += t->next->u.flat.length; + t->next = t->next->next; + } + } + if (t->kid && t->u.flat.length > 1) { + pc[-1] = (state->flags & JSREG_FOLD) ? REOP_FLATi : REOP_FLAT; + pc = WriteCompactIndex(pc, (jschar *)t->kid - state->cpbegin); + pc = WriteCompactIndex(pc, t->u.flat.length); + } else if (t->u.flat.chr < 256) { + pc[-1] = (state->flags & JSREG_FOLD) ? REOP_FLAT1i : REOP_FLAT1; + *pc++ = (jsbytecode) t->u.flat.chr; + } else { + pc[-1] = (state->flags & JSREG_FOLD) + ? REOP_UCFLAT1i + : REOP_UCFLAT1; + SET_ARG(pc, t->u.flat.chr); + pc += ARG_LEN; + } + break; + + case REOP_LPAREN: + JS_ASSERT(emitStateSP); + pc = WriteCompactIndex(pc, t->u.parenIndex); + emitStateSP->continueNode = t; + emitStateSP->continueOp = REOP_RPAREN; + ++emitStateSP; + JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); + t = (RENode *) t->kid; + op = t->op; + continue; + + case REOP_RPAREN: + pc = WriteCompactIndex(pc, t->u.parenIndex); + break; + + case REOP_BACKREF: + pc = WriteCompactIndex(pc, t->u.parenIndex); + break; + + case REOP_ASSERT: + JS_ASSERT(emitStateSP); + emitStateSP->nextTermFixup = pc; + pc += OFFSET_LEN; + emitStateSP->continueNode = t; + emitStateSP->continueOp = REOP_ASSERTTEST; + ++emitStateSP; + JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); + t = (RENode *) t->kid; + op = t->op; + continue; + + case REOP_ASSERTTEST: + case REOP_ASSERTNOTTEST: + if (!SetForwardJumpOffset(emitStateSP->nextTermFixup, pc)) + goto jump_too_big; + break; + + case REOP_ASSERT_NOT: + JS_ASSERT(emitStateSP); + emitStateSP->nextTermFixup = pc; + pc += OFFSET_LEN; + emitStateSP->continueNode = t; + emitStateSP->continueOp = REOP_ASSERTNOTTEST; + ++emitStateSP; + JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); + t = (RENode *) t->kid; + op = t->op; + continue; + + case REOP_QUANT: + JS_ASSERT(emitStateSP); + if (t->u.range.min == 0 && t->u.range.max == (uintN)-1) { + pc[-1] = (t->u.range.greedy) ? REOP_STAR : REOP_MINIMALSTAR; + } else if (t->u.range.min == 0 && t->u.range.max == 1) { + pc[-1] = (t->u.range.greedy) ? REOP_OPT : REOP_MINIMALOPT; + } else if (t->u.range.min == 1 && t->u.range.max == (uintN) -1) { + pc[-1] = (t->u.range.greedy) ? REOP_PLUS : REOP_MINIMALPLUS; + } else { + if (!t->u.range.greedy) + pc[-1] = REOP_MINIMALQUANT; + pc = WriteCompactIndex(pc, t->u.range.min); + /* + * Write max + 1 to avoid using size_t(max) + 1 bytes + * for (uintN)-1 sentinel. + */ + pc = WriteCompactIndex(pc, t->u.range.max + 1); + } + emitStateSP->nextTermFixup = pc; + pc += OFFSET_LEN; + emitStateSP->continueNode = t; + emitStateSP->continueOp = REOP_ENDCHILD; + ++emitStateSP; + JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); + t = (RENode *) t->kid; + op = t->op; + continue; + + case REOP_ENDCHILD: + if (!SetForwardJumpOffset(emitStateSP->nextTermFixup, pc)) + goto jump_too_big; + break; + + case REOP_CLASS: + if (!t->u.ucclass.sense) + pc[-1] = REOP_NCLASS; + pc = WriteCompactIndex(pc, t->u.ucclass.index); + InitNodeCharSet(re, t); + break; + + default: + break; + } + + t = t->next; + if (t) { + op = t->op; + } else { + if (emitStateSP == emitStateStack) + break; + --emitStateSP; + t = emitStateSP->continueNode; + op = (REOp) emitStateSP->continueOp; + } + } + + cleanup: + if (emitStateStack) + JS_free(state->context, emitStateStack); + return pc; + + jump_too_big: + ReportRegExpError(state, JSREPORT_ERROR, JSMSG_REGEXP_TOO_COMPLEX); + pc = NULL; + goto cleanup; +} + +#ifdef JS_TRACER +typedef List LInsList; + +/* Dummy GC for nanojit placement new. */ +static GC gc; + +class RegExpNativeCompiler { + private: + JSRegExp* re; /* Careful: not fully initialized */ + CompilerState* cs; /* RegExp to compile */ + Fragment* fragment; + LirWriter* lir; + + LIns* state; + LIns* gdata; + LIns* cpend; + + JSBool isCaseInsensitive() const { return cs->flags & JSREG_FOLD; } + + void targetCurrentPoint(LIns* ins) { ins->target(lir->ins0(LIR_label)); } + + void targetCurrentPoint(LInsList& fails) + { + LIns* fail = lir->ins0(LIR_label); + for (size_t i = 0; i < fails.size(); ++i) { + fails[i]->target(fail); + } + fails.clear(); + } + + /* + * These functions return the new position after their match operation, + * or NULL if there was an error. + */ + LIns* compileEmpty(RENode* node, LIns* pos, LInsList& fails) + { + return pos; + } + + LIns* compileFlatSingleChar(RENode* node, LIns* pos, LInsList& fails) + { + /* + * Fast case-insensitive test for ASCII letters: convert text + * char to lower case by bit-or-ing in 32 and compare. + */ + JSBool useFastCI = JS_FALSE; + jschar ch = node->u.flat.chr; /* char to test for */ + jschar ch2 = ch; /* 2nd char to test for if ci */ + if (cs->flags & JSREG_FOLD) { + if (L'A' <= ch && ch <= L'Z' || L'a' <= ch || ch <= L'z') { + ch |= 32; + ch2 = ch; + useFastCI = JS_TRUE; + } else if (JS_TOLOWER(ch) != ch) { + ch2 = JS_TOLOWER(ch); + ch = JS_TOUPPER(ch); + } + } + + LIns* to_fail = lir->insBranch(LIR_jf, lir->ins2(LIR_lt, pos, cpend), 0); + fails.add(to_fail); + LIns* text_ch = lir->insLoad(LIR_ldcs, pos, lir->insImm(0)); + LIns* comp_ch = useFastCI ? + lir->ins2(LIR_or, text_ch, lir->insImm(32)) : + text_ch; + if (ch == ch2) { + fails.add(lir->insBranch(LIR_jf, lir->ins2(LIR_eq, comp_ch, lir->insImm(ch)), 0)); + } else { + LIns* to_ok = lir->insBranch(LIR_jt, lir->ins2(LIR_eq, comp_ch, lir->insImm(ch)), 0); + fails.add(lir->insBranch(LIR_jf, lir->ins2(LIR_eq, comp_ch, lir->insImm(ch2)), 0)); + targetCurrentPoint(to_ok); + } + + return lir->ins2(LIR_piadd, pos, lir->insImm(2)); + } + + LIns* compileClass(RENode* node, LIns* pos, LInsList& fails) + { + if (!node->u.ucclass.sense) + return JS_FALSE; + + RECharSet* charSet = InitNodeCharSet(re, node); + LIns* to_fail = lir->insBranch(LIR_jf, lir->ins2(LIR_lt, pos, cpend), 0); + fails.add(to_fail); + LIns* text_ch = lir->insLoad(LIR_ldcs, pos, lir->insImm(0)); + fails.add(lir->insBranch(LIR_jf, lir->ins2(LIR_le, text_ch, lir->insImm(charSet->length)), 0)); + LIns* byteIndex = lir->ins2(LIR_rsh, text_ch, lir->insImm(3)); + LIns* bitmap = lir->insLoad(LIR_ld, lir->insImmPtr(charSet), (int) offsetof(RECharSet, u.bits)); + LIns* byte = lir->insLoad(LIR_ldcb, lir->ins2(LIR_piadd, bitmap, byteIndex), (int) 0); + LIns* bitMask = lir->ins2(LIR_lsh, lir->insImm(1), + lir->ins2(LIR_and, text_ch, lir->insImm(0x7))); + LIns* test = lir->ins2(LIR_eq, lir->ins2(LIR_and, byte, bitMask), lir->insImm(0)); + + LIns* to_next = lir->insBranch(LIR_jt, test, 0); + fails.add(to_next); + return lir->ins2(LIR_piadd, pos, lir->insImm(2)); + } + + LIns* compileAlt(RENode* node, LIns* pos, LInsList& fails) + { + LInsList kidFails(NULL); + if (!compileNode((RENode *) node->kid, pos, kidFails)) + return JS_FALSE; + if (!compileNode(node->next, pos, kidFails)) + return JS_FALSE; + + targetCurrentPoint(kidFails); + if (!compileNode(node->u.altprereq.kid2, pos, fails)) + return JS_FALSE; + /* + * Disable compilation for any regexp where something follows an + * alternation. To make this work, we need to redesign to either + * (a) pass around continuations so we know the right place to go + * when we logically return, or (b) generate explicit backtracking + * code. + */ + if (node->next) + return JS_FALSE; + return pos; + } + + JSBool compileNode(RENode* node, LIns* pos, LInsList& fails) + { + for (; node; node = node->next) { + if (fragment->lirbuf->outOmem()) + return JS_FALSE; + + switch (node->op) { + case REOP_EMPTY: + pos = compileEmpty(node, pos, fails); + break; + case REOP_FLAT: + if (node->u.flat.length != 1) + return JS_FALSE; + pos = compileFlatSingleChar(node, pos, fails); + break; + case REOP_ALT: + case REOP_ALTPREREQ: + pos = compileAlt(node, pos, fails); + break; + case REOP_CLASS: + pos = compileClass(node, pos, fails); + break; + default: + return JS_FALSE; + } + if (!pos) + return JS_FALSE; + } + + lir->insStorei(pos, state, (int) offsetof(REMatchState, cp)); + lir->ins1(LIR_ret, state); + return JS_TRUE; + } + + JSBool compileSticky(RENode* root, LIns* start) + { + LInsList fails(NULL); + if (!compileNode(root, start, fails)) + return JS_FALSE; + targetCurrentPoint(fails); + lir->ins1(LIR_ret, lir->insImm(0)); + return JS_TRUE; + } + + JSBool compileAnchoring(RENode* root, LIns* start) + { + /* Even at the end, the empty regexp would match. */ + LIns* to_next = lir->insBranch(LIR_jf, + lir->ins2(LIR_le, start, cpend), 0); + LInsList fails(NULL); + if (!compileNode(root, start, fails)) + return JS_FALSE; + + targetCurrentPoint(to_next); + lir->ins1(LIR_ret, lir->insImm(0)); + + targetCurrentPoint(fails); + lir->insStorei(lir->ins2(LIR_piadd, start, lir->insImm(2)), gdata, + (int) offsetof(REGlobalData, skipped)); + + return JS_TRUE; + } + + inline LIns* + addName(LirBuffer* lirbuf, LIns* ins, const char* name) + { + debug_only_v(lirbuf->names->addName(ins, name);) + return ins; + } + + public: + RegExpNativeCompiler(JSRegExp *re, CompilerState *cs) + : re(re), cs(cs), fragment(NULL) { } + + JSBool compile(JSContext* cx) + { + GuardRecord* guard; + LIns* skip; + LIns* start; + bool oom = false; + + Fragmento* fragmento = JS_TRACE_MONITOR(cx).reFragmento; + fragment = fragmento->getLoop(re); + if (!fragment) { + fragment = fragmento->getAnchor(re); + fragment->lirbuf = new (&gc) LirBuffer(fragmento, NULL); + /* Scary: required to have the onDestroy method delete the lirbuf. */ + fragment->root = fragment; + } + LirBuffer* lirbuf = fragment->lirbuf; + LirBufWriter* lirb; + if (lirbuf->outOmem()) goto fail2; + /* FIXME Use bug 463260 smart pointer when available. */ + lir = lirb = new (&gc) LirBufWriter(lirbuf); + + /* FIXME Use bug 463260 smart pointer when available. */ + debug_only_v(fragment->lirbuf->names = new (&gc) LirNameMap(&gc, NULL, fragmento->labels);) + /* FIXME Use bug 463260 smart pointer when available. */ + debug_only_v(lir = new (&gc) VerboseWriter(&gc, lir, lirbuf->names);) + + lir->ins0(LIR_start); + lirbuf->state = state = addName(lirbuf, lir->insParam(0, 0), "state"); + lirbuf->param1 = gdata = addName(lirbuf, lir->insParam(1, 0), "gdata"); + start = addName(lirbuf, lir->insLoad(LIR_ldp, lirbuf->param1, (int) offsetof(REGlobalData, skipped)), "start"); + cpend = addName(lirbuf, lir->insLoad(LIR_ldp, lirbuf->param1, offsetof(REGlobalData, cpend)), "cpend"); + + if (cs->flags & JSREG_STICKY) { + if (!compileSticky(cs->result, start)) goto fail; + } else { + if (!compileAnchoring(cs->result, start)) goto fail; + } + + /* Create fake guard record for loop edge. */ + skip = lirb->skip(sizeof(GuardRecord) + sizeof(SideExit)); + guard = (GuardRecord *) skip->payload(); + memset(guard, 0, sizeof(*guard)); + guard->exit = (SideExit *) guard+1; + guard->exit->target = fragment; + fragment->lastIns = lir->insGuard(LIR_loop, lir->insImm(1), skip); + + ::compile(fragmento->assm(), fragment); + if (fragmento->assm()->error() != nanojit::None) { + oom = fragmento->assm()->error() == nanojit::OutOMem; + goto fail; + } + + delete lirb; + debug_only_v(delete lir;) + return JS_TRUE; + fail: + delete lirb; + debug_only_v(delete lir;) + fail2: + if (lirbuf->outOmem() || oom) + fragmento->clearFrags(); + return JS_FALSE; + } +}; + +static inline JSBool +js_CompileRegExpToNative(JSContext *cx, JSRegExp *re, CompilerState *cs) +{ + RegExpNativeCompiler rc(re, cs); + return rc.compile(cx); +} +#endif + +JSRegExp * +js_NewRegExp(JSContext *cx, JSTokenStream *ts, + JSString *str, uintN flags, JSBool flat) +{ + JSRegExp *re; + void *mark; + CompilerState state; + size_t resize; + jsbytecode *endPC; + uintN i; + size_t len; + + re = NULL; + mark = JS_ARENA_MARK(&cx->tempPool); + len = JSSTRING_LENGTH(str); + + state.context = cx; + state.tokenStream = ts; + state.cp = js_UndependString(cx, str); + if (!state.cp) + goto out; + state.cpbegin = state.cp; + state.cpend = state.cp + len; + state.flags = flags; + state.parenCount = 0; + state.classCount = 0; + state.progLength = 0; + state.treeDepth = 0; + state.classBitmapsMem = 0; + for (i = 0; i < CLASS_CACHE_SIZE; i++) + state.classCache[i].start = NULL; + + if (len != 0 && flat) { + state.result = NewRENode(&state, REOP_FLAT); + if (!state.result) + goto out; + state.result->u.flat.chr = *state.cpbegin; + state.result->u.flat.length = len; + state.result->kid = (void *) state.cpbegin; + /* Flat bytecode: REOP_FLAT compact(string_offset) compact(len). */ + state.progLength += 1 + GetCompactIndexWidth(0) + + GetCompactIndexWidth(len); + } else { + if (!ParseRegExp(&state)) + goto out; + } + + resize = offsetof(JSRegExp, program) + state.progLength + 1; + re = (JSRegExp *) JS_malloc(cx, resize); + if (!re) + goto out; + + re->nrefs = 1; + JS_ASSERT(state.classBitmapsMem <= CLASS_BITMAPS_MEM_LIMIT); + re->classCount = state.classCount; + if (re->classCount) { + re->classList = (RECharSet *) + JS_malloc(cx, re->classCount * sizeof(RECharSet)); + if (!re->classList) { + js_DestroyRegExp(cx, re); + re = NULL; + goto out; + } + for (i = 0; i < re->classCount; i++) + re->classList[i].converted = JS_FALSE; + } else { + re->classList = NULL; + } + +#ifdef JS_TRACER + /* + * Try compiling the native code version. For the time being we also + * compile the bytecode version in case we evict the native code + * version from the code cache. + */ + if (TRACING_ENABLED(cx)) + js_CompileRegExpToNative(cx, re, &state); +#endif + /* Compile the bytecode version. */ + endPC = EmitREBytecode(&state, re, state.treeDepth, re->program, state.result); + if (!endPC) { + js_DestroyRegExp(cx, re); + re = NULL; + goto out; + } + *endPC++ = REOP_END; + /* + * Check whether size was overestimated and shrink using realloc. + * This is safe since no pointers to newly parsed regexp or its parts + * besides re exist here. + */ +#if 0 + /* + * FIXME: Until bug 464866 is fixed, we can't move the re object so + * don't shrink it for now. + */ + if ((size_t)(endPC - re->program) != state.progLength + 1) { + JSRegExp *tmp; + JS_ASSERT((size_t)(endPC - re->program) < state.progLength + 1); + resize = offsetof(JSRegExp, program) + (endPC - re->program); + tmp = (JSRegExp *) JS_realloc(cx, re, resize); + if (tmp) + re = tmp; + } +#endif + + re->flags = flags; + re->parenCount = state.parenCount; + re->source = str; + +out: + JS_ARENA_RELEASE(&cx->tempPool, mark); + return re; +} + +JSRegExp * +js_NewRegExpOpt(JSContext *cx, JSString *str, JSString *opt, JSBool flat) +{ + uintN flags; + jschar *s; + size_t i, n; + char charBuf[2]; + + flags = 0; + if (opt) { + JSSTRING_CHARS_AND_LENGTH(opt, s, n); + for (i = 0; i < n; i++) { + switch (s[i]) { + case 'g': + flags |= JSREG_GLOB; + break; + case 'i': + flags |= JSREG_FOLD; + break; + case 'm': + flags |= JSREG_MULTILINE; + break; + case 'y': + flags |= JSREG_STICKY; + break; + default: + charBuf[0] = (char)s[i]; + charBuf[1] = '\0'; + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_BAD_FLAG, charBuf); + return NULL; + } + } + } + return js_NewRegExp(cx, NULL, str, flags, flat); +} + +/* + * Save the current state of the match - the position in the input + * text as well as the position in the bytecode. The state of any + * parent expressions is also saved (preceding state). + * Contents of parenCount parentheses from parenIndex are also saved. + */ +static REBackTrackData * +PushBackTrackState(REGlobalData *gData, REOp op, + jsbytecode *target, REMatchState *x, const jschar *cp, + size_t parenIndex, size_t parenCount) +{ + size_t i; + REBackTrackData *result = + (REBackTrackData *) ((char *)gData->backTrackSP + gData->cursz); + + size_t sz = sizeof(REBackTrackData) + + gData->stateStackTop * sizeof(REProgState) + + parenCount * sizeof(RECapture); + + ptrdiff_t btsize = gData->backTrackStackSize; + ptrdiff_t btincr = ((char *)result + sz) - + ((char *)gData->backTrackStack + btsize); + + re_debug("\tBT_Push: %lu,%lu", + (unsigned long) parenIndex, (unsigned long) parenCount); + + JS_COUNT_OPERATION(gData->cx, JSOW_JUMP * (1 + parenCount)); + if (btincr > 0) { + ptrdiff_t offset = (char *)result - (char *)gData->backTrackStack; + + JS_COUNT_OPERATION(gData->cx, JSOW_ALLOCATION); + btincr = JS_ROUNDUP(btincr, btsize); + JS_ARENA_GROW_CAST(gData->backTrackStack, REBackTrackData *, + &gData->cx->regexpPool, btsize, btincr); + if (!gData->backTrackStack) { + js_ReportOutOfScriptQuota(gData->cx); + gData->ok = JS_FALSE; + return NULL; + } + gData->backTrackStackSize = btsize + btincr; + result = (REBackTrackData *) ((char *)gData->backTrackStack + offset); + } + gData->backTrackSP = result; + result->sz = gData->cursz; + gData->cursz = sz; + + result->backtrack_op = op; + result->backtrack_pc = target; + result->cp = cp; + result->parenCount = parenCount; + result->parenIndex = parenIndex; + + result->saveStateStackTop = gData->stateStackTop; + JS_ASSERT(gData->stateStackTop); + memcpy(result + 1, gData->stateStack, + sizeof(REProgState) * result->saveStateStackTop); + + if (parenCount != 0) { + memcpy((char *)(result + 1) + + sizeof(REProgState) * result->saveStateStackTop, + &x->parens[parenIndex], + sizeof(RECapture) * parenCount); + for (i = 0; i != parenCount; i++) + x->parens[parenIndex + i].index = -1; + } + + return result; +} + + +/* + * Consecutive literal characters. + */ +#if 0 +static REMatchState * +FlatNMatcher(REGlobalData *gData, REMatchState *x, jschar *matchChars, + size_t length) +{ + size_t i; + if (length > gData->cpend - x->cp) + return NULL; + for (i = 0; i != length; i++) { + if (matchChars[i] != x->cp[i]) + return NULL; + } + x->cp += length; + return x; +} +#endif + +static JS_ALWAYS_INLINE REMatchState * +FlatNIMatcher(REGlobalData *gData, REMatchState *x, jschar *matchChars, + size_t length) +{ + size_t i; + JS_ASSERT(gData->cpend >= x->cp); + if (length > (size_t)(gData->cpend - x->cp)) + return NULL; + for (i = 0; i != length; i++) { + if (upcase(matchChars[i]) != upcase(x->cp[i])) + return NULL; + } + x->cp += length; + return x; +} + +/* + * 1. Evaluate DecimalEscape to obtain an EscapeValue E. + * 2. If E is not a character then go to step 6. + * 3. Let ch be E's character. + * 4. Let A be a one-element RECharSet containing the character ch. + * 5. Call CharacterSetMatcher(A, false) and return its Matcher result. + * 6. E must be an integer. Let n be that integer. + * 7. If n=0 or n>NCapturingParens then throw a SyntaxError exception. + * 8. Return an internal Matcher closure that takes two arguments, a State x + * and a Continuation c, and performs the following: + * 1. Let cap be x's captures internal array. + * 2. Let s be cap[n]. + * 3. If s is undefined, then call c(x) and return its result. + * 4. Let e be x's endIndex. + * 5. Let len be s's length. + * 6. Let f be e+len. + * 7. If f>InputLength, return failure. + * 8. If there exists an integer i between 0 (inclusive) and len (exclusive) + * such that Canonicalize(s[i]) is not the same character as + * Canonicalize(Input [e+i]), then return failure. + * 9. Let y be the State (f, cap). + * 10. Call c(y) and return its result. + */ +static REMatchState * +BackrefMatcher(REGlobalData *gData, REMatchState *x, size_t parenIndex) +{ + size_t len, i; + const jschar *parenContent; + RECapture *cap = &x->parens[parenIndex]; + + if (cap->index == -1) + return x; + + len = cap->length; + if (x->cp + len > gData->cpend) + return NULL; + + parenContent = &gData->cpbegin[cap->index]; + if (gData->regexp->flags & JSREG_FOLD) { + for (i = 0; i < len; i++) { + if (upcase(parenContent[i]) != upcase(x->cp[i])) + return NULL; + } + } else { + for (i = 0; i < len; i++) { + if (parenContent[i] != x->cp[i]) + return NULL; + } + } + x->cp += len; + return x; +} + + +/* Add a single character to the RECharSet */ +static void +AddCharacterToCharSet(RECharSet *cs, jschar c) +{ + uintN byteIndex = (uintN)(c >> 3); + JS_ASSERT(c <= cs->length); + cs->u.bits[byteIndex] |= 1 << (c & 0x7); +} + + +/* Add a character range, c1 to c2 (inclusive) to the RECharSet */ +static void +AddCharacterRangeToCharSet(RECharSet *cs, uintN c1, uintN c2) +{ + uintN i; + + uintN byteIndex1 = c1 >> 3; + uintN byteIndex2 = c2 >> 3; + + JS_ASSERT(c2 <= cs->length && c1 <= c2); + + c1 &= 0x7; + c2 &= 0x7; + + if (byteIndex1 == byteIndex2) { + cs->u.bits[byteIndex1] |= ((uint8)0xFF >> (7 - (c2 - c1))) << c1; + } else { + cs->u.bits[byteIndex1] |= 0xFF << c1; + for (i = byteIndex1 + 1; i < byteIndex2; i++) + cs->u.bits[i] = 0xFF; + cs->u.bits[byteIndex2] |= (uint8)0xFF >> (7 - c2); + } +} + +struct CharacterRange { + jschar start; + jschar end; +}; + +/* + * The following characters are taken from the ECMA-262 standard, section 7.2 + * and 7.3, and the Unicode 3 standard, Table 6-1. + */ +static const CharacterRange WhiteSpaceRanges[] = { + /* TAB, LF, VT, FF, CR */ + { 0x0009, 0x000D }, + /* SPACE */ + { 0x0020, 0x0020 }, + /* NO-BREAK SPACE */ + { 0x00A0, 0x00A0 }, + /* + * EN QUAD, EM QUAD, EN SPACE, EM SPACE, THREE-PER-EM SPACE, FOUR-PER-EM + * SPACE, SIX-PER-EM SPACE, FIGURE SPACE, PUNCTUATION SPACE, THIN SPACE, + * HAIR SPACE, ZERO WIDTH SPACE + */ + { 0x2000, 0x200B }, + /* LS, PS */ + { 0x2028, 0x2029 }, + /* NARROW NO-BREAK SPACE */ + { 0x202F, 0x202F }, + /* IDEOGRAPHIC SPACE */ + { 0x3000, 0x3000 } +}; + +/* ECMA-262 standard, section 15.10.2.6. */ +static const CharacterRange WordRanges[] = { + { jschar('0'), jschar('9') }, + { jschar('A'), jschar('Z') }, + { jschar('_'), jschar('_') }, + { jschar('a'), jschar('z') } +}; + +static void +AddCharacterRanges(RECharSet *charSet, + const CharacterRange *range, + const CharacterRange *end) +{ + for (; range < end; ++range) + AddCharacterRangeToCharSet(charSet, range->start, range->end); +} + +static void +AddInvertedCharacterRanges(RECharSet *charSet, + const CharacterRange *range, + const CharacterRange *end) +{ + uint16 previous = 0; + for (; range < end; ++range) { + AddCharacterRangeToCharSet(charSet, previous, range->start - 1); + previous = range->end + 1; + } + AddCharacterRangeToCharSet(charSet, previous, charSet->length); +} + +/* Compile the source of the class into a RECharSet */ +static JSBool +ProcessCharSet(REGlobalData *gData, RECharSet *charSet) +{ + const jschar *src, *end; + JSBool inRange = JS_FALSE; + jschar rangeStart = 0; + uintN byteLength, n; + jschar c, thisCh; + intN nDigits, i; + + JS_ASSERT(!charSet->converted); + /* + * Assert that startIndex and length points to chars inside [] inside + * source string. + */ + JS_ASSERT(1 <= charSet->u.src.startIndex); + JS_ASSERT(charSet->u.src.startIndex + < JSSTRING_LENGTH(gData->regexp->source)); + JS_ASSERT(charSet->u.src.length <= JSSTRING_LENGTH(gData->regexp->source) + - 1 - charSet->u.src.startIndex); + + charSet->converted = JS_TRUE; + src = JSSTRING_CHARS(gData->regexp->source) + charSet->u.src.startIndex; + end = src + charSet->u.src.length; + JS_ASSERT(src[-1] == '['); + JS_ASSERT(end[0] == ']'); + + byteLength = (charSet->length >> 3) + 1; + charSet->u.bits = (uint8 *)JS_malloc(gData->cx, byteLength); + if (!charSet->u.bits) { + JS_ReportOutOfMemory(gData->cx); + gData->ok = JS_FALSE; + return JS_FALSE; + } + memset(charSet->u.bits, 0, byteLength); + + if (src == end) + return JS_TRUE; + + if (*src == '^') { + JS_ASSERT(charSet->sense == JS_FALSE); + ++src; + } else { + JS_ASSERT(charSet->sense == JS_TRUE); + } + + while (src != end) { + switch (*src) { + case '\\': + ++src; + c = *src++; + switch (c) { + case 'b': + thisCh = 0x8; + break; + case 'f': + thisCh = 0xC; + break; + case 'n': + thisCh = 0xA; + break; + case 'r': + thisCh = 0xD; + break; + case 't': + thisCh = 0x9; + break; + case 'v': + thisCh = 0xB; + break; + case 'c': + if (src < end && JS_ISWORD(*src)) { + thisCh = (jschar)(*src++ & 0x1F); + } else { + --src; + thisCh = '\\'; + } + break; + case 'x': + nDigits = 2; + goto lexHex; + case 'u': + nDigits = 4; + lexHex: + n = 0; + for (i = 0; (i < nDigits) && (src < end); i++) { + uintN digit; + c = *src++; + if (!isASCIIHexDigit(c, &digit)) { + /* + * Back off to accepting the original '\' + * as a literal + */ + src -= i + 1; + n = '\\'; + break; + } + n = (n << 4) | digit; + } + thisCh = (jschar)n; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + /* + * This is a non-ECMA extension - decimal escapes (in this + * case, octal!) are supposed to be an error inside class + * ranges, but supported here for backwards compatibility. + */ + n = JS7_UNDEC(c); + c = *src; + if ('0' <= c && c <= '7') { + src++; + n = 8 * n + JS7_UNDEC(c); + c = *src; + if ('0' <= c && c <= '7') { + src++; + i = 8 * n + JS7_UNDEC(c); + if (i <= 0377) + n = i; + else + src--; + } + } + thisCh = (jschar)n; + break; + + case 'd': + AddCharacterRangeToCharSet(charSet, '0', '9'); + continue; /* don't need range processing */ + case 'D': + AddCharacterRangeToCharSet(charSet, 0, '0' - 1); + AddCharacterRangeToCharSet(charSet, + (jschar)('9' + 1), + (jschar)charSet->length); + continue; + case 's': + AddCharacterRanges(charSet, WhiteSpaceRanges, + WhiteSpaceRanges + JS_ARRAY_LENGTH(WhiteSpaceRanges)); + continue; + case 'S': + AddInvertedCharacterRanges(charSet, WhiteSpaceRanges, + WhiteSpaceRanges + JS_ARRAY_LENGTH(WhiteSpaceRanges)); + continue; + case 'w': + AddCharacterRanges(charSet, WordRanges, + WordRanges + JS_ARRAY_LENGTH(WordRanges)); + continue; + case 'W': + AddInvertedCharacterRanges(charSet, WordRanges, + WordRanges + JS_ARRAY_LENGTH(WordRanges)); + continue; + default: + thisCh = c; + break; + + } + break; + + default: + thisCh = *src++; + break; + + } + if (inRange) { + if (gData->regexp->flags & JSREG_FOLD) { + int i; + + JS_ASSERT(rangeStart <= thisCh); + for (i = rangeStart; i <= thisCh; i++) { + jschar uch, dch; + + AddCharacterToCharSet(charSet, i); + uch = upcase(i); + dch = downcase(i); + if (i != uch) + AddCharacterToCharSet(charSet, uch); + if (i != dch) + AddCharacterToCharSet(charSet, dch); + } + } else { + AddCharacterRangeToCharSet(charSet, rangeStart, thisCh); + } + inRange = JS_FALSE; + } else { + if (gData->regexp->flags & JSREG_FOLD) { + AddCharacterToCharSet(charSet, upcase(thisCh)); + AddCharacterToCharSet(charSet, downcase(thisCh)); + } else { + AddCharacterToCharSet(charSet, thisCh); + } + if (src < end - 1) { + if (*src == '-') { + ++src; + inRange = JS_TRUE; + rangeStart = thisCh; + } + } + } + } + return JS_TRUE; +} + +void +js_DestroyRegExp(JSContext *cx, JSRegExp *re) +{ + if (JS_ATOMIC_DECREMENT(&re->nrefs) == 0) { +#ifdef JS_TRACER + /* Don't reuse this compiled code for some new regexp at same addr. */ + Fragment* fragment = JS_TRACE_MONITOR(cx).reFragmento->getLoop(re); + if (fragment) + fragment->blacklist(); +#endif + if (re->classList) { + uintN i; + for (i = 0; i < re->classCount; i++) { + if (re->classList[i].converted) + JS_free(cx, re->classList[i].u.bits); + re->classList[i].u.bits = NULL; + } + JS_free(cx, re->classList); + } + JS_free(cx, re); + } +} + +static JSBool +ReallocStateStack(REGlobalData *gData) +{ + size_t limit = gData->stateStackLimit; + size_t sz = sizeof(REProgState) * limit; + + JS_ARENA_GROW_CAST(gData->stateStack, REProgState *, + &gData->cx->regexpPool, sz, sz); + if (!gData->stateStack) { + js_ReportOutOfScriptQuota(gData->cx); + gData->ok = JS_FALSE; + return JS_FALSE; + } + gData->stateStackLimit = limit + limit; + return JS_TRUE; +} + +#define PUSH_STATE_STACK(data) \ + JS_BEGIN_MACRO \ + ++(data)->stateStackTop; \ + if ((data)->stateStackTop == (data)->stateStackLimit && \ + !ReallocStateStack((data))) { \ + return NULL; \ + } \ + JS_END_MACRO + +/* + * Apply the current op against the given input to see if it's going to match + * or fail. Return false if we don't get a match, true if we do. If updatecp is + * true, then update the current state's cp. Always update startpc to the next + * op. + */ +static JS_ALWAYS_INLINE REMatchState * +SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op, + jsbytecode **startpc, JSBool updatecp) +{ + REMatchState *result = NULL; + jschar matchCh; + size_t parenIndex; + size_t offset, length, index; + jsbytecode *pc = *startpc; /* pc has already been incremented past op */ + jschar *source; + const jschar *startcp = x->cp; + jschar ch; + RECharSet *charSet; + +#ifdef REGEXP_DEBUG + const char *opname = reop_names[op]; + re_debug("\n%06d: %*s%s", pc - gData->regexp->program, + gData->stateStackTop * 2, "", opname); +#endif + switch (op) { + case REOP_EMPTY: + result = x; + break; + case REOP_BOL: + if (x->cp != gData->cpbegin) { + if (!gData->cx->regExpStatics.multiline && + !(gData->regexp->flags & JSREG_MULTILINE)) { + break; + } + if (!RE_IS_LINE_TERM(x->cp[-1])) + break; + } + result = x; + break; + case REOP_EOL: + if (x->cp != gData->cpend) { + if (!gData->cx->regExpStatics.multiline && + !(gData->regexp->flags & JSREG_MULTILINE)) { + break; + } + if (!RE_IS_LINE_TERM(*x->cp)) + break; + } + result = x; + break; + case REOP_WBDRY: + if ((x->cp == gData->cpbegin || !JS_ISWORD(x->cp[-1])) ^ + !(x->cp != gData->cpend && JS_ISWORD(*x->cp))) { + result = x; + } + break; + case REOP_WNONBDRY: + if ((x->cp == gData->cpbegin || !JS_ISWORD(x->cp[-1])) ^ + (x->cp != gData->cpend && JS_ISWORD(*x->cp))) { + result = x; + } + break; + case REOP_DOT: + if (x->cp != gData->cpend && !RE_IS_LINE_TERM(*x->cp)) { + result = x; + result->cp++; + } + break; + case REOP_DIGIT: + if (x->cp != gData->cpend && JS7_ISDEC(*x->cp)) { + result = x; + result->cp++; + } + break; + case REOP_NONDIGIT: + if (x->cp != gData->cpend && !JS7_ISDEC(*x->cp)) { + result = x; + result->cp++; + } + break; + case REOP_ALNUM: + if (x->cp != gData->cpend && JS_ISWORD(*x->cp)) { + result = x; + result->cp++; + } + break; + case REOP_NONALNUM: + if (x->cp != gData->cpend && !JS_ISWORD(*x->cp)) { + result = x; + result->cp++; + } + break; + case REOP_SPACE: + if (x->cp != gData->cpend && JS_ISSPACE(*x->cp)) { + result = x; + result->cp++; + } + break; + case REOP_NONSPACE: + if (x->cp != gData->cpend && !JS_ISSPACE(*x->cp)) { + result = x; + result->cp++; + } + break; + case REOP_BACKREF: + pc = ReadCompactIndex(pc, &parenIndex); + JS_ASSERT(parenIndex < gData->regexp->parenCount); + result = BackrefMatcher(gData, x, parenIndex); + break; + case REOP_FLAT: + pc = ReadCompactIndex(pc, &offset); + JS_ASSERT(offset < JSSTRING_LENGTH(gData->regexp->source)); + pc = ReadCompactIndex(pc, &length); + JS_ASSERT(1 <= length); + JS_ASSERT(length <= JSSTRING_LENGTH(gData->regexp->source) - offset); + if (length <= (size_t)(gData->cpend - x->cp)) { + source = JSSTRING_CHARS(gData->regexp->source) + offset; + re_debug_chars(source, length); + for (index = 0; index != length; index++) { + if (source[index] != x->cp[index]) + return NULL; + } + x->cp += length; + result = x; + } + break; + case REOP_FLAT1: + matchCh = *pc++; + re_debug(" '%c' == '%c'", (char)matchCh, (char)*x->cp); + if (x->cp != gData->cpend && *x->cp == matchCh) { + result = x; + result->cp++; + } + break; + case REOP_FLATi: + pc = ReadCompactIndex(pc, &offset); + JS_ASSERT(offset < JSSTRING_LENGTH(gData->regexp->source)); + pc = ReadCompactIndex(pc, &length); + JS_ASSERT(1 <= length); + JS_ASSERT(length <= JSSTRING_LENGTH(gData->regexp->source) - offset); + source = JSSTRING_CHARS(gData->regexp->source); + result = FlatNIMatcher(gData, x, source + offset, length); + break; + case REOP_FLAT1i: + matchCh = *pc++; + if (x->cp != gData->cpend && upcase(*x->cp) == upcase(matchCh)) { + result = x; + result->cp++; + } + break; + case REOP_UCFLAT1: + matchCh = GET_ARG(pc); + re_debug(" '%c' == '%c'", (char)matchCh, (char)*x->cp); + pc += ARG_LEN; + if (x->cp != gData->cpend && *x->cp == matchCh) { + result = x; + result->cp++; + } + break; + case REOP_UCFLAT1i: + matchCh = GET_ARG(pc); + pc += ARG_LEN; + if (x->cp != gData->cpend && upcase(*x->cp) == upcase(matchCh)) { + result = x; + result->cp++; + } + break; + case REOP_CLASS: + pc = ReadCompactIndex(pc, &index); + JS_ASSERT(index < gData->regexp->classCount); + if (x->cp != gData->cpend) { + charSet = &gData->regexp->classList[index]; + JS_ASSERT(charSet->converted); + ch = *x->cp; + index = ch >> 3; + if (charSet->length != 0 && + ch <= charSet->length && + (charSet->u.bits[index] & (1 << (ch & 0x7)))) { + result = x; + result->cp++; + } + } + break; + case REOP_NCLASS: + pc = ReadCompactIndex(pc, &index); + JS_ASSERT(index < gData->regexp->classCount); + if (x->cp != gData->cpend) { + charSet = &gData->regexp->classList[index]; + JS_ASSERT(charSet->converted); + ch = *x->cp; + index = ch >> 3; + if (charSet->length == 0 || + ch > charSet->length || + !(charSet->u.bits[index] & (1 << (ch & 0x7)))) { + result = x; + result->cp++; + } + } + break; + + default: + JS_ASSERT(JS_FALSE); + } + if (result) { + if (!updatecp) + x->cp = startcp; + *startpc = pc; + re_debug(" * "); + return result; + } + x->cp = startcp; + return NULL; +} + +static JS_ALWAYS_INLINE REMatchState * +ExecuteREBytecode(REGlobalData *gData, REMatchState *x) +{ + REMatchState *result = NULL; + REBackTrackData *backTrackData; + jsbytecode *nextpc, *testpc; + REOp nextop; + RECapture *cap; + REProgState *curState; + const jschar *startcp; + size_t parenIndex, k; + size_t parenSoFar = 0; + + jschar matchCh1, matchCh2; + RECharSet *charSet; + + JSBool anchor; + jsbytecode *pc = gData->regexp->program; + REOp op = (REOp) *pc++; + + /* + * If the first node is a simple match, step the index into the string + * until that match is made, or fail if it can't be found at all. + */ + if (REOP_IS_SIMPLE(op) && !(gData->regexp->flags & JSREG_STICKY)) { + anchor = JS_FALSE; + while (x->cp <= gData->cpend) { + nextpc = pc; /* reset back to start each time */ + result = SimpleMatch(gData, x, op, &nextpc, JS_TRUE); + if (result) { + anchor = JS_TRUE; + x = result; + pc = nextpc; /* accept skip to next opcode */ + op = (REOp) *pc++; + JS_ASSERT(op < REOP_LIMIT); + break; + } + gData->skipped++; + x->cp++; + } + if (!anchor) + goto bad; + } + + for (;;) { +#ifdef REGEXP_DEBUG + const char *opname = reop_names[op]; + re_debug("\n%06d: %*s%s", pc - gData->regexp->program, + gData->stateStackTop * 2, "", opname); +#endif + if (REOP_IS_SIMPLE(op)) { + result = SimpleMatch(gData, x, op, &pc, JS_TRUE); + } else { + curState = &gData->stateStack[gData->stateStackTop]; + switch (op) { + case REOP_END: + goto good; + case REOP_ALTPREREQ2: + nextpc = pc + GET_OFFSET(pc); /* start of next op */ + pc += ARG_LEN; + matchCh2 = GET_ARG(pc); + pc += ARG_LEN; + k = GET_ARG(pc); + pc += ARG_LEN; + + if (x->cp != gData->cpend) { + if (*x->cp == matchCh2) + goto doAlt; + + charSet = &gData->regexp->classList[k]; + if (!charSet->converted && !ProcessCharSet(gData, charSet)) + goto bad; + matchCh1 = *x->cp; + k = matchCh1 >> 3; + if ((charSet->length == 0 || + matchCh1 > charSet->length || + !(charSet->u.bits[k] & (1 << (matchCh1 & 0x7)))) ^ + charSet->sense) { + goto doAlt; + } + } + result = NULL; + break; + + case REOP_ALTPREREQ: + nextpc = pc + GET_OFFSET(pc); /* start of next op */ + pc += ARG_LEN; + matchCh1 = GET_ARG(pc); + pc += ARG_LEN; + matchCh2 = GET_ARG(pc); + pc += ARG_LEN; + if (x->cp == gData->cpend || + (*x->cp != matchCh1 && *x->cp != matchCh2)) { + result = NULL; + break; + } + /* else false thru... */ + + case REOP_ALT: + doAlt: + nextpc = pc + GET_OFFSET(pc); /* start of next alternate */ + pc += ARG_LEN; /* start of this alternate */ + curState->parenSoFar = parenSoFar; + PUSH_STATE_STACK(gData); + op = (REOp) *pc++; + startcp = x->cp; + if (REOP_IS_SIMPLE(op)) { + if (!SimpleMatch(gData, x, op, &pc, JS_TRUE)) { + op = (REOp) *nextpc++; + pc = nextpc; + continue; + } + result = x; + op = (REOp) *pc++; + } + nextop = (REOp) *nextpc++; + if (!PushBackTrackState(gData, nextop, nextpc, x, startcp, 0, 0)) + goto bad; + continue; + + /* + * Occurs at (successful) end of REOP_ALT, + */ + case REOP_JUMP: + /* + * If we have not gotten a result here, it is because of an + * empty match. Do the same thing REOP_EMPTY would do. + */ + if (!result) + result = x; + + --gData->stateStackTop; + pc += GET_OFFSET(pc); + op = (REOp) *pc++; + continue; + + /* + * Occurs at last (successful) end of REOP_ALT, + */ + case REOP_ENDALT: + /* + * If we have not gotten a result here, it is because of an + * empty match. Do the same thing REOP_EMPTY would do. + */ + if (!result) + result = x; + + --gData->stateStackTop; + op = (REOp) *pc++; + continue; + + case REOP_LPAREN: + pc = ReadCompactIndex(pc, &parenIndex); + re_debug("[ %lu ]", (unsigned long) parenIndex); + JS_ASSERT(parenIndex < gData->regexp->parenCount); + if (parenIndex + 1 > parenSoFar) + parenSoFar = parenIndex + 1; + x->parens[parenIndex].index = x->cp - gData->cpbegin; + x->parens[parenIndex].length = 0; + op = (REOp) *pc++; + continue; + + case REOP_RPAREN: + { + ptrdiff_t delta; + + pc = ReadCompactIndex(pc, &parenIndex); + JS_ASSERT(parenIndex < gData->regexp->parenCount); + cap = &x->parens[parenIndex]; + delta = x->cp - (gData->cpbegin + cap->index); + cap->length = (delta < 0) ? 0 : (size_t) delta; + op = (REOp) *pc++; + + if (!result) + result = x; + continue; + } + case REOP_ASSERT: + nextpc = pc + GET_OFFSET(pc); /* start of term after ASSERT */ + pc += ARG_LEN; /* start of ASSERT child */ + op = (REOp) *pc++; + testpc = pc; + if (REOP_IS_SIMPLE(op) && + !SimpleMatch(gData, x, op, &testpc, JS_FALSE)) { + result = NULL; + break; + } + curState->u.assertion.top = + (char *)gData->backTrackSP - (char *)gData->backTrackStack; + curState->u.assertion.sz = gData->cursz; + curState->index = x->cp - gData->cpbegin; + curState->parenSoFar = parenSoFar; + PUSH_STATE_STACK(gData); + if (!PushBackTrackState(gData, REOP_ASSERTTEST, + nextpc, x, x->cp, 0, 0)) { + goto bad; + } + continue; + + case REOP_ASSERT_NOT: + nextpc = pc + GET_OFFSET(pc); + pc += ARG_LEN; + op = (REOp) *pc++; + testpc = pc; + if (REOP_IS_SIMPLE(op) /* Note - fail to fail! */ && + SimpleMatch(gData, x, op, &testpc, JS_FALSE) && + *testpc == REOP_ASSERTNOTTEST) { + result = NULL; + break; + } + curState->u.assertion.top + = (char *)gData->backTrackSP - + (char *)gData->backTrackStack; + curState->u.assertion.sz = gData->cursz; + curState->index = x->cp - gData->cpbegin; + curState->parenSoFar = parenSoFar; + PUSH_STATE_STACK(gData); + if (!PushBackTrackState(gData, REOP_ASSERTNOTTEST, + nextpc, x, x->cp, 0, 0)) { + goto bad; + } + continue; + + case REOP_ASSERTTEST: + --gData->stateStackTop; + --curState; + x->cp = gData->cpbegin + curState->index; + gData->backTrackSP = + (REBackTrackData *) ((char *)gData->backTrackStack + + curState->u.assertion.top); + gData->cursz = curState->u.assertion.sz; + if (result) + result = x; + break; + + case REOP_ASSERTNOTTEST: + --gData->stateStackTop; + --curState; + x->cp = gData->cpbegin + curState->index; + gData->backTrackSP = + (REBackTrackData *) ((char *)gData->backTrackStack + + curState->u.assertion.top); + gData->cursz = curState->u.assertion.sz; + result = (!result) ? x : NULL; + break; + case REOP_STAR: + curState->u.quantifier.min = 0; + curState->u.quantifier.max = (uintN)-1; + goto quantcommon; + case REOP_PLUS: + curState->u.quantifier.min = 1; + curState->u.quantifier.max = (uintN)-1; + goto quantcommon; + case REOP_OPT: + curState->u.quantifier.min = 0; + curState->u.quantifier.max = 1; + goto quantcommon; + case REOP_QUANT: + pc = ReadCompactIndex(pc, &k); + curState->u.quantifier.min = k; + pc = ReadCompactIndex(pc, &k); + /* max is k - 1 to use one byte for (uintN)-1 sentinel. */ + curState->u.quantifier.max = k - 1; + JS_ASSERT(curState->u.quantifier.min + <= curState->u.quantifier.max); + quantcommon: + if (curState->u.quantifier.max == 0) { + pc = pc + GET_OFFSET(pc); + op = (REOp) *pc++; + result = x; + continue; + } + /* Step over */ + nextpc = pc + ARG_LEN; + op = (REOp) *nextpc++; + startcp = x->cp; + if (REOP_IS_SIMPLE(op)) { + if (!SimpleMatch(gData, x, op, &nextpc, JS_TRUE)) { + if (curState->u.quantifier.min == 0) + result = x; + else + result = NULL; + pc = pc + GET_OFFSET(pc); + break; + } + op = (REOp) *nextpc++; + result = x; + } + curState->index = startcp - gData->cpbegin; + curState->continue_op = REOP_REPEAT; + curState->continue_pc = pc; + curState->parenSoFar = parenSoFar; + PUSH_STATE_STACK(gData); + if (curState->u.quantifier.min == 0 && + !PushBackTrackState(gData, REOP_REPEAT, pc, x, startcp, + 0, 0)) { + goto bad; + } + pc = nextpc; + continue; + + case REOP_ENDCHILD: /* marks the end of a quantifier child */ + pc = curState[-1].continue_pc; + op = (REOp) curState[-1].continue_op; + + if (!result) + result = x; + continue; + + case REOP_REPEAT: + --curState; + do { + --gData->stateStackTop; + if (!result) { + /* Failed, see if we have enough children. */ + if (curState->u.quantifier.min == 0) + goto repeatDone; + goto break_switch; + } + if (curState->u.quantifier.min == 0 && + x->cp == gData->cpbegin + curState->index) { + /* matched an empty string, that'll get us nowhere */ + result = NULL; + goto break_switch; + } + if (curState->u.quantifier.min != 0) + curState->u.quantifier.min--; + if (curState->u.quantifier.max != (uintN) -1) + curState->u.quantifier.max--; + if (curState->u.quantifier.max == 0) + goto repeatDone; + nextpc = pc + ARG_LEN; + nextop = (REOp) *nextpc; + startcp = x->cp; + if (REOP_IS_SIMPLE(nextop)) { + nextpc++; + if (!SimpleMatch(gData, x, nextop, &nextpc, JS_TRUE)) { + if (curState->u.quantifier.min == 0) + goto repeatDone; + result = NULL; + goto break_switch; + } + result = x; + } + curState->index = startcp - gData->cpbegin; + PUSH_STATE_STACK(gData); + if (curState->u.quantifier.min == 0 && + !PushBackTrackState(gData, REOP_REPEAT, + pc, x, startcp, + curState->parenSoFar, + parenSoFar - + curState->parenSoFar)) { + goto bad; + } + } while (*nextpc == REOP_ENDCHILD); + pc = nextpc; + op = (REOp) *pc++; + parenSoFar = curState->parenSoFar; + continue; + + repeatDone: + result = x; + pc += GET_OFFSET(pc); + goto break_switch; + + case REOP_MINIMALSTAR: + curState->u.quantifier.min = 0; + curState->u.quantifier.max = (uintN)-1; + goto minimalquantcommon; + case REOP_MINIMALPLUS: + curState->u.quantifier.min = 1; + curState->u.quantifier.max = (uintN)-1; + goto minimalquantcommon; + case REOP_MINIMALOPT: + curState->u.quantifier.min = 0; + curState->u.quantifier.max = 1; + goto minimalquantcommon; + case REOP_MINIMALQUANT: + pc = ReadCompactIndex(pc, &k); + curState->u.quantifier.min = k; + pc = ReadCompactIndex(pc, &k); + /* See REOP_QUANT comments about k - 1. */ + curState->u.quantifier.max = k - 1; + JS_ASSERT(curState->u.quantifier.min + <= curState->u.quantifier.max); + minimalquantcommon: + curState->index = x->cp - gData->cpbegin; + curState->parenSoFar = parenSoFar; + PUSH_STATE_STACK(gData); + if (curState->u.quantifier.min != 0) { + curState->continue_op = REOP_MINIMALREPEAT; + curState->continue_pc = pc; + /* step over */ + pc += OFFSET_LEN; + op = (REOp) *pc++; + } else { + if (!PushBackTrackState(gData, REOP_MINIMALREPEAT, + pc, x, x->cp, 0, 0)) { + goto bad; + } + --gData->stateStackTop; + pc = pc + GET_OFFSET(pc); + op = (REOp) *pc++; + } + continue; + + case REOP_MINIMALREPEAT: + --gData->stateStackTop; + --curState; + + re_debug("{%d,%d}", curState->u.quantifier.min, + curState->u.quantifier.max); +#define PREPARE_REPEAT() \ + JS_BEGIN_MACRO \ + curState->index = x->cp - gData->cpbegin; \ + curState->continue_op = REOP_MINIMALREPEAT; \ + curState->continue_pc = pc; \ + pc += ARG_LEN; \ + for (k = curState->parenSoFar; k < parenSoFar; k++) \ + x->parens[k].index = -1; \ + PUSH_STATE_STACK(gData); \ + op = (REOp) *pc++; \ + JS_ASSERT(op < REOP_LIMIT); \ + JS_END_MACRO + + if (!result) { + re_debug(" - "); + /* + * Non-greedy failure - try to consume another child. + */ + if (curState->u.quantifier.max == (uintN) -1 || + curState->u.quantifier.max > 0) { + PREPARE_REPEAT(); + continue; + } + /* Don't need to adjust pc since we're going to pop. */ + break; + } + if (curState->u.quantifier.min == 0 && + x->cp == gData->cpbegin + curState->index) { + /* Matched an empty string, that'll get us nowhere. */ + result = NULL; + break; + } + if (curState->u.quantifier.min != 0) + curState->u.quantifier.min--; + if (curState->u.quantifier.max != (uintN) -1) + curState->u.quantifier.max--; + if (curState->u.quantifier.min != 0) { + PREPARE_REPEAT(); + continue; + } + curState->index = x->cp - gData->cpbegin; + curState->parenSoFar = parenSoFar; + PUSH_STATE_STACK(gData); + if (!PushBackTrackState(gData, REOP_MINIMALREPEAT, + pc, x, x->cp, + curState->parenSoFar, + parenSoFar - curState->parenSoFar)) { + goto bad; + } + --gData->stateStackTop; + pc = pc + GET_OFFSET(pc); + op = (REOp) *pc++; + JS_ASSERT(op < REOP_LIMIT); + continue; + default: + JS_ASSERT(JS_FALSE); + result = NULL; + } + break_switch:; + } + + /* + * If the match failed and there's a backtrack option, take it. + * Otherwise this is a complete and utter failure. + */ + if (!result) { + if (gData->cursz == 0) + return NULL; + if (!JS_CHECK_OPERATION_LIMIT(gData->cx, JSOW_JUMP)) { + gData->ok = JS_FALSE; + return NULL; + } + + /* Potentially detect explosive regex here. */ + gData->backTrackCount++; + if (gData->backTrackLimit && + gData->backTrackCount >= gData->backTrackLimit) { + JS_ReportErrorNumber(gData->cx, js_GetErrorMessage, NULL, + JSMSG_REGEXP_TOO_COMPLEX); + gData->ok = JS_FALSE; + return NULL; + } + + backTrackData = gData->backTrackSP; + gData->cursz = backTrackData->sz; + gData->backTrackSP = + (REBackTrackData *) ((char *)backTrackData - backTrackData->sz); + x->cp = backTrackData->cp; + pc = backTrackData->backtrack_pc; + op = (REOp) backTrackData->backtrack_op; + JS_ASSERT(op < REOP_LIMIT); + gData->stateStackTop = backTrackData->saveStateStackTop; + JS_ASSERT(gData->stateStackTop); + + memcpy(gData->stateStack, backTrackData + 1, + sizeof(REProgState) * backTrackData->saveStateStackTop); + curState = &gData->stateStack[gData->stateStackTop - 1]; + + if (backTrackData->parenCount) { + memcpy(&x->parens[backTrackData->parenIndex], + (char *)(backTrackData + 1) + + sizeof(REProgState) * backTrackData->saveStateStackTop, + sizeof(RECapture) * backTrackData->parenCount); + parenSoFar = backTrackData->parenIndex + backTrackData->parenCount; + } else { + for (k = curState->parenSoFar; k < parenSoFar; k++) + x->parens[k].index = -1; + parenSoFar = curState->parenSoFar; + } + + re_debug("\tBT_Pop: %ld,%ld", + (unsigned long) backTrackData->parenIndex, + (unsigned long) backTrackData->parenCount); + continue; + } + x = result; + + /* + * Continue with the expression. + */ + op = (REOp)*pc++; + JS_ASSERT(op < REOP_LIMIT); + } + +bad: + re_debug("\n"); + return NULL; + +good: + re_debug("\n"); + return x; +} + +static REMatchState * +MatchRegExp(REGlobalData *gData, REMatchState *x) +{ + REMatchState *result; + const jschar *cp = x->cp; + const jschar *cp2; + uintN j; +#ifdef JS_TRACER + Fragment *fragment; + + /* Run with native regexp if possible. */ + if (TRACING_ENABLED(gData->cx) && + ((fragment = JS_TRACE_MONITOR(gData->cx).reFragmento->getLoop(gData->regexp)) != NULL) + && fragment->code() && !fragment->isBlacklisted()) { + union { NIns *code; REMatchState* (FASTCALL *func)(void*, void*); } u; + u.code = fragment->code(); + REMatchState *lr; + gData->skipped = (ptrdiff_t) x->cp; + + debug_only_v(printf("entering REGEXP trace at %s:%u@%u, code: %p\n", + gData->cx->fp->script->filename, + js_FramePCToLineNumber(gData->cx, gData->cx->fp), + FramePCOffset(gData->cx->fp), + fragment->code());); + +#if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32) + SIMULATE_FASTCALL(lr, x, gData, u.func); +#else + lr = u.func(x, gData); +#endif + + debug_only_v(printf("leaving REGEXP trace\n")); + + gData->skipped = ((const jschar *) gData->skipped) - cp; + return lr; + } +#endif + /* + * Have to include the position beyond the last character + * in order to detect end-of-input/line condition. + */ + for (cp2 = cp; cp2 <= gData->cpend; cp2++) { + gData->skipped = cp2 - cp; + x->cp = cp2; + for (j = 0; j < gData->regexp->parenCount; j++) + x->parens[j].index = -1; + result = ExecuteREBytecode(gData, x); + if (!gData->ok || result || (gData->regexp->flags & JSREG_STICKY)) + return result; + gData->backTrackSP = gData->backTrackStack; + gData->cursz = 0; + gData->stateStackTop = 0; + cp2 = cp + gData->skipped; + } + return NULL; +} + +#define MIN_BACKTRACK_LIMIT 400000 + +static REMatchState * +InitMatch(JSContext *cx, REGlobalData *gData, JSRegExp *re, size_t length) +{ + REMatchState *result; + uintN i; + + gData->backTrackStackSize = INITIAL_BACKTRACK; + JS_ARENA_ALLOCATE_CAST(gData->backTrackStack, REBackTrackData *, + &cx->regexpPool, + INITIAL_BACKTRACK); + if (!gData->backTrackStack) + goto bad; + + gData->backTrackSP = gData->backTrackStack; + gData->cursz = 0; + gData->backTrackCount = 0; + gData->backTrackLimit = 0; + if (JS_GetOptions(cx) & JSOPTION_RELIMIT) { + gData->backTrackLimit = length * length * length; /* O(n^3) */ + if (gData->backTrackLimit < MIN_BACKTRACK_LIMIT) + gData->backTrackLimit = MIN_BACKTRACK_LIMIT; + } + + gData->stateStackLimit = INITIAL_STATESTACK; + JS_ARENA_ALLOCATE_CAST(gData->stateStack, REProgState *, + &cx->regexpPool, + sizeof(REProgState) * INITIAL_STATESTACK); + if (!gData->stateStack) + goto bad; + + gData->stateStackTop = 0; + gData->cx = cx; + gData->regexp = re; + gData->ok = JS_TRUE; + + JS_ARENA_ALLOCATE_CAST(result, REMatchState *, + &cx->regexpPool, + offsetof(REMatchState, parens) + + re->parenCount * sizeof(RECapture)); + if (!result) + goto bad; + + for (i = 0; i < re->classCount; i++) { + if (!re->classList[i].converted && + !ProcessCharSet(gData, &re->classList[i])) { + return NULL; + } + } + + return result; + +bad: + js_ReportOutOfScriptQuota(cx); + gData->ok = JS_FALSE; + return NULL; +} + +JSBool +js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, + JSBool test, jsval *rval) +{ + REGlobalData gData; + REMatchState *x, *result; + + const jschar *cp, *ep; + size_t i, length, start; + JSSubString *morepar; + JSBool ok; + JSRegExpStatics *res; + ptrdiff_t matchlen; + uintN num, morenum; + JSString *parstr, *matchstr; + JSObject *obj; + + RECapture *parsub = NULL; + void *mark; + int64 *timestamp; + + /* + * It's safe to load from cp because JSStrings have a zero at the end, + * and we never let cp get beyond cpend. + */ + start = *indexp; + JSSTRING_CHARS_AND_LENGTH(str, cp, length); + if (start > length) + start = length; + gData.cpbegin = cp; + gData.cpend = cp + length; + cp += start; + gData.start = start; + gData.skipped = 0; + + if (!cx->regexpPool.first.next) { + /* + * The first arena in the regexpPool must have a timestamp at its base. + */ + JS_ARENA_ALLOCATE_CAST(timestamp, int64 *, + &cx->regexpPool, sizeof *timestamp); + if (!timestamp) + return JS_FALSE; + *timestamp = JS_Now(); + } + mark = JS_ARENA_MARK(&cx->regexpPool); + + x = InitMatch(cx, &gData, re, length); + + if (!x) { + ok = JS_FALSE; + goto out; + } + x->cp = cp; + + /* + * Call the recursive matcher to do the real work. Return null on mismatch + * whether testing or not. On match, return an extended Array object. + */ + result = MatchRegExp(&gData, x); + ok = gData.ok; + if (!ok) + goto out; + if (!result) { + *rval = JSVAL_NULL; + goto out; + } + cp = result->cp; + i = cp - gData.cpbegin; + *indexp = i; + matchlen = i - (start + gData.skipped); + ep = cp; + cp -= matchlen; + + if (test) { + /* + * Testing for a match and updating cx->regExpStatics: don't allocate + * an array object, do return true. + */ + *rval = JSVAL_TRUE; + + /* Avoid warning. (gcc doesn't detect that obj is needed iff !test); */ + obj = NULL; + } else { + /* + * The array returned on match has element 0 bound to the matched + * string, elements 1 through state.parenCount bound to the paren + * matches, an index property telling the length of the left context, + * and an input property referring to the input string. + */ + obj = js_NewSlowArrayObject(cx); + if (!obj) { + ok = JS_FALSE; + goto out; + } + *rval = OBJECT_TO_JSVAL(obj); + +#define DEFVAL(val, id) { \ + ok = js_DefineProperty(cx, obj, id, val, \ + JS_PropertyStub, JS_PropertyStub, \ + JSPROP_ENUMERATE, NULL); \ + if (!ok) { \ + cx->weakRoots.newborn[GCX_OBJECT] = NULL; \ + cx->weakRoots.newborn[GCX_STRING] = NULL; \ + goto out; \ + } \ +} + + matchstr = js_NewStringCopyN(cx, cp, matchlen); + if (!matchstr) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + ok = JS_FALSE; + goto out; + } + DEFVAL(STRING_TO_JSVAL(matchstr), INT_TO_JSID(0)); + } + + res = &cx->regExpStatics; + res->input = str; + res->parenCount = re->parenCount; + if (re->parenCount == 0) { + res->lastParen = js_EmptySubString; + } else { + for (num = 0; num < re->parenCount; num++) { + parsub = &result->parens[num]; + if (num < 9) { + if (parsub->index == -1) { + res->parens[num].chars = NULL; + res->parens[num].length = 0; + } else { + res->parens[num].chars = gData.cpbegin + parsub->index; + res->parens[num].length = parsub->length; + } + } else { + morenum = num - 9; + morepar = res->moreParens; + if (!morepar) { + res->moreLength = 10; + morepar = (JSSubString*) + JS_malloc(cx, 10 * sizeof(JSSubString)); + } else if (morenum >= res->moreLength) { + res->moreLength += 10; + morepar = (JSSubString*) + JS_realloc(cx, morepar, + res->moreLength * sizeof(JSSubString)); + } + if (!morepar) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + cx->weakRoots.newborn[GCX_STRING] = NULL; + ok = JS_FALSE; + goto out; + } + res->moreParens = morepar; + if (parsub->index == -1) { + morepar[morenum].chars = NULL; + morepar[morenum].length = 0; + } else { + morepar[morenum].chars = gData.cpbegin + parsub->index; + morepar[morenum].length = parsub->length; + } + } + if (test) + continue; + if (parsub->index == -1) { + ok = js_DefineProperty(cx, obj, INT_TO_JSID(num + 1), + JSVAL_VOID, NULL, NULL, + JSPROP_ENUMERATE, NULL); + } else { + parstr = js_NewStringCopyN(cx, gData.cpbegin + parsub->index, + parsub->length); + if (!parstr) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + cx->weakRoots.newborn[GCX_STRING] = NULL; + ok = JS_FALSE; + goto out; + } + ok = js_DefineProperty(cx, obj, INT_TO_JSID(num + 1), + STRING_TO_JSVAL(parstr), NULL, NULL, + JSPROP_ENUMERATE, NULL); + } + if (!ok) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + cx->weakRoots.newborn[GCX_STRING] = NULL; + goto out; + } + } + if (parsub->index == -1) { + res->lastParen = js_EmptySubString; + } else { + res->lastParen.chars = gData.cpbegin + parsub->index; + res->lastParen.length = parsub->length; + } + } + + if (!test) { + /* + * Define the index and input properties last for better for/in loop + * order (so they come after the elements). + */ + DEFVAL(INT_TO_JSVAL(start + gData.skipped), + ATOM_TO_JSID(cx->runtime->atomState.indexAtom)); + DEFVAL(STRING_TO_JSVAL(str), + ATOM_TO_JSID(cx->runtime->atomState.inputAtom)); + } + +#undef DEFVAL + + res->lastMatch.chars = cp; + res->lastMatch.length = matchlen; + + /* + * For JS1.3 and ECMAv2, emulate Perl5 exactly: + * + * js1.3 "hi", "hi there" "hihitherehi therebye" + */ + res->leftContext.chars = JSSTRING_CHARS(str); + res->leftContext.length = start + gData.skipped; + res->rightContext.chars = ep; + res->rightContext.length = gData.cpend - ep; + +out: + JS_ARENA_RELEASE(&cx->regexpPool, mark); + return ok; +} + +/************************************************************************/ + +#define REGEXP_PROP_ATTRS (JSPROP_PERMANENT | JSPROP_SHARED) +#define RO_REGEXP_PROP_ATTRS (REGEXP_PROP_ATTRS | JSPROP_READONLY) + +static JSPropertySpec regexp_props[] = { + {"source", REGEXP_SOURCE, RO_REGEXP_PROP_ATTRS,0,0}, + {"global", REGEXP_GLOBAL, RO_REGEXP_PROP_ATTRS,0,0}, + {"ignoreCase", REGEXP_IGNORE_CASE, RO_REGEXP_PROP_ATTRS,0,0}, + {"lastIndex", REGEXP_LAST_INDEX, REGEXP_PROP_ATTRS,0,0}, + {"multiline", REGEXP_MULTILINE, RO_REGEXP_PROP_ATTRS,0,0}, + {"sticky", REGEXP_STICKY, RO_REGEXP_PROP_ATTRS,0,0}, + {0,0,0,0,0} +}; + +static JSBool +regexp_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + jsint slot; + JSRegExp *re; + + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + while (OBJ_GET_CLASS(cx, obj) != &js_RegExpClass) { + obj = OBJ_GET_PROTO(cx, obj); + if (!obj) + return JS_TRUE; + } + slot = JSVAL_TO_INT(id); + if (slot == REGEXP_LAST_INDEX) + return JS_GetReservedSlot(cx, obj, 0, vp); + + JS_LOCK_OBJ(cx, obj); + re = (JSRegExp *) JS_GetPrivate(cx, obj); + if (re) { + switch (slot) { + case REGEXP_SOURCE: + *vp = STRING_TO_JSVAL(re->source); + break; + case REGEXP_GLOBAL: + *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_GLOB) != 0); + break; + case REGEXP_IGNORE_CASE: + *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_FOLD) != 0); + break; + case REGEXP_MULTILINE: + *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_MULTILINE) != 0); + break; + case REGEXP_STICKY: + *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_STICKY) != 0); + break; + } + } + JS_UNLOCK_OBJ(cx, obj); + return JS_TRUE; +} + +static JSBool +regexp_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSBool ok; + jsint slot; + jsdouble lastIndex; + + ok = JS_TRUE; + if (!JSVAL_IS_INT(id)) + return ok; + while (OBJ_GET_CLASS(cx, obj) != &js_RegExpClass) { + obj = OBJ_GET_PROTO(cx, obj); + if (!obj) + return JS_TRUE; + } + slot = JSVAL_TO_INT(id); + if (slot == REGEXP_LAST_INDEX) { + if (!JS_ValueToNumber(cx, *vp, &lastIndex)) + return JS_FALSE; + lastIndex = js_DoubleToInteger(lastIndex); + ok = JS_NewNumberValue(cx, lastIndex, vp) && + JS_SetReservedSlot(cx, obj, 0, *vp); + } + return ok; +} + +/* + * RegExp class static properties and their Perl counterparts: + * + * RegExp.input $_ + * RegExp.multiline $* + * RegExp.lastMatch $& + * RegExp.lastParen $+ + * RegExp.leftContext $` + * RegExp.rightContext $' + */ +enum regexp_static_tinyid { + REGEXP_STATIC_INPUT = -1, + REGEXP_STATIC_MULTILINE = -2, + REGEXP_STATIC_LAST_MATCH = -3, + REGEXP_STATIC_LAST_PAREN = -4, + REGEXP_STATIC_LEFT_CONTEXT = -5, + REGEXP_STATIC_RIGHT_CONTEXT = -6 +}; + +JSBool +js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res) +{ + JS_ClearRegExpStatics(cx); + return js_AddRoot(cx, &res->input, "res->input"); +} + +void +js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res) +{ + if (res->moreParens) { + JS_free(cx, res->moreParens); + res->moreParens = NULL; + } + js_RemoveRoot(cx->runtime, &res->input); +} + +static JSBool +regexp_static_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + jsint slot; + JSRegExpStatics *res; + JSString *str; + JSSubString *sub; + + res = &cx->regExpStatics; + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + slot = JSVAL_TO_INT(id); + switch (slot) { + case REGEXP_STATIC_INPUT: + *vp = res->input ? STRING_TO_JSVAL(res->input) + : JS_GetEmptyStringValue(cx); + return JS_TRUE; + case REGEXP_STATIC_MULTILINE: + *vp = BOOLEAN_TO_JSVAL(res->multiline); + return JS_TRUE; + case REGEXP_STATIC_LAST_MATCH: + sub = &res->lastMatch; + break; + case REGEXP_STATIC_LAST_PAREN: + sub = &res->lastParen; + break; + case REGEXP_STATIC_LEFT_CONTEXT: + sub = &res->leftContext; + break; + case REGEXP_STATIC_RIGHT_CONTEXT: + sub = &res->rightContext; + break; + default: + sub = REGEXP_PAREN_SUBSTRING(res, slot); + break; + } + str = js_NewStringCopyN(cx, sub->chars, sub->length); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +regexp_static_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSRegExpStatics *res; + + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + res = &cx->regExpStatics; + /* XXX use if-else rather than switch to keep MSVC1.52 from crashing */ + if (JSVAL_TO_INT(id) == REGEXP_STATIC_INPUT) { + if (!JSVAL_IS_STRING(*vp) && + !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) { + return JS_FALSE; + } + res->input = JSVAL_TO_STRING(*vp); + } else if (JSVAL_TO_INT(id) == REGEXP_STATIC_MULTILINE) { + if (!JSVAL_IS_BOOLEAN(*vp) && + !JS_ConvertValue(cx, *vp, JSTYPE_BOOLEAN, vp)) { + return JS_FALSE; + } + res->multiline = JSVAL_TO_BOOLEAN(*vp); + } + return JS_TRUE; +} +#define REGEXP_STATIC_PROP_ATTRS (REGEXP_PROP_ATTRS | JSPROP_ENUMERATE) +#define RO_REGEXP_STATIC_PROP_ATTRS (REGEXP_STATIC_PROP_ATTRS | JSPROP_READONLY) + +static JSPropertySpec regexp_static_props[] = { + {"input", + REGEXP_STATIC_INPUT, + REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_setProperty}, + {"multiline", + REGEXP_STATIC_MULTILINE, + REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_setProperty}, + {"lastMatch", + REGEXP_STATIC_LAST_MATCH, + RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"lastParen", + REGEXP_STATIC_LAST_PAREN, + RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"leftContext", + REGEXP_STATIC_LEFT_CONTEXT, + RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"rightContext", + REGEXP_STATIC_RIGHT_CONTEXT, + RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + + /* XXX should have block scope and local $1, etc. */ + {"$1", 0, RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"$2", 1, RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"$3", 2, RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"$4", 3, RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"$5", 4, RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"$6", 5, RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"$7", 6, RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"$8", 7, RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + {"$9", 8, RO_REGEXP_STATIC_PROP_ATTRS, + regexp_static_getProperty, regexp_static_getProperty}, + + {0,0,0,0,0} +}; + +static void +regexp_finalize(JSContext *cx, JSObject *obj) +{ + JSRegExp *re; + + re = (JSRegExp *) JS_GetPrivate(cx, obj); + if (!re) + return; + js_DestroyRegExp(cx, re); +} + +/* Forward static prototype. */ +static JSBool +regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + JSBool test, jsval *rval); + +static JSBool +regexp_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return regexp_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, + JS_FALSE, rval); +} + +#if JS_HAS_XDR + +#include "jsxdrapi.h" + +static JSBool +regexp_xdrObject(JSXDRState *xdr, JSObject **objp) +{ + JSRegExp *re; + JSString *source; + uint32 flagsword; + JSObject *obj; + + if (xdr->mode == JSXDR_ENCODE) { + re = (JSRegExp *) JS_GetPrivate(xdr->cx, *objp); + if (!re) + return JS_FALSE; + source = re->source; + flagsword = (uint32)re->flags; + } + if (!JS_XDRString(xdr, &source) || + !JS_XDRUint32(xdr, &flagsword)) { + return JS_FALSE; + } + if (xdr->mode == JSXDR_DECODE) { + obj = js_NewObject(xdr->cx, &js_RegExpClass, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + STOBJ_CLEAR_PARENT(obj); + STOBJ_CLEAR_PROTO(obj); + re = js_NewRegExp(xdr->cx, NULL, source, (uint8)flagsword, JS_FALSE); + if (!re) + return JS_FALSE; + if (!JS_SetPrivate(xdr->cx, obj, re) || + !js_SetLastIndex(xdr->cx, obj, 0)) { + js_DestroyRegExp(xdr->cx, re); + return JS_FALSE; + } + *objp = obj; + } + return JS_TRUE; +} + +#else /* !JS_HAS_XDR */ + +#define regexp_xdrObject NULL + +#endif /* !JS_HAS_XDR */ + +static void +regexp_trace(JSTracer *trc, JSObject *obj) +{ + JSRegExp *re; + + re = (JSRegExp *) JS_GetPrivate(trc->context, obj); + if (re && re->source) + JS_CALL_STRING_TRACER(trc, re->source, "source"); +} + +JSClass js_RegExpClass = { + js_RegExp_str, + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp), + JS_PropertyStub, JS_PropertyStub, + regexp_getProperty, regexp_setProperty, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, regexp_finalize, + NULL, NULL, + regexp_call, NULL, + regexp_xdrObject, NULL, + JS_CLASS_TRACE(regexp_trace), 0 +}; + +static const jschar empty_regexp_ucstr[] = {'(', '?', ':', ')', 0}; + +JSBool +js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp) +{ + JSRegExp *re; + const jschar *source; + jschar *chars; + size_t length, nflags; + uintN flags; + JSString *str; + + if (!JS_InstanceOf(cx, obj, &js_RegExpClass, vp + 2)) + return JS_FALSE; + JS_LOCK_OBJ(cx, obj); + re = (JSRegExp *) JS_GetPrivate(cx, obj); + if (!re) { + JS_UNLOCK_OBJ(cx, obj); + *vp = STRING_TO_JSVAL(cx->runtime->emptyString); + return JS_TRUE; + } + + JSSTRING_CHARS_AND_LENGTH(re->source, source, length); + if (length == 0) { + source = empty_regexp_ucstr; + length = JS_ARRAY_LENGTH(empty_regexp_ucstr) - 1; + } + length += 2; + nflags = 0; + for (flags = re->flags; flags != 0; flags &= flags - 1) + nflags++; + chars = (jschar*) JS_malloc(cx, (length + nflags + 1) * sizeof(jschar)); + if (!chars) { + JS_UNLOCK_OBJ(cx, obj); + return JS_FALSE; + } + + chars[0] = '/'; + js_strncpy(&chars[1], source, length - 2); + chars[length-1] = '/'; + if (nflags) { + if (re->flags & JSREG_GLOB) + chars[length++] = 'g'; + if (re->flags & JSREG_FOLD) + chars[length++] = 'i'; + if (re->flags & JSREG_MULTILINE) + chars[length++] = 'm'; + if (re->flags & JSREG_STICKY) + chars[length++] = 'y'; + } + JS_UNLOCK_OBJ(cx, obj); + chars[length] = 0; + + str = js_NewString(cx, chars, length); + if (!str) { + JS_free(cx, chars); + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +regexp_toString(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + return obj && js_regexp_toString(cx, obj, vp); +} + +static JSBool +regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + JSString *opt, *str; + JSRegExp *oldre, *re; + JSBool ok, ok2; + JSObject *obj2; + size_t length, nbytes; + const jschar *cp, *start, *end; + jschar *nstart, *ncp, *tmp; + + if (!JS_InstanceOf(cx, obj, &js_RegExpClass, argv)) + return JS_FALSE; + opt = NULL; + if (argc == 0) { + str = cx->runtime->emptyString; + } else { + if (JSVAL_IS_OBJECT(argv[0])) { + /* + * If we get passed in a RegExp object we construct a new + * RegExp that is a duplicate of it by re-compiling the + * original source code. ECMA requires that it be an error + * here if the flags are specified. (We must use the flags + * from the original RegExp also). + */ + obj2 = JSVAL_TO_OBJECT(argv[0]); + if (obj2 && OBJ_GET_CLASS(cx, obj2) == &js_RegExpClass) { + if (argc >= 2 && !JSVAL_IS_VOID(argv[1])) { /* 'flags' passed */ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_NEWREGEXP_FLAGGED); + return JS_FALSE; + } + JS_LOCK_OBJ(cx, obj2); + re = (JSRegExp *) JS_GetPrivate(cx, obj2); + if (!re) { + JS_UNLOCK_OBJ(cx, obj2); + return JS_FALSE; + } + re = js_NewRegExp(cx, NULL, re->source, re->flags, JS_FALSE); + JS_UNLOCK_OBJ(cx, obj2); + goto created; + } + } + str = js_ValueToString(cx, argv[0]); + if (!str) + return JS_FALSE; + argv[0] = STRING_TO_JSVAL(str); + if (argc > 1) { + if (JSVAL_IS_VOID(argv[1])) { + opt = NULL; + } else { + opt = js_ValueToString(cx, argv[1]); + if (!opt) + return JS_FALSE; + argv[1] = STRING_TO_JSVAL(opt); + } + } + + /* Escape any naked slashes in the regexp source. */ + JSSTRING_CHARS_AND_LENGTH(str, start, length); + end = start + length; + nstart = ncp = NULL; + for (cp = start; cp < end; cp++) { + if (*cp == '/' && (cp == start || cp[-1] != '\\')) { + nbytes = (++length + 1) * sizeof(jschar); + if (!nstart) { + nstart = (jschar *) JS_malloc(cx, nbytes); + if (!nstart) + return JS_FALSE; + ncp = nstart + (cp - start); + js_strncpy(nstart, start, cp - start); + } else { + tmp = (jschar *) JS_realloc(cx, nstart, nbytes); + if (!tmp) { + JS_free(cx, nstart); + return JS_FALSE; + } + ncp = tmp + (ncp - nstart); + nstart = tmp; + } + *ncp++ = '\\'; + } + if (nstart) + *ncp++ = *cp; + } + + if (nstart) { + /* Don't forget to store the backstop after the new string. */ + JS_ASSERT((size_t)(ncp - nstart) == length); + *ncp = 0; + str = js_NewString(cx, nstart, length); + if (!str) { + JS_free(cx, nstart); + return JS_FALSE; + } + argv[0] = STRING_TO_JSVAL(str); + } + } + + re = js_NewRegExpOpt(cx, str, opt, JS_FALSE); +created: + if (!re) + return JS_FALSE; + JS_LOCK_OBJ(cx, obj); + oldre = (JSRegExp *) JS_GetPrivate(cx, obj); + ok = JS_SetPrivate(cx, obj, re); + ok2 = js_SetLastIndex(cx, obj, 0); + JS_UNLOCK_OBJ(cx, obj); + if (!ok) { + js_DestroyRegExp(cx, re); + return JS_FALSE; + } + if (oldre) + js_DestroyRegExp(cx, oldre); + *rval = OBJECT_TO_JSVAL(obj); + return ok2; +} + +static JSBool +regexp_compile(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + return obj && regexp_compile_sub(cx, obj, argc, vp + 2, vp); +} + +static JSBool +regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + JSBool test, jsval *rval) +{ + JSBool ok, sticky; + JSRegExp *re; + jsdouble lastIndex; + JSString *str; + size_t i; + + ok = JS_InstanceOf(cx, obj, &js_RegExpClass, argv); + if (!ok) + return JS_FALSE; + JS_LOCK_OBJ(cx, obj); + re = (JSRegExp *) JS_GetPrivate(cx, obj); + if (!re) { + JS_UNLOCK_OBJ(cx, obj); + return JS_TRUE; + } + + /* NB: we must reach out: after this paragraph, in order to drop re. */ + HOLD_REGEXP(cx, re); + sticky = (re->flags & JSREG_STICKY) != 0; + if (re->flags & (JSREG_GLOB | JSREG_STICKY)) { + ok = js_GetLastIndex(cx, obj, &lastIndex); + } else { + lastIndex = 0; + } + JS_UNLOCK_OBJ(cx, obj); + if (!ok) + goto out; + + /* Now that obj is unlocked, it's safe to (potentially) grab the GC lock. */ + if (argc == 0) { + str = cx->regExpStatics.input; + if (!str) { + const char *bytes = js_GetStringBytes(cx, re->source); + + if (bytes) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_NO_INPUT, + bytes, + (re->flags & JSREG_GLOB) ? "g" : "", + (re->flags & JSREG_FOLD) ? "i" : "", + (re->flags & JSREG_MULTILINE) ? "m" : "", + (re->flags & JSREG_STICKY) ? "y" : ""); + } + ok = JS_FALSE; + goto out; + } + } else { + str = js_ValueToString(cx, argv[0]); + if (!str) { + ok = JS_FALSE; + goto out; + } + argv[0] = STRING_TO_JSVAL(str); + } + + if (lastIndex < 0 || JSSTRING_LENGTH(str) < lastIndex) { + ok = js_SetLastIndex(cx, obj, 0); + *rval = JSVAL_NULL; + } else { + i = (size_t) lastIndex; + ok = js_ExecuteRegExp(cx, re, str, &i, test, rval); + if (ok && + ((re->flags & JSREG_GLOB) || (*rval != JSVAL_NULL && sticky))) { + ok = js_SetLastIndex(cx, obj, (*rval == JSVAL_NULL) ? 0 : i); + } + } + +out: + DROP_REGEXP(cx, re); + return ok; +} + +static JSBool +regexp_exec(JSContext *cx, uintN argc, jsval *vp) +{ + return regexp_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, JS_FALSE, + vp); +} + +static JSBool +regexp_test(JSContext *cx, uintN argc, jsval *vp) +{ + if (!regexp_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, JS_TRUE, vp)) + return JS_FALSE; + if (*vp != JSVAL_TRUE) + *vp = JSVAL_FALSE; + return JS_TRUE; +} + +#ifdef JS_TRACER +static jsint FASTCALL +Regexp_p_test(JSContext* cx, JSObject* regexp, JSString* str) +{ + jsval vp[3] = { JSVAL_NULL, OBJECT_TO_JSVAL(regexp), STRING_TO_JSVAL(str) }; + if (!regexp_exec_sub(cx, regexp, 1, vp + 2, JS_TRUE, vp)) + return JSVAL_TO_BOOLEAN(JSVAL_VOID); + return *vp == JSVAL_TRUE; +} + +JS_DEFINE_TRCINFO_1(regexp_test, + (3, (static, BOOL_FAIL, Regexp_p_test, CONTEXT, THIS, STRING, 1, 1))) + +#endif + +static JSFunctionSpec regexp_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, regexp_toString, 0,0), +#endif + JS_FN(js_toString_str, regexp_toString, 0,0), + JS_FN("compile", regexp_compile, 2,0), + JS_FN("exec", regexp_exec, 1,0), + JS_TN("test", regexp_test, 1,0, regexp_test_trcinfo), + JS_FS_END +}; + +static JSBool +RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { + /* + * If first arg is regexp and no flags are given, just return the arg. + * (regexp_compile_sub detects the regexp + flags case and throws a + * TypeError.) See 10.15.3.1. + */ + if ((argc < 2 || JSVAL_IS_VOID(argv[1])) && + !JSVAL_IS_PRIMITIVE(argv[0]) && + OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(argv[0])) == &js_RegExpClass) { + *rval = argv[0]; + return JS_TRUE; + } + + /* Otherwise, replace obj with a new RegExp object. */ + obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + + /* + * regexp_compile_sub does not use rval to root its temporaries so we + * can use it to root obj. + */ + *rval = OBJECT_TO_JSVAL(obj); + } + return regexp_compile_sub(cx, obj, argc, argv, rval); +} + +JSObject * +js_InitRegExpClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto, *ctor; + jsval rval; + + proto = JS_InitClass(cx, obj, NULL, &js_RegExpClass, RegExp, 1, + regexp_props, regexp_methods, + regexp_static_props, NULL); + + if (!proto || !(ctor = JS_GetConstructor(cx, proto))) + return NULL; + if (!JS_AliasProperty(cx, ctor, "input", "$_") || + !JS_AliasProperty(cx, ctor, "multiline", "$*") || + !JS_AliasProperty(cx, ctor, "lastMatch", "$&") || + !JS_AliasProperty(cx, ctor, "lastParen", "$+") || + !JS_AliasProperty(cx, ctor, "leftContext", "$`") || + !JS_AliasProperty(cx, ctor, "rightContext", "$'")) { + goto bad; + } + + /* Give RegExp.prototype private data so it matches the empty string. */ + if (!regexp_compile_sub(cx, proto, 0, NULL, &rval)) + goto bad; + return proto; + +bad: + JS_DeleteProperty(cx, obj, js_RegExpClass.name); + return NULL; +} + +JSObject * +js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, + jschar *chars, size_t length, uintN flags) +{ + JSString *str; + JSObject *obj; + JSRegExp *re; + JSTempValueRooter tvr; + + str = js_NewStringCopyN(cx, chars, length); + if (!str) + return NULL; + re = js_NewRegExp(cx, ts, str, flags, JS_FALSE); + if (!re) + return NULL; + JS_PUSH_TEMP_ROOT_STRING(cx, str, &tvr); + obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL, 0); + if (!obj || !JS_SetPrivate(cx, obj, re)) { + js_DestroyRegExp(cx, re); + obj = NULL; + } + if (obj && !js_SetLastIndex(cx, obj, 0)) + obj = NULL; + JS_POP_TEMP_ROOT(cx, &tvr); + return obj; +} + +JSObject * +js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *parent) +{ + JSObject *clone; + JSRegExp *re; + + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass); + clone = js_NewObject(cx, &js_RegExpClass, NULL, parent, 0); + if (!clone) + return NULL; + re = (JSRegExp *) JS_GetPrivate(cx, obj); + if (!JS_SetPrivate(cx, clone, re) || !js_SetLastIndex(cx, clone, 0)) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + return NULL; + } + HOLD_REGEXP(cx, re); + return clone; +} + +JSBool +js_GetLastIndex(JSContext *cx, JSObject *obj, jsdouble *lastIndex) +{ + jsval v; + + return JS_GetReservedSlot(cx, obj, 0, &v) && + JS_ValueToNumber(cx, v, lastIndex); +} + +JSBool +js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex) +{ + jsval v; + + return JS_NewNumberValue(cx, lastIndex, &v) && + JS_SetReservedSlot(cx, obj, 0, v); +} + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsregexp.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsregexp.h new file mode 100644 index 0000000..12d74a3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsregexp.h @@ -0,0 +1,192 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsregexp_h___ +#define jsregexp_h___ +/* + * JS regular expression interface. + */ +#include +#include "jspubtd.h" +#include "jsstr.h" + +#ifdef JS_THREADSAFE +#include "jsdhash.h" +#endif + +JS_BEGIN_EXTERN_C + +struct JSRegExpStatics { + JSString *input; /* input string to match (perl $_, GC root) */ + JSBool multiline; /* whether input contains newlines (perl $*) */ + uint16 parenCount; /* number of valid elements in parens[] */ + uint16 moreLength; /* number of allocated elements in moreParens */ + JSSubString parens[9]; /* last set of parens matched (perl $1, $2) */ + JSSubString *moreParens; /* null or realloc'd vector for $10, etc. */ + JSSubString lastMatch; /* last string matched (perl $&) */ + JSSubString lastParen; /* last paren matched (perl $+) */ + JSSubString leftContext; /* input to left of last match (perl $`) */ + JSSubString rightContext; /* input to right of last match (perl $') */ +}; + +/* + * This struct holds a bitmap representation of a class from a regexp. + * There's a list of these referenced by the classList field in the JSRegExp + * struct below. The initial state has startIndex set to the offset in the + * original regexp source of the beginning of the class contents. The first + * use of the class converts the source representation into a bitmap. + * + */ +typedef struct RECharSet { + JSPackedBool converted; + JSPackedBool sense; + uint16 length; + union { + uint8 *bits; + struct { + size_t startIndex; + size_t length; + } src; + } u; +} RECharSet; + +/* + * This macro is safe because moreParens is guaranteed to be allocated and big + * enough to hold parenCount, or else be null when parenCount is 0. + */ +#define REGEXP_PAREN_SUBSTRING(res, num) \ + (((jsuint)(num) < (jsuint)(res)->parenCount) \ + ? ((jsuint)(num) < 9) \ + ? &(res)->parens[num] \ + : &(res)->moreParens[(num) - 9] \ + : &js_EmptySubString) + +typedef struct RENode RENode; + +struct JSRegExp { + jsrefcount nrefs; /* reference count */ + uint16 flags; /* flags, see jsapi.h's JSREG_* defines */ + size_t parenCount; /* number of parenthesized submatches */ + size_t classCount; /* count [...] bitmaps */ + RECharSet *classList; /* list of [...] bitmaps */ + JSString *source; /* locked source string, sans // */ + jsbytecode program[1]; /* regular expression bytecode */ +}; + +extern JSRegExp * +js_NewRegExp(JSContext *cx, JSTokenStream *ts, + JSString *str, uintN flags, JSBool flat); + +extern JSRegExp * +js_NewRegExpOpt(JSContext *cx, JSString *str, JSString *opt, JSBool flat); + +#define HOLD_REGEXP(cx, re) JS_ATOMIC_INCREMENT(&(re)->nrefs) +#define DROP_REGEXP(cx, re) js_DestroyRegExp(cx, re) + +extern void +js_DestroyRegExp(JSContext *cx, JSRegExp *re); + +/* + * Execute re on input str at *indexp, returning null in *rval on mismatch. + * On match, return true if test is true, otherwise return an array object. + * Update *indexp and cx->regExpStatics always on match. + */ +extern JSBool +js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, + JSBool test, jsval *rval); + +/* + * These two add and remove GC roots, respectively, so their calls must be + * well-ordered. + */ +extern JSBool +js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res); + +extern void +js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res); + +#define VALUE_IS_REGEXP(cx, v) \ + (JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) && \ + OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_RegExpClass) + +extern JSClass js_RegExpClass; + +enum regexp_tinyid { + REGEXP_SOURCE = -1, + REGEXP_GLOBAL = -2, + REGEXP_IGNORE_CASE = -3, + REGEXP_LAST_INDEX = -4, + REGEXP_MULTILINE = -5, + REGEXP_STICKY = -6 +}; + +extern JSObject * +js_InitRegExpClass(JSContext *cx, JSObject *obj); + +/* + * Export js_regexp_toString to the decompiler. + */ +extern JSBool +js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp); + +/* + * Create, serialize/deserialize, or clone a RegExp object. + */ +extern JSObject * +js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, + jschar *chars, size_t length, uintN flags); + +extern JSBool +js_XDRRegExp(JSXDRState *xdr, JSObject **objp); + +extern JSObject * +js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *parent); + +/* + * Get and set the per-object (clone or clone-parent) lastIndex slot. + */ +extern JSBool +js_GetLastIndex(JSContext *cx, JSObject *obj, jsdouble *lastIndex); + +extern JSBool +js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex); + +JS_END_EXTERN_C + +#endif /* jsregexp_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsreops.tbl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsreops.tbl new file mode 100644 index 0000000..d7454c1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsreops.tbl @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=0 ft=C: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "license"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "as is" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contentsof this file are subject to the Mozilla Public License Version + * 1.1 (the "license"); you may not use this file except in compliance with + * the License. You may obtain a copy of thter (the "lgpl"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* Note : contiguity of 'simple opcodes' is important for SimpleMatch() */ + +/* match rest of input against rest of r.e. */ +REOP_DEF(REOP_EMPTY, "empty") +/* beginning of input (or line if multiline) */ +REOP_DEF(REOP_BOL, "bol") +/* end of input (or line if multiline) */ +REOP_DEF(REOP_EOL, "eol") +/* match "" at word boundary */ +REOP_DEF(REOP_WBDRY, "wbdry") +/* match "" at word non-boundary */ +REOP_DEF(REOP_WNONBDRY, "wnonbdry") +/* stands for any character */ +REOP_DEF(REOP_DOT, "dot") +/* match a digit char: [0-9] */ +REOP_DEF(REOP_DIGIT, "digit") +/* match a non-digit char: [^0-9] */ +REOP_DEF(REOP_NONDIGIT, "nondigit") +/* match an alphanumeric char: [0-9a-z_A-Z] */ +REOP_DEF(REOP_ALNUM, "alnum") +/* match a non-alphanumeric char: [^0-9a-z_A-Z] */ +REOP_DEF(REOP_NONALNUM, "nonalnum") +/* match a whitespace char */ +REOP_DEF(REOP_SPACE, "space") +/* match a non-whitespace char */ +REOP_DEF(REOP_NONSPACE, "nonspace") +/* back-reference (e.g., \1) to a parenthetical */ +REOP_DEF(REOP_BACKREF, "backref") +/* match a flat string */ +REOP_DEF(REOP_FLAT, "flat") +/* match a single char */ +REOP_DEF(REOP_FLAT1, "flat1") +/* case-independent REOP_FLAT */ +REOP_DEF(REOP_FLATi, "flati") +/* case-independent REOP_FLAT1 */ +REOP_DEF(REOP_FLAT1i, "flat1i") +/* single Unicode char */ +REOP_DEF(REOP_UCFLAT1, "ucflat1") +/* case-independent REOP_UCFLAT1 */ +REOP_DEF(REOP_UCFLAT1i, "ucflat1i") +/* flat Unicode string; len immediate counts chars */ +REOP_DEF(REOP_UCFLAT, "ucflat") +/* case-independent REOP_UCFLAT */ +REOP_DEF(REOP_UCFLATi, "ucflati") +/* character class with index */ +REOP_DEF(REOP_CLASS, "class") +/* negated character class with index */ +REOP_DEF(REOP_NCLASS, "nclass") + +/* NCLASS is considered to be the last "simple" op-code */ + + +/* alternative subexpressions in kid and next */ +REOP_DEF(REOP_ALT, "alt") +/* quantified atom: atom{1,2} */ +REOP_DEF(REOP_QUANT, "quant") +/* zero or more occurrences of kid */ +REOP_DEF(REOP_STAR, "star") +/* one or more occurrences of kid */ +REOP_DEF(REOP_PLUS, "plus") +/* optional subexpression in kid */ +REOP_DEF(REOP_OPT, "opt") +/* left paren bytecode: kid is u.num'th sub-regexp */ +REOP_DEF(REOP_LPAREN, "lparen") +/* right paren bytecode */ +REOP_DEF(REOP_RPAREN, "rparen") +/* for deoptimized closure loops */ +REOP_DEF(REOP_JUMP, "jump") +/* optimize .* to use a single opcode */ +REOP_DEF(REOP_DOTSTAR, "dotstar") +/* non-capturing version of REOP_LPAREN */ +REOP_DEF(REOP_LPARENNON, "lparennon") +/* zero width positive lookahead assertion */ +REOP_DEF(REOP_ASSERT, "assert") +/* zero width negative lookahead assertion */ +REOP_DEF(REOP_ASSERT_NOT, "assert_not") +/* sentinel at end of assertion child */ +REOP_DEF(REOP_ASSERTTEST, "asserttest") +/* sentinel at end of !assertion child */ +REOP_DEF(REOP_ASSERTNOTTEST, "assertnottest") +/* non-greedy version of * */ +REOP_DEF(REOP_MINIMALSTAR, "minimalstar") +/* non-greedy version of + */ +REOP_DEF(REOP_MINIMALPLUS, "minimalplus") +/* non-greedy version of ? */ +REOP_DEF(REOP_MINIMALOPT, "minimalopt") +/* non-greedy version of {} */ +REOP_DEF(REOP_MINIMALQUANT, "minimalquant") +/* sentinel at end of quantifier child */ +REOP_DEF(REOP_ENDCHILD, "endchild") +/* directs execution of greedy quantifier */ +REOP_DEF(REOP_REPEAT, "repeat") +/* directs execution of non-greedy quantifier */ +REOP_DEF(REOP_MINIMALREPEAT, "minimalrepeat") +/* prerequisite for ALT, either of two chars */ +REOP_DEF(REOP_ALTPREREQ, "altprereq") +/* prerequisite for ALT, a char or a class */ +REOP_DEF(REOP_ALTPREREQ2, "altprereq2") +/* end of final alternate */ +REOP_DEF(REOP_ENDALT, "endalt") +/* concatenation of terms (parse time only) */ +REOP_DEF(REOP_CONCAT, "concat") +/* end of expression */ +REOP_DEF(REOP_END, "end") diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscan.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscan.cpp new file mode 100644 index 0000000..f112a9a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscan.cpp @@ -0,0 +1,2017 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS lexical scanner. + */ +#include "jsstddef.h" +#include /* first to avoid trouble on some systems */ +#include +#include +#include +#ifdef HAVE_MEMORY_H +#include +#endif +#include +#include +#include +#include "jstypes.h" +#include "jsarena.h" /* Added by JSIFY */ +#include "jsutil.h" /* Added by JSIFY */ +#include "jsdtoa.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsemit.h" +#include "jsexn.h" +#include "jsnum.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsregexp.h" +#include "jsscan.h" +#include "jsscript.h" +#include "jsstaticcheck.h" + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#define JS_KEYWORD(keyword, type, op, version) \ + const char js_##keyword##_str[] = #keyword; +#include "jskeyword.tbl" +#undef JS_KEYWORD + +struct keyword { + const char *chars; /* C string with keyword text */ + JSTokenType tokentype; /* JSTokenType */ + JSOp op; /* JSOp */ + JSVersion version; /* JSVersion */ +}; + +static const struct keyword keyword_defs[] = { +#define JS_KEYWORD(keyword, type, op, version) \ + {js_##keyword##_str, type, op, version}, +#include "jskeyword.tbl" +#undef JS_KEYWORD +}; + +#define KEYWORD_COUNT JS_ARRAY_LENGTH(keyword_defs) + +static const struct keyword * +FindKeyword(const jschar *s, size_t length) +{ + register size_t i; + const struct keyword *kw; + const char *chars; + + JS_ASSERT(length != 0); + +#define JSKW_LENGTH() length +#define JSKW_AT(column) s[column] +#define JSKW_GOT_MATCH(index) i = (index); goto got_match; +#define JSKW_TEST_GUESS(index) i = (index); goto test_guess; +#define JSKW_NO_MATCH() goto no_match; +#include "jsautokw.h" +#undef JSKW_NO_MATCH +#undef JSKW_TEST_GUESS +#undef JSKW_GOT_MATCH +#undef JSKW_AT +#undef JSKW_LENGTH + + got_match: + return &keyword_defs[i]; + + test_guess: + kw = &keyword_defs[i]; + chars = kw->chars; + do { + if (*s++ != (unsigned char)(*chars++)) + goto no_match; + } while (--length != 0); + return kw; + + no_match: + return NULL; +} + +JSTokenType +js_CheckKeyword(const jschar *str, size_t length) +{ + const struct keyword *kw; + + JS_ASSERT(length != 0); + kw = FindKeyword(str, length); + return kw ? kw->tokentype : TOK_EOF; +} + +JS_FRIEND_API(void) +js_MapKeywords(void (*mapfun)(const char *)) +{ + size_t i; + + for (i = 0; i != KEYWORD_COUNT; ++i) + mapfun(keyword_defs[i].chars); +} + +JSBool +js_IsIdentifier(JSString *str) +{ + size_t length; + jschar c, *chars, *end; + + JSSTRING_CHARS_AND_LENGTH(str, chars, length); + if (length == 0) + return JS_FALSE; + c = *chars; + if (!JS_ISIDSTART(c)) + return JS_FALSE; + end = chars + length; + while (++chars != end) { + c = *chars; + if (!JS_ISIDENT(c)) + return JS_FALSE; + } + return JS_TRUE; +} + +#define TBMIN 64 + +static JSBool +GrowTokenBuf(JSStringBuffer *sb, size_t newlength) +{ + JSContext *cx; + jschar *base; + ptrdiff_t offset, length; + size_t tbsize; + JSArenaPool *pool; + + cx = (JSContext*) sb->data; + base = sb->base; + offset = PTRDIFF(sb->ptr, base, jschar); + pool = &cx->tempPool; + if (!base) { + tbsize = TBMIN * sizeof(jschar); + length = TBMIN - 1; + JS_ARENA_ALLOCATE_CAST(base, jschar *, pool, tbsize); + } else { + length = PTRDIFF(sb->limit, base, jschar); + if ((size_t)length >= ~(size_t)0 / sizeof(jschar)) { + base = NULL; + } else { + tbsize = (length + 1) * sizeof(jschar); + length += length + 1; + JS_ARENA_GROW_CAST(base, jschar *, pool, tbsize, tbsize); + } + } + if (!base) { + js_ReportOutOfScriptQuota(cx); + sb->base = STRING_BUFFER_ERROR_BASE; + return JS_FALSE; + } + sb->base = base; + sb->limit = base + length; + sb->ptr = base + offset; + return JS_TRUE; +} + +JSBool +js_InitTokenStream(JSContext *cx, JSTokenStream *ts, + const jschar *base, size_t length, + FILE *fp, const char *filename, uintN lineno) +{ + jschar *buf; + size_t nb; + + JS_ASSERT_IF(fp, !base); + JS_ASSERT_IF(!base, length == 0); + nb = fp + ? 2 * JS_LINE_LIMIT * sizeof(jschar) + : JS_LINE_LIMIT * sizeof(jschar); + JS_ARENA_ALLOCATE_CAST(buf, jschar *, &cx->tempPool, nb); + if (!buf) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + memset(buf, 0, nb); + memset(ts, 0, sizeof(*ts)); + ts->filename = filename; + ts->lineno = lineno; + ts->linebuf.base = ts->linebuf.limit = ts->linebuf.ptr = buf; + if (fp) { + ts->file = fp; + ts->userbuf.base = buf + JS_LINE_LIMIT; + ts->userbuf.ptr = ts->userbuf.limit = ts->userbuf.base + JS_LINE_LIMIT; + } else { + ts->userbuf.base = (jschar *)base; + ts->userbuf.limit = (jschar *)base + length; + ts->userbuf.ptr = (jschar *)base; + } + ts->tokenbuf.grow = GrowTokenBuf; + ts->tokenbuf.data = cx; + ts->listener = cx->debugHooks->sourceHandler; + ts->listenerData = cx->debugHooks->sourceHandlerData; + return JS_TRUE; +} + +void +js_CloseTokenStream(JSContext *cx, JSTokenStream *ts) +{ + if (ts->flags & TSF_OWNFILENAME) + JS_free(cx, (void *) ts->filename); +} + +JS_FRIEND_API(int) +js_fgets(char *buf, int size, FILE *file) +{ + int n, i, c; + JSBool crflag; + + n = size - 1; + if (n < 0) + return -1; + + crflag = JS_FALSE; + for (i = 0; i < n && (c = getc(file)) != EOF; i++) { + buf[i] = c; + if (c == '\n') { /* any \n ends a line */ + i++; /* keep the \n; we know there is room for \0 */ + break; + } + if (crflag) { /* \r not followed by \n ends line at the \r */ + ungetc(c, file); + break; /* and overwrite c in buf with \0 */ + } + crflag = (c == '\r'); + } + + buf[i] = '\0'; + return i; +} + +static int32 +GetChar(JSTokenStream *ts) +{ + int32 c; + ptrdiff_t i, j, len, olen; + JSBool crflag; + char cbuf[JS_LINE_LIMIT]; + jschar *ubuf, *nl; + + if (ts->ungetpos != 0) { + c = ts->ungetbuf[--ts->ungetpos]; + } else { + if (ts->linebuf.ptr == ts->linebuf.limit) { + len = PTRDIFF(ts->userbuf.limit, ts->userbuf.ptr, jschar); + if (len <= 0) { + if (!ts->file) { + ts->flags |= TSF_EOF; + return EOF; + } + + /* Fill ts->userbuf so that \r and \r\n convert to \n. */ + crflag = (ts->flags & TSF_CRFLAG) != 0; + len = js_fgets(cbuf, JS_LINE_LIMIT - crflag, ts->file); + if (len <= 0) { + ts->flags |= TSF_EOF; + return EOF; + } + olen = len; + ubuf = ts->userbuf.base; + i = 0; + if (crflag) { + ts->flags &= ~TSF_CRFLAG; + if (cbuf[0] != '\n') { + ubuf[i++] = '\n'; + len++; + ts->linepos--; + } + } + for (j = 0; i < len; i++, j++) + ubuf[i] = (jschar) (unsigned char) cbuf[j]; + ts->userbuf.limit = ubuf + len; + ts->userbuf.ptr = ubuf; + } + if (ts->listener) { + ts->listener(ts->filename, ts->lineno, ts->userbuf.ptr, len, + &ts->listenerTSData, ts->listenerData); + } + + nl = ts->saveEOL; + if (!nl) { + /* + * Any one of \n, \r, or \r\n ends a line (the longest + * match wins). Also allow the Unicode line and paragraph + * separators. + */ + for (nl = ts->userbuf.ptr; nl < ts->userbuf.limit; nl++) { + /* + * Try to prevent value-testing on most characters by + * filtering out characters that aren't 000x or 202x. + */ + if ((*nl & 0xDFD0) == 0) { + if (*nl == '\n') + break; + if (*nl == '\r') { + if (nl + 1 < ts->userbuf.limit && nl[1] == '\n') + nl++; + break; + } + if (*nl == LINE_SEPARATOR || *nl == PARA_SEPARATOR) + break; + } + } + } + + /* + * If there was a line terminator, copy thru it into linebuf. + * Else copy JS_LINE_LIMIT-1 bytes into linebuf. + */ + if (nl < ts->userbuf.limit) + len = PTRDIFF(nl, ts->userbuf.ptr, jschar) + 1; + if (len >= JS_LINE_LIMIT) { + len = JS_LINE_LIMIT - 1; + ts->saveEOL = nl; + } else { + ts->saveEOL = NULL; + } + js_strncpy(ts->linebuf.base, ts->userbuf.ptr, len); + ts->userbuf.ptr += len; + olen = len; + + /* + * Make sure linebuf contains \n for EOL (don't do this in + * userbuf because the user's string might be readonly). + */ + if (nl < ts->userbuf.limit) { + if (*nl == '\r') { + if (ts->linebuf.base[len-1] == '\r') { + /* + * Does the line segment end in \r? We must check + * for a \n at the front of the next segment before + * storing a \n into linebuf. This case matters + * only when we're reading from a file. + */ + if (nl + 1 == ts->userbuf.limit && ts->file) { + len--; + ts->flags |= TSF_CRFLAG; /* clear NLFLAG? */ + if (len == 0) { + /* + * This can happen when a segment ends in + * \r\r. Start over. ptr == limit in this + * case, so we'll fall into buffer-filling + * code. + */ + return GetChar(ts); + } + } else { + ts->linebuf.base[len-1] = '\n'; + } + } + } else if (*nl == '\n') { + if (nl > ts->userbuf.base && + nl[-1] == '\r' && + ts->linebuf.base[len-2] == '\r') { + len--; + JS_ASSERT(ts->linebuf.base[len] == '\n'); + ts->linebuf.base[len-1] = '\n'; + } + } else if (*nl == LINE_SEPARATOR || *nl == PARA_SEPARATOR) { + ts->linebuf.base[len-1] = '\n'; + } + } + + /* Reset linebuf based on adjusted segment length. */ + ts->linebuf.limit = ts->linebuf.base + len; + ts->linebuf.ptr = ts->linebuf.base; + + /* Update position of linebuf within physical userbuf line. */ + if (!(ts->flags & TSF_NLFLAG)) + ts->linepos += ts->linelen; + else + ts->linepos = 0; + if (ts->linebuf.limit[-1] == '\n') + ts->flags |= TSF_NLFLAG; + else + ts->flags &= ~TSF_NLFLAG; + + /* Update linelen from original segment length. */ + ts->linelen = olen; + } + c = *ts->linebuf.ptr++; + } + if (c == '\n') + ts->lineno++; + return c; +} + +static void +UngetChar(JSTokenStream *ts, int32 c) +{ + if (c == EOF) + return; + JS_ASSERT(ts->ungetpos < JS_ARRAY_LENGTH(ts->ungetbuf)); + if (c == '\n') + ts->lineno--; + ts->ungetbuf[ts->ungetpos++] = (jschar)c; +} + +static int32 +PeekChar(JSTokenStream *ts) +{ + int32 c; + + c = GetChar(ts); + UngetChar(ts, c); + return c; +} + +/* + * Peek n chars ahead into ts. Return true if n chars were read, false if + * there weren't enough characters in the input stream. This function cannot + * be used to peek into or past a newline. + */ +static JSBool +PeekChars(JSTokenStream *ts, intN n, jschar *cp) +{ + intN i, j; + int32 c; + + for (i = 0; i < n; i++) { + c = GetChar(ts); + if (c == EOF) + break; + if (c == '\n') { + UngetChar(ts, c); + break; + } + cp[i] = (jschar)c; + } + for (j = i - 1; j >= 0; j--) + UngetChar(ts, cp[j]); + return i == n; +} + +static void +SkipChars(JSTokenStream *ts, intN n) +{ + while (--n >= 0) + GetChar(ts); +} + +static JSBool +MatchChar(JSTokenStream *ts, int32 expect) +{ + int32 c; + + c = GetChar(ts); + if (c == expect) + return JS_TRUE; + UngetChar(ts, c); + return JS_FALSE; +} + +JSBool +js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, + uintN flags, uintN errorNumber, ...) +{ + JSErrorReport report; + char *message; + size_t linelength; + jschar *linechars; + char *linebytes; + va_list ap; + JSBool warning, ok; + JSTokenPos *tp; + uintN index, i; + JSErrorReporter onError; + + JS_ASSERT(ts->linebuf.limit < ts->linebuf.base + JS_LINE_LIMIT); + + if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx)) + return JS_TRUE; + + memset(&report, 0, sizeof report); + report.flags = flags; + report.errorNumber = errorNumber; + message = NULL; + linechars = NULL; + linebytes = NULL; + + MUST_FLOW_THROUGH("out"); + va_start(ap, errorNumber); + ok = js_ExpandErrorArguments(cx, js_GetErrorMessage, NULL, + errorNumber, &message, &report, &warning, + !(flags & JSREPORT_UC), ap); + va_end(ap); + if (!ok) { + warning = JS_FALSE; + goto out; + } + + report.filename = ts->filename; + + if (pn) { + report.lineno = pn->pn_pos.begin.lineno; + if (report.lineno != ts->lineno) + goto report; + tp = &pn->pn_pos; + } else { + /* Point to the current token, not the next one to get. */ + tp = &ts->tokens[ts->cursor].pos; + } + report.lineno = ts->lineno; + linelength = PTRDIFF(ts->linebuf.limit, ts->linebuf.base, jschar); + linechars = (jschar *)JS_malloc(cx, (linelength + 1) * sizeof(jschar)); + if (!linechars) { + warning = JS_FALSE; + goto out; + } + memcpy(linechars, ts->linebuf.base, linelength * sizeof(jschar)); + linechars[linelength] = 0; + linebytes = js_DeflateString(cx, linechars, linelength); + if (!linebytes) { + warning = JS_FALSE; + goto out; + } + report.linebuf = linebytes; + + /* + * FIXME: What should instead happen here is that we should + * find error-tokens in userbuf, if !ts->file. That will + * allow us to deliver a more helpful error message, which + * includes all or part of the bad string or bad token. The + * code here yields something that looks truncated. + * See https://bugzilla.mozilla.org/show_bug.cgi?id=352970 + */ + index = 0; + if (tp->begin.lineno == tp->end.lineno) { + if (tp->begin.index < ts->linepos) + goto report; + + index = tp->begin.index - ts->linepos; + } + + report.tokenptr = report.linebuf + index; + report.uclinebuf = linechars; + report.uctokenptr = report.uclinebuf + index; + + /* + * If there's a runtime exception type associated with this error + * number, set that as the pending exception. For errors occuring at + * compile time, this is very likely to be a JSEXN_SYNTAXERR. + * + * If an exception is thrown but not caught, the JSREPORT_EXCEPTION + * flag will be set in report.flags. Proper behavior for an error + * reporter is to ignore a report with this flag for all but top-level + * compilation errors. The exception will remain pending, and so long + * as the non-top-level "load", "eval", or "compile" native function + * returns false, the top-level reporter will eventually receive the + * uncaught exception report. + * + * XXX it'd probably be best if there was only one call to this + * function, but there seem to be two error reporter call points. + */ + report: + onError = cx->errorReporter; + + /* + * Try to raise an exception only if there isn't one already set -- + * otherwise the exception will describe the last compile-time error, + * which is likely spurious. + */ + if (!(ts->flags & TSF_ERROR)) { + if (js_ErrorToException(cx, message, &report)) + onError = NULL; + } + + /* + * Suppress any compile-time errors that don't occur at the top level. + * This may still fail, as interplevel may be zero in contexts where we + * don't really want to call the error reporter, as when js is called + * by other code which could catch the error. + */ + if (cx->interpLevel != 0 && !JSREPORT_IS_WARNING(flags)) + onError = NULL; + + if (onError) { + JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; + + /* + * If debugErrorHook is present then we give it a chance to veto + * sending the error on to the regular error reporter. + */ + if (hook && !hook(cx, message, &report, + cx->debugHooks->debugErrorHookData)) { + onError = NULL; + } + } + if (onError) + (*onError)(cx, message, &report); + + out: + if (linebytes) + JS_free(cx, linebytes); + if (linechars) + JS_free(cx, linechars); + if (message) + JS_free(cx, message); + if (report.ucmessage) + JS_free(cx, (void *)report.ucmessage); + + if (report.messageArgs) { + if (!(flags & JSREPORT_UC)) { + i = 0; + while (report.messageArgs[i]) + JS_free(cx, (void *)report.messageArgs[i++]); + } + JS_free(cx, (void *)report.messageArgs); + } + + if (!JSREPORT_IS_WARNING(flags)) { + /* Set the error flag to suppress spurious reports. */ + ts->flags |= TSF_ERROR; + } + + return warning; +} + +static JSBool +GrowStringBuffer(JSStringBuffer *sb, size_t newlength) +{ + ptrdiff_t offset; + jschar *bp; + + offset = PTRDIFF(sb->ptr, sb->base, jschar); + JS_ASSERT(offset >= 0); + newlength += offset + 1; + if ((size_t)offset < newlength && newlength < ~(size_t)0 / sizeof(jschar)) + bp = (jschar *) realloc(sb->base, newlength * sizeof(jschar)); + else + bp = NULL; + if (!bp) { + free(sb->base); + sb->base = STRING_BUFFER_ERROR_BASE; + return JS_FALSE; + } + sb->base = bp; + sb->ptr = bp + offset; + sb->limit = bp + newlength - 1; + return JS_TRUE; +} + +static void +FreeStringBuffer(JSStringBuffer *sb) +{ + JS_ASSERT(STRING_BUFFER_OK(sb)); + if (sb->base) + free(sb->base); +} + +void +js_InitStringBuffer(JSStringBuffer *sb) +{ + sb->base = sb->limit = sb->ptr = NULL; + sb->data = NULL; + sb->grow = GrowStringBuffer; + sb->free = FreeStringBuffer; +} + +void +js_FinishStringBuffer(JSStringBuffer *sb) +{ + sb->free(sb); +} + +#define ENSURE_STRING_BUFFER(sb,n) \ + ((sb)->ptr + (n) <= (sb)->limit || sb->grow(sb, n)) + +static void +FastAppendChar(JSStringBuffer *sb, jschar c) +{ + if (!STRING_BUFFER_OK(sb)) + return; + if (!ENSURE_STRING_BUFFER(sb, 1)) + return; + *sb->ptr++ = c; +} + +void +js_AppendChar(JSStringBuffer *sb, jschar c) +{ + jschar *bp; + + if (!STRING_BUFFER_OK(sb)) + return; + if (!ENSURE_STRING_BUFFER(sb, 1)) + return; + bp = sb->ptr; + *bp++ = c; + *bp = 0; + sb->ptr = bp; +} + +void +js_AppendUCString(JSStringBuffer *sb, const jschar *buf, uintN len) +{ + jschar *bp; + + if (!STRING_BUFFER_OK(sb)) + return; + if (len == 0 || !ENSURE_STRING_BUFFER(sb, len)) + return; + bp = sb->ptr; + js_strncpy(bp, buf, len); + bp += len; + *bp = 0; + sb->ptr = bp; +} + +#if JS_HAS_XML_SUPPORT + +void +js_RepeatChar(JSStringBuffer *sb, jschar c, uintN count) +{ + jschar *bp; + + if (!STRING_BUFFER_OK(sb) || count == 0) + return; + if (!ENSURE_STRING_BUFFER(sb, count)) + return; + for (bp = sb->ptr; count; --count) + *bp++ = c; + *bp = 0; + sb->ptr = bp; +} + +void +js_AppendCString(JSStringBuffer *sb, const char *asciiz) +{ + size_t length; + jschar *bp; + + if (!STRING_BUFFER_OK(sb) || *asciiz == '\0') + return; + length = strlen(asciiz); + if (!ENSURE_STRING_BUFFER(sb, length)) + return; + for (bp = sb->ptr; length; --length) + *bp++ = (jschar) *asciiz++; + *bp = 0; + sb->ptr = bp; +} + +void +js_AppendJSString(JSStringBuffer *sb, JSString *str) +{ + js_AppendUCString(sb, JSSTRING_CHARS(str), JSSTRING_LENGTH(str)); +} + +static JSBool +GetXMLEntity(JSContext *cx, JSTokenStream *ts) +{ + ptrdiff_t offset, length, i; + int32 c, d; + JSBool ispair; + jschar *bp, digit; + char *bytes; + JSErrNum msg; + + /* Put the entity, including the '&' already scanned, in ts->tokenbuf. */ + offset = PTRDIFF(ts->tokenbuf.ptr, ts->tokenbuf.base, jschar); + FastAppendChar(&ts->tokenbuf, '&'); + if (!STRING_BUFFER_OK(&ts->tokenbuf)) + return JS_FALSE; + while ((c = GetChar(ts)) != ';') { + if (c == EOF || c == '\n') { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_END_OF_XML_ENTITY); + return JS_FALSE; + } + FastAppendChar(&ts->tokenbuf, (jschar) c); + if (!STRING_BUFFER_OK(&ts->tokenbuf)) + return JS_FALSE; + } + + /* Let length be the number of jschars after the '&', including the ';'. */ + length = PTRDIFF(ts->tokenbuf.ptr, ts->tokenbuf.base, jschar) - offset; + bp = ts->tokenbuf.base + offset; + c = d = 0; + ispair = JS_FALSE; + if (length > 2 && bp[1] == '#') { + /* Match a well-formed XML Character Reference. */ + i = 2; + if (length > 3 && JS_TOLOWER(bp[i]) == 'x') { + if (length > 9) /* at most 6 hex digits allowed */ + goto badncr; + while (++i < length) { + digit = bp[i]; + if (!JS7_ISHEX(digit)) + goto badncr; + c = (c << 4) + JS7_UNHEX(digit); + } + } else { + while (i < length) { + digit = bp[i++]; + if (!JS7_ISDEC(digit)) + goto badncr; + c = (c * 10) + JS7_UNDEC(digit); + if (c < 0) + goto badncr; + } + } + + if (0x10000 <= c && c <= 0x10FFFF) { + /* Form a surrogate pair (c, d) -- c is the high surrogate. */ + d = 0xDC00 + (c & 0x3FF); + c = 0xD7C0 + (c >> 10); + ispair = JS_TRUE; + } else { + /* Enforce the http://www.w3.org/TR/REC-xml/#wf-Legalchar WFC. */ + if (c != 0x9 && c != 0xA && c != 0xD && + !(0x20 <= c && c <= 0xD7FF) && + !(0xE000 <= c && c <= 0xFFFD)) { + goto badncr; + } + } + } else { + /* Try to match one of the five XML 1.0 predefined entities. */ + switch (length) { + case 3: + if (bp[2] == 't') { + if (bp[1] == 'l') + c = '<'; + else if (bp[1] == 'g') + c = '>'; + } + break; + case 4: + if (bp[1] == 'a' && bp[2] == 'm' && bp[3] == 'p') + c = '&'; + break; + case 5: + if (bp[3] == 'o') { + if (bp[1] == 'a' && bp[2] == 'p' && bp[4] == 's') + c = '\''; + else if (bp[1] == 'q' && bp[2] == 'u' && bp[4] == 't') + c = '"'; + } + break; + } + if (c == 0) { + msg = JSMSG_UNKNOWN_XML_ENTITY; + goto bad; + } + } + + /* If we matched, retract ts->tokenbuf and store the entity's value. */ + *bp++ = (jschar) c; + if (ispair) + *bp++ = (jschar) d; + *bp = 0; + ts->tokenbuf.ptr = bp; + return JS_TRUE; + +badncr: + msg = JSMSG_BAD_XML_NCR; +bad: + /* No match: throw a TypeError per ECMA-357 10.3.2.1 step 8(a). */ + JS_ASSERT(STRING_BUFFER_OK(&ts->tokenbuf)); + JS_ASSERT(PTRDIFF(ts->tokenbuf.ptr, bp, jschar) >= 1); + bytes = js_DeflateString(cx, bp + 1, + PTRDIFF(ts->tokenbuf.ptr, bp, jschar) - 1); + if (bytes) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + msg, bytes); + JS_free(cx, bytes); + } + return JS_FALSE; +} + +#endif /* JS_HAS_XML_SUPPORT */ + +JSTokenType +js_PeekToken(JSContext *cx, JSTokenStream *ts) +{ + JSTokenType tt; + + if (ts->lookahead != 0) { + tt = ts->tokens[(ts->cursor + ts->lookahead) & NTOKENS_MASK].type; + } else { + tt = js_GetToken(cx, ts); + js_UngetToken(ts); + } + return tt; +} + +JSTokenType +js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts) +{ + JSTokenType tt; + + if (!ON_CURRENT_LINE(ts, CURRENT_TOKEN(ts).pos)) + return TOK_EOL; + ts->flags |= TSF_NEWLINES; + tt = js_PeekToken(cx, ts); + ts->flags &= ~TSF_NEWLINES; + return tt; +} + +/* + * We have encountered a '\': check for a Unicode escape sequence after it, + * returning the character code value if we found a Unicode escape sequence. + * Otherwise, non-destructively return the original '\'. + */ +static int32 +GetUnicodeEscape(JSTokenStream *ts) +{ + jschar cp[5]; + int32 c; + + if (PeekChars(ts, 5, cp) && cp[0] == 'u' && + JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]) && + JS7_ISHEX(cp[3]) && JS7_ISHEX(cp[4])) + { + c = (((((JS7_UNHEX(cp[1]) << 4) + + JS7_UNHEX(cp[2])) << 4) + + JS7_UNHEX(cp[3])) << 4) + + JS7_UNHEX(cp[4]); + SkipChars(ts, 5); + return c; + } + return '\\'; +} + +static JSToken * +NewToken(JSTokenStream *ts, ptrdiff_t adjust) +{ + JSToken *tp; + + ts->cursor = (ts->cursor + 1) & NTOKENS_MASK; + tp = &CURRENT_TOKEN(ts); + tp->ptr = ts->linebuf.ptr + adjust; + tp->pos.begin.index = ts->linepos + + PTRDIFF(tp->ptr, ts->linebuf.base, jschar) - + ts->ungetpos; + tp->pos.begin.lineno = tp->pos.end.lineno = (uint16)ts->lineno; + return tp; +} + +static JS_ALWAYS_INLINE JSBool +ScanAsSpace(jschar c) +{ + /* Treat little- and big-endian BOMs as whitespace for compatibility. */ + if (JS_ISSPACE(c) || c == 0xfffe || c == 0xfeff) + return JS_TRUE; + return JS_FALSE; +} + +JSTokenType +js_GetToken(JSContext *cx, JSTokenStream *ts) +{ + JSTokenType tt; + int32 c, qc; + JSToken *tp; + JSAtom *atom; + JSBool hadUnicodeEscape; + const struct keyword *kw; +#if JS_HAS_XML_SUPPORT + JSBool inTarget; + size_t targetLength; + ptrdiff_t contentIndex; +#endif + +#define INIT_TOKENBUF() (ts->tokenbuf.ptr = ts->tokenbuf.base) +#define TOKENBUF_LENGTH() PTRDIFF(ts->tokenbuf.ptr, ts->tokenbuf.base, jschar) +#define TOKENBUF_OK() STRING_BUFFER_OK(&ts->tokenbuf) +#define TOKENBUF_TO_ATOM() (TOKENBUF_OK() \ + ? js_AtomizeChars(cx, \ + TOKENBUF_BASE(), \ + TOKENBUF_LENGTH(), \ + 0) \ + : NULL) +#define ADD_TO_TOKENBUF(c) FastAppendChar(&ts->tokenbuf, (jschar) (c)) + +/* The following 4 macros should only be used when TOKENBUF_OK() is true. */ +#define TOKENBUF_BASE() (ts->tokenbuf.base) +#define TOKENBUF_END() (ts->tokenbuf.ptr) +#define TOKENBUF_CHAR(i) (ts->tokenbuf.base[i]) +#define TRIM_TOKENBUF(i) (ts->tokenbuf.ptr = ts->tokenbuf.base + i) +#define NUL_TERM_TOKENBUF() (*ts->tokenbuf.ptr = 0) + + /* Check for a pushed-back token resulting from mismatching lookahead. */ + while (ts->lookahead != 0) { + JS_ASSERT(!(ts->flags & TSF_XMLTEXTMODE)); + ts->lookahead--; + ts->cursor = (ts->cursor + 1) & NTOKENS_MASK; + tt = CURRENT_TOKEN(ts).type; + if (tt != TOK_EOL || (ts->flags & TSF_NEWLINES)) + return tt; + } + + /* If there was a fatal error, keep returning TOK_ERROR. */ + if (ts->flags & TSF_ERROR) + return TOK_ERROR; + +#if JS_HAS_XML_SUPPORT + if (ts->flags & TSF_XMLTEXTMODE) { + tt = TOK_XMLSPACE; /* veto if non-space, return TOK_XMLTEXT */ + tp = NewToken(ts, 0); + INIT_TOKENBUF(); + qc = (ts->flags & TSF_XMLONLYMODE) ? '<' : '{'; + + while ((c = GetChar(ts)) != qc && c != '<' && c != EOF) { + if (c == '&' && qc == '<') { + if (!GetXMLEntity(cx, ts)) + goto error; + tt = TOK_XMLTEXT; + continue; + } + + if (!JS_ISXMLSPACE(c)) + tt = TOK_XMLTEXT; + ADD_TO_TOKENBUF(c); + } + UngetChar(ts, c); + + if (TOKENBUF_LENGTH() == 0) { + atom = NULL; + } else { + atom = TOKENBUF_TO_ATOM(); + if (!atom) + goto error; + } + tp->pos.end.lineno = (uint16)ts->lineno; + tp->t_op = JSOP_STRING; + tp->t_atom = atom; + goto out; + } + + if (ts->flags & TSF_XMLTAGMODE) { + tp = NewToken(ts, 0); + c = GetChar(ts); + if (JS_ISXMLSPACE(c)) { + do { + c = GetChar(ts); + } while (JS_ISXMLSPACE(c)); + UngetChar(ts, c); + tt = TOK_XMLSPACE; + goto out; + } + + if (c == EOF) { + tt = TOK_EOF; + goto out; + } + + INIT_TOKENBUF(); + if (JS_ISXMLNSSTART(c)) { + JSBool sawColon = JS_FALSE; + + ADD_TO_TOKENBUF(c); + while ((c = GetChar(ts)) != EOF && JS_ISXMLNAME(c)) { + if (c == ':') { + int nextc; + + if (sawColon || + (nextc = PeekChar(ts), + ((ts->flags & TSF_XMLONLYMODE) || nextc != '{') && + !JS_ISXMLNAME(nextc))) { + js_ReportCompileErrorNumber(cx, ts, NULL, + JSREPORT_ERROR, + JSMSG_BAD_XML_QNAME); + goto error; + } + sawColon = JS_TRUE; + } + + ADD_TO_TOKENBUF(c); + } + + UngetChar(ts, c); + atom = TOKENBUF_TO_ATOM(); + if (!atom) + goto error; + tp->t_op = JSOP_STRING; + tp->t_atom = atom; + tt = TOK_XMLNAME; + goto out; + } + + switch (c) { + case '{': + if (ts->flags & TSF_XMLONLYMODE) + goto bad_xml_char; + tt = TOK_LC; + goto out; + + case '=': + tt = TOK_ASSIGN; + goto out; + + case '"': + case '\'': + qc = c; + while ((c = GetChar(ts)) != qc) { + if (c == EOF) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_STRING); + goto error; + } + + /* + * XML attribute values are double-quoted when pretty-printed, + * so escape " if it is expressed directly in a single-quoted + * attribute value. + */ + if (c == '"' && !(ts->flags & TSF_XMLONLYMODE)) { + JS_ASSERT(qc == '\''); + js_AppendCString(&ts->tokenbuf, js_quot_entity_str); + continue; + } + + if (c == '&' && (ts->flags & TSF_XMLONLYMODE)) { + if (!GetXMLEntity(cx, ts)) + goto error; + continue; + } + + ADD_TO_TOKENBUF(c); + } + atom = TOKENBUF_TO_ATOM(); + if (!atom) + goto error; + tp->pos.end.lineno = (uint16)ts->lineno; + tp->t_op = JSOP_STRING; + tp->t_atom = atom; + tt = TOK_XMLATTR; + goto out; + + case '>': + tt = TOK_XMLTAGC; + goto out; + + case '/': + if (MatchChar(ts, '>')) { + tt = TOK_XMLPTAGC; + goto out; + } + /* FALL THROUGH */ + + bad_xml_char: + default: + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_CHARACTER); + goto error; + } + /* NOTREACHED */ + } +#endif /* JS_HAS_XML_SUPPORT */ + +retry: + do { + c = GetChar(ts); + if (c == '\n') { + ts->flags &= ~TSF_DIRTYLINE; + if (ts->flags & TSF_NEWLINES) + break; + } + } while (ScanAsSpace((jschar)c)); + + tp = NewToken(ts, -1); + if (c == EOF) { + tt = TOK_EOF; + goto out; + } + + hadUnicodeEscape = JS_FALSE; + if (JS_ISIDSTART(c) || + (c == '\\' && + (qc = GetUnicodeEscape(ts), + hadUnicodeEscape = JS_ISIDSTART(qc)))) { + if (hadUnicodeEscape) + c = qc; + INIT_TOKENBUF(); + for (;;) { + ADD_TO_TOKENBUF(c); + c = GetChar(ts); + if (c == '\\') { + qc = GetUnicodeEscape(ts); + if (!JS_ISIDENT(qc)) + break; + c = qc; + hadUnicodeEscape = JS_TRUE; + } else { + if (!JS_ISIDENT(c)) + break; + } + } + UngetChar(ts, c); + + /* + * Check for keywords unless we saw Unicode escape or parser asks + * to ignore keywords. + */ + if (!hadUnicodeEscape && + !(ts->flags & TSF_KEYWORD_IS_NAME) && + TOKENBUF_OK() && + (kw = FindKeyword(TOKENBUF_BASE(), TOKENBUF_LENGTH()))) { + if (kw->tokentype == TOK_RESERVED) { + if (!js_ReportCompileErrorNumber(cx, ts, NULL, + JSREPORT_WARNING | + JSREPORT_STRICT, + JSMSG_RESERVED_ID, + kw->chars)) { + goto error; + } + } else if (kw->version <= JSVERSION_NUMBER(cx)) { + tt = kw->tokentype; + tp->t_op = (JSOp) kw->op; + goto out; + } + } + + atom = TOKENBUF_TO_ATOM(); + if (!atom) + goto error; + tp->t_op = JSOP_NAME; + tp->t_atom = atom; + tt = TOK_NAME; + goto out; + } + + if (JS7_ISDEC(c) || (c == '.' && JS7_ISDEC(PeekChar(ts)))) { + jsint radix; + const jschar *endptr; + jsdouble dval; + + radix = 10; + INIT_TOKENBUF(); + + if (c == '0') { + ADD_TO_TOKENBUF(c); + c = GetChar(ts); + if (JS_TOLOWER(c) == 'x') { + ADD_TO_TOKENBUF(c); + c = GetChar(ts); + radix = 16; + } else if (JS7_ISDEC(c)) { + radix = 8; + } + } + + while (JS7_ISHEX(c)) { + if (radix < 16) { + if (JS7_ISLET(c)) + break; + + /* + * We permit 08 and 09 as decimal numbers, which makes our + * behaviour a superset of the ECMA numeric grammar. We might + * not always be so permissive, so we warn about it. + */ + if (radix == 8 && c >= '8') { + if (!js_ReportCompileErrorNumber(cx, ts, NULL, + JSREPORT_WARNING, + JSMSG_BAD_OCTAL, + c == '8' ? "08" : "09")) { + goto error; + } + radix = 10; + } + } + ADD_TO_TOKENBUF(c); + c = GetChar(ts); + } + + if (radix == 10 && (c == '.' || JS_TOLOWER(c) == 'e')) { + if (c == '.') { + do { + ADD_TO_TOKENBUF(c); + c = GetChar(ts); + } while (JS7_ISDEC(c)); + } + if (JS_TOLOWER(c) == 'e') { + ADD_TO_TOKENBUF(c); + c = GetChar(ts); + if (c == '+' || c == '-') { + ADD_TO_TOKENBUF(c); + c = GetChar(ts); + } + if (!JS7_ISDEC(c)) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_MISSING_EXPONENT); + goto error; + } + do { + ADD_TO_TOKENBUF(c); + c = GetChar(ts); + } while (JS7_ISDEC(c)); + } + } + + /* Put back the next char and NUL-terminate tokenbuf for js_strto*. */ + UngetChar(ts, c); + ADD_TO_TOKENBUF(0); + + if (!TOKENBUF_OK()) + goto error; + if (radix == 10) { + if (!js_strtod(cx, TOKENBUF_BASE(), TOKENBUF_END(), + &endptr, &dval)) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_OUT_OF_MEMORY); + goto error; + } + } else { + if (!js_strtointeger(cx, TOKENBUF_BASE(), TOKENBUF_END(), + &endptr, radix, &dval)) { + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_OUT_OF_MEMORY); + goto error; + } + } + tp->t_dval = dval; + tt = TOK_NUMBER; + goto out; + } + + if (c == '"' || c == '\'') { + qc = c; + INIT_TOKENBUF(); + while ((c = GetChar(ts)) != qc) { + if (c == '\n' || c == EOF) { + UngetChar(ts, c); + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_STRING); + goto error; + } + if (c == '\\') { + switch (c = GetChar(ts)) { + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + + default: + if ('0' <= c && c < '8') { + int32 val = JS7_UNDEC(c); + + c = PeekChar(ts); + if ('0' <= c && c < '8') { + val = 8 * val + JS7_UNDEC(c); + GetChar(ts); + c = PeekChar(ts); + if ('0' <= c && c < '8') { + int32 save = val; + val = 8 * val + JS7_UNDEC(c); + if (val <= 0377) + GetChar(ts); + else + val = save; + } + } + + c = (jschar)val; + } else if (c == 'u') { + jschar cp[4]; + if (PeekChars(ts, 4, cp) && + JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) && + JS7_ISHEX(cp[2]) && JS7_ISHEX(cp[3])) { + c = (((((JS7_UNHEX(cp[0]) << 4) + + JS7_UNHEX(cp[1])) << 4) + + JS7_UNHEX(cp[2])) << 4) + + JS7_UNHEX(cp[3]); + SkipChars(ts, 4); + } + } else if (c == 'x') { + jschar cp[2]; + if (PeekChars(ts, 2, cp) && + JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1])) { + c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]); + SkipChars(ts, 2); + } + } else if (c == '\n') { + /* ECMA follows C by removing escaped newlines. */ + continue; + } + break; + } + } + ADD_TO_TOKENBUF(c); + } + atom = TOKENBUF_TO_ATOM(); + if (!atom) + goto error; + tp->pos.end.lineno = (uint16)ts->lineno; + tp->t_op = JSOP_STRING; + tp->t_atom = atom; + tt = TOK_STRING; + goto out; + } + + switch (c) { + case '\n': tt = TOK_EOL; goto eol_out; + case ';': tt = TOK_SEMI; break; + case '[': tt = TOK_LB; break; + case ']': tt = TOK_RB; break; + case '{': tt = TOK_LC; break; + case '}': tt = TOK_RC; break; + case '(': tt = TOK_LP; break; + case ')': tt = TOK_RP; break; + case ',': tt = TOK_COMMA; break; + case '?': tt = TOK_HOOK; break; + + case '.': +#if JS_HAS_XML_SUPPORT + if (MatchChar(ts, c)) + tt = TOK_DBLDOT; + else +#endif + tt = TOK_DOT; + break; + + case ':': +#if JS_HAS_XML_SUPPORT + if (MatchChar(ts, c)) { + tt = TOK_DBLCOLON; + break; + } +#endif + /* + * Default so compiler can modify to JSOP_GETTER if 'p getter: v' in an + * object initializer, likewise for setter. + */ + tp->t_op = JSOP_NOP; + tt = TOK_COLON; + break; + + case '|': + if (MatchChar(ts, c)) { + tt = TOK_OR; + } else if (MatchChar(ts, '=')) { + tp->t_op = JSOP_BITOR; + tt = TOK_ASSIGN; + } else { + tt = TOK_BITOR; + } + break; + + case '^': + if (MatchChar(ts, '=')) { + tp->t_op = JSOP_BITXOR; + tt = TOK_ASSIGN; + } else { + tt = TOK_BITXOR; + } + break; + + case '&': + if (MatchChar(ts, c)) { + tt = TOK_AND; + } else if (MatchChar(ts, '=')) { + tp->t_op = JSOP_BITAND; + tt = TOK_ASSIGN; + } else { + tt = TOK_BITAND; + } + break; + + case '=': + if (MatchChar(ts, c)) { + tp->t_op = MatchChar(ts, c) ? JSOP_STRICTEQ : JSOP_EQ; + tt = TOK_EQOP; + } else { + tp->t_op = JSOP_NOP; + tt = TOK_ASSIGN; + } + break; + + case '!': + if (MatchChar(ts, '=')) { + tp->t_op = MatchChar(ts, '=') ? JSOP_STRICTNE : JSOP_NE; + tt = TOK_EQOP; + } else { + tp->t_op = JSOP_NOT; + tt = TOK_UNARYOP; + } + break; + +#if JS_HAS_XML_SUPPORT + case '@': + tt = TOK_AT; + break; +#endif + + case '<': +#if JS_HAS_XML_SUPPORT + /* + * After much testing, it's clear that Postel's advice to protocol + * designers ("be liberal in what you accept, and conservative in what + * you send") invites a natural-law repercussion for JS as "protocol": + * + * "If you are liberal in what you accept, others will utterly fail to + * be conservative in what they send." + * + * Which means you will get within every //-style comment unless we have to. So we set + * TSF_IN_HTML_COMMENT when a either on a clean line, or + * only if (ts->flags & TSF_IN_HTML_COMMENT), in a //-style comment. + * + * This still works as before given a malformed comment hiding hack such as: + * + * + * + * It does not cope with malformed comment hiding hacks where --> is hidden + * by C-style comments, or on a dirty line. Such cases are already broken. + */ +#define TSF_IN_HTML_COMMENT 0x2000 + +/* Ignore keywords and return TOK_NAME instead to the parser. */ +#define TSF_KEYWORD_IS_NAME 0x4000 + +/* Unicode separators that are treated as line terminators, in addition to \n, \r */ +#define LINE_SEPARATOR 0x2028 +#define PARA_SEPARATOR 0x2029 + +/* + * Create a new token stream, either from an input buffer or from a file. + * Return null on file-open or memory-allocation failure. + * + * The function uses JSContext.tempPool to allocate internal buffers. The + * caller should release them using JS_ARENA_RELEASE after it has finished + * with the token stream and has called js_CloseTokenStream. + */ +extern JSBool +js_InitTokenStream(JSContext *cx, JSTokenStream *ts, + const jschar *base, size_t length, + FILE *fp, const char *filename, uintN lineno); + +extern void +js_CloseTokenStream(JSContext *cx, JSTokenStream *ts); + +extern JS_FRIEND_API(int) +js_fgets(char *buf, int size, FILE *file); + +/* + * If the given char array forms JavaScript keyword, return corresponding + * token. Otherwise return TOK_EOF. + */ +extern JSTokenType +js_CheckKeyword(const jschar *chars, size_t length); + +/* + * Friend-exported API entry point to call a mapping function on each reserved + * identifier in the scanner's keyword table. + */ +extern JS_FRIEND_API(void) +js_MapKeywords(void (*mapfun)(const char *)); + +/* + * Check that str forms a valid JS identifier name. The function does not + * check if str is a JS keyword. + */ +extern JSBool +js_IsIdentifier(JSString *str); + +/* + * Report a compile-time error by its number. Return true for a warning, false + * for an error. When pn is not null, use it to report error's location. + * Otherwise use ts, which must not be null. + */ +JSBool +js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, + uintN flags, uintN errorNumber, ...); + +/* + * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error + * message have const jschar* type, not const char*. + */ +#define JSREPORT_UC 0x100 + +/* + * Look ahead one token and return its type. + */ +extern JSTokenType +js_PeekToken(JSContext *cx, JSTokenStream *ts); + +extern JSTokenType +js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts); + +/* + * Get the next token from ts. + */ +extern JSTokenType +js_GetToken(JSContext *cx, JSTokenStream *ts); + +/* + * Push back the last scanned token onto ts. + */ +extern void +js_UngetToken(JSTokenStream *ts); + +/* + * Get the next token from ts if its type is tt. + */ +extern JSBool +js_MatchToken(JSContext *cx, JSTokenStream *ts, JSTokenType tt); + +JS_END_EXTERN_C + +#endif /* jsscan_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscope.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscope.cpp new file mode 100644 index 0000000..1f9bc0c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscope.cpp @@ -0,0 +1,1955 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS symbol tables. + */ +#include "jsstddef.h" +#include +#include +#include "jstypes.h" +#include "jsarena.h" +#include "jsbit.h" +#include "jsclist.h" +#include "jsdhash.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jsapi.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsdbgapi.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsscope.h" +#include "jsstr.h" + +JSScope * +js_GetMutableScope(JSContext *cx, JSObject *obj) +{ + JSScope *scope, *newscope; + JSClass *clasp; + uint32 freeslot; + + scope = OBJ_SCOPE(obj); + JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope)); + if (scope->object == obj) + return scope; + newscope = js_NewScope(cx, 0, scope->map.ops, LOCKED_OBJ_GET_CLASS(obj), + obj); + if (!newscope) + return NULL; + JS_LOCK_SCOPE(cx, newscope); + obj->map = js_HoldObjectMap(cx, &newscope->map); + JS_ASSERT(newscope->map.freeslot == JSSLOT_FREE(STOBJ_GET_CLASS(obj))); + clasp = STOBJ_GET_CLASS(obj); + if (clasp->reserveSlots) { + freeslot = JSSLOT_FREE(clasp) + clasp->reserveSlots(cx, obj); + if (freeslot > STOBJ_NSLOTS(obj)) + freeslot = STOBJ_NSLOTS(obj); + if (newscope->map.freeslot < freeslot) + newscope->map.freeslot = freeslot; + } + scope = (JSScope *) js_DropObjectMap(cx, &scope->map, obj); + JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope); + return newscope; +} + +/* + * JSScope uses multiplicative hashing, _a la_ jsdhash.[ch], but specialized + * to minimize footprint. But if a scope has fewer than SCOPE_HASH_THRESHOLD + * entries, we use linear search and avoid allocating scope->table. + */ +#define SCOPE_HASH_THRESHOLD 6 +#define MIN_SCOPE_SIZE_LOG2 4 +#define MIN_SCOPE_SIZE JS_BIT(MIN_SCOPE_SIZE_LOG2) +#define SCOPE_TABLE_NBYTES(n) ((n) * sizeof(JSScopeProperty *)) + +static void +InitMinimalScope(JSScope *scope) +{ + scope->shape = 0; + scope->hashShift = JS_DHASH_BITS - MIN_SCOPE_SIZE_LOG2; + scope->entryCount = scope->removedCount = 0; + scope->table = NULL; + scope->lastProp = NULL; +} + +static JSBool +CreateScopeTable(JSContext *cx, JSScope *scope, JSBool report) +{ + int sizeLog2; + JSScopeProperty *sprop, **spp; + + JS_ASSERT(!scope->table); + JS_ASSERT(scope->lastProp); + + if (scope->entryCount > SCOPE_HASH_THRESHOLD) { + /* + * Either we're creating a table for a large scope that was populated + * via property cache hit logic under JSOP_INITPROP, JSOP_SETNAME, or + * JSOP_SETPROP; or else calloc failed at least once already. In any + * event, let's try to grow, overallocating to hold at least twice the + * current population. + */ + sizeLog2 = JS_CeilingLog2(2 * scope->entryCount); + scope->hashShift = JS_DHASH_BITS - sizeLog2; + } else { + JS_ASSERT(scope->hashShift == JS_DHASH_BITS - MIN_SCOPE_SIZE_LOG2); + sizeLog2 = MIN_SCOPE_SIZE_LOG2; + } + + scope->table = (JSScopeProperty **) + calloc(JS_BIT(sizeLog2), sizeof(JSScopeProperty *)); + if (!scope->table) { + if (report) + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + js_UpdateMallocCounter(cx, JS_BIT(sizeLog2) * sizeof(JSScopeProperty *)); + + scope->hashShift = JS_DHASH_BITS - sizeLog2; + for (sprop = scope->lastProp; sprop; sprop = sprop->parent) { + spp = js_SearchScope(scope, sprop->id, JS_TRUE); + SPROP_STORE_PRESERVING_COLLISION(spp, sprop); + } + return JS_TRUE; +} + +JSScope * +js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp, + JSObject *obj) +{ + JSScope *scope; + + scope = (JSScope *) JS_malloc(cx, sizeof(JSScope)); + if (!scope) + return NULL; + + js_InitObjectMap(&scope->map, nrefs, ops, clasp); + scope->object = obj; + scope->flags = 0; + InitMinimalScope(scope); + +#ifdef JS_THREADSAFE + js_InitTitle(cx, &scope->title); +#endif + JS_RUNTIME_METER(cx->runtime, liveScopes); + JS_RUNTIME_METER(cx->runtime, totalScopes); + return scope; +} + +#ifdef DEBUG_SCOPE_COUNT +extern void +js_unlog_scope(JSScope *scope); +#endif + +#if defined DEBUG || defined JS_DUMP_PROPTREE_STATS +# include "jsprf.h" +# define LIVE_SCOPE_METER(cx,expr) JS_LOCK_RUNTIME_VOID(cx->runtime,expr) +#else +# define LIVE_SCOPE_METER(cx,expr) /* nothing */ +#endif + +void +js_DestroyScope(JSContext *cx, JSScope *scope) +{ +#ifdef DEBUG_SCOPE_COUNT + js_unlog_scope(scope); +#endif + +#ifdef JS_THREADSAFE + js_FinishTitle(cx, &scope->title); +#endif + if (scope->table) + JS_free(cx, scope->table); + + LIVE_SCOPE_METER(cx, cx->runtime->liveScopeProps -= scope->entryCount); + JS_RUNTIME_UNMETER(cx->runtime, liveScopes); + JS_free(cx, scope); +} + +#ifdef JS_DUMP_PROPTREE_STATS +typedef struct JSScopeStats { + jsrefcount searches; + jsrefcount hits; + jsrefcount misses; + jsrefcount hashes; + jsrefcount steps; + jsrefcount stepHits; + jsrefcount stepMisses; + jsrefcount adds; + jsrefcount redundantAdds; + jsrefcount addFailures; + jsrefcount changeFailures; + jsrefcount compresses; + jsrefcount grows; + jsrefcount removes; + jsrefcount removeFrees; + jsrefcount uselessRemoves; + jsrefcount shrinks; +} JSScopeStats; + +JS_FRIEND_DATA(JSScopeStats) js_scope_stats = {0}; + +# define METER(x) JS_ATOMIC_INCREMENT(&js_scope_stats.x) +#else +# define METER(x) /* nothing */ +#endif + +JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4); +JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD); + +#if JS_BYTES_PER_WORD == 4 +# define HASH_ID(id) ((JSHashNumber)(id)) +#elif JS_BYTES_PER_WORD == 8 +# define HASH_ID(id) ((JSHashNumber)(id) ^ (JSHashNumber)((id) >> 32)) +#else +# error "Unsupported configuration" +#endif + +/* + * Double hashing needs the second hash code to be relatively prime to table + * size, so we simply make hash2 odd. The inputs to multiplicative hash are + * the golden ratio, expressed as a fixed-point 32 bit fraction, and the id + * itself. + */ +#define SCOPE_HASH0(id) (HASH_ID(id) * JS_GOLDEN_RATIO) +#define SCOPE_HASH1(hash0,shift) ((hash0) >> (shift)) +#define SCOPE_HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1) + +JS_FRIEND_API(JSScopeProperty **) +js_SearchScope(JSScope *scope, jsid id, JSBool adding) +{ + JSHashNumber hash0, hash1, hash2; + int hashShift, sizeLog2; + JSScopeProperty *stored, *sprop, **spp, **firstRemoved; + uint32 sizeMask; + + METER(searches); + if (!scope->table) { + /* Not enough properties to justify hashing: search from lastProp. */ + JS_ASSERT(!SCOPE_HAD_MIDDLE_DELETE(scope)); + for (spp = &scope->lastProp; (sprop = *spp); spp = &sprop->parent) { + if (sprop->id == id) { + METER(hits); + return spp; + } + } + METER(misses); + return spp; + } + + /* Compute the primary hash address. */ + METER(hashes); + hash0 = SCOPE_HASH0(id); + hashShift = scope->hashShift; + hash1 = SCOPE_HASH1(hash0, hashShift); + spp = scope->table + hash1; + + /* Miss: return space for a new entry. */ + stored = *spp; + if (SPROP_IS_FREE(stored)) { + METER(misses); + return spp; + } + + /* Hit: return entry. */ + sprop = SPROP_CLEAR_COLLISION(stored); + if (sprop && sprop->id == id) { + METER(hits); + return spp; + } + + /* Collision: double hash. */ + sizeLog2 = JS_DHASH_BITS - hashShift; + hash2 = SCOPE_HASH2(hash0, sizeLog2, hashShift); + sizeMask = JS_BITMASK(sizeLog2); + + /* Save the first removed entry pointer so we can recycle it if adding. */ + if (SPROP_IS_REMOVED(stored)) { + firstRemoved = spp; + } else { + firstRemoved = NULL; + if (adding && !SPROP_HAD_COLLISION(stored)) + SPROP_FLAG_COLLISION(spp, sprop); + } + + for (;;) { + METER(steps); + hash1 -= hash2; + hash1 &= sizeMask; + spp = scope->table + hash1; + + stored = *spp; + if (SPROP_IS_FREE(stored)) { + METER(stepMisses); + return (adding && firstRemoved) ? firstRemoved : spp; + } + + sprop = SPROP_CLEAR_COLLISION(stored); + if (sprop && sprop->id == id) { + METER(stepHits); + return spp; + } + + if (SPROP_IS_REMOVED(stored)) { + if (!firstRemoved) + firstRemoved = spp; + } else { + if (adding && !SPROP_HAD_COLLISION(stored)) + SPROP_FLAG_COLLISION(spp, sprop); + } + } + + /* NOTREACHED */ + return NULL; +} + +static JSBool +ChangeScope(JSContext *cx, JSScope *scope, int change) +{ + int oldlog2, newlog2; + uint32 oldsize, newsize, nbytes; + JSScopeProperty **table, **oldtable, **spp, **oldspp, *sprop; + + if (!scope->table) + return CreateScopeTable(cx, scope, JS_TRUE); + + /* Grow, shrink, or compress by changing scope->table. */ + oldlog2 = JS_DHASH_BITS - scope->hashShift; + newlog2 = oldlog2 + change; + oldsize = JS_BIT(oldlog2); + newsize = JS_BIT(newlog2); + nbytes = SCOPE_TABLE_NBYTES(newsize); + table = (JSScopeProperty **) calloc(nbytes, 1); + if (!table) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + /* Now that we have a new table allocated, update scope members. */ + scope->hashShift = JS_DHASH_BITS - newlog2; + scope->removedCount = 0; + oldtable = scope->table; + scope->table = table; + + /* Treat the above calloc as a JS_malloc, to match CreateScopeTable. */ + cx->runtime->gcMallocBytes += nbytes; + + /* Copy only live entries, leaving removed and free ones behind. */ + for (oldspp = oldtable; oldsize != 0; oldspp++) { + sprop = SPROP_FETCH(oldspp); + if (sprop) { + spp = js_SearchScope(scope, sprop->id, JS_TRUE); + JS_ASSERT(SPROP_IS_FREE(*spp)); + *spp = sprop; + } + oldsize--; + } + + /* Finally, free the old table storage. */ + JS_free(cx, oldtable); + return JS_TRUE; +} + +/* + * Take care to exclude the mark bits in case we're called from the GC. + */ +#define SPROP_FLAGS_NOT_MATCHED (SPROP_MARK | SPROP_FLAG_SHAPE_REGEN) + +static JSDHashNumber +js_HashScopeProperty(JSDHashTable *table, const void *key) +{ + const JSScopeProperty *sprop = (const JSScopeProperty *)key; + JSDHashNumber hash; + JSPropertyOp gsop; + + /* Accumulate from least to most random so the low bits are most random. */ + hash = 0; + gsop = sprop->getter; + if (gsop) + hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsword)gsop; + gsop = sprop->setter; + if (gsop) + hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsword)gsop; + + hash = JS_ROTATE_LEFT32(hash, 4) + ^ (sprop->flags & ~SPROP_FLAGS_NOT_MATCHED); + + hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->attrs; + hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->shortid; + hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->slot; + hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->id; + return hash; +} + +#define SPROP_MATCH(sprop, child) \ + SPROP_MATCH_PARAMS(sprop, (child)->id, (child)->getter, (child)->setter, \ + (child)->slot, (child)->attrs, (child)->flags, \ + (child)->shortid) + +#define SPROP_MATCH_PARAMS(sprop, aid, agetter, asetter, aslot, aattrs, \ + aflags, ashortid) \ + ((sprop)->id == (aid) && \ + SPROP_MATCH_PARAMS_AFTER_ID(sprop, agetter, asetter, aslot, aattrs, \ + aflags, ashortid)) + +#define SPROP_MATCH_PARAMS_AFTER_ID(sprop, agetter, asetter, aslot, aattrs, \ + aflags, ashortid) \ + ((sprop)->getter == (agetter) && \ + (sprop)->setter == (asetter) && \ + (sprop)->slot == (aslot) && \ + (sprop)->attrs == (aattrs) && \ + (((sprop)->flags ^ (aflags)) & ~SPROP_FLAGS_NOT_MATCHED) == 0 && \ + (sprop)->shortid == (ashortid)) + +static JSBool +js_MatchScopeProperty(JSDHashTable *table, + const JSDHashEntryHdr *hdr, + const void *key) +{ + const JSPropertyTreeEntry *entry = (const JSPropertyTreeEntry *)hdr; + const JSScopeProperty *sprop = entry->child; + const JSScopeProperty *kprop = (const JSScopeProperty *)key; + + return SPROP_MATCH(sprop, kprop); +} + +static const JSDHashTableOps PropertyTreeHashOps = { + JS_DHashAllocTable, + JS_DHashFreeTable, + js_HashScopeProperty, + js_MatchScopeProperty, + JS_DHashMoveEntryStub, + JS_DHashClearEntryStub, + JS_DHashFinalizeStub, + NULL +}; + +/* + * A property tree node on rt->propertyFreeList overlays the following prefix + * struct on JSScopeProperty. + */ +typedef struct FreeNode { + jsid id; + JSScopeProperty *next; + JSScopeProperty **prevp; +} FreeNode; + +#define FREENODE(sprop) ((FreeNode *) (sprop)) + +#define FREENODE_INSERT(list, sprop) \ + JS_BEGIN_MACRO \ + FREENODE(sprop)->next = (list); \ + FREENODE(sprop)->prevp = &(list); \ + if (list) \ + FREENODE(list)->prevp = &FREENODE(sprop)->next; \ + (list) = (sprop); \ + JS_END_MACRO + +#define FREENODE_REMOVE(sprop) \ + JS_BEGIN_MACRO \ + *FREENODE(sprop)->prevp = FREENODE(sprop)->next; \ + if (FREENODE(sprop)->next) \ + FREENODE(FREENODE(sprop)->next)->prevp = FREENODE(sprop)->prevp; \ + JS_END_MACRO + +/* NB: Called with rt->gcLock held. */ +static JSScopeProperty * +NewScopeProperty(JSRuntime *rt) +{ + JSScopeProperty *sprop; + + sprop = rt->propertyFreeList; + if (sprop) { + FREENODE_REMOVE(sprop); + } else { + JS_ARENA_ALLOCATE_CAST(sprop, JSScopeProperty *, + &rt->propertyArenaPool, + sizeof(JSScopeProperty)); + if (!sprop) + return NULL; + } + + JS_RUNTIME_METER(rt, livePropTreeNodes); + JS_RUNTIME_METER(rt, totalPropTreeNodes); + return sprop; +} + +#define CHUNKY_KIDS_TAG ((jsuword)1) +#define KIDS_IS_CHUNKY(kids) ((jsuword)(kids) & CHUNKY_KIDS_TAG) +#define KIDS_TO_CHUNK(kids) ((PropTreeKidsChunk *) \ + ((jsuword)(kids) & ~CHUNKY_KIDS_TAG)) +#define CHUNK_TO_KIDS(chunk) ((JSScopeProperty *) \ + ((jsuword)(chunk) | CHUNKY_KIDS_TAG)) +#define MAX_KIDS_PER_CHUNK 10 +#define CHUNK_HASH_THRESHOLD 30 + +typedef struct PropTreeKidsChunk PropTreeKidsChunk; + +struct PropTreeKidsChunk { + JSScopeProperty *kids[MAX_KIDS_PER_CHUNK]; + JSDHashTable *table; + PropTreeKidsChunk *next; +}; + +static PropTreeKidsChunk * +NewPropTreeKidsChunk(JSRuntime *rt) +{ + PropTreeKidsChunk *chunk; + + chunk = (PropTreeKidsChunk *) calloc(1, sizeof *chunk); + if (!chunk) + return NULL; + JS_ASSERT(((jsuword)chunk & CHUNKY_KIDS_TAG) == 0); + JS_RUNTIME_METER(rt, propTreeKidsChunks); + return chunk; +} + +static void +DestroyPropTreeKidsChunk(JSRuntime *rt, PropTreeKidsChunk *chunk) +{ + JS_RUNTIME_UNMETER(rt, propTreeKidsChunks); + if (chunk->table) + JS_DHashTableDestroy(chunk->table); + free(chunk); +} + +/* NB: Called with rt->gcLock held. */ +static JSBool +InsertPropertyTreeChild(JSRuntime *rt, JSScopeProperty *parent, + JSScopeProperty *child, PropTreeKidsChunk *sweptChunk) +{ + JSDHashTable *table; + JSPropertyTreeEntry *entry; + JSScopeProperty **childp, *kids, *sprop; + PropTreeKidsChunk *chunk, **chunkp; + uintN i; + + JS_ASSERT(!parent || child->parent != parent); + + if (!parent) { + table = &rt->propertyTreeHash; + entry = (JSPropertyTreeEntry *) + JS_DHashTableOperate(table, child, JS_DHASH_ADD); + if (!entry) + return JS_FALSE; + childp = &entry->child; + sprop = *childp; + if (!sprop) { + *childp = child; + } else { + /* + * A "Duplicate child" case. + * + * We can't do away with child, as at least one live scope entry + * still points at it. What's more, that scope's lastProp chains + * through an ancestor line to reach child, and js_Enumerate and + * others count on this linkage. We must leave child out of the + * hash table, and not require it to be there when we eventually + * GC it (see RemovePropertyTreeChild, below). + * + * It is necessary to leave the duplicate child out of the hash + * table to preserve entry uniqueness. It is safe to leave the + * child out of the hash table (unlike the duplicate child cases + * below), because the child's parent link will be null, which + * can't dangle. + */ + JS_ASSERT(sprop != child && SPROP_MATCH(sprop, child)); + JS_RUNTIME_METER(rt, duplicatePropTreeNodes); + } + } else { + childp = &parent->kids; + kids = *childp; + if (kids) { + if (KIDS_IS_CHUNKY(kids)) { + chunk = KIDS_TO_CHUNK(kids); + + table = chunk->table; + if (table) { + entry = (JSPropertyTreeEntry *) + JS_DHashTableOperate(table, child, JS_DHASH_ADD); + if (!entry) + return JS_FALSE; + if (!entry->child) { + entry->child = child; + while (chunk->next) + chunk = chunk->next; + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + childp = &chunk->kids[i]; + sprop = *childp; + if (!sprop) + goto insert; + } + chunkp = &chunk->next; + goto new_chunk; + } + } + + do { + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + childp = &chunk->kids[i]; + sprop = *childp; + if (!sprop) + goto insert; + + JS_ASSERT(sprop != child); + if (SPROP_MATCH(sprop, child)) { + /* + * Duplicate child, see comment above. In this + * case, we must let the duplicate be inserted at + * this level in the tree, so we keep iterating, + * looking for an empty slot in which to insert. + */ + JS_ASSERT(sprop != child); + JS_RUNTIME_METER(rt, duplicatePropTreeNodes); + } + } + chunkp = &chunk->next; + } while ((chunk = *chunkp) != NULL); + + new_chunk: + if (sweptChunk) { + chunk = sweptChunk; + } else { + chunk = NewPropTreeKidsChunk(rt); + if (!chunk) + return JS_FALSE; + } + *chunkp = chunk; + childp = &chunk->kids[0]; + } else { + sprop = kids; + JS_ASSERT(sprop != child); + if (SPROP_MATCH(sprop, child)) { + /* + * Duplicate child, see comment above. Once again, we + * must let duplicates created by deletion pile up in a + * kids-chunk-list, in order to find them when sweeping + * and thereby avoid dangling parent pointers. + */ + JS_RUNTIME_METER(rt, duplicatePropTreeNodes); + } + if (sweptChunk) { + chunk = sweptChunk; + } else { + chunk = NewPropTreeKidsChunk(rt); + if (!chunk) + return JS_FALSE; + } + parent->kids = CHUNK_TO_KIDS(chunk); + chunk->kids[0] = sprop; + childp = &chunk->kids[1]; + } + } + insert: + *childp = child; + } + + child->parent = parent; + return JS_TRUE; +} + +/* NB: Called with rt->gcLock held. */ +static PropTreeKidsChunk * +RemovePropertyTreeChild(JSRuntime *rt, JSScopeProperty *child) +{ + PropTreeKidsChunk *freeChunk; + JSScopeProperty *parent, *kids, *kid; + JSDHashTable *table; + PropTreeKidsChunk *list, *chunk, **chunkp, *lastChunk; + uintN i, j; + JSPropertyTreeEntry *entry; + + freeChunk = NULL; + parent = child->parent; + if (!parent) { + /* + * Don't remove child if it is not in rt->propertyTreeHash, but only + * matches a root child in the table that has compatible members. See + * the "Duplicate child" comments in InsertPropertyTreeChild, above. + */ + table = &rt->propertyTreeHash; + } else { + kids = parent->kids; + if (KIDS_IS_CHUNKY(kids)) { + list = chunk = KIDS_TO_CHUNK(kids); + chunkp = &list; + table = chunk->table; + + do { + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + if (chunk->kids[i] == child) { + lastChunk = chunk; + if (!lastChunk->next) { + j = i + 1; + } else { + j = 0; + do { + chunkp = &lastChunk->next; + lastChunk = *chunkp; + } while (lastChunk->next); + } + for (; j < MAX_KIDS_PER_CHUNK; j++) { + if (!lastChunk->kids[j]) + break; + } + --j; + if (chunk != lastChunk || j > i) + chunk->kids[i] = lastChunk->kids[j]; + lastChunk->kids[j] = NULL; + if (j == 0) { + *chunkp = NULL; + if (!list) + parent->kids = NULL; + freeChunk = lastChunk; + } + goto out; + } + } + + chunkp = &chunk->next; + } while ((chunk = *chunkp) != NULL); + } else { + table = NULL; + kid = kids; + if (kid == child) + parent->kids = NULL; + } + } + +out: + if (table) { + entry = (JSPropertyTreeEntry *) + JS_DHashTableOperate(table, child, JS_DHASH_LOOKUP); + + if (entry->child == child) + JS_DHashTableRawRemove(table, &entry->hdr); + } + return freeChunk; +} + +static JSDHashTable * +HashChunks(PropTreeKidsChunk *chunk, uintN n) +{ + JSDHashTable *table; + uintN i; + JSScopeProperty *sprop; + JSPropertyTreeEntry *entry; + + table = JS_NewDHashTable(&PropertyTreeHashOps, NULL, + sizeof(JSPropertyTreeEntry), + JS_DHASH_DEFAULT_CAPACITY(n + 1)); + if (!table) + return NULL; + do { + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + sprop = chunk->kids[i]; + if (!sprop) + break; + entry = (JSPropertyTreeEntry *) + JS_DHashTableOperate(table, sprop, JS_DHASH_ADD); + entry->child = sprop; + } + } while ((chunk = chunk->next) != NULL); + return table; +} + +/* + * Called without cx->runtime->gcLock held. This function acquires that lock + * only when inserting a new child. Thus there may be races to find or add a + * node that result in duplicates. We expect such races to be rare! + * + * We use rt->gcLock, not rt->rtLock, to allow the GC potentially to nest here + * under js_GenerateShape. + */ +static JSScopeProperty * +GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent, + JSScopeProperty *child) +{ + JSRuntime *rt; + JSDHashTable *table; + JSPropertyTreeEntry *entry; + JSScopeProperty *sprop; + PropTreeKidsChunk *chunk; + uintN i, n; + uint32 shape; + + rt = cx->runtime; + if (!parent) { + JS_LOCK_GC(rt); + + table = &rt->propertyTreeHash; + entry = (JSPropertyTreeEntry *) + JS_DHashTableOperate(table, child, JS_DHASH_ADD); + if (!entry) + goto out_of_memory; + + sprop = entry->child; + if (sprop) + goto out; + } else { + /* + * Because chunks are appended at the end and never deleted except by + * the GC, we can search without taking the runtime's GC lock. We may + * miss a matching sprop added by another thread, and make a duplicate + * one, but that is an unlikely, therefore small, cost. The property + * tree has extremely low fan-out below its root in popular embeddings + * with real-world workloads. + * + * Patterns such as defining closures that capture a constructor's + * environment as getters or setters on the new object that is passed + * in as |this| can significantly increase fan-out below the property + * tree root -- see bug 335700 for details. + */ + entry = NULL; + sprop = parent->kids; + if (sprop) { + if (KIDS_IS_CHUNKY(sprop)) { + chunk = KIDS_TO_CHUNK(sprop); + + table = chunk->table; + if (table) { + JS_LOCK_GC(rt); + entry = (JSPropertyTreeEntry *) + JS_DHashTableOperate(table, child, JS_DHASH_LOOKUP); + sprop = entry->child; + if (sprop) { + JS_UNLOCK_GC(rt); + return sprop; + } + goto locked_not_found; + } + + n = 0; + do { + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + sprop = chunk->kids[i]; + if (!sprop) { + n += i; + if (n >= CHUNK_HASH_THRESHOLD) { + chunk = KIDS_TO_CHUNK(parent->kids); + if (!chunk->table) { + table = HashChunks(chunk, n); + JS_LOCK_GC(rt); + if (!table) + goto out_of_memory; + if (chunk->table) + JS_DHashTableDestroy(table); + else + chunk->table = table; + goto locked_not_found; + } + } + goto not_found; + } + + if (SPROP_MATCH(sprop, child)) + return sprop; + } + n += MAX_KIDS_PER_CHUNK; + } while ((chunk = chunk->next) != NULL); + } else { + if (SPROP_MATCH(sprop, child)) + return sprop; + } + } + + not_found: + JS_LOCK_GC(rt); + } + +locked_not_found: + /* + * Call js_GenerateShape before the allocation to prevent collecting the + * new property when the shape generation triggers the GC. + */ + shape = js_GenerateShape(cx, JS_TRUE, NULL); + + sprop = NewScopeProperty(rt); + if (!sprop) + goto out_of_memory; + + sprop->id = child->id; + sprop->getter = child->getter; + sprop->setter = child->setter; + sprop->slot = child->slot; + sprop->attrs = child->attrs; + sprop->flags = child->flags; + sprop->shortid = child->shortid; + sprop->parent = sprop->kids = NULL; + sprop->shape = shape; + + if (!parent) { + entry->child = sprop; + } else { + if (!InsertPropertyTreeChild(rt, parent, sprop, NULL)) + goto out_of_memory; + } + +out: + JS_UNLOCK_GC(rt); + return sprop; + +out_of_memory: + JS_UNLOCK_GC(rt); + JS_ReportOutOfMemory(cx); + return NULL; +} + +#ifdef DEBUG_notbrendan +#define CHECK_ANCESTOR_LINE(scope, sparse) \ + JS_BEGIN_MACRO \ + if ((scope)->table) CheckAncestorLine(scope, sparse); \ + JS_END_MACRO + +static void +CheckAncestorLine(JSScope *scope, JSBool sparse) +{ + uint32 size; + JSScopeProperty **spp, **start, **end, *ancestorLine, *sprop, *aprop; + uint32 entryCount, ancestorCount; + + ancestorLine = SCOPE_LAST_PROP(scope); + if (ancestorLine) + JS_ASSERT(SCOPE_HAS_PROPERTY(scope, ancestorLine)); + + entryCount = 0; + size = SCOPE_CAPACITY(scope); + start = scope->table; + for (spp = start, end = start + size; spp < end; spp++) { + sprop = SPROP_FETCH(spp); + if (sprop) { + entryCount++; + for (aprop = ancestorLine; aprop; aprop = aprop->parent) { + if (aprop == sprop) + break; + } + JS_ASSERT(aprop); + } + } + JS_ASSERT(entryCount == scope->entryCount); + + ancestorCount = 0; + for (sprop = ancestorLine; sprop; sprop = sprop->parent) { + if (SCOPE_HAD_MIDDLE_DELETE(scope) && + !SCOPE_HAS_PROPERTY(scope, sprop)) { + JS_ASSERT(sparse); + continue; + } + ancestorCount++; + } + JS_ASSERT(ancestorCount == scope->entryCount); +} +#else +#define CHECK_ANCESTOR_LINE(scope, sparse) /* nothing */ +#endif + +static void +ReportReadOnlyScope(JSContext *cx, JSScope *scope) +{ + JSString *str; + const char *bytes; + + str = js_ValueToString(cx, OBJECT_TO_JSVAL(scope->object)); + if (!str) + return; + bytes = js_GetStringBytes(cx, str); + if (!bytes) + return; + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_READ_ONLY, bytes); +} + +JSScopeProperty * +js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id, + JSPropertyOp getter, JSPropertyOp setter, uint32 slot, + uintN attrs, uintN flags, intN shortid) +{ + JSScopeProperty **spp, *sprop, *overwriting, **spvec, **spp2, child; + uint32 size, splen, i; + int change; + JSTempValueRooter tvr; + + JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope)); + CHECK_ANCESTOR_LINE(scope, JS_TRUE); + + /* + * You can't add properties to a sealed scope. But note well that you can + * change property attributes in a sealed scope, even though that replaces + * a JSScopeProperty * in the scope's hash table -- but no id is added, so + * the scope remains sealed. + */ + if (SCOPE_IS_SEALED(scope)) { + ReportReadOnlyScope(cx, scope); + return NULL; + } + + /* + * Normalize stub getter and setter values for faster is-stub testing in + * the SPROP_CALL_[GS]ETTER macros. + */ + if (getter == JS_PropertyStub) + getter = NULL; + if (setter == JS_PropertyStub) + setter = NULL; + + /* + * Search for id in order to claim its entry, allocating a property tree + * node if one doesn't already exist for our parameters. + */ + spp = js_SearchScope(scope, id, JS_TRUE); + sprop = overwriting = SPROP_FETCH(spp); + if (!sprop) { + JS_COUNT_OPERATION(cx, JSOW_NEW_PROPERTY); + + /* Check whether we need to grow, if the load factor is >= .75. */ + size = SCOPE_CAPACITY(scope); + if (scope->entryCount + scope->removedCount >= size - (size >> 2)) { + if (scope->removedCount >= size >> 2) { + METER(compresses); + change = 0; + } else { + METER(grows); + change = 1; + } + if (!ChangeScope(cx, scope, change) && + scope->entryCount + scope->removedCount == size - 1) { + METER(addFailures); + return NULL; + } + spp = js_SearchScope(scope, id, JS_TRUE); + JS_ASSERT(!SPROP_FETCH(spp)); + } + } else { + /* Property exists: js_SearchScope must have returned a valid entry. */ + JS_ASSERT(!SPROP_IS_REMOVED(*spp)); + + /* + * If all property members match, this is a redundant add and we can + * return early. If the caller wants to allocate a slot, but doesn't + * care which slot, copy sprop->slot into slot so we can match sprop, + * if all other members match. + */ + if (!(attrs & JSPROP_SHARED) && + slot == SPROP_INVALID_SLOT && + SPROP_HAS_VALID_SLOT(sprop, scope)) { + slot = sprop->slot; + } + if (SPROP_MATCH_PARAMS_AFTER_ID(sprop, getter, setter, slot, attrs, + flags, shortid)) { + METER(redundantAdds); + return sprop; + } + + /* + * If we are clearing sprop to force an existing property to be + * overwritten (apart from a duplicate formal parameter), we must + * unlink it from the ancestor line at scope->lastProp, lazily if + * sprop is not lastProp. And we must remove the entry at *spp, + * precisely so the lazy "middle delete" fixup code further below + * won't find sprop in scope->table, in spite of sprop being on + * the ancestor line. + * + * When we finally succeed in finding or creating a new sprop + * and storing its pointer at *spp, we'll use the |overwriting| + * local saved when we first looked up id to decide whether we're + * indeed creating a new entry, or merely overwriting an existing + * property. + */ + if (sprop == SCOPE_LAST_PROP(scope)) { + do { + SCOPE_REMOVE_LAST_PROP(scope); + if (!SCOPE_HAD_MIDDLE_DELETE(scope)) + break; + sprop = SCOPE_LAST_PROP(scope); + } while (sprop && !SCOPE_HAS_PROPERTY(scope, sprop)); + } else if (!SCOPE_HAD_MIDDLE_DELETE(scope)) { + /* + * If we have no hash table yet, we need one now. The middle + * delete code is simple-minded that way! + */ + if (!scope->table) { + if (!CreateScopeTable(cx, scope, JS_TRUE)) + return NULL; + spp = js_SearchScope(scope, id, JS_TRUE); + sprop = overwriting = SPROP_FETCH(spp); + } + SCOPE_SET_MIDDLE_DELETE(scope); + } + SCOPE_MAKE_UNIQUE_SHAPE(cx, scope); + + /* + * If we fail later on trying to find or create a new sprop, we will + * goto fail_overwrite and restore *spp from |overwriting|. Note that + * we don't bother to keep scope->removedCount in sync, because we'll + * fix up *spp and scope->entryCount shortly, no matter how control + * flow returns from this function. + */ + if (scope->table) + SPROP_STORE_PRESERVING_COLLISION(spp, NULL); + scope->entryCount--; + CHECK_ANCESTOR_LINE(scope, JS_TRUE); + sprop = NULL; + } + + if (!sprop) { + /* + * If properties were deleted from the middle of the list starting at + * scope->lastProp, we may need to fork the property tree and squeeze + * all deleted properties out of scope's ancestor line. Otherwise we + * risk adding a node with the same id as a "middle" node, violating + * the rule that properties along an ancestor line have distinct ids. + */ + if (SCOPE_HAD_MIDDLE_DELETE(scope)) { + JS_ASSERT(scope->table); + CHECK_ANCESTOR_LINE(scope, JS_TRUE); + + splen = scope->entryCount; + if (splen == 0) { + JS_ASSERT(scope->lastProp == NULL); + } else { + /* + * Enumerate live entries in scope->table using a temporary + * vector, by walking the (possibly sparse, due to deletions) + * ancestor line from scope->lastProp. + */ + spvec = (JSScopeProperty **) + JS_malloc(cx, SCOPE_TABLE_NBYTES(splen)); + if (!spvec) + goto fail_overwrite; + i = splen; + sprop = SCOPE_LAST_PROP(scope); + JS_ASSERT(sprop); + do { + /* + * NB: test SCOPE_GET_PROPERTY, not SCOPE_HAS_PROPERTY -- + * the latter insists that sprop->id maps to sprop, while + * the former simply tests whether sprop->id is bound in + * scope. We must allow for duplicate formal parameters + * along the ancestor line, and fork them as needed. + */ + if (!SCOPE_GET_PROPERTY(scope, sprop->id)) + continue; + + JS_ASSERT(sprop != overwriting); + if (i == 0) { + /* + * If our original splen estimate, scope->entryCount, + * is less than the ancestor line height, there must + * be duplicate formal parameters in this (function + * object) scope. Count remaining ancestors in order + * to realloc spvec. + */ + JSScopeProperty *tmp = sprop; + do { + if (SCOPE_GET_PROPERTY(scope, tmp->id)) + i++; + } while ((tmp = tmp->parent) != NULL); + spp2 = (JSScopeProperty **) + JS_realloc(cx, spvec, SCOPE_TABLE_NBYTES(splen+i)); + if (!spp2) { + JS_free(cx, spvec); + goto fail_overwrite; + } + + spvec = spp2; + memmove(spvec + i, spvec, SCOPE_TABLE_NBYTES(splen)); + splen += i; + } + + spvec[--i] = sprop; + } while ((sprop = sprop->parent) != NULL); + JS_ASSERT(i == 0); + + /* + * Now loop forward through spvec, forking the property tree + * whenever we see a "parent gap" due to deletions from scope. + * NB: sprop is null on first entry to the loop body. + */ + do { + if (spvec[i]->parent == sprop) { + sprop = spvec[i]; + } else { + sprop = GetPropertyTreeChild(cx, sprop, spvec[i]); + if (!sprop) { + JS_free(cx, spvec); + goto fail_overwrite; + } + + spp2 = js_SearchScope(scope, sprop->id, JS_FALSE); + JS_ASSERT(SPROP_FETCH(spp2) == spvec[i]); + SPROP_STORE_PRESERVING_COLLISION(spp2, sprop); + } + } while (++i < splen); + JS_free(cx, spvec); + + /* + * Now sprop points to the last property in scope, where the + * ancestor line from sprop to the root is dense w.r.t. scope: + * it contains no nodes not mapped by scope->table, apart from + * any stinking ECMA-mandated duplicate formal parameters. + */ + scope->lastProp = sprop; + CHECK_ANCESTOR_LINE(scope, JS_FALSE); + JS_RUNTIME_METER(cx->runtime, middleDeleteFixups); + } + + SCOPE_CLR_MIDDLE_DELETE(scope); + } + + /* + * Aliases share another property's slot, passed in the |slot| param. + * Shared properties have no slot. Unshared properties that do not + * alias another property's slot get one here, but may lose it due to + * a JS_ClearScope call. + */ + if (!(flags & SPROP_IS_ALIAS)) { + if (attrs & JSPROP_SHARED) { + slot = SPROP_INVALID_SLOT; + } else { + /* + * We may have set slot from a nearly-matching sprop, above. + * If so, we're overwriting that nearly-matching sprop, so we + * can reuse its slot -- we don't need to allocate a new one. + * Similarly, we use a specific slot if provided by the caller. + */ + if (slot == SPROP_INVALID_SLOT && + !js_AllocSlot(cx, scope->object, &slot)) { + goto fail_overwrite; + } + } + } + + /* + * Check for a watchpoint on a deleted property; if one exists, change + * setter to js_watch_set. + * XXXbe this could get expensive with lots of watchpoints... + */ + if (!JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList) && + js_FindWatchPoint(cx->runtime, scope, id)) { + JS_PUSH_TEMP_ROOT_SPROP(cx, overwriting, &tvr); + setter = js_WrapWatchedSetter(cx, id, attrs, setter); + JS_POP_TEMP_ROOT(cx, &tvr); + if (!setter) + goto fail_overwrite; + } + + /* Find or create a property tree node labeled by our arguments. */ + child.id = id; + child.getter = getter; + child.setter = setter; + child.slot = slot; + child.attrs = attrs; + child.flags = flags; + child.shortid = shortid; + sprop = GetPropertyTreeChild(cx, scope->lastProp, &child); + if (!sprop) + goto fail_overwrite; + + /* + * The scope's shape defaults to its last property's shape, but may + * be regenerated later as the scope diverges (from the property cache + * point of view) from the structural type associated with sprop. + */ + SCOPE_EXTEND_SHAPE(cx, scope, sprop); + + /* Store the tree node pointer in the table entry for id. */ + if (scope->table) + SPROP_STORE_PRESERVING_COLLISION(spp, sprop); + scope->entryCount++; + scope->lastProp = sprop; + CHECK_ANCESTOR_LINE(scope, JS_FALSE); +#ifdef DEBUG + if (!overwriting) { + LIVE_SCOPE_METER(cx, ++cx->runtime->liveScopeProps); + JS_RUNTIME_METER(cx->runtime, totalScopeProps); + } +#endif + + /* + * If we reach the hashing threshold, try to allocate scope->table. + * If we can't (a rare event, preceded by swapping to death on most + * modern OSes), stick with linear search rather than whining about + * this little set-back. Therefore we must test !scope->table and + * scope->entryCount >= SCOPE_HASH_THRESHOLD, not merely whether the + * entry count just reached the threshold. + */ + if (!scope->table && scope->entryCount >= SCOPE_HASH_THRESHOLD) + (void) CreateScopeTable(cx, scope, JS_FALSE); + } + + METER(adds); + return sprop; + +fail_overwrite: + if (overwriting) { + /* + * We may or may not have forked overwriting out of scope's ancestor + * line, so we must check (the alternative is to set a flag above, but + * that hurts the common, non-error case). If we did fork overwriting + * out, we'll add it back at scope->lastProp. This means enumeration + * order can change due to a failure to overwrite an id. + * XXXbe very minor incompatibility + */ + for (sprop = SCOPE_LAST_PROP(scope); ; sprop = sprop->parent) { + if (!sprop) { + sprop = SCOPE_LAST_PROP(scope); + if (overwriting->parent == sprop) { + scope->lastProp = overwriting; + } else { + sprop = GetPropertyTreeChild(cx, sprop, overwriting); + if (sprop) { + JS_ASSERT(sprop != overwriting); + scope->lastProp = sprop; + } + overwriting = sprop; + } + break; + } + if (sprop == overwriting) + break; + } + if (overwriting) { + if (scope->table) + SPROP_STORE_PRESERVING_COLLISION(spp, overwriting); + scope->entryCount++; + } + CHECK_ANCESTOR_LINE(scope, JS_TRUE); + } + METER(addFailures); + return NULL; +} + +JSScopeProperty * +js_ChangeScopePropertyAttrs(JSContext *cx, JSScope *scope, + JSScopeProperty *sprop, uintN attrs, uintN mask, + JSPropertyOp getter, JSPropertyOp setter) +{ + JSScopeProperty child, *newsprop, **spp; + + CHECK_ANCESTOR_LINE(scope, JS_TRUE); + + /* Allow only shared (slot-less) => unshared (slot-full) transition. */ + attrs |= sprop->attrs & mask; + JS_ASSERT(!((attrs ^ sprop->attrs) & JSPROP_SHARED) || + !(attrs & JSPROP_SHARED)); + if (getter == JS_PropertyStub) + getter = NULL; + if (setter == JS_PropertyStub) + setter = NULL; + if (sprop->attrs == attrs && + sprop->getter == getter && + sprop->setter == setter) { + return sprop; + } + + child.id = sprop->id; + child.getter = getter; + child.setter = setter; + child.slot = sprop->slot; + child.attrs = attrs; + child.flags = sprop->flags; + child.shortid = sprop->shortid; + + if (SCOPE_LAST_PROP(scope) == sprop) { + /* + * Optimize the case where the last property added to scope is changed + * to have a different attrs, getter, or setter. In the last property + * case, we need not fork the property tree. But since we do not call + * js_AddScopeProperty, we may need to allocate a new slot directly. + */ + if ((sprop->attrs & JSPROP_SHARED) && !(attrs & JSPROP_SHARED)) { + JS_ASSERT(child.slot == SPROP_INVALID_SLOT); + if (!js_AllocSlot(cx, scope->object, &child.slot)) + return NULL; + } + + newsprop = GetPropertyTreeChild(cx, sprop->parent, &child); + if (newsprop) { + spp = js_SearchScope(scope, sprop->id, JS_FALSE); + JS_ASSERT(SPROP_FETCH(spp) == sprop); + + if (scope->table) + SPROP_STORE_PRESERVING_COLLISION(spp, newsprop); + scope->lastProp = newsprop; + CHECK_ANCESTOR_LINE(scope, JS_TRUE); + } + } else { + /* + * Let js_AddScopeProperty handle this |overwriting| case, including + * the conservation of sprop->slot (if it's valid). We must not call + * js_RemoveScopeProperty here, it will free a valid sprop->slot and + * js_AddScopeProperty won't re-allocate it. + */ + newsprop = js_AddScopeProperty(cx, scope, child.id, + child.getter, child.setter, child.slot, + child.attrs, child.flags, child.shortid); + } + + if (newsprop) { + if (scope->shape == sprop->shape) + scope->shape = newsprop->shape; + else + SCOPE_MAKE_UNIQUE_SHAPE(cx, scope); + } +#ifdef JS_DUMP_PROPTREE_STATS + else + METER(changeFailures); +#endif + return newsprop; +} + +JSBool +js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id) +{ + JSScopeProperty **spp, *stored, *sprop; + uint32 size; + + JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope)); + CHECK_ANCESTOR_LINE(scope, JS_TRUE); + if (SCOPE_IS_SEALED(scope)) { + ReportReadOnlyScope(cx, scope); + return JS_FALSE; + } + METER(removes); + + spp = js_SearchScope(scope, id, JS_FALSE); + stored = *spp; + sprop = SPROP_CLEAR_COLLISION(stored); + if (!sprop) { + METER(uselessRemoves); + return JS_TRUE; + } + + /* Convert from a list to a hash so we can handle "middle deletes". */ + if (!scope->table && sprop != scope->lastProp) { + if (!CreateScopeTable(cx, scope, JS_TRUE)) + return JS_FALSE; + spp = js_SearchScope(scope, id, JS_FALSE); + stored = *spp; + sprop = SPROP_CLEAR_COLLISION(stored); + } + + /* First, if sprop is unshared and not cleared, free its slot number. */ + if (SPROP_HAS_VALID_SLOT(sprop, scope)) { + js_FreeSlot(cx, scope->object, sprop->slot); + JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals); + } + + /* Next, remove id by setting its entry to a removed or free sentinel. */ + if (SPROP_HAD_COLLISION(stored)) { + JS_ASSERT(scope->table); + *spp = SPROP_REMOVED; + scope->removedCount++; + } else { + METER(removeFrees); + if (scope->table) + *spp = NULL; + } + scope->entryCount--; + LIVE_SCOPE_METER(cx, --cx->runtime->liveScopeProps); + + /* Update scope->lastProp directly, or set its deferred update flag. */ + if (sprop == SCOPE_LAST_PROP(scope)) { + do { + SCOPE_REMOVE_LAST_PROP(scope); + if (!SCOPE_HAD_MIDDLE_DELETE(scope)) + break; + sprop = SCOPE_LAST_PROP(scope); + } while (sprop && !SCOPE_HAS_PROPERTY(scope, sprop)); + } else if (!SCOPE_HAD_MIDDLE_DELETE(scope)) { + SCOPE_SET_MIDDLE_DELETE(scope); + } + SCOPE_MAKE_UNIQUE_SHAPE(cx, scope); + CHECK_ANCESTOR_LINE(scope, JS_TRUE); + + /* Last, consider shrinking scope's table if its load factor is <= .25. */ + size = SCOPE_CAPACITY(scope); + if (size > MIN_SCOPE_SIZE && scope->entryCount <= size >> 2) { + METER(shrinks); + (void) ChangeScope(cx, scope, -1); + } + + return JS_TRUE; +} + +void +js_ClearScope(JSContext *cx, JSScope *scope) +{ + CHECK_ANCESTOR_LINE(scope, JS_TRUE); + LIVE_SCOPE_METER(cx, cx->runtime->liveScopeProps -= scope->entryCount); + + if (scope->table) + free(scope->table); + SCOPE_CLR_MIDDLE_DELETE(scope); + InitMinimalScope(scope); + JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals); +} + +void +js_TraceId(JSTracer *trc, jsid id) +{ + jsval v; + + v = ID_TO_VALUE(id); + JS_CALL_VALUE_TRACER(trc, v, "id"); +} + +#ifdef DEBUG +static void +PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize) +{ + JSScopeProperty *sprop; + jsid id; + size_t n; + const char *name; + + JS_ASSERT(trc->debugPrinter == PrintPropertyGetterOrSetter); + sprop = (JSScopeProperty *)trc->debugPrintArg; + id = sprop->id; + name = trc->debugPrintIndex ? js_setter_str : js_getter_str; + + if (JSID_IS_ATOM(id)) { + n = js_PutEscapedString(buf, bufsize - 1, + ATOM_TO_STRING(JSID_TO_ATOM(id)), 0); + if (n < bufsize - 1) + JS_snprintf(buf + n, bufsize - n, " %s", name); + } else if (JSID_IS_INT(sprop->id)) { + JS_snprintf(buf, bufsize, "%d %s", JSID_TO_INT(id), name); + } else { + JS_snprintf(buf, bufsize, " %s", name); + } +} +#endif + + +void +js_TraceScopeProperty(JSTracer *trc, JSScopeProperty *sprop) +{ + if (IS_GC_MARKING_TRACER(trc)) + sprop->flags |= SPROP_MARK; + TRACE_ID(trc, sprop->id); + +#if JS_HAS_GETTER_SETTER + if (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER)) { + if (sprop->attrs & JSPROP_GETTER) { + JS_ASSERT(JSVAL_IS_OBJECT((jsval) sprop->getter)); + JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, sprop, 0); + JS_CallTracer(trc, JSVAL_TO_OBJECT((jsval) sprop->getter), + JSTRACE_OBJECT); + } + if (sprop->attrs & JSPROP_SETTER) { + JS_ASSERT(JSVAL_IS_OBJECT((jsval) sprop->setter)); + JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, sprop, 1); + JS_CallTracer(trc, JSVAL_TO_OBJECT((jsval) sprop->setter), + JSTRACE_OBJECT); + } + } +#endif /* JS_HAS_GETTER_SETTER */ +} + +#ifdef JS_DUMP_PROPTREE_STATS + +#include + +static void +MeterKidCount(JSBasicStats *bs, uintN nkids) +{ + JS_BASIC_STATS_ACCUM(bs, nkids); + bs->hist[JS_MIN(nkids, 10)]++; +} + +static void +MeterPropertyTree(JSBasicStats *bs, JSScopeProperty *node) +{ + uintN i, nkids; + JSScopeProperty *kids, *kid; + PropTreeKidsChunk *chunk; + + nkids = 0; + kids = node->kids; + if (kids) { + if (KIDS_IS_CHUNKY(kids)) { + for (chunk = KIDS_TO_CHUNK(kids); chunk; chunk = chunk->next) { + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + kid = chunk->kids[i]; + if (!kid) + break; + MeterPropertyTree(bs, kid); + nkids++; + } + } + } else { + MeterPropertyTree(bs, kids); + nkids = 1; + } + } + + MeterKidCount(bs, nkids); +} + +static JSDHashOperator +js_MeterPropertyTree(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, + void *arg) +{ + JSPropertyTreeEntry *entry = (JSPropertyTreeEntry *)hdr; + JSBasicStats *bs = (JSBasicStats *)arg; + + MeterPropertyTree(bs, entry->child); + return JS_DHASH_NEXT; +} + +static void +DumpSubtree(JSContext *cx, JSScopeProperty *sprop, int level, FILE *fp) +{ + jsval v; + JSString *str; + JSScopeProperty *kids, *kid; + PropTreeKidsChunk *chunk; + uintN i; + + fprintf(fp, "%*sid ", level, ""); + v = ID_TO_VALUE(sprop->id); + if (JSID_IS_INT(sprop->id)) { + fprintf(fp, "%d", JSVAL_TO_INT(v)); + } else { + if (JSID_IS_ATOM(sprop->id)) { + str = JSVAL_TO_STRING(v); + } else { + JS_ASSERT(JSID_IS_OBJECT(sprop->id)); + str = js_ValueToString(cx, v); + fputs("object ", fp); + } + if (!str) + fputs("", fp); + else + js_FileEscapedString(fp, str, '"'); + } + + fprintf(fp, " g/s %p/%p slot %u attrs %x flags %x shortid %d\n", + (void *) sprop->getter, (void *) sprop->setter, sprop->slot, + sprop->attrs, sprop->flags, sprop->shortid); + kids = sprop->kids; + if (kids) { + ++level; + if (KIDS_IS_CHUNKY(kids)) { + chunk = KIDS_TO_CHUNK(kids); + do { + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + kid = chunk->kids[i]; + if (!kid) + break; + JS_ASSERT(kid->parent == sprop); + DumpSubtree(cx, kid, level, fp); + } + } while ((chunk = chunk->next) != NULL); + } else { + kid = kids; + DumpSubtree(cx, kid, level, fp); + } + } +} + +#endif /* JS_DUMP_PROPTREE_STATS */ + +void +js_SweepScopeProperties(JSContext *cx) +{ + JSRuntime *rt = cx->runtime; + JSArena **ap, *a; + JSScopeProperty *limit, *sprop, *parent, *kids, *kid; + uintN liveCount; + PropTreeKidsChunk *chunk, *nextChunk, *freeChunk; + uintN i; + +#ifdef JS_DUMP_PROPTREE_STATS + JSBasicStats bs; + uint32 livePropCapacity = 0, totalLiveCount = 0; + static FILE *logfp; + if (!logfp) + logfp = fopen("/tmp/proptree.stats", "w"); + + JS_BASIC_STATS_INIT(&bs); + MeterKidCount(&bs, rt->propertyTreeHash.entryCount); + JS_DHashTableEnumerate(&rt->propertyTreeHash, js_MeterPropertyTree, &bs); + + { + double props, nodes, mean, sigma; + + props = rt->liveScopePropsPreSweep; + nodes = rt->livePropTreeNodes; + JS_ASSERT(nodes == bs.sum); + mean = JS_MeanAndStdDevBS(&bs, &sigma); + + fprintf(logfp, + "props %g nodes %g beta %g meankids %g sigma %g max %u\n", + props, nodes, nodes / props, mean, sigma, bs.max); + } + + JS_DumpHistogram(&bs, logfp); +#endif + + ap = &rt->propertyArenaPool.first.next; + while ((a = *ap) != NULL) { + limit = (JSScopeProperty *) a->avail; + liveCount = 0; + for (sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) { + /* If the id is null, sprop is already on the freelist. */ + if (sprop->id == JSVAL_NULL) + continue; + + /* + * If the mark bit is set, sprop is alive, so clear the mark bit + * and continue the while loop. + * + * Regenerate sprop->shape if it hasn't already been refreshed + * during the mark phase, when live scopes' lastProp members are + * followed to update both scope->shape and lastProp->shape. + */ + if (sprop->flags & SPROP_MARK) { + sprop->flags &= ~SPROP_MARK; + if (sprop->flags & SPROP_FLAG_SHAPE_REGEN) { + sprop->flags &= ~SPROP_FLAG_SHAPE_REGEN; + } else { + sprop->shape = ++cx->runtime->shapeGen; + JS_ASSERT(sprop->shape != 0); + } + liveCount++; + continue; + } + + /* Ok, sprop is garbage to collect: unlink it from its parent. */ + freeChunk = RemovePropertyTreeChild(rt, sprop); + + /* + * Take care to reparent all sprop's kids to their grandparent. + * InsertPropertyTreeChild can potentially fail for two reasons: + * + * 1. If parent is null, insertion into the root property hash + * table may fail. We are forced to leave the kid out of the + * table (as can already happen with duplicates) but ensure + * that the kid's parent pointer is set to null. + * + * 2. If parent is non-null, allocation of a new KidsChunk can + * fail. To prevent this from happening, we allow sprops's own + * chunks to be reused by the grandparent, which removes the + * need for InsertPropertyTreeChild to malloc a new KidsChunk. + * + * If sprop does not have chunky kids, then we rely on the + * RemovePropertyTreeChild call above (which removed sprop from + * its parent) either leaving one free entry, or else returning + * the now-unused chunk to us so we can reuse it. + * + * We also require the grandparent to have either no kids or else + * chunky kids. A single non-chunky kid would force a new chunk to + * be malloced in some cases (if sprop had a single non-chunky + * kid, or a multiple of MAX_KIDS_PER_CHUNK kids). Note that + * RemovePropertyTreeChild never converts a single-entry chunky + * kid back to a non-chunky kid, so we are assured of correct + * behaviour. + */ + kids = sprop->kids; + if (kids) { + sprop->kids = NULL; + parent = sprop->parent; + + /* Assert that grandparent has no kids or chunky kids. */ + JS_ASSERT(!parent || !parent->kids || + KIDS_IS_CHUNKY(parent->kids)); + if (KIDS_IS_CHUNKY(kids)) { + chunk = KIDS_TO_CHUNK(kids); + do { + nextChunk = chunk->next; + chunk->next = NULL; + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + kid = chunk->kids[i]; + if (!kid) + break; + JS_ASSERT(kid->parent == sprop); + + /* + * Clear a space in the kids array for possible + * re-use by InsertPropertyTreeChild. + */ + chunk->kids[i] = NULL; + if (!InsertPropertyTreeChild(rt, parent, kid, + chunk)) { + /* + * This can happen only if we failed to add an + * entry to the root property hash table. + */ + JS_ASSERT(!parent); + kid->parent = NULL; + } + } + if (!chunk->kids[0]) { + /* The chunk wasn't reused, so we must free it. */ + DestroyPropTreeKidsChunk(rt, chunk); + } + } while ((chunk = nextChunk) != NULL); + } else { + kid = kids; + if (!InsertPropertyTreeChild(rt, parent, kid, freeChunk)) { + /* + * This can happen only if we failed to add an entry + * to the root property hash table. + */ + JS_ASSERT(!parent); + kid->parent = NULL; + } + } + } + + if (freeChunk && !freeChunk->kids[0]) { + /* The chunk wasn't reused, so we must free it. */ + DestroyPropTreeKidsChunk(rt, freeChunk); + } + + /* Clear id so we know (above) that sprop is on the freelist. */ + sprop->id = JSVAL_NULL; + FREENODE_INSERT(rt->propertyFreeList, sprop); + JS_RUNTIME_UNMETER(rt, livePropTreeNodes); + } + + /* If a contains no live properties, return it to the malloc heap. */ + if (liveCount == 0) { + for (sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) + FREENODE_REMOVE(sprop); + JS_ARENA_DESTROY(&rt->propertyArenaPool, a, ap); + } else { +#ifdef JS_DUMP_PROPTREE_STATS + livePropCapacity += limit - (JSScopeProperty *) a->base; + totalLiveCount += liveCount; +#endif + ap = &a->next; + } + } + +#ifdef JS_DUMP_PROPTREE_STATS + fprintf(logfp, "arenautil %g%%\n", + (totalLiveCount && livePropCapacity) + ? (totalLiveCount * 100.0) / livePropCapacity + : 0.0); + +#define RATE(f1, f2) (((double)js_scope_stats.f1 / js_scope_stats.f2) * 100.0) + + fprintf(logfp, "Scope search stats:\n" + " searches: %6u\n" + " hits: %6u %5.2f%% of searches\n" + " misses: %6u %5.2f%%\n" + " hashes: %6u %5.2f%%\n" + " steps: %6u %5.2f%% %5.2f%% of hashes\n" + " stepHits: %6u %5.2f%% %5.2f%%\n" + " stepMisses: %6u %5.2f%% %5.2f%%\n" + " adds: %6u\n" + " redundantAdds: %6u\n" + " addFailures: %6u\n" + " changeFailures: %6u\n" + " compresses: %6u\n" + " grows: %6u\n" + " removes: %6u\n" + " removeFrees: %6u\n" + " uselessRemoves: %6u\n" + " shrinks: %6u\n", + js_scope_stats.searches, + js_scope_stats.hits, RATE(hits, searches), + js_scope_stats.misses, RATE(misses, searches), + js_scope_stats.hashes, RATE(hashes, searches), + js_scope_stats.steps, RATE(steps, searches), RATE(steps, hashes), + js_scope_stats.stepHits, + RATE(stepHits, searches), RATE(stepHits, hashes), + js_scope_stats.stepMisses, + RATE(stepMisses, searches), RATE(stepMisses, hashes), + js_scope_stats.adds, + js_scope_stats.redundantAdds, + js_scope_stats.addFailures, + js_scope_stats.changeFailures, + js_scope_stats.compresses, + js_scope_stats.grows, + js_scope_stats.removes, + js_scope_stats.removeFrees, + js_scope_stats.uselessRemoves, + js_scope_stats.shrinks); + +#undef RATE + + fflush(logfp); +#endif + +#ifdef DUMP_PROPERTY_TREE + { + FILE *dumpfp = fopen("/tmp/proptree.dump", "w"); + if (dumpfp) { + JSPropertyTreeEntry *pte, *end; + + pte = (JSPropertyTreeEntry *) rt->propertyTreeHash.entryStore; + end = pte + JS_DHASH_TABLE_SIZE(&rt->propertyTreeHash); + while (pte < end) { + if (pte->child) + DumpSubtree(cx, pte->child, 0, dumpfp); + pte++; + } + fclose(dumpfp); + } + } +#endif +} + +JSBool +js_InitPropertyTree(JSRuntime *rt) +{ + if (!JS_DHashTableInit(&rt->propertyTreeHash, &PropertyTreeHashOps, NULL, + sizeof(JSPropertyTreeEntry), JS_DHASH_MIN_SIZE)) { + rt->propertyTreeHash.ops = NULL; + return JS_FALSE; + } + JS_INIT_ARENA_POOL(&rt->propertyArenaPool, "properties", + 256 * sizeof(JSScopeProperty), sizeof(void *), NULL); + return JS_TRUE; +} + +void +js_FinishPropertyTree(JSRuntime *rt) +{ + if (rt->propertyTreeHash.ops) { + JS_DHashTableFinish(&rt->propertyTreeHash); + rt->propertyTreeHash.ops = NULL; + } + JS_FinishArenaPool(&rt->propertyArenaPool); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscope.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscope.h new file mode 100644 index 0000000..b7d8455 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscope.h @@ -0,0 +1,419 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsscope_h___ +#define jsscope_h___ +/* + * JS symbol tables. + */ +#include "jstypes.h" +#include "jslock.h" +#include "jsobj.h" +#include "jsprvtd.h" +#include "jspubtd.h" + +JS_BEGIN_EXTERN_C + +/* + * Given P independent, non-unique properties each of size S words mapped by + * all scopes in a runtime, construct a property tree of N nodes each of size + * S+L words (L for tree linkage). A nominal L value is 2 for leftmost-child + * and right-sibling links. We hope that the N < P by enough that the space + * overhead of L, and the overhead of scope entries pointing at property tree + * nodes, is worth it. + * + * The tree construction goes as follows. If any empty scope in the runtime + * has a property X added to it, find or create a node under the tree root + * labeled X, and set scope->lastProp to point at that node. If any non-empty + * scope whose most recently added property is labeled Y has another property + * labeled Z added, find or create a node for Z under the node that was added + * for Y, and set scope->lastProp to point at that node. + * + * A property is labeled by its members' values: id, getter, setter, slot, + * attributes, tiny or short id, and a field telling for..in order. Note that + * labels are not unique in the tree, but they are unique among a node's kids + * (barring rare and benign multi-threaded race condition outcomes, see below) + * and along any ancestor line from the tree root to a given leaf node (except + * for the hard case of duplicate formal parameters to a function). + * + * Thus the root of the tree represents all empty scopes, and the first ply + * of the tree represents all scopes containing one property, etc. Each node + * in the tree can stand for any number of scopes having the same ordered set + * of properties, where that node was the last added to the scope. (We need + * not store the root of the tree as a node, and do not -- all we need are + * links to its kids.) + * + * Sidebar on for..in loop order: ECMA requires no particular order, but this + * implementation has promised and delivered property definition order, and + * compatibility is king. We could use an order number per property, which + * would require a sort in js_Enumerate, and an entry order generation number + * per scope. An order number beats a list, which should be doubly-linked for + * O(1) delete. An even better scheme is to use a parent link in the property + * tree, so that the ancestor line can be iterated from scope->lastProp when + * filling in a JSIdArray from back to front. This parent link also helps the + * GC to sweep properties iteratively. + * + * What if a property Y is deleted from a scope? If Y is the last property in + * the scope, we simply adjust the scope's lastProp member after we remove the + * scope's hash-table entry pointing at that property node. The parent link + * mentioned in the for..in sidebar above makes this adjustment O(1). But if + * Y comes between X and Z in the scope, then we might have to "fork" the tree + * at X, leaving X->Y->Z in case other scopes have those properties added in + * that order; and to finish the fork, we'd add a node labeled Z with the path + * X->Z, if it doesn't exist. This could lead to lots of extra nodes, and to + * O(n^2) growth when deleting lots of properties. + * + * Rather, for O(1) growth all around, we should share the path X->Y->Z among + * scopes having those three properties added in that order, and among scopes + * having only X->Z where Y was deleted. All such scopes have a lastProp that + * points to the Z child of Y. But a scope in which Y was deleted does not + * have a table entry for Y, and when iterating that scope by traversing the + * ancestor line from Z, we will have to test for a table entry for each node, + * skipping nodes that lack entries. + * + * What if we add Y again? X->Y->Z->Y is wrong and we'll enumerate Y twice. + * Therefore we must fork in such a case, if not earlier. Because delete is + * "bursty", we should not fork eagerly. Delaying a fork till we are at risk + * of adding Y after it was deleted already requires a flag in the JSScope, to + * wit, SCOPE_MIDDLE_DELETE. + * + * What about thread safety? If the property tree operations done by requests + * are find-node and insert-node, then the only hazard is duplicate insertion. + * This is harmless except for minor bloat. When all requests have ended or + * been suspended, the GC is free to sweep the tree after marking all nodes + * reachable from scopes, performing remove-node operations as needed. + * + * Is the property tree worth it compared to property storage in each table's + * entries? To decide, we must find the relation <> between the words used + * with a property tree and the words required without a tree. + * + * Model all scopes as one super-scope of capacity T entries (T a power of 2). + * Let alpha be the load factor of this double hash-table. With the property + * tree, each entry in the table is a word-sized pointer to a node that can be + * shared by many scopes. But all such pointers are overhead compared to the + * situation without the property tree, where the table stores property nodes + * directly, as entries each of size S words. With the property tree, we need + * L=2 extra words per node for siblings and kids pointers. Without the tree, + * (1-alpha)*S*T words are wasted on free or removed sentinel-entries required + * by double hashing. + * + * Therefore, + * + * (property tree) <> (no property tree) + * N*(S+L) + T <> S*T + * N*(S+L) + T <> P*S + (1-alpha)*S*T + * N*(S+L) + alpha*T + (1-alpha)*T <> P*S + (1-alpha)*S*T + * + * Note that P is alpha*T by definition, so + * + * N*(S+L) + P + (1-alpha)*T <> P*S + (1-alpha)*S*T + * N*(S+L) <> P*S - P + (1-alpha)*S*T - (1-alpha)*T + * N*(S+L) <> (P + (1-alpha)*T) * (S-1) + * N*(S+L) <> (P + (1-alpha)*P/alpha) * (S-1) + * N*(S+L) <> P * (1/alpha) * (S-1) + * + * Let N = P*beta for a compression ratio beta, beta <= 1: + * + * P*beta*(S+L) <> P * (1/alpha) * (S-1) + * beta*(S+L) <> (S-1)/alpha + * beta <> (S-1)/((S+L)*alpha) + * + * For S = 6 (32-bit architectures) and L = 2, the property tree wins iff + * + * beta < 5/(8*alpha) + * + * We ensure that alpha <= .75, so the property tree wins if beta < .83_. An + * average beta from recent Mozilla browser startups was around .6. + * + * Can we reduce L? Observe that the property tree degenerates into a list of + * lists if at most one property Y follows X in all scopes. In or near such a + * case, we waste a word on the right-sibling link outside of the root ply of + * the tree. Note also that the root ply tends to be large, so O(n^2) growth + * searching it is likely, indicating the need for hashing (but with increased + * thread safety costs). + * + * If only K out of N nodes in the property tree have more than one child, we + * could eliminate the sibling link and overlay a children list or hash-table + * pointer on the leftmost-child link (which would then be either null or an + * only-child link; the overlay could be tagged in the low bit of the pointer, + * or flagged elsewhere in the property tree node, although such a flag must + * not be considered when comparing node labels during tree search). + * + * For such a system, L = 1 + (K * averageChildrenTableSize) / N instead of 2. + * If K << N, L approaches 1 and the property tree wins if beta < .95. + * + * We observe that fan-out below the root ply of the property tree appears to + * have extremely low degree (see the MeterPropertyTree code that histograms + * child-counts in jsscope.c), so instead of a hash-table we use a linked list + * of child node pointer arrays ("kid chunks"). The details are isolated in + * jsscope.c; others must treat JSScopeProperty.kids as opaque. We leave it + * strongly typed for debug-ability of the common (null or one-kid) cases. + * + * One final twist (can you stand it?): the mean number of entries per scope + * in Mozilla is < 5, with a large standard deviation (~8). Instead of always + * allocating scope->table, we leave it null while initializing all the other + * scope members as if it were non-null and minimal-length. Until a property + * is added that crosses the threshold of 6 or more entries for hashing, or + * until a "middle delete" occurs, we use linear search from scope->lastProp + * to find a given id, and save on the space overhead of a hash table. + */ + +struct JSScope { + JSObjectMap map; /* base class state */ +#ifdef JS_THREADSAFE + JSTitle title; /* lock state */ +#endif + JSObject *object; /* object that owns this scope */ + uint32 shape; /* property cache shape identifier */ + uint8 flags; /* flags, see below */ + int8 hashShift; /* multiplicative hash shift */ + uint16 spare; /* reserved */ + uint32 entryCount; /* number of entries in table */ + uint32 removedCount; /* removed entry sentinels in table */ + JSScopeProperty **table; /* table of ptrs to shared tree nodes */ + JSScopeProperty *lastProp; /* pointer to last property added */ +}; + +#ifdef JS_THREADSAFE +JS_STATIC_ASSERT(offsetof(JSScope, title) == sizeof(JSObjectMap)); +#endif + +#define JS_IS_SCOPE_LOCKED(cx, scope) JS_IS_TITLE_LOCKED(cx, &(scope)->title) + +#define OBJ_SCOPE(obj) ((JSScope *)(obj)->map) +#define OBJ_SHAPE(obj) (OBJ_SCOPE(obj)->shape) + +#define SCOPE_MAKE_UNIQUE_SHAPE(cx,scope) \ + ((scope)->shape = js_GenerateShape((cx), JS_FALSE, NULL)) + +#define SCOPE_EXTEND_SHAPE(cx,scope,sprop) \ + JS_BEGIN_MACRO \ + if (!(scope)->lastProp || \ + (scope)->shape == (scope)->lastProp->shape) { \ + (scope)->shape = (sprop)->shape; \ + } else { \ + (scope)->shape = js_GenerateShape((cx), JS_FALSE, sprop); \ + } \ + JS_END_MACRO + +/* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */ +#define SCOPE_CAPACITY(scope) JS_BIT(JS_DHASH_BITS-(scope)->hashShift) + +/* Scope flags and some macros to hide them from other files than jsscope.c. */ +#define SCOPE_MIDDLE_DELETE 0x0001 +#define SCOPE_SEALED 0x0002 +#define SCOPE_BRANDED 0x0004 + +#define SCOPE_HAD_MIDDLE_DELETE(scope) ((scope)->flags & SCOPE_MIDDLE_DELETE) +#define SCOPE_SET_MIDDLE_DELETE(scope) ((scope)->flags |= SCOPE_MIDDLE_DELETE) +#define SCOPE_CLR_MIDDLE_DELETE(scope) ((scope)->flags &= ~SCOPE_MIDDLE_DELETE) + +#define SCOPE_IS_SEALED(scope) ((scope)->flags & SCOPE_SEALED) +#define SCOPE_SET_SEALED(scope) ((scope)->flags |= SCOPE_SEALED) +#if 0 +/* + * Don't define this, it can't be done safely because JS_LOCK_OBJ will avoid + * taking the lock if the object owns its scope and the scope is sealed. + */ +#undef SCOPE_CLR_SEALED(scope) ((scope)->flags &= ~SCOPE_SEALED) +#endif + +/* + * A branded scope's object contains plain old methods (function-valued + * properties without magic getters and setters), and its scope->shape + * evolves whenever a function value changes. + */ +#define SCOPE_IS_BRANDED(scope) ((scope)->flags & SCOPE_BRANDED) +#define SCOPE_SET_BRANDED(scope) ((scope)->flags |= SCOPE_BRANDED) +#define SCOPE_CLR_BRANDED(scope) ((scope)->flags &= ~SCOPE_BRANDED) + +/* + * A little information hiding for scope->lastProp, in case it ever becomes + * a tagged pointer again. + */ +#define SCOPE_LAST_PROP(scope) ((scope)->lastProp) +#define SCOPE_REMOVE_LAST_PROP(scope) ((scope)->lastProp = \ + (scope)->lastProp->parent) + +struct JSScopeProperty { + jsid id; /* int-tagged jsval/untagged JSAtom* */ + JSPropertyOp getter; /* getter and setter hooks or objects */ + JSPropertyOp setter; + uint32 slot; /* abstract index in object slots */ + uint8 attrs; /* attributes, see jsapi.h JSPROP_* */ + uint8 flags; /* flags, see below for defines */ + int16 shortid; /* tinyid, or local arg/var index */ + JSScopeProperty *parent; /* parent node, reverse for..in order */ + JSScopeProperty *kids; /* null, single child, or a tagged ptr + to many-kids data structure */ + uint32 shape; /* property cache shape identifier */ +}; + +/* JSScopeProperty pointer tag bit indicating a collision. */ +#define SPROP_COLLISION ((jsuword)1) +#define SPROP_REMOVED ((JSScopeProperty *) SPROP_COLLISION) + +/* Macros to get and set sprop pointer values and collision flags. */ +#define SPROP_IS_FREE(sprop) ((sprop) == NULL) +#define SPROP_IS_REMOVED(sprop) ((sprop) == SPROP_REMOVED) +#define SPROP_IS_LIVE(sprop) ((sprop) > SPROP_REMOVED) +#define SPROP_FLAG_COLLISION(spp,sprop) (*(spp) = (JSScopeProperty *) \ + ((jsuword)(sprop) | SPROP_COLLISION)) +#define SPROP_HAD_COLLISION(sprop) ((jsuword)(sprop) & SPROP_COLLISION) +#define SPROP_FETCH(spp) SPROP_CLEAR_COLLISION(*(spp)) + +#define SPROP_CLEAR_COLLISION(sprop) \ + ((JSScopeProperty *) ((jsuword)(sprop) & ~SPROP_COLLISION)) + +#define SPROP_STORE_PRESERVING_COLLISION(spp, sprop) \ + (*(spp) = (JSScopeProperty *) ((jsuword)(sprop) \ + | SPROP_HAD_COLLISION(*(spp)))) + +/* Bits stored in sprop->flags. */ +#define SPROP_MARK 0x01 +#define SPROP_IS_ALIAS 0x02 +#define SPROP_HAS_SHORTID 0x04 +#define SPROP_FLAG_SHAPE_REGEN 0x08 + +/* + * If SPROP_HAS_SHORTID is set in sprop->flags, we use sprop->shortid rather + * than id when calling sprop's getter or setter. + */ +#define SPROP_USERID(sprop) \ + (((sprop)->flags & SPROP_HAS_SHORTID) ? INT_TO_JSVAL((sprop)->shortid) \ + : ID_TO_VALUE((sprop)->id)) + +#define SPROP_INVALID_SLOT 0xffffffff + +#define SLOT_IN_SCOPE(slot,scope) ((slot) < (scope)->map.freeslot) +#define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope) + +#define SPROP_HAS_STUB_GETTER(sprop) (!(sprop)->getter) +#define SPROP_HAS_STUB_SETTER(sprop) (!(sprop)->setter) + +/* + * NB: SPROP_GET must not be called if SPROP_HAS_STUB_GETTER(sprop). + */ +#define SPROP_GET(cx,sprop,obj,obj2,vp) \ + (((sprop)->attrs & JSPROP_GETTER) \ + ? js_InternalGetOrSet(cx, obj, (sprop)->id, \ + OBJECT_TO_JSVAL((sprop)->getter), JSACC_READ, \ + 0, 0, vp) \ + : (sprop)->getter(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp)) + +/* + * NB: SPROP_SET must not be called if (SPROP_HAS_STUB_SETTER(sprop) && + * !(sprop->attrs & JSPROP_GETTER)). + */ +#define SPROP_SET(cx,sprop,obj,obj2,vp) \ + (((sprop)->attrs & JSPROP_SETTER) \ + ? js_InternalGetOrSet(cx, obj, (sprop)->id, \ + OBJECT_TO_JSVAL((sprop)->setter), JSACC_WRITE, \ + 1, vp, vp) \ + : ((sprop)->attrs & JSPROP_GETTER) \ + ? (JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, \ + JSMSG_GETTER_ONLY, NULL), JS_FALSE) \ + : (sprop)->setter(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp)) + +/* Macro for common expression to test for shared permanent attributes. */ +#define SPROP_IS_SHARED_PERMANENT(sprop) \ + ((~(sprop)->attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0) + +extern JSScope * +js_GetMutableScope(JSContext *cx, JSObject *obj); + +extern JSScope * +js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp, + JSObject *obj); + +extern void +js_DestroyScope(JSContext *cx, JSScope *scope); + +extern JS_FRIEND_API(JSScopeProperty **) +js_SearchScope(JSScope *scope, jsid id, JSBool adding); + +#define SCOPE_GET_PROPERTY(scope, id) \ + SPROP_FETCH(js_SearchScope(scope, id, JS_FALSE)) + +#define SCOPE_HAS_PROPERTY(scope, sprop) \ + (SCOPE_GET_PROPERTY(scope, (sprop)->id) == (sprop)) + +extern JSScopeProperty * +js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id, + JSPropertyOp getter, JSPropertyOp setter, uint32 slot, + uintN attrs, uintN flags, intN shortid); + +extern JSScopeProperty * +js_ChangeScopePropertyAttrs(JSContext *cx, JSScope *scope, + JSScopeProperty *sprop, uintN attrs, uintN mask, + JSPropertyOp getter, JSPropertyOp setter); + +extern JSBool +js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id); + +extern void +js_ClearScope(JSContext *cx, JSScope *scope); + +/* + * These macros used to inline short code sequences, but they grew over time. + * We retain them for internal backward compatibility, and in case one or both + * ever shrink to inline-able size. + */ +#define TRACE_ID(trc, id) js_TraceId(trc, id) +#define TRACE_SCOPE_PROPERTY(trc, sprop) js_TraceScopeProperty(trc, sprop) + +extern void +js_TraceId(JSTracer *trc, jsid id); + +extern void +js_TraceScopeProperty(JSTracer *trc, JSScopeProperty *sprop); + +extern void +js_SweepScopeProperties(JSContext *cx); + +extern JSBool +js_InitPropertyTree(JSRuntime *rt); + +extern void +js_FinishPropertyTree(JSRuntime *rt); + +JS_END_EXTERN_C + +#endif /* jsscope_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscript.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscript.cpp new file mode 100644 index 0000000..fba6a60 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscript.cpp @@ -0,0 +1,1891 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS script operations. + */ +#include "jsstddef.h" +#include +#include "jstypes.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jsprf.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscope.h" +#include "jsscript.h" +#if JS_HAS_XDR +#include "jsxdrapi.h" +#endif + +#if JS_HAS_SCRIPT_OBJECT + +static const char js_script_exec_str[] = "Script.prototype.exec"; +static const char js_script_compile_str[] = "Script.prototype.compile"; + +/* + * This routine requires that obj has been locked previously. + */ +static jsint +GetScriptExecDepth(JSContext *cx, JSObject *obj) +{ + jsval v; + + JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj)); + v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_START(&js_ScriptClass)); + return JSVAL_TO_INT(v); +} + +static void +AdjustScriptExecDepth(JSContext *cx, JSObject *obj, jsint delta) +{ + jsint execDepth; + + JS_LOCK_OBJ(cx, obj); + execDepth = GetScriptExecDepth(cx, obj); + LOCKED_OBJ_SET_SLOT(obj, JSSLOT_START(&js_ScriptClass), + INT_TO_JSVAL(execDepth + delta)); + JS_UNLOCK_OBJ(cx, obj); +} + +#if JS_HAS_TOSOURCE +static JSBool +script_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + uint32 indent; + JSScript *script; + size_t i, j, k, n; + char buf[16]; + jschar *s, *t; + JSString *str; + + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2)) + return JS_FALSE; + + indent = 0; + if (argc != 0) { + indent = js_ValueToECMAUint32(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + } + + script = (JSScript *) JS_GetPrivate(cx, obj); + + /* Let n count the source string length, j the "front porch" length. */ + j = JS_snprintf(buf, sizeof buf, "(new %s(", js_ScriptClass.name); + n = j + 2; + if (!script) { + /* Let k count the constructor argument string length. */ + k = 0; + s = NULL; /* quell GCC overwarning */ + } else { + str = JS_DecompileScript(cx, script, "Script.prototype.toSource", + (uintN)indent); + if (!str) + return JS_FALSE; + str = js_QuoteString(cx, str, '\''); + if (!str) + return JS_FALSE; + JSSTRING_CHARS_AND_LENGTH(str, s, k); + n += k; + } + + /* Allocate the source string and copy into it. */ + t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar)); + if (!t) + return JS_FALSE; + for (i = 0; i < j; i++) + t[i] = buf[i]; + for (j = 0; j < k; i++, j++) + t[i] = s[j]; + t[i++] = ')'; + t[i++] = ')'; + t[i] = 0; + + /* Create and return a JS string for t. */ + str = JS_NewUCString(cx, t, n); + if (!str) { + JS_free(cx, t); + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} +#endif /* JS_HAS_TOSOURCE */ + +static JSBool +script_toString(JSContext *cx, uintN argc, jsval *vp) +{ + uint32 indent; + JSObject *obj; + JSScript *script; + JSString *str; + + indent = 0; + if (argc != 0) { + indent = js_ValueToECMAUint32(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + } + + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2)) + return JS_FALSE; + script = (JSScript *) JS_GetPrivate(cx, obj); + if (!script) { + *vp = STRING_TO_JSVAL(cx->runtime->emptyString); + return JS_TRUE; + } + + str = JS_DecompileScript(cx, script, "Script.prototype.toString", + (uintN)indent); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + JSString *str; + JSObject *scopeobj; + jsval v; + JSScript *script, *oldscript; + JSStackFrame *caller; + const char *file; + uintN line; + JSPrincipals *principals; + uint32 tcflags; + jsint execDepth; + + /* Make sure obj is a Script object. */ + if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) + return JS_FALSE; + + /* If no args, leave private undefined and return early. */ + if (argc == 0) + goto out; + + /* Otherwise, the first arg is the script source to compile. */ + str = js_ValueToString(cx, argv[0]); + if (!str) + return JS_FALSE; + argv[0] = STRING_TO_JSVAL(str); + + scopeobj = NULL; + if (argc >= 2) { + if (!js_ValueToObject(cx, argv[1], &scopeobj)) + return JS_FALSE; + argv[1] = OBJECT_TO_JSVAL(scopeobj); + } + + /* Compile using the caller's scope chain, which js_Invoke passes to fp. */ + caller = JS_GetScriptedCaller(cx, cx->fp); + JS_ASSERT(!caller || cx->fp->scopeChain == caller->scopeChain); + + if (caller) { + if (!scopeobj) { + scopeobj = js_GetScopeChain(cx, caller); + if (!scopeobj) + return JS_FALSE; + } + + principals = JS_EvalFramePrincipals(cx, cx->fp, caller); + file = js_ComputeFilename(cx, caller, principals, &line); + } else { + file = NULL; + line = 0; + principals = NULL; + } + + /* Ensure we compile this script with the right (inner) principals. */ + scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_compile_str); + if (!scopeobj) + return JS_FALSE; + + /* + * Compile the new script using the caller's scope chain, a la eval(). + * Unlike jsobj.c:obj_eval, however, we do not pass TCF_COMPILE_N_GO in + * tcflags and use NULL for the callerFrame argument, because compilation + * is here separated from execution, and the run-time scope chain may not + * match the compile-time. TCF_COMPILE_N_GO is tested in jsemit.c and + * jsparse.c to optimize based on identity of run- and compile-time scope. + */ + tcflags = 0; + script = js_CompileScript(cx, scopeobj, NULL, principals, tcflags, + JSSTRING_CHARS(str), JSSTRING_LENGTH(str), + NULL, file, line); + if (!script) + return JS_FALSE; + + JS_LOCK_OBJ(cx, obj); + execDepth = GetScriptExecDepth(cx, obj); + + /* + * execDepth must be 0 to allow compilation here, otherwise the JSScript + * struct can be released while running. + */ + if (execDepth > 0) { + JS_UNLOCK_OBJ(cx, obj); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_COMPILE_EXECED_SCRIPT); + return JS_FALSE; + } + + /* Swap script for obj's old script, if any. */ + v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE); + oldscript = (JSScript*) (!JSVAL_IS_VOID(v) ? JSVAL_TO_PRIVATE(v) : NULL); + LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script)); + JS_UNLOCK_OBJ(cx, obj); + + if (oldscript) + js_DestroyScript(cx, oldscript); + + script->u.object = obj; + js_CallNewScriptHook(cx, script, NULL); + +out: + /* Return the object. */ + *rval = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static JSBool +script_compile(JSContext *cx, uintN argc, jsval *vp) +{ + return script_compile_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp); +} + +static JSBool +script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + JSObject *scopeobj, *parent; + JSStackFrame *fp, *caller; + JSPrincipals *principals; + JSScript *script; + JSBool ok; + + if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) + return JS_FALSE; + + scopeobj = NULL; + if (argc != 0) { + if (!js_ValueToObject(cx, argv[0], &scopeobj)) + return JS_FALSE; + argv[0] = OBJECT_TO_JSVAL(scopeobj); + } + + /* + * Emulate eval() by using caller's this, var object, sharp array, etc., + * all propagated by js_Execute via a non-null fourth (down) argument to + * js_Execute. If there is no scripted caller, js_Execute uses its second + * (chain) argument to set the exec frame's varobj, thisp, and scopeChain. + * + * Unlike eval, which the compiler detects, Script.prototype.exec may be + * called from a lightweight function, or even from native code (in which + * case fp->varobj and fp->scopeChain are null). If exec is called from + * a lightweight function, we will need to get a Call object representing + * its frame, to act as the var object and scope chain head. + */ + fp = cx->fp; + caller = JS_GetScriptedCaller(cx, fp); + if (caller && !caller->varobj) { + /* Called from a lightweight function. */ + JS_ASSERT(caller->fun && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags)); + + /* Scope chain links from Call object to callee's parent. */ + parent = OBJ_GET_PARENT(cx, caller->callee); + if (!js_GetCallObject(cx, caller, parent)) + return JS_FALSE; + } + + if (!scopeobj) { + /* No scope object passed in: try to use the caller's scope chain. */ + if (caller) { + /* + * Load caller->scopeChain after the conditional js_GetCallObject + * call above, which resets scopeChain as well as varobj. + */ + scopeobj = js_GetScopeChain(cx, caller); + if (!scopeobj) + return JS_FALSE; + } else { + /* + * Called from native code, so we don't know what scope object to + * use. We could use parent (see above), but Script.prototype.exec + * might be a shared/sealed "superglobal" method. A more general + * approach would use cx->globalObject, which will be the same as + * exec.__parent__ in the non-superglobal case. In the superglobal + * case it's the right object: the global, not the superglobal. + */ + scopeobj = cx->globalObject; + } + } + + scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_exec_str); + if (!scopeobj) + return JS_FALSE; + + /* Keep track of nesting depth for the script. */ + AdjustScriptExecDepth(cx, obj, 1); + + /* Must get to out label after this */ + script = (JSScript *) JS_GetPrivate(cx, obj); + if (!script) { + ok = JS_FALSE; + goto out; + } + + /* Belt-and-braces: check that this script object has access to scopeobj. */ + principals = script->principals; + ok = js_CheckPrincipalsAccess(cx, scopeobj, principals, + CLASS_ATOM(cx, Script)); + if (!ok) + goto out; + + ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval); + +out: + AdjustScriptExecDepth(cx, obj, -1); + return ok; +} + +static JSBool +script_exec(JSContext *cx, uintN argc, jsval *vp) +{ + return script_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp); +} + +#endif /* JS_HAS_SCRIPT_OBJECT */ + +#if JS_HAS_XDR + +JSBool +js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic) +{ + JSContext *cx; + JSScript *script, *oldscript; + JSBool ok; + jsbytecode *code; + uint32 length, lineno, nslots, magic; + uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, i; + uint32 prologLength, version; + JSTempValueRooter tvr; + JSPrincipals *principals; + uint32 encodeable; + JSBool filenameWasSaved; + jssrcnote *notes, *sn; + JSSecurityCallbacks *callbacks; + + cx = xdr->cx; + script = *scriptp; + nsrcnotes = ntrynotes = natoms = nobjects = nupvars = nregexps = 0; + filenameWasSaved = JS_FALSE; + notes = NULL; + + if (xdr->mode == JSXDR_ENCODE) + magic = JSXDR_MAGIC_SCRIPT_CURRENT; + if (!JS_XDRUint32(xdr, &magic)) + return JS_FALSE; + if (magic != JSXDR_MAGIC_SCRIPT_CURRENT) { + /* We do not provide binary compatibility with older scripts. */ + if (!hasMagic) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_SCRIPT_MAGIC); + return JS_FALSE; + } + *hasMagic = JS_FALSE; + return JS_TRUE; + } + if (hasMagic) + *hasMagic = JS_TRUE; + + if (xdr->mode == JSXDR_ENCODE) { + length = script->length; + prologLength = PTRDIFF(script->main, script->code, jsbytecode); + JS_ASSERT((int16)script->version != JSVERSION_UNKNOWN); + version = (uint32)script->version | (script->nfixed << 16); + lineno = (uint32)script->lineno; + nslots = (uint32)script->nslots; + nslots = (uint32)((script->staticDepth << 16) | script->nslots); + natoms = (uint32)script->atomMap.length; + + /* Count the srcnotes, keeping notes pointing at the first one. */ + notes = SCRIPT_NOTES(script); + for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) + continue; + nsrcnotes = PTRDIFF(sn, notes, jssrcnote); + nsrcnotes++; /* room for the terminator */ + + if (script->objectsOffset != 0) + nobjects = JS_SCRIPT_OBJECTS(script)->length; + if (script->upvarsOffset != 0) + nupvars = JS_SCRIPT_UPVARS(script)->length; + if (script->regexpsOffset != 0) + nregexps = JS_SCRIPT_REGEXPS(script)->length; + if (script->trynotesOffset != 0) + ntrynotes = JS_SCRIPT_TRYNOTES(script)->length; + } + + if (!JS_XDRUint32(xdr, &length)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &prologLength)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &version)) + return JS_FALSE; + + /* + * To fuse allocations, we need srcnote, atom, objects, upvar, regexp, + * and trynote counts early. + */ + if (!JS_XDRUint32(xdr, &natoms)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &nsrcnotes)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &ntrynotes)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &nobjects)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &nupvars)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &nregexps)) + return JS_FALSE; + + if (xdr->mode == JSXDR_DECODE) { + script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars, + nregexps, ntrynotes); + if (!script) + return JS_FALSE; + + script->main += prologLength; + script->version = (JSVersion) (version & 0xffff); + script->nfixed = (uint16) (version >> 16); + + /* If we know nsrcnotes, we allocated space for notes in script. */ + notes = SCRIPT_NOTES(script); + *scriptp = script; + JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); + } + + /* + * Control hereafter must goto error on failure, in order for the + * DECODE case to destroy script. + */ + oldscript = xdr->script; + code = script->code; + if (xdr->mode == JSXDR_ENCODE) { + code = js_UntrapScriptCode(cx, script); + if (!code) + goto error; + } + + xdr->script = script; + ok = JS_XDRBytes(xdr, (char *) code, length * sizeof(jsbytecode)); + + if (code != script->code) + JS_free(cx, code); + + if (!ok) + goto error; + + if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) || + !JS_XDRCStringOrNull(xdr, (char **)&script->filename) || + !JS_XDRUint32(xdr, &lineno) || + !JS_XDRUint32(xdr, &nslots)) { + goto error; + } + + callbacks = JS_GetSecurityCallbacks(cx); + if (xdr->mode == JSXDR_ENCODE) { + principals = script->principals; + encodeable = callbacks && callbacks->principalsTranscoder; + if (!JS_XDRUint32(xdr, &encodeable)) + goto error; + if (encodeable && + !callbacks->principalsTranscoder(xdr, &principals)) { + goto error; + } + } else { + if (!JS_XDRUint32(xdr, &encodeable)) + goto error; + if (encodeable) { + if (!(callbacks && callbacks->principalsTranscoder)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_DECODE_PRINCIPALS); + goto error; + } + if (!callbacks->principalsTranscoder(xdr, &principals)) + goto error; + script->principals = principals; + } + } + + if (xdr->mode == JSXDR_DECODE) { + const char *filename = script->filename; + if (filename) { + filename = js_SaveScriptFilename(cx, filename); + if (!filename) + goto error; + JS_free(cx, (void *) script->filename); + script->filename = filename; + filenameWasSaved = JS_TRUE; + } + script->lineno = (uintN)lineno; + script->nslots = (uint16)nslots; + script->staticDepth = nslots >> 16; + } + + for (i = 0; i != natoms; ++i) { + if (!js_XDRAtom(xdr, &script->atomMap.vector[i])) + goto error; + } + + /* + * Here looping from 0-to-length to xdr objects is essential. It ensures + * that block objects from the script->objects array will be written and + * restored in the outer-to-inner order. block_xdrObject relies on this to + * restore the parent chain. + */ + for (i = 0; i != nobjects; ++i) { + if (!js_XDRObject(xdr, &JS_SCRIPT_OBJECTS(script)->vector[i])) + goto error; + } + for (i = 0; i != nupvars; ++i) { + if (!JS_XDRUint32(xdr, &JS_SCRIPT_UPVARS(script)->vector[i])) + goto error; + } + for (i = 0; i != nregexps; ++i) { + if (!js_XDRObject(xdr, &JS_SCRIPT_REGEXPS(script)->vector[i])) + goto error; + } + + if (ntrynotes != 0) { + /* + * We combine tn->kind and tn->stackDepth when serializing as XDR is not + * efficient when serializing small integer types. + */ + JSTryNote *tn, *tnfirst; + uint32 kindAndDepth; + JS_STATIC_ASSERT(sizeof(tn->kind) == sizeof(uint8)); + JS_STATIC_ASSERT(sizeof(tn->stackDepth) == sizeof(uint16)); + + tnfirst = JS_SCRIPT_TRYNOTES(script)->vector; + JS_ASSERT(JS_SCRIPT_TRYNOTES(script)->length == ntrynotes); + tn = tnfirst + ntrynotes; + do { + --tn; + if (xdr->mode == JSXDR_ENCODE) { + kindAndDepth = ((uint32)tn->kind << 16) + | (uint32)tn->stackDepth; + } + if (!JS_XDRUint32(xdr, &kindAndDepth) || + !JS_XDRUint32(xdr, &tn->start) || + !JS_XDRUint32(xdr, &tn->length)) { + goto error; + } + if (xdr->mode == JSXDR_DECODE) { + tn->kind = (uint8)(kindAndDepth >> 16); + tn->stackDepth = (uint16)kindAndDepth; + } + } while (tn != tnfirst); + } + + xdr->script = oldscript; + if (xdr->mode == JSXDR_DECODE) + JS_POP_TEMP_ROOT(cx, &tvr); + return JS_TRUE; + + error: + if (xdr->mode == JSXDR_DECODE) { + JS_POP_TEMP_ROOT(cx, &tvr); + if (script->filename && !filenameWasSaved) { + JS_free(cx, (void *) script->filename); + script->filename = NULL; + } + js_DestroyScript(cx, script); + *scriptp = NULL; + } + xdr->script = oldscript; + return JS_FALSE; +} + +#if JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW +/* + * These cannot be exposed to web content, and chrome does not need them, so + * we take them out of the Mozilla client altogether. Fortunately, there is + * no way to serialize a native function (see fun_xdrObject in jsfun.c). + */ + +static JSBool +script_freeze(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + JSXDRState *xdr; + JSScript *script; + JSBool ok, hasMagic; + uint32 len; + void *buf; + JSString *str; + + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2)) + return JS_FALSE; + script = (JSScript *) JS_GetPrivate(cx, obj); + if (!script) + return JS_TRUE; + + /* create new XDR */ + xdr = JS_XDRNewMem(cx, JSXDR_ENCODE); + if (!xdr) + return JS_FALSE; + + /* write */ + ok = js_XDRScript(xdr, &script, &hasMagic); + if (!ok) + goto out; + if (!hasMagic) { + *vp = JSVAL_VOID; + goto out; + } + + buf = JS_XDRMemGetData(xdr, &len); + if (!buf) { + ok = JS_FALSE; + goto out; + } + + JS_ASSERT((jsword)buf % sizeof(jschar) == 0); + len /= sizeof(jschar); +#if IS_BIG_ENDIAN + { + jschar *chars; + uint32 i; + + /* Swap bytes in Unichars to keep frozen strings machine-independent. */ + chars = (jschar *)buf; + for (i = 0; i < len; i++) + chars[i] = JSXDR_SWAB16(chars[i]); + } +#endif + str = JS_NewUCStringCopyN(cx, (jschar *)buf, len); + if (!str) { + ok = JS_FALSE; + goto out; + } + + *vp = STRING_TO_JSVAL(str); + +out: + JS_XDRDestroy(xdr); + return ok; +} + +static JSBool +script_thaw(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + JSXDRState *xdr; + JSString *str; + void *buf; + uint32 len; + jsval v; + JSScript *script, *oldscript; + JSBool ok, hasMagic; + jsint execDepth; + + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2)) + return JS_FALSE; + + if (argc == 0) + return JS_TRUE; + str = js_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + vp[2] = STRING_TO_JSVAL(str); + + /* create new XDR */ + xdr = JS_XDRNewMem(cx, JSXDR_DECODE); + if (!xdr) + return JS_FALSE; + + JSSTRING_CHARS_AND_LENGTH(str, buf, len); +#if IS_BIG_ENDIAN + { + jschar *from, *to; + uint32 i; + + /* Swap bytes in Unichars to keep frozen strings machine-independent. */ + from = (jschar *)buf; + to = (jschar *) JS_malloc(cx, len * sizeof(jschar)); + if (!to) { + JS_XDRDestroy(xdr); + return JS_FALSE; + } + for (i = 0; i < len; i++) + to[i] = JSXDR_SWAB16(from[i]); + buf = (char *)to; + } +#endif + len *= sizeof(jschar); + JS_XDRMemSetData(xdr, buf, len); + + /* XXXbe should magic mismatch be error, or false return value? */ + ok = js_XDRScript(xdr, &script, &hasMagic); + if (!ok) + goto out; + if (!hasMagic) { + *vp = JSVAL_FALSE; + goto out; + } + + JS_LOCK_OBJ(cx, obj); + execDepth = GetScriptExecDepth(cx, obj); + + /* + * execDepth must be 0 to allow compilation here, otherwise the JSScript + * struct can be released while running. + */ + if (execDepth > 0) { + JS_UNLOCK_OBJ(cx, obj); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_COMPILE_EXECED_SCRIPT); + goto out; + } + + /* Swap script for obj's old script, if any. */ + v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE); + oldscript = !JSVAL_IS_VOID(v) ? JSVAL_TO_PRIVATE(v) : NULL; + LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script)); + JS_UNLOCK_OBJ(cx, obj); + + if (oldscript) + js_DestroyScript(cx, oldscript); + + script->u.object = obj; + js_CallNewScriptHook(cx, script, NULL); + +out: + /* + * We reset the buffer to be NULL so that it doesn't free the chars + * memory owned by str (vp[2]). + */ + JS_XDRMemSetData(xdr, NULL, 0); + JS_XDRDestroy(xdr); +#if IS_BIG_ENDIAN + JS_free(cx, buf); +#endif + *vp = JSVAL_TRUE; + return ok; +} + +static const char js_thaw_str[] = "thaw"; + +#endif /* JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW */ +#endif /* JS_HAS_XDR */ + +#if JS_HAS_SCRIPT_OBJECT + +static JSFunctionSpec script_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, script_toSource, 0,0), +#endif + JS_FN(js_toString_str, script_toString, 0,0), + JS_FN("compile", script_compile, 2,0), + JS_FN("exec", script_exec, 1,0), +#if JS_HAS_XDR_FREEZE_THAW + JS_FN("freeze", script_freeze, 0,0), + JS_FN(js_thaw_str, script_thaw, 1,0), +#endif /* JS_HAS_XDR_FREEZE_THAW */ + JS_FS_END +}; + +#endif /* JS_HAS_SCRIPT_OBJECT */ + +static void +script_finalize(JSContext *cx, JSObject *obj) +{ + JSScript *script; + + script = (JSScript *) JS_GetPrivate(cx, obj); + if (script) + js_DestroyScript(cx, script); +} + +static JSBool +script_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ +#if JS_HAS_SCRIPT_OBJECT + return script_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval); +#else + return JS_FALSE; +#endif +} + +static void +script_trace(JSTracer *trc, JSObject *obj) +{ + JSScript *script; + + script = (JSScript *) JS_GetPrivate(trc->context, obj); + if (script) + js_TraceScript(trc, script); +} + +#if !JS_HAS_SCRIPT_OBJECT +#define JSProto_Script JSProto_Object +#endif + +JS_FRIEND_DATA(JSClass) js_ScriptClass = { + js_Script_str, + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Script), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, script_finalize, + NULL, NULL, script_call, NULL,/*XXXbe xdr*/ + NULL, NULL, JS_CLASS_TRACE(script_trace), NULL +}; + +#if JS_HAS_SCRIPT_OBJECT + +static JSBool +Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + /* If not constructing, replace obj with a new Script object. */ + if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { + obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + + /* + * script_compile_sub does not use rval to root its temporaries so we + * can use it to root obj. + */ + *rval = OBJECT_TO_JSVAL(obj); + } + + if (!JS_SetReservedSlot(cx, obj, 0, INT_TO_JSVAL(0))) + return JS_FALSE; + + return script_compile_sub(cx, obj, argc, argv, rval); +} + +#if JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW + +static JSBool +script_static_thaw(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); + if (!obj) + return JS_FALSE; + vp[1] = OBJECT_TO_JSVAL(obj); + if (!script_thaw(cx, argc, vp)) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static JSFunctionSpec script_static_methods[] = { + JS_FN(js_thaw_str, script_static_thaw, 1,0), + JS_FS_END +}; + +#else /* !JS_HAS_SCRIPT_OBJECT || !JS_HAS_XDR_FREEZE_THAW */ + +#define script_static_methods NULL + +#endif /* !JS_HAS_SCRIPT_OBJECT || !JS_HAS_XDR_FREEZE_THAW */ + +JSObject * +js_InitScriptClass(JSContext *cx, JSObject *obj) +{ + return JS_InitClass(cx, obj, NULL, &js_ScriptClass, Script, 1, + NULL, script_methods, NULL, script_static_methods); +} + +#endif /* JS_HAS_SCRIPT_OBJECT */ + +/* + * Shared script filename management. + */ +static int +js_compare_strings(const void *k1, const void *k2) +{ + return strcmp((const char *) k1, (const char *) k2) == 0; +} + +/* NB: This struct overlays JSHashEntry -- see jshash.h, do not reorganize. */ +typedef struct ScriptFilenameEntry { + JSHashEntry *next; /* hash chain linkage */ + JSHashNumber keyHash; /* key hash function result */ + const void *key; /* ptr to filename, below */ + uint32 flags; /* user-defined filename prefix flags */ + JSPackedBool mark; /* GC mark flag */ + char filename[3]; /* two or more bytes, NUL-terminated */ +} ScriptFilenameEntry; + +static void * +js_alloc_table_space(void *priv, size_t size) +{ + return malloc(size); +} + +static void +js_free_table_space(void *priv, void *item) +{ + free(item); +} + +static JSHashEntry * +js_alloc_sftbl_entry(void *priv, const void *key) +{ + size_t nbytes = offsetof(ScriptFilenameEntry, filename) + + strlen((const char *) key) + 1; + + return (JSHashEntry *) malloc(JS_MAX(nbytes, sizeof(JSHashEntry))); +} + +static void +js_free_sftbl_entry(void *priv, JSHashEntry *he, uintN flag) +{ + if (flag != HT_FREE_ENTRY) + return; + free(he); +} + +static JSHashAllocOps sftbl_alloc_ops = { + js_alloc_table_space, js_free_table_space, + js_alloc_sftbl_entry, js_free_sftbl_entry +}; + +JSBool +js_InitRuntimeScriptState(JSRuntime *rt) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(!rt->scriptFilenameTableLock); + rt->scriptFilenameTableLock = JS_NEW_LOCK(); + if (!rt->scriptFilenameTableLock) + return JS_FALSE; +#endif + JS_ASSERT(!rt->scriptFilenameTable); + rt->scriptFilenameTable = + JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL, + &sftbl_alloc_ops, NULL); + if (!rt->scriptFilenameTable) { + js_FinishRuntimeScriptState(rt); /* free lock if threadsafe */ + return JS_FALSE; + } + JS_INIT_CLIST(&rt->scriptFilenamePrefixes); + return JS_TRUE; +} + +typedef struct ScriptFilenamePrefix { + JSCList links; /* circular list linkage for easy deletion */ + const char *name; /* pointer to pinned ScriptFilenameEntry string */ + size_t length; /* prefix string length, precomputed */ + uint32 flags; /* user-defined flags to inherit from this prefix */ +} ScriptFilenamePrefix; + +void +js_FinishRuntimeScriptState(JSRuntime *rt) +{ + if (rt->scriptFilenameTable) { + JS_HashTableDestroy(rt->scriptFilenameTable); + rt->scriptFilenameTable = NULL; + } +#ifdef JS_THREADSAFE + if (rt->scriptFilenameTableLock) { + JS_DESTROY_LOCK(rt->scriptFilenameTableLock); + rt->scriptFilenameTableLock = NULL; + } +#endif +} + +void +js_FreeRuntimeScriptState(JSRuntime *rt) +{ + ScriptFilenamePrefix *sfp; + + if (!rt->scriptFilenameTable) + return; + + while (!JS_CLIST_IS_EMPTY(&rt->scriptFilenamePrefixes)) { + sfp = (ScriptFilenamePrefix *) rt->scriptFilenamePrefixes.next; + JS_REMOVE_LINK(&sfp->links); + free(sfp); + } + js_FinishRuntimeScriptState(rt); +} + +#ifdef DEBUG_brendan +#define DEBUG_SFTBL +#endif +#ifdef DEBUG_SFTBL +size_t sftbl_savings = 0; +#endif + +static ScriptFilenameEntry * +SaveScriptFilename(JSRuntime *rt, const char *filename, uint32 flags) +{ + JSHashTable *table; + JSHashNumber hash; + JSHashEntry **hep; + ScriptFilenameEntry *sfe; + size_t length; + JSCList *head, *link; + ScriptFilenamePrefix *sfp; + + table = rt->scriptFilenameTable; + hash = JS_HashString(filename); + hep = JS_HashTableRawLookup(table, hash, filename); + sfe = (ScriptFilenameEntry *) *hep; +#ifdef DEBUG_SFTBL + if (sfe) + sftbl_savings += strlen(sfe->filename); +#endif + + if (!sfe) { + sfe = (ScriptFilenameEntry *) + JS_HashTableRawAdd(table, hep, hash, filename, NULL); + if (!sfe) + return NULL; + sfe->key = strcpy(sfe->filename, filename); + sfe->flags = 0; + sfe->mark = JS_FALSE; + } + + /* If saving a prefix, add it to the set in rt->scriptFilenamePrefixes. */ + if (flags != 0) { + /* Search in case filename was saved already; we must be idempotent. */ + sfp = NULL; + length = strlen(filename); + for (head = link = &rt->scriptFilenamePrefixes; + link->next != head; + link = link->next) { + /* Lag link behind sfp to insert in non-increasing length order. */ + sfp = (ScriptFilenamePrefix *) link->next; + if (!strcmp(sfp->name, filename)) + break; + if (sfp->length <= length) { + sfp = NULL; + break; + } + sfp = NULL; + } + + if (!sfp) { + /* No such prefix: add one now. */ + sfp = (ScriptFilenamePrefix *) malloc(sizeof(ScriptFilenamePrefix)); + if (!sfp) + return NULL; + JS_INSERT_AFTER(&sfp->links, link); + sfp->name = sfe->filename; + sfp->length = length; + sfp->flags = 0; + } + + /* + * Accumulate flags in both sfe and sfp: sfe for later access from the + * JS_GetScriptedCallerFilenameFlags debug-API, and sfp so that longer + * filename entries can inherit by prefix. + */ + sfe->flags |= flags; + sfp->flags |= flags; + } + + return sfe; +} + +const char * +js_SaveScriptFilename(JSContext *cx, const char *filename) +{ + JSRuntime *rt; + ScriptFilenameEntry *sfe; + JSCList *head, *link; + ScriptFilenamePrefix *sfp; + + rt = cx->runtime; + JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock); + sfe = SaveScriptFilename(rt, filename, 0); + if (!sfe) { + JS_RELEASE_LOCK(rt->scriptFilenameTableLock); + JS_ReportOutOfMemory(cx); + return NULL; + } + + /* + * Try to inherit flags by prefix. We assume there won't be more than a + * few (dozen! ;-) prefixes, so linear search is tolerable. + * XXXbe every time I've assumed that in the JS engine, I've been wrong! + */ + for (head = &rt->scriptFilenamePrefixes, link = head->next; + link != head; + link = link->next) { + sfp = (ScriptFilenamePrefix *) link; + if (!strncmp(sfp->name, filename, sfp->length)) { + sfe->flags |= sfp->flags; + break; + } + } + JS_RELEASE_LOCK(rt->scriptFilenameTableLock); + return sfe->filename; +} + +const char * +js_SaveScriptFilenameRT(JSRuntime *rt, const char *filename, uint32 flags) +{ + ScriptFilenameEntry *sfe; + + /* This may be called very early, via the jsdbgapi.h entry point. */ + if (!rt->scriptFilenameTable && !js_InitRuntimeScriptState(rt)) + return NULL; + + JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock); + sfe = SaveScriptFilename(rt, filename, flags); + JS_RELEASE_LOCK(rt->scriptFilenameTableLock); + if (!sfe) + return NULL; + + return sfe->filename; +} + +/* + * Back up from a saved filename by its offset within its hash table entry. + */ +#define FILENAME_TO_SFE(fn) \ + ((ScriptFilenameEntry *) ((fn) - offsetof(ScriptFilenameEntry, filename))) + +/* + * The sfe->key member, redundant given sfe->filename but required by the old + * jshash.c code, here gives us a useful sanity check. This assertion will + * very likely botch if someone tries to mark a string that wasn't allocated + * as an sfe->filename. + */ +#define ASSERT_VALID_SFE(sfe) JS_ASSERT((sfe)->key == (sfe)->filename) + +uint32 +js_GetScriptFilenameFlags(const char *filename) +{ + ScriptFilenameEntry *sfe; + + sfe = FILENAME_TO_SFE(filename); + ASSERT_VALID_SFE(sfe); + return sfe->flags; +} + +void +js_MarkScriptFilename(const char *filename) +{ + ScriptFilenameEntry *sfe; + + sfe = FILENAME_TO_SFE(filename); + ASSERT_VALID_SFE(sfe); + sfe->mark = JS_TRUE; +} + +static intN +js_script_filename_marker(JSHashEntry *he, intN i, void *arg) +{ + ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he; + + sfe->mark = JS_TRUE; + return HT_ENUMERATE_NEXT; +} + +void +js_MarkScriptFilenames(JSRuntime *rt, JSBool keepAtoms) +{ + JSCList *head, *link; + ScriptFilenamePrefix *sfp; + + if (!rt->scriptFilenameTable) + return; + + if (keepAtoms) { + JS_HashTableEnumerateEntries(rt->scriptFilenameTable, + js_script_filename_marker, + rt); + } + for (head = &rt->scriptFilenamePrefixes, link = head->next; + link != head; + link = link->next) { + sfp = (ScriptFilenamePrefix *) link; + js_MarkScriptFilename(sfp->name); + } +} + +static intN +js_script_filename_sweeper(JSHashEntry *he, intN i, void *arg) +{ + ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he; + + if (!sfe->mark) + return HT_ENUMERATE_REMOVE; + sfe->mark = JS_FALSE; + return HT_ENUMERATE_NEXT; +} + +void +js_SweepScriptFilenames(JSRuntime *rt) +{ + if (!rt->scriptFilenameTable) + return; + + JS_HashTableEnumerateEntries(rt->scriptFilenameTable, + js_script_filename_sweeper, + rt); +#ifdef DEBUG_notme +#ifdef DEBUG_SFTBL + printf("script filename table savings so far: %u\n", sftbl_savings); +#endif +#endif +} + +/* + * JSScript data structures memory alignment: + * + * JSScript + * JSObjectArray script objects' descriptor if JSScript.objectsOffset != 0, + * use JS_SCRIPT_OBJECTS(script) macro to access it. + * JSObjectArray script regexps' descriptor if JSScript.regexpsOffset != 0, + * use JS_SCRIPT_REGEXPS(script) macro to access it. + * JSTryNoteArray script try notes' descriptor if JSScript.tryNotesOffset + * != 0, use JS_SCRIPT_TRYNOTES(script) macro to access it. + * JSAtom *a[] array of JSScript.atomMap.length atoms pointed by + * JSScript.atomMap.vector if any. + * JSObject *o[] array of JS_SCRIPT_OBJECTS(script)->length objects if any + * pointed by JS_SCRIPT_OBJECTS(script)->vector. + * JSObject *r[] array of JS_SCRIPT_REGEXPS(script)->length regexps if any + * pointed by JS_SCRIPT_REGEXPS(script)->vector. + * JSTryNote t[] array of JS_SCRIPT_TRYNOTES(script)->length try notes if any + * pointed by JS_SCRIPT_TRYNOTES(script)->vector. + * jsbytecode b[] script bytecode pointed by JSScript.code. + * jssrcnote s[] script source notes, use SCRIPT_NOTES(script) to access it + * + * The alignment avoids gaps between entries as alignment requirement for each + * subsequent structure or array is the same or divides the alignment + * requirement for the previous one. + * + * The followings asserts checks that assuming that the alignment requirement + * for JSObjectArray and JSTryNoteArray are sizeof(void *) and for JSTryNote + * it is sizeof(uint32) as the structure consists of 3 uint32 fields. + */ +JS_STATIC_ASSERT(sizeof(JSScript) % sizeof(void *) == 0); +JS_STATIC_ASSERT(sizeof(JSObjectArray) % sizeof(void *) == 0); +JS_STATIC_ASSERT(sizeof(JSTryNoteArray) == sizeof(JSObjectArray)); +JS_STATIC_ASSERT(sizeof(JSAtom *) == sizeof(JSObject *)); +JS_STATIC_ASSERT(sizeof(JSObject *) % sizeof(uint32) == 0); +JS_STATIC_ASSERT(sizeof(JSTryNote) == 3 * sizeof(uint32)); +JS_STATIC_ASSERT(sizeof(uint32) % sizeof(jsbytecode) == 0); +JS_STATIC_ASSERT(sizeof(jsbytecode) % sizeof(jssrcnote) == 0); + +/* + * Check that uint8 offset for object, upvar, regexp, and try note arrays is + * sufficient. + */ +JS_STATIC_ASSERT(sizeof(JSScript) + 2 * sizeof(JSObjectArray) + + sizeof(JSUpvarArray) < JS_BIT(8)); + +JSScript * +js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms, + uint32 nobjects, uint32 nupvars, uint32 nregexps, + uint32 ntrynotes) +{ + size_t size, vectorSize; + JSScript *script; + uint8 *cursor; + + size = sizeof(JSScript) + + sizeof(JSAtom *) * natoms + + length * sizeof(jsbytecode) + + nsrcnotes * sizeof(jssrcnote); + if (nobjects != 0) + size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *); + if (nupvars != 0) + size += sizeof(JSUpvarArray) + nupvars * sizeof(uint32); + if (nregexps != 0) + size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *); + if (ntrynotes != 0) + size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote); + + script = (JSScript *) JS_malloc(cx, size); + if (!script) + return NULL; + memset(script, 0, sizeof(JSScript)); + script->length = length; + script->version = cx->version; + + cursor = (uint8 *)script + sizeof(JSScript); + if (nobjects != 0) { + script->objectsOffset = (uint8)(cursor - (uint8 *)script); + cursor += sizeof(JSObjectArray); + } + if (nupvars != 0) { + script->upvarsOffset = (uint8)(cursor - (uint8 *)script); + cursor += sizeof(JSUpvarArray); + } + if (nregexps != 0) { + script->regexpsOffset = (uint8)(cursor - (uint8 *)script); + cursor += sizeof(JSObjectArray); + } + if (ntrynotes != 0) { + script->trynotesOffset = (uint8)(cursor - (uint8 *)script); + cursor += sizeof(JSTryNoteArray); + } + + if (natoms != 0) { + script->atomMap.length = natoms; + script->atomMap.vector = (JSAtom **)cursor; + vectorSize = natoms * sizeof(script->atomMap.vector[0]); + + /* + * Clear object map's vector so the GC tracing can run when not yet + * all atoms are copied to the array. + */ + memset(cursor, 0, vectorSize); + cursor += vectorSize; + } + + if (nobjects != 0) { + JS_SCRIPT_OBJECTS(script)->length = nobjects; + JS_SCRIPT_OBJECTS(script)->vector = (JSObject **)cursor; + vectorSize = nobjects * sizeof(JS_SCRIPT_OBJECTS(script)->vector[0]); + memset(cursor, 0, vectorSize); + cursor += vectorSize; + } + + if (nupvars != 0) { + JS_SCRIPT_UPVARS(script)->length = nupvars; + JS_SCRIPT_UPVARS(script)->vector = (uint32 *)cursor; + vectorSize = nupvars * sizeof(JS_SCRIPT_UPVARS(script)->vector[0]); + memset(cursor, 0, vectorSize); + cursor += vectorSize; + } + + if (nregexps != 0) { + JS_SCRIPT_REGEXPS(script)->length = nregexps; + JS_SCRIPT_REGEXPS(script)->vector = (JSObject **)cursor; + vectorSize = nregexps * sizeof(JS_SCRIPT_REGEXPS(script)->vector[0]); + memset(cursor, 0, vectorSize); + cursor += vectorSize; + } + + if (ntrynotes != 0) { + JS_SCRIPT_TRYNOTES(script)->length = ntrynotes; + JS_SCRIPT_TRYNOTES(script)->vector = (JSTryNote *)cursor; + vectorSize = ntrynotes * sizeof(JS_SCRIPT_TRYNOTES(script)->vector[0]); +#ifdef DEBUG + memset(cursor, 0, vectorSize); +#endif + cursor += vectorSize; + } + + script->code = script->main = (jsbytecode *)cursor; + JS_ASSERT(cursor + + length * sizeof(jsbytecode) + + nsrcnotes * sizeof(jssrcnote) == + (uint8 *)script + size); + +#ifdef CHECK_SCRIPT_OWNER + script->owner = cx->thread; +#endif + return script; +} + +JSScript * +js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) +{ + uint32 mainLength, prologLength, nsrcnotes, nfixed; + JSScript *script; + const char *filename; + JSFunction *fun; + + /* The counts of indexed things must be checked during code generation. */ + JS_ASSERT(cg->atomList.count <= INDEX_LIMIT); + JS_ASSERT(cg->objectList.length <= INDEX_LIMIT); + JS_ASSERT(cg->regexpList.length <= INDEX_LIMIT); + + mainLength = CG_OFFSET(cg); + prologLength = CG_PROLOG_OFFSET(cg); + CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes); + script = js_NewScript(cx, prologLength + mainLength, nsrcnotes, + cg->atomList.count, cg->objectList.length, + cg->upvarList.count, cg->regexpList.length, + cg->ntrynotes); + if (!script) + return NULL; + + /* Now that we have script, error control flow must go to label bad. */ + script->main += prologLength; + memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode)); + memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode)); + nfixed = (cg->treeContext.flags & TCF_IN_FUNCTION) + ? cg->treeContext.u.fun->u.i.nvars + : cg->treeContext.ngvars + cg->regexpList.length; + JS_ASSERT(nfixed < SLOTNO_LIMIT); + script->nfixed = (uint16) nfixed; + js_InitAtomMap(cx, &script->atomMap, &cg->atomList); + + filename = cg->treeContext.parseContext->tokenStream.filename; + if (filename) { + script->filename = js_SaveScriptFilename(cx, filename); + if (!script->filename) + goto bad; + } + script->lineno = cg->firstLine; + if (script->nfixed + cg->maxStackDepth >= JS_BIT(16)) { + js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, + JSMSG_NEED_DIET, "script"); + goto bad; + } + script->nslots = script->nfixed + cg->maxStackDepth; + script->staticDepth = cg->staticDepth; + script->principals = cg->treeContext.parseContext->principals; + if (script->principals) + JSPRINCIPALS_HOLD(cx, script->principals); + + if (!js_FinishTakingSrcNotes(cx, cg, SCRIPT_NOTES(script))) + goto bad; + if (cg->ntrynotes != 0) + js_FinishTakingTryNotes(cg, JS_SCRIPT_TRYNOTES(script)); + if (cg->objectList.length != 0) + FinishParsedObjects(&cg->objectList, JS_SCRIPT_OBJECTS(script)); + if (cg->regexpList.length != 0) + FinishParsedObjects(&cg->regexpList, JS_SCRIPT_REGEXPS(script)); + if (cg->treeContext.flags & TCF_NO_SCRIPT_RVAL) + script->flags |= JSSF_NO_SCRIPT_RVAL; + + if (cg->upvarList.count != 0) { + JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length); + memcpy(JS_SCRIPT_UPVARS(script)->vector, cg->upvarMap.vector, + cg->upvarList.count * sizeof(uint32)); + ATOM_LIST_INIT(&cg->upvarList); + JS_free(cx, cg->upvarMap.vector); + cg->upvarMap.vector = NULL; + } + + /* + * We initialize fun->u.script to be the script constructed above + * so that the debugger has a valid FUN_SCRIPT(fun). + */ + fun = NULL; + if (cg->treeContext.flags & TCF_IN_FUNCTION) { + fun = cg->treeContext.u.fun; + JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun)); + JS_ASSERT_IF(script->upvarsOffset != 0, + JS_SCRIPT_UPVARS(script)->length == fun->u.i.nupvars); + + js_FreezeLocalNames(cx, fun); + fun->u.i.script = script; +#ifdef CHECK_SCRIPT_OWNER + script->owner = NULL; +#endif + if (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT) + fun->flags |= JSFUN_HEAVYWEIGHT; + } + + /* Tell the debugger about this compiled script. */ + js_CallNewScriptHook(cx, script, fun); + return script; + +bad: + js_DestroyScript(cx, script); + return NULL; +} + +JS_FRIEND_API(void) +js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun) +{ + JSNewScriptHook hook; + + hook = cx->debugHooks->newScriptHook; + if (hook) { + JS_KEEP_ATOMS(cx->runtime); + hook(cx, script->filename, script->lineno, script, fun, + cx->debugHooks->newScriptHookData); + JS_UNKEEP_ATOMS(cx->runtime); + } +} + +JS_FRIEND_API(void) +js_CallDestroyScriptHook(JSContext *cx, JSScript *script) +{ + JSDestroyScriptHook hook; + + hook = cx->debugHooks->destroyScriptHook; + if (hook) + hook(cx, script, cx->debugHooks->destroyScriptHookData); +} + +void +js_DestroyScript(JSContext *cx, JSScript *script) +{ + js_CallDestroyScriptHook(cx, script); + JS_ClearScriptTraps(cx, script); + + if (script->principals) + JSPRINCIPALS_DROP(cx, script->principals); + + if (JS_GSN_CACHE(cx).code == script->code) + JS_CLEAR_GSN_CACHE(cx); + + /* + * The GC flushes all property caches, so no need to purge just the + * entries for this script. + * + * JS_THREADSAFE note: js_FlushPropertyCacheForScript flushes only the + * current thread's property cache, so a script not owned by a function + * or object, which hands off lifetime management for that script to the + * GC, must be used by only one thread over its lifetime. + * + * This should be an API-compatible change, since a script is never safe + * against premature GC if shared among threads without a rooted object + * wrapping it to protect the script's mapped atoms against GC. We use + * script->owner to enforce this requirement via assertions. + */ +#ifdef CHECK_SCRIPT_OWNER + JS_ASSERT_IF(cx->runtime->gcRunning, !script->owner); +#endif + + if (!cx->runtime->gcRunning) { + if (!(cx->fp && (cx->fp->flags & JSFRAME_EVAL))) { +#ifdef CHECK_SCRIPT_OWNER + JS_ASSERT(script->owner == cx->thread); +#endif + js_FlushPropertyCacheForScript(cx, script); + } + } + + JS_free(cx, script); +} + +void +js_TraceScript(JSTracer *trc, JSScript *script) +{ + JSAtomMap *map; + uintN i, length; + JSAtom **vector; + jsval v; + JSObjectArray *objarray; + + map = &script->atomMap; + length = map->length; + vector = map->vector; + for (i = 0; i < length; i++) { + v = ATOM_KEY(vector[i]); + if (JSVAL_IS_TRACEABLE(v)) { + JS_SET_TRACING_INDEX(trc, "atomMap", i); + JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); + } + } + + if (script->objectsOffset != 0) { + objarray = JS_SCRIPT_OBJECTS(script); + i = objarray->length; + do { + --i; + if (objarray->vector[i]) { + JS_SET_TRACING_INDEX(trc, "objects", i); + JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT); + } + } while (i != 0); + } + + if (script->regexpsOffset != 0) { + objarray = JS_SCRIPT_REGEXPS(script); + i = objarray->length; + do { + --i; + if (objarray->vector[i]) { + JS_SET_TRACING_INDEX(trc, "regexps", i); + JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT); + } + } while (i != 0); + } + + if (script->u.object) { + JS_SET_TRACING_NAME(trc, "object"); + JS_CallTracer(trc, script->u.object, JSTRACE_OBJECT); + } + + if (IS_GC_MARKING_TRACER(trc) && script->filename) + js_MarkScriptFilename(script->filename); +} + +typedef struct GSNCacheEntry { + JSDHashEntryHdr hdr; + jsbytecode *pc; + jssrcnote *sn; +} GSNCacheEntry; + +#define GSN_CACHE_THRESHOLD 100 + +jssrcnote * +js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + ptrdiff_t target, offset; + GSNCacheEntry *entry; + jssrcnote *sn, *result; + uintN nsrcnotes; + + + target = PTRDIFF(pc, script->code, jsbytecode); + if ((uint32)target >= script->length) + return NULL; + + if (JS_GSN_CACHE(cx).code == script->code) { + JS_METER_GSN_CACHE(cx, hits); + entry = (GSNCacheEntry *) + JS_DHashTableOperate(&JS_GSN_CACHE(cx).table, pc, + JS_DHASH_LOOKUP); + return entry->sn; + } + + JS_METER_GSN_CACHE(cx, misses); + offset = 0; + for (sn = SCRIPT_NOTES(script); ; sn = SN_NEXT(sn)) { + if (SN_IS_TERMINATOR(sn)) { + result = NULL; + break; + } + offset += SN_DELTA(sn); + if (offset == target && SN_IS_GETTABLE(sn)) { + result = sn; + break; + } + } + + if (JS_GSN_CACHE(cx).code != script->code && + script->length >= GSN_CACHE_THRESHOLD) { + JS_CLEAR_GSN_CACHE(cx); + nsrcnotes = 0; + for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); + sn = SN_NEXT(sn)) { + if (SN_IS_GETTABLE(sn)) + ++nsrcnotes; + } + if (!JS_DHashTableInit(&JS_GSN_CACHE(cx).table, JS_DHashGetStubOps(), + NULL, sizeof(GSNCacheEntry), + JS_DHASH_DEFAULT_CAPACITY(nsrcnotes))) { + JS_GSN_CACHE(cx).table.ops = NULL; + } else { + pc = script->code; + for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); + sn = SN_NEXT(sn)) { + pc += SN_DELTA(sn); + if (SN_IS_GETTABLE(sn)) { + entry = (GSNCacheEntry *) + JS_DHashTableOperate(&JS_GSN_CACHE(cx).table, pc, + JS_DHASH_ADD); + entry->pc = pc; + entry->sn = sn; + } + } + JS_GSN_CACHE(cx).code = script->code; + JS_METER_GSN_CACHE(cx, fills); + } + } + + return result; +} + +uintN +js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp) +{ + return js_PCToLineNumber(cx, fp->script, fp->imacpc ? fp->imacpc : fp->regs->pc); +} + +uintN +js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + JSFunction *fun; + uintN lineno; + ptrdiff_t offset, target; + jssrcnote *sn; + JSSrcNoteType type; + + /* Cope with JSStackFrame.pc value prior to entering js_Interpret. */ + if (!pc) + return 0; + + /* + * Special case: function definition needs no line number note because + * the function's script contains its starting line number. + */ + if (js_CodeSpec[*pc].format & JOF_INDEXBASE) + pc += js_CodeSpec[*pc].length; + if (*pc == JSOP_DEFFUN) { + GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun); + return fun->u.i.script->lineno; + } + + /* + * General case: walk through source notes accumulating their deltas, + * keeping track of line-number notes, until we pass the note for pc's + * offset within script->code. + */ + lineno = script->lineno; + offset = 0; + target = PTRDIFF(pc, script->code, jsbytecode); + for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + offset += SN_DELTA(sn); + type = (JSSrcNoteType) SN_TYPE(sn); + if (type == SRC_SETLINE) { + if (offset <= target) + lineno = (uintN) js_GetSrcNoteOffset(sn, 0); + } else if (type == SRC_NEWLINE) { + if (offset <= target) + lineno++; + } + if (offset > target) + break; + } + return lineno; +} + +/* The line number limit is the same as the jssrcnote offset limit. */ +#define SN_LINE_LIMIT (SN_3BYTE_OFFSET_FLAG << 16) + +jsbytecode * +js_LineNumberToPC(JSScript *script, uintN target) +{ + ptrdiff_t offset, best; + uintN lineno, bestdiff, diff; + jssrcnote *sn; + JSSrcNoteType type; + + offset = 0; + best = -1; + lineno = script->lineno; + bestdiff = SN_LINE_LIMIT; + for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + /* + * Exact-match only if offset is not in the prolog; otherwise use + * nearest greater-or-equal line number match. + */ + if (lineno == target && script->code + offset >= script->main) + goto out; + if (lineno >= target) { + diff = lineno - target; + if (diff < bestdiff) { + bestdiff = diff; + best = offset; + } + } + offset += SN_DELTA(sn); + type = (JSSrcNoteType) SN_TYPE(sn); + if (type == SRC_SETLINE) { + lineno = (uintN) js_GetSrcNoteOffset(sn, 0); + } else if (type == SRC_NEWLINE) { + lineno++; + } + } + if (best >= 0) + offset = best; +out: + return script->code + offset; +} + +JS_FRIEND_API(uintN) +js_GetScriptLineExtent(JSScript *script) +{ + uintN lineno; + jssrcnote *sn; + JSSrcNoteType type; + + lineno = script->lineno; + for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + type = (JSSrcNoteType) SN_TYPE(sn); + if (type == SRC_SETLINE) { + lineno = (uintN) js_GetSrcNoteOffset(sn, 0); + } else if (type == SRC_NEWLINE) { + lineno++; + } + } + return 1 + lineno - script->lineno; +} + +#if JS_HAS_GENERATORS + +JSBool +js_IsInsideTryWithFinally(JSScript *script, jsbytecode *pc) +{ + JSTryNoteArray *tarray; + JSTryNote *tn, *tnlimit; + uint32 off; + + JS_ASSERT(script->code <= pc); + JS_ASSERT(pc < script->code + script->length); + + if (!script->trynotesOffset != 0) + return JS_FALSE; + tarray = JS_SCRIPT_TRYNOTES(script); + JS_ASSERT(tarray->length != 0); + + tn = tarray->vector; + tnlimit = tn + tarray->length; + off = (uint32)(pc - script->main); + do { + if (off - tn->start < tn->length) { + if (tn->kind == JSTRY_FINALLY) + return JS_TRUE; + JS_ASSERT(tn->kind == JSTRY_CATCH); + } + } while (++tn != tnlimit); + return JS_FALSE; +} + +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscript.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscript.h new file mode 100644 index 0000000..00f7ca7 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsscript.h @@ -0,0 +1,330 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsscript_h___ +#define jsscript_h___ +/* + * JS script descriptor. + */ +#include "jsatom.h" +#include "jsprvtd.h" + +JS_BEGIN_EXTERN_C + +/* + * Type of try note associated with each catch or finally block, and also with + * for-in loops. + */ +typedef enum JSTryNoteKind { + JSTRY_CATCH, + JSTRY_FINALLY, + JSTRY_ITER +} JSTryNoteKind; + +/* + * Exception handling record. + */ +struct JSTryNote { + uint8 kind; /* one of JSTryNoteKind */ + uint8 padding; /* explicit padding on uint16 boundary */ + uint16 stackDepth; /* stack depth upon exception handler entry */ + uint32 start; /* start of the try statement or for-in loop + relative to script->main */ + uint32 length; /* length of the try statement or for-in loop */ +}; + +typedef struct JSTryNoteArray { + JSTryNote *vector; /* array of indexed try notes */ + uint32 length; /* count of indexed try notes */ +} JSTryNoteArray; + +typedef struct JSObjectArray { + JSObject **vector; /* array of indexed objects */ + uint32 length; /* count of indexed objects */ +} JSObjectArray; + +typedef struct JSUpvarArray { + uint32 *vector; /* array of indexed upvar cookies */ + uint32 length; /* count of indexed upvar cookies */ +} JSUpvarArray; + +#define MAKE_UPVAR_COOKIE(skip,slot) ((skip) << 16 | (slot)) +#define UPVAR_FRAME_SKIP(cookie) ((uint32)(cookie) >> 16) +#define UPVAR_FRAME_SLOT(cookie) ((uint16)(cookie)) + +#define JS_OBJECT_ARRAY_SIZE(length) \ + (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length)) + +#if defined DEBUG && defined JS_THREADSAFE +# define CHECK_SCRIPT_OWNER 1 +#endif + +struct JSScript { + jsbytecode *code; /* bytecodes and their immediate operands */ + uint32 length; /* length of code vector */ + uint16 version; /* JS version under which script was compiled */ + uint16 nfixed; /* number of slots besides stack operands in + slot array */ + uint8 objectsOffset; /* offset to the array of nested function, + block, scope, xml and one-time regexps + objects or 0 if none */ + uint8 upvarsOffset; /* offset of the array of display ("up") + closure vars or 0 if none */ + uint8 regexpsOffset; /* offset to the array of to-be-cloned + regexps or 0 if none. */ + uint8 trynotesOffset; /* offset to the array of try notes or + 0 if none */ + uint8 flags; /* see below */ + jsbytecode *main; /* main entry point, after predef'ing prolog */ + JSAtomMap atomMap; /* maps immediate index to literal struct */ + const char *filename; /* source filename or null */ + uint32 lineno; /* base line number of script */ + uint16 nslots; /* vars plus maximum stack depth */ + uint16 staticDepth;/* static depth for display maintenance */ + JSPrincipals *principals;/* principals for this script */ + union { + JSObject *object; /* optional Script-class object wrapper */ + JSScript *nextToGC; /* next to GC in rt->scriptsToGC list */ + } u; +#ifdef CHECK_SCRIPT_OWNER + JSThread *owner; /* for thread-safe life-cycle assertions */ +#endif +}; + +#define JSSF_NO_SCRIPT_RVAL 0x01 /* no need for result value of last + expression statement */ + +static JS_INLINE uintN +StackDepth(JSScript *script) +{ + return script->nslots - script->nfixed; +} + +/* No need to store script->notes now that it is allocated right after code. */ +#define SCRIPT_NOTES(script) ((jssrcnote*)((script)->code+(script)->length)) + +#define JS_SCRIPT_OBJECTS(script) \ + (JS_ASSERT((script)->objectsOffset != 0), \ + (JSObjectArray *)((uint8 *)(script) + (script)->objectsOffset)) + +#define JS_SCRIPT_UPVARS(script) \ + (JS_ASSERT((script)->upvarsOffset != 0), \ + (JSUpvarArray *)((uint8 *)(script) + (script)->upvarsOffset)) + +#define JS_SCRIPT_REGEXPS(script) \ + (JS_ASSERT((script)->regexpsOffset != 0), \ + (JSObjectArray *)((uint8 *)(script) + (script)->regexpsOffset)) + +#define JS_SCRIPT_TRYNOTES(script) \ + (JS_ASSERT((script)->trynotesOffset != 0), \ + (JSTryNoteArray *)((uint8 *)(script) + (script)->trynotesOffset)) + +#define JS_GET_SCRIPT_ATOM(script_, index, atom) \ + JS_BEGIN_MACRO \ + if (cx->fp && cx->fp->imacpc && cx->fp->script == script_) { \ + JS_ASSERT((size_t)(index) < js_common_atom_count); \ + (atom) = COMMON_ATOMS_START(&cx->runtime->atomState)[index]; \ + } else { \ + JSAtomMap *atoms_ = &(script_)->atomMap; \ + JS_ASSERT((uint32)(index) < atoms_->length); \ + (atom) = atoms_->vector[index]; \ + } \ + JS_END_MACRO + +#define JS_GET_SCRIPT_OBJECT(script, index, obj) \ + JS_BEGIN_MACRO \ + JSObjectArray *objects_ = JS_SCRIPT_OBJECTS(script); \ + JS_ASSERT((uint32)(index) < objects_->length); \ + (obj) = objects_->vector[index]; \ + JS_END_MACRO + +#define JS_GET_SCRIPT_FUNCTION(script, index, fun) \ + JS_BEGIN_MACRO \ + JSObject *funobj_; \ + \ + JS_GET_SCRIPT_OBJECT(script, index, funobj_); \ + JS_ASSERT(HAS_FUNCTION_CLASS(funobj_)); \ + JS_ASSERT(funobj_ == (JSObject *) STOBJ_GET_PRIVATE(funobj_)); \ + (fun) = (JSFunction *) funobj_; \ + JS_ASSERT(FUN_INTERPRETED(fun)); \ + JS_END_MACRO + +#define JS_GET_SCRIPT_REGEXP(script, index, obj) \ + JS_BEGIN_MACRO \ + JSObjectArray *regexps_ = JS_SCRIPT_REGEXPS(script); \ + JS_ASSERT((uint32)(index) < regexps_->length); \ + (obj) = regexps_->vector[index]; \ + JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_RegExpClass); \ + JS_END_MACRO + +/* + * Check if pc is inside a try block that has finally code. GC calls this to + * check if it is necessary to schedule generator.close() invocation for an + * unreachable generator. + */ +JSBool +js_IsInsideTryWithFinally(JSScript *script, jsbytecode *pc); + +extern JS_FRIEND_DATA(JSClass) js_ScriptClass; + +extern JSObject * +js_InitScriptClass(JSContext *cx, JSObject *obj); + +/* + * On first new context in rt, initialize script runtime state, specifically + * the script filename table and its lock. + */ +extern JSBool +js_InitRuntimeScriptState(JSRuntime *rt); + +/* + * On last context destroy for rt, if script filenames are all GC'd, free the + * script filename table and its lock. + */ +extern void +js_FinishRuntimeScriptState(JSRuntime *rt); + +/* + * On JS_DestroyRuntime(rt), forcibly free script filename prefixes and any + * script filename table entries that have not been GC'd, the latter using + * js_FinishRuntimeScriptState. + * + * This allows script filename prefixes to outlive any context in rt. + */ +extern void +js_FreeRuntimeScriptState(JSRuntime *rt); + +extern const char * +js_SaveScriptFilename(JSContext *cx, const char *filename); + +extern const char * +js_SaveScriptFilenameRT(JSRuntime *rt, const char *filename, uint32 flags); + +extern uint32 +js_GetScriptFilenameFlags(const char *filename); + +extern void +js_MarkScriptFilename(const char *filename); + +extern void +js_MarkScriptFilenames(JSRuntime *rt, JSBool keepAtoms); + +extern void +js_SweepScriptFilenames(JSRuntime *rt); + +/* + * Two successively less primitive ways to make a new JSScript. The first + * does *not* call a non-null cx->runtime->newScriptHook -- only the second, + * js_NewScriptFromCG, calls this optional debugger hook. + * + * The js_NewScript function can't know whether the script it creates belongs + * to a function, or is top-level or eval code, but the debugger wants access + * to the newly made script's function, if any -- so callers of js_NewScript + * are responsible for notifying the debugger after successfully creating any + * kind (function or other) of new JSScript. + */ +extern JSScript * +js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms, + uint32 nobjects, uint32 nupvars, uint32 nregexps, + uint32 ntrynotes); + +extern JSScript * +js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg); + +/* + * New-script-hook calling is factored from js_NewScriptFromCG so that it + * and callers of js_XDRScript can share this code. In the case of callers + * of js_XDRScript, the hook should be invoked only after successful decode + * of any owning function (the fun parameter) or script object (null fun). + */ +extern JS_FRIEND_API(void) +js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun); + +extern JS_FRIEND_API(void) +js_CallDestroyScriptHook(JSContext *cx, JSScript *script); + +extern void +js_DestroyScript(JSContext *cx, JSScript *script); + +extern void +js_TraceScript(JSTracer *trc, JSScript *script); + +/* + * To perturb as little code as possible, we introduce a js_GetSrcNote lookup + * cache without adding an explicit cx parameter. Thus js_GetSrcNote becomes + * a macro that uses cx from its calls' lexical environments. + */ +#define js_GetSrcNote(script,pc) js_GetSrcNoteCached(cx, script, pc) + +extern jssrcnote * +js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc); + +/* + * NOTE: use js_FramePCToLineNumber(cx, fp) when you have an active fp, in + * preference to js_PCToLineNumber (cx, fp->script fp->regs->pc), because + * fp->imacpc may be non-null, indicating an active imacro. + */ +extern uintN +js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp); + +extern uintN +js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc); + +extern jsbytecode * +js_LineNumberToPC(JSScript *script, uintN lineno); + +extern JS_FRIEND_API(uintN) +js_GetScriptLineExtent(JSScript *script); + +/* + * If magic is non-null, js_XDRScript succeeds on magic number mismatch but + * returns false in *magic; it reflects a match via a true *magic out param. + * If magic is null, js_XDRScript returns false on bad magic number errors, + * which it reports. + * + * NB: callers must call js_CallNewScriptHook after successful JSXDR_DECODE + * and subsequent set-up of owning function or script object, if any. + */ +extern JSBool +js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *magic); + +JS_END_EXTERN_C + +#endif /* jsscript_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsshell.msg b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsshell.msg new file mode 100644 index 0000000..7074fe9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsshell.msg @@ -0,0 +1,51 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + Error messages for JSShell. See js.msg for format. +*/ + +MSG_DEF(JSSMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "") +MSG_DEF(JSSMSG_CANT_OPEN, 1, 2, JSEXN_NONE, "can't open {0}: {1}") +MSG_DEF(JSSMSG_TRAP_USAGE, 2, 0, JSEXN_NONE, "usage: trap [fun] [pc] expr") +MSG_DEF(JSSMSG_LINE2PC_USAGE, 3, 0, JSEXN_NONE, "usage: line2pc [fun] line") +MSG_DEF(JSSMSG_FILE_SCRIPTS_ONLY, 4, 0, JSEXN_NONE, "only works on JS scripts read from files") +MSG_DEF(JSSMSG_UNEXPECTED_EOF, 5, 1, JSEXN_NONE, "unexpected EOF in {0}") +MSG_DEF(JSSMSG_DOEXP_USAGE, 6, 0, JSEXN_NONE, "usage: doexp obj id") +MSG_DEF(JSSMSG_SCRIPTS_ONLY, 7, 0, JSEXN_NONE, "only works on scripts") diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstaticcheck.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstaticcheck.h new file mode 100644 index 0000000..2614659 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstaticcheck.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsstaticcheck_h___ +#define jsstaticcheck_h___ + +#ifdef NS_STATIC_CHECKING +/* + * Trigger a control flow check to make sure that code flows through label + */ +inline __attribute__ ((unused)) void MUST_FLOW_THROUGH(const char *label) { +} + +/* avoid unused goto-label warnings */ +#define MUST_FLOW_LABEL(label) goto label; label: +#else +#define MUST_FLOW_THROUGH(label) ((void)0) +#define MUST_FLOW_LABEL(label) +#endif + +#endif /* jsstaticcheck_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstddef.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstddef.h new file mode 100644 index 0000000..45b417f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstddef.h @@ -0,0 +1,87 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * stddef inclusion here to first declare ptrdif as a signed long instead of a + * signed int. + */ + +#ifdef _WINDOWS +# ifndef XP_WIN +# define XP_WIN +# endif +#if defined(_WIN32) || defined(WIN32) +# ifndef XP_WIN32 +# define XP_WIN32 +# endif +#else +# ifndef XP_WIN16 +# define XP_WIN16 +# endif +#endif +#endif + +#ifdef XP_WIN16 +#ifndef _PTRDIFF_T_DEFINED +typedef long ptrdiff_t; + +/* + * The Win16 compiler treats pointer differences as 16-bit signed values. + * This macro allows us to treat them as 17-bit signed values, stored in + * a 32-bit type. + */ +#define PTRDIFF(p1, p2, type) \ + ((((unsigned long)(p1)) - ((unsigned long)(p2))) / sizeof(type)) + +#define _PTRDIFF_T_DEFINED +#endif /*_PTRDIFF_T_DEFINED*/ +#else /*WIN16*/ + +#define PTRDIFF(p1, p2, type) \ + ((p1) - (p2)) + +#endif + +#include + +#ifdef __cplusplus +# define __cplusplus_only(x) x +#else +# define __cplusplus_only(x) /* nothing */ +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstr.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstr.cpp new file mode 100644 index 0000000..eeb505d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstr.cpp @@ -0,0 +1,5347 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS string type implementation. + * + * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these + * native methods store strings (possibly newborn) converted from their 'this' + * parameter and arguments on the stack: 'this' conversions at argv[-1], arg + * conversions at their index (argv[0], argv[1]). This is a legitimate method + * of rooting things that might lose their newborn root due to subsequent GC + * allocations in the same native method. + */ +#include "jsstddef.h" +#include +#include +#include "jstypes.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jshash.h" /* Added by JSIFY */ +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsregexp.h" +#include "jsscope.h" +#include "jsstr.h" +#include "jsbit.h" + +#define JSSTRDEP_RECURSION_LIMIT 100 + +size_t +js_MinimizeDependentStrings(JSString *str, int level, JSString **basep) +{ + JSString *base; + size_t start, length; + + JS_ASSERT(JSSTRING_IS_DEPENDENT(str)); + base = JSSTRDEP_BASE(str); + start = JSSTRDEP_START(str); + if (JSSTRING_IS_DEPENDENT(base)) { + if (level < JSSTRDEP_RECURSION_LIMIT) { + start += js_MinimizeDependentStrings(base, level + 1, &base); + } else { + do { + start += JSSTRDEP_START(base); + base = JSSTRDEP_BASE(base); + } while (JSSTRING_IS_DEPENDENT(base)); + } + if (start == 0) { + JS_ASSERT(JSSTRDEP_IS_PREFIX(str)); + JSPREFIX_SET_BASE(str, base); + } else if (start <= JSSTRDEP_START_MASK) { + length = JSSTRDEP_LENGTH(str); + JSSTRDEP_INIT(str, base, start, length); + } + } + *basep = base; + return start; +} + +jschar * +js_GetDependentStringChars(JSString *str) +{ + size_t start; + JSString *base; + + start = js_MinimizeDependentStrings(str, 0, &base); + JS_ASSERT(start < JSFLATSTR_LENGTH(base)); + return JSFLATSTR_CHARS(base) + start; +} + +const jschar * +js_GetStringChars(JSContext *cx, JSString *str) +{ + if (!js_MakeStringImmutable(cx, str)) + return NULL; + return JSFLATSTR_CHARS(str); +} + +JSString * JS_FASTCALL +js_ConcatStrings(JSContext *cx, JSString *left, JSString *right) +{ + size_t rn, ln, lrdist, n; + jschar *rs, *ls, *s; + JSString *ldep; /* non-null if left should become dependent */ + JSString *str; + + JSSTRING_CHARS_AND_LENGTH(right, rs, rn); + if (rn == 0) + return left; + + JSSTRING_CHARS_AND_LENGTH(left, ls, ln); + if (ln == 0) + return right; + + if (!JSSTRING_IS_MUTABLE(left)) { + /* We must copy if left does not own a buffer to realloc. */ + s = (jschar *) JS_malloc(cx, (ln + rn + 1) * sizeof(jschar)); + if (!s) + return NULL; + js_strncpy(s, ls, ln); + ldep = NULL; + } else { + /* We can realloc left's space and make it depend on our result. */ + JS_ASSERT(JSSTRING_IS_FLAT(left)); + s = (jschar *) JS_realloc(cx, ls, (ln + rn + 1) * sizeof(jschar)); + if (!s) + return NULL; + + /* Take care: right could depend on left! */ + lrdist = (size_t)(rs - ls); + if (lrdist < ln) + rs = s + lrdist; + left->u.chars = ls = s; + ldep = left; + } + + js_strncpy(s + ln, rs, rn); + n = ln + rn; + s[n] = 0; + str = js_NewString(cx, s, n); + if (!str) { + /* Out of memory: clean up any space we (re-)allocated. */ + if (!ldep) { + JS_free(cx, s); + } else { + s = (jschar *) JS_realloc(cx, ls, (ln + 1) * sizeof(jschar)); + if (s) + left->u.chars = s; + } + } else { + JSFLATSTR_SET_MUTABLE(str); + + /* Morph left into a dependent prefix if we realloc'd its buffer. */ + if (ldep) { + JSPREFIX_INIT(ldep, str, ln); +#ifdef DEBUG + { + JSRuntime *rt = cx->runtime; + JS_RUNTIME_METER(rt, liveDependentStrings); + JS_RUNTIME_METER(rt, totalDependentStrings); + JS_LOCK_RUNTIME_VOID(rt, + (rt->strdepLengthSum += (double)ln, + rt->strdepLengthSquaredSum += (double)ln * (double)ln)); + } +#endif + } + } + + return str; +} + +const jschar * +js_UndependString(JSContext *cx, JSString *str) +{ + size_t n, size; + jschar *s; + + if (JSSTRING_IS_DEPENDENT(str)) { + n = JSSTRDEP_LENGTH(str); + size = (n + 1) * sizeof(jschar); + s = (jschar *) JS_malloc(cx, size); + if (!s) + return NULL; + + js_strncpy(s, JSSTRDEP_CHARS(str), n); + s[n] = 0; + JSFLATSTR_INIT(str, s, n); + +#ifdef DEBUG + { + JSRuntime *rt = cx->runtime; + JS_RUNTIME_UNMETER(rt, liveDependentStrings); + JS_RUNTIME_UNMETER(rt, totalDependentStrings); + JS_LOCK_RUNTIME_VOID(rt, + (rt->strdepLengthSum -= (double)n, + rt->strdepLengthSquaredSum -= (double)n * (double)n)); + } +#endif + } + + return JSFLATSTR_CHARS(str); +} + +JSBool +js_MakeStringImmutable(JSContext *cx, JSString *str) +{ + if (JSSTRING_IS_DEPENDENT(str) && !js_UndependString(cx, str)) { + JS_RUNTIME_METER(cx->runtime, badUndependStrings); + return JS_FALSE; + } + JSFLATSTR_CLEAR_MUTABLE(str); + return JS_TRUE; +} + +static JSString * +ArgToRootedString(JSContext *cx, uintN argc, jsval *vp, uintN arg) +{ + JSObject *obj; + JSString *str; + + if (arg >= argc) + return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + vp += 2 + arg; + + if (JSVAL_IS_OBJECT(*vp)) { + obj = JSVAL_TO_OBJECT(*vp); + if (!obj) + return ATOM_TO_STRING(cx->runtime->atomState.nullAtom); + if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, vp)) + return NULL; + } + if (JSVAL_IS_STRING(*vp)) + return JSVAL_TO_STRING(*vp); + if (JSVAL_IS_INT(*vp)) { + str = js_NumberToString(cx, JSVAL_TO_INT(*vp)); + } else if (JSVAL_IS_DOUBLE(*vp)) { + str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(*vp)); + } else if (JSVAL_IS_BOOLEAN(*vp)) { + return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[ + JSVAL_TO_BOOLEAN(*vp)? 1 : 0]); + } else { + JS_ASSERT(JSVAL_IS_VOID(*vp)); + return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } + if (str) + *vp = STRING_TO_JSVAL(str); + return str; +} + +/* + * Forward declarations for URI encode/decode and helper routines + */ +static JSBool +str_decodeURI(JSContext *cx, uintN argc, jsval *vp); + +static JSBool +str_decodeURI_Component(JSContext *cx, uintN argc, jsval *vp); + +static JSBool +str_encodeURI(JSContext *cx, uintN argc, jsval *vp); + +static JSBool +str_encodeURI_Component(JSContext *cx, uintN argc, jsval *vp); + +static uint32 +Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length); + +/* + * Contributions from the String class to the set of methods defined for the + * global object. escape and unescape used to be defined in the Mocha library, + * but as ECMA decided to spec them, they've been moved to the core engine + * and made ECMA-compliant. (Incomplete escapes are interpreted as literal + * characters by unescape.) + */ + +/* + * Stuff to emulate the old libmocha escape, which took a second argument + * giving the type of escape to perform. Retained for compatibility, and + * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes. + */ + +#define URL_XALPHAS ((uint8) 1) +#define URL_XPALPHAS ((uint8) 2) +#define URL_PATH ((uint8) 4) + +static const uint8 urlCharType[256] = +/* Bit 0 xalpha -- the alphas + * Bit 1 xpalpha -- as xalpha but + * converts spaces to plus and plus to %20 + * Bit 2 ... path -- as xalphas but doesn't escape '/' + */ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */ + 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */ + 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */ + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */ + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */ + 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */ + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */ + 0, }; + +/* This matches the ECMA escape set when mask is 7 (default.) */ + +#define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask)) + +/* See ECMA-262 Edition 3 B.2.1 */ +JSBool +js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSString *str; + size_t i, ni, length, newlength; + const jschar *chars; + jschar *newchars; + jschar ch; + jsint mask; + jsdouble d; + const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH; + if (argc > 1) { + d = js_ValueToNumber(cx, &argv[1]); + if (JSVAL_IS_NULL(argv[1])) + return JS_FALSE; + if (!JSDOUBLE_IS_FINITE(d) || + (mask = (jsint)d) != d || + mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH)) + { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_STRING_MASK, numBuf); + return JS_FALSE; + } + } + + str = ArgToRootedString(cx, argc, argv - 2, 0); + if (!str) + return JS_FALSE; + + JSSTRING_CHARS_AND_LENGTH(str, chars, length); + newlength = length; + + /* Take a first pass and see how big the result string will need to be. */ + for (i = 0; i < length; i++) { + if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) + continue; + if (ch < 256) { + if (mask == URL_XPALPHAS && ch == ' ') + continue; /* The character will be encoded as '+' */ + newlength += 2; /* The character will be encoded as %XX */ + } else { + newlength += 5; /* The character will be encoded as %uXXXX */ + } + + /* + * This overflow test works because newlength is incremented by at + * most 5 on each iteration. + */ + if (newlength < length) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + } + + if (newlength >= ~(size_t)0 / sizeof(jschar)) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + + newchars = (jschar *) JS_malloc(cx, (newlength + 1) * sizeof(jschar)); + if (!newchars) + return JS_FALSE; + for (i = 0, ni = 0; i < length; i++) { + if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) { + newchars[ni++] = ch; + } else if (ch < 256) { + if (mask == URL_XPALPHAS && ch == ' ') { + newchars[ni++] = '+'; /* convert spaces to pluses */ + } else { + newchars[ni++] = '%'; + newchars[ni++] = digits[ch >> 4]; + newchars[ni++] = digits[ch & 0xF]; + } + } else { + newchars[ni++] = '%'; + newchars[ni++] = 'u'; + newchars[ni++] = digits[ch >> 12]; + newchars[ni++] = digits[(ch & 0xF00) >> 8]; + newchars[ni++] = digits[(ch & 0xF0) >> 4]; + newchars[ni++] = digits[ch & 0xF]; + } + } + JS_ASSERT(ni == newlength); + newchars[newlength] = 0; + + str = js_NewString(cx, newchars, newlength); + if (!str) { + JS_free(cx, newchars); + return JS_FALSE; + } + *rval = STRING_TO_JSVAL(str); + return JS_TRUE; +} +#undef IS_OK + +static JSBool +str_escape(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + return obj && js_str_escape(cx, obj, argc, vp + 2, vp); +} + +/* See ECMA-262 Edition 3 B.2.2 */ +static JSBool +str_unescape(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + size_t i, ni, length; + const jschar *chars; + jschar *newchars; + jschar ch; + + str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return JS_FALSE; + + JSSTRING_CHARS_AND_LENGTH(str, chars, length); + + /* Don't bother allocating less space for the new string. */ + newchars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar)); + if (!newchars) + return JS_FALSE; + ni = i = 0; + while (i < length) { + ch = chars[i++]; + if (ch == '%') { + if (i + 1 < length && + JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1])) + { + ch = JS7_UNHEX(chars[i]) * 16 + JS7_UNHEX(chars[i + 1]); + i += 2; + } else if (i + 4 < length && chars[i] == 'u' && + JS7_ISHEX(chars[i + 1]) && JS7_ISHEX(chars[i + 2]) && + JS7_ISHEX(chars[i + 3]) && JS7_ISHEX(chars[i + 4])) + { + ch = (((((JS7_UNHEX(chars[i + 1]) << 4) + + JS7_UNHEX(chars[i + 2])) << 4) + + JS7_UNHEX(chars[i + 3])) << 4) + + JS7_UNHEX(chars[i + 4]); + i += 5; + } + } + newchars[ni++] = ch; + } + newchars[ni] = 0; + + str = js_NewString(cx, newchars, ni); + if (!str) { + JS_free(cx, newchars); + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +#if JS_HAS_UNEVAL +static JSBool +str_uneval(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + str = js_ValueToSource(cx, argc != 0 ? vp[2] : JSVAL_VOID); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} +#endif + +const char js_escape_str[] = "escape"; +const char js_unescape_str[] = "unescape"; +#if JS_HAS_UNEVAL +const char js_uneval_str[] = "uneval"; +#endif +const char js_decodeURI_str[] = "decodeURI"; +const char js_encodeURI_str[] = "encodeURI"; +const char js_decodeURIComponent_str[] = "decodeURIComponent"; +const char js_encodeURIComponent_str[] = "encodeURIComponent"; + +static JSFunctionSpec string_functions[] = { + JS_FN(js_escape_str, str_escape, 1,0), + JS_FN(js_unescape_str, str_unescape, 1,0), +#if JS_HAS_UNEVAL + JS_FN(js_uneval_str, str_uneval, 1,0), +#endif + JS_FN(js_decodeURI_str, str_decodeURI, 1,0), + JS_FN(js_encodeURI_str, str_encodeURI, 1,0), + JS_FN(js_decodeURIComponent_str, str_decodeURI_Component, 1,0), + JS_FN(js_encodeURIComponent_str, str_encodeURI_Component, 1,0), + + JS_FS_END +}; + +jschar js_empty_ucstr[] = {0}; +JSSubString js_EmptySubString = {0, js_empty_ucstr}; + +enum string_tinyid { + STRING_LENGTH = -1 +}; + +static JSPropertySpec string_props[] = { + {js_length_str, STRING_LENGTH, + JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED, 0,0}, + {0,0,0,0,0} +}; + +static JSBool +str_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + jsval v; + JSString *str; + jsint slot; + + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + + slot = JSVAL_TO_INT(id); + if (slot == STRING_LENGTH) { + if (OBJ_GET_CLASS(cx, obj) == &js_StringClass) { + /* Follow ECMA-262 by fetching intrinsic length of our string. */ + v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); + JS_ASSERT(JSVAL_IS_STRING(v)); + str = JSVAL_TO_STRING(v); + } else { + /* Preserve compatibility: convert obj to a string primitive. */ + str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + if (!str) + return JS_FALSE; + } + + *vp = INT_TO_JSVAL((jsint) JSSTRING_LENGTH(str)); + } + return JS_TRUE; +} + +#define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT) + +static JSBool +str_enumerate(JSContext *cx, JSObject *obj) +{ + jsval v; + JSString *str, *str1; + size_t i, length; + + v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); + JS_ASSERT(JSVAL_IS_STRING(v)); + str = JSVAL_TO_STRING(v); + + length = JSSTRING_LENGTH(str); + for (i = 0; i < length; i++) { + str1 = js_NewDependentString(cx, str, i, 1); + if (!str1) + return JS_FALSE; + if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(i), + STRING_TO_JSVAL(str1), NULL, NULL, + STRING_ELEMENT_ATTRS, NULL)) { + return JS_FALSE; + } + } + return JS_TRUE; +} + +static JSBool +str_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + JSObject **objp) +{ + jsval v; + JSString *str, *str1; + jsint slot; + + if (!JSVAL_IS_INT(id) || (flags & JSRESOLVE_ASSIGNING)) + return JS_TRUE; + + v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); + JS_ASSERT(JSVAL_IS_STRING(v)); + str = JSVAL_TO_STRING(v); + + slot = JSVAL_TO_INT(id); + if ((size_t)slot < JSSTRING_LENGTH(str)) { + str1 = js_GetUnitString(cx, str, (size_t)slot); + if (!str1) + return JS_FALSE; + if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(slot), + STRING_TO_JSVAL(str1), NULL, NULL, + STRING_ELEMENT_ATTRS, NULL)) { + return JS_FALSE; + } + *objp = obj; + } + return JS_TRUE; +} + +JSClass js_StringClass = { + js_String_str, + JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | + JSCLASS_HAS_CACHED_PROTO(JSProto_String), + JS_PropertyStub, JS_PropertyStub, str_getProperty, JS_PropertyStub, + str_enumerate, (JSResolveOp)str_resolve, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +#define NORMALIZE_THIS(cx,vp,str) \ + JS_BEGIN_MACRO \ + if (JSVAL_IS_STRING(vp[1])) { \ + str = JSVAL_TO_STRING(vp[1]); \ + } else { \ + str = NormalizeThis(cx, vp); \ + if (!str) \ + return JS_FALSE; \ + } \ + JS_END_MACRO + +static JSString * +NormalizeThis(JSContext *cx, jsval *vp) +{ + JSString *str; + + if (JSVAL_IS_NULL(vp[1]) && JSVAL_IS_NULL(JS_THIS(cx, vp))) + return NULL; + str = js_ValueToString(cx, vp[1]); + if (!str) + return NULL; + vp[1] = STRING_TO_JSVAL(str); + return str; +} + +#if JS_HAS_TOSOURCE + +/* + * String.prototype.quote is generic (as are most string methods), unlike + * toSource, toString, and valueOf. + */ +static JSBool +str_quote(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + NORMALIZE_THIS(cx, vp, str); + str = js_QuoteString(cx, str, '"'); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +str_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + jsval v; + JSString *str; + size_t i, j, k, n; + char buf[16]; + jschar *s, *t; + + if (!js_GetPrimitiveThis(cx, vp, &js_StringClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_STRING(v)); + str = js_QuoteString(cx, JSVAL_TO_STRING(v), '"'); + if (!str) + return JS_FALSE; + j = JS_snprintf(buf, sizeof buf, "(new %s(", js_StringClass.name); + JSSTRING_CHARS_AND_LENGTH(str, s, k); + n = j + k + 2; + t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar)); + if (!t) + return JS_FALSE; + for (i = 0; i < j; i++) + t[i] = buf[i]; + for (j = 0; j < k; i++, j++) + t[i] = s[j]; + t[i++] = ')'; + t[i++] = ')'; + t[i] = 0; + str = js_NewString(cx, t, n); + if (!str) { + JS_free(cx, t); + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +#endif /* JS_HAS_TOSOURCE */ + +static JSBool +str_toString(JSContext *cx, uintN argc, jsval *vp) +{ + return js_GetPrimitiveThis(cx, vp, &js_StringClass, vp); +} + +/* + * Java-like string native methods. + */ + +static JSString * +SubstringTail(JSContext *cx, JSString *str, jsdouble length, jsdouble begin, jsdouble end) +{ + if (begin < 0) + begin = 0; + else if (begin > length) + begin = length; + + if (end < 0) + end = 0; + else if (end > length) + end = length; + if (end < begin) { + /* ECMA emulates old JDK1.0 java.lang.String.substring. */ + jsdouble tmp = begin; + begin = end; + end = tmp; + } + + return js_NewDependentString(cx, str, (size_t)begin, (size_t)(end - begin)); +} + +static JSBool +str_substring(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + jsdouble d; + jsdouble length, begin, end; + + NORMALIZE_THIS(cx, vp, str); + if (argc != 0) { + d = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + length = JSSTRING_LENGTH(str); + begin = js_DoubleToInteger(d); + if (argc == 1) { + end = length; + } else { + d = js_ValueToNumber(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return JS_FALSE; + end = js_DoubleToInteger(d); + } + + str = SubstringTail(cx, str, length, begin, end); + if (!str) + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +#ifdef JS_TRACER +static JSString* FASTCALL +String_p_toString(JSContext* cx, JSObject* obj) +{ + if (!JS_InstanceOf(cx, obj, &js_StringClass, NULL)) + return NULL; + jsval v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); + JS_ASSERT(JSVAL_IS_STRING(v)); + return JSVAL_TO_STRING(v); +} + +static JSString* FASTCALL +String_p_substring(JSContext* cx, JSString* str, int32 begin, int32 end) +{ + JS_ASSERT(JS_ON_TRACE(cx)); + + size_t length = JSSTRING_LENGTH(str); + return SubstringTail(cx, str, length, begin, end); +} + +static JSString* FASTCALL +String_p_substring_1(JSContext* cx, JSString* str, int32 begin) +{ + JS_ASSERT(JS_ON_TRACE(cx)); + + size_t length = JSSTRING_LENGTH(str); + return SubstringTail(cx, str, length, begin, length); +} +#endif + +JSString* JS_FASTCALL +js_toLowerCase(JSContext *cx, JSString *str) +{ + size_t i, n; + jschar *s, *news; + + JSSTRING_CHARS_AND_LENGTH(str, s, n); + news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar)); + if (!news) + return NULL; + for (i = 0; i < n; i++) + news[i] = JS_TOLOWER(s[i]); + news[n] = 0; + str = js_NewString(cx, news, n); + if (!str) { + JS_free(cx, news); + return NULL; + } + return str; +} + +static JSBool +str_toLowerCase(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + NORMALIZE_THIS(cx, vp, str); + str = js_toLowerCase(cx, str); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +str_toLocaleLowerCase(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + /* + * Forcefully ignore the first (or any) argument and return toLowerCase(), + * ECMA has reserved that argument, presumably for defining the locale. + */ + if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) { + NORMALIZE_THIS(cx, vp, str); + return cx->localeCallbacks->localeToLowerCase(cx, str, vp); + } + return str_toLowerCase(cx, 0, vp); +} + +JSString* JS_FASTCALL +js_toUpperCase(JSContext *cx, JSString *str) +{ + size_t i, n; + jschar *s, *news; + + JSSTRING_CHARS_AND_LENGTH(str, s, n); + news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar)); + if (!news) + return NULL; + for (i = 0; i < n; i++) + news[i] = JS_TOUPPER(s[i]); + news[n] = 0; + str = js_NewString(cx, news, n); + if (!str) { + JS_free(cx, news); + return NULL; + } + return str; +} + +static JSBool +str_toUpperCase(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + NORMALIZE_THIS(cx, vp, str); + str = js_toUpperCase(cx, str); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +str_toLocaleUpperCase(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + /* + * Forcefully ignore the first (or any) argument and return toUpperCase(), + * ECMA has reserved that argument, presumably for defining the locale. + */ + if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) { + NORMALIZE_THIS(cx, vp, str); + return cx->localeCallbacks->localeToUpperCase(cx, str, vp); + } + return str_toUpperCase(cx, 0, vp); +} + +static JSBool +str_localeCompare(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str, *thatStr; + + NORMALIZE_THIS(cx, vp, str); + if (argc == 0) { + *vp = JSVAL_ZERO; + } else { + thatStr = js_ValueToString(cx, vp[2]); + if (!thatStr) + return JS_FALSE; + if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) { + vp[2] = STRING_TO_JSVAL(thatStr); + return cx->localeCallbacks->localeCompare(cx, str, thatStr, vp); + } + *vp = INT_TO_JSVAL(js_CompareStrings(str, thatStr)); + } + return JS_TRUE; +} + +static JSBool +str_charAt(JSContext *cx, uintN argc, jsval *vp) +{ + jsval t; + JSString *str; + jsint i; + jsdouble d; + + t = vp[1]; + if (JSVAL_IS_STRING(t) && argc != 0 && JSVAL_IS_INT(vp[2])) { + str = JSVAL_TO_STRING(t); + i = JSVAL_TO_INT(vp[2]); + if ((size_t)i >= JSSTRING_LENGTH(str)) + goto out_of_range; + } else { + str = NormalizeThis(cx, vp); + if (!str) + return JS_FALSE; + + if (argc == 0) { + d = 0.0; + } else { + d = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + d = js_DoubleToInteger(d); + } + + if (d < 0 || JSSTRING_LENGTH(str) <= d) + goto out_of_range; + i = (jsint) d; + } + + str = js_GetUnitString(cx, str, (size_t)i); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; + +out_of_range: + *vp = JS_GetEmptyStringValue(cx); + return JS_TRUE; +} + +static JSBool +str_charCodeAt(JSContext *cx, uintN argc, jsval *vp) +{ + jsval t; + JSString *str; + jsint i; + jsdouble d; + + t = vp[1]; + if (JSVAL_IS_STRING(t) && argc != 0 && JSVAL_IS_INT(vp[2])) { + str = JSVAL_TO_STRING(t); + i = JSVAL_TO_INT(vp[2]); + if ((size_t)i >= JSSTRING_LENGTH(str)) + goto out_of_range; + } else { + str = NormalizeThis(cx, vp); + if (!str) + return JS_FALSE; + + if (argc == 0) { + d = 0.0; + } else { + d = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + d = js_DoubleToInteger(d); + } + + if (d < 0 || JSSTRING_LENGTH(str) <= d) + goto out_of_range; + i = (jsint) d; + } + + *vp = INT_TO_JSVAL(JSSTRING_CHARS(str)[i]); + return JS_TRUE; + +out_of_range: + *vp = JS_GetNaNValue(cx); + return JS_TRUE; +} + +#ifdef JS_TRACER +int32 FASTCALL +js_String_p_charCodeAt(JSString* str, int32 i) +{ + if (i < 0 || (int32)JSSTRING_LENGTH(str) <= i) + return -1; + return JSSTRING_CHARS(str)[i]; +} +#endif + +jsint +js_BoyerMooreHorspool(const jschar *text, jsint textlen, + const jschar *pat, jsint patlen, + jsint start) +{ + jsint i, j, k, m; + uint8 skip[BMH_CHARSET_SIZE]; + jschar c; + + JS_ASSERT(0 < patlen && patlen <= BMH_PATLEN_MAX); + for (i = 0; i < BMH_CHARSET_SIZE; i++) + skip[i] = (uint8)patlen; + m = patlen - 1; + for (i = 0; i < m; i++) { + c = pat[i]; + if (c >= BMH_CHARSET_SIZE) + return BMH_BAD_PATTERN; + skip[c] = (uint8)(m - i); + } + for (k = start + m; + k < textlen; + k += ((c = text[k]) >= BMH_CHARSET_SIZE) ? patlen : skip[c]) { + for (i = k, j = m; ; i--, j--) { + if (j < 0) + return i + 1; + if (text[i] != pat[j]) + break; + } + } + return -1; +} + +static JSBool +str_indexOf(JSContext *cx, uintN argc, jsval *vp) +{ + jsval t; + JSString *str, *str2; + const jschar *text, *pat; + jsint i, j, index, textlen, patlen; + jsdouble d; + + t = vp[1]; + if (JSVAL_IS_STRING(t) && argc != 0 && JSVAL_IS_STRING(vp[2])) { + str = JSVAL_TO_STRING(t); + str2 = JSVAL_TO_STRING(vp[2]); + } else { + str = NormalizeThis(cx, vp); + if (!str) + return JS_FALSE; + + str2 = ArgToRootedString(cx, argc, vp, 0); + if (!str2) + return JS_FALSE; + } + + text = JSSTRING_CHARS(str); + textlen = (jsint) JSSTRING_LENGTH(str); + pat = JSSTRING_CHARS(str2); + patlen = (jsint) JSSTRING_LENGTH(str2); + + if (argc > 1) { + d = js_ValueToNumber(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return JS_FALSE; + d = js_DoubleToInteger(d); + if (d < 0) + i = 0; + else if (d > textlen) + i = textlen; + else + i = (jsint)d; + } else { + i = 0; + } + if (patlen == 0) { + *vp = INT_TO_JSVAL(i); + return JS_TRUE; + } + + /* XXX tune the BMH threshold (512) */ + if (textlen - i >= 512 && (jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2) { + index = js_BoyerMooreHorspool(text, textlen, pat, patlen, i); + if (index != BMH_BAD_PATTERN) + goto out; + } + + index = -1; + j = 0; + while (i + j < textlen) { + if (text[i + j] == pat[j]) { + if (++j == patlen) { + index = i; + break; + } + } else { + i++; + j = 0; + } + } + +out: + *vp = INT_TO_JSVAL(index); + return JS_TRUE; +} + +static JSBool +str_lastIndexOf(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str, *str2; + const jschar *text, *pat; + jsint i, j, textlen, patlen; + jsdouble d; + + NORMALIZE_THIS(cx, vp, str); + text = JSSTRING_CHARS(str); + textlen = (jsint) JSSTRING_LENGTH(str); + + str2 = ArgToRootedString(cx, argc, vp, 0); + if (!str2) + return JS_FALSE; + pat = JSSTRING_CHARS(str2); + patlen = (jsint) JSSTRING_LENGTH(str2); + + if (argc > 1) { + d = js_ValueToNumber(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return JS_FALSE; + if (JSDOUBLE_IS_NaN(d)) { + i = textlen; + } else { + d = js_DoubleToInteger(d); + if (d < 0) + i = 0; + else if (d > textlen) + i = textlen; + else + i = (jsint)d; + } + } else { + i = textlen; + } + + if (patlen == 0) { + *vp = INT_TO_JSVAL(i); + return JS_TRUE; + } + + j = 0; + while (i >= 0) { + /* Don't assume that text is NUL-terminated: it could be dependent. */ + if (i + j < textlen && text[i + j] == pat[j]) { + if (++j == patlen) + break; + } else { + i--; + j = 0; + } + } + *vp = INT_TO_JSVAL(i); + return JS_TRUE; +} + +static JSBool +js_TrimString(JSContext *cx, jsval *vp, JSBool trimLeft, JSBool trimRight) +{ + JSString *str; + const jschar *chars; + size_t length, begin, end; + + NORMALIZE_THIS(cx, vp, str); + JSSTRING_CHARS_AND_LENGTH(str, chars, length); + begin = 0; + end = length; + + if (trimLeft) { + while (begin < length && JS_ISSPACE(chars[begin])) + ++begin; + } + + if (trimRight) { + while (end > begin && JS_ISSPACE(chars[end-1])) + --end; + } + + str = js_NewDependentString(cx, str, begin, end - begin); + if (!str) + return JS_FALSE; + + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +str_trim(JSContext *cx, uintN argc, jsval *vp) +{ + return js_TrimString(cx, vp, JS_TRUE, JS_TRUE); +} + +static JSBool +str_trimLeft(JSContext *cx, uintN argc, jsval *vp) +{ + return js_TrimString(cx, vp, JS_TRUE, JS_FALSE); +} + +static JSBool +str_trimRight(JSContext *cx, uintN argc, jsval *vp) +{ + return js_TrimString(cx, vp, JS_FALSE, JS_TRUE); +} + +/* + * Perl-inspired string functions. + */ +typedef struct GlobData { + jsbytecode *pc; /* in: program counter resulting in us matching */ + uintN flags; /* inout: mode and flag bits, see below */ + uintN optarg; /* in: index of optional flags argument */ + JSString *str; /* out: 'this' parameter object as string */ + JSRegExp *regexp; /* out: regexp parameter object private data */ +} GlobData; + +/* + * Mode and flag bit definitions for match_or_replace's GlobData.flags field. + */ +#define MODE_MATCH 0x00 /* in: return match array on success */ +#define MODE_REPLACE 0x01 /* in: match and replace */ +#define MODE_SEARCH 0x02 /* in: search only, return match index or -1 */ +#define GET_MODE(f) ((f) & 0x03) +#define FORCE_FLAT 0x04 /* in: force flat (non-regexp) string match */ +#define KEEP_REGEXP 0x08 /* inout: keep GlobData.regexp alive for caller + of match_or_replace; if set on input + but clear on output, regexp ownership + does not pass to caller */ +#define GLOBAL_REGEXP 0x10 /* out: regexp had the 'g' flag */ + +static JSBool +match_or_replace(JSContext *cx, + JSBool (*glob)(JSContext *cx, jsint count, GlobData *data), + void (*destroy)(JSContext *cx, GlobData *data), + GlobData *data, uintN argc, jsval *vp) +{ + JSString *str, *src, *opt; + JSObject *reobj; + JSRegExp *re; + size_t index, length; + JSBool ok, test; + jsint count; + + NORMALIZE_THIS(cx, vp, str); + data->str = str; + + if (argc != 0 && VALUE_IS_REGEXP(cx, vp[2])) { + reobj = JSVAL_TO_OBJECT(vp[2]); + re = (JSRegExp *) JS_GetPrivate(cx, reobj); + } else { + src = ArgToRootedString(cx, argc, vp, 0); + if (!src) + return JS_FALSE; + if (data->optarg < argc) { + opt = js_ValueToString(cx, vp[2 + data->optarg]); + if (!opt) + return JS_FALSE; + } else { + opt = NULL; + } + re = js_NewRegExpOpt(cx, src, opt, (data->flags & FORCE_FLAT) != 0); + if (!re) + return JS_FALSE; + reobj = NULL; + } + /* From here on, all control flow must reach the matching DROP. */ + data->regexp = re; + HOLD_REGEXP(cx, re); + + if (re->flags & JSREG_GLOB) + data->flags |= GLOBAL_REGEXP; + index = 0; + if (GET_MODE(data->flags) == MODE_SEARCH) { + ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, vp); + if (ok) { + *vp = (*vp == JSVAL_TRUE) + ? INT_TO_JSVAL(cx->regExpStatics.leftContext.length) + : INT_TO_JSVAL(-1); + } + } else if (data->flags & GLOBAL_REGEXP) { + if (reobj) { + /* Set the lastIndex property's reserved slot to 0. */ + ok = js_SetLastIndex(cx, reobj, 0); + } else { + ok = JS_TRUE; + } + if (ok) { + length = JSSTRING_LENGTH(str); + for (count = 0; index <= length; count++) { + ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, vp); + if (!ok || *vp != JSVAL_TRUE) + break; + ok = glob(cx, count, data); + if (!ok) + break; + if (cx->regExpStatics.lastMatch.length == 0) { + if (index == length) + break; + index++; + } + } + if (!ok && destroy) + destroy(cx, data); + } + } else { + if (GET_MODE(data->flags) == MODE_REPLACE) { + test = JS_TRUE; + } else { + /* + * MODE_MATCH implies str_match is being called from a script or a + * scripted function. If the caller cares only about testing null + * vs. non-null return value, optimize away the array object that + * would normally be returned in *vp. + * + * Assume a full array result is required, then prove otherwise. + */ + test = JS_FALSE; + if (data->pc && (*data->pc == JSOP_CALL || *data->pc == JSOP_NEW)) { + JS_ASSERT(js_CodeSpec[*data->pc].length == 3); + switch (data->pc[3]) { + case JSOP_POP: + case JSOP_IFEQ: + case JSOP_IFNE: + case JSOP_IFEQX: + case JSOP_IFNEX: + test = JS_TRUE; + break; + default:; + } + } + } + ok = js_ExecuteRegExp(cx, re, str, &index, test, vp); + } + + DROP_REGEXP(cx, re); + if (reobj) { + /* Tell our caller that it doesn't need to destroy data->regexp. */ + data->flags &= ~KEEP_REGEXP; + } else if (!ok || !(data->flags & KEEP_REGEXP)) { + /* Caller didn't want to keep data->regexp, so null and destroy it. */ + data->regexp = NULL; + js_DestroyRegExp(cx, re); + } + + return ok; +} + +typedef struct MatchData { + GlobData base; + jsval *arrayval; /* NB: local root pointer */ +} MatchData; + +static JSBool +match_glob(JSContext *cx, jsint count, GlobData *data) +{ + MatchData *mdata; + JSObject *arrayobj; + JSSubString *matchsub; + JSString *matchstr; + jsval v; + + mdata = (MatchData *)data; + arrayobj = JSVAL_TO_OBJECT(*mdata->arrayval); + if (!arrayobj) { + arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL); + if (!arrayobj) + return JS_FALSE; + *mdata->arrayval = OBJECT_TO_JSVAL(arrayobj); + } + matchsub = &cx->regExpStatics.lastMatch; + matchstr = js_NewStringCopyN(cx, matchsub->chars, matchsub->length); + if (!matchstr) + return JS_FALSE; + v = STRING_TO_JSVAL(matchstr); + JS_ASSERT(count <= JSVAL_INT_MAX); + + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); + return OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(count), &v); +} + +JSBool +js_StringMatchHelper(JSContext *cx, uintN argc, jsval *vp, jsbytecode *pc) +{ + JSTempValueRooter tvr; + MatchData mdata; + JSBool ok; + + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + mdata.base.pc = pc; + mdata.base.flags = MODE_MATCH; + mdata.base.optarg = 1; + mdata.arrayval = &tvr.u.value; + ok = match_or_replace(cx, match_glob, NULL, &mdata.base, argc, vp); + if (ok && !JSVAL_IS_NULL(*mdata.arrayval)) + *vp = *mdata.arrayval; + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +static JSBool +str_match(JSContext *cx, uintN argc, jsval *vp) +{ + JSStackFrame *fp; + + for (fp = cx->fp; fp && !fp->regs; fp = fp->down) + JS_ASSERT(!fp->script); + return js_StringMatchHelper(cx, argc, vp, fp ? fp->regs->pc : NULL); +} + +#ifdef JS_TRACER +static JSObject* FASTCALL +String_p_match(JSContext* cx, JSString* str, jsbytecode *pc, JSObject* regexp) +{ + jsval vp[3] = { JSVAL_NULL, STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp) }; + if (!js_StringMatchHelper(cx, 1, vp, pc)) + return (JSObject*) JSVAL_TO_BOOLEAN(JSVAL_VOID); + JS_ASSERT(JSVAL_IS_NULL(vp[0]) || + (!JSVAL_IS_PRIMITIVE(vp[0]) && OBJ_IS_ARRAY(cx, JSVAL_TO_OBJECT(vp[0])))); + return JSVAL_TO_OBJECT(vp[0]); +} + +static JSObject* FASTCALL +String_p_match_obj(JSContext* cx, JSObject* str, jsbytecode *pc, JSObject* regexp) +{ + jsval vp[3] = { JSVAL_NULL, OBJECT_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp) }; + if (!js_StringMatchHelper(cx, 1, vp, pc)) + return (JSObject*) JSVAL_TO_BOOLEAN(JSVAL_VOID); + JS_ASSERT(JSVAL_IS_NULL(vp[0]) || + (!JSVAL_IS_PRIMITIVE(vp[0]) && OBJ_IS_ARRAY(cx, JSVAL_TO_OBJECT(vp[0])))); + return JSVAL_TO_OBJECT(vp[0]); +} +#endif + +static JSBool +str_search(JSContext *cx, uintN argc, jsval *vp) +{ + GlobData data; + + data.flags = MODE_SEARCH; + data.optarg = 1; + return match_or_replace(cx, NULL, NULL, &data, argc, vp); +} + +typedef struct ReplaceData { + GlobData base; /* base struct state */ + JSObject *lambda; /* replacement function object or null */ + JSString *repstr; /* replacement string */ + jschar *dollar; /* null or pointer to first $ in repstr */ + jschar *dollarEnd; /* limit pointer for js_strchr_limit */ + jschar *chars; /* result chars, null initially */ + size_t length; /* result length, 0 initially */ + jsint index; /* index in result of next replacement */ + jsint leftIndex; /* left context index in base.str->chars */ + JSSubString dollarStr; /* for "$$" interpret_dollar result */ +} ReplaceData; + +static JSSubString * +interpret_dollar(JSContext *cx, jschar *dp, jschar *ep, ReplaceData *rdata, + size_t *skip) +{ + JSRegExpStatics *res; + jschar dc, *cp; + uintN num, tmp; + + JS_ASSERT(*dp == '$'); + + /* If there is only a dollar, bail now */ + if (dp + 1 >= ep) + return NULL; + + /* Interpret all Perl match-induced dollar variables. */ + res = &cx->regExpStatics; + dc = dp[1]; + if (JS7_ISDEC(dc)) { + /* ECMA-262 Edition 3: 1-9 or 01-99 */ + num = JS7_UNDEC(dc); + if (num > res->parenCount) + return NULL; + + cp = dp + 2; + if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) { + tmp = 10 * num + JS7_UNDEC(dc); + if (tmp <= res->parenCount) { + cp++; + num = tmp; + } + } + if (num == 0) + return NULL; + + /* Adjust num from 1 $n-origin to 0 array-index-origin. */ + num--; + *skip = cp - dp; + return REGEXP_PAREN_SUBSTRING(res, num); + } + + *skip = 2; + switch (dc) { + case '$': + rdata->dollarStr.chars = dp; + rdata->dollarStr.length = 1; + return &rdata->dollarStr; + case '&': + return &res->lastMatch; + case '+': + return &res->lastParen; + case '`': + return &res->leftContext; + case '\'': + return &res->rightContext; + } + return NULL; +} + +static JSBool +find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep) +{ + JSString *repstr; + size_t replen, skip; + jschar *dp, *ep; + JSSubString *sub; + JSObject *lambda; + + lambda = rdata->lambda; + if (lambda) { + uintN argc, i, j, m, n, p; + jsval *invokevp, *sp; + void *mark; + JSBool ok; + + /* + * Save the regExpStatics from the current regexp, since they may be + * clobbered by a RegExp usage in the lambda function. Note that all + * members of JSRegExpStatics are JSSubStrings, so not GC roots, save + * input, which is rooted otherwise via vp[1] in str_replace. + */ + JSRegExpStatics save = cx->regExpStatics; + JSBool freeMoreParens = JS_FALSE; + + /* + * In the lambda case, not only do we find the replacement string's + * length, we compute repstr and return it via rdata for use within + * do_replace. The lambda is called with arguments ($&, $1, $2, ..., + * index, input), i.e., all the properties of a regexp match array. + * For $&, etc., we must create string jsvals from cx->regExpStatics. + * We grab up stack space to keep the newborn strings GC-rooted. + */ + p = rdata->base.regexp->parenCount; + argc = 1 + p + 2; + invokevp = js_AllocStack(cx, 2 + argc, &mark); + if (!invokevp) + return JS_FALSE; + + /* Push lambda and its 'this' parameter. */ + sp = invokevp; + *sp++ = OBJECT_TO_JSVAL(lambda); + *sp++ = OBJECT_TO_JSVAL(OBJ_GET_PARENT(cx, lambda)); + +#define PUSH_REGEXP_STATIC(sub) \ + JS_BEGIN_MACRO \ + JSString *str = js_NewStringCopyN(cx, \ + cx->regExpStatics.sub.chars, \ + cx->regExpStatics.sub.length); \ + if (!str) { \ + ok = JS_FALSE; \ + goto lambda_out; \ + } \ + *sp++ = STRING_TO_JSVAL(str); \ + JS_END_MACRO + + /* Push $&, $1, $2, ... */ + PUSH_REGEXP_STATIC(lastMatch); + i = 0; + m = cx->regExpStatics.parenCount; + n = JS_MIN(m, 9); + for (j = 0; i < n; i++, j++) + PUSH_REGEXP_STATIC(parens[j]); + for (j = 0; i < m; i++, j++) + PUSH_REGEXP_STATIC(moreParens[j]); + + /* + * We need to clear moreParens in the top-of-stack cx->regExpStatics + * to it won't be possibly realloc'ed, leaving the bottom-of-stack + * moreParens pointing to freed memory. + */ + cx->regExpStatics.moreParens = NULL; + freeMoreParens = JS_TRUE; + +#undef PUSH_REGEXP_STATIC + + /* Make sure to push undefined for any unmatched parens. */ + for (; i < p; i++) + *sp++ = JSVAL_VOID; + + /* Push match index and input string. */ + *sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length); + *sp++ = STRING_TO_JSVAL(rdata->base.str); + + ok = js_Invoke(cx, argc, invokevp, 0); + if (ok) { + /* + * NB: we count on the newborn string root to hold any string + * created by this js_ValueToString that would otherwise be GC- + * able, until we use rdata->repstr in do_replace. + */ + repstr = js_ValueToString(cx, *invokevp); + if (!repstr) { + ok = JS_FALSE; + } else { + rdata->repstr = repstr; + *sizep = JSSTRING_LENGTH(repstr); + } + } + + lambda_out: + js_FreeStack(cx, mark); + if (freeMoreParens) + JS_free(cx, cx->regExpStatics.moreParens); + cx->regExpStatics = save; + return ok; + } + + repstr = rdata->repstr; + replen = JSSTRING_LENGTH(repstr); + for (dp = rdata->dollar, ep = rdata->dollarEnd; dp; + dp = js_strchr_limit(dp, '$', ep)) { + sub = interpret_dollar(cx, dp, ep, rdata, &skip); + if (sub) { + replen += sub->length - skip; + dp += skip; + } + else + dp++; + } + *sizep = replen; + return JS_TRUE; +} + +static void +do_replace(JSContext *cx, ReplaceData *rdata, jschar *chars) +{ + JSString *repstr; + jschar *bp, *cp, *dp, *ep; + size_t len, skip; + JSSubString *sub; + + repstr = rdata->repstr; + bp = cp = JSSTRING_CHARS(repstr); + for (dp = rdata->dollar, ep = rdata->dollarEnd; dp; + dp = js_strchr_limit(dp, '$', ep)) { + len = dp - cp; + js_strncpy(chars, cp, len); + chars += len; + cp = dp; + sub = interpret_dollar(cx, dp, ep, rdata, &skip); + if (sub) { + len = sub->length; + js_strncpy(chars, sub->chars, len); + chars += len; + cp += skip; + dp += skip; + } else { + dp++; + } + } + js_strncpy(chars, cp, JSSTRING_LENGTH(repstr) - (cp - bp)); +} + +static void +replace_destroy(JSContext *cx, GlobData *data) +{ + ReplaceData *rdata; + + rdata = (ReplaceData *)data; + JS_free(cx, rdata->chars); + rdata->chars = NULL; +} + +static JSBool +replace_glob(JSContext *cx, jsint count, GlobData *data) +{ + ReplaceData *rdata; + JSString *str; + size_t leftoff, leftlen, replen, growth; + const jschar *left; + jschar *chars; + + rdata = (ReplaceData *)data; + str = data->str; + leftoff = rdata->leftIndex; + left = JSSTRING_CHARS(str) + leftoff; + leftlen = cx->regExpStatics.lastMatch.chars - left; + rdata->leftIndex = cx->regExpStatics.lastMatch.chars - JSSTRING_CHARS(str); + rdata->leftIndex += cx->regExpStatics.lastMatch.length; + if (!find_replen(cx, rdata, &replen)) + return JS_FALSE; + growth = leftlen + replen; + chars = (jschar *) + (rdata->chars + ? JS_realloc(cx, rdata->chars, (rdata->length + growth + 1) + * sizeof(jschar)) + : JS_malloc(cx, (growth + 1) * sizeof(jschar))); + if (!chars) + return JS_FALSE; + rdata->chars = chars; + rdata->length += growth; + chars += rdata->index; + rdata->index += growth; + js_strncpy(chars, left, leftlen); + chars += leftlen; + do_replace(cx, rdata, chars); + return JS_TRUE; +} + +static JSBool +str_replace(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *lambda; + JSString *repstr; + + if (argc >= 2 && JS_TypeOfValue(cx, vp[3]) == JSTYPE_FUNCTION) { + lambda = JSVAL_TO_OBJECT(vp[3]); + repstr = NULL; + } else { + lambda = NULL; + repstr = ArgToRootedString(cx, argc, vp, 1); + if (!repstr) + return JS_FALSE; + } + + return js_StringReplaceHelper(cx, argc, lambda, repstr, vp); +} + +#ifdef JS_TRACER +static JSString* FASTCALL +String_p_replace_str(JSContext* cx, JSString* str, JSObject* regexp, JSString* repstr) +{ + jsval vp[4] = { + JSVAL_NULL, STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp), STRING_TO_JSVAL(repstr) + }; + if (!js_StringReplaceHelper(cx, 2, NULL, repstr, vp)) + return NULL; + JS_ASSERT(JSVAL_IS_STRING(vp[0])); + return JSVAL_TO_STRING(vp[0]); +} + +static JSString* FASTCALL +String_p_replace_str2(JSContext* cx, JSString* str, JSString* patstr, JSString* repstr) +{ + jsval vp[4] = { + JSVAL_NULL, STRING_TO_JSVAL(str), STRING_TO_JSVAL(patstr), STRING_TO_JSVAL(repstr) + }; + if (!js_StringReplaceHelper(cx, 2, NULL, repstr, vp)) + return NULL; + JS_ASSERT(JSVAL_IS_STRING(vp[0])); + return JSVAL_TO_STRING(vp[0]); +} + +static JSString* FASTCALL +String_p_replace_str3(JSContext* cx, JSString* str, JSString* patstr, JSString* repstr, + JSString* flagstr) +{ + jsval vp[5] = { + JSVAL_NULL, STRING_TO_JSVAL(str), STRING_TO_JSVAL(patstr), STRING_TO_JSVAL(repstr), + STRING_TO_JSVAL(flagstr) + }; + if (!js_StringReplaceHelper(cx, 3, NULL, repstr, vp)) + return NULL; + JS_ASSERT(JSVAL_IS_STRING(vp[0])); + return JSVAL_TO_STRING(vp[0]); +} +#endif + +JSBool +js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda, + JSString *repstr, jsval *vp) +{ + ReplaceData rdata; + JSBool ok; + size_t leftlen, rightlen, length; + jschar *chars; + JSString *str; + + /* + * For ECMA Edition 3, the first argument is to be converted to a string + * to match in a "flat" sense (without regular expression metachars having + * special meanings) UNLESS the first arg is a RegExp object. + */ + rdata.base.flags = MODE_REPLACE | KEEP_REGEXP | FORCE_FLAT; + rdata.base.optarg = 2; + + rdata.lambda = lambda; + rdata.repstr = repstr; + if (repstr) { + rdata.dollarEnd = JSSTRING_CHARS(repstr) + JSSTRING_LENGTH(repstr); + rdata.dollar = js_strchr_limit(JSSTRING_CHARS(repstr), '$', + rdata.dollarEnd); + } else { + rdata.dollar = rdata.dollarEnd = NULL; + } + rdata.chars = NULL; + rdata.length = 0; + rdata.index = 0; + rdata.leftIndex = 0; + + ok = match_or_replace(cx, replace_glob, replace_destroy, &rdata.base, + argc, vp); + if (!ok) + return JS_FALSE; + + if (!rdata.chars) { + if ((rdata.base.flags & GLOBAL_REGEXP) || *vp != JSVAL_TRUE) { + /* Didn't match even once. */ + *vp = STRING_TO_JSVAL(rdata.base.str); + goto out; + } + leftlen = cx->regExpStatics.leftContext.length; + ok = find_replen(cx, &rdata, &length); + if (!ok) + goto out; + length += leftlen; + chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar)); + if (!chars) { + ok = JS_FALSE; + goto out; + } + js_strncpy(chars, cx->regExpStatics.leftContext.chars, leftlen); + do_replace(cx, &rdata, chars + leftlen); + rdata.chars = chars; + rdata.length = length; + } + + rightlen = cx->regExpStatics.rightContext.length; + length = rdata.length + rightlen; + chars = (jschar *) + JS_realloc(cx, rdata.chars, (length + 1) * sizeof(jschar)); + if (!chars) { + JS_free(cx, rdata.chars); + ok = JS_FALSE; + goto out; + } + js_strncpy(chars + rdata.length, cx->regExpStatics.rightContext.chars, + rightlen); + chars[length] = 0; + + str = js_NewString(cx, chars, length); + if (!str) { + JS_free(cx, chars); + ok = JS_FALSE; + goto out; + } + *vp = STRING_TO_JSVAL(str); + +out: + /* If KEEP_REGEXP is still set, it's our job to destroy regexp now. */ + if (rdata.base.flags & KEEP_REGEXP) + js_DestroyRegExp(cx, rdata.base.regexp); + return ok; +} + +/* + * Subroutine used by str_split to find the next split point in str, starting + * at offset *ip and looking either for the separator substring given by sep, or + * for the next re match. In the re case, return the matched separator in *sep, + * and the possibly updated offset in *ip. + * + * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next + * separator occurrence if found, or str->length if no separator is found. + */ +static jsint +find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip, + JSSubString *sep) +{ + jsint i, j, k; + size_t length; + jschar *chars; + + /* + * Stop if past end of string. If at end of string, we will compare the + * null char stored there (by js_NewString*) to sep->chars[j] in the while + * loop at the end of this function, so that + * + * "ab,".split(',') => ["ab", ""] + * + * and the resulting array converts back to the string "ab," for symmetry. + * However, we ape Perl and do this only if there is a sufficiently large + * limit argument (see str_split). + */ + i = *ip; + length = JSSTRING_LENGTH(str); + if ((size_t)i > length) + return -1; + + chars = JSSTRING_CHARS(str); + + /* + * Match a regular expression against the separator at or above index i. + * Call js_ExecuteRegExp with true for the test argument. On successful + * match, get the separator from cx->regExpStatics.lastMatch. + */ + if (re) { + size_t index; + jsval rval; + + again: + /* JS1.2 deviated from Perl by never matching at end of string. */ + index = (size_t)i; + if (!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &rval)) + return -2; + if (rval != JSVAL_TRUE) { + /* Mismatch: ensure our caller advances i past end of string. */ + sep->length = 1; + return length; + } + i = (jsint)index; + *sep = cx->regExpStatics.lastMatch; + if (sep->length == 0) { + /* + * Empty string match: never split on an empty match at the start + * of a find_split cycle. Same rule as for an empty global match + * in match_or_replace. + */ + if (i == *ip) { + /* + * "Bump-along" to avoid sticking at an empty match, but don't + * bump past end of string -- our caller must do that by adding + * sep->length to our return value. + */ + if ((size_t)i == length) + return -1; + i++; + goto again; + } + if ((size_t)i == length) { + /* + * If there was a trivial zero-length match at the end of the + * split, then we shouldn't output the matched string at the end + * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15. + */ + sep->chars = NULL; + } + } + JS_ASSERT((size_t)i >= sep->length); + return i - sep->length; + } + + /* + * Special case: if sep is the empty string, split str into one character + * substrings. Let our caller worry about whether to split once at end of + * string into an empty substring. + */ + if (sep->length == 0) + return ((size_t)i == length) ? -1 : i + 1; + + /* + * Now that we know sep is non-empty, search starting at i in str for an + * occurrence of all of sep's chars. If we find them, return the index of + * the first separator char. Otherwise, return length. + */ + j = 0; + while ((size_t)(k = i + j) < length) { + if (chars[k] == sep->chars[j]) { + if ((size_t)++j == sep->length) + return i; + } else { + i++; + j = 0; + } + } + return k; +} + +static JSBool +str_split(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str, *sub; + JSObject *arrayobj; + jsval v; + JSBool ok, limited; + JSRegExp *re; + JSSubString *sep, tmp; + jsdouble d; + jsint i, j; + uint32 len, limit; + + NORMALIZE_THIS(cx, vp, str); + + arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL); + if (!arrayobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(arrayobj); + + if (argc == 0) { + v = STRING_TO_JSVAL(str); + ok = OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(0), &v); + } else { + if (VALUE_IS_REGEXP(cx, vp[2])) { + re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(vp[2])); + sep = &tmp; + + /* Set a magic value so we can detect a successful re match. */ + sep->chars = NULL; + sep->length = 0; + } else { + JSString *str2 = js_ValueToString(cx, vp[2]); + if (!str2) + return JS_FALSE; + vp[2] = STRING_TO_JSVAL(str2); + + /* + * Point sep at a local copy of str2's header because find_split + * will modify sep->length. + */ + JSSTRING_CHARS_AND_LENGTH(str2, tmp.chars, tmp.length); + sep = &tmp; + re = NULL; + } + + /* Use the second argument as the split limit, if given. */ + limited = (argc > 1) && !JSVAL_IS_VOID(vp[3]); + limit = 0; /* Avoid warning. */ + if (limited) { + d = js_ValueToNumber(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return JS_FALSE; + + /* Clamp limit between 0 and 1 + string length. */ + limit = js_DoubleToECMAUint32(d); + if (limit > JSSTRING_LENGTH(str)) + limit = 1 + JSSTRING_LENGTH(str); + } + + len = i = 0; + while ((j = find_split(cx, str, re, &i, sep)) >= 0) { + if (limited && len >= limit) + break; + sub = js_NewDependentString(cx, str, i, (size_t)(j - i)); + if (!sub) + return JS_FALSE; + v = STRING_TO_JSVAL(sub); + if (!JS_SetElement(cx, arrayobj, len, &v)) + return JS_FALSE; + len++; + + /* + * Imitate perl's feature of including parenthesized substrings + * that matched part of the delimiter in the new array, after the + * split substring that was delimited. + */ + if (re && sep->chars) { + uintN num; + JSSubString *parsub; + + for (num = 0; num < cx->regExpStatics.parenCount; num++) { + if (limited && len >= limit) + break; + parsub = REGEXP_PAREN_SUBSTRING(&cx->regExpStatics, num); + sub = js_NewStringCopyN(cx, parsub->chars, parsub->length); + if (!sub) + return JS_FALSE; + v = STRING_TO_JSVAL(sub); + if (!JS_SetElement(cx, arrayobj, len, &v)) + return JS_FALSE; + len++; + } + sep->chars = NULL; + } + i = j + sep->length; + } + ok = (j != -2); + } + return ok; +} + +#ifdef JS_TRACER +static JSObject* FASTCALL +String_p_split(JSContext* cx, JSString* str, JSString* sepstr) +{ + // FIXME: Avoid building and then parsing this array. + jsval vp[4] = { JSVAL_NULL, STRING_TO_JSVAL(str), STRING_TO_JSVAL(sepstr), JSVAL_VOID }; + if (!str_split(cx, 2, vp)) + return NULL; + JS_ASSERT(JSVAL_IS_OBJECT(vp[0])); + return JSVAL_TO_OBJECT(vp[0]); +} +#endif + +#if JS_HAS_PERL_SUBSTR +static JSBool +str_substr(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + jsdouble d; + jsdouble length, begin, end; + + NORMALIZE_THIS(cx, vp, str); + if (argc != 0) { + d = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + length = JSSTRING_LENGTH(str); + begin = js_DoubleToInteger(d); + if (begin < 0) { + begin += length; + if (begin < 0) + begin = 0; + } else if (begin > length) { + begin = length; + } + + if (argc == 1) { + end = length; + } else { + d = js_ValueToNumber(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return JS_FALSE; + end = js_DoubleToInteger(d); + if (end < 0) + end = 0; + end += begin; + if (end > length) + end = length; + } + + str = js_NewDependentString(cx, str, + (size_t)begin, + (size_t)(end - begin)); + if (!str) + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} +#endif /* JS_HAS_PERL_SUBSTR */ + +/* + * Python-esque sequence operations. + */ +static JSBool +str_concat(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str, *str2; + jsval *argv; + uintN i; + + NORMALIZE_THIS(cx, vp, str); + + for (i = 0, argv = vp + 2; i < argc; i++) { + str2 = js_ValueToString(cx, argv[i]); + if (!str2) + return JS_FALSE; + argv[i] = STRING_TO_JSVAL(str2); + + str = js_ConcatStrings(cx, str, str2); + if (!str) + return JS_FALSE; + } + + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +#ifdef JS_TRACER +static JSString* FASTCALL +String_p_concat_1int(JSContext* cx, JSString* str, int32 i) +{ + // FIXME: should be able to use stack buffer and avoid istr... + JSString* istr = js_NumberToString(cx, i); + if (!istr) + return NULL; + return js_ConcatStrings(cx, str, istr); +} + +static JSString* FASTCALL +String_p_concat_2str(JSContext* cx, JSString* str, JSString* a, JSString* b) +{ + str = js_ConcatStrings(cx, str, a); + if (str) + return js_ConcatStrings(cx, str, b); + return NULL; +} + +static JSString* FASTCALL +String_p_concat_3str(JSContext* cx, JSString* str, JSString* a, JSString* b, JSString* c) +{ + str = js_ConcatStrings(cx, str, a); + if (str) { + str = js_ConcatStrings(cx, str, b); + if (str) + return js_ConcatStrings(cx, str, c); + } + return NULL; +} +#endif + +static JSBool +str_slice(JSContext *cx, uintN argc, jsval *vp) +{ + jsval t, v; + JSString *str; + + t = vp[1]; + v = vp[2]; + if (argc == 1 && JSVAL_IS_STRING(t) && JSVAL_IS_INT(v)) { + size_t begin, end, length; + + str = JSVAL_TO_STRING(t); + begin = JSVAL_TO_INT(v); + end = JSSTRING_LENGTH(str); + if (begin <= end) { + length = end - begin; + if (length == 0) { + str = cx->runtime->emptyString; + } else { + str = (length == 1) + ? js_GetUnitString(cx, str, begin) + : js_NewDependentString(cx, str, begin, length); + if (!str) + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; + } + } + + NORMALIZE_THIS(cx, vp, str); + + if (argc != 0) { + double begin, end, length; + + begin = js_ValueToNumber(cx, &vp[2]); + if (JSVAL_IS_NULL(vp[2])) + return JS_FALSE; + begin = js_DoubleToInteger(begin); + length = JSSTRING_LENGTH(str); + if (begin < 0) { + begin += length; + if (begin < 0) + begin = 0; + } else if (begin > length) { + begin = length; + } + + if (argc == 1) { + end = length; + } else { + end = js_ValueToNumber(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return JS_FALSE; + end = js_DoubleToInteger(end); + if (end < 0) { + end += length; + if (end < 0) + end = 0; + } else if (end > length) { + end = length; + } + if (end < begin) + end = begin; + } + + str = js_NewDependentString(cx, str, + (size_t)begin, + (size_t)(end - begin)); + if (!str) + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +#if JS_HAS_STR_HTML_HELPERS +/* + * HTML composition aids. + */ +static JSBool +tagify(JSContext *cx, const char *begin, JSString *param, const char *end, + jsval *vp) +{ + JSString *str; + jschar *tagbuf; + size_t beglen, endlen, parlen, taglen; + size_t i, j; + + NORMALIZE_THIS(cx, vp, str); + + if (!end) + end = begin; + + beglen = strlen(begin); + taglen = 1 + beglen + 1; /* '' */ + parlen = 0; /* Avoid warning. */ + if (param) { + parlen = JSSTRING_LENGTH(param); + taglen += 2 + parlen + 1; /* '="param"' */ + } + endlen = strlen(end); + taglen += JSSTRING_LENGTH(str) + 2 + endlen + 1; /* 'str' */ + + if (taglen >= ~(size_t)0 / sizeof(jschar)) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + + tagbuf = (jschar *) JS_malloc(cx, (taglen + 1) * sizeof(jschar)); + if (!tagbuf) + return JS_FALSE; + + j = 0; + tagbuf[j++] = '<'; + for (i = 0; i < beglen; i++) + tagbuf[j++] = (jschar)begin[i]; + if (param) { + tagbuf[j++] = '='; + tagbuf[j++] = '"'; + js_strncpy(&tagbuf[j], JSSTRING_CHARS(param), parlen); + j += parlen; + tagbuf[j++] = '"'; + } + tagbuf[j++] = '>'; + js_strncpy(&tagbuf[j], JSSTRING_CHARS(str), JSSTRING_LENGTH(str)); + j += JSSTRING_LENGTH(str); + tagbuf[j++] = '<'; + tagbuf[j++] = '/'; + for (i = 0; i < endlen; i++) + tagbuf[j++] = (jschar)end[i]; + tagbuf[j++] = '>'; + JS_ASSERT(j == taglen); + tagbuf[j] = 0; + + str = js_NewString(cx, tagbuf, taglen); + if (!str) { + free((char *)tagbuf); + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +tagify_value(JSContext *cx, uintN argc, jsval *vp, + const char *begin, const char *end) +{ + JSString *param; + + param = ArgToRootedString(cx, argc, vp, 0); + if (!param) + return JS_FALSE; + return tagify(cx, begin, param, end, vp); +} + +static JSBool +str_bold(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify(cx, "b", NULL, NULL, vp); +} + +static JSBool +str_italics(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify(cx, "i", NULL, NULL, vp); +} + +static JSBool +str_fixed(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify(cx, "tt", NULL, NULL, vp); +} + +static JSBool +str_fontsize(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify_value(cx, argc, vp, "font size", "font"); +} + +static JSBool +str_fontcolor(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify_value(cx, argc, vp, "font color", "font"); +} + +static JSBool +str_link(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify_value(cx, argc, vp, "a href", "a"); +} + +static JSBool +str_anchor(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify_value(cx, argc, vp, "a name", "a"); +} + +static JSBool +str_strike(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify(cx, "strike", NULL, NULL, vp); +} + +static JSBool +str_small(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify(cx, "small", NULL, NULL, vp); +} + +static JSBool +str_big(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify(cx, "big", NULL, NULL, vp); +} + +static JSBool +str_blink(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify(cx, "blink", NULL, NULL, vp); +} + +static JSBool +str_sup(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify(cx, "sup", NULL, NULL, vp); +} + +static JSBool +str_sub(JSContext *cx, uintN argc, jsval *vp) +{ + return tagify(cx, "sub", NULL, NULL, vp); +} +#endif /* JS_HAS_STR_HTML_HELPERS */ + +#ifdef JS_TRACER +JSString* FASTCALL +js_String_getelem(JSContext* cx, JSString* str, int32 i) +{ + if ((size_t)i >= JSSTRING_LENGTH(str)) + return NULL; + return js_GetUnitString(cx, str, (size_t)i); +} +#endif + +JS_DEFINE_CALLINFO_2(extern, BOOL, js_EqualStrings, STRING, STRING, 1, 1) +JS_DEFINE_CALLINFO_2(extern, INT32, js_CompareStrings, STRING, STRING, 1, 1) + +JS_DEFINE_TRCINFO_1(str_toString, + (2, (extern, STRING_FAIL, String_p_toString, CONTEXT, THIS, 1, 1))) +JS_DEFINE_TRCINFO_2(str_substring, + (4, (static, STRING_FAIL, String_p_substring, CONTEXT, THIS_STRING, INT32, INT32, 1, 1)), + (3, (static, STRING_FAIL, String_p_substring_1, CONTEXT, THIS_STRING, INT32, 1, 1))) +JS_DEFINE_TRCINFO_1(str_charAt, + (3, (extern, STRING_FAIL, js_String_getelem, CONTEXT, THIS_STRING, INT32, 1, 1))) +JS_DEFINE_TRCINFO_1(str_charCodeAt, + (2, (extern, INT32_FAIL, js_String_p_charCodeAt, THIS_STRING, INT32, 1, 1))) +JS_DEFINE_TRCINFO_4(str_concat, + (3, (static, STRING_FAIL, String_p_concat_1int, CONTEXT, THIS_STRING, INT32, 1, 1)), + (3, (extern, STRING_FAIL, js_ConcatStrings, CONTEXT, THIS_STRING, STRING, 1, 1)), + (4, (static, STRING_FAIL, String_p_concat_2str, CONTEXT, THIS_STRING, STRING, STRING, 1, 1)), + (5, (static, STRING_FAIL, String_p_concat_3str, CONTEXT, THIS_STRING, STRING, STRING, STRING, 1, 1))) +JS_DEFINE_TRCINFO_2(str_match, + (4, (static, OBJECT_FAIL_VOID, String_p_match, CONTEXT, THIS_STRING, PC, REGEXP, 1, 1)), + (4, (static, OBJECT_FAIL_VOID, String_p_match_obj, CONTEXT, THIS, PC, REGEXP, 1, 1))) +JS_DEFINE_TRCINFO_3(str_replace, + (4, (static, STRING_FAIL, String_p_replace_str, CONTEXT, THIS_STRING, REGEXP, STRING, 1, 1)), + (4, (static, STRING_FAIL, String_p_replace_str2, CONTEXT, THIS_STRING, STRING, STRING, 1, 1)), + (5, (static, STRING_FAIL, String_p_replace_str3, CONTEXT, THIS_STRING, STRING, STRING, STRING, 1, 1))) +JS_DEFINE_TRCINFO_1(str_split, + (3, (static, OBJECT_FAIL_NULL, String_p_split, CONTEXT, THIS_STRING, STRING, 0, 0))) +JS_DEFINE_TRCINFO_1(str_toLowerCase, + (2, (extern, STRING_FAIL, js_toLowerCase, CONTEXT, THIS_STRING, 1, 1))) +JS_DEFINE_TRCINFO_1(str_toUpperCase, + (2, (extern, STRING_FAIL, js_toUpperCase, CONTEXT, THIS_STRING, 1, 1))) + +#define GENERIC JSFUN_GENERIC_NATIVE +#define PRIMITIVE JSFUN_THISP_PRIMITIVE +#define GENERIC_PRIMITIVE (GENERIC | PRIMITIVE) + +static JSFunctionSpec string_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN("quote", str_quote, 0,GENERIC_PRIMITIVE), + JS_FN(js_toSource_str, str_toSource, 0,JSFUN_THISP_STRING), +#endif + + /* Java-like methods. */ + JS_TN(js_toString_str, str_toString, 0,JSFUN_THISP_STRING, str_toString_trcinfo), + JS_FN(js_valueOf_str, str_toString, 0,JSFUN_THISP_STRING), + JS_FN(js_toJSON_str, str_toString, 0,JSFUN_THISP_STRING), + JS_TN("substring", str_substring, 2,GENERIC_PRIMITIVE, str_substring_trcinfo), + JS_TN("toLowerCase", str_toLowerCase, 0,GENERIC_PRIMITIVE, str_toLowerCase_trcinfo), + JS_TN("toUpperCase", str_toUpperCase, 0,GENERIC_PRIMITIVE, str_toUpperCase_trcinfo), + JS_TN("charAt", str_charAt, 1,GENERIC_PRIMITIVE, str_charAt_trcinfo), + JS_TN("charCodeAt", str_charCodeAt, 1,GENERIC_PRIMITIVE, str_charCodeAt_trcinfo), + JS_FN("indexOf", str_indexOf, 1,GENERIC_PRIMITIVE), + JS_FN("lastIndexOf", str_lastIndexOf, 1,GENERIC_PRIMITIVE), + JS_FN("trim", str_trim, 0,GENERIC_PRIMITIVE), + JS_FN("trimLeft", str_trimLeft, 0,GENERIC_PRIMITIVE), + JS_FN("trimRight", str_trimRight, 0,GENERIC_PRIMITIVE), + JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,GENERIC_PRIMITIVE), + JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,GENERIC_PRIMITIVE), + JS_FN("localeCompare", str_localeCompare, 1,GENERIC_PRIMITIVE), + + /* Perl-ish methods (search is actually Python-esque). */ + JS_TN("match", str_match, 1,GENERIC_PRIMITIVE, str_match_trcinfo), + JS_FN("search", str_search, 1,GENERIC_PRIMITIVE), + JS_TN("replace", str_replace, 2,GENERIC_PRIMITIVE, str_replace_trcinfo), + JS_TN("split", str_split, 2,GENERIC_PRIMITIVE, str_split_trcinfo), +#if JS_HAS_PERL_SUBSTR + JS_FN("substr", str_substr, 2,GENERIC_PRIMITIVE), +#endif + + /* Python-esque sequence methods. */ + JS_TN("concat", str_concat, 1,GENERIC_PRIMITIVE, str_concat_trcinfo), + JS_FN("slice", str_slice, 2,GENERIC_PRIMITIVE), + + /* HTML string methods. */ +#if JS_HAS_STR_HTML_HELPERS + JS_FN("bold", str_bold, 0,PRIMITIVE), + JS_FN("italics", str_italics, 0,PRIMITIVE), + JS_FN("fixed", str_fixed, 0,PRIMITIVE), + JS_FN("fontsize", str_fontsize, 1,PRIMITIVE), + JS_FN("fontcolor", str_fontcolor, 1,PRIMITIVE), + JS_FN("link", str_link, 1,PRIMITIVE), + JS_FN("anchor", str_anchor, 1,PRIMITIVE), + JS_FN("strike", str_strike, 0,PRIMITIVE), + JS_FN("small", str_small, 0,PRIMITIVE), + JS_FN("big", str_big, 0,PRIMITIVE), + JS_FN("blink", str_blink, 0,PRIMITIVE), + JS_FN("sup", str_sup, 0,PRIMITIVE), + JS_FN("sub", str_sub, 0,PRIMITIVE), +#endif + + JS_FS_END +}; + +static JSBool +String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSString *str; + + if (argc > 0) { + str = js_ValueToString(cx, argv[0]); + if (!str) + return JS_FALSE; + argv[0] = STRING_TO_JSVAL(str); + } else { + str = cx->runtime->emptyString; + } + if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { + *rval = STRING_TO_JSVAL(str); + return JS_TRUE; + } + STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str)); + return JS_TRUE; +} + +static JSBool +str_fromCharCode(JSContext *cx, uintN argc, jsval *vp) +{ + jsval *argv; + uintN i; + uint16 code; + jschar *chars; + JSString *str; + + argv = vp + 2; + JS_ASSERT(argc < ARRAY_INIT_LIMIT); + if (argc == 1 && + (code = js_ValueToUint16(cx, &argv[0])) < UNIT_STRING_LIMIT) { + str = js_GetUnitStringForChar(cx, code); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; + } + chars = (jschar *) JS_malloc(cx, (argc + 1) * sizeof(jschar)); + if (!chars) + return JS_FALSE; + for (i = 0; i < argc; i++) { + code = js_ValueToUint16(cx, &argv[i]); + if (JSVAL_IS_NULL(argv[i])) { + JS_free(cx, chars); + return JS_FALSE; + } + chars[i] = (jschar)code; + } + chars[i] = 0; + str = js_NewString(cx, chars, argc); + if (!str) { + JS_free(cx, chars); + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +#ifdef JS_TRACER +static JSString* FASTCALL +String_fromCharCode(JSContext* cx, int32 i) +{ + JS_ASSERT(JS_ON_TRACE(cx)); + jschar c = (jschar)i; + if (c < UNIT_STRING_LIMIT) + return js_GetUnitStringForChar(cx, c); + return js_NewStringCopyN(cx, &c, 1); +} +#endif + +JS_DEFINE_TRCINFO_1(str_fromCharCode, + (2, (static, STRING_FAIL, String_fromCharCode, CONTEXT, INT32, 1, 1))) + +static JSFunctionSpec string_static_methods[] = { + JS_TN("fromCharCode", str_fromCharCode, 1, 0, str_fromCharCode_trcinfo), + JS_FS_END +}; + +static JSHashNumber +js_hash_string_pointer(const void *key) +{ + return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS; +} + +JSBool +js_InitRuntimeStringState(JSContext *cx) +{ + JSRuntime *rt; + + rt = cx->runtime; + rt->emptyString = ATOM_TO_STRING(rt->atomState.emptyAtom); + return JS_TRUE; +} + +JSBool +js_InitDeflatedStringCache(JSRuntime *rt) +{ + JSHashTable *cache; + + /* Initialize string cache */ + JS_ASSERT(!rt->deflatedStringCache); + cache = JS_NewHashTable(8, js_hash_string_pointer, + JS_CompareValues, JS_CompareValues, + NULL, NULL); + if (!cache) + return JS_FALSE; + rt->deflatedStringCache = cache; + +#ifdef JS_THREADSAFE + JS_ASSERT(!rt->deflatedStringCacheLock); + rt->deflatedStringCacheLock = JS_NEW_LOCK(); + if (!rt->deflatedStringCacheLock) + return JS_FALSE; +#endif + return JS_TRUE; +} + +#define UNIT_STRING_SPACE(sp) ((jschar *) ((sp) + UNIT_STRING_LIMIT)) +#define UNIT_STRING_SPACE_RT(rt) UNIT_STRING_SPACE((rt)->unitStrings) + +#define IN_UNIT_STRING_SPACE(sp,cp) \ + ((size_t)((cp) - UNIT_STRING_SPACE(sp)) < 2 * UNIT_STRING_LIMIT) +#define IN_UNIT_STRING_SPACE_RT(rt,cp) \ + IN_UNIT_STRING_SPACE((rt)->unitStrings, cp) + +JSString * +js_GetUnitStringForChar(JSContext *cx, jschar c) +{ + jschar *cp, i; + JSRuntime *rt; + JSString **sp; + + JS_ASSERT(c < UNIT_STRING_LIMIT); + rt = cx->runtime; + if (!rt->unitStrings) { + sp = (JSString **) calloc(UNIT_STRING_LIMIT * sizeof(JSString *) + + UNIT_STRING_LIMIT * 2 * sizeof(jschar), + 1); + if (!sp) { + JS_ReportOutOfMemory(cx); + return NULL; + } + cp = UNIT_STRING_SPACE(sp); + for (i = 0; i < UNIT_STRING_LIMIT; i++) { + *cp = i; + cp += 2; + } + JS_LOCK_GC(rt); + if (!rt->unitStrings) { + rt->unitStrings = sp; + JS_UNLOCK_GC(rt); + } else { + JS_UNLOCK_GC(rt); + free(sp); + } + } + if (!rt->unitStrings[c]) { + JSString *str; + + cp = UNIT_STRING_SPACE_RT(rt); + str = js_NewString(cx, cp + 2 * c, 1); + if (!str) + return NULL; + JS_LOCK_GC(rt); + if (!rt->unitStrings[c]) + rt->unitStrings[c] = str; + JS_UNLOCK_GC(rt); + } + return rt->unitStrings[c]; +} + +JSString * +js_GetUnitString(JSContext *cx, JSString *str, size_t index) +{ + jschar c; + + JS_ASSERT(index < JSSTRING_LENGTH(str)); + c = JSSTRING_CHARS(str)[index]; + if (c >= UNIT_STRING_LIMIT) + return js_NewDependentString(cx, str, index, 1); + return js_GetUnitStringForChar(cx, c); +} + +void +js_FinishUnitStrings(JSRuntime *rt) +{ + free(rt->unitStrings); + rt->unitStrings = NULL; +} + +void +js_FinishRuntimeStringState(JSContext *cx) +{ + cx->runtime->emptyString = NULL; +} + +void +js_FinishDeflatedStringCache(JSRuntime *rt) +{ + if (rt->deflatedStringCache) { + JS_HashTableDestroy(rt->deflatedStringCache); + rt->deflatedStringCache = NULL; + } +#ifdef JS_THREADSAFE + if (rt->deflatedStringCacheLock) { + JS_DESTROY_LOCK(rt->deflatedStringCacheLock); + rt->deflatedStringCacheLock = NULL; + } +#endif +} + +JSObject * +js_InitStringClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + + /* Define the escape, unescape functions in the global object. */ + if (!JS_DefineFunctions(cx, obj, string_functions)) + return NULL; + + proto = JS_InitClass(cx, obj, NULL, &js_StringClass, String, 1, + string_props, string_methods, + NULL, string_static_methods); + if (!proto) + return NULL; + STOBJ_SET_SLOT(proto, JSSLOT_PRIVATE, + STRING_TO_JSVAL(cx->runtime->emptyString)); + return proto; +} + +JSString * +js_NewString(JSContext *cx, jschar *chars, size_t length) +{ + JSString *str; + + if (length > JSSTRING_LENGTH_MASK) { + js_ReportAllocationOverflow(cx); + return NULL; + } + + str = (JSString *) js_NewGCThing(cx, GCX_STRING, sizeof(JSString)); + if (!str) + return NULL; + JSFLATSTR_INIT(str, chars, length); +#ifdef DEBUG + { + JSRuntime *rt = cx->runtime; + JS_RUNTIME_METER(rt, liveStrings); + JS_RUNTIME_METER(rt, totalStrings); + JS_LOCK_RUNTIME_VOID(rt, + (rt->lengthSum += (double)length, + rt->lengthSquaredSum += (double)length * (double)length)); + } +#endif + return str; +} + +JSString * +js_NewDependentString(JSContext *cx, JSString *base, size_t start, + size_t length) +{ + JSString *ds; + + if (length == 0) + return cx->runtime->emptyString; + + if (start == 0 && length == JSSTRING_LENGTH(base)) + return base; + + if (start > JSSTRDEP_START_MASK || + (start != 0 && length > JSSTRDEP_LENGTH_MASK)) { + return js_NewStringCopyN(cx, JSSTRING_CHARS(base) + start, length); + } + + ds = (JSString *)js_NewGCThing(cx, GCX_STRING, sizeof(JSString)); + if (!ds) + return NULL; + if (start == 0) + JSPREFIX_INIT(ds, base, length); + else + JSSTRDEP_INIT(ds, base, start, length); +#ifdef DEBUG + { + JSRuntime *rt = cx->runtime; + JS_RUNTIME_METER(rt, liveDependentStrings); + JS_RUNTIME_METER(rt, totalDependentStrings); + JS_RUNTIME_METER(rt, liveStrings); + JS_RUNTIME_METER(rt, totalStrings); + JS_LOCK_RUNTIME_VOID(rt, + (rt->strdepLengthSum += (double)length, + rt->strdepLengthSquaredSum += (double)length * (double)length)); + JS_LOCK_RUNTIME_VOID(rt, + (rt->lengthSum += (double)length, + rt->lengthSquaredSum += (double)length * (double)length)); + } +#endif + return ds; +} + +#ifdef DEBUG +#include + +void printJSStringStats(JSRuntime *rt) +{ + double mean, sigma; + + mean = JS_MeanAndStdDev(rt->totalStrings, rt->lengthSum, + rt->lengthSquaredSum, &sigma); + + fprintf(stderr, "%lu total strings, mean length %g (sigma %g)\n", + (unsigned long)rt->totalStrings, mean, sigma); + + mean = JS_MeanAndStdDev(rt->totalDependentStrings, rt->strdepLengthSum, + rt->strdepLengthSquaredSum, &sigma); + + fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n", + (unsigned long)rt->totalDependentStrings, mean, sigma); +} +#endif + +JSString * +js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n) +{ + jschar *news; + JSString *str; + + news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar)); + if (!news) + return NULL; + js_strncpy(news, s, n); + news[n] = 0; + str = js_NewString(cx, news, n); + if (!str) + JS_free(cx, news); + return str; +} + +JSString * +js_NewStringCopyZ(JSContext *cx, const jschar *s) +{ + size_t n, m; + jschar *news; + JSString *str; + + n = js_strlen(s); + m = (n + 1) * sizeof(jschar); + news = (jschar *) JS_malloc(cx, m); + if (!news) + return NULL; + memcpy(news, s, m); + str = js_NewString(cx, news, n); + if (!str) + JS_free(cx, news); + return str; +} + +void +js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str) +{ + JSHashNumber hash; + JSHashEntry *he, **hep; + + hash = js_hash_string_pointer(str); + JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock); + hep = JS_HashTableRawLookup(rt->deflatedStringCache, hash, str); + he = *hep; + if (he) { +#ifdef DEBUG + rt->deflatedStringCacheBytes -= JSSTRING_LENGTH(str); +#endif + free(he->value); + JS_HashTableRawRemove(rt->deflatedStringCache, hep, he); + } + JS_RELEASE_LOCK(rt->deflatedStringCacheLock); +} + +static JSStringFinalizeOp str_finalizers[GCX_NTYPES - GCX_EXTERNAL_STRING] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +intN +js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop, + JSStringFinalizeOp newop) +{ + uintN i; + + for (i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) { + if (str_finalizers[i] == oldop) { + str_finalizers[i] = newop; + return (intN) i; + } + } + return -1; +} + +/* + * cx is NULL when we are called from js_FinishAtomState to force the + * finalization of the permanently interned strings. + */ +void +js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx) +{ + jschar *chars; + JSBool valid; + JSStringFinalizeOp finalizer; + + JS_RUNTIME_UNMETER(rt, liveStrings); + if (JSSTRING_IS_DEPENDENT(str)) { + /* A dependent string can not be external and must be valid. */ + JS_ASSERT(type < 0); + JS_ASSERT(JSSTRDEP_BASE(str)); + JS_RUNTIME_UNMETER(rt, liveDependentStrings); + valid = JS_TRUE; + } else { + /* A stillborn string has null chars, so is not valid. */ + chars = JSFLATSTR_CHARS(str); + valid = (chars != NULL); + if (valid) { + if (IN_UNIT_STRING_SPACE_RT(rt, chars)) { + JS_ASSERT(rt->unitStrings[*chars] == str); + JS_ASSERT(type < 0); + rt->unitStrings[*chars] = NULL; + } else if (type < 0) { + free(chars); + } else { + JS_ASSERT((uintN) type < JS_ARRAY_LENGTH(str_finalizers)); + finalizer = str_finalizers[type]; + if (finalizer) { + /* + * Assume that the finalizer for the permanently interned + * string knows how to deal with null context. + */ + finalizer(cx, str); + } + } + } + } + if (valid) + js_PurgeDeflatedStringCache(rt, str); +} + +JS_FRIEND_API(const char *) +js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun) +{ + JSString *str; + + str = v2sfun(cx, v); + if (!str) + return NULL; + str = js_QuoteString(cx, str, 0); + if (!str) + return NULL; + return js_GetStringBytes(cx, str); +} + +JS_FRIEND_API(JSString *) +js_ValueToString(JSContext *cx, jsval v) +{ + JSObject *obj; + JSString *str; + + if (JSVAL_IS_OBJECT(v)) { + obj = JSVAL_TO_OBJECT(v); + if (!obj) + return ATOM_TO_STRING(cx->runtime->atomState.nullAtom); + if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v)) + return NULL; + } + if (JSVAL_IS_STRING(v)) { + str = JSVAL_TO_STRING(v); + } else if (JSVAL_IS_INT(v)) { + str = js_NumberToString(cx, JSVAL_TO_INT(v)); + } else if (JSVAL_IS_DOUBLE(v)) { + str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(v)); + } else if (JSVAL_IS_BOOLEAN(v)) { + str = js_BooleanToString(cx, JSVAL_TO_BOOLEAN(v)); + } else { + str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } + return str; +} + +JS_FRIEND_API(JSString *) +js_ValueToSource(JSContext *cx, jsval v) +{ + JSTempValueRooter tvr; + JSString *str; + + if (JSVAL_IS_VOID(v)) + return ATOM_TO_STRING(cx->runtime->atomState.void0Atom); + if (JSVAL_IS_STRING(v)) + return js_QuoteString(cx, JSVAL_TO_STRING(v), '"'); + if (JSVAL_IS_PRIMITIVE(v)) { + /* Special case to preserve negative zero, _contra_ toString. */ + if (JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) { + /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */ + static const jschar js_negzero_ucNstr[] = {'-', '0'}; + + return js_NewStringCopyN(cx, js_negzero_ucNstr, 2); + } + return js_ValueToString(cx, v); + } + + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v), + cx->runtime->atomState.toSourceAtom, + 0, NULL, &tvr.u.value)) { + str = NULL; + } else { + str = js_ValueToString(cx, tvr.u.value); + } + JS_POP_TEMP_ROOT(cx, &tvr); + return str; +} + +/* + * str is not necessarily a GC thing here. + */ +uint32 +js_HashString(JSString *str) +{ + const jschar *s; + size_t n; + uint32 h; + + JSSTRING_CHARS_AND_LENGTH(str, s, n); + for (h = 0; n; s++, n--) + h = JS_ROTATE_LEFT32(h, 4) ^ *s; + return h; +} + +/* + * str is not necessarily a GC thing here. + */ +JSBool JS_FASTCALL +js_EqualStrings(JSString *str1, JSString *str2) +{ + size_t n; + const jschar *s1, *s2; + + JS_ASSERT(str1); + JS_ASSERT(str2); + + /* Fast case: pointer equality could be a quick win. */ + if (str1 == str2) + return JS_TRUE; + + n = JSSTRING_LENGTH(str1); + if (n != JSSTRING_LENGTH(str2)) + return JS_FALSE; + + if (n == 0) + return JS_TRUE; + + s1 = JSSTRING_CHARS(str1), s2 = JSSTRING_CHARS(str2); + do { + if (*s1 != *s2) + return JS_FALSE; + ++s1, ++s2; + } while (--n != 0); + + return JS_TRUE; +} + +int32 JS_FASTCALL +js_CompareStrings(JSString *str1, JSString *str2) +{ + size_t l1, l2, n, i; + const jschar *s1, *s2; + intN cmp; + + JS_ASSERT(str1); + JS_ASSERT(str2); + + /* Fast case: pointer equality could be a quick win. */ + if (str1 == str2) + return 0; + + JSSTRING_CHARS_AND_LENGTH(str1, s1, l1); + JSSTRING_CHARS_AND_LENGTH(str2, s2, l2); + n = JS_MIN(l1, l2); + for (i = 0; i < n; i++) { + cmp = s1[i] - s2[i]; + if (cmp != 0) + return cmp; + } + return (intN)(l1 - l2); +} + +size_t +js_strlen(const jschar *s) +{ + const jschar *t; + + for (t = s; *t != 0; t++) + continue; + return (size_t)(t - s); +} + +jschar * +js_strchr(const jschar *s, jschar c) +{ + while (*s != 0) { + if (*s == c) + return (jschar *)s; + s++; + } + return NULL; +} + +jschar * +js_strchr_limit(const jschar *s, jschar c, const jschar *limit) +{ + while (s < limit) { + if (*s == c) + return (jschar *)s; + s++; + } + return NULL; +} + +const jschar * +js_SkipWhiteSpace(const jschar *s, const jschar *end) +{ + JS_ASSERT(s <= end); + while (s != end && JS_ISSPACE(*s)) + s++; + return s; +} + +jschar * +js_InflateString(JSContext *cx, const char *bytes, size_t *lengthp) +{ + size_t nbytes, nchars, i; + jschar *chars; +#ifdef DEBUG + JSBool ok; +#endif + + nbytes = *lengthp; + if (js_CStringsAreUTF8) { + if (!js_InflateStringToBuffer(cx, bytes, nbytes, NULL, &nchars)) + goto bad; + chars = (jschar *) JS_malloc(cx, (nchars + 1) * sizeof (jschar)); + if (!chars) + goto bad; +#ifdef DEBUG + ok = +#endif + js_InflateStringToBuffer(cx, bytes, nbytes, chars, &nchars); + JS_ASSERT(ok); + } else { + nchars = nbytes; + chars = (jschar *) JS_malloc(cx, (nchars + 1) * sizeof(jschar)); + if (!chars) + goto bad; + for (i = 0; i < nchars; i++) + chars[i] = (unsigned char) bytes[i]; + } + *lengthp = nchars; + chars[nchars] = 0; + return chars; + + bad: + /* + * For compatibility with callers of JS_DecodeBytes we must zero lengthp + * on errors. + */ + *lengthp = 0; + return NULL; +} + +/* + * May be called with null cx by js_GetStringBytes, see below. + */ +char * +js_DeflateString(JSContext *cx, const jschar *chars, size_t nchars) +{ + size_t nbytes, i; + char *bytes; +#ifdef DEBUG + JSBool ok; +#endif + + if (js_CStringsAreUTF8) { + nbytes = js_GetDeflatedStringLength(cx, chars, nchars); + if (nbytes == (size_t) -1) + return NULL; + bytes = (char *) (cx ? JS_malloc(cx, nbytes + 1) : malloc(nbytes + 1)); + if (!bytes) + return NULL; +#ifdef DEBUG + ok = +#endif + js_DeflateStringToBuffer(cx, chars, nchars, bytes, &nbytes); + JS_ASSERT(ok); + } else { + nbytes = nchars; + bytes = (char *) (cx ? JS_malloc(cx, nbytes + 1) : malloc(nbytes + 1)); + if (!bytes) + return NULL; + for (i = 0; i < nbytes; i++) + bytes[i] = (char) chars[i]; + } + bytes[nbytes] = 0; + return bytes; +} + +/* + * May be called with null cx through js_GetStringBytes, see below. + */ +size_t +js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars) +{ + size_t nbytes; + const jschar *end; + uintN c, c2; + char buffer[10]; + + if (!js_CStringsAreUTF8) + return nchars; + + nbytes = nchars; + for (end = chars + nchars; chars != end; chars++) { + c = *chars; + if (c < 0x80) + continue; + if (0xD800 <= c && c <= 0xDFFF) { + /* Surrogate pair. */ + chars++; + if (c >= 0xDC00 || chars == end) + goto bad_surrogate; + c2 = *chars; + if (c2 < 0xDC00 || c2 > 0xDFFF) + goto bad_surrogate; + c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000; + } + c >>= 11; + nbytes++; + while (c) { + c >>= 5; + nbytes++; + } + } + return nbytes; + + bad_surrogate: + if (cx) { + JS_snprintf(buffer, 10, "0x%x", c); + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, + NULL, JSMSG_BAD_SURROGATE_CHAR, buffer); + } + return (size_t) -1; +} + +JSBool +js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen, + char *dst, size_t *dstlenp) +{ + size_t dstlen, i, origDstlen, utf8Len; + jschar c, c2; + uint32 v; + uint8 utf8buf[6]; + + dstlen = *dstlenp; + if (!js_CStringsAreUTF8) { + if (srclen > dstlen) { + for (i = 0; i < dstlen; i++) + dst[i] = (char) src[i]; + if (cx) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BUFFER_TOO_SMALL); + } + return JS_FALSE; + } + for (i = 0; i < srclen; i++) + dst[i] = (char) src[i]; + *dstlenp = srclen; + return JS_TRUE; + } + + origDstlen = dstlen; + while (srclen) { + c = *src++; + srclen--; + if ((c >= 0xDC00) && (c <= 0xDFFF)) + goto badSurrogate; + if (c < 0xD800 || c > 0xDBFF) { + v = c; + } else { + if (srclen < 1) + goto badSurrogate; + c2 = *src; + if ((c2 < 0xDC00) || (c2 > 0xDFFF)) + goto badSurrogate; + src++; + srclen--; + v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000; + } + if (v < 0x0080) { + /* no encoding necessary - performance hack */ + if (dstlen == 0) + goto bufferTooSmall; + *dst++ = (char) v; + utf8Len = 1; + } else { + utf8Len = js_OneUcs4ToUtf8Char(utf8buf, v); + if (utf8Len > dstlen) + goto bufferTooSmall; + for (i = 0; i < utf8Len; i++) + *dst++ = (char) utf8buf[i]; + } + dstlen -= utf8Len; + } + *dstlenp = (origDstlen - dstlen); + return JS_TRUE; + +badSurrogate: + *dstlenp = (origDstlen - dstlen); + /* Delegate error reporting to the measurement function. */ + if (cx) + js_GetDeflatedStringLength(cx, src - 1, srclen + 1); + return JS_FALSE; + +bufferTooSmall: + *dstlenp = (origDstlen - dstlen); + if (cx) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BUFFER_TOO_SMALL); + } + return JS_FALSE; +} + +JSBool +js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen, + jschar *dst, size_t *dstlenp) +{ + size_t dstlen, i, origDstlen, offset, j, n; + uint32 v; + + if (!js_CStringsAreUTF8) { + if (dst) { + dstlen = *dstlenp; + if (srclen > dstlen) { + for (i = 0; i < dstlen; i++) + dst[i] = (unsigned char) src[i]; + if (cx) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BUFFER_TOO_SMALL); + } + return JS_FALSE; + } + for (i = 0; i < srclen; i++) + dst[i] = (unsigned char) src[i]; + } + *dstlenp = srclen; + return JS_TRUE; + } + + dstlen = dst ? *dstlenp : (size_t) -1; + origDstlen = dstlen; + offset = 0; + + while (srclen) { + v = (uint8) *src; + n = 1; + if (v & 0x80) { + while (v & (0x80 >> n)) + n++; + if (n > srclen) + goto bufferTooSmall; + if (n == 1 || n > 6) + goto badCharacter; + for (j = 1; j < n; j++) { + if ((src[j] & 0xC0) != 0x80) + goto badCharacter; + } + v = Utf8ToOneUcs4Char((uint8 *)src, n); + if (v >= 0x10000) { + v -= 0x10000; + if (v > 0xFFFFF || dstlen < 2) { + *dstlenp = (origDstlen - dstlen); + if (cx) { + char buffer[10]; + JS_snprintf(buffer, 10, "0x%x", v + 0x10000); + JS_ReportErrorFlagsAndNumber(cx, + JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_UTF8_CHAR_TOO_LARGE, + buffer); + } + return JS_FALSE; + } + if (dstlen < 2) + goto bufferTooSmall; + if (dst) { + *dst++ = (jschar)((v >> 10) + 0xD800); + v = (jschar)((v & 0x3FF) + 0xDC00); + } + dstlen--; + } + } + if (!dstlen) + goto bufferTooSmall; + if (dst) + *dst++ = (jschar) v; + dstlen--; + offset += n; + src += n; + srclen -= n; + } + *dstlenp = (origDstlen - dstlen); + return JS_TRUE; + +badCharacter: + *dstlenp = (origDstlen - dstlen); + if (cx) { + char buffer[10]; + JS_snprintf(buffer, 10, "%d", offset); + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_MALFORMED_UTF8_CHAR, + buffer); + } + return JS_FALSE; + +bufferTooSmall: + *dstlenp = (origDstlen - dstlen); + if (cx) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BUFFER_TOO_SMALL); + } + return JS_FALSE; +} + +JSBool +js_SetStringBytes(JSContext *cx, JSString *str, char *bytes, size_t length) +{ + JSRuntime *rt; + JSHashTable *cache; + JSBool ok; + JSHashNumber hash; + JSHashEntry **hep; + + rt = cx->runtime; + JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock); + + cache = rt->deflatedStringCache; + hash = js_hash_string_pointer(str); + hep = JS_HashTableRawLookup(cache, hash, str); + JS_ASSERT(*hep == NULL); + ok = JS_HashTableRawAdd(cache, hep, hash, str, bytes) != NULL; +#ifdef DEBUG + if (ok) + rt->deflatedStringCacheBytes += length; +#endif + + JS_RELEASE_LOCK(rt->deflatedStringCacheLock); + return ok; +} + +const char * +js_GetStringBytes(JSContext *cx, JSString *str) +{ + JSRuntime *rt; + JSHashTable *cache; + char *bytes; + JSHashNumber hash; + JSHashEntry *he, **hep; + + if (cx) { + rt = cx->runtime; + } else { + /* JS_GetStringBytes calls us with null cx. */ + rt = js_GetGCStringRuntime(str); + } + +#ifdef JS_THREADSAFE + if (!rt->deflatedStringCacheLock) { + /* + * Called from last GC (see js_DestroyContext), after runtime string + * state has been finalized. We have no choice but to leak here. + */ + return js_DeflateString(NULL, JSSTRING_CHARS(str), + JSSTRING_LENGTH(str)); + } +#endif + + JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock); + + cache = rt->deflatedStringCache; + hash = js_hash_string_pointer(str); + hep = JS_HashTableRawLookup(cache, hash, str); + he = *hep; + if (he) { + bytes = (char *) he->value; + + /* Try to catch failure to JS_ShutDown between runtime epochs. */ + if (!js_CStringsAreUTF8) { + JS_ASSERT_IF(*bytes != (char) JSSTRING_CHARS(str)[0], + *bytes == '\0' && JSSTRING_LENGTH(str) == 0); + } + } else { + bytes = js_DeflateString(cx, JSSTRING_CHARS(str), + JSSTRING_LENGTH(str)); + if (bytes) { + if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) { +#ifdef DEBUG + rt->deflatedStringCacheBytes += JSSTRING_LENGTH(str); +#endif + } else { + if (cx) + JS_free(cx, bytes); + else + free(bytes); + bytes = NULL; + } + } + } + + JS_RELEASE_LOCK(rt->deflatedStringCacheLock); + return bytes; +} + +/* + * From java.lang.Character.java: + * + * The character properties are currently encoded into 32 bits in the + * following manner: + * + * 10 bits signed offset used for converting case + * 1 bit if 1, adding the signed offset converts the character to + * lowercase + * 1 bit if 1, subtracting the signed offset converts the character to + * uppercase + * 1 bit if 1, character has a titlecase equivalent (possibly itself) + * 3 bits 0 may not be part of an identifier + * 1 ignorable control; may continue a Unicode identifier or JS + * identifier + * 2 may continue a JS identifier but not a Unicode identifier + * (unused) + * 3 may continue a Unicode identifier or JS identifier + * 4 is a JS whitespace character + * 5 may start or continue a JS identifier; + * may continue but not start a Unicode identifier (_) + * 6 may start or continue a JS identifier but not a Unicode + * identifier ($) + * 7 may start or continue a Unicode identifier or JS identifier + * Thus: + * 5, 6, 7 may start a JS identifier + * 1, 2, 3, 5, 6, 7 may continue a JS identifier + * 7 may start a Unicode identifier + * 1, 3, 5, 7 may continue a Unicode identifier + * 1 is ignorable within an identifier + * 4 is JS whitespace + * 2 bits 0 this character has no numeric property + * 1 adding the digit offset to the character code and then + * masking with 0x1F will produce the desired numeric value + * 2 this character has a "strange" numeric value + * 3 a JS supradecimal digit: adding the digit offset to the + * character code, then masking with 0x1F, then adding 10 + * will produce the desired numeric value + * 5 bits digit offset + * 1 bit XML 1.0 name start character + * 1 bit XML 1.0 name character + * 2 bits reserved for future use + * 5 bits character type + */ + +/* The X table has 1024 entries for a total of 1024 bytes. */ + +const uint8 js_X[] = { + 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000 */ + 8, 9, 10, 11, 12, 13, 14, 15, /* 0x0200 */ + 16, 17, 18, 19, 20, 21, 22, 23, /* 0x0400 */ + 24, 25, 26, 27, 28, 28, 28, 28, /* 0x0600 */ + 28, 28, 28, 28, 29, 30, 31, 32, /* 0x0800 */ + 33, 34, 35, 36, 37, 38, 39, 40, /* 0x0A00 */ + 41, 42, 43, 44, 45, 46, 28, 28, /* 0x0C00 */ + 47, 48, 49, 50, 51, 52, 53, 28, /* 0x0E00 */ + 28, 28, 54, 55, 56, 57, 58, 59, /* 0x1000 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1200 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1400 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1600 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1800 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1A00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1C00 */ + 60, 60, 61, 62, 63, 64, 65, 66, /* 0x1E00 */ + 67, 68, 69, 70, 71, 72, 73, 74, /* 0x2000 */ + 75, 75, 75, 76, 77, 78, 28, 28, /* 0x2200 */ + 79, 80, 81, 82, 83, 83, 84, 85, /* 0x2400 */ + 86, 85, 28, 28, 87, 88, 89, 28, /* 0x2600 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2800 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2A00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2C00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2E00 */ + 90, 91, 92, 93, 94, 56, 95, 28, /* 0x3000 */ + 96, 97, 98, 99, 83, 100, 83, 101, /* 0x3200 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3400 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3600 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3800 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3A00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3C00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3E00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4000 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4200 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4400 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4600 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4800 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4A00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4C00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x4E00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5A00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5C00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5E00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6A00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6C00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6E00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7A00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7C00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7E00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8A00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8C00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8E00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9A00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9C00 */ + 56, 56, 56, 56, 56, 56, 102, 28, /* 0x9E00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA000 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA200 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA400 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA600 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA800 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xAA00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAC00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAE00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBA00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBC00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBE00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCA00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCC00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCE00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD400 */ + 56, 56, 56, 56, 56, 56, 103, 28, /* 0xD600 */ +104, 104, 104, 104, 104, 104, 104, 104, /* 0xD800 */ +104, 104, 104, 104, 104, 104, 104, 104, /* 0xDA00 */ +104, 104, 104, 104, 104, 104, 104, 104, /* 0xDC00 */ +104, 104, 104, 104, 104, 104, 104, 104, /* 0xDE00 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xE000 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xE200 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xE400 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xE600 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xE800 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xEA00 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xEC00 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xEE00 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xF000 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xF200 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xF400 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xF600 */ +105, 105, 105, 105, 56, 56, 56, 56, /* 0xF800 */ +106, 28, 28, 28, 107, 108, 109, 110, /* 0xFA00 */ + 56, 56, 56, 56, 111, 112, 113, 114, /* 0xFC00 */ +115, 116, 56, 117, 118, 119, 120, 121 /* 0xFE00 */ +}; + +/* The Y table has 7808 entries for a total of 7808 bytes. */ + +const uint8 js_Y[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 0, 1, 1, 1, 1, 1, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 2, 3, 3, 3, 4, 3, 3, 3, /* 0 */ + 5, 6, 3, 7, 3, 8, 3, 3, /* 0 */ + 9, 9, 9, 9, 9, 9, 9, 9, /* 0 */ + 9, 9, 3, 3, 7, 7, 7, 3, /* 0 */ + 3, 10, 10, 10, 10, 10, 10, 10, /* 1 */ + 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */ + 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */ + 10, 10, 10, 5, 3, 6, 11, 12, /* 1 */ + 11, 13, 13, 13, 13, 13, 13, 13, /* 1 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */ + 13, 13, 13, 5, 7, 6, 7, 0, /* 1 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 2, 3, 4, 4, 4, 4, 15, 15, /* 2 */ + 11, 15, 16, 5, 7, 8, 15, 11, /* 2 */ + 15, 7, 17, 17, 11, 16, 15, 3, /* 2 */ + 11, 18, 16, 6, 19, 19, 19, 3, /* 2 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */ + 20, 20, 20, 20, 20, 20, 20, 7, /* 3 */ + 20, 20, 20, 20, 20, 20, 20, 16, /* 3 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */ + 21, 21, 21, 21, 21, 21, 21, 7, /* 3 */ + 21, 21, 21, 21, 21, 21, 21, 22, /* 3 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 25, 26, 23, 24, 23, 24, 23, 24, /* 4 */ + 16, 23, 24, 23, 24, 23, 24, 23, /* 4 */ + 24, 23, 24, 23, 24, 23, 24, 23, /* 5 */ + 24, 16, 23, 24, 23, 24, 23, 24, /* 5 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */ + 27, 23, 24, 23, 24, 23, 24, 28, /* 5 */ + 16, 29, 23, 24, 23, 24, 30, 23, /* 6 */ + 24, 31, 31, 23, 24, 16, 32, 32, /* 6 */ + 33, 23, 24, 31, 34, 16, 35, 36, /* 6 */ + 23, 24, 16, 16, 35, 37, 16, 38, /* 6 */ + 23, 24, 23, 24, 23, 24, 38, 23, /* 6 */ + 24, 39, 40, 16, 23, 24, 39, 23, /* 6 */ + 24, 41, 41, 23, 24, 23, 24, 42, /* 6 */ + 23, 24, 16, 40, 23, 24, 40, 40, /* 6 */ + 40, 40, 40, 40, 43, 44, 45, 43, /* 7 */ + 44, 45, 43, 44, 45, 23, 24, 23, /* 7 */ + 24, 23, 24, 23, 24, 23, 24, 23, /* 7 */ + 24, 23, 24, 23, 24, 16, 23, 24, /* 7 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */ + 16, 43, 44, 45, 23, 24, 46, 46, /* 7 */ + 46, 46, 23, 24, 23, 24, 23, 24, /* 7 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */ + 16, 16, 16, 47, 48, 16, 49, 49, /* 9 */ + 50, 50, 16, 51, 16, 16, 16, 16, /* 9 */ + 49, 16, 16, 52, 16, 16, 16, 16, /* 9 */ + 53, 54, 16, 16, 16, 16, 16, 54, /* 9 */ + 16, 16, 55, 16, 16, 16, 16, 16, /* 9 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 9 */ + 16, 16, 16, 56, 16, 16, 16, 16, /* 10 */ + 56, 16, 57, 57, 16, 16, 16, 16, /* 10 */ + 16, 16, 58, 16, 16, 16, 16, 16, /* 10 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */ + 16, 46, 46, 46, 46, 46, 46, 46, /* 10 */ + 59, 59, 59, 59, 59, 59, 59, 59, /* 10 */ + 59, 11, 11, 59, 59, 59, 59, 59, /* 10 */ + 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */ + 11, 11, 11, 11, 11, 11, 11, 11, /* 11 */ + 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */ + 11, 11, 11, 11, 11, 11, 11, 46, /* 11 */ + 59, 59, 59, 59, 59, 11, 11, 11, /* 11 */ + 11, 11, 46, 46, 46, 46, 46, 46, /* 11 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 46, 46, /* 13 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */ + 60, 60, 46, 46, 46, 46, 46, 46, /* 13 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */ + 46, 46, 46, 46, 3, 3, 46, 46, /* 13 */ + 46, 46, 59, 46, 46, 46, 3, 46, /* 13 */ + 46, 46, 46, 46, 11, 11, 61, 3, /* 14 */ + 62, 62, 62, 46, 63, 46, 64, 64, /* 14 */ + 16, 20, 20, 20, 20, 20, 20, 20, /* 14 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 14 */ + 20, 20, 46, 20, 20, 20, 20, 20, /* 14 */ + 20, 20, 20, 20, 65, 66, 66, 66, /* 14 */ + 16, 21, 21, 21, 21, 21, 21, 21, /* 14 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 14 */ + 21, 21, 16, 21, 21, 21, 21, 21, /* 15 */ + 21, 21, 21, 21, 67, 68, 68, 46, /* 15 */ + 69, 70, 38, 38, 38, 71, 72, 46, /* 15 */ + 46, 46, 38, 46, 38, 46, 38, 46, /* 15 */ + 38, 46, 23, 24, 23, 24, 23, 24, /* 15 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 15 */ + 73, 74, 16, 40, 46, 46, 46, 46, /* 15 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 15 */ + 46, 75, 75, 75, 75, 75, 75, 75, /* 16 */ + 75, 75, 75, 75, 75, 46, 75, 75, /* 16 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */ + 46, 74, 74, 74, 74, 74, 74, 74, /* 17 */ + 74, 74, 74, 74, 74, 46, 74, 74, /* 17 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */ + 23, 24, 15, 60, 60, 60, 60, 46, /* 18 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 40, 23, 24, 23, 24, 46, 46, 23, /* 19 */ + 24, 46, 46, 23, 24, 46, 46, 46, /* 19 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */ + 23, 24, 23, 24, 46, 46, 23, 24, /* 19 */ + 23, 24, 23, 24, 23, 24, 46, 46, /* 19 */ + 23, 24, 46, 46, 46, 46, 46, 46, /* 19 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 76, 76, 76, 76, 76, 76, 76, /* 20 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 20 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */ + 76, 76, 76, 76, 76, 76, 76, 46, /* 21 */ + 46, 59, 3, 3, 3, 3, 3, 3, /* 21 */ + 46, 77, 77, 77, 77, 77, 77, 77, /* 21 */ + 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */ + 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */ + 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */ + 77, 77, 77, 77, 77, 77, 77, 16, /* 22 */ + 46, 3, 46, 46, 46, 46, 46, 46, /* 22 */ + 46, 60, 60, 60, 60, 60, 60, 60, /* 22 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */ + 60, 60, 46, 60, 60, 60, 60, 60, /* 22 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */ + 60, 60, 46, 60, 60, 60, 3, 60, /* 22 */ + 3, 60, 60, 3, 60, 46, 46, 46, /* 23 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */ + 40, 40, 40, 46, 46, 46, 46, 46, /* 23 */ + 40, 40, 40, 3, 3, 46, 46, 46, /* 23 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */ + 46, 46, 46, 46, 3, 46, 46, 46, /* 24 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */ + 46, 46, 46, 3, 46, 46, 46, 3, /* 24 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 24 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */ + 40, 40, 40, 46, 46, 46, 46, 46, /* 24 */ + 59, 40, 40, 40, 40, 40, 40, 40, /* 25 */ + 40, 40, 40, 60, 60, 60, 60, 60, /* 25 */ + 60, 60, 60, 46, 46, 46, 46, 46, /* 25 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 25 */ + 78, 78, 78, 78, 78, 78, 78, 78, /* 25 */ + 78, 78, 3, 3, 3, 3, 46, 46, /* 25 */ + 60, 40, 40, 40, 40, 40, 40, 40, /* 25 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 25 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 46, 46, 40, 40, 40, 40, 40, 46, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 27 */ + 40, 40, 40, 40, 40, 40, 40, 46, /* 27 */ + 40, 40, 40, 40, 3, 40, 60, 60, /* 27 */ + 60, 60, 60, 60, 60, 79, 79, 60, /* 27 */ + 60, 60, 60, 60, 60, 59, 59, 60, /* 27 */ + 60, 15, 60, 60, 60, 60, 46, 46, /* 27 */ + 9, 9, 9, 9, 9, 9, 9, 9, /* 27 */ + 9, 9, 46, 46, 46, 46, 46, 46, /* 27 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 60, 60, 80, 46, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 46, 46, 60, 40, 80, 80, /* 29 */ + 80, 60, 60, 60, 60, 60, 60, 60, /* 30 */ + 60, 80, 80, 80, 80, 60, 46, 46, /* 30 */ + 15, 60, 60, 60, 60, 46, 46, 46, /* 30 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 30 */ + 40, 40, 60, 60, 3, 3, 81, 81, /* 30 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 30 */ + 3, 46, 46, 46, 46, 46, 46, 46, /* 30 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 30 */ + 46, 60, 80, 80, 46, 40, 40, 40, /* 31 */ + 40, 40, 40, 40, 40, 46, 46, 40, /* 31 */ + 40, 46, 46, 40, 40, 40, 40, 40, /* 31 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 31 */ + 40, 46, 40, 46, 46, 46, 40, 40, /* 31 */ + 40, 40, 46, 46, 60, 46, 80, 80, /* 31 */ + 80, 60, 60, 60, 60, 46, 46, 80, /* 32 */ + 80, 46, 46, 80, 80, 60, 46, 46, /* 32 */ + 46, 46, 46, 46, 46, 46, 46, 80, /* 32 */ + 46, 46, 46, 46, 40, 40, 46, 40, /* 32 */ + 40, 40, 60, 60, 46, 46, 81, 81, /* 32 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 32 */ + 40, 40, 4, 4, 82, 82, 82, 82, /* 32 */ + 19, 83, 15, 46, 46, 46, 46, 46, /* 32 */ + 46, 46, 60, 46, 46, 40, 40, 40, /* 33 */ + 40, 40, 40, 46, 46, 46, 46, 40, /* 33 */ + 40, 46, 46, 40, 40, 40, 40, 40, /* 33 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 33 */ + 40, 46, 40, 40, 46, 40, 40, 46, /* 33 */ + 40, 40, 46, 46, 60, 46, 80, 80, /* 33 */ + 80, 60, 60, 46, 46, 46, 46, 60, /* 34 */ + 60, 46, 46, 60, 60, 60, 46, 46, /* 34 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */ + 46, 40, 40, 40, 40, 46, 40, 46, /* 34 */ + 46, 46, 46, 46, 46, 46, 81, 81, /* 34 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 34 */ + 60, 60, 40, 40, 40, 46, 46, 46, /* 34 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */ + 46, 60, 60, 80, 46, 40, 40, 40, /* 35 */ + 40, 40, 40, 40, 46, 40, 46, 40, /* 35 */ + 40, 40, 46, 40, 40, 40, 40, 40, /* 35 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 35 */ + 40, 46, 40, 40, 46, 40, 40, 40, /* 35 */ + 40, 40, 46, 46, 60, 40, 80, 80, /* 35 */ + 80, 60, 60, 60, 60, 60, 46, 60, /* 36 */ + 60, 80, 46, 80, 80, 60, 46, 46, /* 36 */ + 15, 46, 46, 46, 46, 46, 46, 46, /* 36 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */ + 40, 46, 46, 46, 46, 46, 81, 81, /* 36 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 36 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */ + 46, 60, 80, 80, 46, 40, 40, 40, /* 37 */ + 40, 40, 40, 40, 40, 46, 46, 40, /* 37 */ + 40, 46, 46, 40, 40, 40, 40, 40, /* 37 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 37 */ + 40, 46, 40, 40, 46, 46, 40, 40, /* 37 */ + 40, 40, 46, 46, 60, 40, 80, 60, /* 37 */ + 80, 60, 60, 60, 46, 46, 46, 80, /* 38 */ + 80, 46, 46, 80, 80, 60, 46, 46, /* 38 */ + 46, 46, 46, 46, 46, 46, 60, 80, /* 38 */ + 46, 46, 46, 46, 40, 40, 46, 40, /* 38 */ + 40, 40, 46, 46, 46, 46, 81, 81, /* 38 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 38 */ + 15, 46, 46, 46, 46, 46, 46, 46, /* 38 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 38 */ + 46, 46, 60, 80, 46, 40, 40, 40, /* 39 */ + 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */ + 40, 46, 40, 40, 40, 40, 46, 46, /* 39 */ + 46, 40, 40, 46, 40, 46, 40, 40, /* 39 */ + 46, 46, 46, 40, 40, 46, 46, 46, /* 39 */ + 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */ + 40, 40, 40, 40, 40, 40, 46, 40, /* 39 */ + 40, 40, 46, 46, 46, 46, 80, 80, /* 39 */ + 60, 80, 80, 46, 46, 46, 80, 80, /* 40 */ + 80, 46, 80, 80, 80, 60, 46, 46, /* 40 */ + 46, 46, 46, 46, 46, 46, 46, 80, /* 40 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */ + 46, 46, 46, 46, 46, 46, 46, 81, /* 40 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 40 */ + 84, 19, 19, 46, 46, 46, 46, 46, /* 40 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */ + 46, 80, 80, 80, 46, 40, 40, 40, /* 41 */ + 40, 40, 40, 40, 40, 46, 40, 40, /* 41 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */ + 40, 40, 40, 40, 46, 40, 40, 40, /* 41 */ + 40, 40, 46, 46, 46, 46, 60, 60, /* 41 */ + 60, 80, 80, 80, 80, 46, 60, 60, /* 42 */ + 60, 46, 60, 60, 60, 60, 46, 46, /* 42 */ + 46, 46, 46, 46, 46, 60, 60, 46, /* 42 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */ + 40, 40, 46, 46, 46, 46, 81, 81, /* 42 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 42 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */ + 46, 46, 80, 80, 46, 40, 40, 40, /* 43 */ + 40, 40, 40, 40, 40, 46, 40, 40, /* 43 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */ + 40, 40, 40, 40, 46, 40, 40, 40, /* 43 */ + 40, 40, 46, 46, 46, 46, 80, 60, /* 43 */ + 80, 80, 80, 80, 80, 46, 60, 80, /* 44 */ + 80, 46, 80, 80, 60, 60, 46, 46, /* 44 */ + 46, 46, 46, 46, 46, 80, 80, 46, /* 44 */ + 46, 46, 46, 46, 46, 46, 40, 46, /* 44 */ + 40, 40, 46, 46, 46, 46, 81, 81, /* 44 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 44 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */ + 46, 46, 80, 80, 46, 40, 40, 40, /* 45 */ + 40, 40, 40, 40, 40, 46, 40, 40, /* 45 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */ + 40, 40, 46, 46, 46, 46, 80, 80, /* 45 */ + 80, 60, 60, 60, 46, 46, 80, 80, /* 46 */ + 80, 46, 80, 80, 80, 60, 46, 46, /* 46 */ + 46, 46, 46, 46, 46, 46, 46, 80, /* 46 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */ + 40, 40, 46, 46, 46, 46, 81, 81, /* 46 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 46 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 47 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */ + 40, 40, 40, 40, 40, 40, 40, 3, /* 47 */ + 40, 60, 40, 40, 60, 60, 60, 60, /* 47 */ + 60, 60, 60, 46, 46, 46, 46, 4, /* 47 */ + 40, 40, 40, 40, 40, 40, 59, 60, /* 48 */ + 60, 60, 60, 60, 60, 60, 60, 15, /* 48 */ + 9, 9, 9, 9, 9, 9, 9, 9, /* 48 */ + 9, 9, 3, 3, 46, 46, 46, 46, /* 48 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */ + 46, 40, 40, 46, 40, 46, 46, 40, /* 49 */ + 40, 46, 40, 46, 46, 40, 46, 46, /* 49 */ + 46, 46, 46, 46, 40, 40, 40, 40, /* 49 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 49 */ + 46, 40, 40, 40, 46, 40, 46, 40, /* 49 */ + 46, 46, 40, 40, 46, 40, 40, 3, /* 49 */ + 40, 60, 40, 40, 60, 60, 60, 60, /* 49 */ + 60, 60, 46, 60, 60, 40, 46, 46, /* 49 */ + 40, 40, 40, 40, 40, 46, 59, 46, /* 50 */ + 60, 60, 60, 60, 60, 60, 46, 46, /* 50 */ + 9, 9, 9, 9, 9, 9, 9, 9, /* 50 */ + 9, 9, 46, 46, 40, 40, 46, 46, /* 50 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */ + 15, 15, 15, 15, 3, 3, 3, 3, /* 51 */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 51 */ + 3, 3, 3, 15, 15, 15, 15, 15, /* 51 */ + 60, 60, 15, 15, 15, 15, 15, 15, /* 51 */ + 78, 78, 78, 78, 78, 78, 78, 78, /* 51 */ + 78, 78, 85, 85, 85, 85, 85, 85, /* 51 */ + 85, 85, 85, 85, 15, 60, 15, 60, /* 51 */ + 15, 60, 5, 6, 5, 6, 80, 80, /* 51 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 52 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */ + 40, 40, 46, 46, 46, 46, 46, 46, /* 52 */ + 46, 60, 60, 60, 60, 60, 60, 60, /* 52 */ + 60, 60, 60, 60, 60, 60, 60, 80, /* 52 */ + 60, 60, 60, 60, 60, 3, 60, 60, /* 53 */ + 60, 60, 60, 60, 46, 46, 46, 46, /* 53 */ + 60, 60, 60, 60, 60, 60, 46, 60, /* 53 */ + 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 53 */ + 60, 60, 60, 60, 60, 60, 46, 46, /* 53 */ + 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */ + 46, 60, 46, 46, 46, 46, 46, 46, /* 53 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */ + 76, 76, 76, 76, 76, 76, 46, 46, /* 55 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 55 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */ + 16, 16, 16, 16, 16, 16, 16, 46, /* 55 */ + 46, 46, 46, 3, 46, 46, 46, 46, /* 55 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 46, 46, 46, 46, 46, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 46, 46, 46, 46, 46, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 46, 46, 46, 46, 46, 46, /* 59 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 16, 16, /* 61 */ + 16, 16, 16, 16, 46, 46, 46, 46, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 46, 46, 46, 46, 46, 46, /* 62 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */ + 86, 86, 86, 86, 86, 86, 46, 46, /* 63 */ + 87, 87, 87, 87, 87, 87, 46, 46, /* 63 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */ + 86, 86, 86, 86, 86, 86, 46, 46, /* 64 */ + 87, 87, 87, 87, 87, 87, 46, 46, /* 64 */ + 16, 86, 16, 86, 16, 86, 16, 86, /* 64 */ + 46, 87, 46, 87, 46, 87, 46, 87, /* 64 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 64 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 64 */ + 88, 88, 89, 89, 89, 89, 90, 90, /* 64 */ + 91, 91, 92, 92, 93, 93, 46, 46, /* 64 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */ + 86, 86, 16, 94, 16, 46, 16, 16, /* 65 */ + 87, 87, 95, 95, 96, 11, 38, 11, /* 65 */ + 11, 11, 16, 94, 16, 46, 16, 16, /* 66 */ + 97, 97, 97, 97, 96, 11, 11, 11, /* 66 */ + 86, 86, 16, 16, 46, 46, 16, 16, /* 66 */ + 87, 87, 98, 98, 46, 11, 11, 11, /* 66 */ + 86, 86, 16, 16, 16, 99, 16, 16, /* 66 */ + 87, 87, 100, 100, 101, 11, 11, 11, /* 66 */ + 46, 46, 16, 94, 16, 46, 16, 16, /* 66 */ +102, 102, 103, 103, 96, 11, 11, 46, /* 66 */ + 2, 2, 2, 2, 2, 2, 2, 2, /* 67 */ + 2, 2, 2, 2, 104, 104, 104, 104, /* 67 */ + 8, 8, 8, 8, 8, 8, 3, 3, /* 67 */ + 5, 6, 5, 5, 5, 6, 5, 5, /* 67 */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */ +105, 106, 104, 104, 104, 104, 104, 46, /* 67 */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */ + 3, 5, 6, 3, 3, 3, 3, 12, /* 67 */ + 12, 3, 3, 3, 7, 5, 6, 46, /* 68 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */ + 46, 46, 104, 104, 104, 104, 104, 104, /* 68 */ + 17, 46, 46, 46, 17, 17, 17, 17, /* 68 */ + 17, 17, 7, 7, 7, 5, 6, 16, /* 68 */ +107, 107, 107, 107, 107, 107, 107, 107, /* 69 */ +107, 107, 7, 7, 7, 5, 6, 46, /* 69 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 69 */ + 4, 4, 4, 4, 46, 46, 46, 46, /* 69 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 70 */ + 60, 60, 60, 60, 60, 79, 79, 79, /* 70 */ + 79, 60, 46, 46, 46, 46, 46, 46, /* 70 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */ + 15, 15, 38, 15, 15, 15, 15, 38, /* 71 */ + 15, 15, 16, 38, 38, 38, 16, 16, /* 71 */ + 38, 38, 38, 16, 15, 38, 15, 15, /* 71 */ + 38, 38, 38, 38, 38, 38, 15, 15, /* 71 */ + 15, 15, 15, 15, 38, 15, 38, 15, /* 71 */ + 38, 15, 38, 38, 38, 38, 16, 16, /* 71 */ + 38, 38, 15, 38, 16, 40, 40, 40, /* 71 */ + 40, 46, 46, 46, 46, 46, 46, 46, /* 71 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */ + 46, 46, 46, 19, 19, 19, 19, 19, /* 72 */ + 19, 19, 19, 19, 19, 19, 19, 108, /* 72 */ +109, 109, 109, 109, 109, 109, 109, 109, /* 72 */ +109, 109, 109, 109, 110, 110, 110, 110, /* 72 */ +111, 111, 111, 111, 111, 111, 111, 111, /* 72 */ +111, 111, 111, 111, 112, 112, 112, 112, /* 72 */ +113, 113, 113, 46, 46, 46, 46, 46, /* 73 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 73 */ + 7, 7, 7, 7, 7, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */ + 15, 15, 7, 15, 7, 15, 15, 15, /* 74 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */ + 15, 15, 15, 46, 46, 46, 46, 46, /* 74 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 46, 46, 46, 46, 46, 46, /* 76 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 76 */ + 15, 46, 15, 15, 15, 15, 15, 15, /* 77 */ + 7, 7, 7, 7, 15, 15, 15, 15, /* 77 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */ + 7, 7, 15, 15, 15, 15, 15, 15, /* 77 */ + 15, 5, 6, 15, 15, 15, 15, 15, /* 77 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 46, 46, 46, 46, 46, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */ + 15, 15, 15, 15, 15, 46, 46, 46, /* 79 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 80 */ + 15, 15, 15, 46, 46, 46, 46, 46, /* 80 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */ +114, 114, 114, 114, 114, 114, 114, 114, /* 80 */ +114, 114, 114, 114, 114, 114, 114, 114, /* 80 */ +114, 114, 114, 114, 82, 82, 82, 82, /* 80 */ + 82, 82, 82, 82, 82, 82, 82, 82, /* 80 */ + 82, 82, 82, 82, 82, 82, 82, 82, /* 81 */ +115, 115, 115, 115, 115, 115, 115, 115, /* 81 */ +115, 115, 115, 115, 115, 115, 115, 115, /* 81 */ +115, 115, 115, 115, 15, 15, 15, 15, /* 81 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */ + 15, 15, 15, 15, 15, 15, 116, 116, /* 81 */ +116, 116, 116, 116, 116, 116, 116, 116, /* 81 */ +116, 116, 116, 116, 116, 116, 116, 116, /* 82 */ +116, 116, 116, 116, 116, 116, 116, 116, /* 82 */ +117, 117, 117, 117, 117, 117, 117, 117, /* 82 */ +117, 117, 117, 117, 117, 117, 117, 117, /* 82 */ +117, 117, 117, 117, 117, 117, 117, 117, /* 82 */ +117, 117, 118, 46, 46, 46, 46, 46, /* 82 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 46, 46, /* 84 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 46, 46, 46, 46, /* 86 */ + 46, 46, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 46, 15, 15, 15, 15, 46, 15, 15, /* 87 */ + 15, 15, 46, 46, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 46, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 88 */ + 15, 15, 15, 15, 46, 15, 46, 15, /* 88 */ + 15, 15, 15, 46, 46, 46, 15, 46, /* 88 */ + 15, 15, 15, 15, 15, 15, 15, 46, /* 88 */ + 46, 15, 15, 15, 15, 15, 15, 15, /* 88 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 88 */ + 46, 46, 46, 46, 46, 46, 119, 119, /* 88 */ +119, 119, 119, 119, 119, 119, 119, 119, /* 88 */ +114, 114, 114, 114, 114, 114, 114, 114, /* 89 */ +114, 114, 83, 83, 83, 83, 83, 83, /* 89 */ + 83, 83, 83, 83, 15, 46, 46, 46, /* 89 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */ + 46, 15, 15, 15, 15, 15, 15, 15, /* 89 */ + 15, 15, 15, 15, 15, 15, 15, 46, /* 89 */ + 2, 3, 3, 3, 15, 59, 3, 120, /* 90 */ + 5, 6, 5, 6, 5, 6, 5, 6, /* 90 */ + 5, 6, 15, 15, 5, 6, 5, 6, /* 90 */ + 5, 6, 5, 6, 8, 5, 6, 5, /* 90 */ + 15, 121, 121, 121, 121, 121, 121, 121, /* 90 */ +121, 121, 60, 60, 60, 60, 60, 60, /* 90 */ + 8, 59, 59, 59, 59, 59, 15, 15, /* 90 */ + 46, 46, 46, 46, 46, 46, 46, 15, /* 90 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 46, 46, 46, /* 92 */ + 46, 60, 60, 59, 59, 59, 59, 46, /* 92 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 3, 59, 59, 59, 46, /* 93 */ + 46, 46, 46, 46, 46, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 46, 46, 46, /* 94 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 95 */ + 40, 40, 40, 40, 40, 40, 40, 46, /* 95 */ + 15, 15, 85, 85, 85, 85, 15, 15, /* 95 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 95 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 15, 46, 46, 46, /* 96 */ + 85, 85, 85, 85, 85, 85, 85, 85, /* 96 */ + 85, 85, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 46, 46, 46, 46, /* 97 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */ + 15, 15, 15, 15, 46, 46, 46, 15, /* 97 */ +114, 114, 114, 114, 114, 114, 114, 114, /* 98 */ +114, 114, 15, 15, 15, 15, 15, 15, /* 98 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */ + 15, 46, 46, 46, 46, 46, 46, 46, /* 98 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 98 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 46, 46, 46, 46, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 46, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 46, /* 100 */ + 46, 46, 46, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 46, 46, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 46, /* 101 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */ + 40, 40, 40, 40, 40, 40, 46, 46, /* 102 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */ + 40, 40, 40, 40, 46, 46, 46, 46, /* 103 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */ + 40, 40, 40, 40, 40, 40, 46, 46, /* 106 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */ + 16, 16, 16, 16, 16, 16, 16, 46, /* 107 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 107 */ + 46, 46, 46, 16, 16, 16, 16, 16, /* 107 */ + 46, 46, 46, 46, 46, 46, 60, 40, /* 107 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 107 */ + 40, 7, 40, 40, 40, 40, 40, 40, /* 107 */ + 40, 40, 40, 40, 40, 40, 40, 46, /* 107 */ + 40, 40, 40, 40, 40, 46, 40, 46, /* 107 */ + 40, 40, 46, 40, 40, 46, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 46, 46, 46, 46, 46, 46, /* 109 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 109 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */ + 46, 46, 46, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 5, 6, /* 111 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 46, 46, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */ + 40, 40, 40, 40, 46, 46, 46, 46, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */ + 60, 60, 60, 60, 46, 46, 46, 46, /* 115 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */ + 3, 8, 8, 12, 12, 5, 6, 5, /* 115 */ + 6, 5, 6, 5, 6, 5, 6, 5, /* 115 */ + 6, 5, 6, 5, 6, 46, 46, 46, /* 116 */ + 46, 3, 3, 3, 3, 12, 12, 12, /* 116 */ + 3, 3, 3, 46, 3, 3, 3, 3, /* 116 */ + 8, 5, 6, 5, 6, 5, 6, 3, /* 116 */ + 3, 3, 7, 8, 7, 7, 7, 46, /* 116 */ + 3, 4, 3, 3, 46, 46, 46, 46, /* 116 */ + 40, 40, 40, 46, 40, 46, 40, 40, /* 116 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 116 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 46, 46, 104, /* 117 */ + 46, 3, 3, 3, 4, 3, 3, 3, /* 118 */ + 5, 6, 3, 7, 3, 8, 3, 3, /* 118 */ + 9, 9, 9, 9, 9, 9, 9, 9, /* 118 */ + 9, 9, 3, 3, 7, 7, 7, 3, /* 118 */ + 3, 10, 10, 10, 10, 10, 10, 10, /* 118 */ + 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */ + 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */ + 10, 10, 10, 5, 3, 6, 11, 12, /* 118 */ + 11, 13, 13, 13, 13, 13, 13, 13, /* 119 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */ + 13, 13, 13, 5, 7, 6, 7, 46, /* 119 */ + 46, 3, 5, 6, 3, 3, 40, 40, /* 119 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */ + 59, 40, 40, 40, 40, 40, 40, 40, /* 119 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 59, 59, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 46, /* 120 */ + 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */ + 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */ + 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */ + 46, 46, 40, 40, 40, 46, 46, 46, /* 121 */ + 4, 4, 7, 11, 15, 4, 4, 46, /* 121 */ + 7, 7, 7, 7, 7, 15, 15, 46, /* 121 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 121 */ + 46, 46, 46, 46, 46, 15, 46, 46 /* 121 */ +}; + +/* The A table has 124 entries for a total of 496 bytes. */ + +const uint32 js_A[] = { +0x0001000F, /* 0 Cc, ignorable */ +0x0004000F, /* 1 Cc, whitespace */ +0x0004000C, /* 2 Zs, whitespace */ +0x00000018, /* 3 Po */ +0x0006001A, /* 4 Sc, currency */ +0x00000015, /* 5 Ps */ +0x00000016, /* 6 Pe */ +0x00000019, /* 7 Sm */ +0x00000014, /* 8 Pd */ +0x00036089, /* 9 Nd, identifier part, decimal 16 */ +0x0827FF81, /* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 */ +0x0000001B, /* 11 Sk */ +0x00050017, /* 12 Pc, underscore */ +0x0817FF82, /* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */ +0x0000000C, /* 14 Zs */ +0x0000001C, /* 15 So */ +0x00070182, /* 16 Ll, identifier start */ +0x0000600B, /* 17 No, decimal 16 */ +0x0000500B, /* 18 No, decimal 8 */ +0x0000800B, /* 19 No, strange */ +0x08270181, /* 20 Lu, hasLower (add 32), identifier start */ +0x08170182, /* 21 Ll, hasUpper (subtract 32), identifier start */ +0xE1D70182, /* 22 Ll, hasUpper (subtract -121), identifier start */ +0x00670181, /* 23 Lu, hasLower (add 1), identifier start */ +0x00570182, /* 24 Ll, hasUpper (subtract 1), identifier start */ +0xCE670181, /* 25 Lu, hasLower (add -199), identifier start */ +0x3A170182, /* 26 Ll, hasUpper (subtract 232), identifier start */ +0xE1E70181, /* 27 Lu, hasLower (add -121), identifier start */ +0x4B170182, /* 28 Ll, hasUpper (subtract 300), identifier start */ +0x34A70181, /* 29 Lu, hasLower (add 210), identifier start */ +0x33A70181, /* 30 Lu, hasLower (add 206), identifier start */ +0x33670181, /* 31 Lu, hasLower (add 205), identifier start */ +0x32A70181, /* 32 Lu, hasLower (add 202), identifier start */ +0x32E70181, /* 33 Lu, hasLower (add 203), identifier start */ +0x33E70181, /* 34 Lu, hasLower (add 207), identifier start */ +0x34E70181, /* 35 Lu, hasLower (add 211), identifier start */ +0x34670181, /* 36 Lu, hasLower (add 209), identifier start */ +0x35670181, /* 37 Lu, hasLower (add 213), identifier start */ +0x00070181, /* 38 Lu, identifier start */ +0x36A70181, /* 39 Lu, hasLower (add 218), identifier start */ +0x00070185, /* 40 Lo, identifier start */ +0x36670181, /* 41 Lu, hasLower (add 217), identifier start */ +0x36E70181, /* 42 Lu, hasLower (add 219), identifier start */ +0x00AF0181, /* 43 Lu, hasLower (add 2), hasTitle, identifier start */ +0x007F0183, /* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */ +0x009F0182, /* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start */ +0x00000000, /* 46 unassigned */ +0x34970182, /* 47 Ll, hasUpper (subtract 210), identifier start */ +0x33970182, /* 48 Ll, hasUpper (subtract 206), identifier start */ +0x33570182, /* 49 Ll, hasUpper (subtract 205), identifier start */ +0x32970182, /* 50 Ll, hasUpper (subtract 202), identifier start */ +0x32D70182, /* 51 Ll, hasUpper (subtract 203), identifier start */ +0x33D70182, /* 52 Ll, hasUpper (subtract 207), identifier start */ +0x34570182, /* 53 Ll, hasUpper (subtract 209), identifier start */ +0x34D70182, /* 54 Ll, hasUpper (subtract 211), identifier start */ +0x35570182, /* 55 Ll, hasUpper (subtract 213), identifier start */ +0x36970182, /* 56 Ll, hasUpper (subtract 218), identifier start */ +0x36570182, /* 57 Ll, hasUpper (subtract 217), identifier start */ +0x36D70182, /* 58 Ll, hasUpper (subtract 219), identifier start */ +0x00070084, /* 59 Lm, identifier start */ +0x00030086, /* 60 Mn, identifier part */ +0x09A70181, /* 61 Lu, hasLower (add 38), identifier start */ +0x09670181, /* 62 Lu, hasLower (add 37), identifier start */ +0x10270181, /* 63 Lu, hasLower (add 64), identifier start */ +0x0FE70181, /* 64 Lu, hasLower (add 63), identifier start */ +0x09970182, /* 65 Ll, hasUpper (subtract 38), identifier start */ +0x09570182, /* 66 Ll, hasUpper (subtract 37), identifier start */ +0x10170182, /* 67 Ll, hasUpper (subtract 64), identifier start */ +0x0FD70182, /* 68 Ll, hasUpper (subtract 63), identifier start */ +0x0F970182, /* 69 Ll, hasUpper (subtract 62), identifier start */ +0x0E570182, /* 70 Ll, hasUpper (subtract 57), identifier start */ +0x0BD70182, /* 71 Ll, hasUpper (subtract 47), identifier start */ +0x0D970182, /* 72 Ll, hasUpper (subtract 54), identifier start */ +0x15970182, /* 73 Ll, hasUpper (subtract 86), identifier start */ +0x14170182, /* 74 Ll, hasUpper (subtract 80), identifier start */ +0x14270181, /* 75 Lu, hasLower (add 80), identifier start */ +0x0C270181, /* 76 Lu, hasLower (add 48), identifier start */ +0x0C170182, /* 77 Ll, hasUpper (subtract 48), identifier start */ +0x00034089, /* 78 Nd, identifier part, decimal 0 */ +0x00000087, /* 79 Me */ +0x00030088, /* 80 Mc, identifier part */ +0x00037489, /* 81 Nd, identifier part, decimal 26 */ +0x00005A0B, /* 82 No, decimal 13 */ +0x00006E0B, /* 83 No, decimal 23 */ +0x0000740B, /* 84 No, decimal 26 */ +0x0000000B, /* 85 No */ +0xFE170182, /* 86 Ll, hasUpper (subtract -8), identifier start */ +0xFE270181, /* 87 Lu, hasLower (add -8), identifier start */ +0xED970182, /* 88 Ll, hasUpper (subtract -74), identifier start */ +0xEA970182, /* 89 Ll, hasUpper (subtract -86), identifier start */ +0xE7170182, /* 90 Ll, hasUpper (subtract -100), identifier start */ +0xE0170182, /* 91 Ll, hasUpper (subtract -128), identifier start */ +0xE4170182, /* 92 Ll, hasUpper (subtract -112), identifier start */ +0xE0970182, /* 93 Ll, hasUpper (subtract -126), identifier start */ +0xFDD70182, /* 94 Ll, hasUpper (subtract -9), identifier start */ +0xEDA70181, /* 95 Lu, hasLower (add -74), identifier start */ +0xFDE70181, /* 96 Lu, hasLower (add -9), identifier start */ +0xEAA70181, /* 97 Lu, hasLower (add -86), identifier start */ +0xE7270181, /* 98 Lu, hasLower (add -100), identifier start */ +0xFE570182, /* 99 Ll, hasUpper (subtract -7), identifier start */ +0xE4270181, /* 100 Lu, hasLower (add -112), identifier start */ +0xFE670181, /* 101 Lu, hasLower (add -7), identifier start */ +0xE0270181, /* 102 Lu, hasLower (add -128), identifier start */ +0xE0A70181, /* 103 Lu, hasLower (add -126), identifier start */ +0x00010010, /* 104 Cf, ignorable */ +0x0004000D, /* 105 Zl, whitespace */ +0x0004000E, /* 106 Zp, whitespace */ +0x0000400B, /* 107 No, decimal 0 */ +0x0000440B, /* 108 No, decimal 2 */ +0x0427438A, /* 109 Nl, hasLower (add 16), identifier start, decimal 1 */ +0x0427818A, /* 110 Nl, hasLower (add 16), identifier start, strange */ +0x0417638A, /* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 */ +0x0417818A, /* 112 Nl, hasUpper (subtract 16), identifier start, strange */ +0x0007818A, /* 113 Nl, identifier start, strange */ +0x0000420B, /* 114 No, decimal 1 */ +0x0000720B, /* 115 No, decimal 25 */ +0x06A0001C, /* 116 So, hasLower (add 26) */ +0x0690001C, /* 117 So, hasUpper (subtract 26) */ +0x00006C0B, /* 118 No, decimal 22 */ +0x0000560B, /* 119 No, decimal 11 */ +0x0007738A, /* 120 Nl, identifier start, decimal 25 */ +0x0007418A, /* 121 Nl, identifier start, decimal 0 */ +0x00000013, /* 122 Cs */ +0x00000012 /* 123 Co */ +}; + +const jschar js_uriReservedPlusPound_ucstr[] = + {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0}; +const jschar js_uriUnescaped_ucstr[] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0}; + +#define URI_CHUNK 64U + +/* Concatenate jschars onto the buffer */ +static JSBool +AddCharsToURI(JSContext *cx, JSCharBuffer *buf, + const jschar *chars, size_t length) +{ + size_t total; + jschar *newchars; + + total = buf->length + length + 1; + if (!buf->chars || + JS_HOWMANY(total, URI_CHUNK) > JS_HOWMANY(buf->length + 1, URI_CHUNK)) { + total = JS_ROUNDUP(total, URI_CHUNK); + newchars = (jschar *) JS_realloc(cx, buf->chars, + total * sizeof(jschar)); + if (!newchars) + return JS_FALSE; + buf->chars = newchars; + } + js_strncpy(buf->chars + buf->length, chars, length); + buf->length += length; + buf->chars[buf->length] = 0; + return JS_TRUE; +} + +static JSBool +TransferBufferToString(JSContext *cx, JSCharBuffer *cb, jsval *rval) +{ + jschar *chars; + size_t n; + JSString *str; + + /* + * Shrinking realloc can fail (e.g., with a BSD-style allocator), but we + * don't worry about that case here. + */ + n = cb->length; + chars = (jschar *) JS_realloc(cx, cb->chars, (n + 1) * sizeof(jschar)); + if (!chars) + chars = cb->chars; + str = js_NewString(cx, chars, n); + if (!str) + return JS_FALSE; + + /* Successful allocation transfer ownership of cb->chars to the string. */ +#ifdef DEBUG + memset(cb, JS_FREE_PATTERN, sizeof *cb); +#endif + + *rval = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +/* + * ECMA 3, 15.1.3 URI Handling Function Properties + * + * The following are implementations of the algorithms + * given in the ECMA specification for the hidden functions + * 'Encode' and 'Decode'. + */ +static JSBool +Encode(JSContext *cx, JSString *str, const jschar *unescapedSet, + const jschar *unescapedSet2, jsval *rval) +{ + size_t length, j, k, L; + JSCharBuffer cb; + jschar *chars, c, c2; + uint32 v; + uint8 utf8buf[6]; + jschar hexBuf[4]; + static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */ + + JSSTRING_CHARS_AND_LENGTH(str, chars, length); + if (length == 0) { + *rval = STRING_TO_JSVAL(cx->runtime->emptyString); + return JS_TRUE; + } + + cb.length = 0; + cb.chars = NULL; + + /* From this point the control must goto bad on failures. */ + hexBuf[0] = '%'; + hexBuf[3] = 0; + for (k = 0; k < length; k++) { + c = chars[k]; + if (js_strchr(unescapedSet, c) || + (unescapedSet2 && js_strchr(unescapedSet2, c))) { + if (!AddCharsToURI(cx, &cb, &c, 1)) + goto bad; + } else { + if ((c >= 0xDC00) && (c <= 0xDFFF)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_URI, NULL); + goto bad; + } + if (c < 0xD800 || c > 0xDBFF) { + v = c; + } else { + k++; + if (k == length) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_URI, NULL); + goto bad; + } + c2 = chars[k]; + if ((c2 < 0xDC00) || (c2 > 0xDFFF)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_URI, NULL); + goto bad; + } + v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000; + } + L = js_OneUcs4ToUtf8Char(utf8buf, v); + for (j = 0; j < L; j++) { + hexBuf[1] = HexDigits[utf8buf[j] >> 4]; + hexBuf[2] = HexDigits[utf8buf[j] & 0xf]; + if (!AddCharsToURI(cx, &cb, hexBuf, 3)) + goto bad; + } + } + } + + if (!TransferBufferToString(cx, &cb, rval)) + goto bad; + + return JS_TRUE; + + bad: + JS_free(cx, cb.chars); + return JS_FALSE; +} + +static JSBool +Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval) +{ + size_t length, start, k; + JSCharBuffer cb; + jschar *chars, c, H; + uint32 v; + jsuint B; + uint8 octets[6]; + intN j, n; + + JSSTRING_CHARS_AND_LENGTH(str, chars, length); + if (length == 0) { + *rval = STRING_TO_JSVAL(cx->runtime->emptyString); + return JS_TRUE; + } + + cb.length = 0; + cb.chars = NULL; + + /* From this point the control must goto bad on failures. */ + for (k = 0; k < length; k++) { + c = chars[k]; + if (c == '%') { + start = k; + if ((k + 2) >= length) + goto report_bad_uri; + if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2])) + goto report_bad_uri; + B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]); + k += 2; + if (!(B & 0x80)) { + c = (jschar)B; + } else { + n = 1; + while (B & (0x80 >> n)) + n++; + if (n == 1 || n > 6) + goto report_bad_uri; + octets[0] = (uint8)B; + if (k + 3 * (n - 1) >= length) + goto report_bad_uri; + for (j = 1; j < n; j++) { + k++; + if (chars[k] != '%') + goto report_bad_uri; + if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2])) + goto report_bad_uri; + B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]); + if ((B & 0xC0) != 0x80) + goto report_bad_uri; + k += 2; + octets[j] = (char)B; + } + v = Utf8ToOneUcs4Char(octets, n); + if (v >= 0x10000) { + v -= 0x10000; + if (v > 0xFFFFF) + goto report_bad_uri; + c = (jschar)((v & 0x3FF) + 0xDC00); + H = (jschar)((v >> 10) + 0xD800); + if (!AddCharsToURI(cx, &cb, &H, 1)) + goto bad; + } else { + c = (jschar)v; + } + } + if (js_strchr(reservedSet, c)) { + if (!AddCharsToURI(cx, &cb, &chars[start], (k - start + 1))) + goto bad; + } else { + if (!AddCharsToURI(cx, &cb, &c, 1)) + goto bad; + } + } else { + if (!AddCharsToURI(cx, &cb, &c, 1)) + return JS_FALSE; + } + } + + if (!TransferBufferToString(cx, &cb, rval)) + goto bad; + + return JS_TRUE; + + report_bad_uri: + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI); + /* FALL THROUGH */ + + bad: + JS_free(cx, cb.chars); + return JS_FALSE; +} + +static JSBool +str_decodeURI(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return JS_FALSE; + return Decode(cx, str, js_uriReservedPlusPound_ucstr, vp); +} + +static JSBool +str_decodeURI_Component(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return JS_FALSE; + return Decode(cx, str, js_empty_ucstr, vp); +} + +static JSBool +str_encodeURI(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return JS_FALSE; + return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr, + vp); +} + +static JSBool +str_encodeURI_Component(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return JS_FALSE; + return Encode(cx, str, js_uriUnescaped_ucstr, NULL, vp); +} + +/* + * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at + * least 6 bytes long. Return the number of UTF-8 bytes of data written. + */ +int +js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char) +{ + int utf8Length = 1; + + JS_ASSERT(ucs4Char <= 0x7FFFFFFF); + if (ucs4Char < 0x80) { + *utf8Buffer = (uint8)ucs4Char; + } else { + int i; + uint32 a = ucs4Char >> 11; + utf8Length = 2; + while (a) { + a >>= 5; + utf8Length++; + } + i = utf8Length; + while (--i) { + utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80); + ucs4Char >>= 6; + } + *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char); + } + return utf8Length; +} + +/* + * Convert a utf8 character sequence into a UCS-4 character and return that + * character. It is assumed that the caller already checked that the sequence + * is valid. + */ +static uint32 +Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length) +{ + uint32 ucs4Char; + uint32 minucs4Char; + /* from Unicode 3.1, non-shortest form is illegal */ + static const uint32 minucs4Table[] = { + 0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000 + }; + + JS_ASSERT(utf8Length >= 1 && utf8Length <= 6); + if (utf8Length == 1) { + ucs4Char = *utf8Buffer; + JS_ASSERT(!(ucs4Char & 0x80)); + } else { + JS_ASSERT((*utf8Buffer & (0x100 - (1 << (7-utf8Length)))) == + (0x100 - (1 << (8-utf8Length)))); + ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1); + minucs4Char = minucs4Table[utf8Length-2]; + while (--utf8Length) { + JS_ASSERT((*utf8Buffer & 0xC0) == 0x80); + ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F); + } + if (ucs4Char < minucs4Char || + ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) { + ucs4Char = 0xFFFD; + } + } + return ucs4Char; +} + +#if defined DEBUG || defined JS_DUMP_PROPTREE_STATS + +JS_FRIEND_API(size_t) +js_PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp, + JSString *str, uint32 quote) +{ + jschar *chars, *charsEnd; + size_t n; + const char *escape; + char c; + uintN u, hex, shift; + enum { + STOP, FIRST_QUOTE, LAST_QUOTE, CHARS, ESCAPE_START, ESCAPE_MORE + } state; + + JS_ASSERT(quote == 0 || quote == '\'' || quote == '"'); + JS_ASSERT_IF(buffer, bufferSize != 0); + JS_ASSERT_IF(!buffer, bufferSize == 0); + JS_ASSERT_IF(fp, !buffer); + + JSSTRING_CHARS_AND_END(str, chars, charsEnd); + n = 0; + --bufferSize; + state = FIRST_QUOTE; + shift = 0; + hex = 0; + u = 0; + c = 0; /* to quell GCC warnings */ + + for (;;) { + switch (state) { + case STOP: + goto stop; + case FIRST_QUOTE: + state = CHARS; + goto do_quote; + case LAST_QUOTE: + state = STOP; + do_quote: + if (quote == 0) + continue; + c = (char)quote; + break; + case CHARS: + if (chars == charsEnd) { + state = LAST_QUOTE; + continue; + } + u = *chars++; + if (u < ' ') { + if (u != 0) { + escape = strchr(js_EscapeMap, (int)u); + if (escape) { + u = escape[1]; + goto do_escape; + } + } + goto do_hex_escape; + } + if (u < 127) { + if (u == quote || u == '\\') + goto do_escape; + c = (char)u; + } else if (u < 0x100) { + goto do_hex_escape; + } else { + shift = 16; + hex = u; + u = 'u'; + goto do_escape; + } + break; + do_hex_escape: + shift = 8; + hex = u; + u = 'x'; + do_escape: + c = '\\'; + state = ESCAPE_START; + break; + case ESCAPE_START: + JS_ASSERT(' ' <= u && u < 127); + c = (char)u; + state = ESCAPE_MORE; + break; + case ESCAPE_MORE: + if (shift == 0) { + state = CHARS; + continue; + } + shift -= 4; + u = 0xF & (hex >> shift); + c = (char)(u + (u < 10 ? '0' : 'A' - 10)); + break; + } + if (buffer) { + if (n == bufferSize) + break; + buffer[n] = c; + } else if (fp) { + fputc(c, fp); + } + n++; + } + stop: + if (buffer) + buffer[n] = '\0'; + return n; +} + +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstr.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstr.h new file mode 100644 index 0000000..349754e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsstr.h @@ -0,0 +1,662 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsstr_h___ +#define jsstr_h___ +/* + * JS string type implementation. + * + * A JS string is a counted array of unicode characters. To support handoff + * of API client memory, the chars are allocated separately from the length, + * necessitating a pointer after the count, to form a separately allocated + * string descriptor. String descriptors are GC'ed, while their chars are + * allocated from the malloc heap. + */ +#include +#include "jspubtd.h" +#include "jsprvtd.h" + +JS_BEGIN_EXTERN_C + +/* + * The GC-thing "string" type. + * + * When the JSSTRFLAG_DEPENDENT bit of the length field is unset, the u.chars + * field points to a flat character array owned by its GC-thing descriptor. + * The array is terminated at index length by a zero character and the size of + * the array in bytes is (length + 1) * sizeof(jschar). The terminator is + * purely a backstop, in case the chars pointer flows out to native code that + * requires \u0000 termination. + * + * A flat string with JSSTRFLAG_MUTABLE set means that the string is accessible + * only from one thread and it is possible to turn it into a dependent string + * of the same length to optimize js_ConcatStrings. It is also possible to grow + * such a string, but extreme care must be taken to ensure that no other code + * relies on the original length of the string. + * + * A flat string with JSSTRFLAG_ATOMIZED set means that the string is hashed as + * an atom. This flag is used to avoid re-hashing the already-atomized string. + * + * When JSSTRFLAG_DEPENDENT is set, the string depends on characters of another + * string strongly referenced by the u.base field. The base member may point to + * another dependent string if JSSTRING_CHARS has not been called yet. + * + * JSSTRFLAG_PREFIX determines the kind of the dependent string. When the flag + * is unset, the length field encodes both starting position relative to the + * base string and the number of characters in the dependent string, see + * JSSTRDEP_START_MASK and JSSTRDEP_LENGTH_MASK macros below for details. + * + * When JSSTRFLAG_PREFIX is set, the dependent string is a prefix of the base + * string. The number of characters in the prefix is encoded using all non-flag + * bits of the length field and spans the same 0 .. SIZE_T_MAX/4 range as the + * length of the flat string. + * + * NB: Always use the JSSTRING_LENGTH and JSSTRING_CHARS accessor macros. + */ +struct JSString { + size_t length; + union { + jschar *chars; + JSString *base; + } u; +}; + +/* + * Definitions for flags stored in the high order bits of JSString.length. + * JSSTRFLAG_PREFIX and JSSTRFLAG_MUTABLE are two aliases for the same value. + * JSSTRFLAG_PREFIX should be used only if JSSTRFLAG_DEPENDENT is set and + * JSSTRFLAG_MUTABLE should be used only if the string is flat. + * JSSTRFLAG_ATOMIZED is used only with the flat immutable strings. + */ +#define JSSTRFLAG_DEPENDENT JSSTRING_BIT(JS_BITS_PER_WORD - 1) +#define JSSTRFLAG_PREFIX JSSTRING_BIT(JS_BITS_PER_WORD - 2) +#define JSSTRFLAG_MUTABLE JSSTRFLAG_PREFIX +#define JSSTRFLAG_ATOMIZED JSSTRING_BIT(JS_BITS_PER_WORD - 3) + +#define JSSTRING_LENGTH_BITS (JS_BITS_PER_WORD - 3) +#define JSSTRING_LENGTH_MASK JSSTRING_BITMASK(JSSTRING_LENGTH_BITS) + +/* Universal JSString type inquiry and accessor macros. */ +#define JSSTRING_BIT(n) ((size_t)1 << (n)) +#define JSSTRING_BITMASK(n) (JSSTRING_BIT(n) - 1) +#define JSSTRING_HAS_FLAG(str,flg) ((str)->length & (flg)) +#define JSSTRING_IS_DEPENDENT(str) JSSTRING_HAS_FLAG(str, JSSTRFLAG_DEPENDENT) +#define JSSTRING_IS_FLAT(str) (!JSSTRING_IS_DEPENDENT(str)) +#define JSSTRING_IS_MUTABLE(str) (((str)->length & (JSSTRFLAG_DEPENDENT | \ + JSSTRFLAG_MUTABLE)) == \ + JSSTRFLAG_MUTABLE) +#define JSSTRING_IS_ATOMIZED(str) (((str)->length & (JSSTRFLAG_DEPENDENT | \ + JSSTRFLAG_ATOMIZED)) ==\ + JSSTRFLAG_ATOMIZED) + +#define JSSTRING_CHARS(str) (JSSTRING_IS_DEPENDENT(str) \ + ? JSSTRDEP_CHARS(str) \ + : JSFLATSTR_CHARS(str)) +#define JSSTRING_LENGTH(str) (JSSTRING_IS_DEPENDENT(str) \ + ? JSSTRDEP_LENGTH(str) \ + : JSFLATSTR_LENGTH(str)) + +#define JSSTRING_CHARS_AND_LENGTH(str, chars_, length_) \ + ((void)(JSSTRING_IS_DEPENDENT(str) \ + ? ((length_) = JSSTRDEP_LENGTH(str), \ + (chars_) = JSSTRDEP_CHARS(str)) \ + : ((length_) = JSFLATSTR_LENGTH(str), \ + (chars_) = JSFLATSTR_CHARS(str)))) + +#define JSSTRING_CHARS_AND_END(str, chars_, end) \ + ((void)((end) = JSSTRING_IS_DEPENDENT(str) \ + ? JSSTRDEP_LENGTH(str) + ((chars_) = JSSTRDEP_CHARS(str)) \ + : JSFLATSTR_LENGTH(str) + ((chars_) = JSFLATSTR_CHARS(str)))) + +/* Specific flat string initializer and accessor macros. */ +#define JSFLATSTR_INIT(str, chars_, length_) \ + ((void)(JS_ASSERT(((length_) & ~JSSTRING_LENGTH_MASK) == 0), \ + (str)->length = (length_), (str)->u.chars = (chars_))) + +#define JSFLATSTR_LENGTH(str) \ + (JS_ASSERT(JSSTRING_IS_FLAT(str)), (str)->length & JSSTRING_LENGTH_MASK) + +#define JSFLATSTR_CHARS(str) \ + (JS_ASSERT(JSSTRING_IS_FLAT(str)), (str)->u.chars) + +/* + * Macros to manipulate atomized and mutable flags of flat strings. It is safe + * to use these without extra locking due to the following properties: + * + * * We do not have a macro like JSFLATSTR_CLEAR_ATOMIZED as a string + * remains atomized until the GC collects it. + * + * * A thread may call JSFLATSTR_SET_MUTABLE only when it is the only thread + * accessing the string until a later call to JSFLATSTR_CLEAR_MUTABLE. + * + * * Multiple threads can call JSFLATSTR_CLEAR_MUTABLE but the macro + * actually clears the mutable flag only when the flag is set -- in which + * case only one thread can access the string (see previous property). + * + * Thus, when multiple threads access the string, JSFLATSTR_SET_ATOMIZED is + * the only macro that can update the length field of the string by changing + * the mutable bit from 0 to 1. We call the macro only after the string has + * been hashed. When some threads in js_ValueToStringId see that the flag is + * set, it knows that the string was atomized. + * + * On the other hand, if the thread sees that the flag is unset, it could be + * seeing a stale value when another thread has just atomized the string and + * set the flag. But this can lead only to an extra call to js_AtomizeString. + * This function would find that the string was already hashed and return it + * with the atomized bit set. + */ +#define JSFLATSTR_SET_ATOMIZED(str) \ + ((void)(JS_ASSERT(JSSTRING_IS_FLAT(str) && !JSSTRING_IS_MUTABLE(str)), \ + (str)->length |= JSSTRFLAG_ATOMIZED)) + +#define JSFLATSTR_SET_MUTABLE(str) \ + ((void)(JS_ASSERT(JSSTRING_IS_FLAT(str) && !JSSTRING_IS_ATOMIZED(str)), \ + (str)->length |= JSSTRFLAG_MUTABLE)) + +#define JSFLATSTR_CLEAR_MUTABLE(str) \ + ((void)(JS_ASSERT(JSSTRING_IS_FLAT(str)), \ + JSSTRING_HAS_FLAG(str, JSSTRFLAG_MUTABLE) && \ + ((str)->length &= ~JSSTRFLAG_MUTABLE))) + +/* Specific dependent string shift/mask accessor and mutator macros. */ +#define JSSTRDEP_START_BITS (JSSTRING_LENGTH_BITS-JSSTRDEP_LENGTH_BITS) +#define JSSTRDEP_START_SHIFT JSSTRDEP_LENGTH_BITS +#define JSSTRDEP_START_MASK JSSTRING_BITMASK(JSSTRDEP_START_BITS) +#define JSSTRDEP_LENGTH_BITS (JSSTRING_LENGTH_BITS / 2) +#define JSSTRDEP_LENGTH_MASK JSSTRING_BITMASK(JSSTRDEP_LENGTH_BITS) + +#define JSSTRDEP_IS_PREFIX(str) JSSTRING_HAS_FLAG(str, JSSTRFLAG_PREFIX) + +#define JSSTRDEP_START(str) (JSSTRDEP_IS_PREFIX(str) ? 0 \ + : (((str)->length \ + >> JSSTRDEP_START_SHIFT) \ + & JSSTRDEP_START_MASK)) +#define JSSTRDEP_LENGTH(str) ((str)->length \ + & (JSSTRDEP_IS_PREFIX(str) \ + ? JSSTRING_LENGTH_MASK \ + : JSSTRDEP_LENGTH_MASK)) + +#define JSSTRDEP_INIT(str,bstr,off,len) \ + ((str)->length = JSSTRFLAG_DEPENDENT \ + | ((off) << JSSTRDEP_START_SHIFT) \ + | (len), \ + (str)->u.base = (bstr)) + +#define JSPREFIX_INIT(str,bstr,len) \ + ((str)->length = JSSTRFLAG_DEPENDENT | JSSTRFLAG_PREFIX | (len), \ + (str)->u.base = (bstr)) + +#define JSSTRDEP_BASE(str) ((str)->u.base) +#define JSPREFIX_BASE(str) JSSTRDEP_BASE(str) +#define JSPREFIX_SET_BASE(str,bstr) ((str)->u.base = (bstr)) + +#define JSSTRDEP_CHARS(str) \ + (JSSTRING_IS_DEPENDENT(JSSTRDEP_BASE(str)) \ + ? js_GetDependentStringChars(str) \ + : JSFLATSTR_CHARS(JSSTRDEP_BASE(str)) + JSSTRDEP_START(str)) + +extern size_t +js_MinimizeDependentStrings(JSString *str, int level, JSString **basep); + +extern jschar * +js_GetDependentStringChars(JSString *str); + +extern const jschar * +js_GetStringChars(JSContext *cx, JSString *str); + +extern JSString * JS_FASTCALL +js_ConcatStrings(JSContext *cx, JSString *left, JSString *right); + +extern const jschar * +js_UndependString(JSContext *cx, JSString *str); + +extern JSBool +js_MakeStringImmutable(JSContext *cx, JSString *str); + +extern JSString* JS_FASTCALL +js_toLowerCase(JSContext *cx, JSString *str); + +extern JSString* JS_FASTCALL +js_toUpperCase(JSContext *cx, JSString *str); + +typedef struct JSCharBuffer { + size_t length; + jschar *chars; +} JSCharBuffer; + +struct JSSubString { + size_t length; + const jschar *chars; +}; + +extern jschar js_empty_ucstr[]; +extern JSSubString js_EmptySubString; + +/* Unicode character attribute lookup tables. */ +extern const uint8 js_X[]; +extern const uint8 js_Y[]; +extern const uint32 js_A[]; + +/* Enumerated Unicode general category types. */ +typedef enum JSCharType { + JSCT_UNASSIGNED = 0, + JSCT_UPPERCASE_LETTER = 1, + JSCT_LOWERCASE_LETTER = 2, + JSCT_TITLECASE_LETTER = 3, + JSCT_MODIFIER_LETTER = 4, + JSCT_OTHER_LETTER = 5, + JSCT_NON_SPACING_MARK = 6, + JSCT_ENCLOSING_MARK = 7, + JSCT_COMBINING_SPACING_MARK = 8, + JSCT_DECIMAL_DIGIT_NUMBER = 9, + JSCT_LETTER_NUMBER = 10, + JSCT_OTHER_NUMBER = 11, + JSCT_SPACE_SEPARATOR = 12, + JSCT_LINE_SEPARATOR = 13, + JSCT_PARAGRAPH_SEPARATOR = 14, + JSCT_CONTROL = 15, + JSCT_FORMAT = 16, + JSCT_PRIVATE_USE = 18, + JSCT_SURROGATE = 19, + JSCT_DASH_PUNCTUATION = 20, + JSCT_START_PUNCTUATION = 21, + JSCT_END_PUNCTUATION = 22, + JSCT_CONNECTOR_PUNCTUATION = 23, + JSCT_OTHER_PUNCTUATION = 24, + JSCT_MATH_SYMBOL = 25, + JSCT_CURRENCY_SYMBOL = 26, + JSCT_MODIFIER_SYMBOL = 27, + JSCT_OTHER_SYMBOL = 28 +} JSCharType; + +/* Character classifying and mapping macros, based on java.lang.Character. */ +#define JS_CCODE(c) (js_A[js_Y[(js_X[(uint16)(c)>>6]<<6)|((c)&0x3F)]]) +#define JS_CTYPE(c) (JS_CCODE(c) & 0x1F) + +#define JS_ISALPHA(c) ((((1 << JSCT_UPPERCASE_LETTER) | \ + (1 << JSCT_LOWERCASE_LETTER) | \ + (1 << JSCT_TITLECASE_LETTER) | \ + (1 << JSCT_MODIFIER_LETTER) | \ + (1 << JSCT_OTHER_LETTER)) \ + >> JS_CTYPE(c)) & 1) + +#define JS_ISALNUM(c) ((((1 << JSCT_UPPERCASE_LETTER) | \ + (1 << JSCT_LOWERCASE_LETTER) | \ + (1 << JSCT_TITLECASE_LETTER) | \ + (1 << JSCT_MODIFIER_LETTER) | \ + (1 << JSCT_OTHER_LETTER) | \ + (1 << JSCT_DECIMAL_DIGIT_NUMBER)) \ + >> JS_CTYPE(c)) & 1) + +/* A unicode letter, suitable for use in an identifier. */ +#define JS_ISLETTER(c) ((((1 << JSCT_UPPERCASE_LETTER) | \ + (1 << JSCT_LOWERCASE_LETTER) | \ + (1 << JSCT_TITLECASE_LETTER) | \ + (1 << JSCT_MODIFIER_LETTER) | \ + (1 << JSCT_OTHER_LETTER) | \ + (1 << JSCT_LETTER_NUMBER)) \ + >> JS_CTYPE(c)) & 1) + +/* + * 'IdentifierPart' from ECMA grammar, is Unicode letter or combining mark or + * digit or connector punctuation. + */ +#define JS_ISIDPART(c) ((((1 << JSCT_UPPERCASE_LETTER) | \ + (1 << JSCT_LOWERCASE_LETTER) | \ + (1 << JSCT_TITLECASE_LETTER) | \ + (1 << JSCT_MODIFIER_LETTER) | \ + (1 << JSCT_OTHER_LETTER) | \ + (1 << JSCT_LETTER_NUMBER) | \ + (1 << JSCT_NON_SPACING_MARK) | \ + (1 << JSCT_COMBINING_SPACING_MARK) | \ + (1 << JSCT_DECIMAL_DIGIT_NUMBER) | \ + (1 << JSCT_CONNECTOR_PUNCTUATION)) \ + >> JS_CTYPE(c)) & 1) + +/* Unicode control-format characters, ignored in input */ +#define JS_ISFORMAT(c) (((1 << JSCT_FORMAT) >> JS_CTYPE(c)) & 1) + +/* + * Per ECMA-262 15.10.2.6, these characters are the only ones that make up a + * "word", as far as a RegExp is concerned. If we want a Unicode-friendlier + * definition of "word", we should rename this macro to something regexp-y. + */ +#define JS_ISWORD(c) ((c) < 128 && (isalnum(c) || (c) == '_')) + +#define JS_ISIDSTART(c) (JS_ISLETTER(c) || (c) == '_' || (c) == '$') +#define JS_ISIDENT(c) (JS_ISIDPART(c) || (c) == '_' || (c) == '$') + +#define JS_ISXMLSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || \ + (c) == '\n') +#define JS_ISXMLNSSTART(c) ((JS_CCODE(c) & 0x00000100) || (c) == '_') +#define JS_ISXMLNS(c) ((JS_CCODE(c) & 0x00000080) || (c) == '.' || \ + (c) == '-' || (c) == '_') +#define JS_ISXMLNAMESTART(c) (JS_ISXMLNSSTART(c) || (c) == ':') +#define JS_ISXMLNAME(c) (JS_ISXMLNS(c) || (c) == ':') + +#define JS_ISDIGIT(c) (JS_CTYPE(c) == JSCT_DECIMAL_DIGIT_NUMBER) + +/* XXXbe unify on A/X/Y tbls, avoid ctype.h? */ +/* XXXbe fs, etc. ? */ +#define JS_ISSPACE(c) ((JS_CCODE(c) & 0x00070000) == 0x00040000) +#define JS_ISPRINT(c) ((c) < 128 && isprint(c)) + +#define JS_ISUPPER(c) (JS_CTYPE(c) == JSCT_UPPERCASE_LETTER) +#define JS_ISLOWER(c) (JS_CTYPE(c) == JSCT_LOWERCASE_LETTER) + +#define JS_TOUPPER(c) ((jschar) ((JS_CCODE(c) & 0x00100000) \ + ? (c) - ((int32)JS_CCODE(c) >> 22) \ + : (c))) +#define JS_TOLOWER(c) ((jschar) ((JS_CCODE(c) & 0x00200000) \ + ? (c) + ((int32)JS_CCODE(c) >> 22) \ + : (c))) + +/* + * Shorthands for ASCII (7-bit) decimal and hex conversion. + * Manually inline isdigit for performance; MSVC doesn't do this for us. + */ +#define JS7_ISDEC(c) ((((unsigned)(c)) - '0') <= 9) +#define JS7_UNDEC(c) ((c) - '0') +#define JS7_ISHEX(c) ((c) < 128 && isxdigit(c)) +#define JS7_UNHEX(c) (uintN)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a') +#define JS7_ISLET(c) ((c) < 128 && isalpha(c)) + +/* Initialize per-runtime string state for the first context in the runtime. */ +extern JSBool +js_InitRuntimeStringState(JSContext *cx); + +extern JSBool +js_InitDeflatedStringCache(JSRuntime *rt); + +/* + * Maximum character code for which we will create a pinned unit string on + * demand -- see JSRuntime.unitStrings in jscntxt.h. + */ +#define UNIT_STRING_LIMIT 256U + +/* + * Get the independent string containing only character code at index in str + * (backstopped with a zero character as usual for independent strings). + */ +extern JSString * +js_GetUnitString(JSContext *cx, JSString *str, size_t index); + +/* + * Get the independent string containing only the character code c, which must + * be less than UNIT_STRING_LIMIT. + */ +extern JSString * +js_GetUnitStringForChar(JSContext *cx, jschar c); + +extern void +js_FinishUnitStrings(JSRuntime *rt); + +extern void +js_FinishRuntimeStringState(JSContext *cx); + +extern void +js_FinishDeflatedStringCache(JSRuntime *rt); + +/* Initialize the String class, returning its prototype object. */ +extern JSClass js_StringClass; + +extern JSObject * +js_InitStringClass(JSContext *cx, JSObject *obj); + +extern const char js_escape_str[]; +extern const char js_unescape_str[]; +extern const char js_uneval_str[]; +extern const char js_decodeURI_str[]; +extern const char js_encodeURI_str[]; +extern const char js_decodeURIComponent_str[]; +extern const char js_encodeURIComponent_str[]; + +/* GC-allocate a string descriptor for the given malloc-allocated chars. */ +extern JSString * +js_NewString(JSContext *cx, jschar *chars, size_t length); + +extern JSString * +js_NewDependentString(JSContext *cx, JSString *base, size_t start, + size_t length); + +/* Copy a counted string and GC-allocate a descriptor for it. */ +extern JSString * +js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n); + +/* Copy a C string and GC-allocate a descriptor for it. */ +extern JSString * +js_NewStringCopyZ(JSContext *cx, const jschar *s); + +/* + * Free the chars held by str when it is finalized by the GC. When type is + * less then zero, it denotes an internal string. Otherwise it denotes the + * type of the external string allocated with JS_NewExternalString. + * + * This function always needs rt but can live with null cx. + */ +extern void +js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx); + +/* + * Convert a value to a printable C string. + */ +typedef JSString *(*JSValueToStringFun)(JSContext *cx, jsval v); + +extern JS_FRIEND_API(const char *) +js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun); + +#define js_ValueToPrintableString(cx,v) \ + js_ValueToPrintable(cx, v, js_ValueToString) + +#define js_ValueToPrintableSource(cx,v) \ + js_ValueToPrintable(cx, v, js_ValueToSource) + +/* + * Convert a value to a string, returning null after reporting an error, + * otherwise returning a new string reference. + */ +extern JS_FRIEND_API(JSString *) +js_ValueToString(JSContext *cx, jsval v); + +/* + * Convert a value to its source expression, returning null after reporting + * an error, otherwise returning a new string reference. + */ +extern JS_FRIEND_API(JSString *) +js_ValueToSource(JSContext *cx, jsval v); + +/* + * Compute a hash function from str. The caller can call this function even if + * str is not a GC-allocated thing. + */ +extern uint32 +js_HashString(JSString *str); + +/* + * Test if strings are equal. The caller can call the function even if str1 + * or str2 are not GC-allocated things. + */ +extern JSBool JS_FASTCALL +js_EqualStrings(JSString *str1, JSString *str2); + +/* + * Return less than, equal to, or greater than zero depending on whether + * str1 is less than, equal to, or greater than str2. + */ +extern int32 JS_FASTCALL +js_CompareStrings(JSString *str1, JSString *str2); + +/* + * Boyer-Moore-Horspool superlinear search for pat:patlen in text:textlen. + * The patlen argument must be positive and no greater than BMH_PATLEN_MAX. + * The start argument tells where in text to begin the search. + * + * Return the index of pat in text, or -1 if not found. + */ +#define BMH_CHARSET_SIZE 256 /* ISO-Latin-1 */ +#define BMH_PATLEN_MAX 255 /* skip table element is uint8 */ + +#define BMH_BAD_PATTERN (-2) /* return value if pat is not ISO-Latin-1 */ + +extern jsint +js_BoyerMooreHorspool(const jschar *text, jsint textlen, + const jschar *pat, jsint patlen, + jsint start); + +extern size_t +js_strlen(const jschar *s); + +extern jschar * +js_strchr(const jschar *s, jschar c); + +extern jschar * +js_strchr_limit(const jschar *s, jschar c, const jschar *limit); + +#define js_strncpy(t, s, n) memcpy((t), (s), (n) * sizeof(jschar)) + +/* + * Return s advanced past any Unicode white space characters. + */ +extern const jschar * +js_SkipWhiteSpace(const jschar *s, const jschar *end); + +/* + * Inflate bytes to JS chars and vice versa. Report out of memory via cx + * and return null on error, otherwise return the jschar or byte vector that + * was JS_malloc'ed. length is updated with the length of the new string in jschars. + */ +extern jschar * +js_InflateString(JSContext *cx, const char *bytes, size_t *length); + +extern char * +js_DeflateString(JSContext *cx, const jschar *chars, size_t length); + +/* + * Inflate bytes to JS chars into a buffer. 'chars' must be large enough for + * 'length' jschars. The buffer is NOT null-terminated. The destination length + * must be be initialized with the buffer size and will contain on return the + * number of copied chars. + */ +extern JSBool +js_InflateStringToBuffer(JSContext* cx, const char *bytes, size_t length, + jschar *chars, size_t* charsLength); + +/* + * Get number of bytes in the deflated sequence of characters. + */ +extern size_t +js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, + size_t charsLength); + +/* + * Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for + * 'length chars. The buffer is NOT null-terminated. The destination length + * must to be initialized with the buffer size and will contain on return the + * number of copied bytes. + */ +extern JSBool +js_DeflateStringToBuffer(JSContext* cx, const jschar *chars, + size_t charsLength, char *bytes, size_t* length); + +/* + * Associate bytes with str in the deflated string cache, returning true on + * successful association, false on out of memory. + */ +extern JSBool +js_SetStringBytes(JSContext *cx, JSString *str, char *bytes, size_t length); + +/* + * Find or create a deflated string cache entry for str that contains its + * characters chopped from Unicode code points into bytes. + */ +extern const char * +js_GetStringBytes(JSContext *cx, JSString *str); + +/* Remove a deflated string cache entry associated with str if any. */ +extern void +js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str); + +/* Export a few natives and a helper to other files in SpiderMonkey. */ +extern JSBool +js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval); + +extern JSBool +js_StringMatchHelper(JSContext *cx, uintN argc, jsval *vp, jsbytecode *pc); + +extern JSBool +js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda, + JSString *repstr, jsval *vp); + +/* + * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at + * least 6 bytes long. Return the number of UTF-8 bytes of data written. + */ +extern int +js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char); + +/* + * Write str into buffer escaping any non-printable or non-ASCII character. + * Guarantees that a NUL is at the end of the buffer. Returns the length of + * the written output, NOT including the NUL. If buffer is null, just returns + * the length of the output. If quote is not 0, it must be a single or double + * quote character that will quote the output. + * + * The function is only defined for debug builds. +*/ +#define js_PutEscapedString(buffer, bufferSize, str, quote) \ + js_PutEscapedStringImpl(buffer, bufferSize, NULL, str, quote) + +/* + * Write str into file escaping any non-printable or non-ASCII character. + * Returns the number of bytes written to file. If quote is not 0, it must + * be a single or double quote character that will quote the output. + * + * The function is only defined for debug builds. +*/ +#define js_FileEscapedString(file, str, quote) \ + (JS_ASSERT(file), js_PutEscapedStringImpl(NULL, 0, file, str, quote)) + +extern JS_FRIEND_API(size_t) +js_PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp, + JSString *str, uint32 quote); + +JS_END_EXTERN_C + +#endif /* jsstr_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstracer.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstracer.cpp new file mode 100644 index 0000000..7cfb474 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstracer.cpp @@ -0,0 +1,8276 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * Andreas Gal + * Mike Shaver + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsstddef.h" // always first +#include "jsbit.h" // low-level (NSPR-based) headers next +#include "jsprf.h" +#include // standard headers next +#ifdef _MSC_VER +#include +#define alloca _alloca +#endif +#ifdef SOLARIS +#include +#endif + +#include "nanojit/nanojit.h" +#include "jsarray.h" // higher-level library and API headers +#include "jsbool.h" +#include "jscntxt.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsregexp.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsdate.h" +#include "jsstaticcheck.h" +#include "jstracer.h" + +#include "jsautooplen.h" // generated headers last + +/* Never use JSVAL_IS_BOOLEAN because it restricts the value (true, false) and + the type. What you want to use is JSVAL_TAG(x) == JSVAL_BOOLEAN and then + handle the undefined case properly (bug 457363). */ +#undef JSVAL_IS_BOOLEAN +#define JSVAL_IS_BOOLEAN(x) JS_STATIC_ASSERT(0) + +/* Use a fake tag to represent boxed values, borrowing from the integer tag + range since we only use JSVAL_INT to indicate integers. */ +#define JSVAL_BOXED 3 + +/* Map to translate a type tag into a printable representation. */ +static const char typeChar[] = "OIDVS?B?"; + +/* Number of iterations of a loop where we start tracing. That is, we don't + start tracing until the beginning of the HOTLOOP-th iteration. */ +#define HOTLOOP 2 + +/* Number of times we wait to exit on a side exit before we try to extend the tree. */ +#define HOTEXIT 1 + +/* Max call depths for inlining. */ +#define MAX_CALLDEPTH 10 + +/* Max number of type mismatchs before we trash the tree. */ +#define MAX_MISMATCH 20 + +/* Max blacklist level of inner tree immediate recompiling */ +#define MAX_INNER_RECORD_BLACKLIST -16 + +/* Max native stack size. */ +#define MAX_NATIVE_STACK_SLOTS 1024 + +/* Max call stack size. */ +#define MAX_CALL_STACK_ENTRIES 64 + +/* Max number of branches per tree. */ +#define MAX_BRANCHES 16 + +/* Macros for demote slot lists */ +#define ALLOCA_UNDEMOTE_SLOTLIST(num) (unsigned*)alloca(((num) + 1) * sizeof(unsigned)) +#define ADD_UNDEMOTE_SLOT(list, slot) list[++list[0]] = slot +#define NUM_UNDEMOTE_SLOTS(list) list[0] +#define CLEAR_UNDEMOTE_SLOTLIST(list) list[0] = 0 + +#ifdef JS_JIT_SPEW +#define ABORT_TRACE(msg) do { debug_only_v(fprintf(stdout, "abort: %d: %s\n", __LINE__, msg);) return false; } while (0) +#else +#define ABORT_TRACE(msg) return false +#endif + +#ifdef JS_JIT_SPEW +struct __jitstats { +#define JITSTAT(x) uint64 x; +#include "jitstats.tbl" +#undef JITSTAT +} jitstats = { 0LL, }; + +JS_STATIC_ASSERT(sizeof(jitstats) % sizeof(uint64) == 0); + +enum jitstat_ids { +#define JITSTAT(x) STAT ## x ## ID, +#include "jitstats.tbl" +#undef JITSTAT + STAT_IDS_TOTAL +}; + +static JSPropertySpec jitstats_props[] = { +#define JITSTAT(x) { #x, STAT ## x ## ID, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT }, +#include "jitstats.tbl" +#undef JITSTAT + { 0 } +}; + +static JSBool +jitstats_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + int index = -1; + + if (JSVAL_IS_STRING(id)) { + JSString* str = JSVAL_TO_STRING(id); + if (strcmp(JS_GetStringBytes(str), "HOTLOOP") == 0) { + *vp = INT_TO_JSVAL(HOTLOOP); + return JS_TRUE; + } + } + + if (JSVAL_IS_INT(id)) + index = JSVAL_TO_INT(id); + + uint64 result = 0; + switch (index) { +#define JITSTAT(x) case STAT ## x ## ID: result = jitstats.x; break; +#include "jitstats.tbl" +#undef JITSTAT + default: + *vp = JSVAL_VOID; + return JS_TRUE; + } + + if (result < JSVAL_INT_MAX) { + *vp = INT_TO_JSVAL(result); + return JS_TRUE; + } + char retstr[64]; + JS_snprintf(retstr, sizeof retstr, "%llu", result); + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, retstr)); + return JS_TRUE; +} + +JSClass jitstats_class = { + "jitstats", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, JS_PropertyStub, + jitstats_getProperty, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +void +js_InitJITStatsClass(JSContext *cx, JSObject *glob) +{ + JS_InitClass(cx, glob, NULL, &jitstats_class, NULL, 0, jitstats_props, NULL, NULL, NULL); +} + +#define AUDIT(x) (jitstats.x++) +#else +#define AUDIT(x) ((void)0) +#endif /* JS_JIT_SPEW */ + +#define INS_CONST(c) addName(lir->insImm(c), #c) +#define INS_CONSTPTR(p) addName(lir->insImmPtr((void*) (p)), #p) + +using namespace avmplus; +using namespace nanojit; + +static GC gc = GC(); +static avmplus::AvmCore s_core = avmplus::AvmCore(); +static avmplus::AvmCore* core = &s_core; + +#ifdef JS_JIT_SPEW +void +js_DumpPeerStability(Fragmento* frago, const void* ip); +#endif + +/* We really need a better way to configure the JIT. Shaver, where is my fancy JIT object? */ +static bool nesting_enabled = true; +#if defined(NANOJIT_IA32) +static bool did_we_check_sse2 = false; +#endif + +#ifdef JS_JIT_SPEW +static bool verbose_debug = getenv("TRACEMONKEY") && strstr(getenv("TRACEMONKEY"), "verbose"); +#define debug_only_v(x) if (verbose_debug) { x; } +#else +#define debug_only_v(x) +#endif + +/* The entire VM shares one oracle. Collisions and concurrent updates are tolerated and worst + case cause performance regressions. */ +static Oracle oracle; + +/* Blacklists the root peer fragment at a fragment's PC. This is so blacklisting stays at the + top of the peer list and not scattered around. */ +void +js_BlacklistPC(Fragmento* frago, Fragment* frag); + +Tracker::Tracker() +{ + pagelist = 0; +} + +Tracker::~Tracker() +{ + clear(); +} + +jsuword +Tracker::getPageBase(const void* v) const +{ + return jsuword(v) & ~jsuword(NJ_PAGE_SIZE-1); +} + +struct Tracker::Page* +Tracker::findPage(const void* v) const +{ + jsuword base = getPageBase(v); + struct Tracker::Page* p = pagelist; + while (p) { + if (p->base == base) { + return p; + } + p = p->next; + } + return 0; +} + +struct Tracker::Page* +Tracker::addPage(const void* v) { + jsuword base = getPageBase(v); + struct Tracker::Page* p = (struct Tracker::Page*) + GC::Alloc(sizeof(*p) - sizeof(p->map) + (NJ_PAGE_SIZE >> 2) * sizeof(LIns*)); + p->base = base; + p->next = pagelist; + pagelist = p; + return p; +} + +void +Tracker::clear() +{ + while (pagelist) { + Page* p = pagelist; + pagelist = pagelist->next; + GC::Free(p); + } +} + +bool +Tracker::has(const void *v) const +{ + return get(v) != NULL; +} + +#if defined NANOJIT_64BIT +#define PAGEMASK 0x7ff +#else +#define PAGEMASK 0xfff +#endif + +LIns* +Tracker::get(const void* v) const +{ + struct Tracker::Page* p = findPage(v); + if (!p) + return NULL; + return p->map[(jsuword(v) & PAGEMASK) >> 2]; +} + +void +Tracker::set(const void* v, LIns* i) +{ + struct Tracker::Page* p = findPage(v); + if (!p) + p = addPage(v); + p->map[(jsuword(v) & PAGEMASK) >> 2] = i; +} + +static inline bool isNumber(jsval v) +{ + return JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v); +} + +static inline jsdouble asNumber(jsval v) +{ + JS_ASSERT(isNumber(v)); + if (JSVAL_IS_DOUBLE(v)) + return *JSVAL_TO_DOUBLE(v); + return (jsdouble)JSVAL_TO_INT(v); +} + +static inline bool isInt32(jsval v) +{ + if (!isNumber(v)) + return false; + jsdouble d = asNumber(v); + jsint i; + return JSDOUBLE_IS_INT(d, i); +} + +/* Return JSVAL_DOUBLE for all numbers (int and double) and the tag otherwise. */ +static inline uint8 getPromotedType(jsval v) +{ + return JSVAL_IS_INT(v) ? JSVAL_DOUBLE : uint8(JSVAL_TAG(v)); +} + +/* Return JSVAL_INT for all whole numbers that fit into signed 32-bit and the tag otherwise. */ +static inline uint8 getCoercedType(jsval v) +{ + return isInt32(v) ? JSVAL_INT : (uint8) JSVAL_TAG(v); +} + +/* Tell the oracle that a certain global variable should not be demoted. */ +void +Oracle::markGlobalSlotUndemotable(JSScript* script, unsigned slot) +{ + _dontDemote.set(&gc, (slot % ORACLE_SIZE)); +} + +/* Consult with the oracle whether we shouldn't demote a certain global variable. */ +bool +Oracle::isGlobalSlotUndemotable(JSScript* script, unsigned slot) const +{ + return _dontDemote.get(slot % ORACLE_SIZE); +} + +/* Tell the oracle that a certain slot at a certain bytecode location should not be demoted. */ +void +Oracle::markStackSlotUndemotable(JSScript* script, jsbytecode* ip, unsigned slot) +{ + uint32 hash = uint32(intptr_t(ip)) + (slot << 5); + hash %= ORACLE_SIZE; + _dontDemote.set(&gc, hash); +} + +/* Consult with the oracle whether we shouldn't demote a certain slot. */ +bool +Oracle::isStackSlotUndemotable(JSScript* script, jsbytecode* ip, unsigned slot) const +{ + uint32 hash = uint32(intptr_t(ip)) + (slot << 5); + hash %= ORACLE_SIZE; + return _dontDemote.get(hash); +} + +/* Clear the oracle. */ +void +Oracle::clear() +{ + _dontDemote.reset(); +} + +#if defined(NJ_SOFTFLOAT) +JS_DEFINE_CALLINFO_1(static, DOUBLE, i2f, INT32, 1, 1) +JS_DEFINE_CALLINFO_1(static, DOUBLE, u2f, UINT32, 1, 1) +#endif + +static bool isi2f(LInsp i) +{ + if (i->isop(LIR_i2f)) + return true; + +#if defined(NJ_SOFTFLOAT) + if (i->isop(LIR_qjoin) && + i->oprnd1()->isop(LIR_call) && + i->oprnd2()->isop(LIR_callh)) + { + if (i->oprnd1()->callInfo() == &i2f_ci) + return true; + } +#endif + + return false; +} + +static bool isu2f(LInsp i) +{ + if (i->isop(LIR_u2f)) + return true; + +#if defined(NJ_SOFTFLOAT) + if (i->isop(LIR_qjoin) && + i->oprnd1()->isop(LIR_call) && + i->oprnd2()->isop(LIR_callh)) + { + if (i->oprnd1()->callInfo() == &u2f_ci) + return true; + } +#endif + + return false; +} + +static LInsp iu2fArg(LInsp i) +{ +#if defined(NJ_SOFTFLOAT) + if (i->isop(LIR_qjoin)) + return i->oprnd1()->arg(0); +#endif + + return i->oprnd1(); +} + + +static LIns* demote(LirWriter *out, LInsp i) +{ + if (i->isCall()) + return callArgN(i, 0); + if (isi2f(i) || isu2f(i)) + return iu2fArg(i); + if (i->isconst()) + return i; + AvmAssert(i->isconstq()); + double cf = i->constvalf(); + int32_t ci = cf > 0x7fffffff ? uint32_t(cf) : int32_t(cf); + return out->insImm(ci); +} + +static bool isPromoteInt(LIns* i) +{ + jsdouble d; + return isi2f(i) || i->isconst() || + (i->isconstq() && (d = i->constvalf()) == jsdouble(jsint(d)) && !JSDOUBLE_IS_NEGZERO(d)); +} + +static bool isPromoteUint(LIns* i) +{ + jsdouble d; + return isu2f(i) || i->isconst() || + (i->isconstq() && (d = i->constvalf()) == (jsdouble)(jsuint)d && !JSDOUBLE_IS_NEGZERO(d)); +} + +static bool isPromote(LIns* i) +{ + return isPromoteInt(i) || isPromoteUint(i); +} + +static bool isconst(LIns* i, int32_t c) +{ + return i->isconst() && i->constval() == c; +} + +static bool overflowSafe(LIns* i) +{ + LIns* c; + return (i->isop(LIR_and) && ((c = i->oprnd2())->isconst()) && + ((c->constval() & 0xc0000000) == 0)) || + (i->isop(LIR_rsh) && ((c = i->oprnd2())->isconst()) && + ((c->constval() > 0))); +} + +#if defined(NJ_SOFTFLOAT) +/* soft float */ + +JS_DEFINE_CALLINFO_1(static, DOUBLE, fneg, DOUBLE, 1, 1) +JS_DEFINE_CALLINFO_2(static, INT32, fcmpeq, DOUBLE, DOUBLE, 1, 1) +JS_DEFINE_CALLINFO_2(static, INT32, fcmplt, DOUBLE, DOUBLE, 1, 1) +JS_DEFINE_CALLINFO_2(static, INT32, fcmple, DOUBLE, DOUBLE, 1, 1) +JS_DEFINE_CALLINFO_2(static, INT32, fcmpgt, DOUBLE, DOUBLE, 1, 1) +JS_DEFINE_CALLINFO_2(static, INT32, fcmpge, DOUBLE, DOUBLE, 1, 1) +JS_DEFINE_CALLINFO_2(static, DOUBLE, fmul, DOUBLE, DOUBLE, 1, 1) +JS_DEFINE_CALLINFO_2(static, DOUBLE, fadd, DOUBLE, DOUBLE, 1, 1) +JS_DEFINE_CALLINFO_2(static, DOUBLE, fdiv, DOUBLE, DOUBLE, 1, 1) +JS_DEFINE_CALLINFO_2(static, DOUBLE, fsub, DOUBLE, DOUBLE, 1, 1) + +jsdouble FASTCALL +fneg(jsdouble x) +{ + return -x; +} + +jsdouble FASTCALL +i2f(int32 i) +{ + return i; +} + +jsdouble FASTCALL +u2f(jsuint u) +{ + return u; +} + +int32 FASTCALL +fcmpeq(jsdouble x, jsdouble y) +{ + return x==y; +} + +int32 FASTCALL +fcmplt(jsdouble x, jsdouble y) +{ + return x < y; +} + +int32 FASTCALL +fcmple(jsdouble x, jsdouble y) +{ + return x <= y; +} + +int32 FASTCALL +fcmpgt(jsdouble x, jsdouble y) +{ + return x > y; +} + +int32 FASTCALL +fcmpge(jsdouble x, jsdouble y) +{ + return x >= y; +} + +jsdouble FASTCALL +fmul(jsdouble x, jsdouble y) +{ + return x * y; +} + +jsdouble FASTCALL +fadd(jsdouble x, jsdouble y) +{ + return x + y; +} + +jsdouble FASTCALL +fdiv(jsdouble x, jsdouble y) +{ + return x / y; +} + +jsdouble FASTCALL +fsub(jsdouble x, jsdouble y) +{ + return x - y; +} + +class SoftFloatFilter: public LirWriter +{ +public: + SoftFloatFilter(LirWriter* out): + LirWriter(out) + { + } + + LInsp quadCall(const CallInfo *ci, LInsp args[]) { + LInsp qlo, qhi; + + qlo = out->insCall(ci, args); + qhi = out->ins1(LIR_callh, qlo); + return out->qjoin(qlo, qhi); + } + + LInsp ins1(LOpcode v, LInsp s0) + { + if (v == LIR_fneg) + return quadCall(&fneg_ci, &s0); + + if (v == LIR_i2f) + return quadCall(&i2f_ci, &s0); + + if (v == LIR_u2f) + return quadCall(&u2f_ci, &s0); + + return out->ins1(v, s0); + } + + LInsp ins2(LOpcode v, LInsp s0, LInsp s1) + { + LInsp args[2]; + LInsp bv; + + // change the numeric value and order of these LIR opcodes and die + if (LIR_fadd <= v && v <= LIR_fdiv) { + static const CallInfo *fmap[] = { &fadd_ci, &fsub_ci, &fmul_ci, &fdiv_ci }; + + args[0] = s1; + args[1] = s0; + + return quadCall(fmap[v - LIR_fadd], args); + } + + if (LIR_feq <= v && v <= LIR_fge) { + static const CallInfo *fmap[] = { &fcmpeq_ci, &fcmplt_ci, &fcmpgt_ci, &fcmple_ci, &fcmpge_ci }; + + args[0] = s1; + args[1] = s0; + + bv = out->insCall(fmap[v - LIR_feq], args); + return out->ins2(LIR_eq, bv, out->insImm(1)); + } + + return out->ins2(v, s0, s1); + } + + LInsp insCall(const CallInfo *ci, LInsp args[]) + { + // if the return type is ARGSIZE_F, we have + // to do a quadCall ( qjoin(call,callh) ) + if ((ci->_argtypes & 3) == ARGSIZE_F) + return quadCall(ci, args); + + return out->insCall(ci, args); + } +}; + +#endif // NJ_SOFTFLOAT + +class FuncFilter: public LirWriter +{ +public: + FuncFilter(LirWriter* out): + LirWriter(out) + { + } + + LInsp ins2(LOpcode v, LInsp s0, LInsp s1) + { + if (s0 == s1 && v == LIR_feq) { + if (isPromote(s0)) { + // double(int) and double(uint) cannot be nan + return insImm(1); + } + if (s0->isop(LIR_fmul) || s0->isop(LIR_fsub) || s0->isop(LIR_fadd)) { + LInsp lhs = s0->oprnd1(); + LInsp rhs = s0->oprnd2(); + if (isPromote(lhs) && isPromote(rhs)) { + // add/sub/mul promoted ints can't be nan + return insImm(1); + } + } + } else if (LIR_feq <= v && v <= LIR_fge) { + if (isPromoteInt(s0) && isPromoteInt(s1)) { + // demote fcmp to cmp + v = LOpcode(v + (LIR_eq - LIR_feq)); + return out->ins2(v, demote(out, s0), demote(out, s1)); + } else if (isPromoteUint(s0) && isPromoteUint(s1)) { + // uint compare + v = LOpcode(v + (LIR_eq - LIR_feq)); + if (v != LIR_eq) + v = LOpcode(v + (LIR_ult - LIR_lt)); // cmp -> ucmp + return out->ins2(v, demote(out, s0), demote(out, s1)); + } + } else if (v == LIR_or && + s0->isop(LIR_lsh) && isconst(s0->oprnd2(), 16) && + s1->isop(LIR_and) && isconst(s1->oprnd2(), 0xffff)) { + LIns* msw = s0->oprnd1(); + LIns* lsw = s1->oprnd1(); + LIns* x; + LIns* y; + if (lsw->isop(LIR_add) && + lsw->oprnd1()->isop(LIR_and) && + lsw->oprnd2()->isop(LIR_and) && + isconst(lsw->oprnd1()->oprnd2(), 0xffff) && + isconst(lsw->oprnd2()->oprnd2(), 0xffff) && + msw->isop(LIR_add) && + msw->oprnd1()->isop(LIR_add) && + msw->oprnd2()->isop(LIR_rsh) && + msw->oprnd1()->oprnd1()->isop(LIR_rsh) && + msw->oprnd1()->oprnd2()->isop(LIR_rsh) && + isconst(msw->oprnd2()->oprnd2(), 16) && + isconst(msw->oprnd1()->oprnd1()->oprnd2(), 16) && + isconst(msw->oprnd1()->oprnd2()->oprnd2(), 16) && + (x = lsw->oprnd1()->oprnd1()) == msw->oprnd1()->oprnd1()->oprnd1() && + (y = lsw->oprnd2()->oprnd1()) == msw->oprnd1()->oprnd2()->oprnd1() && + lsw == msw->oprnd2()->oprnd1()) { + return out->ins2(LIR_add, x, y); + } + } +#ifdef NANOJIT_ARM + else if (v == LIR_lsh || + v == LIR_rsh || + v == LIR_ush) + { + // needed on ARM -- arm doesn't mask shifts to 31 like x86 does + if (s1->isconst()) + s1->setimm16(s1->constval() & 31); + else + s1 = out->ins2(LIR_and, s1, out->insImm(31)); + return out->ins2(v, s0, s1); + } +#endif + + return out->ins2(v, s0, s1); + } + + LInsp insCall(const CallInfo *ci, LInsp args[]) + { + LInsp s0 = args[0]; + if (ci == &js_DoubleToUint32_ci) { + if (s0->isconstq()) + return out->insImm(js_DoubleToECMAUint32(s0->constvalf())); + if (isi2f(s0) || isu2f(s0)) + return iu2fArg(s0); + } else if (ci == &js_DoubleToInt32_ci) { + if (s0->isconstq()) + return out->insImm(js_DoubleToECMAInt32(s0->constvalf())); + if (s0->isop(LIR_fadd) || s0->isop(LIR_fsub)) { + LInsp lhs = s0->oprnd1(); + LInsp rhs = s0->oprnd2(); + if (isPromote(lhs) && isPromote(rhs)) { + LOpcode op = LOpcode(s0->opcode() & ~LIR64); + return out->ins2(op, demote(out, lhs), demote(out, rhs)); + } + } + if (isi2f(s0) || isu2f(s0)) + return iu2fArg(s0); + // XXX ARM -- check for qjoin(call(UnboxDouble),call(UnboxDouble)) + if (s0->isCall() && s0->callInfo() == &js_UnboxDouble_ci) { + LIns* args2[] = { callArgN(s0, 0) }; + return out->insCall(&js_UnboxInt32_ci, args2); + } + if (s0->isCall() && s0->callInfo() == &js_StringToNumber_ci) { + // callArgN's ordering is that as seen by the builtin, not as stored in args here. + // True story! + LIns* args2[] = { callArgN(s0, 1), callArgN(s0, 0) }; + return out->insCall(&js_StringToInt32_ci, args2); + } + } else if (ci == &js_BoxDouble_ci) { + JS_ASSERT(s0->isQuad()); + if (s0->isop(LIR_i2f)) { + LIns* args2[] = { s0->oprnd1(), args[1] }; + return out->insCall(&js_BoxInt32_ci, args2); + } + if (s0->isCall() && s0->callInfo() == &js_UnboxDouble_ci) + return callArgN(s0, 0); + } + return out->insCall(ci, args); + } +}; + +/* In debug mode vpname contains a textual description of the type of the + slot during the forall iteration over al slots. */ +#ifdef JS_JIT_SPEW +#define DEF_VPNAME const char* vpname; unsigned vpnum +#define SET_VPNAME(name) do { vpname = name; vpnum = 0; } while(0) +#define INC_VPNUM() do { ++vpnum; } while(0) +#else +#define DEF_VPNAME do {} while (0) +#define vpname "" +#define vpnum 0 +#define SET_VPNAME(name) ((void)0) +#define INC_VPNUM() ((void)0) +#endif + +/* Iterate over all interned global variables. */ +#define FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, code) \ + JS_BEGIN_MACRO \ + DEF_VPNAME; \ + JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); \ + unsigned n; \ + jsval* vp; \ + SET_VPNAME("global"); \ + for (n = 0; n < ngslots; ++n) { \ + vp = &STOBJ_GET_SLOT(globalObj, gslots[n]); \ + { code; } \ + INC_VPNUM(); \ + } \ + JS_END_MACRO + +/* Iterate over all slots in the frame, consisting of args, vars, and stack + (except for the top-level frame which does not have args or vars. */ +#define FORALL_FRAME_SLOTS(fp, depth, code) \ + JS_BEGIN_MACRO \ + jsval* vp; \ + jsval* vpstop; \ + if (fp->callee) { \ + if (depth == 0) { \ + SET_VPNAME("callee"); \ + vp = &fp->argv[-2]; \ + { code; } \ + SET_VPNAME("this"); \ + vp = &fp->argv[-1]; \ + { code; } \ + SET_VPNAME("argv"); \ + vp = &fp->argv[0]; vpstop = &fp->argv[fp->fun->nargs]; \ + while (vp < vpstop) { code; ++vp; INC_VPNUM(); } \ + } \ + SET_VPNAME("vars"); \ + vp = fp->slots; vpstop = &fp->slots[fp->script->nfixed]; \ + while (vp < vpstop) { code; ++vp; INC_VPNUM(); } \ + } \ + SET_VPNAME("stack"); \ + vp = StackBase(fp); vpstop = fp->regs->sp; \ + while (vp < vpstop) { code; ++vp; INC_VPNUM(); } \ + if (fsp < fspstop - 1) { \ + JSStackFrame* fp2 = fsp[1]; \ + int missing = fp2->fun->nargs - fp2->argc; \ + if (missing > 0) { \ + SET_VPNAME("missing"); \ + vp = fp->regs->sp; \ + vpstop = vp + missing; \ + while (vp < vpstop) { code; ++vp; INC_VPNUM(); } \ + } \ + } \ + JS_END_MACRO + +/* Iterate over all slots in each pending frame. */ +#define FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, code) \ + JS_BEGIN_MACRO \ + DEF_VPNAME; \ + unsigned n; \ + JSStackFrame* currentFrame = cx->fp; \ + JSStackFrame* entryFrame; \ + JSStackFrame* fp = currentFrame; \ + for (n = 0; n < callDepth; ++n) { fp = fp->down; } \ + entryFrame = fp; \ + unsigned frames = callDepth+1; \ + JSStackFrame** fstack = \ + (JSStackFrame**) alloca(frames * sizeof (JSStackFrame*)); \ + JSStackFrame** fspstop = &fstack[frames]; \ + JSStackFrame** fsp = fspstop-1; \ + fp = currentFrame; \ + for (;; fp = fp->down) { *fsp-- = fp; if (fp == entryFrame) break; } \ + unsigned depth; \ + for (depth = 0, fsp = fstack; fsp < fspstop; ++fsp, ++depth) { \ + fp = *fsp; \ + FORALL_FRAME_SLOTS(fp, depth, code); \ + } \ + JS_END_MACRO + +#define FORALL_SLOTS(cx, ngslots, gslots, callDepth, code) \ + JS_BEGIN_MACRO \ + FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, code); \ + FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, code); \ + JS_END_MACRO + +/* Calculate the total number of native frame slots we need from this frame + all the way back to the entry frame, including the current stack usage. */ +unsigned +js_NativeStackSlots(JSContext *cx, unsigned callDepth) +{ + JSStackFrame* fp = cx->fp; + unsigned slots = 0; +#if defined _DEBUG + unsigned int origCallDepth = callDepth; +#endif + for (;;) { + unsigned operands = fp->regs->sp - StackBase(fp); + slots += operands; + if (fp->callee) + slots += fp->script->nfixed; + if (callDepth-- == 0) { + if (fp->callee) + slots += 2/*callee,this*/ + fp->fun->nargs; +#if defined _DEBUG + unsigned int m = 0; + FORALL_SLOTS_IN_PENDING_FRAMES(cx, origCallDepth, m++); + JS_ASSERT(m == slots); +#endif + return slots; + } + JSStackFrame* fp2 = fp; + fp = fp->down; + int missing = fp2->fun->nargs - fp2->argc; + if (missing > 0) + slots += missing; + } + JS_NOT_REACHED("js_NativeStackSlots"); +} + +/* Capture the type map for the selected slots of the global object. */ +void +TypeMap::captureGlobalTypes(JSContext* cx, SlotList& slots) +{ + unsigned ngslots = slots.length(); + uint16* gslots = slots.data(); + setLength(ngslots); + uint8* map = data(); + uint8* m = map; + FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, + uint8 type = getCoercedType(*vp); + if ((type == JSVAL_INT) && oracle.isGlobalSlotUndemotable(cx->fp->script, gslots[n])) + type = JSVAL_DOUBLE; + JS_ASSERT(type != JSVAL_BOXED); + *m++ = type; + ); +} + +/* Capture the type map for the currently pending stack frames. */ +void +TypeMap::captureStackTypes(JSContext* cx, unsigned callDepth) +{ + setLength(js_NativeStackSlots(cx, callDepth)); + uint8* map = data(); + uint8* m = map; + FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, + uint8 type = getCoercedType(*vp); + if ((type == JSVAL_INT) && + oracle.isStackSlotUndemotable(cx->fp->script, cx->fp->regs->pc, unsigned(m - map))) { + type = JSVAL_DOUBLE; + } + debug_only_v(printf("capture %s%d: %d\n", vpname, vpnum, type);) + *m++ = type; + ); +} + +/* Compare this type map to another one and see whether they match. */ +bool +TypeMap::matches(TypeMap& other) const +{ + if (length() != other.length()) + return false; + return !memcmp(data(), other.data(), length()); +} + +/* Use the provided storage area to create a new type map that contains the partial type map + with the rest of it filled up from the complete type map. */ +static void +mergeTypeMaps(uint8** partial, unsigned* plength, uint8* complete, unsigned clength, uint8* mem) +{ + unsigned l = *plength; + JS_ASSERT(l < clength); + memcpy(mem, *partial, l * sizeof(uint8)); + memcpy(mem + l, complete + l, (clength - l) * sizeof(uint8)); + *partial = mem; + *plength = clength; +} + +static void +js_TrashTree(JSContext* cx, Fragment* f); + +TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* _anchor, Fragment* _fragment, + TreeInfo* ti, unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap, + VMSideExit* innermostNestedGuard, Fragment* outerToBlacklist) +{ + JS_ASSERT(!_fragment->vmprivate && ti); + + this->cx = cx; + this->traceMonitor = &JS_TRACE_MONITOR(cx); + this->globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); + this->anchor = _anchor; + this->fragment = _fragment; + this->lirbuf = _fragment->lirbuf; + this->treeInfo = ti; + this->callDepth = _anchor ? _anchor->calldepth : 0; + this->atoms = cx->fp->script->atomMap.vector; + this->deepAborted = false; + this->applyingArguments = false; + this->trashTree = false; + this->whichTreeToTrash = _fragment->root; + this->global_dslots = this->globalObj->dslots; + this->terminate = false; + this->outerToBlacklist = outerToBlacklist; + this->wasRootFragment = _fragment == _fragment->root; + + debug_only_v(printf("recording starting from %s:%u@%u\n", + cx->fp->script->filename, + js_FramePCToLineNumber(cx, cx->fp), + FramePCOffset(cx->fp));) + debug_only_v(printf("globalObj=%p, shape=%d\n", this->globalObj, OBJ_SHAPE(this->globalObj));) + + lir = lir_buf_writer = new (&gc) LirBufWriter(lirbuf); +#ifdef DEBUG + if (verbose_debug) + lir = verbose_filter = new (&gc) VerboseWriter(&gc, lir, lirbuf->names); +#endif +#ifdef NJ_SOFTFLOAT + lir = float_filter = new (&gc) SoftFloatFilter(lir); +#endif + lir = cse_filter = new (&gc) CseFilter(lir, &gc); + lir = expr_filter = new (&gc) ExprFilter(lir); + lir = func_filter = new (&gc) FuncFilter(lir); + lir->ins0(LIR_start); + + if (!nanojit::AvmCore::config.tree_opt || fragment->root == fragment) + lirbuf->state = addName(lir->insParam(0, 0), "state"); + + lirbuf->sp = addName(lir->insLoad(LIR_ldp, lirbuf->state, (int)offsetof(InterpState, sp)), "sp"); + lirbuf->rp = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, rp)), "rp"); + cx_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, cx)), "cx"); + gp_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, gp)), "gp"); + eos_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eos)), "eos"); + eor_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eor)), "eor"); + + /* read into registers all values on the stack and all globals we know so far */ + import(treeInfo, lirbuf->sp, ngslots, callDepth, globalTypeMap, stackTypeMap); + + /* If we are attached to a tree call guard, make sure the guard the inner tree exited from + is what we expect it to be. */ + if (_anchor && _anchor->exitType == NESTED_EXIT) { + LIns* nested_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, + offsetof(InterpState, lastTreeExitGuard)), + "lastTreeExitGuard"); + guard(true, lir->ins2(LIR_eq, nested_ins, INS_CONSTPTR(innermostNestedGuard)), NESTED_EXIT); + } +} + +TreeInfo::~TreeInfo() +{ + UnstableExit* temp; + + while (unstableExits) { + temp = unstableExits->next; + delete unstableExits; + unstableExits = temp; + } +} + +TraceRecorder::~TraceRecorder() +{ + JS_ASSERT(nextRecorderToAbort == NULL); + JS_ASSERT(treeInfo && (fragment || wasDeepAborted())); +#ifdef DEBUG + TraceRecorder* tr = JS_TRACE_MONITOR(cx).abortStack; + while (tr != NULL) + { + JS_ASSERT(this != tr); + tr = tr->nextRecorderToAbort; + } +#endif + if (fragment) { + if (wasRootFragment && !fragment->root->code()) { + JS_ASSERT(!fragment->root->vmprivate); + delete treeInfo; + } + if (trashTree) + js_TrashTree(cx, whichTreeToTrash); + } else if (wasRootFragment) { + delete treeInfo; + } +#ifdef DEBUG + delete verbose_filter; +#endif + delete cse_filter; + delete expr_filter; + delete func_filter; +#ifdef NJ_SOFTFLOAT + delete float_filter; +#endif + delete lir_buf_writer; +} + +void TraceRecorder::removeFragmentoReferences() +{ + fragment = NULL; +} + +/* Add debug information to a LIR instruction as we emit it. */ +inline LIns* +TraceRecorder::addName(LIns* ins, const char* name) +{ +#ifdef DEBUG + lirbuf->names->addName(ins, name); +#endif + return ins; +} + +/* Determine the current call depth (starting with the entry frame.) */ +unsigned +TraceRecorder::getCallDepth() const +{ + return callDepth; +} + +/* Determine the offset in the native global frame for a jsval we track */ +ptrdiff_t +TraceRecorder::nativeGlobalOffset(jsval* p) const +{ + JS_ASSERT(isGlobal(p)); + if (size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS) + return size_t(p - globalObj->fslots) * sizeof(double); + return ((p - globalObj->dslots) + JS_INITIAL_NSLOTS) * sizeof(double); +} + +/* Determine whether a value is a global stack slot */ +bool +TraceRecorder::isGlobal(jsval* p) const +{ + return ((size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS) || + (size_t(p - globalObj->dslots) < (STOBJ_NSLOTS(globalObj) - JS_INITIAL_NSLOTS))); +} + +/* Determine the offset in the native stack for a jsval we track */ +ptrdiff_t +TraceRecorder::nativeStackOffset(jsval* p) const +{ +#ifdef DEBUG + size_t slow_offset = 0; + FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, + if (vp == p) goto done; + slow_offset += sizeof(double) + ); + + /* + * If it's not in a pending frame, it must be on the stack of the current frame above + * sp but below fp->slots + script->nslots. + */ + JS_ASSERT(size_t(p - cx->fp->slots) < cx->fp->script->nslots); + slow_offset += size_t(p - cx->fp->regs->sp) * sizeof(double); + +done: +#define RETURN(offset) { JS_ASSERT((offset) == slow_offset); return offset; } +#else +#define RETURN(offset) { return offset; } +#endif + size_t offset = 0; + JSStackFrame* currentFrame = cx->fp; + JSStackFrame* entryFrame; + JSStackFrame* fp = currentFrame; + for (unsigned n = 0; n < callDepth; ++n) { fp = fp->down; } + entryFrame = fp; + unsigned frames = callDepth+1; + JSStackFrame** fstack = (JSStackFrame **)alloca(frames * sizeof (JSStackFrame *)); + JSStackFrame** fspstop = &fstack[frames]; + JSStackFrame** fsp = fspstop-1; + fp = currentFrame; + for (;; fp = fp->down) { *fsp-- = fp; if (fp == entryFrame) break; } + for (fsp = fstack; fsp < fspstop; ++fsp) { + fp = *fsp; + if (fp->callee) { + if (fsp == fstack) { + if (size_t(p - &fp->argv[-2]) < size_t(2/*callee,this*/ + fp->fun->nargs)) + RETURN(offset + size_t(p - &fp->argv[-2]) * sizeof(double)); + offset += (2/*callee,this*/ + fp->fun->nargs) * sizeof(double); + } + if (size_t(p - &fp->slots[0]) < fp->script->nfixed) + RETURN(offset + size_t(p - &fp->slots[0]) * sizeof(double)); + offset += fp->script->nfixed * sizeof(double); + } + jsval* spbase = StackBase(fp); + if (size_t(p - spbase) < size_t(fp->regs->sp - spbase)) + RETURN(offset + size_t(p - spbase) * sizeof(double)); + offset += size_t(fp->regs->sp - spbase) * sizeof(double); + if (fsp < fspstop - 1) { + JSStackFrame* fp2 = fsp[1]; + int missing = fp2->fun->nargs - fp2->argc; + if (missing > 0) { + if (size_t(p - fp->regs->sp) < size_t(missing)) + RETURN(offset + size_t(p - fp->regs->sp) * sizeof(double)); + offset += size_t(missing) * sizeof(double); + } + } + } + + /* + * If it's not in a pending frame, it must be on the stack of the current frame above + * sp but below fp->slots + script->nslots. + */ + JS_ASSERT(size_t(p - currentFrame->slots) < currentFrame->script->nslots); + offset += size_t(p - currentFrame->regs->sp) * sizeof(double); + RETURN(offset); +#undef RETURN +} + +/* Track the maximum number of native frame slots we need during + execution. */ +void +TraceRecorder::trackNativeStackUse(unsigned slots) +{ + if (slots > treeInfo->maxNativeStackSlots) + treeInfo->maxNativeStackSlots = slots; +} + +/* Unbox a jsval into a slot. Slots are wide enough to hold double values directly (instead of + storing a pointer to them). We now assert instead of type checking, the caller must ensure the + types are compatible. */ +static void +ValueToNative(JSContext* cx, jsval v, uint8 type, double* slot) +{ + unsigned tag = JSVAL_TAG(v); + switch (type) { + case JSVAL_INT: + jsint i; + if (JSVAL_IS_INT(v)) + *(jsint*)slot = JSVAL_TO_INT(v); + else if ((tag == JSVAL_DOUBLE) && JSDOUBLE_IS_INT(*JSVAL_TO_DOUBLE(v), i)) + *(jsint*)slot = i; + else + JS_ASSERT(JSVAL_IS_INT(v)); + debug_only_v(printf("int<%d> ", *(jsint*)slot);) + return; + case JSVAL_DOUBLE: + jsdouble d; + if (JSVAL_IS_INT(v)) + d = JSVAL_TO_INT(v); + else + d = *JSVAL_TO_DOUBLE(v); + JS_ASSERT(JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v)); + *(jsdouble*)slot = d; + debug_only_v(printf("double<%g> ", d);) + return; + case JSVAL_BOOLEAN: + JS_ASSERT(tag == JSVAL_BOOLEAN); + *(JSBool*)slot = JSVAL_TO_BOOLEAN(v); + debug_only_v(printf("boolean<%d> ", *(JSBool*)slot);) + return; + case JSVAL_STRING: + JS_ASSERT(tag == JSVAL_STRING); + *(JSString**)slot = JSVAL_TO_STRING(v); + debug_only_v(printf("string<%p> ", *(JSString**)slot);) + return; + default: + /* Note: we should never see JSVAL_BOXED in an entry type map. */ + JS_ASSERT(type == JSVAL_OBJECT); + JS_ASSERT(tag == JSVAL_OBJECT); + *(JSObject**)slot = JSVAL_TO_OBJECT(v); + debug_only_v(printf("object<%p:%s> ", JSVAL_TO_OBJECT(v), + JSVAL_IS_NULL(v) + ? "null" + : STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v))->name);) + return; + } +} + +/* We maintain an emergency recovery pool of doubles so we can recover safely if a trace runs + out of memory (doubles or objects). */ +static jsval +AllocateDoubleFromRecoveryPool(JSContext* cx) +{ + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + JS_ASSERT(tm->recoveryDoublePoolPtr > tm->recoveryDoublePool); + return *--tm->recoveryDoublePoolPtr; +} + +static bool +js_ReplenishRecoveryPool(JSContext* cx, JSTraceMonitor* tm) +{ + /* We should not be called with a full pool. */ + JS_ASSERT((size_t) (tm->recoveryDoublePoolPtr - tm->recoveryDoublePool) < + MAX_NATIVE_STACK_SLOTS); + + /* + * When the GC runs in js_NewDoubleInRootedValue, it resets + * tm->recoveryDoublePoolPtr back to tm->recoveryDoublePool. + */ + JSRuntime* rt = cx->runtime; + uintN gcNumber = rt->gcNumber; + jsval* ptr = tm->recoveryDoublePoolPtr; + while (ptr < tm->recoveryDoublePool + MAX_NATIVE_STACK_SLOTS) { + if (!js_NewDoubleInRootedValue(cx, 0.0, ptr)) + goto oom; + if (rt->gcNumber != gcNumber) { + JS_ASSERT(tm->recoveryDoublePoolPtr == tm->recoveryDoublePool); + ptr = tm->recoveryDoublePool; + if (uintN(rt->gcNumber - gcNumber) > uintN(1)) + goto oom; + continue; + } + ++ptr; + } + tm->recoveryDoublePoolPtr = ptr; + return true; + +oom: + /* + * Already massive GC pressure, no need to hold doubles back. + * We won't run any native code anyway. + */ + tm->recoveryDoublePoolPtr = tm->recoveryDoublePool; + return false; +} + +/* Box a value from the native stack back into the jsval format. Integers + that are too large to fit into a jsval are automatically boxed into + heap-allocated doubles. */ +static bool +NativeToValue(JSContext* cx, jsval& v, uint8 type, double* slot) +{ + jsint i; + jsdouble d; + switch (type) { + case JSVAL_BOOLEAN: + v = BOOLEAN_TO_JSVAL(*(JSBool*)slot); + debug_only_v(printf("boolean<%d> ", *(JSBool*)slot);) + break; + case JSVAL_INT: + i = *(jsint*)slot; + debug_only_v(printf("int<%d> ", i);) + store_int: + if (INT_FITS_IN_JSVAL(i)) { + v = INT_TO_JSVAL(i); + break; + } + d = (jsdouble)i; + goto store_double; + case JSVAL_DOUBLE: + d = *slot; + debug_only_v(printf("double<%g> ", d);) + if (JSDOUBLE_IS_INT(d, i)) + goto store_int; + store_double: { + /* Its not safe to trigger the GC here, so use an emergency heap if we are out of + double boxes. */ + if (cx->doubleFreeList) { +#ifdef DEBUG + bool ok = +#endif + js_NewDoubleInRootedValue(cx, d, &v); + JS_ASSERT(ok); + return true; + } + v = AllocateDoubleFromRecoveryPool(cx); + JS_ASSERT(JSVAL_IS_DOUBLE(v) && *JSVAL_TO_DOUBLE(v) == 0.0); + *JSVAL_TO_DOUBLE(v) = d; + return true; + } + case JSVAL_STRING: + v = STRING_TO_JSVAL(*(JSString**)slot); + JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING); /* if this fails the pointer was not aligned */ + debug_only_v(printf("string<%p> ", *(JSString**)slot);) + break; + case JSVAL_BOXED: + v = *(jsval*)slot; + debug_only_v(printf("box<%lx> ", v)); + break; + default: + JS_ASSERT(type == JSVAL_OBJECT); + v = OBJECT_TO_JSVAL(*(JSObject**)slot); + JS_ASSERT(JSVAL_TAG(v) == JSVAL_OBJECT); /* if this fails the pointer was not aligned */ + debug_only_v(printf("object<%p:%s> ", JSVAL_TO_OBJECT(v), + JSVAL_IS_NULL(v) + ? "null" + : STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v))->name);) + break; + } + return true; +} + +/* Attempt to unbox the given list of interned globals onto the native global frame. */ +static void +BuildNativeGlobalFrame(JSContext* cx, unsigned ngslots, uint16* gslots, uint8* mp, double* np) +{ + debug_only_v(printf("global: ");) + FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, + ValueToNative(cx, *vp, *mp, np + gslots[n]); + ++mp; + ); + debug_only_v(printf("\n");) +} + +/* Attempt to unbox the given JS frame onto a native frame. */ +static void +BuildNativeStackFrame(JSContext* cx, unsigned callDepth, uint8* mp, double* np) +{ + debug_only_v(printf("stack: ");) + FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, + debug_only_v(printf("%s%u=", vpname, vpnum);) + ValueToNative(cx, *vp, *mp, np); + ++mp; ++np; + ); + debug_only_v(printf("\n");) +} + +/* Box the given native frame into a JS frame. This only fails due to a hard error + (out of memory for example). */ +static int +FlushNativeGlobalFrame(JSContext* cx, unsigned ngslots, uint16* gslots, uint8* mp, double* np) +{ + uint8* mp_base = mp; + FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, + if (!NativeToValue(cx, *vp, *mp, np + gslots[n])) + return -1; + ++mp; + ); + debug_only_v(printf("\n");) + return mp - mp_base; +} + +/** + * Box the given native stack frame into the virtual machine stack. This fails + * only due to a hard error (out of memory for example). + * + * @param callDepth the distance between the entry frame into our trace and + * cx->fp when we make this call. If this is not called as a + * result of a nested exit, callDepth is 0. + * @param mp pointer to an array of type tags (JSVAL_INT, etc.) that indicate + * what the types of the things on the stack are. + * @param np pointer to the native stack. We want to copy values from here to + * the JS stack as needed. + * @param stopFrame if non-null, this frame and everything above it should not + * be restored. + * @return the number of things we popped off of np. + */ +static int +FlushNativeStackFrame(JSContext* cx, unsigned callDepth, uint8* mp, double* np, + JSStackFrame* stopFrame) +{ + jsval* stopAt = stopFrame ? &stopFrame->argv[-2] : NULL; + uint8* mp_base = mp; + /* Root all string and object references first (we don't need to call the GC for this). */ + FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, + if (vp == stopAt) goto skip; + debug_only_v(printf("%s%u=", vpname, vpnum);) + if (!NativeToValue(cx, *vp, *mp, np)) + return -1; + ++mp; ++np + ); +skip: + // Restore thisp from the now-restored argv[-1] in each pending frame. + // Keep in mind that we didn't restore frames at stopFrame and above! + // Scope to keep |fp| from leaking into the macros we're using. + { + unsigned n = callDepth+1; // +1 to make sure we restore the entry frame + JSStackFrame* fp = cx->fp; + if (stopFrame) { + for (; fp != stopFrame; fp = fp->down) { + JS_ASSERT(n != 0); + --n; + } + // Skip over stopFrame itself. + JS_ASSERT(n != 0); + --n; + fp = fp->down; + } + for (; n != 0; fp = fp->down) { + --n; + if (fp->callee) { // might not have it if the entry frame is global + JS_ASSERT(JSVAL_IS_OBJECT(fp->argv[-1])); + fp->thisp = JSVAL_TO_OBJECT(fp->argv[-1]); + } + } + } + debug_only_v(printf("\n");) + return mp - mp_base; +} + +/* Emit load instructions onto the trace that read the initial stack state. */ +void +TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, uint8& t, + const char *prefix, uintN index, JSStackFrame *fp) +{ + LIns* ins; + if (t == JSVAL_INT) { /* demoted */ + JS_ASSERT(isInt32(*p)); + /* Ok, we have a valid demotion attempt pending, so insert an integer + read and promote it to double since all arithmetic operations expect + to see doubles on entry. The first op to use this slot will emit a + f2i cast which will cancel out the i2f we insert here. */ + ins = lir->insLoadi(base, offset); + ins = lir->ins1(LIR_i2f, ins); + } else { + JS_ASSERT(t == JSVAL_BOXED || isNumber(*p) == (t == JSVAL_DOUBLE)); + if (t == JSVAL_DOUBLE) { + ins = lir->insLoad(LIR_ldq, base, offset); + } else if (t == JSVAL_BOOLEAN) { + ins = lir->insLoad(LIR_ld, base, offset); + } else { + ins = lir->insLoad(LIR_ldp, base, offset); + } + } + tracker.set(p, ins); +#ifdef DEBUG + char name[64]; + JS_ASSERT(strlen(prefix) < 10); + void* mark = NULL; + jsuword* localNames = NULL; + const char* funName = NULL; + if (*prefix == 'a' || *prefix == 'v') { + mark = JS_ARENA_MARK(&cx->tempPool); + if (JS_GET_LOCAL_NAME_COUNT(fp->fun) != 0) + localNames = js_GetLocalNameArray(cx, fp->fun, &cx->tempPool); + funName = fp->fun->atom ? js_AtomToPrintableString(cx, fp->fun->atom) : ""; + } + if (!strcmp(prefix, "argv")) { + if (index < fp->fun->nargs) { + JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(localNames[index]); + JS_snprintf(name, sizeof name, "$%s.%s", funName, js_AtomToPrintableString(cx, atom)); + } else { + JS_snprintf(name, sizeof name, "$%s.", funName, index); + } + } else if (!strcmp(prefix, "vars")) { + JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(localNames[fp->fun->nargs + index]); + JS_snprintf(name, sizeof name, "$%s.%s", funName, js_AtomToPrintableString(cx, atom)); + } else { + JS_snprintf(name, sizeof name, "$%s%d", prefix, index); + } + + if (mark) + JS_ARENA_RELEASE(&cx->tempPool, mark); + addName(ins, name); + + static const char* typestr[] = { + "object", "int", "double", "3", "string", "5", "boolean", "any" + }; + debug_only_v(printf("import vp=%p name=%s type=%s flags=%d\n", + p, name, typestr[t & 7], t >> 3);) +#endif +} + +void +TraceRecorder::import(TreeInfo* treeInfo, LIns* sp, unsigned ngslots, unsigned callDepth, + uint8* globalTypeMap, uint8* stackTypeMap) +{ + /* If we get a partial list that doesn't have all the types (i.e. recording from a side + exit that was recorded but we added more global slots later), merge the missing types + from the entry type map. This is safe because at the loop edge we verify that we + have compatible types for all globals (entry type and loop edge type match). While + a different trace of the tree might have had a guard with a different type map for + these slots we just filled in here (the guard we continue from didn't know about them), + since we didn't take that particular guard the only way we could have ended up here + is if that other trace had at its end a compatible type distribution with the entry + map. Since thats exactly what we used to fill in the types our current side exit + didn't provide, this is always safe to do. */ + unsigned length; + if (ngslots < (length = traceMonitor->globalTypeMap->length())) + mergeTypeMaps(&globalTypeMap, &ngslots, + traceMonitor->globalTypeMap->data(), length, + (uint8*)alloca(sizeof(uint8) * length)); + JS_ASSERT(ngslots == traceMonitor->globalTypeMap->length()); + + /* the first time we compile a tree this will be empty as we add entries lazily */ + uint16* gslots = traceMonitor->globalSlots->data(); + uint8* m = globalTypeMap; + FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, + import(gp_ins, nativeGlobalOffset(vp), vp, *m, vpname, vpnum, NULL); + m++; + ); + ptrdiff_t offset = -treeInfo->nativeStackBase; + m = stackTypeMap; + FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, + import(sp, offset, vp, *m, vpname, vpnum, fp); + m++; offset += sizeof(double); + ); +} + +/* Lazily import a global slot if we don't already have it in the tracker. */ +bool +TraceRecorder::lazilyImportGlobalSlot(unsigned slot) +{ + if (slot != uint16(slot)) /* we use a table of 16-bit ints, bail out if that's not enough */ + return false; + jsval* vp = &STOBJ_GET_SLOT(globalObj, slot); + if (tracker.has(vp)) + return true; /* we already have it */ + unsigned index = traceMonitor->globalSlots->length(); + /* If this the first global we are adding, remember the shape of the global object. */ + if (index == 0) + traceMonitor->globalShape = OBJ_SHAPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain)); + /* Add the slot to the list of interned global slots. */ + traceMonitor->globalSlots->add(slot); + uint8 type = getCoercedType(*vp); + if ((type == JSVAL_INT) && oracle.isGlobalSlotUndemotable(cx->fp->script, slot)) + type = JSVAL_DOUBLE; + traceMonitor->globalTypeMap->add(type); + import(gp_ins, slot*sizeof(double), vp, type, "global", index, NULL); + return true; +} + +/* Write back a value onto the stack or global frames. */ +LIns* +TraceRecorder::writeBack(LIns* i, LIns* base, ptrdiff_t offset) +{ + /* Sink all type casts targeting the stack into the side exit by simply storing the original + (uncasted) value. Each guard generates the side exit map based on the types of the + last stores to every stack location, so its safe to not perform them on-trace. */ + if (isPromoteInt(i)) + i = ::demote(lir, i); + return lir->insStorei(i, base, offset); +} + +/* Update the tracker, then issue a write back store. */ +void +TraceRecorder::set(jsval* p, LIns* i, bool initializing) +{ + JS_ASSERT(initializing || tracker.has(p)); + tracker.set(p, i); + /* If we are writing to this location for the first time, calculate the offset into the + native frame manually, otherwise just look up the last load or store associated with + the same source address (p) and use the same offset/base. */ + LIns* x = nativeFrameTracker.get(p); + if (!x) { + if (isGlobal(p)) + x = writeBack(i, gp_ins, nativeGlobalOffset(p)); + else + x = writeBack(i, lirbuf->sp, -treeInfo->nativeStackBase + nativeStackOffset(p)); + nativeFrameTracker.set(p, x); + } else { +#define ASSERT_VALID_CACHE_HIT(base, offset) \ + JS_ASSERT(base == lirbuf->sp || base == gp_ins); \ + JS_ASSERT(offset == ((base == lirbuf->sp) \ + ? -treeInfo->nativeStackBase + nativeStackOffset(p) \ + : nativeGlobalOffset(p))); \ + + if (x->isop(LIR_st) || x->isop(LIR_stq)) { + ASSERT_VALID_CACHE_HIT(x->oprnd2(), x->oprnd3()->constval()); + writeBack(i, x->oprnd2(), x->oprnd3()->constval()); + } else { + JS_ASSERT(x->isop(LIR_sti) || x->isop(LIR_stqi)); + ASSERT_VALID_CACHE_HIT(x->oprnd2(), x->immdisp()); + writeBack(i, x->oprnd2(), x->immdisp()); + } + } +#undef ASSERT_VALID_CACHE_HIT +} + +LIns* +TraceRecorder::get(jsval* p) const +{ + return tracker.get(p); +} + +/* Determine whether the current branch instruction terminates the loop. */ +static bool +js_IsLoopExit(jsbytecode* pc, jsbytecode* header) +{ + switch (*pc) { + case JSOP_LT: + case JSOP_GT: + case JSOP_LE: + case JSOP_GE: + case JSOP_NE: + case JSOP_EQ: + /* These ops try to dispatch a JSOP_IFEQ or JSOP_IFNE that follows. */ + JS_ASSERT(js_CodeSpec[*pc].length == 1); + pc++; + break; + + default: + for (;;) { + if (*pc == JSOP_AND || *pc == JSOP_OR) + pc += GET_JUMP_OFFSET(pc); + else if (*pc == JSOP_ANDX || *pc == JSOP_ORX) + pc += GET_JUMPX_OFFSET(pc); + else + break; + } + } + + switch (*pc) { + case JSOP_IFEQ: + case JSOP_IFNE: + /* + * Forward jumps are usually intra-branch, but for-in loops jump to the + * trailing enditer to clean up, so check for that case here. + */ + if (pc[GET_JUMP_OFFSET(pc)] == JSOP_ENDITER) + return true; + return pc + GET_JUMP_OFFSET(pc) == header; + + case JSOP_IFEQX: + case JSOP_IFNEX: + if (pc[GET_JUMPX_OFFSET(pc)] == JSOP_ENDITER) + return true; + return pc + GET_JUMPX_OFFSET(pc) == header; + + default:; + } + return false; +} + +/* Determine whether the current branch is a loop edge (taken or not taken). */ +static bool +js_IsLoopEdge(jsbytecode* pc, jsbytecode* header) +{ + switch (*pc) { + case JSOP_IFEQ: + case JSOP_IFNE: + return ((pc + GET_JUMP_OFFSET(pc)) == header); + case JSOP_IFEQX: + case JSOP_IFNEX: + return ((pc + GET_JUMPX_OFFSET(pc)) == header); + default: + JS_ASSERT((*pc == JSOP_AND) || (*pc == JSOP_ANDX) || + (*pc == JSOP_OR) || (*pc == JSOP_ORX)); + } + return false; +} + +/* Promote slots if necessary to match the called tree' type map and report error if thats + impossible. */ +bool +TraceRecorder::adjustCallerTypes(Fragment* f, unsigned* demote_slots, bool& trash) +{ + JSTraceMonitor* tm = traceMonitor; + uint8* m = tm->globalTypeMap->data(); + uint16* gslots = traceMonitor->globalSlots->data(); + unsigned ngslots = traceMonitor->globalSlots->length(); + uint8* map = ((TreeInfo*)f->vmprivate)->stackTypeMap.data(); + bool ok = true; + trash = false; + FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, + LIns* i = get(vp); + bool isPromote = isPromoteInt(i); + if (isPromote && *m == JSVAL_DOUBLE) + lir->insStorei(get(vp), gp_ins, nativeGlobalOffset(vp)); + else if (!isPromote && *m == JSVAL_INT) { + oracle.markGlobalSlotUndemotable(cx->fp->script, nativeGlobalOffset(vp)/sizeof(double)); + trash = true; + ok = false; + } + ++m; + ); + m = map; + FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0, + LIns* i = get(vp); + bool isPromote = isPromoteInt(i); + if (isPromote && *m == JSVAL_DOUBLE) { + lir->insStorei(get(vp), lirbuf->sp, + -treeInfo->nativeStackBase + nativeStackOffset(vp)); + /* Aggressively undo speculation so the inner tree will compile if this fails. */ + ADD_UNDEMOTE_SLOT(demote_slots, unsigned(m - map)); + } else if (!isPromote && *m == JSVAL_INT) { + debug_only_v(printf("adjusting will fail, %s%d, slot %d\n", vpname, vpnum, m - map);) + ok = false; + ADD_UNDEMOTE_SLOT(demote_slots, unsigned(m - map)); + } else if (JSVAL_IS_INT(*vp) && *m == JSVAL_DOUBLE) { + /* Aggressively undo speculation so the inner tree will compile if this fails. */ + ADD_UNDEMOTE_SLOT(demote_slots, unsigned(m - map)); + } + ++m; + ); + /* If this isn't okay, tell the oracle. */ + if (!ok) { + for (unsigned i = 1; i <= NUM_UNDEMOTE_SLOTS(demote_slots); i++) + oracle.markStackSlotUndemotable(cx->fp->script, cx->fp->regs->pc, demote_slots[i]); + } + JS_ASSERT(f == f->root); + return ok; +} + +uint8 +TraceRecorder::determineSlotType(jsval* vp) const +{ + uint8 m; + LIns* i = get(vp); + m = isNumber(*vp) + ? (isPromoteInt(i) ? JSVAL_INT : JSVAL_DOUBLE) + : JSVAL_TAG(*vp); + JS_ASSERT((m != JSVAL_INT) || isInt32(*vp)); + return m; +} + +#define IMACRO_PC_ADJ_BITS 8 +#define SCRIPT_PC_ADJ_BITS (32 - IMACRO_PC_ADJ_BITS) + +// The stored imacro_pc_adj byte offset is biased by 1. +#define IMACRO_PC_ADJ_LIMIT (JS_BIT(IMACRO_PC_ADJ_BITS) - 1) +#define SCRIPT_PC_ADJ_LIMIT JS_BIT(SCRIPT_PC_ADJ_BITS) + +#define IMACRO_PC_ADJ(ip) ((uintptr_t)(ip) >> SCRIPT_PC_ADJ_BITS) +#define SCRIPT_PC_ADJ(ip) ((ip) & JS_BITMASK(SCRIPT_PC_ADJ_BITS)) + +#define FI_SCRIPT_PC(fi,fp) ((fp)->script->code + SCRIPT_PC_ADJ((fi).ip_adj)) + +#define FI_IMACRO_PC(fi,fp) (IMACRO_PC_ADJ((fi).ip_adj) \ + ? imacro_code[*FI_SCRIPT_PC(fi, fp)] + \ + IMACRO_PC_ADJ((fi).ip_adj) \ + : NULL) + +#define IMACRO_PC_OK(fp,pc) JS_ASSERT(uintN((pc)-imacro_code[*(fp)->imacpc]) \ + < JS_BIT(IMACRO_PC_ADJ_BITS)) +#define ENCODE_IP_ADJ(fp,pc) ((fp)->imacpc \ + ? (IMACRO_PC_OK(fp, pc), \ + (((pc) - imacro_code[*(fp)->imacpc]) \ + << SCRIPT_PC_ADJ_BITS) + \ + (fp)->imacpc - (fp)->script->code) \ + : (pc) - (fp)->script->code) + +#define DECODE_IP_ADJ(ip,fp) (IMACRO_PC_ADJ(ip) \ + ? (fp)->imacpc = (fp)->script->code + \ + SCRIPT_PC_ADJ(ip), \ + (fp)->regs->pc = imacro_code[*(fp)->imacpc] + \ + IMACRO_PC_ADJ(ip) \ + : (fp)->regs->pc = (fp)->script->code + (ip)) + +static jsbytecode* imacro_code[JSOP_LIMIT]; + +LIns* +TraceRecorder::snapshot(ExitType exitType) +{ + JSStackFrame* fp = cx->fp; + JSFrameRegs* regs = fp->regs; + jsbytecode* pc = regs->pc; + if (exitType == BRANCH_EXIT && js_IsLoopExit(pc, (jsbytecode*)fragment->root->ip)) + exitType = LOOP_EXIT; + + /* Check for a return-value opcode that needs to restart at the next instruction. */ + const JSCodeSpec& cs = js_CodeSpec[*pc]; + + /* WARNING: don't return before restoring the original pc if (resumeAfter). */ + bool resumeAfter = (pendingTraceableNative && + JSTN_ERRTYPE(pendingTraceableNative) == FAIL_JSVAL); + if (resumeAfter) { + JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_APPLY || *pc == JSOP_NEXTITER); + pc += cs.length; + regs->pc = pc; + MUST_FLOW_THROUGH("restore_pc"); + } + + /* Generate the entry map for the (possibly advanced) pc and stash it in the trace. */ + unsigned stackSlots = js_NativeStackSlots(cx, callDepth); + + /* It's sufficient to track the native stack use here since all stores above the + stack watermark defined by guards are killed. */ + trackNativeStackUse(stackSlots + 1); + + /* Capture the type map into a temporary location. */ + unsigned ngslots = traceMonitor->globalSlots->length(); + unsigned typemap_size = (stackSlots + ngslots) * sizeof(uint8); + uint8* typemap = (uint8*)alloca(typemap_size); + uint8* m = typemap; + + /* Determine the type of a store by looking at the current type of the actual value the + interpreter is using. For numbers we have to check what kind of store we used last + (integer or double) to figure out what the side exit show reflect in its typemap. */ + FORALL_SLOTS(cx, ngslots, traceMonitor->globalSlots->data(), callDepth, + *m++ = determineSlotType(vp); + ); + JS_ASSERT(unsigned(m - typemap) == ngslots + stackSlots); + + /* If we are capturing the stack state on a specific instruction, the value on or near + the top of the stack is a boxed value. Either pc[-cs.length] is JSOP_NEXTITER and we + want one below top of stack, or else it's JSOP_CALL and we want top of stack. */ + if (resumeAfter) { + m[(pc[-cs.length] == JSOP_NEXTITER) ? -2 : -1] = JSVAL_BOXED; + + /* Now restore the the original pc (after which early returns are ok). */ + MUST_FLOW_LABEL(restore_pc); + regs->pc = pc - cs.length; + } else { + /* If we take a snapshot on a goto, advance to the target address. This avoids inner + trees returning on a break goto, which the outer recorder then would confuse with + a break in the outer tree. */ + if (*pc == JSOP_GOTO) + pc += GET_JUMP_OFFSET(pc); + else if (*pc == JSOP_GOTOX) + pc += GET_JUMPX_OFFSET(pc); + } + intptr_t ip_adj = ENCODE_IP_ADJ(fp, pc); + + /* Check if we already have a matching side exit. If so use that side exit structure, + otherwise we have to create our own. */ + VMSideExit** exits = treeInfo->sideExits.data(); + unsigned nexits = treeInfo->sideExits.length(); + if (exitType == LOOP_EXIT) { + for (unsigned n = 0; n < nexits; ++n) { + VMSideExit* e = exits[n]; + if (e->ip_adj == ip_adj && + !memcmp(getTypeMap(exits[n]), typemap, typemap_size)) { + LIns* data = lir_buf_writer->skip(sizeof(GuardRecord)); + GuardRecord* rec = (GuardRecord*)data->payload(); + /* setup guard record structure with shared side exit */ + memset(rec, 0, sizeof(GuardRecord)); + VMSideExit* exit = exits[n]; + rec->exit = exit; + exit->addGuard(rec); + AUDIT(mergedLoopExits); + return data; + } + } + } + + /* We couldn't find a matching side exit, so create our own side exit structure. */ + LIns* data = lir_buf_writer->skip(sizeof(GuardRecord) + + sizeof(VMSideExit) + + (stackSlots + ngslots) * sizeof(uint8)); + GuardRecord* rec = (GuardRecord*)data->payload(); + VMSideExit* exit = (VMSideExit*)(rec + 1); + /* setup guard record structure */ + memset(rec, 0, sizeof(GuardRecord)); + rec->exit = exit; + /* setup side exit structure */ + memset(exit, 0, sizeof(VMSideExit)); + exit->from = fragment; + exit->calldepth = callDepth; + exit->numGlobalSlots = ngslots; + exit->numStackSlots = stackSlots; + exit->numStackSlotsBelowCurrentFrame = cx->fp->callee + ? nativeStackOffset(&cx->fp->argv[-2])/sizeof(double) + : 0; + exit->exitType = exitType; + exit->addGuard(rec); + exit->ip_adj = ip_adj; + exit->sp_adj = (stackSlots * sizeof(double)) - treeInfo->nativeStackBase; + exit->rp_adj = exit->calldepth * sizeof(FrameInfo); + memcpy(getTypeMap(exit), typemap, typemap_size); + + /* BIG FAT WARNING: If compilation fails, we currently don't reset the lirbuf so its safe + to keep references to the side exits here. If we ever start rewinding those lirbufs, + we have to make sure we purge the side exits that then no longer will be in valid + memory. */ + if (exitType == LOOP_EXIT) + treeInfo->sideExits.add(exit); + return data; +} + +/* Emit a guard for condition (cond), expecting to evaluate to boolean result (expected) + and using the supplied side exit if the conditon doesn't hold. */ +LIns* +TraceRecorder::guard(bool expected, LIns* cond, LIns* exit) +{ + return lir->insGuard(expected ? LIR_xf : LIR_xt, cond, exit); +} + +/* Emit a guard for condition (cond), expecting to evaluate to boolean result (expected) + and generate a side exit with type exitType to jump to if the condition does not hold. */ +LIns* +TraceRecorder::guard(bool expected, LIns* cond, ExitType exitType) +{ + return guard(expected, cond, snapshot(exitType)); +} + +/* Try to match the type of a slot to type t. checkType is used to verify that the type of + * values flowing into the loop edge is compatible with the type we expect in the loop header. + * + * @param v Value. + * @param t Typemap entry for value. + * @param stage_val Outparam for set() address. + * @param stage_ins Outparam for set() instruction. + * @param stage_count Outparam for set() buffer count. + * @return True if types are compatible, false otherwise. + */ +bool +TraceRecorder::checkType(jsval& v, uint8 t, jsval*& stage_val, LIns*& stage_ins, + unsigned& stage_count) +{ + if (t == JSVAL_INT) { /* initially all whole numbers cause the slot to be demoted */ + debug_only_v(printf("checkType(tag=1, t=%d, isnum=%d, i2f=%d) stage_count=%d\n", + t, + isNumber(v), + isPromoteInt(get(&v)), + stage_count);) + if (!isNumber(v)) + return false; /* not a number? type mismatch */ + LIns* i = get(&v); + /* This is always a type mismatch, we can't close a double to an int. */ + if (!isPromoteInt(i)) + return false; + /* Looks good, slot is an int32, the last instruction should be promotable. */ + JS_ASSERT(isInt32(v) && isPromoteInt(i)); + /* Overwrite the value in this slot with the argument promoted back to an integer. */ + stage_val = &v; + stage_ins = f2i(i); + stage_count++; + return true; + } + if (t == JSVAL_DOUBLE) { + debug_only_v(printf("checkType(tag=2, t=%d, isnum=%d, promote=%d) stage_count=%d\n", + t, + isNumber(v), + isPromoteInt(get(&v)), + stage_count);) + if (!isNumber(v)) + return false; /* not a number? type mismatch */ + LIns* i = get(&v); + /* We sink i2f conversions into the side exit, but at the loop edge we have to make + sure we promote back to double if at loop entry we want a double. */ + if (isPromoteInt(i)) { + stage_val = &v; + stage_ins = lir->ins1(LIR_i2f, i); + stage_count++; + } + return true; + } + /* for non-number types we expect a precise match of the type */ +#ifdef DEBUG + if (JSVAL_TAG(v) != t) { + debug_only_v(printf("Type mismatch: val %c, map %c ", typeChar[JSVAL_TAG(v)], + typeChar[t]);) + } +#endif + debug_only_v(printf("checkType(tag=%d, t=%d) stage_count=%d\n", + (int) JSVAL_TAG(v), t, stage_count);) + return JSVAL_TAG(v) == t; +} + +/** + * Make sure that the current values in the given stack frame and all stack frames + * up and including entryFrame are type-compatible with the entry map. + * + * @param root_peer First fragment in peer list. + * @param stable_peer Outparam for first type stable peer. + * @param trash Whether to trash the tree (demotion). + * @param demotes Array to store demotable stack slots. + * @return True if type stable, false otherwise. + */ +bool +TraceRecorder::deduceTypeStability(Fragment* root_peer, Fragment** stable_peer, unsigned* demotes) +{ + uint8* m; + uint8* typemap; + unsigned ngslots = traceMonitor->globalSlots->length(); + uint16* gslots = traceMonitor->globalSlots->data(); + JS_ASSERT(traceMonitor->globalTypeMap->length() == ngslots); + + if (stable_peer) + *stable_peer = NULL; + + CLEAR_UNDEMOTE_SLOTLIST(demotes); + + /* + * Rather than calculate all of this stuff twice, it gets cached locally. The "stage" buffers + * are for calls to set() that will change the exit types. + */ + bool success; + bool unstable_from_undemotes; + unsigned stage_count; + jsval** stage_vals = (jsval**)alloca(sizeof(jsval*) * (ngslots + treeInfo->stackTypeMap.length())); + LIns** stage_ins = (LIns**)alloca(sizeof(LIns*) * (ngslots + treeInfo->stackTypeMap.length())); + + /* First run through and see if we can close ourselves - best case! */ + stage_count = 0; + success = false; + unstable_from_undemotes = false; + + debug_only_v(printf("Checking type stability against self=%p\n", fragment);) + + m = typemap = traceMonitor->globalTypeMap->data(); + FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, + debug_only_v(printf("%s%d ", vpname, vpnum);) + if (!checkType(*vp, *m, stage_vals[stage_count], stage_ins[stage_count], stage_count)) { + /* If the failure was an int->double, tell the oracle. */ + if (*m == JSVAL_INT && isNumber(*vp) && !isPromoteInt(get(vp))) + oracle.markGlobalSlotUndemotable(cx->fp->script, gslots[n]); + trashTree = true; + goto checktype_fail_1; + } + ++m; + ); + m = typemap = treeInfo->stackTypeMap.data(); + FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0, + debug_only_v(printf("%s%d ", vpname, vpnum);) + if (!checkType(*vp, *m, stage_vals[stage_count], stage_ins[stage_count], stage_count)) { + if (*m == JSVAL_INT && isNumber(*vp) && !isPromoteInt(get(vp))) + ADD_UNDEMOTE_SLOT(demotes, unsigned(m - typemap)); + else + goto checktype_fail_1; + } + ++m; + ); + + /* + * If there's an exit that's unstable because of undemotable slots, we want to search for + * peers just in case we can make a connection. + */ + if (NUM_UNDEMOTE_SLOTS(demotes)) + unstable_from_undemotes = true; + else + success = true; + +checktype_fail_1: + /* If we got a success and we don't need to recompile, we should just close here. */ + if (success) { + for (unsigned i = 0; i < stage_count; i++) + set(stage_vals[i], stage_ins[i]); + return true; + /* If we need to trash, don't bother checking peers. */ + } else if (trashTree) { + return false; + } else { + CLEAR_UNDEMOTE_SLOTLIST(demotes); + } + + /* At this point the tree is about to be incomplete, so let's see if we can connect to any + * peer fragment that is type stable. + */ + Fragment* f; + TreeInfo* ti; + for (f = root_peer; f != NULL; f = f->peer) { + debug_only_v(printf("Checking type stability against peer=%p (code=%p)\n", f, f->code());) + if (!f->code()) + continue; + ti = (TreeInfo*)f->vmprivate; + /* Don't allow varying stack depths */ + if (ti->stackTypeMap.length() != treeInfo->stackTypeMap.length()) + continue; + stage_count = 0; + success = false; + m = ti->stackTypeMap.data(); + + FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0, + if (!checkType(*vp, *m, stage_vals[stage_count], stage_ins[stage_count], stage_count)) + goto checktype_fail_2; + ++m; + ); + + success = true; + +checktype_fail_2: + if (success) { + /* + * There was a successful match. We don't care about restoring the saved staging, but + * we do need to clear the original undemote list. + */ + for (unsigned i = 0; i < stage_count; i++) + set(stage_vals[i], stage_ins[i]); + if (stable_peer) + *stable_peer = f; + return false; + } + } + + JS_ASSERT(NUM_UNDEMOTE_SLOTS(demotes) == 0); + + /* + * If this is a loop trace and it would be stable with demotions, build an undemote list + * and return true. Our caller should sniff this and trash the tree, recording a new one + * that will assumedly stabilize. + */ + if (unstable_from_undemotes && fragment->kind == LoopTrace) { + typemap = m = treeInfo->stackTypeMap.data(); + FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0, + if (*m == JSVAL_INT) { + JS_ASSERT(isNumber(*vp)); + if (!isPromoteInt(get(vp))) + ADD_UNDEMOTE_SLOT(demotes, unsigned(m - typemap)); + } else if (*m == JSVAL_DOUBLE) { + JS_ASSERT(isNumber(*vp)); + ADD_UNDEMOTE_SLOT(demotes, unsigned(m - typemap)); + } else { + JS_ASSERT(*m == JSVAL_TAG(*vp)); + } + m++; + ); + return true; + } + + return false; +} + +/* Check whether the current pc location is the loop header of the loop this recorder records. */ +bool +TraceRecorder::isLoopHeader(JSContext* cx) const +{ + return cx->fp->regs->pc == fragment->root->ip; +} + +/* Compile the current fragment. */ +void +TraceRecorder::compile(Fragmento* fragmento) +{ + if (treeInfo->maxNativeStackSlots >= MAX_NATIVE_STACK_SLOTS) { + debug_only_v(printf("Trace rejected: excessive stack use.\n")); + js_BlacklistPC(fragmento, fragment); + return; + } + ++treeInfo->branchCount; + if (lirbuf->outOmem()) { + fragmento->assm()->setError(nanojit::OutOMem); + return; + } + ::compile(fragmento->assm(), fragment); + if (anchor) + fragmento->assm()->patch(anchor); + if (fragmento->assm()->error() != nanojit::None) + return; + JS_ASSERT(fragment->code()); + JS_ASSERT(!fragment->vmprivate); + if (fragment == fragment->root) + fragment->vmprivate = treeInfo; + /* :TODO: windows support */ +#if defined DEBUG && !defined WIN32 + const char* filename = cx->fp->script->filename; + char* label = (char*)malloc((filename ? strlen(filename) : 7) + 16); + sprintf(label, "%s:%u", filename ? filename : "", + js_FramePCToLineNumber(cx, cx->fp)); + fragmento->labels->add(fragment, sizeof(Fragment), 0, label); + free(label); +#endif + AUDIT(traceCompleted); +} + +static bool +js_JoinPeersIfCompatible(Fragmento* frago, Fragment* stableFrag, TreeInfo* stableTree, + VMSideExit* exit) +{ + JS_ASSERT(exit->numStackSlots == stableTree->stackTypeMap.length()); + /* Must have a matching type unstable exit. */ + if (memcmp(getTypeMap(exit) + exit->numGlobalSlots, + stableTree->stackTypeMap.data(), + stableTree->stackTypeMap.length()) != 0) { + return false; + } + + exit->target = stableFrag; + frago->assm()->patch(exit); + + stableTree->dependentTrees.addUnique(exit->from->root); + + return true; +} + +/* Complete and compile a trace and link it to the existing tree if appropriate. */ +bool +TraceRecorder::closeLoop(Fragmento* fragmento, bool& demote, unsigned *demotes) +{ + bool stable; + LIns* exitIns; + Fragment* peer; + VMSideExit* exit; + Fragment* peer_root; + + demote = false; + + exitIns = snapshot(UNSTABLE_LOOP_EXIT); + exit = (VMSideExit*)((GuardRecord*)exitIns->payload())->exit; + + if (callDepth != 0) { + debug_only_v(printf("Stack depth mismatch, possible recursion\n");) + js_BlacklistPC(fragmento, fragment); + trashTree = true; + return false; + } + + JS_ASSERT(exit->numStackSlots == treeInfo->stackTypeMap.length()); + + peer_root = fragmento->getLoop(fragment->root->ip); + JS_ASSERT(peer_root != NULL); + stable = deduceTypeStability(peer_root, &peer, demotes); + + #if DEBUG + if (!stable || NUM_UNDEMOTE_SLOTS(demotes)) + AUDIT(unstableLoopVariable); + #endif + + if (trashTree) { + debug_only_v(printf("Trashing tree from type instability.\n");) + return false; + } + + if (stable && NUM_UNDEMOTE_SLOTS(demotes)) { + JS_ASSERT(fragment->kind == LoopTrace); + demote = true; + return false; + } + + if (!stable) { + fragment->lastIns = lir->insGuard(LIR_x, lir->insImm(1), exitIns); + + /* + * If we didn't find a type stable peer, we compile the loop anyway and + * hope it becomes stable later. + */ + if (!peer) { + /* + * If such a fragment does not exist, let's compile the loop ahead + * of time anyway. Later, if the loop becomes type stable, we will + * connect these two fragments together. + */ + debug_only_v(printf("Trace has unstable loop variable with no stable peer, " + "compiling anyway.\n");) + UnstableExit* uexit = new UnstableExit; + uexit->fragment = fragment; + uexit->exit = exit; + uexit->next = treeInfo->unstableExits; + treeInfo->unstableExits = uexit; + + /* + * If we walked out of a loop, this exit is wrong. We need to back + * up to the if operation. + */ + if (walkedOutOfLoop()) + exit->ip_adj = terminate_ip_adj; + + /* If we were trying to stabilize a promotable tree, trash it. */ + if (promotedPeer) + js_TrashTree(cx, promotedPeer); + } else { + JS_ASSERT(peer->code()); + exit->target = peer; + debug_only_v(printf("Joining type-unstable trace to target fragment %p.\n", peer);) + stable = true; + ((TreeInfo*)peer->vmprivate)->dependentTrees.addUnique(fragment->root); + } + + compile(fragmento); + } else { + exit->target = fragment->root; +#if defined(JS_HAS_OPERATION_COUNT) && !JS_HAS_OPERATION_COUNT + exit->exitType = TIMEOUT_EXIT; + guard(false, + lir->ins_eq0(lir->insLoadi(cx_ins, + offsetof(JSContext, operationCount))), + exitIns); +#endif + fragment->lastIns = lir->insGuard(LIR_loop, lir->insImm(1), exitIns); + compile(fragmento); + } + + if (fragmento->assm()->error() != nanojit::None) + return false; + + joinEdgesToEntry(fragmento, peer_root); + + debug_only_v(printf("recording completed at %s:%u@%u via closeLoop\n", + cx->fp->script->filename, + js_FramePCToLineNumber(cx, cx->fp), + FramePCOffset(cx->fp));) + return true; +} + +void +TraceRecorder::joinEdgesToEntry(Fragmento* fragmento, Fragment* peer_root) +{ + if (fragment->kind == LoopTrace) { + TreeInfo* ti; + Fragment* peer; + uint8* t1, *t2; + UnstableExit* uexit, **unext; + + unsigned* demotes = (unsigned*)alloca(treeInfo->stackTypeMap.length() * sizeof(unsigned)); + for (peer = peer_root; peer != NULL; peer = peer->peer) { + if (!peer->code()) + continue; + ti = (TreeInfo*)peer->vmprivate; + uexit = ti->unstableExits; + unext = &ti->unstableExits; + while (uexit != NULL) { + bool remove = js_JoinPeersIfCompatible(fragmento, fragment, treeInfo, uexit->exit); + JS_ASSERT(!remove || fragment != peer); + debug_only_v(if (remove) { + printf("Joining type-stable trace to target exit %p->%p.\n", + uexit->fragment, uexit->exit); }); + if (!remove) { + /* See if this exit contains mismatch demotions, which imply trashing a tree. + This is actually faster than trashing the original tree as soon as the + instability is detected, since we could have compiled a fairly stable + tree that ran faster with integers. */ + unsigned count = 0; + t1 = treeInfo->stackTypeMap.data(); + t2 = getTypeMap(uexit->exit) + uexit->exit->numGlobalSlots; + for (unsigned i = 0; i < uexit->exit->numStackSlots; i++) { + if (t2[i] == JSVAL_INT && t1[i] == JSVAL_DOUBLE) { + demotes[count++] = i; + } else if (t2[i] != t1[i]) { + count = 0; + break; + } + } + if (count) { + for (unsigned i = 0; i < count; i++) + oracle.markStackSlotUndemotable(cx->fp->script, + cx->fp->regs->pc, demotes[i]); + js_TrashTree(cx, uexit->fragment->root); + break; + } + } + if (remove) { + *unext = uexit->next; + delete uexit; + uexit = *unext; + } else { + unext = &uexit->next; + uexit = uexit->next; + } + } + } + } + + debug_only_v(js_DumpPeerStability(fragmento, peer_root->ip);) +} + +/* Emit an always-exit guard and compile the tree (used for break statements. */ +void +TraceRecorder::endLoop(Fragmento* fragmento) +{ + LIns* exitIns = snapshot(LOOP_EXIT); + + if (callDepth != 0) { + debug_only_v(printf("Stack depth mismatch, possible recursion\n");) + js_BlacklistPC(fragmento, fragment); + trashTree = true; + return; + } + + fragment->lastIns = lir->insGuard(LIR_x, lir->insImm(1), exitIns); + compile(fragmento); + + if (fragmento->assm()->error() != nanojit::None) + return; + + joinEdgesToEntry(fragmento, fragmento->getLoop(fragment->root->ip)); + + debug_only_v(printf("recording completed at %s:%u@%u via endLoop\n", + cx->fp->script->filename, + js_FramePCToLineNumber(cx, cx->fp), + FramePCOffset(cx->fp));) +} + +/* Emit code to adjust the stack to match the inner tree's stack expectations. */ +void +TraceRecorder::prepareTreeCall(Fragment* inner) +{ + TreeInfo* ti = (TreeInfo*)inner->vmprivate; + inner_sp_ins = lirbuf->sp; + /* The inner tree expects to be called from the current frame. If the outer tree (this + trace) is currently inside a function inlining code (calldepth > 0), we have to advance + the native stack pointer such that we match what the inner trace expects to see. We + move it back when we come out of the inner tree call. */ + if (callDepth > 0) { + /* Calculate the amount we have to lift the native stack pointer by to compensate for + any outer frames that the inner tree doesn't expect but the outer tree has. */ + ptrdiff_t sp_adj = nativeStackOffset(&cx->fp->argv[-2]); + /* Calculate the amount we have to lift the call stack by */ + ptrdiff_t rp_adj = callDepth * sizeof(FrameInfo); + /* Guard that we have enough stack space for the tree we are trying to call on top + of the new value for sp. */ + debug_only_v(printf("sp_adj=%d outer=%d inner=%d\n", + sp_adj, treeInfo->nativeStackBase, ti->nativeStackBase)); + LIns* sp_top = lir->ins2i(LIR_piadd, lirbuf->sp, + - treeInfo->nativeStackBase /* rebase sp to beginning of outer tree's stack */ + + sp_adj /* adjust for stack in outer frame inner tree can't see */ + + ti->maxNativeStackSlots * sizeof(double)); /* plus the inner tree's stack */ + guard(true, lir->ins2(LIR_lt, sp_top, eos_ins), OOM_EXIT); + /* Guard that we have enough call stack space. */ + LIns* rp_top = lir->ins2i(LIR_piadd, lirbuf->rp, rp_adj + + ti->maxCallDepth * sizeof(FrameInfo)); + guard(true, lir->ins2(LIR_lt, rp_top, eor_ins), OOM_EXIT); + /* We have enough space, so adjust sp and rp to their new level. */ + lir->insStorei(inner_sp_ins = lir->ins2i(LIR_piadd, lirbuf->sp, + - treeInfo->nativeStackBase /* rebase sp to beginning of outer tree's stack */ + + sp_adj /* adjust for stack in outer frame inner tree can't see */ + + ti->nativeStackBase), /* plus the inner tree's stack base */ + lirbuf->state, offsetof(InterpState, sp)); + lir->insStorei(lir->ins2i(LIR_piadd, lirbuf->rp, rp_adj), + lirbuf->state, offsetof(InterpState, rp)); + } +} + +/* Record a call to an inner tree. */ +void +TraceRecorder::emitTreeCall(Fragment* inner, VMSideExit* exit) +{ + TreeInfo* ti = (TreeInfo*)inner->vmprivate; + /* Invoke the inner tree. */ + LIns* args[] = { INS_CONSTPTR(inner), lirbuf->state }; /* reverse order */ + LIns* ret = lir->insCall(&js_CallTree_ci, args); + /* Read back all registers, in case the called tree changed any of them. */ + import(ti, inner_sp_ins, exit->numGlobalSlots, exit->calldepth, + getTypeMap(exit), getTypeMap(exit) + exit->numGlobalSlots); + /* Restore sp and rp to their original values (we still have them in a register). */ + if (callDepth > 0) { + lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp)); + lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp)); + } + /* Guard that we come out of the inner tree along the same side exit we came out when + we called the inner tree at recording time. */ + guard(true, lir->ins2(LIR_eq, ret, INS_CONSTPTR(exit)), NESTED_EXIT); + /* Register us as a dependent tree of the inner tree. */ + ((TreeInfo*)inner->vmprivate)->dependentTrees.addUnique(fragment->root); +} + +/* Add a if/if-else control-flow merge point to the list of known merge points. */ +void +TraceRecorder::trackCfgMerges(jsbytecode* pc) +{ + /* If we hit the beginning of an if/if-else, then keep track of the merge point after it. */ + JS_ASSERT((*pc == JSOP_IFEQ) || (*pc == JSOP_IFEQX)); + jssrcnote* sn = js_GetSrcNote(cx->fp->script, pc); + if (sn != NULL) { + if (SN_TYPE(sn) == SRC_IF) { + cfgMerges.add((*pc == JSOP_IFEQ) + ? pc + GET_JUMP_OFFSET(pc) + : pc + GET_JUMPX_OFFSET(pc)); + } else if (SN_TYPE(sn) == SRC_IF_ELSE) + cfgMerges.add(pc + js_GetSrcNoteOffset(sn, 0)); + } +} + +/* Invert the direction of the guard if this is a loop edge that is not + taken (thin loop). */ +void +TraceRecorder::flipIf(jsbytecode* pc, bool& cond) +{ + if (js_IsLoopEdge(pc, (jsbytecode*)fragment->root->ip)) { + switch (*pc) { + case JSOP_IFEQ: + case JSOP_IFEQX: + if (!cond) + return; + break; + case JSOP_IFNE: + case JSOP_IFNEX: + if (cond) + return; + break; + default: + JS_NOT_REACHED("flipIf"); + } + /* We are about to walk out of the loop, so terminate it with + an inverse loop condition. */ + debug_only_v(printf("Walking out of the loop, terminating it anyway.\n");) + cond = !cond; + terminate = true; + /* If when we get to closeLoop the tree is decided to be type unstable, we need to + reverse this logic because the loop won't be closed after all. Store the real + value of the IP the interpreter expects, so we can use it in our final LIR_x. + */ + if (*pc == JSOP_IFEQX || *pc == JSOP_IFNEX) + pc += GET_JUMPX_OFFSET(pc); + else + pc += GET_JUMP_OFFSET(pc); + terminate_ip_adj = ENCODE_IP_ADJ(cx->fp, pc); + } +} + +/* Emit code for a fused IFEQ/IFNE. */ +void +TraceRecorder::fuseIf(jsbytecode* pc, bool cond, LIns* x) +{ + if (x->isconst()) // no need to guard if condition is constant + return; + if (*pc == JSOP_IFEQ) { + flipIf(pc, cond); + guard(cond, x, BRANCH_EXIT); + trackCfgMerges(pc); + } else if (*pc == JSOP_IFNE) { + flipIf(pc, cond); + guard(cond, x, BRANCH_EXIT); + } +} + +bool +TraceRecorder::hasMethod(JSObject* obj, jsid id) +{ + if (!obj) + return false; + + JSObject* pobj; + JSProperty* prop; + int protoIndex = OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop); + if (protoIndex < 0 || !prop) + return false; + + bool found = false; + if (OBJ_IS_NATIVE(pobj)) { + JSScope* scope = OBJ_SCOPE(pobj); + JSScopeProperty* sprop = (JSScopeProperty*) prop; + + if (SPROP_HAS_STUB_GETTER(sprop) && + SPROP_HAS_VALID_SLOT(sprop, scope)) { + jsval v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot); + if (VALUE_IS_FUNCTION(cx, v)) { + found = true; + if (!SCOPE_IS_BRANDED(scope)) { + SCOPE_MAKE_UNIQUE_SHAPE(cx, scope); + SCOPE_SET_BRANDED(scope); + } + } + } + } + + OBJ_DROP_PROPERTY(cx, pobj, prop); + return found; +} + +bool +TraceRecorder::hasToStringMethod(JSObject* obj) +{ + JS_ASSERT(cx->fp->regs->sp + 1 <= cx->fp->slots + cx->fp->script->nslots); + + return hasMethod(obj, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom)); +} + +bool +TraceRecorder::hasValueOfMethod(JSObject* obj) +{ + JS_ASSERT(cx->fp->regs->sp + 2 <= cx->fp->slots + cx->fp->script->nslots); + + return hasMethod(obj, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom)); +} + +bool +TraceRecorder::hasIteratorMethod(JSObject* obj) +{ + JS_ASSERT(cx->fp->regs->sp + 2 <= cx->fp->slots + cx->fp->script->nslots); + + return hasMethod(obj, ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom)); +} + +int +nanojit::StackFilter::getTop(LInsp guard) +{ + VMSideExit* e = (VMSideExit*)guard->record()->exit; + if (sp == lirbuf->sp) + return e->sp_adj; + JS_ASSERT(sp == lirbuf->rp); + return e->rp_adj; +} + +#if defined NJ_VERBOSE +void +nanojit::LirNameMap::formatGuard(LIns *i, char *out) +{ + VMSideExit *x; + + x = (VMSideExit *)i->record()->exit; + sprintf(out, + "%s: %s %s -> %lu:%lu sp%+ld rp%+ld", + formatRef(i), + lirNames[i->opcode()], + i->oprnd1()->isCond() ? formatRef(i->oprnd1()) : "", + IMACRO_PC_ADJ(x->ip_adj), + SCRIPT_PC_ADJ(x->ip_adj), + (long int)x->sp_adj, + (long int)x->rp_adj); +} +#endif + +void +nanojit::Fragment::onDestroy() +{ + if (root == this) { + delete mergeCounts; + delete lirbuf; + } + delete (TreeInfo *)vmprivate; +} + +void +js_DeleteRecorder(JSContext* cx) +{ + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + + /* Aborting and completing a trace end up here. */ + JS_ASSERT(tm->onTrace); + tm->onTrace = false; + + delete tm->recorder; + tm->recorder = NULL; +} + +/** + * Checks whether the shape of the global object has changed. + */ +static inline bool +js_CheckGlobalObjectShape(JSContext* cx, JSTraceMonitor* tm, JSObject* globalObj) +{ + /* Check the global shape. */ + if (OBJ_SHAPE(globalObj) != tm->globalShape) { + AUDIT(globalShapeMismatchAtEntry); + debug_only_v(printf("Global shape mismatch (%u vs. %u), flushing cache.\n", + OBJ_SHAPE(globalObj), tm->globalShape);) + return false; + } + return true; +} + +static bool +js_StartRecorder(JSContext* cx, VMSideExit* anchor, Fragment* f, TreeInfo* ti, + unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap, + VMSideExit* expectedInnerExit, Fragment* outer) +{ + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + + /* + * Emulate on-trace semantics and avoid rooting headaches while recording, + * by suppressing last-ditch GC attempts while recording a trace. This does + * means that trace recording must not nest or the following assertion will + * botch. + */ + JS_ASSERT(!tm->onTrace); + tm->onTrace = true; + + /* start recording if no exception during construction */ + tm->recorder = new (&gc) TraceRecorder(cx, anchor, f, ti, + ngslots, globalTypeMap, stackTypeMap, + expectedInnerExit, outer); + if (cx->throwing) { + js_AbortRecording(cx, "setting up recorder failed"); + return false; + } + /* clear any leftover error state */ + tm->fragmento->assm()->setError(None); + return true; +} + +static void +js_TrashTree(JSContext* cx, Fragment* f) +{ + JS_ASSERT((!f->code()) == (!f->vmprivate)); + JS_ASSERT(f == f->root); + if (!f->code()) + return; + AUDIT(treesTrashed); + debug_only_v(printf("Trashing tree info.\n");) + Fragmento* fragmento = JS_TRACE_MONITOR(cx).fragmento; + TreeInfo* ti = (TreeInfo*)f->vmprivate; + f->vmprivate = NULL; + f->releaseCode(fragmento); + Fragment** data = ti->dependentTrees.data(); + unsigned length = ti->dependentTrees.length(); + for (unsigned n = 0; n < length; ++n) + js_TrashTree(cx, data[n]); + delete ti; + JS_ASSERT(!f->code() && !f->vmprivate); +} + +static int +js_SynthesizeFrame(JSContext* cx, const FrameInfo& fi) +{ + JS_ASSERT(HAS_FUNCTION_CLASS(fi.callee)); + + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, fi.callee); + JS_ASSERT(FUN_INTERPRETED(fun)); + + /* Assert that we have a correct sp distance from cx->fp->slots in fi. */ + JS_ASSERT_IF(!FI_IMACRO_PC(fi, cx->fp), + js_ReconstructStackDepth(cx, cx->fp->script, FI_SCRIPT_PC(fi, cx->fp)) + == uintN(fi.s.spdist - cx->fp->script->nfixed)); + + uintN nframeslots = JS_HOWMANY(sizeof(JSInlineFrame), sizeof(jsval)); + JSScript* script = fun->u.i.script; + size_t nbytes = (nframeslots + script->nslots) * sizeof(jsval); + + /* Code duplicated from inline_call: case in js_Interpret (FIXME). */ + JSArena* a = cx->stackPool.current; + void* newmark = (void*) a->avail; + uintN argc = fi.s.argc & 0x7fff; + jsval* vp = cx->fp->slots + fi.s.spdist - (2 + argc); + uintN missing = 0; + jsval* newsp; + + if (fun->nargs > argc) { + const JSFrameRegs& regs = *cx->fp->regs; + + newsp = vp + 2 + fun->nargs; + JS_ASSERT(newsp > regs.sp); + if ((jsuword) newsp <= a->limit) { + if ((jsuword) newsp > a->avail) + a->avail = (jsuword) newsp; + jsval* argsp = newsp; + do { + *--argsp = JSVAL_VOID; + } while (argsp != regs.sp); + missing = 0; + } else { + missing = fun->nargs - argc; + nbytes += (2 + fun->nargs) * sizeof(jsval); + } + } + + /* Allocate the inline frame with its vars and operands. */ + if (a->avail + nbytes <= a->limit) { + newsp = (jsval *) a->avail; + a->avail += nbytes; + JS_ASSERT(missing == 0); + } else { + JS_ARENA_ALLOCATE_CAST(newsp, jsval *, &cx->stackPool, nbytes); + if (!newsp) { + js_ReportOutOfScriptQuota(cx); + return 0; + } + + /* + * Move args if the missing ones overflow arena a, then push + * undefined for the missing args. + */ + if (missing) { + memcpy(newsp, vp, (2 + argc) * sizeof(jsval)); + vp = newsp; + newsp = vp + 2 + argc; + do { + *newsp++ = JSVAL_VOID; + } while (--missing != 0); + } + } + + /* Claim space for the stack frame and initialize it. */ + JSInlineFrame* newifp = (JSInlineFrame *) newsp; + newsp += nframeslots; + + newifp->frame.callobj = NULL; + newifp->frame.argsobj = NULL; + newifp->frame.varobj = NULL; + newifp->frame.script = script; + newifp->frame.callee = fi.callee; + newifp->frame.fun = fun; + + bool constructing = fi.s.argc & 0x8000; + newifp->frame.argc = argc; + + jsbytecode* imacro_pc = FI_IMACRO_PC(fi, cx->fp); + jsbytecode* script_pc = FI_SCRIPT_PC(fi, cx->fp); + newifp->callerRegs.pc = imacro_pc ? imacro_pc : script_pc; + newifp->callerRegs.sp = cx->fp->slots + fi.s.spdist; + cx->fp->imacpc = imacro_pc ? script_pc : NULL; + + newifp->frame.argv = newifp->callerRegs.sp - argc; + JS_ASSERT(newifp->frame.argv); +#ifdef DEBUG + // Initialize argv[-1] to a known-bogus value so we'll catch it if + // someone forgets to initialize it later. + newifp->frame.argv[-1] = JSVAL_HOLE; +#endif + JS_ASSERT(newifp->frame.argv >= StackBase(cx->fp) + 2); + + newifp->frame.rval = JSVAL_VOID; + newifp->frame.down = cx->fp; + newifp->frame.annotation = NULL; + newifp->frame.scopeChain = OBJ_GET_PARENT(cx, fi.callee); + newifp->frame.sharpDepth = 0; + newifp->frame.sharpArray = NULL; + newifp->frame.flags = constructing ? JSFRAME_CONSTRUCTING : 0; + newifp->frame.dormantNext = NULL; + newifp->frame.xmlNamespace = NULL; + newifp->frame.blockChain = NULL; + newifp->mark = newmark; + newifp->frame.thisp = NULL; // will be set by js_ExecuteTree -> FlushNativeStackFrame + + newifp->frame.regs = cx->fp->regs; + newifp->frame.regs->pc = script->code; + newifp->frame.regs->sp = newsp + script->nfixed; + newifp->frame.imacpc = NULL; + newifp->frame.slots = newsp; + if (script->staticDepth < JS_DISPLAY_SIZE) { + JSStackFrame **disp = &cx->display[script->staticDepth]; + newifp->frame.displaySave = *disp; + *disp = &newifp->frame; + } +#ifdef DEBUG + newifp->frame.pcDisabledSave = 0; +#endif + + /* + * Note that cx->fp->script is still the caller's script; set the callee + * inline frame's idea of caller version from its version. + */ + newifp->callerVersion = (JSVersion) cx->fp->script->version; + + cx->fp->regs = &newifp->callerRegs; + cx->fp = &newifp->frame; + + if (fun->flags & JSFUN_HEAVYWEIGHT) { + /* + * Set hookData to null because the failure case for js_GetCallObject + * involves it calling the debugger hook. + */ + newifp->hookData = NULL; + if (!js_GetCallObject(cx, &newifp->frame, newifp->frame.scopeChain)) + return -1; + } + + /* + * If there's a call hook, invoke it to compute the hookData used by + * debuggers that cooperate with the interpreter. + */ + JSInterpreterHook hook = cx->debugHooks->callHook; + if (hook) { + newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0, + cx->debugHooks->callHookData); + } else { + newifp->hookData = NULL; + } + + // FIXME? we must count stack slots from caller's operand stack up to (but not including) + // callee's, including missing arguments. Could we shift everything down to the caller's + // fp->slots (where vars start) and avoid some of the complexity? + return (fi.s.spdist - cx->fp->down->script->nfixed) + + ((fun->nargs > cx->fp->argc) ? fun->nargs - cx->fp->argc : 0) + + script->nfixed; +} + +bool +js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, Fragment* outer, unsigned* demotes) +{ + JS_ASSERT(cx->fp->regs->pc == f->ip && f->root == f); + + /* Avoid recording loops in overlarge scripts. */ + if (cx->fp->script->length >= SCRIPT_PC_ADJ_LIMIT) { + js_AbortRecording(cx, "script too large"); + return false; + } + + /* Make sure the global type map didn't change on us. */ + JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); + if (!js_CheckGlobalObjectShape(cx, tm, globalObj)) { + js_FlushJITCache(cx); + return false; + } + TypeMap current; + current.captureGlobalTypes(cx, *tm->globalSlots); + if (!current.matches(*tm->globalTypeMap)) { + js_FlushJITCache(cx); + debug_only_v(printf("Global type map mismatch in RecordTree, flushing cache.\n");) + return false; + } + + AUDIT(recorderStarted); + + /* Try to find an unused peer fragment, or allocate a new one. */ + while (f->code() && f->peer) + f = f->peer; + if (f->code()) + f = JS_TRACE_MONITOR(cx).fragmento->getAnchor(f->root->ip); + + f->recordAttempts++; + f->root = f; + /* allocate space to store the LIR for this tree */ + if (!f->lirbuf) { + f->lirbuf = new (&gc) LirBuffer(tm->fragmento, NULL); +#ifdef DEBUG + f->lirbuf->names = new (&gc) LirNameMap(&gc, NULL, tm->fragmento->labels); +#endif + } + + if (f->lirbuf->outOmem()) { + js_FlushJITCache(cx); + debug_only_v(printf("Out of memory recording new tree, flushing cache.\n");) + return false; + } + + JS_ASSERT(!f->code() && !f->vmprivate); + + /* setup the VM-private treeInfo structure for this fragment */ + TreeInfo* ti = new (&gc) TreeInfo(f); + + /* capture the coerced type of each active slot in the stack type map */ + ti->stackTypeMap.captureStackTypes(cx, 0/*callDepth*/); + + if (demotes) { + /* If we get a list of demotions, an outer tree is telling us our types are not callable. */ + uint8* typeMap = ti->stackTypeMap.data(); + for (unsigned i = 1; i <= NUM_UNDEMOTE_SLOTS(demotes); i++) { + JS_ASSERT(demotes[i] < ti->stackTypeMap.length()); + if (typeMap[demotes[i]] == JSVAL_INT) + typeMap[demotes[i]] = JSVAL_DOUBLE; + } + } + + /* Check for duplicate entry type maps. This is always wrong and hints at trace explosion + since we are trying to stabilize something without properly connecting peer edges. */ + #ifdef DEBUG + TreeInfo* ti_other; + for (Fragment* peer = tm->fragmento->getLoop(f->root->ip); peer != NULL; peer = peer->peer) { + if (!peer->code() || peer == f) + continue; + ti_other = (TreeInfo*)peer->vmprivate; + JS_ASSERT(ti_other); + JS_ASSERT(!ti->stackTypeMap.matches(ti_other->stackTypeMap)); + } + #endif + + /* determine the native frame layout at the entry point */ + unsigned entryNativeStackSlots = ti->stackTypeMap.length(); + JS_ASSERT(entryNativeStackSlots == js_NativeStackSlots(cx, 0/*callDepth*/)); + ti->nativeStackBase = (entryNativeStackSlots - + (cx->fp->regs->sp - StackBase(cx->fp))) * sizeof(double); + ti->maxNativeStackSlots = entryNativeStackSlots; + ti->maxCallDepth = 0; + ti->script = cx->fp->script; + + /* recording primary trace */ + if (!js_StartRecorder(cx, NULL, f, ti, + tm->globalSlots->length(), tm->globalTypeMap->data(), + ti->stackTypeMap.data(), NULL, outer)) { + return false; + } + + return true; +} + +static bool +js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, Fragment* outer) +{ + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + Fragment* from = exit->from->root; + unsigned* demotes; + + JS_ASSERT(exit->from->root->code()); + + demotes = ALLOCA_UNDEMOTE_SLOTLIST(exit->numStackSlots); + CLEAR_UNDEMOTE_SLOTLIST(demotes); + + uint8* t2 = getTypeMap(exit) + exit->numGlobalSlots; + for (unsigned i = 0; i < exit->numStackSlots; i++) { + if (t2[i] == JSVAL_DOUBLE) + ADD_UNDEMOTE_SLOT(demotes, i); + } + + if (!NUM_UNDEMOTE_SLOTS(demotes)) + demotes = NULL; + + if (!js_RecordTree(cx, tm, from->first, outer, demotes)) + return false; + + tm->recorder->setPromotedPeer(demotes ? from : NULL); + + return true; +} + +static bool +js_AttemptToExtendTree(JSContext* cx, VMSideExit* anchor, VMSideExit* exitedFrom, Fragment* outer) +{ + Fragment* f = anchor->from->root; + JS_ASSERT(f->vmprivate); + TreeInfo* ti = (TreeInfo*)f->vmprivate; + + /* Don't grow trees above a certain size to avoid code explosion due to tail duplication. */ + if (ti->branchCount >= MAX_BRANCHES) + return false; + + Fragment* c; + if (!(c = anchor->target)) { + c = JS_TRACE_MONITOR(cx).fragmento->createBranch(anchor, cx->fp->regs->pc); + c->spawnedFrom = anchor; + c->parent = f; + anchor->target = c; + c->root = f; + } + + debug_only_v(printf("trying to attach another branch to the tree (hits = %d)\n", c->hits());) + + if (++c->hits() >= HOTEXIT) { + /* start tracing secondary trace from this point */ + c->lirbuf = f->lirbuf; + unsigned ngslots; + uint8* globalTypeMap; + uint8* stackTypeMap; + TypeMap fullMap; + if (exitedFrom == NULL) { + /* If we are coming straight from a simple side exit, just use that exit's type map + as starting point. */ + ngslots = anchor->numGlobalSlots; + globalTypeMap = getTypeMap(anchor); + stackTypeMap = globalTypeMap + ngslots; + } else { + /* If we side-exited on a loop exit and continue on a nesting guard, the nesting + guard (anchor) has the type information for everything below the current scope, + and the actual guard we exited from has the types for everything in the current + scope (and whatever it inlined). We have to merge those maps here. */ + VMSideExit* e1 = anchor; + VMSideExit* e2 = exitedFrom; + fullMap.add(getTypeMap(e1) + e1->numGlobalSlots, e1->numStackSlotsBelowCurrentFrame); + fullMap.add(getTypeMap(e2) + e2->numGlobalSlots, e2->numStackSlots); + ngslots = e2->numGlobalSlots; + globalTypeMap = getTypeMap(e2); + stackTypeMap = fullMap.data(); + } + return js_StartRecorder(cx, anchor, c, (TreeInfo*)f->vmprivate, + ngslots, globalTypeMap, stackTypeMap, exitedFrom, outer); + } + return false; +} + +static VMSideExit* +js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount, + VMSideExit** innermostNestedGuardp); + +static Fragment* +js_FindVMCompatiblePeer(JSContext* cx, Fragment* f); + +static bool +js_CloseLoop(JSContext* cx) +{ + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + Fragmento* fragmento = tm->fragmento; + TraceRecorder* r = tm->recorder; + JS_ASSERT(fragmento && r); + bool walkedOutOfLoop = r->walkedOutOfLoop(); + + if (fragmento->assm()->error()) { + js_AbortRecording(cx, "Error during recording"); + + /* If we ran out of memory, flush the code cache and abort. */ + if (fragmento->assm()->error() == OutOMem) + js_FlushJITCache(cx); + return false; + } + + bool demote; + Fragment* f = r->getFragment(); + TreeInfo* ti = r->getTreeInfo(); + unsigned* demotes = ALLOCA_UNDEMOTE_SLOTLIST(ti->stackTypeMap.length()); + r->closeLoop(fragmento, demote, demotes); + JS_ASSERT(!demote || NUM_UNDEMOTE_SLOTS(demotes)); + js_DeleteRecorder(cx); + + /* + * If we just walked out of a thin loop, we can't immediately start the + * compiler again here since we didn't return to the loop header. + */ + if (demote && !walkedOutOfLoop) + return js_RecordTree(cx, tm, f, NULL, demotes); + return false; +} + +bool +js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount) +{ +#ifdef JS_THREADSAFE + if (OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->title.ownercx != cx) { + js_AbortRecording(cx, "Global object not owned by this context"); + return false; /* we stay away from shared global objects */ + } +#endif + Fragmento* fragmento = JS_TRACE_MONITOR(cx).fragmento; + /* If we hit our own loop header, close the loop and compile the trace. */ + if (r->isLoopHeader(cx)) + return js_CloseLoop(cx); + /* does this branch go to an inner loop? */ + Fragment* f = fragmento->getLoop(cx->fp->regs->pc); + Fragment* peer_root = f; + if (nesting_enabled && f) { + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + + /* Make sure inner tree call will not run into an out-of-memory condition. */ + if (tm->recoveryDoublePoolPtr < (tm->recoveryDoublePool + MAX_NATIVE_STACK_SLOTS) && + !js_ReplenishRecoveryPool(cx, tm)) { + js_AbortRecording(cx, "Couldn't call inner tree (out of memory)"); + return false; + } + + /* Make sure the shape of the global object still matches (this might flush + the JIT cache). */ + JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); + if (!js_CheckGlobalObjectShape(cx, tm, globalObj)) { + js_AbortRecording(cx, "Couldn't call inner tree (prep failed)"); + return false; + } + + debug_only_v(printf("Looking for type-compatible peer (%s:%d@%d)\n", + cx->fp->script->filename, + js_FramePCToLineNumber(cx, cx->fp), + FramePCOffset(cx->fp));) + + /* Find an acceptable peer, make sure our types fit. */ + Fragment* empty; + bool trash = false; + bool success = false; + unsigned* demotes = NULL; + + f = r->findNestedCompatiblePeer(f, &empty); + if (f && f->code()) { + TreeInfo* ti = (TreeInfo*)f->vmprivate; + /* alloca docs says it lasts out of scopes. */ + demotes = ALLOCA_UNDEMOTE_SLOTLIST(ti->stackTypeMap.length()); + CLEAR_UNDEMOTE_SLOTLIST(demotes); + success = r->adjustCallerTypes(f, demotes, trash); + } + + if (!success) { + AUDIT(noCompatInnerTrees); + debug_only_v(printf("No compatible inner tree (%p).\n", f);) + + if (trash) { + js_AbortRecording(cx, "No compatible inner tree (global demotions"); + return false; + } + + Fragment* old = fragmento->getLoop(tm->recorder->getFragment()->root->ip); + if (old == NULL) + old = tm->recorder->getFragment(); + js_AbortRecording(cx, "No compatible inner tree"); + if (!f && ++peer_root->hits() < MAX_INNER_RECORD_BLACKLIST) + return false; + if (old->recordAttempts < MAX_MISMATCH) + old->resetHits(); + f = empty ? empty : tm->fragmento->getAnchor(cx->fp->regs->pc); + return js_RecordTree(cx, tm, f, old, demotes); + } + + r->prepareTreeCall(f); + VMSideExit* innermostNestedGuard = NULL; + VMSideExit* lr = js_ExecuteTree(cx, f, inlineCallCount, &innermostNestedGuard); + if (!lr) { + js_AbortRecording(cx, "Couldn't call inner tree"); + return false; + } + Fragment* old; + switch (lr->exitType) { + case LOOP_EXIT: + /* If the inner tree exited on an unknown loop exit, grow the tree around it. */ + if (innermostNestedGuard) { + js_AbortRecording(cx, "Inner tree took different side exit, abort recording"); + return js_AttemptToExtendTree(cx, innermostNestedGuard, lr, NULL); + } + /* emit a call to the inner tree and continue recording the outer tree trace */ + r->emitTreeCall(f, lr); + return true; + case UNSTABLE_LOOP_EXIT: + /* abort recording so the inner loop can become type stable. */ + old = fragmento->getLoop(tm->recorder->getFragment()->root->ip); + js_AbortRecording(cx, "Inner tree is trying to stabilize, abort outer recording"); + old->resetHits(); + return js_AttemptToStabilizeTree(cx, lr, old); + case BRANCH_EXIT: + /* abort recording the outer tree, extend the inner tree */ + old = fragmento->getLoop(tm->recorder->getFragment()->root->ip); + js_AbortRecording(cx, "Inner tree is trying to grow, abort outer recording"); + old->resetHits(); + return js_AttemptToExtendTree(cx, lr, NULL, old); + default: + debug_only_v(printf("exit_type=%d\n", lr->exitType);) + js_AbortRecording(cx, "Inner tree not suitable for calling"); + return false; + } + } + + /* not returning to our own loop header, not an inner loop we can call, abort trace */ + AUDIT(returnToDifferentLoopHeader); + JS_ASSERT(!cx->fp->imacpc); + debug_only_v(printf("loop edge to %d, header %d\n", + cx->fp->regs->pc - cx->fp->script->code, + (jsbytecode*)r->getFragment()->root->ip - cx->fp->script->code)); + js_AbortRecording(cx, "Loop edge does not return to header"); + return false; +} + +static bool +js_IsEntryTypeCompatible(jsval* vp, uint8* m) +{ + unsigned tag = JSVAL_TAG(*vp); + + debug_only_v(printf("%c/%c ", "OIDISIBI"[tag], "OID?S?B?"[*m]);) + + switch (*m) { + case JSVAL_INT: + jsint i; + if (JSVAL_IS_INT(*vp)) + return true; + if ((tag == JSVAL_DOUBLE) && JSDOUBLE_IS_INT(*JSVAL_TO_DOUBLE(*vp), i)) + return true; + debug_only_v(printf("int != tag%u(value=%lu) ", tag, *vp);) + return false; + case JSVAL_DOUBLE: + if (JSVAL_IS_INT(*vp) || tag == JSVAL_DOUBLE) + return true; + debug_only_v(printf("double != tag%u ", tag);) + return false; + case JSVAL_BOOLEAN: + if (tag == JSVAL_BOOLEAN) + return true; + debug_only_v(printf("bool != tag%u", tag);) + return false; + case JSVAL_STRING: + if (tag == JSVAL_STRING) + return true; + debug_only_v(printf("string != tag%u", tag);) + return false; + default: + JS_ASSERT(*m == JSVAL_OBJECT); + if (tag == JSVAL_OBJECT) + return true; + debug_only_v(printf("object != tag%u", tag);) + return false; + } +} + +Fragment* TraceRecorder::findNestedCompatiblePeer(Fragment* f, Fragment** empty) +{ + Fragment* demote; + JSTraceMonitor* tm; + unsigned max_demotes; + + if (empty) + *empty = NULL; + demote = NULL; + + tm = &JS_TRACE_MONITOR(cx); + unsigned int ngslots = tm->globalSlots->length(); + uint16* gslots = tm->globalSlots->data(); + uint8* m = tm->globalTypeMap->data(); + + if (ngslots) { + FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, + debug_only_v(printf("%s%d=", vpname, vpnum);) + if (!js_IsEntryTypeCompatible(vp, m)) + return NULL; + m++; + ); + } + + /* We keep a maximum tally - we want to select the peer most likely to work so we don't keep + * recording. + */ + max_demotes = 0; + + TreeInfo* ti; + for (; f != NULL; f = f->peer) { + if (!f->code()) { + if (empty) + *empty = f; + continue; + } + + unsigned demotes = 0; + ti = (TreeInfo*)f->vmprivate; + m = ti->stackTypeMap.data(); + + debug_only_v(printf("checking nested types %p: ", f);) + + FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0, + debug_only_v(printf("%s%d=", vpname, vpnum);) + if (!js_IsEntryTypeCompatible(vp, m)) + goto check_fail; + if (*m == JSVAL_STRING && *vp == JSVAL_VOID) + goto check_fail; + if (*m == JSVAL_INT && !isPromoteInt(get(vp))) + demotes++; + m++; + ); + JS_ASSERT(unsigned(m - ti->stackTypeMap.data()) == ti->stackTypeMap.length()); + + debug_only_v(printf(" (demotes %d)\n", demotes);) + + if (demotes) { + if (demotes > max_demotes) { + demote = f; + max_demotes = demotes; + } + continue; + } else { + return f; + } + +check_fail: + debug_only_v(printf("\n")); + continue; + } + + if (demote) + return demote; + + return NULL; +} + +/** + * Check if types are usable for trace execution. + * + * @param cx Context. + * @param ti Tree info of peer we're testing. + * @return True if compatible (with or without demotions), false otherwise. + */ +static bool +js_CheckEntryTypes(JSContext* cx, TreeInfo* ti) +{ + JSTraceMonitor* tm; + + tm = &JS_TRACE_MONITOR(cx); + unsigned int ngslots = tm->globalSlots->length(); + uint16* gslots = tm->globalSlots->data(); + uint8* m = tm->globalTypeMap->data(); + + if (ngslots) { + FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, + debug_only_v(printf("%s%d=", vpname, vpnum);) + if (!js_IsEntryTypeCompatible(vp, m)) + goto check_fail; + m++; + ); + } + + m = ti->stackTypeMap.data(); + FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0, + debug_only_v(printf("%s%d=", vpname, vpnum);) + if (!js_IsEntryTypeCompatible(vp, m)) + goto check_fail; + m++; + ); + JS_ASSERT(unsigned(m - ti->stackTypeMap.data()) == ti->stackTypeMap.length()); + + debug_only_v(printf("\n");) + return true; + +check_fail: + debug_only_v(printf("\n");) + return false; +} + +/** + * Find an acceptable entry tree given a PC. + * + * @param cx Context. + * @param f First peer fragment. + * @param nodemote If true, will try to find a peer that does not require demotion. + */ +static Fragment* +js_FindVMCompatiblePeer(JSContext* cx, Fragment* f) +{ + for (; f != NULL; f = f->peer) { + if (f->vmprivate == NULL) + continue; + debug_only_v(printf("checking vm types %p (ip: %p): ", f, f->ip);) + if (js_CheckEntryTypes(cx, (TreeInfo*)f->vmprivate)) + return f; + } + return NULL; +} + +/** + * Executes a tree. + */ +static VMSideExit* +js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount, + VMSideExit** innermostNestedGuardp) +{ + JS_ASSERT(f->code() && f->vmprivate); + + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); + TreeInfo* ti = (TreeInfo*)f->vmprivate; + unsigned ngslots = tm->globalSlots->length(); + uint16* gslots = tm->globalSlots->data(); + unsigned globalFrameSize = STOBJ_NSLOTS(globalObj); + double* global = (double*)alloca((globalFrameSize+1) * sizeof(double)); + double stack_buffer[MAX_NATIVE_STACK_SLOTS]; + double* stack = stack_buffer; + + /* Make sure the global object is sane. */ + JS_ASSERT(!ngslots || (OBJ_SHAPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain)) == tm->globalShape)); + /* Make sure our caller replenished the double pool. */ + JS_ASSERT(tm->recoveryDoublePoolPtr >= tm->recoveryDoublePool + MAX_NATIVE_STACK_SLOTS); + +#ifdef DEBUG + memset(stack_buffer, 0xCD, sizeof(stack_buffer)); + memset(global, 0xCD, (globalFrameSize+1)*sizeof(double)); +#endif + + debug_only(*(uint64*)&global[globalFrameSize] = 0xdeadbeefdeadbeefLL;) + debug_only_v(printf("entering trace at %s:%u@%u, native stack slots: %u code: %p\n", + cx->fp->script->filename, + js_FramePCToLineNumber(cx, cx->fp), + FramePCOffset(cx->fp), + ti->maxNativeStackSlots, + f->code());) + + if (ngslots) + BuildNativeGlobalFrame(cx, ngslots, gslots, tm->globalTypeMap->data(), global); + BuildNativeStackFrame(cx, 0/*callDepth*/, ti->stackTypeMap.data(), stack); + + double* entry_sp = &stack[ti->nativeStackBase/sizeof(double)]; + FrameInfo callstack_buffer[MAX_CALL_STACK_ENTRIES]; + FrameInfo* callstack = callstack_buffer; + + InterpState state; + state.sp = (void*)entry_sp; + state.eos = ((double*)state.sp) + MAX_NATIVE_STACK_SLOTS; + state.rp = callstack; + state.eor = callstack + MAX_CALL_STACK_ENTRIES; + state.gp = global; + state.cx = cx; + state.lastTreeExitGuard = NULL; + state.lastTreeCallGuard = NULL; + state.rpAtLastTreeCall = NULL; + union { NIns *code; GuardRecord* (FASTCALL *func)(InterpState*, Fragment*); } u; + u.code = f->code(); + +#ifdef JS_JIT_SPEW +#if defined(NANOJIT_IA32) || (defined(NANOJIT_AMD64) && defined(__GNUC__)) + uint64 start = rdtsc(); +#endif +#endif + + /* + * We may be called from js_MonitorLoopEdge while not recording, or while + * recording. Rather than over-generalize by using a counter instead of a + * flag, we simply sample and update tm->onTrace if necessary. + */ + bool onTrace = tm->onTrace; + if (!onTrace) + tm->onTrace = true; + VMSideExit* lr; + + debug_only(fflush(NULL);) + GuardRecord* rec; +#if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32) + SIMULATE_FASTCALL(rec, &state, NULL, u.func); +#else + rec = u.func(&state, NULL); +#endif + lr = (VMSideExit*)rec->exit; + + AUDIT(traceTriggered); + + JS_ASSERT(lr->exitType != LOOP_EXIT || !lr->calldepth); + + tm->onTrace = onTrace; + + /* Except if we find that this is a nested bailout, the guard the call returned is the + one we have to use to adjust pc and sp. */ + VMSideExit* innermost = lr; + + /* While executing a tree we do not update state.sp and state.rp even if they grow. Instead, + guards tell us by how much sp and rp should be incremented in case of a side exit. When + calling a nested tree, however, we actively adjust sp and rp. If we have such frames + from outer trees on the stack, then rp will have been adjusted. Before we can process + the stack of the frames of the tree we directly exited from, we have to first work our + way through the outer frames and generate interpreter frames for them. Once the call + stack (rp) is empty, we can process the final frames (which again are not directly + visible and only the guard we exited on will tells us about). */ + FrameInfo* rp = (FrameInfo*)state.rp; + if (lr->exitType == NESTED_EXIT) { + VMSideExit* nested = state.lastTreeCallGuard; + if (!nested) { + /* If lastTreeCallGuard is not set in state, we only have a single level of + nesting in this exit, so lr itself is the innermost and outermost nested + guard, and hence we set nested to lr. The calldepth of the innermost guard + is not added to state.rp, so we do it here manually. For a nesting depth + greater than 1 the CallTree builtin already added the innermost guard's + calldepth to state.rpAtLastTreeCall. */ + nested = lr; + rp += lr->calldepth; + } else { + /* During unwinding state.rp gets overwritten at every step and we restore + it here to its state at the innermost nested guard. The builtin already + added the calldepth of that innermost guard to rpAtLastTreeCall. */ + rp = (FrameInfo*)state.rpAtLastTreeCall; + } + innermost = state.lastTreeExitGuard; + if (innermostNestedGuardp) + *innermostNestedGuardp = nested; + JS_ASSERT(nested); + JS_ASSERT(nested->exitType == NESTED_EXIT); + JS_ASSERT(state.lastTreeExitGuard); + JS_ASSERT(state.lastTreeExitGuard->exitType != NESTED_EXIT); + } + + while (callstack < rp) { + /* Synthesize a stack frame and write out the values in it using the type map pointer + on the native call stack. */ + if (js_SynthesizeFrame(cx, *callstack) < 0) + return NULL; + int slots = FlushNativeStackFrame(cx, 1/*callDepth*/, callstack->typemap, stack, cx->fp); +#ifdef DEBUG + JSStackFrame* fp = cx->fp; + debug_only_v(printf("synthesized deep frame for %s:%u@%u, slots=%d\n", + fp->script->filename, + js_FramePCToLineNumber(cx, fp), + FramePCOffset(fp), + slots);) +#endif + if (slots < 0) + return NULL; + /* Keep track of the additional frames we put on the interpreter stack and the native + stack slots we consumed. */ + ++inlineCallCount; + ++callstack; + stack += slots; + } + + /* We already synthesized the frames around the innermost guard. Here we just deal + with additional frames inside the tree we are bailing out from. */ + JS_ASSERT(rp == callstack); + unsigned calldepth = innermost->calldepth; + unsigned calldepth_slots = 0; + for (unsigned n = 0; n < calldepth; ++n) { + int nslots = js_SynthesizeFrame(cx, callstack[n]); + if (nslots < 0) + return NULL; + calldepth_slots += nslots; + ++inlineCallCount; +#ifdef DEBUG + JSStackFrame* fp = cx->fp; + debug_only_v(printf("synthesized shallow frame for %s:%u@%u\n", + fp->script->filename, js_FramePCToLineNumber(cx, fp), + FramePCOffset(fp));) +#endif + } + + /* Adjust sp and pc relative to the tree we exited from (not the tree we entered into). + These are our final values for sp and pc since js_SynthesizeFrame has already taken + care of all frames in between. */ + JSStackFrame* fp = cx->fp; + + /* If we are not exiting from an inlined frame the state->sp is spbase, otherwise spbase + is whatever slots frames around us consume. */ + DECODE_IP_ADJ(innermost->ip_adj, fp); + fp->regs->sp = StackBase(fp) + (innermost->sp_adj / sizeof(double)) - calldepth_slots; + JS_ASSERT_IF(!fp->imacpc, + fp->slots + fp->script->nfixed + + js_ReconstructStackDepth(cx, fp->script, fp->regs->pc) == fp->regs->sp); + + +#if defined(JS_JIT_SPEW) && (defined(NANOJIT_IA32) || (defined(NANOJIT_AMD64) && defined(__GNUC__))) + uint64 cycles = rdtsc() - start; +#elif defined(JS_JIT_SPEW) + uint64 cycles = 0; +#endif + + debug_only_v(printf("leaving trace at %s:%u@%u, op=%s, lr=%p, exitType=%d, sp=%d, " + "calldepth=%d, cycles=%llu\n", + fp->script->filename, + js_FramePCToLineNumber(cx, fp), + FramePCOffset(fp), + js_CodeName[fp->imacpc ? *fp->imacpc : *fp->regs->pc], + lr, + lr->exitType, + fp->regs->sp - StackBase(fp), + calldepth, + cycles)); + + /* If this trace is part of a tree, later branches might have added additional globals for + with we don't have any type information available in the side exit. We merge in this + information from the entry type-map. See also comment in the constructor of TraceRecorder + why this is always safe to do. */ + unsigned exit_gslots = innermost->numGlobalSlots; + JS_ASSERT(ngslots == tm->globalTypeMap->length()); + JS_ASSERT(ngslots >= exit_gslots); + uint8* globalTypeMap = getTypeMap(innermost); + if (exit_gslots < ngslots) + mergeTypeMaps(&globalTypeMap, &exit_gslots, tm->globalTypeMap->data(), ngslots, + (uint8*)alloca(sizeof(uint8) * ngslots)); + JS_ASSERT(exit_gslots == tm->globalTypeMap->length()); + + /* write back interned globals */ + int slots = FlushNativeGlobalFrame(cx, exit_gslots, gslots, globalTypeMap, global); + if (slots < 0) + return NULL; + JS_ASSERT_IF(ngslots != 0, globalFrameSize == STOBJ_NSLOTS(globalObj)); + JS_ASSERT(*(uint64*)&global[globalFrameSize] == 0xdeadbeefdeadbeefLL); + + /* write back native stack frame */ + slots = FlushNativeStackFrame(cx, innermost->calldepth, + getTypeMap(innermost) + innermost->numGlobalSlots, + stack, NULL); + if (slots < 0) + return NULL; + JS_ASSERT(unsigned(slots) == innermost->numStackSlots); + +#ifdef DEBUG + // Verify that our state restoration worked + for (JSStackFrame* fp = cx->fp; fp; fp = fp->down) { + JS_ASSERT(!fp->callee || JSVAL_IS_OBJECT(fp->argv[-1])); + JS_ASSERT(!fp->callee || fp->thisp == JSVAL_TO_OBJECT(fp->argv[-1])); + } +#endif + + AUDIT(sideExitIntoInterpreter); + + return innermost; +} + +bool +js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount) +{ + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + + /* Is the recorder currently active? */ + if (tm->recorder) { + if (js_RecordLoopEdge(cx, tm->recorder, inlineCallCount)) + return true; + /* recording was aborted, treat like a regular loop edge hit */ + } + JS_ASSERT(!tm->recorder); + + + /* Check the recovery pool of doubles (this might trigger a GC). */ + if (tm->recoveryDoublePoolPtr < (tm->recoveryDoublePool + MAX_NATIVE_STACK_SLOTS) && + !js_ReplenishRecoveryPool(cx, tm)) { + return false; /* Out of memory, don't try to record now. */ + } + + /* Make sure the shape of the global object still matches (this might flush the JIT cache). */ + JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); + if (!js_CheckGlobalObjectShape(cx, tm, globalObj)) + js_FlushJITCache(cx); + + jsbytecode* pc = cx->fp->regs->pc; + Fragmento* fragmento = tm->fragmento; + Fragment* f; + f = fragmento->getLoop(pc); + if (!f) + f = fragmento->getAnchor(pc); + + /* If we have no code in the anchor and no peers, we definitively won't be able to + activate any trees so increment the hit counter and start compiling if appropriate. */ + if (!f->code() && !f->peer) { +monitor_loop: + if (++f->hits() >= HOTLOOP) { + /* We can give RecordTree the root peer. If that peer is already taken, it will + walk the peer list and find us a free slot or allocate a new tree if needed. */ + return js_RecordTree(cx, tm, f->first, NULL, NULL); + } + /* Threshold not reached yet. */ + return false; + } + + debug_only_v(printf("Looking for compat peer %d@%d, from %p (ip: %p, hits=%d)\n", + js_FramePCToLineNumber(cx, cx->fp), + FramePCOffset(cx->fp), + f, f->ip, f->hits());) + Fragment* match = js_FindVMCompatiblePeer(cx, f); + /* If we didn't find a tree that actually matched, keep monitoring the loop. */ + if (!match) + goto monitor_loop; + + VMSideExit* lr = NULL; + VMSideExit* innermostNestedGuard = NULL; + + lr = js_ExecuteTree(cx, match, inlineCallCount, &innermostNestedGuard); + if (!lr) + return false; + + /* If we exit on a branch, or on a tree call guard, try to grow the inner tree (in case + of a branch exit), or the tree nested around the tree we exited from (in case of the + tree call guard). */ + switch (lr->exitType) { + case UNSTABLE_LOOP_EXIT: + return js_AttemptToStabilizeTree(cx, lr, NULL); + case BRANCH_EXIT: + return js_AttemptToExtendTree(cx, lr, NULL, NULL); + case LOOP_EXIT: + if (innermostNestedGuard) + return js_AttemptToExtendTree(cx, innermostNestedGuard, lr, NULL); + return false; + default: + /* No, this was an unusual exit (i.e. out of memory/GC), so just resume interpretation. */ + return false; + } +} + +bool +js_MonitorRecording(TraceRecorder* tr) +{ + JSContext* cx = tr->cx; + + if (tr->lirbuf->outOmem()) { + js_AbortRecording(cx, "no more LIR memory"); + js_FlushJITCache(cx); + return false; + } + + if (tr->walkedOutOfLoop()) + return js_CloseLoop(cx); + + // Clear one-shot state used to communicate between record_JSOP_CALL and mid- and post- + // opcode-case-guts record hooks (record_EnterFrame, record_FastNativeCallComplete). + tr->applyingArguments = false; + tr->pendingTraceableNative = NULL; + + // In the future, handle dslots realloc by computing an offset from dslots instead. + if (tr->global_dslots != tr->globalObj->dslots) { + js_AbortRecording(cx, "globalObj->dslots reallocated"); + return false; + } + + // Process deepAbort() requests now. + if (tr->wasDeepAborted()) { + js_AbortRecording(cx, "deep abort requested"); + return false; + } + + jsbytecode* pc = cx->fp->regs->pc; + + /* If we hit a break, end the loop and generate an always taken loop exit guard. For other + downward gotos (like if/else) continue recording. */ + if (*pc == JSOP_GOTO || *pc == JSOP_GOTOX) { + jssrcnote* sn = js_GetSrcNote(cx->fp->script, pc); + if (sn && SN_TYPE(sn) == SRC_BREAK) { + AUDIT(breakLoopExits); + tr->endLoop(JS_TRACE_MONITOR(cx).fragmento); + js_DeleteRecorder(cx); + return false; /* done recording */ + } + } + + /* An explicit return from callDepth 0 should end the loop, not abort it. */ + if (*pc == JSOP_RETURN && tr->callDepth == 0) { + AUDIT(returnLoopExits); + tr->endLoop(JS_TRACE_MONITOR(cx).fragmento); + js_DeleteRecorder(cx); + return false; /* done recording */ + } + + /* If it's not a break or a return from a loop, continue recording and follow the trace. */ + return true; +} + +/* If used on a loop trace, blacklists the root peer instead of the given fragment. */ +void +js_BlacklistPC(Fragmento* frago, Fragment* frag) +{ + if (frag->kind == LoopTrace) + frag = frago->getLoop(frag->ip); + frag->blacklist(); +} + +void +js_AbortRecording(JSContext* cx, const char* reason) +{ + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + JS_ASSERT(tm->recorder != NULL); + AUDIT(recorderAborted); + + /* Abort the trace and blacklist its starting point. */ + JSStackFrame* fp = cx->fp; + if (fp) { + debug_only_v(printf("Abort recording (line %d, pc %d): %s.\n", + js_FramePCToLineNumber(cx, fp), + FramePCOffset(fp), + reason);) + } + Fragment* f = tm->recorder->getFragment(); + if (!f) { + js_DeleteRecorder(cx); + return; + } + JS_ASSERT(!f->vmprivate); + js_BlacklistPC(tm->fragmento, f); + Fragment* outer = tm->recorder->getOuterToBlacklist(); + /* Give outer two chances to stabilize before we start blacklisting. */ + if (outer != NULL && outer->recordAttempts >= 2) + js_BlacklistPC(tm->fragmento, outer); + js_DeleteRecorder(cx); + /* If this is the primary trace and we didn't succeed compiling, trash the TreeInfo object. */ + if (!f->code() && (f->root == f)) + js_TrashTree(cx, f); +} + +#if defined NANOJIT_IA32 +static bool +js_CheckForSSE2() +{ + int features = 0; +#if defined _MSC_VER + __asm + { + pushad + mov eax, 1 + cpuid + mov features, edx + popad + } +#elif defined __GNUC__ + asm("xchg %%esi, %%ebx\n" /* we can't clobber ebx on gcc (PIC register) */ + "mov $0x01, %%eax\n" + "cpuid\n" + "mov %%edx, %0\n" + "xchg %%esi, %%ebx\n" + : "=m" (features) + : /* We have no inputs */ + : "%eax", "%esi", "%ecx", "%edx" + ); +#elif defined __SUNPRO_C || defined __SUNPRO_CC + asm("push %%ebx\n" + "mov $0x01, %%eax\n" + "cpuid\n" + "pop %%ebx\n" + : "=d" (features) + : /* We have no inputs */ + : "%eax", "%ecx" + ); +#endif + return (features & (1<<26)) != 0; +} +#endif + +static void InitIMacroCode(); + +extern void +js_InitJIT(JSTraceMonitor *tm) +{ +#if defined NANOJIT_IA32 + if (!did_we_check_sse2) { + avmplus::AvmCore::cmov_available = + avmplus::AvmCore::sse2_available = js_CheckForSSE2(); + did_we_check_sse2 = true; + } +#endif + if (!tm->fragmento) { + JS_ASSERT(!tm->globalSlots && !tm->globalTypeMap && !tm->recoveryDoublePool); + Fragmento* fragmento = new (&gc) Fragmento(core, 24); + verbose_only(fragmento->labels = new (&gc) LabelMap(core, NULL);) + tm->fragmento = fragmento; + tm->globalSlots = new (&gc) SlotList(); + tm->globalTypeMap = new (&gc) TypeMap(); + tm->recoveryDoublePoolPtr = tm->recoveryDoublePool = new jsval[MAX_NATIVE_STACK_SLOTS]; + } + if (!tm->reFragmento) { + Fragmento* fragmento = new (&gc) Fragmento(core, 20); + verbose_only(fragmento->labels = new (&gc) LabelMap(core, NULL);) + tm->reFragmento = fragmento; + } + InitIMacroCode(); +#if !defined XP_WIN + debug_only(memset(&jitstats, 0, sizeof(jitstats))); +#endif +} + +extern void +js_FinishJIT(JSTraceMonitor *tm) +{ +#ifdef JS_JIT_SPEW + printf("recorder: started(%llu), aborted(%llu), completed(%llu), different header(%llu), " + "trees trashed(%llu), slot promoted(%llu), unstable loop variable(%llu), " + "breaks(%llu), returns(%llu), unstableInnerCalls(%llu)\n", + jitstats.recorderStarted, jitstats.recorderAborted, jitstats.traceCompleted, + jitstats.returnToDifferentLoopHeader, jitstats.treesTrashed, jitstats.slotPromoted, + jitstats.unstableLoopVariable, jitstats.breakLoopExits, jitstats.returnLoopExits, + jitstats.noCompatInnerTrees); + printf("monitor: triggered(%llu), exits(%llu), type mismatch(%llu), " + "global mismatch(%llu)\n", jitstats.traceTriggered, jitstats.sideExitIntoInterpreter, + jitstats.typeMapMismatchAtEntry, jitstats.globalShapeMismatchAtEntry); +#endif + if (tm->fragmento != NULL) { + JS_ASSERT(tm->globalSlots && tm->globalTypeMap && tm->recoveryDoublePool); + verbose_only(delete tm->fragmento->labels;) + delete tm->fragmento; + tm->fragmento = NULL; + delete tm->globalSlots; + tm->globalSlots = NULL; + delete tm->globalTypeMap; + tm->globalTypeMap = NULL; + delete[] tm->recoveryDoublePool; + tm->recoveryDoublePool = tm->recoveryDoublePoolPtr = NULL; + } + if (tm->reFragmento != NULL) { + verbose_only(delete tm->reFragmento->labels;) + delete tm->reFragmento; + } +} + +void +TraceRecorder::pushAbortStack() +{ + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + + JS_ASSERT(tm->abortStack != this); + + nextRecorderToAbort = tm->abortStack; + tm->abortStack = this; +} + +void +TraceRecorder::popAbortStack() +{ + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + + JS_ASSERT(tm->abortStack == this); + + tm->abortStack = nextRecorderToAbort; + nextRecorderToAbort = NULL; +} + +extern void +js_FlushJITOracle(JSContext* cx) +{ + if (!TRACING_ENABLED(cx)) + return; + oracle.clear(); +} + +extern void +js_FlushJITCache(JSContext* cx) +{ + if (!TRACING_ENABLED(cx)) + return; + debug_only_v(printf("Flushing cache.\n");) + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + if (tm->recorder) + js_AbortRecording(cx, "flush cache"); + TraceRecorder* tr; + while ((tr = tm->abortStack) != NULL) { + tr->removeFragmentoReferences(); + tr->deepAbort(); + tr->popAbortStack(); + } + Fragmento* fragmento = tm->fragmento; + if (fragmento) { + fragmento->clearFrags(); +#ifdef DEBUG + JS_ASSERT(fragmento->labels); + delete fragmento->labels; + fragmento->labels = new (&gc) LabelMap(core, NULL); +#endif + } + if (cx->fp) { + tm->globalShape = OBJ_SHAPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain)); + tm->globalSlots->clear(); + tm->globalTypeMap->clear(); + } +} + +jsval& +TraceRecorder::argval(unsigned n) const +{ + JS_ASSERT(n < cx->fp->fun->nargs); + return cx->fp->argv[n]; +} + +jsval& +TraceRecorder::varval(unsigned n) const +{ + JS_ASSERT(n < cx->fp->script->nslots); + return cx->fp->slots[n]; +} + +jsval& +TraceRecorder::stackval(int n) const +{ + jsval* sp = cx->fp->regs->sp; + return sp[n]; +} + +LIns* +TraceRecorder::scopeChain() const +{ + return lir->insLoad(LIR_ldp, + lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp)), + offsetof(JSStackFrame, scopeChain)); +} + +static inline bool +FrameInRange(JSStackFrame* fp, JSStackFrame *target, unsigned callDepth) +{ + while (fp != target) { + if (callDepth-- == 0) + return false; + if (!(fp = fp->down)) + return false; + } + return true; +} + +bool +TraceRecorder::activeCallOrGlobalSlot(JSObject* obj, jsval*& vp) +{ + JS_ASSERT(obj != globalObj); + + JSAtom* atom = atoms[GET_INDEX(cx->fp->regs->pc)]; + JSObject* obj2; + JSProperty* prop; + if (js_FindProperty(cx, ATOM_TO_JSID(atom), &obj, &obj2, &prop) < 0 || !prop) + ABORT_TRACE("failed to find name in non-global scope chain"); + + if (obj == globalObj) { + JSScopeProperty* sprop = (JSScopeProperty*) prop; + if (obj2 != obj || !SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj))) { + OBJ_DROP_PROPERTY(cx, obj2, prop); + ABORT_TRACE("prototype or slotless globalObj property"); + } + + if (!lazilyImportGlobalSlot(sprop->slot)) + ABORT_TRACE("lazy import of global slot failed"); + vp = &STOBJ_GET_SLOT(obj, sprop->slot); + OBJ_DROP_PROPERTY(cx, obj2, prop); + return true; + } + + if (obj == obj2 && OBJ_GET_CLASS(cx, obj) == &js_CallClass) { + JSStackFrame* cfp = (JSStackFrame*) JS_GetPrivate(cx, obj); + if (cfp && FrameInRange(cx->fp, cfp, callDepth)) { + JSScopeProperty* sprop = (JSScopeProperty*) prop; + uintN slot = sprop->shortid; + + vp = NULL; + if (sprop->getter == js_GetCallArg) { + JS_ASSERT(slot < cfp->fun->nargs); + vp = &cfp->argv[slot]; + } else if (sprop->getter == js_GetCallVar) { + JS_ASSERT(slot < cfp->script->nslots); + vp = &cfp->slots[slot]; + } + OBJ_DROP_PROPERTY(cx, obj2, prop); + if (!vp) + ABORT_TRACE("dynamic property of Call object"); + return true; + } + } + + OBJ_DROP_PROPERTY(cx, obj2, prop); + ABORT_TRACE("fp->scopeChain is not global or active call object"); +} + +LIns* +TraceRecorder::arg(unsigned n) +{ + return get(&argval(n)); +} + +void +TraceRecorder::arg(unsigned n, LIns* i) +{ + set(&argval(n), i); +} + +LIns* +TraceRecorder::var(unsigned n) +{ + return get(&varval(n)); +} + +void +TraceRecorder::var(unsigned n, LIns* i) +{ + set(&varval(n), i); +} + +LIns* +TraceRecorder::stack(int n) +{ + return get(&stackval(n)); +} + +void +TraceRecorder::stack(int n, LIns* i) +{ + set(&stackval(n), i, n >= 0); +} + +LIns* +TraceRecorder::alu(LOpcode v, jsdouble v0, jsdouble v1, LIns* s0, LIns* s1) +{ + if (v == LIR_fadd || v == LIR_fsub) { + jsdouble r; + if (v == LIR_fadd) + r = v0 + v1; + else + r = v0 - v1; + /* + * Calculate the result of the addition for the current values. If the + * value is not within the integer range, don't even try to demote + * here. + */ + if (!JSDOUBLE_IS_NEGZERO(r) && (jsint(r) == r) && isPromoteInt(s0) && isPromoteInt(s1)) { + LIns* d0 = ::demote(lir, s0); + LIns* d1 = ::demote(lir, s1); + /* + * If the inputs are constant, generate an integer constant for + * this operation. + */ + if (d0->isconst() && d1->isconst()) + return lir->ins1(LIR_i2f, lir->insImm(jsint(r))); + /* + * Speculatively generate code that will perform the addition over + * the integer inputs as an integer addition/subtraction and exit + * if that fails. + */ + v = (LOpcode)((int)v & ~LIR64); + LIns* result = lir->ins2(v, d0, d1); + if (!overflowSafe(d0) || !overflowSafe(d1)) { + lir->insGuard(LIR_xt, lir->ins1(LIR_ov, result), + snapshot(OVERFLOW_EXIT)); + } + return lir->ins1(LIR_i2f, result); + } + /* + * The result doesn't fit into the integer domain, so either generate + * a floating point constant or a floating point operation. + */ + if (s0->isconst() && s1->isconst()) { + jsdpun u; + u.d = r; + return lir->insImmq(u.u64); + } + return lir->ins2(v, s0, s1); + } + return lir->ins2(v, s0, s1); +} + +LIns* +TraceRecorder::f2i(LIns* f) +{ + return lir->insCall(&js_DoubleToInt32_ci, &f); +} + +LIns* +TraceRecorder::makeNumberInt32(LIns* f) +{ + JS_ASSERT(f->isQuad()); + LIns* x; + if (!isPromote(f)) { + x = f2i(f); + guard(true, lir->ins2(LIR_feq, f, lir->ins1(LIR_i2f, x)), MISMATCH_EXIT); + } else { + x = ::demote(lir, f); + } + return x; +} + +LIns* +TraceRecorder::stringify(jsval& v) +{ + LIns* v_ins = get(&v); + if (JSVAL_IS_STRING(v)) + return v_ins; + + LIns* args[] = { v_ins, cx_ins }; + const CallInfo* ci; + if (JSVAL_IS_NUMBER(v)) { + ci = &js_NumberToString_ci; + } else if (JSVAL_TAG(v) == JSVAL_BOOLEAN) { + ci = &js_BooleanOrUndefinedToString_ci; + } else { + /* We can't stringify objects here (use imacros instead), just return NULL. */ + return NULL; + } + v_ins = lir->insCall(ci, args); + guard(false, lir->ins_eq0(v_ins), OOM_EXIT); + return v_ins; +} + +bool +TraceRecorder::call_imacro(jsbytecode* imacro) +{ + JSStackFrame* fp = cx->fp; + JSFrameRegs* regs = fp->regs; + + if (!fp->imacpc) { + fp->imacpc = regs->pc; + fp->flags |= JSFRAME_IMACRO_START; + regs->pc = imacro; + atoms = COMMON_ATOMS_START(&cx->runtime->atomState); + } + return false; +} + +bool +TraceRecorder::ifop() +{ + jsval& v = stackval(-1); + LIns* v_ins = get(&v); + bool cond; + LIns* x; + /* no need to guard if condition is constant */ + if (v_ins->isconst() || v_ins->isconstq()) + return true; + if (JSVAL_TAG(v) == JSVAL_BOOLEAN) { + /* test for boolean is true, negate later if we are testing for false */ + cond = JSVAL_TO_BOOLEAN(v) == 1; + x = lir->ins2i(LIR_eq, v_ins, 1); + } else if (JSVAL_IS_OBJECT(v)) { + cond = !JSVAL_IS_NULL(v); + x = v_ins; + } else if (isNumber(v)) { + jsdouble d = asNumber(v); + cond = !JSDOUBLE_IS_NaN(d) && d; + jsdpun u; + u.d = 0; + x = lir->ins2(LIR_and, + lir->ins2(LIR_feq, v_ins, v_ins), + lir->ins_eq0(lir->ins2(LIR_feq, v_ins, lir->insImmq(u.u64)))); + } else if (JSVAL_IS_STRING(v)) { + cond = JSSTRING_LENGTH(JSVAL_TO_STRING(v)) != 0; + x = lir->ins2(LIR_piand, + lir->insLoad(LIR_ldp, + v_ins, + (int)offsetof(JSString, length)), + INS_CONSTPTR(JSSTRING_LENGTH_MASK)); + } else { + JS_NOT_REACHED("ifop"); + return false; + } + flipIf(cx->fp->regs->pc, cond); + bool expected = cond; + if (!x->isCond()) { + x = lir->ins_eq0(x); + expected = !expected; + } + guard(expected, x, BRANCH_EXIT); + return true; +} + +bool +TraceRecorder::switchop() +{ + jsval& v = stackval(-1); + LIns* v_ins = get(&v); + /* no need to guard if condition is constant */ + if (v_ins->isconst() || v_ins->isconstq()) + return true; + if (isNumber(v)) { + jsdouble d = asNumber(v); + jsdpun u; + u.d = d; + guard(true, + addName(lir->ins2(LIR_feq, v_ins, lir->insImmq(u.u64)), + "guard(switch on numeric)"), + BRANCH_EXIT); + } else if (JSVAL_IS_STRING(v)) { + LIns* args[] = { v_ins, INS_CONSTPTR(JSVAL_TO_STRING(v)) }; + guard(true, + addName(lir->ins_eq0(lir->ins_eq0(lir->insCall(&js_EqualStrings_ci, args))), + "guard(switch on string)"), + BRANCH_EXIT); + } else if (JSVAL_TAG(v) == JSVAL_BOOLEAN) { + guard(true, + addName(lir->ins2(LIR_eq, v_ins, lir->insImm(JSVAL_TO_BOOLEAN(v))), + "guard(switch on boolean)"), + BRANCH_EXIT); + } else { + ABORT_TRACE("switch on object or null"); + } + return true; +} + +bool +TraceRecorder::inc(jsval& v, jsint incr, bool pre) +{ + LIns* v_ins = get(&v); + if (!inc(v, v_ins, incr, pre)) + return false; + set(&v, v_ins); + return true; +} + +/* + * On exit, v_ins is the incremented unboxed value, and the appropriate + * value (pre- or post-increment as described by pre) is stacked. + */ +bool +TraceRecorder::inc(jsval& v, LIns*& v_ins, jsint incr, bool pre) +{ + if (!isNumber(v)) + ABORT_TRACE("can only inc numbers"); + + jsdpun u; + u.d = jsdouble(incr); + + LIns* v_after = alu(LIR_fadd, asNumber(v), incr, v_ins, lir->insImmq(u.u64)); + + const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc]; + JS_ASSERT(cs.ndefs == 1); + stack(-cs.nuses, pre ? v_after : v_ins); + v_ins = v_after; + return true; +} + +bool +TraceRecorder::incProp(jsint incr, bool pre) +{ + jsval& l = stackval(-1); + if (JSVAL_IS_PRIMITIVE(l)) + ABORT_TRACE("incProp on primitive"); + + JSObject* obj = JSVAL_TO_OBJECT(l); + LIns* obj_ins = get(&l); + + uint32 slot; + LIns* v_ins; + if (!prop(obj, obj_ins, slot, v_ins)) + return false; + + if (slot == SPROP_INVALID_SLOT) + ABORT_TRACE("incProp on invalid slot"); + + jsval& v = STOBJ_GET_SLOT(obj, slot); + if (!inc(v, v_ins, incr, pre)) + return false; + + if (!box_jsval(v, v_ins)) + return false; + + LIns* dslots_ins = NULL; + stobj_set_slot(obj_ins, slot, dslots_ins, v_ins); + return true; +} + +bool +TraceRecorder::incElem(jsint incr, bool pre) +{ + jsval& r = stackval(-1); + jsval& l = stackval(-2); + jsval* vp; + LIns* v_ins; + LIns* addr_ins; + if (!elem(l, r, vp, v_ins, addr_ins)) + return false; + if (!addr_ins) // if we read a hole, abort + return false; + if (!inc(*vp, v_ins, incr, pre)) + return false; + if (!box_jsval(*vp, v_ins)) + return false; + lir->insStorei(v_ins, addr_ins, 0); + return true; +} + +static bool +evalCmp(LOpcode op, double result) +{ + bool cond; + switch (op) { + case LIR_feq: + cond = (result == 0); + break; + case LIR_flt: + cond = result < 0; + break; + case LIR_fgt: + cond = result > 0; + break; + case LIR_fle: + cond = result <= 0; + break; + case LIR_fge: + cond = result >= 0; + break; + default: + JS_NOT_REACHED("unexpected comparison op"); + return false; + } + return cond; +} + +static bool +evalCmp(LOpcode op, double l, double r) +{ + return evalCmp(op, l - r); +} + +static bool +evalCmp(LOpcode op, JSString* l, JSString* r) +{ + if (op == LIR_feq) + return js_EqualStrings(l, r); + return evalCmp(op, js_CompareStrings(l, r)); +} + +static struct { + jsbytecode obj_any[13]; + jsbytecode any_obj[11]; + jsbytecode obj_obj[22]; +} binary_imacros = { + { + JSOP_SWAP, + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(valueOf), + JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER), + JSOP_CALL, 0, 1, + JSOP_SWAP, + JSOP_IMACOP, + JSOP_STOP + }, + + { + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(valueOf), + JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER), + JSOP_CALL, 0, 1, + JSOP_IMACOP, + JSOP_STOP + }, + + { + JSOP_SWAP, + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(valueOf), + JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER), + JSOP_CALL, 0, 1, + JSOP_SWAP, + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(valueOf), + JSOP_STRING, 0, COMMON_TYPE_ATOM_INDEX(JSTYPE_NUMBER), + JSOP_CALL, 0, 1, + JSOP_IMACOP, + JSOP_STOP + } +}; + +JS_STATIC_ASSERT(sizeof(binary_imacros) < IMACRO_PC_ADJ_LIMIT); + +bool +TraceRecorder::cmp(LOpcode op, int flags) +{ + jsval& r = stackval(-1); + jsval& l = stackval(-2); + LIns* x = NULL; + bool negate = !!(flags & CMP_NEGATE); + bool cond; + LIns* l_ins = get(&l); + LIns* r_ins = get(&r); + bool fp = false; + + if (op != LIR_feq) { + if (JSVAL_IS_OBJECT(l) && hasValueOfMethod(l)) { + if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r)) + return call_imacro(binary_imacros.obj_obj); + return call_imacro(binary_imacros.obj_any); + } + if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r)) + return call_imacro(binary_imacros.any_obj); + } + + // CMP_STRICT is set only for JSOP_STRICTEQ and JSOP_STRICTNE, which correspond to the + // === and !== operators. negate is true for !== and false for ===. The strict equality + // operators produce false if the types of the operands differ, i.e. if only one of + // them is a number. + if ((flags & CMP_STRICT) && getPromotedType(l) != getPromotedType(r)) { + x = INS_CONST(negate); + cond = negate; + } else if (JSVAL_IS_STRING(l) || JSVAL_IS_STRING(r)) { + // Comparing equality of a string against null always produces false. + if (op == LIR_feq && + ((JSVAL_IS_NULL(l) && l_ins->isconst()) || + (JSVAL_IS_NULL(r) && r_ins->isconst()))) { + x = INS_CONST(negate); + cond = negate; + } else { + if (!JSVAL_IS_STRING(l) || !JSVAL_IS_STRING(r)) + ABORT_TRACE("unsupported type for cmp vs string"); + + LIns* args[] = { r_ins, l_ins }; + if (op == LIR_feq) + l_ins = lir->ins_eq0(lir->insCall(&js_EqualStrings_ci, args)); + else + l_ins = lir->insCall(&js_CompareStrings_ci, args); + r_ins = lir->insImm(0); + cond = evalCmp(op, JSVAL_TO_STRING(l), JSVAL_TO_STRING(r)); + } + } else if (isNumber(l) || isNumber(r)) { + jsval tmp[2] = {l, r}; + JSAutoTempValueRooter tvr(cx, 2, tmp); + + fp = true; + + // TODO: coerce non-numbers to numbers if it's not string-on-string above + jsdouble lnum; + jsdouble rnum; + LIns* args[] = { l_ins, cx_ins }; + if (l == JSVAL_NULL && l_ins->isconst()) { + jsdpun u; + u.d = (op == LIR_feq) ? js_NaN : 0.0; + l_ins = lir->insImmq(u.u64); + } else if (JSVAL_IS_STRING(l)) { + l_ins = lir->insCall(&js_StringToNumber_ci, args); + } else if (JSVAL_TAG(l) == JSVAL_BOOLEAN) { + /* + * What I really want here is for undefined to be type-specialized + * differently from real booleans. Failing that, I want to be able + * to cmov on quads. Failing that, I want to have small forward + * branches. Failing that, I want to be able to ins_choose on quads + * without cmov. Failing that, eat flaming builtin! + */ + l_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); + } else if (!isNumber(l)) { + ABORT_TRACE("unsupported LHS type for cmp vs number"); + } + lnum = js_ValueToNumber(cx, &tmp[0]); + + args[0] = r_ins; + args[1] = cx_ins; + if (r == JSVAL_NULL && r_ins->isconst()) { + jsdpun u; + u.d = (op == LIR_feq) ? js_NaN : 0.0; + r_ins = lir->insImmq(u.u64); + } else if (JSVAL_IS_STRING(r)) { + r_ins = lir->insCall(&js_StringToNumber_ci, args); + } else if (JSVAL_TAG(r) == JSVAL_BOOLEAN) { + // See above for the sob story. + r_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); + } else if (!isNumber(r)) { + ABORT_TRACE("unsupported RHS type for cmp vs number"); + } + rnum = js_ValueToNumber(cx, &tmp[1]); + cond = evalCmp(op, lnum, rnum); + } else if ((JSVAL_TAG(l) == JSVAL_BOOLEAN) && (JSVAL_TAG(r) == JSVAL_BOOLEAN)) { + // The well-known values of JSVAL_TRUE and JSVAL_FALSE make this very easy. + // In particular: JSVAL_TO_BOOLEAN(0) < JSVAL_TO_BOOLEAN(1) so all of these comparisons do + // the right thing. + cond = evalCmp(op, l, r); + // For ==, !=, ===, and !=== the result is magically correct even if undefined (2) is + // involved. For the relational operations we need some additional cmov magic to make + // the result always false (since undefined becomes NaN per ECMA and that doesn't + // compare to anything, even itself). The code for this is emitted a few lines down. + } else if (JSVAL_IS_OBJECT(l) && JSVAL_IS_OBJECT(r)) { + if (op != LIR_feq) { + JS_NOT_REACHED("we should have converted to numbers already"); + return false; + } + cond = (l == r); + } else { + ABORT_TRACE("unsupported operand types for cmp"); + } + + /* If we didn't generate a constant result yet, then emit the comparison now. */ + if (!x) { + /* If the result is not a number or it's not a quad, we must use an integer compare. */ + if (!fp) { + JS_ASSERT(op >= LIR_feq && op <= LIR_fge); + op = LOpcode(op + (LIR_eq - LIR_feq)); + } + x = lir->ins2(op, l_ins, r_ins); + if (negate) { + x = lir->ins_eq0(x); + cond = !cond; + } + // For boolean comparison we need a bit post-processing to make the result false if + // either side is undefined. + if (op != LIR_eq && (JSVAL_TAG(l) == JSVAL_BOOLEAN) && (JSVAL_TAG(r) == JSVAL_BOOLEAN)) { + x = lir->ins_choose(lir->ins2i(LIR_eq, + lir->ins2i(LIR_and, + lir->ins2(LIR_or, l_ins, r_ins), + JSVAL_TO_BOOLEAN(JSVAL_VOID)), + JSVAL_TO_BOOLEAN(JSVAL_VOID)), + lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_FALSE)), + x); + x = lir->ins_eq0(lir->ins_eq0(x)); + if ((l == JSVAL_VOID) || (r == JSVAL_VOID)) + cond = false; + } + } + + /* Don't guard if the same path is always taken. */ + if (!x->isconst()) { + if (flags & CMP_CASE) { + guard(cond, x, BRANCH_EXIT); + return true; + } + + /* The interpreter fuses comparisons and the following branch, + so we have to do that here as well. */ + if (flags & CMP_TRY_BRANCH_AFTER_COND) { + fuseIf(cx->fp->regs->pc + 1, cond, x); + } + } else if (flags & CMP_CASE) { + return true; + } + + /* We update the stack after the guard. This is safe since + the guard bails out at the comparison and the interpreter + will therefore re-execute the comparison. This way the + value of the condition doesn't have to be calculated and + saved on the stack in most cases. */ + set(&l, x); + return true; +} + +bool +TraceRecorder::unary(LOpcode op) +{ + jsval& v = stackval(-1); + bool intop = !(op & LIR64); + if (isNumber(v)) { + LIns* a = get(&v); + if (intop) + a = f2i(a); + a = lir->ins1(op, a); + if (intop) + a = lir->ins1(LIR_i2f, a); + set(&v, a); + return true; + } + return false; +} + +bool +TraceRecorder::binary(LOpcode op) +{ + jsval& r = stackval(-1); + jsval& l = stackval(-2); + + if (JSVAL_IS_OBJECT(l) && hasValueOfMethod(l)) { + if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r)) + return call_imacro(binary_imacros.obj_obj); + return call_imacro(binary_imacros.obj_any); + } + if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r)) + return call_imacro(binary_imacros.any_obj); + + bool intop = !(op & LIR64); + LIns* a = get(&l); + LIns* b = get(&r); + + bool leftIsNumber = isNumber(l); + jsdouble lnum = leftIsNumber ? asNumber(l) : 0; + + bool rightIsNumber = isNumber(r); + jsdouble rnum = rightIsNumber ? asNumber(r) : 0; + + if ((op >= LIR_sub && op <= LIR_ush) || // sub, mul, (callh), or, xor, (not,) lsh, rsh, ush + (op >= LIR_fsub && op <= LIR_fdiv)) { // fsub, fmul, fdiv + LIns* args[2]; + if (JSVAL_IS_STRING(l)) { + args[0] = a; + args[1] = cx_ins; + a = lir->insCall(&js_StringToNumber_ci, args); + lnum = js_StringToNumber(cx, JSVAL_TO_STRING(l)); + leftIsNumber = true; + } + if (JSVAL_IS_STRING(r)) { + args[0] = b; + args[1] = cx_ins; + b = lir->insCall(&js_StringToNumber_ci, args); + rnum = js_StringToNumber(cx, JSVAL_TO_STRING(r)); + rightIsNumber = true; + } + } + if (JSVAL_TAG(l) == JSVAL_BOOLEAN) { + LIns* args[] = { a, cx_ins }; + a = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); + lnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_BOOLEAN(l)); + leftIsNumber = true; + } + if (JSVAL_TAG(r) == JSVAL_BOOLEAN) { + LIns* args[] = { b, cx_ins }; + b = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); + rnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_BOOLEAN(r)); + rightIsNumber = true; + } + if (leftIsNumber && rightIsNumber) { + if (intop) { + LIns *args[] = { a }; + a = lir->insCall(op == LIR_ush ? &js_DoubleToUint32_ci : &js_DoubleToInt32_ci, args); + b = f2i(b); + } + a = alu(op, lnum, rnum, a, b); + if (intop) + a = lir->ins1(op == LIR_ush ? LIR_u2f : LIR_i2f, a); + set(&l, a); + return true; + } + return false; +} + +JS_STATIC_ASSERT(offsetof(JSObjectOps, newObjectMap) == 0); + +bool +TraceRecorder::map_is_native(JSObjectMap* map, LIns* map_ins, LIns*& ops_ins, size_t op_offset) +{ + ops_ins = addName(lir->insLoad(LIR_ldp, map_ins, offsetof(JSObjectMap, ops)), "ops"); + LIns* n = lir->insLoad(LIR_ldp, ops_ins, op_offset); + +#define OP(ops) (*(JSObjectOp*) ((char*)(ops) + op_offset)) + + if (OP(map->ops) == OP(&js_ObjectOps)) { + guard(true, addName(lir->ins2(LIR_eq, n, INS_CONSTPTR(OP(&js_ObjectOps))), + "guard(native-map)"), + MISMATCH_EXIT); + return true; + } + +#undef OP + ABORT_TRACE("non-native map"); +} + +bool +TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, jsuword& pcval) +{ + jsbytecode* pc = cx->fp->regs->pc; + JS_ASSERT(*pc != JSOP_INITPROP && *pc != JSOP_SETNAME && *pc != JSOP_SETPROP); + + // Mimic the interpreter's special case for dense arrays by skipping up one + // hop along the proto chain when accessing a named (not indexed) property, + // typically to find Array.prototype methods. + JSObject* aobj = obj; + if (OBJ_IS_DENSE_ARRAY(cx, obj)) { + aobj = OBJ_GET_PROTO(cx, obj); + obj_ins = stobj_get_fslot(obj_ins, JSSLOT_PROTO); + } + + LIns* map_ins = lir->insLoad(LIR_ldp, obj_ins, (int)offsetof(JSObject, map)); + LIns* ops_ins; + + // Interpreter calls to PROPERTY_CACHE_TEST guard on native object ops + // (newObjectMap == js_ObjectOps.newObjectMap) which is required to use + // native objects (those whose maps are scopes), or even more narrow + // conditions required because the cache miss case will call a particular + // object-op (js_GetProperty, js_SetProperty). + // + // We parameterize using offsetof and guard on match against the hook at + // the given offset in js_ObjectOps. TraceRecorder::record_JSOP_SETPROP + // guards the js_SetProperty case. + uint32 format = js_CodeSpec[*pc].format; + uint32 mode = JOF_MODE(format); + + // No need to guard native-ness of global object. + JS_ASSERT(OBJ_IS_NATIVE(globalObj)); + if (aobj != globalObj) { + size_t op_offset = 0; + if (mode == JOF_PROP || mode == JOF_VARPROP) { + JS_ASSERT(!(format & JOF_SET)); + op_offset = offsetof(JSObjectOps, getProperty); + } else { + JS_ASSERT(mode == JOF_NAME); + } + + if (!map_is_native(aobj->map, map_ins, ops_ins, op_offset)) + return false; + } + + JSAtom* atom; + JSPropCacheEntry* entry; + PROPERTY_CACHE_TEST(cx, pc, aobj, obj2, entry, atom); + if (atom) { + // Miss: pre-fill the cache for the interpreter, as well as for our needs. + // FIXME: 452357 - correctly propagate exceptions into the interpreter from + // js_FindPropertyHelper, js_LookupPropertyWithFlags, and elsewhere. + jsid id = ATOM_TO_JSID(atom); + JSProperty* prop; + if (JOF_OPMODE(*pc) == JOF_NAME) { + JS_ASSERT(aobj == obj); + if (js_FindPropertyHelper(cx, id, &obj, &obj2, &prop, &entry) < 0) + ABORT_TRACE("failed to find name"); + } else { + int protoIndex = js_LookupPropertyWithFlags(cx, aobj, id, + cx->resolveFlags, + &obj2, &prop); + if (protoIndex < 0) + ABORT_TRACE("failed to lookup property"); + + if (prop) { + js_FillPropertyCache(cx, aobj, OBJ_SHAPE(aobj), 0, protoIndex, obj2, + (JSScopeProperty*) prop, &entry); + } + } + + if (!prop) { + // Propagate obj from js_FindPropertyHelper to record_JSOP_BINDNAME + // via our obj2 out-parameter. If we are recording JSOP_SETNAME and + // the global it's assigning does not yet exist, create it. + obj2 = obj; + + // Use PCVAL_NULL to return "no such property" to our caller. + pcval = PCVAL_NULL; + ABORT_TRACE("failed to find property"); + } + + OBJ_DROP_PROPERTY(cx, obj2, prop); + if (!entry) + ABORT_TRACE("failed to fill property cache"); + } + +#ifdef JS_THREADSAFE + // There's a potential race in any JS_THREADSAFE embedding that's nuts + // enough to share mutable objects on the scope or proto chain, but we + // don't care about such insane embeddings. Anyway, the (scope, proto) + // entry->vcap coordinates must reach obj2 from aobj at this point. + JS_ASSERT(cx->requestDepth); +#endif + + // Emit guard(s), common code for both hit and miss cases. + // Check for first-level cache hit and guard on kshape if possible. + // Otherwise guard on key object exact match. + if (PCVCAP_TAG(entry->vcap) <= 1) { + if (aobj != globalObj) { + LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)), + "shape"); + guard(true, addName(lir->ins2i(LIR_eq, shape_ins, entry->kshape), "guard(kshape)"), + MISMATCH_EXIT); + } + } else { +#ifdef DEBUG + JSOp op = JSOp(*pc); + ptrdiff_t pcoff = (op == JSOP_GETARGPROP) ? ARGNO_LEN : + (op == JSOP_GETLOCALPROP) ? SLOTNO_LEN : 0; + jsatomid index = js_GetIndexFromBytecode(cx, cx->fp->script, pc, pcoff); + JS_ASSERT(entry->kpc == (jsbytecode*) atoms[index]); + JS_ASSERT(entry->kshape == jsuword(aobj)); +#endif + if (aobj != globalObj) { + guard(true, addName(lir->ins2i(LIR_eq, obj_ins, entry->kshape), "guard(kobj)"), + MISMATCH_EXIT); + } + } + + // For any hit that goes up the scope and/or proto chains, we will need to + // guard on the shape of the object containing the property. + if (PCVCAP_TAG(entry->vcap) >= 1) { + jsuword vcap = entry->vcap; + uint32 vshape = PCVCAP_SHAPE(vcap); + JS_ASSERT(OBJ_SHAPE(obj2) == vshape); + + LIns* obj2_ins; + if (PCVCAP_TAG(entry->vcap) == 1) { + // Duplicate the special case in PROPERTY_CACHE_TEST. + obj2_ins = stobj_get_fslot(obj_ins, JSSLOT_PROTO); + guard(false, lir->ins_eq0(obj2_ins), MISMATCH_EXIT); + } else { + obj2_ins = INS_CONSTPTR(obj2); + } + map_ins = lir->insLoad(LIR_ldp, obj2_ins, (int)offsetof(JSObject, map)); + if (!map_is_native(obj2->map, map_ins, ops_ins)) + return false; + + LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)), + "shape"); + guard(true, + addName(lir->ins2i(LIR_eq, shape_ins, vshape), "guard(vshape)"), + MISMATCH_EXIT); + } + + pcval = entry->vword; + return true; +} + +bool +TraceRecorder::test_property_cache_direct_slot(JSObject* obj, LIns* obj_ins, uint32& slot) +{ + JSObject* obj2; + jsuword pcval; + + /* + * Property cache ensures that we are dealing with an existing property, + * and guards the shape for us. + */ + if (!test_property_cache(obj, obj_ins, obj2, pcval)) + return false; + + /* No such property means invalid slot, which callers must check for first. */ + if (PCVAL_IS_NULL(pcval)) { + slot = SPROP_INVALID_SLOT; + return true; + } + + /* Insist on obj being the directly addressed object. */ + if (obj2 != obj) + ABORT_TRACE("test_property_cache_direct_slot hit prototype chain"); + + /* Don't trace getter or setter calls, our caller wants a direct slot. */ + if (PCVAL_IS_SPROP(pcval)) { + JSScopeProperty* sprop = PCVAL_TO_SPROP(pcval); + + uint32 setflags = (js_CodeSpec[*cx->fp->regs->pc].format & (JOF_SET | JOF_INCDEC)); + if (setflags && !SPROP_HAS_STUB_SETTER(sprop)) + ABORT_TRACE("non-stub setter"); + if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop)) + ABORT_TRACE("non-stub getter"); + if (!SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj))) + ABORT_TRACE("no valid slot"); + slot = sprop->slot; + } else { + if (!PCVAL_IS_SLOT(pcval)) + ABORT_TRACE("PCE is not a slot"); + slot = PCVAL_TO_SLOT(pcval); + } + return true; +} + +void +TraceRecorder::stobj_set_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins, LIns* v_ins) +{ + if (slot < JS_INITIAL_NSLOTS) { + addName(lir->insStorei(v_ins, obj_ins, + offsetof(JSObject, fslots) + slot * sizeof(jsval)), + "set_slot(fslots)"); + } else { + if (!dslots_ins) + dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots)); + addName(lir->insStorei(v_ins, dslots_ins, + (slot - JS_INITIAL_NSLOTS) * sizeof(jsval)), + "set_slot(dslots"); + } +} + +LIns* +TraceRecorder::stobj_get_fslot(LIns* obj_ins, unsigned slot) +{ + JS_ASSERT(slot < JS_INITIAL_NSLOTS); + return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval)); +} + +LIns* +TraceRecorder::stobj_get_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins) +{ + if (slot < JS_INITIAL_NSLOTS) + return stobj_get_fslot(obj_ins, slot); + + if (!dslots_ins) + dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots)); + return lir->insLoad(LIR_ldp, dslots_ins, (slot - JS_INITIAL_NSLOTS) * sizeof(jsval)); +} + +bool +TraceRecorder::native_set(LIns* obj_ins, JSScopeProperty* sprop, LIns*& dslots_ins, LIns* v_ins) +{ + if (SPROP_HAS_STUB_SETTER(sprop) && sprop->slot != SPROP_INVALID_SLOT) { + stobj_set_slot(obj_ins, sprop->slot, dslots_ins, v_ins); + return true; + } + ABORT_TRACE("unallocated or non-stub sprop"); +} + +bool +TraceRecorder::native_get(LIns* obj_ins, LIns* pobj_ins, JSScopeProperty* sprop, + LIns*& dslots_ins, LIns*& v_ins) +{ + if (!SPROP_HAS_STUB_GETTER(sprop)) + return false; + + if (sprop->slot != SPROP_INVALID_SLOT) + v_ins = stobj_get_slot(pobj_ins, sprop->slot, dslots_ins); + else + v_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID)); + return true; +} + +// So box_jsval can emit no LIR_or at all to tag an object jsval. +JS_STATIC_ASSERT(JSVAL_OBJECT == 0); + +bool +TraceRecorder::box_jsval(jsval v, LIns*& v_ins) +{ + if (isNumber(v)) { + LIns* args[] = { v_ins, cx_ins }; + v_ins = lir->insCall(&js_BoxDouble_ci, args); + guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), + OOM_EXIT); + return true; + } + switch (JSVAL_TAG(v)) { + case JSVAL_BOOLEAN: + v_ins = lir->ins2i(LIR_pior, lir->ins2i(LIR_pilsh, v_ins, JSVAL_TAGBITS), JSVAL_BOOLEAN); + return true; + case JSVAL_OBJECT: + return true; + case JSVAL_STRING: + v_ins = lir->ins2(LIR_pior, v_ins, INS_CONST(JSVAL_STRING)); + return true; + } + return false; +} + +bool +TraceRecorder::unbox_jsval(jsval v, LIns*& v_ins) +{ + if (isNumber(v)) { + // JSVAL_IS_NUMBER(v) + guard(false, + lir->ins_eq0(lir->ins2(LIR_pior, + lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_INT)), + lir->ins2i(LIR_eq, + lir->ins2(LIR_piand, v_ins, + INS_CONST(JSVAL_TAGMASK)), + JSVAL_DOUBLE))), + MISMATCH_EXIT); + LIns* args[] = { v_ins }; + v_ins = lir->insCall(&js_UnboxDouble_ci, args); + return true; + } + switch (JSVAL_TAG(v)) { + case JSVAL_BOOLEAN: + guard(true, + lir->ins2i(LIR_eq, + lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)), + JSVAL_BOOLEAN), + MISMATCH_EXIT); + v_ins = lir->ins2i(LIR_ush, v_ins, JSVAL_TAGBITS); + return true; + case JSVAL_OBJECT: + guard(true, + lir->ins2i(LIR_eq, + lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)), + JSVAL_OBJECT), + MISMATCH_EXIT); + return true; + case JSVAL_STRING: + guard(true, + lir->ins2i(LIR_eq, + lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)), + JSVAL_STRING), + MISMATCH_EXIT); + v_ins = lir->ins2(LIR_piand, v_ins, INS_CONST(~JSVAL_TAGMASK)); + return true; + } + return false; +} + +bool +TraceRecorder::getThis(LIns*& this_ins) +{ + if (cx->fp->callee) { /* in a function */ + if (JSVAL_IS_NULL(cx->fp->argv[-1])) + return false; + this_ins = get(&cx->fp->argv[-1]); + guard(false, lir->ins_eq0(this_ins), MISMATCH_EXIT); + } else { /* in global code */ + this_ins = scopeChain(); + } + return true; +} + +bool +TraceRecorder::guardClass(JSObject* obj, LIns* obj_ins, JSClass* clasp, ExitType exitType) +{ + bool cond = STOBJ_GET_CLASS(obj) == clasp; + + LIns* class_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, classword)); + class_ins = lir->ins2(LIR_piand, class_ins, lir->insImm(~3)); + + char namebuf[32]; + JS_snprintf(namebuf, sizeof namebuf, "guard(class is %s)", clasp->name); + guard(cond, addName(lir->ins2(LIR_eq, class_ins, INS_CONSTPTR(clasp)), namebuf), exitType); + return cond; +} + +bool +TraceRecorder::guardDenseArray(JSObject* obj, LIns* obj_ins, ExitType exitType) +{ + return guardClass(obj, obj_ins, &js_ArrayClass, exitType); +} + +bool +TraceRecorder::guardDenseArrayIndex(JSObject* obj, jsint idx, LIns* obj_ins, + LIns* dslots_ins, LIns* idx_ins, ExitType exitType) +{ + jsuint length = ARRAY_DENSE_LENGTH(obj); + + bool cond = (jsuint(idx) < jsuint(obj->fslots[JSSLOT_ARRAY_LENGTH]) && jsuint(idx) < length); + if (cond) { + /* Guard array length */ + LIns* exit = guard(true, + lir->ins2(LIR_ult, idx_ins, stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH)), + exitType)->oprnd2(); + /* dslots must not be NULL */ + guard(false, + lir->ins_eq0(dslots_ins), + exit); + /* Guard array capacity */ + guard(true, + lir->ins2(LIR_ult, + idx_ins, + lir->insLoad(LIR_ldp, dslots_ins, 0 - (int)sizeof(jsval))), + exit); + } else { + /* If not idx < length, stay on trace (and read value as undefined). */ + LIns* br1 = lir->insBranch(LIR_jf, + lir->ins2(LIR_ult, + idx_ins, + stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH)), + NULL); + /* If dslots is NULL, stay on trace (and read value as undefined). */ + LIns* br2 = lir->insBranch(LIR_jt, lir->ins_eq0(dslots_ins), NULL); + /* If not idx < capacity, stay on trace (and read value as undefined). */ + LIns* br3 = lir->insBranch(LIR_jf, + lir->ins2(LIR_ult, + idx_ins, + lir->insLoad(LIR_ldp, dslots_ins, 0 - (int)sizeof(jsval))), + NULL); + lir->insGuard(LIR_x, lir->insImm(1), snapshot(exitType)); + LIns* label = lir->ins0(LIR_label); + br1->target(label); + br2->target(label); + br3->target(label); + } + return cond; +} + +/* + * Guard that a computed property access via an element op (JSOP_GETELEM, etc.) + * does not find an alias to a global variable, or a property without a slot, + * or a slot-ful property with a getter or setter (depending on op_offset in + * JSObjectOps). Finally, beware resolve hooks mutating objects. Oh, and watch + * out for bears too ;-). + * + * One win here is that we do not need to generate a guard that obj_ins does + * not result in the global object on trace, because we guard on shape and rule + * out obj's shape being the global object's shape at recording time. This is + * safe because the global shape cannot change on trace. + */ +bool +TraceRecorder::guardElemOp(JSObject* obj, LIns* obj_ins, jsid id, size_t op_offset, jsval* vp) +{ + LIns* map_ins = lir->insLoad(LIR_ldp, obj_ins, (int)offsetof(JSObject, map)); + LIns* ops_ins; + if (!map_is_native(obj->map, map_ins, ops_ins, op_offset)) + return false; + + uint32 shape = OBJ_SHAPE(obj); + if (JSID_IS_ATOM(id) && shape == traceMonitor->globalShape) + ABORT_TRACE("elem op probably aliases global"); + + JSObject* pobj; + JSProperty* prop; + if (!js_LookupProperty(cx, obj, id, &pobj, &prop)) + return false; + + if (vp) + *vp = JSVAL_VOID; + if (prop) { + bool traceable_slot = true; + if (pobj == obj) { + JSScopeProperty* sprop = (JSScopeProperty*) prop; + traceable_slot = ((op_offset == offsetof(JSObjectOps, getProperty)) + ? SPROP_HAS_STUB_GETTER(sprop) + : SPROP_HAS_STUB_SETTER(sprop)) && + SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)); + if (vp && traceable_slot) + *vp = LOCKED_OBJ_GET_SLOT(obj, sprop->slot); + } + + OBJ_DROP_PROPERTY(cx, pobj, prop); + if (pobj != obj) + ABORT_TRACE("elem op hit prototype property, can't shape-guard"); + if (!traceable_slot) + ABORT_TRACE("elem op hit direct and slotless getter or setter"); + } + + // If we got this far, we're almost safe -- but we must check for a rogue resolve hook. + if (OBJ_SHAPE(obj) != shape) + ABORT_TRACE("resolve hook mutated elem op base object"); + + LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)), "shape"); + guard(true, addName(lir->ins2i(LIR_eq, shape_ins, shape), "guard(shape)"), MISMATCH_EXIT); + return true; +} + +void +TraceRecorder::clearFrameSlotsFromCache() +{ + /* Clear out all slots of this frame in the nativeFrameTracker. Different locations on the + VM stack might map to different locations on the native stack depending on the + number of arguments (i.e.) of the next call, so we have to make sure we map + those in to the cache with the right offsets. */ + JSStackFrame* fp = cx->fp; + jsval* vp; + jsval* vpstop; + if (fp->callee) { + vp = &fp->argv[-2]; + vpstop = &fp->argv[fp->fun->nargs]; + while (vp < vpstop) + nativeFrameTracker.set(vp++, (LIns*)0); + } + vp = &fp->slots[0]; + vpstop = &fp->slots[fp->script->nslots]; + while (vp < vpstop) + nativeFrameTracker.set(vp++, (LIns*)0); +} + +bool +TraceRecorder::record_EnterFrame() +{ + JSStackFrame* fp = cx->fp; + + if (++callDepth >= MAX_CALLDEPTH) + ABORT_TRACE("exceeded maximum call depth"); + // FIXME: Allow and attempt to inline a single level of recursion until we compile + // recursive calls as independent trees (459301). + if (fp->script == fp->down->script && fp->down->down && fp->down->down->script == fp->script) + ABORT_TRACE("recursive call"); + + debug_only_v(printf("EnterFrame %s, callDepth=%d\n", + js_AtomToPrintableString(cx, cx->fp->fun->atom), + callDepth);) + LIns* void_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID)); + + jsval* vp = &fp->argv[fp->argc]; + jsval* vpstop = vp + ptrdiff_t(fp->fun->nargs) - ptrdiff_t(fp->argc); + if (applyingArguments) { + applyingArguments = false; + while (vp < vpstop) { + JS_ASSERT(vp >= fp->down->regs->sp); + nativeFrameTracker.set(vp, (LIns*)0); + LIns* arg_ins = get(&fp->down->argv[fp->argc + (vp - vpstop)]); + set(vp++, arg_ins, true); + } + } else { + while (vp < vpstop) { + if (vp >= fp->down->regs->sp) + nativeFrameTracker.set(vp, (LIns*)0); + set(vp++, void_ins, true); + } + } + + vp = &fp->slots[0]; + vpstop = vp + fp->script->nfixed; + while (vp < vpstop) + set(vp++, void_ins, true); + return true; +} + +bool +TraceRecorder::record_LeaveFrame() +{ + debug_only_v( + if (cx->fp->fun) + printf("LeaveFrame (back to %s), callDepth=%d\n", + js_AtomToPrintableString(cx, cx->fp->fun->atom), + callDepth); + ); + if (callDepth-- <= 0) + ABORT_TRACE("returned out of a loop we started tracing"); + + // LeaveFrame gets called after the interpreter popped the frame and + // stored rval, so cx->fp not cx->fp->down, and -1 not 0. + atoms = cx->fp->script->atomMap.vector; + set(&stackval(-1), rval_ins, true); + return true; +} + +bool +TraceRecorder::record_JSOP_INTERRUPT() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_PUSH() +{ + stack(0, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID))); + return true; +} + +bool +TraceRecorder::record_JSOP_POPV() +{ + jsval& rval = stackval(-1); + LIns *rval_ins = get(&rval); + if (!box_jsval(rval, rval_ins)) + return false; + + // Store it in cx->fp->rval. NB: Tricky dependencies. cx->fp is the right + // frame because POPV appears only in global and eval code and we don't + // trace JSOP_EVAL or leaving the frame where tracing started. + LIns *fp_ins = lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp)); + lir->insStorei(rval_ins, fp_ins, offsetof(JSStackFrame, rval)); + return true; +} + +bool +TraceRecorder::record_JSOP_ENTERWITH() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_LEAVEWITH() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_RETURN() +{ + jsval& rval = stackval(-1); + JSStackFrame *fp = cx->fp; + if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && JSVAL_IS_PRIMITIVE(rval)) { + JS_ASSERT(OBJECT_TO_JSVAL(fp->thisp) == fp->argv[-1]); + rval_ins = get(&fp->argv[-1]); + } else { + rval_ins = get(&rval); + } + debug_only_v(printf("returning from %s\n", js_AtomToPrintableString(cx, cx->fp->fun->atom));) + clearFrameSlotsFromCache(); + return true; +} + +bool +TraceRecorder::record_JSOP_GOTO() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_IFEQ() +{ + trackCfgMerges(cx->fp->regs->pc); + return ifop(); +} + +bool +TraceRecorder::record_JSOP_IFNE() +{ + return ifop(); +} + +bool +TraceRecorder::record_JSOP_ARGUMENTS() +{ +#if 1 + ABORT_TRACE("can't trace arguments yet"); +#else + LIns* args[] = { cx_ins }; + LIns* a_ins = lir->insCall(&js_Arguments_ci, args); + guard(false, lir->ins_eq0(a_ins), OOM_EXIT); + stack(0, a_ins); + return true; +#endif +} + +bool +TraceRecorder::record_JSOP_DUP() +{ + stack(0, get(&stackval(-1))); + return true; +} + +bool +TraceRecorder::record_JSOP_DUP2() +{ + stack(0, get(&stackval(-2))); + stack(1, get(&stackval(-1))); + return true; +} + +bool +TraceRecorder::record_JSOP_SWAP() +{ + jsval& l = stackval(-2); + jsval& r = stackval(-1); + LIns* l_ins = get(&l); + LIns* r_ins = get(&r); + set(&r, l_ins); + set(&l, r_ins); + return true; +} + +bool +TraceRecorder::record_JSOP_SETCONST() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_BITOR() +{ + return binary(LIR_or); +} + +bool +TraceRecorder::record_JSOP_BITXOR() +{ + return binary(LIR_xor); +} + +bool +TraceRecorder::record_JSOP_BITAND() +{ + return binary(LIR_and); +} + +bool +TraceRecorder::record_JSOP_EQ() +{ + return cmp(LIR_feq, CMP_TRY_BRANCH_AFTER_COND); +} + +bool +TraceRecorder::record_JSOP_NE() +{ + return cmp(LIR_feq, CMP_NEGATE | CMP_TRY_BRANCH_AFTER_COND); +} + +bool +TraceRecorder::record_JSOP_LT() +{ + return cmp(LIR_flt, CMP_TRY_BRANCH_AFTER_COND); +} + +bool +TraceRecorder::record_JSOP_LE() +{ + return cmp(LIR_fle, CMP_TRY_BRANCH_AFTER_COND); +} + +bool +TraceRecorder::record_JSOP_GT() +{ + return cmp(LIR_fgt, CMP_TRY_BRANCH_AFTER_COND); +} + +bool +TraceRecorder::record_JSOP_GE() +{ + return cmp(LIR_fge, CMP_TRY_BRANCH_AFTER_COND); +} + +bool +TraceRecorder::record_JSOP_LSH() +{ + return binary(LIR_lsh); +} + +bool +TraceRecorder::record_JSOP_RSH() +{ + return binary(LIR_rsh); +} + +bool +TraceRecorder::record_JSOP_URSH() +{ + return binary(LIR_ush); +} + +static struct { + jsbytecode obj_any[10]; + jsbytecode any_obj[8]; + jsbytecode obj_obj[16]; +} add_imacros = { + { + JSOP_SWAP, + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString), + JSOP_CALL, 0, 0, + JSOP_SWAP, + JSOP_ADD, + JSOP_STOP + }, + + { + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString), + JSOP_CALL, 0, 0, + JSOP_ADD, + JSOP_STOP + }, + + { + JSOP_SWAP, + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString), + JSOP_CALL, 0, 0, + JSOP_SWAP, + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(toString), + JSOP_CALL, 0, 0, + JSOP_ADD, + JSOP_STOP + } +}; + +JS_STATIC_ASSERT(sizeof(add_imacros) < IMACRO_PC_ADJ_LIMIT); + +bool +TraceRecorder::record_JSOP_ADD() +{ + jsval& r = stackval(-1); + jsval& l = stackval(-2); + + if (JSVAL_IS_OBJECT(l) && hasToStringMethod(l)) { + if (JSVAL_IS_OBJECT(r) && hasToStringMethod(r)) + return call_imacro(add_imacros.obj_obj); + return call_imacro(add_imacros.obj_any); + } + if (JSVAL_IS_OBJECT(r) && hasToStringMethod(r)) + return call_imacro(add_imacros.any_obj); + + if (JSVAL_IS_STRING(l) || JSVAL_IS_STRING(r)) { + LIns* args[] = { stringify(r), stringify(l), cx_ins }; + if (!args[0] || !args[1]) + ABORT_TRACE("can't stringify objects"); + LIns* concat = lir->insCall(&js_ConcatStrings_ci, args); + guard(false, lir->ins_eq0(concat), OOM_EXIT); + set(&l, concat); + return true; + } + + return binary(LIR_fadd); +} + +bool +TraceRecorder::record_JSOP_SUB() +{ + return binary(LIR_fsub); +} + +bool +TraceRecorder::record_JSOP_MUL() +{ + return binary(LIR_fmul); +} + +bool +TraceRecorder::record_JSOP_DIV() +{ + return binary(LIR_fdiv); +} + +bool +TraceRecorder::record_JSOP_MOD() +{ + jsval& r = stackval(-1); + jsval& l = stackval(-2); + + if (JSVAL_IS_OBJECT(l) && hasValueOfMethod(l)) { + if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r)) + return call_imacro(binary_imacros.obj_obj); + return call_imacro(binary_imacros.obj_any); + } + if (JSVAL_IS_OBJECT(r) && hasValueOfMethod(r)) + return call_imacro(binary_imacros.any_obj); + + if (isNumber(l) && isNumber(r)) { + LIns* l_ins = get(&l); + LIns* r_ins = get(&r); + LIns* x; + /* We can't demote this in a filter since we need the actual values of l and r. */ + if (isPromote(l_ins) && isPromote(r_ins) && asNumber(l) >= 0 && asNumber(r) > 0) { + LIns* args[] = { ::demote(lir, r_ins), ::demote(lir, l_ins) }; + x = lir->insCall(&js_imod_ci, args); + guard(false, lir->ins2(LIR_eq, x, lir->insImm(-1)), BRANCH_EXIT); + x = lir->ins1(LIR_i2f, x); + } else { + LIns* args[] = { r_ins, l_ins }; + x = lir->insCall(&js_dmod_ci, args); + } + set(&l, x); + return true; + } + return false; +} + +bool +TraceRecorder::record_JSOP_NOT() +{ + jsval& v = stackval(-1); + if (JSVAL_TAG(v) == JSVAL_BOOLEAN) { + set(&v, lir->ins_eq0(lir->ins2i(LIR_eq, get(&v), 1))); + return true; + } + if (isNumber(v)) { + LIns* v_ins = get(&v); + set(&v, lir->ins2(LIR_or, lir->ins2(LIR_feq, v_ins, lir->insImmq(0)), + lir->ins_eq0(lir->ins2(LIR_feq, v_ins, v_ins)))); + return true; + } + if (JSVAL_IS_OBJECT(v)) { + set(&v, lir->ins_eq0(get(&v))); + return true; + } + JS_ASSERT(JSVAL_IS_STRING(v)); + set(&v, lir->ins_eq0(lir->ins2(LIR_piand, + lir->insLoad(LIR_ldp, get(&v), (int)offsetof(JSString, length)), + INS_CONSTPTR(JSSTRING_LENGTH_MASK)))); + return true; +} + +bool +TraceRecorder::record_JSOP_BITNOT() +{ + return unary(LIR_not); +} + +bool +TraceRecorder::record_JSOP_NEG() +{ + jsval& v = stackval(-1); + if (isNumber(v)) { + LIns* a = get(&v); + + /* If we're a promoted integer, we have to watch out for 0s since -0 is a double. + Only follow this path if we're not an integer that's 0 and we're not a double + that's zero. + */ + if (isPromoteInt(a) && + (!JSVAL_IS_INT(v) || JSVAL_TO_INT(v) != 0) && + (!JSVAL_IS_DOUBLE(v) || !JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v)))) { + a = lir->ins1(LIR_neg, ::demote(lir, a)); + lir->insGuard(LIR_xt, lir->ins1(LIR_ov, a), snapshot(OVERFLOW_EXIT)); + lir->insGuard(LIR_xt, lir->ins2(LIR_eq, a, lir->insImm(0)), snapshot(OVERFLOW_EXIT)); + a = lir->ins1(LIR_i2f, a); + } else { + a = lir->ins1(LIR_fneg, a); + } + + set(&v, a); + return true; + } + return false; +} + +JSBool +js_Array(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval); + +JSBool +js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +JSBool +js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +JSBool +js_fun_apply(JSContext* cx, uintN argc, jsval* vp); + +bool +TraceRecorder::functionCall(bool constructing) +{ + JSStackFrame* fp = cx->fp; + jsbytecode *pc = fp->regs->pc; + uintN argc = GET_ARGC(pc); + + jsval& fval = stackval(0 - (2 + argc)); + JS_ASSERT(&fval >= StackBase(fp)); + + if (!VALUE_IS_FUNCTION(cx, fval)) + ABORT_TRACE("callee is not a function"); + + jsval& tval = stackval(0 - (argc + 1)); + LIns* this_ins = get(&tval); + + if (this_ins->isconstp() && !this_ins->constvalp() && !guardShapelessCallee(fval)) + return false; + + /* + * Require that the callee be a function object, to avoid guarding on its + * class here. We know if the callee and this were pushed by JSOP_CALLNAME + * or JSOP_CALLPROP that callee is a *particular* function, since these hit + * the property cache and guard on the object (this) in which the callee + * was found. So it's sufficient to test here that the particular function + * is interpreted, not guard on that condition. + * + * Bytecode sequences that push shapeless callees must guard on the callee + * class being Function and the function being interpreted. + */ + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(fval)); + + if (FUN_INTERPRETED(fun)) { + if (constructing) { + LIns* args[] = { get(&fval), cx_ins }; + LIns* tv_ins = lir->insCall(&js_FastNewObject_ci, args); + guard(false, lir->ins_eq0(tv_ins), OOM_EXIT); + set(&tval, tv_ins); + } + return interpretedFunctionCall(fval, fun, argc, constructing); + } + + LIns* arg1_ins = NULL; + jsval arg1 = JSVAL_VOID; + jsval thisval = tval; + if (!constructing && FUN_FAST_NATIVE(fun) == js_fun_apply) { + if (argc != 2) + ABORT_TRACE("can't trace Function.prototype.apply with other than 2 args"); + + if (!guardShapelessCallee(tval)) + return false; + JSObject* tfunobj = JSVAL_TO_OBJECT(tval); + JSFunction* tfun = GET_FUNCTION_PRIVATE(cx, tfunobj); + + jsval& oval = stackval(-2); + if (JSVAL_IS_PRIMITIVE(oval)) + ABORT_TRACE("can't trace Function.prototype.apply with primitive 1st arg"); + + jsval& aval = stackval(-1); + if (JSVAL_IS_PRIMITIVE(aval)) + ABORT_TRACE("can't trace Function.prototype.apply with primitive 2nd arg"); + JSObject* aobj = JSVAL_TO_OBJECT(aval); + + LIns* aval_ins = get(&aval); + if (!aval_ins->isCall()) + ABORT_TRACE("can't trace Function.prototype.apply on non-builtin-call 2nd arg"); + + if (aval_ins->callInfo() == &js_Arguments_ci) { + JS_ASSERT(OBJ_GET_CLASS(cx, aobj) == &js_ArgumentsClass); + JS_ASSERT(OBJ_GET_PRIVATE(cx, aobj) == fp); + if (!FUN_INTERPRETED(tfun)) + ABORT_TRACE("can't trace Function.prototype.apply(native_function, arguments)"); + + // We can only fasttrack applys where the argument array we pass in has the + // same length (fp->argc) as the number of arguments the function expects (tfun->nargs). + argc = fp->argc; + if (tfun->nargs != argc || fp->fun->nargs != argc) + ABORT_TRACE("can't trace Function.prototype.apply(scripted_function, arguments)"); + + jsval* sp = fp->regs->sp - 4; + set(sp, get(&tval)); + *sp++ = tval; + set(sp, get(&oval)); + *sp++ = oval; + jsval* newsp = sp + argc; + if (newsp > fp->slots + fp->script->nslots) { + JSArena* a = cx->stackPool.current; + if (jsuword(newsp) > a->limit) + ABORT_TRACE("can't grow stack for Function.prototype.apply"); + if (jsuword(newsp) > a->avail) + a->avail = jsuword(newsp); + } + + jsval* argv = fp->argv; + for (uintN i = 0; i < JS_MIN(argc, 2); i++) { + set(&sp[i], get(&argv[i])); + sp[i] = argv[i]; + } + applyingArguments = true; + return interpretedFunctionCall(tval, tfun, argc, false); + } + + if (aval_ins->callInfo() != &js_Array_1str_ci) + ABORT_TRACE("can't trace Function.prototype.apply on other than [str] 2nd arg"); + + JS_ASSERT(OBJ_IS_ARRAY(cx, aobj)); + JS_ASSERT(aobj->fslots[JSSLOT_ARRAY_LENGTH] == 1); + JS_ASSERT(JSVAL_IS_STRING(aobj->dslots[0])); + + if (FUN_INTERPRETED(tfun)) + ABORT_TRACE("can't trace Function.prototype.apply for scripted functions"); + + if (!(tfun->flags & JSFUN_TRACEABLE)) + ABORT_TRACE("Function.prototype.apply on untraceable native"); + + thisval = oval; + this_ins = get(&oval); + arg1_ins = callArgN(aval_ins, 2); + arg1 = aobj->dslots[0]; + fun = tfun; + argc = 1; + } + + if (!constructing && !(fun->flags & JSFUN_TRACEABLE)) + ABORT_TRACE("untraceable native"); + + static JSTraceableNative knownNatives[] = { + { (JSFastNative)js_Array, &js_FastNewArray_ci, "pC", "", FAIL_NULL | JSTN_MORE }, + { (JSFastNative)js_Array, &js_Array_1int_ci, "pC", "i", FAIL_NULL | JSTN_MORE }, + { (JSFastNative)js_Array, &js_Array_2obj_ci, "pC", "oo", FAIL_NULL | JSTN_MORE }, + { (JSFastNative)js_Array, &js_Array_3num_ci, "pC", "ddd", FAIL_NULL | JSTN_MORE }, + { (JSFastNative)js_Object, &js_FastNewObject_ci, "fC", "", FAIL_NULL | JSTN_MORE }, + { (JSFastNative)js_Date, &js_FastNewDate_ci, "pC", "", FAIL_NULL }, + }; + + LIns* args[5]; + JSTraceableNative* known = constructing ? knownNatives : FUN_TRCINFO(fun); + do { + if (constructing && (JSFastNative)fun->u.n.native != known->native) + continue; + + uintN knownargc = strlen(known->argtypes); + if (argc != knownargc) + continue; + + intN prefixc = strlen(known->prefix); + JS_ASSERT(prefixc <= 3); + LIns** argp = &args[argc + prefixc - 1]; + char argtype; + +#if defined _DEBUG + memset(args, 0xCD, sizeof(args)); +#endif + + uintN i; + for (i = prefixc; i--; ) { + argtype = known->prefix[i]; + if (argtype == 'C') { + *argp = cx_ins; + } else if (argtype == 'T') { /* this, as an object */ + if (!JSVAL_IS_OBJECT(thisval)) + goto next_specialization; + *argp = this_ins; + } else if (argtype == 'S') { /* this, as a string */ + if (!JSVAL_IS_STRING(thisval)) + goto next_specialization; + *argp = this_ins; + } else if (argtype == 'f') { + *argp = INS_CONSTPTR(JSVAL_TO_OBJECT(fval)); + } else if (argtype == 'p') { + JSObject* ctor = JSVAL_TO_OBJECT(fval); + jsval pval; + if (!OBJ_GET_PROPERTY(cx, ctor, + ATOM_TO_JSID(cx->runtime->atomState + .classPrototypeAtom), + &pval)) { + ABORT_TRACE("error getting prototype from constructor"); + } + if (!JSVAL_IS_OBJECT(pval)) + ABORT_TRACE("got primitive prototype from constructor"); + *argp = INS_CONSTPTR(JSVAL_TO_OBJECT(pval)); + } else if (argtype == 'R') { + *argp = INS_CONSTPTR(cx->runtime); + } else if (argtype == 'P') { + *argp = INS_CONSTPTR(pc); + } else if (argtype == 'D') { /* this, as a number */ + if (!isNumber(thisval)) + goto next_specialization; + *argp = this_ins; + } else { + JS_NOT_REACHED("unknown prefix arg type"); + } + argp--; + } + + for (i = knownargc; i--; ) { + jsval& arg = (!constructing && i == 0 && arg1_ins) ? arg1 : stackval(0 - (i + 1)); + *argp = (!constructing && i == 0 && arg1_ins) ? arg1_ins : get(&arg); + + argtype = known->argtypes[i]; + if (argtype == 'd' || argtype == 'i') { + if (!isNumber(arg)) + goto next_specialization; + if (argtype == 'i') + *argp = f2i(*argp); + } else if (argtype == 'o') { + if (!JSVAL_IS_OBJECT(arg)) + goto next_specialization; + } else if (argtype == 's') { + if (!JSVAL_IS_STRING(arg)) + goto next_specialization; + } else if (argtype == 'r') { + if (!VALUE_IS_REGEXP(cx, arg)) + goto next_specialization; + } else if (argtype == 'f') { + if (!VALUE_IS_FUNCTION(cx, arg)) + goto next_specialization; + } else if (argtype == 'v') { + if (!box_jsval(arg, *argp)) + return false; + } else { + goto next_specialization; + } + argp--; + } + + /* + * If we got this far, and we have a charCodeAt, check that charCodeAt + * isn't going to return a NaN. + */ + if (!constructing && known->builtin == &js_String_p_charCodeAt_ci) { + JSString* str = JSVAL_TO_STRING(thisval); + jsval& arg = arg1_ins ? arg1 : stackval(-1); + + JS_ASSERT(JSVAL_IS_STRING(thisval)); + JS_ASSERT(isNumber(arg)); + + if (JSVAL_IS_INT(arg)) { + if (size_t(JSVAL_TO_INT(arg)) >= JSSTRING_LENGTH(str)) + ABORT_TRACE("invalid charCodeAt index"); + } else { + double d = js_DoubleToInteger(*JSVAL_TO_DOUBLE(arg)); + if (d < 0 || JSSTRING_LENGTH(str) <= d) + ABORT_TRACE("invalid charCodeAt index"); + } + } + goto success; + +next_specialization:; + } while ((known++)->flags & JSTN_MORE); + + if (!constructing) + ABORT_TRACE("unknown native"); + if (!(fun->flags & JSFUN_TRACEABLE) && FUN_CLASP(fun)) + ABORT_TRACE("can't trace native constructor"); + ABORT_TRACE("can't trace unknown constructor"); + +success: +#if defined _DEBUG + JS_ASSERT(args[0] != (LIns *)0xcdcdcdcd); +#endif + + LIns* res_ins = lir->insCall(known->builtin, args); + if (!constructing) + rval_ins = res_ins; + switch (JSTN_ERRTYPE(known)) { + case FAIL_NULL: + guard(false, lir->ins_eq0(res_ins), OOM_EXIT); + break; + case FAIL_NEG: + { + res_ins = lir->ins1(LIR_i2f, res_ins); + jsdpun u; + u.d = 0.0; + guard(false, lir->ins2(LIR_flt, res_ins, lir->insImmq(u.u64)), OOM_EXIT); + break; + } + case FAIL_VOID: + guard(false, lir->ins2i(LIR_eq, res_ins, JSVAL_TO_BOOLEAN(JSVAL_VOID)), OOM_EXIT); + break; + default:; + } + set(&fval, res_ins); + + if (!constructing) { + /* + * The return value will be processed by FastNativeCallComplete since + * we have to know the actual return value type for calls that return + * jsval (like Array_p_pop). + */ + pendingTraceableNative = known; + } + + return true; +} + +bool +TraceRecorder::record_JSOP_NEW() +{ + return functionCall(true); +} + +bool +TraceRecorder::record_JSOP_DELNAME() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_DELPROP() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_DELELEM() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_TYPEOF() +{ + jsval& r = stackval(-1); + LIns* type; + if (JSVAL_IS_STRING(r)) { + type = INS_CONSTPTR(ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_STRING])); + } else if (isNumber(r)) { + type = INS_CONSTPTR(ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER])); + } else { + LIns* args[] = { get(&r), cx_ins }; + if (JSVAL_TAG(r) == JSVAL_BOOLEAN) { + // We specialize identically for boolean and undefined. We must not have a hole here. + // Pass the unboxed type here, since TypeOfBoolean knows how to handle it. + JS_ASSERT(JSVAL_TO_BOOLEAN(r) <= 2); + type = lir->insCall(&js_TypeOfBoolean_ci, args); + } else { + JS_ASSERT(JSVAL_IS_OBJECT(r)); + type = lir->insCall(&js_TypeOfObject_ci, args); + } + } + set(&r, type); + return true; +} + +bool +TraceRecorder::record_JSOP_VOID() +{ + stack(-1, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID))); + return true; +} + +bool +TraceRecorder::record_JSOP_INCNAME() +{ + return incName(1); +} + +bool +TraceRecorder::record_JSOP_INCPROP() +{ + return incProp(1); +} + +bool +TraceRecorder::record_JSOP_INCELEM() +{ + return incElem(1); +} + +bool +TraceRecorder::record_JSOP_DECNAME() +{ + return incName(-1); +} + +bool +TraceRecorder::record_JSOP_DECPROP() +{ + return incProp(-1); +} + +bool +TraceRecorder::record_JSOP_DECELEM() +{ + return incElem(-1); +} + +bool +TraceRecorder::incName(jsint incr, bool pre) +{ + jsval* vp; + if (!name(vp)) + return false; + LIns* v_ins = get(vp); + if (!inc(*vp, v_ins, incr, pre)) + return false; + set(vp, v_ins); + return true; +} + +bool +TraceRecorder::record_JSOP_NAMEINC() +{ + return incName(1, false); +} + +bool +TraceRecorder::record_JSOP_PROPINC() +{ + return incProp(1, false); +} + +// XXX consolidate with record_JSOP_GETELEM code... +bool +TraceRecorder::record_JSOP_ELEMINC() +{ + return incElem(1, false); +} + +bool +TraceRecorder::record_JSOP_NAMEDEC() +{ + return incName(-1, false); +} + +bool +TraceRecorder::record_JSOP_PROPDEC() +{ + return incProp(-1, false); +} + +bool +TraceRecorder::record_JSOP_ELEMDEC() +{ + return incElem(-1, false); +} + +bool +TraceRecorder::record_JSOP_GETPROP() +{ + return getProp(stackval(-1)); +} + +bool +TraceRecorder::record_JSOP_SETPROP() +{ + jsval& l = stackval(-2); + if (JSVAL_IS_PRIMITIVE(l)) + ABORT_TRACE("primitive this for SETPROP"); + + JSObject* obj = JSVAL_TO_OBJECT(l); + if (obj->map->ops->setProperty != js_SetProperty) + ABORT_TRACE("non-native JSObjectOps::setProperty"); + return true; +} + +bool +TraceRecorder::record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop) +{ + if (sprop->setter == js_watch_set) + ABORT_TRACE("watchpoint detected"); + + jsbytecode* pc = cx->fp->regs->pc; + jsval& r = stackval(-1); + jsval& l = stackval(-2); + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(l)); + JSObject* obj = JSVAL_TO_OBJECT(l); + LIns* obj_ins = get(&l); + + if (obj == globalObj) { + JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj))); + uint32 slot = sprop->slot; + if (!lazilyImportGlobalSlot(slot)) + ABORT_TRACE("lazy import of global slot failed"); + + LIns* r_ins = get(&r); + set(&STOBJ_GET_SLOT(obj, slot), r_ins); + + JS_ASSERT(*pc != JSOP_INITPROP); + if (pc[JSOP_SETPROP_LENGTH] != JSOP_POP) + set(&l, r_ins); + return true; + } + + // The global object's shape is guarded at trace entry, all others need a guard here. + LIns* map_ins = lir->insLoad(LIR_ldp, obj_ins, (int)offsetof(JSObject, map)); + LIns* ops_ins; + if (!map_is_native(obj->map, map_ins, ops_ins, offsetof(JSObjectOps, setProperty))) + return false; + + LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)), "shape"); + guard(true, addName(lir->ins2i(LIR_eq, shape_ins, entry->kshape), "guard(shape)"), + MISMATCH_EXIT); + + if (entry->kshape != PCVCAP_SHAPE(entry->vcap)) { + LIns* args[] = { INS_CONSTPTR(sprop), obj_ins, cx_ins }; + LIns* ok_ins = lir->insCall(&js_AddProperty_ci, args); + guard(false, lir->ins_eq0(ok_ins), OOM_EXIT); + } + + LIns* dslots_ins = NULL; + LIns* v_ins = get(&r); + LIns* boxed_ins = v_ins; + if (!box_jsval(r, boxed_ins)) + return false; + if (!native_set(obj_ins, sprop, dslots_ins, boxed_ins)) + return false; + + if (*pc != JSOP_INITPROP && pc[JSOP_SETPROP_LENGTH] != JSOP_POP) + set(&l, v_ins); + return true; +} + +bool +TraceRecorder::record_SetPropMiss(JSPropCacheEntry* entry) +{ + if (entry->kpc != cx->fp->regs->pc || !PCVAL_IS_SPROP(entry->vword)) + ABORT_TRACE("can't trace uncacheable property set"); + + JSScopeProperty* sprop = PCVAL_TO_SPROP(entry->vword); + +#ifdef DEBUG + jsval& l = stackval(-2); + JSObject* obj = JSVAL_TO_OBJECT(l); + JSScope* scope = OBJ_SCOPE(obj); + JS_ASSERT(scope->object == obj); + JS_ASSERT(scope->shape == PCVCAP_SHAPE(entry->vcap)); + JS_ASSERT(SCOPE_HAS_PROPERTY(scope, sprop)); +#endif + + return record_SetPropHit(entry, sprop); +} + +bool +TraceRecorder::record_JSOP_GETELEM() +{ + jsval& idx = stackval(-1); + jsval& lval = stackval(-2); + + LIns* obj_ins = get(&lval); + LIns* idx_ins = get(&idx); + + if (JSVAL_IS_STRING(lval) && JSVAL_IS_INT(idx)) { + int i = JSVAL_TO_INT(idx); + if ((size_t)i >= JSSTRING_LENGTH(JSVAL_TO_STRING(lval))) + ABORT_TRACE("Invalid string index in JSOP_GETELEM"); + idx_ins = makeNumberInt32(idx_ins); + LIns* args[] = { idx_ins, obj_ins, cx_ins }; + LIns* unitstr_ins = lir->insCall(&js_String_getelem_ci, args); + guard(false, lir->ins_eq0(unitstr_ins), MISMATCH_EXIT); + set(&lval, unitstr_ins); + return true; + } + + if (JSVAL_IS_PRIMITIVE(lval)) + ABORT_TRACE("JSOP_GETLEM on a primitive"); + + JSObject* obj = JSVAL_TO_OBJECT(lval); + jsval id; + jsval v; + LIns* v_ins; + + /* Property access using a string name. */ + if (JSVAL_IS_STRING(idx)) { + if (!js_ValueToStringId(cx, idx, &id)) + return false; + // Store the interned string to the stack to save the interpreter from redoing this work. + idx = ID_TO_VALUE(id); + jsuint index; + if (js_IdIsIndex(idx, &index) && guardDenseArray(obj, obj_ins, BRANCH_EXIT)) { + v = (index >= ARRAY_DENSE_LENGTH(obj)) ? JSVAL_HOLE : obj->dslots[index]; + if (v == JSVAL_HOLE) + ABORT_TRACE("can't see through hole in dense array"); + } else { + if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, getProperty), &v)) + return false; + } + LIns* args[] = { idx_ins, obj_ins, cx_ins }; + v_ins = lir->insCall(&js_Any_getprop_ci, args); + guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), MISMATCH_EXIT); + if (!unbox_jsval(v, v_ins)) + ABORT_TRACE("JSOP_GETELEM"); + set(&lval, v_ins); + return true; + } + + /* At this point we expect a whole number or we bail. */ + if (!JSVAL_IS_INT(idx)) + ABORT_TRACE("non-string, non-int JSOP_GETELEM index"); + if (JSVAL_TO_INT(idx) < 0) + ABORT_TRACE("negative JSOP_GETELEM index"); + + /* Accessing an object using integer index but not a dense array. */ + if (!OBJ_IS_DENSE_ARRAY(cx, obj)) { + idx_ins = makeNumberInt32(idx_ins); + LIns* args[] = { idx_ins, obj_ins, cx_ins }; + if (!js_IndexToId(cx, JSVAL_TO_INT(idx), &id)) + return false; + idx = ID_TO_VALUE(id); + if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, getProperty), &v)) + return false; + LIns* v_ins = lir->insCall(&js_Any_getelem_ci, args); + guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), MISMATCH_EXIT); + if (!unbox_jsval(v, v_ins)) + ABORT_TRACE("JSOP_GETELEM"); + set(&lval, v_ins); + return true; + } + + jsval* vp; + LIns* addr_ins; + if (!elem(lval, idx, vp, v_ins, addr_ins)) + return false; + set(&lval, v_ins); + return true; +} + +bool +TraceRecorder::record_JSOP_SETELEM() +{ + jsval& v = stackval(-1); + jsval& idx = stackval(-2); + jsval& lval = stackval(-3); + + /* no guards for type checks, trace specialized this already */ + if (JSVAL_IS_PRIMITIVE(lval)) + ABORT_TRACE("left JSOP_SETELEM operand is not an object"); + + JSObject* obj = JSVAL_TO_OBJECT(lval); + LIns* obj_ins = get(&lval); + LIns* idx_ins = get(&idx); + LIns* v_ins = get(&v); + jsid id; + + LIns* boxed_v_ins = v_ins; + if (!box_jsval(v, boxed_v_ins)) + ABORT_TRACE("boxing JSOP_SETELEM value"); + + if (JSVAL_IS_STRING(idx)) { + if (!js_ValueToStringId(cx, idx, &id)) + return false; + // Store the interned string to the stack to save the interpreter from redoing this work. + idx = ID_TO_VALUE(id); + if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, setProperty), NULL)) + return false; + LIns* args[] = { boxed_v_ins, idx_ins, obj_ins, cx_ins }; + LIns* ok_ins = lir->insCall(&js_Any_setprop_ci, args); + guard(false, lir->ins_eq0(ok_ins), MISMATCH_EXIT); + } else if (JSVAL_IS_INT(idx)) { + if (JSVAL_TO_INT(idx) < 0) + ABORT_TRACE("negative JSOP_SETELEM index"); + idx_ins = makeNumberInt32(idx_ins); + LIns* args[] = { boxed_v_ins, idx_ins, obj_ins, cx_ins }; + LIns* res_ins; + if (guardDenseArray(obj, obj_ins, BRANCH_EXIT)) { + res_ins = lir->insCall(&js_Array_dense_setelem_ci, args); + } else { + if (!js_IndexToId(cx, JSVAL_TO_INT(idx), &id)) + return false; + idx = ID_TO_VALUE(id); + if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, setProperty), NULL)) + return false; + res_ins = lir->insCall(&js_Any_setelem_ci, args); + } + guard(false, lir->ins_eq0(res_ins), MISMATCH_EXIT); + } else { + ABORT_TRACE("non-string, non-int JSOP_SETELEM index"); + } + + jsbytecode* pc = cx->fp->regs->pc; + if (*pc == JSOP_SETELEM && pc[JSOP_SETELEM_LENGTH] != JSOP_POP) + set(&lval, v_ins); + + return true; +} + +bool +TraceRecorder::record_JSOP_CALLNAME() +{ + JSObject* obj = cx->fp->scopeChain; + if (obj != globalObj) { + jsval* vp; + if (!activeCallOrGlobalSlot(obj, vp)) + return false; + stack(0, get(vp)); + stack(1, INS_CONSTPTR(globalObj)); + return true; + } + + LIns* obj_ins = scopeChain(); + JSObject* obj2; + jsuword pcval; + if (!test_property_cache(obj, obj_ins, obj2, pcval)) + return false; + + if (PCVAL_IS_NULL(pcval) || !PCVAL_IS_OBJECT(pcval)) + ABORT_TRACE("callee is not an object"); + JS_ASSERT(HAS_FUNCTION_CLASS(PCVAL_TO_OBJECT(pcval))); + + stack(0, INS_CONSTPTR(PCVAL_TO_OBJECT(pcval))); + stack(1, obj_ins); + return true; +} + +bool +TraceRecorder::record_JSOP_GETUPVAR() +{ + ABORT_TRACE("GETUPVAR"); +} + +bool +TraceRecorder::record_JSOP_CALLUPVAR() +{ + ABORT_TRACE("CALLUPVAR"); +} + +bool +TraceRecorder::guardShapelessCallee(jsval& callee) +{ + guard(true, + addName(lir->ins2(LIR_eq, get(&callee), INS_CONSTPTR(JSVAL_TO_OBJECT(callee))), + "guard(shapeless callee)"), + MISMATCH_EXIT); + return true; +} + +bool +TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, bool constructing) +{ + if (JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(fval)) != globalObj) + ABORT_TRACE("JSOP_CALL or JSOP_NEW crosses global scopes"); + + JSStackFrame* fp = cx->fp; + + // TODO: track the copying via the tracker... + if (argc < fun->nargs && + jsuword(fp->regs->sp + (fun->nargs - argc)) > cx->stackPool.current->limit) { + ABORT_TRACE("can't trace calls with too few args requiring argv move"); + } + + // Generate a type map for the outgoing frame and stash it in the LIR + unsigned stackSlots = js_NativeStackSlots(cx, 0/*callDepth*/); + LIns* data = lir_buf_writer->skip(stackSlots * sizeof(uint8)); + uint8* typemap = (uint8 *)data->payload(); + uint8* m = typemap; + /* Determine the type of a store by looking at the current type of the actual value the + interpreter is using. For numbers we have to check what kind of store we used last + (integer or double) to figure out what the side exit show reflect in its typemap. */ + FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0/*callDepth*/, + *m++ = determineSlotType(vp); + ); + + if (argc >= 0x8000) + ABORT_TRACE("too many arguments"); + + FrameInfo fi = { + JSVAL_TO_OBJECT(fval), + ENCODE_IP_ADJ(fp, fp->regs->pc), + typemap, + { { fp->regs->sp - fp->slots, argc | (constructing ? 0x8000 : 0) } } + }; + + unsigned callDepth = getCallDepth(); + if (callDepth >= treeInfo->maxCallDepth) + treeInfo->maxCallDepth = callDepth + 1; + + lir->insStorei(INS_CONSTPTR(fi.callee), lirbuf->rp, + callDepth * sizeof(FrameInfo) + offsetof(FrameInfo, callee)); + lir->insStorei(INS_CONSTPTR(fi.ip_adj), lirbuf->rp, + callDepth * sizeof(FrameInfo) + offsetof(FrameInfo, ip_adj)); + lir->insStorei(INS_CONSTPTR(fi.typemap), lirbuf->rp, + callDepth * sizeof(FrameInfo) + offsetof(FrameInfo, typemap)); + lir->insStorei(INS_CONST(fi.word), lirbuf->rp, + callDepth * sizeof(FrameInfo) + offsetof(FrameInfo, word)); + + atoms = fun->u.i.script->atomMap.vector; + return true; +} + +bool +TraceRecorder::record_JSOP_CALL() +{ + return functionCall(false); +} + +bool +TraceRecorder::record_JSOP_APPLY() +{ + return functionCall(false); +} + +bool +TraceRecorder::record_FastNativeCallComplete() +{ + JS_ASSERT(pendingTraceableNative); + + /* At this point the generated code has already called the native function + and we can no longer fail back to the original pc location (JSOP_CALL) + because that would cause the interpreter to re-execute the native + function, which might have side effects. + + Instead, snapshot(), which is invoked from unbox_jsval(), will see that + we are currently parked on a traceable native's JSOP_CALL instruction, + and it will advance the pc to restore by the length of the current + opcode, and indicate in the type map that the element on top of the + stack is a boxed value which doesn't need to be boxed if the type guard + generated by unbox_jsval() fails. */ + JS_ASSERT(*cx->fp->regs->pc == JSOP_CALL || + *cx->fp->regs->pc == JSOP_APPLY); + + jsval& v = stackval(-1); + LIns* v_ins = get(&v); + + bool ok = true; + switch (JSTN_ERRTYPE(pendingTraceableNative)) { + case FAIL_JSVAL: + ok = unbox_jsval(v, v_ins); + if (ok) + set(&v, v_ins); + break; + case FAIL_NEG: + /* Already added i2f in functionCall. */ + JS_ASSERT(JSVAL_IS_NUMBER(v)); + break; + default: + /* Convert the result to double if the builtin returns int32. */ + if (JSVAL_IS_NUMBER(v) && + (pendingTraceableNative->builtin->_argtypes & 3) == nanojit::ARGSIZE_LO) { + set(&v, lir->ins1(LIR_i2f, v_ins)); + } + } + + // We'll null pendingTraceableNative in js_MonitorRecording, on the next op cycle. + // There must be a next op since the stack is non-empty. + return ok; +} + +bool +TraceRecorder::name(jsval*& vp) +{ + JSObject* obj = cx->fp->scopeChain; + if (obj != globalObj) + return activeCallOrGlobalSlot(obj, vp); + + /* Can't use prop here, because we don't want unboxing from global slots. */ + LIns* obj_ins = scopeChain(); + uint32 slot; + if (!test_property_cache_direct_slot(obj, obj_ins, slot)) + return false; + + if (slot == SPROP_INVALID_SLOT) + ABORT_TRACE("name op can't find named property"); + + if (!lazilyImportGlobalSlot(slot)) + ABORT_TRACE("lazy import of global slot failed"); + + vp = &STOBJ_GET_SLOT(obj, slot); + return true; +} + +bool +TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins) +{ + /* + * Can't specialize to assert obj != global, must guard to avoid aliasing + * stale homes of stacked global variables. + */ + if (obj == globalObj) + ABORT_TRACE("prop op aliases global"); + guard(false, lir->ins2(LIR_eq, obj_ins, INS_CONSTPTR(globalObj)), MISMATCH_EXIT); + + /* + * Property cache ensures that we are dealing with an existing property, + * and guards the shape for us. + */ + JSObject* obj2; + jsuword pcval; + if (!test_property_cache(obj, obj_ins, obj2, pcval)) + return false; + + /* Check for non-existent property reference, which results in undefined. */ + const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc]; + if (PCVAL_IS_NULL(pcval)) { + v_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID)); + JS_ASSERT(cs.ndefs == 1); + stack(-cs.nuses, v_ins); + slot = SPROP_INVALID_SLOT; + return true; + } + + /* Insist if setting on obj being the directly addressed object. */ + uint32 setflags = (cs.format & (JOF_SET | JOF_INCDEC)); + LIns* dslots_ins = NULL; + if (obj2 != obj) { + if (setflags) + ABORT_TRACE("JOF_SET opcode hit prototype chain"); + + /* + * We're getting a proto-property. Walk up the prototype chain emitting + * proto slot loads, updating obj as we go, leaving obj set to obj2 with + * obj_ins the last proto-load. + */ + while (obj != obj2) { + obj_ins = stobj_get_slot(obj_ins, JSSLOT_PROTO, dslots_ins); + obj = STOBJ_GET_PROTO(obj); + } + } + + /* Don't trace getter or setter calls, our caller wants a direct slot. */ + if (PCVAL_IS_SPROP(pcval)) { + JSScopeProperty* sprop = PCVAL_TO_SPROP(pcval); + + if (setflags && !SPROP_HAS_STUB_SETTER(sprop)) + ABORT_TRACE("non-stub setter"); + if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop)) { + // FIXME 450335: generalize this away from regexp built-in getters. + if (setflags == 0 && + sprop->getter == js_RegExpClass.getProperty && + sprop->shortid < 0) { + if (sprop->shortid == REGEXP_LAST_INDEX) + ABORT_TRACE("can't trace regexp.lastIndex yet"); + LIns* args[] = { INS_CONSTPTR(sprop), obj_ins, cx_ins }; + v_ins = lir->insCall(&js_CallGetter_ci, args); + guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT); + if (!unbox_jsval((sprop->shortid == REGEXP_SOURCE) ? JSVAL_STRING : JSVAL_BOOLEAN, + v_ins)) { + ABORT_TRACE("unboxing"); + } + JS_ASSERT(cs.ndefs == 1); + stack(-cs.nuses, v_ins); + return true; + } + ABORT_TRACE("non-stub getter"); + } + if (!SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj))) + ABORT_TRACE("no valid slot"); + slot = sprop->slot; + } else { + if (!PCVAL_IS_SLOT(pcval)) + ABORT_TRACE("PCE is not a slot"); + slot = PCVAL_TO_SLOT(pcval); + } + + v_ins = stobj_get_slot(obj_ins, slot, dslots_ins); + if (!unbox_jsval(STOBJ_GET_SLOT(obj, slot), v_ins)) + ABORT_TRACE("unboxing"); + return true; +} + +bool +TraceRecorder::elem(jsval& oval, jsval& idx, jsval*& vp, LIns*& v_ins, LIns*& addr_ins) +{ + /* no guards for type checks, trace specialized this already */ + if (JSVAL_IS_PRIMITIVE(oval) || !JSVAL_IS_INT(idx)) + return false; + + JSObject* obj = JSVAL_TO_OBJECT(oval); + LIns* obj_ins = get(&oval); + + /* make sure the object is actually a dense array */ + if (!guardDenseArray(obj, obj_ins)) + return false; + + /* check that the index is within bounds */ + jsint i = JSVAL_TO_INT(idx); + LIns* idx_ins = makeNumberInt32(get(&idx)); + + LIns* dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots)); + if (!guardDenseArrayIndex(obj, i, obj_ins, dslots_ins, idx_ins, BRANCH_EXIT)) { + LIns* rt_ins = lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, runtime)); + guard(true, + lir->ins_eq0(lir->insLoad(LIR_ldp, rt_ins, + offsetof(JSRuntime, anyArrayProtoHasElement))), + MISMATCH_EXIT); + // Return undefined and indicate that we didn't actually read this (addr_ins). + v_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID)); + addr_ins = NULL; + return true; + } + + // We can't "see through" a hole to a possible Array.prototype property, so + // we abort here and guard below (after unboxing). + vp = &obj->dslots[i]; + if (*vp == JSVAL_HOLE) + ABORT_TRACE("can't see through hole in dense array"); + + addr_ins = lir->ins2(LIR_piadd, dslots_ins, + lir->ins2i(LIR_pilsh, idx_ins, (sizeof(jsval) == 4) ? 2 : 3)); + + /* Load the value and guard on its type to unbox it. */ + v_ins = lir->insLoad(LIR_ldp, addr_ins, 0); + if (!unbox_jsval(*vp, v_ins)) + return false; + + if (JSVAL_TAG(*vp) == JSVAL_BOOLEAN) { + // Optimize to guard for a hole only after untagging, so we know that + // we have a boolean, to avoid an extra guard for non-boolean values. + guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_HOLE))), + MISMATCH_EXIT); + } + return true; +} + +bool +TraceRecorder::getProp(JSObject* obj, LIns* obj_ins) +{ + uint32 slot; + LIns* v_ins; + if (!prop(obj, obj_ins, slot, v_ins)) + return false; + + const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc]; + JS_ASSERT(cs.ndefs == 1); + stack(-cs.nuses, v_ins); + return true; +} + +bool +TraceRecorder::getProp(jsval& v) +{ + if (JSVAL_IS_PRIMITIVE(v)) + ABORT_TRACE("primitive lhs"); + + return getProp(JSVAL_TO_OBJECT(v), get(&v)); +} + +bool +TraceRecorder::record_JSOP_NAME() +{ + jsval* vp; + if (!name(vp)) + return false; + stack(0, get(vp)); + return true; +} + +bool +TraceRecorder::record_JSOP_DOUBLE() +{ + jsval v = jsval(atoms[GET_INDEX(cx->fp->regs->pc)]); + jsdpun u; + u.d = *JSVAL_TO_DOUBLE(v); + stack(0, lir->insImmq(u.u64)); + return true; +} + +bool +TraceRecorder::record_JSOP_STRING() +{ + JSAtom* atom = atoms[GET_INDEX(cx->fp->regs->pc)]; + JS_ASSERT(ATOM_IS_STRING(atom)); + stack(0, INS_CONSTPTR(ATOM_TO_STRING(atom))); + return true; +} + +bool +TraceRecorder::record_JSOP_ZERO() +{ + jsdpun u; + u.d = 0.0; + stack(0, lir->insImmq(u.u64)); + return true; +} + +bool +TraceRecorder::record_JSOP_ONE() +{ + jsdpun u; + u.d = 1.0; + stack(0, lir->insImmq(u.u64)); + return true; +} + +bool +TraceRecorder::record_JSOP_NULL() +{ + stack(0, INS_CONSTPTR(NULL)); + return true; +} + +bool +TraceRecorder::record_JSOP_THIS() +{ + LIns* this_ins; + if (!getThis(this_ins)) + return false; + stack(0, this_ins); + return true; +} + +bool +TraceRecorder::record_JSOP_FALSE() +{ + stack(0, lir->insImm(0)); + return true; +} + +bool +TraceRecorder::record_JSOP_TRUE() +{ + stack(0, lir->insImm(1)); + return true; +} + +bool +TraceRecorder::record_JSOP_OR() +{ + return ifop(); +} + +bool +TraceRecorder::record_JSOP_AND() +{ + return ifop(); +} + +bool +TraceRecorder::record_JSOP_TABLESWITCH() +{ + return switchop(); +} + +bool +TraceRecorder::record_JSOP_LOOKUPSWITCH() +{ + return switchop(); +} + +bool +TraceRecorder::record_JSOP_STRICTEQ() +{ + return cmp(LIR_feq, CMP_STRICT); +} + +bool +TraceRecorder::record_JSOP_STRICTNE() +{ + return cmp(LIR_feq, CMP_STRICT | CMP_NEGATE); +} + +bool +TraceRecorder::record_JSOP_OBJECT() +{ + JSStackFrame* fp = cx->fp; + JSScript* script = fp->script; + unsigned index = atoms - script->atomMap.vector + GET_INDEX(fp->regs->pc); + + JSObject* obj; + JS_GET_SCRIPT_OBJECT(script, index, obj); + stack(0, INS_CONSTPTR(obj)); + return true; +} + +bool +TraceRecorder::record_JSOP_POP() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_POS() +{ + jsval& r = stackval(-1); + return isNumber(r); +} + +bool +TraceRecorder::record_JSOP_TRAP() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_GETARG() +{ + stack(0, arg(GET_ARGNO(cx->fp->regs->pc))); + return true; +} + +bool +TraceRecorder::record_JSOP_SETARG() +{ + arg(GET_ARGNO(cx->fp->regs->pc), stack(-1)); + return true; +} + +bool +TraceRecorder::record_JSOP_GETLOCAL() +{ + stack(0, var(GET_SLOTNO(cx->fp->regs->pc))); + return true; +} + +bool +TraceRecorder::record_JSOP_SETLOCAL() +{ + var(GET_SLOTNO(cx->fp->regs->pc), stack(-1)); + return true; +} + +bool +TraceRecorder::record_JSOP_UINT16() +{ + jsdpun u; + u.d = (jsdouble)GET_UINT16(cx->fp->regs->pc); + stack(0, lir->insImmq(u.u64)); + return true; +} + +bool +TraceRecorder::record_JSOP_NEWINIT() +{ + JSProtoKey key = JSProtoKey(GET_INT8(cx->fp->regs->pc)); + JSObject* obj; + const CallInfo *ci; + if (key == JSProto_Array) { + if (!js_GetClassPrototype(cx, globalObj, INT_TO_JSID(key), &obj)) + return false; + ci = &js_FastNewArray_ci; + } else { + jsval v_obj; + if (!js_FindClassObject(cx, globalObj, INT_TO_JSID(key), &v_obj)) + return false; + if (JSVAL_IS_PRIMITIVE(v_obj)) + ABORT_TRACE("primitive Object value"); + obj = JSVAL_TO_OBJECT(v_obj); + ci = &js_FastNewObject_ci; + } + LIns* args[] = { INS_CONSTPTR(obj), cx_ins }; + LIns* v_ins = lir->insCall(ci, args); + guard(false, lir->ins_eq0(v_ins), OOM_EXIT); + stack(0, v_ins); + return true; +} + +bool +TraceRecorder::record_JSOP_ENDINIT() +{ + jsval& v = stackval(-1); + JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + JSObject* obj = JSVAL_TO_OBJECT(v); + if (OBJ_IS_DENSE_ARRAY(cx, obj)) { + // Until we get JSOP_NEWARRAY working, we do our optimizing here... + if (obj->fslots[JSSLOT_ARRAY_LENGTH] == 1 && + obj->dslots && JSVAL_IS_STRING(obj->dslots[0])) { + LIns* v_ins = get(&v); + JS_ASSERT(v_ins->isCall() && v_ins->callInfo() == &js_FastNewArray_ci); + LIns* args[] = { stack(1), callArgN(v_ins, 1), cx_ins }; + v_ins = lir->insCall(&js_Array_1str_ci, args); + set(&v, v_ins); + } + } + return true; +} + +bool +TraceRecorder::record_JSOP_INITPROP() +{ + // All the action is in record_SetPropHit. + return true; +} + +bool +TraceRecorder::record_JSOP_INITELEM() +{ + return record_JSOP_SETELEM(); +} + +bool +TraceRecorder::record_JSOP_DEFSHARP() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_USESHARP() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_INCARG() +{ + return inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1); +} + +bool +TraceRecorder::record_JSOP_INCLOCAL() +{ + return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), 1); +} + +bool +TraceRecorder::record_JSOP_DECARG() +{ + return inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1); +} + +bool +TraceRecorder::record_JSOP_DECLOCAL() +{ + return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), -1); +} + +bool +TraceRecorder::record_JSOP_ARGINC() +{ + return inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1, false); +} + +bool +TraceRecorder::record_JSOP_LOCALINC() +{ + return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), 1, false); +} + +bool +TraceRecorder::record_JSOP_ARGDEC() +{ + return inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1, false); +} + +bool +TraceRecorder::record_JSOP_LOCALDEC() +{ + return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), -1, false); +} + +bool +TraceRecorder::record_JSOP_IMACOP() +{ + JS_ASSERT(cx->fp->imacpc); + return true; +} + +static struct { + jsbytecode for_in[10]; + jsbytecode for_each[10]; +} iter_imacros = { + { + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(iterator), + JSOP_INT8, JSITER_ENUMERATE, + JSOP_CALL, 0, 1, + JSOP_PUSH, + JSOP_STOP + }, + + { + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(iterator), + JSOP_INT8, JSITER_ENUMERATE | JSITER_FOREACH, + JSOP_CALL, 0, 1, + JSOP_PUSH, + JSOP_STOP + } +}; + +JS_STATIC_ASSERT(sizeof(iter_imacros) < IMACRO_PC_ADJ_LIMIT); + +bool +TraceRecorder::record_JSOP_ITER() +{ + jsval& v = stackval(-1); + if (!JSVAL_IS_PRIMITIVE(v)) { + jsuint flags = cx->fp->regs->pc[1]; + + if (!hasIteratorMethod(v)) { + LIns* args[] = { get(&v), INS_CONST(flags), cx_ins }; + LIns* v_ins = lir->insCall(&js_FastValueToIterator_ci, args); + guard(false, lir->ins_eq0(v_ins), MISMATCH_EXIT); + set(&v, v_ins); + + LIns* void_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID)); + stack(0, void_ins); + return true; + } + + if (flags == JSITER_ENUMERATE) + return call_imacro(iter_imacros.for_in); + if (flags == (JSITER_ENUMERATE | JSITER_FOREACH)) + return call_imacro(iter_imacros.for_each); + ABORT_TRACE("unimplemented JSITER_* flags"); + } + + ABORT_TRACE("for-in on a primitive value"); +} + +static JSTraceableNative js_FastCallIteratorNext_tn = { + NULL, // JSFastNative native; + &js_FastCallIteratorNext_ci, // const nanojit::CallInfo *builtin; + "C", // const char *prefix; + "o", // const char *argtypes; + FAIL_JSVAL // uintN flags; +}; + +static jsbytecode nextiter_imacro[] = { + JSOP_POP, + JSOP_DUP, + JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(next), + JSOP_CALL, 0, 0, + JSOP_TRUE, + JSOP_STOP +}; + +JS_STATIC_ASSERT(sizeof(nextiter_imacro) < IMACRO_PC_ADJ_LIMIT); + +bool +TraceRecorder::record_JSOP_NEXTITER() +{ + jsval& iterobj_val = stackval(-2); + if (!JSVAL_IS_PRIMITIVE(iterobj_val)) { + LIns* iterobj_ins = get(&iterobj_val); + + if (guardClass(JSVAL_TO_OBJECT(iterobj_val), iterobj_ins, &js_IteratorClass, BRANCH_EXIT)) { + LIns* args[] = { iterobj_ins, cx_ins }; + LIns* v_ins = lir->insCall(&js_FastCallIteratorNext_ci, args); + guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT); + + LIns* flag_ins = lir->ins_eq0(lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_HOLE))); + stack(-1, v_ins); + stack(0, flag_ins); + + pendingTraceableNative = &js_FastCallIteratorNext_tn; + return true; + } + + // Custom iterator, possibly a generator. + return call_imacro(nextiter_imacro); + } + + ABORT_TRACE("for-in on a primitive value"); +} + +bool +TraceRecorder::record_IteratorNextComplete() +{ + JS_ASSERT(*cx->fp->regs->pc == JSOP_NEXTITER); + JS_ASSERT(pendingTraceableNative == &js_FastCallIteratorNext_tn); + + jsval& v = stackval(-2); + LIns* v_ins = get(&v); + if (unbox_jsval(v, v_ins)) { + set(&v, v_ins); + return true; + } + return false; +} + +bool +TraceRecorder::record_JSOP_ENDITER() +{ + LIns* args[] = { stack(-2), cx_ins }; + LIns* ok_ins = lir->insCall(&js_CloseIterator_ci, args); + guard(false, lir->ins_eq0(ok_ins), MISMATCH_EXIT); + return true; +} + +bool +TraceRecorder::record_JSOP_FORNAME() +{ + jsval* vp; + if (name(vp)) { + set(vp, stack(-1)); + return true; + } + return false; +} + +bool +TraceRecorder::record_JSOP_FORPROP() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_FORELEM() +{ + return record_JSOP_DUP(); +} + +bool +TraceRecorder::record_JSOP_FORARG() +{ + return record_JSOP_SETARG(); +} + +bool +TraceRecorder::record_JSOP_FORLOCAL() +{ + return record_JSOP_SETLOCAL(); +} + +bool +TraceRecorder::record_JSOP_POPN() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_BINDNAME() +{ + JSObject* obj = cx->fp->scopeChain; + if (obj != globalObj) + ABORT_TRACE("JSOP_BINDNAME crosses global scopes"); + + LIns* obj_ins = scopeChain(); + JSObject* obj2; + jsuword pcval; + if (!test_property_cache(obj, obj_ins, obj2, pcval)) + return false; + if (obj2 != obj) + ABORT_TRACE("JSOP_BINDNAME found a non-direct property on the global object"); + + stack(0, obj_ins); + return true; +} + +bool +TraceRecorder::record_JSOP_SETNAME() +{ + jsval& l = stackval(-2); + JS_ASSERT(!JSVAL_IS_PRIMITIVE(l)); + + /* + * Trace cases that are global code or in lightweight functions scoped by + * the global object only. + */ + JSObject* obj = JSVAL_TO_OBJECT(l); + if (obj != cx->fp->scopeChain || obj != globalObj) + ABORT_TRACE("JSOP_SETNAME left operand is not the global object"); + + // The rest of the work is in record_SetPropHit. + return true; +} + +bool +TraceRecorder::record_JSOP_THROW() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_IN() +{ + jsval& rval = stackval(-1); + jsval& lval = stackval(-2); + + if (JSVAL_IS_PRIMITIVE(rval)) + ABORT_TRACE("JSOP_IN on non-object right operand"); + JSObject* obj = JSVAL_TO_OBJECT(rval); + LIns* obj_ins = get(&rval); + + jsid id; + LIns* x; + if (JSVAL_IS_INT(lval)) { + id = INT_JSVAL_TO_JSID(lval); + LIns* args[] = { makeNumberInt32(get(&lval)), obj_ins, cx_ins }; + x = lir->insCall(&js_HasNamedPropertyInt32_ci, args); + } else if (JSVAL_IS_STRING(lval)) { + if (!js_ValueToStringId(cx, lval, &id)) + ABORT_TRACE("left operand of JSOP_IN didn't convert to a string-id"); + LIns* args[] = { get(&lval), obj_ins, cx_ins }; + x = lir->insCall(&js_HasNamedProperty_ci, args); + } else { + ABORT_TRACE("string or integer expected"); + } + + guard(false, lir->ins2i(LIR_eq, x, JSVAL_TO_BOOLEAN(JSVAL_VOID)), OOM_EXIT); + x = lir->ins2i(LIR_eq, x, 1); + + JSObject* obj2; + JSProperty* prop; + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) + ABORT_TRACE("OBJ_LOOKUP_PROPERTY failed in JSOP_IN"); + bool cond = prop != NULL; + if (prop) + OBJ_DROP_PROPERTY(cx, obj2, prop); + + /* The interpreter fuses comparisons and the following branch, + so we have to do that here as well. */ + fuseIf(cx->fp->regs->pc + 1, cond, x); + + /* We update the stack after the guard. This is safe since + the guard bails out at the comparison and the interpreter + will therefore re-execute the comparison. This way the + value of the condition doesn't have to be calculated and + saved on the stack in most cases. */ + set(&lval, x); + return true; +} + +bool +TraceRecorder::record_JSOP_INSTANCEOF() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_DEBUGGER() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_GOSUB() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_RETSUB() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_EXCEPTION() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_LINENO() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_CONDSWITCH() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_CASE() +{ + return cmp(LIR_feq, CMP_CASE); +} + +bool +TraceRecorder::record_JSOP_DEFAULT() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_EVAL() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_ENUMELEM() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_GETTER() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_SETTER() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_DEFFUN() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_DEFCONST() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_DEFVAR() +{ + return false; +} + +/* + * XXX could hoist out to jsinterp.h and share with jsinterp.cpp, but + * XXX jsopcode.cpp has different definitions of same-named macros. + */ +#define GET_FULL_INDEX(PCOFF) \ + (atoms - script->atomMap.vector + GET_INDEX(regs.pc + PCOFF)) + +#define LOAD_FUNCTION(PCOFF) \ + JS_GET_SCRIPT_FUNCTION(script, GET_FULL_INDEX(PCOFF), fun) + +bool +TraceRecorder::record_JSOP_ANONFUNOBJ() +{ + JSFunction* fun; + JSFrameRegs& regs = *cx->fp->regs; + JSScript* script = cx->fp->script; + LOAD_FUNCTION(0); // needs script, regs, fun + + JSObject* obj = FUN_OBJECT(fun); + if (OBJ_GET_PARENT(cx, obj) != cx->fp->scopeChain) + ABORT_TRACE("can't trace with activation object on scopeChain"); + + stack(0, INS_CONSTPTR(obj)); + return true; +} + +bool +TraceRecorder::record_JSOP_NAMEDFUNOBJ() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_SETLOCALPOP() +{ + var(GET_SLOTNO(cx->fp->regs->pc), stack(-1)); + return true; +} + +bool +TraceRecorder::record_JSOP_SETCALL() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_TRY() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_FINALLY() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_NOP() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_ARGSUB() +{ + JSStackFrame* fp = cx->fp; + if (!(fp->fun->flags & JSFUN_HEAVYWEIGHT)) { + uintN slot = GET_ARGNO(fp->regs->pc); + if (slot < fp->fun->nargs && slot < fp->argc && !fp->argsobj) { + stack(0, get(&cx->fp->argv[slot])); + return true; + } + } + ABORT_TRACE("can't trace JSOP_ARGSUB hard case"); +} + +bool +TraceRecorder::record_JSOP_ARGCNT() +{ + if (!(cx->fp->fun->flags & JSFUN_HEAVYWEIGHT)) { + jsdpun u; + u.d = cx->fp->argc; + stack(0, lir->insImmq(u.u64)); + return true; + } + ABORT_TRACE("can't trace heavyweight JSOP_ARGCNT"); +} + +bool +TraceRecorder::record_DefLocalFunSetSlot(uint32 slot, JSObject* obj) +{ + var(slot, INS_CONSTPTR(obj)); + return true; +} + +bool +TraceRecorder::record_JSOP_DEFLOCALFUN() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_GOTOX() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_IFEQX() +{ + trackCfgMerges(cx->fp->regs->pc); + return record_JSOP_IFEQ(); +} + +bool +TraceRecorder::record_JSOP_IFNEX() +{ + return record_JSOP_IFNE(); +} + +bool +TraceRecorder::record_JSOP_ORX() +{ + return record_JSOP_OR(); +} + +bool +TraceRecorder::record_JSOP_ANDX() +{ + return record_JSOP_AND(); +} + +bool +TraceRecorder::record_JSOP_GOSUBX() +{ + return record_JSOP_GOSUB(); +} + +bool +TraceRecorder::record_JSOP_CASEX() +{ + return cmp(LIR_feq, CMP_CASE); +} + +bool +TraceRecorder::record_JSOP_DEFAULTX() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_TABLESWITCHX() +{ + return switchop(); +} + +bool +TraceRecorder::record_JSOP_LOOKUPSWITCHX() +{ + return switchop(); +} + +bool +TraceRecorder::record_JSOP_BACKPATCH() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_BACKPATCH_POP() +{ + return true; +} + +bool +TraceRecorder::record_JSOP_THROWING() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_SETRVAL() +{ + // If we implement this, we need to update JSOP_STOP. + return false; +} + +bool +TraceRecorder::record_JSOP_RETRVAL() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_GETGVAR() +{ + jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)]; + if (JSVAL_IS_NULL(slotval)) + return true; // We will see JSOP_NAME from the interpreter's jump, so no-op here. + + uint32 slot = JSVAL_TO_INT(slotval); + + if (!lazilyImportGlobalSlot(slot)) + ABORT_TRACE("lazy import of global slot failed"); + + stack(0, get(&STOBJ_GET_SLOT(globalObj, slot))); + return true; +} + +bool +TraceRecorder::record_JSOP_SETGVAR() +{ + jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)]; + if (JSVAL_IS_NULL(slotval)) + return true; // We will see JSOP_NAME from the interpreter's jump, so no-op here. + + uint32 slot = JSVAL_TO_INT(slotval); + + if (!lazilyImportGlobalSlot(slot)) + ABORT_TRACE("lazy import of global slot failed"); + + set(&STOBJ_GET_SLOT(globalObj, slot), stack(-1)); + return true; +} + +bool +TraceRecorder::record_JSOP_INCGVAR() +{ + jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)]; + if (JSVAL_IS_NULL(slotval)) + return true; // We will see JSOP_INCNAME from the interpreter's jump, so no-op here. + + uint32 slot = JSVAL_TO_INT(slotval); + + if (!lazilyImportGlobalSlot(slot)) + ABORT_TRACE("lazy import of global slot failed"); + + return inc(STOBJ_GET_SLOT(globalObj, slot), 1); +} + +bool +TraceRecorder::record_JSOP_DECGVAR() +{ + jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)]; + if (JSVAL_IS_NULL(slotval)) + return true; // We will see JSOP_INCNAME from the interpreter's jump, so no-op here. + + uint32 slot = JSVAL_TO_INT(slotval); + + if (!lazilyImportGlobalSlot(slot)) + ABORT_TRACE("lazy import of global slot failed"); + + return inc(STOBJ_GET_SLOT(globalObj, slot), -1); +} + +bool +TraceRecorder::record_JSOP_GVARINC() +{ + jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)]; + if (JSVAL_IS_NULL(slotval)) + return true; // We will see JSOP_INCNAME from the interpreter's jump, so no-op here. + + uint32 slot = JSVAL_TO_INT(slotval); + + if (!lazilyImportGlobalSlot(slot)) + ABORT_TRACE("lazy import of global slot failed"); + + return inc(STOBJ_GET_SLOT(globalObj, slot), 1, false); +} + +bool +TraceRecorder::record_JSOP_GVARDEC() +{ + jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)]; + if (JSVAL_IS_NULL(slotval)) + return true; // We will see JSOP_INCNAME from the interpreter's jump, so no-op here. + + uint32 slot = JSVAL_TO_INT(slotval); + + if (!lazilyImportGlobalSlot(slot)) + ABORT_TRACE("lazy import of global slot failed"); + + return inc(STOBJ_GET_SLOT(globalObj, slot), -1, false); +} + +bool +TraceRecorder::record_JSOP_REGEXP() +{ + return false; +} + +// begin JS_HAS_XML_SUPPORT + +bool +TraceRecorder::record_JSOP_DEFXMLNS() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_ANYNAME() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_QNAMEPART() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_QNAMECONST() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_QNAME() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_TOATTRNAME() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_TOATTRVAL() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_ADDATTRNAME() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_ADDATTRVAL() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_BINDXMLNAME() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_SETXMLNAME() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_XMLNAME() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_DESCENDANTS() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_FILTER() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_ENDFILTER() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_TOXML() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_TOXMLLIST() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_XMLTAGEXPR() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_XMLELTEXPR() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_XMLOBJECT() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_XMLCDATA() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_XMLCOMMENT() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_XMLPI() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_GETFUNNS() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_STARTXML() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_STARTXMLEXPR() +{ + return false; +} + +// end JS_HAS_XML_SUPPORT + +bool +TraceRecorder::record_JSOP_CALLPROP() +{ + jsval& l = stackval(-1); + JSObject* obj; + LIns* obj_ins; + LIns* this_ins; + if (!JSVAL_IS_PRIMITIVE(l)) { + obj = JSVAL_TO_OBJECT(l); + obj_ins = get(&l); + this_ins = obj_ins; // |this| for subsequent call + if (JSVAL_IS_NULL(l)) + ABORT_TRACE("callprop on null"); + if (!this_ins->isconstp()) + guard(false, lir->ins_eq0(this_ins), MISMATCH_EXIT); + } else { + jsint i; + debug_only(const char* protoname = NULL;) + if (JSVAL_IS_STRING(l)) { + i = JSProto_String; + debug_only(protoname = "String.prototype";) + } else if (JSVAL_IS_NUMBER(l)) { + i = JSProto_Number; + debug_only(protoname = "Number.prototype";) + } else if (JSVAL_TAG(l) == JSVAL_BOOLEAN) { + if (l == JSVAL_VOID) + ABORT_TRACE("callprop on void"); + guard(false, lir->ins2i(LIR_eq, get(&l), JSVAL_TO_BOOLEAN(JSVAL_VOID)), MISMATCH_EXIT); + i = JSProto_Boolean; + debug_only(protoname = "Boolean.prototype";) + } else { + JS_ASSERT(JSVAL_IS_NULL(l) || JSVAL_IS_VOID(l)); + ABORT_TRACE("callprop on null or void"); + } + + if (!js_GetClassPrototype(cx, NULL, INT_TO_JSID(i), &obj)) + ABORT_TRACE("GetClassPrototype failed!"); + + obj_ins = INS_CONSTPTR(obj); + debug_only(obj_ins = addName(obj_ins, protoname);) + this_ins = get(&l); // use primitive as |this| + } + + JSObject* obj2; + jsuword pcval; + if (!test_property_cache(obj, obj_ins, obj2, pcval)) + return false; + + if (PCVAL_IS_NULL(pcval) || !PCVAL_IS_OBJECT(pcval)) + ABORT_TRACE("callee is not an object"); + JS_ASSERT(HAS_FUNCTION_CLASS(PCVAL_TO_OBJECT(pcval))); + + if (JSVAL_IS_PRIMITIVE(l)) { + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, PCVAL_TO_OBJECT(pcval)); + if (!PRIMITIVE_THIS_TEST(fun, l)) + ABORT_TRACE("callee does not accept primitive |this|"); + } + + stack(0, this_ins); + stack(-1, INS_CONSTPTR(PCVAL_TO_OBJECT(pcval))); + return true; +} + +bool +TraceRecorder::record_JSOP_DELDESC() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_UINT24() +{ + jsdpun u; + u.d = (jsdouble)GET_UINT24(cx->fp->regs->pc); + stack(0, lir->insImmq(u.u64)); + return true; +} + +bool +TraceRecorder::record_JSOP_INDEXBASE() +{ + atoms += GET_INDEXBASE(cx->fp->regs->pc); + return true; +} + +bool +TraceRecorder::record_JSOP_RESETBASE() +{ + atoms = cx->fp->script->atomMap.vector; + return true; +} + +bool +TraceRecorder::record_JSOP_RESETBASE0() +{ + atoms = cx->fp->script->atomMap.vector; + return true; +} + +bool +TraceRecorder::record_JSOP_CALLELEM() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_STOP() +{ + JSStackFrame *fp = cx->fp; + + if (fp->imacpc) { + // End of imacro, so return true to the interpreter immediately. The + // interpreter's JSOP_STOP case will return from the imacro, back to + // the pc after the calling op, still in the same JSStackFrame. + atoms = fp->script->atomMap.vector; + return true; + } + + /* + * We know falling off the end of a constructor returns the new object that + * was passed in via fp->argv[-1], while falling off the end of a function + * returns undefined. + * + * NB: we do not support script rval (eval, API users who want the result + * of the last expression-statement, debugger API calls). + */ + if (fp->flags & JSFRAME_CONSTRUCTING) { + JS_ASSERT(OBJECT_TO_JSVAL(fp->thisp) == fp->argv[-1]); + rval_ins = get(&fp->argv[-1]); + } else { + rval_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID)); + } + clearFrameSlotsFromCache(); + return true; +} + +bool +TraceRecorder::record_JSOP_GETXPROP() +{ + jsval& l = stackval(-1); + if (JSVAL_IS_PRIMITIVE(l)) + ABORT_TRACE("primitive-this for GETXPROP?"); + + JSObject* obj = JSVAL_TO_OBJECT(l); + if (obj != cx->fp->scopeChain || obj != globalObj) + return false; + + jsval* vp; + if (!name(vp)) + return false; + stack(-1, get(vp)); + return true; +} + +bool +TraceRecorder::record_JSOP_CALLXMLNAME() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_TYPEOFEXPR() +{ + return record_JSOP_TYPEOF(); +} + +bool +TraceRecorder::record_JSOP_ENTERBLOCK() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_LEAVEBLOCK() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_GENERATOR() +{ + return false; +#if 0 + JSStackFrame* fp = cx->fp; + if (fp->callobj || fp->argsobj || fp->varobj) + ABORT_TRACE("can't trace hard-case generator"); + + // Generate a type map for the outgoing frame and stash it in the LIR + unsigned stackSlots = js_NativeStackSlots(cx, 0/*callDepth*/); + LIns* data = lir_buf_writer->skip(stackSlots * sizeof(uint8)); + uint8* typemap = (uint8 *)data->payload(); + uint8* m = typemap; + /* Determine the type of a store by looking at the current type of the actual value the + interpreter is using. For numbers we have to check what kind of store we used last + (integer or double) to figure out what the side exit show reflect in its typemap. */ + FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0/*callDepth*/, + *m++ = determineSlotType(vp); + ); + FlushNativeStackFrame(cx, 0, typemap, state.???, NULL); + + LIns* args[] = { INS_CONST(fp->argc), INS_CONSTPTR(fp->callee), cx_ins }; + LIns* g_ins = lir->insCall(&js_FastNewGenerator_ci, args); + guard(false, lir->ins_eq0(g_ins), OOM_EXIT); + return true; +#endif +} + +bool +TraceRecorder::record_JSOP_YIELD() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_ARRAYPUSH() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_ENUMCONSTELEM() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_LEAVEBLOCKEXPR() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_GETTHISPROP() +{ + LIns* this_ins; + + /* its safe to just use cx->fp->thisp here because getThis() returns false if thisp + is not available */ + return getThis(this_ins) && getProp(cx->fp->thisp, this_ins); +} + +bool +TraceRecorder::record_JSOP_GETARGPROP() +{ + return getProp(argval(GET_ARGNO(cx->fp->regs->pc))); +} + +bool +TraceRecorder::record_JSOP_GETLOCALPROP() +{ + return getProp(varval(GET_SLOTNO(cx->fp->regs->pc))); +} + +bool +TraceRecorder::record_JSOP_INDEXBASE1() +{ + atoms += 1 << 16; + return true; +} + +bool +TraceRecorder::record_JSOP_INDEXBASE2() +{ + atoms += 2 << 16; + return true; +} + +bool +TraceRecorder::record_JSOP_INDEXBASE3() +{ + atoms += 3 << 16; + return true; +} + +bool +TraceRecorder::record_JSOP_CALLGVAR() +{ + jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)]; + if (JSVAL_IS_NULL(slotval)) + return true; // We will see JSOP_CALLNAME from the interpreter's jump, so no-op here. + + uint32 slot = JSVAL_TO_INT(slotval); + + if (!lazilyImportGlobalSlot(slot)) + ABORT_TRACE("lazy import of global slot failed"); + + jsval& v = STOBJ_GET_SLOT(cx->fp->scopeChain, slot); + stack(0, get(&v)); + stack(1, INS_CONSTPTR(NULL)); + return true; +} + +bool +TraceRecorder::record_JSOP_CALLLOCAL() +{ + uintN slot = GET_SLOTNO(cx->fp->regs->pc); + stack(0, var(slot)); + stack(1, INS_CONSTPTR(NULL)); + return true; +} + +bool +TraceRecorder::record_JSOP_CALLARG() +{ + uintN slot = GET_ARGNO(cx->fp->regs->pc); + stack(0, arg(slot)); + stack(1, INS_CONSTPTR(NULL)); + return true; +} + +bool +TraceRecorder::record_JSOP_NULLTHIS() +{ + stack(0, INS_CONSTPTR(NULL)); + return true; +} + +bool +TraceRecorder::record_JSOP_INT8() +{ + jsdpun u; + u.d = (jsdouble)GET_INT8(cx->fp->regs->pc); + stack(0, lir->insImmq(u.u64)); + return true; +} + +bool +TraceRecorder::record_JSOP_INT32() +{ + jsdpun u; + u.d = (jsdouble)GET_INT32(cx->fp->regs->pc); + stack(0, lir->insImmq(u.u64)); + return true; +} + +bool +TraceRecorder::record_JSOP_LENGTH() +{ + jsval& l = stackval(-1); + if (JSVAL_IS_PRIMITIVE(l)) { + if (!JSVAL_IS_STRING(l)) + ABORT_TRACE("non-string primitives unsupported"); + LIns* str_ins = get(&l); + LIns* len_ins = lir->insLoad(LIR_ldp, str_ins, (int)offsetof(JSString, length)); + + LIns* masked_len_ins = lir->ins2(LIR_piand, + len_ins, + INS_CONSTPTR(JSSTRING_LENGTH_MASK)); + + LIns *choose_len_ins = + lir->ins_choose(lir->ins_eq0(lir->ins2(LIR_piand, + len_ins, + INS_CONSTPTR(JSSTRFLAG_DEPENDENT))), + masked_len_ins, + lir->ins_choose(lir->ins_eq0(lir->ins2(LIR_piand, + len_ins, + INS_CONSTPTR(JSSTRFLAG_PREFIX))), + lir->ins2(LIR_piand, + len_ins, + INS_CONSTPTR(JSSTRDEP_LENGTH_MASK)), + masked_len_ins)); + + set(&l, lir->ins1(LIR_i2f, choose_len_ins)); + return true; + } + + JSObject* obj = JSVAL_TO_OBJECT(l); + if (!OBJ_IS_DENSE_ARRAY(cx, obj)) + ABORT_TRACE("only dense arrays supported"); + if (!guardDenseArray(obj, get(&l))) + ABORT_TRACE("OBJ_IS_DENSE_ARRAY but not?!?"); + LIns* v_ins = lir->ins1(LIR_i2f, stobj_get_fslot(get(&l), JSSLOT_ARRAY_LENGTH)); + set(&l, v_ins); + return true; +} + +bool +TraceRecorder::record_JSOP_NEWARRAY() +{ + return false; +} + +bool +TraceRecorder::record_JSOP_HOLE() +{ + stack(0, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_HOLE))); + return true; +} + +#ifdef JS_JIT_SPEW +/* Prints information about entry typemaps and unstable exits for all peers at a PC */ +void +js_DumpPeerStability(Fragmento* frago, const void* ip) +{ + Fragment* f; + TreeInfo* ti; + bool looped = false; + unsigned length = 0; + + for (f = frago->getLoop(ip); f != NULL; f = f->peer) { + if (!f->vmprivate) + continue; + printf("fragment %p:\nENTRY: ", f); + ti = (TreeInfo*)f->vmprivate; + if (looped) + JS_ASSERT(ti->stackTypeMap.length() == length); + for (unsigned i = 0; i < ti->stackTypeMap.length(); i++) + printf("%d ", ti->stackTypeMap.data()[i]); + printf("\n"); + UnstableExit* uexit = ti->unstableExits; + while (uexit != NULL) { + printf("EXIT: "); + uint8* m = getTypeMap(uexit->exit) + uexit->exit->numGlobalSlots; + for (unsigned i = 0; i < uexit->exit->numStackSlots; i++) + printf("%d ", m[i]); + printf("\n"); + uexit = uexit->next; + } + length = ti->stackTypeMap.length(); + looped = true; + } +} +#endif + +/* + * 17 potentially-converting binary operators: + * | ^ & == != < <= > >= << >> >>> + - * / % + */ +JS_STATIC_ASSERT((uintN)(JSOP_MOD - JSOP_BITOR) == 16); + +/* + * Use an old trick: bias imacro_code[op] by -1 to allow zero high + * FrameInfo.ip_adj byte to mean "not in an imacro". + */ +static void +InitIMacroCode() +{ + if (imacro_code[JSOP_NEXTITER]) { + JS_ASSERT(imacro_code[JSOP_NEXTITER] == nextiter_imacro - 1); + return; + } + + for (uintN op = JSOP_BITOR; op <= JSOP_MOD; op++) + imacro_code[op] = (jsbytecode*)&binary_imacros - 1; + + // NB: above loop mis-set JSOP_ADD's entry, so order here is crucial. + imacro_code[JSOP_ADD] = (jsbytecode*)&add_imacros - 1; + + imacro_code[JSOP_ITER] = (jsbytecode*)&iter_imacros - 1; + imacro_code[JSOP_NEXTITER] = nextiter_imacro - 1; +} + +#define UNUSED(n) bool TraceRecorder::record_JSOP_UNUSED##n() { return false; } + +UNUSED(131) +UNUSED(201) +UNUSED(202) +UNUSED(203) +UNUSED(204) +UNUSED(205) +UNUSED(206) +UNUSED(207) +UNUSED(208) +UNUSED(209) +UNUSED(219) +UNUSED(226) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstracer.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstracer.h new file mode 100644 index 0000000..9295acb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstracer.h @@ -0,0 +1,552 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * Andreas Gal + * Mike Shaver + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jstracer_h___ +#define jstracer_h___ + +#ifdef JS_TRACER + +#include "jscntxt.h" +#include "jsstddef.h" +#include "jstypes.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsinterp.h" +#include "jsbuiltins.h" + +#if defined(DEBUG) && !defined(JS_JIT_SPEW) +#define JS_JIT_SPEW +#endif + +template +class Queue : public avmplus::GCObject { + T* _data; + unsigned _len; + unsigned _max; + + void ensure(unsigned size) { + while (_max < size) + _max <<= 1; + _data = (T*)realloc(_data, _max * sizeof(T)); + } +public: + Queue(unsigned max = 16) { + this->_max = max; + this->_len = 0; + this->_data = (T*)malloc(max * sizeof(T)); + } + + ~Queue() { + free(_data); + } + + bool contains(T a) { + for (unsigned n = 0; n < _len; ++n) + if (_data[n] == a) + return true; + return false; + } + + void add(T a) { + ensure(_len + 1); + JS_ASSERT(_len <= _max); + _data[_len++] = a; + } + + void add(T* chunk, unsigned size) { + ensure(_len + size); + JS_ASSERT(_len <= _max); + memcpy(&_data[_len], chunk, size * sizeof(T)); + _len += size; + } + + void addUnique(T a) { + if (!contains(a)) + add(a); + } + + void setLength(unsigned len) { + ensure(len + 1); + _len = len; + } + + void clear() { + _len = 0; + } + + unsigned length() const { + return _len; + } + + T* data() const { + return _data; + } +}; + +/* + * Tracker is used to keep track of values being manipulated by the interpreter + * during trace recording. + */ +class Tracker { + struct Page { + struct Page* next; + jsuword base; + nanojit::LIns* map[1]; + }; + struct Page* pagelist; + + jsuword getPageBase(const void* v) const; + struct Page* findPage(const void* v) const; + struct Page* addPage(const void* v); +public: + Tracker(); + ~Tracker(); + + bool has(const void* v) const; + nanojit::LIns* get(const void* v) const; + void set(const void* v, nanojit::LIns* ins); + void clear(); +}; + +/* + * The oracle keeps track of slots that should not be demoted to int because we know them + * to overflow or they result in type-unstable traces. We are using a simple hash table. + * Collisions lead to loss of optimization (demotable slots are not demoted) but have no + * correctness implications. + */ +#define ORACLE_SIZE 4096 + +class Oracle { + avmplus::BitSet _dontDemote; +public: + void markGlobalSlotUndemotable(JSScript* script, unsigned slot); + bool isGlobalSlotUndemotable(JSScript* script, unsigned slot) const; + void markStackSlotUndemotable(JSScript* script, jsbytecode* ip, unsigned slot); + bool isStackSlotUndemotable(JSScript* script, jsbytecode* ip, unsigned slot) const; + void clear(); +}; + +typedef Queue SlotList; + +class TypeMap : public Queue { +public: + void captureGlobalTypes(JSContext* cx, SlotList& slots); + void captureStackTypes(JSContext* cx, unsigned callDepth); + bool matches(TypeMap& other) const; +}; + +enum ExitType { + BRANCH_EXIT, + LOOP_EXIT, + NESTED_EXIT, + MISMATCH_EXIT, + OOM_EXIT, + OVERFLOW_EXIT, + UNSTABLE_LOOP_EXIT, + TIMEOUT_EXIT +}; + +struct VMSideExit : public nanojit::SideExit +{ + intptr_t ip_adj; + intptr_t sp_adj; + intptr_t rp_adj; + int32_t calldepth; + uint32 numGlobalSlots; + uint32 numStackSlots; + uint32 numStackSlotsBelowCurrentFrame; + ExitType exitType; +}; + +static inline uint8* getTypeMap(nanojit::SideExit* exit) +{ + return (uint8*)(((VMSideExit*)exit) + 1); +} + +struct InterpState +{ + void* sp; /* native stack pointer, stack[0] is spbase[0] */ + void* rp; /* call stack pointer */ + void* gp; /* global frame pointer */ + JSContext *cx; /* current VM context handle */ + void* eos; /* first unusable word after the native stack */ + void* eor; /* first unusable word after the call stack */ + VMSideExit* lastTreeExitGuard; /* guard we exited on during a tree call */ + VMSideExit* lastTreeCallGuard; /* guard we want to grow from if the tree + call exit guard mismatched */ + void* rpAtLastTreeCall; /* value of rp at innermost tree call guard */ +}; + +struct UnstableExit +{ + nanojit::Fragment* fragment; + VMSideExit* exit; + UnstableExit* next; +}; + +class TreeInfo MMGC_SUBCLASS_DECL { + nanojit::Fragment* fragment; +public: + JSScript* script; + unsigned maxNativeStackSlots; + ptrdiff_t nativeStackBase; + unsigned maxCallDepth; + TypeMap stackTypeMap; + Queue dependentTrees; + unsigned branchCount; + Queue sideExits; + UnstableExit* unstableExits; + + TreeInfo(nanojit::Fragment* _fragment) : unstableExits(NULL) { + fragment = _fragment; + } + ~TreeInfo(); +}; + +struct FrameInfo { + JSObject* callee; // callee function object + intptr_t ip_adj; // callee script-based pc index and imacro pc + uint8* typemap; // typemap for the stack frame + union { + struct { + uint16 spdist; // distance from fp->slots to fp->regs->sp at JSOP_CALL + uint16 argc; // actual argument count, may be < fun->nargs + } s; + uint32 word; // for spdist/argc LIR store in record_JSOP_CALL + }; +}; + +class TraceRecorder : public avmplus::GCObject { + JSContext* cx; + JSTraceMonitor* traceMonitor; + JSObject* globalObj; + Tracker tracker; + Tracker nativeFrameTracker; + char* entryTypeMap; + unsigned callDepth; + JSAtom** atoms; + VMSideExit* anchor; + nanojit::Fragment* fragment; + TreeInfo* treeInfo; + nanojit::LirBuffer* lirbuf; + nanojit::LirWriter* lir; + nanojit::LirBufWriter* lir_buf_writer; + nanojit::LirWriter* verbose_filter; + nanojit::LirWriter* cse_filter; + nanojit::LirWriter* expr_filter; + nanojit::LirWriter* func_filter; +#ifdef NJ_SOFTFLOAT + nanojit::LirWriter* float_filter; +#endif + nanojit::LIns* cx_ins; + nanojit::LIns* gp_ins; + nanojit::LIns* eos_ins; + nanojit::LIns* eor_ins; + nanojit::LIns* rval_ins; + nanojit::LIns* inner_sp_ins; + bool deepAborted; + bool applyingArguments; + bool trashTree; + nanojit::Fragment* whichTreeToTrash; + Queue cfgMerges; + jsval* global_dslots; + JSTraceableNative* pendingTraceableNative; + bool terminate; + intptr_t terminate_ip_adj; + nanojit::Fragment* outerToBlacklist; + nanojit::Fragment* promotedPeer; + TraceRecorder* nextRecorderToAbort; + bool wasRootFragment; + + bool isGlobal(jsval* p) const; + ptrdiff_t nativeGlobalOffset(jsval* p) const; + ptrdiff_t nativeStackOffset(jsval* p) const; + void import(nanojit::LIns* base, ptrdiff_t offset, jsval* p, uint8& t, + const char *prefix, uintN index, JSStackFrame *fp); + void import(TreeInfo* treeInfo, nanojit::LIns* sp, unsigned ngslots, unsigned callDepth, + uint8* globalTypeMap, uint8* stackTypeMap); + void trackNativeStackUse(unsigned slots); + + bool lazilyImportGlobalSlot(unsigned slot); + + nanojit::LIns* guard(bool expected, nanojit::LIns* cond, ExitType exitType); + nanojit::LIns* guard(bool expected, nanojit::LIns* cond, nanojit::LIns* exit); + nanojit::LIns* addName(nanojit::LIns* ins, const char* name); + + nanojit::LIns* get(jsval* p) const; + nanojit::LIns* writeBack(nanojit::LIns* i, nanojit::LIns* base, ptrdiff_t offset); + void set(jsval* p, nanojit::LIns* l, bool initializing = false); + + bool checkType(jsval& v, uint8 t, jsval*& stage_val, nanojit::LIns*& stage_ins, + unsigned& stage_count); + bool deduceTypeStability(nanojit::Fragment* root_peer, nanojit::Fragment** stable_peer, + unsigned* demotes); + + jsval& argval(unsigned n) const; + jsval& varval(unsigned n) const; + jsval& stackval(int n) const; + + nanojit::LIns* scopeChain() const; + bool activeCallOrGlobalSlot(JSObject* obj, jsval*& vp); + + nanojit::LIns* arg(unsigned n); + void arg(unsigned n, nanojit::LIns* i); + nanojit::LIns* var(unsigned n); + void var(unsigned n, nanojit::LIns* i); + nanojit::LIns* stack(int n); + void stack(int n, nanojit::LIns* i); + + nanojit::LIns* alu(nanojit::LOpcode op, jsdouble v0, jsdouble v1, + nanojit::LIns* s0, nanojit::LIns* s1); + nanojit::LIns* f2i(nanojit::LIns* f); + nanojit::LIns* makeNumberInt32(nanojit::LIns* f); + nanojit::LIns* stringify(jsval& v); + + bool call_imacro(jsbytecode* imacro); + + bool ifop(); + bool switchop(); + bool inc(jsval& v, jsint incr, bool pre = true); + bool inc(jsval& v, nanojit::LIns*& v_ins, jsint incr, bool pre = true); + bool incProp(jsint incr, bool pre = true); + bool incElem(jsint incr, bool pre = true); + bool incName(jsint incr, bool pre = true); + + enum { CMP_NEGATE = 1, CMP_TRY_BRANCH_AFTER_COND = 2, CMP_CASE = 4, CMP_STRICT = 8 }; + bool cmp(nanojit::LOpcode op, int flags = 0); + + bool unary(nanojit::LOpcode op); + bool binary(nanojit::LOpcode op); + + bool ibinary(nanojit::LOpcode op); + bool iunary(nanojit::LOpcode op); + bool bbinary(nanojit::LOpcode op); + void demote(jsval& v, jsdouble result); + + bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins, nanojit::LIns*& ops_ins, + size_t op_offset = 0); + bool test_property_cache(JSObject* obj, nanojit::LIns* obj_ins, JSObject*& obj2, + jsuword& pcval); + bool test_property_cache_direct_slot(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot); + void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot, + nanojit::LIns*& dslots_ins, nanojit::LIns* v_ins); + nanojit::LIns* stobj_get_fslot(nanojit::LIns* obj_ins, unsigned slot); + nanojit::LIns* stobj_get_slot(nanojit::LIns* obj_ins, unsigned slot, + nanojit::LIns*& dslots_ins); + bool native_set(nanojit::LIns* obj_ins, JSScopeProperty* sprop, + nanojit::LIns*& dslots_ins, nanojit::LIns* v_ins); + bool native_get(nanojit::LIns* obj_ins, nanojit::LIns* pobj_ins, JSScopeProperty* sprop, + nanojit::LIns*& dslots_ins, nanojit::LIns*& v_ins); + + bool name(jsval*& vp); + bool prop(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot, nanojit::LIns*& v_ins); + bool elem(jsval& oval, jsval& idx, jsval*& vp, nanojit::LIns*& v_ins, nanojit::LIns*& addr_ins); + + bool getProp(JSObject* obj, nanojit::LIns* obj_ins); + bool getProp(jsval& v); + bool getThis(nanojit::LIns*& this_ins); + + bool box_jsval(jsval v, nanojit::LIns*& v_ins); + bool unbox_jsval(jsval v, nanojit::LIns*& v_ins); + bool guardClass(JSObject* obj, nanojit::LIns* obj_ins, JSClass* clasp, + ExitType exitType = MISMATCH_EXIT); + bool guardDenseArray(JSObject* obj, nanojit::LIns* obj_ins, + ExitType exitType = MISMATCH_EXIT); + bool guardDenseArrayIndex(JSObject* obj, jsint idx, nanojit::LIns* obj_ins, + nanojit::LIns* dslots_ins, nanojit::LIns* idx_ins, + ExitType exitType); + bool guardElemOp(JSObject* obj, nanojit::LIns* obj_ins, jsid id, size_t op_offset, jsval* vp); + void clearFrameSlotsFromCache(); + bool guardShapelessCallee(jsval& callee); + bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, bool constructing); + bool functionCall(bool constructing); + + void trackCfgMerges(jsbytecode* pc); + void flipIf(jsbytecode* pc, bool& cond); + void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x); + + bool hasMethod(JSObject* obj, jsid id); + bool hasToStringMethod(JSObject* obj); + bool hasToStringMethod(jsval v) { + JS_ASSERT(JSVAL_IS_OBJECT(v)); + return hasToStringMethod(JSVAL_TO_OBJECT(v)); + } + bool hasValueOfMethod(JSObject* obj); + bool hasValueOfMethod(jsval v) { + JS_ASSERT(JSVAL_IS_OBJECT(v)); + return hasValueOfMethod(JSVAL_TO_OBJECT(v)); + } + bool hasIteratorMethod(JSObject* obj); + bool hasIteratorMethod(jsval v) { + JS_ASSERT(JSVAL_IS_OBJECT(v)); + return hasIteratorMethod(JSVAL_TO_OBJECT(v)); + } + +public: + friend bool js_MonitorRecording(TraceRecorder* tr); + + TraceRecorder(JSContext* cx, VMSideExit*, nanojit::Fragment*, TreeInfo*, + unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap, + VMSideExit* expectedInnerExit, nanojit::Fragment* outerToBlacklist); + ~TraceRecorder(); + + uint8 determineSlotType(jsval* vp) const; + nanojit::LIns* snapshot(ExitType exitType); + nanojit::Fragment* getFragment() const { return fragment; } + bool isLoopHeader(JSContext* cx) const; + void compile(nanojit::Fragmento* fragmento); + bool closeLoop(nanojit::Fragmento* fragmento, bool& demote, unsigned *demotes); + void endLoop(nanojit::Fragmento* fragmento); + void joinEdgesToEntry(nanojit::Fragmento* fragmento, nanojit::Fragment* peer_root); + void blacklist() { fragment->blacklist(); } + bool adjustCallerTypes(nanojit::Fragment* f, unsigned* demote_slots, bool& trash); + nanojit::Fragment* findNestedCompatiblePeer(nanojit::Fragment* f, nanojit::Fragment** empty); + void prepareTreeCall(nanojit::Fragment* inner); + void emitTreeCall(nanojit::Fragment* inner, VMSideExit* exit); + unsigned getCallDepth() const; + void pushAbortStack(); + void popAbortStack(); + void removeFragmentoReferences(); + + bool record_EnterFrame(); + bool record_LeaveFrame(); + bool record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop); + bool record_SetPropMiss(JSPropCacheEntry* entry); + bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj); + bool record_FastNativeCallComplete(); + bool record_IteratorNextComplete(); + + nanojit::Fragment* getOuterToBlacklist() { return outerToBlacklist; } + void deepAbort() { deepAborted = true; } + bool wasDeepAborted() { return deepAborted; } + bool walkedOutOfLoop() { return terminate; } + void setPromotedPeer(nanojit::Fragment* peer) { promotedPeer = peer; } + TreeInfo* getTreeInfo() { return treeInfo; } + +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + bool record_##op(); +# include "jsopcode.tbl" +#undef OPDEF +}; + +#define TRACING_ENABLED(cx) JS_HAS_OPTION(cx, JSOPTION_JIT) +#define TRACE_RECORDER(cx) (JS_TRACE_MONITOR(cx).recorder) +#define SET_TRACE_RECORDER(cx,tr) (JS_TRACE_MONITOR(cx).recorder = (tr)) + +#define JSOP_IS_BINARY(op) ((uintN)((op) - JSOP_BITOR) <= (uintN)(JSOP_MOD - JSOP_BITOR)) + +/* + * See jsinterp.cpp for the ENABLE_TRACER definition. Also note how comparing x + * to JSOP_* constants specializes trace-recording code at compile time either + * to include imacro support, or exclude it altogether for this particular x. + * + * We save macro-generated code size also via bool TraceRecorder::record_JSOP_* + * return type, instead of a three-state: OK, ABORTED, IMACRO_STARTED. But the + * price of this is the JSFRAME_IMACRO_START frame flag. We need one more bit + * to detect that TraceRecorder::call_imacro was invoked by the record_JSOP_* + * method invoked by TRACE_ARGS_. + */ +#define RECORD_ARGS(x,args) \ + JS_BEGIN_MACRO \ + if (!js_MonitorRecording(TRACE_RECORDER(cx))) { \ + ENABLE_TRACER(0); \ + } else { \ + TRACE_ARGS_(x, args, \ + if ((fp->flags & JSFRAME_IMACRO_START) && \ + (x == JSOP_ITER || x == JSOP_NEXTITER || \ + JSOP_IS_BINARY(x))) { \ + fp->flags &= ~JSFRAME_IMACRO_START; \ + atoms = COMMON_ATOMS_START(&rt->atomState); \ + op = JSOp(*regs.pc); \ + DO_OP(); \ + } \ + ); \ + } \ + JS_END_MACRO + +#define TRACE_ARGS_(x,args,onfalse) \ + JS_BEGIN_MACRO \ + TraceRecorder* tr_ = TRACE_RECORDER(cx); \ + if (tr_ && !tr_->record_##x args) { \ + onfalse \ + js_AbortRecording(cx, #x); \ + ENABLE_TRACER(0); \ + } \ + JS_END_MACRO + +#define TRACE_ARGS(x,args) TRACE_ARGS_(x, args, ) + +#define RECORD(x) RECORD_ARGS(x, ()) +#define TRACE_0(x) TRACE_ARGS(x, ()) +#define TRACE_1(x,a) TRACE_ARGS(x, (a)) +#define TRACE_2(x,a,b) TRACE_ARGS(x, (a, b)) + +extern bool +js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount); + +extern bool +js_MonitorRecording(TraceRecorder *tr); + +extern void +js_AbortRecording(JSContext* cx, const char* reason); + +extern void +js_InitJIT(JSTraceMonitor *tm); + +extern void +js_FinishJIT(JSTraceMonitor *tm); + +extern void +js_FlushJITCache(JSContext* cx); + +extern void +js_FlushJITOracle(JSContext* cx); + +#else /* !JS_TRACER */ + +#define RECORD(x) ((void)0) +#define TRACE_0(x) ((void)0) +#define TRACE_1(x,a) ((void)0) +#define TRACE_2(x,a,b) ((void)0) + +#endif /* !JS_TRACER */ + +#endif /* jstracer_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstypes.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstypes.h new file mode 100644 index 0000000..bf09bfe --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jstypes.h @@ -0,0 +1,490 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: jstypes.h +** Description: Definitions of NSPR's basic types +** +** Prototypes and macros used to make up for deficiencies in ANSI environments +** that we have found. +** +** Since we do not wrap and all the other standard headers, authors +** of portable code will not know in general that they need these definitions. +** Instead of requiring these authors to find the dependent uses in their code +** and take the following steps only in those C files, we take steps once here +** for all C files. +**/ + +#ifndef jstypes_h___ +#define jstypes_h___ + +#include + +/*********************************************************************** +** MACROS: JS_EXTERN_API +** JS_EXPORT_API +** DESCRIPTION: +** These are only for externally visible routines and globals. For +** internal routines, just use "extern" for type checking and that +** will not export internal cross-file or forward-declared symbols. +** Define a macro for declaring procedures return types. We use this to +** deal with windoze specific type hackery for DLL definitions. Use +** JS_EXTERN_API when the prototype for the method is declared. Use +** JS_EXPORT_API for the implementation of the method. +** +** Example: +** in dowhim.h +** JS_EXTERN_API( void ) DoWhatIMean( void ); +** in dowhim.c +** JS_EXPORT_API( void ) DoWhatIMean( void ) { return; } +** +** +***********************************************************************/ +#ifdef WIN32 + +/* These also work for __MWERKS__ */ +# define JS_EXTERN_API(__type) extern __declspec(dllexport) __type +# define JS_EXPORT_API(__type) __declspec(dllexport) __type +# define JS_EXTERN_DATA(__type) extern __declspec(dllexport) __type +# define JS_EXPORT_DATA(__type) __declspec(dllexport) __type + +#elif defined(XP_OS2) && defined(__declspec) + +# define JS_EXTERN_API(__type) extern __declspec(dllexport) __type +# define JS_EXPORT_API(__type) __declspec(dllexport) __type +# define JS_EXTERN_DATA(__type) extern __declspec(dllexport) __type +# define JS_EXPORT_DATA(__type) __declspec(dllexport) __type + +#else /* Unix */ + +# ifdef HAVE_VISIBILITY_ATTRIBUTE +# define JS_EXTERNAL_VIS __attribute__((visibility ("default"))) +# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# define JS_EXTERNAL_VIS __global +# else +# define JS_EXTERNAL_VIS +# endif + +# define JS_EXTERN_API(__type) extern JS_EXTERNAL_VIS __type +# define JS_EXPORT_API(__type) JS_EXTERNAL_VIS __type +# define JS_EXTERN_DATA(__type) extern JS_EXTERNAL_VIS __type +# define JS_EXPORT_DATA(__type) JS_EXTERNAL_VIS __type + +#endif + +#ifdef _WIN32 +# if defined(__MWERKS__) || defined(__GNUC__) +# define JS_IMPORT_API(__x) __x +# else +# define JS_IMPORT_API(__x) __declspec(dllimport) __x +# endif +#elif defined(XP_OS2) && defined(__declspec) +# define JS_IMPORT_API(__x) __declspec(dllimport) __x +#else +# define JS_IMPORT_API(__x) JS_EXPORT_API (__x) +#endif + +#if defined(_WIN32) && !defined(__MWERKS__) +# define JS_IMPORT_DATA(__x) __declspec(dllimport) __x +#elif defined(XP_OS2) && defined(__declspec) +# define JS_IMPORT_DATA(__x) __declspec(dllimport) __x +#else +# define JS_IMPORT_DATA(__x) JS_EXPORT_DATA (__x) +#endif + +/* + * The linkage of JS API functions differs depending on whether the file is + * used within the JS library or not. Any source file within the JS + * interpreter should define EXPORT_JS_API whereas any client of the library + * should not. STATIC_JS_API is used to build JS as a static library. + */ +#if defined(STATIC_JS_API) + +# define JS_PUBLIC_API(t) t +# define JS_PUBLIC_DATA(t) t + +#elif defined(EXPORT_JS_API) + +# define JS_PUBLIC_API(t) JS_EXPORT_API(t) +# define JS_PUBLIC_DATA(t) JS_EXPORT_DATA(t) + +#else + +# define JS_PUBLIC_API(t) JS_IMPORT_API(t) +# define JS_PUBLIC_DATA(t) JS_IMPORT_DATA(t) + +#endif + +#define JS_FRIEND_API(t) JS_PUBLIC_API(t) +#define JS_FRIEND_DATA(t) JS_PUBLIC_DATA(t) + +#if defined(_MSC_VER) && defined(_M_IX86) +#define JS_FASTCALL __fastcall +#elif defined(__GNUC__) && defined(__i386__) && \ + ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +#define JS_FASTCALL __attribute__((fastcall)) +#else +#define JS_FASTCALL +#define JS_NO_FASTCALL +#endif + +#ifndef JS_INLINE +# if defined __cplusplus +# define JS_INLINE inline +# elif defined _MSC_VER +# define JS_INLINE __inline +# elif defined __GNUC__ +# define JS_INLINE __inline__ +# else +# define JS_INLINE inline +# endif +#endif + +#ifndef JS_ALWAYS_INLINE +# if defined DEBUG +# define JS_ALWAYS_INLINE JS_INLINE +# elif defined _MSC_VER +# define JS_ALWAYS_INLINE __forceinline +# elif defined __GNUC__ +# define JS_ALWAYS_INLINE __attribute__((always_inline)) +# else +# define JS_ALWAYS_INLINE JS_INLINE +# endif +#endif + +/*********************************************************************** +** MACROS: JS_BEGIN_MACRO +** JS_END_MACRO +** DESCRIPTION: +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +***********************************************************************/ +#define JS_BEGIN_MACRO do { + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# define JS_END_MACRO \ + } __pragma(warning(push)) __pragma(warning(disable:4127)) \ + while (0) __pragma(warning(pop)) +#else +# define JS_END_MACRO } while (0) +#endif + +/*********************************************************************** +** MACROS: JS_BEGIN_EXTERN_C +** JS_END_EXTERN_C +** DESCRIPTION: +** Macro shorthands for conditional C++ extern block delimiters. +***********************************************************************/ +#ifdef __cplusplus + +# define JS_BEGIN_EXTERN_C extern "C" { +# define JS_END_EXTERN_C } + +#else + +# define JS_BEGIN_EXTERN_C +# define JS_END_EXTERN_C + +#endif + +/*********************************************************************** +** MACROS: JS_BIT +** JS_BITMASK +** DESCRIPTION: +** Bit masking macros. XXX n must be <= 31 to be portable +***********************************************************************/ +#define JS_BIT(n) ((JSUint32)1 << (n)) +#define JS_BITMASK(n) (JS_BIT(n) - 1) + +/*********************************************************************** +** MACROS: JS_PTR_TO_INT32 +** JS_PTR_TO_UINT32 +** JS_INT32_TO_PTR +** JS_UINT32_TO_PTR +** DESCRIPTION: +** Integer to pointer and pointer to integer conversion macros. +***********************************************************************/ +#define JS_PTR_TO_INT32(x) ((jsint)((char *)(x) - (char *)0)) +#define JS_PTR_TO_UINT32(x) ((jsuint)((char *)(x) - (char *)0)) +#define JS_INT32_TO_PTR(x) ((void *)((char *)0 + (jsint)(x))) +#define JS_UINT32_TO_PTR(x) ((void *)((char *)0 + (jsuint)(x))) + +/*********************************************************************** +** MACROS: JS_HOWMANY +** JS_ROUNDUP +** JS_MIN +** JS_MAX +** DESCRIPTION: +** Commonly used macros for operations on compatible types. +***********************************************************************/ +#define JS_HOWMANY(x,y) (((x)+(y)-1)/(y)) +#define JS_ROUNDUP(x,y) (JS_HOWMANY(x,y)*(y)) +#define JS_MIN(x,y) ((x)<(y)?(x):(y)) +#define JS_MAX(x,y) ((x)>(y)?(x):(y)) + +#if (defined(XP_WIN) && !defined(CROSS_COMPILE)) || defined (WINCE) +# include "jscpucfg.h" /* Use standard Mac or Windows configuration */ +#elif defined(XP_UNIX) || defined(XP_BEOS) || defined(XP_OS2) || defined(CROSS_COMPILE) +# include "jsautocfg.h" /* Use auto-detected configuration */ +#else +# error "Must define one of XP_BEOS, XP_OS2, XP_WIN or XP_UNIX" +#endif + +JS_BEGIN_EXTERN_C + +/************************************************************************ +** TYPES: JSUint8 +** JSInt8 +** DESCRIPTION: +** The int8 types are known to be 8 bits each. There is no type that +** is equivalent to a plain "char". +************************************************************************/ +#if JS_BYTES_PER_BYTE == 1 +typedef unsigned char JSUint8; +typedef signed char JSInt8; +#else +# error No suitable type for JSInt8/JSUint8 +#endif + +/************************************************************************ +** TYPES: JSUint16 +** JSInt16 +** DESCRIPTION: +** The int16 types are known to be 16 bits each. +************************************************************************/ +#if JS_BYTES_PER_SHORT == 2 +typedef unsigned short JSUint16; +typedef short JSInt16; +#else +# error No suitable type for JSInt16/JSUint16 +#endif + +/************************************************************************ +** TYPES: JSUint32 +** JSInt32 +** DESCRIPTION: +** The int32 types are known to be 32 bits each. +************************************************************************/ +#if JS_BYTES_PER_INT == 4 +typedef unsigned int JSUint32; +typedef int JSInt32; +# define JS_INT32(x) x +# define JS_UINT32(x) x ## U +#elif JS_BYTES_PER_LONG == 4 +typedef unsigned long JSUint32; +typedef long JSInt32; +# define JS_INT32(x) x ## L +# define JS_UINT32(x) x ## UL +#else +# error No suitable type for JSInt32/JSUint32 +#endif + +/************************************************************************ +** TYPES: JSUint64 +** JSInt64 +** DESCRIPTION: +** The int64 types are known to be 64 bits each. Care must be used when +** declaring variables of type JSUint64 or JSInt64. Different hardware +** architectures and even different compilers have varying support for +** 64 bit values. The only guaranteed portability requires the use of +** the JSLL_ macros (see jslong.h). +************************************************************************/ +#ifdef JS_HAVE_LONG_LONG + +# if JS_BYTES_PER_LONG == 8 +typedef long JSInt64; +typedef unsigned long JSUint64; +# elif defined(WIN16) +typedef __int64 JSInt64; +typedef unsigned __int64 JSUint64; +# elif defined(WIN32) && !defined(__GNUC__) +typedef __int64 JSInt64; +typedef unsigned __int64 JSUint64; +# else +typedef long long JSInt64; +typedef unsigned long long JSUint64; +# endif /* JS_BYTES_PER_LONG == 8 */ + +#else /* !JS_HAVE_LONG_LONG */ + +typedef struct { +# ifdef IS_LITTLE_ENDIAN + JSUint32 lo, hi; +# else + JSUint32 hi, lo; +#endif +} JSInt64; +typedef JSInt64 JSUint64; + +#endif /* !JS_HAVE_LONG_LONG */ + +/************************************************************************ +** TYPES: JSUintn +** JSIntn +** DESCRIPTION: +** The JSIntn types are most appropriate for automatic variables. They are +** guaranteed to be at least 16 bits, though various architectures may +** define them to be wider (e.g., 32 or even 64 bits). These types are +** never valid for fields of a structure. +************************************************************************/ +#if JS_BYTES_PER_INT >= 2 +typedef int JSIntn; +typedef unsigned int JSUintn; +#else +# error 'sizeof(int)' not sufficient for platform use +#endif + +/************************************************************************ +** TYPES: JSFloat64 +** DESCRIPTION: +** NSPR's floating point type is always 64 bits. +************************************************************************/ +typedef double JSFloat64; + +/************************************************************************ +** TYPES: JSSize +** DESCRIPTION: +** A type for representing the size of objects. +************************************************************************/ +typedef size_t JSSize; + +/************************************************************************ +** TYPES: JSPtrDiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer sutraction. +************************************************************************/ +typedef ptrdiff_t JSPtrdiff; + +/************************************************************************ +** TYPES: JSUptrdiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer sutraction. +************************************************************************/ +#if JS_BYTES_PER_WORD == 8 && JS_BYTES_PER_LONG != 8 +typedef JSUint64 JSUptrdiff; +#else +typedef unsigned long JSUptrdiff; +#endif + +/************************************************************************ +** TYPES: JSBool +** DESCRIPTION: +** Use JSBool for variables and parameter types. Use JS_FALSE and JS_TRUE +** for clarity of target type in assignments and actual arguments. Use +** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans +** just as you would C int-valued conditions. +************************************************************************/ +typedef JSIntn JSBool; +#define JS_TRUE (JSIntn)1 +#define JS_FALSE (JSIntn)0 + +/************************************************************************ +** TYPES: JSPackedBool +** DESCRIPTION: +** Use JSPackedBool within structs where bitfields are not desireable +** but minimum and consistent overhead matters. +************************************************************************/ +typedef JSUint8 JSPackedBool; + +/* +** A JSWord is an integer that is the same size as a void* +*/ +#if JS_BYTES_PER_WORD == 8 && JS_BYTES_PER_LONG != 8 +typedef JSInt64 JSWord; +typedef JSUint64 JSUword; +#else +typedef long JSWord; +typedef unsigned long JSUword; +#endif + +#include "jsotypes.h" + +/*********************************************************************** +** MACROS: JS_LIKELY +** JS_UNLIKELY +** DESCRIPTION: +** These macros allow you to give a hint to the compiler about branch +** probability so that it can better optimize. Use them like this: +** +** if (JS_LIKELY(v == 1)) { +** ... expected code path ... +** } +** +** if (JS_UNLIKELY(v == 0)) { +** ... non-expected code path ... +** } +** +***********************************************************************/ +#if defined(__GNUC__) && (__GNUC__ > 2) + +# define JS_LIKELY(x) (__builtin_expect((x), 1)) +# define JS_UNLIKELY(x) (__builtin_expect((x), 0)) + +#else + +# define JS_LIKELY(x) (x) +# define JS_UNLIKELY(x) (x) + +#endif + +/*********************************************************************** +** MACROS: JS_ARRAY_LENGTH +** JS_ARRAY_END +** DESCRIPTION: +** Macros to get the number of elements and the pointer to one past the +** last element of a C array. Use them like this: +** +** jschar buf[10], *s; +** JSString *str; +** ... +** for (s = buf; s != JS_ARRAY_END(buf); ++s) *s = ...; +** ... +** str = JS_NewStringCopyN(cx, buf, JS_ARRAY_LENGTH(buf)); +** ... +** +***********************************************************************/ + +#define JS_ARRAY_LENGTH(array) (sizeof (array) / sizeof (array)[0]) +#define JS_ARRAY_END(array) ((array) + JS_ARRAY_LENGTH(array)) + +JS_END_EXTERN_C + +#endif /* jstypes_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsutil.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsutil.cpp new file mode 100644 index 0000000..5d7eb88 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsutil.cpp @@ -0,0 +1,345 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * PR assertion checker. + */ +#include "jsstddef.h" +#include +#include +#include "jstypes.h" +#include "jsutil.h" + +#ifdef WIN32 +# include +#endif + +JS_PUBLIC_API(void) JS_Assert(const char *s, const char *file, JSIntn ln) +{ + fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln); +#if defined(WIN32) + DebugBreak(); + exit(3); +#elif defined(XP_OS2) || (defined(__GNUC__) && defined(__i386)) + asm("int $3"); +#endif + abort(); +} + +#ifdef JS_BASIC_STATS + +#include +#include +#include "jscompat.h" +#include "jsbit.h" + +/* + * Histogram bins count occurrences of values <= the bin label, as follows: + * + * linear: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or more + * 2**x: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 or more + * 10**x: 0, 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 or more + * + * We wish to count occurrences of 0 and 1 values separately, always. + */ +static uint32 +BinToVal(uintN logscale, uintN bin) +{ + JS_ASSERT(bin <= 10); + if (bin <= 1 || logscale == 0) + return bin; + --bin; + if (logscale == 2) + return JS_BIT(bin); + JS_ASSERT(logscale == 10); + return (uint32) pow(10.0, (double) bin); +} + +static uintN +ValToBin(uintN logscale, uint32 val) +{ + uintN bin; + + if (val <= 1) + return val; + bin = (logscale == 10) + ? (uintN) ceil(log10((double) val)) + : (logscale == 2) + ? (uintN) JS_CeilingLog2(val) + : val; + return JS_MIN(bin, 10); +} + +void +JS_BasicStatsAccum(JSBasicStats *bs, uint32 val) +{ + uintN oldscale, newscale, bin; + double mean; + + ++bs->num; + if (bs->max < val) + bs->max = val; + bs->sum += val; + bs->sqsum += (double)val * val; + + oldscale = bs->logscale; + if (oldscale != 10) { + mean = bs->sum / bs->num; + if (bs->max > 16 && mean > 8) { + newscale = (bs->max > 1e6 && mean > 1000) ? 10 : 2; + if (newscale != oldscale) { + uint32 newhist[11], newbin; + + memset(newhist, 0, sizeof newhist); + for (bin = 0; bin <= 10; bin++) { + newbin = ValToBin(newscale, BinToVal(oldscale, bin)); + newhist[newbin] += bs->hist[bin]; + } + memcpy(bs->hist, newhist, sizeof bs->hist); + bs->logscale = newscale; + } + } + } + + bin = ValToBin(bs->logscale, val); + ++bs->hist[bin]; +} + +double +JS_MeanAndStdDev(uint32 num, double sum, double sqsum, double *sigma) +{ + double var; + + if (num == 0 || sum == 0) { + *sigma = 0; + return 0; + } + + var = num * sqsum - sum * sum; + if (var < 0 || num == 1) + var = 0; + else + var /= (double)num * (num - 1); + + /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */ + *sigma = (var != 0) ? sqrt(var) : 0; + return sum / num; +} + +void +JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp) +{ + double mean, sigma; + + mean = JS_MeanAndStdDevBS(bs, &sigma); + fprintf(fp, "\nmean %s %g, std. deviation %g, max %lu\n", + title, mean, sigma, (unsigned long) bs->max); + JS_DumpHistogram(bs, fp); +} + +void +JS_DumpHistogram(JSBasicStats *bs, FILE *fp) +{ + uintN bin; + uint32 cnt, max, prev, val, i; + double sum, mean; + + for (bin = 0, max = 0, sum = 0; bin <= 10; bin++) { + cnt = bs->hist[bin]; + if (max < cnt) + max = cnt; + sum += cnt; + } + mean = sum / cnt; + for (bin = 0, prev = 0; bin <= 10; bin++, prev = val) { + val = BinToVal(bs->logscale, bin); + cnt = bs->hist[bin]; + if (prev + 1 >= val) + fprintf(fp, " [%6u]", val); + else + fprintf(fp, "[%6u, %6u]", prev + 1, val); + fprintf(fp, "%s %8u ", (bin == 10) ? "+" : ":", cnt); + if (cnt != 0) { + if (max > 1e6 && mean > 1e3) + cnt = (uint32) ceil(log10((double) cnt)); + else if (max > 16 && mean > 8) + cnt = JS_CeilingLog2(cnt); + for (i = 0; i < cnt; i++) + putc('*', fp); + } + putc('\n', fp); + } +} + +#endif /* JS_BASIC_STATS */ + +#if defined DEBUG_notme && defined XP_UNIX + +#define __USE_GNU 1 +#include +#include +#include "jshash.h" +#include "jsprf.h" + +JSCallsite js_calltree_root = {0, NULL, NULL, 0, NULL, NULL, NULL, NULL}; + +static JSCallsite * +CallTree(void **bp) +{ + void **bpup, **bpdown, *pc; + JSCallsite *parent, *site, **csp; + Dl_info info; + int ok, offset; + const char *symbol; + char *method; + + /* Reverse the stack frame list to avoid recursion. */ + bpup = NULL; + for (;;) { + bpdown = (void**) bp[0]; + bp[0] = (void*) bpup; + if ((void**) bpdown[0] < bpdown) + break; + bpup = bp; + bp = bpdown; + } + + /* Reverse the stack again, finding and building a path in the tree. */ + parent = &js_calltree_root; + do { + bpup = (void**) bp[0]; + bp[0] = (void*) bpdown; + pc = bp[1]; + + csp = &parent->kids; + while ((site = *csp) != NULL) { + if (site->pc == (uint32)pc) { + /* Put the most recently used site at the front of siblings. */ + *csp = site->siblings; + site->siblings = parent->kids; + parent->kids = site; + + /* Site already built -- go up the stack. */ + goto upward; + } + csp = &site->siblings; + } + + /* Check for recursion: see if pc is on our ancestor line. */ + for (site = parent; site; site = site->parent) { + if (site->pc == (uint32)pc) + goto upward; + } + + /* + * Not in tree at all: let's find our symbolic callsite info. + * XXX static syms are masked by nearest lower global + */ + info.dli_fname = info.dli_sname = NULL; + ok = dladdr(pc, &info); + if (ok < 0) { + fprintf(stderr, "dladdr failed!\n"); + return NULL; + } + +/* XXXbe sub 0x08040000? or something, see dbaron bug with tenthumbs comment */ + symbol = info.dli_sname; + offset = (char*)pc - (char*)info.dli_fbase; + method = symbol + ? strdup(symbol) + : JS_smprintf("%s+%X", + info.dli_fname ? info.dli_fname : "main", + offset); + if (!method) + return NULL; + + /* Create a new callsite record. */ + site = (JSCallsite *) malloc(sizeof(JSCallsite)); + if (!site) + return NULL; + + /* Insert the new site into the tree. */ + site->pc = (uint32)pc; + site->name = method; + site->library = info.dli_fname; + site->offset = offset; + site->parent = parent; + site->siblings = parent->kids; + parent->kids = site; + site->kids = NULL; + + upward: + parent = site; + bpdown = bp; + bp = bpup; + } while (bp); + + return site; +} + +JSCallsite * +JS_Backtrace(int skip) +{ + void **bp, **bpdown; + + /* Stack walking code adapted from Kipp's "leaky". */ +#if defined(__i386) + __asm__( "movl %%ebp, %0" : "=g"(bp)); +#elif defined(__x86_64__) + __asm__( "movq %%rbp, %0" : "=g"(bp)); +#else + /* + * It would be nice if this worked uniformly, but at least on i386 and + * x86_64, it stopped working with gcc 4.1, because it points to the + * end of the saved registers instead of the start. + */ + bp = (void**) __builtin_frame_address(0); +#endif + while (--skip >= 0) { + bpdown = (void**) *bp++; + if (bpdown < bp) + break; + bp = bpdown; + } + + return CallTree(bp); +} + +#endif /* DEBUG_notme && XP_UNIX */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsutil.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsutil.h new file mode 100644 index 0000000..a6c329c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsutil.h @@ -0,0 +1,168 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * PR assertion checker. + */ + +#ifndef jsutil_h___ +#define jsutil_h___ + +JS_BEGIN_EXTERN_C + +#ifdef DEBUG + +extern JS_PUBLIC_API(void) +JS_Assert(const char *s, const char *file, JSIntn ln); + +#define JS_ASSERT(expr) \ + ((expr) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__)) + +#define JS_ASSERT_IF(cond, expr) \ + ((!(cond) || (expr)) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__)) + +#define JS_NOT_REACHED(reason) \ + JS_Assert(reason, __FILE__, __LINE__) + +#else + +#define JS_ASSERT(expr) ((void) 0) +#define JS_ASSERT_IF(cond,expr) ((void) 0) +#define JS_NOT_REACHED(reason) + +#endif /* defined(DEBUG) */ + +/* + * Compile-time assert. "condition" must be a constant expression. + * The macro can be used only in places where an "extern" declaration is + * allowed. + */ + +/* + * Sun Studio C++ compiler has a bug + * "sizeof expression not accepted as size of array parameter" + * The bug number is 6688515. It is not public yet. + * Turn off this assert for Sun Studio until this bug is fixed. + */ +#ifdef __SUNPRO_CC +#define JS_STATIC_ASSERT(condition) +#else +#define JS_STATIC_ASSERT(condition) \ + extern void js_static_assert(int arg[(condition) ? 1 : -1]) +#endif + +/* + * Abort the process in a non-graceful manner. This will cause a core file, + * call to the debugger or other moral equivalent as well as causing the + * entire process to stop. + */ +extern JS_PUBLIC_API(void) JS_Abort(void); + +#if 0 +# define JS_BASIC_STATS 1 +# define JS_SCOPE_DEPTH_METER 1 +#endif + +#if defined DEBUG && !defined JS_BASIC_STATS +# define JS_BASIC_STATS 1 +#endif + +#ifdef JS_BASIC_STATS + +#include + +typedef struct JSBasicStats { + uint32 num; + uint32 max; + double sum; + double sqsum; + uint32 logscale; /* logarithmic scale: 0 (linear), 2, 10 */ + uint32 hist[11]; +} JSBasicStats; + +#define JS_INIT_STATIC_BASIC_STATS {0,0,0,0,0,{0,0,0,0,0,0,0,0,0,0,0}} +#define JS_BASIC_STATS_INIT(bs) memset((bs), 0, sizeof(JSBasicStats)) + +#define JS_BASIC_STATS_ACCUM(bs,val) \ + JS_BasicStatsAccum(bs, val) + +#define JS_MeanAndStdDevBS(bs,sigma) \ + JS_MeanAndStdDev((bs)->num, (bs)->sum, (bs)->sqsum, sigma) + +extern void +JS_BasicStatsAccum(JSBasicStats *bs, uint32 val); + +extern double +JS_MeanAndStdDev(uint32 num, double sum, double sqsum, double *sigma); + +extern void +JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp); + +extern void +JS_DumpHistogram(JSBasicStats *bs, FILE *fp); + +#else + +#define JS_BASIC_STATS_ACCUM(bs,val) /* nothing */ + +#endif /* JS_BASIC_STATS */ + + +#ifdef XP_UNIX + +typedef struct JSCallsite JSCallsite; + +struct JSCallsite { + uint32 pc; + char *name; + const char *library; + int offset; + JSCallsite *parent; + JSCallsite *siblings; + JSCallsite *kids; + void *handy; +}; + +extern JSCallsite *JS_Backtrace(int skip); + +#endif + +JS_END_EXTERN_C + +#endif /* jsutil_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsversion.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsversion.h new file mode 100644 index 0000000..b16953b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsversion.h @@ -0,0 +1,243 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS configuration macros. + */ +#ifndef JS_VERSION +#define JS_VERSION 180 +#endif + +/* + * Compile-time JS version configuration. The JS version numbers lie on the + * number line like so: + * + * 1.0 1.1 1.2 1.3 1.4 ECMAv3 1.5 1.6 1.7 1.8 + * ^ ^ + * | | + * basis for ECMAv1 close to ECMAv2 + * + * where ECMAv3 stands for ECMA-262 Edition 3. See the runtime version enum + * JSVersion in jspubtd.h. Code in the engine can therefore count on version + * <= JSVERSION_1_4 to mean "before the Third Edition of ECMA-262" and version + * > JSVERSION_1_4 to mean "at or after the Third Edition". + * + * In the (likely?) event that SpiderMonkey grows to implement JavaScript 2.0, + * or ECMA-262 Edition 4 (JS2 without certain extensions), the version number + * to use would be near 200, or greater. + * + * The JS_VERSION_ECMA_3 version is the minimal configuration conforming to + * the ECMA-262 Edition 3 specification. Use it for minimal embeddings, where + * you're sure you don't need any of the extensions disabled in this version. + * In order to facilitate testing, JS_HAS_OBJ_PROTO_PROP is defined as part of + * the JS_VERSION_ECMA_3_TEST version. + * + * To keep things sane in the modern age, where we need exceptions in order to + * implement, e.g., iterators and generators, we are dropping support for all + * versions <= 1.4. + */ +#define JS_VERSION_ECMA_3 148 +#define JS_VERSION_ECMA_3_TEST 149 + +#if JS_VERSION == JS_VERSION_ECMA_3 || \ + JS_VERSION == JS_VERSION_ECMA_3_TEST + +#define JS_HAS_STR_HTML_HELPERS 0 /* has str.anchor, str.bold, etc. */ +#define JS_HAS_PERL_SUBSTR 0 /* has str.substr */ +#if JS_VERSION == JS_VERSION_ECMA_3_TEST +#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ +#else +#define JS_HAS_OBJ_PROTO_PROP 0 /* has o.__proto__ etc. */ +#endif +#define JS_HAS_OBJ_WATCHPOINT 0 /* has o.watch and o.unwatch */ +#define JS_HAS_EVAL_THIS_SCOPE 0 /* Math.eval is same as with (Math) */ +#define JS_HAS_SHARP_VARS 0 /* has #n=, #n# for object literals */ +#define JS_HAS_SCRIPT_OBJECT 0 /* has (new Script("x++")).exec() */ +#define JS_HAS_XDR 0 /* has XDR API and internal support */ +#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */ +#define JS_HAS_TOSOURCE 0 /* has Object/Array toSource method */ +#define JS_HAS_DEBUGGER_KEYWORD 0 /* has hook for debugger keyword */ +#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */ +#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ +#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */ +#define JS_HAS_UNEVAL 0 /* has uneval() top-level function */ +#define JS_HAS_CONST 0 /* has JS2 const as alternative var */ +#define JS_HAS_FUN_EXPR_STMT 0 /* has function expression statement */ +#define JS_HAS_LVALUE_RETURN 1 /* has o.item(i) = j; for native item */ +#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */ +#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ +#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ +#define JS_HAS_GENERATORS 0 /* has yield in generator function */ +#define JS_HAS_BLOCK_SCOPE 0 /* has block scope via let/arraycomp */ +#define JS_HAS_DESTRUCTURING 0 /* has [a,b] = ... or {p:a,q:b} = ... */ +#define JS_HAS_GENERATOR_EXPRS 0 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_EXPR_CLOSURES 0 /* has function (formals) listexpr */ + +#elif JS_VERSION < 150 + +#error "unsupported JS_VERSION" + +#elif JS_VERSION == 150 + +#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */ +#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */ +#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ +#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ +#define JS_HAS_EVAL_THIS_SCOPE 1 /* Math.eval is same as with (Math) */ +#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */ +#define JS_HAS_SCRIPT_OBJECT 1 /* has (new Script("x++")).exec() */ +#define JS_HAS_XDR 1 /* has XDR API and internal support */ +#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */ +#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ +#define JS_HAS_DEBUGGER_KEYWORD 1 /* has hook for debugger keyword */ +#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ +#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ +#define JS_HAS_GETTER_SETTER 1 /* has JS2 getter/setter functions */ +#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ +#define JS_HAS_CONST 1 /* has JS2 const as alternative var */ +#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */ +#define JS_HAS_LVALUE_RETURN 1 /* has o.item(i) = j; for native item */ +#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */ +#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ +#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ +#define JS_HAS_GENERATORS 0 /* has yield in generator function */ +#define JS_HAS_BLOCK_SCOPE 0 /* has block scope via let/arraycomp */ +#define JS_HAS_DESTRUCTURING 0 /* has [a,b] = ... or {p:a,q:b} = ... */ +#define JS_HAS_GENERATOR_EXPRS 0 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_EXPR_CLOSURES 0 /* has function (formals) listexpr */ + +#elif JS_VERSION == 160 + +#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */ +#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */ +#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ +#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ +#define JS_HAS_EVAL_THIS_SCOPE 1 /* Math.eval is same as with (Math) */ +#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */ +#define JS_HAS_SCRIPT_OBJECT 1 /* has (new Script("x++")).exec() */ +#define JS_HAS_XDR 1 /* has XDR API and internal support */ +#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */ +#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ +#define JS_HAS_DEBUGGER_KEYWORD 1 /* has hook for debugger keyword */ +#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ +#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ +#define JS_HAS_GETTER_SETTER 1 /* has JS2 getter/setter functions */ +#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ +#define JS_HAS_CONST 1 /* has JS2 const as alternative var */ +#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */ +#define JS_HAS_LVALUE_RETURN 1 /* has o.item(i) = j; for native item */ +#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */ +#define JS_HAS_XML_SUPPORT 1 /* has ECMAScript for XML support */ +#define JS_HAS_ARRAY_EXTRAS 1 /* has indexOf and Lispy extras */ +#define JS_HAS_GENERATORS 0 /* has yield in generator function */ +#define JS_HAS_BLOCK_SCOPE 0 /* has block scope via let/arraycomp */ +#define JS_HAS_DESTRUCTURING 0 /* has [a,b] = ... or {p:a,q:b} = ... */ +#define JS_HAS_GENERATOR_EXPRS 0 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_EXPR_CLOSURES 0 /* has function (formals) listexpr */ + +#elif JS_VERSION == 170 + +#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */ +#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */ +#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ +#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ +#define JS_HAS_EVAL_THIS_SCOPE 1 /* Math.eval is same as with (Math) */ +#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */ +#define JS_HAS_SCRIPT_OBJECT 0 /* has (new Script("x++")).exec() */ +#define JS_HAS_XDR 1 /* has XDR API and internal support */ +#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */ +#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ +#define JS_HAS_DEBUGGER_KEYWORD 1 /* has hook for debugger keyword */ +#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ +#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ +#define JS_HAS_GETTER_SETTER 1 /* has JS2 getter/setter functions */ +#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ +#define JS_HAS_CONST 1 /* has JS2 const as alternative var */ +#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */ +#define JS_HAS_LVALUE_RETURN 1 /* has o.item(i) = j; for native item */ +#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */ +#define JS_HAS_XML_SUPPORT 1 /* has ECMAScript for XML support */ +#define JS_HAS_ARRAY_EXTRAS 1 /* has indexOf and Lispy extras */ +#define JS_HAS_GENERATORS 1 /* has yield in generator function */ +#define JS_HAS_BLOCK_SCOPE 1 /* has block scope via let/arraycomp */ +#define JS_HAS_DESTRUCTURING 1 /* has [a,b] = ... or {p:a,q:b} = ... */ +#define JS_HAS_GENERATOR_EXPRS 0 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_EXPR_CLOSURES 0 /* has function (formals) listexpr */ + +#elif JS_VERSION == 180 + +#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */ +#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */ +#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ +#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ +#define JS_HAS_EVAL_THIS_SCOPE 1 /* Math.eval is same as with (Math) */ +#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */ +#define JS_HAS_SCRIPT_OBJECT 0 /* has (new Script("x++")).exec() */ +#define JS_HAS_XDR 1 /* has XDR API and internal support */ +#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */ +#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ +#define JS_HAS_DEBUGGER_KEYWORD 1 /* has hook for debugger keyword */ +#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ +#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ +#define JS_HAS_GETTER_SETTER 1 /* has JS2 getter/setter functions */ +#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ +#define JS_HAS_CONST 1 /* has JS2 const as alternative var */ +#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */ +#define JS_HAS_LVALUE_RETURN 1 /* has o.item(i) = j; for native item */ +#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */ +#define JS_HAS_XML_SUPPORT 1 /* has ECMAScript for XML support */ +#define JS_HAS_ARRAY_EXTRAS 1 /* has indexOf and Lispy extras */ +#define JS_HAS_GENERATORS 1 /* has yield in generator function */ +#define JS_HAS_BLOCK_SCOPE 1 /* has block scope via let/arraycomp */ +#define JS_HAS_DESTRUCTURING 2 /* has [a,b] = ... or {p:a,q:b} = ... */ +#define JS_HAS_GENERATOR_EXPRS 1 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_EXPR_CLOSURES 1 /* has function (formals) listexpr */ + +#else + +#error "unknown JS_VERSION" + +#endif + +/* Features that are present in all versions. */ +#define JS_HAS_RESERVED_JAVA_KEYWORDS 1 +#define JS_HAS_RESERVED_ECMA_KEYWORDS 1 + +/* Feature-test macro for evolving destructuring support. */ +#define JS_HAS_DESTRUCTURING_SHORTHAND (JS_HAS_DESTRUCTURING == 2) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxdrapi.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxdrapi.cpp new file mode 100644 index 0000000..5643e73 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxdrapi.cpp @@ -0,0 +1,800 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "jsstddef.h" +#include "jsversion.h" + +#if JS_HAS_XDR + +#include +#include "jstypes.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jsdhash.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jscntxt.h" +#include "jsnum.h" +#include "jsobj.h" /* js_XDRObject */ +#include "jsscript.h" /* js_XDRScript */ +#include "jsstr.h" +#include "jsxdrapi.h" + +#ifdef DEBUG +#define DBG(x) x +#else +#define DBG(x) ((void)0) +#endif + +typedef struct JSXDRMemState { + JSXDRState state; + char *base; + uint32 count; + uint32 limit; +} JSXDRMemState; + +#define MEM_BLOCK 8192 +#define MEM_PRIV(xdr) ((JSXDRMemState *)(xdr)) + +#define MEM_BASE(xdr) (MEM_PRIV(xdr)->base) +#define MEM_COUNT(xdr) (MEM_PRIV(xdr)->count) +#define MEM_LIMIT(xdr) (MEM_PRIV(xdr)->limit) + +#define MEM_LEFT(xdr, bytes) \ + JS_BEGIN_MACRO \ + if ((xdr)->mode == JSXDR_DECODE && \ + MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \ + JS_ReportErrorNumber((xdr)->cx, js_GetErrorMessage, NULL, \ + JSMSG_END_OF_DATA); \ + return 0; \ + } \ + JS_END_MACRO + +#define MEM_NEED(xdr, bytes) \ + JS_BEGIN_MACRO \ + if ((xdr)->mode == JSXDR_ENCODE) { \ + if (MEM_LIMIT(xdr) && \ + MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \ + uint32 limit_ = JS_ROUNDUP(MEM_COUNT(xdr) + bytes, MEM_BLOCK);\ + void *data_ = JS_realloc((xdr)->cx, MEM_BASE(xdr), limit_); \ + if (!data_) \ + return 0; \ + MEM_BASE(xdr) = (char *) data_; \ + MEM_LIMIT(xdr) = limit_; \ + } \ + } else { \ + MEM_LEFT(xdr, bytes); \ + } \ + JS_END_MACRO + +#define MEM_DATA(xdr) ((void *)(MEM_BASE(xdr) + MEM_COUNT(xdr))) +#define MEM_INCR(xdr,bytes) (MEM_COUNT(xdr) += (bytes)) + +static JSBool +mem_get32(JSXDRState *xdr, uint32 *lp) +{ + MEM_LEFT(xdr, 4); + *lp = *(uint32 *)MEM_DATA(xdr); + MEM_INCR(xdr, 4); + return JS_TRUE; +} + +static JSBool +mem_set32(JSXDRState *xdr, uint32 *lp) +{ + MEM_NEED(xdr, 4); + *(uint32 *)MEM_DATA(xdr) = *lp; + MEM_INCR(xdr, 4); + return JS_TRUE; +} + +static JSBool +mem_getbytes(JSXDRState *xdr, char *bytes, uint32 len) +{ + MEM_LEFT(xdr, len); + memcpy(bytes, MEM_DATA(xdr), len); + MEM_INCR(xdr, len); + return JS_TRUE; +} + +static JSBool +mem_setbytes(JSXDRState *xdr, char *bytes, uint32 len) +{ + MEM_NEED(xdr, len); + memcpy(MEM_DATA(xdr), bytes, len); + MEM_INCR(xdr, len); + return JS_TRUE; +} + +static void * +mem_raw(JSXDRState *xdr, uint32 len) +{ + void *data; + if (xdr->mode == JSXDR_ENCODE) { + MEM_NEED(xdr, len); + } else if (xdr->mode == JSXDR_DECODE) { + MEM_LEFT(xdr, len); + } + data = MEM_DATA(xdr); + MEM_INCR(xdr, len); + return data; +} + +static JSBool +mem_seek(JSXDRState *xdr, int32 offset, JSXDRWhence whence) +{ + switch (whence) { + case JSXDR_SEEK_CUR: + if ((int32)MEM_COUNT(xdr) + offset < 0) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_SEEK_BEYOND_START); + return JS_FALSE; + } + if (offset > 0) + MEM_NEED(xdr, offset); + MEM_COUNT(xdr) += offset; + return JS_TRUE; + case JSXDR_SEEK_SET: + if (offset < 0) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_SEEK_BEYOND_START); + return JS_FALSE; + } + if (xdr->mode == JSXDR_ENCODE) { + if ((uint32)offset > MEM_COUNT(xdr)) + MEM_NEED(xdr, offset - MEM_COUNT(xdr)); + MEM_COUNT(xdr) = offset; + } else { + if ((uint32)offset > MEM_LIMIT(xdr)) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_SEEK_BEYOND_END); + return JS_FALSE; + } + MEM_COUNT(xdr) = offset; + } + return JS_TRUE; + case JSXDR_SEEK_END: + if (offset >= 0 || + xdr->mode == JSXDR_ENCODE || + (int32)MEM_LIMIT(xdr) + offset < 0) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_END_SEEK); + return JS_FALSE; + } + MEM_COUNT(xdr) = MEM_LIMIT(xdr) + offset; + return JS_TRUE; + default: { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%d", whence); + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_WHITHER_WHENCE, numBuf); + return JS_FALSE; + } + } +} + +static uint32 +mem_tell(JSXDRState *xdr) +{ + return MEM_COUNT(xdr); +} + +static void +mem_finalize(JSXDRState *xdr) +{ + JS_free(xdr->cx, MEM_BASE(xdr)); +} + +static JSXDROps xdrmem_ops = { + mem_get32, mem_set32, mem_getbytes, mem_setbytes, + mem_raw, mem_seek, mem_tell, mem_finalize +}; + +JS_PUBLIC_API(void) +JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx) +{ + xdr->mode = mode; + xdr->cx = cx; + xdr->registry = NULL; + xdr->numclasses = xdr->maxclasses = 0; + xdr->reghash = NULL; + xdr->userdata = NULL; + xdr->script = NULL; +} + +JS_PUBLIC_API(JSXDRState *) +JS_XDRNewMem(JSContext *cx, JSXDRMode mode) +{ + JSXDRState *xdr = (JSXDRState *) JS_malloc(cx, sizeof(JSXDRMemState)); + if (!xdr) + return NULL; + JS_XDRInitBase(xdr, mode, cx); + if (mode == JSXDR_ENCODE) { + if (!(MEM_BASE(xdr) = (char *) JS_malloc(cx, MEM_BLOCK))) { + JS_free(cx, xdr); + return NULL; + } + } else { + /* XXXbe ok, so better not deref MEM_BASE(xdr) if not ENCODE */ + MEM_BASE(xdr) = NULL; + } + xdr->ops = &xdrmem_ops; + MEM_COUNT(xdr) = 0; + MEM_LIMIT(xdr) = MEM_BLOCK; + return xdr; +} + +JS_PUBLIC_API(void *) +JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp) +{ + if (xdr->ops != &xdrmem_ops) + return NULL; + *lp = MEM_COUNT(xdr); + return MEM_BASE(xdr); +} + +JS_PUBLIC_API(void) +JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len) +{ + if (xdr->ops != &xdrmem_ops) + return; + MEM_LIMIT(xdr) = len; + MEM_BASE(xdr) = (char *) data; + MEM_COUNT(xdr) = 0; +} + +JS_PUBLIC_API(uint32) +JS_XDRMemDataLeft(JSXDRState *xdr) +{ + if (xdr->ops != &xdrmem_ops) + return 0; + return MEM_LIMIT(xdr) - MEM_COUNT(xdr); +} + +JS_PUBLIC_API(void) +JS_XDRMemResetData(JSXDRState *xdr) +{ + if (xdr->ops != &xdrmem_ops) + return; + MEM_COUNT(xdr) = 0; +} + +JS_PUBLIC_API(void) +JS_XDRDestroy(JSXDRState *xdr) +{ + JSContext *cx = xdr->cx; + xdr->ops->finalize(xdr); + if (xdr->registry) { + JS_free(cx, xdr->registry); + if (xdr->reghash) + JS_DHashTableDestroy((JSDHashTable *) xdr->reghash); + } + JS_free(cx, xdr); +} + +JS_PUBLIC_API(JSBool) +JS_XDRUint8(JSXDRState *xdr, uint8 *b) +{ + uint32 l = *b; + if (!JS_XDRUint32(xdr, &l)) + return JS_FALSE; + *b = (uint8) l; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRUint16(JSXDRState *xdr, uint16 *s) +{ + uint32 l = *s; + if (!JS_XDRUint32(xdr, &l)) + return JS_FALSE; + *s = (uint16) l; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRUint32(JSXDRState *xdr, uint32 *lp) +{ + JSBool ok = JS_TRUE; + if (xdr->mode == JSXDR_ENCODE) { + uint32 xl = JSXDR_SWAB32(*lp); + ok = xdr->ops->set32(xdr, &xl); + } else if (xdr->mode == JSXDR_DECODE) { + ok = xdr->ops->get32(xdr, lp); + *lp = JSXDR_SWAB32(*lp); + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32 len) +{ + uint32 padlen; + static char padbuf[JSXDR_ALIGN-1]; + + if (xdr->mode == JSXDR_ENCODE) { + if (!xdr->ops->setbytes(xdr, bytes, len)) + return JS_FALSE; + } else { + if (!xdr->ops->getbytes(xdr, bytes, len)) + return JS_FALSE; + } + len = xdr->ops->tell(xdr); + if (len % JSXDR_ALIGN) { + padlen = JSXDR_ALIGN - (len % JSXDR_ALIGN); + if (xdr->mode == JSXDR_ENCODE) { + if (!xdr->ops->setbytes(xdr, padbuf, padlen)) + return JS_FALSE; + } else { + if (!xdr->ops->seek(xdr, padlen, JSXDR_SEEK_CUR)) + return JS_FALSE; + } + } + return JS_TRUE; +} + +/** + * Convert between a C string and the XDR representation: + * leading 32-bit count, then counted vector of chars, + * then possibly \0 padding to multiple of 4. + */ +JS_PUBLIC_API(JSBool) +JS_XDRCString(JSXDRState *xdr, char **sp) +{ + uint32 len; + + if (xdr->mode == JSXDR_ENCODE) + len = strlen(*sp); + JS_XDRUint32(xdr, &len); + if (xdr->mode == JSXDR_DECODE) { + if (!(*sp = (char *) JS_malloc(xdr->cx, len + 1))) + return JS_FALSE; + } + if (!JS_XDRBytes(xdr, *sp, len)) { + if (xdr->mode == JSXDR_DECODE) + JS_free(xdr->cx, *sp); + return JS_FALSE; + } + if (xdr->mode == JSXDR_DECODE) { + (*sp)[len] = '\0'; + } else if (xdr->mode == JSXDR_FREE) { + JS_free(xdr->cx, *sp); + *sp = NULL; + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRCStringOrNull(JSXDRState *xdr, char **sp) +{ + uint32 null = (*sp == NULL); + if (!JS_XDRUint32(xdr, &null)) + return JS_FALSE; + if (null) { + *sp = NULL; + return JS_TRUE; + } + return JS_XDRCString(xdr, sp); +} + +static JSBool +XDRChars(JSXDRState *xdr, jschar *chars, uint32 nchars) +{ + uint32 i, padlen, nbytes; + jschar *raw; + + nbytes = nchars * sizeof(jschar); + padlen = nbytes % JSXDR_ALIGN; + if (padlen) { + padlen = JSXDR_ALIGN - padlen; + nbytes += padlen; + } + if (!(raw = (jschar *) xdr->ops->raw(xdr, nbytes))) + return JS_FALSE; + if (xdr->mode == JSXDR_ENCODE) { + for (i = 0; i != nchars; i++) + raw[i] = JSXDR_SWAB16(chars[i]); + if (padlen) + memset((char *)raw + nbytes - padlen, 0, padlen); + } else if (xdr->mode == JSXDR_DECODE) { + for (i = 0; i != nchars; i++) + chars[i] = JSXDR_SWAB16(raw[i]); + } + return JS_TRUE; +} + +/* + * Convert between a JS (Unicode) string and the XDR representation. + */ +JS_PUBLIC_API(JSBool) +JS_XDRString(JSXDRState *xdr, JSString **strp) +{ + uint32 nchars; + jschar *chars; + + if (xdr->mode == JSXDR_ENCODE) + nchars = JSSTRING_LENGTH(*strp); + if (!JS_XDRUint32(xdr, &nchars)) + return JS_FALSE; + + if (xdr->mode == JSXDR_DECODE) { + chars = (jschar *) JS_malloc(xdr->cx, (nchars + 1) * sizeof(jschar)); + if (!chars) + return JS_FALSE; + } else { + chars = JSSTRING_CHARS(*strp); + } + + if (!XDRChars(xdr, chars, nchars)) + goto bad; + if (xdr->mode == JSXDR_DECODE) { + chars[nchars] = 0; + *strp = JS_NewUCString(xdr->cx, chars, nchars); + if (!*strp) + goto bad; + } + return JS_TRUE; + +bad: + if (xdr->mode == JSXDR_DECODE) + JS_free(xdr->cx, chars); + return JS_FALSE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp) +{ + uint32 null = (*strp == NULL); + if (!JS_XDRUint32(xdr, &null)) + return JS_FALSE; + if (null) { + *strp = NULL; + return JS_TRUE; + } + return JS_XDRString(xdr, strp); +} + +static JSBool +XDRDoubleValue(JSXDRState *xdr, jsdouble *dp) +{ + jsdpun u; + + if (xdr->mode == JSXDR_ENCODE) + u.d = *dp; + if (!JS_XDRUint32(xdr, &u.s.lo) || !JS_XDRUint32(xdr, &u.s.hi)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *dp = u.d; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRDouble(JSXDRState *xdr, jsdouble **dpp) +{ + jsdouble d; + + if (xdr->mode == JSXDR_ENCODE) + d = **dpp; + if (!XDRDoubleValue(xdr, &d)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) { + *dpp = JS_NewDouble(xdr->cx, d); + if (!*dpp) + return JS_FALSE; + } + return JS_TRUE; +} + +/* These are magic pseudo-tags: see jsapi.h, near the top, for real tags. */ +#define JSVAL_XDRNULL 0x8 +#define JSVAL_XDRVOID 0xA + +static JSBool +XDRValueBody(JSXDRState *xdr, uint32 type, jsval *vp) +{ + switch (type) { + case JSVAL_XDRNULL: + *vp = JSVAL_NULL; + break; + case JSVAL_XDRVOID: + *vp = JSVAL_VOID; + break; + case JSVAL_STRING: { + JSString *str; + if (xdr->mode == JSXDR_ENCODE) + str = JSVAL_TO_STRING(*vp); + if (!JS_XDRString(xdr, &str)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = STRING_TO_JSVAL(str); + break; + } + case JSVAL_DOUBLE: { + jsdouble *dp; + if (xdr->mode == JSXDR_ENCODE) + dp = JSVAL_TO_DOUBLE(*vp); + if (!JS_XDRDouble(xdr, &dp)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = DOUBLE_TO_JSVAL(dp); + break; + } + case JSVAL_OBJECT: { + JSObject *obj; + if (xdr->mode == JSXDR_ENCODE) + obj = JSVAL_TO_OBJECT(*vp); + if (!js_XDRObject(xdr, &obj)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = OBJECT_TO_JSVAL(obj); + break; + } + case JSVAL_BOOLEAN: { + uint32 b; + if (xdr->mode == JSXDR_ENCODE) + b = (uint32) JSVAL_TO_BOOLEAN(*vp); + if (!JS_XDRUint32(xdr, &b)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = BOOLEAN_TO_JSVAL(!!b); + break; + } + default: { + uint32 i; + + JS_ASSERT(type & JSVAL_INT); + if (xdr->mode == JSXDR_ENCODE) + i = (uint32) JSVAL_TO_INT(*vp); + if (!JS_XDRUint32(xdr, &i)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = INT_TO_JSVAL((int32) i); + break; + } + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRValue(JSXDRState *xdr, jsval *vp) +{ + uint32 type; + + if (xdr->mode == JSXDR_ENCODE) { + if (JSVAL_IS_NULL(*vp)) + type = JSVAL_XDRNULL; + else if (JSVAL_IS_VOID(*vp)) + type = JSVAL_XDRVOID; + else + type = JSVAL_TAG(*vp); + } + return JS_XDRUint32(xdr, &type) && XDRValueBody(xdr, type, vp); +} + +JSBool +js_XDRAtom(JSXDRState *xdr, JSAtom **atomp) +{ + jsval v; + uint32 type; + jsdouble d; + + if (xdr->mode == JSXDR_ENCODE) { + v = ATOM_KEY(*atomp); + return JS_XDRValue(xdr, &v); + } + + /* + * Inline JS_XDRValue when decoding to avoid ceation of GC things when + * then corresponding atom already exists. See bug 321985. + */ + if (!JS_XDRUint32(xdr, &type)) + return JS_FALSE; + if (type == JSVAL_STRING) + return js_XDRStringAtom(xdr, atomp); + + if (type == JSVAL_DOUBLE) { + if (!XDRDoubleValue(xdr, &d)) + return JS_FALSE; + *atomp = js_AtomizeDouble(xdr->cx, d); + return *atomp != NULL; + } + + return XDRValueBody(xdr, type, &v) && + js_AtomizePrimitiveValue(xdr->cx, v, atomp); +} + +extern JSBool +js_XDRStringAtom(JSXDRState *xdr, JSAtom **atomp) +{ + JSString *str; + uint32 nchars; + JSAtom *atom; + JSContext *cx; + jschar *chars; + jschar stackChars[256]; + + if (xdr->mode == JSXDR_ENCODE) { + JS_ASSERT(ATOM_IS_STRING(*atomp)); + str = ATOM_TO_STRING(*atomp); + return JS_XDRString(xdr, &str); + } + + /* + * Inline JS_XDRString when decoding to avoid JSString allocation + * for already existing atoms. See bug 321985. + */ + if (!JS_XDRUint32(xdr, &nchars)) + return JS_FALSE; + atom = NULL; + cx = xdr->cx; + if (nchars <= JS_ARRAY_LENGTH(stackChars)) { + chars = stackChars; + } else { + /* + * This is very uncommon. Don't use the tempPool arena for this as + * most allocations here will be bigger than tempPool's arenasize. + */ + chars = (jschar *) JS_malloc(cx, nchars * sizeof(jschar)); + if (!chars) + return JS_FALSE; + } + + if (XDRChars(xdr, chars, nchars)) + atom = js_AtomizeChars(cx, chars, nchars, 0); + if (chars != stackChars) + JS_free(cx, chars); + + if (!atom) + return JS_FALSE; + *atomp = atom; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRScript(JSXDRState *xdr, JSScript **scriptp) +{ + if (!js_XDRScript(xdr, scriptp, NULL)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + js_CallNewScriptHook(xdr->cx, *scriptp, NULL); + return JS_TRUE; +} + +#define CLASS_REGISTRY_MIN 8 +#define CLASS_INDEX_TO_ID(i) ((i)+1) +#define CLASS_ID_TO_INDEX(id) ((id)-1) + +typedef struct JSRegHashEntry { + JSDHashEntryHdr hdr; + const char *name; + uint32 index; +} JSRegHashEntry; + +JS_PUBLIC_API(JSBool) +JS_XDRRegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *idp) +{ + uintN numclasses, maxclasses; + JSClass **registry; + + numclasses = xdr->numclasses; + maxclasses = xdr->maxclasses; + if (numclasses == maxclasses) { + maxclasses = (maxclasses == 0) ? CLASS_REGISTRY_MIN : maxclasses << 1; + registry = (JSClass **) + JS_realloc(xdr->cx, xdr->registry, maxclasses * sizeof(JSClass *)); + if (!registry) + return JS_FALSE; + xdr->registry = registry; + xdr->maxclasses = maxclasses; + } else { + JS_ASSERT(numclasses && numclasses < maxclasses); + registry = xdr->registry; + } + + registry[numclasses] = clasp; + if (xdr->reghash) { + JSRegHashEntry *entry = (JSRegHashEntry *) + JS_DHashTableOperate((JSDHashTable *) xdr->reghash, + clasp->name, JS_DHASH_ADD); + if (!entry) { + JS_ReportOutOfMemory(xdr->cx); + return JS_FALSE; + } + entry->name = clasp->name; + entry->index = numclasses; + } + *idp = CLASS_INDEX_TO_ID(numclasses); + xdr->numclasses = ++numclasses; + return JS_TRUE; +} + +JS_PUBLIC_API(uint32) +JS_XDRFindClassIdByName(JSXDRState *xdr, const char *name) +{ + uintN i, numclasses; + + numclasses = xdr->numclasses; + if (numclasses >= 10) { + JSRegHashEntry *entry; + + /* Bootstrap reghash from registry on first overpopulated Find. */ + if (!xdr->reghash) { + xdr->reghash = + JS_NewDHashTable(JS_DHashGetStubOps(), NULL, + sizeof(JSRegHashEntry), + JS_DHASH_DEFAULT_CAPACITY(numclasses)); + if (xdr->reghash) { + for (i = 0; i < numclasses; i++) { + JSClass *clasp = xdr->registry[i]; + entry = (JSRegHashEntry *) + JS_DHashTableOperate((JSDHashTable *) xdr->reghash, + clasp->name, JS_DHASH_ADD); + entry->name = clasp->name; + entry->index = i; + } + } + } + + /* If we managed to create reghash, use it for O(1) Find. */ + if (xdr->reghash) { + entry = (JSRegHashEntry *) + JS_DHashTableOperate((JSDHashTable *) xdr->reghash, + name, JS_DHASH_LOOKUP); + if (JS_DHASH_ENTRY_IS_BUSY(&entry->hdr)) + return CLASS_INDEX_TO_ID(entry->index); + } + } + + /* Only a few classes, or we couldn't malloc reghash: use linear search. */ + for (i = 0; i < numclasses; i++) { + if (!strcmp(name, xdr->registry[i]->name)) + return CLASS_INDEX_TO_ID(i); + } + return 0; +} + +JS_PUBLIC_API(JSClass *) +JS_XDRFindClassById(JSXDRState *xdr, uint32 id) +{ + uintN i = CLASS_ID_TO_INDEX(id); + + if (i >= xdr->numclasses) + return NULL; + return xdr->registry[i]; +} + +#endif /* JS_HAS_XDR */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxdrapi.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxdrapi.h new file mode 100644 index 0000000..23b2636 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxdrapi.h @@ -0,0 +1,220 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsxdrapi_h___ +#define jsxdrapi_h___ + +/* + * JS external data representation interface API. + * + * The XDR system is comprised of three major parts: + * + * - the state serialization/deserialization APIs, which allow consumers + * of the API to serialize JS runtime state (script bytecodes, atom maps, + * object graphs, etc.) for later restoration. These portions + * are implemented in various appropriate files, such as jsscript.c + * for the script portions and jsobj.c for object state. + * - the callback APIs through which the runtime requests an opaque + * representation of a native object, and through which the runtime + * constructs a live native object from an opaque representation. These + * portions are the responsibility of the native object implementor. + * - utility functions for en/decoding of primitive types, such as + * JSStrings. This portion is implemented in jsxdrapi.c. + * + * Spiritually guided by Sun's XDR, where appropriate. + */ + +#include "jspubtd.h" +#include "jsprvtd.h" + +JS_BEGIN_EXTERN_C + +/* We use little-endian byteorder for all encoded data */ + +#if defined IS_LITTLE_ENDIAN +#define JSXDR_SWAB32(x) x +#define JSXDR_SWAB16(x) x +#elif defined IS_BIG_ENDIAN +#define JSXDR_SWAB32(x) (((uint32)(x) >> 24) | \ + (((uint32)(x) >> 8) & 0xff00) | \ + (((uint32)(x) << 8) & 0xff0000) | \ + ((uint32)(x) << 24)) +#define JSXDR_SWAB16(x) (((uint16)(x) >> 8) | ((uint16)(x) << 8)) +#else +#error "unknown byte order" +#endif + +#define JSXDR_ALIGN 4 + +typedef enum JSXDRMode { + JSXDR_ENCODE, + JSXDR_DECODE, + JSXDR_FREE +} JSXDRMode; + +typedef enum JSXDRWhence { + JSXDR_SEEK_SET, + JSXDR_SEEK_CUR, + JSXDR_SEEK_END +} JSXDRWhence; + +typedef struct JSXDROps { + JSBool (*get32)(JSXDRState *, uint32 *); + JSBool (*set32)(JSXDRState *, uint32 *); + JSBool (*getbytes)(JSXDRState *, char *, uint32); + JSBool (*setbytes)(JSXDRState *, char *, uint32); + void * (*raw)(JSXDRState *, uint32); + JSBool (*seek)(JSXDRState *, int32, JSXDRWhence); + uint32 (*tell)(JSXDRState *); + void (*finalize)(JSXDRState *); +} JSXDROps; + +struct JSXDRState { + JSXDRMode mode; + JSXDROps *ops; + JSContext *cx; + JSClass **registry; + uintN numclasses; + uintN maxclasses; + void *reghash; + void *userdata; + JSScript *script; +}; + +extern JS_PUBLIC_API(void) +JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx); + +extern JS_PUBLIC_API(JSXDRState *) +JS_XDRNewMem(JSContext *cx, JSXDRMode mode); + +extern JS_PUBLIC_API(void *) +JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp); + +extern JS_PUBLIC_API(void) +JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len); + +extern JS_PUBLIC_API(uint32) +JS_XDRMemDataLeft(JSXDRState *xdr); + +extern JS_PUBLIC_API(void) +JS_XDRMemResetData(JSXDRState *xdr); + +extern JS_PUBLIC_API(void) +JS_XDRDestroy(JSXDRState *xdr); + +extern JS_PUBLIC_API(JSBool) +JS_XDRUint8(JSXDRState *xdr, uint8 *b); + +extern JS_PUBLIC_API(JSBool) +JS_XDRUint16(JSXDRState *xdr, uint16 *s); + +extern JS_PUBLIC_API(JSBool) +JS_XDRUint32(JSXDRState *xdr, uint32 *lp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32 len); + +extern JS_PUBLIC_API(JSBool) +JS_XDRCString(JSXDRState *xdr, char **sp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRCStringOrNull(JSXDRState *xdr, char **sp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRString(JSXDRState *xdr, JSString **strp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRDouble(JSXDRState *xdr, jsdouble **dp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRValue(JSXDRState *xdr, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRScript(JSXDRState *xdr, JSScript **scriptp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRRegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *lp); + +extern JS_PUBLIC_API(uint32) +JS_XDRFindClassIdByName(JSXDRState *xdr, const char *name); + +extern JS_PUBLIC_API(JSClass *) +JS_XDRFindClassById(JSXDRState *xdr, uint32 id); + +/* + * Magic numbers. + */ +#define JSXDR_MAGIC_SCRIPT_1 0xdead0001 +#define JSXDR_MAGIC_SCRIPT_2 0xdead0002 +#define JSXDR_MAGIC_SCRIPT_3 0xdead0003 +#define JSXDR_MAGIC_SCRIPT_4 0xdead0004 +#define JSXDR_MAGIC_SCRIPT_5 0xdead0005 +#define JSXDR_MAGIC_SCRIPT_6 0xdead0006 +#define JSXDR_MAGIC_SCRIPT_7 0xdead0007 +#define JSXDR_MAGIC_SCRIPT_8 0xdead0008 +#define JSXDR_MAGIC_SCRIPT_9 0xdead0009 +#define JSXDR_MAGIC_SCRIPT_CURRENT JSXDR_MAGIC_SCRIPT_9 + +/* + * Bytecode version number. Increment the subtrahend whenever JS bytecode + * changes incompatibly. + * + * This version number should be XDR'ed once near the front of any file or + * larger storage unit containing XDR'ed bytecode and other data, and checked + * before deserialization of bytecode. If the saved version does not match + * the current version, abort deserialization and invalidate the file. + */ +#define JSXDR_BYTECODE_VERSION (0xb973c0de - 37) + +/* + * Library-private functions. + */ +extern JSBool +js_XDRAtom(JSXDRState *xdr, JSAtom **atomp); + +extern JSBool +js_XDRStringAtom(JSXDRState *xdr, JSAtom **atomp); + +JS_END_EXTERN_C + +#endif /* ! jsxdrapi_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxml.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxml.cpp new file mode 100644 index 0000000..b909219 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxml.cpp @@ -0,0 +1,8343 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey E4X code, released August, 2004. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsstddef.h" +#include "jsversion.h" + +#if JS_HAS_XML_SUPPORT + +#include +#include +#include +#include "jstypes.h" +#include "jsbit.h" +#include "jsprf.h" +#include "jsutil.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsxml.h" +#include "jsstaticcheck.h" + +#ifdef DEBUG +#include /* for #ifdef DEBUG memset calls */ +#endif + +/* + * NOTES + * - in the js shell, you must use the -x command line option, or call + * options('xml') before compiling anything that uses XML literals + * + * TODO + * - XXXbe patrol + * - Fuse objects and their JSXML* private data into single GC-things + * - fix function::foo vs. x.(foo == 42) collision using proper namespacing + * - fix the !TCF_HAS_DEFXMLNS optimization in js_FoldConstants + * - JSCLASS_DOCUMENT_OBSERVER support -- live two-way binding to Gecko's DOM! + * - JS_TypeOfValue sure could use a cleaner interface to "types" + */ + +#ifdef XML_METERING +static struct { + jsrefcount qname; + jsrefcount xmlnamespace; + jsrefcount xml; + jsrefcount xmlobj; +} xml_stats; + +#define METER(x) JS_ATOMIC_INCREMENT(&(x)) +#define UNMETER(x) JS_ATOMIC_DECREMENT(&(x)) +#else +#define METER(x) /* nothing */ +#define UNMETER(x) /* nothing */ +#endif + +/* + * Random utilities and global functions. + */ +const char js_isXMLName_str[] = "isXMLName"; +const char js_XMLList_str[] = "XMLList"; +const char js_localName_str[] = "localName"; +const char js_xml_parent_str[] = "parent"; +const char js_prefix_str[] = "prefix"; +const char js_toXMLString_str[] = "toXMLString"; +const char js_uri_str[] = "uri"; + +const char js_amp_entity_str[] = "&"; +const char js_gt_entity_str[] = ">"; +const char js_lt_entity_str[] = "<"; +const char js_quot_entity_str[] = """; + +#define IS_EMPTY(str) (JSSTRING_LENGTH(str) == 0) +#define IS_STAR(str) (JSSTRING_LENGTH(str) == 1 && *JSSTRING_CHARS(str) == '*') +/* Slot indexes shared between Namespace and QName objects. */ +const uint32 JSSLOT_PREFIX = JSSLOT_PRIVATE; +const uint32 JSSLOT_URI = JSSLOT_PRIVATE + 1; + +/* Namespace-specific slot. */ +const uint32 JSSLOT_DECLARED = JSSLOT_PRIVATE + 2; + +/* QName-specific slot. */ +const uint32 JSSLOT_LOCAL_NAME = JSSLOT_PRIVATE + 2; + +const uint32 NAMESPACE_RESERVED_SLOTS = 3; +const uint32 QNAME_RESERVED_SLOTS = 3; + +static JSBool +IsQNameClass(JSClass *clasp) +{ + return clasp == &js_QNameClass.base || + clasp == &js_AttributeNameClass || + clasp == &js_AnyNameClass; +} + +static JSString * +GetSlotString(const JSObject *obj, uint32 slot) +{ + jsval v; + + JS_ASSERT(slot == JSSLOT_PREFIX || + slot == JSSLOT_URI || + slot == JSSLOT_LOCAL_NAME); + JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_NamespaceClass.base || + IsQNameClass(STOBJ_GET_CLASS(obj))); + JS_ASSERT_IF(STOBJ_GET_CLASS(obj) == &js_NamespaceClass.base, + slot != JSSLOT_LOCAL_NAME); + + v = obj->fslots[slot]; + if (JSVAL_IS_VOID(v)) + return NULL; + JS_ASSERT(JSVAL_IS_STRING(v)); + return JSVAL_TO_STRING(v); +} + +static JS_INLINE JSString * +GetPrefix(const JSObject *obj) +{ + return GetSlotString(obj, JSSLOT_PREFIX); +} + +static JSString * +GetURI(const JSObject *obj) +{ + return GetSlotString(obj, JSSLOT_URI); +} + +static JSString * +GetLocalName(const JSObject *obj) +{ + return GetSlotString(obj, JSSLOT_LOCAL_NAME); +} + +static JSBool +IsDeclared(const JSObject *obj) +{ + jsval v; + + JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_NamespaceClass.base); + v = obj->fslots[JSSLOT_DECLARED]; + JS_ASSERT(JSVAL_IS_VOID(v) || v == JSVAL_TRUE); + return v == JSVAL_TRUE; +} + +static JSBool +xml_isXMLName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + *rval = BOOLEAN_TO_JSVAL(js_IsXMLName(cx, argv[0])); + return JS_TRUE; +} + +/* + * Namespace class and library functions. + */ +enum namespace_tinyid { + NAMESPACE_PREFIX = -1, + NAMESPACE_URI = -2 +}; + +static JSBool +namespace_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + + if (STOBJ_GET_CLASS(obj) != &js_NamespaceClass.base) + return JS_TRUE; + + switch (JSVAL_TO_INT(id)) { + case NAMESPACE_PREFIX: + *vp = obj->fslots[JSSLOT_PREFIX]; + break; + case NAMESPACE_URI: + *vp = obj->fslots[JSSLOT_URI]; + break; + } + return JS_TRUE; +} + +static void +namespace_finalize(JSContext *cx, JSObject *obj) +{ + if (cx->runtime->functionNamespaceObject == obj) + cx->runtime->functionNamespaceObject = NULL; +} + +static JSBool +namespace_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +{ + JSObject *obj2; + + JS_ASSERT(JSVAL_IS_OBJECT(v)); + obj2 = JSVAL_TO_OBJECT(v); + *bp = (!obj2 || OBJ_GET_CLASS(cx, obj2) != &js_NamespaceClass.base) + ? JS_FALSE + : js_EqualStrings(GetURI(obj), GetURI(obj2)); + return JS_TRUE; +} + +JS_FRIEND_DATA(JSExtendedClass) js_NamespaceClass = { + { "Namespace", + JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED | + JSCLASS_HAS_RESERVED_SLOTS(NAMESPACE_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Namespace), + JS_PropertyStub, JS_PropertyStub, namespace_getProperty, NULL, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, namespace_finalize, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }, + namespace_equality,NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +#define NAMESPACE_ATTRS \ + (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED) + +static JSPropertySpec namespace_props[] = { + {js_prefix_str, NAMESPACE_PREFIX, NAMESPACE_ATTRS, 0, 0}, + {js_uri_str, NAMESPACE_URI, NAMESPACE_ATTRS, 0, 0}, + {0,0,0,0,0} +}; + +static JSBool +namespace_toString(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_NamespaceClass.base, vp)) + return JS_FALSE; + *vp = obj->fslots[JSSLOT_URI]; + return JS_TRUE; +} + +static JSFunctionSpec namespace_methods[] = { + JS_FN(js_toString_str, namespace_toString, 0,0), + JS_FS_END +}; + +static JSObject * +NewXMLNamespace(JSContext *cx, JSString *prefix, JSString *uri, JSBool declared) +{ + JSObject *obj; + + obj = js_NewObject(cx, &js_NamespaceClass.base, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_VOID(obj->fslots[JSSLOT_PREFIX])); + JS_ASSERT(JSVAL_IS_VOID(obj->fslots[JSSLOT_URI])); + JS_ASSERT(JSVAL_IS_VOID(obj->fslots[JSSLOT_DECLARED])); + if (prefix) + obj->fslots[JSSLOT_PREFIX] = STRING_TO_JSVAL(prefix); + if (uri) + obj->fslots[JSSLOT_URI] = STRING_TO_JSVAL(uri); + if (declared) + obj->fslots[JSSLOT_DECLARED] = JSVAL_TRUE; + METER(xml_stats.xmlnamespace); + return obj; +} + +/* + * QName class and library functions. + */ +enum qname_tinyid { + QNAME_URI = -1, + QNAME_LOCALNAME = -2 +}; + +static JSBool +qname_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + if (!JSVAL_IS_INT(id)) + return JS_TRUE; + + if (STOBJ_GET_CLASS(obj) != &js_QNameClass.base) + return JS_TRUE; + + switch (JSVAL_TO_INT(id)) { + case QNAME_URI: + *vp = obj->fslots[JSSLOT_URI]; + if (*vp == JSVAL_VOID) + *vp = JSVAL_NULL; + break; + case QNAME_LOCALNAME: + *vp = obj->fslots[JSSLOT_LOCAL_NAME]; + break; + } + return JS_TRUE; +} + +static void +anyname_finalize(JSContext* cx, JSObject* obj) +{ + /* Make sure the next call to js_GetAnyName doesn't try to use obj. */ + if (cx->runtime->anynameObject == obj) + cx->runtime->anynameObject = NULL; +} + +static JSBool +qname_identity(JSObject *qna, JSObject *qnb) +{ + JSString *uri1 = GetURI(qna); + JSString *uri2 = GetURI(qnb); + + if (!uri1 ^ !uri2) + return JS_FALSE; + if (uri1 && !js_EqualStrings(uri1, uri2)) + return JS_FALSE; + return js_EqualStrings(GetLocalName(qna), GetLocalName(qnb)); +} + +static JSBool +qname_equality(JSContext *cx, JSObject *qn, jsval v, JSBool *bp) +{ + JSObject *obj2; + + JS_ASSERT(JSVAL_IS_OBJECT(v)); + obj2 = JSVAL_TO_OBJECT(v); + *bp = (!obj2 || OBJ_GET_CLASS(cx, obj2) != &js_QNameClass.base) + ? JS_FALSE + : qname_identity(qn, obj2); + return JS_TRUE; +} + +JS_FRIEND_DATA(JSExtendedClass) js_QNameClass = { + { "QName", + JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED | + JSCLASS_HAS_RESERVED_SLOTS(QNAME_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_QName), + JS_PropertyStub, JS_PropertyStub, qname_getProperty, NULL, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }, + qname_equality, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +/* + * Classes for the ECMA-357-internal types AttributeName and AnyName, which + * are like QName, except that they have no property getters. They share the + * qname_toString method, and therefore are exposed as constructable objects + * in this implementation. + */ +JS_FRIEND_DATA(JSClass) js_AttributeNameClass = { + js_AttributeName_str, + JSCLASS_CONSTRUCT_PROTOTYPE | + JSCLASS_HAS_RESERVED_SLOTS(QNAME_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_AttributeName), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +JS_FRIEND_DATA(JSClass) js_AnyNameClass = { + js_AnyName_str, + JSCLASS_CONSTRUCT_PROTOTYPE | + JSCLASS_HAS_RESERVED_SLOTS(QNAME_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_AnyName), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, anyname_finalize, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +#define QNAME_ATTRS \ + (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED) + +static JSPropertySpec qname_props[] = { + {js_uri_str, QNAME_URI, QNAME_ATTRS, 0, 0}, + {js_localName_str, QNAME_LOCALNAME, QNAME_ATTRS, 0, 0}, + {0,0,0,0,0} +}; + +static JSBool +qname_toString(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + JSClass *clasp; + JSString *uri, *str, *qualstr; + size_t length; + jschar *chars; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + clasp = OBJ_GET_CLASS(cx, obj); + if (clasp != &js_AttributeNameClass && + clasp != &js_AnyNameClass && + !JS_InstanceOf(cx, obj, &js_QNameClass.base, vp + 2)) { + return JS_FALSE; + } + + uri = GetURI(obj); + if (!uri) { + /* No uri means wildcard qualifier. */ + str = ATOM_TO_STRING(cx->runtime->atomState.starQualifierAtom); + } else if (IS_EMPTY(uri)) { + /* Empty string for uri means localName is in no namespace. */ + str = cx->runtime->emptyString; + } else { + qualstr = ATOM_TO_STRING(cx->runtime->atomState.qualifierAtom); + str = js_ConcatStrings(cx, uri, qualstr); + if (!str) + return JS_FALSE; + } + str = js_ConcatStrings(cx, str, GetLocalName(obj)); + if (!str) + return JS_FALSE; + + if (str && clasp == &js_AttributeNameClass) { + length = JSSTRING_LENGTH(str); + chars = (jschar *) JS_malloc(cx, (length + 2) * sizeof(jschar)); + if (!chars) + return JS_FALSE; + *chars = '@'; + js_strncpy(chars + 1, JSSTRING_CHARS(str), length); + chars[++length] = 0; + str = js_NewString(cx, chars, length); + if (!str) { + JS_free(cx, chars); + return JS_FALSE; + } + } + + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSFunctionSpec qname_methods[] = { + JS_FN(js_toString_str, qname_toString, 0,0), + JS_FS_END +}; + + +static void +InitXMLQName(JSObject *obj, JSString *uri, JSString *prefix, + JSString *localName) +{ + JS_ASSERT(JSVAL_IS_VOID(obj->fslots[JSSLOT_PREFIX])); + JS_ASSERT(JSVAL_IS_VOID(obj->fslots[JSSLOT_URI])); + JS_ASSERT(JSVAL_IS_VOID(obj->fslots[JSSLOT_LOCAL_NAME])); + if (uri) + obj->fslots[JSSLOT_URI] = STRING_TO_JSVAL(uri); + if (prefix) + obj->fslots[JSSLOT_PREFIX] = STRING_TO_JSVAL(prefix); + if (localName) + obj->fslots[JSSLOT_LOCAL_NAME] = STRING_TO_JSVAL(localName); +} + +static JSObject * +NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix, JSString *localName, + JSClass *clasp = &js_QNameClass.base) +{ + JSObject *obj; + + JS_ASSERT(IsQNameClass(clasp)); + obj = js_NewObject(cx, clasp, NULL, NULL, 0); + if (!obj) + return NULL; + InitXMLQName(obj, uri, prefix, localName); + METER(xml_stats.qname); + return obj; +} + +JSObject * +js_ConstructXMLQNameObject(JSContext *cx, jsval nsval, jsval lnval) +{ + jsval argv[2]; + + /* + * ECMA-357 11.1.2, + * The _QualifiedIdentifier : PropertySelector :: PropertySelector_ + * production, step 2. + */ + if (!JSVAL_IS_PRIMITIVE(nsval) && + OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(nsval)) == &js_AnyNameClass) { + nsval = JSVAL_NULL; + } + + argv[0] = nsval; + argv[1] = lnval; + return js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, argv); +} + +static JSBool +IsXMLName(const jschar *cp, size_t n) +{ + JSBool rv; + jschar c; + + rv = JS_FALSE; + if (n != 0 && JS_ISXMLNSSTART(*cp)) { + while (--n != 0) { + c = *++cp; + if (!JS_ISXMLNS(c)) + return rv; + } + rv = JS_TRUE; + } + return rv; +} + +JSBool +js_IsXMLName(JSContext *cx, jsval v) +{ + JSString *name; + JSErrorReporter older; + + /* + * Inline specialization of the QName constructor called with v passed as + * the only argument, to compute the localName for the constructed qname, + * without actually allocating the object or computing its uri and prefix. + * See ECMA-357 13.1.2.1 step 1 and 13.3.2. + */ + if (!JSVAL_IS_PRIMITIVE(v) && + IsQNameClass(OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)))) { + name = GetLocalName(JSVAL_TO_OBJECT(v)); + } else { + older = JS_SetErrorReporter(cx, NULL); + name = js_ValueToString(cx, v); + JS_SetErrorReporter(cx, older); + if (!name) { + JS_ClearPendingException(cx); + return JS_FALSE; + } + } + + return IsXMLName(JSSTRING_CHARS(name), JSSTRING_LENGTH(name)); +} + +/* + * When argc is -1, it indicates argv is empty but the code should behave as + * if argc is 1 and argv[0] is JSVAL_VOID. + */ +static JSBool +NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, + jsval *rval) +{ + jsval urival, prefixval; + JSObject *uriobj; + JSBool isNamespace, isQName; + JSClass *clasp; + JSString *empty, *uri, *prefix; + + isNamespace = isQName = JS_FALSE; +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + uriobj = NULL; +#endif + if (argc <= 0) { + urival = JSVAL_VOID; + } else { + urival = argv[argc > 1]; + if (!JSVAL_IS_PRIMITIVE(urival)) { + uriobj = JSVAL_TO_OBJECT(urival); + clasp = OBJ_GET_CLASS(cx, uriobj); + isNamespace = (clasp == &js_NamespaceClass.base); + isQName = (clasp == &js_QNameClass.base); + } + } + + if (!obj) { + /* Namespace called as function. */ + if (argc == 1 && isNamespace) { + /* Namespace called with one Namespace argument is identity. */ + *rval = urival; + return JS_TRUE; + } + + obj = js_NewObject(cx, &js_NamespaceClass.base, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(obj); + } + METER(xml_stats.xmlnamespace); + + empty = cx->runtime->emptyString; + obj->fslots[JSSLOT_PREFIX] = STRING_TO_JSVAL(empty); + obj->fslots[JSSLOT_URI] = STRING_TO_JSVAL(empty); + + if (argc == 1 || argc == -1) { + if (isNamespace) { + obj->fslots[JSSLOT_URI] = uriobj->fslots[JSSLOT_URI]; + obj->fslots[JSSLOT_PREFIX] = uriobj->fslots[JSSLOT_PREFIX]; + } else if (isQName && (uri = GetURI(uriobj))) { + obj->fslots[JSSLOT_URI] = STRING_TO_JSVAL(uri); + obj->fslots[JSSLOT_PREFIX] = uriobj->fslots[JSSLOT_PREFIX]; + } else { + uri = js_ValueToString(cx, urival); + if (!uri) + return JS_FALSE; + obj->fslots[JSSLOT_URI] = STRING_TO_JSVAL(uri); + if (!IS_EMPTY(uri)) + obj->fslots[JSSLOT_PREFIX] = JSVAL_VOID; + } + } else if (argc == 2) { + if (!isQName || !(uri = GetURI(uriobj))) { + uri = js_ValueToString(cx, urival); + if (!uri) + return JS_FALSE; + } + obj->fslots[JSSLOT_URI] = STRING_TO_JSVAL(uri); + + prefixval = argv[0]; + if (IS_EMPTY(uri)) { + if (!JSVAL_IS_VOID(prefixval)) { + prefix = js_ValueToString(cx, prefixval); + if (!prefix) + return JS_FALSE; + if (!IS_EMPTY(prefix)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_XML_NAMESPACE, + js_ValueToPrintableString(cx, + STRING_TO_JSVAL(prefix))); + return JS_FALSE; + } + } + } else if (JSVAL_IS_VOID(prefixval) || !js_IsXMLName(cx, prefixval)) { + obj->fslots[JSSLOT_PREFIX] = JSVAL_VOID; + } else { + prefix = js_ValueToString(cx, prefixval); + if (!prefix) + return JS_FALSE; + obj->fslots[JSSLOT_PREFIX] = STRING_TO_JSVAL(prefix); + } + } + + return JS_TRUE; +} + +static JSBool +Namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return NamespaceHelper(cx, + (cx->fp->flags & JSFRAME_CONSTRUCTING) ? obj : NULL, + argc, argv, rval); +} + +/* + * When argc is -1, it indicates argv is empty but the code should behave as + * if argc is 1 and argv[0] is JSVAL_VOID. + */ +static JSBool +QNameHelper(JSContext *cx, JSObject *obj, JSClass *clasp, intN argc, + jsval *argv, jsval *rval) +{ + jsval nameval, nsval; + JSBool isQName, isNamespace; + JSObject *qn; + JSString *uri, *prefix, *name; + JSObject *obj2; + + JS_ASSERT(clasp == &js_QNameClass.base || + clasp == &js_AttributeNameClass); + if (argc <= 0) { + nameval = JSVAL_VOID; + isQName = JS_FALSE; + } else { + nameval = argv[argc > 1]; + isQName = + !JSVAL_IS_PRIMITIVE(nameval) && + OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(nameval)) == &js_QNameClass.base; + } + + if (!obj) { + /* QName called as function. */ + if (argc == 1 && isQName) { + /* QName called with one QName argument is identity. */ + *rval = nameval; + return JS_TRUE; + } + + /* + * Create and return a new QName or AttributeName object exactly as if + * constructed. + */ + obj = js_NewObject(cx, clasp, NULL, NULL, 0); + if (!obj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(obj); + } + METER(xml_stats.qname); + + if (isQName) { + /* If namespace is not specified and name is a QName, clone it. */ + qn = JSVAL_TO_OBJECT(nameval); + if (argc == 1) { + uri = GetURI(qn); + prefix = GetPrefix(qn); + name = GetLocalName(qn); + goto out; + } + + /* Namespace and qname were passed -- use the qname's localName. */ + nameval = qn->fslots[JSSLOT_LOCAL_NAME]; + } + + if (argc == 0) { + name = cx->runtime->emptyString; + } else if (argc < 0) { + name = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } else { + name = js_ValueToString(cx, nameval); + if (!name) + return JS_FALSE; + argv[argc > 1] = STRING_TO_JSVAL(name); + } + + if (argc > 1 && !JSVAL_IS_VOID(argv[0])) { + nsval = argv[0]; + } else if (IS_STAR(name)) { + nsval = JSVAL_NULL; + } else { + if (!js_GetDefaultXMLNamespace(cx, &nsval)) + return JS_FALSE; + JS_ASSERT(!JSVAL_IS_PRIMITIVE(nsval)); + JS_ASSERT(OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(nsval)) == + &js_NamespaceClass.base); + } + + if (JSVAL_IS_NULL(nsval)) { + /* NULL prefix represents *undefined* in ECMA-357 13.3.2 5(a). */ + uri = prefix = NULL; + } else { + /* + * Inline specialization of the Namespace constructor called with + * nsval passed as the only argument, to compute the uri and prefix + * for the constructed namespace, without actually allocating the + * object or computing other members. See ECMA-357 13.3.2 6(a) and + * 13.2.2. + */ + isNamespace = isQName = JS_FALSE; + if (!JSVAL_IS_PRIMITIVE(nsval)) { + obj2 = JSVAL_TO_OBJECT(nsval); + clasp = OBJ_GET_CLASS(cx, obj2); + isNamespace = (clasp == &js_NamespaceClass.base); + isQName = (clasp == &js_QNameClass.base); + } +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + else obj2 = NULL; +#endif + + if (isNamespace) { + uri = GetURI(obj2); + prefix = GetPrefix(obj2); + } else if (isQName && (uri = GetURI(obj2))) { + JS_ASSERT(argc > 1); + prefix = GetPrefix(obj2); + } else { + JS_ASSERT(argc > 1); + uri = js_ValueToString(cx, nsval); + if (!uri) + return JS_FALSE; + argv[0] = STRING_TO_JSVAL(uri); /* local root */ + + /* NULL here represents *undefined* in ECMA-357 13.2.2 3(c)iii. */ + prefix = IS_EMPTY(uri) ? cx->runtime->emptyString : NULL; + } + } + +out: + InitXMLQName(obj, uri, prefix, name); + return JS_TRUE; +} + +static JSBool +QName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return QNameHelper(cx, (cx->fp->flags & JSFRAME_CONSTRUCTING) ? obj : NULL, + &js_QNameClass.base, argc, argv, rval); +} + +static JSBool +AttributeName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + return QNameHelper(cx, (cx->fp->flags & JSFRAME_CONSTRUCTING) ? obj : NULL, + &js_AttributeNameClass, argc, argv, rval); +} + +/* + * XMLArray library functions. + */ +static JSBool +namespace_identity(const void *a, const void *b) +{ + const JSObject *nsa = (const JSObject *) a; + const JSObject *nsb = (const JSObject *) b; + JSString *prefixa = GetPrefix(nsa); + JSString *prefixb = GetPrefix(nsb); + + if (prefixa && prefixb) { + if (!js_EqualStrings(prefixa, prefixb)) + return JS_FALSE; + } else { + if (prefixa || prefixb) + return JS_FALSE; + } + return js_EqualStrings(GetURI(nsa), GetURI(nsb)); +} + +static JSBool +attr_identity(const void *a, const void *b) +{ + const JSXML *xmla = (const JSXML *) a; + const JSXML *xmlb = (const JSXML *) b; + + return qname_identity(xmla->name, xmlb->name); +} + +static void +XMLArrayCursorInit(JSXMLArrayCursor *cursor, JSXMLArray *array) +{ + JSXMLArrayCursor *next; + + cursor->array = array; + cursor->index = 0; + next = cursor->next = array->cursors; + if (next) + next->prevp = &cursor->next; + cursor->prevp = &array->cursors; + array->cursors = cursor; + cursor->root = NULL; +} + +static void +XMLArrayCursorFinish(JSXMLArrayCursor *cursor) +{ + JSXMLArrayCursor *next; + + if (!cursor->array) + return; + next = cursor->next; + if (next) + next->prevp = cursor->prevp; + *cursor->prevp = next; + cursor->array = NULL; +} + +static void * +XMLArrayCursorNext(JSXMLArrayCursor *cursor) +{ + JSXMLArray *array; + + array = cursor->array; + if (!array || cursor->index >= array->length) + return NULL; + return cursor->root = array->vector[cursor->index++]; +} + +static void * +XMLArrayCursorItem(JSXMLArrayCursor *cursor) +{ + JSXMLArray *array; + + array = cursor->array; + if (!array || cursor->index >= array->length) + return NULL; + return cursor->root = array->vector[cursor->index]; +} + +static void +XMLArrayCursorTrace(JSTracer *trc, JSXMLArrayCursor *cursor) +{ + void *root; +#ifdef DEBUG + size_t index = 0; +#endif + + for (; cursor; cursor = cursor->next) { + root = cursor->root; + JS_SET_TRACING_INDEX(trc, "cursor_root", index++); + js_CallValueTracerIfGCThing(trc, (jsval)root); + } +} + +/* NB: called with null cx from the GC, via xml_trace => XMLArrayTrim. */ +static JSBool +XMLArraySetCapacity(JSContext *cx, JSXMLArray *array, uint32 capacity) +{ + void **vector; + + if (capacity == 0) { + /* We could let realloc(p, 0) free this, but purify gets confused. */ + if (array->vector) + free(array->vector); + vector = NULL; + } else { + if ( +#if JS_BITS_PER_WORD == 32 + (size_t)capacity > ~(size_t)0 / sizeof(void *) || +#endif + !(vector = (void **) + realloc(array->vector, capacity * sizeof(void *)))) { + if (cx) + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + } + array->capacity = JSXML_PRESET_CAPACITY | capacity; + array->vector = vector; + return JS_TRUE; +} + +static void +XMLArrayTrim(JSXMLArray *array) +{ + if (array->capacity & JSXML_PRESET_CAPACITY) + return; + if (array->length < array->capacity) + XMLArraySetCapacity(NULL, array, array->length); +} + +static JSBool +XMLArrayInit(JSContext *cx, JSXMLArray *array, uint32 capacity) +{ + array->length = array->capacity = 0; + array->vector = NULL; + array->cursors = NULL; + return capacity == 0 || XMLArraySetCapacity(cx, array, capacity); +} + +static void +XMLArrayFinish(JSContext *cx, JSXMLArray *array) +{ + JSXMLArrayCursor *cursor; + + JS_free(cx, array->vector); + + while ((cursor = array->cursors) != NULL) + XMLArrayCursorFinish(cursor); + +#ifdef DEBUG + memset(array, 0xd5, sizeof *array); +#endif +} + +#define XML_NOT_FOUND ((uint32) -1) + +static uint32 +XMLArrayFindMember(const JSXMLArray *array, void *elt, JSIdentityOp identity) +{ + void **vector; + uint32 i, n; + + /* The identity op must not reallocate array->vector. */ + vector = array->vector; + if (identity) { + for (i = 0, n = array->length; i < n; i++) { + if (identity(vector[i], elt)) + return i; + } + } else { + for (i = 0, n = array->length; i < n; i++) { + if (vector[i] == elt) + return i; + } + } + return XML_NOT_FOUND; +} + +/* + * Grow array vector capacity by powers of two to LINEAR_THRESHOLD, and after + * that, grow by LINEAR_INCREMENT. Both must be powers of two, and threshold + * should be greater than increment. + */ +#define LINEAR_THRESHOLD 256 +#define LINEAR_INCREMENT 32 + +static JSBool +XMLArrayAddMember(JSContext *cx, JSXMLArray *array, uint32 index, void *elt) +{ + uint32 capacity, i; + int log2; + void **vector; + + if (index >= array->length) { + if (index >= JSXML_CAPACITY(array)) { + /* Arrange to clear JSXML_PRESET_CAPACITY from array->capacity. */ + capacity = index + 1; + if (index >= LINEAR_THRESHOLD) { + capacity = JS_ROUNDUP(capacity, LINEAR_INCREMENT); + } else { + JS_CEILING_LOG2(log2, capacity); + capacity = JS_BIT(log2); + } + if ( +#if JS_BITS_PER_WORD == 32 + (size_t)capacity > ~(size_t)0 / sizeof(void *) || +#endif + !(vector = (void **) + realloc(array->vector, capacity * sizeof(void *)))) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + array->capacity = capacity; + array->vector = vector; + for (i = array->length; i < index; i++) + vector[i] = NULL; + } + array->length = index + 1; + } + + array->vector[index] = elt; + return JS_TRUE; +} + +static JSBool +XMLArrayInsert(JSContext *cx, JSXMLArray *array, uint32 i, uint32 n) +{ + uint32 j; + JSXMLArrayCursor *cursor; + + j = array->length; + JS_ASSERT(i <= j); + if (!XMLArraySetCapacity(cx, array, j + n)) + return JS_FALSE; + + array->length = j + n; + JS_ASSERT(n != (uint32)-1); + while (j != i) { + --j; + array->vector[j + n] = array->vector[j]; + } + + for (cursor = array->cursors; cursor; cursor = cursor->next) { + if (cursor->index > i) + cursor->index += n; + } + return JS_TRUE; +} + +static void * +XMLArrayDelete(JSContext *cx, JSXMLArray *array, uint32 index, JSBool compress) +{ + uint32 length; + void **vector, *elt; + JSXMLArrayCursor *cursor; + + length = array->length; + if (index >= length) + return NULL; + + vector = array->vector; + elt = vector[index]; + if (compress) { + while (++index < length) + vector[index-1] = vector[index]; + array->length = length - 1; + array->capacity = JSXML_CAPACITY(array); + } else { + vector[index] = NULL; + } + + for (cursor = array->cursors; cursor; cursor = cursor->next) { + if (cursor->index > index) + --cursor->index; + } + return elt; +} + +static void +XMLArrayTruncate(JSContext *cx, JSXMLArray *array, uint32 length) +{ + void **vector; + + JS_ASSERT(!array->cursors); + if (length >= array->length) + return; + + if (length == 0) { + if (array->vector) + free(array->vector); + vector = NULL; + } else { + vector = (void **) realloc(array->vector, length * sizeof(void *)); + if (!vector) + return; + } + + if (array->length > length) + array->length = length; + array->capacity = length; + array->vector = vector; +} + +#define XMLARRAY_FIND_MEMBER(a,e,f) XMLArrayFindMember(a, (void *)(e), f) +#define XMLARRAY_HAS_MEMBER(a,e,f) (XMLArrayFindMember(a, (void *)(e), f) != \ + XML_NOT_FOUND) +#define XMLARRAY_MEMBER(a,i,t) (((i) < (a)->length) \ + ? (t *) (a)->vector[i] \ + : NULL) +#define XMLARRAY_SET_MEMBER(a,i,e) JS_BEGIN_MACRO \ + if ((a)->length <= (i)) \ + (a)->length = (i) + 1; \ + ((a)->vector[i] = (void *)(e)); \ + JS_END_MACRO +#define XMLARRAY_ADD_MEMBER(x,a,i,e)XMLArrayAddMember(x, a, i, (void *)(e)) +#define XMLARRAY_INSERT(x,a,i,n) XMLArrayInsert(x, a, i, n) +#define XMLARRAY_APPEND(x,a,e) XMLARRAY_ADD_MEMBER(x, a, (a)->length, (e)) +#define XMLARRAY_DELETE(x,a,i,c,t) ((t *) XMLArrayDelete(x, a, i, c)) +#define XMLARRAY_TRUNCATE(x,a,n) XMLArrayTruncate(x, a, n) + +/* + * Define XML setting property strings and constants early, so everyone can + * use the same names and their magic numbers (tinyids, flags). + */ +static const char js_ignoreComments_str[] = "ignoreComments"; +static const char js_ignoreProcessingInstructions_str[] + = "ignoreProcessingInstructions"; +static const char js_ignoreWhitespace_str[] = "ignoreWhitespace"; +static const char js_prettyPrinting_str[] = "prettyPrinting"; +static const char js_prettyIndent_str[] = "prettyIndent"; + +/* + * NB: These XML static property tinyids must + * (a) not collide with the generic negative tinyids at the top of jsfun.c; + * (b) index their corresponding xml_static_props array elements. + * Don't change 'em! + */ +enum xml_static_tinyid { + XML_IGNORE_COMMENTS, + XML_IGNORE_PROCESSING_INSTRUCTIONS, + XML_IGNORE_WHITESPACE, + XML_PRETTY_PRINTING, + XML_PRETTY_INDENT +}; + +static JSBool +xml_setting_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + return JS_TRUE; +} + +static JSBool +xml_setting_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + uint8 flag; + + JS_ASSERT(JSVAL_IS_INT(id)); + + flag = JS_BIT(JSVAL_TO_INT(id)); + if (js_ValueToBoolean(*vp)) + cx->xmlSettingFlags |= flag; + else + cx->xmlSettingFlags &= ~flag; + return JS_TRUE; +} + +static JSPropertySpec xml_static_props[] = { + {js_ignoreComments_str, XML_IGNORE_COMMENTS, JSPROP_PERMANENT, + xml_setting_getter, xml_setting_setter}, + {js_ignoreProcessingInstructions_str, + XML_IGNORE_PROCESSING_INSTRUCTIONS, JSPROP_PERMANENT, + xml_setting_getter, xml_setting_setter}, + {js_ignoreWhitespace_str, XML_IGNORE_WHITESPACE, JSPROP_PERMANENT, + xml_setting_getter, xml_setting_setter}, + {js_prettyPrinting_str, XML_PRETTY_PRINTING, JSPROP_PERMANENT, + xml_setting_getter, xml_setting_setter}, + {js_prettyIndent_str, XML_PRETTY_INDENT, JSPROP_PERMANENT, + xml_setting_getter, NULL}, + {0,0,0,0,0} +}; + +/* Derive cx->xmlSettingFlags bits from xml_static_props tinyids. */ +#define XSF_IGNORE_COMMENTS JS_BIT(XML_IGNORE_COMMENTS) +#define XSF_IGNORE_PROCESSING_INSTRUCTIONS \ + JS_BIT(XML_IGNORE_PROCESSING_INSTRUCTIONS) +#define XSF_IGNORE_WHITESPACE JS_BIT(XML_IGNORE_WHITESPACE) +#define XSF_PRETTY_PRINTING JS_BIT(XML_PRETTY_PRINTING) +#define XSF_CACHE_VALID JS_BIT(XML_PRETTY_INDENT) + +/* + * Extra, unrelated but necessarily disjoint flag used by ParseNodeToXML. + * This flag means a couple of things: + * + * - The top JSXML created for a parse tree must have an object owning it. + * + * - That the default namespace normally inherited from the temporary + * tag that wraps a runtime-concatenated XML source + * string must, in the case of a precompiled XML object tree, inherit via + * ad-hoc code in ParseNodeToXML. + * + * Because of the second purpose, we name this flag XSF_PRECOMPILED_ROOT. + */ +#define XSF_PRECOMPILED_ROOT (XSF_CACHE_VALID << 1) + +/* Macros for special-casing xml:, xmlns= and xmlns:foo= in ParseNodeToQName. */ +#define IS_XML(str) \ + (JSSTRING_LENGTH(str) == 3 && IS_XML_CHARS(JSSTRING_CHARS(str))) + +#define IS_XMLNS(str) \ + (JSSTRING_LENGTH(str) == 5 && IS_XMLNS_CHARS(JSSTRING_CHARS(str))) + +#define IS_XML_CHARS(chars) \ + (JS_TOLOWER((chars)[0]) == 'x' && \ + JS_TOLOWER((chars)[1]) == 'm' && \ + JS_TOLOWER((chars)[2]) == 'l') + +#define HAS_NS_AFTER_XML(chars) \ + (JS_TOLOWER((chars)[3]) == 'n' && \ + JS_TOLOWER((chars)[4]) == 's') + +#define IS_XMLNS_CHARS(chars) \ + (IS_XML_CHARS(chars) && HAS_NS_AFTER_XML(chars)) + +#define STARTS_WITH_XML(chars,length) \ + (length >= 3 && IS_XML_CHARS(chars)) + +static const char xml_namespace_str[] = "http://www.w3.org/XML/1998/namespace"; +static const char xmlns_namespace_str[] = "http://www.w3.org/2000/xmlns/"; + +static JSObject * +ParseNodeToQName(JSContext *cx, JSParseContext *pc, JSParseNode *pn, + JSXMLArray *inScopeNSes, JSBool isAttributeName) +{ + JSString *str, *uri, *prefix, *localName; + size_t length, offset; + const jschar *start, *limit, *colon; + uint32 n; + JSObject *ns; + JSString *nsprefix; + + JS_ASSERT(pn->pn_arity == PN_NULLARY); + str = ATOM_TO_STRING(pn->pn_atom); + JSSTRING_CHARS_AND_LENGTH(str, start, length); + JS_ASSERT(length != 0 && *start != '@'); + JS_ASSERT(length != 1 || *start != '*'); + + uri = cx->runtime->emptyString; + limit = start + length; + colon = js_strchr_limit(start, ':', limit); + if (colon) { + offset = PTRDIFF(colon, start, jschar); + prefix = js_NewDependentString(cx, str, 0, offset); + if (!prefix) + return NULL; + + if (STARTS_WITH_XML(start, offset)) { + if (offset == 3) { + uri = JS_InternString(cx, xml_namespace_str); + if (!uri) + return NULL; + } else if (offset == 5 && HAS_NS_AFTER_XML(start)) { + uri = JS_InternString(cx, xmlns_namespace_str); + if (!uri) + return NULL; + } else { + uri = NULL; + } + } else { + uri = NULL; + n = inScopeNSes->length; + while (n != 0) { + --n; + ns = XMLARRAY_MEMBER(inScopeNSes, n, JSObject); + nsprefix = GetPrefix(ns); + if (nsprefix && js_EqualStrings(nsprefix, prefix)) { + uri = GetURI(ns); + break; + } + } + } + + if (!uri) { + js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn, + JSREPORT_ERROR, + JSMSG_BAD_XML_NAMESPACE, + js_ValueToPrintableString(cx, + STRING_TO_JSVAL(prefix))); + return NULL; + } + + localName = js_NewStringCopyN(cx, colon + 1, length - (offset + 1)); + if (!localName) + return NULL; + } else { + if (isAttributeName) { + /* + * An unprefixed attribute is not in any namespace, so set prefix + * as well as uri to the empty string. + */ + prefix = uri; + } else { + /* + * Loop from back to front looking for the closest declared default + * namespace. + */ + n = inScopeNSes->length; + while (n != 0) { + --n; + ns = XMLARRAY_MEMBER(inScopeNSes, n, JSObject); + nsprefix = GetPrefix(ns); + if (!nsprefix || IS_EMPTY(nsprefix)) { + uri = GetURI(ns); + break; + } + } + prefix = IS_EMPTY(uri) ? cx->runtime->emptyString : NULL; + } + localName = str; + } + + return NewXMLQName(cx, uri, prefix, localName); +} + +static JSString * +ChompXMLWhitespace(JSContext *cx, JSString *str) +{ + size_t length, newlength, offset; + const jschar *cp, *start, *end; + jschar c; + + JSSTRING_CHARS_AND_LENGTH(str, start, length); + for (cp = start, end = cp + length; cp < end; cp++) { + c = *cp; + if (!JS_ISXMLSPACE(c)) + break; + } + while (end > cp) { + c = end[-1]; + if (!JS_ISXMLSPACE(c)) + break; + --end; + } + newlength = PTRDIFF(end, cp, jschar); + if (newlength == length) + return str; + offset = PTRDIFF(cp, start, jschar); + return js_NewDependentString(cx, str, offset, newlength); +} + +static JSXML * +ParseNodeToXML(JSContext *cx, JSParseContext *pc, JSParseNode *pn, + JSXMLArray *inScopeNSes, uintN flags) +{ + JSXML *xml, *kid, *attr, *attrj; + JSString *str; + uint32 length, n, i, j; + JSParseNode *pn2, *pn3, *head, **pnp; + JSObject *ns; + JSObject *qn, *attrjqn; + JSXMLClass xml_class; + int stackDummy; + + if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { + js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn, JSREPORT_ERROR, + JSMSG_OVER_RECURSED); + return NULL; + } + +#define PN2X_SKIP_CHILD ((JSXML *) 1) + + /* + * Cases return early to avoid common code that gets an outermost xml's + * object, which protects GC-things owned by xml and its descendants from + * garbage collection. + */ + xml = NULL; + if (!js_EnterLocalRootScope(cx)) + return NULL; + switch (pn->pn_type) { + case TOK_XMLELEM: + length = inScopeNSes->length; + pn2 = pn->pn_head; + xml = ParseNodeToXML(cx, pc, pn2, inScopeNSes, flags); + if (!xml) + goto fail; + + flags &= ~XSF_PRECOMPILED_ROOT; + n = pn->pn_count; + JS_ASSERT(n >= 2); + n -= 2; + if (!XMLArraySetCapacity(cx, &xml->xml_kids, n)) + goto fail; + + i = 0; + while ((pn2 = pn2->pn_next) != NULL) { + if (!pn2->pn_next) { + /* Don't append the end tag! */ + JS_ASSERT(pn2->pn_type == TOK_XMLETAGO); + break; + } + + if ((flags & XSF_IGNORE_WHITESPACE) && + n > 1 && pn2->pn_type == TOK_XMLSPACE) { + --n; + continue; + } + + kid = ParseNodeToXML(cx, pc, pn2, inScopeNSes, flags); + if (kid == PN2X_SKIP_CHILD) { + --n; + continue; + } + + if (!kid) + goto fail; + + /* Store kid in xml right away, to protect it from GC. */ + XMLARRAY_SET_MEMBER(&xml->xml_kids, i, kid); + kid->parent = xml; + ++i; + + /* XXX where is this documented in an XML spec, or in E4X? */ + if ((flags & XSF_IGNORE_WHITESPACE) && + n > 1 && kid->xml_class == JSXML_CLASS_TEXT) { + str = ChompXMLWhitespace(cx, kid->xml_value); + if (!str) + goto fail; + kid->xml_value = str; + } + } + + JS_ASSERT(i == n); + if (n < pn->pn_count - 2) + XMLArrayTrim(&xml->xml_kids); + XMLARRAY_TRUNCATE(cx, inScopeNSes, length); + break; + + case TOK_XMLLIST: + xml = js_NewXML(cx, JSXML_CLASS_LIST); + if (!xml) + goto fail; + + n = pn->pn_count; + if (!XMLArraySetCapacity(cx, &xml->xml_kids, n)) + goto fail; + + i = 0; + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + /* + * Always ignore insignificant whitespace in lists -- we shouldn't + * condition this on an XML.ignoreWhitespace setting when the list + * constructor is XMLList (note XML/XMLList unification hazard). + */ + if (pn2->pn_type == TOK_XMLSPACE) { + --n; + continue; + } + + kid = ParseNodeToXML(cx, pc, pn2, inScopeNSes, flags); + if (kid == PN2X_SKIP_CHILD) { + --n; + continue; + } + + if (!kid) + goto fail; + + XMLARRAY_SET_MEMBER(&xml->xml_kids, i, kid); + ++i; + } + + if (n < pn->pn_count) + XMLArrayTrim(&xml->xml_kids); + break; + + case TOK_XMLSTAGO: + case TOK_XMLPTAGC: + length = inScopeNSes->length; + pn2 = pn->pn_head; + JS_ASSERT(pn2->pn_type == TOK_XMLNAME); + if (pn2->pn_arity == PN_LIST) + goto syntax; + + xml = js_NewXML(cx, JSXML_CLASS_ELEMENT); + if (!xml) + goto fail; + + /* First pass: check syntax and process namespace declarations. */ + JS_ASSERT(pn->pn_count >= 1); + n = pn->pn_count - 1; + pnp = &pn2->pn_next; + head = *pnp; + while ((pn2 = *pnp) != NULL) { + size_t length; + const jschar *chars; + + if (pn2->pn_type != TOK_XMLNAME || pn2->pn_arity != PN_NULLARY) + goto syntax; + + /* Enforce "Well-formedness constraint: Unique Att Spec". */ + for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) { + if (pn3->pn_atom == pn2->pn_atom) { + js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn2, + JSREPORT_ERROR, + JSMSG_DUPLICATE_XML_ATTR, + js_ValueToPrintableString(cx, + ATOM_KEY(pn2->pn_atom))); + goto fail; + } + } + + str = ATOM_TO_STRING(pn2->pn_atom); + pn2 = pn2->pn_next; + JS_ASSERT(pn2); + if (pn2->pn_type != TOK_XMLATTR) + goto syntax; + + JSSTRING_CHARS_AND_LENGTH(str, chars, length); + if (length >= 5 && + IS_XMLNS_CHARS(chars) && + (length == 5 || chars[5] == ':')) { + JSString *uri, *prefix; + + uri = ATOM_TO_STRING(pn2->pn_atom); + if (length == 5) { + /* 10.3.2.1. Step 6(h)(i)(1)(a). */ + prefix = cx->runtime->emptyString; + } else { + prefix = js_NewStringCopyN(cx, chars + 6, length - 6); + if (!prefix) + goto fail; + } + + /* + * Once the new ns is appended to xml->xml_namespaces, it is + * protected from GC by the object that owns xml -- which is + * either xml->object if outermost, or the object owning xml's + * oldest ancestor if !outermost. + */ + ns = NewXMLNamespace(cx, prefix, uri, JS_TRUE); + if (!ns) + goto fail; + + /* + * Don't add a namespace that's already in scope. If someone + * extracts a child property from its parent via [[Get]], then + * we enforce the invariant, noted many times in ECMA-357, that + * the child's namespaces form a possibly-improper superset of + * its ancestors' namespaces. + */ + if (!XMLARRAY_HAS_MEMBER(inScopeNSes, ns, namespace_identity)) { + if (!XMLARRAY_APPEND(cx, inScopeNSes, ns) || + !XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) { + goto fail; + } + } + + JS_ASSERT(n >= 2); + n -= 2; + *pnp = pn2->pn_next; + /* XXXbe recycle pn2 */ + continue; + } + + pnp = &pn2->pn_next; + } + + /* + * If called from js_ParseNodeToXMLObject, emulate the effect of the + * ... wrapping done by "ToXML Applied to + * the String Type" (ECMA-357 10.3.1). + */ + if (flags & XSF_PRECOMPILED_ROOT) { + JS_ASSERT(length >= 1); + ns = XMLARRAY_MEMBER(inScopeNSes, 0, JSObject); + JS_ASSERT(!XMLARRAY_HAS_MEMBER(&xml->xml_namespaces, ns, + namespace_identity)); + ns = NewXMLNamespace(cx, GetPrefix(ns), GetURI(ns), JS_FALSE); + if (!ns) + goto fail; + if (!XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) + goto fail; + } + XMLArrayTrim(&xml->xml_namespaces); + + /* Second pass: process tag name and attributes, using namespaces. */ + pn2 = pn->pn_head; + qn = ParseNodeToQName(cx, pc, pn2, inScopeNSes, JS_FALSE); + if (!qn) + goto fail; + xml->name = qn; + + JS_ASSERT((n & 1) == 0); + n >>= 1; + if (!XMLArraySetCapacity(cx, &xml->xml_attrs, n)) + goto fail; + + for (i = 0; (pn2 = pn2->pn_next) != NULL; i++) { + qn = ParseNodeToQName(cx, pc, pn2, inScopeNSes, JS_TRUE); + if (!qn) { + xml->xml_attrs.length = i; + goto fail; + } + + /* + * Enforce "Well-formedness constraint: Unique Att Spec", part 2: + * this time checking local name and namespace URI. + */ + for (j = 0; j < i; j++) { + attrj = XMLARRAY_MEMBER(&xml->xml_attrs, j, JSXML); + attrjqn = attrj->name; + if (js_EqualStrings(GetURI(attrjqn), GetURI(qn)) && + js_EqualStrings(GetLocalName(attrjqn), GetLocalName(qn))) { + js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn2, + JSREPORT_ERROR, + JSMSG_DUPLICATE_XML_ATTR, + js_ValueToPrintableString(cx, + ATOM_KEY(pn2->pn_atom))); + goto fail; + } + } + + pn2 = pn2->pn_next; + JS_ASSERT(pn2); + JS_ASSERT(pn2->pn_type == TOK_XMLATTR); + + attr = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE); + if (!attr) + goto fail; + + XMLARRAY_SET_MEMBER(&xml->xml_attrs, i, attr); + attr->parent = xml; + attr->name = qn; + attr->xml_value = ATOM_TO_STRING(pn2->pn_atom); + } + + /* Point tag closes its own namespace scope. */ + if (pn->pn_type == TOK_XMLPTAGC) + XMLARRAY_TRUNCATE(cx, inScopeNSes, length); + break; + + case TOK_XMLSPACE: + case TOK_XMLTEXT: + case TOK_XMLCDATA: + case TOK_XMLCOMMENT: + case TOK_XMLPI: + str = ATOM_TO_STRING(pn->pn_atom); + qn = NULL; + if (pn->pn_type == TOK_XMLCOMMENT) { + if (flags & XSF_IGNORE_COMMENTS) + goto skip_child; + xml_class = JSXML_CLASS_COMMENT; + } else if (pn->pn_type == TOK_XMLPI) { + if (IS_XML(str)) { + js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn, + JSREPORT_ERROR, + JSMSG_RESERVED_ID, + js_ValueToPrintableString(cx, + STRING_TO_JSVAL(str))); + goto fail; + } + + if (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS) + goto skip_child; + + qn = ParseNodeToQName(cx, pc, pn, inScopeNSes, JS_FALSE); + if (!qn) + goto fail; + + str = pn->pn_atom2 + ? ATOM_TO_STRING(pn->pn_atom2) + : cx->runtime->emptyString; + xml_class = JSXML_CLASS_PROCESSING_INSTRUCTION; + } else { + /* CDATA section content, or element text. */ + xml_class = JSXML_CLASS_TEXT; + } + + xml = js_NewXML(cx, xml_class); + if (!xml) + goto fail; + xml->name = qn; + if (pn->pn_type == TOK_XMLSPACE) + xml->xml_flags |= XMLF_WHITESPACE_TEXT; + xml->xml_value = str; + break; + + default: + goto syntax; + } + + js_LeaveLocalRootScopeWithResult(cx, (jsval) xml); + if ((flags & XSF_PRECOMPILED_ROOT) && !js_GetXMLObject(cx, xml)) + return NULL; + return xml; + +skip_child: + js_LeaveLocalRootScope(cx); + return PN2X_SKIP_CHILD; + +#undef PN2X_SKIP_CHILD + +syntax: + js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn, JSREPORT_ERROR, + JSMSG_BAD_XML_MARKUP); +fail: + js_LeaveLocalRootScope(cx); + return NULL; +} + +/* + * XML helper, object-ops, and library functions. We start with the helpers, + * in ECMA-357 order, but merging XML (9.1) and XMLList (9.2) helpers. + */ +static JSBool +GetXMLSetting(JSContext *cx, const char *name, jsval *vp) +{ + jsval v; + + if (!js_FindClassObject(cx, NULL, INT_TO_JSID(JSProto_XML), &v)) + return JS_FALSE; + if (!VALUE_IS_FUNCTION(cx, v)) { + *vp = JSVAL_VOID; + return JS_TRUE; + } + return JS_GetProperty(cx, JSVAL_TO_OBJECT(v), name, vp); +} + +static JSBool +FillSettingsCache(JSContext *cx) +{ + int i; + const char *name; + jsval v; + + /* Note: XML_PRETTY_INDENT is not a boolean setting. */ + for (i = XML_IGNORE_COMMENTS; i < XML_PRETTY_INDENT; i++) { + name = xml_static_props[i].name; + if (!GetXMLSetting(cx, name, &v)) + return JS_FALSE; + if (js_ValueToBoolean(v)) + cx->xmlSettingFlags |= JS_BIT(i); + else + cx->xmlSettingFlags &= ~JS_BIT(i); + } + + cx->xmlSettingFlags |= XSF_CACHE_VALID; + return JS_TRUE; +} + +static JSBool +GetBooleanXMLSetting(JSContext *cx, const char *name, JSBool *bp) +{ + int i; + + if (!(cx->xmlSettingFlags & XSF_CACHE_VALID) && !FillSettingsCache(cx)) + return JS_FALSE; + + for (i = 0; xml_static_props[i].name; i++) { + if (!strcmp(xml_static_props[i].name, name)) { + *bp = (cx->xmlSettingFlags & JS_BIT(i)) != 0; + return JS_TRUE; + } + } + *bp = JS_FALSE; + return JS_TRUE; +} + +static JSBool +GetUint32XMLSetting(JSContext *cx, const char *name, uint32 *uip) +{ + jsval v; + + return GetXMLSetting(cx, name, &v) && JS_ValueToECMAUint32(cx, v, uip); +} + +static JSBool +GetXMLSettingFlags(JSContext *cx, uintN *flagsp) +{ + JSBool flag; + + /* Just get the first flag to validate the setting flags cache. */ + if (!GetBooleanXMLSetting(cx, js_ignoreComments_str, &flag)) + return JS_FALSE; + *flagsp = cx->xmlSettingFlags; + return JS_TRUE; +} + +static JSXML * +ParseXMLSource(JSContext *cx, JSString *src) +{ + jsval nsval; + JSString *uri; + size_t urilen, srclen, length, offset, dstlen; + jschar *chars; + const jschar *srcp, *endp; + JSXML *xml; + JSParseContext pc; + const char *filename; + uintN lineno; + JSStackFrame *fp; + JSOp op; + JSParseNode *pn; + JSXMLArray nsarray; + uintN flags; + + static const char prefix[] = ""; + static const char suffix[] = ""; + +#define constrlen(constr) (sizeof(constr) - 1) + + if (!js_GetDefaultXMLNamespace(cx, &nsval)) + return NULL; + uri = GetURI(JSVAL_TO_OBJECT(nsval)); + uri = js_EscapeAttributeValue(cx, uri, JS_FALSE); + + urilen = JSSTRING_LENGTH(uri); + srclen = JSSTRING_LENGTH(src); + length = constrlen(prefix) + urilen + constrlen(middle) + srclen + + constrlen(suffix); + + chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar)); + if (!chars) + return NULL; + + dstlen = length; + js_InflateStringToBuffer(cx, prefix, constrlen(prefix), chars, &dstlen); + offset = dstlen; + js_strncpy(chars + offset, JSSTRING_CHARS(uri), urilen); + offset += urilen; + dstlen = length - offset + 1; + js_InflateStringToBuffer(cx, middle, constrlen(middle), chars + offset, + &dstlen); + offset += dstlen; + srcp = JSSTRING_CHARS(src); + js_strncpy(chars + offset, srcp, srclen); + offset += srclen; + dstlen = length - offset + 1; + js_InflateStringToBuffer(cx, suffix, constrlen(suffix), chars + offset, + &dstlen); + chars [offset + dstlen] = 0; + + xml = NULL; + for (fp = cx->fp; fp && !fp->regs; fp = fp->down) + JS_ASSERT(!fp->script); + filename = NULL; + lineno = 1; + if (fp) { + op = (JSOp) *fp->regs->pc; + if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) { + filename = fp->script->filename; + lineno = js_FramePCToLineNumber(cx, fp); + for (endp = srcp + srclen; srcp < endp; srcp++) { + if (*srcp == '\n') + --lineno; + } + } + } + + if (!js_InitParseContext(cx, &pc, NULL, NULL, chars, length, NULL, + filename, lineno)) + goto out; + pn = js_ParseXMLText(cx, cx->fp->scopeChain, &pc, JS_FALSE); + if (pn && XMLArrayInit(cx, &nsarray, 1)) { + if (GetXMLSettingFlags(cx, &flags)) + xml = ParseNodeToXML(cx, &pc, pn, &nsarray, flags); + + XMLArrayFinish(cx, &nsarray); + } + js_FinishParseContext(cx, &pc); + +out: + JS_free(cx, chars); + return xml; + +#undef constrlen +} + +/* + * Errata in 10.3.1, 10.4.1, and 13.4.4.24 (at least). + * + * 10.3.1 Step 6(a) fails to NOTE that implementations that do not enforce + * the constraint: + * + * for all x belonging to XML: + * x.[[InScopeNamespaces]] >= x.[[Parent]].[[InScopeNamespaces]] + * + * must union x.[[InScopeNamespaces]] into x[0].[[InScopeNamespaces]] here + * (in new sub-step 6(a), renumbering the others to (b) and (c)). + * + * Same goes for 10.4.1 Step 7(a). + * + * In order for XML.prototype.namespaceDeclarations() to work correctly, the + * default namespace thereby unioned into x[0].[[InScopeNamespaces]] must be + * flagged as not declared, so that 13.4.4.24 Step 8(a) can exclude all such + * undeclared namespaces associated with x not belonging to ancestorNS. + */ +static JSXML * +OrphanXMLChild(JSContext *cx, JSXML *xml, uint32 i) +{ + JSObject *ns; + + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, 0, JSObject); + xml = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (!ns || !xml) + return xml; + if (xml->xml_class == JSXML_CLASS_ELEMENT) { + if (!XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) + return NULL; + ns->fslots[JSSLOT_DECLARED] = JSVAL_VOID; + } + xml->parent = NULL; + return xml; +} + +static JSObject * +ToXML(JSContext *cx, jsval v) +{ + JSObject *obj; + JSXML *xml; + JSClass *clasp; + JSString *str; + uint32 length; + + if (JSVAL_IS_PRIMITIVE(v)) { + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) + goto bad; + } else { + obj = JSVAL_TO_OBJECT(v); + if (OBJECT_IS_XML(cx, obj)) { + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (xml->xml_class == JSXML_CLASS_LIST) { + if (xml->xml_kids.length != 1) + goto bad; + xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (xml) { + JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); + return js_GetXMLObject(cx, xml); + } + } + return obj; + } + + clasp = OBJ_GET_CLASS(cx, obj); + if (clasp->flags & JSCLASS_DOCUMENT_OBSERVER) { + JS_ASSERT(0); + } + + if (clasp != &js_StringClass && + clasp != &js_NumberClass && + clasp != &js_BooleanClass) { + goto bad; + } + } + + str = js_ValueToString(cx, v); + if (!str) + return NULL; + if (IS_EMPTY(str)) { + length = 0; +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + xml = NULL; +#endif + } else { + xml = ParseXMLSource(cx, str); + if (!xml) + return NULL; + length = JSXML_LENGTH(xml); + } + + if (length == 0) { + obj = js_NewXMLObject(cx, JSXML_CLASS_TEXT); + if (!obj) + return NULL; + } else if (length == 1) { + xml = OrphanXMLChild(cx, xml, 0); + if (!xml) + return NULL; + obj = js_GetXMLObject(cx, xml); + if (!obj) + return NULL; + } else { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SYNTAX_ERROR); + return NULL; + } + return obj; + +bad: + js_ReportValueError(cx, JSMSG_BAD_XML_CONVERSION, + JSDVG_IGNORE_STACK, v, NULL); + return NULL; +} + +static JSBool +Append(JSContext *cx, JSXML *list, JSXML *kid); + +static JSObject * +ToXMLList(JSContext *cx, jsval v) +{ + JSObject *obj, *listobj; + JSXML *xml, *list, *kid; + JSClass *clasp; + JSString *str; + uint32 i, length; + + if (JSVAL_IS_PRIMITIVE(v)) { + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) + goto bad; + } else { + obj = JSVAL_TO_OBJECT(v); + if (OBJECT_IS_XML(cx, obj)) { + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (xml->xml_class != JSXML_CLASS_LIST) { + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) + return NULL; + list = (JSXML *) JS_GetPrivate(cx, listobj); + if (!Append(cx, list, xml)) + return NULL; + return listobj; + } + return obj; + } + + clasp = OBJ_GET_CLASS(cx, obj); + if (clasp->flags & JSCLASS_DOCUMENT_OBSERVER) { + JS_ASSERT(0); + } + + if (clasp != &js_StringClass && + clasp != &js_NumberClass && + clasp != &js_BooleanClass) { + goto bad; + } + } + + str = js_ValueToString(cx, v); + if (!str) + return NULL; + if (IS_EMPTY(str)) { + xml = NULL; + length = 0; + } else { + if (!js_EnterLocalRootScope(cx)) + return NULL; + xml = ParseXMLSource(cx, str); + if (!xml) { + js_LeaveLocalRootScope(cx); + return NULL; + } + length = JSXML_LENGTH(xml); + } + + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (listobj) { + list = (JSXML *) JS_GetPrivate(cx, listobj); + for (i = 0; i < length; i++) { + kid = OrphanXMLChild(cx, xml, i); + if (!kid || !Append(cx, list, kid)) { + listobj = NULL; + break; + } + } + } + + if (xml) + js_LeaveLocalRootScopeWithResult(cx, (jsval) listobj); + return listobj; + +bad: + js_ReportValueError(cx, JSMSG_BAD_XMLLIST_CONVERSION, + JSDVG_IGNORE_STACK, v, NULL); + return NULL; +} + +/* + * ECMA-357 10.2.1 Steps 5-7 pulled out as common subroutines of XMLToXMLString + * and their library-public js_* counterparts. The guts of MakeXMLCDataString, + * MakeXMLCommentString, and MakeXMLPIString are further factored into a common + * MakeXMLSpecialString subroutine. + * + * These functions take ownership of sb->base, if sb is non-null, in all cases + * of success or failure. + */ +static JSString * +MakeXMLSpecialString(JSContext *cx, JSStringBuffer *sb, + JSString *str, JSString *str2, + const jschar *prefix, size_t prefixlength, + const jschar *suffix, size_t suffixlength) +{ + JSStringBuffer localSB; + size_t length, length2, newlength; + jschar *bp, *base; + + if (!sb) { + sb = &localSB; + js_InitStringBuffer(sb); + } + + length = JSSTRING_LENGTH(str); + length2 = str2 ? JSSTRING_LENGTH(str2) : 0; + newlength = STRING_BUFFER_OFFSET(sb) + + prefixlength + length + ((length2 != 0) ? 1 + length2 : 0) + + suffixlength; + bp = base = (jschar *) + JS_realloc(cx, sb->base, (newlength + 1) * sizeof(jschar)); + if (!bp) { + js_FinishStringBuffer(sb); + return NULL; + } + + bp += STRING_BUFFER_OFFSET(sb); + js_strncpy(bp, prefix, prefixlength); + bp += prefixlength; + js_strncpy(bp, JSSTRING_CHARS(str), length); + bp += length; + if (length2 != 0) { + *bp++ = (jschar) ' '; + js_strncpy(bp, JSSTRING_CHARS(str2), length2); + bp += length2; + } + js_strncpy(bp, suffix, suffixlength); + bp[suffixlength] = 0; + + str = js_NewString(cx, base, newlength); + if (!str) + free(base); + return str; +} + +static JSString * +MakeXMLCDATAString(JSContext *cx, JSStringBuffer *sb, JSString *str) +{ + static const jschar cdata_prefix_ucNstr[] = {'<', '!', '[', + 'C', 'D', 'A', 'T', 'A', + '['}; + static const jschar cdata_suffix_ucNstr[] = {']', ']', '>'}; + + return MakeXMLSpecialString(cx, sb, str, NULL, + cdata_prefix_ucNstr, 9, + cdata_suffix_ucNstr, 3); +} + +static JSString * +MakeXMLCommentString(JSContext *cx, JSStringBuffer *sb, JSString *str) +{ + static const jschar comment_prefix_ucNstr[] = {'<', '!', '-', '-'}; + static const jschar comment_suffix_ucNstr[] = {'-', '-', '>'}; + + return MakeXMLSpecialString(cx, sb, str, NULL, + comment_prefix_ucNstr, 4, + comment_suffix_ucNstr, 3); +} + +static JSString * +MakeXMLPIString(JSContext *cx, JSStringBuffer *sb, JSString *name, + JSString *value) +{ + static const jschar pi_prefix_ucNstr[] = {'<', '?'}; + static const jschar pi_suffix_ucNstr[] = {'?', '>'}; + + return MakeXMLSpecialString(cx, sb, name, value, + pi_prefix_ucNstr, 2, + pi_suffix_ucNstr, 2); +} + +/* + * ECMA-357 10.2.1 17(d-g) pulled out into a common subroutine that appends + * equals, a double quote, an attribute value, and a closing double quote. + */ +static void +AppendAttributeValue(JSContext *cx, JSStringBuffer *sb, JSString *valstr) +{ + js_AppendChar(sb, '='); + valstr = js_EscapeAttributeValue(cx, valstr, JS_TRUE); + if (!valstr) { + if (STRING_BUFFER_OK(sb)) { + free(sb->base); + sb->base = STRING_BUFFER_ERROR_BASE; + } + return; + } + js_AppendJSString(sb, valstr); +} + +/* + * ECMA-357 10.2.1.1 EscapeElementValue helper method. + * + * This function takes ownership of sb->base, if sb is non-null, in all cases + * of success or failure. + */ +static JSString * +EscapeElementValue(JSContext *cx, JSStringBuffer *sb, JSString *str) +{ + size_t length, newlength; + const jschar *cp, *start, *end; + jschar c; + + JSSTRING_CHARS_AND_LENGTH(str, start, length); + newlength = length; + for (cp = start, end = cp + length; cp < end; cp++) { + c = *cp; + if (c == '<' || c == '>') + newlength += 3; + else if (c == '&') + newlength += 4; + + if (newlength < length) { + js_ReportAllocationOverflow(cx); + return NULL; + } + } + if ((sb && STRING_BUFFER_OFFSET(sb) != 0) || newlength > length) { + JSStringBuffer localSB; + if (!sb) { + sb = &localSB; + js_InitStringBuffer(sb); + } + if (!sb->grow(sb, newlength)) { + JS_ReportOutOfMemory(cx); + return NULL; + } + for (cp = start; cp < end; cp++) { + c = *cp; + if (c == '<') + js_AppendCString(sb, js_lt_entity_str); + else if (c == '>') + js_AppendCString(sb, js_gt_entity_str); + else if (c == '&') + js_AppendCString(sb, js_amp_entity_str); + else + js_AppendChar(sb, c); + } + JS_ASSERT(STRING_BUFFER_OK(sb)); + str = js_NewString(cx, sb->base, STRING_BUFFER_OFFSET(sb)); + if (!str) + js_FinishStringBuffer(sb); + } + return str; +} + +/* + * ECMA-357 10.2.1.2 EscapeAttributeValue helper method. + * This function takes ownership of sb->base, if sb is non-null, in all cases. + */ +static JSString * +EscapeAttributeValue(JSContext *cx, JSStringBuffer *sb, JSString *str, + JSBool quote) +{ + size_t length, newlength; + const jschar *cp, *start, *end; + jschar c; + + JSSTRING_CHARS_AND_LENGTH(str, start, length); + newlength = length + (quote ? 2 : 0); + for (cp = start, end = cp + length; cp < end; cp++) { + c = *cp; + if (c == '"') + newlength += 5; + else if (c == '<') + newlength += 3; + else if (c == '&' || c == '\n' || c == '\r' || c == '\t') + newlength += 4; + + if (newlength < length) { + js_ReportAllocationOverflow(cx); + return NULL; + } + } + if ((sb && STRING_BUFFER_OFFSET(sb) != 0) || newlength > length) { + JSStringBuffer localSB; + if (!sb) { + sb = &localSB; + js_InitStringBuffer(sb); + } + if (!sb->grow(sb, newlength)) { + JS_ReportOutOfMemory(cx); + return NULL; + } + if (quote) + js_AppendChar(sb, '"'); + for (cp = start; cp < end; cp++) { + c = *cp; + if (c == '"') + js_AppendCString(sb, js_quot_entity_str); + else if (c == '<') + js_AppendCString(sb, js_lt_entity_str); + else if (c == '&') + js_AppendCString(sb, js_amp_entity_str); + else if (c == '\n') + js_AppendCString(sb, " "); + else if (c == '\r') + js_AppendCString(sb, " "); + else if (c == '\t') + js_AppendCString(sb, " "); + else + js_AppendChar(sb, c); + } + if (quote) + js_AppendChar(sb, '"'); + JS_ASSERT(STRING_BUFFER_OK(sb)); + str = js_NewString(cx, sb->base, STRING_BUFFER_OFFSET(sb)); + if (!str) + js_FinishStringBuffer(sb); + } + return str; +} + +/* 13.3.5.4 [[GetNamespace]]([InScopeNamespaces]) */ +static JSObject * +GetNamespace(JSContext *cx, JSObject *qn, const JSXMLArray *inScopeNSes) +{ + JSString *uri, *prefix, *nsprefix; + JSObject *match, *ns; + uint32 i, n; + jsval argv[2]; + + uri = GetURI(qn); + prefix = GetPrefix(qn); + JS_ASSERT(uri); + if (!uri) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_XML_NAMESPACE, + prefix + ? js_ValueToPrintableString(cx, + STRING_TO_JSVAL(prefix)) + : js_undefined_str); + return NULL; + } + + /* Look for a matching namespace in inScopeNSes, if provided. */ + match = NULL; + if (inScopeNSes) { + for (i = 0, n = inScopeNSes->length; i < n; i++) { + ns = XMLARRAY_MEMBER(inScopeNSes, i, JSObject); + if (!ns) + continue; + + /* + * Erratum, very tricky, and not specified in ECMA-357 13.3.5.4: + * If we preserve prefixes, we must match null prefix against + * an empty prefix of ns, in order to avoid generating redundant + * prefixed and default namespaces for cases such as: + * + * x = + * print(x.toXMLString()); + * + * Per 10.3.2.1, the namespace attribute in t has an empty string + * prefix (*not* a null prefix), per 10.3.2.1 Step 6(h)(i)(1): + * + * 1. If the [local name] property of a is "xmlns" + * a. Map ns.prefix to the empty string + * + * But t's name has a null prefix in this implementation, meaning + * *undefined*, per 10.3.2.1 Step 6(c)'s NOTE (which refers to + * the http://www.w3.org/TR/xml-infoset/ spec, item 2.2.3, without + * saying how "no value" maps to an ECMA-357 value -- but it must + * map to the *undefined* prefix value). + * + * Since "" != undefined (or null, in the current implementation) + * the ECMA-357 spec will fail to match in [[GetNamespace]] called + * on t with argument {} U {(prefix="", uri="http://foo.com")}. + * This spec bug leads to ToXMLString results that duplicate the + * declared namespace. + */ + if (js_EqualStrings(GetURI(ns), uri)) { + nsprefix = GetPrefix(ns); + if (nsprefix == prefix || + ((nsprefix && prefix) + ? js_EqualStrings(nsprefix, prefix) + : IS_EMPTY(nsprefix ? nsprefix : prefix))) { + match = ns; + break; + } + } + } + } + + /* If we didn't match, make a new namespace from qn. */ + if (!match) { + argv[0] = prefix ? STRING_TO_JSVAL(prefix) : JSVAL_VOID; + argv[1] = STRING_TO_JSVAL(uri); + ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, NULL, + 2, argv); + if (!ns) + return NULL; + match = ns; + } + return match; +} + +static JSString * +GeneratePrefix(JSContext *cx, JSString *uri, JSXMLArray *decls) +{ + const jschar *cp, *start, *end; + size_t length, newlength, offset; + uint32 i, n, m, serial; + jschar *bp, *dp; + JSBool done; + JSObject *ns; + JSString *nsprefix, *prefix; + + JS_ASSERT(!IS_EMPTY(uri)); + + /* + * If there are no *declared* namespaces, skip all collision detection and + * return a short prefix quickly; an example of such a situation: + * + * var x = ; + * var n = new Namespace("http://example.com/"); + * x.@n::att = "val"; + * x.toXMLString(); + * + * This is necessary for various log10 uses below to be valid. + */ + if (decls->length == 0) + return JS_NewStringCopyZ(cx, "a"); + + /* + * Try peeling off the last filename suffix or pathname component till + * we have a valid XML name. This heuristic will prefer "xul" given + * ".../there.is.only.xul", "xbl" given ".../xbl", and "xbl2" given any + * likely URI of the form ".../xbl2/2005". + */ + JSSTRING_CHARS_AND_END(uri, start, end); + cp = end; + while (--cp > start) { + if (*cp == '.' || *cp == '/' || *cp == ':') { + ++cp; + length = PTRDIFF(end, cp, jschar); + if (IsXMLName(cp, length) && !STARTS_WITH_XML(cp, length)) + break; + end = --cp; + } + } + length = PTRDIFF(end, cp, jschar); + + /* + * If the namespace consisted only of non-XML names or names that begin + * case-insensitively with "xml", arbitrarily create a prefix consisting + * of 'a's of size length (allowing dp-calculating code to work with or + * without this branch executing) plus the space for storing a hyphen and + * the serial number (avoiding reallocation if a collision happens). + */ + bp = (jschar *) cp; + newlength = length; + if (STARTS_WITH_XML(cp, length) || !IsXMLName(cp, length)) { + newlength = length + 2 + (size_t) log10((double) decls->length); + bp = (jschar *) + JS_malloc(cx, (newlength + 1) * sizeof(jschar)); + if (!bp) + return NULL; + + bp[newlength] = 0; + for (i = 0; i < newlength; i++) + bp[i] = 'a'; + } + + /* + * Now search through decls looking for a collision. If we collide with + * an existing prefix, start tacking on a hyphen and a serial number. + */ + serial = 0; + do { + done = JS_TRUE; + for (i = 0, n = decls->length; i < n; i++) { + ns = XMLARRAY_MEMBER(decls, i, JSObject); + if (ns && (nsprefix = GetPrefix(ns)) && + JSSTRING_LENGTH(nsprefix) == newlength && + !memcmp(JSSTRING_CHARS(nsprefix), bp, + newlength * sizeof(jschar))) { + if (bp == cp) { + newlength = length + 2 + (size_t) log10((double) n); + bp = (jschar *) + JS_malloc(cx, (newlength + 1) * sizeof(jschar)); + if (!bp) + return NULL; + js_strncpy(bp, cp, length); + } + + ++serial; + JS_ASSERT(serial <= n); + dp = bp + length + 2 + (size_t) log10((double) serial); + *dp = 0; + for (m = serial; m != 0; m /= 10) + *--dp = (jschar)('0' + m % 10); + *--dp = '-'; + JS_ASSERT(dp == bp + length); + + done = JS_FALSE; + break; + } + } + } while (!done); + + if (bp == cp) { + offset = PTRDIFF(cp, start, jschar); + prefix = js_NewDependentString(cx, uri, offset, length); + } else { + prefix = js_NewString(cx, bp, newlength); + if (!prefix) + JS_free(cx, bp); + } + return prefix; +} + +static JSBool +namespace_match(const void *a, const void *b) +{ + const JSObject *nsa = (const JSObject *) a; + const JSObject *nsb = (const JSObject *) b; + JSString *prefixa, *prefixb = GetPrefix(nsb); + + if (prefixb) { + prefixa = GetPrefix(nsa); + return prefixa && js_EqualStrings(prefixa, prefixb); + } + return js_EqualStrings(GetURI(nsa), GetURI(nsb)); +} + +/* ECMA-357 10.2.1 and 10.2.2 */ +#define TO_SOURCE_FLAG 0x80000000 + +static JSString * +XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes, + uint32 indentLevel) +{ + JSBool pretty, indentKids; + JSStringBuffer sb; + JSString *str, *prefix, *kidstr, *nsuri; + JSXMLArrayCursor cursor; + uint32 i, n, nextIndentLevel; + JSXMLArray empty, decls, ancdecls; + JSObject *ns, *ns2; + JSXML *attr, *kid; + + if (!GetBooleanXMLSetting(cx, js_prettyPrinting_str, &pretty)) + return NULL; + + js_InitStringBuffer(&sb); + if (pretty) { + js_RepeatChar(&sb, ' ', indentLevel & ~TO_SOURCE_FLAG); + + if (!STRING_BUFFER_OK(&sb)) { + JS_ReportOutOfMemory(cx); + return NULL; + } + } + str = NULL; + + switch (xml->xml_class) { + case JSXML_CLASS_TEXT: + /* Step 4. */ + if (pretty) { + str = ChompXMLWhitespace(cx, xml->xml_value); + if (!str) + return NULL; + } else { + str = xml->xml_value; + } + return EscapeElementValue(cx, &sb, str); + + case JSXML_CLASS_ATTRIBUTE: + /* Step 5. */ + return EscapeAttributeValue(cx, &sb, xml->xml_value, + (indentLevel & TO_SOURCE_FLAG) != 0); + + case JSXML_CLASS_COMMENT: + /* Step 6. */ + return MakeXMLCommentString(cx, &sb, xml->xml_value); + + case JSXML_CLASS_PROCESSING_INSTRUCTION: + /* Step 7. */ + return MakeXMLPIString(cx, &sb, GetLocalName(xml->name), + xml->xml_value); + + case JSXML_CLASS_LIST: + /* ECMA-357 10.2.2. */ + XMLArrayCursorInit(&cursor, &xml->xml_kids); + i = 0; + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + if (pretty && i != 0) + js_AppendChar(&sb, '\n'); + + kidstr = XMLToXMLString(cx, kid, ancestorNSes, indentLevel); + if (!kidstr) + break; + + js_AppendJSString(&sb, kidstr); + ++i; + } + XMLArrayCursorFinish(&cursor); + if (kid) + goto list_out; + + if (!sb.base) + return cx->runtime->emptyString; + + if (!STRING_BUFFER_OK(&sb)) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + str = js_NewString(cx, sb.base, STRING_BUFFER_OFFSET(&sb)); + list_out: + if (!str && STRING_BUFFER_OK(&sb)) + js_FinishStringBuffer(&sb); + return str; + + default:; + } + + /* After this point, control must flow through label out: to exit. */ + if (!js_EnterLocalRootScope(cx)) + return NULL; + + /* ECMA-357 10.2.1 step 8 onward: handle ToXMLString on an XML element. */ + if (!ancestorNSes) { + XMLArrayInit(cx, &empty, 0); + ancestorNSes = ∅ + } + XMLArrayInit(cx, &decls, 0); + ancdecls.capacity = 0; + + /* Clone in-scope namespaces not in ancestorNSes into decls. */ + XMLArrayCursorInit(&cursor, &xml->xml_namespaces); + while ((ns = (JSObject *) XMLArrayCursorNext(&cursor)) != NULL) { + if (!IsDeclared(ns)) + continue; + if (!XMLARRAY_HAS_MEMBER(ancestorNSes, ns, namespace_identity)) { + /* NOTE: may want to exclude unused namespaces here. */ + ns2 = NewXMLNamespace(cx, GetPrefix(ns), GetURI(ns), JS_TRUE); + if (!ns2 || !XMLARRAY_APPEND(cx, &decls, ns2)) + break; + } + } + XMLArrayCursorFinish(&cursor); + if (ns) + goto out; + + /* + * Union ancestorNSes and decls into ancdecls. Note that ancdecls does + * not own its member references. In the spec, ancdecls has no name, but + * is always written out as (AncestorNamespaces U namespaceDeclarations). + */ + if (!XMLArrayInit(cx, &ancdecls, ancestorNSes->length + decls.length)) + goto out; + for (i = 0, n = ancestorNSes->length; i < n; i++) { + ns2 = XMLARRAY_MEMBER(ancestorNSes, i, JSObject); + if (!ns2) + continue; + JS_ASSERT(!XMLARRAY_HAS_MEMBER(&decls, ns2, namespace_identity)); + if (!XMLARRAY_APPEND(cx, &ancdecls, ns2)) + goto out; + } + for (i = 0, n = decls.length; i < n; i++) { + ns2 = XMLARRAY_MEMBER(&decls, i, JSObject); + if (!ns2) + continue; + JS_ASSERT(!XMLARRAY_HAS_MEMBER(&ancdecls, ns2, namespace_identity)); + if (!XMLARRAY_APPEND(cx, &ancdecls, ns2)) + goto out; + } + + /* Step 11, except we don't clone ns unless its prefix is undefined. */ + ns = GetNamespace(cx, xml->name, &ancdecls); + if (!ns) + goto out; + + /* Step 12 (NULL means *undefined* here), plus the deferred ns cloning. */ + prefix = GetPrefix(ns); + if (!prefix) { + /* + * Create a namespace prefix that isn't used by any member of decls. + * Assign the new prefix to a copy of ns. Flag this namespace as if + * it were declared, for assertion-testing's sake later below. + * + * Erratum: if prefix and xml->name are both null (*undefined* in + * ECMA-357), we know that xml was named using the default namespace + * (proof: see GetNamespace and the Namespace constructor called with + * two arguments). So we ought not generate a new prefix here, when + * we can declare ns as the default namespace for xml. + * + * This helps descendants inherit the namespace instead of redundantly + * redeclaring it with generated prefixes in each descendant. + */ + nsuri = GetURI(ns); + if (!GetPrefix(xml->name)) { + prefix = cx->runtime->emptyString; + } else { + prefix = GeneratePrefix(cx, nsuri, &ancdecls); + if (!prefix) + goto out; + } + ns = NewXMLNamespace(cx, prefix, nsuri, JS_TRUE); + if (!ns) + goto out; + + /* + * If the xml->name was unprefixed, we must remove any declared default + * namespace from decls before appending ns. How can you get a default + * namespace in decls that doesn't match the one from name? Apparently + * by calling x.setNamespace(ns) where ns has no prefix. The other way + * to fix this is to update x's in-scope namespaces when setNamespace + * is called, but that's not specified by ECMA-357. + * + * Likely Erratum here, depending on whether the lack of update to x's + * in-scope namespace in XML.prototype.setNamespace (13.4.4.36) is an + * erratum or not. Note that changing setNamespace to update the list + * of in-scope namespaces will change x.namespaceDeclarations(). + */ + if (IS_EMPTY(prefix)) { + i = XMLArrayFindMember(&decls, ns, namespace_match); + if (i != XML_NOT_FOUND) + XMLArrayDelete(cx, &decls, i, JS_TRUE); + } + + /* + * In the spec, ancdecls has no name, but is always written out as + * (AncestorNamespaces U namespaceDeclarations). Since we compute + * that union in ancdecls, any time we append a namespace strong + * ref to decls, we must also append a weak ref to ancdecls. Order + * matters here: code at label out: releases strong refs in decls. + */ + if (!XMLARRAY_APPEND(cx, &ancdecls, ns) || + !XMLARRAY_APPEND(cx, &decls, ns)) { + goto out; + } + } + + /* Format the element or point-tag into sb. */ + js_AppendChar(&sb, '<'); + + if (prefix && !IS_EMPTY(prefix)) { + js_AppendJSString(&sb, prefix); + js_AppendChar(&sb, ':'); + } + js_AppendJSString(&sb, GetLocalName(xml->name)); + + /* + * Step 16 makes a union to avoid writing two loops in step 17, to share + * common attribute value appending spec-code. We prefer two loops for + * faster code and less data overhead. + */ + + /* Step 17(b): append attributes. */ + XMLArrayCursorInit(&cursor, &xml->xml_attrs); + while ((attr = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + js_AppendChar(&sb, ' '); + ns2 = GetNamespace(cx, attr->name, &ancdecls); + if (!ns2) + break; + + /* 17(b)(ii): NULL means *undefined* here. */ + prefix = GetPrefix(ns2); + if (!prefix) { + prefix = GeneratePrefix(cx, GetURI(ns2), &ancdecls); + if (!prefix) + break; + + /* Again, we avoid copying ns2 until we know it's prefix-less. */ + ns2 = NewXMLNamespace(cx, prefix, GetURI(ns2), JS_TRUE); + if (!ns2) + break; + + /* + * In the spec, ancdecls has no name, but is always written out as + * (AncestorNamespaces U namespaceDeclarations). Since we compute + * that union in ancdecls, any time we append a namespace strong + * ref to decls, we must also append a weak ref to ancdecls. Order + * matters here: code at label out: releases strong refs in decls. + */ + if (!XMLARRAY_APPEND(cx, &ancdecls, ns2) || + !XMLARRAY_APPEND(cx, &decls, ns2)) { + break; + } + } + + /* 17(b)(iii). */ + if (!IS_EMPTY(prefix)) { + js_AppendJSString(&sb, prefix); + js_AppendChar(&sb, ':'); + } + + /* 17(b)(iv). */ + js_AppendJSString(&sb, GetLocalName(attr->name)); + + /* 17(d-g). */ + AppendAttributeValue(cx, &sb, attr->xml_value); + } + XMLArrayCursorFinish(&cursor); + if (attr) + goto out; + + /* Step 17(c): append XML namespace declarations. */ + XMLArrayCursorInit(&cursor, &decls); + while ((ns2 = (JSObject *) XMLArrayCursorNext(&cursor)) != NULL) { + JS_ASSERT(IsDeclared(ns2)); + + js_AppendCString(&sb, " xmlns"); + + /* 17(c)(ii): NULL means *undefined* here. */ + prefix = GetPrefix(ns2); + if (!prefix) { + prefix = GeneratePrefix(cx, GetURI(ns2), &ancdecls); + if (!prefix) + break; + ns2->fslots[JSSLOT_PREFIX] = STRING_TO_JSVAL(prefix); + } + + /* 17(c)(iii). */ + if (!IS_EMPTY(prefix)) { + js_AppendChar(&sb, ':'); + js_AppendJSString(&sb, prefix); + } + + /* 17(d-g). */ + AppendAttributeValue(cx, &sb, GetURI(ns2)); + } + XMLArrayCursorFinish(&cursor); + if (ns2) + goto out; + + /* Step 18: handle point tags. */ + n = xml->xml_kids.length; + if (n == 0) { + js_AppendCString(&sb, "/>"); + } else { + /* Steps 19 through 25: handle element content, and open the end-tag. */ + js_AppendChar(&sb, '>'); + indentKids = n > 1 || + (n == 1 && + (kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML)) && + kid->xml_class != JSXML_CLASS_TEXT); + + if (pretty && indentKids) { + if (!GetUint32XMLSetting(cx, js_prettyIndent_str, &i)) + goto out; + nextIndentLevel = indentLevel + i; + } else { + nextIndentLevel = indentLevel & TO_SOURCE_FLAG; + } + + XMLArrayCursorInit(&cursor, &xml->xml_kids); + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + if (pretty && indentKids) + js_AppendChar(&sb, '\n'); + + kidstr = XMLToXMLString(cx, kid, &ancdecls, nextIndentLevel); + if (!kidstr) + break; + + js_AppendJSString(&sb, kidstr); + } + XMLArrayCursorFinish(&cursor); + if (kid) + goto out; + + if (pretty && indentKids) { + js_AppendChar(&sb, '\n'); + js_RepeatChar(&sb, ' ', indentLevel & ~TO_SOURCE_FLAG); + } + js_AppendCString(&sb, "name)); + js_AppendChar(&sb, '>'); + } + + if (!STRING_BUFFER_OK(&sb)) { + JS_ReportOutOfMemory(cx); + goto out; + } + + str = js_NewString(cx, sb.base, STRING_BUFFER_OFFSET(&sb)); +out: + js_LeaveLocalRootScopeWithResult(cx, STRING_TO_JSVAL(str)); + if (!str && STRING_BUFFER_OK(&sb)) + js_FinishStringBuffer(&sb); + XMLArrayFinish(cx, &decls); + if (ancdecls.capacity != 0) + XMLArrayFinish(cx, &ancdecls); + return str; +} + +/* ECMA-357 10.2 */ +static JSString * +ToXMLString(JSContext *cx, jsval v, uint32 toSourceFlag) +{ + JSObject *obj; + JSString *str; + JSXML *xml; + + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_XML_CONVERSION, + JSVAL_IS_NULL(v) ? js_null_str : js_undefined_str); + return NULL; + } + + if (JSVAL_IS_BOOLEAN(v) || JSVAL_IS_NUMBER(v)) + return js_ValueToString(cx, v); + + if (JSVAL_IS_STRING(v)) + return EscapeElementValue(cx, NULL, JSVAL_TO_STRING(v)); + + obj = JSVAL_TO_OBJECT(v); + if (!OBJECT_IS_XML(cx, obj)) { + if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v)) + return NULL; + str = js_ValueToString(cx, v); + if (!str) + return NULL; + return EscapeElementValue(cx, NULL, str); + } + + /* Handle non-element cases in this switch, returning from each case. */ + xml = (JSXML *) JS_GetPrivate(cx, obj); + return XMLToXMLString(cx, xml, NULL, toSourceFlag | 0); +} + +static JSObject * +ToAttributeName(JSContext *cx, jsval v) +{ + JSString *name, *uri, *prefix; + JSObject *obj; + JSClass *clasp; + JSObject *qn; + + if (JSVAL_IS_STRING(v)) { + name = JSVAL_TO_STRING(v); + uri = prefix = cx->runtime->emptyString; + } else { + if (JSVAL_IS_PRIMITIVE(v)) { + js_ReportValueError(cx, JSMSG_BAD_XML_ATTR_NAME, + JSDVG_IGNORE_STACK, v, NULL); + return NULL; + } + + obj = JSVAL_TO_OBJECT(v); + clasp = OBJ_GET_CLASS(cx, obj); + if (clasp == &js_AttributeNameClass) + return obj; + + if (clasp == &js_QNameClass.base) { + qn = obj; + uri = GetURI(qn); + prefix = GetPrefix(qn); + name = GetLocalName(qn); + } else { + if (clasp == &js_AnyNameClass) { + name = ATOM_TO_STRING(cx->runtime->atomState.starAtom); + } else { + name = js_ValueToString(cx, v); + if (!name) + return NULL; + } + uri = prefix = cx->runtime->emptyString; + } + } + + qn = NewXMLQName(cx, uri, prefix, name, &js_AttributeNameClass); + if (!qn) + return NULL; + return qn; +} + +static void +ReportBadXMLName(JSContext *cx, jsval id) +{ + js_ReportValueError(cx, JSMSG_BAD_XML_NAME, JSDVG_IGNORE_STACK, id, NULL); +} + +static JSBool +IsFunctionQName(JSContext *cx, JSObject *qn, jsid *funidp) +{ + JSAtom *atom; + JSString *uri; + + atom = cx->runtime->atomState.lazy.functionNamespaceURIAtom; + uri = GetURI(qn); + if (uri && atom && + (uri == ATOM_TO_STRING(atom) || + js_EqualStrings(uri, ATOM_TO_STRING(atom)))) { + return JS_ValueToId(cx, STRING_TO_JSVAL(GetLocalName(qn)), funidp); + } + *funidp = 0; + return JS_TRUE; +} + +JSBool +js_IsFunctionQName(JSContext *cx, JSObject *obj, jsid *funidp) +{ + if (OBJ_GET_CLASS(cx, obj) == &js_QNameClass.base) + return IsFunctionQName(cx, obj, funidp); + *funidp = 0; + return JS_TRUE; +} + +static JSObject * +ToXMLName(JSContext *cx, jsval v, jsid *funidp) +{ + JSString *name; + JSObject *obj; + JSClass *clasp; + uint32 index; + + if (JSVAL_IS_STRING(v)) { + name = JSVAL_TO_STRING(v); + } else { + if (JSVAL_IS_PRIMITIVE(v)) { + ReportBadXMLName(cx, v); + return NULL; + } + + obj = JSVAL_TO_OBJECT(v); + clasp = OBJ_GET_CLASS(cx, obj); + if (clasp == &js_AttributeNameClass || clasp == &js_QNameClass.base) + goto out; + if (clasp == &js_AnyNameClass) { + name = ATOM_TO_STRING(cx->runtime->atomState.starAtom); + goto construct; + } + name = js_ValueToString(cx, v); + if (!name) + return NULL; + } + + /* + * ECMA-357 10.6.1 step 1 seems to be incorrect. The spec says: + * + * 1. If ToString(ToNumber(P)) == ToString(P), throw a TypeError exception + * + * First, _P_ should be _s_, to refer to the given string. + * + * Second, why does ToXMLName applied to the string type throw TypeError + * only for numeric literals without any leading or trailing whitespace? + * + * If the idea is to reject uint32 property names, then the check needs to + * be stricter, to exclude hexadecimal and floating point literals. + */ + if (js_IdIsIndex(STRING_TO_JSVAL(name), &index)) + goto bad; + + if (*JSSTRING_CHARS(name) == '@') { + name = js_NewDependentString(cx, name, 1, JSSTRING_LENGTH(name) - 1); + if (!name) + return NULL; + *funidp = 0; + return ToAttributeName(cx, STRING_TO_JSVAL(name)); + } + +construct: + v = STRING_TO_JSVAL(name); + obj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, &v); + if (!obj) + return NULL; + +out: + if (!IsFunctionQName(cx, obj, funidp)) + return NULL; + return obj; + +bad: + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_XML_NAME, + js_ValueToPrintableString(cx, STRING_TO_JSVAL(name))); + return NULL; +} + +/* ECMA-357 9.1.1.13 XML [[AddInScopeNamespace]]. */ +static JSBool +AddInScopeNamespace(JSContext *cx, JSXML *xml, JSObject *ns) +{ + JSString *prefix, *prefix2; + JSObject *match, *ns2; + uint32 i, n, m; + + if (xml->xml_class != JSXML_CLASS_ELEMENT) + return JS_TRUE; + + /* NULL means *undefined* here -- see ECMA-357 9.1.1.13 step 2. */ + prefix = GetPrefix(ns); + if (!prefix) { + match = NULL; + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns2 = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (ns2 && js_EqualStrings(GetURI(ns2), GetURI(ns))) { + match = ns2; + break; + } + } + if (!match && !XMLARRAY_ADD_MEMBER(cx, &xml->xml_namespaces, n, ns)) + return JS_FALSE; + } else { + if (IS_EMPTY(prefix) && IS_EMPTY(GetURI(xml->name))) + return JS_TRUE; + match = NULL; +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + m = XML_NOT_FOUND; +#endif + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns2 = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (ns2 && (prefix2 = GetPrefix(ns2)) && + js_EqualStrings(prefix2, prefix)) { + match = ns2; + m = i; + break; + } + } + if (match && !js_EqualStrings(GetURI(match), GetURI(ns))) { + ns2 = XMLARRAY_DELETE(cx, &xml->xml_namespaces, m, JS_TRUE, + JSObject); + JS_ASSERT(ns2 == match); + match->fslots[JSSLOT_PREFIX] = JSVAL_VOID; + if (!AddInScopeNamespace(cx, xml, match)) + return JS_FALSE; + } + if (!XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) + return JS_FALSE; + } + + /* OPTION: enforce that descendants have superset namespaces. */ + return JS_TRUE; +} + +/* ECMA-357 9.2.1.6 XMLList [[Append]]. */ +static JSBool +Append(JSContext *cx, JSXML *list, JSXML *xml) +{ + uint32 i, j, k, n; + JSXML *kid; + + JS_ASSERT(list->xml_class == JSXML_CLASS_LIST); + i = list->xml_kids.length; + n = 1; + if (xml->xml_class == JSXML_CLASS_LIST) { + list->xml_target = xml->xml_target; + list->xml_targetprop = xml->xml_targetprop; + n = JSXML_LENGTH(xml); + k = i + n; + if (!XMLArraySetCapacity(cx, &list->xml_kids, k)) + return JS_FALSE; + for (j = 0; j < n; j++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, j, JSXML); + if (kid) + XMLARRAY_SET_MEMBER(&list->xml_kids, i + j, kid); + } + return JS_TRUE; + } + + list->xml_target = xml->parent; + if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) + list->xml_targetprop = NULL; + else + list->xml_targetprop = xml->name; + if (!XMLARRAY_ADD_MEMBER(cx, &list->xml_kids, i, xml)) + return JS_FALSE; + return JS_TRUE; +} + +/* ECMA-357 9.1.1.7 XML [[DeepCopy]] and 9.2.1.7 XMLList [[DeepCopy]]. */ +static JSXML * +DeepCopyInLRS(JSContext *cx, JSXML *xml, uintN flags); + +static JSXML * +DeepCopy(JSContext *cx, JSXML *xml, JSObject *obj, uintN flags) +{ + JSXML *copy; + JSBool ok; + + /* Our caller may not be protecting newborns with a local root scope. */ + if (!js_EnterLocalRootScope(cx)) + return NULL; + copy = DeepCopyInLRS(cx, xml, flags); + if (copy) { + if (obj) { + /* Caller provided the object for this copy, hook 'em up. */ + ok = JS_SetPrivate(cx, obj, copy); + if (ok) + copy->object = obj; + } else { + ok = js_GetXMLObject(cx, copy) != NULL; + } + if (!ok) + copy = NULL; + } + js_LeaveLocalRootScopeWithResult(cx, (jsval) copy); + return copy; +} + +/* + * (i) We must be in a local root scope (InLRS). + * (ii) parent must have a rooted object. + * (iii) from's owning object must be locked if not thread-local. + */ +static JSBool +DeepCopySetInLRS(JSContext *cx, JSXMLArray *from, JSXMLArray *to, JSXML *parent, + uintN flags) +{ + uint32 j, n; + JSXMLArrayCursor cursor; + JSBool ok; + JSXML *kid, *kid2; + JSString *str; + + JS_ASSERT(cx->localRootStack); + + n = from->length; + if (!XMLArraySetCapacity(cx, to, n)) + return JS_FALSE; + + XMLArrayCursorInit(&cursor, from); + j = 0; + ok = JS_TRUE; + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + if ((flags & XSF_IGNORE_COMMENTS) && + kid->xml_class == JSXML_CLASS_COMMENT) { + continue; + } + if ((flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS) && + kid->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) { + continue; + } + if ((flags & XSF_IGNORE_WHITESPACE) && + (kid->xml_flags & XMLF_WHITESPACE_TEXT)) { + continue; + } + kid2 = DeepCopyInLRS(cx, kid, flags); + if (!kid2) { + to->length = j; + ok = JS_FALSE; + break; + } + + if ((flags & XSF_IGNORE_WHITESPACE) && + n > 1 && kid2->xml_class == JSXML_CLASS_TEXT) { + str = ChompXMLWhitespace(cx, kid2->xml_value); + if (!str) { + to->length = j; + ok = JS_FALSE; + break; + } + kid2->xml_value = str; + } + + XMLARRAY_SET_MEMBER(to, j, kid2); + ++j; + if (parent->xml_class != JSXML_CLASS_LIST) + kid2->parent = parent; + } + XMLArrayCursorFinish(&cursor); + if (!ok) + return JS_FALSE; + + if (j < n) + XMLArrayTrim(to); + return JS_TRUE; +} + +static JSXML * +DeepCopyInLRS(JSContext *cx, JSXML *xml, uintN flags) +{ + JSXML *copy; + JSObject *qn; + JSBool ok; + uint32 i, n; + JSObject *ns, *ns2; + + /* Our caller must be protecting newborn objects. */ + JS_ASSERT(cx->localRootStack); + + JS_CHECK_RECURSION(cx, return NULL); + + copy = js_NewXML(cx, (JSXMLClass) xml->xml_class); + if (!copy) + return NULL; + qn = xml->name; + if (qn) { + qn = NewXMLQName(cx, GetURI(qn), GetPrefix(qn), GetLocalName(qn)); + if (!qn) { + ok = JS_FALSE; + goto out; + } + } + copy->name = qn; + copy->xml_flags = xml->xml_flags; + + if (JSXML_HAS_VALUE(xml)) { + copy->xml_value = xml->xml_value; + ok = JS_TRUE; + } else { + ok = DeepCopySetInLRS(cx, &xml->xml_kids, ©->xml_kids, copy, flags); + if (!ok) + goto out; + + if (xml->xml_class == JSXML_CLASS_LIST) { + copy->xml_target = xml->xml_target; + copy->xml_targetprop = xml->xml_targetprop; + } else { + n = xml->xml_namespaces.length; + ok = XMLArraySetCapacity(cx, ©->xml_namespaces, n); + if (!ok) + goto out; + for (i = 0; i < n; i++) { + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (!ns) + continue; + ns2 = NewXMLNamespace(cx, GetPrefix(ns), GetURI(ns), + IsDeclared(ns)); + if (!ns2) { + copy->xml_namespaces.length = i; + ok = JS_FALSE; + goto out; + } + XMLARRAY_SET_MEMBER(©->xml_namespaces, i, ns2); + } + + ok = DeepCopySetInLRS(cx, &xml->xml_attrs, ©->xml_attrs, copy, + 0); + if (!ok) + goto out; + } + } + +out: + if (!ok) + return NULL; + return copy; +} + +/* ECMA-357 9.1.1.4 XML [[DeleteByIndex]]. */ +static void +DeleteByIndex(JSContext *cx, JSXML *xml, uint32 index) +{ + JSXML *kid; + + if (JSXML_HAS_KIDS(xml) && index < xml->xml_kids.length) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); + if (kid) + kid->parent = NULL; + XMLArrayDelete(cx, &xml->xml_kids, index, JS_TRUE); + } +} + +typedef JSBool (*JSXMLNameMatcher)(JSObject *nameqn, JSXML *xml); + +static JSBool +MatchAttrName(JSObject *nameqn, JSXML *attr) +{ + JSObject *attrqn = attr->name; + JSString *localName = GetLocalName(nameqn); + JSString *uri; + + return (IS_STAR(localName) || + js_EqualStrings(GetLocalName(attrqn), localName)) && + (!(uri = GetURI(nameqn)) || + js_EqualStrings(GetURI(attrqn), uri)); +} + +static JSBool +MatchElemName(JSObject *nameqn, JSXML *elem) +{ + JSString *localName = GetLocalName(nameqn); + JSString *uri; + + return (IS_STAR(localName) || + (elem->xml_class == JSXML_CLASS_ELEMENT && + js_EqualStrings(GetLocalName(elem->name), localName))) && + (!(uri = GetURI(nameqn)) || + (elem->xml_class == JSXML_CLASS_ELEMENT && + js_EqualStrings(GetURI(elem->name), uri))); +} + +/* ECMA-357 9.1.1.8 XML [[Descendants]] and 9.2.1.8 XMLList [[Descendants]]. */ +static JSBool +DescendantsHelper(JSContext *cx, JSXML *xml, JSObject *nameqn, JSXML *list) +{ + uint32 i, n; + JSXML *attr, *kid; + + JS_CHECK_RECURSION(cx, return JS_FALSE); + + if (xml->xml_class == JSXML_CLASS_ELEMENT && + OBJ_GET_CLASS(cx, nameqn) == &js_AttributeNameClass) { + for (i = 0, n = xml->xml_attrs.length; i < n; i++) { + attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); + if (attr && MatchAttrName(nameqn, attr)) { + if (!Append(cx, list, attr)) + return JS_FALSE; + } + } + } + + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (!kid) + continue; + if (OBJ_GET_CLASS(cx, nameqn) != &js_AttributeNameClass && + MatchElemName(nameqn, kid)) { + if (!Append(cx, list, kid)) + return JS_FALSE; + } + if (!DescendantsHelper(cx, kid, nameqn, list)) + return JS_FALSE; + } + return JS_TRUE; +} + +static JSXML * +Descendants(JSContext *cx, JSXML *xml, jsval id) +{ + jsid funid; + JSObject *nameqn; + JSObject *listobj; + JSXML *list, *kid; + uint32 i, n; + JSBool ok; + + nameqn = ToXMLName(cx, id, &funid); + if (!nameqn) + return NULL; + + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) + return NULL; + list = (JSXML *) JS_GetPrivate(cx, listobj); + if (funid) + return list; + + /* + * Protect nameqn's object and strings from GC by linking list to it + * temporarily. The cx->newborn[GCX_OBJECT] GC root protects listobj, + * which protects list. Any other object allocations occuring beneath + * DescendantsHelper use local roots. + */ + list->name = nameqn; + if (!js_EnterLocalRootScope(cx)) + return NULL; + if (xml->xml_class == JSXML_CLASS_LIST) { + ok = JS_TRUE; + for (i = 0, n = xml->xml_kids.length; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + ok = DescendantsHelper(cx, kid, nameqn, list); + if (!ok) + break; + } + } + } else { + ok = DescendantsHelper(cx, xml, nameqn, list); + } + js_LeaveLocalRootScopeWithResult(cx, (jsval) list); + if (!ok) + return NULL; + list->name = NULL; + return list; +} + +static JSBool +xml_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); + +/* Recursive (JSXML *) parameterized version of Equals. */ +static JSBool +XMLEquals(JSContext *cx, JSXML *xml, JSXML *vxml, JSBool *bp) +{ + JSObject *qn, *vqn; + uint32 i, j, n; + JSXMLArrayCursor cursor, vcursor; + JSXML *kid, *vkid, *attr, *vattr; + JSBool ok; + JSObject *xobj, *vobj; + +retry: + if (xml->xml_class != vxml->xml_class) { + if (xml->xml_class == JSXML_CLASS_LIST && xml->xml_kids.length == 1) { + xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (xml) + goto retry; + } + if (vxml->xml_class == JSXML_CLASS_LIST && vxml->xml_kids.length == 1) { + vxml = XMLARRAY_MEMBER(&vxml->xml_kids, 0, JSXML); + if (vxml) + goto retry; + } + *bp = JS_FALSE; + return JS_TRUE; + } + + qn = xml->name; + vqn = vxml->name; + if (qn) { + *bp = vqn && + js_EqualStrings(GetLocalName(qn), GetLocalName(vqn)) && + js_EqualStrings(GetURI(qn), GetURI(vqn)); + } else { + *bp = vqn == NULL; + } + if (!*bp) + return JS_TRUE; + + if (JSXML_HAS_VALUE(xml)) { + *bp = js_EqualStrings(xml->xml_value, vxml->xml_value); + } else if (xml->xml_kids.length != vxml->xml_kids.length) { + *bp = JS_FALSE; + } else { + XMLArrayCursorInit(&cursor, &xml->xml_kids); + XMLArrayCursorInit(&vcursor, &vxml->xml_kids); + for (;;) { + kid = (JSXML *) XMLArrayCursorNext(&cursor); + vkid = (JSXML *) XMLArrayCursorNext(&vcursor); + if (!kid || !vkid) { + *bp = !kid && !vkid; + ok = JS_TRUE; + break; + } + xobj = js_GetXMLObject(cx, kid); + vobj = js_GetXMLObject(cx, vkid); + ok = xobj && vobj && + xml_equality(cx, xobj, OBJECT_TO_JSVAL(vobj), bp); + if (!ok || !*bp) + break; + } + XMLArrayCursorFinish(&vcursor); + XMLArrayCursorFinish(&cursor); + if (!ok) + return JS_FALSE; + + if (*bp && xml->xml_class == JSXML_CLASS_ELEMENT) { + n = xml->xml_attrs.length; + if (n != vxml->xml_attrs.length) + *bp = JS_FALSE; + for (i = 0; *bp && i < n; i++) { + attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); + if (!attr) + continue; + j = XMLARRAY_FIND_MEMBER(&vxml->xml_attrs, attr, attr_identity); + if (j == XML_NOT_FOUND) { + *bp = JS_FALSE; + break; + } + vattr = XMLARRAY_MEMBER(&vxml->xml_attrs, j, JSXML); + if (!vattr) + continue; + *bp = js_EqualStrings(attr->xml_value, vattr->xml_value); + } + } + } + + return JS_TRUE; +} + +/* ECMA-357 9.1.1.9 XML [[Equals]] and 9.2.1.9 XMLList [[Equals]]. */ +static JSBool +Equals(JSContext *cx, JSXML *xml, jsval v, JSBool *bp) +{ + JSObject *vobj; + JSXML *vxml; + + if (JSVAL_IS_PRIMITIVE(v)) { + *bp = JS_FALSE; + if (xml->xml_class == JSXML_CLASS_LIST) { + if (xml->xml_kids.length == 1) { + vxml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (!vxml) + return JS_TRUE; + vobj = js_GetXMLObject(cx, vxml); + if (!vobj) + return JS_FALSE; + return js_XMLObjectOps.equality(cx, vobj, v, bp); + } + if (JSVAL_IS_VOID(v) && xml->xml_kids.length == 0) + *bp = JS_TRUE; + } + } else { + vobj = JSVAL_TO_OBJECT(v); + if (!OBJECT_IS_XML(cx, vobj)) { + *bp = JS_FALSE; + } else { + vxml = (JSXML *) JS_GetPrivate(cx, vobj); + if (!XMLEquals(cx, xml, vxml, bp)) + return JS_FALSE; + } + } + return JS_TRUE; +} + +static JSBool +CheckCycle(JSContext *cx, JSXML *xml, JSXML *kid) +{ + JS_ASSERT(kid->xml_class != JSXML_CLASS_LIST); + + do { + if (xml == kid) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CYCLIC_VALUE, js_XML_str); + return JS_FALSE; + } + } while ((xml = xml->parent) != NULL); + + return JS_TRUE; +} + +/* ECMA-357 9.1.1.11 XML [[Insert]]. */ +static JSBool +Insert(JSContext *cx, JSXML *xml, uint32 i, jsval v) +{ + uint32 j, n; + JSXML *vxml, *kid; + JSObject *vobj; + JSString *str; + + if (!JSXML_HAS_KIDS(xml)) + return JS_TRUE; + + n = 1; + vxml = NULL; + if (!JSVAL_IS_PRIMITIVE(v)) { + vobj = JSVAL_TO_OBJECT(v); + if (OBJECT_IS_XML(cx, vobj)) { + vxml = (JSXML *) JS_GetPrivate(cx, vobj); + if (vxml->xml_class == JSXML_CLASS_LIST) { + n = vxml->xml_kids.length; + if (n == 0) + return JS_TRUE; + for (j = 0; j < n; j++) { + kid = XMLARRAY_MEMBER(&vxml->xml_kids, j, JSXML); + if (!kid) + continue; + if (!CheckCycle(cx, xml, kid)) + return JS_FALSE; + } + } else if (vxml->xml_class == JSXML_CLASS_ELEMENT) { + /* OPTION: enforce that descendants have superset namespaces. */ + if (!CheckCycle(cx, xml, vxml)) + return JS_FALSE; + } + } + } + if (!vxml) { + str = js_ValueToString(cx, v); + if (!str) + return JS_FALSE; + + vxml = js_NewXML(cx, JSXML_CLASS_TEXT); + if (!vxml) + return JS_FALSE; + vxml->xml_value = str; + } + + if (i > xml->xml_kids.length) + i = xml->xml_kids.length; + + if (!XMLArrayInsert(cx, &xml->xml_kids, i, n)) + return JS_FALSE; + + if (vxml->xml_class == JSXML_CLASS_LIST) { + for (j = 0; j < n; j++) { + kid = XMLARRAY_MEMBER(&vxml->xml_kids, j, JSXML); + if (!kid) + continue; + kid->parent = xml; + XMLARRAY_SET_MEMBER(&xml->xml_kids, i + j, kid); + + /* OPTION: enforce that descendants have superset namespaces. */ + } + } else { + vxml->parent = xml; + XMLARRAY_SET_MEMBER(&xml->xml_kids, i, vxml); + } + return JS_TRUE; +} + +static JSBool +IndexToIdVal(JSContext *cx, uint32 index, jsval *idvp) +{ + JSString *str; + + if (index <= JSVAL_INT_MAX) { + *idvp = INT_TO_JSVAL(index); + } else { + str = js_NumberToString(cx, (jsdouble) index); + if (!str) + return JS_FALSE; + *idvp = STRING_TO_JSVAL(str); + } + return JS_TRUE; +} + +/* ECMA-357 9.1.1.12 XML [[Replace]]. */ +static JSBool +Replace(JSContext *cx, JSXML *xml, uint32 i, jsval v) +{ + uint32 n; + JSXML *vxml, *kid; + JSObject *vobj; + JSString *str; + + if (!JSXML_HAS_KIDS(xml)) + return JS_TRUE; + + /* + * 9.1.1.12 + * [[Replace]] handles _i >= x.[[Length]]_ by incrementing _x.[[Length]_. + * It should therefore constrain callers to pass in _i <= x.[[Length]]_. + */ + n = xml->xml_kids.length; + if (i > n) + i = n; + + vxml = NULL; + if (!JSVAL_IS_PRIMITIVE(v)) { + vobj = JSVAL_TO_OBJECT(v); + if (OBJECT_IS_XML(cx, vobj)) + vxml = (JSXML *) JS_GetPrivate(cx, vobj); + } + + switch (vxml ? vxml->xml_class : JSXML_CLASS_LIMIT) { + case JSXML_CLASS_ELEMENT: + /* OPTION: enforce that descendants have superset namespaces. */ + if (!CheckCycle(cx, xml, vxml)) + return JS_FALSE; + case JSXML_CLASS_COMMENT: + case JSXML_CLASS_PROCESSING_INSTRUCTION: + case JSXML_CLASS_TEXT: + goto do_replace; + + case JSXML_CLASS_LIST: + if (i < n) + DeleteByIndex(cx, xml, i); + if (!Insert(cx, xml, i, v)) + return JS_FALSE; + break; + + default: + str = js_ValueToString(cx, v); + if (!str) + return JS_FALSE; + + vxml = js_NewXML(cx, JSXML_CLASS_TEXT); + if (!vxml) + return JS_FALSE; + vxml->xml_value = str; + + do_replace: + vxml->parent = xml; + if (i < n) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid) + kid->parent = NULL; + } + if (!XMLARRAY_ADD_MEMBER(cx, &xml->xml_kids, i, vxml)) + return JS_FALSE; + break; + } + + return JS_TRUE; +} + +/* ECMA-357 9.1.1.3 XML [[Delete]], 9.2.1.3 XML [[Delete]] qname cases. */ +static void +DeleteNamedProperty(JSContext *cx, JSXML *xml, JSObject *nameqn, + JSBool attributes) +{ + JSXMLArray *array; + uint32 index, deleteCount; + JSXML *kid; + JSXMLNameMatcher matcher; + + if (xml->xml_class == JSXML_CLASS_LIST) { + array = &xml->xml_kids; + for (index = 0; index < array->length; index++) { + kid = XMLARRAY_MEMBER(array, index, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) + DeleteNamedProperty(cx, kid, nameqn, attributes); + } + } else if (xml->xml_class == JSXML_CLASS_ELEMENT) { + if (attributes) { + array = &xml->xml_attrs; + matcher = MatchAttrName; + } else { + array = &xml->xml_kids; + matcher = MatchElemName; + } + deleteCount = 0; + for (index = 0; index < array->length; index++) { + kid = XMLARRAY_MEMBER(array, index, JSXML); + if (kid && matcher(nameqn, kid)) { + kid->parent = NULL; + XMLArrayDelete(cx, array, index, JS_FALSE); + ++deleteCount; + } else if (deleteCount != 0) { + XMLARRAY_SET_MEMBER(array, + index - deleteCount, + array->vector[index]); + } + } + array->length -= deleteCount; + } +} + +/* ECMA-357 9.2.1.3 index case. */ +static void +DeleteListElement(JSContext *cx, JSXML *xml, uint32 index) +{ + JSXML *kid, *parent; + uint32 kidIndex; + + JS_ASSERT(xml->xml_class == JSXML_CLASS_LIST); + + if (index < xml->xml_kids.length) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); + if (kid) { + parent = kid->parent; + if (parent) { + JS_ASSERT(parent != xml); + JS_ASSERT(JSXML_HAS_KIDS(parent)); + + if (kid->xml_class == JSXML_CLASS_ATTRIBUTE) { + DeleteNamedProperty(cx, parent, kid->name, JS_TRUE); + } else { + kidIndex = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, + NULL); + JS_ASSERT(kidIndex != XML_NOT_FOUND); + DeleteByIndex(cx, parent, kidIndex); + } + } + XMLArrayDelete(cx, &xml->xml_kids, index, JS_TRUE); + } + } +} + +static JSBool +SyncInScopeNamespaces(JSContext *cx, JSXML *xml) +{ + JSXMLArray *nsarray; + uint32 i, n; + JSObject *ns; + + nsarray = &xml->xml_namespaces; + while ((xml = xml->parent) != NULL) { + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (ns && !XMLARRAY_HAS_MEMBER(nsarray, ns, namespace_identity)) { + if (!XMLARRAY_APPEND(cx, nsarray, ns)) + return JS_FALSE; + } + } + } + return JS_TRUE; +} + +static JSBool +GetNamedProperty(JSContext *cx, JSXML *xml, JSObject* nameqn, JSXML *list) +{ + JSXMLArray *array; + JSXMLNameMatcher matcher; + JSXMLArrayCursor cursor; + JSXML *kid; + JSBool attrs; + + if (xml->xml_class == JSXML_CLASS_LIST) { + XMLArrayCursorInit(&cursor, &xml->xml_kids); + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + if (kid->xml_class == JSXML_CLASS_ELEMENT && + !GetNamedProperty(cx, kid, nameqn, list)) { + break; + } + } + XMLArrayCursorFinish(&cursor); + if (kid) + return JS_FALSE; + } else if (xml->xml_class == JSXML_CLASS_ELEMENT) { + attrs = (OBJ_GET_CLASS(cx, nameqn) == &js_AttributeNameClass); + if (attrs) { + array = &xml->xml_attrs; + matcher = MatchAttrName; + } else { + array = &xml->xml_kids; + matcher = MatchElemName; + } + + XMLArrayCursorInit(&cursor, array); + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + if (matcher(nameqn, kid)) { + if (!attrs && + kid->xml_class == JSXML_CLASS_ELEMENT && + !SyncInScopeNamespaces(cx, kid)) { + break; + } + if (!Append(cx, list, kid)) + break; + } + } + XMLArrayCursorFinish(&cursor); + if (kid) + return JS_FALSE; + } + + return JS_TRUE; +} + +/* ECMA-357 9.1.1.1 XML [[Get]] and 9.2.1.1 XMLList [[Get]]. */ +static JSBool +GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSXML *xml, *list, *kid; + uint32 index; + JSObject *kidobj, *listobj; + JSObject *nameqn; + jsid funid; + jsval roots[2]; + JSTempValueRooter tvr; + + xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); + if (!xml) + return JS_TRUE; + + if (js_IdIsIndex(id, &index)) { + if (xml->xml_class != JSXML_CLASS_LIST) { + *vp = (index == 0) ? OBJECT_TO_JSVAL(obj) : JSVAL_VOID; + } else { + /* + * ECMA-357 9.2.1.1 starts here. + * + * Erratum: 9.2 is not completely clear that indexed properties + * correspond to kids, but that's what it seems to say, and it's + * what any sane user would want. + */ + if (index < xml->xml_kids.length) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); + if (!kid) { + *vp = JSVAL_VOID; + return JS_TRUE; + } + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + return JS_FALSE; + + *vp = OBJECT_TO_JSVAL(kidobj); + } else { + *vp = JSVAL_VOID; + } + } + return JS_TRUE; + } + + /* + * ECMA-357 9.2.1.1/9.1.1.1 qname case. + */ + nameqn = ToXMLName(cx, id, &funid); + if (!nameqn) + return JS_FALSE; + if (funid) + return js_GetXMLFunction(cx, obj, funid, vp); + + roots[0] = OBJECT_TO_JSVAL(nameqn); + JS_PUSH_TEMP_ROOT(cx, 1, roots, &tvr); + + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (listobj) { + roots[1] = OBJECT_TO_JSVAL(listobj); + tvr.count++; + + list = (JSXML *) JS_GetPrivate(cx, listobj); + if (!GetNamedProperty(cx, xml, nameqn, list)) { + listobj = NULL; + } else { + /* + * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the + * given list's [[TargetProperty]] to the property that is being + * appended. This means that any use of the internal [[Get]] + * property returns a list which, when used by e.g. [[Insert]] + * duplicates the last element matched by id. See bug 336921. + */ + list->xml_target = xml; + list->xml_targetprop = nameqn; + *vp = OBJECT_TO_JSVAL(listobj); + } + } + + JS_POP_TEMP_ROOT(cx, &tvr); + return listobj != NULL; +} + +static JSXML * +CopyOnWrite(JSContext *cx, JSXML *xml, JSObject *obj) +{ + JS_ASSERT(xml->object != obj); + + xml = DeepCopy(cx, xml, obj, 0); + if (!xml) + return NULL; + + JS_ASSERT(xml->object == obj); + return xml; +} + +#define CHECK_COPY_ON_WRITE(cx,xml,obj) \ + (xml->object == obj ? xml : CopyOnWrite(cx, xml, obj)) + +static JSString * +KidToString(JSContext *cx, JSXML *xml, uint32 index) +{ + JSXML *kid; + JSObject *kidobj; + + kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); + if (!kid) + return cx->runtime->emptyString; + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + return NULL; + return js_ValueToString(cx, OBJECT_TO_JSVAL(kidobj)); +} + +/* Forward declared -- its implementation uses other statics that call it. */ +static JSBool +ResolveValue(JSContext *cx, JSXML *list, JSXML **result); + +/* ECMA-357 9.1.1.2 XML [[Put]] and 9.2.1.2 XMLList [[Put]]. */ +static JSBool +PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSBool ok, primitiveAssign; + enum { OBJ_ROOT, ID_ROOT, VAL_ROOT }; + jsval roots[3]; + JSTempValueRooter tvr; + JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match; + JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj; + JSObject *targetprop, *nameqn, *attrqn; + uint32 index, i, j, k, n, q, matchIndex; + jsval attrval, nsval; + jsid funid; + JSString *left, *right, *space, *uri; + JSObject *ns; + + xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); + if (!xml) + return JS_TRUE; + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + /* Precompute vxml for 9.2.1.2 2(c)(vii)(2-3) and 2(d) and 9.1.1.2 1. */ + vxml = NULL; + if (!JSVAL_IS_PRIMITIVE(*vp)) { + vobj = JSVAL_TO_OBJECT(*vp); + if (OBJECT_IS_XML(cx, vobj)) + vxml = (JSXML *) JS_GetPrivate(cx, vobj); + } + + ok = js_EnterLocalRootScope(cx); + if (!ok) + return JS_FALSE; + MUST_FLOW_THROUGH("out"); + roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); + roots[ID_ROOT] = id; + roots[VAL_ROOT] = *vp; + JS_PUSH_TEMP_ROOT(cx, 3, roots, &tvr); + + if (js_IdIsIndex(id, &index)) { + if (xml->xml_class != JSXML_CLASS_LIST) { + /* See NOTE in spec: this variation is reserved for future use. */ + ReportBadXMLName(cx, id); + goto bad; + } + + /* + * Step 1 of ECMA-357 9.2.1.2 index case sets i to the property index. + */ + i = index; + + /* 2(a-b). */ + if (xml->xml_target) { + ok = ResolveValue(cx, xml->xml_target, &rxml); + if (!ok) + goto out; + if (!rxml) + goto out; + JS_ASSERT(rxml->object); + } else { + rxml = NULL; + } + + /* 2(c). */ + if (index >= xml->xml_kids.length) { + /* 2(c)(i). */ + if (rxml) { + if (rxml->xml_class == JSXML_CLASS_LIST) { + if (rxml->xml_kids.length != 1) + goto out; + rxml = XMLARRAY_MEMBER(&rxml->xml_kids, 0, JSXML); + if (!rxml) + goto out; + ok = js_GetXMLObject(cx, rxml) != NULL; + if (!ok) + goto out; + } + + /* + * Erratum: ECMA-357 9.2.1.2 step 2(c)(ii) sets + * _y.[[Parent]] = r_ where _r_ is the result of + * [[ResolveValue]] called on _x.[[TargetObject]] in + * 2(a)(i). This can result in text parenting text: + * + * var MYXML = new XML(); + * MYXML.appendChild(new XML("Giants")); + * + * (testcase from Werner Sharp ). + * + * To match insertChildAfter, insertChildBefore, + * prependChild, and setChildren, we should silently + * do nothing in this case. + */ + if (!JSXML_HAS_KIDS(rxml)) + goto out; + } + + /* 2(c)(ii) is distributed below as several js_NewXML calls. */ + targetprop = xml->xml_targetprop; + if (!targetprop || IS_STAR(GetLocalName(targetprop))) { + /* 2(c)(iv)(1-2), out of order w.r.t. 2(c)(iii). */ + kid = js_NewXML(cx, JSXML_CLASS_TEXT); + if (!kid) + goto bad; + } else { + nameobj = targetprop; + if (!nameobj) + goto bad; + if (OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass) { + /* + * 2(c)(iii)(1-3). + * Note that rxml can't be null here, because target + * and targetprop are non-null. + */ + ok = GetProperty(cx, rxml->object, id, &attrval); + if (!ok) + goto out; + if (JSVAL_IS_PRIMITIVE(attrval)) /* no such attribute */ + goto out; + attrobj = JSVAL_TO_OBJECT(attrval); + attr = (JSXML *) JS_GetPrivate(cx, attrobj); + if (JSXML_LENGTH(attr) != 0) + goto out; + + kid = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE); + } else { + /* 2(c)(v). */ + kid = js_NewXML(cx, JSXML_CLASS_ELEMENT); + } + if (!kid) + goto bad; + + /* An important bit of 2(c)(ii). */ + kid->name = targetprop; + } + + /* Final important bit of 2(c)(ii). */ + kid->parent = rxml; + + /* 2(c)(vi-vii). */ + i = xml->xml_kids.length; + if (kid->xml_class != JSXML_CLASS_ATTRIBUTE) { + /* + * 2(c)(vii)(1) tests whether _y.[[Parent]]_ is not null. + * y.[[Parent]] is here called kid->parent, which we know + * from 2(c)(ii) is _r_, here called rxml. So let's just + * test that! Erratum, the spec should be simpler here. + */ + if (rxml) { + JS_ASSERT(JSXML_HAS_KIDS(rxml)); + n = rxml->xml_kids.length; + j = n - 1; + if (n != 0 && i != 0) { + for (n = j, j = 0; j < n; j++) { + if (rxml->xml_kids.vector[j] == + xml->xml_kids.vector[i-1]) { + break; + } + } + } + + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + goto bad; + ok = Insert(cx, rxml, j + 1, OBJECT_TO_JSVAL(kidobj)); + if (!ok) + goto out; + } + + /* + * 2(c)(vii)(2-3). + * Erratum: [[PropertyName]] in 2(c)(vii)(3) must be a + * typo for [[TargetProperty]]. + */ + if (vxml) { + kid->name = (vxml->xml_class == JSXML_CLASS_LIST) + ? vxml->xml_targetprop + : vxml->name; + } + } + + /* 2(c)(viii). */ + ok = Append(cx, xml, kid); + if (!ok) + goto out; + } + + /* 2(d). */ + if (!vxml || + vxml->xml_class == JSXML_CLASS_TEXT || + vxml->xml_class == JSXML_CLASS_ATTRIBUTE) { + ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); + if (!ok) + goto out; + roots[VAL_ROOT] = *vp; + } + + /* 2(e). */ + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (!kid) + goto out; + parent = kid->parent; + if (kid->xml_class == JSXML_CLASS_ATTRIBUTE) { + nameobj = kid->name; + if (OBJ_GET_CLASS(cx, nameobj) != &js_AttributeNameClass) { + nameobj = NewXMLQName(cx, GetURI(nameobj), GetPrefix(nameobj), + GetLocalName(nameobj), + &js_AttributeNameClass); + if (!nameobj) + goto bad; + } + id = OBJECT_TO_JSVAL(nameobj); + + if (parent) { + /* 2(e)(i). */ + parentobj = js_GetXMLObject(cx, parent); + if (!parentobj) + goto bad; + ok = PutProperty(cx, parentobj, id, vp); + if (!ok) + goto out; + + /* 2(e)(ii). */ + ok = GetProperty(cx, parentobj, id, vp); + if (!ok) + goto out; + attr = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(*vp)); + + /* 2(e)(iii). */ + xml->xml_kids.vector[i] = attr->xml_kids.vector[0]; + } + } + + /* 2(f). */ + else if (vxml && vxml->xml_class == JSXML_CLASS_LIST) { + /* + * 2(f)(i) + * + * Erratum: the spec says to create a shallow copy _c_ of _V_, but + * if we do that we never change the parent of each child in the + * list. Since [[Put]] when called on an XML object deeply copies + * the provided list _V_, we also do so here. Perhaps the shallow + * copy was a misguided optimization? + */ + copy = DeepCopyInLRS(cx, vxml, 0); + if (!copy) + goto bad; + copyobj = js_GetXMLObject(cx, copy); + if (!copyobj) + goto bad; + + JS_ASSERT(parent != xml); + if (parent) { + q = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, NULL); + JS_ASSERT(q != XML_NOT_FOUND); + ok = Replace(cx, parent, q, OBJECT_TO_JSVAL(copyobj)); + if (!ok) + goto out; + +#ifdef DEBUG + /* Erratum: this loop in the spec is useless. */ + for (j = 0, n = copy->xml_kids.length; j < n; j++) { + kid2 = XMLARRAY_MEMBER(&parent->xml_kids, q + j, JSXML); + JS_ASSERT(XMLARRAY_MEMBER(©->xml_kids, j, JSXML) + == kid2); + } +#endif + } + + /* + * 2(f)(iv-vi). + * Erratum: notice the unhandled zero-length V basis case and + * the off-by-one errors for the n != 0 cases in the spec. + */ + n = copy->xml_kids.length; + if (n == 0) { + XMLArrayDelete(cx, &xml->xml_kids, i, JS_TRUE); + } else { + ok = XMLArrayInsert(cx, &xml->xml_kids, i + 1, n - 1); + if (!ok) + goto out; + + for (j = 0; j < n; j++) + xml->xml_kids.vector[i + j] = copy->xml_kids.vector[j]; + } + } + + /* 2(g). */ + else if (vxml || JSXML_HAS_VALUE(kid)) { + if (parent) { + q = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, NULL); + JS_ASSERT(q != XML_NOT_FOUND); + ok = Replace(cx, parent, q, *vp); + if (!ok) + goto out; + + vxml = XMLARRAY_MEMBER(&parent->xml_kids, q, JSXML); + if (!vxml) + goto out; + roots[VAL_ROOT] = *vp = OBJECT_TO_JSVAL(vxml->object); + } + + /* + * 2(g)(iii). + * Erratum: _V_ may not be of type XML, but all index-named + * properties _x[i]_ in an XMLList _x_ must be of type XML, + * according to 9.2.1.1 Overview and other places in the spec. + * + * Thanks to 2(d), we know _V_ (*vp here) is either a string + * or an XML/XMLList object. If *vp is a string, call ToXML + * on it to satisfy the constraint. + */ + if (!vxml) { + JS_ASSERT(JSVAL_IS_STRING(*vp)); + vobj = ToXML(cx, *vp); + if (!vobj) + goto bad; + roots[VAL_ROOT] = *vp = OBJECT_TO_JSVAL(vobj); + vxml = (JSXML *) JS_GetPrivate(cx, vobj); + } + XMLARRAY_SET_MEMBER(&xml->xml_kids, i, vxml); + } + + /* 2(h). */ + else { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + goto bad; + id = ATOM_KEY(cx->runtime->atomState.starAtom); + ok = PutProperty(cx, kidobj, id, vp); + if (!ok) + goto out; + } + } else { + /* + * ECMA-357 9.2.1.2/9.1.1.2 qname case. + */ + nameqn = ToXMLName(cx, id, &funid); + if (!nameqn) + goto bad; + if (funid) { + ok = js_SetProperty(cx, obj, funid, vp); + goto out; + } + nameobj = nameqn; + roots[ID_ROOT] = OBJECT_TO_JSVAL(nameobj); + + if (xml->xml_class == JSXML_CLASS_LIST) { + /* + * Step 3 of 9.2.1.2. + * Erratum: if x.[[Length]] > 1 or [[ResolveValue]] returns null + * or an r with r.[[Length]] != 1, throw TypeError. + */ + n = JSXML_LENGTH(xml); + if (n > 1) + goto type_error; + if (n == 0) { + ok = ResolveValue(cx, xml, &rxml); + if (!ok) + goto out; + if (!rxml || JSXML_LENGTH(rxml) != 1) + goto type_error; + ok = Append(cx, xml, rxml); + if (!ok) + goto out; + } + JS_ASSERT(JSXML_LENGTH(xml) == 1); + xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (!xml) + goto out; + JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); + obj = js_GetXMLObject(cx, xml); + if (!obj) + goto bad; + roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); + + /* FALL THROUGH to non-list case */ + } + + /* + * ECMA-357 9.1.1.2. + * Erratum: move steps 3 and 4 to before 1 and 2, to avoid wasted + * effort in ToString or [[DeepCopy]]. + */ + + if (JSXML_HAS_VALUE(xml)) + goto out; + + if (!vxml || + vxml->xml_class == JSXML_CLASS_TEXT || + vxml->xml_class == JSXML_CLASS_ATTRIBUTE) { + ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); + if (!ok) + goto out; + } else { + rxml = DeepCopyInLRS(cx, vxml, 0); + if (!rxml || !js_GetXMLObject(cx, rxml)) + goto bad; + vxml = rxml; + *vp = OBJECT_TO_JSVAL(vxml->object); + } + roots[VAL_ROOT] = *vp; + + /* + * 6. + * Erratum: why is this done here, so early? use is way later.... + */ + ok = js_GetDefaultXMLNamespace(cx, &nsval); + if (!ok) + goto out; + + if (OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass) { + /* 7(a). */ + if (!js_IsXMLName(cx, OBJECT_TO_JSVAL(nameobj))) + goto out; + + /* 7(b-c). */ + if (vxml && vxml->xml_class == JSXML_CLASS_LIST) { + n = vxml->xml_kids.length; + if (n == 0) { + *vp = STRING_TO_JSVAL(cx->runtime->emptyString); + } else { + left = KidToString(cx, vxml, 0); + if (!left) + goto bad; + + space = ATOM_TO_STRING(cx->runtime->atomState.spaceAtom); + for (i = 1; i < n; i++) { + left = js_ConcatStrings(cx, left, space); + if (!left) + goto bad; + right = KidToString(cx, vxml, i); + if (!right) + goto bad; + left = js_ConcatStrings(cx, left, right); + if (!left) + goto bad; + } + + roots[VAL_ROOT] = *vp = STRING_TO_JSVAL(left); + } + } else { + ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); + if (!ok) + goto out; + roots[VAL_ROOT] = *vp; + } + + /* 7(d-e). */ + match = NULL; + for (i = 0, n = xml->xml_attrs.length; i < n; i++) { + attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); + if (!attr) + continue; + attrqn = attr->name; + if (js_EqualStrings(GetLocalName(attrqn), + GetLocalName(nameqn))) { + uri = GetURI(nameqn); + if (!uri || js_EqualStrings(GetURI(attrqn), uri)) { + if (!match) { + match = attr; + } else { + DeleteNamedProperty(cx, xml, attrqn, JS_TRUE); + --i; + } + } + } + } + + /* 7(f). */ + attr = match; + if (!attr) { + /* 7(f)(i-ii). */ + uri = GetURI(nameqn); + if (!uri) { + left = right = cx->runtime->emptyString; + } else { + left = uri; + right = GetPrefix(nameqn); + } + nameqn = NewXMLQName(cx, left, right, GetLocalName(nameqn)); + if (!nameqn) + goto bad; + + /* 7(f)(iii). */ + attr = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE); + if (!attr) + goto bad; + attr->parent = xml; + attr->name = nameqn; + + /* 7(f)(iv). */ + ok = XMLARRAY_ADD_MEMBER(cx, &xml->xml_attrs, n, attr); + if (!ok) + goto out; + + /* 7(f)(v-vi). */ + ns = GetNamespace(cx, nameqn, NULL); + if (!ns) + goto bad; + ok = AddInScopeNamespace(cx, xml, ns); + if (!ok) + goto out; + } + + /* 7(g). */ + attr->xml_value = JSVAL_TO_STRING(*vp); + goto out; + } + + /* 8-9. */ + if (!js_IsXMLName(cx, OBJECT_TO_JSVAL(nameobj)) && + !IS_STAR(GetLocalName(nameqn))) { + goto out; + } + + /* 10-11. */ + id = JSVAL_VOID; + primitiveAssign = !vxml && !IS_STAR(GetLocalName(nameqn)); + + /* 12. */ + k = n = xml->xml_kids.length; + matchIndex = XML_NOT_FOUND; + kid2 = NULL; + while (k != 0) { + --k; + kid = XMLARRAY_MEMBER(&xml->xml_kids, k, JSXML); + if (kid && MatchElemName(nameqn, kid)) { + if (matchIndex != XML_NOT_FOUND) + DeleteByIndex(cx, xml, matchIndex); + matchIndex = k; + kid2 = kid; + } + } + + /* + * Erratum: ECMA-357 specified child insertion inconsistently: + * insertChildBefore and insertChildAfter insert an arbitrary XML + * instance, and therefore can create cycles, but appendChild as + * specified by the "Overview" of 13.4.4.3 calls [[DeepCopy]] on + * its argument. But the "Semantics" in 13.4.4.3 do not include + * any [[DeepCopy]] call. + * + * Fixing this (https://bugzilla.mozilla.org/show_bug.cgi?id=312692) + * required adding cycle detection, and allowing duplicate kids to + * be created (see comment 6 in the bug). Allowing duplicate kid + * references means the loop above will delete all but the lowest + * indexed reference, and each [[DeleteByIndex]] nulls the kid's + * parent. Thus the need to restore parent here. This is covered + * by https://bugzilla.mozilla.org/show_bug.cgi?id=327564. + */ + if (kid2) { + JS_ASSERT(kid2->parent == xml || !kid2->parent); + if (!kid2->parent) + kid2->parent = xml; + } + + /* 13. */ + if (matchIndex == XML_NOT_FOUND) { + /* 13(a). */ + matchIndex = n; + + /* 13(b). */ + if (primitiveAssign) { + uri = GetURI(nameqn); + if (!uri) { + ns = JSVAL_TO_OBJECT(nsval); + left = GetURI(ns); + right = GetPrefix(ns); + } else { + left = uri; + right = GetPrefix(nameqn); + } + nameqn = NewXMLQName(cx, left, right, GetLocalName(nameqn)); + if (!nameqn) + goto bad; + + /* 13(b)(iii). */ + vobj = js_NewXMLObject(cx, JSXML_CLASS_ELEMENT); + if (!vobj) + goto bad; + vxml = (JSXML *) JS_GetPrivate(cx, vobj); + vxml->parent = xml; + vxml->name = nameqn; + + /* 13(b)(iv-vi). */ + ns = GetNamespace(cx, nameqn, NULL); + if (!ns) + goto bad; + ok = Replace(cx, xml, matchIndex, OBJECT_TO_JSVAL(vobj)); + if (!ok) + goto out; + ok = AddInScopeNamespace(cx, vxml, ns); + if (!ok) + goto out; + } + } + + /* 14. */ + if (primitiveAssign) { + JSXMLArrayCursor cursor; + + XMLArrayCursorInit(&cursor, &xml->xml_kids); + cursor.index = matchIndex; + kid = (JSXML *) XMLArrayCursorItem(&cursor); + if (JSXML_HAS_KIDS(kid)) { + XMLArrayFinish(cx, &kid->xml_kids); + ok = XMLArrayInit(cx, &kid->xml_kids, 1); + } + + /* 14(b-c). */ + /* XXXbe Erratum? redundant w.r.t. 7(b-c) else clause above */ + if (ok) { + ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); + if (ok && !IS_EMPTY(JSVAL_TO_STRING(*vp))) { + roots[VAL_ROOT] = *vp; + if ((JSXML *) XMLArrayCursorItem(&cursor) == kid) + ok = Replace(cx, kid, 0, *vp); + } + } + XMLArrayCursorFinish(&cursor); + } else { + /* 15(a). */ + ok = Replace(cx, xml, matchIndex, *vp); + } + } + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + js_LeaveLocalRootScope(cx); + return ok; + +type_error: + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_XMLLIST_PUT, + js_ValueToPrintableString(cx, id)); +bad: + ok = JS_FALSE; + goto out; +} + +/* ECMA-357 9.1.1.10 XML [[ResolveValue]], 9.2.1.10 XMLList [[ResolveValue]]. */ +static JSBool +ResolveValue(JSContext *cx, JSXML *list, JSXML **result) +{ + JSXML *target, *base; + JSObject *targetprop; + jsval id, tv; + + /* Our caller must be protecting newborn objects. */ + JS_ASSERT(cx->localRootStack); + + if (list->xml_class != JSXML_CLASS_LIST || list->xml_kids.length != 0) { + if (!js_GetXMLObject(cx, list)) + return JS_FALSE; + *result = list; + return JS_TRUE; + } + + target = list->xml_target; + targetprop = list->xml_targetprop; + if (!target || !targetprop || IS_STAR(GetLocalName(targetprop))) { + *result = NULL; + return JS_TRUE; + } + + if (OBJ_GET_CLASS(cx, targetprop) == &js_AttributeNameClass) { + *result = NULL; + return JS_TRUE; + } + + if (!ResolveValue(cx, target, &base)) + return JS_FALSE; + if (!base) { + *result = NULL; + return JS_TRUE; + } + if (!js_GetXMLObject(cx, base)) + return JS_FALSE; + + id = OBJECT_TO_JSVAL(targetprop); + if (!GetProperty(cx, base->object, id, &tv)) + return JS_FALSE; + target = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(tv)); + + if (JSXML_LENGTH(target) == 0) { + if (base->xml_class == JSXML_CLASS_LIST && JSXML_LENGTH(base) > 1) { + *result = NULL; + return JS_TRUE; + } + tv = STRING_TO_JSVAL(cx->runtime->emptyString); + if (!PutProperty(cx, base->object, id, &tv)) + return JS_FALSE; + if (!GetProperty(cx, base->object, id, &tv)) + return JS_FALSE; + target = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(tv)); + } + + *result = target; + return JS_TRUE; +} + +static JSBool +HasNamedProperty(JSXML *xml, JSObject *nameqn) +{ + JSBool found; + JSXMLArrayCursor cursor; + JSXML *kid; + JSXMLArray *array; + JSXMLNameMatcher matcher; + uint32 i, n; + + if (xml->xml_class == JSXML_CLASS_LIST) { + found = JS_FALSE; + XMLArrayCursorInit(&cursor, &xml->xml_kids); + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + found = HasNamedProperty(kid, nameqn); + if (found) + break; + } + XMLArrayCursorFinish(&cursor); + return found; + } + + if (xml->xml_class == JSXML_CLASS_ELEMENT) { + if (OBJ_GET_CLASS(cx, nameqn) == &js_AttributeNameClass) { + array = &xml->xml_attrs; + matcher = MatchAttrName; + } else { + array = &xml->xml_kids; + matcher = MatchElemName; + } + for (i = 0, n = array->length; i < n; i++) { + kid = XMLARRAY_MEMBER(array, i, JSXML); + if (kid && matcher(nameqn, kid)) + return JS_TRUE; + } + } + + return JS_FALSE; +} + +static JSBool +HasIndexedProperty(JSXML *xml, uint32 i) +{ + if (xml->xml_class == JSXML_CLASS_LIST) + return i < JSXML_LENGTH(xml); + + if (xml->xml_class == JSXML_CLASS_ELEMENT) + return i == 0; + + return JS_FALSE; +} + +static JSBool +HasSimpleContent(JSXML *xml); + +static JSBool +HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found) +{ + JSObject *pobj; + JSProperty *prop; + JSXML *xml; + JSTempValueRooter tvr; + JSBool ok; + + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_XMLClass); + + if (!js_LookupProperty(cx, obj, funid, &pobj, &prop)) + return JS_FALSE; + if (prop) { + OBJ_DROP_PROPERTY(cx, pobj, prop); + } else { + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (HasSimpleContent(xml)) { + /* + * Search in String.prototype to set found whenever + * js_GetXMLFunction returns existing function. + */ + JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); + ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(JSProto_String), + &tvr.u.object); + JS_ASSERT(tvr.u.object); + if (ok) { + ok = js_LookupProperty(cx, tvr.u.object, funid, &pobj, &prop); + if (ok && prop) + OBJ_DROP_PROPERTY(cx, pobj, prop); + } + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return JS_FALSE; + } + } + *found = (prop != NULL); + return JS_TRUE; +} + +/* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */ +static JSBool +HasProperty(JSContext *cx, JSObject *obj, jsval id, JSBool *found) +{ + JSXML *xml; + uint32 i; + JSObject *qn; + jsid funid; + + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (js_IdIsIndex(id, &i)) { + *found = HasIndexedProperty(xml, i); + } else { + qn = ToXMLName(cx, id, &funid); + if (!qn) + return JS_FALSE; + if (funid) { + if (!HasFunctionProperty(cx, obj, funid, found)) + return JS_FALSE; + } else { + *found = HasNamedProperty(xml, qn); + } + } + return JS_TRUE; +} + +static void +xml_finalize(JSContext *cx, JSObject *obj) +{ + JSXML *xml; + + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (!xml) + return; + if (xml->object == obj) + xml->object = NULL; +} + +static void +xml_trace_vector(JSTracer *trc, JSXML **vec, uint32 len) +{ + uint32 i; + JSXML *xml; + + for (i = 0; i < len; i++) { + xml = vec[i]; + if (xml) { + JS_SET_TRACING_INDEX(trc, "xml_vector", i); + JS_CallTracer(trc, xml, JSTRACE_XML); + } + } +} + +/* + * js_XMLObjectOps.newObjectMap == js_NewObjectMap, so XML objects appear to + * be native. Therefore, xml_lookupProperty must return a valid JSProperty + * pointer parameter via *propp to signify "property found". Since the only + * call to xml_lookupProperty is via OBJ_LOOKUP_PROPERTY, and then only from + * js_FindProperty (in jsobj.c, called from jsinterp.c) or from JSOP_IN case + * in the interpreter, the only time we add a JSScopeProperty here is when an + * unqualified name is being accessed or when "name in xml" is called. + * + * This scope property keeps the JSOP_NAME code in js_Interpret happy by + * giving it an sprop with (getter, setter) == (GetProperty, PutProperty). + * + * NB: xml_deleteProperty must take care to remove any property added here. + * + * FIXME This clashes with the function namespace implementation which also + * uses native properties. Effectively after xml_lookupProperty any property + * stored previously using assignments to xml.function::name will be removed. + * We partially workaround the problem in js_GetXMLFunction. There we take + * advantage of the fact that typically function:: is used to access the + * functions from XML.prototype. So when js_GetProperty returns a non-function + * property, we assume that it represents the result of GetProperty setter + * hiding the function and use an extra prototype chain lookup to recover it. + * For a proper solution see bug 355257. +*/ +static JSBool +xml_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp) +{ + jsval v; + JSBool found; + JSXML *xml; + uint32 i; + JSObject *qn; + jsid funid; + JSScopeProperty *sprop; + + v = ID_TO_VALUE(id); + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (js_IdIsIndex(v, &i)) { + found = HasIndexedProperty(xml, i); + } else { + qn = ToXMLName(cx, v, &funid); + if (!qn) + return JS_FALSE; + if (funid) + return js_LookupProperty(cx, obj, funid, objp, propp); + found = HasNamedProperty(xml, qn); + } + if (!found) { + *objp = NULL; + *propp = NULL; + } else { + sprop = js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, + SPROP_INVALID_SLOT, JSPROP_ENUMERATE, + 0, 0); + if (!sprop) + return JS_FALSE; + + JS_LOCK_OBJ(cx, obj); + *objp = obj; + *propp = (JSProperty *) sprop; + } + return JS_TRUE; +} + +static JSBool +xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + JSProperty **propp) +{ + if (VALUE_IS_FUNCTION(cx, value) || getter || setter || + (attrs & JSPROP_ENUMERATE) == 0 || + (attrs & (JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED))) { + return js_DefineProperty(cx, obj, id, value, getter, setter, attrs, + propp); + } + + if (!PutProperty(cx, obj, ID_TO_VALUE(id), &value)) + return JS_FALSE; + if (propp) + *propp = NULL; + return JS_TRUE; +} + +static JSBool +xml_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + if (id == JS_DEFAULT_XML_NAMESPACE_ID) { + *vp = JSVAL_VOID; + return JS_TRUE; + } + + return GetProperty(cx, obj, ID_TO_VALUE(id), vp); +} + +static JSBool +xml_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return PutProperty(cx, obj, ID_TO_VALUE(id), vp); +} + +static JSBool +FoundProperty(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + JSBool *foundp) +{ + if (!prop) + return HasProperty(cx, obj, ID_TO_VALUE(id), foundp); + + *foundp = JS_TRUE; + return JS_TRUE; +} + +static JSBool +xml_getAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp) +{ + JSBool found; + + if (!FoundProperty(cx, obj, id, prop, &found)) + return JS_FALSE; + *attrsp = found ? JSPROP_ENUMERATE : 0; + return JS_TRUE; +} + +static JSBool +xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp) +{ + JSBool found; + + if (!FoundProperty(cx, obj, id, prop, &found)) + return JS_FALSE; + if (found) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_SET_XML_ATTRS); + } + return !found; +} + +static JSBool +xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) +{ + JSXML *xml; + jsval idval; + uint32 index; + JSObject *nameqn; + jsid funid; + + idval = ID_TO_VALUE(id); + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (js_IdIsIndex(idval, &index)) { + if (xml->xml_class != JSXML_CLASS_LIST) { + /* See NOTE in spec: this variation is reserved for future use. */ + ReportBadXMLName(cx, id); + return JS_FALSE; + } + + /* ECMA-357 9.2.1.3. */ + DeleteListElement(cx, xml, index); + } else { + nameqn = ToXMLName(cx, idval, &funid); + if (!nameqn) + return JS_FALSE; + if (funid) + return js_DeleteProperty(cx, obj, funid, rval); + + DeleteNamedProperty(cx, xml, nameqn, + OBJ_GET_CLASS(cx, nameqn) == + &js_AttributeNameClass); + } + + /* + * If this object has its own (mutable) scope, then we may have added a + * property to the scope in xml_lookupProperty for it to return to mean + * "found" and to provide a handle for access operations to call the + * property's getter or setter. But now it's time to remove any such + * property, to purge the property cache and remove the scope entry. + */ + if (OBJ_SCOPE(obj)->object == obj && !js_DeleteProperty(cx, obj, id, rval)) + return JS_FALSE; + + *rval = JSVAL_TRUE; + return JS_TRUE; +} + +static JSBool +xml_defaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp) +{ + JSXML *xml; + + if (hint == JSTYPE_OBJECT) { + /* Called from for..in code in js_Interpret: return an XMLList. */ + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (xml->xml_class != JSXML_CLASS_LIST) { + obj = ToXMLList(cx, OBJECT_TO_JSVAL(obj)); + if (!obj) + return JS_FALSE; + } + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; + } + + return JS_CallFunctionName(cx, obj, js_toString_str, 0, NULL, vp); +} + +static JSBool +xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp) +{ + JSXML *xml; + uint32 length, index; + JSXMLArrayCursor *cursor; + + xml = (JSXML *) JS_GetPrivate(cx, obj); + length = JSXML_LENGTH(xml); + + switch (enum_op) { + case JSENUMERATE_INIT: + if (length == 0) { + cursor = NULL; + } else { + cursor = (JSXMLArrayCursor *) JS_malloc(cx, sizeof *cursor); + if (!cursor) + return JS_FALSE; + XMLArrayCursorInit(cursor, &xml->xml_kids); + } + *statep = PRIVATE_TO_JSVAL(cursor); + if (idp) + *idp = INT_TO_JSID(length); + break; + + case JSENUMERATE_NEXT: + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor && cursor->array && (index = cursor->index) < length) { + *idp = INT_TO_JSID(index); + cursor->index = index + 1; + break; + } + /* FALL THROUGH */ + + case JSENUMERATE_DESTROY: + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor) { + XMLArrayCursorFinish(cursor); + JS_free(cx, cursor); + } + *statep = JSVAL_NULL; + break; + } + return JS_TRUE; +} + +static JSBool +xml_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +{ + return JS_TRUE; +} + +static void +xml_trace(JSTracer *trc, JSObject *obj) +{ + JSXML *xml; + + xml = (JSXML *) JS_GetPrivate(trc->context, obj); + if (xml) + JS_CALL_TRACER(trc, xml, JSTRACE_XML, "private"); +} + +static void +xml_clear(JSContext *cx, JSObject *obj) +{ +} + +static JSBool +HasSimpleContent(JSXML *xml) +{ + JSXML *kid; + JSBool simple; + uint32 i, n; + +again: + switch (xml->xml_class) { + case JSXML_CLASS_COMMENT: + case JSXML_CLASS_PROCESSING_INSTRUCTION: + return JS_FALSE; + case JSXML_CLASS_LIST: + if (xml->xml_kids.length == 0) + return JS_TRUE; + if (xml->xml_kids.length == 1) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (kid) { + xml = kid; + goto again; + } + } + /* FALL THROUGH */ + default: + simple = JS_TRUE; + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + simple = JS_FALSE; + break; + } + } + return simple; + } +} + +/* + * 11.2.2.1 Step 3(d) onward. + */ +static JSObject * +xml_getMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + JSTempValueRooter tvr; + + JS_ASSERT(JS_InstanceOf(cx, obj, &js_XMLClass, NULL)); + + /* + * As our callers have a bad habit of passing a pointer to an unrooted + * local value as vp, we use a proper root here. + */ + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); + if (!js_GetXMLFunction(cx, obj, id, &tvr.u.value)) + obj = NULL; + *vp = tvr.u.value; + JS_POP_TEMP_ROOT(cx, &tvr); + return obj; +} + +static JSBool +xml_setMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return js_SetProperty(cx, obj, id, vp); +} + +static JSBool +xml_enumerateValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + jsval *statep, jsid *idp, jsval *vp) +{ + JSXML *xml, *kid; + uint32 length, index; + JSXMLArrayCursor *cursor; + JSObject *kidobj; + + xml = (JSXML *) JS_GetPrivate(cx, obj); + length = JSXML_LENGTH(xml); + JS_ASSERT(INT_FITS_IN_JSVAL(length)); + + switch (enum_op) { + case JSENUMERATE_INIT: + if (length == 0) { + cursor = NULL; + } else { + cursor = (JSXMLArrayCursor *) JS_malloc(cx, sizeof *cursor); + if (!cursor) + return JS_FALSE; + XMLArrayCursorInit(cursor, &xml->xml_kids); + } + *statep = PRIVATE_TO_JSVAL(cursor); + if (idp) + *idp = INT_TO_JSID(length); + if (vp) + *vp = JSVAL_VOID; + break; + + case JSENUMERATE_NEXT: + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor && cursor->array && (index = cursor->index) < length) { + while (!(kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML))) { + if (++index == length) + goto destroy; + } + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + return JS_FALSE; + JS_ASSERT(INT_FITS_IN_JSVAL(index)); + *idp = INT_TO_JSID(index); + *vp = OBJECT_TO_JSVAL(kidobj); + cursor->index = index + 1; + break; + } + /* FALL THROUGH */ + + case JSENUMERATE_DESTROY: + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor) { + destroy: + XMLArrayCursorFinish(cursor); + JS_free(cx, cursor); + } + *statep = JSVAL_NULL; + break; + } + return JS_TRUE; +} + +static JSBool +xml_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +{ + JSXML *xml, *vxml; + JSObject *vobj; + JSBool ok; + JSString *str, *vstr; + jsdouble d, d2; + + xml = (JSXML *) JS_GetPrivate(cx, obj); + vxml = NULL; + if (!JSVAL_IS_PRIMITIVE(v)) { + vobj = JSVAL_TO_OBJECT(v); + if (OBJECT_IS_XML(cx, vobj)) + vxml = (JSXML *) JS_GetPrivate(cx, vobj); + } + + if (xml->xml_class == JSXML_CLASS_LIST) { + ok = Equals(cx, xml, v, bp); + } else if (vxml) { + if (vxml->xml_class == JSXML_CLASS_LIST) { + ok = Equals(cx, vxml, OBJECT_TO_JSVAL(obj), bp); + } else { + if (((xml->xml_class == JSXML_CLASS_TEXT || + xml->xml_class == JSXML_CLASS_ATTRIBUTE) && + HasSimpleContent(vxml)) || + ((vxml->xml_class == JSXML_CLASS_TEXT || + vxml->xml_class == JSXML_CLASS_ATTRIBUTE) && + HasSimpleContent(xml))) { + ok = js_EnterLocalRootScope(cx); + if (ok) { + str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + vstr = js_ValueToString(cx, v); + ok = str && vstr; + if (ok) + *bp = js_EqualStrings(str, vstr); + js_LeaveLocalRootScope(cx); + } + } else { + ok = XMLEquals(cx, xml, vxml, bp); + } + } + } else { + ok = js_EnterLocalRootScope(cx); + if (ok) { + if (HasSimpleContent(xml)) { + str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + vstr = js_ValueToString(cx, v); + ok = str && vstr; + if (ok) + *bp = js_EqualStrings(str, vstr); + } else if (JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v)) { + str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + if (!str) { + ok = JS_FALSE; + } else if (JSVAL_IS_STRING(v)) { + *bp = js_EqualStrings(str, JSVAL_TO_STRING(v)); + } else { + ok = JS_ValueToNumber(cx, STRING_TO_JSVAL(str), &d); + if (ok) { + d2 = JSVAL_IS_INT(v) ? JSVAL_TO_INT(v) + : *JSVAL_TO_DOUBLE(v); + *bp = JSDOUBLE_COMPARE(d, ==, d2, JS_FALSE); + } + } + } else { + *bp = JS_FALSE; + } + js_LeaveLocalRootScope(cx); + } + } + return ok; +} + +static JSBool +xml_concatenate(JSContext *cx, JSObject *obj, jsval v, jsval *vp) +{ + JSBool ok; + JSObject *listobj, *robj; + JSXML *list, *lxml, *rxml; + + ok = js_EnterLocalRootScope(cx); + if (!ok) + return JS_FALSE; + + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) { + ok = JS_FALSE; + goto out; + } + + list = (JSXML *) JS_GetPrivate(cx, listobj); + lxml = (JSXML *) JS_GetPrivate(cx, obj); + ok = Append(cx, list, lxml); + if (!ok) + goto out; + + if (VALUE_IS_XML(cx, v)) { + rxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + } else { + robj = ToXML(cx, v); + if (!robj) { + ok = JS_FALSE; + goto out; + } + rxml = (JSXML *) JS_GetPrivate(cx, robj); + } + ok = Append(cx, list, rxml); + if (!ok) + goto out; + + *vp = OBJECT_TO_JSVAL(listobj); +out: + js_LeaveLocalRootScopeWithResult(cx, *vp); + return ok; +} + +/* Use js_NewObjectMap so XML objects satisfy OBJ_IS_NATIVE tests. */ +JS_FRIEND_DATA(JSXMLObjectOps) js_XMLObjectOps = { + { js_NewObjectMap, js_DestroyObjectMap, + xml_lookupProperty, xml_defineProperty, + xml_getProperty, xml_setProperty, + xml_getAttributes, xml_setAttributes, + xml_deleteProperty, xml_defaultValue, + xml_enumerate, js_CheckAccess, + NULL, NULL, + NULL, NULL, + NULL, xml_hasInstance, + js_SetProtoOrParent, js_SetProtoOrParent, + js_TraceObject, xml_clear, + NULL, NULL }, + xml_getMethod, xml_setMethod, + xml_enumerateValues, xml_equality, + xml_concatenate +}; + +static JSObjectOps * +xml_getObjectOps(JSContext *cx, JSClass *clasp) +{ + return &js_XMLObjectOps.base; +} + +JS_FRIEND_DATA(JSClass) js_XMLClass = { + js_XML_str, + JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE | + JSCLASS_HAS_CACHED_PROTO(JSProto_XML), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, xml_finalize, + xml_getObjectOps, NULL, NULL, NULL, + NULL, NULL, JS_CLASS_TRACE(xml_trace), NULL +}; + +static JSXML * +StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp) +{ + JSXML *xml; + JSFunction *fun; + char numBuf[12]; + + JS_ASSERT(VALUE_IS_FUNCTION(cx, *vp)); + + *objp = JS_THIS_OBJECT(cx, vp); + xml = (JSXML *) JS_GetInstancePrivate(cx, *objp, &js_XMLClass, vp + 2); + if (!xml || xml->xml_class != JSXML_CLASS_LIST) + return xml; + + if (xml->xml_kids.length == 1) { + xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (xml) { + *objp = js_GetXMLObject(cx, xml); + if (!*objp) + return NULL; + vp[1] = OBJECT_TO_JSVAL(*objp); + return xml; + } + } + + fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(*vp)); + JS_snprintf(numBuf, sizeof numBuf, "%u", xml->xml_kids.length); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_NON_LIST_XML_METHOD, + JS_GetFunctionName(fun), numBuf); + return NULL; +} + +/* Beware: these two are not bracketed by JS_BEGIN/END_MACRO. */ +#define XML_METHOD_PROLOG \ + JSObject *obj = JS_THIS_OBJECT(cx, vp); \ + JSXML *xml = (JSXML *)JS_GetInstancePrivate(cx, obj, &js_XMLClass, vp+2); \ + if (!xml) \ + return JS_FALSE + +#define NON_LIST_XML_METHOD_PROLOG \ + JSObject *obj; \ + JSXML *xml = StartNonListXMLMethod(cx, vp, &obj); \ + if (!xml) \ + return JS_FALSE; \ + JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST) + +static JSBool +xml_addNamespace(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *ns; + + NON_LIST_XML_METHOD_PROLOG; + if (xml->xml_class != JSXML_CLASS_ELEMENT) + goto done; + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + if (!NamespaceHelper(cx, NULL, argc == 0 ? -1 : 1, vp + 2, vp)) + return JS_FALSE; + JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp)); + + ns = JSVAL_TO_OBJECT(*vp); + if (!AddInScopeNamespace(cx, xml, ns)) + return JS_FALSE; + ns->fslots[JSSLOT_DECLARED] = JSVAL_TRUE; + + done: + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static JSBool +xml_appendChild(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name, v; + JSObject *vobj; + JSXML *vxml; + + NON_LIST_XML_METHOD_PROLOG; + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + if (!js_GetAnyName(cx, &name)) + return JS_FALSE; + + if (!GetProperty(cx, obj, name, &v)) + return JS_FALSE; + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + vobj = JSVAL_TO_OBJECT(v); + JS_ASSERT(OBJECT_IS_XML(cx, vobj)); + vxml = (JSXML *) JS_GetPrivate(cx, vobj); + JS_ASSERT(vxml->xml_class == JSXML_CLASS_LIST); + + if (!IndexToIdVal(cx, vxml->xml_kids.length, &name)) + return JS_FALSE; + *vp = (argc != 0) ? vp[2] : JSVAL_VOID; + if (!PutProperty(cx, JSVAL_TO_OBJECT(v), name, vp)) + return JS_FALSE; + + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_attribute(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *qn; + + if (argc == 0) { + js_ReportMissingArg(cx, vp, 0); + return JS_FALSE; + } + + qn = ToAttributeName(cx, vp[2]); + if (!qn) + return JS_FALSE; + vp[2] = OBJECT_TO_JSVAL(qn); /* local root */ + + return GetProperty(cx, JS_THIS_OBJECT(cx, vp), vp[2], vp); +} + +/* XML and XMLList */ +static JSBool +xml_attributes(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSObject *qn; + JSTempValueRooter tvr; + JSBool ok; + + name = ATOM_KEY(cx->runtime->atomState.starAtom); + qn = ToAttributeName(cx, name); + if (!qn) + return JS_FALSE; + name = OBJECT_TO_JSVAL(qn); + JS_PUSH_SINGLE_TEMP_ROOT(cx, name, &tvr); + ok = GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp); + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +static JSXML * +xml_list_helper(JSContext *cx, JSXML *xml, jsval *rval) +{ + JSObject *listobj; + JSXML *list; + + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) + return NULL; + + *rval = OBJECT_TO_JSVAL(listobj); + list = (JSXML *) JS_GetPrivate(cx, listobj); + list->xml_target = xml; + return list; +} + +static JSBool +xml_child_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval name, + jsval *rval) +{ + uint32 index; + JSXML *kid; + JSObject *kidobj; + + /* ECMA-357 13.4.4.6 */ + JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); + + if (js_IdIsIndex(name, &index)) { + if (index >= JSXML_LENGTH(xml)) { + *rval = JSVAL_VOID; + } else { + kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); + if (!kid) { + *rval = JSVAL_VOID; + } else { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(kidobj); + } + } + return JS_TRUE; + } + + return GetProperty(cx, obj, name, rval); +} + +/* XML and XMLList */ +static JSBool +xml_child(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name, v; + JSXML *list, *kid, *vxml; + JSXMLArrayCursor cursor; + JSObject *kidobj; + + XML_METHOD_PROLOG; + name = argc != 0 ? vp[2] : JSVAL_VOID; + if (xml->xml_class == JSXML_CLASS_LIST) { + /* ECMA-357 13.5.4.4 */ + list = xml_list_helper(cx, xml, vp); + if (!list) + return JS_FALSE; + + XMLArrayCursorInit(&cursor, &xml->xml_kids); + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + break; + if (!xml_child_helper(cx, kidobj, kid, name, &v)) + break; + if (JSVAL_IS_VOID(v)) { + /* The property didn't exist in this kid. */ + continue; + } + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + if ((!JSXML_HAS_KIDS(vxml) || vxml->xml_kids.length != 0) && + !Append(cx, list, vxml)) { + break; + } + } + XMLArrayCursorFinish(&cursor); + return !kid; + } + + /* ECMA-357 Edition 2 13.3.4.6 (note 13.3, not 13.4 as in Edition 1). */ + if (!xml_child_helper(cx, obj, xml, name, vp)) + return JS_FALSE; + if (JSVAL_IS_VOID(*vp) && !xml_list_helper(cx, xml, vp)) + return JS_FALSE; + return JS_TRUE; +} + +static JSBool +xml_childIndex(JSContext *cx, uintN argc, jsval *vp) +{ + JSXML *parent; + uint32 i, n; + + NON_LIST_XML_METHOD_PROLOG; + parent = xml->parent; + if (!parent || xml->xml_class == JSXML_CLASS_ATTRIBUTE) { + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; + } + for (i = 0, n = JSXML_LENGTH(parent); i < n; i++) { + if (XMLARRAY_MEMBER(&parent->xml_kids, i, JSXML) == xml) + break; + } + JS_ASSERT(i < n); + return js_NewNumberInRootedValue(cx, i, vp); +} + +/* XML and XMLList */ +static JSBool +xml_children(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + + name = ATOM_KEY(cx->runtime->atomState.starAtom); + return GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp); +} + +/* XML and XMLList */ +static JSBool +xml_comments_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval *vp) +{ + JSXML *list, *kid, *vxml; + JSBool ok; + uint32 i, n; + JSObject *kidobj; + jsval v; + + list = xml_list_helper(cx, xml, vp); + if (!list) + return JS_FALSE; + + ok = JS_TRUE; + + if (xml->xml_class == JSXML_CLASS_LIST) { + /* 13.5.4.6 Step 2. */ + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + ok = js_EnterLocalRootScope(cx); + if (!ok) + break; + kidobj = js_GetXMLObject(cx, kid); + if (kidobj) { + ok = xml_comments_helper(cx, kidobj, kid, &v); + } else { + ok = JS_FALSE; + v = JSVAL_NULL; + } + js_LeaveLocalRootScopeWithResult(cx, v); + if (!ok) + break; + vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + if (JSXML_LENGTH(vxml) != 0) { + ok = Append(cx, list, vxml); + if (!ok) + break; + } + } + } + } else { + /* 13.4.4.9 Step 2. */ + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_COMMENT) { + ok = Append(cx, list, kid); + if (!ok) + break; + } + } + } + + return ok; +} + +static JSBool +xml_comments(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + return xml_comments_helper(cx, obj, xml, vp); +} + +/* XML and XMLList */ +static JSBool +xml_contains(JSContext *cx, uintN argc, jsval *vp) +{ + jsval value; + JSBool eq; + JSXMLArrayCursor cursor; + JSXML *kid; + JSObject *kidobj; + + XML_METHOD_PROLOG; + value = argc != 0 ? vp[2] : JSVAL_VOID; + if (xml->xml_class == JSXML_CLASS_LIST) { + eq = JS_FALSE; + XMLArrayCursorInit(&cursor, &xml->xml_kids); + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj || !xml_equality(cx, kidobj, value, &eq)) + break; + if (eq) + break; + } + XMLArrayCursorFinish(&cursor); + if (kid && !eq) + return JS_FALSE; + } else { + if (!xml_equality(cx, obj, value, &eq)) + return JS_FALSE; + } + *vp = BOOLEAN_TO_JSVAL(eq); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_copy(JSContext *cx, uintN argc, jsval *vp) +{ + JSXML *copy; + + XML_METHOD_PROLOG; + copy = DeepCopy(cx, xml, NULL, 0); + if (!copy) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(copy->object); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_descendants(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSXML *list; + + XML_METHOD_PROLOG; + name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : vp[2]; + list = Descendants(cx, xml, name); + if (!list) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(list->object); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_elements_helper(JSContext *cx, JSObject *obj, JSXML *xml, + JSObject *nameqn, jsval *vp) +{ + JSXML *list, *kid, *vxml; + jsval v; + JSBool ok; + JSXMLArrayCursor cursor; + JSObject *kidobj; + uint32 i, n; + + list = xml_list_helper(cx, xml, vp); + if (!list) + return JS_FALSE; + + list->xml_targetprop = nameqn; + ok = JS_TRUE; + + if (xml->xml_class == JSXML_CLASS_LIST) { + /* 13.5.4.6 */ + XMLArrayCursorInit(&cursor, &xml->xml_kids); + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + if (kid->xml_class == JSXML_CLASS_ELEMENT) { + ok = js_EnterLocalRootScope(cx); + if (!ok) + break; + kidobj = js_GetXMLObject(cx, kid); + if (kidobj) { + ok = xml_elements_helper(cx, kidobj, kid, nameqn, &v); + } else { + ok = JS_FALSE; + v = JSVAL_NULL; + } + js_LeaveLocalRootScopeWithResult(cx, v); + if (!ok) + break; + vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + if (JSXML_LENGTH(vxml) != 0) { + ok = Append(cx, list, vxml); + if (!ok) + break; + } + } + } + XMLArrayCursorFinish(&cursor); + } else { + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT && + MatchElemName(nameqn, kid)) { + ok = Append(cx, list, kid); + if (!ok) + break; + } + } + } + + return ok; +} + +static JSBool +xml_elements(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSObject *nameqn; + jsid funid; + + XML_METHOD_PROLOG; + + name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : vp[2]; + nameqn = ToXMLName(cx, name, &funid); + if (!nameqn) + return JS_FALSE; + vp[2] = OBJECT_TO_JSVAL(nameqn); + + if (funid) + return xml_list_helper(cx, xml, vp) != NULL; + + return xml_elements_helper(cx, obj, xml, nameqn, vp); +} + +/* XML and XMLList */ +static JSBool +xml_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + jsval name; + JSBool found; + + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_XMLClass, vp + 2)) + return JS_FALSE; + + name = argc != 0 ? vp[2] : JSVAL_VOID; + if (!HasProperty(cx, obj, name, &found)) + return JS_FALSE; + if (found) { + *vp = JSVAL_TRUE; + return JS_TRUE; + } + return js_HasOwnPropertyHelper(cx, js_LookupProperty, argc, vp); +} + +/* XML and XMLList */ +static JSBool +xml_hasComplexContent(JSContext *cx, uintN argc, jsval *vp) +{ + JSXML *kid; + JSObject *kidobj; + uint32 i, n; + + XML_METHOD_PROLOG; +again: + switch (xml->xml_class) { + case JSXML_CLASS_ATTRIBUTE: + case JSXML_CLASS_COMMENT: + case JSXML_CLASS_PROCESSING_INSTRUCTION: + case JSXML_CLASS_TEXT: + *vp = JSVAL_FALSE; + break; + case JSXML_CLASS_LIST: + if (xml->xml_kids.length == 0) { + *vp = JSVAL_TRUE; + } else if (xml->xml_kids.length == 1) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (kid) { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + return JS_FALSE; + obj = kidobj; + xml = (JSXML *) JS_GetPrivate(cx, obj); + goto again; + } + } + /* FALL THROUGH */ + default: + *vp = JSVAL_FALSE; + for (i = 0, n = xml->xml_kids.length; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + *vp = JSVAL_TRUE; + break; + } + } + break; + } + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_hasSimpleContent(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + *vp = BOOLEAN_TO_JSVAL(HasSimpleContent(xml)); + return JS_TRUE; +} + +typedef struct JSTempRootedNSArray { + JSTempValueRooter tvr; + JSXMLArray array; + jsval value; /* extra root for temporaries */ +} JSTempRootedNSArray; + +static void +TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len) +{ + uint32 i; + JSObject *obj; + + for (i = 0; i < len; i++) { + obj = vec[i]; + if (obj) { + JS_SET_TRACING_INDEX(trc, "vector", i); + JS_CallTracer(trc, obj, JSTRACE_OBJECT); + } + } +} + +static void +trace_temp_ns_array(JSTracer *trc, JSTempValueRooter *tvr) +{ + JSTempRootedNSArray *tmp = (JSTempRootedNSArray *)tvr; + + TraceObjectVector(trc, + (JSObject **) tmp->array.vector, + tmp->array.length); + XMLArrayCursorTrace(trc, tmp->array.cursors); + JS_CALL_VALUE_TRACER(trc, tmp->value, "temp_ns_array_value"); +} + +static void +InitTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) +{ + XMLArrayInit(cx, &tmp->array, 0); + tmp->value = JSVAL_NULL; + JS_PUSH_TEMP_ROOT_TRACE(cx, trace_temp_ns_array, &tmp->tvr); +} + +static void +FinishTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) +{ + JS_ASSERT(tmp->tvr.u.trace == trace_temp_ns_array); + JS_POP_TEMP_ROOT(cx, &tmp->tvr); + XMLArrayFinish(cx, &tmp->array); +} + +/* + * Populate a new JS array with elements of JSTempRootedNSArray.array and + * place the result into rval. rval must point to a rooted location. + */ +static JSBool +TempNSArrayToJSArray(JSContext *cx, JSTempRootedNSArray *tmp, jsval *rval) +{ + JSObject *arrayobj; + uint32 i, n; + JSObject *ns; + + arrayobj = js_NewArrayObject(cx, 0, NULL); + if (!arrayobj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(arrayobj); + for (i = 0, n = tmp->array.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&tmp->array, i, JSObject); + if (!ns) + continue; + tmp->value = OBJECT_TO_JSVAL(ns); + if (!OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(i), &tmp->value)) + return JS_FALSE; + } + return JS_TRUE; +} + +static JSBool +FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) +{ + uint32 length, i, j, n; + JSObject *ns, *ns2; + JSString *prefix, *prefix2; + + length = nsarray->length; + do { + if (xml->xml_class != JSXML_CLASS_ELEMENT) + continue; + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (!ns) + continue; + + prefix = GetPrefix(ns); + for (j = 0; j < length; j++) { + ns2 = XMLARRAY_MEMBER(nsarray, j, JSObject); + if (ns2) { + prefix2 = GetPrefix(ns2); + if ((prefix2 && prefix) + ? js_EqualStrings(prefix2, prefix) + : js_EqualStrings(GetURI(ns2), GetURI(ns))) { + break; + } + } + } + + if (j == length) { + if (!XMLARRAY_APPEND(cx, nsarray, ns)) + return JS_FALSE; + ++length; + } + } + } while ((xml = xml->parent) != NULL); + JS_ASSERT(length == nsarray->length); + + return JS_TRUE; +} + +static JSBool +xml_inScopeNamespaces(JSContext *cx, uintN argc, jsval *vp) +{ + JSTempRootedNSArray namespaces; + JSBool ok; + + NON_LIST_XML_METHOD_PROLOG; + + InitTempNSArray(cx, &namespaces); + ok = FindInScopeNamespaces(cx, xml, &namespaces.array) && + TempNSArrayToJSArray(cx, &namespaces, vp); + FinishTempNSArray(cx, &namespaces); + return ok; +} + +static JSBool +xml_insertChildAfter(JSContext *cx, uintN argc, jsval *vp) +{ + jsval arg; + JSXML *kid; + uint32 i; + + NON_LIST_XML_METHOD_PROLOG; + *vp = OBJECT_TO_JSVAL(obj); + if (!JSXML_HAS_KIDS(xml) || argc == 0) + return JS_TRUE; + + arg = vp[2]; + if (JSVAL_IS_NULL(arg)) { + kid = NULL; + i = 0; + } else { + if (!VALUE_IS_XML(cx, arg)) + return JS_TRUE; + kid = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(arg)); + i = XMLARRAY_FIND_MEMBER(&xml->xml_kids, kid, NULL); + if (i == XML_NOT_FOUND) + return JS_TRUE; + ++i; + } + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + return Insert(cx, xml, i, argc >= 2 ? vp[3] : JSVAL_VOID); +} + +static JSBool +xml_insertChildBefore(JSContext *cx, uintN argc, jsval *vp) +{ + jsval arg; + JSXML *kid; + uint32 i; + + NON_LIST_XML_METHOD_PROLOG; + *vp = OBJECT_TO_JSVAL(obj); + if (!JSXML_HAS_KIDS(xml) || argc == 0) + return JS_TRUE; + + arg = vp[2]; + if (JSVAL_IS_NULL(arg)) { + kid = NULL; + i = xml->xml_kids.length; + } else { + if (!VALUE_IS_XML(cx, arg)) + return JS_TRUE; + kid = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(arg)); + i = XMLARRAY_FIND_MEMBER(&xml->xml_kids, kid, NULL); + if (i == XML_NOT_FOUND) + return JS_TRUE; + } + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + return Insert(cx, xml, i, argc >= 2 ? vp[3] : JSVAL_VOID); +} + +/* XML and XMLList */ +static JSBool +xml_length(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + if (xml->xml_class != JSXML_CLASS_LIST) { + *vp = JSVAL_ONE; + } else { + if (!js_NewNumberInRootedValue(cx, xml->xml_kids.length, vp)) + return JS_FALSE; + } + return JS_TRUE; +} + +static JSBool +xml_localName(JSContext *cx, uintN argc, jsval *vp) +{ + NON_LIST_XML_METHOD_PROLOG; + *vp = xml->name ? xml->name->fslots[JSSLOT_LOCAL_NAME] : JSVAL_NULL; + return JS_TRUE; +} + +static JSBool +xml_name(JSContext *cx, uintN argc, jsval *vp) +{ + NON_LIST_XML_METHOD_PROLOG; + *vp = OBJECT_TO_JSVAL(xml->name); + return JS_TRUE; +} + +static JSBool +xml_namespace(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *prefix, *nsprefix; + JSTempRootedNSArray inScopeNSes; + JSBool ok; + jsuint i, length; + JSObject *ns; + + NON_LIST_XML_METHOD_PROLOG; + if (argc == 0 && !JSXML_HAS_NAME(xml)) { + *vp = JSVAL_NULL; + return JS_TRUE; + } + + if (argc == 0) { + prefix = NULL; + } else { + prefix = js_ValueToString(cx, vp[2]); + if (!prefix) + return JS_FALSE; + vp[2] = STRING_TO_JSVAL(prefix); /* local root */ + } + + InitTempNSArray(cx, &inScopeNSes); + MUST_FLOW_THROUGH("out"); + ok = FindInScopeNamespaces(cx, xml, &inScopeNSes.array); + if (!ok) + goto out; + + if (!prefix) { + ns = GetNamespace(cx, xml->name, &inScopeNSes.array); + if (!ns) { + ok = JS_FALSE; + goto out; + } + } else { + ns = NULL; + for (i = 0, length = inScopeNSes.array.length; i < length; i++) { + ns = XMLARRAY_MEMBER(&inScopeNSes.array, i, JSObject); + if (ns) { + nsprefix = GetPrefix(ns); + if (nsprefix && js_EqualStrings(nsprefix, prefix)) + break; + ns = NULL; + } + } + } + + *vp = (!ns) ? JSVAL_VOID : OBJECT_TO_JSVAL(ns); + + out: + FinishTempNSArray(cx, &inScopeNSes); + return JS_TRUE; +} + +static JSBool +xml_namespaceDeclarations(JSContext *cx, uintN argc, jsval *vp) +{ + JSBool ok; + JSTempRootedNSArray ancestors, declared; + JSXML *yml; + uint32 i, n; + JSObject *ns; + + NON_LIST_XML_METHOD_PROLOG; + if (JSXML_HAS_VALUE(xml)) + return JS_TRUE; + + /* From here, control flow must goto out to finish these arrays. */ + ok = JS_TRUE; + InitTempNSArray(cx, &ancestors); + InitTempNSArray(cx, &declared); + yml = xml; + + while ((yml = yml->parent) != NULL) { + JS_ASSERT(yml->xml_class == JSXML_CLASS_ELEMENT); + for (i = 0, n = yml->xml_namespaces.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject); + if (ns && + !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { + ok = XMLARRAY_APPEND(cx, &ancestors.array, ns); + if (!ok) + goto out; + } + } + } + + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (!ns) + continue; + if (!IsDeclared(ns)) + continue; + if (!XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { + ok = XMLARRAY_APPEND(cx, &declared.array, ns); + if (!ok) + goto out; + } + } + + ok = TempNSArrayToJSArray(cx, &declared, vp); + +out: + /* Finishing must be in reverse order of initialization to follow LIFO. */ + FinishTempNSArray(cx, &declared); + FinishTempNSArray(cx, &ancestors); + return ok; +} + +static const char js_attribute_str[] = "attribute"; +static const char js_text_str[] = "text"; + +/* Exported to jsgc.c #ifdef DEBUG. */ +const char *js_xml_class_str[] = { + "list", + "element", + js_attribute_str, + "processing-instruction", + js_text_str, + "comment" +}; + +static JSBool +xml_nodeKind(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + NON_LIST_XML_METHOD_PROLOG; + str = JS_InternString(cx, js_xml_class_str[xml->xml_class]); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static void +NormalizingDelete(JSContext *cx, JSXML *xml, uint32 index) +{ + if (xml->xml_class == JSXML_CLASS_LIST) + DeleteListElement(cx, xml, index); + else + DeleteByIndex(cx, xml, index); +} + +/* XML and XMLList */ +static JSBool +xml_normalize_helper(JSContext *cx, JSObject *obj, JSXML *xml) +{ + JSXML *kid, *kid2; + uint32 i, n; + JSObject *kidobj; + JSString *str; + + if (!JSXML_HAS_KIDS(xml)) + return JS_TRUE; + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + for (i = 0, n = xml->xml_kids.length; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (!kid) + continue; + if (kid->xml_class == JSXML_CLASS_ELEMENT) { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj || !xml_normalize_helper(cx, kidobj, kid)) + return JS_FALSE; + } else if (kid->xml_class == JSXML_CLASS_TEXT) { + while (i + 1 < n && + (kid2 = XMLARRAY_MEMBER(&xml->xml_kids, i + 1, JSXML)) && + kid2->xml_class == JSXML_CLASS_TEXT) { + str = js_ConcatStrings(cx, kid->xml_value, kid2->xml_value); + if (!str) + return JS_FALSE; + NormalizingDelete(cx, xml, i + 1); + n = xml->xml_kids.length; + kid->xml_value = str; + } + if (IS_EMPTY(kid->xml_value)) { + NormalizingDelete(cx, xml, i); + n = xml->xml_kids.length; + --i; + } + } + } + + return JS_TRUE; +} + +static JSBool +xml_normalize(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + *vp = OBJECT_TO_JSVAL(obj); + return xml_normalize_helper(cx, obj, xml); +} + +/* XML and XMLList */ +static JSBool +xml_parent(JSContext *cx, uintN argc, jsval *vp) +{ + JSXML *parent, *kid; + uint32 i, n; + JSObject *parentobj; + + XML_METHOD_PROLOG; + parent = xml->parent; + if (xml->xml_class == JSXML_CLASS_LIST) { + *vp = JSVAL_VOID; + n = xml->xml_kids.length; + if (n == 0) + return JS_TRUE; + + kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (!kid) + return JS_TRUE; + parent = kid->parent; + for (i = 1; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->parent != parent) + return JS_TRUE; + } + } + + if (!parent) { + *vp = JSVAL_NULL; + return JS_TRUE; + } + + parentobj = js_GetXMLObject(cx, parent); + if (!parentobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(parentobj); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_processingInstructions_helper(JSContext *cx, JSObject *obj, JSXML *xml, + JSObject *nameqn, jsval *vp) +{ + JSXML *list, *kid, *vxml; + JSBool ok; + JSXMLArrayCursor cursor; + JSObject *kidobj; + jsval v; + uint32 i, n; + JSString *localName; + + list = xml_list_helper(cx, xml, vp); + if (!list) + return JS_FALSE; + + list->xml_targetprop = nameqn; + ok = JS_TRUE; + + if (xml->xml_class == JSXML_CLASS_LIST) { + /* 13.5.4.17 Step 4 (misnumbered 9 -- Erratum?). */ + XMLArrayCursorInit(&cursor, &xml->xml_kids); + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + if (kid->xml_class == JSXML_CLASS_ELEMENT) { + ok = js_EnterLocalRootScope(cx); + if (!ok) + break; + kidobj = js_GetXMLObject(cx, kid); + if (kidobj) { + ok = xml_processingInstructions_helper(cx, kidobj, kid, + nameqn, &v); + } else { + ok = JS_FALSE; + v = JSVAL_NULL; + } + js_LeaveLocalRootScopeWithResult(cx, v); + if (!ok) + break; + vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + if (JSXML_LENGTH(vxml) != 0) { + ok = Append(cx, list, vxml); + if (!ok) + break; + } + } + } + XMLArrayCursorFinish(&cursor); + } else { + /* 13.4.4.28 Step 4. */ + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) { + localName = GetLocalName(nameqn); + if (IS_STAR(localName) || + js_EqualStrings(localName, GetLocalName(kid->name))) { + ok = Append(cx, list, kid); + if (!ok) + break; + } + } + } + } + + return ok; +} + +static JSBool +xml_processingInstructions(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSObject *nameqn; + jsid funid; + + XML_METHOD_PROLOG; + + name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : vp[2]; + nameqn = ToXMLName(cx, name, &funid); + if (!nameqn) + return JS_FALSE; + vp[2] = OBJECT_TO_JSVAL(nameqn); + + if (funid) + return xml_list_helper(cx, xml, vp) != NULL; + + return xml_processingInstructions_helper(cx, obj, xml, nameqn, vp); +} + +static JSBool +xml_prependChild(JSContext *cx, uintN argc, jsval *vp) +{ + NON_LIST_XML_METHOD_PROLOG; + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(obj); + return Insert(cx, xml, 0, argc != 0 ? vp[2] : JSVAL_VOID); +} + +/* XML and XMLList */ +static JSBool +xml_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp) +{ + uint32 index; + + XML_METHOD_PROLOG; + *vp = JSVAL_FALSE; + if (argc != 0 && js_IdIsIndex(vp[2], &index)) { + if (xml->xml_class == JSXML_CLASS_LIST) { + /* 13.5.4.18. */ + *vp = BOOLEAN_TO_JSVAL(index < xml->xml_kids.length); + } else { + /* 13.4.4.30. */ + *vp = BOOLEAN_TO_JSVAL(index == 0); + } + } + return JS_TRUE; +} + +static JSBool +namespace_full_match(const void *a, const void *b) +{ + const JSObject *nsa = (const JSObject *) a; + const JSObject *nsb = (const JSObject *) b; + JSString *prefixa = GetPrefix(nsa); + JSString *prefixb; + + if (prefixa) { + prefixb = GetPrefix(nsb); + if (prefixb && !js_EqualStrings(prefixa, prefixb)) + return JS_FALSE; + } + return js_EqualStrings(GetURI(nsa), GetURI(nsb)); +} + +static JSBool +xml_removeNamespace_helper(JSContext *cx, JSXML *xml, JSObject *ns) +{ + JSObject *thisns, *attrns; + uint32 i, n; + JSXML *attr, *kid; + + thisns = GetNamespace(cx, xml->name, &xml->xml_namespaces); + JS_ASSERT(thisns); + if (thisns == ns) + return JS_TRUE; + + for (i = 0, n = xml->xml_attrs.length; i < n; i++) { + attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); + if (!attr) + continue; + attrns = GetNamespace(cx, attr->name, &xml->xml_namespaces); + JS_ASSERT(attrns); + if (attrns == ns) + return JS_TRUE; + } + + i = XMLARRAY_FIND_MEMBER(&xml->xml_namespaces, ns, namespace_full_match); + if (i != XML_NOT_FOUND) + XMLArrayDelete(cx, &xml->xml_namespaces, i, JS_TRUE); + + for (i = 0, n = xml->xml_kids.length; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + if (!xml_removeNamespace_helper(cx, kid, ns)) + return JS_FALSE; + } + } + return JS_TRUE; +} + +static JSBool +xml_removeNamespace(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *ns; + + NON_LIST_XML_METHOD_PROLOG; + if (xml->xml_class != JSXML_CLASS_ELEMENT) + goto done; + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + if (!NamespaceHelper(cx, NULL, argc == 0 ? -1 : 1, vp + 2, vp)) + return JS_FALSE; + JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp)); + ns = JSVAL_TO_OBJECT(*vp); + + /* NOTE: remove ns from each ancestor if not used by that ancestor. */ + if (!xml_removeNamespace_helper(cx, xml, ns)) + return JS_FALSE; + done: + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static JSBool +xml_replace(JSContext *cx, uintN argc, jsval *vp) +{ + jsval value; + JSXML *vxml, *kid; + uint32 index, i; + JSObject *nameqn; + + NON_LIST_XML_METHOD_PROLOG; + if (xml->xml_class != JSXML_CLASS_ELEMENT) + goto done; + + if (argc <= 1) { + value = STRING_TO_JSVAL(ATOM_TO_STRING(cx->runtime->atomState. + typeAtoms[JSTYPE_VOID])); + } else { + value = vp[3]; + vxml = VALUE_IS_XML(cx, value) + ? (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(value)) + : NULL; + if (!vxml) { + if (!JS_ConvertValue(cx, value, JSTYPE_STRING, &vp[3])) + return JS_FALSE; + value = vp[3]; + } else { + vxml = DeepCopy(cx, vxml, NULL, 0); + if (!vxml) + return JS_FALSE; + value = vp[3] = OBJECT_TO_JSVAL(vxml->object); + } + } + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + if (argc == 0 || !js_IdIsIndex(vp[2], &index)) { + /* + * Call function QName per spec, not ToXMLName, to avoid attribute + * names. + */ + if (!QNameHelper(cx, NULL, &js_QNameClass.base, argc == 0 ? -1 : 1, + vp + 2, vp)) { + return JS_FALSE; + } + JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp)); + nameqn = JSVAL_TO_OBJECT(*vp); + + i = xml->xml_kids.length; + index = XML_NOT_FOUND; + while (i != 0) { + --i; + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && MatchElemName(nameqn, kid)) { + if (i != XML_NOT_FOUND) + DeleteByIndex(cx, xml, i); + index = i; + } + } + + if (index == XML_NOT_FOUND) + goto done; + } + + if (!Replace(cx, xml, index, value)) + return JS_FALSE; + + done: + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static JSBool +xml_setChildren(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + if (!StartNonListXMLMethod(cx, vp, &obj)) + return JS_FALSE; + + *vp = argc != 0 ? vp[2] : JSVAL_VOID; /* local root */ + if (!PutProperty(cx, obj, ATOM_KEY(cx->runtime->atomState.starAtom), vp)) + return JS_FALSE; + + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static JSBool +xml_setLocalName(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSObject *nameqn; + JSString *namestr; + + NON_LIST_XML_METHOD_PROLOG; + if (!JSXML_HAS_NAME(xml)) + return JS_TRUE; + + if (argc == 0) { + namestr = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } else { + name = vp[2]; + if (!JSVAL_IS_PRIMITIVE(name) && + OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(name)) == &js_QNameClass.base) { + nameqn = JSVAL_TO_OBJECT(name); + namestr = GetLocalName(nameqn); + } else { + if (!JS_ConvertValue(cx, name, JSTYPE_STRING, &vp[2])) + return JS_FALSE; + name = vp[2]; + namestr = JSVAL_TO_STRING(name); + } + } + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + xml->name->fslots[JSSLOT_LOCAL_NAME] = namestr + ? STRING_TO_JSVAL(namestr) + : JSVAL_VOID; + return JS_TRUE; +} + +static JSBool +xml_setName(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSObject *nameqn; + JSXML *nsowner; + JSXMLArray *nsarray; + uint32 i, n; + JSObject *ns; + + NON_LIST_XML_METHOD_PROLOG; + if (!JSXML_HAS_NAME(xml)) + return JS_TRUE; + + if (argc == 0) { + name = STRING_TO_JSVAL(ATOM_TO_STRING(cx->runtime->atomState. + typeAtoms[JSTYPE_VOID])); + } else { + name = vp[2]; + if (!JSVAL_IS_PRIMITIVE(name) && + OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(name)) == &js_QNameClass.base && + !GetURI(nameqn = JSVAL_TO_OBJECT(name))) { + name = vp[2] = nameqn->fslots[JSSLOT_LOCAL_NAME]; + } + } + + nameqn = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, &name); + if (!nameqn) + return JS_FALSE; + + /* ECMA-357 13.4.4.35 Step 4. */ + if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) + nameqn->fslots[JSSLOT_URI] = STRING_TO_JSVAL(cx->runtime->emptyString); + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + xml->name = nameqn; + + /* + * Erratum: nothing in 13.4.4.35 talks about making the name match the + * in-scope namespaces, either by finding an in-scope namespace with a + * matching uri and setting the new name's prefix to that namespace's + * prefix, or by extending the in-scope namespaces for xml (which are in + * xml->parent if xml is an attribute or a PI). + */ + if (xml->xml_class == JSXML_CLASS_ELEMENT) { + nsowner = xml; + } else { + if (!xml->parent || xml->parent->xml_class != JSXML_CLASS_ELEMENT) + return JS_TRUE; + nsowner = xml->parent; + } + + if (GetPrefix(nameqn)) { + /* + * The name being set has a prefix, which originally came from some + * namespace object (which may be the null namespace, where both the + * prefix and uri are the empty string). We must go through a full + * GetNamespace in case that namespace is in-scope in nsowner. + * + * If we find such an in-scope namespace, we return true right away, + * in this block. Otherwise, we fall through to the final return of + * AddInScopeNamespace(cx, nsowner, ns). + */ + ns = GetNamespace(cx, nameqn, &nsowner->xml_namespaces); + if (!ns) + return JS_FALSE; + + /* XXXbe have to test membership to see whether GetNamespace added */ + if (XMLARRAY_HAS_MEMBER(&nsowner->xml_namespaces, ns, NULL)) + return JS_TRUE; + } else { + /* + * At this point, we know prefix of nameqn is null, so its uri can't + * be the empty string (the null namespace always uses the empty string + * for both prefix and uri). + * + * This means we must inline GetNamespace and specialize it to match + * uri only, never prefix. If we find a namespace with nameqn's uri + * already in nsowner->xml_namespaces, then all that we need do is set + * prefix of nameqn to that namespace's prefix. + * + * If no such namespace exists, we can create one without going through + * the constructor, because we know uri of nameqn is non-empty (so + * prefix does not need to be converted from null to empty by QName). + */ + JS_ASSERT(!IS_EMPTY(GetURI(nameqn))); + + nsarray = &nsowner->xml_namespaces; + for (i = 0, n = nsarray->length; i < n; i++) { + ns = XMLARRAY_MEMBER(nsarray, i, JSObject); + if (ns && js_EqualStrings(GetURI(ns), GetURI(nameqn))) { + nameqn->fslots[JSSLOT_PREFIX] = ns->fslots[JSSLOT_PREFIX]; + return JS_TRUE; + } + } + + ns = NewXMLNamespace(cx, NULL, GetURI(nameqn), JS_TRUE); + if (!ns) + return JS_FALSE; + } + + if (!AddInScopeNamespace(cx, nsowner, ns)) + return JS_FALSE; + vp[0] = JSVAL_VOID; + return JS_TRUE; +} + +static JSBool +xml_setNamespace(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *qn; + JSObject *ns; + jsval qnargv[2]; + JSXML *nsowner; + + NON_LIST_XML_METHOD_PROLOG; + if (!JSXML_HAS_NAME(xml)) + return JS_TRUE; + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj, + argc == 0 ? 0 : 1, vp + 2); + if (!ns) + return JS_FALSE; + vp[0] = OBJECT_TO_JSVAL(ns); + ns->fslots[JSSLOT_DECLARED] = JSVAL_TRUE; + + qnargv[0] = vp[2] = OBJECT_TO_JSVAL(ns); + qnargv[1] = OBJECT_TO_JSVAL(xml->name); + qn = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, qnargv); + if (!qn) + return JS_FALSE; + + xml->name = qn; + + /* + * Erratum: the spec fails to update the governing in-scope namespaces. + * See the erratum noted in xml_setName, above. + */ + if (xml->xml_class == JSXML_CLASS_ELEMENT) { + nsowner = xml; + } else { + if (!xml->parent || xml->parent->xml_class != JSXML_CLASS_ELEMENT) + return JS_TRUE; + nsowner = xml->parent; + } + if (!AddInScopeNamespace(cx, nsowner, ns)) + return JS_FALSE; + vp[0] = JSVAL_VOID; + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_text_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval *vp) +{ + JSXML *list, *kid, *vxml; + uint32 i, n; + JSBool ok; + JSObject *kidobj; + jsval v; + + list = xml_list_helper(cx, xml, vp); + if (!list) + return JS_FALSE; + + if (xml->xml_class == JSXML_CLASS_LIST) { + ok = JS_TRUE; + for (i = 0, n = xml->xml_kids.length; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + ok = js_EnterLocalRootScope(cx); + if (!ok) + break; + kidobj = js_GetXMLObject(cx, kid); + if (kidobj) { + ok = xml_text_helper(cx, kidobj, kid, &v); + } else { + ok = JS_FALSE; + v = JSVAL_NULL; + } + js_LeaveLocalRootScopeWithResult(cx, v); + if (!ok) + return JS_FALSE; + vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + if (JSXML_LENGTH(vxml) != 0 && !Append(cx, list, vxml)) + return JS_FALSE; + } + } + } else { + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_TEXT) { + if (!Append(cx, list, kid)) + return JS_FALSE; + } + } + } + return JS_TRUE; +} + +static JSBool +xml_text(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + return xml_text_helper(cx, obj, xml, vp); +} + +/* XML and XMLList */ +static JSString * +xml_toString_helper(JSContext *cx, JSXML *xml) +{ + JSString *str, *kidstr; + JSXML *kid; + JSXMLArrayCursor cursor; + + if (xml->xml_class == JSXML_CLASS_ATTRIBUTE || + xml->xml_class == JSXML_CLASS_TEXT) { + return xml->xml_value; + } + + if (!HasSimpleContent(xml)) + return ToXMLString(cx, OBJECT_TO_JSVAL(xml->object), 0); + + str = cx->runtime->emptyString; + if (!js_EnterLocalRootScope(cx)) + return NULL; + XMLArrayCursorInit(&cursor, &xml->xml_kids); + while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { + if (kid->xml_class != JSXML_CLASS_COMMENT && + kid->xml_class != JSXML_CLASS_PROCESSING_INSTRUCTION) { + kidstr = xml_toString_helper(cx, kid); + if (!kidstr) { + str = NULL; + break; + } + str = js_ConcatStrings(cx, str, kidstr); + if (!str) + break; + } + } + XMLArrayCursorFinish(&cursor); + js_LeaveLocalRootScopeWithResult(cx, STRING_TO_JSVAL(str)); + return str; +} + +static JSBool +xml_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + jsval thisv; + JSString *str; + + thisv = JS_THIS(cx, vp); + if (JSVAL_IS_NULL(thisv)) + return JS_FALSE; + str = ToXMLString(cx, thisv, TO_SOURCE_FLAG); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +xml_toString(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + XML_METHOD_PROLOG; + str = xml_toString_helper(cx, xml); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_toXMLString(JSContext *cx, uintN argc, jsval *vp) +{ + jsval thisv; + JSString *str; + + thisv = JS_THIS(cx, vp); + if (JSVAL_IS_NULL(thisv)) + return JS_FALSE; + str = ToXMLString(cx, thisv, 0); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_valueOf(JSContext *cx, uintN argc, jsval *vp) +{ + *vp = JS_THIS(cx, vp); + return !JSVAL_IS_NULL(*vp); +} + +static JSFunctionSpec xml_methods[] = { + JS_FN("addNamespace", xml_addNamespace, 1,0), + JS_FN("appendChild", xml_appendChild, 1,0), + JS_FN(js_attribute_str, xml_attribute, 1,0), + JS_FN("attributes", xml_attributes, 0,0), + JS_FN("child", xml_child, 1,0), + JS_FN("childIndex", xml_childIndex, 0,0), + JS_FN("children", xml_children, 0,0), + JS_FN("comments", xml_comments, 0,0), + JS_FN("contains", xml_contains, 1,0), + JS_FN("copy", xml_copy, 0,0), + JS_FN("descendants", xml_descendants, 1,0), + JS_FN("elements", xml_elements, 1,0), + JS_FN("hasOwnProperty", xml_hasOwnProperty, 1,0), + JS_FN("hasComplexContent", xml_hasComplexContent, 1,0), + JS_FN("hasSimpleContent", xml_hasSimpleContent, 1,0), + JS_FN("inScopeNamespaces", xml_inScopeNamespaces, 0,0), + JS_FN("insertChildAfter", xml_insertChildAfter, 2,0), + JS_FN("insertChildBefore", xml_insertChildBefore, 2,0), + JS_FN(js_length_str, xml_length, 0,0), + JS_FN(js_localName_str, xml_localName, 0,0), + JS_FN(js_name_str, xml_name, 0,0), + JS_FN(js_namespace_str, xml_namespace, 1,0), + JS_FN("namespaceDeclarations", xml_namespaceDeclarations, 0,0), + JS_FN("nodeKind", xml_nodeKind, 0,0), + JS_FN("normalize", xml_normalize, 0,0), + JS_FN(js_xml_parent_str, xml_parent, 0,0), + JS_FN("processingInstructions",xml_processingInstructions,1,0), + JS_FN("prependChild", xml_prependChild, 1,0), + JS_FN("propertyIsEnumerable", xml_propertyIsEnumerable, 1,0), + JS_FN("removeNamespace", xml_removeNamespace, 1,0), + JS_FN("replace", xml_replace, 2,0), + JS_FN("setChildren", xml_setChildren, 1,0), + JS_FN("setLocalName", xml_setLocalName, 1,0), + JS_FN("setName", xml_setName, 1,0), + JS_FN("setNamespace", xml_setNamespace, 1,0), + JS_FN(js_text_str, xml_text, 0,0), + JS_FN(js_toSource_str, xml_toSource, 0,0), + JS_FN(js_toString_str, xml_toString, 0,0), + JS_FN(js_toXMLString_str, xml_toXMLString, 0,0), + JS_FN(js_valueOf_str, xml_valueOf, 0,0), + JS_FS_END +}; + +static JSBool +CopyXMLSettings(JSContext *cx, JSObject *from, JSObject *to) +{ + int i; + const char *name; + jsval v; + + for (i = XML_IGNORE_COMMENTS; i < XML_PRETTY_INDENT; i++) { + name = xml_static_props[i].name; + if (!JS_GetProperty(cx, from, name, &v)) + return JS_FALSE; + if (JSVAL_IS_BOOLEAN(v) && !JS_SetProperty(cx, to, name, &v)) + return JS_FALSE; + } + + name = xml_static_props[i].name; + if (!JS_GetProperty(cx, from, name, &v)) + return JS_FALSE; + if (JSVAL_IS_NUMBER(v) && !JS_SetProperty(cx, to, name, &v)) + return JS_FALSE; + return JS_TRUE; +} + +static JSBool +SetDefaultXMLSettings(JSContext *cx, JSObject *obj) +{ + int i; + jsval v; + + for (i = XML_IGNORE_COMMENTS; i < XML_PRETTY_INDENT; i++) { + v = JSVAL_TRUE; + if (!JS_SetProperty(cx, obj, xml_static_props[i].name, &v)) + return JS_FALSE; + } + v = INT_TO_JSVAL(2); + return JS_SetProperty(cx, obj, xml_static_props[i].name, &v); +} + +static JSBool +xml_settings(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *settings; + JSObject *obj; + + settings = JS_NewObject(cx, NULL, NULL, NULL); + if (!settings) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(settings); + obj = JS_THIS_OBJECT(cx, vp); + return obj && CopyXMLSettings(cx, obj, settings); +} + +static JSBool +xml_setSettings(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj, *settings; + jsval v; + JSBool ok; + + obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + v = (argc == 0) ? JSVAL_VOID : vp[2]; + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { + cx->xmlSettingFlags = 0; + ok = SetDefaultXMLSettings(cx, obj); + } else { + if (JSVAL_IS_PRIMITIVE(v)) + return JS_TRUE; + settings = JSVAL_TO_OBJECT(v); + cx->xmlSettingFlags = 0; + ok = CopyXMLSettings(cx, settings, obj); + } + if (ok) + cx->xmlSettingFlags |= XSF_CACHE_VALID; + return ok; +} + +static JSBool +xml_defaultSettings(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *settings; + + settings = JS_NewObject(cx, NULL, NULL, NULL); + if (!settings) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(settings); + return SetDefaultXMLSettings(cx, settings); +} + +static JSFunctionSpec xml_static_methods[] = { + JS_FN("settings", xml_settings, 0,0), + JS_FN("setSettings", xml_setSettings, 1,0), + JS_FN("defaultSettings", xml_defaultSettings, 0,0), + JS_FS_END +}; + +static JSBool +XML(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + jsval v; + JSXML *xml, *copy; + JSObject *xobj, *vobj; + JSClass *clasp; + + v = argv[0]; + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) + v = STRING_TO_JSVAL(cx->runtime->emptyString); + + xobj = ToXML(cx, v); + if (!xobj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(xobj); + xml = (JSXML *) JS_GetPrivate(cx, xobj); + + if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && !JSVAL_IS_PRIMITIVE(v)) { + vobj = JSVAL_TO_OBJECT(v); + clasp = OBJ_GET_CLASS(cx, vobj); + if (clasp == &js_XMLClass || + (clasp->flags & JSCLASS_DOCUMENT_OBSERVER)) { + /* No need to lock obj, it's newly constructed and thread local. */ + copy = DeepCopy(cx, xml, obj, 0); + if (!copy) + return JS_FALSE; + JS_ASSERT(copy->object == obj); + *rval = OBJECT_TO_JSVAL(obj); + return JS_TRUE; + } + } + return JS_TRUE; +} + +static JSBool +XMLList(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + jsval v; + JSObject *vobj, *listobj; + JSXML *xml, *list; + + v = argv[0]; + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) + v = STRING_TO_JSVAL(cx->runtime->emptyString); + + if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && !JSVAL_IS_PRIMITIVE(v)) { + vobj = JSVAL_TO_OBJECT(v); + if (OBJECT_IS_XML(cx, vobj)) { + xml = (JSXML *) JS_GetPrivate(cx, vobj); + if (xml->xml_class == JSXML_CLASS_LIST) { + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(listobj); + + list = (JSXML *) JS_GetPrivate(cx, listobj); + if (!Append(cx, list, xml)) + return JS_FALSE; + return JS_TRUE; + } + } + } + + /* Toggle on XML support since the script has explicitly requested it. */ + listobj = ToXMLList(cx, v); + if (!listobj) + return JS_FALSE; + + *rval = OBJECT_TO_JSVAL(listobj); + return JS_TRUE; +} + +#define JSXML_LIST_SIZE (offsetof(JSXML, u) + sizeof(struct JSXMLListVar)) +#define JSXML_ELEMENT_SIZE (offsetof(JSXML, u) + sizeof(struct JSXMLElemVar)) +#define JSXML_LEAF_SIZE (offsetof(JSXML, u) + sizeof(JSString *)) + +static size_t sizeof_JSXML[JSXML_CLASS_LIMIT] = { + JSXML_LIST_SIZE, /* JSXML_CLASS_LIST */ + JSXML_ELEMENT_SIZE, /* JSXML_CLASS_ELEMENT */ + JSXML_LEAF_SIZE, /* JSXML_CLASS_ATTRIBUTE */ + JSXML_LEAF_SIZE, /* JSXML_CLASS_PROCESSING_INSTRUCTION */ + JSXML_LEAF_SIZE, /* JSXML_CLASS_TEXT */ + JSXML_LEAF_SIZE /* JSXML_CLASS_COMMENT */ +}; + +#ifdef DEBUG_notme +JSCList xml_leaks = JS_INIT_STATIC_CLIST(&xml_leaks); +uint32 xml_serial; +#endif + +JSXML * +js_NewXML(JSContext *cx, JSXMLClass xml_class) +{ + JSXML *xml; + + xml = (JSXML *) js_NewGCThing(cx, GCX_XML, sizeof_JSXML[xml_class]); + if (!xml) + return NULL; + + xml->object = NULL; + xml->domnode = NULL; + xml->parent = NULL; + xml->name = NULL; + xml->xml_class = xml_class; + xml->xml_flags = 0; + if (JSXML_CLASS_HAS_VALUE(xml_class)) { + xml->xml_value = cx->runtime->emptyString; + } else { + XMLArrayInit(cx, &xml->xml_kids, 0); + if (xml_class == JSXML_CLASS_LIST) { + xml->xml_target = NULL; + xml->xml_targetprop = NULL; + } else { + XMLArrayInit(cx, &xml->xml_namespaces, 0); + XMLArrayInit(cx, &xml->xml_attrs, 0); + } + } + +#ifdef DEBUG_notme + JS_APPEND_LINK(&xml->links, &xml_leaks); + xml->serial = xml_serial++; +#endif + METER(xml_stats.xml); + return xml; +} + +void +js_TraceXML(JSTracer *trc, JSXML *xml) +{ + if (xml->object) + JS_CALL_OBJECT_TRACER(trc, xml->object, "object"); + if (xml->name) + JS_CALL_OBJECT_TRACER(trc, xml->name, "name"); + if (xml->parent) + JS_CALL_TRACER(trc, xml->parent, JSTRACE_XML, "xml_parent"); + + if (JSXML_HAS_VALUE(xml)) { + if (xml->xml_value) + JS_CALL_STRING_TRACER(trc, xml->xml_value, "value"); + return; + } + + xml_trace_vector(trc, + (JSXML **) xml->xml_kids.vector, + xml->xml_kids.length); + XMLArrayCursorTrace(trc, xml->xml_kids.cursors); + if (IS_GC_MARKING_TRACER(trc)) + XMLArrayTrim(&xml->xml_kids); + + if (xml->xml_class == JSXML_CLASS_LIST) { + if (xml->xml_target) + JS_CALL_TRACER(trc, xml->xml_target, JSTRACE_XML, "target"); + if (xml->xml_targetprop) + JS_CALL_OBJECT_TRACER(trc, xml->xml_targetprop, "targetprop"); + } else { + TraceObjectVector(trc, + (JSObject **) xml->xml_namespaces.vector, + xml->xml_namespaces.length); + XMLArrayCursorTrace(trc, xml->xml_namespaces.cursors); + if (IS_GC_MARKING_TRACER(trc)) + XMLArrayTrim(&xml->xml_namespaces); + + xml_trace_vector(trc, + (JSXML **) xml->xml_attrs.vector, + xml->xml_attrs.length); + XMLArrayCursorTrace(trc, xml->xml_attrs.cursors); + if (IS_GC_MARKING_TRACER(trc)) + XMLArrayTrim(&xml->xml_attrs); + } +} + +void +js_FinalizeXML(JSContext *cx, JSXML *xml) +{ + if (JSXML_HAS_KIDS(xml)) { + XMLArrayFinish(cx, &xml->xml_kids); + if (xml->xml_class == JSXML_CLASS_ELEMENT) { + XMLArrayFinish(cx, &xml->xml_namespaces); + XMLArrayFinish(cx, &xml->xml_attrs); + } + } + +#ifdef DEBUG_notme + JS_REMOVE_LINK(&xml->links); +#endif +} + +JSObject * +js_ParseNodeToXMLObject(JSContext *cx, JSParseContext *pc, JSParseNode *pn) +{ + jsval nsval; + JSObject *ns; + JSXMLArray nsarray; + JSXML *xml; + + if (!js_GetDefaultXMLNamespace(cx, &nsval)) + return NULL; + JS_ASSERT(!JSVAL_IS_PRIMITIVE(nsval)); + ns = JSVAL_TO_OBJECT(nsval); + + if (!XMLArrayInit(cx, &nsarray, 1)) + return NULL; + + XMLARRAY_APPEND(cx, &nsarray, ns); + xml = ParseNodeToXML(cx, pc, pn, &nsarray, XSF_PRECOMPILED_ROOT); + XMLArrayFinish(cx, &nsarray); + if (!xml) + return NULL; + + return xml->object; +} + +JSObject * +js_NewXMLObject(JSContext *cx, JSXMLClass xml_class) +{ + JSXML *xml; + JSObject *obj; + JSTempValueRooter tvr; + + xml = js_NewXML(cx, xml_class); + if (!xml) + return NULL; + JS_PUSH_TEMP_ROOT_XML(cx, xml, &tvr); + obj = js_GetXMLObject(cx, xml); + JS_POP_TEMP_ROOT(cx, &tvr); + return obj; +} + +static JSObject * +NewXMLObject(JSContext *cx, JSXML *xml) +{ + JSObject *obj; + + obj = js_NewObject(cx, &js_XMLClass, NULL, NULL, 0); + if (!obj || !JS_SetPrivate(cx, obj, xml)) { + cx->weakRoots.newborn[GCX_OBJECT] = NULL; + return NULL; + } + METER(xml_stats.xmlobj); + return obj; +} + +JSObject * +js_GetXMLObject(JSContext *cx, JSXML *xml) +{ + JSObject *obj; + + obj = xml->object; + if (obj) { + JS_ASSERT(JS_GetPrivate(cx, obj) == xml); + return obj; + } + + /* + * A JSXML cannot be shared among threads unless it has an object. + * A JSXML cannot be given an object unless: + * (a) it has no parent; or + * (b) its parent has no object (therefore is thread-private); or + * (c) its parent's object is locked. + * + * Once given an object, a JSXML is immutable. + */ + JS_ASSERT(!xml->parent || + !xml->parent->object || + JS_IS_OBJ_LOCKED(cx, xml->parent->object)); + + obj = NewXMLObject(cx, xml); + if (!obj) + return NULL; + xml->object = obj; + return obj; +} + +JSObject * +js_InitNamespaceClass(JSContext *cx, JSObject *obj) +{ + return JS_InitClass(cx, obj, NULL, &js_NamespaceClass.base, Namespace, 2, + namespace_props, namespace_methods, NULL, NULL); +} + +JSObject * +js_InitQNameClass(JSContext *cx, JSObject *obj) +{ + return JS_InitClass(cx, obj, NULL, &js_QNameClass.base, QName, 2, + qname_props, qname_methods, NULL, NULL); +} + +JSObject * +js_InitAttributeNameClass(JSContext *cx, JSObject *obj) +{ + return JS_InitClass(cx, obj, NULL, &js_AttributeNameClass, AttributeName, 2, + qname_props, qname_methods, NULL, NULL); +} + +JSObject * +js_InitAnyNameClass(JSContext *cx, JSObject *obj) +{ + jsval v; + + if (!js_GetAnyName(cx, &v)) + return NULL; + return JSVAL_TO_OBJECT(v); +} + +JSObject * +js_InitXMLClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto, *pobj; + JSFunction *fun; + JSXML *xml; + JSProperty *prop; + JSScopeProperty *sprop; + jsval cval, vp[3]; + + /* Define the isXMLName function. */ + if (!JS_DefineFunction(cx, obj, js_isXMLName_str, xml_isXMLName, 1, 0)) + return NULL; + + /* Define the XML class constructor and prototype. */ + proto = JS_InitClass(cx, obj, NULL, &js_XMLClass, XML, 1, + NULL, xml_methods, + xml_static_props, xml_static_methods); + if (!proto) + return NULL; + + xml = js_NewXML(cx, JSXML_CLASS_TEXT); + if (!xml || !JS_SetPrivate(cx, proto, xml)) + return NULL; + xml->object = proto; + METER(xml_stats.xmlobj); + + /* + * Prepare to set default settings on the XML constructor we just made. + * NB: We can't use JS_GetConstructor, because it calls OBJ_GET_PROPERTY, + * which is xml_getProperty, which creates a new XMLList every time! We + * must instead call js_LookupProperty directly. + */ + if (!js_LookupProperty(cx, proto, + ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), + &pobj, &prop)) { + return NULL; + } + JS_ASSERT(prop); + sprop = (JSScopeProperty *) prop; + JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))); + cval = OBJ_GET_SLOT(cx, pobj, sprop->slot); + OBJ_DROP_PROPERTY(cx, pobj, prop); + JS_ASSERT(VALUE_IS_FUNCTION(cx, cval)); + + /* Set default settings. */ + vp[0] = JSVAL_NULL; + vp[1] = cval; + vp[2] = JSVAL_VOID; + if (!xml_setSettings(cx, 1, vp)) + return NULL; + + /* Define the XMLList function and give it the same prototype as XML. */ + fun = JS_DefineFunction(cx, obj, js_XMLList_str, XMLList, 1, 0); + if (!fun) + return NULL; + if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), proto, + JSPROP_READONLY | JSPROP_PERMANENT)) { + return NULL; + } + return proto; +} + +JSObject * +js_InitXMLClasses(JSContext *cx, JSObject *obj) +{ + if (!js_InitNamespaceClass(cx, obj)) + return NULL; + if (!js_InitQNameClass(cx, obj)) + return NULL; + if (!js_InitAttributeNameClass(cx, obj)) + return NULL; + if (!js_InitAnyNameClass(cx, obj)) + return NULL; + if (!js_InitXMLFilterClass(cx, obj)) + return NULL; + return js_InitXMLClass(cx, obj); +} + +JSBool +js_GetFunctionNamespace(JSContext *cx, jsval *vp) +{ + JSRuntime *rt; + JSObject *obj; + JSAtom *atom; + JSString *prefix, *uri; + + /* An invalid URI, for internal use only, guaranteed not to collide. */ + static const char anti_uri[] = "@mozilla.org/js/function"; + + /* Optimize by avoiding JS_LOCK_GC(rt) for the common case. */ + rt = cx->runtime; + obj = rt->functionNamespaceObject; + if (!obj) { + JS_LOCK_GC(rt); + obj = rt->functionNamespaceObject; + if (!obj) { + JS_UNLOCK_GC(rt); + + /* + * Note that any race to atomize anti_uri here is resolved by + * the atom table code, such that at most one atom for anti_uri + * is created. We store in rt->atomState.lazy unconditionally, + * since we are guaranteed to overwrite either null or the same + * atom pointer. + */ + atom = js_Atomize(cx, anti_uri, sizeof anti_uri - 1, ATOM_PINNED); + if (!atom) + return JS_FALSE; + rt->atomState.lazy.functionNamespaceURIAtom = atom; + + prefix = ATOM_TO_STRING(rt->atomState.typeAtoms[JSTYPE_FUNCTION]); + uri = ATOM_TO_STRING(atom); + obj = NewXMLNamespace(cx, prefix, uri, JS_FALSE); + if (!obj) + return JS_FALSE; + + /* + * Avoid entraining any in-scope Object.prototype. The loss of + * Namespace.prototype is not detectable, as there is no way to + * refer to this instance in scripts. When used to qualify method + * names, its prefix and uri references are copied to the QName. + */ + OBJ_CLEAR_PROTO(cx, obj); + OBJ_CLEAR_PARENT(cx, obj); + + JS_LOCK_GC(rt); + if (!rt->functionNamespaceObject) + rt->functionNamespaceObject = obj; + else + obj = rt->functionNamespaceObject; + } + JS_UNLOCK_GC(rt); + } + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +/* + * Note the asymmetry between js_GetDefaultXMLNamespace and js_SetDefaultXML- + * Namespace. Get searches fp->scopeChain for JS_DEFAULT_XML_NAMESPACE_ID, + * while Set sets JS_DEFAULT_XML_NAMESPACE_ID in fp->varobj (unless fp is a + * lightweight function activation). There's no requirement that fp->varobj + * lie directly on fp->scopeChain, although it should be reachable using the + * prototype chain from a scope object (cf. JSOPTION_VAROBJFIX in jsapi.h). + * + * If Get can't find JS_DEFAULT_XML_NAMESPACE_ID along the scope chain, it + * creates a default namespace via 'new Namespace()'. In contrast, Set uses + * its v argument as the uri of a new Namespace, with "" as the prefix. See + * ECMA-357 12.1 and 12.1.1. Note that if Set is called with a Namespace n, + * the default XML namespace will be set to ("", n.uri). So the uri string + * is really the only usefully stored value of the default namespace. + */ +JSBool +js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) +{ + JSStackFrame *fp; + JSObject *ns, *obj, *tmp; + jsval v; + + fp = cx->fp; + ns = fp->xmlNamespace; + if (ns) { + *vp = OBJECT_TO_JSVAL(ns); + return JS_TRUE; + } + + obj = NULL; + for (tmp = fp->scopeChain; tmp; tmp = OBJ_GET_PARENT(cx, obj)) { + obj = tmp; + if (!OBJ_GET_PROPERTY(cx, obj, JS_DEFAULT_XML_NAMESPACE_ID, &v)) + return JS_FALSE; + if (!JSVAL_IS_PRIMITIVE(v)) { + fp->xmlNamespace = JSVAL_TO_OBJECT(v); + *vp = v; + return JS_TRUE; + } + } + + ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj, 0, NULL); + if (!ns) + return JS_FALSE; + v = OBJECT_TO_JSVAL(ns); + if (obj && + !OBJ_DEFINE_PROPERTY(cx, obj, JS_DEFAULT_XML_NAMESPACE_ID, v, + JS_PropertyStub, JS_PropertyStub, + JSPROP_PERMANENT, NULL)) { + return JS_FALSE; + } + fp->xmlNamespace = ns; + *vp = v; + return JS_TRUE; +} + +JSBool +js_SetDefaultXMLNamespace(JSContext *cx, jsval v) +{ + jsval argv[2]; + JSObject *ns, *varobj; + JSStackFrame *fp; + + argv[0] = STRING_TO_JSVAL(cx->runtime->emptyString); + argv[1] = v; + ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, NULL, 2, argv); + if (!ns) + return JS_FALSE; + v = OBJECT_TO_JSVAL(ns); + + fp = cx->fp; + varobj = fp->varobj; + if (varobj) { + if (!OBJ_DEFINE_PROPERTY(cx, varobj, JS_DEFAULT_XML_NAMESPACE_ID, v, + JS_PropertyStub, JS_PropertyStub, + JSPROP_PERMANENT, NULL)) { + return JS_FALSE; + } + } else { + JS_ASSERT(fp->fun && !JSFUN_HEAVYWEIGHT_TEST(fp->fun->flags)); + } + fp->xmlNamespace = JSVAL_TO_OBJECT(v); + return JS_TRUE; +} + +JSBool +js_ToAttributeName(JSContext *cx, jsval *vp) +{ + JSObject *qn; + + qn = ToAttributeName(cx, *vp); + if (!qn) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(qn); + return JS_TRUE; +} + +JSString * +js_EscapeAttributeValue(JSContext *cx, JSString *str, JSBool quote) +{ + return EscapeAttributeValue(cx, NULL, str, quote); +} + +JSString * +js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, JSString *str2) +{ + size_t len, len2, newlen; + jschar *chars, *chars2; + + JSSTRING_CHARS_AND_LENGTH(str, chars, len); + if (!JSSTRING_IS_MUTABLE(str)) { + str = js_NewStringCopyN(cx, chars, len); + if (!str) + return NULL; + chars = JSFLATSTR_CHARS(str); + } else { + /* + * Reallocating str (because we know it has no other references) + * requires purging any deflated string cached for it. + */ + js_PurgeDeflatedStringCache(cx->runtime, str); + } + + JSSTRING_CHARS_AND_LENGTH(str2, chars2, len2); + newlen = (isName) ? len + 1 + len2 : len + 2 + len2 + 1; + chars = (jschar *) JS_realloc(cx, chars, (newlen+1) * sizeof(jschar)); + if (!chars) + return NULL; + + JSFLATSTR_INIT(str, chars, newlen); + chars += len; + if (isName) { + *chars++ = ' '; + js_strncpy(chars, chars2, len2); + chars += len2; + } else { + *chars++ = '='; + *chars++ = '"'; + js_strncpy(chars, chars2, len2); + chars += len2; + *chars++ = '"'; + } + *chars = 0; + return str; +} + +JSString * +js_EscapeElementValue(JSContext *cx, JSString *str) +{ + return EscapeElementValue(cx, NULL, str); +} + +JSString * +js_ValueToXMLString(JSContext *cx, jsval v) +{ + return ToXMLString(cx, v, 0); +} + +static JSBool +anyname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + *rval = ATOM_KEY(cx->runtime->atomState.starAtom); + return JS_TRUE; +} + +JSBool +js_GetAnyName(JSContext *cx, jsval *vp) +{ + JSRuntime *rt; + JSObject *obj; + JSBool ok; + + /* Optimize by avoiding JS_LOCK_GC(rt) for the common case. */ + rt = cx->runtime; + obj = rt->anynameObject; + if (!obj) { + JS_LOCK_GC(rt); + obj = rt->anynameObject; + if (!obj) { + JS_UNLOCK_GC(rt); + + /* + * Protect multiple newborns created below, in the do-while(0) + * loop used to ensure that we leave this local root scope. + */ + ok = js_EnterLocalRootScope(cx); + if (!ok) + return JS_FALSE; + + do { + obj = js_NewObjectWithGivenProto(cx, &js_AnyNameClass, NULL, + NULL, 0); + if (!obj) { + ok = JS_FALSE; + break; + } + InitXMLQName(obj, rt->emptyString, rt->emptyString, + ATOM_TO_STRING(rt->atomState.starAtom)); + METER(xml_stats.qname); + + /* + * Avoid entraining any Object.prototype found via cx's scope + * chain or global object. This loses the default toString, + * but no big deal: we want to customize toString anyway for + * clearer diagnostics. + */ + if (!JS_DefineFunction(cx, obj, js_toString_str, + anyname_toString, 0, 0)) { + ok = JS_FALSE; + break; + } + JS_ASSERT(!OBJ_GET_PROTO(cx, obj)); + JS_ASSERT(!OBJ_GET_PARENT(cx, obj)); + } while (0); + + js_LeaveLocalRootScopeWithResult(cx, OBJECT_TO_JSVAL(obj)); + if (!ok) + return JS_FALSE; + + JS_LOCK_GC(rt); + if (!rt->anynameObject) + rt->anynameObject = obj; + else + obj = rt->anynameObject; + } + JS_UNLOCK_GC(rt); + } + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +JSBool +js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp) +{ + JSObject *nameobj; + jsval v; + JSObject *qn; + jsid funid; + JSObject *obj, *target, *proto, *pobj; + JSXML *xml; + JSBool found; + JSProperty *prop; + const char *printable; + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(nameval)); + nameobj = JSVAL_TO_OBJECT(nameval); + if (OBJ_GET_CLASS(cx, nameobj) == &js_AnyNameClass) { + v = STRING_TO_JSVAL(ATOM_TO_STRING(cx->runtime->atomState.starAtom)); + nameobj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, + &v); + if (!nameobj) + return JS_FALSE; + } else { + JS_ASSERT(OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass || + OBJ_GET_CLASS(cx, nameobj) == &js_QNameClass.base); + } + + qn = nameobj; + if (!IsFunctionQName(cx, qn, &funid)) + return JS_FALSE; + + obj = cx->fp->scopeChain; + do { + /* Skip any With object that can wrap XML. */ + target = obj; + while (OBJ_GET_CLASS(cx, target) == &js_WithClass) { + proto = OBJ_GET_PROTO(cx, target); + if (!proto) + break; + target = proto; + } + + if (OBJECT_IS_XML(cx, target)) { + if (funid == 0) { + xml = (JSXML *) JS_GetPrivate(cx, target); + found = HasNamedProperty(xml, qn); + } else { + if (!HasFunctionProperty(cx, target, funid, &found)) + return JS_FALSE; + } + if (found) { + *idp = OBJECT_TO_JSID(nameobj); + *objp = target; + return JS_TRUE; + } + } else if (funid != 0) { + if (!OBJ_LOOKUP_PROPERTY(cx, target, funid, &pobj, &prop)) + return JS_FALSE; + if (prop) { + OBJ_DROP_PROPERTY(cx, pobj, prop); + *idp = funid; + *objp = target; + return JS_TRUE; + } + } + } while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL); + + printable = js_ValueToPrintableString(cx, OBJECT_TO_JSVAL(nameobj)); + if (printable) { + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_UNDEFINED_XML_NAME, printable); + } + return JS_FALSE; +} + +JSBool +js_GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + JSObject *target; + JSXML *xml; + JSTempValueRooter tvr; + JSBool ok; + + JS_ASSERT(OBJECT_IS_XML(cx, obj)); + + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); + + /* + * See comments before xml_lookupProperty about the need for the proto + * chain lookup. + */ + target = obj; + for (;;) { + ok = js_GetProperty(cx, target, id, vp); + if (!ok) + goto out; + if (VALUE_IS_FUNCTION(cx, *vp)) { + ok = JS_TRUE; + goto out; + } + target = OBJ_GET_PROTO(cx, target); + if (target == NULL) + break; + tvr.u.object = target; + } + + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (HasSimpleContent(xml)) { + /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ + ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(JSProto_String), + &tvr.u.object); + if (!ok) + goto out; + JS_ASSERT(tvr.u.object); + ok = OBJ_GET_PROPERTY(cx, tvr.u.object, id, vp); + } + + out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +static JSXML * +GetPrivate(JSContext *cx, JSObject *obj, const char *method) +{ + JSXML *xml; + + xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); + if (!xml) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_METHOD, + js_XML_str, method, OBJ_GET_CLASS(cx, obj)->name); + } + return xml; +} + +JSBool +js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSXML *xml, *list; + + xml = GetPrivate(cx, obj, "descendants internal method"); + if (!xml) + return JS_FALSE; + + list = Descendants(cx, xml, id); + if (!list) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(list->object); + return JS_TRUE; +} + +JSBool +js_DeleteXMLListElements(JSContext *cx, JSObject *listobj) +{ + JSXML *list; + uint32 n; + + list = (JSXML *) JS_GetPrivate(cx, listobj); + for (n = list->xml_kids.length; n != 0; --n) + DeleteListElement(cx, list, 0); + + return JS_TRUE; +} + +typedef struct JSXMLFilter { + JSXML *list; + JSXML *result; + JSXML *kid; + JSXMLArrayCursor cursor; + +} JSXMLFilter; + +static void +xmlfilter_trace(JSTracer *trc, JSObject *obj) +{ + JSXMLFilter *filter; + + filter = (JSXMLFilter *) JS_GetPrivate(trc->context, obj); + if (!filter) + return; + + JS_ASSERT(filter->list); + JS_CALL_TRACER(trc, filter->list, JSTRACE_XML, "list"); + if (filter->result) + JS_CALL_TRACER(trc, filter->result, JSTRACE_XML, "result"); + if (filter->kid) + JS_CALL_TRACER(trc, filter->kid, JSTRACE_XML, "kid"); + + /* + * We do not need to trace the cursor as that would be done when + * tracing the filter->list. + */ +} + +static void +xmlfilter_finalize(JSContext *cx, JSObject *obj) +{ + JSXMLFilter *filter; + + filter = (JSXMLFilter *) JS_GetPrivate(cx, obj); + if (!filter) + return; + + XMLArrayCursorFinish(&filter->cursor); + JS_free(cx, filter); +} + +JSClass js_XMLFilterClass = { + "XMLFilter", + JSCLASS_HAS_PRIVATE | + JSCLASS_IS_ANONYMOUS | + JSCLASS_MARK_IS_TRACE | + JSCLASS_HAS_CACHED_PROTO(JSProto_XMLFilter), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, xmlfilter_finalize, + NULL, NULL, NULL, NULL, + NULL, NULL, JS_CLASS_TRACE(xmlfilter_trace), NULL +}; + +JSObject * +js_InitXMLFilterClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + + proto = JS_InitClass(cx, obj, NULL, &js_XMLFilterClass, NULL, 0, NULL, + NULL, NULL, NULL); + if (!proto) + return NULL; + + OBJ_CLEAR_PROTO(cx, proto); + return proto; +} + +JSBool +js_StepXMLListFilter(JSContext *cx, JSBool initialized) +{ + jsval *sp; + JSObject *obj, *filterobj, *resobj, *kidobj; + JSXML *xml, *list; + JSXMLFilter *filter; + + sp = cx->fp->regs->sp; + if (!initialized) { + /* + * We haven't iterated yet, so initialize the filter based on the + * value stored in sp[-2]. + */ + if (!VALUE_IS_XML(cx, sp[-2])) { + js_ReportValueError(cx, JSMSG_NON_XML_FILTER, -2, sp[-2], NULL); + return JS_FALSE; + } + obj = JSVAL_TO_OBJECT(sp[-2]); + xml = (JSXML *) JS_GetPrivate(cx, obj); + + if (xml->xml_class == JSXML_CLASS_LIST) { + list = xml; + } else { + obj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!obj) + return JS_FALSE; + + /* + * Root just-created obj. sp[-2] cannot be used yet for rooting + * as it may be the only root holding xml. + */ + sp[-1] = OBJECT_TO_JSVAL(obj); + list = (JSXML *) JS_GetPrivate(cx, obj); + if (!Append(cx, list, xml)) + return JS_FALSE; + } + + filterobj = js_NewObject(cx, &js_XMLFilterClass, NULL, NULL, 0); + if (!filterobj) + return JS_FALSE; + + filter = (JSXMLFilter *) JS_malloc(cx, sizeof *filter); + if (!filter) + return JS_FALSE; + + /* + * Init all filter fields before JS_SetPrivate exposes it to + * xmlfilter_trace or xmlfilter_finalize. + */ + filter->list = list; + filter->result = NULL; + filter->kid = NULL; + XMLArrayCursorInit(&filter->cursor, &list->xml_kids); + JS_SetPrivate(cx, filterobj, filter); + + /* Store filterobj to use in the later iterations. */ + sp[-2] = OBJECT_TO_JSVAL(filterobj); + + resobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!resobj) + return JS_FALSE; + + /* This also roots resobj. */ + filter->result = (JSXML *) JS_GetPrivate(cx, resobj); + } else { + /* We have iterated at least once. */ + JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[-2])); + JS_ASSERT(OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(sp[-2])) == + &js_XMLFilterClass); + filter = (JSXMLFilter *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(sp[-2])); + JS_ASSERT(filter->kid); + + /* Check if the filter expression wants to append the element. */ + if (js_ValueToBoolean(sp[-1]) && + !Append(cx, filter->result, filter->kid)) { + return JS_FALSE; + } + } + + /* Do the iteration. */ + filter->kid = (JSXML *) XMLArrayCursorNext(&filter->cursor); + if (!filter->kid) { + /* + * Do not defer finishing the cursor until the next GC cycle to avoid + * accumulation of dead cursors associated with filter->list. + */ + XMLArrayCursorFinish(&filter->cursor); + JS_ASSERT(filter->result->object); + sp[-2] = OBJECT_TO_JSVAL(filter->result->object); + kidobj = NULL; + } else { + kidobj = js_GetXMLObject(cx, filter->kid); + if (!kidobj) + return JS_FALSE; + } + + /* Null as kidobj at sp[-1] signals filter termination. */ + sp[-1] = OBJECT_TO_JSVAL(kidobj); + return JS_TRUE; +} + +JSObject * +js_ValueToXMLObject(JSContext *cx, jsval v) +{ + return ToXML(cx, v); +} + +JSObject * +js_ValueToXMLListObject(JSContext *cx, jsval v) +{ + return ToXMLList(cx, v); +} + +JSObject * +js_CloneXMLObject(JSContext *cx, JSObject *obj) +{ + uintN flags; + JSXML *xml; + + if (!GetXMLSettingFlags(cx, &flags)) + return NULL; + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (flags & (XSF_IGNORE_COMMENTS | + XSF_IGNORE_PROCESSING_INSTRUCTIONS | + XSF_IGNORE_WHITESPACE)) { + xml = DeepCopy(cx, xml, NULL, flags); + if (!xml) + return NULL; + return xml->object; + } + return NewXMLObject(cx, xml); +} + +JSObject * +js_NewXMLSpecialObject(JSContext *cx, JSXMLClass xml_class, JSString *name, + JSString *value) +{ + uintN flags; + JSObject *obj; + JSXML *xml; + JSObject *qn; + + if (!GetXMLSettingFlags(cx, &flags)) + return NULL; + + if ((xml_class == JSXML_CLASS_COMMENT && + (flags & XSF_IGNORE_COMMENTS)) || + (xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION && + (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS))) { + return js_NewXMLObject(cx, JSXML_CLASS_TEXT); + } + + obj = js_NewXMLObject(cx, xml_class); + if (!obj) + return NULL; + xml = (JSXML *) JS_GetPrivate(cx, obj); + if (name) { + qn = NewXMLQName(cx, cx->runtime->emptyString, NULL, name); + if (!qn) + return NULL; + xml->name = qn; + } + xml->xml_value = value; + return obj; +} + +JSString * +js_MakeXMLCDATAString(JSContext *cx, JSString *str) +{ + return MakeXMLCDATAString(cx, NULL, str); +} + +JSString * +js_MakeXMLCommentString(JSContext *cx, JSString *str) +{ + return MakeXMLCommentString(cx, NULL, str); +} + +JSString * +js_MakeXMLPIString(JSContext *cx, JSString *name, JSString *str) +{ + return MakeXMLPIString(cx, NULL, name, str); +} + +#endif /* JS_HAS_XML_SUPPORT */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxml.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxml.h new file mode 100644 index 0000000..6952efc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/jsxml.h @@ -0,0 +1,298 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey E4X code, released August, 2004. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsxml_h___ +#define jsxml_h___ + +#include "jsstddef.h" +#include "jspubtd.h" + +JS_BEGIN_EXTERN_C + +extern const char js_AnyName_str[]; +extern const char js_AttributeName_str[]; +extern const char js_isXMLName_str[]; +extern const char js_XMLList_str[]; + +extern const char js_amp_entity_str[]; +extern const char js_gt_entity_str[]; +extern const char js_lt_entity_str[]; +extern const char js_quot_entity_str[]; + +typedef JSBool +(* JSIdentityOp)(const void *a, const void *b); + +struct JSXMLArray { + uint32 length; + uint32 capacity; + void **vector; + JSXMLArrayCursor *cursors; +}; + +#define JSXML_PRESET_CAPACITY JS_BIT(31) +#define JSXML_CAPACITY_MASK JS_BITMASK(31) +#define JSXML_CAPACITY(array) ((array)->capacity & JSXML_CAPACITY_MASK) + +struct JSXMLArrayCursor { + JSXMLArray *array; + uint32 index; + JSXMLArrayCursor *next; + JSXMLArrayCursor **prevp; + void *root; +}; + +/* + * NB: don't reorder this enum without changing all array initializers that + * depend on it in jsxml.c. + */ +typedef enum JSXMLClass { + JSXML_CLASS_LIST, + JSXML_CLASS_ELEMENT, + JSXML_CLASS_ATTRIBUTE, + JSXML_CLASS_PROCESSING_INSTRUCTION, + JSXML_CLASS_TEXT, + JSXML_CLASS_COMMENT, + JSXML_CLASS_LIMIT +} JSXMLClass; + +#define JSXML_CLASS_HAS_KIDS(class_) ((class_) < JSXML_CLASS_ATTRIBUTE) +#define JSXML_CLASS_HAS_VALUE(class_) ((class_) >= JSXML_CLASS_ATTRIBUTE) +#define JSXML_CLASS_HAS_NAME(class_) \ + ((uintN)((class_) - JSXML_CLASS_ELEMENT) <= \ + (uintN)(JSXML_CLASS_PROCESSING_INSTRUCTION - JSXML_CLASS_ELEMENT)) + +#ifdef DEBUG_notme +#include "jsclist.h" +#endif + +typedef struct JSXMLListVar { + JSXMLArray kids; /* NB: must come first */ + JSXML *target; + JSObject *targetprop; +} JSXMLListVar; + +typedef struct JSXMLElemVar { + JSXMLArray kids; /* NB: must come first */ + JSXMLArray namespaces; + JSXMLArray attrs; +} JSXMLElemVar; + +struct JSXML { +#ifdef DEBUG_notme + JSCList links; + uint32 serial; +#endif + JSObject *object; + void *domnode; /* DOM node if mapped info item */ + JSXML *parent; + JSObject *name; + uint16 xml_class; /* discriminates u, below */ + uint16 xml_flags; /* flags, see below */ + union { + JSXMLListVar list; + JSXMLElemVar elem; + JSString *value; + } u; + + /* Don't add anything after u -- see js_NewXML for why. */ +}; + +/* union member shorthands */ +#define xml_kids u.list.kids +#define xml_target u.list.target +#define xml_targetprop u.list.targetprop +#define xml_namespaces u.elem.namespaces +#define xml_attrs u.elem.attrs +#define xml_value u.value + +/* xml_flags values */ +#define XMLF_WHITESPACE_TEXT 0x1 + +/* xml_class-testing macros */ +#define JSXML_HAS_KIDS(xml) JSXML_CLASS_HAS_KIDS((xml)->xml_class) +#define JSXML_HAS_VALUE(xml) JSXML_CLASS_HAS_VALUE((xml)->xml_class) +#define JSXML_HAS_NAME(xml) JSXML_CLASS_HAS_NAME((xml)->xml_class) +#define JSXML_LENGTH(xml) (JSXML_CLASS_HAS_KIDS((xml)->xml_class) \ + ? (xml)->xml_kids.length \ + : 0) + +extern JSXML * +js_NewXML(JSContext *cx, JSXMLClass xml_class); + +extern void +js_TraceXML(JSTracer *trc, JSXML *xml); + +extern void +js_FinalizeXML(JSContext *cx, JSXML *xml); + +extern JSObject * +js_ParseNodeToXMLObject(JSContext *cx, JSParseContext *pc, JSParseNode *pn); + +extern JSObject * +js_NewXMLObject(JSContext *cx, JSXMLClass xml_class); + +extern JSObject * +js_GetXMLObject(JSContext *cx, JSXML *xml); + +extern JS_FRIEND_DATA(JSXMLObjectOps) js_XMLObjectOps; +extern JS_FRIEND_DATA(JSClass) js_XMLClass; +extern JS_FRIEND_DATA(JSExtendedClass) js_NamespaceClass; +extern JS_FRIEND_DATA(JSExtendedClass) js_QNameClass; +extern JS_FRIEND_DATA(JSClass) js_AttributeNameClass; +extern JS_FRIEND_DATA(JSClass) js_AnyNameClass; +extern JSClass js_XMLFilterClass; + +/* + * Macros to test whether an object or a value is of type "xml" (per typeof). + * NB: jsobj.h must be included before any call to OBJECT_IS_XML, and jsapi.h + * and jsobj.h must be included before any call to VALUE_IS_XML. + */ +#define OBJECT_IS_XML(cx,obj) ((obj)->map->ops == &js_XMLObjectOps.base) +#define VALUE_IS_XML(cx,v) (!JSVAL_IS_PRIMITIVE(v) && \ + OBJECT_IS_XML(cx, JSVAL_TO_OBJECT(v))) + +extern JSObject * +js_InitNamespaceClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitQNameClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitAttributeNameClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitAnyNameClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitXMLClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitXMLClasses(JSContext *cx, JSObject *obj); + +extern JSBool +js_GetFunctionNamespace(JSContext *cx, jsval *vp); + +/* + * If obj is QName corresponding to function::name, set *funidp to name's id, + * otherwise set *funidp to 0. + */ +JSBool +js_IsFunctionQName(JSContext *cx, JSObject *obj, jsid *funidp); + +extern JSBool +js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp); + +extern JSBool +js_SetDefaultXMLNamespace(JSContext *cx, jsval v); + +/* + * Return true if v is a XML QName object, or if it converts to a string that + * contains a valid XML qualified name (one containing no :), false otherwise. + * NB: This function is an infallible predicate, it hides exceptions. + */ +extern JSBool +js_IsXMLName(JSContext *cx, jsval v); + +extern JSBool +js_ToAttributeName(JSContext *cx, jsval *vp); + +extern JSString * +js_EscapeAttributeValue(JSContext *cx, JSString *str, JSBool quote); + +extern JSString * +js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, + JSString *str2); + +extern JSString * +js_EscapeElementValue(JSContext *cx, JSString *str); + +extern JSString * +js_ValueToXMLString(JSContext *cx, jsval v); + +extern JSObject * +js_ConstructXMLQNameObject(JSContext *cx, jsval nsval, jsval lnval); + +extern JSBool +js_GetAnyName(JSContext *cx, jsval *vp); + +/* + * Note: nameval must be either QName, AttributeName, or AnyName. + */ +extern JSBool +js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp); + +extern JSBool +js_GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JSBool +js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + +extern JSBool +js_DeleteXMLListElements(JSContext *cx, JSObject *listobj); + +extern JSObject * +js_InitXMLFilterClass(JSContext *cx, JSObject* obj); + +extern JSBool +js_StepXMLListFilter(JSContext *cx, JSBool initialized); + +extern JSObject * +js_ValueToXMLObject(JSContext *cx, jsval v); + +extern JSObject * +js_ValueToXMLListObject(JSContext *cx, jsval v); + +extern JSObject * +js_CloneXMLObject(JSContext *cx, JSObject *obj); + +extern JSObject * +js_NewXMLSpecialObject(JSContext *cx, JSXMLClass xml_class, JSString *name, + JSString *value); + +extern JSString * +js_MakeXMLCDATAString(JSContext *cx, JSString *str); + +extern JSString * +js_MakeXMLCommentString(JSContext *cx, JSString *str); + +extern JSString * +js_MakeXMLPIString(JSContext *cx, JSString *name, JSString *str); + +JS_END_EXTERN_C + +#endif /* jsxml_h___ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/lock_SunOS.s b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/lock_SunOS.s new file mode 100644 index 0000000..6feb202 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/lock_SunOS.s @@ -0,0 +1,119 @@ +! +! ***** BEGIN LICENSE BLOCK ***** +! Version: MPL 1.1/GPL 2.0/LGPL 2.1 +! +! The contents of this file are subject to the Mozilla Public License Version +! 1.1 (the "License"); you may not use this file except in compliance with +! the License. You may obtain a copy of the License at +! http://www.mozilla.org/MPL/ +! +! Software distributed under the License is distributed on an "AS IS" basis, +! WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +! for the specific language governing rights and limitations under the +! License. +! +! The Original Code is Mozilla Communicator client code, released +! March 31, 1998. +! +! The Initial Developer of the Original Code is +! Netscape Communications Corporation. +! Portions created by the Initial Developer are Copyright (C) 1998-1999 +! the Initial Developer. All Rights Reserved. +! +! Contributor(s): +! +! Alternatively, the contents of this file may be used under the terms of +! either the GNU General Public License Version 2 or later (the "GPL"), or +! the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +! in which case the provisions of the GPL or the LGPL are applicable instead +! of those above. If you wish to allow use of your version of this file only +! under the terms of either the GPL or the LGPL, and not to allow others to +! use your version of this file under the terms of the MPL, indicate your +! decision by deleting the provisions above and replace them with the notice +! and other provisions required by the GPL or the LGPL. If you do not delete +! the provisions above, a recipient may use your version of this file under +! the terms of any one of the MPL, the GPL or the LGPL. +! +! ***** END LICENSE BLOCK ***** + +! +! atomic compare-and-swap routines for V8 sparc +! and for V8+ (ultrasparc) +! +! +! standard asm linkage macros; this module must be compiled +! with the -P option (use C preprocessor) + +#include + +! ====================================================================== +! +! Perform the sequence *a = b atomically with respect to previous value +! of a (a0). If *a==a0 then assign *a to b, all in one atomic operation. +! Returns 1 if assignment happened, and 0 otherwise. +! +! usage : old_val = compare_and_swap(address, oldval, newval) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [input] - the old value to compare with +! %o2 [input] - the new value to set for [%o0] +! %o3 [local] - work register +! ----------------------- +#ifndef ULTRA_SPARC +! v8 + + ENTRY(compare_and_swap) ! standard assembler/ELF prologue + + stbar + mov -1,%o3 ! busy flag + swap [%o0],%o3 ! get current value +l1: cmp %o3,-1 ! busy? + be,a l1 ! if so, spin + swap [%o0],%o3 ! using branch-delay to swap back value + cmp %o1,%o3 ! compare old with current + be,a l2 ! if equal then swap in new value + swap [%o0],%o2 ! done. + swap [%o0],%o3 ! otherwise, swap back current value + retl + mov 0,%o0 ! return false +l2: retl + mov 1,%o0 ! return true + + SET_SIZE(compare_and_swap) ! standard assembler/ELF epilogue + +! +! end +! +#else /* ULTRA_SPARC */ +! ====================================================================== +! +! v9 + + ENTRY(compare_and_swap) ! standard assembler/ELF prologue + + stbar + cas [%o0],%o1,%o2 ! compare *w with old value and set to new if equal + cmp %o1,%o2 ! did we succeed? + be,a m1 ! yes + mov 1,%o0 ! return true (annulled when no jump) + mov 0,%o0 ! return false +m1: retl + nop + + SET_SIZE(compare_and_swap) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/plify_jsdhash.sed b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/plify_jsdhash.sed new file mode 100644 index 0000000..6827485 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/plify_jsdhash.sed @@ -0,0 +1,35 @@ +/ * Double hashing implementation./a\ + * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! +/ * Double hashing, a la Knuth 6./a\ + * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! +s/jsdhash_h___/pldhash_h___/ +s/jsdhash\.bigdump/pldhash.bigdump/ +s/jstypes\.h/nscore.h/ +s/jsbit\.h/prbit.h/ +s/jsdhash\.h/pldhash.h/ +s/jsdhash\.c/pldhash.c/ +s/jsdhash:/pldhash:/ +s/jsutil\.h/nsDebug.h/ +s/JS_DHASH/PL_DHASH/g +s/JS_DHash/PL_DHash/g +s/JSDHash/PLDHash/g +s/JSHash/PLHash/g +s/uint32 /PRUint32/g +s/\([^U]\)int32 /\1PRInt32/g +s/uint16 /PRUint16/g +s/\([^U]\)int16 /\1PRInt16/g +s/uint32/PRUint32/g +s/\([^U]\)int32/\1PRInt32/g +s/uint16/PRUint16/g +s/\([^U]\)int16/\1PRInt16/g +s/JSBool/PRBool/g +s/extern JS_PUBLIC_API(\([^()]*\))/NS_COM_GLUE \1/ +s/JS_PUBLIC_API(\([^()]*\))/\1/ +s/JS_NewDHashTable/PL_NewDHashTable/ +s/JS_ASSERT(0)/NS_NOTREACHED("0")/ +s/\( *\)JS_ASSERT(\(.*\));/\1NS_ASSERTION(\2,\n\1 "\2");/ +s/JSDHASH_ONELINE_ASSERT(\(.*\));/NS_ASSERTION(\1, "\1");/ +s/JS_UNLIKELY/NS_UNLIKELY/g +s/JS_LIKELY/NS_LIKELY/g +s/JS_/PR_/g +s/fprintf(stderr,/printf_stderr(/ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/prmjtime.cpp b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/prmjtime.cpp new file mode 100644 index 0000000..881dd70 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/prmjtime.cpp @@ -0,0 +1,846 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * PR time code. + */ +#include "jsstddef.h" +#ifdef SOLARIS +#define _REENTRANT 1 +#endif +#include +#include +#include "jstypes.h" +#include "jsutil.h" + +#include "jsprf.h" +#include "jslock.h" +#include "prmjtime.h" + +#define PRMJ_DO_MILLISECONDS 1 + +#ifdef XP_OS2 +#include +#endif +#ifdef XP_WIN +#include +#include +#include /* for fabs */ +#include /* for timeBegin/EndPeriod */ +/* VC++ 8.0 or later, and not WINCE */ +#if _MSC_VER >= 1400 && !defined(WINCE) +#define NS_HAVE_INVALID_PARAMETER_HANDLER 1 +#endif +#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER +#include /* for _set_invalid_parameter_handler */ +#include /* for _CrtSetReportMode */ +#endif + +#ifdef JS_THREADSAFE +#include +#endif + +#endif + +#if defined(XP_UNIX) || defined(XP_BEOS) + +#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ +extern int gettimeofday(struct timeval *tv); +#endif + +#include + +#endif /* XP_UNIX */ + +#define PRMJ_YEAR_DAYS 365L +#define PRMJ_FOUR_YEARS_DAYS (4 * PRMJ_YEAR_DAYS + 1) +#define PRMJ_CENTURY_DAYS (25 * PRMJ_FOUR_YEARS_DAYS - 1) +#define PRMJ_FOUR_CENTURIES_DAYS (4 * PRMJ_CENTURY_DAYS + 1) +#define PRMJ_HOUR_SECONDS 3600L +#define PRMJ_DAY_SECONDS (24L * PRMJ_HOUR_SECONDS) +#define PRMJ_YEAR_SECONDS (PRMJ_DAY_SECONDS * PRMJ_YEAR_DAYS) +#define PRMJ_MAX_UNIX_TIMET 2145859200L /*time_t value equiv. to 12/31/2037 */ + +/* function prototypes */ +static void PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm); +/* + * get the difference in seconds between this time zone and UTC (GMT) + */ +JSInt32 +PRMJ_LocalGMTDifference() +{ + struct tm ltime; + + /* get the difference between this time zone and GMT */ + memset((char *)<ime,0,sizeof(ltime)); + ltime.tm_mday = 2; + ltime.tm_year = 70; + return (JSInt32)mktime(<ime) - (24L * 3600L); +} + +/* Constants for GMT offset from 1970 */ +#define G1970GMTMICROHI 0x00dcdcad /* micro secs to 1970 hi */ +#define G1970GMTMICROLOW 0x8b3fa000 /* micro secs to 1970 low */ + +#define G2037GMTMICROHI 0x00e45fab /* micro secs to 2037 high */ +#define G2037GMTMICROLOW 0x7a238000 /* micro secs to 2037 low */ + +/* Convert from base time to extended time */ +static JSInt64 +PRMJ_ToExtendedTime(JSInt32 base_time) +{ + JSInt64 exttime; + JSInt64 g1970GMTMicroSeconds; + JSInt64 low; + JSInt32 diff; + JSInt64 tmp; + JSInt64 tmp1; + + diff = PRMJ_LocalGMTDifference(); + JSLL_UI2L(tmp, PRMJ_USEC_PER_SEC); + JSLL_I2L(tmp1,diff); + JSLL_MUL(tmp,tmp,tmp1); + + JSLL_UI2L(g1970GMTMicroSeconds,G1970GMTMICROHI); + JSLL_UI2L(low,G1970GMTMICROLOW); +#ifndef JS_HAVE_LONG_LONG + JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16); + JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16); +#else + JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,32); +#endif + JSLL_ADD(g1970GMTMicroSeconds,g1970GMTMicroSeconds,low); + + JSLL_I2L(exttime,base_time); + JSLL_ADD(exttime,exttime,g1970GMTMicroSeconds); + JSLL_SUB(exttime,exttime,tmp); + return exttime; +} + +#ifdef XP_WIN +typedef struct CalibrationData +{ + long double freq; /* The performance counter frequency */ + long double offset; /* The low res 'epoch' */ + long double timer_offset; /* The high res 'epoch' */ + + /* The last high res time that we returned since recalibrating */ + JSInt64 last; + + JSBool calibrated; + +#ifdef JS_THREADSAFE + CRITICAL_SECTION data_lock; + CRITICAL_SECTION calibration_lock; +#endif +} CalibrationData; + +static const JSInt64 win2un = JSLL_INIT(0x19DB1DE, 0xD53E8000); + +static CalibrationData calibration = { 0 }; + +#define FILETIME2INT64(ft) (((JSInt64)ft.dwHighDateTime) << 32LL | (JSInt64)ft.dwLowDateTime) + +static void +NowCalibrate() +{ + FILETIME ft, ftStart; + LARGE_INTEGER liFreq, now; + + if (calibration.freq == 0.0) { + if(!QueryPerformanceFrequency(&liFreq)) { + /* High-performance timer is unavailable */ + calibration.freq = -1.0; + } else { + calibration.freq = (long double) liFreq.QuadPart; + } + } + if (calibration.freq > 0.0) { + JSInt64 calibrationDelta = 0; + + /* By wrapping a timeBegin/EndPeriod pair of calls around this loop, + the loop seems to take much less time (1 ms vs 15ms) on Vista. */ + timeBeginPeriod(1); + GetSystemTimeAsFileTime(&ftStart); + do { + GetSystemTimeAsFileTime(&ft); + } while (memcmp(&ftStart,&ft, sizeof(ft)) == 0); + timeEndPeriod(1); + + /* + calibrationDelta = (FILETIME2INT64(ft) - FILETIME2INT64(ftStart))/10; + fprintf(stderr, "Calibration delta was %I64d us\n", calibrationDelta); + */ + + QueryPerformanceCounter(&now); + + calibration.offset = (long double) FILETIME2INT64(ft); + calibration.timer_offset = (long double) now.QuadPart; + + /* The windows epoch is around 1600. The unix epoch is around + 1970. win2un is the difference (in windows time units which + are 10 times more highres than the JS time unit) */ + calibration.offset -= win2un; + calibration.offset *= 0.1; + calibration.last = 0; + + calibration.calibrated = JS_TRUE; + } +} + +#define CALIBRATIONLOCK_SPINCOUNT 0 +#define DATALOCK_SPINCOUNT 4096 +#define LASTLOCK_SPINCOUNT 4096 + +#ifdef JS_THREADSAFE +static PRStatus +NowInit(void) +{ + memset(&calibration, 0, sizeof(calibration)); + NowCalibrate(); + InitializeCriticalSectionAndSpinCount(&calibration.calibration_lock, CALIBRATIONLOCK_SPINCOUNT); + InitializeCriticalSectionAndSpinCount(&calibration.data_lock, DATALOCK_SPINCOUNT); + return PR_SUCCESS; +} + +void +PRMJ_NowShutdown() +{ + DeleteCriticalSection(&calibration.calibration_lock); + DeleteCriticalSection(&calibration.data_lock); +} + +#define MUTEX_LOCK(m) EnterCriticalSection(m) +#define MUTEX_TRYLOCK(m) TryEnterCriticalSection(m) +#define MUTEX_UNLOCK(m) LeaveCriticalSection(m) +#define MUTEX_SETSPINCOUNT(m, c) SetCriticalSectionSpinCount((m),(c)) + +static PRCallOnceType calibrationOnce = { 0 }; + +#else + +#define MUTEX_LOCK(m) +#define MUTEX_TRYLOCK(m) 1 +#define MUTEX_UNLOCK(m) +#define MUTEX_SETSPINCOUNT(m, c) + +#endif + + +#endif /* XP_WIN */ + +/* + +Win32 python-esque pseudo code +Please see bug 363258 for why the win32 timing code is so complex. + +calibration mutex : Win32CriticalSection(spincount=0) +data mutex : Win32CriticalSection(spincount=4096) + +def NowInit(): + init mutexes + PRMJ_NowCalibration() + +def NowCalibration(): + expensive up-to-15ms call + +def PRMJ_Now(): + returnedTime = 0 + needCalibration = False + cachedOffset = 0.0 + calibrated = False + PR_CallOnce(PRMJ_NowInit) + do + if not global.calibrated or needCalibration: + acquire calibration mutex + acquire data mutex + + // Only recalibrate if someone didn't already + if cachedOffset == calibration.offset: + // Have all waiting threads immediately wait + set data mutex spin count = 0 + PRMJ_NowCalibrate() + calibrated = 1 + + set data mutex spin count = default + release data mutex + release calibration mutex + + calculate lowres time + + if highres timer available: + acquire data mutex + calculate highres time + cachedOffset = calibration.offset + highres time = calibration.last = max(highres time, calibration.last) + release data mutex + + get kernel tick interval + + if abs(highres - lowres) < kernel tick: + returnedTime = highres time + needCalibration = False + else: + if calibrated: + returnedTime = lowres + needCalibration = False + else: + needCalibration = True + else: + returnedTime = lowres + while needCalibration + +*/ + +JSInt64 +PRMJ_Now(void) +{ +#ifdef XP_OS2 + JSInt64 s, us, ms2us, s2us; + struct timeb b; +#endif +#ifdef XP_WIN + static int nCalls = 0; + long double lowresTime, highresTimerValue; + FILETIME ft; + LARGE_INTEGER now; + JSBool calibrated = JS_FALSE; + JSBool needsCalibration = JS_FALSE; + JSInt64 returnedTime; + long double cachedOffset = 0.0; +#endif +#if defined(XP_UNIX) || defined(XP_BEOS) + struct timeval tv; + JSInt64 s, us, s2us; +#endif /* XP_UNIX */ + +#ifdef XP_OS2 + ftime(&b); + JSLL_UI2L(ms2us, PRMJ_USEC_PER_MSEC); + JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); + JSLL_UI2L(s, b.time); + JSLL_UI2L(us, b.millitm); + JSLL_MUL(us, us, ms2us); + JSLL_MUL(s, s, s2us); + JSLL_ADD(s, s, us); + return s; +#endif +#ifdef XP_WIN + + /* To avoid regressing startup time (where high resolution is likely + not needed), give the old behavior for the first few calls. + This does not appear to be needed on Vista as the timeBegin/timeEndPeriod + calls seem to immediately take effect. */ + int thiscall = JS_ATOMIC_INCREMENT(&nCalls); + /* 10 seems to be the number of calls to load with a blank homepage */ + if (thiscall <= 10) { + GetSystemTimeAsFileTime(&ft); + return (FILETIME2INT64(ft)-win2un)/10L; + } + + /* For non threadsafe platforms, NowInit is not necessary */ +#ifdef JS_THREADSAFE + PR_CallOnce(&calibrationOnce, NowInit); +#endif + do { + if (!calibration.calibrated || needsCalibration) { + MUTEX_LOCK(&calibration.calibration_lock); + MUTEX_LOCK(&calibration.data_lock); + + /* Recalibrate only if no one else did before us */ + if(calibration.offset == cachedOffset) { + /* Since calibration can take a while, make any other + threads immediately wait */ + MUTEX_SETSPINCOUNT(&calibration.data_lock, 0); + + NowCalibrate(); + + calibrated = JS_TRUE; + + /* Restore spin count */ + MUTEX_SETSPINCOUNT(&calibration.data_lock, DATALOCK_SPINCOUNT); + } + MUTEX_UNLOCK(&calibration.data_lock); + MUTEX_UNLOCK(&calibration.calibration_lock); + } + + + /* Calculate a low resolution time */ + GetSystemTimeAsFileTime(&ft); + lowresTime = 0.1*(long double)(FILETIME2INT64(ft) - win2un); + + if (calibration.freq > 0.0) { + long double highresTime, diff; + + DWORD timeAdjustment, timeIncrement; + BOOL timeAdjustmentDisabled; + + /* Default to 15.625 ms if the syscall fails */ + long double skewThreshold = 15625.25; + /* Grab high resolution time */ + QueryPerformanceCounter(&now); + highresTimerValue = (long double)now.QuadPart; + + MUTEX_LOCK(&calibration.data_lock); + highresTime = calibration.offset + PRMJ_USEC_PER_SEC* + (highresTimerValue-calibration.timer_offset)/calibration.freq; + cachedOffset = calibration.offset; + + /* On some dual processor/core systems, we might get an earlier time + so we cache the last time that we returned */ + calibration.last = max(calibration.last,(JSInt64)highresTime); + returnedTime = calibration.last; + MUTEX_UNLOCK(&calibration.data_lock); + + /* Rather than assume the NT kernel ticks every 15.6ms, ask it */ + if (GetSystemTimeAdjustment(&timeAdjustment, + &timeIncrement, + &timeAdjustmentDisabled)) { + if (timeAdjustmentDisabled) { + /* timeAdjustment is in units of 100ns */ + skewThreshold = timeAdjustment/10.0; + } else { + /* timeIncrement is in units of 100ns */ + skewThreshold = timeIncrement/10.0; + } + } + + /* Check for clock skew */ + diff = lowresTime - highresTime; + + /* For some reason that I have not determined, the skew can be + up to twice a kernel tick. This does not seem to happen by + itself, but I have only seen it triggered by another program + doing some kind of file I/O. The symptoms are a negative diff + followed by an equally large positive diff. */ + if (fabs(diff) > 2*skewThreshold) { + /*fprintf(stderr,"Clock skew detected (diff = %f)!\n", diff);*/ + + if (calibrated) { + /* If we already calibrated once this instance, and the + clock is still skewed, then either the processor(s) are + wildly changing clockspeed or the system is so busy that + we get switched out for long periods of time. In either + case, it would be infeasible to make use of high + resolution results for anything, so let's resort to old + behavior for this call. It's possible that in the + future, the user will want the high resolution timer, so + we don't disable it entirely. */ + returnedTime = (JSInt64)lowresTime; + needsCalibration = JS_FALSE; + } else { + /* It is possible that when we recalibrate, we will return a + value less than what we have returned before; this is + unavoidable. We cannot tell the different between a + faulty QueryPerformanceCounter implementation and user + changes to the operating system time. Since we must + respect user changes to the operating system time, we + cannot maintain the invariant that Date.now() never + decreases; the old implementation has this behavior as + well. */ + needsCalibration = JS_TRUE; + } + } else { + /* No detectable clock skew */ + returnedTime = (JSInt64)highresTime; + needsCalibration = JS_FALSE; + } + } else { + /* No high resolution timer is available, so fall back */ + returnedTime = (JSInt64)lowresTime; + } + } while (needsCalibration); + + return returnedTime; +#endif + +#if defined(XP_UNIX) || defined(XP_BEOS) +#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ + gettimeofday(&tv); +#else + gettimeofday(&tv, 0); +#endif /* _SVID_GETTOD */ + JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); + JSLL_UI2L(s, tv.tv_sec); + JSLL_UI2L(us, tv.tv_usec); + JSLL_MUL(s, s, s2us); + JSLL_ADD(s, s, us); + return s; +#endif /* XP_UNIX */ +} + +/* Get the DST timezone offset for the time passed in */ +JSInt64 +PRMJ_DSTOffset(JSInt64 local_time) +{ + JSInt64 us2s; + time_t local; + JSInt32 diff; + JSInt64 maxtimet; + struct tm tm; + PRMJTime prtm; +#ifndef HAVE_LOCALTIME_R + struct tm *ptm; +#endif + + + JSLL_UI2L(us2s, PRMJ_USEC_PER_SEC); + JSLL_DIV(local_time, local_time, us2s); + + /* get the maximum of time_t value */ + JSLL_UI2L(maxtimet,PRMJ_MAX_UNIX_TIMET); + + if(JSLL_CMP(local_time,>,maxtimet)){ + JSLL_UI2L(local_time,PRMJ_MAX_UNIX_TIMET); + } else if(!JSLL_GE_ZERO(local_time)){ + /*go ahead a day to make localtime work (does not work with 0) */ + JSLL_UI2L(local_time,PRMJ_DAY_SECONDS); + } + JSLL_L2UI(local,local_time); + PRMJ_basetime(local_time,&prtm); +#ifndef HAVE_LOCALTIME_R + ptm = localtime(&local); + if(!ptm){ + return 0; + } + tm = *ptm; +#else + localtime_r(&local,&tm); /* get dst information */ +#endif + + diff = ((tm.tm_hour - prtm.tm_hour) * PRMJ_HOUR_SECONDS) + + ((tm.tm_min - prtm.tm_min) * 60); + + if(diff < 0){ + diff += PRMJ_DAY_SECONDS; + } + + JSLL_UI2L(local_time,diff); + + JSLL_MUL(local_time,local_time,us2s); + + return(local_time); +} + +#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER +static void +PRMJ_InvalidParameterHandler(const wchar_t *expression, + const wchar_t *function, + const wchar_t *file, + unsigned int line, + uintptr_t pReserved) +{ + /* empty */ +} +#endif + +/* Format a time value into a buffer. Same semantics as strftime() */ +size_t +PRMJ_FormatTime(char *buf, int buflen, const char *fmt, PRMJTime *prtm) +{ + size_t result = 0; +#if defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) + struct tm a; + int fake_tm_year = 0; +#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER + _invalid_parameter_handler oldHandler; + int oldReportMode; +#endif + + /* Zero out the tm struct. Linux, SunOS 4 struct tm has extra members int + * tm_gmtoff, char *tm_zone; when tm_zone is garbage, strftime gets + * confused and dumps core. NSPR20 prtime.c attempts to fill these in by + * calling mktime on the partially filled struct, but this doesn't seem to + * work as well; the result string has "can't get timezone" for ECMA-valid + * years. Might still make sense to use this, but find the range of years + * for which valid tz information exists, and map (per ECMA hint) from the + * given year into that range. + + * N.B. This hasn't been tested with anything that actually _uses_ + * tm_gmtoff; zero might be the wrong thing to set it to if you really need + * to format a time. This fix is for jsdate.c, which only uses + * JS_FormatTime to get a string representing the time zone. */ + memset(&a, 0, sizeof(struct tm)); + + a.tm_sec = prtm->tm_sec; + a.tm_min = prtm->tm_min; + a.tm_hour = prtm->tm_hour; + a.tm_mday = prtm->tm_mday; + a.tm_mon = prtm->tm_mon; + a.tm_wday = prtm->tm_wday; + + /* + * Years before 1900 and after 9999 cause strftime() to abort on Windows. + * To avoid that we replace it with FAKE_YEAR_BASE + year % 100 and then + * replace matching substrings in the strftime() result with the real year. + * Note that FAKE_YEAR_BASE should be a multiple of 100 to make 2-digit + * year formats (%y) work correctly (since we won't find the fake year + * in that case). + * e.g. new Date(1873, 0).toLocaleFormat('%Y %y') => "1873 73" + * See bug 327869. + */ +#define FAKE_YEAR_BASE 9900 + if (prtm->tm_year < 1900 || prtm->tm_year > 9999) { + fake_tm_year = FAKE_YEAR_BASE + prtm->tm_year % 100; + a.tm_year = fake_tm_year - 1900; + } + else { + a.tm_year = prtm->tm_year - 1900; + } + a.tm_yday = prtm->tm_yday; + a.tm_isdst = prtm->tm_isdst; + + /* + * Even with the above, SunOS 4 seems to detonate if tm_zone and tm_gmtoff + * are null. This doesn't quite work, though - the timezone is off by + * tzoff + dst. (And mktime seems to return -1 for the exact dst + * changeover time.) + */ + +#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER + oldHandler = _set_invalid_parameter_handler(PRMJ_InvalidParameterHandler); + oldReportMode = _CrtSetReportMode(_CRT_ASSERT, 0); +#endif + + result = strftime(buf, buflen, fmt, &a); + +#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER + _set_invalid_parameter_handler(oldHandler); + _CrtSetReportMode(_CRT_ASSERT, oldReportMode); +#endif + + if (fake_tm_year && result) { + char real_year[16]; + char fake_year[16]; + size_t real_year_len; + size_t fake_year_len; + char* p; + + sprintf(real_year, "%d", prtm->tm_year); + real_year_len = strlen(real_year); + sprintf(fake_year, "%d", fake_tm_year); + fake_year_len = strlen(fake_year); + + /* Replace the fake year in the result with the real year. */ + for (p = buf; (p = strstr(p, fake_year)); p += real_year_len) { + size_t new_result = result + real_year_len - fake_year_len; + if ((int)new_result >= buflen) { + return 0; + } + memmove(p + real_year_len, p + fake_year_len, strlen(p + fake_year_len)); + memcpy(p, real_year, real_year_len); + result = new_result; + *(buf + result) = '\0'; + } + } +#endif + return result; +} + +/* table for number of days in a month */ +static int mtab[] = { + /* jan, feb,mar,apr,may,jun */ + 31,28,31,30,31,30, + /* july,aug,sep,oct,nov,dec */ + 31,31,30,31,30,31 +}; + +/* + * basic time calculation functionality for localtime and gmtime + * setups up prtm argument with correct values based upon input number + * of seconds. + */ +static void +PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm) +{ + /* convert tsecs back to year,month,day,hour,secs */ + JSInt32 year = 0; + JSInt32 month = 0; + JSInt32 yday = 0; + JSInt32 mday = 0; + JSInt32 wday = 6; /* start on a Sunday */ + JSInt32 days = 0; + JSInt32 seconds = 0; + JSInt32 minutes = 0; + JSInt32 hours = 0; + JSInt32 isleap = 0; + + /* Temporaries used for various computations */ + JSInt64 result; + JSInt64 result1; + JSInt64 result2; + + JSInt64 base; + + /* Some variables for intermediate result storage to make computing isleap + easier/faster */ + JSInt32 fourCenturyBlocks; + JSInt32 centuriesLeft; + JSInt32 fourYearBlocksLeft; + JSInt32 yearsLeft; + + /* Since leap years work by 400/100/4 year intervals, precompute the length + of those in seconds if they start at the beginning of year 1. */ + JSInt64 fourYears; + JSInt64 century; + JSInt64 fourCenturies; + + JSLL_UI2L(result, PRMJ_DAY_SECONDS); + + JSLL_I2L(fourYears, PRMJ_FOUR_YEARS_DAYS); + JSLL_MUL(fourYears, fourYears, result); + + JSLL_I2L(century, PRMJ_CENTURY_DAYS); + JSLL_MUL(century, century, result); + + JSLL_I2L(fourCenturies, PRMJ_FOUR_CENTURIES_DAYS); + JSLL_MUL(fourCenturies, fourCenturies, result); + + /* get the base time via UTC */ + base = PRMJ_ToExtendedTime(0); + JSLL_UI2L(result, PRMJ_USEC_PER_SEC); + JSLL_DIV(base,base,result); + JSLL_ADD(tsecs,tsecs,base); + + /* Compute our |year|, |isleap|, and part of |days|. When this part is + done, |year| should hold the year our date falls in (number of whole + years elapsed before our date), isleap should hold 1 if the year the + date falls in is a leap year and 0 otherwise. */ + + /* First do year 0; it's special and nonleap. */ + JSLL_UI2L(result, PRMJ_YEAR_SECONDS); + if (!JSLL_CMP(tsecs,<,result)) { + days = PRMJ_YEAR_DAYS; + year = 1; + JSLL_SUB(tsecs, tsecs, result); + } + + /* Now use those constants we computed above */ + JSLL_UDIVMOD(&result1, &result2, tsecs, fourCenturies); + JSLL_L2I(fourCenturyBlocks, result1); + year += fourCenturyBlocks * 400; + days += fourCenturyBlocks * PRMJ_FOUR_CENTURIES_DAYS; + tsecs = result2; + + JSLL_UDIVMOD(&result1, &result2, tsecs, century); + JSLL_L2I(centuriesLeft, result1); + year += centuriesLeft * 100; + days += centuriesLeft * PRMJ_CENTURY_DAYS; + tsecs = result2; + + JSLL_UDIVMOD(&result1, &result2, tsecs, fourYears); + JSLL_L2I(fourYearBlocksLeft, result1); + year += fourYearBlocksLeft * 4; + days += fourYearBlocksLeft * PRMJ_FOUR_YEARS_DAYS; + tsecs = result2; + + /* Recall that |result| holds PRMJ_YEAR_SECONDS */ + JSLL_UDIVMOD(&result1, &result2, tsecs, result); + JSLL_L2I(yearsLeft, result1); + year += yearsLeft; + days += yearsLeft * PRMJ_YEAR_DAYS; + tsecs = result2; + + /* now compute isleap. Note that we don't have to use %, since we've + already computed those remainders. Also note that they're all offset by + 1 because of the 1 for year 0. */ + isleap = + (yearsLeft == 3) && (fourYearBlocksLeft != 24 || centuriesLeft == 3); + JS_ASSERT(isleap == + ((year % 4 == 0) && (year % 100 != 0 || year % 400 == 0))); + + JSLL_UI2L(result1,PRMJ_DAY_SECONDS); + + JSLL_DIV(result,tsecs,result1); + JSLL_L2I(mday,result); + + /* let's find the month */ + while(((month == 1 && isleap) ? + (mday >= mtab[month] + 1) : + (mday >= mtab[month]))){ + yday += mtab[month]; + days += mtab[month]; + + mday -= mtab[month]; + + /* it's a Feb, check if this is a leap year */ + if(month == 1 && isleap != 0){ + yday++; + days++; + mday--; + } + month++; + } + + /* now adjust tsecs */ + JSLL_MUL(result,result,result1); + JSLL_SUB(tsecs,tsecs,result); + + mday++; /* day of month always start with 1 */ + days += mday; + wday = (days + wday) % 7; + + yday += mday; + + /* get the hours */ + JSLL_UI2L(result1,PRMJ_HOUR_SECONDS); + JSLL_DIV(result,tsecs,result1); + JSLL_L2I(hours,result); + JSLL_MUL(result,result,result1); + JSLL_SUB(tsecs,tsecs,result); + + /* get minutes */ + JSLL_UI2L(result1,60); + JSLL_DIV(result,tsecs,result1); + JSLL_L2I(minutes,result); + JSLL_MUL(result,result,result1); + JSLL_SUB(tsecs,tsecs,result); + + JSLL_L2I(seconds,tsecs); + + prtm->tm_usec = 0L; + prtm->tm_sec = (JSInt8)seconds; + prtm->tm_min = (JSInt8)minutes; + prtm->tm_hour = (JSInt8)hours; + prtm->tm_mday = (JSInt8)mday; + prtm->tm_mon = (JSInt8)month; + prtm->tm_wday = (JSInt8)wday; + prtm->tm_year = (JSInt16)year; + prtm->tm_yday = (JSInt16)yday; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/prmjtime.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/prmjtime.h new file mode 100644 index 0000000..e553945 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/prmjtime.h @@ -0,0 +1,103 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prmjtime_h___ +#define prmjtime_h___ +/* + * PR date stuff for mocha and java. Placed here temporarily not to break + * Navigator and localize changes to mocha. + */ +#include +#include "jslong.h" +#ifdef MOZILLA_CLIENT +#include "jscompat.h" +#endif + +JS_BEGIN_EXTERN_C + +typedef struct PRMJTime PRMJTime; + +/* + * Broken down form of 64 bit time value. + */ +struct PRMJTime { + JSInt32 tm_usec; /* microseconds of second (0-999999) */ + JSInt8 tm_sec; /* seconds of minute (0-59) */ + JSInt8 tm_min; /* minutes of hour (0-59) */ + JSInt8 tm_hour; /* hour of day (0-23) */ + JSInt8 tm_mday; /* day of month (1-31) */ + JSInt8 tm_mon; /* month of year (0-11) */ + JSInt8 tm_wday; /* 0=sunday, 1=monday, ... */ + JSInt32 tm_year; /* absolute year, AD */ + JSInt16 tm_yday; /* day of year (0 to 365) */ + JSInt8 tm_isdst; /* non-zero if DST in effect */ +}; + +/* Some handy constants */ +#define PRMJ_USEC_PER_SEC 1000000L +#define PRMJ_USEC_PER_MSEC 1000L + +/* Return the current local time in micro-seconds */ +extern JSInt64 +PRMJ_Now(void); + +/* Release the resources associated with PRMJ_Now; don't call PRMJ_Now again */ +#if defined(JS_THREADSAFE) && defined(XP_WIN) +extern void +PRMJ_NowShutdown(void); +#else +#define PRMJ_NowShutdown() +#endif + +/* get the difference between this time zone and gmt timezone in seconds */ +extern JSInt32 +PRMJ_LocalGMTDifference(void); + +/* Format a time value into a buffer. Same semantics as strftime() */ +extern size_t +PRMJ_FormatTime(char *buf, int buflen, const char *fmt, PRMJTime *tm); + +/* Get the DST offset for the local time passed in */ +extern JSInt64 +PRMJ_DSTOffset(JSInt64 local_time); + +JS_END_EXTERN_C + +#endif /* prmjtime_h___ */ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.1.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.1.mk new file mode 100644 index 0000000..09c7cb9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.1.mk @@ -0,0 +1,65 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for AIX +# + +CC = xlC_r +CCC = xlC_r + +RANLIB = ranlib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< +ARCH := aix +CPU_ARCH = rs6000 +GFX_ARCH = x +INLINES = js_compare_and_swap:js_fast_lock1:js_fast_unlock1:js_lock_get_slot:js_lock_set_slot:js_lock_scope1 + +OS_CFLAGS = -qarch=com -qinline+$(INLINES) -DXP_UNIX -DAIX -DAIXV3 -DSYSV -DHAVE_LOCALTIME_R +OS_LIBS = -lbsd -lsvld -lm +#-lpthreads -lc_r + +MKSHLIB = $(LD) -bM:SRE -bh:4 -bnoentry -berok +XLDFLAGS += -lc + +ifdef JS_THREADSAFE +XLDFLAGS += -lsvld +endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.2.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.2.mk new file mode 100644 index 0000000..1e3f1f1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.2.mk @@ -0,0 +1,64 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for AIX +# + +CC = xlC_r +CCC = xlC_r +CFLAGS += -qarch=com -qnoansialias -qinline+$(INLINES) -DXP_UNIX -DAIX -DAIXV3 -DSYSV -DHAVE_LOCALTIME_R + +RANLIB = ranlib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< +ARCH := aix +CPU_ARCH = rs6000 +GFX_ARCH = x +INLINES = js_compare_and_swap:js_fast_lock1:js_fast_unlock1:js_lock_get_slot:js_lock_set_slot:js_lock_scope1 + +#-lpthreads -lc_r + +MKSHLIB = /usr/lpp/xlC/bin/makeC++SharedLib_r -p 0 -G -berok + +ifdef JS_THREADSAFE +XLDFLAGS += -ldl +endif + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.3.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.3.mk new file mode 100644 index 0000000..df05d8c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/AIX4.3.mk @@ -0,0 +1,65 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for AIX +# + +CC = xlC_r +CCC = xlC_r +CFLAGS += -qarch=com -qnoansialias -qinline+$(INLINES) -DXP_UNIX -DAIX -DAIXV3 -DSYSV -DAIX4_3 -DHAVE_LOCALTIME_R + +RANLIB = ranlib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< +ARCH := aix +CPU_ARCH = rs6000 +GFX_ARCH = x +INLINES = js_compare_and_swap:js_fast_lock1:js_fast_unlock1:js_lock_get_slot:js_lock_set_slot:js_lock_scope1 + +#-lpthreads -lc_r + +MKSHLIB_BIN = /usr/ibmcxx/bin/makeC++SharedLib_r +MKSHLIB = $(MKSHLIB_BIN) -p 0 -G -berok -bM:UR + +ifdef JS_THREADSAFE +XLDFLAGS += -ldl +endif + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Cygwin.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Cygwin.mk new file mode 100644 index 0000000..6319682 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Cygwin.mk @@ -0,0 +1,14 @@ +CC = gcc +CXX = g++ +LD = g++ +OS_CFLAGS_NO_ANSI = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DHAVE_LOCALTIME_R +OS_CFLAGS = -ansi $(OS_CFLAGS_NO_ANSI) +PROGRAM_CFLAGS = $(OPTIMIZER) $(OS_CFLAGS_NO_ANSI) $(DEFINES) $(INCLUDES) $(XCFLAGS) +RANLIB = ranlib +MKSHLIB = $(LD) -shared $(XMKSHLIBOPTS) + +all: + +obj/js.o: js.cpp + @$(MAKE_OBJDIR) + $(CXX) -o $@ -c $(PROGRAM_CFLAGS) js.cpp diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin.mk new file mode 100644 index 0000000..86c4b9d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin.mk @@ -0,0 +1,85 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = gcc +CCC = g++ +CFLAGS += -Wall -Wno-format -MMD +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DDARWIN + +RANLIB = ranlib +MKSHLIB = $(CCC) -dynamiclib $(XMKSHLIBOPTS) -framework System + +SO_SUFFIX = dylib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS+= -DX86_LINUX +OS_CFLAGS += -DAVMPLUS_IA32 -DAVMPLUS_UNIX +NANOJIT_ARCH = i386 +endif +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin1.3.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin1.3.mk new file mode 100644 index 0000000..05d3767 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin1.3.mk @@ -0,0 +1,81 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = cc +CCC = g++ +CFLAGS += -Wall -Wno-format +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DRHAPSODY + +RANLIB = ranlib +MKSHLIB = libtool $(XMKSHLIBOPTS) -framework System + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS+= -DX86_LINUX +endif +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin1.4.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin1.4.mk new file mode 100644 index 0000000..f7b6af8 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin1.4.mk @@ -0,0 +1,41 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mike McCabe +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +include $(DEPTH)/config/Darwin1.3.mk diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin5.2.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin5.2.mk new file mode 100644 index 0000000..9b9b6ff --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin5.2.mk @@ -0,0 +1,81 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = cc +CCC = g++ +CFLAGS += -Wall -Wno-format +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DDARWIN + +RANLIB = ranlib +MKSHLIB = libtool $(XMKSHLIBOPTS) -framework System + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS+= -DX86_LINUX +endif +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin5.3.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin5.3.mk new file mode 100644 index 0000000..9b9b6ff --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin5.3.mk @@ -0,0 +1,81 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = cc +CCC = g++ +CFLAGS += -Wall -Wno-format +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DDARWIN + +RANLIB = ranlib +MKSHLIB = libtool $(XMKSHLIBOPTS) -framework System + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS+= -DX86_LINUX +endif +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin64.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin64.mk new file mode 100644 index 0000000..db195b5 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Darwin64.mk @@ -0,0 +1,72 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = cc +CCC = g++ +CFLAGS += -Wall -Wno-format -MMD +OS_LDFLAGS += -m64 +OS_CFLAGS = -m64 -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DDARWIN + +RANLIB = ranlib +MKSHLIB = $(CCC) -dynamiclib $(XMKSHLIBOPTS) -framework System + +SO_SUFFIX = dylib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86_64 +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.10.10.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.10.10.mk new file mode 100644 index 0000000..8cd9d20 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.10.10.mk @@ -0,0 +1,77 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for HPUX +# + +# CC = gcc +# CCC = g++ +# CFLAGS += -Wall -Wno-format -fPIC + +CC = cc -Ae +Z +CCC = CC -Ae +a1 +eh +Z + +RANLIB = echo +MKSHLIB = $(LD) -b + +SO_SUFFIX = sl + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = hppa +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DHPUX -DSYSV -DHAVE_LOCALTIME_R +OS_LIBS = -ldld + +ifeq ($(OS_RELEASE),B.10) +PLATFORM_FLAGS += -DHPUX10 -Dhpux10 +PORT_FLAGS += -DRW_NO_OVERLOAD_SCHAR -DHAVE_MODEL_H +ifeq ($(OS_VERSION),.10) +PLATFORM_FLAGS += -DHPUX10_10 +endif +ifeq ($(OS_VERSION),.20) +PLATFORM_FLAGS += -DHPUX10_20 +endif +ifeq ($(OS_VERSION),.30) +PLATFORM_FLAGS += -DHPUX10_30 +endif +endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.10.20.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.10.20.mk new file mode 100644 index 0000000..8cd9d20 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.10.20.mk @@ -0,0 +1,77 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for HPUX +# + +# CC = gcc +# CCC = g++ +# CFLAGS += -Wall -Wno-format -fPIC + +CC = cc -Ae +Z +CCC = CC -Ae +a1 +eh +Z + +RANLIB = echo +MKSHLIB = $(LD) -b + +SO_SUFFIX = sl + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = hppa +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DHPUX -DSYSV -DHAVE_LOCALTIME_R +OS_LIBS = -ldld + +ifeq ($(OS_RELEASE),B.10) +PLATFORM_FLAGS += -DHPUX10 -Dhpux10 +PORT_FLAGS += -DRW_NO_OVERLOAD_SCHAR -DHAVE_MODEL_H +ifeq ($(OS_VERSION),.10) +PLATFORM_FLAGS += -DHPUX10_10 +endif +ifeq ($(OS_VERSION),.20) +PLATFORM_FLAGS += -DHPUX10_20 +endif +ifeq ($(OS_VERSION),.30) +PLATFORM_FLAGS += -DHPUX10_30 +endif +endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.11.00.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.11.00.mk new file mode 100644 index 0000000..239188d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/HP-UXB.11.00.mk @@ -0,0 +1,80 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for HPUX +# + +ifdef NS_USE_NATIVE + CC = cc +Z +DAportable +DS2.0 +u4 +# LD = aCC +Z -b -Wl,+s -Wl,-B,symbolic +else + CC = gcc -Wall -Wno-format -fPIC + CCC = g++ -Wall -Wno-format -fPIC +endif + +RANLIB = echo +MKSHLIB = $(LD) -b + +SO_SUFFIX = sl + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = hppa +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DHPUX -DSYSV -D_HPUX -DNATIVE -D_POSIX_C_SOURCE=199506L -DHAVE_LOCALTIME_R +OS_LIBS = -ldld + +XLDFLAGS = -lpthread + +ifeq ($(OS_RELEASE),B.10) +PLATFORM_FLAGS += -DHPUX10 -Dhpux10 +PORT_FLAGS += -DRW_NO_OVERLOAD_SCHAR -DHAVE_MODEL_H +ifeq ($(OS_VERSION),.10) +PLATFORM_FLAGS += -DHPUX10_10 +endif +ifeq ($(OS_VERSION),.20) +PLATFORM_FLAGS += -DHPUX10_20 +endif +ifeq ($(OS_VERSION),.30) +PLATFORM_FLAGS += -DHPUX10_30 +endif +endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX.mk new file mode 100644 index 0000000..88b162f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX.mk @@ -0,0 +1,87 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX +# + +CPU_ARCH = mips +GFX_ARCH = x + +RANLIB = /bin/true + +#NS_USE_GCC = 1 + +ifndef NS_USE_NATIVE +CC = gcc +CCC = g++ +AS = $(CC) -x assembler-with-cpp +ODD_CFLAGS = -Wall -Wno-format +ifdef BUILD_OPT +OPTIMIZER = -O6 +endif +else +ifeq ($(OS_RELEASE),6.2) +CC = cc -n32 -DIRIX6_2 +endif +ifeq ($(OS_RELEASE),6.3) +CC = cc -n32 -DIRIX6_3 +endif +ifeq ($(OS_RELEASE),6.5) +CC = cc -n32 -DIRIX6_5 +endif +CCC = CC +# LD = CC +ODD_CFLAGS = -fullwarn -xansi +ifdef BUILD_OPT +OPTIMIZER += -Olimit 4000 +endif +endif + +# For purify +HAVE_PURIFY = 1 +PURE_OS_CFLAGS = $(ODD_CFLAGS) -DXP_UNIX -DSVR4 -DSW_THREADS -DIRIX -DHAVE_LOCALTIME_R + +OS_CFLAGS = $(PURE_OS_CFLAGS) -MDupdate $(DEPENDENCIES) + +BSDECHO = echo +MKSHLIB = $(LD) -n32 -shared + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX5.3.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX5.3.mk new file mode 100644 index 0000000..f38cc94 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX5.3.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX5.3 +# + +include $(DEPTH)/config/IRIX.mk diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.1.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.1.mk new file mode 100644 index 0000000..354f1d1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.1.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX6.3 +# + +include $(DEPTH)/config/IRIX.mk diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.2.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.2.mk new file mode 100644 index 0000000..354f1d1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.2.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX6.3 +# + +include $(DEPTH)/config/IRIX.mk diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.3.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.3.mk new file mode 100644 index 0000000..354f1d1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.3.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX6.3 +# + +include $(DEPTH)/config/IRIX.mk diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.5.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.5.mk new file mode 100644 index 0000000..354f1d1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/IRIX6.5.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX6.3 +# + +include $(DEPTH)/config/IRIX.mk diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Linux_All.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Linux_All.mk new file mode 100644 index 0000000..6c289b4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Linux_All.mk @@ -0,0 +1,105 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for all versions of Linux +# + +CC = gcc +CCC = g++ +LD = g++ +CFLAGS += -Wall -Wno-format -MMD +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DHAVE_LOCALTIME_R -DLINUX + +RANLIB = echo +MKSHLIB = $(LD) -shared $(XMKSHLIBOPTS) + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +# don't filter in x86-64 architecture +ifneq (x86_64,$(CPU_ARCH)) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS += -DX86_LINUX -DAVMPLUS_IA32 -DAVMPLUS_UNIX -DAVMPLUS_LINUX +NANOJIT_ARCH = i386 +endif # 86 +endif # !x86_64 + +#JIT disabled until x64 port is cleaned up +#ifeq ($(CPU_ARCH),x86_64) +#OS_CFLAGS += -DAVMPLUS_AMD64 -DAVMPLUS_64BIT -DAVMPLUS_UNIX -DAVMPLUS_LINUX +#NANOJIT_ARCH = i386 +#endif + +ifeq ($(CPU_ARCH),arm) +OS_CFLAGS += -DAVMPLUS_ARM -DAVMPLUS_UNIX -DAVMPLUS_LINUX +NANOJIT_ARCH = ARM +endif + +GFX_ARCH = x + +OS_LIBS = -lm -lc + +ASFLAGS += -x assembler-with-cpp + + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +ifeq ($(CPU_ARCH),x86_64) +# Use VA_COPY() standard macro on x86-64 +# FIXME: better use it everywhere +OS_CFLAGS += -DHAVE_VA_COPY -DVA_COPY=va_copy +endif + +ifeq ($(CPU_ARCH),x86_64) +# We need PIC code for shared libraries +# FIXME: better patch rules.mk & fdlibm/Makefile* +OS_CFLAGS += -DPIC -fPIC +endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/MSYS.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/MSYS.mk new file mode 100644 index 0000000..61c3ab6 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/MSYS.mk @@ -0,0 +1,7 @@ +CC = gcc +CXX = g++ +LD = g++ +OS_CFLAGS = -DXP_WIN -DEXPORT_JS_API=1 +RANLIB = ranlib +MKSHLIB = $(LD) -shared $(XMKSHLIBOPTS) +OTHER_LIBS = -lwinmm diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Mac_OS10.0.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Mac_OS10.0.mk new file mode 100644 index 0000000..74ba151 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/Mac_OS10.0.mk @@ -0,0 +1,82 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = cc +CCC = g++ +CFLAGS += -Wall -Wno-format +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE +-DRHAPSODY + +RANLIB = ranlib +MKSHLIB = libtool -dynamic $(XMKSHLIBOPTS) -framework System + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS+= -DX86_LINUX +endif +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/OSF1V4.0.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/OSF1V4.0.mk new file mode 100644 index 0000000..337ca74 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/OSF1V4.0.mk @@ -0,0 +1,72 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for Data General DG/UX +# + +# +# Initial DG/UX port by Marc Fraioli (fraioli@dg-rtp.dg.com) +# + +ifndef NS_USE_NATIVE +CC = gcc +CCC = g++ +CFLAGS += -mieee -Wall -Wno-format +else +CC = cc +CCC = cxx +CFLAGS += -ieee -std +# LD = cxx +endif + +RANLIB = echo +MKSHLIB = $(LD) -shared -taso -all -expect_unresolved "*" + +# +# _DGUX_SOURCE is needed to turn on a lot of stuff in the headers if +# you're not using DG's compiler. It shouldn't hurt if you are. +# +# _POSIX4A_DRAFT10_SOURCE is needed to pick up localtime_r, used in +# prtime.c +# +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -DDGUX -D_DGUX_SOURCE -D_POSIX4A_DRAFT10_SOURCE -DOSF1 -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl + +NOSUCHFILE = /no-such-file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/OSF1V5.0.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/OSF1V5.0.mk new file mode 100644 index 0000000..b65738c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/OSF1V5.0.mk @@ -0,0 +1,69 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for Tru64 Unix 5.0 +# + +# +# Initial DG/UX port by Marc Fraioli (fraioli@dg-rtp.dg.com) +# + +ifndef NS_USE_NATIVE +CC = gcc +CCC = g++ +CFLAGS += -mieee -Wall -Wno-format +else +CC = cc +CCC = cxx +CFLAGS += -ieee -std -pthread +# LD = cxx +endif + +RANLIB = echo +MKSHLIB = $(LD) -shared -all -expect_unresolved "*" + +# +# _POSIX4A_DRAFT10_SOURCE is needed to pick up localtime_r, used in +# prtime.c +# +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_POSIX4A_DRAFT10_SOURCE -DOSF1 -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl + +NOSUCHFILE = /no-such-file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS4.1.4.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS4.1.4.mk new file mode 100644 index 0000000..62f4815 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS4.1.4.mk @@ -0,0 +1,101 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS4.1 +# + +CC = gcc +CCC = g++ +RANLIB = ranlib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = sparc +GFX_ARCH = x + +# A pile of -D's to build xfe on sunos +MOZ_CFLAGS = -DSTRINGS_ALIGNED -DNO_REGEX -DNO_ISDIR -DUSE_RE_COMP \ + -DNO_REGCOMP -DUSE_GETWD -DNO_MEMMOVE -DNO_ALLOCA \ + -DBOGUS_MB_MAX -DNO_CONST + +# Purify doesn't like -MDupdate +NOMD_OS_CFLAGS = -DXP_UNIX -Wall -Wno-format -DSW_THREADS -DSUNOS4 -DNEED_SYSCALL \ + $(MOZ_CFLAGS) + +OS_CFLAGS = $(NOMD_OS_CFLAGS) -MDupdate $(DEPENDENCIES) +OS_LIBS = -ldl -lm + +MKSHLIB = $(LD) -L$(MOTIF)/lib + +HAVE_PURIFY = 1 +MOTIF = /home/motif/usr +MOTIFLIB = -L$(MOTIF)/lib -lXm +INCLUDES += -I/usr/X11R5/include -I$(MOTIF)/include + +NOSUCHFILE = /solaris-rm-f-sucks + +LOCALE_MAP = $(DEPTH)/cmd/xfe/intl/sunos.lm + +EN_LOCALE = en_US +DE_LOCALE = de +FR_LOCALE = fr +JP_LOCALE = ja +SJIS_LOCALE = ja_JP.SJIS +KR_LOCALE = ko +CN_LOCALE = zh +TW_LOCALE = zh_TW +I2_LOCALE = i2 +IT_LOCALE = it +SV_LOCALE = sv +ES_LOCALE = es +NL_LOCALE = nl +PT_LOCALE = pt + +LOC_LIB_DIR = /usr/openwin/lib/locale + +BSDECHO = echo + +# +# These defines are for building unix plugins +# +BUILD_UNIX_PLUGINS = 1 +DSO_LDOPTS = +DSO_LDFLAGS = diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.10.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.10.mk new file mode 100644 index 0000000..dc0b0a0 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.10.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.10, using vendor gcc and NSPR +# + +include $(DEPTH)/config/SunOS5.5.mk + +INCLUDES += -I/usr/sfw/include/mozilla/nspr +OTHER_LIBS += -L/usr/sfw/lib/mozilla -R/usr/sfw/lib/mozilla + +CC=gcc + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.3.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.3.mk new file mode 100644 index 0000000..bd615de --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.3.mk @@ -0,0 +1,91 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.3 +# + +CC = gcc +CCC = g++ +CFLAGS += -Wall -Wno-format + +#CC = /opt/SUNWspro/SC3.0.1/bin/cc +RANLIB = echo + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = sparc +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -DSOLARIS -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl -ldl + +ASFLAGS += -P -L -K PIC -D_ASM -D__STDC__=0 + +HAVE_PURIFY = 1 + +NOSUCHFILE = /solaris-rm-f-sucks + +ifndef JS_NO_ULTRA +ULTRA_OPTIONS := -xarch=v8plus +ULTRA_OPTIONSD := -DULTRA_SPARC +else +ULTRA_OPTIONS := -xarch=v8 +ULTRA_OPTIONSD := +endif + +ifeq ($(OS_CPUARCH),sun4u) +DEFINES += $(ULTRA_OPTIONSD) +ifeq ($(findstring gcc,$(CC)),gcc) +DEFINES += -Wa,$(ULTRA_OPTIONS),$(ULTRA_OPTIONSD) +else +ASFLAGS += $(ULTRA_OPTIONS) $(ULTRA_OPTIONSD) +endif +endif + +ifeq ($(OS_CPUARCH),sun4m) +ifeq ($(findstring gcc,$(CC)),gcc) +DEFINES += -Wa,-xarch=v8 +else +ASFLAGS += -xarch=v8 +endif +endif + +MKSHLIB = $(LD) -G diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.4.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.4.mk new file mode 100644 index 0000000..de01924 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.4.mk @@ -0,0 +1,92 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.4 +# + +ifdef NS_USE_NATIVE +CC = cc +CCC = CC +else +CC = gcc +CCC = g++ +CFLAGS += -Wall -Wno-format +endif + +RANLIB = echo + +CPU_ARCH = sparc +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D__svr4 -DSOLARIS -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl -ldl + +ASFLAGS += -P -L -K PIC -D_ASM -D__STDC__=0 + +HAVE_PURIFY = 1 + +NOSUCHFILE = /solaris-rm-f-sucks + +ifndef JS_NO_ULTRA +ULTRA_OPTIONS := -xarch=v8plus +ULTRA_OPTIONSD := -DULTRA_SPARC +else +ULTRA_OPTIONS := -xarch=v8 +ULTRA_OPTIONSD := +endif + +ifeq ($(OS_CPUARCH),sun4u) +DEFINES += $(ULTRA_OPTIONSD) +ifeq ($(findstring gcc,$(CC)),gcc) +DEFINES += -Wa,$(ULTRA_OPTIONS),$(ULTRA_OPTIONSD) +else +ASFLAGS += $(ULTRA_OPTIONS) $(ULTRA_OPTIONSD) +endif +endif + +ifeq ($(OS_CPUARCH),sun4m) +ifeq ($(findstring gcc,$(CC)),gcc) +DEFINES += -Wa,-xarch=v8 +else +ASFLAGS += -xarch=v8 +endif +endif + +MKSHLIB = $(LD) -G diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.5.1.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.5.1.mk new file mode 100644 index 0000000..648f72f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.5.1.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.5.1 +# + +include $(DEPTH)/config/SunOS5.5.mk diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.5.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.5.mk new file mode 100644 index 0000000..e26b3a3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.5.mk @@ -0,0 +1,87 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.5 +# + +AS = /usr/ccs/bin/as +ifndef NS_USE_NATIVE +CC = gcc +CCC = g++ +CFLAGS += -Wall -Wno-format +else +CC = cc +CCC = CC +endif + +RANLIB = echo + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = sparc +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -DSOLARIS -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl -ldl + +ASFLAGS += -P -L -K PIC -D_ASM -D__STDC__=0 + +HAVE_PURIFY = 1 + +NOSUCHFILE = /solaris-rm-f-sucks + +ifeq ($(OS_CPUARCH),sun4u) # ultra sparc? +ifeq ($(CC),gcc) # using gcc? +ifndef JS_NO_ULTRA # do we want ultra? +ifdef JS_THREADSAFE # only in thread-safe mode +DEFINES += -DULTRA_SPARC +DEFINES += -Wa,-xarch=v8plus,-DULTRA_SPARC +else +ASFLAGS += -xarch=v8plus -DULTRA_SPARC +endif +endif +endif +endif + +MKSHLIB = $(LD) -G + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.6.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.6.mk new file mode 100644 index 0000000..efe1152 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.6.mk @@ -0,0 +1,89 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.5 +# + +AS = /usr/ccs/bin/as +ifndef NS_USE_NATIVE + CC = gcc + CCC = g++ + CFLAGS += -Wall -Wno-format +else + CC = cc + CCC = CC + CFLAGS += -mt -KPIC +# LD = CC +endif + +RANLIB = echo + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = sparc +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -DSOLARIS -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl -ldl + +ASFLAGS += -P -L -K PIC -D_ASM -D__STDC__=0 + +HAVE_PURIFY = 1 + +NOSUCHFILE = /solaris-rm-f-sucks + +ifeq ($(OS_CPUARCH),sun4u) # ultra sparc? +ifeq ($(CC),gcc) # using gcc? +ifndef JS_NO_ULTRA # do we want ultra? +ifdef JS_THREADSAFE # only in thread-safe mode +DEFINES += -DULTRA_SPARC +DEFINES += -Wa,-xarch=v8plus,-DULTRA_SPARC +else +ASFLAGS += -xarch=v8plus -DULTRA_SPARC +endif +endif +endif +endif + +MKSHLIB = $(LD) -G + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.7.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.7.mk new file mode 100644 index 0000000..2cb02f2 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.7.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.7 +# + +include $(DEPTH)/config/SunOS5.5.mk diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.8.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.8.mk new file mode 100644 index 0000000..dd8a32d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.8.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.8 +# + +include $(DEPTH)/config/SunOS5.5.mk diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.9.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.9.mk new file mode 100644 index 0000000..b01ec9c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/SunOS5.9.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.9 +# + +include $(DEPTH)/config/SunOS5.5.mk diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT4.0.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT4.0.mk new file mode 100644 index 0000000..1d36f91 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT4.0.mk @@ -0,0 +1,118 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Windows NT using MS Visual C++ (version?) +# + +CC = cl +CXX = cl + +RANLIB = echo + +PDBFILE = $(basename $(@F)).pdb + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86 # XXX fixme +GFX_ARCH = win32 + +# MSVC compiler options for both debug/optimize +# -nologo - suppress copyright message +# -W3 - Warning level 3 +# -Gm - enable minimal rebuild +# -Z7 - put debug info into the executable, not in .pdb file +# -Zi - put debug info into .pdb file +# -YX - automatic precompiled headers +# -GX - enable C++ exception support +WIN_CFLAGS = -nologo -W3 + +# MSVC compiler options for debug builds linked to MSVCRTD.DLL +# -MDd - link with MSVCRTD.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_IDG_CFLAGS = -MDd -Od -Z7 + +# MSVC compiler options for debug builds linked to MSVCRT.DLL +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_DEBUG_CFLAGS = -MD -Od -Zi -Fd$(OBJDIR)/$(PDBFILE) + +# MSVC compiler options for release (optimized) builds +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, C-runtime) +# -O2 - Optimize for speed +# -G5 - Optimize for Pentium +WIN_OPT_CFLAGS = -MD -O2 + +ifdef BUILD_OPT +OPTIMIZER = $(WIN_OPT_CFLAGS) +else +ifdef BUILD_IDG +OPTIMIZER = $(WIN_IDG_CFLAGS) +else +OPTIMIZER = $(WIN_DEBUG_CFLAGS) +endif +endif + +OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 $(WIN_CFLAGS) +JSDLL_CFLAGS = -DEXPORT_JS_API +OS_LIBS = -lm -lc + +PREBUILT_CPUCFG = 1 +USE_MSVC = 1 + +LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \ + winmm.lib \ + -nologo\ + -subsystem:windows -dll -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +EXE_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib -nologo\ + -subsystem:console -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +# CAFEDIR = t:/cafe +# JCLASSPATH = $(CAFEDIR)/Java/Lib/classes.zip +# JAVAC = $(CAFEDIR)/Bin/sj.exe +# JAVAH = $(CAFEDIR)/Java/Bin/javah.exe +# JCFLAGS = -I$(CAFEDIR)/Java/Include -I$(CAFEDIR)/Java/Include/win32 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.0.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.0.mk new file mode 100644 index 0000000..7681e01 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.0.mk @@ -0,0 +1,118 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Windows NT using MS Visual C++ (version?) +# + +CC = cl +CXX = cl + +RANLIB = echo + +PDBFILE = $(basename $(@F)).pdb + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86 # XXX fixme +GFX_ARCH = win32 + +# MSVC compiler options for both debug/optimize +# -nologo - suppress copyright message +# -W3 - Warning level 3 +# -Gm - enable minimal rebuild +# -Z7 - put debug info into the executable, not in .pdb file +# -Zi - put debug info into .pdb file +# -YX - automatic precompiled headers +# -GX - enable C++ exception support +WIN_CFLAGS = -nologo -W3 + +# MSVC compiler options for debug builds linked to MSVCRTD.DLL +# -MDd - link with MSVCRTD.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_IDG_CFLAGS = -MDd -Od -Z7 + +# MSVC compiler options for debug builds linked to MSVCRT.DLL +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_DEBUG_CFLAGS = -MD -Od -Zi -Fd$(OBJDIR)/$(PDBFILE) + +# MSVC compiler options for release (optimized) builds +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, C-runtime) +# -O2 - Optimize for speed +# -G5 - Optimize for Pentium +WIN_OPT_CFLAGS = -MD -O2 + +ifdef BUILD_OPT +OPTIMIZER = $(WIN_OPT_CFLAGS) +else +ifdef BUILD_IDG +OPTIMIZER = $(WIN_IDG_CFLAGS) +else +OPTIMIZER = $(WIN_DEBUG_CFLAGS) +endif +endif + +OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500 $(WIN_CFLAGS) +JSDLL_CFLAGS = -DEXPORT_JS_API +OS_LIBS = -lm -lc + +PREBUILT_CPUCFG = 1 +USE_MSVC = 1 + +LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \ + winmm.lib \ + -nologo\ + -subsystem:windows -dll -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +EXE_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib -nologo\ + -subsystem:console -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +# CAFEDIR = t:/cafe +# JCLASSPATH = $(CAFEDIR)/Java/Lib/classes.zip +# JAVAC = $(CAFEDIR)/Bin/sj.exe +# JAVAH = $(CAFEDIR)/Java/Bin/javah.exe +# JCFLAGS = -I$(CAFEDIR)/Java/Include -I$(CAFEDIR)/Java/Include/win32 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.1.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.1.mk new file mode 100644 index 0000000..7681e01 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.1.mk @@ -0,0 +1,118 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Windows NT using MS Visual C++ (version?) +# + +CC = cl +CXX = cl + +RANLIB = echo + +PDBFILE = $(basename $(@F)).pdb + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86 # XXX fixme +GFX_ARCH = win32 + +# MSVC compiler options for both debug/optimize +# -nologo - suppress copyright message +# -W3 - Warning level 3 +# -Gm - enable minimal rebuild +# -Z7 - put debug info into the executable, not in .pdb file +# -Zi - put debug info into .pdb file +# -YX - automatic precompiled headers +# -GX - enable C++ exception support +WIN_CFLAGS = -nologo -W3 + +# MSVC compiler options for debug builds linked to MSVCRTD.DLL +# -MDd - link with MSVCRTD.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_IDG_CFLAGS = -MDd -Od -Z7 + +# MSVC compiler options for debug builds linked to MSVCRT.DLL +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_DEBUG_CFLAGS = -MD -Od -Zi -Fd$(OBJDIR)/$(PDBFILE) + +# MSVC compiler options for release (optimized) builds +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, C-runtime) +# -O2 - Optimize for speed +# -G5 - Optimize for Pentium +WIN_OPT_CFLAGS = -MD -O2 + +ifdef BUILD_OPT +OPTIMIZER = $(WIN_OPT_CFLAGS) +else +ifdef BUILD_IDG +OPTIMIZER = $(WIN_IDG_CFLAGS) +else +OPTIMIZER = $(WIN_DEBUG_CFLAGS) +endif +endif + +OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500 $(WIN_CFLAGS) +JSDLL_CFLAGS = -DEXPORT_JS_API +OS_LIBS = -lm -lc + +PREBUILT_CPUCFG = 1 +USE_MSVC = 1 + +LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \ + winmm.lib \ + -nologo\ + -subsystem:windows -dll -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +EXE_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib -nologo\ + -subsystem:console -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +# CAFEDIR = t:/cafe +# JCLASSPATH = $(CAFEDIR)/Java/Lib/classes.zip +# JAVAC = $(CAFEDIR)/Bin/sj.exe +# JAVAH = $(CAFEDIR)/Java/Bin/javah.exe +# JCFLAGS = -I$(CAFEDIR)/Java/Include -I$(CAFEDIR)/Java/Include/win32 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.2.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.2.mk new file mode 100644 index 0000000..5fbcbfe --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT5.2.mk @@ -0,0 +1,118 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Windows NT using MS Visual C++ (version?) +# + +CC = cl +CXX = cl + +RANLIB = echo + +PDBFILE = $(basename $(@F)).pdb + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86 # XXX fixme +GFX_ARCH = win32 + +# MSVC compiler options for both debug/optimize +# -nologo - suppress copyright message +# -W3 - Warning level 3 +# -Gm - enable minimal rebuild +# -Z7 - put debug info into the executable, not in .pdb file +# -Zi - put debug info into .pdb file +# -YX - automatic precompiled headers +# -GX - enable C++ exception support +WIN_CFLAGS = -nologo -W3 + +# MSVC compiler options for debug builds linked to MSVCRTD.DLL +# -MDd - link with MSVCRTD.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_IDG_CFLAGS = -MDd -Od -Z7 + +# MSVC compiler options for debug builds linked to MSVCRT.DLL +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_DEBUG_CFLAGS = -MD -Od -Zi -Fd$(OBJDIR)/$(PDBFILE) + +# MSVC compiler options for release (optimized) builds +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, C-runtime) +# -O2 - Optimize for speed +# -G5 - Optimize for Pentium +WIN_OPT_CFLAGS = -MD -O2 + +ifdef BUILD_OPT +OPTIMIZER = $(WIN_OPT_CFLAGS) +else +ifdef BUILD_IDG +OPTIMIZER = $(WIN_IDG_CFLAGS) +else +OPTIMIZER = $(WIN_DEBUG_CFLAGS) +endif +endif + +OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500 $(WIN_CFLAGS) -DAVMPLUS_WIN32 -DAVMPLUS_IA32 +JSDLL_CFLAGS = -DEXPORT_JS_API +OS_LIBS = -lm -lc + +PREBUILT_CPUCFG = 1 +USE_MSVC = 1 + +LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \ + winmm.lib \ + -nologo\ + -subsystem:windows -dll -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +EXE_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib -nologo\ + -subsystem:console -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +# CAFEDIR = t:/cafe +# JCLASSPATH = $(CAFEDIR)/Java/Lib/classes.zip +# JAVAC = $(CAFEDIR)/Bin/sj.exe +# JAVAH = $(CAFEDIR)/Java/Bin/javah.exe +# JCFLAGS = -I$(CAFEDIR)/Java/Include -I$(CAFEDIR)/Java/Include/win32 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT6.0.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT6.0.mk new file mode 100644 index 0000000..7681e01 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/WINNT6.0.mk @@ -0,0 +1,118 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Windows NT using MS Visual C++ (version?) +# + +CC = cl +CXX = cl + +RANLIB = echo + +PDBFILE = $(basename $(@F)).pdb + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86 # XXX fixme +GFX_ARCH = win32 + +# MSVC compiler options for both debug/optimize +# -nologo - suppress copyright message +# -W3 - Warning level 3 +# -Gm - enable minimal rebuild +# -Z7 - put debug info into the executable, not in .pdb file +# -Zi - put debug info into .pdb file +# -YX - automatic precompiled headers +# -GX - enable C++ exception support +WIN_CFLAGS = -nologo -W3 + +# MSVC compiler options for debug builds linked to MSVCRTD.DLL +# -MDd - link with MSVCRTD.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_IDG_CFLAGS = -MDd -Od -Z7 + +# MSVC compiler options for debug builds linked to MSVCRT.DLL +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_DEBUG_CFLAGS = -MD -Od -Zi -Fd$(OBJDIR)/$(PDBFILE) + +# MSVC compiler options for release (optimized) builds +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, C-runtime) +# -O2 - Optimize for speed +# -G5 - Optimize for Pentium +WIN_OPT_CFLAGS = -MD -O2 + +ifdef BUILD_OPT +OPTIMIZER = $(WIN_OPT_CFLAGS) +else +ifdef BUILD_IDG +OPTIMIZER = $(WIN_IDG_CFLAGS) +else +OPTIMIZER = $(WIN_DEBUG_CFLAGS) +endif +endif + +OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500 $(WIN_CFLAGS) +JSDLL_CFLAGS = -DEXPORT_JS_API +OS_LIBS = -lm -lc + +PREBUILT_CPUCFG = 1 +USE_MSVC = 1 + +LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \ + winmm.lib \ + -nologo\ + -subsystem:windows -dll -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +EXE_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib -nologo\ + -subsystem:console -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +# CAFEDIR = t:/cafe +# JCLASSPATH = $(CAFEDIR)/Java/Lib/classes.zip +# JAVAC = $(CAFEDIR)/Bin/sj.exe +# JAVAH = $(CAFEDIR)/Java/Bin/javah.exe +# JCFLAGS = -I$(CAFEDIR)/Java/Include -I$(CAFEDIR)/Java/Include/win32 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/dgux.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/dgux.mk new file mode 100644 index 0000000..3b5967e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/ref-config/dgux.mk @@ -0,0 +1,64 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for Data General DG/UX +# + +# +# Initial DG/UX port by Marc Fraioli (fraioli@dg-rtp.dg.com) +# + +AS = as +CC = gcc +CCC = g++ + +RANLIB = echo + +# +# _DGUX_SOURCE is needed to turn on a lot of stuff in the headers if +# you're not using DG's compiler. It shouldn't hurt if you are. +# +# _POSIX4A_DRAFT10_SOURCE is needed to pick up localtime_r, used in +# prtime.c +# +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -DDGUX -D_DGUX_SOURCE -D_POSIX4A_DRAFT10_SOURCE -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl + +NOSUCHFILE = /no-such-file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/resource.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/resource.h new file mode 100644 index 0000000..9301810 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by js3240.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/rules.mk b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/rules.mk new file mode 100644 index 0000000..5a1e053 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/rules.mk @@ -0,0 +1,206 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Michael Ang +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# JSRef GNUmake makefile rules +# + +ifdef USE_MSVC +LIB_OBJS = $(addprefix $(OBJDIR)/, $(LIB_CPPFILES:.cpp=.obj)) +PROG_OBJS = $(addprefix $(OBJDIR)/, $(PROG_CPPFILES:.cpp=.obj)) +else +LIB_OBJS = $(addprefix $(OBJDIR)/, $(LIB_CPPFILES:.cpp=.o)) +LIB_OBJS += $(addprefix $(OBJDIR)/, $(LIB_ASFILES:.s=.o)) +PROG_OBJS = $(addprefix $(OBJDIR)/, $(PROG_CPPFILES:.cpp=.o)) +endif + +CPPFILES = $(LIB_CPPFILES) $(PROG_CPPFILES) +OBJS = $(LIB_OBJS) $(PROG_OBJS) + +ifdef USE_MSVC +# TARGETS = $(LIBRARY) # $(PROGRAM) not supported for MSVC yet +TARGETS += $(SHARED_LIBRARY) $(PROGRAM) # it is now +else +TARGETS += $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) +endif + +all: + +$(LOOP_OVER_PREDIRS) +ifneq "$(strip $(TARGETS))" "" + $(MAKE) -f Makefile.ref $(TARGETS) +endif + +$(LOOP_OVER_DIRS) + +$(OBJDIR)/%: %.cpp + @$(MAKE_OBJDIR) + $(CXX) -o $@ $(CFLAGS) $(OPTIMIZER) $< $(LDFLAGS) + +# This rule must come before the rule with no dep on header +$(OBJDIR)/%.o: %.cpp %.h + @$(MAKE_OBJDIR) + $(CXX) -o $@ -c $(CFLAGS) $(OPTIMIZER) $< + +$(OBJDIR)/jsinterp.o: jsinterp.cpp jsinterp.h + @$(MAKE_OBJDIR) + $(CXX) -o $@ -c $(CFLAGS) $(INTERP_OPTIMIZER) jsinterp.cpp + +$(OBJDIR)/jsbuiltins.o: jsbuiltins.cpp jsinterp.h + @$(MAKE_OBJDIR) + $(CXX) -o $@ -c $(CFLAGS) $(BUILTINS_OPTIMIZER) jsbuiltins.cpp + +$(OBJDIR)/%.o: %.cpp + @$(MAKE_OBJDIR) + $(CXX) -o $@ -c $(CFLAGS) $(OPTIMIZER) $< + +$(OBJDIR)/%.o: %.s + @$(MAKE_OBJDIR) + $(AS) -o $@ $(ASFLAGS) $< + +# This rule must come before rule with no dep on header +$(OBJDIR)/%.obj: %.cpp %.h + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(JSDLL_CFLAGS) $(OPTIMIZER) $< + +$(OBJDIR)/jsinterp.obj: jsinterp.cpp jsinterp.h + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(JSDLL_CFLAGS) $(INTERP_OPTIMIZER) jsinterp.cpp + +$(OBJDIR)/jsbuiltins.obj: jsbuiltins.cpp jsinterp.h + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(JSDLL_CFLAGS) $(BUILTINS_OPTIMIZER) jsbuiltins.cpp + +$(OBJDIR)/%.obj: %.cpp + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(JSDLL_CFLAGS) $(OPTIMIZER) $< + +$(OBJDIR)/js.obj: js.cpp + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(OPTIMIZER) $< + +ifeq ($(OS_ARCH),OS2) +$(LIBRARY): $(LIB_OBJS) + $(AR) $@ $? $(AR_OS2_SUFFIX) + $(RANLIB) $@ +else +ifdef USE_MSVC +$(SHARED_LIBRARY): $(LIB_OBJS) + link.exe $(LIB_LINK_FLAGS) /base:0x61000000 $(OTHER_LIBS) \ + /out:"$@" /pdb:none\ + /implib:"$(OBJDIR)/$(@F:.dll=.lib)" $^ +else +$(LIBRARY): $(LIB_OBJS) + $(AR) rv $@ $? + $(RANLIB) $@ + +$(SHARED_LIBRARY): $(LIB_OBJS) + $(MKSHLIB) -o $@ $(LIB_OBJS) $(LDFLAGS) $(OTHER_LIBS) +endif +endif + +# Java stuff +$(CLASSDIR)/$(OBJDIR)/$(JARPATH)/%.class: %.java + mkdir -p $(@D) + $(JAVAC) $(JAVAC_FLAGS) $< + +define MAKE_OBJDIR +if test ! -d $(@D); then rm -rf $(@D); mkdir -p $(@D); fi +endef + +ifdef DIRS +LOOP_OVER_DIRS = \ + @for d in $(DIRS); do \ + if test -d $$d; then \ + set -e; \ + echo "cd $$d; $(MAKE) -f Makefile.ref $@"; \ + cd $$d; $(MAKE) -f Makefile.ref $@; cd ..; \ + set +e; \ + else \ + echo "Skipping non-directory $$d..."; \ + fi; \ + done +endif + +ifdef PREDIRS +LOOP_OVER_PREDIRS = \ + @for d in $(PREDIRS); do \ + if test -d $$d; then \ + set -e; \ + echo "cd $$d; $(MAKE) -f Makefile.ref $@"; \ + cd $$d; $(MAKE) -f Makefile.ref $@; cd ..; \ + set +e; \ + else \ + echo "Skipping non-directory $$d..."; \ + fi; \ + done +endif + +export: + +$(LOOP_OVER_PREDIRS) + mkdir -p $(DIST)/include $(DIST)/$(LIBDIR) $(DIST)/bin +ifneq "$(strip $(HFILES))" "" + $(CP) $(HFILES) $(DIST)/include +endif +ifneq "$(strip $(LIBRARY))" "" + $(CP) $(LIBRARY) $(DIST)/$(LIBDIR) +endif +ifneq "$(strip $(JARS))" "" + $(CP) $(JARS) $(DIST)/$(LIBDIR) +endif +ifneq "$(strip $(SHARED_LIBRARY))" "" + $(CP) $(SHARED_LIBRARY) $(DIST)/$(LIBDIR) +endif +ifneq "$(strip $(PROGRAM))" "" + $(CP) $(PROGRAM) $(DIST)/bin +endif + +$(LOOP_OVER_DIRS) + +clean: + +$(LOOP_OVER_PREDIRS) + rm -rf $(OBJS) $(GARBAGE) + +clobber: + +$(LOOP_OVER_PREDIRS) + rm -rf $(OBJS) $(TARGETS) $(DEPENDENCIES) $(GARBAGE) + if test -d $(OBJDIR); then rmdir $(OBJDIR); fi + +tar: + tar cvf $(TARNAME) $(TARFILES) + gzip $(TARNAME) + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/time.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/time.sh new file mode 100755 index 0000000..05b3499 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/time.sh @@ -0,0 +1,13 @@ +#!/bin/bash +echo -n interp:' ' +for i in 1 2 3 4 5; do + INTERP=`Darwin_OPT.OBJ/js -e 'var d = Date.now(); load("'$1'"); print(Date.now() - d);'` + echo -n $INTERP' ' +done +echo -ne '\njit: ' +for i in 1 2 3 4 5; do + JIT=`Darwin_OPT.OBJ/js -j -e 'var d = Date.now(); load("'$1'"); print(Date.now() - d);'` + echo -n $JIT' ' +done +echo -ne '\njit factor: ' +(echo scale=2; echo $INTERP / $JIT ) | bc diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/win32.order b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/win32.order new file mode 100644 index 0000000..069403d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/js/win32.order @@ -0,0 +1,384 @@ +js_MarkGCThing ; 5893956 +JS_GetPrivate ; 2090130 +JS_HashTableRawLookup ; 1709984 +js_Mark ; 1547496 +js_GetToken ; 1406677 +js_UngetToken ; 1154416 +js_MarkAtom ; 992874 +js_MatchToken ; 980277 +js_CompareStrings ; 662772 +js_Lock ; 628184 +js_Unlock ; 628184 +js_HashString ; 611102 +js_DropScopeProperty ; 546476 +JS_malloc ; 484350 +js_InflateStringToBuffer ; 460739 +js_HoldScopeProperty ; 442612 +JS_free ; 382991 +js_MarkScript ; 376942 +js_HashId ; 365238 +JS_CompareValues ; 352366 +js_IdToValue ; 337594 +JS_GetClass ; 325296 +js_LookupProperty ; 324680 +js_GetAtom ; 244669 +js_DropProperty ; 223217 +JS_GetParent ; 209680 +js_LiveContext ; 205767 +js_PeekToken ; 200646 +js_GetSlotThreadSafe ; 198839 +JS_GetStringChars ; 190862 +JS_HashTableRawAdd ; 179156 +js_FoldConstants ; 162626 +js_EmitTree ; 145634 +JS_EnumerateStub ; 140640 +js_NewSrcNote ; 136983 +js_GetProperty ; 135639 +js_NewScopeProperty ; 135057 +js_MutateScope ; 135057 +js_GetMutableScope ; 135057 +js_AllocSlot ; 132401 +JS_GetRuntime ; 127316 +JS_FrameIterator ; 121963 +JS_GetFrameFunctionObject ; 120567 +js_AllocGCThing ; 119828 +js_DestroyScopeProperty ; 115989 +js_Emit3 ; 109135 +JS_HashTableLookup ; 107154 +JS_InstanceOf ; 103905 +js_DefineProperty ; 99514 +js_strncpy ; 88276 +js_PeekTokenSameLine ; 87197 +js_HoldObjectMap ; 79084 +js_DropObjectMap ; 77824 +js_NewObject ; 72421 +js_ValueToString ; 72143 +js_GetClassPrototype ; 66235 +js_UnlockRuntime ; 64699 +js_LockRuntime ; 64699 +js_ContextIterator ; 64586 +JS_ClearWatchPointsForObject ; 64155 +js_FinalizeObject ; 63925 +js_IndexAtom ; 63789 +JS_SetPrivate ; 63702 +JS_GetGlobalObject ; 63546 +js_Emit1 ; 63012 +JS_ContextIterator ; 57847 +JS_GetInstancePrivate ; 57817 +JS_HashTableRawRemove ; 57057 +js_Invoke ; 53568 +js_FindProperty ; 53150 +JS_GetFrameScript ; 51395 +js_LinkFunctionObject ; 50651 +js_SetSrcNoteOffset ; 47735 +js_InWithStatement ; 47346 +js_NewFunction ; 47074 +js_NewSrcNote2 ; 46165 +JS_HashTableAdd ; 45503 +JS_HashTableRemove ; 45213 +js_InCatchBlock ; 42198 +js_AddRootRT ; 40587 +js_AddRoot ; 40587 +js_SetProperty ; 40558 +JS_AddNamedRoot ; 40462 +js_RemoveRoot ; 40384 +JS_RemoveRootRT ; 38129 +js_NewString ; 37471 +js_DefineFunction ; 36629 +JS_GetContextThread ; 36498 +JS_LookupProperty ; 35137 +JS_ValueToString ; 34072 +JS_realloc ; 33776 +JS_DefineFunction ; 33268 +JS_SetErrorReporter ; 32851 +js_FinalizeString ; 30311 +js_FinalizeStringRT ; 30311 +JS_ArenaAllocate ; 30099 +JS_BeginRequest ; 29323 +JS_EndRequest ; 29323 +JS_GetContextPrivate ; 29189 +JS_CompactArenaPool ; 28874 +js_ValueToStringAtom ; 27934 +JS_ValueToId ; 26517 +js_ValueToBoolean ; 25908 +JS_InternString ; 25467 +js_PopStatement ; 24364 +js_PushStatement ; 24364 +js_NewStringCopyN ; 23911 +js_FlushPropertyCacheByProp ; 23883 +js_GetStringBytes ; 23421 +JS_ArenaRelease ; 23267 +JS_GetStringBytes ; 23106 +js_FreeStack ; 22399 +js_AllocStack ; 22399 +JS_SetProperty ; 21240 +js_InitObjectMap ; 19991 +js_NewScope ; 19991 +js_strlen ; 19070 +JS_GetScriptPrincipals ; 18063 +js_SrcNoteLength ; 17369 +js_DestroyObjectMap ; 17198 +js_DestroyScope ; 17198 +JS_GetStringLength ; 16306 +js_PopStatementCG ; 15418 +JS_GetFrameAnnotation ; 14949 +js_Interpret ; 14032 +js_TransferScopeLock ; 13899 +JS_ResolveStandardClass ; 13645 +JS_ResumeRequest ; 12837 +JS_SuspendRequest ; 12837 +JS_GetProperty ; 12488 +JS_NewObject ; 11660 +js_AllocTryNotes ; 11418 +js_NewNumberValue ; 10859 +js_InternalInvoke ; 10051 +js_NewDouble ; 9936 +js_SetJumpOffset ; 9886 +js_SkipWhiteSpace ; 9299 +js_NewDoubleValue ; 7474 +JS_GetPendingException ; 7404 +js_NewObjectMap ; 7236 +JS_ClearPendingException ; 7092 +JS_strtod ; 7053 +js_strtod ; 7053 +js_InflateString ; 7004 +JS_GetFunctionName ; 6808 +JS_NewHashTable ; 6794 +JS_NewFunction ; 6575 +js_FreeSlot ; 6476 +js_LockScope ; 6332 +JS_HashTableEnumerateEntries ; 6285 +js_GetLengthProperty ; 6162 +js_LockObj ; 6149 +JS_NewUCStringCopyN ; 5994 +JS_NewNumberValue ; 5904 +js_NewStringCopyZ ; 5809 +JS_NewUCStringCopyZ ; 5809 +js_DeflateString ; 5612 +js_ValueToNumber ; 5456 +JS_SetOptions ; 5322 +js_NewScript ; 4941 +js_InitCodeGenerator ; 4810 +js_FinishTakingSrcNotes ; 4810 +js_NewScriptFromParams ; 4810 +js_FinishTakingTryNotes ; 4810 +js_NewScriptFromCG ; 4810 +js_FinishCodeGenerator ; 4810 +JS_strdup ; 4534 +JS_HashTableDestroy ; 4119 +js_CheckRedeclaration ; 3965 +JS_DefineFunctions ; 3808 +js_EmitFunctionBody ; 3739 +js_TryMethod ; 3685 +js_DefaultValue ; 3610 +js_CloneFunctionObject ; 3577 +JS_InitClass ; 3546 +js_SetClassPrototype ; 3377 +JS_GetPrototype ; 3268 +JS_DefineProperties ; 3115 +js_FindVariable ; 3093 +js_DestroyScript ; 3041 +JS_ClearScriptTraps ; 3041 +js_FreeAtomMap ; 3041 +JS_NewStringCopyZ ; 2953 +js_AtomizeObject ; 2709 +JS_ValueToBoolean ; 2643 +js_SetLengthProperty ; 2637 +JS_GetOptions ; 2593 +js_ValueToObject ; 2522 +js_ValueToNonNullObject ; 2510 +js_StringToObject ; 2482 +JS_SetElement ; 2448 +js_NumberToString ; 2407 +JS_TypeOfValue ; 2275 +js_NewBufferTokenStream ; 2253 +js_NewTokenStream ; 2253 +js_CloseTokenStream ; 2253 +JS_RemoveRoot ; 2148 +JS_NewDouble ; 2129 +JS_vsnprintf ; 1937 +JS_snprintf ; 1937 +JS_CallFunctionValue ; 1844 +JS_DHashVoidPtrKeyStub ; 1840 +JS_DHashTableOperate ; 1840 +js_SetProtoOrParent ; 1758 +js_DoubleToInteger ; 1729 +JS_SetVersion ; 1531 +js_ValueToFunction ; 1476 +JS_SetPrototype ; 1408 +JS_CeilingLog2 ; 1317 +js_Execute ; 1199 +js_CompileFunctionBody ; 1182 +JS_CompileUCFunctionForPrincipals ; 1182 +js_GetSrcNoteOffset ; 1139 +JS_DHashMatchEntryStub ; 1094 +JS_VersionToString ; 1090 +JS_CompileUCScriptForPrincipals ; 1071 +js_CompileTokenStream ; 1071 +js_CurrentThreadId ; 1058 +JS_IdToValue ; 1046 +js_ConstructObject ; 974 +JS_DestroyScript ; 967 +js_PCToLineNumber ; 967 +JS_DefineProperty ; 930 +JS_GetScriptFilename ; 924 +JS_GetFramePC ; 899 +JS_EvaluateUCScriptForPrincipals ; 892 +JS_PCToLineNumber ; 848 +JS_StringToVersion ; 761 +js_ExecuteRegExp ; 755 +JS_MaybeGC ; 717 +JS_ValueToNumber ; 698 +JS_GetVersion ; 698 +JS_AliasProperty ; 693 +js_AtomizeValue ; 664 +js_BooleanToString ; 664 +js_SetSlotThreadSafe ; 596 +JS_DHashClearEntryStub ; 584 +JS_DHashTableRawRemove ; 584 +JS_DefineObject ; 557 +js_PutCallObject ; 516 +js_GetCallObject ; 516 +js_strchr ; 511 +JS_DefineUCProperty ; 480 +JS_dtostr ; 475 +JS_ValueToInt32 ; 464 +js_ValueToInt32 ; 464 +JS_FinishArenaPool ; 453 +js_NewTryNote ; 441 +js_strtointeger ; 437 +JS_vsmprintf ; 428 +JS_DHashTableInit ; 423 +JS_DHashAllocTable ; 423 +JS_DHashGetStubOps ; 423 +JS_NewDHashTable ; 423 +JS_DHashTableDestroy ; 423 +JS_DHashFreeTable ; 423 +JS_DHashTableFinish ; 423 +js_EmitBreak ; 412 +js_GetAttributes ; 412 +JS_DefineConstDoubles ; 407 +JS_ArenaGrow ; 374 +js_AtomizeInt ; 372 +JS_SetParent ; 345 +JS_CloneFunctionObject ; 343 +JS_IsNativeFrame ; 343 +JS_ReportErrorNumber ; 340 +js_ErrorToException ; 340 +js_ReportErrorNumberVA ; 340 +js_GetErrorMessage ; 340 +js_ExpandErrorArguments ; 340 +js_ReportUncaughtException ; 315 +JS_IsExceptionPending ; 315 +js_ReportErrorAgain ; 315 +js_ErrorFromException ; 315 +JS_LookupUCProperty ; 307 +JS_InitArenaPool ; 293 +PRMJ_Now ; 262 +DllMain@12 ; 235 +JS_ExecuteScript ; 232 +JS_GetFrameFunction ; 226 +PRMJ_LocalGMTDifference ; 175 +JS_GetConstructor ; 175 +JS_SetGlobalObject ; 164 +js_LockGCThing ; 155 +js_NewRegExpObject ; 152 +js_NewRegExp ; 152 +js_InitObjectClass ; 131 +js_InitFunctionClass ; 131 +js_EmitN ; 128 +JS_ArenaFinish ; 124 +js_GC ; 124 +js_SweepAtomState ; 124 +js_MarkAtomState ; 124 +JS_ArenaRealloc ; 124 +js_ForceGC ; 124 +js_FlushPropertyCache ; 122 +js_InitNumberClass ; 114 +JS_smprintf ; 112 +js_DoubleToECMAInt32 ; 112 +js_ValueToECMAInt32 ; 111 +JS_ValueToECMAInt32 ; 111 +JS_SetContextPrivate ; 109 +PRMJ_DSTOffset ; 108 +js_Clear ; 105 +JS_ClearScope ; 105 +JS_NewScriptObject ; 104 +JS_smprintf_free ; 104 +JS_ConvertValue ; 99 +js_GetSrcNote ; 98 +JS_ValueToECMAUint32 ; 93 +js_ValueToECMAUint32 ; 93 +js_printf ; 93 +js_DoubleToECMAUint32 ; 93 +js_DestroyRegExp ; 89 +js_UnlockGCThing ; 89 +js_TryValueOf ; 87 +js_NewSrcNote3 ; 86 +JS_ConvertStub ; 81 +JS_SetPendingException ; 80 +js_InitStringClass ; 79 +JS_GC ; 78 +js_InitArrayClass ; 74 +js_InitDateClass ; 67 +JS_NewContext ; 64 +JS_AddArgumentFormatter ; 64 +js_InitContextForLocking ; 64 +js_NewContext ; 64 +JS_SetBranchCallback ; 64 +JS_ClearRegExpStatics ; 64 +js_InitRegExpStatics ; 64 +js_InitCallClass ; 63 +js_InitRegExpClass ; 61 +js_Enumerate ; 58 +JS_DestroyContext ; 46 +js_DestroyContext ; 46 +js_FreeRegExpStatics ; 46 +js_InitScanner ; 39 +js_NewPrinter ; 36 +js_DestroyPrinter ; 36 +js_GetPrinterOutput ; 36 +JS_FreeArenaPool ; 36 +js_DecompileCode ; 34 +js_EmitContinue ; 33 +js_CheckAccess ; 30 +js_DecompileValueGenerator ; 28 +js_InitMathClass ; 27 +js_InitExceptionClasses ; 25 +js_NewArrayObject ; 24 +js_InitArgumentsClass ; 21 +js_puts ; 20 +js_InitBooleanClass ; 19 +JS_InitStandardClasses ; 19 +js_InitScriptClass ; 19 +js_obj_toString ; 15 +js_GetArgsValue ; 14 +js_GetArgsObject ; 14 +JS_DestroyIdArray ; 11 +js_NewIdArray ; 11 +JS_GetElement ; 11 +JS_EvaluateScript ; 9 +JS_EvaluateUCScript ; 9 +JS_DecompileFunction ; 8 +js_DecompileFunction ; 8 +JS_NewString ; 8 +js_SetStringBytes ; 8 +JS_GetArrayLength ; 7 +JS_NewArrayObject ; 7 +JS_IsArrayObject ; 7 +JS_ValueToObject ; 7 +JS_DefineElement ; 6 +js_DecompileScript ; 6 +JS_PushArguments ; 4 +JS_PopArguments ; 4 +JS_PushArgumentsVA ; 4 +js_PutArgsObject ; 2 +JS_SetGCCallbackRT ; 2 +JS_Init ; 1 +js_SetupLocks ; 1 +js_InitRuntimeNumberState ; 1 +js_InitRuntimeStringState ; 1 +js_InitLock ; 1 +js_InitGC ; 1 +js_InitAtomState ; 1 +js_InitStringGlobals ; 1 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-help.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-help.txt new file mode 100644 index 0000000..e20938b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-help.txt @@ -0,0 +1,12 @@ +Usage: jscoverage SOURCE-DIRECTORY DESTINATION-DIRECTORY +Instrument JavaScript with code coverage information. + +Options: + --encoding=ENCODING assume .js files use the given character encoding + --exclude=PATH do not copy PATH + --js-version=VERSION use the specified JavaScript version + --no-highlight do not perform syntax highlighting + --no-instrument=PATH copy but do not instrument PATH + -v, --verbose explain what is being done + -h, --help display this help and exit + -V, --version display version information and exit diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-highlight.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-highlight.css new file mode 100644 index 0000000..31a4695 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-highlight.css @@ -0,0 +1,38 @@ +/* + jscoverage-highlight.css - JSCoverage syntax highlighting style sheet + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/* keyword, type, symbol, cbracket */ +#sourceTable .k { + font-weight: bold; +} + +/* string, regexp, number */ +#sourceTable .s { + color: #006400; +} + +/* specialchar */ +#sourceTable .t { + color: #2e8b57; +} + +/* comment */ +#sourceTable .c { + font-style: italic; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-ie.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-ie.css new file mode 100644 index 0000000..afb2b80 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-ie.css @@ -0,0 +1,89 @@ +#headingDiv { + position: static; + margin-left: 10px; + margin-right: 10px; + padding-top: 0.5em; +} + +#tabs { + clear: all; + position: static; + top: auto; + left: auto; + right: auto; + height: auto; + margin-left: 10px; + margin-right: 10px; +} + +#tabs div { + position: relative; + height: auto; + line-height: normal; + padding-top: 5px; + padding-bottom: 5px; +} + +#tabs div.selected { + padding-bottom: 6px; + z-index: 2; +} + +.TabPage { + position: relative; + top: -1px; + left: auto; + right: auto; + bottom: auto; + clear: left; + margin-left: 10px; + margin-right: 10px; + padding: 10px; + z-index: 1; +} + +#locationDiv { + margin-bottom: 10px; +} + +#iframeDiv { + position: static; + width: 100%; +} + +#summaryDiv { + position: static; + width: 100%; +} + +#fileDiv { + margin-bottom: 10px; +} + +#sourceDiv { + position: static; + width: 100%; +} + +#storeDiv { + position: static; + width: 100%; +} + +/* some defaults */ + +.TabPage { + height: 650px; +} + +#iframeDiv { + height: 600px; +} + +#summaryDiv { + height: 600px; +} + +#sourceDiv { + height: 600px; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-overlay.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-overlay.js new file mode 100644 index 0000000..35e6181 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-overlay.js @@ -0,0 +1,211 @@ +/* + jscoverage-overlay.js - script for XUL overlay + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +Components.utils.import('resource://gre/modules/jscoverage.jsm'); + +// https://developer.mozilla.org/en/Code_snippets/Tabbed_browser +function openAndReuseOneTabPerURL(url) { + var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] + .getService(Components.interfaces.nsIWindowMediator); + var browserEnumerator = wm.getEnumerator("navigator:browser"); + + // Check each browser instance for our URL + var found = false; + while (!found && browserEnumerator.hasMoreElements()) { + var browserWin = browserEnumerator.getNext(); + var tabbrowser = browserWin.getBrowser(); + + // Check each tab of this browser instance + var numTabs = tabbrowser.browsers.length; + for(var index=0; index 0) { + write(','); + } + var value = coverage[line]; + if (value === undefined || value === null) { + value = 'null'; + } + write(value.toString()); + } + write('],"source":['); + var source = coverage.source; + length = source.length; + for (line = 0; line < length; line++) { + if (line > 0) { + write(','); + } + write(jscoverage_quote(source[line])); + } + write(']}'); + } + write('}'); + alert('Coverage data stored.'); + } + finally { + fileOutputStream.close(); + } + } + catch (e) { + alert(e); + dump(e); + dump('\n'); + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server-help.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server-help.txt new file mode 100644 index 0000000..98415b4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server-help.txt @@ -0,0 +1,17 @@ +Usage: jscoverage-server [OPTION]... +Run a server for instrumenting JavaScript with code coverage information. + +Options: + --document-root=DIR serve content from DIR (default: current directory) + --encoding=ENCODING assume .js files use the given character encoding + --ip-address=ADDRESS bind to ADDRESS (default: 127.0.0.1) + --js-version=VERSION use the specified JavaScript version + --no-highlight do not perform syntax highlighting + --no-instrument=URL do not instrument URL + --port=PORT use PORT for TCP port (default: 8080) + --proxy run as a proxy + --report-dir=DIR store report to DIR (default: `jscoverage-report') + --shutdown stop a running server + -v, --verbose explain what is being done + -h, --help display this help and exit + -V, --version display version information and exit diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server.1 b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server.1 new file mode 100644 index 0000000..cfb4b09 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server.1 @@ -0,0 +1,79 @@ +.TH jscoverage-server 1 local +.SH NAME +jscoverage-server \- Run a server for instrumenting JavaScript with code coverage information + +.SH SYNOPSIS +jscoverage-server [OPTION]... + +.SH DESCRIPTION + +jscoverage-server is a simple web server that instruments JavaScript code as it is served. + +.SH OPTIONS + +.TP +.B --document-root=DIR +serve content from +.B DIR +(default: current directory). + +.TP +.B --encoding=ENCODING +assume .js files use the given character encoding. + +.TP +.B --ip-address=ADDRESS +bind to +.B ADDRESS +(default: 127.0.0.1). + +.TP +.B --js-version=VERSION +use the specified JavaScript version; valid values for +.B VERSION +are 1.0, 1.1, 1.2, ..., 1.8, or ECMAv3 (the default). + +.TP +.B --no-highlight +do not perform syntax highlighting. + +.TP +.B --no-instrument=URL +do not instrument +.B URL. + +.TP +.B --port=PORT +use +.B PORT +for TCP port (default: 8080). + +.TP +.B --proxy +run as a proxy. + +.TP +.B --report-dir=DIR +store report to +.B DIR +(default: jscoverage-report). + +.TP +.B --shutdown +stop a running server. + +.TP +.B -v, --verbose +explain what is being done. + +.TP +.B -h, --help +display this help and exit. + +.TP +.B -V, --version +display version information and exit. +. +.SH AUTHORS + +siliconforks.com diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server.c new file mode 100644 index 0000000..7fc02bc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-server.c @@ -0,0 +1,1307 @@ +/* + jscoverage-server.c - JSCoverage server main routine + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include +#include +#include +#include + +#include +#ifdef HAVE_PTHREAD_H +#include +#endif + +#include "encoding.h" +#include "global.h" +#include "http-server.h" +#include "instrument-js.h" +#include "resource-manager.h" +#include "stream.h" +#include "util.h" + +static const char * specified_encoding = NULL; +const char * jscoverage_encoding = "ISO-8859-1"; +bool jscoverage_highlight = true; + +typedef struct SourceCache { + char * url; + uint16_t * characters; + size_t num_characters; + struct SourceCache * next; +} SourceCache; + +static SourceCache * source_cache = NULL; + +static const struct { + const char * extension; + const char * mime_type; +} mime_types[] = { + {".gif", "image/gif"}, + {".jpg", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".png", "image/png"}, + {".css", "text/css"}, + {".html", "text/html"}, + {".htm", "text/html"}, + {".js", "text/javascript"}, + {".txt", "text/plain"}, + {".xml", "application/xml"}, +}; + +static bool verbose = false; +static const char * report_directory = "jscoverage-report"; +static const char * document_root = "."; +static bool proxy = false; +static const char ** no_instrument; +static size_t num_no_instrument = 0; + +#ifdef __MINGW32__ +CRITICAL_SECTION javascript_mutex; +CRITICAL_SECTION source_cache_mutex; +#define LOCK EnterCriticalSection +#define UNLOCK LeaveCriticalSection +#else +pthread_mutex_t javascript_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t source_cache_mutex = PTHREAD_MUTEX_INITIALIZER; +#define LOCK pthread_mutex_lock +#define UNLOCK pthread_mutex_unlock +#endif + +static const SourceCache * find_cached_source(const char * url) { + SourceCache * result = NULL; + LOCK(&source_cache_mutex); + for (SourceCache * p = source_cache; p != NULL; p = p->next) { + if (strcmp(url, p->url) == 0) { + result = p; + break; + } + } + UNLOCK(&source_cache_mutex); + return result; +} + +static void add_cached_source(const char * url, uint16_t * characters, size_t num_characters) { + SourceCache * new_source_cache = xmalloc(sizeof(SourceCache)); + new_source_cache->url = xstrdup(url); + new_source_cache->characters = characters; + new_source_cache->num_characters = num_characters; + LOCK(&source_cache_mutex); + new_source_cache->next = source_cache; + source_cache = new_source_cache; + UNLOCK(&source_cache_mutex); +} + +static int get(const char * url, uint16_t ** characters, size_t * num_characters) __attribute__((warn_unused_result)); + +static int get(const char * url, uint16_t ** characters, size_t * num_characters) { + char * host = NULL; + uint16_t port; + char * abs_path = NULL; + char * query = NULL; + HTTPConnection * connection = NULL; + HTTPExchange * exchange = NULL; + Stream * stream = NULL; + + int result = URL_parse(url, &host, &port, &abs_path, &query); + if (result != 0) { + goto done; + } + + connection = HTTPConnection_new_client(host, port); + if (connection == NULL) { + result = -1; + goto done; + } + + exchange = HTTPExchange_new(connection); + HTTPExchange_set_request_uri(exchange, url); + result = HTTPExchange_write_request_headers(exchange); + if (result != 0) { + goto done; + } + + result = HTTPExchange_read_response_headers(exchange); + if (result != 0) { + goto done; + } + + stream = Stream_new(0); + result = HTTPExchange_read_entire_response_entity_body(exchange, stream); + if (result != 0) { + goto done; + } + char * encoding = HTTPMessage_get_charset(HTTPExchange_get_response_message(exchange)); + if (encoding == NULL) { + encoding = xstrdup(jscoverage_encoding); + } + result = jscoverage_bytes_to_characters(encoding, stream->data, stream->length, characters, num_characters); + free(encoding); + if (result != 0) { + goto done; + } + + result = 0; + +done: + if (stream != NULL) { + Stream_delete(stream); + } + if (exchange != NULL) { + HTTPExchange_delete(exchange); + } + if (connection != NULL) { + if (HTTPConnection_delete(connection) != 0) { + HTTPServer_log_err("Warning: error closing connection after retrieving URL: %s\n", url); + } + } + free(host); + free(abs_path); + free(query); + return result; +} + +static void send_response(HTTPExchange * exchange, uint16_t status_code, const char * html) { + HTTPExchange_set_status_code(exchange, status_code); + if (HTTPExchange_write_response(exchange, html, strlen(html)) != 0) { + HTTPServer_log_err("Warning: error writing to client\n"); + } +} + +/* +RFC 2396, Appendix A: we are checking for `pchar' +*/ +static bool is_escaped(char c) { + /* `pchar' */ + if (strchr(":@&=+$,", c) != NULL) { + return false; + } + + if (isalnum((unsigned char) c)) { + return false; + } + + /* `mark' */ + if (strchr("-_.!~*'()", c) != NULL) { + return false; + } + + return true; +} + +static char * encode_uri_component(const char * s) { + size_t length = 0; + for (const char * p = s; *p != '\0'; p++) { + if (is_escaped(*p)) { + length = addst(length, 3); + } + else { + length = addst(length, 1); + } + } + + length = addst(length, 1); + char * result = xmalloc(length); + size_t i = 0; + for (const char * p = s; *p != '\0'; p++) { + if (is_escaped(*p)) { + result[i] = '%'; + i++; + snprintf(result + i, 3, "%02X", *p); + i += 2; + } + else { + result[i] = *p; + i++; + } + } + result[i] = '\0'; + + return result; +} + +static unsigned int hex_value(char c) { + if ('0' <= c && c <= '9') { + return c - '0'; + } + else if ('A' <= c && c <= 'F') { + return c - 'A' + 10; + } + else if ('a' <= c && c <= 'f') { + return c - 'a' + 10; + } + else { + return 0; + } +} + +static char * decode_uri_component(const char * s) { + size_t length = strlen(s); + char * result = xmalloc(length + 1); + char * p = result; + while (*s != '\0') { + if (*s == '%') { + if (s[1] == '\0' || s[2] == '\0') { + *p = '\0'; + return result; + } + *p = hex_value(s[1]) * 16 + hex_value(s[2]); + s += 2; + } + else { + *p = *s; + } + p++; + s++; + } + *p = '\0'; + return result; +} + +static const char * get_entity(char c) { + switch(c) { + case '<': + return "<"; + case '>': + return ">"; + case '&': + return "&"; + case '\'': + return "'"; + case '"': + return """; + default: + return NULL; + } +} + +static char * encode_html(const char * s) { + size_t length = 0; + for (const char * p = s; *p != '\0'; p++) { + const char * entity = get_entity(*p); + if (entity == NULL) { + length = addst(length, 1); + } + else { + length = addst(length, strlen(entity)); + } + } + + length = addst(length, 1); + char * result = xmalloc(length); + size_t i = 0; + for (const char * p = s; *p != '\0'; p++) { + const char * entity = get_entity(*p); + if (entity == NULL) { + result[i] = *p; + i++; + } + else { + strcpy(result + i, entity); + i += strlen(entity); + } + } + result[i] = '\0'; + + return result; +} + +static const char * get_content_type(const char * path) { + char * last_dot = strrchr(path, '.'); + if (last_dot == NULL) { + return "application/octet-stream"; + } + for (size_t i = 0; i < sizeof(mime_types) / sizeof(mime_types[0]); i++) { + if (strcmp(last_dot, mime_types[i].extension) == 0) { + return mime_types[i].mime_type; + } + } + return "application/octet-stream"; +} + +/** +Checks whether a URI is on the no-instrument list. +@param uri the HTTP "Request-URI"; must not be NULL, and must not be a zero-length string +@return true if the URI is on the no-instrument list, false otherwise +*/ +static bool is_no_instrument(const char * uri) { + assert(*uri != '\0'); + + for (size_t i = 0; i < num_no_instrument; i++) { + if (str_starts_with(uri, no_instrument[i])) { + return true; + } + + /* + For a local URL, accept "/foo/bar" and "foo/bar" on the no-instrument list. + */ + if (! proxy && str_starts_with(uri + 1, no_instrument[i])) { + return true; + } + } + + return false; +} + +static bool is_javascript(HTTPExchange * exchange) { + const char * header = HTTPExchange_find_response_header(exchange, HTTP_CONTENT_TYPE); + if (header == NULL) { + /* guess based on extension */ + return str_ends_with(HTTPExchange_get_request_uri(exchange), ".js"); + } + else { + char * semicolon = strchr(header, ';'); + char * content_type; + if (semicolon == NULL) { + content_type = xstrdup(header); + } + else { + content_type = xstrndup(header, semicolon - header); + } + /* RFC 4329 */ + bool result = strcmp(content_type, "text/javascript") == 0 || + strcmp(content_type, "text/ecmascript") == 0 || + strcmp(content_type, "text/javascript1.0") == 0 || + strcmp(content_type, "text/javascript1.1") == 0 || + strcmp(content_type, "text/javascript1.2") == 0 || + strcmp(content_type, "text/javascript1.3") == 0 || + strcmp(content_type, "text/javascript1.4") == 0 || + strcmp(content_type, "text/javascript1.5") == 0 || + strcmp(content_type, "text/jscript") == 0 || + strcmp(content_type, "text/livescript") == 0 || + strcmp(content_type, "text/x-javascript") == 0 || + strcmp(content_type, "text/x-ecmascript") == 0 || + strcmp(content_type, "application/x-javascript") == 0 || + strcmp(content_type, "application/x-ecmascript") == 0 || + strcmp(content_type, "application/javascript") == 0 || + strcmp(content_type, "application/ecmascript") == 0; + free(content_type); + return result; + } +} + +static bool should_instrument_request(HTTPExchange * exchange) { + if (! is_javascript(exchange)) { + return false; + } + + if (is_no_instrument(HTTPExchange_get_request_uri(exchange))) { + return false; + } + + return true; +} + +static int merge(Coverage * coverage, FILE * f) __attribute__((warn_unused_result)); + +static int merge(Coverage * coverage, FILE * f) { + Stream * stream = Stream_new(0); + Stream_write_file_contents(stream, f); + + LOCK(&javascript_mutex); + int result = jscoverage_parse_json(coverage, stream->data, stream->length); + UNLOCK(&javascript_mutex); + + Stream_delete(stream); + return result; +} + +static void write_js_quoted_string(FILE * f, char * data, size_t length) { + putc('"', f); + for (size_t i = 0; i < length; i++) { + char c = data[i]; + switch (c) { + case '\b': + fputs("\\b", f); + break; + case '\f': + fputs("\\f", f); + break; + case '\n': + fputs("\\n", f); + break; + case '\r': + fputs("\\r", f); + break; + case '\t': + fputs("\\t", f); + break; + /* IE doesn't support this */ + /* + case '\v': + fputs("\\v", f); + break; + */ + case '"': + fputs("\\\"", f); + break; + case '\\': + fputs("\\\\", f); + break; + default: + putc(c, f); + break; + } + } + putc('"', f); +} + +static void write_source(const char * id, const uint16_t * characters, size_t num_characters, FILE * f) { + Stream * output = Stream_new(num_characters); + jscoverage_write_source(id, characters, num_characters, output); + fwrite(output->data, 1, output->length, f); + Stream_delete(output); +} + +static void write_json_for_file(const FileCoverage * file_coverage, int i, void * p) { + FILE * f = p; + + if (i > 0) { + putc(',', f); + } + + write_js_quoted_string(f, file_coverage->id, strlen(file_coverage->id)); + + fputs(":{\"coverage\":[", f); + for (uint32_t i = 0; i < file_coverage->num_coverage_lines; i++) { + if (i > 0) { + putc(',', f); + } + int timesExecuted = file_coverage->coverage_lines[i]; + if (timesExecuted < 0) { + fputs("null", f); + } + else { + fprintf(f, "%d", timesExecuted); + } + } + fputs("],\"source\":", f); + if (file_coverage->source_lines == NULL) { + if (proxy) { + const SourceCache * cached = find_cached_source(file_coverage->id); + if (cached == NULL) { + uint16_t * characters; + size_t num_characters; + if (get(file_coverage->id, &characters, &num_characters) == 0) { + write_source(file_coverage->id, characters, num_characters, f); + add_cached_source(file_coverage->id, characters, num_characters); + } + else { + fputs("[]", f); + HTTPServer_log_err("Warning: cannot retrieve URL: %s\n", file_coverage->id); + } + } + else { + write_source(file_coverage->id, cached->characters, cached->num_characters, f); + } + } + else { + /* check that the path begins with / */ + if (file_coverage->id[0] == '/') { + char * source_path = make_path(document_root, file_coverage->id + 1); + FILE * source_file = fopen(source_path, "rb"); + free(source_path); + if (source_file == NULL) { + fputs("[]", f); + HTTPServer_log_err("Warning: cannot open file: %s\n", file_coverage->id); + } + else { + Stream * stream = Stream_new(0); + Stream_write_file_contents(stream, source_file); + fclose(source_file); + uint16_t * characters; + size_t num_characters; + int result = jscoverage_bytes_to_characters(jscoverage_encoding, stream->data, stream->length, &characters, &num_characters); + Stream_delete(stream); + if (result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED) { + fputs("[]", f); + HTTPServer_log_err("Warning: encoding %s not supported\n", jscoverage_encoding); + } + else if (result == JSCOVERAGE_ERROR_INVALID_BYTE_SEQUENCE) { + fputs("[]", f); + HTTPServer_log_err("Warning: error decoding %s in file %s\n", jscoverage_encoding, file_coverage->id); + } + else { + write_source(file_coverage->id, characters, num_characters, f); + free(characters); + } + } + } + else { + /* path does not begin with / */ + fputs("[]", f); + HTTPServer_log_err("Warning: invalid source path: %s\n", file_coverage->id); + } + } + } + else { + fputc('[', f); + for (uint32_t i = 0; i < file_coverage->num_source_lines; i++) { + if (i > 0) { + fputc(',', f); + } + char * source_line = file_coverage->source_lines[i]; + write_js_quoted_string(f, source_line, strlen(source_line)); + } + fputc(']', f); + } + fputc('}', f); +} + +static int write_json(Coverage * coverage, const char * path) __attribute__((warn_unused_result)); + +static int write_json(Coverage * coverage, const char * path) { + /* write the JSON */ + FILE * f = fopen(path, "wb"); + if (f == NULL) { + return -1; + } + putc('{', f); + Coverage_foreach_file(coverage, write_json_for_file, f); + putc('}', f); + if (fclose(f) == EOF) { + return -1; + } + return 0; +} + +static void handle_jscoverage_request(HTTPExchange * exchange) { + /* set the `Server' response-header (RFC 2616 14.38, 3.8) */ + HTTPExchange_set_response_header(exchange, HTTP_SERVER, "jscoverage-server/" VERSION); + + const char * abs_path = HTTPExchange_get_abs_path(exchange); + assert(*abs_path != '\0'); + if (str_starts_with(abs_path, "/jscoverage-store")) { + if (strcmp(HTTPExchange_get_method(exchange), "POST") != 0) { + HTTPExchange_set_response_header(exchange, HTTP_ALLOW, "POST"); + send_response(exchange, 405, "Method not allowed\n"); + return; + } + + Stream * json = Stream_new(0); + + /* read the POST body */ + if (HTTPExchange_read_entire_request_entity_body(exchange, json) != 0) { + Stream_delete(json); + send_response(exchange, 400, "Could not read request body\n"); + return; + } + + Coverage * coverage = Coverage_new(); + LOCK(&javascript_mutex); + int result = jscoverage_parse_json(coverage, json->data, json->length); + UNLOCK(&javascript_mutex); + Stream_delete(json); + + if (result != 0) { + Coverage_delete(coverage); + send_response(exchange, 400, "Could not parse coverage data\n"); + return; + } + + mkdir_if_necessary(report_directory); + char * current_report_directory; + if (str_starts_with(abs_path, "/jscoverage-store/") && abs_path[18] != '\0') { + char * dir = decode_uri_component(abs_path + 18); + current_report_directory = make_path(report_directory, dir); + free(dir); + } + else { + current_report_directory = xstrdup(report_directory); + } + mkdir_if_necessary(current_report_directory); + char * path = make_path(current_report_directory, "jscoverage.json"); + + /* check if the JSON file exists */ + struct stat buf; + if (stat(path, &buf) == 0) { + /* it exists: merge */ + FILE * f = fopen(path, "rb"); + if (f == NULL) { + result = 1; + } + else { + result = merge(coverage, f); + if (fclose(f) == EOF) { + result = 1; + } + } + if (result != 0) { + free(current_report_directory); + free(path); + Coverage_delete(coverage); + send_response(exchange, 500, "Could not merge with existing coverage data\n"); + return; + } + } + + result = write_json(coverage, path); + free(path); + Coverage_delete(coverage); + if (result != 0) { + free(current_report_directory); + send_response(exchange, 500, "Could not write coverage data\n"); + return; + } + + /* copy other files */ + jscoverage_copy_resources(current_report_directory); + path = make_path(current_report_directory, "jscoverage.js"); + free(current_report_directory); + FILE * f = fopen(path, "ab"); + free(path); + if (f == NULL) { + send_response(exchange, 500, "Could not write to file: jscoverage.js\n"); + return; + } + fputs("jscoverage_isReport = true;\r\n", f); + if (fclose(f) == EOF) { + send_response(exchange, 500, "Could not write to file: jscoverage.js\n"); + return; + } + + send_response(exchange, 200, "Coverage data stored\n"); + } + else if (str_starts_with(abs_path, "/jscoverage-shutdown")) { + if (strcmp(HTTPExchange_get_method(exchange), "POST") != 0) { + HTTPExchange_set_response_header(exchange, HTTP_ALLOW, "POST"); + send_response(exchange, 405, "Method not allowed\n"); + return; + } + + /* allow only from localhost */ + struct sockaddr_in client; + if (HTTPExchange_get_peer(exchange, &client) != 0) { + send_response(exchange, 500, "Cannot get client address\n"); + return; + } + if (client.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { + send_response(exchange, 403, "This operation can be performed only by localhost\n"); + return; + } + + send_response(exchange, 200, "The server will now shut down\n"); + HTTPServer_shutdown(); + } + else { + const char * path = abs_path + 1; + const struct Resource * resource = get_resource(path); + if (resource == NULL) { + send_response(exchange, 404, "Not found\n"); + return; + } + HTTPExchange_set_response_header(exchange, HTTP_CONTENT_TYPE, get_content_type(path)); + if (HTTPExchange_write_response(exchange, resource->data, resource->length) != 0) { + HTTPServer_log_err("Warning: error writing to client\n"); + return; + } + if (strcmp(abs_path, "/jscoverage.js") == 0) { + const char * s = "jscoverage_isServer = true;\r\n"; + if (HTTPExchange_write_response(exchange, s, strlen(s)) != 0) { + HTTPServer_log_err("Warning: error writing to client\n"); + } + } + } +} + +static void instrument_js(const char * id, const uint16_t * characters, size_t num_characters, Stream * output_stream) { + const struct Resource * resource = get_resource("report.js"); + Stream_write(output_stream, resource->data, resource->length); + + LOCK(&javascript_mutex); + jscoverage_instrument_js(id, characters, num_characters, output_stream); + UNLOCK(&javascript_mutex); +} + +static bool is_hop_by_hop_header(const char * h) { + /* hop-by-hop headers (RFC 2616 13.5.1) */ + return strcasecmp(h, HTTP_CONNECTION) == 0 || + strcasecmp(h, "Keep-Alive") == 0 || + strcasecmp(h, HTTP_PROXY_AUTHENTICATE) == 0 || + strcasecmp(h, HTTP_PROXY_AUTHORIZATION) == 0 || + strcasecmp(h, HTTP_TE) == 0 || + strcasecmp(h, HTTP_TRAILER) == 0 || + strcasecmp(h, HTTP_TRANSFER_ENCODING) == 0 || + strcasecmp(h, HTTP_UPGRADE) == 0; +} + +static void add_via_header(HTTPMessage * message, const char * version) { + char * value; + xasprintf(&value, "%s jscoverage-server", version); + HTTPMessage_add_header(message, HTTP_VIA, value); + free(value); +} + +static int copy_http_message_body(HTTPMessage * from, HTTPMessage * to) __attribute__((warn_unused_result)); + +static int copy_http_message_body(HTTPMessage * from, HTTPMessage * to) { + uint8_t * buffer[8192]; + for (;;) { + size_t bytes_read; + int result = HTTPMessage_read_message_body(from, buffer, 8192, &bytes_read); + if (result != 0) { + return result; + } + if (bytes_read == 0) { + return 0; + } + result = HTTPMessage_write(to, buffer, bytes_read); + if (result != 0) { + return result; + } + } +} + +static void handle_proxy_request(HTTPExchange * client_exchange) { + HTTPConnection * server_connection = NULL; + HTTPExchange * server_exchange = NULL; + + const char * abs_path = HTTPExchange_get_abs_path(client_exchange); + if (str_starts_with(abs_path, "/jscoverage")) { + handle_jscoverage_request(client_exchange); + return; + } + + const char * host = HTTPExchange_get_host(client_exchange); + uint16_t port = HTTPExchange_get_port(client_exchange); + + /* create a new connection */ + server_connection = HTTPConnection_new_client(host, port); + if (server_connection == NULL) { + send_response(client_exchange, 504, "Could not connect to server\n"); + goto done; + } + + /* create a new exchange */ + server_exchange = HTTPExchange_new(server_connection); + HTTPExchange_set_method(server_exchange, HTTPExchange_get_method(client_exchange)); + HTTPExchange_set_request_uri(server_exchange, HTTPExchange_get_request_uri(client_exchange)); + for (const HTTPHeader * h = HTTPExchange_get_request_headers(client_exchange); h != NULL; h = h->next) { + if (strcasecmp(h->name, HTTP_TRAILER) == 0 || strcasecmp(h->name, HTTP_TRANSFER_ENCODING) == 0) { + /* do nothing: we want to keep this header */ + } + else if (is_hop_by_hop_header(h->name) || + strcasecmp(h->name, HTTP_ACCEPT_ENCODING) == 0 || + strcasecmp(h->name, HTTP_RANGE) == 0) { + continue; + } + HTTPExchange_add_request_header(server_exchange, h->name, h->value); + } + add_via_header(HTTPExchange_get_request_message(server_exchange), HTTPExchange_get_request_http_version(client_exchange)); + + /* send the request */ + if (HTTPExchange_write_request_headers(server_exchange) != 0) { + send_response(client_exchange, 502, "Could not write to server\n"); + goto done; + } + + /* handle POST or PUT */ + if (HTTPExchange_request_has_body(client_exchange)) { + HTTPMessage * client_request = HTTPExchange_get_request_message(client_exchange); + HTTPMessage * server_request = HTTPExchange_get_request_message(server_exchange); + if (copy_http_message_body(client_request, server_request) != 0) { + send_response(client_exchange, 400, "Error copying request body from client to server\n"); + goto done; + } + } + + if (HTTPExchange_flush_request(server_exchange) != 0) { + send_response(client_exchange, 502, "Could not write to server\n"); + goto done; + } + + /* receive the response */ + if (HTTPExchange_read_response_headers(server_exchange) != 0) { + send_response(client_exchange, 502, "Could not read headers from server\n"); + goto done; + } + + HTTPExchange_set_status_code(client_exchange, HTTPExchange_get_status_code(server_exchange)); + + if (HTTPExchange_response_has_body(server_exchange) && should_instrument_request(server_exchange)) { + /* needs instrumentation */ + Stream * input_stream = Stream_new(0); + if (HTTPExchange_read_entire_response_entity_body(server_exchange, input_stream) != 0) { + Stream_delete(input_stream); + send_response(client_exchange, 502, "Could not read body from server\n"); + goto done; + } + + const char * request_uri = HTTPExchange_get_request_uri(client_exchange); + char * encoding = HTTPMessage_get_charset(HTTPExchange_get_response_message(server_exchange)); + if (encoding == NULL) { + encoding = xstrdup(jscoverage_encoding); + } + uint16_t * characters; + size_t num_characters; + int result = jscoverage_bytes_to_characters(encoding, input_stream->data, input_stream->length, &characters, &num_characters); + free(encoding); + Stream_delete(input_stream); + if (result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED) { + send_response(client_exchange, 500, "Encoding not supported\n"); + goto done; + } + else if (result == JSCOVERAGE_ERROR_INVALID_BYTE_SEQUENCE) { + send_response(client_exchange, 502, "Error decoding response\n"); + goto done; + } + + Stream * output_stream = Stream_new(0); + instrument_js(request_uri, characters, num_characters, output_stream); + + /* send the headers to the client */ + for (const HTTPHeader * h = HTTPExchange_get_response_headers(server_exchange); h != NULL; h = h->next) { + if (is_hop_by_hop_header(h->name) || strcasecmp(h->name, HTTP_CONTENT_LENGTH) == 0) { + continue; + } + else if (strcasecmp(h->name, HTTP_CONTENT_TYPE) == 0) { + HTTPExchange_add_response_header(client_exchange, HTTP_CONTENT_TYPE, "text/javascript; charset=ISO-8859-1"); + continue; + } + HTTPExchange_add_response_header(client_exchange, h->name, h->value); + } + add_via_header(HTTPExchange_get_response_message(client_exchange), HTTPExchange_get_response_http_version(server_exchange)); + HTTPExchange_set_response_content_length(client_exchange, output_stream->length); + + /* send the instrumented code to the client */ + if (HTTPExchange_write_response(client_exchange, output_stream->data, output_stream->length) != 0) { + HTTPServer_log_err("Warning: error writing to client\n"); + } + + /* characters go on the cache */ + /* + free(characters); + */ + Stream_delete(output_stream); + add_cached_source(request_uri, characters, num_characters); + } + else { + /* does not need instrumentation */ + + /* send the headers to the client */ + for (const HTTPHeader * h = HTTPExchange_get_response_headers(server_exchange); h != NULL; h = h->next) { + if (strcasecmp(h->name, HTTP_TRAILER) == 0 || strcasecmp(h->name, HTTP_TRANSFER_ENCODING) == 0) { + /* do nothing: we want to keep this header */ + } + else if (is_hop_by_hop_header(h->name)) { + continue; + } + HTTPExchange_add_response_header(client_exchange, h->name, h->value); + } + add_via_header(HTTPExchange_get_response_message(client_exchange), HTTPExchange_get_response_http_version(server_exchange)); + + if (HTTPExchange_write_response_headers(client_exchange) != 0) { + HTTPServer_log_err("Warning: error writing to client\n"); + goto done; + } + + if (HTTPExchange_response_has_body(server_exchange)) { + /* read the body from the server and send it to the client */ + HTTPMessage * client_response = HTTPExchange_get_response_message(client_exchange); + HTTPMessage * server_response = HTTPExchange_get_response_message(server_exchange); + if (copy_http_message_body(server_response, client_response) != 0) { + HTTPServer_log_err("Warning: error copying response body from server to client\n"); + goto done; + } + } + } + +done: + if (server_exchange != NULL) { + HTTPExchange_delete(server_exchange); + } + if (server_connection != NULL) { + if (HTTPConnection_delete(server_connection) != 0) { + HTTPServer_log_err("Warning: error closing connection to server\n"); + } + } +} + +static void handle_local_request(HTTPExchange * exchange) { + /* add the `Server' response-header (RFC 2616 14.38, 3.8) */ + HTTPExchange_add_response_header(exchange, HTTP_SERVER, "jscoverage-server/" VERSION); + + char * decoded_path = NULL; + char * filesystem_path = NULL; + + const char * abs_path = HTTPExchange_get_abs_path(exchange); + assert(*abs_path != '\0'); + + decoded_path = decode_uri_component(abs_path); + + if (str_starts_with(decoded_path, "/jscoverage")) { + handle_jscoverage_request(exchange); + goto done; + } + + if (strstr(decoded_path, "..") != NULL) { + send_response(exchange, 403, "Forbidden\n"); + goto done; + } + + filesystem_path = make_path(document_root, decoded_path + 1); + size_t filesystem_path_length = strlen(filesystem_path); + if (filesystem_path_length > 0 && filesystem_path[filesystem_path_length - 1] == '/') { + /* stat on Windows doesn't work with trailing slash */ + filesystem_path[filesystem_path_length - 1] = '\0'; + } + + struct stat buf; + if (stat(filesystem_path, &buf) == -1) { + send_response(exchange, 404, "Not found\n"); + goto done; + } + + if (S_ISDIR(buf.st_mode)) { + if (abs_path[strlen(abs_path) - 1] != '/') { + const char * request_uri = HTTPExchange_get_request_uri(exchange); + char * uri = xmalloc(strlen(request_uri) + 2); + strcpy(uri, request_uri); + strcat(uri, "/"); + HTTPExchange_add_response_header(exchange, "Location", uri); + free(uri); + send_response(exchange, 301, "Moved permanently\n"); + goto done; + } + + DIR * d = opendir(filesystem_path); + if (d == NULL) { + send_response(exchange, 404, "Not found\n"); + goto done; + } + + struct dirent * entry; + while ((entry = readdir(d)) != NULL) { + char * href = encode_uri_component(entry->d_name); + char * html_href = encode_html(href); + char * link = encode_html(entry->d_name); + char * directory_entry; + xasprintf(&directory_entry, "%s
\n", html_href, link); + if (HTTPExchange_write_response(exchange, directory_entry, strlen(directory_entry)) != 0) { + HTTPServer_log_err("Warning: error writing to client\n"); + } + free(directory_entry); + free(href); + free(html_href); + free(link); + } + closedir(d); + } + else if (S_ISREG(buf.st_mode)) { + FILE * f = fopen(filesystem_path, "rb"); + if (f == NULL) { + send_response(exchange, 404, "Not found\n"); + goto done; + } + + /* + When do we send a charset with Content-Type? + if Content-Type is "text" or "application" + if instrumented JavaScript + use Content-Type: application/javascript; charset=ISO-8859-1 + else if --encoding is given + use that encoding + else + send no charset + else + send no charset + */ + const char * content_type = get_content_type(filesystem_path); + if (strcmp(content_type, "text/javascript") == 0 && ! is_no_instrument(abs_path)) { + HTTPExchange_set_response_header(exchange, HTTP_CONTENT_TYPE, "text/javascript; charset=ISO-8859-1"); + + Stream * input_stream = Stream_new(0); + Stream_write_file_contents(input_stream, f); + + uint16_t * characters; + size_t num_characters; + int result = jscoverage_bytes_to_characters(jscoverage_encoding, input_stream->data, input_stream->length, &characters, &num_characters); + Stream_delete(input_stream); + + if (result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED) { + send_response(exchange, 500, "Encoding not supported\n"); + goto done; + } + else if (result == JSCOVERAGE_ERROR_INVALID_BYTE_SEQUENCE) { + send_response(exchange, 500, "Error decoding JavaScript file\n"); + goto done; + } + + Stream * output_stream = Stream_new(0); + instrument_js(abs_path, characters, num_characters, output_stream); + free(characters); + + if (HTTPExchange_write_response(exchange, output_stream->data, output_stream->length) != 0) { + HTTPServer_log_err("Warning: error writing to client\n"); + } + Stream_delete(output_stream); + } + else { + /* send the Content-Type with charset if necessary */ + if (specified_encoding != NULL && (str_starts_with(content_type, "text/") || str_starts_with(content_type, "application/"))) { + char * content_type_with_charset = NULL; + xasprintf(&content_type_with_charset, "%s; charset=%s", content_type, specified_encoding); + HTTPExchange_set_response_header(exchange, HTTP_CONTENT_TYPE, content_type_with_charset); + free(content_type_with_charset); + } + else { + HTTPExchange_set_response_header(exchange, HTTP_CONTENT_TYPE, content_type); + } + + char buffer[8192]; + size_t bytes_read; + while ((bytes_read = fread(buffer, 1, 8192, f)) > 0) { + if (HTTPExchange_write_response(exchange, buffer, bytes_read) != 0) { + HTTPServer_log_err("Warning: error writing to client\n"); + } + } + } + fclose(f); + } + else { + send_response(exchange, 404, "Not found\n"); + goto done; + } + +done: + free(filesystem_path); + free(decoded_path); +} + +static void handler(HTTPExchange * exchange) { + if (verbose) { + HTTPServer_log_out("%s", HTTPExchange_get_request_line(exchange)); + } + + if (proxy) { + handle_proxy_request(exchange); + } + else { + handle_local_request(exchange); + } +} + +int main(int argc, char ** argv) { + program = "jscoverage-server"; + + const char * ip_address = "127.0.0.1"; + const char * port = "8080"; + int shutdown = 0; + + no_instrument = xnew(const char *, argc - 1); + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { + copy_resource_to_stream("jscoverage-server-help.txt", stdout); + exit(EXIT_SUCCESS); + } + else if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) { + version(); + } + else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) { + verbose = 1; + } + + else if (strcmp(argv[i], "--report-dir") == 0) { + i++; + if (i == argc) { + fatal_command_line("--report-dir: option requires an argument"); + } + report_directory = argv[i]; + } + else if (strncmp(argv[i], "--report-dir=", 13) == 0) { + report_directory = argv[i] + 13; + } + + else if (strcmp(argv[i], "--document-root") == 0) { + i++; + if (i == argc) { + fatal_command_line("--document-root: option requires an argument"); + } + document_root = argv[i]; + } + else if (strncmp(argv[i], "--document-root=", 16) == 0) { + document_root = argv[i] + 16; + } + + else if (strcmp(argv[i], "--encoding") == 0) { + i++; + if (i == argc) { + fatal_command_line("--encoding: option requires an argument"); + } + jscoverage_encoding = argv[i]; + specified_encoding = jscoverage_encoding; + } + else if (strncmp(argv[i], "--encoding=", 11) == 0) { + jscoverage_encoding = argv[i] + 11; + specified_encoding = jscoverage_encoding; + } + + else if (strcmp(argv[i], "--ip-address") == 0) { + i++; + if (i == argc) { + fatal_command_line("--ip-address: option requires an argument"); + } + ip_address = argv[i]; + } + else if (strncmp(argv[i], "--ip-address=", 13) == 0) { + ip_address = argv[i] + 13; + } + + else if (strcmp(argv[i], "--js-version") == 0) { + i++; + if (i == argc) { + fatal_command_line("--js-version: option requires an argument"); + } + jscoverage_set_js_version(argv[i]); + } + else if (strncmp(argv[i], "--js-version=", 13) == 0) { + jscoverage_set_js_version(argv[i] + 13); + } + + else if (strcmp(argv[i], "--no-highlight") == 0) { + jscoverage_highlight = false; + } + + else if (strcmp(argv[i], "--no-instrument") == 0) { + i++; + if (i == argc) { + fatal_command_line("--no-instrument: option requires an argument"); + } + no_instrument[num_no_instrument] = argv[i]; + num_no_instrument++; + } + else if (strncmp(argv[i], "--no-instrument=", 16) == 0) { + no_instrument[num_no_instrument] = argv[i] + 16; + num_no_instrument++; + } + + else if (strcmp(argv[i], "--port") == 0) { + i++; + if (i == argc) { + fatal_command_line("--port: option requires an argument"); + } + port = argv[i]; + } + else if (strncmp(argv[i], "--port=", 7) == 0) { + port = argv[i] + 7; + } + + else if (strcmp(argv[i], "--proxy") == 0) { + proxy = 1; + } + + else if (strcmp(argv[i], "--shutdown") == 0) { + shutdown = 1; + } + + else if (strncmp(argv[i], "-", 1) == 0) { + fatal_command_line("unrecognized option `%s'", argv[i]); + } + else { + fatal_command_line("too many arguments"); + } + } + + /* check the port */ + char * end; + unsigned long numeric_port = strtoul(port, &end, 10); + if (*end != '\0') { + fatal_command_line("--port: option must be an integer"); + } + if (numeric_port > UINT16_MAX) { + fatal_command_line("--port: option must be 16 bits"); + } + + /* is this a shutdown? */ + if (shutdown) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + fatal("could not start Winsock"); + } +#endif + + /* INADDR_LOOPBACK */ + HTTPConnection * connection = HTTPConnection_new_client("127.0.0.1", numeric_port); + if (connection == NULL) { + fatal("could not connect to server"); + } + HTTPExchange * exchange = HTTPExchange_new(connection); + HTTPExchange_set_method(exchange, "POST"); + HTTPExchange_set_request_uri(exchange, "/jscoverage-shutdown"); + if (HTTPExchange_write_request_headers(exchange) != 0) { + fatal("could not write request headers to server"); + } + if (HTTPExchange_read_response_headers(exchange) != 0) { + fatal("could not read response headers from server"); + } + Stream * stream = Stream_new(0); + if (HTTPExchange_read_entire_response_entity_body(exchange, stream) != 0) { + fatal("could not read response body from server"); + } + fwrite(stream->data, 1, stream->length, stdout); + Stream_delete(stream); + HTTPExchange_delete(exchange); + if (HTTPConnection_delete(connection) != 0) { + fatal("could not close connection with server"); + } + exit(EXIT_SUCCESS); + } + + jscoverage_init(); + +#ifndef __MINGW32__ + /* handle broken pipe */ + signal(SIGPIPE, SIG_IGN); +#endif + +#ifdef __MINGW32__ +InitializeCriticalSection(&javascript_mutex); +InitializeCriticalSection(&source_cache_mutex); +#endif + + if (verbose) { + printf("Starting HTTP server on %s:%lu\n", ip_address, numeric_port); + fflush(stdout); + } + HTTPServer_run(ip_address, (uint16_t) numeric_port, handler); + if (verbose) { + printf("Stopping HTTP server\n"); + fflush(stdout); + } + + jscoverage_cleanup(); + + free(no_instrument); + + LOCK(&source_cache_mutex); + while (source_cache != NULL) { + SourceCache * p = source_cache; + source_cache = source_cache->next; + free(p->url); + free(p->characters); + free(p); + } + UNLOCK(&source_cache_mutex); + + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-throbber.gif b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage-throbber.gif new file mode 100644 index 0000000000000000000000000000000000000000..f13c0b4ecc4327d891568b6494d60f0428741094 GIT binary patch literal 425 zcmZ?wbhEHbWM^P!c+AZJ1gxyA3JMB#c6JU94habfwY9Yk4GjwxEI4rBz=H=5{-XlL z|J;7AA;Hd$0j@@R2F#2={fa+X7`Yhu8FWB~fsAEf5&Ph&u(TrN>S}q#&`BOgn?s%^ zhV^T?;!vunS}Ag6b-d=(MIOf|ho~muQL2<$8FFRyeM?aWj}wbSQt>D~sr0mR%9Yjf zPE!>;PBMoq#ivwRwQ38{0bZhx9;cK;R1@$xKqa;6%azshgF*v64mgJ_#iR73%F-$k kU + +#include +#include +#include + +#include "global.h" +#include "instrument.h" +#include "instrument-js.h" +#include "resource-manager.h" +#include "util.h" + +const char * jscoverage_encoding = "ISO-8859-1"; +bool jscoverage_highlight = true; + +int main(int argc, char ** argv) { + int verbose = 0; + + // program = argv[0]; + program = "jscoverage"; + + char * source = NULL; + char * destination = NULL; + + char ** no_instrument = xnew(char *, argc - 1); + int num_no_instrument = 0; + + char ** exclude = xnew(char *, argc - 1); + int num_exclude = 0; + + jscoverage_highlight = false; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { + copy_resource_to_stream("jscoverage-help.txt", stdout); + exit(EXIT_SUCCESS); + } + else if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) { + version(); + } + else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) { + verbose = 1; + } + else if (strcmp(argv[i], "--mozilla") == 0) { + jscoverage_mozilla = true; + jscoverage_set_js_version("180"); + } + else if (strcmp(argv[i], "--no-instrument") == 0) { + i++; + if (i == argc) { + fatal_command_line("--no-instrument: option requires an argument"); + } + no_instrument[num_no_instrument] = argv[i]; + num_no_instrument++; + } + else if (strncmp(argv[i], "--no-instrument=", 16) == 0) { + no_instrument[num_no_instrument] = argv[i] + 16; + num_no_instrument++; + } + else if (strcmp(argv[i], "--exclude") == 0) { + i++; + if (i == argc) { + fatal_command_line("--exclude: option requires an argument"); + } + exclude[num_exclude] = argv[i]; + num_exclude++; + } + else if (strncmp(argv[i], "--exclude=", 10) == 0) { + exclude[num_exclude] = argv[i] + 10; + num_exclude++; + } + else if (strcmp(argv[i], "--encoding") == 0) { + i++; + if (i == argc) { + fatal_command_line("--encoding: option requires an argument"); + } + jscoverage_encoding = argv[i]; + } + else if (strncmp(argv[i], "--encoding=", 11) == 0) { + jscoverage_encoding = argv[i] + 11; + } + else if (strcmp(argv[i], "--js-version") == 0) { + i++; + if (i == argc) { + fatal_command_line("--js-version: option requires an argument"); + } + jscoverage_set_js_version(argv[i]); + } + else if (strncmp(argv[i], "--js-version=", 13) == 0) { + jscoverage_set_js_version(argv[i] + 13); + } + else if (strncmp(argv[i], "-", 1) == 0) { + fatal_command_line("unrecognized option `%s'", argv[i]); + } + else if (source == NULL) { + source = argv[i]; + } + else if (destination == NULL) { + destination = argv[i]; + } + else { + fatal_command_line("too many arguments"); + } + } + + if (source == NULL || destination == NULL) { + fatal_command_line("missing argument"); + } + + source = make_canonical_path(source); + destination = make_canonical_path(destination); + + jscoverage_init(); + jscoverage_instrument(source, destination, verbose, exclude, num_exclude, no_instrument, num_no_instrument); + jscoverage_cleanup(); + + free(source); + free(destination); + free(exclude); + free(no_instrument); + + exit(EXIT_SUCCESS); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.css new file mode 100644 index 0000000..98af69b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.css @@ -0,0 +1,328 @@ +/* + jscoverage.css - code coverage for JavaScript + Copyright (C) 2007, 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +body { + background-color: #bfffbf; + font-family: sans-serif; + font-size: 100%; + margin: 0; +} + +#mainDiv { + font-size: 0.8125em; +} + +#headingDiv { + position: absolute; + top: 0.5em; + left: 1.5em; + right: 1.5em; + bottom: 0; + line-height: 1.5em; +} + +h1 { + float: left; + margin: 0; + padding-bottom: 0.5em; + font-size: 1.3em; +} + +.ProgressBar { + float: left; + visibility: hidden; +} + +.ProgressPercentage { + display: block; + float: left; + width: 5em; + text-align: right; +} + +.ProgressGraph { + float: left; + width: 100px; + height: 10px; + border: 1px solid black; + margin-top: 0.3em; + background-color: #d4d0c8; + overflow: hidden; +} + +.ProgressCovered { + /* windows system color ActiveCaption or Highlight */ + background-color: #0a246a; + width: 0; + height: 10px; + overflow: hidden; +} + +#progressLabel { + display: block; + float: left; + padding-left: 0.3em; +} + +/******************************************************************************* +browser tab +*/ + +input#location, button { + border: 1px solid black; + margin-left: 1px; + margin-right: 1px; +} + +#iframeDiv { + position: absolute; + top: 3.5em; + left: 1em; + right: 1em; + bottom: 1em; +} + +iframe { + width: 100%; + height: 100%; +} + +/******************************************************************************* +summary tab +*/ + +#summaryDiv { + position: absolute; + top: 3em; + left: 1em; + right: 1em; + bottom: 1em; + overflow: auto; +} + +table#summaryTable { + width: 100%; + margin-left: 0px; + margin-right: 0px; + border-collapse: collapse; + font-size: small; +} + +table#summaryTable th, table#summaryTable td { + border-left: 1px solid #d9d9d9; +} + +table#summaryTable th.leftColumn, table#summaryTable td.leftColumn { + border-left-width: 0px; +} + +table#summaryTable th, table#summaryTable td { + padding: 2px; +} + +th { + background-color: #e6ffe6; +} + +td.numeric { + text-align: right; +} + +abbr { + cursor: help; +} + +tr#summaryTotals td.leftColumn span { + float: right; +} +tr#summaryTotals td.leftColumn span.title { + float: left; + font-weight: bold; +} +tr#summaryTotals td { + background-color: #ffd; +} +td.coverage { + width: 150px; +} +td.coverage span { + float: right; + margin-right: 5px; +} +.pctGraph { + width: 100px; + height: 10px; + float: right; + border: 1px solid #000; + background-color: #e00000; + overflow: hidden; + margin-top: 4px; +} +.pctGraph .covered { + background-color: #00f000; + width: 0; + height: 10px; +} +.pctGraph .skipped { + background-color: #d4d0c8; + width: 100px; + height: 10px; +} +tbody#summaryTbody tr.even td { + background-color: #e6ffe6; +} + +/******************************************************************************* +source tab +*/ + +#fileDiv { + font-size: large; + font-weight: bold; +} + +#sourceDiv { + position: absolute; + top: 3em; + left: 1em; + right: 1em; + bottom: 1em; + overflow: auto; +} + +table#sourceTable { + border: 0px; + border-collapse: collapse; + font-size: small; +} + +/* +IE default behavior is to make
 smaller than surrounding text.  Because
+the table already has font-size small, this would make the font-size within the
+
 x-small.  So we don't rely on the default.
+*/
+table#sourceTable pre {
+  font-size: medium;
+}
+
+table#sourceTable td {
+  border: 0px;
+  padding-top: 0px;
+  padding-bottom: 0px;
+  padding-left: 10px;
+  padding-right: 10px;
+}
+
+table#sourceTable pre {
+  border: 0px;
+  margin: 0px;
+}
+
+.g {
+  background-color: #bfffbf;
+}
+
+.y {
+  background-color: #ffffbf;
+}
+
+.r {
+  background-color: #ffbfbf;
+}
+
+/*******************************************************************************
+store tab
+*/
+
+#storeDiv {
+  position: absolute;
+  top: 3em;
+  left: 1em;
+  right: 1em;
+  bottom: 1em;
+  overflow: auto;
+}
+
+/*******************************************************************************
+about tab
+*/
+
+p {
+  margin-top: 0;
+}
+
+/*******************************************************************************
+tabs
+*/
+
+#tabs {
+  position: absolute;
+  top: 3em;
+  left: 1.5em;
+  right: 1.5em;
+  height: 2em;
+}
+
+#tabs div {
+  background-color: white;
+  position: relative;
+  float: left;
+  border: 1px solid black;
+  border-bottom-width: 0;
+  cursor: pointer;
+  margin-left: 0.5em;
+  margin-right: 0.5em;
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  height: 2em;
+  z-index: 1;
+  line-height: 1.8em;
+}
+
+#tabs div.selected {
+  z-index: 3;
+  cursor: default;
+}
+
+#tabs div.disabled {
+  /* windows system color GrayText */
+  color: #808080;
+  cursor: default; 
+}
+
+.TabPage {
+  background-color: white;
+  border: 1px solid black;
+  position: absolute;
+  top: 5em;
+  left: 1.5em;
+  right: 1.5em;
+  bottom: 1.5em;
+  z-index: 2;
+  padding: 1em;
+  display: none;
+}
+
+#tabPages div.selected {
+  display: block;
+}
+
+img {
+  visibility: hidden;
+}
diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.html
new file mode 100644
index 0000000..601f62a
--- /dev/null
+++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.html
@@ -0,0 +1,125 @@
+
+
+
+
+
+JSCoverage
+
+
+
+
+
+
+
+
+
+

JSCoverage

+
+ +
+ +
+
Browser
+
Summary
+
Source
+
Store
+
About
+
+
+
+
+ URL: + +
+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
FileStatementsExecutedCoverage
+ Total: + 0 + 00 +
+
+
+ 0% +
+
+
+
+
+
+
+
+ + loading... +
+
+
+

+ This is version 0.4 of JSCoverage, a program that calculates code + coverage statistics for JavaScript. +

+

+ See http://siliconforks.com/jscoverage/ for more information. +

+

+ Copyright © 2007, 2008 siliconforks.com +

+
+
+
+ + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.js new file mode 100644 index 0000000..9e2ea5b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.js @@ -0,0 +1,1024 @@ +/* + jscoverage.js - code coverage for JavaScript + Copyright (C) 2007, 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/** +Initializes the _$jscoverage object in a window. This should be the first +function called in the page. +@param w this should always be the global window object +*/ +function jscoverage_init(w) { + try { + // in Safari, "import" is a syntax error + Components.utils['import']('resource://gre/modules/jscoverage.jsm'); + jscoverage_isInvertedMode = true; + return; + } + catch (e) {} + + if (w.opener && w.opener.top._$jscoverage) { + // we are in inverted mode + jscoverage_isInvertedMode = true; + if (! w._$jscoverage) { + w._$jscoverage = w.opener.top._$jscoverage; + } + } + else { + // we are not in inverted mode + jscoverage_isInvertedMode = false; + if (! w._$jscoverage) { + w._$jscoverage = {}; + } + } +} + +var jscoverage_currentFile = null; +var jscoverage_currentLine = null; + +var jscoverage_inLengthyOperation = false; + +/* +Possible states: + isInvertedMode isServer isReport tabs +normal false false false Browser +inverted true false false +server, normal false true false Browser, Store +server, inverted true true false Store +report false false true +*/ +var jscoverage_isInvertedMode = false; +var jscoverage_isServer = false; +var jscoverage_isReport = false; + +jscoverage_init(window); + +function jscoverage_createRequest() { + // Note that the IE7 XMLHttpRequest does not support file URL's. + // http://xhab.blogspot.com/2006/11/ie7-support-for-xmlhttprequest.html + // http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx +//#JSCOVERAGE_IF + if (window.ActiveXObject) { + return new ActiveXObject("Microsoft.XMLHTTP"); + } + else { + return new XMLHttpRequest(); + } +} + +// http://www.quirksmode.org/js/findpos.html +function jscoverage_findPos(obj) { + var result = 0; + do { + result += obj.offsetTop; + obj = obj.offsetParent; + } + while (obj); + return result; +} + +// http://www.quirksmode.org/viewport/compatibility.html +function jscoverage_getViewportHeight() { +//#JSCOVERAGE_IF /MSIE/.test(navigator.userAgent) + if (self.innerHeight) { + // all except Explorer + return self.innerHeight; + } + else if (document.documentElement && document.documentElement.clientHeight) { + // Explorer 6 Strict Mode + return document.documentElement.clientHeight; + } + else if (document.body) { + // other Explorers + return document.body.clientHeight; + } + else { + throw "Couldn't calculate viewport height"; + } +//#JSCOVERAGE_ENDIF +} + +/** +Indicates visually that a lengthy operation has begun. The progress bar is +displayed, and the cursor is changed to busy (on browsers which support this). +*/ +function jscoverage_beginLengthyOperation() { + jscoverage_inLengthyOperation = true; + + var progressBar = document.getElementById('progressBar'); + progressBar.style.visibility = 'visible'; + ProgressBar.setPercentage(progressBar, 0); + var progressLabel = document.getElementById('progressLabel'); + progressLabel.style.visibility = 'visible'; + + /* blacklist buggy browsers */ +//#JSCOVERAGE_IF + if (! /Opera|WebKit/.test(navigator.userAgent)) { + /* + Change the cursor style of each element. Note that changing the class of the + element (to one with a busy cursor) is buggy in IE. + */ + var tabs = document.getElementById('tabs').getElementsByTagName('div'); + var i; + for (i = 0; i < tabs.length; i++) { + tabs.item(i).style.cursor = 'wait'; + } + } +} + +/** +Removes the progress bar and busy cursor. +*/ +function jscoverage_endLengthyOperation() { + var progressBar = document.getElementById('progressBar'); + ProgressBar.setPercentage(progressBar, 100); + setTimeout(function() { + jscoverage_inLengthyOperation = false; + progressBar.style.visibility = 'hidden'; + var progressLabel = document.getElementById('progressLabel'); + progressLabel.style.visibility = 'hidden'; + progressLabel.innerHTML = ''; + + var tabs = document.getElementById('tabs').getElementsByTagName('div'); + var i; + for (i = 0; i < tabs.length; i++) { + tabs.item(i).style.cursor = ''; + } + }, 50); +} + +function jscoverage_setSize() { +//#JSCOVERAGE_IF /MSIE/.test(navigator.userAgent) + var viewportHeight = jscoverage_getViewportHeight(); + + /* + border-top-width: 1px + padding-top: 10px + padding-bottom: 10px + border-bottom-width: 1px + margin-bottom: 10px + ---- + 32px + */ + var tabPages = document.getElementById('tabPages'); + var tabPageHeight = (viewportHeight - jscoverage_findPos(tabPages) - 32) + 'px'; + var nodeList = tabPages.childNodes; + var length = nodeList.length; + for (var i = 0; i < length; i++) { + var node = nodeList.item(i); + if (node.nodeType !== 1) { + continue; + } + node.style.height = tabPageHeight; + } + + var iframeDiv = document.getElementById('iframeDiv'); + // may not exist if we have removed the first tab + if (iframeDiv) { + iframeDiv.style.height = (viewportHeight - jscoverage_findPos(iframeDiv) - 21) + 'px'; + } + + var summaryDiv = document.getElementById('summaryDiv'); + summaryDiv.style.height = (viewportHeight - jscoverage_findPos(summaryDiv) - 21) + 'px'; + + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.style.height = (viewportHeight - jscoverage_findPos(sourceDiv) - 21) + 'px'; + + var storeDiv = document.getElementById('storeDiv'); + if (storeDiv) { + storeDiv.style.height = (viewportHeight - jscoverage_findPos(storeDiv) - 21) + 'px'; + } +//#JSCOVERAGE_ENDIF +} + +/** +Returns the boolean value of a string. Values 'false', 'f', 'no', 'n', 'off', +and '0' (upper or lower case) are false. +@param s the string +@return a boolean value +*/ +function jscoverage_getBooleanValue(s) { + s = s.toLowerCase(); + if (s === 'false' || s === 'f' || s === 'no' || s === 'n' || s === 'off' || s === '0') { + return false; + } + return true; +} + +function jscoverage_removeTab(id) { + var tab = document.getElementById(id + 'Tab'); + tab.parentNode.removeChild(tab); + var tabPage = document.getElementById(id + 'TabPage'); + tabPage.parentNode.removeChild(tabPage); +} + +/** +Initializes the contents of the tabs. This sets the initial values of the +input field and iframe in the "Browser" tab and the checkbox in the "Summary" +tab. +@param queryString this should always be location.search +*/ +function jscoverage_initTabContents(queryString) { + var showMissingColumn = false; + var parameters, parameter, i, index, url, name, value; + if (queryString.length > 0) { + // chop off the question mark + queryString = queryString.substring(1); + parameters = queryString.split(/&|;/); + for (i = 0; i < parameters.length; i++) { + parameter = parameters[i]; + index = parameter.indexOf('='); + if (index === -1) { + // still works with old syntax + url = parameter; + } + else { + name = parameter.substr(0, index); + value = parameter.substr(index + 1); + if (name === 'missing' || name === 'm') { + showMissingColumn = jscoverage_getBooleanValue(value); + } + else if (name === 'url' || name === 'u') { + url = value; + } + } + } + } + + var checkbox = document.getElementById('checkbox'); + checkbox.checked = showMissingColumn; + if (showMissingColumn) { + jscoverage_appendMissingColumn(); + } + + // this will automatically propagate to the input field + if (url) { + frames[0].location = url; + } + + // if the browser tab is absent, we have to initialize the summary tab + if (! document.getElementById('browserTab')) { + jscoverage_recalculateSummaryTab(); + } +} + +function jscoverage_body_load() { + var progressBar = document.getElementById('progressBar'); + ProgressBar.init(progressBar); + + function reportError(e) { + jscoverage_endLengthyOperation(); + var summaryThrobber = document.getElementById('summaryThrobber'); + summaryThrobber.style.visibility = 'hidden'; + var div = document.getElementById('summaryErrorDiv'); + div.innerHTML = 'Error: ' + e; + } + + if (jscoverage_isReport) { + jscoverage_beginLengthyOperation(); + var summaryThrobber = document.getElementById('summaryThrobber'); + summaryThrobber.style.visibility = 'visible'; + var request = jscoverage_createRequest(); + try { + request.open('GET', 'jscoverage.json', true); + request.onreadystatechange = function (event) { + if (request.readyState === 4) { + try { + if (request.status !== 0 && request.status !== 200) { + throw request.status; + } + var response = request.responseText; + if (response === '') { + throw 404; + } + var json = eval('(' + response + ')'); + var file; + for (file in json) { + var fileCoverage = json[file]; + _$jscoverage[file] = fileCoverage.coverage; + _$jscoverage[file].source = fileCoverage.source; + } + jscoverage_recalculateSummaryTab(); + summaryThrobber.style.visibility = 'hidden'; + } + catch (e) { + reportError(e); + } + } + }; + request.send(null); + } + catch (e) { + reportError(e); + } + + jscoverage_removeTab('browser'); + jscoverage_removeTab('store'); + } + else { + if (jscoverage_isInvertedMode) { + jscoverage_removeTab('browser'); + } + + if (! jscoverage_isServer) { + jscoverage_removeTab('store'); + } + } + + jscoverage_initTabControl(); + + jscoverage_initTabContents(location.search); +} + +function jscoverage_body_resize() { + if (/MSIE/.test(navigator.userAgent)) { + jscoverage_setSize(); + } +} + +// ----------------------------------------------------------------------------- +// tab 1 + +function jscoverage_updateBrowser() { + var input = document.getElementById("location"); + frames[0].location = input.value; +} + +function jscoverage_input_keypress(e) { + if (e.keyCode === 13) { + jscoverage_updateBrowser(); + } +} + +function jscoverage_button_click() { + jscoverage_updateBrowser(); +} + +function jscoverage_browser_load() { + /* update the input box */ + var input = document.getElementById("location"); + + /* sometimes IE seems to fire this after the tab has been removed */ + if (input) { + input.value = frames[0].location; + } +} + +// ----------------------------------------------------------------------------- +// tab 2 + +function jscoverage_createLink(file, line) { + var link = document.createElement("a"); + + var url; + var call; + var text; + if (line) { + url = file + ".jscoverage.html?" + line; + call = "jscoverage_get('" + file + "', " + line + ");"; + text = line.toString(); + } + else { + url = file + ".jscoverage.html"; + call = "jscoverage_get('" + file + "');"; + text = file; + } + + link.setAttribute('href', 'javascript:' + call); + link.appendChild(document.createTextNode(text)); + + return link; +} + +function jscoverage_recalculateSummaryTab(cc) { + var checkbox = document.getElementById('checkbox'); + var showMissingColumn = checkbox.checked; + + if (! cc) { + cc = window._$jscoverage; + } + if (! cc) { +//#JSCOVERAGE_IF 0 + throw "No coverage information found."; +//#JSCOVERAGE_ENDIF + } + + var tbody = document.getElementById("summaryTbody"); + while (tbody.hasChildNodes()) { + tbody.removeChild(tbody.firstChild); + } + + var totals = { files:0, statements:0, executed:0, coverage:0, skipped:0 }; + + var file; + var files = []; + for (file in cc) { + files.push(file); + } + files.sort(); + + var rowCounter = 0; + for (var f = 0; f < files.length; f++) { + file = files[f]; + var lineNumber; + var num_statements = 0; + var num_executed = 0; + var missing = []; + var fileCC = cc[file]; + var length = fileCC.length; + var currentConditionalEnd = 0; + var conditionals = null; + if (fileCC.conditionals) { + conditionals = fileCC.conditionals; + } + for (lineNumber = 0; lineNumber < length; lineNumber++) { + var n = fileCC[lineNumber]; + + if (lineNumber === currentConditionalEnd) { + currentConditionalEnd = 0; + } + else if (currentConditionalEnd === 0 && conditionals && conditionals[lineNumber]) { + currentConditionalEnd = conditionals[lineNumber]; + } + + if (currentConditionalEnd !== 0) { + continue; + } + + if (n === undefined || n === null) { + continue; + } + + if (n === 0) { + missing.push(lineNumber); + } + else { + num_executed++; + } + num_statements++; + } + + var percentage = ( num_statements === 0 ? 0 : parseInt(100 * num_executed / num_statements) ); + + var row = document.createElement("tr"); + row.className = ( rowCounter++ % 2 == 0 ? "odd" : "even" ); + + var cell = document.createElement("td"); + cell.className = 'leftColumn'; + var link = jscoverage_createLink(file); + cell.appendChild(link); + + row.appendChild(cell); + + cell = document.createElement("td"); + cell.className = 'numeric'; + cell.appendChild(document.createTextNode(num_statements)); + row.appendChild(cell); + + cell = document.createElement("td"); + cell.className = 'numeric'; + cell.appendChild(document.createTextNode(num_executed)); + row.appendChild(cell); + + // new coverage td containing a bar graph + cell = document.createElement("td"); + cell.className = 'coverage'; + var pctGraph = document.createElement("div"), + covered = document.createElement("div"), + pct = document.createElement("span"); + pctGraph.className = "pctGraph"; + if( num_statements === 0 ) { + covered.className = "skipped"; + pct.appendChild(document.createTextNode("N/A")); + } else { + covered.className = "covered"; + covered.style.width = percentage + "px"; + pct.appendChild(document.createTextNode(percentage + '%')); + } + pct.className = "pct"; + pctGraph.appendChild(covered); + cell.appendChild(pctGraph); + cell.appendChild(pct); + row.appendChild(cell); + + if (showMissingColumn) { + cell = document.createElement("td"); + for (var i = 0; i < missing.length; i++) { + if (i !== 0) { + cell.appendChild(document.createTextNode(", ")); + } + link = jscoverage_createLink(file, missing[i]); + cell.appendChild(link); + } + row.appendChild(cell); + } + + tbody.appendChild(row); + + totals['files'] ++; + totals['statements'] += num_statements; + totals['executed'] += num_executed; + totals['coverage'] += percentage; + if( num_statements === 0 ) { + totals['skipped']++; + } + + // write totals data into summaryTotals row + var tr = document.getElementById("summaryTotals"); + if (tr) { + var tds = tr.getElementsByTagName("td"); + tds[0].getElementsByTagName("span")[1].firstChild.nodeValue = totals['files']; + tds[1].firstChild.nodeValue = totals['statements']; + tds[2].firstChild.nodeValue = totals['executed']; + + var coverage = parseInt(totals['coverage'] / ( totals['files'] - totals['skipped'] ) ); + if( isNaN( coverage ) ) { + coverage = 0; + } + tds[3].getElementsByTagName("span")[0].firstChild.nodeValue = coverage + '%'; + tds[3].getElementsByTagName("div")[1].style.width = coverage + 'px'; + } + + } + jscoverage_endLengthyOperation(); +} + +function jscoverage_appendMissingColumn() { + var headerRow = document.getElementById('headerRow'); + var missingHeader = document.createElement('th'); + missingHeader.id = 'missingHeader'; + missingHeader.innerHTML = 'Missing'; + headerRow.appendChild(missingHeader); + var summaryTotals = document.getElementById('summaryTotals'); + var empty = document.createElement('td'); + empty.id = 'missingCell'; + summaryTotals.appendChild(empty); +} + +function jscoverage_removeMissingColumn() { + var missingNode; + missingNode = document.getElementById('missingHeader'); + missingNode.parentNode.removeChild(missingNode); + missingNode = document.getElementById('missingCell'); + missingNode.parentNode.removeChild(missingNode); +} + +function jscoverage_checkbox_click() { + if (jscoverage_inLengthyOperation) { + return false; + } + jscoverage_beginLengthyOperation(); + var checkbox = document.getElementById('checkbox'); + var showMissingColumn = checkbox.checked; + setTimeout(function() { + if (showMissingColumn) { + jscoverage_appendMissingColumn(); + } + else { + jscoverage_removeMissingColumn(); + } + jscoverage_recalculateSummaryTab(); + }, 50); + return true; +} + +// ----------------------------------------------------------------------------- +// tab 3 + +function jscoverage_makeTable() { + var coverage = _$jscoverage[jscoverage_currentFile]; + var lines = coverage.source; + + // this can happen if there is an error in the original JavaScript file + if (! lines) { + lines = []; + } + + var rows = ['']; + var i = 0; + var progressBar = document.getElementById('progressBar'); + var tableHTML; + var currentConditionalEnd = 0; + + function joinTableRows() { + tableHTML = rows.join(''); + ProgressBar.setPercentage(progressBar, 60); + /* + This may be a long delay, so set a timeout of 100 ms to make sure the + display is updated. + */ + setTimeout(appendTable, 100); + } + + function appendTable() { + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.innerHTML = tableHTML; + ProgressBar.setPercentage(progressBar, 80); + setTimeout(jscoverage_scrollToLine, 0); + } + + while (i < lines.length) { + var lineNumber = i + 1; + + if (lineNumber === currentConditionalEnd) { + currentConditionalEnd = 0; + } + else if (currentConditionalEnd === 0 && coverage.conditionals && coverage.conditionals[lineNumber]) { + currentConditionalEnd = coverage.conditionals[lineNumber]; + } + + var row = ''; + row += ''; + var timesExecuted = coverage[lineNumber]; + if (timesExecuted !== undefined && timesExecuted !== null) { + if (currentConditionalEnd !== 0) { + row += ''; + } + else { + row += ''; + } + row += ''; + row += ''; + row += '\n'; + rows[lineNumber] = row; + i++; + } + rows[i + 1] = '
' + lineNumber + ''; + } + else if (timesExecuted === 0) { + row += ''; + } + else { + row += ''; + } + row += timesExecuted; + row += '
' + lines[i] + '
'; + ProgressBar.setPercentage(progressBar, 40); + setTimeout(joinTableRows, 0); +} + +function jscoverage_scrollToLine() { + jscoverage_selectTab('sourceTab'); + if (! window.jscoverage_currentLine) { + jscoverage_endLengthyOperation(); + return; + } + var div = document.getElementById('sourceDiv'); + if (jscoverage_currentLine === 1) { + div.scrollTop = 0; + } + else { + var cell = document.getElementById('line-' + jscoverage_currentLine); + + // this might not be there if there is an error in the original JavaScript + if (cell) { + var divOffset = jscoverage_findPos(div); + var cellOffset = jscoverage_findPos(cell); + div.scrollTop = cellOffset - divOffset; + } + } + jscoverage_currentLine = 0; + jscoverage_endLengthyOperation(); +} + +/** +Loads the given file (and optional line) in the source tab. +*/ +function jscoverage_get(file, line) { + if (jscoverage_inLengthyOperation) { + return; + } + jscoverage_beginLengthyOperation(); + setTimeout(function() { + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.innerHTML = ''; + jscoverage_selectTab('sourceTab'); + if (file === jscoverage_currentFile) { + jscoverage_currentLine = line; + jscoverage_recalculateSourceTab(); + } + else { + if (jscoverage_currentFile === null) { + var tab = document.getElementById('sourceTab'); + tab.className = ''; + tab.onclick = jscoverage_tab_click; + } + jscoverage_currentFile = file; + jscoverage_currentLine = line || 1; // when changing the source, always scroll to top + var fileDiv = document.getElementById('fileDiv'); + fileDiv.innerHTML = jscoverage_currentFile; + jscoverage_recalculateSourceTab(); + return; + } + }, 50); +} + +/** +Calculates coverage statistics for the current source file. +*/ +function jscoverage_recalculateSourceTab() { + if (! jscoverage_currentFile) { + jscoverage_endLengthyOperation(); + return; + } + var progressLabel = document.getElementById('progressLabel'); + progressLabel.innerHTML = 'Calculating coverage ...'; + var progressBar = document.getElementById('progressBar'); + ProgressBar.setPercentage(progressBar, 20); + setTimeout(jscoverage_makeTable, 0); +} + +// ----------------------------------------------------------------------------- +// tabs + +/** +Initializes the tab control. This function must be called when the document is +loaded. +*/ +function jscoverage_initTabControl() { + var tabs = document.getElementById('tabs'); + var i; + var child; + var tabNum = 0; + for (i = 0; i < tabs.childNodes.length; i++) { + child = tabs.childNodes.item(i); + if (child.nodeType === 1) { + if (child.className !== 'disabled') { + child.onclick = jscoverage_tab_click; + } + tabNum++; + } + } + jscoverage_selectTab(0); +} + +/** +Selects a tab. +@param tab the integer index of the tab (0, 1, 2, or 3) + OR + the ID of the tab element + OR + the tab element itself +*/ +function jscoverage_selectTab(tab) { + if (typeof tab !== 'number') { + tab = jscoverage_tabIndexOf(tab); + } + var tabs = document.getElementById('tabs'); + var tabPages = document.getElementById('tabPages'); + var nodeList; + var tabNum; + var i; + var node; + + nodeList = tabs.childNodes; + tabNum = 0; + for (i = 0; i < nodeList.length; i++) { + node = nodeList.item(i); + if (node.nodeType !== 1) { + continue; + } + + if (node.className !== 'disabled') { + if (tabNum === tab) { + node.className = 'selected'; + } + else { + node.className = ''; + } + } + tabNum++; + } + + nodeList = tabPages.childNodes; + tabNum = 0; + for (i = 0; i < nodeList.length; i++) { + node = nodeList.item(i); + if (node.nodeType !== 1) { + continue; + } + + if (tabNum === tab) { + node.className = 'selected TabPage'; + } + else { + node.className = 'TabPage'; + } + tabNum++; + } +} + +/** +Returns an integer (0, 1, 2, or 3) representing the index of a given tab. +@param tab the ID of the tab element + OR + the tab element itself +*/ +function jscoverage_tabIndexOf(tab) { + if (typeof tab === 'string') { + tab = document.getElementById(tab); + } + var tabs = document.getElementById('tabs'); + var i; + var child; + var tabNum = 0; + for (i = 0; i < tabs.childNodes.length; i++) { + child = tabs.childNodes.item(i); + if (child.nodeType === 1) { + if (child === tab) { + return tabNum; + } + tabNum++; + } + } +//#JSCOVERAGE_IF 0 + throw "Tab not found"; +//#JSCOVERAGE_ENDIF +} + +function jscoverage_tab_click(e) { + if (jscoverage_inLengthyOperation) { + return; + } + var target; +//#JSCOVERAGE_IF + if (e) { + target = e.target; + } + else if (window.event) { + // IE + target = window.event.srcElement; + } + if (target.className === 'selected') { + return; + } + jscoverage_beginLengthyOperation(); + setTimeout(function() { + if (target.id === 'summaryTab') { + var tbody = document.getElementById("summaryTbody"); + while (tbody.hasChildNodes()) { + tbody.removeChild(tbody.firstChild); + } + } + else if (target.id === 'sourceTab') { + var sourceDiv = document.getElementById('sourceDiv'); + sourceDiv.innerHTML = ''; + } + jscoverage_selectTab(target); + if (target.id === 'summaryTab') { + jscoverage_recalculateSummaryTab(); + } + else if (target.id === 'sourceTab') { + jscoverage_recalculateSourceTab(); + } + else { + jscoverage_endLengthyOperation(); + } + }, 50); +} + +// ----------------------------------------------------------------------------- +// progress bar + +var ProgressBar = { + init: function(element) { + element._percentage = 0; + + /* doing this via JavaScript crashes Safari */ +/* + var pctGraph = document.createElement('div'); + pctGraph.className = 'pctGraph'; + element.appendChild(pctGraph); + var covered = document.createElement('div'); + covered.className = 'covered'; + pctGraph.appendChild(covered); + var pct = document.createElement('span'); + pct.className = 'pct'; + element.appendChild(pct); +*/ + + ProgressBar._update(element); + }, + setPercentage: function(element, percentage) { + element._percentage = percentage; + ProgressBar._update(element); + }, + _update: function(element) { + var pctGraph = element.getElementsByTagName('div').item(0); + var covered = pctGraph.getElementsByTagName('div').item(0); + var pct = element.getElementsByTagName('span').item(0); + pct.innerHTML = element._percentage.toString() + '%'; + covered.style.width = element._percentage + 'px'; + } +}; + +// ----------------------------------------------------------------------------- +// reports + +function jscoverage_pad(s) { + return '0000'.substr(s.length) + s; +} + +function jscoverage_quote(s) { + return '"' + s.replace(/[\u0000-\u001f"\\\u007f-\uffff]/g, function (c) { + switch (c) { + case '\b': + return '\\b'; + case '\f': + return '\\f'; + case '\n': + return '\\n'; + case '\r': + return '\\r'; + case '\t': + return '\\t'; + // IE doesn't support this + /* + case '\v': + return '\\v'; + */ + case '"': + return '\\"'; + case '\\': + return '\\\\'; + default: + return '\\u' + jscoverage_pad(c.charCodeAt(0).toString(16)); + } + }) + '"'; +} + +function jscoverage_serializeCoverageToJSON() { + var json = []; + for (var file in _$jscoverage) { + var coverage = _$jscoverage[file]; + var array = []; + var length = coverage.length; + for (var line = 0; line < length; line++) { + var value = coverage[line]; + if (value === undefined || value === null) { + value = 'null'; + } + array.push(value); + } + json.push(jscoverage_quote(file) + ':[' + array.join(',') + ']'); + } + return '{' + json.join(',') + '}'; +} + +function jscoverage_storeButton_click() { + if (jscoverage_inLengthyOperation) { + return; + } + + jscoverage_beginLengthyOperation(); + var img = document.getElementById('storeImg'); + img.style.visibility = 'visible'; + + var request = jscoverage_createRequest(); + request.open('POST', '/jscoverage-store', true); + request.onreadystatechange = function (event) { + if (request.readyState === 4) { + var message; + try { + if (request.status !== 200 && request.status !== 201 && request.status !== 204) { + throw request.status; + } + message = request.responseText; + } + catch (e) { + if (e.toString().search(/^\d{3}$/) === 0) { + message = e + ': ' + request.responseText; + } + else { + message = 'Could not connect to server: ' + e; + } + } + + jscoverage_endLengthyOperation(); + var img = document.getElementById('storeImg'); + img.style.visibility = 'hidden'; + + var div = document.getElementById('storeDiv'); + div.appendChild(document.createTextNode(new Date() + ': ' + message)); + div.appendChild(document.createElement('br')); + } + }; + request.setRequestHeader('Content-Type', 'application/json'); + var json = jscoverage_serializeCoverageToJSON(); + request.setRequestHeader('Content-Length', json.length.toString()); + request.send(json); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.jsm b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.jsm new file mode 100644 index 0000000..053691c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.jsm @@ -0,0 +1,22 @@ +/* + jscoverage.jsm - Firefox module + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +var EXPORTED_SYMBOLS = ['_$jscoverage']; + +var _$jscoverage = {}; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.manifest b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.manifest new file mode 100644 index 0000000..a0f3d9f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.manifest @@ -0,0 +1,2 @@ +content jscoverage jscoverage/ +overlay chrome://browser/content/browser.xul chrome://jscoverage/content/jscoverage.xul diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.xul b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.xul new file mode 100644 index 0000000..c7296b2 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/jscoverage.xul @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/iconv.m4 b/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/iconv.m4 new file mode 100644 index 0000000..66bc76f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/iconv.m4 @@ -0,0 +1,180 @@ +# iconv.m4 serial AM6 (gettext-0.17) +dnl Copyright (C) 2000-2002, 2007 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], +[ + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([iconv]) +]) + +AC_DEFUN([AM_ICONV_LINK], +[ + dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and + dnl those with the standalone portable GNU libiconv installed). + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + + dnl Add $INCICONV to CPPFLAGS before performing the following checks, + dnl because if the user has installed libiconv and not disabled its use + dnl via --without-libiconv-prefix, he wants to use it. The first + dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. + am_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) + + AC_CACHE_CHECK([for iconv], am_cv_func_iconv, [ + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + AC_TRY_LINK([#include +#include ], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + am_cv_func_iconv=yes) + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include +#include ], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + am_cv_lib_iconv=yes + am_cv_func_iconv=yes) + LIBS="$am_save_LIBS" + fi + ]) + if test "$am_cv_func_iconv" = yes; then + AC_CACHE_CHECK([for working iconv], am_cv_func_iconv_works, [ + dnl This tests against bugs in AIX 5.1 and HP-UX 11.11. + am_save_LIBS="$LIBS" + if test $am_cv_lib_iconv = yes; then + LIBS="$LIBS $LIBICONV" + fi + AC_TRY_RUN([ +#include +#include +int main () +{ + /* Test against AIX 5.1 bug: Failures are not distinguishable from successful + returns. */ + { + iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); + if (cd_utf8_to_88591 != (iconv_t)(-1)) + { + static const char input[] = "\342\202\254"; /* EURO SIGN */ + char buf[10]; + const char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_utf8_to_88591, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + return 1; + } + } +#if 0 /* This bug could be worked around by the caller. */ + /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + char buf[50]; + const char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_88591_to_utf8, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if ((int)res > 0) + return 1; + } + } +#endif + /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is + provided. */ + if (/* Try standardized names. */ + iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) + /* Try IRIX, OSF/1 names. */ + && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) + /* Try AIX names. */ + && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) + /* Try HP-UX names. */ + && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) + return 1; + return 0; +}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no], + [case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac]) + LIBS="$am_save_LIBS" + ]) + case "$am_cv_func_iconv_works" in + *no) am_func_iconv=no am_cv_lib_iconv=no ;; + *) am_func_iconv=yes ;; + esac + else + am_func_iconv=no am_cv_lib_iconv=no + fi + if test "$am_func_iconv" = yes; then + AC_DEFINE(HAVE_ICONV, 1, + [Define if you have the iconv() function and it works.]) + fi + if test "$am_cv_lib_iconv" = yes; then + AC_MSG_CHECKING([how to link with libiconv]) + AC_MSG_RESULT([$LIBICONV]) + else + dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV + dnl either. + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + AC_SUBST(LIBICONV) + AC_SUBST(LTLIBICONV) +]) + +AC_DEFUN([AM_ICONV], +[ + AM_ICONV_LINK + if test "$am_cv_func_iconv" = yes; then + AC_MSG_CHECKING([for iconv declaration]) + AC_CACHE_VAL(am_cv_proto_iconv, [ + AC_TRY_COMPILE([ +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif +], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) + am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + AC_MSG_RESULT([$]{ac_t:- + }[$]am_cv_proto_iconv) + AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, + [Define as const if the declaration of iconv() needs const.]) + fi +]) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-ld.m4 b/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-ld.m4 new file mode 100644 index 0000000..96c4e2c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-ld.m4 @@ -0,0 +1,110 @@ +# lib-ld.m4 serial 3 (gettext-0.13) +dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Subroutines of libtool.m4, +dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision +dnl with libtool.m4. + +dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. +AC_DEFUN([AC_LIB_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +case `$LD -v 2>&1 conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + [re_direlt='/[^/][^/]*/\.\./'] + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(acl_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break ;; + *) + test "$with_gnu_ld" != yes && break ;; + esac + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$acl_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_LIB_PROG_LD_GNU +]) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-link.m4 b/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-link.m4 new file mode 100644 index 0000000..e3d26fc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-link.m4 @@ -0,0 +1,709 @@ +# lib-link.m4 serial 13 (gettext-0.17) +dnl Copyright (C) 2001-2007 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_PREREQ(2.54) + +dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and +dnl augments the CPPFLAGS variable. +dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname +dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + ac_cv_lib[]Name[]_libs="$LIB[]NAME" + ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" + ac_cv_lib[]Name[]_cppflags="$INC[]NAME" + ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX" + ]) + LIB[]NAME="$ac_cv_lib[]Name[]_libs" + LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" + INC[]NAME="$ac_cv_lib[]Name[]_cppflags" + LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + AC_SUBST([LIB]NAME[_PREFIX]) + dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the + dnl results of this search when this library appears as a dependency. + HAVE_LIB[]NAME=yes + undefine([Name]) + undefine([NAME]) +]) + +dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) +dnl searches for libname and the libraries corresponding to explicit and +dnl implicit dependencies, together with the specified include files and +dnl the ability to compile and link the specified testcode. If found, it +dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and +dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and +dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs +dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. +dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname +dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + + dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + + dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, + dnl because if the user has installed lib[]Name and not disabled its use + dnl via --without-lib[]Name-prefix, he wants to use it. + ac_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + + AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIB[]NAME" + AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) + LIBS="$ac_save_LIBS" + ]) + if test "$ac_cv_lib[]Name" = yes; then + HAVE_LIB[]NAME=yes + AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) + AC_MSG_CHECKING([how to link with lib[]$1]) + AC_MSG_RESULT([$LIB[]NAME]) + else + HAVE_LIB[]NAME=no + dnl If $LIB[]NAME didn't lead to a usable library, we don't need + dnl $INC[]NAME either. + CPPFLAGS="$ac_save_CPPFLAGS" + LIB[]NAME= + LTLIB[]NAME= + LIB[]NAME[]_PREFIX= + fi + AC_SUBST([HAVE_LIB]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + AC_SUBST([LIB]NAME[_PREFIX]) + undefine([Name]) + undefine([NAME]) +]) + +dnl Determine the platform dependent parameters needed to use rpath: +dnl acl_libext, +dnl acl_shlibext, +dnl acl_hardcode_libdir_flag_spec, +dnl acl_hardcode_libdir_separator, +dnl acl_hardcode_direct, +dnl acl_hardcode_minus_L. +AC_DEFUN([AC_LIB_RPATH], +[ + dnl Tell automake >= 1.10 to complain if config.rpath is missing. + m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) + AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS + AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir + AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + ]) + wl="$acl_cv_wl" + acl_libext="$acl_cv_libext" + acl_shlibext="$acl_cv_shlibext" + acl_libname_spec="$acl_cv_libname_spec" + acl_library_names_spec="$acl_cv_library_names_spec" + acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + acl_hardcode_direct="$acl_cv_hardcode_direct" + acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" + dnl Determine whether the user wants rpath handling at all. + AC_ARG_ENABLE(rpath, + [ --disable-rpath do not hardcode runtime library paths], + :, enable_rpath=yes) +]) + +dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. +dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found +dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_LINKFLAGS_BODY], +[ + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + dnl Autoconf >= 2.61 supports dots in --with options. + define([N_A_M_E],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit([$1],[.],[_])],[$1])]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib]N_A_M_E[-prefix], +[ --with-lib]N_A_M_E[-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib + --without-lib]N_A_M_E[-prefix don't search for lib$1 in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi +]) + dnl Search the library and its dependencies in $additional_libdir and + dnl $LDFLAGS. Using breadth-first-seach. + LIB[]NAME= + LTLIB[]NAME= + INC[]NAME= + LIB[]NAME[]_PREFIX= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='$1 $2' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + dnl See if it was already located by an earlier AC_LIB_LINKFLAGS + dnl or AC_LIB_HAVE_LINKFLAGS call. + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" + else + dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined + dnl that this library doesn't exist. So just drop it. + : + fi + else + dnl Search the library lib$name in $additional_libdir and $LDFLAGS + dnl and the already constructed $LIBNAME/$LTLIBNAME. + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + dnl The same code as in the loop below: + dnl First look for a shared library. + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + dnl Then look for a static library. + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + dnl First look for a shared library. + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + dnl Then look for a static library. + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + dnl Found the library. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + dnl Linking with a shared library. We attempt to hardcode its + dnl directory into the executable's runpath, unless it's the + dnl standard /usr/lib. + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then + dnl No hardcoding is needed. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + dnl The hardcoding into $LIBNAME is system dependent. + if test "$acl_hardcode_direct" = yes; then + dnl Using DIR/libNAME.so during linking hardcodes DIR into the + dnl resulting binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + dnl Rely on "-L$found_dir". + dnl But don't add it if it's already contained in the LDFLAGS + dnl or the already constructed $LIBNAME + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH + dnl here, because this doesn't fit in flags passed to the + dnl compiler. So give up. No hardcoding. This affects only + dnl very old systems. + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + dnl Linking with a static library. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" + else + dnl We shouldn't come here, but anyway it's good to have a + dnl fallback. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" + fi + fi + dnl Assume the include files are nearby. + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + LIB[]NAME[]_PREFIX="$basedir" + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + dnl Potentially add $additional_includedir to $INCNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's /usr/local/include and we are using GCC on Linux, + dnl 3. if it's already present in $CPPFLAGS or the already + dnl constructed $INCNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INC[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $INCNAME. + INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + dnl Look for dependencies. + if test -n "$found_la"; then + dnl Read the .la file. It defines the variables + dnl dlname, library_names, old_library, dependency_libs, current, + dnl age, revision, installed, dlopen, dlpreopen, libdir. + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + dnl We use only dependency_libs. + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's /usr/local/lib and we are using GCC on Linux, + dnl 3. if it's already present in $LDFLAGS or the already + dnl constructed $LIBNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LIBNAME. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LTLIBNAME. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + dnl Handle this in the next round. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + dnl Handle this in the next round. Throw away the .la's + dnl directory; it is already contained in a preceding -L + dnl option. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + dnl Most likely an immediate library name. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" + ;; + esac + done + fi + else + dnl Didn't find the library; assume it is in the system directories + dnl known to the linker and runtime loader. (All the system + dnl directories known to the linker should also be known to the + dnl runtime loader, otherwise the system is severely misconfigured.) + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user must + dnl pass all path elements in one option. We can arrange that for a + dnl single library, but not when more than one $LIBNAMEs are used. + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + else + dnl The -rpath options are cumulative. + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + dnl When using libtool, the option that works for both libraries and + dnl executables is -R. The -R options are cumulative. + for found_dir in $ltrpathdirs; do + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" + done + fi +]) + +dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, +dnl unless already present in VAR. +dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes +dnl contains two or three consecutive elements that belong together. +AC_DEFUN([AC_LIB_APPENDTOVAR], +[ + for element in [$2]; do + haveit= + for x in $[$1]; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + [$1]="${[$1]}${[$1]:+ }$element" + fi + done +]) + +dnl For those cases where a variable contains several -L and -l options +dnl referring to unknown libraries and directories, this macro determines the +dnl necessary additional linker options for the runtime path. +dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) +dnl sets LDADDVAR to linker options needed together with LIBSVALUE. +dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, +dnl otherwise linking without libtool is assumed. +AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], +[ + AC_REQUIRE([AC_LIB_RPATH]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + $1= + if test "$enable_rpath" != no; then + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode directories into the resulting + dnl binary. + rpathdirs= + next= + for opt in $2; do + if test -n "$next"; then + dir="$next" + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem"; then + rpathdirs="$rpathdirs $dir" + fi + next= + else + case $opt in + -L) next=yes ;; + -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem"; then + rpathdirs="$rpathdirs $dir" + fi + next= ;; + *) next= ;; + esac + fi + done + if test "X$rpathdirs" != "X"; then + if test -n ""$3""; then + dnl libtool is used for linking. Use -R options. + for dir in $rpathdirs; do + $1="${$1}${$1:+ }-R$dir" + done + else + dnl The linker is used for linking directly. + if test -n "$acl_hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user + dnl must pass all path elements in one option. + alldirs= + for dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="$flag" + else + dnl The -rpath options are cumulative. + for dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="${$1}${$1:+ }$flag" + done + fi + fi + fi + fi + fi + AC_SUBST([$1]) +]) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-prefix.m4 b/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-prefix.m4 new file mode 100644 index 0000000..a8684e1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/m4/lib-prefix.m4 @@ -0,0 +1,185 @@ +# lib-prefix.m4 serial 5 (gettext-0.15) +dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and +dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't +dnl require excessive bracketing. +ifdef([AC_HELP_STRING], +[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], +[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) + +dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed +dnl to access previously installed libraries. The basic assumption is that +dnl a user will want packages to use other packages he previously installed +dnl with the same --prefix option. +dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate +dnl libraries, but is otherwise very convenient. +AC_DEFUN([AC_LIB_PREFIX], +[ + AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib-prefix], +[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib + --without-lib-prefix don't search for libraries in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi +]) + if test $use_additional = yes; then + dnl Potentially add $additional_includedir to $CPPFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's already present in $CPPFLAGS, + dnl 3. if it's /usr/local/include and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + for x in $CPPFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $CPPFLAGS. + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" + fi + fi + fi + fi + dnl Potentially add $additional_libdir to $LDFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's already present in $LDFLAGS, + dnl 3. if it's /usr/local/lib and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + for x in $LDFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LDFLAGS. + LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" + fi + fi + fi + fi + fi +]) + +dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, +dnl acl_final_exec_prefix, containing the values to which $prefix and +dnl $exec_prefix will expand at the end of the configure script. +AC_DEFUN([AC_LIB_PREPARE_PREFIX], +[ + dnl Unfortunately, prefix and exec_prefix get only finally determined + dnl at the end of configure. + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the +dnl variables prefix and exec_prefix bound to the values they will have +dnl at the end of the configure script. +AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], +[ + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + $1 + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing +dnl the basename of the libdir, either "lib" or "lib64". +AC_DEFUN([AC_LIB_PREPARE_MULTILIB], +[ + dnl There is no formal standard regarding lib and lib64. The current + dnl practice is that on a system supporting 32-bit and 64-bit instruction + dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit + dnl libraries go under $prefix/lib. We determine the compiler's default + dnl mode by looking at the compiler's library search path. If at least + dnl of its elements ends in /lib64 or points to a directory whose absolute + dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the + dnl default, namely "lib". + acl_libdirstem=lib + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi +]) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/make-bin-dist.sh.in b/bruml/lib/socket.io/support/expresso/deps/jscoverage/make-bin-dist.sh.in new file mode 100644 index 0000000..16bde27 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/make-bin-dist.sh.in @@ -0,0 +1,24 @@ +#!/bin/sh + +set -e + +version=@VERSION@ +distdir=jscoverage-${version} +zipfile=${distdir}-windows.zip + +rm -fr $distdir +mkdir $distdir + +cp -a doc $distdir +cp -a jscoverage.exe jscoverage-server.exe $distdir +strip $distdir/*.exe +cp -a COPYING $distdir +unix2dos $distdir/COPYING +cp -a README $distdir/README.txt +unix2dos $distdir/README.txt + +timestamp=`cat TIMESTAMP` +find $distdir -exec touch -d "$timestamp" {} \; + +rm -f $zipfile +zip -X -r $zipfile $distdir -x '*/.svn/*' diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/make-dist.sh.in b/bruml/lib/socket.io/support/expresso/deps/jscoverage/make-dist.sh.in new file mode 100644 index 0000000..f0a4282 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/make-dist.sh.in @@ -0,0 +1,43 @@ +#!/bin/sh + +set -e + +version=@VERSION@ +distdir=jscoverage-${version} + +rm -fr $distdir +mkdir $distdir + +# copy all files in SVN +for file in $(svn status -qv | sed 's/.* //' | sort) +do + if [ -f "$file" ] + then + cp -a --parents "$file" $distdir + fi +done + +# add generated files +cp -a --parents aclocal.m4 \ + configure \ + config.h.in \ + Makefile.in config.guess config.sub depcomp install-sh missing \ + $distdir +cp -a --parents tests/Makefile.in $distdir +cp -a --parents doc/instrumented $distdir +cp -a --parents doc/instrumented-inverted $distdir + +# remove unnecessary files +rm $distdir/TIMESTAMP +rm $distdir/bootstrap.sh +rm $distdir/make-maintainer-clean.sh +rm -r $distdir/scriptaculous* +rm -r $distdir/selenium + +timestamp=`cat TIMESTAMP` +find $distdir -exec touch -d "$timestamp" {} \; + +tarfile=${distdir}.tar +tar cvf $tarfile --owner=root --group=root $distdir +bzip2 -c $tarfile > ${tarfile}.bz2 +lzma -c $tarfile > ${tarfile}.lzma diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/missing b/bruml/lib/socket.io/support/expresso/deps/jscoverage/missing new file mode 100755 index 0000000..1c8ff70 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/missing @@ -0,0 +1,367 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2006-05-10.23 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case $1 in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $1 in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/report.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/report.js new file mode 100644 index 0000000..13ce04a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/report.js @@ -0,0 +1,76 @@ +if (! window.jscoverage_report) { + window.jscoverage_report = function jscoverage_report(dir) { + var createRequest = function () { + if (window.XMLHttpRequest) { + return new XMLHttpRequest(); + } + else if (window.ActiveXObject) { + return new ActiveXObject("Microsoft.XMLHTTP"); + } + }; + + var pad = function (s) { + return '0000'.substr(s.length) + s; + }; + + var quote = function (s) { + return '"' + s.replace(/[\u0000-\u001f"\\\u007f-\uffff]/g, function (c) { + switch (c) { + case '\b': + return '\\b'; + case '\f': + return '\\f'; + case '\n': + return '\\n'; + case '\r': + return '\\r'; + case '\t': + return '\\t'; + // IE doesn't support this + /* + case '\v': + return '\\v'; + */ + case '"': + return '\\"'; + case '\\': + return '\\\\'; + default: + return '\\u' + pad(c.charCodeAt(0).toString(16)); + } + }) + '"'; + }; + + var json = []; + for (var file in top._$jscoverage) { + var coverage = top._$jscoverage[file]; + var array = []; + var length = coverage.length; + for (var line = 0; line < length; line++) { + var value = coverage[line]; + if (value === undefined || value === null) { + value = 'null'; + } + array.push(value); + } + json.push(quote(file) + ':[' + array.join(',') + ']'); + } + json = '{' + json.join(',') + '}'; + + var request = createRequest(); + var url = '/jscoverage-store'; + if (dir) { + url += '/' + encodeURIComponent(dir); + } + request.open('POST', url, false); + request.setRequestHeader('Content-Type', 'application/json'); + request.setRequestHeader('Content-Length', json.length.toString()); + request.send(json); + if (request.status === 200 || request.status === 201 || request.status === 204) { + return request.responseText; + } + else { + throw request.status; + } + }; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/resource-manager.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/resource-manager.c new file mode 100644 index 0000000..e8e8885 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/resource-manager.c @@ -0,0 +1,59 @@ +/* + resource-manager.c - handles embedded files + Copyright (C) 2007, 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include "resource-manager.h" + +#include +#include +#include + +#include "util.h" + +#include "resources.c" + +const struct Resource * get_resource(const char * name) { + int num_resources = sizeof(RESOURCES) / sizeof(struct Resource); + for (int i = 0; i < num_resources; i++) { + if (strcmp(RESOURCES[i].name, name) == 0) { + return &RESOURCES[i]; + } + } + return NULL; +} + +void copy_resource_to_stream(const char * resource, FILE * stream) { + const struct Resource * r = get_resource(resource); + assert(r != NULL); + if (fwrite(r->data, 1, r->length, stream) != r->length) { + fatal("cannot write to stream"); + } +} + +void copy_resource(const char * resource, const char * destination_directory) { + char * file = make_path(destination_directory, resource); + char * directory = make_dirname(file); + mkdirs(directory); + free(directory); + FILE * f = xfopen(file, "wb"); + copy_resource_to_stream(resource, f); + fclose(f); + free(file); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/resource-manager.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/resource-manager.h new file mode 100644 index 0000000..5a0a681 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/resource-manager.h @@ -0,0 +1,46 @@ +/* + resource-manager.h - handles embedded files + Copyright (C) 2007, 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef RESOURCE_MANAGER_H_ +#define RESOURCE_MANAGER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct Resource { + const char * name; + const unsigned char * data; + const size_t length; +}; + +const struct Resource * get_resource(const char * name); + +void copy_resource_to_stream(const char * resource, FILE * stream); + +void copy_resource(const char * resource, const char * destination_directory); + +#ifdef __cplusplus +} +#endif + +#endif /* RESOURCE_MANAGER_H_ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/stream.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/stream.c new file mode 100644 index 0000000..cc6adc0 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/stream.c @@ -0,0 +1,129 @@ +/* + stream.c - `Stream' object + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#define _GNU_SOURCE + +#include + +#include "stream.h" + +#include +#include +#include + +#include "util.h" + +Stream * Stream_new(size_t capacity) { + Stream * result = xmalloc(sizeof(Stream)); + result->length = 0; + if (capacity == 0) { + capacity = 8192; + } + result->capacity = capacity; + result->data = xmalloc(capacity); + return result; +} + +void Stream_write(Stream * stream, const void * p, size_t size) { + size_t stream_length = stream->length; + size_t stream_capacity = stream->capacity; + if (stream_capacity - stream_length < size) { + if (SIZE_MAX - size < stream_length) { + fatal("out of memory"); + } + + if (SIZE_MAX / 2 < stream_capacity) { + stream_capacity = SIZE_MAX; + } + else { + stream_capacity *= 2; + } + + size_t new_length = stream_length + size; + if (stream_capacity < new_length) { + stream_capacity = new_length; + } + + stream->data = xrealloc(stream->data, stream_capacity); + stream->capacity = stream_capacity; + memcpy(stream->data + stream_length, p, size); + stream->length = new_length; + } + else { + memcpy(stream->data + stream_length, p, size); + stream->length = stream_length + size; + } +} + +void Stream_write_string(Stream * stream, const char * s) { + Stream_write(stream, s, strlen(s)); +} + +void Stream_write_char(Stream * stream, char c) { + size_t stream_length = stream->length; + if (stream_length == stream->capacity) { + if (stream->capacity == SIZE_MAX) { + fatal("out of memory"); + } + + if (SIZE_MAX / 2 < stream->capacity) { + stream->capacity = SIZE_MAX; + } + else { + stream->capacity *= 2; + } + + stream->data = xrealloc(stream->data, stream->capacity); + } + stream->data[stream_length] = c; + stream->length = stream_length + 1; +} + +void Stream_printf(Stream * stream, const char * format, ...) { + va_list a; + va_start(a, format); + + char * s = NULL; + /* note that size does not include the NUL character */ + int size = vasprintf(&s, format, a); + if (size < 0) { + fatal("out of memory"); + } + Stream_write(stream, s, size); + free(s); + + va_end(a); +} + +void Stream_write_file_contents(Stream * stream, FILE * f) { + char buffer[8192]; + size_t bytes_read; + while ((bytes_read = fread(buffer, 1, 8192, f)) > 0) { + Stream_write(stream, buffer, bytes_read); + } +} + +void Stream_delete(Stream * stream) { + free(stream->data); + free(stream); +} + +void Stream_reset(Stream * stream) { + stream->length = 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/stream.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/stream.h new file mode 100644 index 0000000..41c376f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/stream.h @@ -0,0 +1,57 @@ +/* + stream.h - `Stream' object + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef STREAM_H_ +#define STREAM_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Stream { + uint8_t * data; + size_t length; + size_t capacity; +} Stream; + +Stream * Stream_new(size_t capacity); + +void Stream_write(Stream * stream, const void * p, size_t size); + +void Stream_write_string(Stream * stream, const char * s); + +void Stream_write_char(Stream * stream, char c); + +void Stream_printf(Stream * stream, const char * format, ...) __attribute__((format(printf, 2, 3))); + +void Stream_write_file_contents(Stream * stream, FILE * f); + +void Stream_reset(Stream * stream); + +void Stream_delete(Stream * stream); + +#ifdef __cplusplus +} +#endif + +#endif /* STREAM_H_ */ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/Makefile.am b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/Makefile.am new file mode 100644 index 0000000..c58d2a3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/Makefile.am @@ -0,0 +1,130 @@ +# Makefile.am - build tests +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +noinst_PROGRAMS = asprintf \ + encodings \ + gethostbyname \ + http-client-bad-body \ + http-client-bad-url \ + http-client-close-after-request \ + http-server-bad-body \ + http-server-bad-headers \ + http-server-charset \ + http-server-chunked \ + http-server-close-immediately \ + json \ + mkdirs \ + recursive-dir-list \ + streams + +AM_CFLAGS = @XP_DEF@ -I../js -I../js/obj +AM_CXXFLAGS = @XP_DEF@ -I../js -I../js/obj + +asprintf_SOURCES = asprintf.c ../util.c + +encodings_SOURCES = encodings.c ../encoding.c ../util.c +encodings_LDADD = @LIBICONV@ + +gethostbyname_SOURCES = gethostbyname.c ../http-host.c ../util.c +gethostbyname_LDADD = @EXTRA_SOCKET_LIBS@ + +http_client_bad_body_SOURCES = http-client-bad-body.c ../http-url.c ../util.c +http_client_bad_body_LDADD = @EXTRA_SOCKET_LIBS@ + +http_client_bad_url_SOURCES = http-client-bad-url.c ../util.c +http_client_bad_url_LDADD = @EXTRA_SOCKET_LIBS@ + +http_client_close_after_request_LDADD = @EXTRA_SOCKET_LIBS@ + +http_server_bad_body_LDADD = @EXTRA_SOCKET_LIBS@ + +http_server_bad_headers_LDADD = @EXTRA_SOCKET_LIBS@ + +http_server_charset_SOURCES = http-server-charset.c ../stream.c ../util.c +http_server_charset_LDADD = @EXTRA_SOCKET_LIBS@ + +http_server_chunked_SOURCES = http-server-chunked.c ../stream.c ../util.c +http_server_chunked_LDADD = @EXTRA_SOCKET_LIBS@ + +http_server_close_immediately_LDADD = @EXTRA_SOCKET_LIBS@ + +json_SOURCES = json.c ../encoding.c ../highlight.c ../instrument-js.cpp ../resource-manager.c ../stream.c ../util.c +json_LDADD = ../js/obj/libjs.a -lm @LIBICONV@ @EXTRA_TIMER_LIBS@ + +mkdirs_SOURCES = mkdirs.c ../util.c + +recursive_dir_list_SOURCES = recursive-dir-list.c ../util.c + +streams_SOURCES = streams.c ../stream.c ../util.c + +TESTS = encodings.sh \ + fatal.sh \ + help.sh \ + invalid-option.sh \ + javascript.sh \ + javascript-ignore.sh \ + javascript-utf-8.sh \ + no-arguments.sh \ + recursive.sh \ + recursive-crlf.sh \ + recursive-exclude.sh \ + recursive-fatal.sh \ + recursive-no-instrument.sh \ + same-directory.sh \ + version.sh \ + asprintf.sh \ + mkdirs.sh \ + recursive-dir-list.sh \ + streams.sh \ + charset.sh \ + chunked.sh \ + gethostbyname.sh \ + json.sh \ + proxy.sh \ + proxy-bad-request-body.sh \ + proxy-bad-response-body.sh \ + proxy-bad-response-body-javascript.sh \ + proxy-bad-response-headers.sh \ + proxy-no-server.sh \ + proxy-url.sh \ + server.sh \ + server-bad-requests.sh \ + server-close-after-request.sh \ + server-content-types.sh \ + server-directory-listing.sh \ + server-directory-redirect.sh \ + server-encoded-url.sh \ + server-error.sh \ + server-help.sh \ + server-ip-address.sh \ + server-shutdown.sh \ + server-shutdown-bad-method.sh \ + server-special-file.sh \ + server-unreadable-directory.sh \ + server-unreadable-file.sh \ + server-verbose.sh \ + server-version.sh \ + store.sh \ + store-bad-json.sh \ + store-bad-request-body.sh \ + store-bad-response-headers.sh \ + store-escaped-characters.sh \ + store-server-bad-body.sh \ + store-server-closes-immediately.sh \ + store-source-not-found.sh \ + store-unreadable-json.sh \ + store-unwritable-json.sh diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/Makefile.in b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/Makefile.in new file mode 100644 index 0000000..bbe0402 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/Makefile.in @@ -0,0 +1,846 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am - build tests +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = asprintf$(EXEEXT) encodings$(EXEEXT) \ + gethostbyname$(EXEEXT) http-client-bad-body$(EXEEXT) \ + http-client-bad-url$(EXEEXT) \ + http-client-close-after-request$(EXEEXT) \ + http-server-bad-body$(EXEEXT) http-server-bad-headers$(EXEEXT) \ + http-server-charset$(EXEEXT) http-server-chunked$(EXEEXT) \ + http-server-close-immediately$(EXEEXT) json$(EXEEXT) \ + mkdirs$(EXEEXT) recursive-dir-list$(EXEEXT) streams$(EXEEXT) +subdir = tests +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am_asprintf_OBJECTS = asprintf.$(OBJEXT) util.$(OBJEXT) +asprintf_OBJECTS = $(am_asprintf_OBJECTS) +asprintf_LDADD = $(LDADD) +am_encodings_OBJECTS = encodings.$(OBJEXT) encoding.$(OBJEXT) \ + util.$(OBJEXT) +encodings_OBJECTS = $(am_encodings_OBJECTS) +encodings_DEPENDENCIES = +am_gethostbyname_OBJECTS = gethostbyname.$(OBJEXT) http-host.$(OBJEXT) \ + util.$(OBJEXT) +gethostbyname_OBJECTS = $(am_gethostbyname_OBJECTS) +gethostbyname_DEPENDENCIES = +am_http_client_bad_body_OBJECTS = http-client-bad-body.$(OBJEXT) \ + http-url.$(OBJEXT) util.$(OBJEXT) +http_client_bad_body_OBJECTS = $(am_http_client_bad_body_OBJECTS) +http_client_bad_body_DEPENDENCIES = +am_http_client_bad_url_OBJECTS = http-client-bad-url.$(OBJEXT) \ + util.$(OBJEXT) +http_client_bad_url_OBJECTS = $(am_http_client_bad_url_OBJECTS) +http_client_bad_url_DEPENDENCIES = +http_client_close_after_request_SOURCES = \ + http-client-close-after-request.c +http_client_close_after_request_OBJECTS = \ + http-client-close-after-request.$(OBJEXT) +http_client_close_after_request_DEPENDENCIES = +http_server_bad_body_SOURCES = http-server-bad-body.c +http_server_bad_body_OBJECTS = http-server-bad-body.$(OBJEXT) +http_server_bad_body_DEPENDENCIES = +http_server_bad_headers_SOURCES = http-server-bad-headers.c +http_server_bad_headers_OBJECTS = http-server-bad-headers.$(OBJEXT) +http_server_bad_headers_DEPENDENCIES = +am_http_server_charset_OBJECTS = http-server-charset.$(OBJEXT) \ + stream.$(OBJEXT) util.$(OBJEXT) +http_server_charset_OBJECTS = $(am_http_server_charset_OBJECTS) +http_server_charset_DEPENDENCIES = +am_http_server_chunked_OBJECTS = http-server-chunked.$(OBJEXT) \ + stream.$(OBJEXT) util.$(OBJEXT) +http_server_chunked_OBJECTS = $(am_http_server_chunked_OBJECTS) +http_server_chunked_DEPENDENCIES = +http_server_close_immediately_SOURCES = \ + http-server-close-immediately.c +http_server_close_immediately_OBJECTS = \ + http-server-close-immediately.$(OBJEXT) +http_server_close_immediately_DEPENDENCIES = +am_json_OBJECTS = json.$(OBJEXT) encoding.$(OBJEXT) \ + highlight.$(OBJEXT) instrument-js.$(OBJEXT) \ + resource-manager.$(OBJEXT) stream.$(OBJEXT) util.$(OBJEXT) +json_OBJECTS = $(am_json_OBJECTS) +json_DEPENDENCIES = ../js/obj/libjs.a +am_mkdirs_OBJECTS = mkdirs.$(OBJEXT) util.$(OBJEXT) +mkdirs_OBJECTS = $(am_mkdirs_OBJECTS) +mkdirs_LDADD = $(LDADD) +am_recursive_dir_list_OBJECTS = recursive-dir-list.$(OBJEXT) \ + util.$(OBJEXT) +recursive_dir_list_OBJECTS = $(am_recursive_dir_list_OBJECTS) +recursive_dir_list_LDADD = $(LDADD) +am_streams_OBJECTS = streams.$(OBJEXT) stream.$(OBJEXT) util.$(OBJEXT) +streams_OBJECTS = $(am_streams_OBJECTS) +streams_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +SOURCES = $(asprintf_SOURCES) $(encodings_SOURCES) \ + $(gethostbyname_SOURCES) $(http_client_bad_body_SOURCES) \ + $(http_client_bad_url_SOURCES) \ + http-client-close-after-request.c http-server-bad-body.c \ + http-server-bad-headers.c $(http_server_charset_SOURCES) \ + $(http_server_chunked_SOURCES) http-server-close-immediately.c \ + $(json_SOURCES) $(mkdirs_SOURCES) \ + $(recursive_dir_list_SOURCES) $(streams_SOURCES) +DIST_SOURCES = $(asprintf_SOURCES) $(encodings_SOURCES) \ + $(gethostbyname_SOURCES) $(http_client_bad_body_SOURCES) \ + $(http_client_bad_url_SOURCES) \ + http-client-close-after-request.c http-server-bad-body.c \ + http-server-bad-headers.c $(http_server_charset_SOURCES) \ + $(http_server_chunked_SOURCES) http-server-close-immediately.c \ + $(json_SOURCES) $(mkdirs_SOURCES) \ + $(recursive_dir_list_SOURCES) $(streams_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ +EXTRA_THREAD_LIBS = @EXTRA_THREAD_LIBS@ +EXTRA_TIMER_LIBS = @EXTRA_TIMER_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBICONV = @LTLIBICONV@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +XP_DEF = @XP_DEF@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CFLAGS = @XP_DEF@ -I../js -I../js/obj +AM_CXXFLAGS = @XP_DEF@ -I../js -I../js/obj +asprintf_SOURCES = asprintf.c ../util.c +encodings_SOURCES = encodings.c ../encoding.c ../util.c +encodings_LDADD = @LIBICONV@ +gethostbyname_SOURCES = gethostbyname.c ../http-host.c ../util.c +gethostbyname_LDADD = @EXTRA_SOCKET_LIBS@ +http_client_bad_body_SOURCES = http-client-bad-body.c ../http-url.c ../util.c +http_client_bad_body_LDADD = @EXTRA_SOCKET_LIBS@ +http_client_bad_url_SOURCES = http-client-bad-url.c ../util.c +http_client_bad_url_LDADD = @EXTRA_SOCKET_LIBS@ +http_client_close_after_request_LDADD = @EXTRA_SOCKET_LIBS@ +http_server_bad_body_LDADD = @EXTRA_SOCKET_LIBS@ +http_server_bad_headers_LDADD = @EXTRA_SOCKET_LIBS@ +http_server_charset_SOURCES = http-server-charset.c ../stream.c ../util.c +http_server_charset_LDADD = @EXTRA_SOCKET_LIBS@ +http_server_chunked_SOURCES = http-server-chunked.c ../stream.c ../util.c +http_server_chunked_LDADD = @EXTRA_SOCKET_LIBS@ +http_server_close_immediately_LDADD = @EXTRA_SOCKET_LIBS@ +json_SOURCES = json.c ../encoding.c ../highlight.c ../instrument-js.cpp ../resource-manager.c ../stream.c ../util.c +json_LDADD = ../js/obj/libjs.a -lm @LIBICONV@ @EXTRA_TIMER_LIBS@ +mkdirs_SOURCES = mkdirs.c ../util.c +recursive_dir_list_SOURCES = recursive-dir-list.c ../util.c +streams_SOURCES = streams.c ../stream.c ../util.c +TESTS = encodings.sh \ + fatal.sh \ + help.sh \ + invalid-option.sh \ + javascript.sh \ + javascript-ignore.sh \ + javascript-utf-8.sh \ + no-arguments.sh \ + recursive.sh \ + recursive-crlf.sh \ + recursive-exclude.sh \ + recursive-fatal.sh \ + recursive-no-instrument.sh \ + same-directory.sh \ + version.sh \ + asprintf.sh \ + mkdirs.sh \ + recursive-dir-list.sh \ + streams.sh \ + charset.sh \ + chunked.sh \ + gethostbyname.sh \ + json.sh \ + proxy.sh \ + proxy-bad-request-body.sh \ + proxy-bad-response-body.sh \ + proxy-bad-response-body-javascript.sh \ + proxy-bad-response-headers.sh \ + proxy-no-server.sh \ + proxy-url.sh \ + server.sh \ + server-bad-requests.sh \ + server-close-after-request.sh \ + server-content-types.sh \ + server-directory-listing.sh \ + server-directory-redirect.sh \ + server-encoded-url.sh \ + server-error.sh \ + server-help.sh \ + server-ip-address.sh \ + server-shutdown.sh \ + server-shutdown-bad-method.sh \ + server-special-file.sh \ + server-unreadable-directory.sh \ + server-unreadable-file.sh \ + server-verbose.sh \ + server-version.sh \ + store.sh \ + store-bad-json.sh \ + store-bad-request-body.sh \ + store-bad-response-headers.sh \ + store-escaped-characters.sh \ + store-server-bad-body.sh \ + store-server-closes-immediately.sh \ + store-source-not-found.sh \ + store-unreadable-json.sh \ + store-unwritable-json.sh + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .cpp .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign tests/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +asprintf$(EXEEXT): $(asprintf_OBJECTS) $(asprintf_DEPENDENCIES) + @rm -f asprintf$(EXEEXT) + $(LINK) $(asprintf_OBJECTS) $(asprintf_LDADD) $(LIBS) +encodings$(EXEEXT): $(encodings_OBJECTS) $(encodings_DEPENDENCIES) + @rm -f encodings$(EXEEXT) + $(LINK) $(encodings_OBJECTS) $(encodings_LDADD) $(LIBS) +gethostbyname$(EXEEXT): $(gethostbyname_OBJECTS) $(gethostbyname_DEPENDENCIES) + @rm -f gethostbyname$(EXEEXT) + $(LINK) $(gethostbyname_OBJECTS) $(gethostbyname_LDADD) $(LIBS) +http-client-bad-body$(EXEEXT): $(http_client_bad_body_OBJECTS) $(http_client_bad_body_DEPENDENCIES) + @rm -f http-client-bad-body$(EXEEXT) + $(LINK) $(http_client_bad_body_OBJECTS) $(http_client_bad_body_LDADD) $(LIBS) +http-client-bad-url$(EXEEXT): $(http_client_bad_url_OBJECTS) $(http_client_bad_url_DEPENDENCIES) + @rm -f http-client-bad-url$(EXEEXT) + $(LINK) $(http_client_bad_url_OBJECTS) $(http_client_bad_url_LDADD) $(LIBS) +http-client-close-after-request$(EXEEXT): $(http_client_close_after_request_OBJECTS) $(http_client_close_after_request_DEPENDENCIES) + @rm -f http-client-close-after-request$(EXEEXT) + $(LINK) $(http_client_close_after_request_OBJECTS) $(http_client_close_after_request_LDADD) $(LIBS) +http-server-bad-body$(EXEEXT): $(http_server_bad_body_OBJECTS) $(http_server_bad_body_DEPENDENCIES) + @rm -f http-server-bad-body$(EXEEXT) + $(LINK) $(http_server_bad_body_OBJECTS) $(http_server_bad_body_LDADD) $(LIBS) +http-server-bad-headers$(EXEEXT): $(http_server_bad_headers_OBJECTS) $(http_server_bad_headers_DEPENDENCIES) + @rm -f http-server-bad-headers$(EXEEXT) + $(LINK) $(http_server_bad_headers_OBJECTS) $(http_server_bad_headers_LDADD) $(LIBS) +http-server-charset$(EXEEXT): $(http_server_charset_OBJECTS) $(http_server_charset_DEPENDENCIES) + @rm -f http-server-charset$(EXEEXT) + $(LINK) $(http_server_charset_OBJECTS) $(http_server_charset_LDADD) $(LIBS) +http-server-chunked$(EXEEXT): $(http_server_chunked_OBJECTS) $(http_server_chunked_DEPENDENCIES) + @rm -f http-server-chunked$(EXEEXT) + $(LINK) $(http_server_chunked_OBJECTS) $(http_server_chunked_LDADD) $(LIBS) +http-server-close-immediately$(EXEEXT): $(http_server_close_immediately_OBJECTS) $(http_server_close_immediately_DEPENDENCIES) + @rm -f http-server-close-immediately$(EXEEXT) + $(LINK) $(http_server_close_immediately_OBJECTS) $(http_server_close_immediately_LDADD) $(LIBS) +json$(EXEEXT): $(json_OBJECTS) $(json_DEPENDENCIES) + @rm -f json$(EXEEXT) + $(CXXLINK) $(json_OBJECTS) $(json_LDADD) $(LIBS) +mkdirs$(EXEEXT): $(mkdirs_OBJECTS) $(mkdirs_DEPENDENCIES) + @rm -f mkdirs$(EXEEXT) + $(LINK) $(mkdirs_OBJECTS) $(mkdirs_LDADD) $(LIBS) +recursive-dir-list$(EXEEXT): $(recursive_dir_list_OBJECTS) $(recursive_dir_list_DEPENDENCIES) + @rm -f recursive-dir-list$(EXEEXT) + $(LINK) $(recursive_dir_list_OBJECTS) $(recursive_dir_list_LDADD) $(LIBS) +streams$(EXEEXT): $(streams_OBJECTS) $(streams_DEPENDENCIES) + @rm -f streams$(EXEEXT) + $(LINK) $(streams_OBJECTS) $(streams_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asprintf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encoding.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encodings.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gethostbyname.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/highlight.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-client-bad-body.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-client-bad-url.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-client-close-after-request.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-host.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-server-bad-body.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-server-bad-headers.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-server-charset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-server-chunked.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-server-close-immediately.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-url.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/instrument-js.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkdirs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recursive-dir-list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resource-manager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/streams.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +util.o: ../util.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util.o -MD -MP -MF $(DEPDIR)/util.Tpo -c -o util.o `test -f '../util.c' || echo '$(srcdir)/'`../util.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/util.Tpo $(DEPDIR)/util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../util.c' object='util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util.o `test -f '../util.c' || echo '$(srcdir)/'`../util.c + +util.obj: ../util.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util.obj -MD -MP -MF $(DEPDIR)/util.Tpo -c -o util.obj `if test -f '../util.c'; then $(CYGPATH_W) '../util.c'; else $(CYGPATH_W) '$(srcdir)/../util.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/util.Tpo $(DEPDIR)/util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../util.c' object='util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util.obj `if test -f '../util.c'; then $(CYGPATH_W) '../util.c'; else $(CYGPATH_W) '$(srcdir)/../util.c'; fi` + +encoding.o: ../encoding.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT encoding.o -MD -MP -MF $(DEPDIR)/encoding.Tpo -c -o encoding.o `test -f '../encoding.c' || echo '$(srcdir)/'`../encoding.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/encoding.Tpo $(DEPDIR)/encoding.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../encoding.c' object='encoding.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o encoding.o `test -f '../encoding.c' || echo '$(srcdir)/'`../encoding.c + +encoding.obj: ../encoding.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT encoding.obj -MD -MP -MF $(DEPDIR)/encoding.Tpo -c -o encoding.obj `if test -f '../encoding.c'; then $(CYGPATH_W) '../encoding.c'; else $(CYGPATH_W) '$(srcdir)/../encoding.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/encoding.Tpo $(DEPDIR)/encoding.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../encoding.c' object='encoding.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o encoding.obj `if test -f '../encoding.c'; then $(CYGPATH_W) '../encoding.c'; else $(CYGPATH_W) '$(srcdir)/../encoding.c'; fi` + +http-host.o: ../http-host.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT http-host.o -MD -MP -MF $(DEPDIR)/http-host.Tpo -c -o http-host.o `test -f '../http-host.c' || echo '$(srcdir)/'`../http-host.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/http-host.Tpo $(DEPDIR)/http-host.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../http-host.c' object='http-host.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o http-host.o `test -f '../http-host.c' || echo '$(srcdir)/'`../http-host.c + +http-host.obj: ../http-host.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT http-host.obj -MD -MP -MF $(DEPDIR)/http-host.Tpo -c -o http-host.obj `if test -f '../http-host.c'; then $(CYGPATH_W) '../http-host.c'; else $(CYGPATH_W) '$(srcdir)/../http-host.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/http-host.Tpo $(DEPDIR)/http-host.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../http-host.c' object='http-host.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o http-host.obj `if test -f '../http-host.c'; then $(CYGPATH_W) '../http-host.c'; else $(CYGPATH_W) '$(srcdir)/../http-host.c'; fi` + +http-url.o: ../http-url.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT http-url.o -MD -MP -MF $(DEPDIR)/http-url.Tpo -c -o http-url.o `test -f '../http-url.c' || echo '$(srcdir)/'`../http-url.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/http-url.Tpo $(DEPDIR)/http-url.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../http-url.c' object='http-url.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o http-url.o `test -f '../http-url.c' || echo '$(srcdir)/'`../http-url.c + +http-url.obj: ../http-url.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT http-url.obj -MD -MP -MF $(DEPDIR)/http-url.Tpo -c -o http-url.obj `if test -f '../http-url.c'; then $(CYGPATH_W) '../http-url.c'; else $(CYGPATH_W) '$(srcdir)/../http-url.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/http-url.Tpo $(DEPDIR)/http-url.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../http-url.c' object='http-url.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o http-url.obj `if test -f '../http-url.c'; then $(CYGPATH_W) '../http-url.c'; else $(CYGPATH_W) '$(srcdir)/../http-url.c'; fi` + +stream.o: ../stream.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stream.o -MD -MP -MF $(DEPDIR)/stream.Tpo -c -o stream.o `test -f '../stream.c' || echo '$(srcdir)/'`../stream.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stream.Tpo $(DEPDIR)/stream.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../stream.c' object='stream.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stream.o `test -f '../stream.c' || echo '$(srcdir)/'`../stream.c + +stream.obj: ../stream.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stream.obj -MD -MP -MF $(DEPDIR)/stream.Tpo -c -o stream.obj `if test -f '../stream.c'; then $(CYGPATH_W) '../stream.c'; else $(CYGPATH_W) '$(srcdir)/../stream.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stream.Tpo $(DEPDIR)/stream.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../stream.c' object='stream.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stream.obj `if test -f '../stream.c'; then $(CYGPATH_W) '../stream.c'; else $(CYGPATH_W) '$(srcdir)/../stream.c'; fi` + +highlight.o: ../highlight.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT highlight.o -MD -MP -MF $(DEPDIR)/highlight.Tpo -c -o highlight.o `test -f '../highlight.c' || echo '$(srcdir)/'`../highlight.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/highlight.Tpo $(DEPDIR)/highlight.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../highlight.c' object='highlight.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o highlight.o `test -f '../highlight.c' || echo '$(srcdir)/'`../highlight.c + +highlight.obj: ../highlight.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT highlight.obj -MD -MP -MF $(DEPDIR)/highlight.Tpo -c -o highlight.obj `if test -f '../highlight.c'; then $(CYGPATH_W) '../highlight.c'; else $(CYGPATH_W) '$(srcdir)/../highlight.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/highlight.Tpo $(DEPDIR)/highlight.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../highlight.c' object='highlight.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o highlight.obj `if test -f '../highlight.c'; then $(CYGPATH_W) '../highlight.c'; else $(CYGPATH_W) '$(srcdir)/../highlight.c'; fi` + +resource-manager.o: ../resource-manager.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT resource-manager.o -MD -MP -MF $(DEPDIR)/resource-manager.Tpo -c -o resource-manager.o `test -f '../resource-manager.c' || echo '$(srcdir)/'`../resource-manager.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/resource-manager.Tpo $(DEPDIR)/resource-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../resource-manager.c' object='resource-manager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o resource-manager.o `test -f '../resource-manager.c' || echo '$(srcdir)/'`../resource-manager.c + +resource-manager.obj: ../resource-manager.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT resource-manager.obj -MD -MP -MF $(DEPDIR)/resource-manager.Tpo -c -o resource-manager.obj `if test -f '../resource-manager.c'; then $(CYGPATH_W) '../resource-manager.c'; else $(CYGPATH_W) '$(srcdir)/../resource-manager.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/resource-manager.Tpo $(DEPDIR)/resource-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../resource-manager.c' object='resource-manager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o resource-manager.obj `if test -f '../resource-manager.c'; then $(CYGPATH_W) '../resource-manager.c'; else $(CYGPATH_W) '$(srcdir)/../resource-manager.c'; fi` + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +instrument-js.o: ../instrument-js.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT instrument-js.o -MD -MP -MF $(DEPDIR)/instrument-js.Tpo -c -o instrument-js.o `test -f '../instrument-js.cpp' || echo '$(srcdir)/'`../instrument-js.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/instrument-js.Tpo $(DEPDIR)/instrument-js.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../instrument-js.cpp' object='instrument-js.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o instrument-js.o `test -f '../instrument-js.cpp' || echo '$(srcdir)/'`../instrument-js.cpp + +instrument-js.obj: ../instrument-js.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT instrument-js.obj -MD -MP -MF $(DEPDIR)/instrument-js.Tpo -c -o instrument-js.obj `if test -f '../instrument-js.cpp'; then $(CYGPATH_W) '../instrument-js.cpp'; else $(CYGPATH_W) '$(srcdir)/../instrument-js.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/instrument-js.Tpo $(DEPDIR)/instrument-js.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../instrument-js.cpp' object='instrument-js.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o instrument-js.obj `if test -f '../instrument-js.cpp'; then $(CYGPATH_W) '../instrument-js.cpp'; else $(CYGPATH_W) '$(srcdir)/../instrument-js.cpp'; fi` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; ws='[ ]'; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *$$ws$$tst$$ws*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + echo "XPASS: $$tst"; \ + ;; \ + *) \ + echo "PASS: $$tst"; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *$$ws$$tst$$ws*) \ + xfail=`expr $$xfail + 1`; \ + echo "XFAIL: $$tst"; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + echo "FAIL: $$tst"; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + echo "SKIP: $$tst"; \ + fi; \ + done; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="All $$all tests passed"; \ + else \ + banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all tests failed"; \ + else \ + banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + skipped="($$skip tests were not run)"; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-generic clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/asprintf.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/asprintf.c new file mode 100644 index 0000000..7f8246b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/asprintf.c @@ -0,0 +1,42 @@ +/* + asprintf.c - test `asprintf' function + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include + +#include "util.h" + +int main(void) { + int result; + char * s; + + result = asprintf(&s, "%s %d %c", "abc", 123, 'x'); + assert(result == 9); + assert(strcmp("abc 123 x", s) == 0); + free(s); + + char * long_string = "abcdefghijklmnopqrstuvwxyz"; + result = asprintf(&s, "%s %s %s %s", long_string, long_string, long_string, long_string); + assert(result == 107); + assert(strcmp("abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz", s) == 0); + free(s); + + exit(EXIT_SUCCESS); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/asprintf.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/asprintf.sh new file mode 100755 index 0000000..c7843e4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/asprintf.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# asprintf.sh - test `asprintf' function +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +$VALGRIND ./asprintf diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/charset.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/charset.sh new file mode 100755 index 0000000..9fb07eb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/charset.sh @@ -0,0 +1,110 @@ +#!/bin/sh +# charset.sh - test jscoverage-server with different charset values +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${proxy_server_port}/jscoverage-shutdown" > /dev/null + wait $proxy_server_pid +} + +cleanup() { + shutdown + kill -9 $origin_server_pid +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +if jscoverage-server --version | grep -q 'iconv\|MultiByteToWideChar' +then + character_encoding_support=yes +else + character_encoding_support=no +fi + +$VALGRIND jscoverage-server --proxy --no-highlight > OUT 2> ERR & +proxy_server_pid=$! +proxy_server_port=8080 + +./http-server-charset & +origin_server_pid=$! + +sleep $delay + +case "$character_encoding_support" in + yes) + cat ../report.js > EXPECTED + cat javascript-utf-8.expected/javascript-utf-8.js | sed 's/javascript-utf-8.js/http:\/\/127.0.0.1:8000\/utf-8.js/g' >> EXPECTED + curl -s -x 127.0.0.1:8080 http://127.0.0.1:8000/utf-8.js > ACTUAL + diff EXPECTED ACTUAL + ;; + *) + echo 500 > EXPECTED + ! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:8000/utf-8.js 2> /dev/null > ACTUAL + diff EXPECTED ACTUAL + ;; +esac + +shutdown + +$VALGRIND jscoverage-server --proxy > OUT 2> ERR & +proxy_server_pid=$! +proxy_server_port=8080 + +sleep $delay + +case "$character_encoding_support" in + yes) + cat ../report.js > EXPECTED + cat javascript.expected/javascript-iso-8859-1.js | sed 's/javascript-iso-8859-1.js/http:\/\/127.0.0.1:8000\/iso-8859-1.js/g' >> EXPECTED + curl -s -x 127.0.0.1:8080 http://127.0.0.1:8000/iso-8859-1.js > ACTUAL + diff EXPECTED ACTUAL + ;; + *) + echo 500 > EXPECTED + ! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:8000/iso-8859-1.js 2> /dev/null > ACTUAL + diff EXPECTED ACTUAL + ;; +esac + +# bogus charset +echo 500 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:8000/bogus.js 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL + +# malformed encoding +case "$character_encoding_support" in + yes) + status=502 + ;; + *) + status=500 + ;; +esac +echo $status > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:8000/malformed.js 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/chunked.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/chunked.sh new file mode 100755 index 0000000..2986552 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/chunked.sh @@ -0,0 +1,74 @@ +#!/bin/sh +# chunked.sh - test jscoverage-server with Transfer-Encoding: chunked +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${proxy_server_port}/jscoverage-shutdown" > /dev/null + wait $proxy_server_pid +} + +cleanup() { + shutdown + kill -9 $origin_server_pid +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +$VALGRIND jscoverage-server --proxy > OUT 2> ERR & +proxy_server_pid=$! +proxy_server_port=8080 + +./http-server-chunked & +origin_server_pid=$! + +sleep $delay + +echo 'hello world' > EXPECTED +curl -s -x 127.0.0.1:8080 http://127.0.0.1:8000/lower > ACTUAL +diff EXPECTED ACTUAL + +echo 'HELLO WORLD' > EXPECTED +curl -s -x 127.0.0.1:8080 http://127.0.0.1:8000/upper > ACTUAL +diff EXPECTED ACTUAL + +# curl doesn't understand trailers ??? +# echo 'hello world' > EXPECTED +# curl -s -x 127.0.0.1:8080 http://127.0.0.1:8000/trailer > ACTUAL +# diff EXPECTED ACTUAL + +echo 200 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:8000/overflow 2> /dev/null > ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL + +echo 200 > EXPECTED +! curl -f -w '%{http_code}\n' -o /dev/null -x 127.0.0.1:8080 http://127.0.0.1:8000/javascript 2> /dev/null > ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL + +echo 200 > EXPECTED +! curl -f -w '%{http_code}\n' -o /dev/null -x 127.0.0.1:8080 http://127.0.0.1:8000/multiple 2> /dev/null > ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/common.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/common.sh new file mode 100644 index 0000000..e55b342 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/common.sh @@ -0,0 +1,7 @@ +export PATH=.:..:../js/obj:$PATH + +json_cmp() { + echo 'EXPECTED = ' | cat - $1 > EXPECTED + echo 'ACTUAL = ' | cat - $2 > ACTUAL + js -f EXPECTED -f ACTUAL -f json-cmp.js +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/destination-is-existing-directory.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/destination-is-existing-directory.expected.err new file mode 100644 index 0000000..8a59e6b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/destination-is-existing-directory.expected.err @@ -0,0 +1,2 @@ +jscoverage: refusing to overwrite directory: bar +Try `jscoverage --help' for more information. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/destination-is-file.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/destination-is-file.expected.err new file mode 100644 index 0000000..bb3778d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/destination-is-file.expected.err @@ -0,0 +1,2 @@ +jscoverage: not a directory: bar +Try `jscoverage --help' for more information. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encoding-requires-argument.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encoding-requires-argument.expected.err new file mode 100644 index 0000000..4b3fd0c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encoding-requires-argument.expected.err @@ -0,0 +1,2 @@ +jscoverage: --encoding: option requires an argument +Try `jscoverage --help' for more information. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encodings.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encodings.c new file mode 100644 index 0000000..26f8707 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encodings.c @@ -0,0 +1,223 @@ +/* + encodings.c - test handling different character encodings + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include + +#include "encoding.h" +#include "stream.h" + +int main(void) { + jschar * characters; + size_t num_characters; + int result; + + /* e, e grave, e acute, e circumflex */ + uint8_t utf8[] = { + 'e', + 0xc3, + 0xa8, + 0xc3, + 0xa9, + 0xc3, + 0xaa, + }; + + result = jscoverage_bytes_to_characters("UTF-8", utf8, 7, &characters, &num_characters); + +#if HAVE_ICONV || HAVE_MULTIBYTETOWIDECHAR + assert(result == 0); + assert(num_characters == 4); + assert(characters[0] == 'e'); + assert(characters[1] == 0xe8); + assert(characters[2] == 0xe9); + assert(characters[3] == 0xea); + + free(characters); +#else + assert(result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED); +#endif + + /* + BOM is 0xfeff + = 1111 1110 1111 1111 + UTF: 1110---- 10------ 10------ + = 11101111 10111011 10111111 + = EF BB BF + */ + uint8_t utf8_with_bom[] = { + 0xef, + 0xbb, + 0xbf, + 'e', + 0xc3, + 0xa8, + 0xc3, + 0xa9, + 0xc3, + 0xaa, + }; + + result = jscoverage_bytes_to_characters("UTF-8", utf8_with_bom, 10, &characters, &num_characters); + +#if HAVE_ICONV || HAVE_MULTIBYTETOWIDECHAR + assert(result == 0); + assert(num_characters == 4); + assert(characters[0] == 'e'); + assert(characters[1] == 0xe8); + assert(characters[2] == 0xe9); + assert(characters[3] == 0xea); + + free(characters); +#else + assert(result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED); +#endif + + uint8_t utf16be[] = { + 0, 'e', + 0, 0xe8, + 0, 0xe9, + 0, 0xea, + }; + + result = jscoverage_bytes_to_characters("UTF-16BE", utf16be, 8, &characters, &num_characters); + +#ifdef HAVE_ICONV + assert(result == 0); + assert(num_characters == 4); + assert(characters[0] == 'e'); + assert(characters[1] == 0xe8); + assert(characters[2] == 0xe9); + assert(characters[3] == 0xea); + + free(characters); +#else + assert(result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED); +#endif + + uint8_t utf16be_with_bom[] = { + 0xfe, 0xff, + 0, 'e', + 0, 0xe8, + 0, 0xe9, + 0, 0xea, + }; + + result = jscoverage_bytes_to_characters("UTF-16BE", utf16be_with_bom, 10, &characters, &num_characters); + +#ifdef HAVE_ICONV + assert(result == 0); + assert(num_characters == 4); + assert(characters[0] == 'e'); + assert(characters[1] == 0xe8); + assert(characters[2] == 0xe9); + assert(characters[3] == 0xea); + + free(characters); +#else + assert(result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED); +#endif + + uint8_t utf16le[] = { + 'e', 0, + 0xe8, 0, + 0xe9, 0, + 0xea, 0, + }; + + result = jscoverage_bytes_to_characters("UTF-16LE", utf16le, 8, &characters, &num_characters); + +#ifdef HAVE_ICONV + assert(result == 0); + assert(num_characters == 4); + assert(characters[0] == 'e'); + assert(characters[1] == 0xe8); + assert(characters[2] == 0xe9); + assert(characters[3] == 0xea); + + free(characters); +#else + assert(result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED); +#endif + + uint8_t utf16le_with_bom[] = { + 0xff, 0xfe, + 'e', 0, + 0xe8, 0, + 0xe9, 0, + 0xea, 0, + }; + + result = jscoverage_bytes_to_characters("UTF-16LE", utf16le_with_bom, 10, &characters, &num_characters); + +#ifdef HAVE_ICONV + assert(result == 0); + assert(num_characters == 4); + assert(characters[0] == 'e'); + assert(characters[1] == 0xe8); + assert(characters[2] == 0xe9); + assert(characters[3] == 0xea); + + free(characters); +#else + assert(result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED); +#endif + + /* bogus encoding */ + uint8_t bogus[] = {'b', 'o', 'g', 'u', 's'}; + + result = jscoverage_bytes_to_characters("BOGUS", bogus, 5, &characters, &num_characters); + + assert(result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED); + +#ifdef HAVE_ICONV + /* malformed US-ASCII */ + /* NOTE: Windows simply discards the high bit */ + uint8_t malformed_ascii[] = { + 'e', + 0xe8, + 0xe9, + 0xea, + }; + + result = jscoverage_bytes_to_characters("US-ASCII", malformed_ascii, 4, &characters, &num_characters); + + assert(result == JSCOVERAGE_ERROR_INVALID_BYTE_SEQUENCE); +#endif + + /* malformed UTF-8 */ + uint8_t malformed_utf8[] = { + 'e', + 0xe8, + 0xe9, + 0xea, + }; + + result = jscoverage_bytes_to_characters("UTF-8", malformed_utf8, 4, &characters, &num_characters); + +#if HAVE_ICONV || HAVE_MULTIBYTETOWIDECHAR + assert(result == JSCOVERAGE_ERROR_INVALID_BYTE_SEQUENCE); +#else + assert(result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED); +#endif + + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encodings.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encodings.sh new file mode 100755 index 0000000..5db0f13 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/encodings.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# encodings.sh - test handling different character encodings +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +$VALGRIND ./encodings diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/exclude-requires-argument.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/exclude-requires-argument.expected.err new file mode 100644 index 0000000..6feb597 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/exclude-requires-argument.expected.err @@ -0,0 +1,2 @@ +jscoverage: --exclude: option requires an argument +Try `jscoverage --help' for more information. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/fatal.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/fatal.sh new file mode 100755 index 0000000..90b8d94 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/fatal.sh @@ -0,0 +1,110 @@ +#!/bin/sh +# fatal.sh - test various fatal errors +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr DIR DIR2 OUT ERR' 1 2 3 15 + +export PATH=.:..:$PATH + +rm -fr DIR DIR2 + +$VALGRIND jscoverage javascript-xml DIR > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +diff --strip-trailing-cr javascript-xml.expected.err ERR + +rm -fr DIR + +$VALGRIND jscoverage javascript-invalid DIR > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +diff --strip-trailing-cr javascript-invalid.expected.err ERR + +rm -fr DIR + +$VALGRIND jscoverage javascript-setter DIR > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +diff --strip-trailing-cr javascript-setter.expected.err ERR + +rm -fr DIR + +$VALGRIND jscoverage 1 2 3 > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +diff --strip-trailing-cr too-many-arguments.expected.err ERR + +rm -fr DIR + +$VALGRIND jscoverage --no-instrument > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +diff --strip-trailing-cr no-instrument-requires-argument.expected.err ERR + +$VALGRIND jscoverage --exclude > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +diff --strip-trailing-cr exclude-requires-argument.expected.err ERR + +$VALGRIND jscoverage --encoding > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +diff --strip-trailing-cr encoding-requires-argument.expected.err ERR + +# first arg does not exist +rm -f foo +$VALGRIND jscoverage foo bar > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +# diff --strip-trailing-cr source-does-not-exist.expected.err ERR + +# first arg is file +touch foo +$VALGRIND jscoverage foo bar > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +# diff --strip-trailing-cr source-is-file.expected.err ERR +rm foo + +# second arg is file +rm -fr bar +touch bar +$VALGRIND jscoverage javascript bar > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +# diff --strip-trailing-cr destination-is-file.expected.err ERR +rm bar + +# second arg is directory, but not from previous run +rm -fr bar +mkdir bar +touch bar/foo +$VALGRIND jscoverage javascript bar > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +# diff --strip-trailing-cr destination-is-existing-directory.expected.err ERR +rm -fr bar + +# huge JavaScript file +mkdir -p DIR +perl -e 'for (1 .. 65536) {print "x = $_\n";}' > DIR/big.js +$VALGRIND jscoverage DIR DIR2 > OUT 2> ERR && exit 1 +echo 'jscoverage: file big.js contains more than 65,535 lines' | diff --strip-trailing-cr - ERR + +rm -fr DIR DIR2 OUT ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/gethostbyname.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/gethostbyname.c new file mode 100644 index 0000000..ef5d7b3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/gethostbyname.c @@ -0,0 +1,53 @@ +/* + gethostbyname.c - test host lookup + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include +#include +#include + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#include "http-server.h" + +int main(int argc, char ** argv) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + return 1; + } +#endif + + if (argc < 2) { + exit(EXIT_FAILURE); + } + + struct in_addr a; + if (xgethostbyname(argv[1], &a) != 0) { + exit(EXIT_FAILURE); + } + char * result = inet_ntoa(a); + printf("%s\n", result); + + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/gethostbyname.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/gethostbyname.sh new file mode 100755 index 0000000..eae74e3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/gethostbyname.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# gethostbyname.sh - test host lookup +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +echo 127.0.0.1 > EXPECTED +./gethostbyname localhost > ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL + +! ./gethostbyname foo diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/help.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/help.sh new file mode 100755 index 0000000..5aaa31a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/help.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# help.sh - test `--help' option +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr OUT ERR' 1 2 3 15 + +export PATH=.:..:$PATH + +$VALGRIND jscoverage --help > OUT 2> ERR +test -s OUT +test ! -s ERR +diff --strip-trailing-cr ../jscoverage-help.txt OUT + +$VALGRIND jscoverage -h > OUT 2> ERR +test -s OUT +test ! -s ERR +diff --strip-trailing-cr ../jscoverage-help.txt OUT + +rm -fr OUT ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-bad-body.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-bad-body.c new file mode 100644 index 0000000..9985c62 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-bad-body.c @@ -0,0 +1,98 @@ +/* + http-client-bad-body.c - HTTP client that outputs a bad body + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include +#include +#include + +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include + +#include "http-server.h" +#include "util.h" + +int main(int argc, char ** argv) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + return 1; + } +#endif + + int result; + + if (argc < 3) { + fprintf(stderr, "Usage: %s PORT URL\n", argv[0]); + exit(EXIT_FAILURE); + } + + uint16_t connect_port = atoi(argv[1]); + char * url = argv[2]; + char * host; + uint16_t port; + char * abs_path; + char * query; + result = URL_parse(url, &host, &port, &abs_path, &query); + assert(result == 0); + + struct sockaddr_in a; + a.sin_family = AF_INET; + a.sin_port = htons(connect_port); + a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + SOCKET s = socket(PF_INET, SOCK_STREAM, 0); + assert(s != INVALID_SOCKET); + + result = connect(s, (struct sockaddr *) &a, sizeof(a)); + assert(result == 0); + + /* send request */ + char * message; + xasprintf(&message, "POST %s HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\nHello\n", url); + size_t message_length = strlen(message); + ssize_t bytes_sent = send(s, message, message_length, 0); + assert(bytes_sent == (ssize_t) message_length); + + /* read response */ + for (;;) { + uint8_t buffer[8192]; + ssize_t bytes_read = recv(s, buffer, 8192, 0); + assert(bytes_read >= 0); + if (bytes_read == 0) { + break; + } + } + + closesocket(s); + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-bad-url.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-bad-url.c new file mode 100644 index 0000000..fdb917b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-bad-url.c @@ -0,0 +1,77 @@ +/* + http-client-bad-url.c - HTTP client that sends bad URLs + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include +#include + +#include "http-server.h" +#include "util.h" + +int main(int argc, char ** argv) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + return 1; + } +#endif + + int result; + + if (argc < 3) { + fprintf(stderr, "Usage: %s PORT URL\n", argv[0]); + exit(EXIT_FAILURE); + } + + uint16_t connect_port = atoi(argv[1]); + char * url = argv[2]; + + struct sockaddr_in a; + a.sin_family = AF_INET; + a.sin_port = htons(connect_port); + a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + SOCKET s = socket(PF_INET, SOCK_STREAM, 0); + assert(s != INVALID_SOCKET); + + result = connect(s, (struct sockaddr *) &a, sizeof(a)); + assert(result == 0); + + /* send request */ + char * message; + xasprintf(&message, "GET %s HTTP/1.1\r\nConnection: close\r\n\r\n", url); + size_t message_length = strlen(message); + ssize_t bytes_sent = send(s, message, message_length, 0); + assert(bytes_sent == (ssize_t) message_length); + + /* read response */ + for (;;) { + uint8_t buffer[8192]; + ssize_t bytes_read = recv(s, buffer, 8192, 0); + assert(bytes_read >= 0); + if (bytes_read == 0) { + break; + } + } + + closesocket(s); + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-close-after-request.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-close-after-request.c new file mode 100644 index 0000000..e67431a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-client-close-after-request.c @@ -0,0 +1,57 @@ +/* + http-client-close-after-request.c - HTTP client that closes connection after sending request + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include +#include + +#include "http-server.h" + +int main(void) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + return 1; + } +#endif + + int result; + + struct sockaddr_in a; + a.sin_family = AF_INET; + a.sin_port = htons(8000); + a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + SOCKET s = socket(PF_INET, SOCK_STREAM, 0); + assert(s != INVALID_SOCKET); + + result = connect(s, (struct sockaddr *) &a, sizeof(a)); + assert(result == 0); + + /* send request */ + char * message = "GET http://127.0.0.1:8000/ HTTP/1.1\r\nConnection: close\r\nHost: 127.0.0.1:8000\r\n\r\n"; + size_t message_length = strlen(message); + ssize_t bytes_sent = send(s, message, message_length, 0); + assert(bytes_sent == (ssize_t) message_length); + + closesocket(s); + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-bad-body.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-bad-body.c new file mode 100644 index 0000000..f8c362d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-bad-body.c @@ -0,0 +1,97 @@ +/* + http-server-bad-body.c - HTTP server that outputs a bad body + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include + +#include "http-server.h" + +int main(void) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + return 1; + } +#endif + + SOCKET s = socket(PF_INET, SOCK_STREAM, 0); + assert(s != INVALID_SOCKET); + + int optval = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval)); + + struct sockaddr_in a; + a.sin_family = AF_INET; + a.sin_port = htons(8000); + a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + int result = bind(s, (struct sockaddr *) &a, sizeof(a)); + assert(result == 0); + + result = listen(s, 5); + assert(result == 0); + + for (;;) { + struct sockaddr_in client_address; + size_t size = sizeof(client_address); + int client_socket = accept(s, (struct sockaddr *) &client_address, &size); + assert(client_socket > 0); + + /* read request */ + int state = 0; + while (state != 2) { + uint8_t buffer[8192]; + ssize_t bytes_read = recv(client_socket, buffer, 8192, 0); + assert(bytes_read > 0); + for (int i = 0; i < bytes_read && state != 2; i++) { + uint8_t byte = buffer[i]; + switch (state) { + case 0: + if (byte == '\n') { + state = 1; + } + else { + state = 0; + } + break; + case 1: + if (byte == '\n') { + state = 2; + } + else if (byte == '\r') { + state = 1; + } + else { + state = 0; + } + } + } + } + + /* send response */ + char * message = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-type: text/html\r\nTransfer-Encoding: chunked\r\n\r\nHello\n"; + size_t message_length = strlen(message); + ssize_t bytes_sent = send(client_socket, message, message_length, 0); + assert(bytes_sent == (ssize_t) message_length); + + closesocket(client_socket); + } + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-bad-headers.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-bad-headers.c new file mode 100644 index 0000000..bbef80f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-bad-headers.c @@ -0,0 +1,97 @@ +/* + http-server-bad-headers.c - HTTP server that outputs bad headers + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include + +#include "http-server.h" + +int main(void) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + return 1; + } +#endif + + SOCKET s = socket(PF_INET, SOCK_STREAM, 0); + assert(s != INVALID_SOCKET); + + int optval = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval)); + + struct sockaddr_in a; + a.sin_family = AF_INET; + a.sin_port = htons(8000); + a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + int result = bind(s, (struct sockaddr *) &a, sizeof(a)); + assert(result == 0); + + result = listen(s, 5); + assert(result == 0); + + for (;;) { + struct sockaddr_in client_address; + size_t size = sizeof(client_address); + int client_socket = accept(s, (struct sockaddr *) &client_address, &size); + assert(client_socket > 0); + + /* read request */ + int state = 0; + while (state != 2) { + uint8_t buffer[8192]; + ssize_t bytes_read = recv(client_socket, buffer, 8192, 0); + assert(bytes_read > 0); + for (int i = 0; i < bytes_read && state != 2; i++) { + uint8_t byte = buffer[i]; + switch (state) { + case 0: + if (byte == '\n') { + state = 1; + } + else { + state = 0; + } + break; + case 1: + if (byte == '\n') { + state = 2; + } + else if (byte == '\r') { + state = 1; + } + else { + state = 0; + } + } + } + } + + /* send response */ + char * message = "HTTP/1.1 200 OK\r\nHere is some bogosity!\r\nConnection: close\r\nContent-type: text/html\r\n\r\nHello\n"; + size_t message_length = strlen(message); + ssize_t bytes_sent = send(client_socket, message, message_length, 0); + assert(bytes_sent == (ssize_t) message_length); + + closesocket(client_socket); + } + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-charset.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-charset.c new file mode 100644 index 0000000..7ea7bb8 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-charset.c @@ -0,0 +1,144 @@ +/* + http-server-charset.c - HTTP server that outputs different charset values + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include + +#include "http-server.h" +#include "stream.h" +#include "util.h" + +int main(void) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + return 1; + } +#endif + + SOCKET s = socket(PF_INET, SOCK_STREAM, 0); + assert(s != INVALID_SOCKET); + + int optval = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval)); + + struct sockaddr_in a; + a.sin_family = AF_INET; + a.sin_port = htons(8000); + a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + int result = bind(s, (struct sockaddr *) &a, sizeof(a)); + assert(result == 0); + + result = listen(s, 5); + assert(result == 0); + + for (;;) { + struct sockaddr_in client_address; + size_t size = sizeof(client_address); + int client_socket = accept(s, (struct sockaddr *) &client_address, &size); + assert(client_socket > 0); + + /* read request */ + Stream * stream = Stream_new(0); + int state = 0; + while (state != 2) { + uint8_t buffer[8192]; + ssize_t bytes_read = recv(client_socket, buffer, 8192, 0); + assert(bytes_read > 0); + Stream_write(stream, buffer, bytes_read); + for (int i = 0; i < bytes_read && state != 2; i++) { + uint8_t byte = buffer[i]; + switch (state) { + case 0: + if (byte == '\n') { + state = 1; + } + break; + case 1: + if (byte == '\n') { + state = 2; + } + else if (byte == '\r') { + state = 1; + } + else { + state = 0; + } + break; + } + } + } + + char * method; + char * url; + char * request_line = (char *) stream->data; + char * first_space = strchr(request_line, ' '); + assert(first_space != NULL); + char * second_space = strchr(first_space + 1, ' '); + assert(second_space != NULL); + method = xstrndup(request_line, first_space - request_line); + url = xstrndup(first_space + 1, second_space - (first_space + 1)); + + /* send response */ + char * message; + if (strcmp(url, "http://127.0.0.1:8000/utf-8.js") == 0 || strcmp(url, "/utf-8.js") == 0) { + message = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-type: text/javascript; charset=UTF-8\r\n" + "\r\n" + "var s = 'eèéê';\n" + "var r = /eèéê/;\n"; + } + else if (strcmp(url, "http://127.0.0.1:8000/iso-8859-1.js") == 0 || strcmp(url, "/iso-8859-1.js") == 0) { + message = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-type: text/javascript; charset=ISO-8859-1\r\n" + "\r\n" + "var s = 'eèéê';\n" + "var r = /eèéê/;\n"; + } + else if (strcmp(url, "http://127.0.0.1:8000/bogus.js") == 0 || strcmp(url, "/bogus.js") == 0) { + message = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-type: text/javascript; charset=BOGUS\r\n" + "\r\n" + "var s = 'eèéê';\n" + "var r = /eèéê/;\n"; + } + else if (strcmp(url, "http://127.0.0.1:8000/malformed.js") == 0 || strcmp(url, "/malformed.js") == 0) { + message = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-type: text/javascript; charset=UTF-8\r\n" + "\r\n" + "var s = 'eèéê';\n" + "var r = /eèéê/;\n"; + } + else { + abort(); + } + size_t message_length = strlen(message); + ssize_t bytes_sent = send(client_socket, message, message_length, 0); + assert(bytes_sent == (ssize_t) message_length); + + closesocket(client_socket); + } + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-chunked.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-chunked.c new file mode 100644 index 0000000..909cb07 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-chunked.c @@ -0,0 +1,196 @@ +/* + http-server-chunked.c - HTTP server that outputs chunked response + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include + +#include "http-server.h" +#include "stream.h" +#include "util.h" + +int main(void) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + return 1; + } +#endif + + SOCKET s = socket(PF_INET, SOCK_STREAM, 0); + assert(s != INVALID_SOCKET); + + int optval = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval)); + + struct sockaddr_in a; + a.sin_family = AF_INET; + a.sin_port = htons(8000); + a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + int result = bind(s, (struct sockaddr *) &a, sizeof(a)); + assert(result == 0); + + result = listen(s, 5); + assert(result == 0); + + for (;;) { + struct sockaddr_in client_address; + size_t size = sizeof(client_address); + int client_socket = accept(s, (struct sockaddr *) &client_address, &size); + assert(client_socket > 0); + + /* read request */ + Stream * stream = Stream_new(0); + int state = 0; + while (state != 2) { + uint8_t buffer[8192]; + ssize_t bytes_read = recv(client_socket, buffer, 8192, 0); + assert(bytes_read > 0); + Stream_write(stream, buffer, bytes_read); + for (int i = 0; i < bytes_read && state != 2; i++) { + uint8_t byte = buffer[i]; + switch (state) { + case 0: + if (byte == '\n') { + state = 1; + } + else { + state = 0; + } + break; + case 1: + if (byte == '\n') { + state = 2; + } + else if (byte == '\r') { + state = 1; + } + else { + state = 0; + } + break; + } + } + } + + char * method; + char * url; + char * request_line = (char *) stream->data; + char * first_space = strchr(request_line, ' '); + assert(first_space != NULL); + char * second_space = strchr(first_space + 1, ' '); + assert(second_space != NULL); + method = xstrndup(request_line, first_space - request_line); + url = xstrndup(first_space + 1, second_space - (first_space + 1)); + + /* send response */ + char * message; + if (strcmp(url, "http://127.0.0.1:8000/lower") == 0 || strcmp(url, "/lower") == 0) { + message = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-type: text/html\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "b\r\n" + "hello world\r\n" + "1\r\n" + "\n\r\n" + "0\r\n" + "\r\n"; + } + else if (strcmp(url, "http://127.0.0.1:8000/upper") == 0 || strcmp(url, "/upper") == 0) { + message = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-type: text/html\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "B\r\n" + "HELLO WORLD\r\n" + "1\r\n" + "\n\r\n" + "0\r\n" + "\r\n"; + } + else if (strcmp(url, "http://127.0.0.1:8000/javascript") == 0 || strcmp(url, "/javascript") == 0) { + message = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-Type: text/javascript\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "B\r\n" + "hello = 10;\r\n" + "1\r\n" + "\n\r\n" + "0\r\n" + "\r\n"; + } + else if (strcmp(url, "http://127.0.0.1:8000/trailer") == 0 || strcmp(url, "/trailer") == 0) { + message = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-type: text/html\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "b\r\n" + "hello world\r\n" + "1\r\n" + "\n\r\n" + "0\r\n" + "X-Foo: bar\r\n" + "X-Bar: foo\r\n" + "\r\n"; + } + else if (strcmp(url, "http://127.0.0.1:8000/overflow") == 0) { + message = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-type: text/html\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "100000000\r\n" + "hello world\r\n" + "1\r\n" + "\n\r\n" + "0\r\n" + "\r\n"; + } + else if (strcmp(url, "http://127.0.0.1:8000/multiple") == 0) { + message = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-type: text/html\r\n" + "Transfer-Encoding: foo; foo = bar, bar; foo = \"bar\"\r\n" + "Transfer-Encoding: foobar; foo = \"\\\"bar\\\"\", chunked\r\n" + "\r\n" + "b\r\n" + "hello world\r\n" + "1\r\n" + "\n\r\n" + "0\r\n" + "\r\n"; + } + else { + abort(); + } + size_t message_length = strlen(message); + ssize_t bytes_sent = send(client_socket, message, message_length, 0); + assert(bytes_sent == (ssize_t) message_length); + + closesocket(client_socket); + } + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-close-immediately.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-close-immediately.c new file mode 100644 index 0000000..b8c7176 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/http-server-close-immediately.c @@ -0,0 +1,60 @@ +/* + http-server-close-immediately.c - HTTP server that closes connection immediately + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include +#include +#include + +#include "http-server.h" + +int main(void) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + return 1; + } +#endif + + SOCKET s = socket(PF_INET, SOCK_STREAM, 0); + assert(s != INVALID_SOCKET); + + int optval = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval)); + + struct sockaddr_in a; + a.sin_family = AF_INET; + a.sin_port = htons(8000); + a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + int result = bind(s, (struct sockaddr *) &a, sizeof(a)); + assert(result == 0); + + result = listen(s, 5); + assert(result == 0); + + for (;;) { + struct sockaddr_in client_address; + size_t size = sizeof(client_address); + int client_socket = accept(s, (struct sockaddr *) &client_address, &size); + assert(client_socket > 0); + closesocket(client_socket); + } + return 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/invalid-option.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/invalid-option.expected.err new file mode 100644 index 0000000..91538d9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/invalid-option.expected.err @@ -0,0 +1,2 @@ +jscoverage: unrecognized option `--foo' +Try `jscoverage --help' for more information. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/invalid-option.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/invalid-option.sh new file mode 100755 index 0000000..bf9607c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/invalid-option.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# invalid-option.sh - test invalid option +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr OUT ERR' 1 2 3 15 + +export PATH=.:..:$PATH + +$VALGRIND jscoverage --foo > OUT 2> ERR && exit 1 +test ! -s OUT +diff --strip-trailing-cr invalid-option.expected.err ERR + +rm -fr OUT ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore.expected/ignore.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore.expected/ignore.js new file mode 100644 index 0000000..824f204 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore.expected/ignore.js @@ -0,0 +1,106 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['ignore.js']) { + _$jscoverage['ignore.js'] = []; + _$jscoverage['ignore.js'][1] = 0; + _$jscoverage['ignore.js'][3] = 0; + _$jscoverage['ignore.js'][4] = 0; + _$jscoverage['ignore.js'][6] = 0; + _$jscoverage['ignore.js'][7] = 0; + _$jscoverage['ignore.js'][10] = 0; + _$jscoverage['ignore.js'][14] = 0; + _$jscoverage['ignore.js'][16] = 0; + _$jscoverage['ignore.js'][17] = 0; + _$jscoverage['ignore.js'][22] = 0; + _$jscoverage['ignore.js'][23] = 0; + _$jscoverage['ignore.js'][27] = 0; + _$jscoverage['ignore.js'][32] = 0; + _$jscoverage['ignore.js'][34] = 0; + _$jscoverage['ignore.js'][35] = 0; + _$jscoverage['ignore.js'][37] = 0; + _$jscoverage['ignore.js'][38] = 0; + _$jscoverage['ignore.js'][42] = 0; + _$jscoverage['ignore.js'][43] = 0; + _$jscoverage['ignore.js'][44] = 0; +} +_$jscoverage['ignore.js'].conditionals = []; +_$jscoverage['ignore.js'][1]++; +function createRequest() { + _$jscoverage['ignore.js'][3]++; + if (window.XMLHttpRequest) { + _$jscoverage['ignore.js'].conditionals[6] = 11; + _$jscoverage['ignore.js'][4]++; + return new XMLHttpRequest(); + } + else { + _$jscoverage['ignore.js'].conditionals[4] = 5; + _$jscoverage['ignore.js'][6]++; + if (window.ActiveXObject) { + _$jscoverage['ignore.js'].conditionals[9] = 11; + _$jscoverage['ignore.js'][7]++; + return new ActiveXObject("Msxml2.XMLHTTP"); + } + else { + _$jscoverage['ignore.js'].conditionals[7] = 8; + _$jscoverage['ignore.js'][10]++; + throw "no XMLHttpRequest implementation available"; + } + } +} +_$jscoverage['ignore.js'][14]++; +function createRequest2() { + _$jscoverage['ignore.js'][16]++; + if (window.XMLHttpRequest) { + _$jscoverage['ignore.js'][17]++; + return new XMLHttpRequest(); + } + else { + _$jscoverage['ignore.js'].conditionals[17] = 18; + } + _$jscoverage['ignore.js'][22]++; + if (window.ActiveXObject) { + _$jscoverage['ignore.js'][23]++; + return new ActiveXObject("Msxml2.XMLHTTP"); + } + else { + _$jscoverage['ignore.js'].conditionals[23] = 24; + } + _$jscoverage['ignore.js'][27]++; + throw "no XMLHttpRequest implementation available"; +} +_$jscoverage['ignore.js'][32]++; +function log(s) { + _$jscoverage['ignore.js'][34]++; + if (window.console && window.console.log) { + _$jscoverage['ignore.js'].conditionals[37] = 39; + _$jscoverage['ignore.js'][35]++; + console.log(s); + } + else { + _$jscoverage['ignore.js'].conditionals[35] = 36; + _$jscoverage['ignore.js'][37]++; + if (window.opera && window.opera.postError) { + _$jscoverage['ignore.js'][38]++; + opera.postError(s); + } + else { + _$jscoverage['ignore.js'].conditionals[38] = 39; + } + } +} +_$jscoverage['ignore.js'][42]++; +var request = createRequest(); +_$jscoverage['ignore.js'][43]++; +var request2 = createRequest2(); +_$jscoverage['ignore.js'][44]++; +log("created requests"); +if (!( 0)) { + _$jscoverage['ignore.js'].conditionals[26] = 28; +} +if (!( ! window.XMLHttpRequest)) { + _$jscoverage['ignore.js'].conditionals[20] = 29; +} +_$jscoverage['ignore.js'].source = ["function createRequest() {","//#JSCOVERAGE_IF"," if (window.XMLHttpRequest) {"," return new XMLHttpRequest();"," }"," else if (window.ActiveXObject) {"," return new ActiveXObject('Msxml2.XMLHTTP');"," }"," else {"," throw 'no XMLHttpRequest implementation available';"," }","}","","function createRequest2() {","//#JSCOVERAGE_IF"," if (window.XMLHttpRequest) {"," return new XMLHttpRequest();"," }","","//#JSCOVERAGE_IF ! window.XMLHttpRequest","//#JSCOVERAGE_IF"," if (window.ActiveXObject) {"," return new ActiveXObject('Msxml2.XMLHTTP');"," }","","//#JSCOVERAGE_IF 0"," throw 'no XMLHttpRequest implementation available';","//#JSCOVERAGE_ENDIF","//#JSCOVERAGE_ENDIF","}","","function log(s) {","//#JSCOVERAGE_IF"," if (window.console && window.console.log) {"," console.log(s);"," }"," else if (window.opera && window.opera.postError) {"," opera.postError(s);"," }","}","","var request = createRequest();","var request2 = createRequest2();","log('created requests');"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore.sh new file mode 100755 index 0000000..ec1edbd --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# javascript-ignore.sh - test ignoring lines of code +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr DIR' 1 2 3 15 + +export PATH=.:..:$PATH + +rm -fr DIR +$VALGRIND jscoverage --no-highlight javascript-ignore DIR +diff -u --strip-trailing-cr javascript-ignore.expected/ignore.js DIR/ignore.js +rm -fr DIR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore/ignore.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore/ignore.js new file mode 100644 index 0000000..8579ff0 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-ignore/ignore.js @@ -0,0 +1,44 @@ +function createRequest() { +//#JSCOVERAGE_IF + if (window.XMLHttpRequest) { + return new XMLHttpRequest(); + } + else if (window.ActiveXObject) { + return new ActiveXObject('Msxml2.XMLHTTP'); + } + else { + throw 'no XMLHttpRequest implementation available'; + } +} + +function createRequest2() { +//#JSCOVERAGE_IF + if (window.XMLHttpRequest) { + return new XMLHttpRequest(); + } + +//#JSCOVERAGE_IF ! window.XMLHttpRequest +//#JSCOVERAGE_IF + if (window.ActiveXObject) { + return new ActiveXObject('Msxml2.XMLHTTP'); + } + +//#JSCOVERAGE_IF 0 + throw 'no XMLHttpRequest implementation available'; +//#JSCOVERAGE_ENDIF +//#JSCOVERAGE_ENDIF +} + +function log(s) { +//#JSCOVERAGE_IF + if (window.console && window.console.log) { + console.log(s); + } + else if (window.opera && window.opera.postError) { + opera.postError(s); + } +} + +var request = createRequest(); +var request2 = createRequest2(); +log('created requests'); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-invalid.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-invalid.expected.err new file mode 100644 index 0000000..bd39cb1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-invalid.expected.err @@ -0,0 +1,2 @@ +jscoverage:javascript-invalid.js:1: SyntaxError: missing ; before statement +jscoverage: parse error in file javascript-invalid.js diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-invalid/javascript-invalid.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-invalid/javascript-invalid.js new file mode 100644 index 0000000..74b863c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-invalid/javascript-invalid.js @@ -0,0 +1 @@ +x y diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-setter.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-setter.expected.err new file mode 100644 index 0000000..d353089 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-setter.expected.err @@ -0,0 +1 @@ +jscoverage:javascript-setter.js:2: expected function diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-setter/javascript-setter.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-setter/javascript-setter.js new file mode 100644 index 0000000..715bc1e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-setter/javascript-setter.js @@ -0,0 +1,3 @@ +var obj = { + x setter: 3 +}; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8.expected/javascript-utf-8.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8.expected/javascript-utf-8.js new file mode 100644 index 0000000..fa04a2c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8.expected/javascript-utf-8.js @@ -0,0 +1,15 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-utf-8.js']) { + _$jscoverage['javascript-utf-8.js'] = []; + _$jscoverage['javascript-utf-8.js'][1] = 0; + _$jscoverage['javascript-utf-8.js'][2] = 0; +} +_$jscoverage['javascript-utf-8.js'][1]++; +var s = "e\u00e8\u00e9\u00ea"; +_$jscoverage['javascript-utf-8.js'][2]++; +var r = /e\u00e8\u00e9\u00ea/; +_$jscoverage['javascript-utf-8.js'].source = ["var s = 'eèéê';","var r = /eèéê/;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8.sh new file mode 100755 index 0000000..bada1bc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# javascript-utf-8.sh - test a JavaScript file with UTF-8 encoding +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr DIR' 1 2 3 15 + +export PATH=.:..:$PATH + +if jscoverage-server --version | grep -q 'iconv\|MultiByteToWideChar' +then + character_encoding_support=yes +else + character_encoding_support=no +fi + +rm -fr DIR +case "$character_encoding_support" in + yes) + $VALGRIND jscoverage --no-highlight --encoding=UTF-8 javascript-utf-8 DIR + diff -u --strip-trailing-cr javascript-utf-8.expected/javascript-utf-8.js DIR/javascript-utf-8.js + ;; + *) + ! $VALGRIND jscoverage --no-highlight --encoding=UTF-8 javascript-utf-8 DIR > OUT 2> ERR + echo "jscoverage: encoding UTF-8 not supported" | diff - ERR + ;; +esac +rm -fr DIR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8/javascript-utf-8.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8/javascript-utf-8.js new file mode 100644 index 0000000..799cd6e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-utf-8/javascript-utf-8.js @@ -0,0 +1,2 @@ +var s = 'eèéê'; +var r = /eèéê/; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-xml.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-xml.expected.err new file mode 100644 index 0000000..017c45e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-xml.expected.err @@ -0,0 +1 @@ +jscoverage:javascript-xml.js:3: unsupported node type (75) diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-xml/javascript-xml.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-xml/javascript-xml.js new file mode 100644 index 0000000..a802d93 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript-xml/javascript-xml.js @@ -0,0 +1,8 @@ +// ECMA 357 11.1.4 +// an XML object representing a person with a name and age +var person = John25; +// a variable containing an XML object representing two employees +var e = + Joe20 + Sue30 +; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-array-comprehension.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-array-comprehension.js new file mode 100644 index 0000000..4ecdc1f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-array-comprehension.js @@ -0,0 +1,32 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-array-comprehension.js']) { + _$jscoverage['javascript-array-comprehension.js'] = []; + _$jscoverage['javascript-array-comprehension.js'][3] = 0; + _$jscoverage['javascript-array-comprehension.js'][4] = 0; + _$jscoverage['javascript-array-comprehension.js'][5] = 0; + _$jscoverage['javascript-array-comprehension.js'][8] = 0; + _$jscoverage['javascript-array-comprehension.js'][9] = 0; + _$jscoverage['javascript-array-comprehension.js'][12] = 0; + _$jscoverage['javascript-array-comprehension.js'][14] = 0; +} +_$jscoverage['javascript-array-comprehension.js'][3]++; +function range(begin, end) { + _$jscoverage['javascript-array-comprehension.js'][4]++; + for (let i = begin; i < end; ++i) { + _$jscoverage['javascript-array-comprehension.js'][5]++; + yield i; +} +} +_$jscoverage['javascript-array-comprehension.js'][8]++; +var ten_squares = [i * i for each (i in range(0, 10))]; +_$jscoverage['javascript-array-comprehension.js'][9]++; +var evens = [i for each (i in range(0, 21)) if (i % 2 == 0)]; +_$jscoverage['javascript-array-comprehension.js'][12]++; +var optimized = [1 for each (i in x) if (0)]; +_$jscoverage['javascript-array-comprehension.js'][14]++; +[i for each (a in x) for each (b in y)]; +_$jscoverage['javascript-array-comprehension.js'].source = ["// https://developer.mozilla.org/en/New_in_JavaScript_1.7","","function range(begin, end) {"," for (let i = begin; i < end; ++i) {"," yield i;"," }","}","var ten_squares = [i * i for each (i in range(0, 10))];","var evens = [i for each (i in range(0, 21)) if (i % 2 == 0)];","","// test optimization","var optimized = [i for each (i in x) if (0)];","","[i for each (a in x) for each (b in y)]"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-assign.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-assign.js new file mode 100644 index 0000000..fc3a7ec --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-assign.js @@ -0,0 +1,51 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-assign.js']) { + _$jscoverage['javascript-assign.js'] = []; + _$jscoverage['javascript-assign.js'][1] = 0; + _$jscoverage['javascript-assign.js'][2] = 0; + _$jscoverage['javascript-assign.js'][3] = 0; + _$jscoverage['javascript-assign.js'][4] = 0; + _$jscoverage['javascript-assign.js'][5] = 0; + _$jscoverage['javascript-assign.js'][6] = 0; + _$jscoverage['javascript-assign.js'][7] = 0; + _$jscoverage['javascript-assign.js'][8] = 0; + _$jscoverage['javascript-assign.js'][9] = 0; + _$jscoverage['javascript-assign.js'][10] = 0; + _$jscoverage['javascript-assign.js'][11] = 0; + _$jscoverage['javascript-assign.js'][12] = 0; + _$jscoverage['javascript-assign.js'][13] = 0; + _$jscoverage['javascript-assign.js'][14] = 0; +} +_$jscoverage['javascript-assign.js'][1]++; +var x = 1; +_$jscoverage['javascript-assign.js'][2]++; +var y = 1; +_$jscoverage['javascript-assign.js'][3]++; +x = y; +_$jscoverage['javascript-assign.js'][4]++; +x += y; +_$jscoverage['javascript-assign.js'][5]++; +x -= y; +_$jscoverage['javascript-assign.js'][6]++; +x *= y; +_$jscoverage['javascript-assign.js'][7]++; +x %= y; +_$jscoverage['javascript-assign.js'][8]++; +x <<= y; +_$jscoverage['javascript-assign.js'][9]++; +x >>= y; +_$jscoverage['javascript-assign.js'][10]++; +x >>>= y; +_$jscoverage['javascript-assign.js'][11]++; +x &= y; +_$jscoverage['javascript-assign.js'][12]++; +x |= y; +_$jscoverage['javascript-assign.js'][13]++; +x ^= y; +_$jscoverage['javascript-assign.js'][14]++; +x /= y; +_$jscoverage['javascript-assign.js'].source = ["var x = 1;","var y = 1;","x = y;","x += y;","x -= y;","x *= y;","x %= y;","x <<= y;","x >>= y;","x >>>= y;","x &= y;","x |= y;","x ^= y;","x /= y;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-colon.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-colon.js new file mode 100644 index 0000000..c99da2b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-colon.js @@ -0,0 +1,24 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-colon.js']) { + _$jscoverage['javascript-colon.js'] = []; + _$jscoverage['javascript-colon.js'][1] = 0; + _$jscoverage['javascript-colon.js'][4] = 0; + _$jscoverage['javascript-colon.js'][5] = 0; + _$jscoverage['javascript-colon.js'][6] = 0; +} +_$jscoverage['javascript-colon.js'][1]++; +x: +y = 0; +_$jscoverage['javascript-colon.js'][4]++; +y: +{ + _$jscoverage['javascript-colon.js'][5]++; + let y = 1; + _$jscoverage['javascript-colon.js'][6]++; + print(y); +} +_$jscoverage['javascript-colon.js'].source = ["x:"," y = 0;","","y: {"," let y = 1;"," print(y);","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-comma.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-comma.js new file mode 100644 index 0000000..5912427 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-comma.js @@ -0,0 +1,12 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-comma.js']) { + _$jscoverage['javascript-comma.js'] = []; + _$jscoverage['javascript-comma.js'][1] = 0; +} +_$jscoverage['javascript-comma.js'][1]++; +x = y, y = x; +_$jscoverage['javascript-comma.js'].source = ["x = y, y = x;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-cr.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-cr.js new file mode 100644 index 0000000..38d52fb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-cr.js @@ -0,0 +1,12 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-cr.js']) { + _$jscoverage['javascript-cr.js'] = []; + _$jscoverage['javascript-cr.js'][4] = 0; +} +_$jscoverage['javascript-cr.js'][4]++; +var x = 1; +_$jscoverage['javascript-cr.js'].source = ["/*","This file has CR line endings.","*/","var x = 1;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-crlf.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-crlf.js new file mode 100644 index 0000000..82a2d12 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-crlf.js @@ -0,0 +1,12 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-crlf.js']) { + _$jscoverage['javascript-crlf.js'] = []; + _$jscoverage['javascript-crlf.js'][4] = 0; +} +_$jscoverage['javascript-crlf.js'][4]++; +var x = 1; +_$jscoverage['javascript-crlf.js'].source = ["/*","This file has CRLF line endings.","*/","var x = 1;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-debugger.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-debugger.js new file mode 100644 index 0000000..a78516e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-debugger.js @@ -0,0 +1,21 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-debugger.js']) { + _$jscoverage['javascript-debugger.js'] = []; + _$jscoverage['javascript-debugger.js'][1] = 0; + _$jscoverage['javascript-debugger.js'][2] = 0; + _$jscoverage['javascript-debugger.js'][5] = 0; +} +_$jscoverage['javascript-debugger.js'][1]++; +try { + _$jscoverage['javascript-debugger.js'][2]++; + f(); +} +catch (e) { + _$jscoverage['javascript-debugger.js'][5]++; + debugger; +} +_$jscoverage['javascript-debugger.js'].source = ["try {"," f();","}","catch (e) {"," debugger;","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-dec.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-dec.js new file mode 100644 index 0000000..4ba2323 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-dec.js @@ -0,0 +1,15 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-dec.js']) { + _$jscoverage['javascript-dec.js'] = []; + _$jscoverage['javascript-dec.js'][1] = 0; + _$jscoverage['javascript-dec.js'][2] = 0; +} +_$jscoverage['javascript-dec.js'][1]++; +x--; +_$jscoverage['javascript-dec.js'][2]++; +--x; +_$jscoverage['javascript-dec.js'].source = ["x--;","--x;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-delete.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-delete.js new file mode 100644 index 0000000..bc96a8f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-delete.js @@ -0,0 +1,12 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-delete.js']) { + _$jscoverage['javascript-delete.js'] = []; + _$jscoverage['javascript-delete.js'][1] = 0; +} +_$jscoverage['javascript-delete.js'][1]++; +delete x; +_$jscoverage['javascript-delete.js'].source = ["delete x;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-destructuring.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-destructuring.js new file mode 100644 index 0000000..ac3d0eb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-destructuring.js @@ -0,0 +1,96 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-destructuring.js']) { + _$jscoverage['javascript-destructuring.js'] = []; + _$jscoverage['javascript-destructuring.js'][3] = 0; + _$jscoverage['javascript-destructuring.js'][5] = 0; + _$jscoverage['javascript-destructuring.js'][6] = 0; + _$jscoverage['javascript-destructuring.js'][8] = 0; + _$jscoverage['javascript-destructuring.js'][10] = 0; + _$jscoverage['javascript-destructuring.js'][11] = 0; + _$jscoverage['javascript-destructuring.js'][12] = 0; + _$jscoverage['javascript-destructuring.js'][15] = 0; + _$jscoverage['javascript-destructuring.js'][16] = 0; + _$jscoverage['javascript-destructuring.js'][17] = 0; + _$jscoverage['javascript-destructuring.js'][20] = 0; + _$jscoverage['javascript-destructuring.js'][21] = 0; + _$jscoverage['javascript-destructuring.js'][23] = 0; + _$jscoverage['javascript-destructuring.js'][24] = 0; + _$jscoverage['javascript-destructuring.js'][25] = 0; + _$jscoverage['javascript-destructuring.js'][26] = 0; + _$jscoverage['javascript-destructuring.js'][27] = 0; + _$jscoverage['javascript-destructuring.js'][30] = 0; + _$jscoverage['javascript-destructuring.js'][31] = 0; + _$jscoverage['javascript-destructuring.js'][32] = 0; + _$jscoverage['javascript-destructuring.js'][35] = 0; + _$jscoverage['javascript-destructuring.js'][37] = 0; + _$jscoverage['javascript-destructuring.js'][38] = 0; + _$jscoverage['javascript-destructuring.js'][39] = 0; + _$jscoverage['javascript-destructuring.js'][40] = 0; + _$jscoverage['javascript-destructuring.js'][41] = 0; +} +_$jscoverage['javascript-destructuring.js'][3]++; +[a, b] = [b, a]; +_$jscoverage['javascript-destructuring.js'][5]++; +function f() { + _$jscoverage['javascript-destructuring.js'][6]++; + return [1, 2]; +} +_$jscoverage['javascript-destructuring.js'][8]++; +[a, b] = f(); +_$jscoverage['javascript-destructuring.js'][10]++; +for (let [name, value] in Iterator(obj)) { + _$jscoverage['javascript-destructuring.js'][11]++; + print(name); + _$jscoverage['javascript-destructuring.js'][12]++; + print(value); +} +_$jscoverage['javascript-destructuring.js'][15]++; +for each (let {name: n, family: {father: f}} in people) { + _$jscoverage['javascript-destructuring.js'][16]++; + print(n); + _$jscoverage['javascript-destructuring.js'][17]++; + print(f); +} +_$jscoverage['javascript-destructuring.js'][20]++; +var [a, , b] = f(); +_$jscoverage['javascript-destructuring.js'][21]++; +[, , ,] = f(); +_$jscoverage['javascript-destructuring.js'][23]++; +function g() { + _$jscoverage['javascript-destructuring.js'][24]++; + var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url); + _$jscoverage['javascript-destructuring.js'][25]++; + if (! parsedURL) { + _$jscoverage['javascript-destructuring.js'][26]++; + return null; + } + _$jscoverage['javascript-destructuring.js'][27]++; + var [, protocol, fullhost, fullpath] = parsedURL; +} +_$jscoverage['javascript-destructuring.js'][30]++; +function h(a, [b, c], {foo: d, "bar": e}) { + _$jscoverage['javascript-destructuring.js'][31]++; + f(); + _$jscoverage['javascript-destructuring.js'][32]++; + g(); +} +_$jscoverage['javascript-destructuring.js'][35]++; +x = (function ([a, b]) { + return a + b; +}); +_$jscoverage['javascript-destructuring.js'][37]++; +({x: x0, y: y0}) = point; +_$jscoverage['javascript-destructuring.js'][38]++; +var {x: x0, y: y0} = point; +_$jscoverage['javascript-destructuring.js'][39]++; +let ({x: x0, y: y0} = point) { + _$jscoverage['javascript-destructuring.js'][40]++; + print(x0); + _$jscoverage['javascript-destructuring.js'][41]++; + print(y0); +} +_$jscoverage['javascript-destructuring.js'].source = ["// https://developer.mozilla.org/en/New_in_JavaScript_1.7","","[a, b] = [b, a];","","function f() {"," return [1, 2];","}","[a, b] = f();","","for (let [name, value] in Iterator(obj)) {"," print(name);"," print(value);","}","","for each (let {name: n, family: { father: f } } in people) {"," print(n);"," print(f);","}","","var [a, , b] = f();","[,,,] = f();","","function g() {"," var parsedURL = /^(\\w+)\\:\\/\\/([^\\/]+)\\/(.*)$/.exec(url);"," if (!parsedURL)"," return null;"," var [, protocol, fullhost, fullpath] = parsedURL;","}","","function h(a, [b, c], {foo: d, 'bar': e}) {"," f();"," g();","}","","x = function([a, b]) a + b;","","({x: x0, y: y0}) = point;","var {x: x0, y: y0} = point;","let ({x: x0, y: y0} = point) {"," print(x0);"," print(y0);","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-do.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-do.js new file mode 100644 index 0000000..23d4557 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-do.js @@ -0,0 +1,28 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-do.js']) { + _$jscoverage['javascript-do.js'] = []; + _$jscoverage['javascript-do.js'][1] = 0; + _$jscoverage['javascript-do.js'][3] = 0; + _$jscoverage['javascript-do.js'][4] = 0; + _$jscoverage['javascript-do.js'][8] = 0; + _$jscoverage['javascript-do.js'][9] = 0; +} +_$jscoverage['javascript-do.js'][1]++; +var x; +_$jscoverage['javascript-do.js'][3]++; +do { + _$jscoverage['javascript-do.js'][4]++; + x = false; +} +while (x); +_$jscoverage['javascript-do.js'][8]++; +do { + _$jscoverage['javascript-do.js'][9]++; + x = false; +} +while (x); +_$jscoverage['javascript-do.js'].source = ["var x;","","do {"," x = false;","}","while (x);","","do"," x = false;","while (x);"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-dot.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-dot.js new file mode 100644 index 0000000..ca91faa --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-dot.js @@ -0,0 +1,30 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-dot.js']) { + _$jscoverage['javascript-dot.js'] = []; + _$jscoverage['javascript-dot.js'][1] = 0; + _$jscoverage['javascript-dot.js'][2] = 0; + _$jscoverage['javascript-dot.js'][3] = 0; + _$jscoverage['javascript-dot.js'][4] = 0; + _$jscoverage['javascript-dot.js'][5] = 0; + _$jscoverage['javascript-dot.js'][7] = 0; + _$jscoverage['javascript-dot.js'][8] = 0; +} +_$jscoverage['javascript-dot.js'][1]++; +x.y = y.x; +_$jscoverage['javascript-dot.js'][2]++; +x.y = y.x; +_$jscoverage['javascript-dot.js'][3]++; +x[y] = y[x]; +_$jscoverage['javascript-dot.js'][4]++; +x["2y"] = y["var"]; +_$jscoverage['javascript-dot.js'][5]++; +x[""] = y[""]; +_$jscoverage['javascript-dot.js'][7]++; +print((123).toString()); +_$jscoverage['javascript-dot.js'][8]++; +({}).toString(); +_$jscoverage['javascript-dot.js'].source = ["x.y = y.x;","x[\"y\"] = y[\"x\"];","x[y] = y[x];","x['2y'] = y['var'];","x[''] = y[\"\"];","","print(123.0.toString());","({}.toString());"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-empty.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-empty.js new file mode 100644 index 0000000..646be4b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-empty.js @@ -0,0 +1,9 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-empty.js']) { + _$jscoverage['javascript-empty.js'] = []; +} +_$jscoverage['javascript-empty.js'].source = []; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-for.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-for.js new file mode 100644 index 0000000..07b9fc2 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-for.js @@ -0,0 +1,51 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-for.js']) { + _$jscoverage['javascript-for.js'] = []; + _$jscoverage['javascript-for.js'][1] = 0; + _$jscoverage['javascript-for.js'][2] = 0; + _$jscoverage['javascript-for.js'][5] = 0; + _$jscoverage['javascript-for.js'][6] = 0; + _$jscoverage['javascript-for.js'][9] = 0; + _$jscoverage['javascript-for.js'][10] = 0; + _$jscoverage['javascript-for.js'][13] = 0; + _$jscoverage['javascript-for.js'][14] = 0; + _$jscoverage['javascript-for.js'][17] = 0; + _$jscoverage['javascript-for.js'][18] = 0; + _$jscoverage['javascript-for.js'][20] = 0; + _$jscoverage['javascript-for.js'][21] = 0; +} +_$jscoverage['javascript-for.js'][1]++; +for (i in x) { + _$jscoverage['javascript-for.js'][2]++; + x(); +} +_$jscoverage['javascript-for.js'][5]++; +for (var i in x) { + _$jscoverage['javascript-for.js'][6]++; + x(); +} +_$jscoverage['javascript-for.js'][9]++; +for (i = 0; i < x; i++) { + _$jscoverage['javascript-for.js'][10]++; + x(); +} +_$jscoverage['javascript-for.js'][13]++; +for (var j = 0; j < x; j++) { + _$jscoverage['javascript-for.js'][14]++; + x(); +} +_$jscoverage['javascript-for.js'][17]++; +for (i in x) { + _$jscoverage['javascript-for.js'][18]++; + x(); +} +_$jscoverage['javascript-for.js'][20]++; +for (i.value in x) { + _$jscoverage['javascript-for.js'][21]++; + x(); +} +_$jscoverage['javascript-for.js'].source = ["for (i in x) {"," x();","}","","for (var i in x) {"," x();","}","","for (i = 0; i < x; i++) {"," x();","}","","for (var j = 0; j < x; j++) {"," x();","}","","for (i in x)"," x();","","for (i.value in x) {"," x();","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-foreach.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-foreach.js new file mode 100644 index 0000000..2c63a81 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-foreach.js @@ -0,0 +1,16 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-foreach.js']) { + _$jscoverage['javascript-foreach.js'] = []; + _$jscoverage['javascript-foreach.js'][6] = 0; + _$jscoverage['javascript-foreach.js'][7] = 0; +} +_$jscoverage['javascript-foreach.js'][6]++; +for each (var item in obj) { + _$jscoverage['javascript-foreach.js'][7]++; + sum += item; +} +_$jscoverage['javascript-foreach.js'].source = ["/*","https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Object_Manipulation_Statements","https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/for_each...in","*/","","for each (var item in obj) {"," sum += item;","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-function.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-function.js new file mode 100644 index 0000000..5adada1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-function.js @@ -0,0 +1,79 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-function.js']) { + _$jscoverage['javascript-function.js'] = []; + _$jscoverage['javascript-function.js'][1] = 0; + _$jscoverage['javascript-function.js'][3] = 0; + _$jscoverage['javascript-function.js'][4] = 0; + _$jscoverage['javascript-function.js'][7] = 0; + _$jscoverage['javascript-function.js'][8] = 0; + _$jscoverage['javascript-function.js'][9] = 0; + _$jscoverage['javascript-function.js'][12] = 0; + _$jscoverage['javascript-function.js'][13] = 0; + _$jscoverage['javascript-function.js'][16] = 0; + _$jscoverage['javascript-function.js'][17] = 0; + _$jscoverage['javascript-function.js'][20] = 0; + _$jscoverage['javascript-function.js'][21] = 0; + _$jscoverage['javascript-function.js'][24] = 0; + _$jscoverage['javascript-function.js'][25] = 0; + _$jscoverage['javascript-function.js'][28] = 0; + _$jscoverage['javascript-function.js'][29] = 0; + _$jscoverage['javascript-function.js'][32] = 0; + _$jscoverage['javascript-function.js'][33] = 0; + _$jscoverage['javascript-function.js'][36] = 0; + _$jscoverage['javascript-function.js'][37] = 0; +} +_$jscoverage['javascript-function.js'][1]++; +function x() { +} +_$jscoverage['javascript-function.js'][3]++; +function x() { + _$jscoverage['javascript-function.js'][4]++; + ; +} +_$jscoverage['javascript-function.js'][7]++; +function x() { + _$jscoverage['javascript-function.js'][8]++; + x(); + _$jscoverage['javascript-function.js'][9]++; + return "x"; +} +_$jscoverage['javascript-function.js'][12]++; +function x(a) { + _$jscoverage['javascript-function.js'][13]++; + x(); +} +_$jscoverage['javascript-function.js'][16]++; +function x(a, b) { + _$jscoverage['javascript-function.js'][17]++; + x(); +} +_$jscoverage['javascript-function.js'][20]++; +x = (function () { + _$jscoverage['javascript-function.js'][21]++; + x(); +}); +_$jscoverage['javascript-function.js'][24]++; +(function () { + _$jscoverage['javascript-function.js'][25]++; + print("x"); +})(); +_$jscoverage['javascript-function.js'][28]++; +(function (a) { + _$jscoverage['javascript-function.js'][29]++; + print("x"); +})(1); +_$jscoverage['javascript-function.js'][32]++; +(function (a, b) { + _$jscoverage['javascript-function.js'][33]++; + print("x"); +})(1, 2); +_$jscoverage['javascript-function.js'][36]++; +(function () { + _$jscoverage['javascript-function.js'][37]++; + print("x"); +}).call(window); +_$jscoverage['javascript-function.js'].source = ["function x() {}","","function x() {"," ;","}","","function x() {"," x();"," return 'x';","}","","function x(a) {"," x();","}","","function x(a, b) {"," x();","}","","x = function() {"," x();","};","","(function () {"," print('x');","})();","","(function (a) {"," print('x');","})(1);","","(function (a, b) {"," print('x');","})(1, 2);","","(function () {"," print('x');","}).call(window);"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-generator-expression.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-generator-expression.js new file mode 100644 index 0000000..6ef1f11 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-generator-expression.js @@ -0,0 +1,45 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-generator-expression.js']) { + _$jscoverage['javascript-generator-expression.js'] = []; + _$jscoverage['javascript-generator-expression.js'][3] = 0; + _$jscoverage['javascript-generator-expression.js'][4] = 0; + _$jscoverage['javascript-generator-expression.js'][5] = 0; + _$jscoverage['javascript-generator-expression.js'][6] = 0; + _$jscoverage['javascript-generator-expression.js'][9] = 0; + _$jscoverage['javascript-generator-expression.js'][12] = 0; + _$jscoverage['javascript-generator-expression.js'][13] = 0; + _$jscoverage['javascript-generator-expression.js'][14] = 0; + _$jscoverage['javascript-generator-expression.js'][16] = 0; + _$jscoverage['javascript-generator-expression.js'][18] = 0; +} +_$jscoverage['javascript-generator-expression.js'][3]++; +var it = (i + 3 for (i in someObj)); +_$jscoverage['javascript-generator-expression.js'][4]++; +try { + _$jscoverage['javascript-generator-expression.js'][5]++; + while (true) { + _$jscoverage['javascript-generator-expression.js'][6]++; + document.write(it.next() + "
\n"); +} +} +catch (err if err instanceof StopIteration) { + _$jscoverage['javascript-generator-expression.js'][9]++; + document.write("End of record.
\n"); +} +_$jscoverage['javascript-generator-expression.js'][12]++; +function handleResults(results) { + _$jscoverage['javascript-generator-expression.js'][13]++; + for (let i in results) { + _$jscoverage['javascript-generator-expression.js'][14]++; + ; +} +} +_$jscoverage['javascript-generator-expression.js'][16]++; +handleResults((i for (i in obj) if (i > 3))); +_$jscoverage['javascript-generator-expression.js'][18]++; +it = (1 for (a in x) for (b in y)); +_$jscoverage['javascript-generator-expression.js'].source = ["// https://developer.mozilla.org/en/New_in_JavaScript_1.8","","let it = (i + 3 for (i in someObj));","try {"," while (true) {"," document.write(it.next() + \"<br>\\n\");"," }","} catch (err if err instanceof StopIteration) {"," document.write(\"End of record.<br>\\n\");","}","","function handleResults( results ) {"," for ( let i in results )"," ;","}","handleResults( i for ( i in obj ) if ( i > 3 ) );","","it = (1 for(a in x) for(b in y));"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-generator.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-generator.js new file mode 100644 index 0000000..fa9cece --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-generator.js @@ -0,0 +1,32 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-generator.js']) { + _$jscoverage['javascript-generator.js'] = []; + _$jscoverage['javascript-generator.js'][3] = 0; + _$jscoverage['javascript-generator.js'][4] = 0; + _$jscoverage['javascript-generator.js'][5] = 0; + _$jscoverage['javascript-generator.js'][6] = 0; + _$jscoverage['javascript-generator.js'][7] = 0; + _$jscoverage['javascript-generator.js'][8] = 0; + _$jscoverage['javascript-generator.js'][9] = 0; +} +_$jscoverage['javascript-generator.js'][3]++; +function fib() { + _$jscoverage['javascript-generator.js'][4]++; + var i = 0, j = 1; + _$jscoverage['javascript-generator.js'][5]++; + while (true) { + _$jscoverage['javascript-generator.js'][6]++; + yield i; + _$jscoverage['javascript-generator.js'][7]++; + var t = i; + _$jscoverage['javascript-generator.js'][8]++; + i = j; + _$jscoverage['javascript-generator.js'][9]++; + j += t; +} +} +_$jscoverage['javascript-generator.js'].source = ["// https://developer.mozilla.org/en/New_in_JavaScript_1.7","","function fib() {"," var i = 0, j = 1;"," while (true) {"," yield i;"," var t = i;"," i = j;"," j += t;"," }","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-getter-setter.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-getter-setter.js new file mode 100644 index 0000000..cffc83f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-getter-setter.js @@ -0,0 +1,31 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-getter-setter.js']) { + _$jscoverage['javascript-getter-setter.js'] = []; + _$jscoverage['javascript-getter-setter.js'][1] = 0; + _$jscoverage['javascript-getter-setter.js'][4] = 0; + _$jscoverage['javascript-getter-setter.js'][7] = 0; + _$jscoverage['javascript-getter-setter.js'][11] = 0; + _$jscoverage['javascript-getter-setter.js'][14] = 0; + _$jscoverage['javascript-getter-setter.js'][17] = 0; +} +_$jscoverage['javascript-getter-setter.js'][1]++; +var o = {_x: 123, get x () { + _$jscoverage['javascript-getter-setter.js'][4]++; + return this._x; +}, set x (value) { + _$jscoverage['javascript-getter-setter.js'][7]++; + this._x = value; +}}; +_$jscoverage['javascript-getter-setter.js'][11]++; +o = {_x: 123, get x get_x() { + _$jscoverage['javascript-getter-setter.js'][14]++; + return this._x; +}, set x set_x(value) { + _$jscoverage['javascript-getter-setter.js'][17]++; + this._x = value; +}}; +_$jscoverage['javascript-getter-setter.js'].source = ["var o = {"," _x: 123,"," get x() {"," return this._x;"," },"," set x(value) {"," this._x = value;"," }","};","","o = {"," _x: 123,"," get x get_x() {"," return this._x;"," },"," set x set_x(value) {"," this._x = value;"," }","};"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-hook.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-hook.js new file mode 100644 index 0000000..08f33d0 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-hook.js @@ -0,0 +1,15 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-hook.js']) { + _$jscoverage['javascript-hook.js'] = []; + _$jscoverage['javascript-hook.js'][1] = 0; + _$jscoverage['javascript-hook.js'][2] = 0; +} +_$jscoverage['javascript-hook.js'][1]++; +var x = 1; +_$jscoverage['javascript-hook.js'][2]++; +var y = x === 1? "x": "y"; +_$jscoverage['javascript-hook.js'].source = ["var x = 1;","var y = x === 1? \"x\": \"y\";"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-if.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-if.js new file mode 100644 index 0000000..8559e59 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-if.js @@ -0,0 +1,71 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-if.js']) { + _$jscoverage['javascript-if.js'] = []; + _$jscoverage['javascript-if.js'][1] = 0; + _$jscoverage['javascript-if.js'][3] = 0; + _$jscoverage['javascript-if.js'][4] = 0; + _$jscoverage['javascript-if.js'][6] = 0; + _$jscoverage['javascript-if.js'][7] = 0; + _$jscoverage['javascript-if.js'][10] = 0; + _$jscoverage['javascript-if.js'][11] = 0; + _$jscoverage['javascript-if.js'][13] = 0; + _$jscoverage['javascript-if.js'][15] = 0; + _$jscoverage['javascript-if.js'][16] = 0; + _$jscoverage['javascript-if.js'][19] = 0; + _$jscoverage['javascript-if.js'][22] = 0; + _$jscoverage['javascript-if.js'][23] = 0; + _$jscoverage['javascript-if.js'][25] = 0; + _$jscoverage['javascript-if.js'][26] = 0; + _$jscoverage['javascript-if.js'][29] = 0; +} +_$jscoverage['javascript-if.js'][1]++; +var x = 0; +_$jscoverage['javascript-if.js'][3]++; +if (x) { + _$jscoverage['javascript-if.js'][4]++; + x = 0; +} +_$jscoverage['javascript-if.js'][6]++; +if (x) { + _$jscoverage['javascript-if.js'][7]++; + x = 0; +} +_$jscoverage['javascript-if.js'][10]++; +if (x) { + _$jscoverage['javascript-if.js'][11]++; + x = 0; +} +else { + _$jscoverage['javascript-if.js'][13]++; + x = 0; +} +_$jscoverage['javascript-if.js'][15]++; +if (x) { + _$jscoverage['javascript-if.js'][16]++; + x = 0; +} +else { + _$jscoverage['javascript-if.js'][19]++; + x = 0; +} +_$jscoverage['javascript-if.js'][22]++; +if (x) { + _$jscoverage['javascript-if.js'][23]++; + x = 0; +} +else { + _$jscoverage['javascript-if.js'][25]++; + if (x) { + _$jscoverage['javascript-if.js'][26]++; + x = 0; + } + else { + _$jscoverage['javascript-if.js'][29]++; + x = 0; + } +} +_$jscoverage['javascript-if.js'].source = ["var x = 0;","","if (x)"," x = 0;","","if (x) {"," x = 0;","}","","if (x)"," x = 0;","else"," x = 0;","","if (x) {"," x = 0;","}","else {"," x = 0;","}","","if (x) {"," x = 0;","}","else if (x) {"," x = 0;","}","else {"," x = 0;","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-in.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-in.js new file mode 100644 index 0000000..5f6b35a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-in.js @@ -0,0 +1,19 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-in.js']) { + _$jscoverage['javascript-in.js'] = []; + _$jscoverage['javascript-in.js'][1] = 0; + _$jscoverage['javascript-in.js'][2] = 0; + _$jscoverage['javascript-in.js'][3] = 0; +} +_$jscoverage['javascript-in.js'][1]++; +var x = {}; +_$jscoverage['javascript-in.js'][2]++; +if ("a" in x) { + _$jscoverage['javascript-in.js'][3]++; + x = null; +} +_$jscoverage['javascript-in.js'].source = ["var x = {};","if ('a' in x) {"," x = null;","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-inc.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-inc.js new file mode 100644 index 0000000..7c1730f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-inc.js @@ -0,0 +1,15 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-inc.js']) { + _$jscoverage['javascript-inc.js'] = []; + _$jscoverage['javascript-inc.js'][1] = 0; + _$jscoverage['javascript-inc.js'][2] = 0; +} +_$jscoverage['javascript-inc.js'][1]++; +x++; +_$jscoverage['javascript-inc.js'][2]++; +++x; +_$jscoverage['javascript-inc.js'].source = ["x++;","++x;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-iso-8859-1.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-iso-8859-1.js new file mode 100644 index 0000000..e4650a9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-iso-8859-1.js @@ -0,0 +1,15 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-iso-8859-1.js']) { + _$jscoverage['javascript-iso-8859-1.js'] = []; + _$jscoverage['javascript-iso-8859-1.js'][1] = 0; + _$jscoverage['javascript-iso-8859-1.js'][2] = 0; +} +_$jscoverage['javascript-iso-8859-1.js'][1]++; +var s = "e\u00e8\u00e9\u00ea"; +_$jscoverage['javascript-iso-8859-1.js'][2]++; +var r = /e\u00e8\u00e9\u00ea/; +_$jscoverage['javascript-iso-8859-1.js'].source = ["var s = 'eèéê';","var r = /eèéê/;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-lambda.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-lambda.js new file mode 100644 index 0000000..9681cd9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-lambda.js @@ -0,0 +1,14 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-lambda.js']) { + _$jscoverage['javascript-lambda.js'] = []; + _$jscoverage['javascript-lambda.js'][3] = 0; +} +_$jscoverage['javascript-lambda.js'][3]++; +var square = (function (x) { + return x * x; +}); +_$jscoverage['javascript-lambda.js'].source = ["// https://developer.mozilla.org/en/New_in_JavaScript_1.8","","var square = function(x) x * x;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-let.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-let.js new file mode 100644 index 0000000..b726ff7 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-let.js @@ -0,0 +1,148 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-let.js']) { + _$jscoverage['javascript-let.js'] = []; + _$jscoverage['javascript-let.js'][5] = 0; + _$jscoverage['javascript-let.js'][6] = 0; + _$jscoverage['javascript-let.js'][11] = 0; + _$jscoverage['javascript-let.js'][15] = 0; + _$jscoverage['javascript-let.js'][16] = 0; + _$jscoverage['javascript-let.js'][17] = 0; + _$jscoverage['javascript-let.js'][20] = 0; + _$jscoverage['javascript-let.js'][22] = 0; + _$jscoverage['javascript-let.js'][23] = 0; + _$jscoverage['javascript-let.js'][24] = 0; + _$jscoverage['javascript-let.js'][26] = 0; + _$jscoverage['javascript-let.js'][27] = 0; + _$jscoverage['javascript-let.js'][28] = 0; + _$jscoverage['javascript-let.js'][30] = 0; + _$jscoverage['javascript-let.js'][33] = 0; + _$jscoverage['javascript-let.js'][34] = 0; + _$jscoverage['javascript-let.js'][35] = 0; + _$jscoverage['javascript-let.js'][36] = 0; + _$jscoverage['javascript-let.js'][37] = 0; + _$jscoverage['javascript-let.js'][39] = 0; + _$jscoverage['javascript-let.js'][42] = 0; + _$jscoverage['javascript-let.js'][43] = 0; + _$jscoverage['javascript-let.js'][45] = 0; + _$jscoverage['javascript-let.js'][46] = 0; + _$jscoverage['javascript-let.js'][48] = 0; + _$jscoverage['javascript-let.js'][51] = 0; + _$jscoverage['javascript-let.js'][52] = 0; + _$jscoverage['javascript-let.js'][55] = 0; + _$jscoverage['javascript-let.js'][56] = 0; + _$jscoverage['javascript-let.js'][60] = 0; + _$jscoverage['javascript-let.js'][64] = 0; + _$jscoverage['javascript-let.js'][65] = 0; + _$jscoverage['javascript-let.js'][69] = 0; + _$jscoverage['javascript-let.js'][70] = 0; + _$jscoverage['javascript-let.js'][71] = 0; + _$jscoverage['javascript-let.js'][74] = 0; + _$jscoverage['javascript-let.js'][75] = 0; + _$jscoverage['javascript-let.js'][76] = 0; + _$jscoverage['javascript-let.js'][78] = 0; + _$jscoverage['javascript-let.js'][79] = 0; +} +_$jscoverage['javascript-let.js'][5]++; +let (x = x + 10, y = 12) { + _$jscoverage['javascript-let.js'][6]++; + print(x + y + "\n"); +} +_$jscoverage['javascript-let.js'][11]++; +print(let(x = x + 10, y = 12) x + y + "
\n"); +_$jscoverage['javascript-let.js'][15]++; +if (x > y) { + { + _$jscoverage['javascript-let.js'][16]++; + let gamma = 12.7 + y; + _$jscoverage['javascript-let.js'][17]++; + i = gamma * x; + } +} +_$jscoverage['javascript-let.js'][20]++; +var list = document.getElementById("list"); +_$jscoverage['javascript-let.js'][22]++; +for (var i = 1; i <= 5; i++) { + { + _$jscoverage['javascript-let.js'][23]++; + var item = document.createElement("LI"); + _$jscoverage['javascript-let.js'][24]++; + item.appendChild(document.createTextNode("Item " + i)); + _$jscoverage['javascript-let.js'][26]++; + let j = i; + _$jscoverage['javascript-let.js'][27]++; + item.onclick = (function (ev) { + _$jscoverage['javascript-let.js'][28]++; + alert("Item " + j + " is clicked."); +}); + _$jscoverage['javascript-let.js'][30]++; + list.appendChild(item); + } +} +_$jscoverage['javascript-let.js'][33]++; +function varTest() { + _$jscoverage['javascript-let.js'][34]++; + var x = 31; + _$jscoverage['javascript-let.js'][35]++; + if (true) { + _$jscoverage['javascript-let.js'][36]++; + var x = 71; + _$jscoverage['javascript-let.js'][37]++; + alert(x); + } + _$jscoverage['javascript-let.js'][39]++; + alert(x); +} +_$jscoverage['javascript-let.js'][42]++; +function letTest() { + _$jscoverage['javascript-let.js'][43]++; + var x = 31; + { + _$jscoverage['javascript-let.js'][45]++; + let x = 71; + _$jscoverage['javascript-let.js'][46]++; + alert(x); + } + _$jscoverage['javascript-let.js'][48]++; + alert(x); +} +_$jscoverage['javascript-let.js'][51]++; +function letTests() { + _$jscoverage['javascript-let.js'][52]++; + var x = 10; + _$jscoverage['javascript-let.js'][55]++; + let (x = x + 20) { + _$jscoverage['javascript-let.js'][56]++; + alert(x); + } + _$jscoverage['javascript-let.js'][60]++; + alert(let(x = x + 20) x); + { + _$jscoverage['javascript-let.js'][64]++; + let x = x + 20; + _$jscoverage['javascript-let.js'][65]++; + alert(x); + } +} +_$jscoverage['javascript-let.js'][69]++; +var x = "global"; +_$jscoverage['javascript-let.js'][70]++; +var x = 42; +_$jscoverage['javascript-let.js'][71]++; +document.write(this.x + "
\n"); +_$jscoverage['javascript-let.js'][74]++; +var i = 0; +_$jscoverage['javascript-let.js'][75]++; +for (let i = i; i < 10; i++) { + _$jscoverage['javascript-let.js'][76]++; + document.write(i + "
\n"); +} +_$jscoverage['javascript-let.js'][78]++; +for (let [name, value] in obj) { + _$jscoverage['javascript-let.js'][79]++; + document.write("Name: " + name + ", Value: " + value + "
\n"); +} +_$jscoverage['javascript-let.js'].source = ["// https://developer.mozilla.org/en/New_in_JavaScript_1.7","","// let statement","","let (x = x+10, y = 12) {"," print(x+y + \"\\n\");","}","","// let expressions","","print( let(x = x + 10, y = 12) x+y + \"<br>\\n\");","","// let definitions","","if (x > y) {"," let gamma = 12.7 + y;"," i = gamma * x;","}","","var list = document.getElementById(\"list\");","","for (var i = 1; i <= 5; i++) {"," var item = document.createElement(\"LI\");"," item.appendChild(document.createTextNode(\"Item \" + i));",""," let j = i;"," item.onclick = function (ev) {"," alert(\"Item \" + j + \" is clicked.\");"," };"," list.appendChild(item);","}","","function varTest() {"," var x = 31;"," if (true) {"," var x = 71; // same variable!"," alert(x); // 71"," }"," alert(x); // 71","}","","function letTest() {"," let x = 31;"," if (true) {"," let x = 71; // different variable"," alert(x); // 71"," }"," alert(x); // 31","}","","function letTests() {"," let x = 10;",""," // let-statement"," let (x = x + 20) {"," alert(x); // 30"," }",""," // let-expression"," alert(let (x = x + 20) x); // 30",""," // let-definition"," {"," let x = x + 20; // x here evaluates to undefined"," alert(x); // undefined + 20 ==> NaN"," }","}","","var x = 'global';","let x = 42;","document.write(this.x + \"<br>\\n\");","","// let-scoped variables in for loops","var i=0;","for ( let i=i ; i < 10 ; i++ )"," document.write(i + \"<br>\\n\");","","for ( let [name,value] in obj )"," document.write(\"Name: \" + name + \", Value: \" + value + \"<br>\\n\");"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-lf.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-lf.js new file mode 100644 index 0000000..c698ede --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-lf.js @@ -0,0 +1,12 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-lf.js']) { + _$jscoverage['javascript-lf.js'] = []; + _$jscoverage['javascript-lf.js'][4] = 0; +} +_$jscoverage['javascript-lf.js'][4]++; +var x = 1; +_$jscoverage['javascript-lf.js'].source = ["/*","This file has LF line endings.","*/","var x = 1;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-new.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-new.js new file mode 100644 index 0000000..417227a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-new.js @@ -0,0 +1,22 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-new.js']) { + _$jscoverage['javascript-new.js'] = []; + _$jscoverage['javascript-new.js'][1] = 0; + _$jscoverage['javascript-new.js'][2] = 0; + _$jscoverage['javascript-new.js'][3] = 0; + _$jscoverage['javascript-new.js'][4] = 0; +} +_$jscoverage['javascript-new.js'][1]++; +function X() { +} +_$jscoverage['javascript-new.js'][2]++; +x = new X(); +_$jscoverage['javascript-new.js'][3]++; +x = new X(1); +_$jscoverage['javascript-new.js'][4]++; +x = new X(1, 2); +_$jscoverage['javascript-new.js'].source = ["function X() {}","x = new X();","x = new X(1);","x = new X(1, 2);"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-number.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-number.js new file mode 100644 index 0000000..45a9b77 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-number.js @@ -0,0 +1,57 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-number.js']) { + _$jscoverage['javascript-number.js'] = []; + _$jscoverage['javascript-number.js'][1] = 0; + _$jscoverage['javascript-number.js'][2] = 0; + _$jscoverage['javascript-number.js'][3] = 0; + _$jscoverage['javascript-number.js'][5] = 0; + _$jscoverage['javascript-number.js'][6] = 0; + _$jscoverage['javascript-number.js'][8] = 0; + _$jscoverage['javascript-number.js'][9] = 0; + _$jscoverage['javascript-number.js'][11] = 0; + _$jscoverage['javascript-number.js'][12] = 0; + _$jscoverage['javascript-number.js'][13] = 0; + _$jscoverage['javascript-number.js'][14] = 0; + _$jscoverage['javascript-number.js'][15] = 0; + _$jscoverage['javascript-number.js'][16] = 0; + _$jscoverage['javascript-number.js'][17] = 0; + _$jscoverage['javascript-number.js'][18] = 0; + _$jscoverage['javascript-number.js'][19] = 0; +} +_$jscoverage['javascript-number.js'][1]++; +x = 1; +_$jscoverage['javascript-number.js'][2]++; +y = 2; +_$jscoverage['javascript-number.js'][3]++; +z = 10.5; +_$jscoverage['javascript-number.js'][5]++; +a = Number.POSITIVE_INFINITY; +_$jscoverage['javascript-number.js'][6]++; +a = Number.NEGATIVE_INFINITY; +_$jscoverage['javascript-number.js'][8]++; +a = 0; +_$jscoverage['javascript-number.js'][9]++; +a = -0; +_$jscoverage['javascript-number.js'][11]++; +a = Number.NaN; +_$jscoverage['javascript-number.js'][12]++; +a = Number.NaN; +_$jscoverage['javascript-number.js'][13]++; +a = 0 / (-0); +_$jscoverage['javascript-number.js'][14]++; +a = Number.NaN; +_$jscoverage['javascript-number.js'][15]++; +a = (-0) / 0; +_$jscoverage['javascript-number.js'][16]++; +a = Number.NaN; +_$jscoverage['javascript-number.js'][17]++; +a = -0 / (-0); +_$jscoverage['javascript-number.js'][18]++; +a = (-0) / -0; +_$jscoverage['javascript-number.js'][19]++; +a = (-0) / (-0); +_$jscoverage['javascript-number.js'].source = ["x = 1;","y = 2;","z = 10.5;","","a = 1 / 0;","a = -1 / 0;","","a = 0;","a = -0;","","a = 0 / 0;","a = 0 / -0;","a = 0 / (-0);","a = -0 / 0;","a = (-0) / 0;","a = -0 / -0;","a = -0 / (-0);","a = (-0) / -0;","a = (-0) / (-0);"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-object.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-object.js new file mode 100644 index 0000000..b3cf03f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-object.js @@ -0,0 +1,15 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-object.js']) { + _$jscoverage['javascript-object.js'] = []; + _$jscoverage['javascript-object.js'][1] = 0; + _$jscoverage['javascript-object.js'][2] = 0; +} +_$jscoverage['javascript-object.js'][1]++; +x = /x\(\)\\\//i; +_$jscoverage['javascript-object.js'][2]++; +y = /\u0001\u002f/gm; +_$jscoverage['javascript-object.js'].source = ["x = /x\\(\\)\\\\\\//i;","y = /\\u0001\\u002f/gm;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-op.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-op.js new file mode 100644 index 0000000..b6966aa --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-op.js @@ -0,0 +1,108 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-op.js']) { + _$jscoverage['javascript-op.js'] = []; + _$jscoverage['javascript-op.js'][1] = 0; + _$jscoverage['javascript-op.js'][4] = 0; + _$jscoverage['javascript-op.js'][5] = 0; + _$jscoverage['javascript-op.js'][8] = 0; + _$jscoverage['javascript-op.js'][9] = 0; + _$jscoverage['javascript-op.js'][11] = 0; + _$jscoverage['javascript-op.js'][13] = 0; + _$jscoverage['javascript-op.js'][16] = 0; + _$jscoverage['javascript-op.js'][17] = 0; + _$jscoverage['javascript-op.js'][20] = 0; + _$jscoverage['javascript-op.js'][21] = 0; + _$jscoverage['javascript-op.js'][24] = 0; + _$jscoverage['javascript-op.js'][25] = 0; + _$jscoverage['javascript-op.js'][28] = 0; + _$jscoverage['javascript-op.js'][29] = 0; + _$jscoverage['javascript-op.js'][30] = 0; + _$jscoverage['javascript-op.js'][31] = 0; + _$jscoverage['javascript-op.js'][34] = 0; + _$jscoverage['javascript-op.js'][35] = 0; + _$jscoverage['javascript-op.js'][36] = 0; + _$jscoverage['javascript-op.js'][37] = 0; + _$jscoverage['javascript-op.js'][40] = 0; + _$jscoverage['javascript-op.js'][41] = 0; + _$jscoverage['javascript-op.js'][42] = 0; + _$jscoverage['javascript-op.js'][45] = 0; + _$jscoverage['javascript-op.js'][46] = 0; + _$jscoverage['javascript-op.js'][47] = 0; + _$jscoverage['javascript-op.js'][48] = 0; + _$jscoverage['javascript-op.js'][51] = 0; + _$jscoverage['javascript-op.js'][52] = 0; + _$jscoverage['javascript-op.js'][53] = 0; + _$jscoverage['javascript-op.js'][54] = 0; + _$jscoverage['javascript-op.js'][55] = 0; +} +_$jscoverage['javascript-op.js'][1]++; +var a = 1, b = 1, c = 1, d = 1; +_$jscoverage['javascript-op.js'][4]++; +x = a || b || c; +_$jscoverage['javascript-op.js'][5]++; +x = a || b || c || d; +_$jscoverage['javascript-op.js'][8]++; +x = a && b && c; +_$jscoverage['javascript-op.js'][9]++; +x = a && b && c && d; +_$jscoverage['javascript-op.js'][11]++; +x = a && b || c; +_$jscoverage['javascript-op.js'][13]++; +x = a || b && c; +_$jscoverage['javascript-op.js'][16]++; +x = a | b | c; +_$jscoverage['javascript-op.js'][17]++; +x = a | b | c | d; +_$jscoverage['javascript-op.js'][20]++; +x = a ^ b ^ c; +_$jscoverage['javascript-op.js'][21]++; +x = a ^ b ^ c ^ d; +_$jscoverage['javascript-op.js'][24]++; +x = a & b & c; +_$jscoverage['javascript-op.js'][25]++; +x = a & b & c & d; +_$jscoverage['javascript-op.js'][28]++; +x = a == b; +_$jscoverage['javascript-op.js'][29]++; +x = a != b; +_$jscoverage['javascript-op.js'][30]++; +x = a === b; +_$jscoverage['javascript-op.js'][31]++; +x = a !== b; +_$jscoverage['javascript-op.js'][34]++; +x = a < b; +_$jscoverage['javascript-op.js'][35]++; +x = a <= b; +_$jscoverage['javascript-op.js'][36]++; +x = a > b; +_$jscoverage['javascript-op.js'][37]++; +x = a >= b; +_$jscoverage['javascript-op.js'][40]++; +x = a << b; +_$jscoverage['javascript-op.js'][41]++; +x = a >> b; +_$jscoverage['javascript-op.js'][42]++; +x = a >>> b; +_$jscoverage['javascript-op.js'][45]++; +x = a + b; +_$jscoverage['javascript-op.js'][46]++; +x = a + b + c; +_$jscoverage['javascript-op.js'][47]++; +x = a + b + c + d; +_$jscoverage['javascript-op.js'][48]++; +x = a - b; +_$jscoverage['javascript-op.js'][51]++; +x = a * b; +_$jscoverage['javascript-op.js'][52]++; +x = a * b * c; +_$jscoverage['javascript-op.js'][53]++; +x = a * b * c * d; +_$jscoverage['javascript-op.js'][54]++; +x = a / b; +_$jscoverage['javascript-op.js'][55]++; +x = a % b; +_$jscoverage['javascript-op.js'].source = ["var a = 1, b = 1, c = 1, d = 1;","","/* TOK_OR */","x = a || b || c;","x = a || b || c || d;","","/* TOK_AND */","x = a && b && c;","x = a && b && c && d;","","x = a && b || c;","","x = a || b && c;","","// TOK_BITOR","x = a | b | c;","x = a | b | c | d;","","// TOK_BITXOR","x = a ^ b ^ c;","x = a ^ b ^ c ^ d;","","// TOK_BITAND","x = a & b & c;","x = a & b & c & d;","","// TOK_EQUOP","x = a == b;","x = a != b;","x = a === b;","x = a !== b;","","// TOK_RELOP","x = a < b;","x = a <= b;","x = a > b;","x = a >= b;","","// TOK_SHOP","x = a << b;","x = a >> b;","x = a >>> b;","","/* TOK_PLUS, TOK_MINUS */","x = a + b;","x = a + b + c;","x = a + b + c + d;","x = a - b;","","// TOK_STAR, TOK_DIVOP","x = a * b;","x = a * b * c;","x = a * b * c * d;","x = a / b;","x = a % b;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-primary.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-primary.js new file mode 100644 index 0000000..c6e46d9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-primary.js @@ -0,0 +1,21 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-primary.js']) { + _$jscoverage['javascript-primary.js'] = []; + _$jscoverage['javascript-primary.js'][1] = 0; + _$jscoverage['javascript-primary.js'][2] = 0; + _$jscoverage['javascript-primary.js'][3] = 0; + _$jscoverage['javascript-primary.js'][4] = 0; +} +_$jscoverage['javascript-primary.js'][1]++; +x = true; +_$jscoverage['javascript-primary.js'][2]++; +x = false; +_$jscoverage['javascript-primary.js'][3]++; +x = null; +_$jscoverage['javascript-primary.js'][4]++; +x = this; +_$jscoverage['javascript-primary.js'].source = ["x = true;","x = false;","x = null;","x = this;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rb.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rb.js new file mode 100644 index 0000000..df807b1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rb.js @@ -0,0 +1,24 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-rb.js']) { + _$jscoverage['javascript-rb.js'] = []; + _$jscoverage['javascript-rb.js'][1] = 0; + _$jscoverage['javascript-rb.js'][2] = 0; + _$jscoverage['javascript-rb.js'][3] = 0; + _$jscoverage['javascript-rb.js'][4] = 0; + _$jscoverage['javascript-rb.js'][5] = 0; +} +_$jscoverage['javascript-rb.js'][1]++; +x = []; +_$jscoverage['javascript-rb.js'][2]++; +x = [x]; +_$jscoverage['javascript-rb.js'][3]++; +x = [x, y]; +_$jscoverage['javascript-rb.js'][4]++; +x = [x, y,]; +_$jscoverage['javascript-rb.js'][5]++; +x = [x, , y]; +_$jscoverage['javascript-rb.js'].source = ["x = [];","x = [x];","x = [x, y];","x = [x, y,];","x = [x,, y];"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rc.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rc.js new file mode 100644 index 0000000..e3108d0 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rc.js @@ -0,0 +1,15 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-rc.js']) { + _$jscoverage['javascript-rc.js'] = []; + _$jscoverage['javascript-rc.js'][1] = 0; + _$jscoverage['javascript-rc.js'][4] = 0; +} +_$jscoverage['javascript-rc.js'][1]++; +x = {x: y}; +_$jscoverage['javascript-rc.js'][4]++; +x = {x: y, y: x}; +_$jscoverage['javascript-rc.js'].source = ["x = {"," x: y","};","x = {"," x: y,"," y: x","};"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rp.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rp.js new file mode 100644 index 0000000..47df295 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-rp.js @@ -0,0 +1,12 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-rp.js']) { + _$jscoverage['javascript-rp.js'] = []; + _$jscoverage['javascript-rp.js'][1] = 0; +} +_$jscoverage['javascript-rp.js'][1]++; +x = a + (b - c); +_$jscoverage['javascript-rp.js'].source = ["x = a + (b - c);"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-special-characters.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-special-characters.js new file mode 100644 index 0000000..0154e86 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-special-characters.js @@ -0,0 +1,30 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-special-characters.js']) { + _$jscoverage['javascript-special-characters.js'] = []; + _$jscoverage['javascript-special-characters.js'][1] = 0; + _$jscoverage['javascript-special-characters.js'][2] = 0; + _$jscoverage['javascript-special-characters.js'][5] = 0; + _$jscoverage['javascript-special-characters.js'][6] = 0; + _$jscoverage['javascript-special-characters.js'][9] = 0; + _$jscoverage['javascript-special-characters.js'][10] = 0; +} +_$jscoverage['javascript-special-characters.js'][1]++; +function f() { + _$jscoverage['javascript-special-characters.js'][2]++; + return "'"; +} +_$jscoverage['javascript-special-characters.js'][5]++; +function g() { + _$jscoverage['javascript-special-characters.js'][6]++; + return "\""; +} +_$jscoverage['javascript-special-characters.js'][9]++; +function h() { + _$jscoverage['javascript-special-characters.js'][10]++; + return "\\"; +} +_$jscoverage['javascript-special-characters.js'].source = ["function f() {","\treturn '\\'';","}"," ","function g() {","\treturn \"\\\"\";","}"," ","function h() {","\treturn '\\\\';","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-string.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-string.js new file mode 100644 index 0000000..3dbacc8 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-string.js @@ -0,0 +1,36 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-string.js']) { + _$jscoverage['javascript-string.js'] = []; + _$jscoverage['javascript-string.js'][1] = 0; + _$jscoverage['javascript-string.js'][2] = 0; + _$jscoverage['javascript-string.js'][3] = 0; + _$jscoverage['javascript-string.js'][4] = 0; + _$jscoverage['javascript-string.js'][5] = 0; + _$jscoverage['javascript-string.js'][6] = 0; + _$jscoverage['javascript-string.js'][7] = 0; + _$jscoverage['javascript-string.js'][8] = 0; + _$jscoverage['javascript-string.js'][10] = 0; +} +_$jscoverage['javascript-string.js'][1]++; +x = ""; +_$jscoverage['javascript-string.js'][2]++; +x = ""; +_$jscoverage['javascript-string.js'][3]++; +x = "x"; +_$jscoverage['javascript-string.js'][4]++; +x = "x"; +_$jscoverage['javascript-string.js'][5]++; +x = "\""; +_$jscoverage['javascript-string.js'][6]++; +x = "'"; +_$jscoverage['javascript-string.js'][7]++; +x = "\b\t\n\u000b\f\r\"'\\"; +_$jscoverage['javascript-string.js'][8]++; +x = new RegExp("x\\(\\)\\\\\\/"); +_$jscoverage['javascript-string.js'][10]++; +x = "foobar"; +_$jscoverage['javascript-string.js'].source = ["x = \"\";","x = '';","x = \"x\";","x = 'x';","x = \"\\\"\";","x = '\\'';","x = \"\\b\\t\\n\\v\\f\\r\\\"\\'\\\\\";","x = new RegExp('x\\\\(\\\\)\\\\\\\\\\\\/');","","x = 'foo\\","bar';"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-switch.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-switch.js new file mode 100644 index 0000000..e198d7f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-switch.js @@ -0,0 +1,55 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-switch.js']) { + _$jscoverage['javascript-switch.js'] = []; + _$jscoverage['javascript-switch.js'][1] = 0; + _$jscoverage['javascript-switch.js'][3] = 0; + _$jscoverage['javascript-switch.js'][4] = 0; + _$jscoverage['javascript-switch.js'][6] = 0; + _$jscoverage['javascript-switch.js'][7] = 0; + _$jscoverage['javascript-switch.js'][8] = 0; + _$jscoverage['javascript-switch.js'][10] = 0; + _$jscoverage['javascript-switch.js'][11] = 0; + _$jscoverage['javascript-switch.js'][14] = 0; + _$jscoverage['javascript-switch.js'][16] = 0; + _$jscoverage['javascript-switch.js'][17] = 0; + _$jscoverage['javascript-switch.js'][18] = 0; + _$jscoverage['javascript-switch.js'][20] = 0; +} +_$jscoverage['javascript-switch.js'][1]++; +switch (x) { +case x: + _$jscoverage['javascript-switch.js'][3]++; + x = 0; + _$jscoverage['javascript-switch.js'][4]++; + break; +case y: + _$jscoverage['javascript-switch.js'][6]++; + x = 0; + _$jscoverage['javascript-switch.js'][7]++; + y = 0; + _$jscoverage['javascript-switch.js'][8]++; + break; +default: + _$jscoverage['javascript-switch.js'][10]++; + x = 0; + _$jscoverage['javascript-switch.js'][11]++; + break; +} +_$jscoverage['javascript-switch.js'][14]++; +switch (x) { +case 1: + _$jscoverage['javascript-switch.js'][16]++; + let y = 1; + _$jscoverage['javascript-switch.js'][17]++; + f(y); + _$jscoverage['javascript-switch.js'][18]++; + break; +case 2: + _$jscoverage['javascript-switch.js'][20]++; + break; +} +_$jscoverage['javascript-switch.js'].source = ["switch (x) {","case x:"," x = 0;"," break;","case y:"," x = 0;"," y = 0;"," break;","default:"," x = 0;"," break;","}","","switch (x) {","case 1:"," let y = 1;"," f(y);"," break;","case 2:"," break;","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-throw.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-throw.js new file mode 100644 index 0000000..2acaa17 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-throw.js @@ -0,0 +1,21 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-throw.js']) { + _$jscoverage['javascript-throw.js'] = []; + _$jscoverage['javascript-throw.js'][1] = 0; + _$jscoverage['javascript-throw.js'][2] = 0; + _$jscoverage['javascript-throw.js'][5] = 0; +} +_$jscoverage['javascript-throw.js'][1]++; +try { + _$jscoverage['javascript-throw.js'][2]++; + throw "x"; +} +catch (e) { + _$jscoverage['javascript-throw.js'][5]++; + ; +} +_$jscoverage['javascript-throw.js'].source = ["try {"," throw \"x\";","}","catch (e) {"," ;","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-try.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-try.js new file mode 100644 index 0000000..8111f17 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-try.js @@ -0,0 +1,66 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-try.js']) { + _$jscoverage['javascript-try.js'] = []; + _$jscoverage['javascript-try.js'][1] = 0; + _$jscoverage['javascript-try.js'][3] = 0; + _$jscoverage['javascript-try.js'][4] = 0; + _$jscoverage['javascript-try.js'][7] = 0; + _$jscoverage['javascript-try.js'][10] = 0; + _$jscoverage['javascript-try.js'][11] = 0; + _$jscoverage['javascript-try.js'][14] = 0; + _$jscoverage['javascript-try.js'][17] = 0; + _$jscoverage['javascript-try.js'][18] = 0; + _$jscoverage['javascript-try.js'][21] = 0; + _$jscoverage['javascript-try.js'][24] = 0; + _$jscoverage['javascript-try.js'][25] = 0; + _$jscoverage['javascript-try.js'][28] = 0; + _$jscoverage['javascript-try.js'][31] = 0; +} +_$jscoverage['javascript-try.js'][1]++; +function f() { +} +_$jscoverage['javascript-try.js'][3]++; +try { + _$jscoverage['javascript-try.js'][4]++; + f(); +} +catch (e) { + _$jscoverage['javascript-try.js'][7]++; + f(); +} +_$jscoverage['javascript-try.js'][10]++; +try { + _$jscoverage['javascript-try.js'][11]++; + f(); +} +catch (e if e instanceof E) { + _$jscoverage['javascript-try.js'][14]++; + f(); +} +_$jscoverage['javascript-try.js'][17]++; +try { + _$jscoverage['javascript-try.js'][18]++; + f(); +} +finally { + _$jscoverage['javascript-try.js'][21]++; + f(); +} +_$jscoverage['javascript-try.js'][24]++; +try { + _$jscoverage['javascript-try.js'][25]++; + f(); +} +catch (e) { + _$jscoverage['javascript-try.js'][28]++; + f(); +} +finally { + _$jscoverage['javascript-try.js'][31]++; + f(); +} +_$jscoverage['javascript-try.js'].source = ["function f() {}","","try {"," f();","}","catch (e) {"," f();","}","","try {"," f();","}","catch (e if e instanceof E) {"," f();","}","","try {"," f();","}","finally {"," f();","}","","try {"," f();","}","catch (e) {"," f();","}","finally {"," f();","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-unaryop.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-unaryop.js new file mode 100644 index 0000000..ca06e39 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-unaryop.js @@ -0,0 +1,27 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-unaryop.js']) { + _$jscoverage['javascript-unaryop.js'] = []; + _$jscoverage['javascript-unaryop.js'][1] = 0; + _$jscoverage['javascript-unaryop.js'][2] = 0; + _$jscoverage['javascript-unaryop.js'][3] = 0; + _$jscoverage['javascript-unaryop.js'][4] = 0; + _$jscoverage['javascript-unaryop.js'][5] = 0; + _$jscoverage['javascript-unaryop.js'][6] = 0; +} +_$jscoverage['javascript-unaryop.js'][1]++; +x = - x; +_$jscoverage['javascript-unaryop.js'][2]++; +x = + x; +_$jscoverage['javascript-unaryop.js'][3]++; +x = ! x; +_$jscoverage['javascript-unaryop.js'][4]++; +x = ~ x; +_$jscoverage['javascript-unaryop.js'][5]++; +x = typeof x; +_$jscoverage['javascript-unaryop.js'][6]++; +x = void x; +_$jscoverage['javascript-unaryop.js'].source = ["x = -x;","x = +x;","x = !x;","x = ~x;","x = typeof x;","x = void x;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-var.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-var.js new file mode 100644 index 0000000..904bbcf --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-var.js @@ -0,0 +1,15 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-var.js']) { + _$jscoverage['javascript-var.js'] = []; + _$jscoverage['javascript-var.js'][1] = 0; + _$jscoverage['javascript-var.js'][2] = 0; +} +_$jscoverage['javascript-var.js'][1]++; +var x; +_$jscoverage['javascript-var.js'][2]++; +var y = x, z = x; +_$jscoverage['javascript-var.js'].source = ["var x;","var y = x, z = x;"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-while.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-while.js new file mode 100644 index 0000000..b15afa2 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-while.js @@ -0,0 +1,79 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-while.js']) { + _$jscoverage['javascript-while.js'] = []; + _$jscoverage['javascript-while.js'][1] = 0; + _$jscoverage['javascript-while.js'][2] = 0; + _$jscoverage['javascript-while.js'][5] = 0; + _$jscoverage['javascript-while.js'][6] = 0; + _$jscoverage['javascript-while.js'][9] = 0; + _$jscoverage['javascript-while.js'][10] = 0; + _$jscoverage['javascript-while.js'][12] = 0; + _$jscoverage['javascript-while.js'][13] = 0; + _$jscoverage['javascript-while.js'][15] = 0; + _$jscoverage['javascript-while.js'][16] = 0; + _$jscoverage['javascript-while.js'][17] = 0; + _$jscoverage['javascript-while.js'][21] = 0; + _$jscoverage['javascript-while.js'][23] = 0; + _$jscoverage['javascript-while.js'][24] = 0; + _$jscoverage['javascript-while.js'][28] = 0; + _$jscoverage['javascript-while.js'][29] = 0; + _$jscoverage['javascript-while.js'][30] = 0; + _$jscoverage['javascript-while.js'][31] = 0; + _$jscoverage['javascript-while.js'][32] = 0; +} +_$jscoverage['javascript-while.js'][1]++; +while (x) { + _$jscoverage['javascript-while.js'][2]++; + x(); +} +_$jscoverage['javascript-while.js'][5]++; +while (x) { + _$jscoverage['javascript-while.js'][6]++; + ; +} +_$jscoverage['javascript-while.js'][9]++; +while (x) { + _$jscoverage['javascript-while.js'][10]++; + x(); +} +_$jscoverage['javascript-while.js'][12]++; +while (x) { + _$jscoverage['javascript-while.js'][13]++; + ; +} +_$jscoverage['javascript-while.js'][15]++; +while (x) { + _$jscoverage['javascript-while.js'][16]++; + if (x) { + _$jscoverage['javascript-while.js'][17]++; + continue; + } +} +_$jscoverage['javascript-while.js'][21]++; +label: +while (x) { + _$jscoverage['javascript-while.js'][23]++; + if (x) { + _$jscoverage['javascript-while.js'][24]++; + continue label; + } +} +_$jscoverage['javascript-while.js'][28]++; +label2: +{ + _$jscoverage['javascript-while.js'][29]++; + f(); + _$jscoverage['javascript-while.js'][30]++; + while (x) { + _$jscoverage['javascript-while.js'][31]++; + if (x) { + _$jscoverage['javascript-while.js'][32]++; + break label2; + } +} +} +_$jscoverage['javascript-while.js'].source = ["while (x) {"," x();","}","","while (x) {"," ;","}","","while (x)"," x();","","while (x)"," ;","","while (x) {"," if (x) {"," continue;"," }","}","","label:","while (x) {"," if (x) {"," continue label;"," }","}","","label2: {"," f();"," while (x) {"," if (x) {"," break label2;"," }"," }","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-with.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-with.js new file mode 100644 index 0000000..52aea68 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.expected/javascript-with.js @@ -0,0 +1,30 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['javascript-with.js']) { + _$jscoverage['javascript-with.js'] = []; + _$jscoverage['javascript-with.js'][1] = 0; + _$jscoverage['javascript-with.js'][2] = 0; + _$jscoverage['javascript-with.js'][4] = 0; + _$jscoverage['javascript-with.js'][5] = 0; + _$jscoverage['javascript-with.js'][8] = 0; + _$jscoverage['javascript-with.js'][9] = 0; +} +_$jscoverage['javascript-with.js'][1]++; +function f() { +} +_$jscoverage['javascript-with.js'][2]++; +var x = {}; +_$jscoverage['javascript-with.js'][4]++; +with (x) { + _$jscoverage['javascript-with.js'][5]++; + f(); +} +_$jscoverage['javascript-with.js'][8]++; +with (x) { + _$jscoverage['javascript-with.js'][9]++; + f(); +} +_$jscoverage['javascript-with.js'].source = ["function f() {}","var x = {};","","with (x) {"," f();","}","","with (x)"," f();"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.sh new file mode 100755 index 0000000..6209a0f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# javascript.sh - test various JavaScript constructs +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr DIR' 1 2 3 15 + +export PATH=.:..:$PATH + +if jscoverage-server --version | grep -q 'iconv\|MultiByteToWideChar' +then + character_encoding_support=yes +else + character_encoding_support=no +fi + +rm -fr DIR +case "$character_encoding_support" in + yes) + $VALGRIND jscoverage --js-version 180 --encoding ISO-8859-1 javascript DIR + ;; + *) + $VALGRIND jscoverage --js-version=180 --exclude=javascript-iso-8859-1.js javascript DIR + ;; +esac +for i in javascript/*.js +do + if [ $character_encoding_support = no -a $i = javascript/javascript-iso-8859-1.js ] + then + continue + fi + FILE=${i##javascript/} + EXPECTED=javascript.expected/${FILE} + ACTUAL=DIR/${FILE} + diff -u -r --strip-trailing-cr $EXPECTED $ACTUAL +done + +# rm -fr DIR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-array-comprehension.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-array-comprehension.js new file mode 100644 index 0000000..2d9b048 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-array-comprehension.js @@ -0,0 +1,14 @@ +// https://developer.mozilla.org/en/New_in_JavaScript_1.7 + +function range(begin, end) { + for (let i = begin; i < end; ++i) { + yield i; + } +} +var ten_squares = [i * i for each (i in range(0, 10))]; +var evens = [i for each (i in range(0, 21)) if (i % 2 == 0)]; + +// test optimization +var optimized = [i for each (i in x) if (0)]; + +[i for each (a in x) for each (b in y)] diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-assign.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-assign.js new file mode 100644 index 0000000..d17bdd1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-assign.js @@ -0,0 +1,14 @@ +var x = 1; +var y = 1; +x = y; +x += y; +x -= y; +x *= y; +x %= y; +x <<= y; +x >>= y; +x >>>= y; +x &= y; +x |= y; +x ^= y; +x /= y; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-colon.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-colon.js new file mode 100644 index 0000000..69bade1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-colon.js @@ -0,0 +1,7 @@ +x: + y = 0; + +y: { + let y = 1; + print(y); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-comma.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-comma.js new file mode 100644 index 0000000..15c162c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-comma.js @@ -0,0 +1 @@ +x = y, y = x; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-cr.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-cr.js new file mode 100644 index 0000000..fad02c7 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-cr.js @@ -0,0 +1 @@ +/* This file has CR line endings. */ var x = 1; \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-crlf.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-crlf.js new file mode 100644 index 0000000..53dcd0e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-crlf.js @@ -0,0 +1,4 @@ +/* +This file has CRLF line endings. +*/ +var x = 1; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-debugger.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-debugger.js new file mode 100644 index 0000000..dc33421 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-debugger.js @@ -0,0 +1,6 @@ +try { + f(); +} +catch (e) { + debugger; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-dec.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-dec.js new file mode 100644 index 0000000..46d5bc3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-dec.js @@ -0,0 +1,2 @@ +x--; +--x; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-delete.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-delete.js new file mode 100644 index 0000000..ae9a3d0 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-delete.js @@ -0,0 +1 @@ +delete x; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-destructuring.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-destructuring.js new file mode 100644 index 0000000..c8cf4c9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-destructuring.js @@ -0,0 +1,42 @@ +// https://developer.mozilla.org/en/New_in_JavaScript_1.7 + +[a, b] = [b, a]; + +function f() { + return [1, 2]; +} +[a, b] = f(); + +for (let [name, value] in Iterator(obj)) { + print(name); + print(value); +} + +for each (let {name: n, family: { father: f } } in people) { + print(n); + print(f); +} + +var [a, , b] = f(); +[,,,] = f(); + +function g() { + var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url); + if (!parsedURL) + return null; + var [, protocol, fullhost, fullpath] = parsedURL; +} + +function h(a, [b, c], {foo: d, 'bar': e}) { + f(); + g(); +} + +x = function([a, b]) a + b; + +({x: x0, y: y0}) = point; +var {x: x0, y: y0} = point; +let ({x: x0, y: y0} = point) { + print(x0); + print(y0); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-do.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-do.js new file mode 100644 index 0000000..e6bbee9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-do.js @@ -0,0 +1,10 @@ +var x; + +do { + x = false; +} +while (x); + +do + x = false; +while (x); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-dot.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-dot.js new file mode 100644 index 0000000..0b35cdc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-dot.js @@ -0,0 +1,8 @@ +x.y = y.x; +x["y"] = y["x"]; +x[y] = y[x]; +x['2y'] = y['var']; +x[''] = y[""]; + +print(123.0.toString()); +({}.toString()); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-empty.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-empty.js new file mode 100644 index 0000000..e69de29 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-for.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-for.js new file mode 100644 index 0000000..166b586 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-for.js @@ -0,0 +1,22 @@ +for (i in x) { + x(); +} + +for (var i in x) { + x(); +} + +for (i = 0; i < x; i++) { + x(); +} + +for (var j = 0; j < x; j++) { + x(); +} + +for (i in x) + x(); + +for (i.value in x) { + x(); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-foreach.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-foreach.js new file mode 100644 index 0000000..52cb266 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-foreach.js @@ -0,0 +1,8 @@ +/* +https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Object_Manipulation_Statements +https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/for_each...in +*/ + +for each (var item in obj) { + sum += item; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-function.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-function.js new file mode 100644 index 0000000..94fc8bd --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-function.js @@ -0,0 +1,38 @@ +function x() {} + +function x() { + ; +} + +function x() { + x(); + return 'x'; +} + +function x(a) { + x(); +} + +function x(a, b) { + x(); +} + +x = function() { + x(); +}; + +(function () { + print('x'); +})(); + +(function (a) { + print('x'); +})(1); + +(function (a, b) { + print('x'); +})(1, 2); + +(function () { + print('x'); +}).call(window); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-generator-expression.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-generator-expression.js new file mode 100644 index 0000000..cafec77 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-generator-expression.js @@ -0,0 +1,18 @@ +// https://developer.mozilla.org/en/New_in_JavaScript_1.8 + +let it = (i + 3 for (i in someObj)); +try { + while (true) { + document.write(it.next() + "
\n"); + } +} catch (err if err instanceof StopIteration) { + document.write("End of record.
\n"); +} + +function handleResults( results ) { + for ( let i in results ) + ; +} +handleResults( i for ( i in obj ) if ( i > 3 ) ); + +it = (1 for(a in x) for(b in y)); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-generator.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-generator.js new file mode 100644 index 0000000..6c1f32a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-generator.js @@ -0,0 +1,11 @@ +// https://developer.mozilla.org/en/New_in_JavaScript_1.7 + +function fib() { + var i = 0, j = 1; + while (true) { + yield i; + var t = i; + i = j; + j += t; + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-getter-setter.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-getter-setter.js new file mode 100644 index 0000000..31fca86 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-getter-setter.js @@ -0,0 +1,19 @@ +var o = { + _x: 123, + get x() { + return this._x; + }, + set x(value) { + this._x = value; + } +}; + +o = { + _x: 123, + get x get_x() { + return this._x; + }, + set x set_x(value) { + this._x = value; + } +}; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-hook.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-hook.js new file mode 100644 index 0000000..0e690f8 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-hook.js @@ -0,0 +1,2 @@ +var x = 1; +var y = x === 1? "x": "y"; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-if.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-if.js new file mode 100644 index 0000000..43d489e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-if.js @@ -0,0 +1,30 @@ +var x = 0; + +if (x) + x = 0; + +if (x) { + x = 0; +} + +if (x) + x = 0; +else + x = 0; + +if (x) { + x = 0; +} +else { + x = 0; +} + +if (x) { + x = 0; +} +else if (x) { + x = 0; +} +else { + x = 0; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-in.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-in.js new file mode 100644 index 0000000..75ba66e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-in.js @@ -0,0 +1,4 @@ +var x = {}; +if ('a' in x) { + x = null; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-inc.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-inc.js new file mode 100644 index 0000000..065c7bf --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-inc.js @@ -0,0 +1,2 @@ +x++; +++x; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-iso-8859-1.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-iso-8859-1.js new file mode 100644 index 0000000..2658cee --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-iso-8859-1.js @@ -0,0 +1,2 @@ +var s = 'eèéê'; +var r = /eèéê/; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-lambda.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-lambda.js new file mode 100644 index 0000000..0e5062f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-lambda.js @@ -0,0 +1,3 @@ +// https://developer.mozilla.org/en/New_in_JavaScript_1.8 + +var square = function(x) x * x; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-let.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-let.js new file mode 100644 index 0000000..7bb777b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-let.js @@ -0,0 +1,79 @@ +// https://developer.mozilla.org/en/New_in_JavaScript_1.7 + +// let statement + +let (x = x+10, y = 12) { + print(x+y + "\n"); +} + +// let expressions + +print( let(x = x + 10, y = 12) x+y + "
\n"); + +// let definitions + +if (x > y) { + let gamma = 12.7 + y; + i = gamma * x; +} + +var list = document.getElementById("list"); + +for (var i = 1; i <= 5; i++) { + var item = document.createElement("LI"); + item.appendChild(document.createTextNode("Item " + i)); + + let j = i; + item.onclick = function (ev) { + alert("Item " + j + " is clicked."); + }; + list.appendChild(item); +} + +function varTest() { + var x = 31; + if (true) { + var x = 71; // same variable! + alert(x); // 71 + } + alert(x); // 71 +} + +function letTest() { + let x = 31; + if (true) { + let x = 71; // different variable + alert(x); // 71 + } + alert(x); // 31 +} + +function letTests() { + let x = 10; + + // let-statement + let (x = x + 20) { + alert(x); // 30 + } + + // let-expression + alert(let (x = x + 20) x); // 30 + + // let-definition + { + let x = x + 20; // x here evaluates to undefined + alert(x); // undefined + 20 ==> NaN + } +} + +var x = 'global'; +let x = 42; +document.write(this.x + "
\n"); + +// let-scoped variables in for loops +var i=0; +for ( let i=i ; i < 10 ; i++ ) + document.write(i + "
\n"); + +for ( let [name,value] in obj ) + document.write("Name: " + name + ", Value: " + value + "
\n"); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-lf.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-lf.js new file mode 100644 index 0000000..2741068 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-lf.js @@ -0,0 +1,4 @@ +/* +This file has LF line endings. +*/ +var x = 1; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-new.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-new.js new file mode 100644 index 0000000..6801585 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-new.js @@ -0,0 +1,4 @@ +function X() {} +x = new X(); +x = new X(1); +x = new X(1, 2); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-number.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-number.js new file mode 100644 index 0000000..95603d7 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-number.js @@ -0,0 +1,19 @@ +x = 1; +y = 2; +z = 10.5; + +a = 1 / 0; +a = -1 / 0; + +a = 0; +a = -0; + +a = 0 / 0; +a = 0 / -0; +a = 0 / (-0); +a = -0 / 0; +a = (-0) / 0; +a = -0 / -0; +a = -0 / (-0); +a = (-0) / -0; +a = (-0) / (-0); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-object.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-object.js new file mode 100644 index 0000000..83ce7be --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-object.js @@ -0,0 +1,2 @@ +x = /x\(\)\\\//i; +y = /\u0001\u002f/gm; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-op.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-op.js new file mode 100644 index 0000000..9c6e8bb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-op.js @@ -0,0 +1,55 @@ +var a = 1, b = 1, c = 1, d = 1; + +/* TOK_OR */ +x = a || b || c; +x = a || b || c || d; + +/* TOK_AND */ +x = a && b && c; +x = a && b && c && d; + +x = a && b || c; + +x = a || b && c; + +// TOK_BITOR +x = a | b | c; +x = a | b | c | d; + +// TOK_BITXOR +x = a ^ b ^ c; +x = a ^ b ^ c ^ d; + +// TOK_BITAND +x = a & b & c; +x = a & b & c & d; + +// TOK_EQUOP +x = a == b; +x = a != b; +x = a === b; +x = a !== b; + +// TOK_RELOP +x = a < b; +x = a <= b; +x = a > b; +x = a >= b; + +// TOK_SHOP +x = a << b; +x = a >> b; +x = a >>> b; + +/* TOK_PLUS, TOK_MINUS */ +x = a + b; +x = a + b + c; +x = a + b + c + d; +x = a - b; + +// TOK_STAR, TOK_DIVOP +x = a * b; +x = a * b * c; +x = a * b * c * d; +x = a / b; +x = a % b; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-primary.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-primary.js new file mode 100644 index 0000000..9a7bc4e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-primary.js @@ -0,0 +1,4 @@ +x = true; +x = false; +x = null; +x = this; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rb.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rb.js new file mode 100644 index 0000000..57e897c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rb.js @@ -0,0 +1,5 @@ +x = []; +x = [x]; +x = [x, y]; +x = [x, y,]; +x = [x,, y]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rc.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rc.js new file mode 100644 index 0000000..f654a9a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rc.js @@ -0,0 +1,7 @@ +x = { + x: y +}; +x = { + x: y, + y: x +}; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rp.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rp.js new file mode 100644 index 0000000..2e17573 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-rp.js @@ -0,0 +1 @@ +x = a + (b - c); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-special-characters.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-special-characters.js new file mode 100644 index 0000000..dc8ec36 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-special-characters.js @@ -0,0 +1,11 @@ +function f() { + return '\''; +} + +function g() { + return "\""; +} + +function h() { + return '\\'; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-string.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-string.js new file mode 100644 index 0000000..463824a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-string.js @@ -0,0 +1,11 @@ +x = ""; +x = ''; +x = "x"; +x = 'x'; +x = "\""; +x = '\''; +x = "\b\t\n\v\f\r\"\'\\"; +x = new RegExp('x\\(\\)\\\\\\/'); + +x = 'foo\ +bar'; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-switch.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-switch.js new file mode 100644 index 0000000..bb6e01e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-switch.js @@ -0,0 +1,21 @@ +switch (x) { +case x: + x = 0; + break; +case y: + x = 0; + y = 0; + break; +default: + x = 0; + break; +} + +switch (x) { +case 1: + let y = 1; + f(y); + break; +case 2: + break; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-throw.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-throw.js new file mode 100644 index 0000000..1fc73c4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-throw.js @@ -0,0 +1,6 @@ +try { + throw "x"; +} +catch (e) { + ; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-try.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-try.js new file mode 100644 index 0000000..47a5de4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-try.js @@ -0,0 +1,32 @@ +function f() {} + +try { + f(); +} +catch (e) { + f(); +} + +try { + f(); +} +catch (e if e instanceof E) { + f(); +} + +try { + f(); +} +finally { + f(); +} + +try { + f(); +} +catch (e) { + f(); +} +finally { + f(); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-unaryop.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-unaryop.js new file mode 100644 index 0000000..0173913 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-unaryop.js @@ -0,0 +1,6 @@ +x = -x; +x = +x; +x = !x; +x = ~x; +x = typeof x; +x = void x; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-var.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-var.js new file mode 100644 index 0000000..4902a44 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-var.js @@ -0,0 +1,2 @@ +var x; +var y = x, z = x; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-while.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-while.js new file mode 100644 index 0000000..f1ec6b5 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-while.js @@ -0,0 +1,35 @@ +while (x) { + x(); +} + +while (x) { + ; +} + +while (x) + x(); + +while (x) + ; + +while (x) { + if (x) { + continue; + } +} + +label: +while (x) { + if (x) { + continue label; + } +} + +label2: { + f(); + while (x) { + if (x) { + break label2; + } + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-with.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-with.js new file mode 100644 index 0000000..58fd1ac --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/javascript/javascript-with.js @@ -0,0 +1,9 @@ +function f() {} +var x = {}; + +with (x) { + f(); +} + +with (x) + f(); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json-cmp.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json-cmp.js new file mode 100644 index 0000000..37e9144 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json-cmp.js @@ -0,0 +1,65 @@ +/* + json-cmp.js - compare JSON files + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +function json_equals(json1, json2) { + if (json1 === null || json2 === null) { + return json1 === json2; + } + else if (json1.constructor === Array && json2.constructor === Array) { + if (json1.length !== json2.length) { + return false; + } + var length = json1.length; + for (var i = 0; i < length; i++) { + if (! json_equals(json1[i], json2[i])) { + return false; + } + } + return true; + } + else if (typeof(json1) === 'object' && typeof(json2) === 'object') { + var i; + for (i in json1) { + if (! (i in json2)) { + return false; + } + if (! json_equals(json1[i], json2[i])) { + return false; + } + } + for (i in json2) { + if (! (i in json1)) { + return false; + } + } + return true; + } + else { + return json1 === json2; + } +} + +if (json_equals(EXPECTED, ACTUAL)) { + quit(0); +} +else { + print(EXPECTED.toSource()); + print(ACTUAL.toSource()); + quit(1); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json.c new file mode 100644 index 0000000..3522d86 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json.c @@ -0,0 +1,48 @@ +/* + json.c - test JSON manipulation + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include + +#include "instrument-js.h" +#include "stream.h" +#include "util.h" + +bool jscoverage_highlight = true; + +int main(void) { + jscoverage_init(); + + Stream * stream = Stream_new(0); + + FILE * f = xfopen("store.json", "r"); + Stream_write_file_contents(stream, f); + fclose(f); + + Coverage * coverage = Coverage_new(); + int result = jscoverage_parse_json(coverage, stream->data, stream->length); + assert(result == 0); + + Coverage_delete(coverage); + Stream_delete(stream); + jscoverage_cleanup(); + + exit(EXIT_SUCCESS); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json.sh new file mode 100755 index 0000000..2f84d4d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/json.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# json.sh - test JSON parsing +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +$VALGRIND ./json diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/mkdirs.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/mkdirs.c new file mode 100644 index 0000000..027cff6 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/mkdirs.c @@ -0,0 +1,42 @@ +/* + mkdirs.c - test `mkdirs' function + Copyright (C) 2007, 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include + +#include "util.h" + +void cleanup(void) { + system("rm -fr DIR"); +} + +int main(void) { + atexit(cleanup); + + system("rm -fr DIR"); + + mkdirs("DIR/a/b"); + + struct stat buf; + xstat("DIR/a/b", &buf); + assert(S_ISDIR(buf.st_mode)); + + exit(EXIT_SUCCESS); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/mkdirs.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/mkdirs.sh new file mode 100755 index 0000000..f1dc922 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/mkdirs.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# mkdirs.sh - test `mkdirs' function +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +$VALGRIND ./mkdirs diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/netcat.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/netcat.pl new file mode 100644 index 0000000..5df75be --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/netcat.pl @@ -0,0 +1,35 @@ +use strict; +use warnings; + +use Socket; + +binmode(STDIN); +$| = 1; +binmode(STDOUT); + +if (@ARGV != 2) { + die "Usage: netcat.pl HOST PORT\n"; +} + +my $host = shift; +my $port = shift; + +my $address = inet_aton($host) or die; +my $address_and_port = sockaddr_in($port, $address); +my $protocol = getprotobyname('tcp'); +socket(SOCKET, PF_INET, SOCK_STREAM, $protocol) or die; + +my $old = select(SOCKET); +$| = 1; +select($old); +binmode(SOCKET); + +connect(SOCKET, $address_and_port) or die; +while () { + print SOCKET $_; +} +while () { + print; +} +close(SOCKET); +exit 0; \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-arguments.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-arguments.expected.err new file mode 100644 index 0000000..c6e2707 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-arguments.expected.err @@ -0,0 +1,2 @@ +jscoverage: missing argument +Try `jscoverage --help' for more information. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-arguments.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-arguments.sh new file mode 100755 index 0000000..73eb586 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-arguments.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# no-arguments.sh - test jscoverage with no arguments +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +export PATH=.:..:$PATH + +trap 'rm -fr OUT ERR' 1 2 3 15 + +$VALGRIND jscoverage > OUT 2> ERR && exit 1 +test ! -s OUT +diff --strip-trailing-cr no-arguments.expected.err ERR + +rm -fr OUT ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-instrument-requires-argument.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-instrument-requires-argument.expected.err new file mode 100644 index 0000000..fdceb30 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/no-instrument-requires-argument.expected.err @@ -0,0 +1,2 @@ +jscoverage: --no-instrument: option requires an argument +Try `jscoverage --help' for more information. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-request-body.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-request-body.sh new file mode 100755 index 0000000..0532f38 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-request-body.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# proxy-bad-request-body.sh - test jscoverage-server --proxy with a bad request body +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${proxy_server_port}/jscoverage-shutdown" > /dev/null + wait $proxy_server_pid +} + +shutdown_perl() { + wget -q -O- --post-data= http://127.0.0.1:8000/perl-shutdown > /dev/null + wait $origin_server_pid +} + +cleanup() { + shutdown + shutdown_perl +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +cd recursive +perl ../server.pl > /dev/null 2> /dev/null & +origin_server_pid=$! +cd .. + +$VALGRIND jscoverage-server --proxy > OUT 2> ERR & +proxy_server_pid=$! +proxy_server_port=8080 + +sleep $delay + +./http-client-bad-body 8080 http://127.0.0.1:8000/ diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body-javascript.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body-javascript.sh new file mode 100755 index 0000000..df63686 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body-javascript.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# proxy-bad-response-body-javascript.sh - test jscoverage-server --proxy with bad JavaScript response body +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${proxy_server_port}/jscoverage-shutdown" > /dev/null + wait $proxy_server_pid + kill -9 $origin_server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +./http-server-bad-body & +origin_server_pid=$! + +$VALGRIND jscoverage-server --proxy > OUT 2> ERR & +proxy_server_pid=$! +proxy_server_port=8080 + +sleep $delay + +echo 200 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:8000/script.js 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body.expected.err new file mode 100644 index 0000000..9dd02ee --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body.expected.err @@ -0,0 +1 @@ +Warning: error copying response body from server to client diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body.sh new file mode 100755 index 0000000..aace044 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-body.sh @@ -0,0 +1,54 @@ +#!/bin/sh +# proxy-bad-response-body.sh - test jscoverage-server --proxy with bad response body +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${proxy_server_port}/jscoverage-shutdown" > /dev/null + wait $proxy_server_pid + kill -9 $origin_server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +./http-server-bad-body & +origin_server_pid=$! + +$VALGRIND jscoverage-server --proxy > OUT 2> ERR & +proxy_server_pid=$! +proxy_server_port=8080 + +sleep $delay + +echo 200 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:8000/index.html 2> /dev/null > ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL +diff --strip-trailing-cr proxy-bad-response-body.expected.err ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-headers.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-headers.sh new file mode 100755 index 0000000..e21e22a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-bad-response-headers.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# proxy-bad-response-headers.sh - test jscoverage-server --proxy with bad response headers +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${proxy_server_port}/jscoverage-shutdown" > /dev/null + wait $proxy_server_pid + kill -9 $origin_server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +./http-server-bad-headers & +origin_server_pid=$! + +$VALGRIND jscoverage-server --proxy > OUT 2> ERR & +proxy_server_pid=$! +proxy_server_port=8080 + +sleep $delay + +echo 502 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:8000/index.html 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-no-server.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-no-server.sh new file mode 100755 index 0000000..75f34f6 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-no-server.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# proxy-no-server.sh - test jscoverage-server --proxy without origin server +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${proxy_server_port}/jscoverage-shutdown" > /dev/null + wait $proxy_server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +$VALGRIND jscoverage-server --proxy > OUT 2> ERR & +proxy_server_pid=$! +proxy_server_port=8080 + +sleep $delay + +echo 504 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:1/index.html 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-url.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-url.sh new file mode 100755 index 0000000..413f116 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy-url.sh @@ -0,0 +1,67 @@ +#!/bin/sh +# proxy-url.sh - test jscoverage-server --proxy with different URLs +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${proxy_server_port}/jscoverage-shutdown" > /dev/null + wait $proxy_server_pid + if [ "$origin_server_pid" != "" ] + then + kill -9 $origin_server_pid + fi +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +$VALGRIND jscoverage-server --proxy > OUT 2> ERR & +proxy_server_pid=$! +proxy_server_port=8080 + +sleep $delay + +echo 504 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:/index.html 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL + +./http-client-bad-url 8080 http://127.0.0.1:123456/index.html +./http-client-bad-url 8080 http://127.0.0.1:xyz/index.html + +cd recursive +perl ../server.pl > /dev/null 2> /dev/null & +origin_server_pid=$! +cd .. + +sleep $delay + +./http-client-bad-url 8080 http://127.0.0.1:8000 +./http-client-bad-url 8080 'http://127.0.0.1:8000?foo' +./http-client-bad-url 8080 'foo' diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy.sh new file mode 100755 index 0000000..903ab62 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/proxy.sh @@ -0,0 +1,143 @@ +#!/bin/sh +# proxy.sh - test jscoverage-server --proxy +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${proxy_server_port}/jscoverage-shutdown" > /dev/null + wait $proxy_server_pid +} + +shutdown_perl() { + wget -q -O- --post-data= http://127.0.0.1:8000/perl-shutdown > /dev/null + wait $origin_server_pid +} + +cleanup() { + rm -fr EXPECTED ACTUAL DIR OUT + shutdown + shutdown_perl +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +cd recursive +perl ../server.pl > /dev/null 2> /dev/null & +origin_server_pid=$! +cd .. + +rm -fr DIR +mkdir DIR +$VALGRIND jscoverage-server --no-highlight --proxy --report-dir=DIR > OUT 2> ERR & +proxy_server_pid=$! +proxy_server_port=8080 + +sleep $delay + +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/index.html | diff recursive/index.html - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/style.css | diff recursive/style.css - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/unix.txt | diff recursive/unix.txt - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/windows.txt | diff recursive/windows.txt - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/image.png | diff recursive/image.png - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/x | diff recursive/x - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/1/1.html | diff recursive/1/1.html - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/1/1.css | diff recursive/1/1.css - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/1/2/2.html | diff recursive/1/2/2.html - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/1/2/2.css | diff recursive/1/2/2.css - + +# test localhost +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://localhost:8000/index.html | diff recursive/index.html - + +# test actual hostname +h=`hostname` +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://${h}:8000/index.html | diff recursive/index.html - + +# test query string +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/index.html?foo | diff recursive/index.html - + +# test POST +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' --post-file=recursive/index.html http://127.0.0.1:8000/ | diff recursive/index.html - + +# test javascript +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/script.js > OUT +cat ../report.js recursive.expected/script.js | sed 's/@PREFIX@/http:\/\/127.0.0.1:8000\//g' | diff --strip-trailing-cr - OUT +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/1/1.js > OUT +cat ../report.js recursive.expected/1/1.js | sed 's/@PREFIX@/http:\/\/127.0.0.1:8000\//g' | diff --strip-trailing-cr - OUT +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/1/2/2.js > OUT +cat ../report.js recursive.expected/1/2/2.js | sed 's/@PREFIX@/http:\/\/127.0.0.1:8000\//g' | diff --strip-trailing-cr - OUT + +## test jscoverage +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://siliconforks.com/jscoverage.html | diff ../jscoverage.html - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://siliconforks.com/jscoverage.css | diff ../jscoverage.css - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://siliconforks.com/jscoverage-throbber.gif | diff ../jscoverage-throbber.gif - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://siliconforks.com/jscoverage.js > OUT +echo -e 'jscoverage_isServer = true;\r' | cat ../jscoverage.js - | diff - OUT + +# load/store +wget -q -O- -e 'http_proxy=http://127.0.0.1:8080/' --post-data='{}' http://siliconforks.com/jscoverage-store > /dev/null +echo -n '{}' | diff - DIR/jscoverage.json +diff ../jscoverage.html DIR/jscoverage.html +diff ../jscoverage.css DIR/jscoverage.css +diff ../jscoverage-throbber.gif DIR/jscoverage-throbber.gif +echo -e 'jscoverage_isReport = true;\r' | cat ../jscoverage.js - | diff - DIR/jscoverage.js + +# send it an FTP request +echo 400 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 ftp://ftp.example.com 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL + +# nonexistent domain +echo 504 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://nonexistent 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL + +# 404 not found +echo 404 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://127.0.0.1:8000/missing 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL +echo 404 > EXPECTED +! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://siliconforks.com/jscoverage-missing 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL + +## send it a server request +#echo 400 > EXPECTED +#! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/ 2> /dev/null > ACTUAL +#diff EXPECTED ACTUAL + +# kill $proxy_server_pid +shutdown + +$VALGRIND jscoverage-server --no-highlight --port=8081 --proxy --report-dir=DIR --no-instrument=http://127.0.0.1:8000/1/ & +proxy_server_pid=$! +proxy_server_port=8081 + +sleep $delay + +wget -q -O- -e 'http_proxy=http://127.0.0.1:8081/' http://127.0.0.1:8000/script.js > OUT +cat ../report.js recursive.expected/script.js | sed 's/@PREFIX@/http:\/\/127.0.0.1:8000\//g' | diff --strip-trailing-cr - OUT +wget -q -O- -e 'http_proxy=http://127.0.0.1:8081/' http://127.0.0.1:8000/1/1.js | diff --strip-trailing-cr recursive/1/1.js - +wget -q -O- -e 'http_proxy=http://127.0.0.1:8081/' http://127.0.0.1:8000/1/2/2.js | diff --strip-trailing-cr recursive/1/2/2.js - diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-crlf.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-crlf.sh new file mode 100755 index 0000000..c95ee81 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-crlf.sh @@ -0,0 +1,59 @@ +#!/bin/sh +# recursive-crlf.sh - test recursive directory instrumentation, CRLF line endings +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr TMP EXPECTED DIR OUT' 0 1 2 3 15 + +export PATH=.:..:$PATH + +rm -fr TMP EXPECTED DIR OUT + +mkdir -p TMP/1/2 +cd recursive +cp *.html *.js *.css *.png *.txt x ../TMP +cp 1/1.html 1/1.js 1/1.css ../TMP/1 +cp 1/2/2.html 1/2/2.js 1/2/2.css ../TMP/1/2 +cd .. +unix2dos TMP/script.js > /dev/null 2> /dev/null +unix2dos TMP/1/1.js > /dev/null 2> /dev/null +unix2dos TMP/1/2/2.js > /dev/null 2> /dev/null + +mkdir -p EXPECTED/1/2 +cd recursive.expected +cp *.html *.js *.css *.png *.txt x ../EXPECTED +cp 1/1.html 1/1.js 1/1.css ../EXPECTED/1 +cp 1/2/2.html 1/2/2.js 1/2/2.css ../EXPECTED/1/2 +cd .. +cat recursive.expected/script.js | sed 's/@PREFIX@//g' > EXPECTED/script.js +cat recursive.expected/1/1.js | sed 's/@PREFIX@//g' > EXPECTED/1/1.js +cat recursive.expected/1/2/2.js | sed 's/@PREFIX@//g' > EXPECTED/1/2/2.js +cp ../jscoverage.css ../jscoverage-highlight.css ../jscoverage-ie.css \ + ../jscoverage-throbber.gif \ + ../jscoverage.html \ + ../jscoverage.js EXPECTED + +$VALGRIND jscoverage --no-highlight TMP DIR +test -d DIR +diff --strip-trailing-cr -r EXPECTED DIR + +$VALGRIND jscoverage --no-highlight --verbose TMP DIR > OUT +test -d DIR +sort OUT -o OUT +diff --strip-trailing-cr verbose.expected.out OUT +diff --strip-trailing-cr -r EXPECTED DIR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-dir-list.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-dir-list.c new file mode 100644 index 0000000..2f1a7bf --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-dir-list.c @@ -0,0 +1,93 @@ +/* + recursive-dir-list.c - test `make_recursive_dir_list' function + Copyright (C) 2007, 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include + +#include "util.h" + +struct Expected { + int count; + const char * name; +}; + +void cleanup(void) { + system("rm -fr DIR"); +} + +void touch(const char * file) { + FILE * f = fopen(file, "w"); + if (f == NULL) { + fatal("cannot open file: %s", file); + } + fclose(f); +} + +void verify(struct Expected * expected, struct DirListEntry * actual, int length) { + struct DirListEntry * p = actual; + while (p != NULL) { + char * name = p->name; + for (int i = 0; i < length; i++) { + if (strcmp(expected[i].name, name) == 0) { + expected[i].count++; + break; + } + } + p = p->next; + } + + /* now verify the totals */ + for (int i = 0; i < length; i++) { + assert(expected[i].count == 1); + } +} + +int main(void) { + atexit(cleanup); + + system("rm -fr DIR"); + + /* simple case */ + xmkdir("DIR"); + xmkdir("DIR/a"); + xmkdir("DIR/a/b"); + xmkdir("DIR/c"); + xmkdir("DIR/d"); + touch("DIR/0"); + touch("DIR/a/1"); + touch("DIR/a/b/2"); + touch("DIR/c/3"); + touch("DIR/c/4"); + /* DIR/d is empty */ + + struct Expected expected[] = { + {0, "c/4"}, + {0, "c/3"}, + {0, "a/b/2"}, + {0, "a/1"}, + {0, "0"}, + }; + + struct DirListEntry * list = make_recursive_dir_list("DIR"); + verify(expected, list, sizeof(expected) / sizeof(expected[0])); + free_dir_list(list); + + exit(EXIT_SUCCESS); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-dir-list.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-dir-list.sh new file mode 100755 index 0000000..d232a0a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-dir-list.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# recursive-dir-list.sh - test `make_recursive_dir_list' function +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +$VALGRIND ./recursive-dir-list diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-exclude.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-exclude.sh new file mode 100755 index 0000000..4e5d42e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-exclude.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# recursive-exclude.sh - test `--exclude' option +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr EXPECTED DIR' 1 2 3 15 + +export PATH=.:..:$PATH + +rm -fr DIR +rm -fr EXPECTED +cp -r recursive.expected EXPECTED +find EXPECTED -name .svn | xargs rm -fr +rm EXPECTED/script.js +cat recursive.expected/1/1.js | sed 's/@PREFIX@//g' > EXPECTED/1/1.js +rm -fr EXPECTED/1/2 +cp ../jscoverage.css ../jscoverage-highlight.css ../jscoverage-ie.css \ + ../jscoverage-throbber.gif \ + ../jscoverage.html \ + ../jscoverage.js EXPECTED + +$VALGRIND jscoverage --no-highlight --exclude=.svn --exclude=1/.svn --exclude=1/2/.svn --exclude 1/2 --exclude=script.js recursive DIR +test -d DIR +diff --strip-trailing-cr -r EXPECTED DIR + +rm -fr EXPECTED DIR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-fatal.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-fatal.sh new file mode 100755 index 0000000..7fdd151 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-fatal.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# recursive-fatal.sh - test various fatal errors +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr DIR DIR2 SYM ERR' 1 2 3 15 + +export PATH=.:..:$PATH + +rm -fr DIR DIR2 SYM ERR + +mkdir DIR +$VALGRIND jscoverage DIR DIR 2>ERR && exit 1 + +$VALGRIND jscoverage DIR DIR/1 2>ERR && exit 1 + +mkdir DIR/1 +$VALGRIND jscoverage DIR/1 DIR 2>ERR && exit 1 + +cp -r DIR SYM +$VALGRIND jscoverage DIR SYM 2>ERR && exit 1 + +$VALGRIND jscoverage SYM DIR 2>ERR && exit 1 + +rm -fr DIR DIR2 SYM ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-no-instrument.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-no-instrument.sh new file mode 100755 index 0000000..1203bec --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive-no-instrument.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# recursive-no-instrument.sh - test `--no-instrument' option +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr EXPECTED DIR' 1 2 3 15 + +export PATH=.:..:$PATH + +rm -fr DIR +rm -fr EXPECTED +cp -r recursive.expected EXPECTED +find EXPECTED -name .svn | xargs rm -fr +cat recursive/script.js | sed 's/@PREFIX@//g' > EXPECTED/script.js +cat recursive.expected/1/1.js | sed 's/@PREFIX@//g' > EXPECTED/1/1.js +cat recursive/1/2/2.js | sed 's/@PREFIX@//g' > EXPECTED/1/2/2.js +cp ../jscoverage.css ../jscoverage-highlight.css ../jscoverage-ie.css \ + ../jscoverage-throbber.gif \ + ../jscoverage.html \ + ../jscoverage.js EXPECTED + +$VALGRIND jscoverage --no-highlight --exclude=.svn --exclude=1/.svn --exclude=1/2/.svn --no-instrument 1/2 --no-instrument=script.js recursive DIR +test -d DIR +diff --strip-trailing-cr -r EXPECTED DIR + +rm -fr EXPECTED DIR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.css new file mode 100644 index 0000000..563d20e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.css @@ -0,0 +1,3 @@ +body { + color: green; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.html new file mode 100644 index 0000000..e292b54 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.html @@ -0,0 +1,12 @@ + + + +1 + + + + +1
+Next + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.js new file mode 100644 index 0000000..e237b0f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/1.js @@ -0,0 +1,12 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['@PREFIX@1/1.js']) { + _$jscoverage['@PREFIX@1/1.js'] = []; + _$jscoverage['@PREFIX@1/1.js'][1] = 0; +} +_$jscoverage['@PREFIX@1/1.js'][1]++; +alert("This is 1"); +_$jscoverage['@PREFIX@1/1.js'].source = ["alert(\"This is 1\");"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.css new file mode 100644 index 0000000..7cfe2bf --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.css @@ -0,0 +1,3 @@ +body { + color: blue; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.html new file mode 100644 index 0000000..bb83ca6 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.html @@ -0,0 +1,11 @@ + + + +2 + + + + +2 + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.js new file mode 100644 index 0000000..09184a3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/1/2/2.js @@ -0,0 +1,12 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['@PREFIX@1/2/2.js']) { + _$jscoverage['@PREFIX@1/2/2.js'] = []; + _$jscoverage['@PREFIX@1/2/2.js'][1] = 0; +} +_$jscoverage['@PREFIX@1/2/2.js'][1]++; +alert("This is 2"); +_$jscoverage['@PREFIX@1/2/2.js'].source = ["alert(\"This is 2\");"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/image.png b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/image.png new file mode 100644 index 0000000000000000000000000000000000000000..da5ef5d4034bf027d1f96585fcc1f11f1bb3f1df GIT binary patch literal 67 zcmeAS@N?(olHy`uVBq!ia0vp^j3CSbBp9sfW`_bPE>9Q75RU7~Klm9K85tR*x4jDk O$$Gl_xvX + + +Test + + + + +Test
+Next + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/script.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/script.js new file mode 100644 index 0000000..d9bf48b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/script.js @@ -0,0 +1,19 @@ +/* automatically generated by JSCoverage - do not edit */ +if (! top._$jscoverage) { + top._$jscoverage = {}; +} +var _$jscoverage = top._$jscoverage; +if (! _$jscoverage['@PREFIX@script.js']) { + _$jscoverage['@PREFIX@script.js'] = []; + _$jscoverage['@PREFIX@script.js'][1] = 0; + _$jscoverage['@PREFIX@script.js'][4] = 0; + _$jscoverage['@PREFIX@script.js'][5] = 0; +} +_$jscoverage['@PREFIX@script.js'][1]++; +alert("hello"); +_$jscoverage['@PREFIX@script.js'][4]++; +if ("a" < "b" && "a" > "b") { + _$jscoverage['@PREFIX@script.js'][5]++; + alert("?"); +} +_$jscoverage['@PREFIX@script.js'].source = ["alert(\"hello\");","","// test formatting &lt; &gt; &amp;","if ('a' < 'b' && 'a' > 'b') {"," alert(\"?\");","}"]; diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/style.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/style.css new file mode 100644 index 0000000..60f1eab --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/style.css @@ -0,0 +1,3 @@ +body { + color: red; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/unix.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/unix.txt new file mode 100644 index 0000000..01e79c3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/unix.txt @@ -0,0 +1,3 @@ +1 +2 +3 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/windows.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/windows.txt new file mode 100644 index 0000000..294d779 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/windows.txt @@ -0,0 +1,3 @@ +1 +2 +3 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/x b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/x new file mode 100644 index 0000000..587be6b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.expected/x @@ -0,0 +1 @@ +x diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.sh new file mode 100755 index 0000000..f7c0d09 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# recursive.sh - test recursive directory instrumentation +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr EXPECTED DIR OUT' 1 2 3 15 + +export PATH=.:..:$PATH + +rm -fr DIR +rm -fr EXPECTED +cp -r recursive.expected EXPECTED +find EXPECTED -name .svn | xargs rm -fr +cat recursive.expected/script.js | sed 's/@PREFIX@//g' > EXPECTED/script.js +cat recursive.expected/1/1.js | sed 's/@PREFIX@//g' > EXPECTED/1/1.js +cat recursive.expected/1/2/2.js | sed 's/@PREFIX@//g' > EXPECTED/1/2/2.js +cp ../jscoverage.css ../jscoverage-highlight.css ../jscoverage-ie.css \ + ../jscoverage-throbber.gif \ + ../jscoverage.html \ + ../jscoverage.js EXPECTED + +$VALGRIND jscoverage --no-highlight --exclude=.svn --exclude=1/.svn --exclude=1/2/.svn recursive DIR +test -d DIR +diff --strip-trailing-cr -r EXPECTED DIR + +$VALGRIND jscoverage --no-highlight --verbose --exclude .svn --exclude 1/.svn --exclude 1/2/.svn recursive DIR >OUT +test -d DIR +sort OUT -o OUT +diff --strip-trailing-cr verbose.expected.out OUT +diff --strip-trailing-cr -r EXPECTED DIR + +# does it handle an argument with a slash at the end? +$VALGRIND jscoverage --no-highlight --exclude=.svn --exclude=1/.svn --exclude=1/2/.svn recursive/ DIR +diff --strip-trailing-cr -r EXPECTED DIR +$VALGRIND jscoverage --no-highlight --exclude=.svn --exclude=1/.svn --exclude=1/2/.svn recursive DIR/ +diff --strip-trailing-cr -r EXPECTED DIR +$VALGRIND jscoverage --no-highlight --exclude=.svn --exclude=1/.svn --exclude=1/2/.svn recursive/ DIR/ +diff --strip-trailing-cr -r EXPECTED DIR + +rm -fr EXPECTED DIR OUT diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.css new file mode 100644 index 0000000..563d20e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.css @@ -0,0 +1,3 @@ +body { + color: green; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.html new file mode 100644 index 0000000..e292b54 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.html @@ -0,0 +1,12 @@ + + + +1 + + + + +1
+Next + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.js new file mode 100644 index 0000000..5f73e02 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/1.js @@ -0,0 +1 @@ +alert("This is 1"); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.css new file mode 100644 index 0000000..7cfe2bf --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.css @@ -0,0 +1,3 @@ +body { + color: blue; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.html b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.html new file mode 100644 index 0000000..bb83ca6 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.html @@ -0,0 +1,11 @@ + + + +2 + + + + +2 + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.js new file mode 100644 index 0000000..e0f7496 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/1/2/2.js @@ -0,0 +1 @@ +alert("This is 2"); diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/image.png b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/image.png new file mode 100644 index 0000000000000000000000000000000000000000..da5ef5d4034bf027d1f96585fcc1f11f1bb3f1df GIT binary patch literal 67 zcmeAS@N?(olHy`uVBq!ia0vp^j3CSbBp9sfW`_bPE>9Q75RU7~Klm9K85tR*x4jDk O$$Gl_xvX + + +Test + + + + +Test
+Next + + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/script.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/script.js new file mode 100644 index 0000000..1671f23 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/script.js @@ -0,0 +1,6 @@ +alert("hello"); + +// test formatting < > & +if ('a' < 'b' && 'a' > 'b') { + alert("?"); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/style.css b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/style.css new file mode 100644 index 0000000..60f1eab --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/style.css @@ -0,0 +1,3 @@ +body { + color: red; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/unix.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/unix.txt new file mode 100644 index 0000000..01e79c3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/unix.txt @@ -0,0 +1,3 @@ +1 +2 +3 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/windows.txt b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/windows.txt new file mode 100644 index 0000000..294d779 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/windows.txt @@ -0,0 +1,3 @@ +1 +2 +3 diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/x b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/x new file mode 100644 index 0000000..587be6b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/recursive/x @@ -0,0 +1 @@ +x diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/same-directory.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/same-directory.expected.err new file mode 100644 index 0000000..4f9362a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/same-directory.expected.err @@ -0,0 +1 @@ +jscoverage: source and destination are the same diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/same-directory.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/same-directory.sh new file mode 100755 index 0000000..e07867b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/same-directory.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# same-directory.sh - test with source and destination same directory +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr OUT ERR' 1 2 3 15 + +export PATH=.:..:$PATH + +$VALGRIND jscoverage javascript javascript > OUT 2> ERR && exit 1 +test ! -s OUT +test -s ERR +diff --strip-trailing-cr same-directory.expected.err ERR + +rm -fr OUT ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-bad-requests.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-bad-requests.sh new file mode 100755 index 0000000..e85a18d --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-bad-requests.sh @@ -0,0 +1,104 @@ +#!/bin/sh +# server-bad-requests.sh - test jscoverage-server with bad requests +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown + rm -fr EXPECTED ACTUAL OUT ERR +} + +bad_request() { + /bin/echo -ne "$1" | $NETCAT 127.0.0.1 $server_port > OUT 2> ERR + echo 'HTTP/1.1 400 Bad Request' > EXPECTED + head -n 1 OUT > ACTUAL + diff --strip-trailing-cr EXPECTED ACTUAL +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +if which netcat > /dev/null 2> /dev/null +then + NETCAT=netcat +elif which nc > /dev/null 2> /dev/null +then + NETCAT=nc +else + NETCAT='perl netcat.pl'; +fi + +rm -fr EXPECTED ACTUAL OUT ERR +$VALGRIND jscoverage-server --port 8000 > /dev/null 2> /dev/null & +server_pid=$! +server_port=8000 + +sleep $delay + +# send NUL in Request-Line +bad_request 'GET \0000 HTTP/1.1\r\n\r\n' + +# send empty Request-Line +bad_request '\r\n\r\n' + +# send bad Request-Line +bad_request ' \r\n\r\n' +bad_request 'GET\r\n\r\n' +bad_request 'GET \r\n\r\n' +bad_request 'GET \r\n\r\n' +bad_request 'GET /\r\n\r\n' +bad_request 'GET / \r\n\r\n' + +# bad Host header +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nHost: foo:bar\r\n\r\n' + +# NUL in header +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nFoo: \0000\r\n\r\n' + +# missing header +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\n: bar\r\n\r\n' + +# missing header value +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nFoo:\r\n\r\n' + +# bad Transfer-Encoding +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: foo;\r\n\r\n' +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: foo; bar\r\n\r\n' +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: foo; bar = "\r\n\r\n' +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: foo; bar = "\r\n\r\n' +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: foo; bar = "\\\0200"\r\n\r\n' +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: foo; bar = "\0177"\r\n\r\n' +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: foo; bar = ;\r\n\r\n' + +# bad Content-Length +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nContent-Length: 4294967296\r\n\r\n' +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nContent-Length: 4294967300\r\n\r\n' +bad_request 'GET / HTTP/1.1\r\nConnection: close\r\nContent-Length: foo\r\n\r\n' diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-close-after-request.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-close-after-request.sh new file mode 100755 index 0000000..4a27b33 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-close-after-request.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# server-close-after-request.sh - test jscoverage-server with client that closes connection after request +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +$VALGRIND jscoverage-server --port 8000 > OUT 2> ERR & +server_pid=$! +server_port=8000 + +sleep $delay + +./http-client-close-after-request diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-content-types.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-content-types.sh new file mode 100755 index 0000000..69e6b6a --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-content-types.sh @@ -0,0 +1,68 @@ +#!/bin/sh +# server-content-types.sh - test jscoverage-server Content-Type headers +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown + rm -f x x.y +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +$VALGRIND jscoverage-server > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +echo text/html > EXPECTED +! curl -f -w '%{content_type}\n' -o /dev/null http://127.0.0.1:8080/recursive/index.html 2> /dev/null > ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL + +echo text/plain > EXPECTED +! curl -f -w '%{content_type}\n' -o /dev/null http://127.0.0.1:8080/recursive/unix.txt 2> /dev/null > ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL + +echo text/plain > EXPECTED +! curl -f -w '%{content_type}\n' -o /dev/null http://127.0.0.1:8080/recursive/windows.txt 2> /dev/null > ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL + +touch x +echo application/octet-stream > EXPECTED +! curl -f -w '%{content_type}\n' -o /dev/null http://127.0.0.1:8080/x 2> /dev/null > ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL + +touch x.y +echo application/octet-stream > EXPECTED +! curl -f -w '%{content_type}\n' -o /dev/null http://127.0.0.1:8080/x.y 2> /dev/null > ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-listing.expected b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-listing.expected new file mode 100644 index 0000000..2a9fdd3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-listing.expected @@ -0,0 +1,4 @@ +.
+..
+1&2.txt
+1 2.txt
diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-listing.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-listing.sh new file mode 100755 index 0000000..fca3c2f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-listing.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# server-directory-listing.sh - test jscoverage-server directory listings +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +mkdir DIR +$VALGRIND jscoverage-server --document-root=DIR & +server_pid=$! +server_port=8080 + +sleep $delay + +# make some funny files +echo x > 'DIR/1&2.txt' +echo x > 'DIR/1 2.txt' + +sort server-directory-listing.expected -o EXPECTED +wget -q -O- http://127.0.0.1:8080/ > ACTUAL +sort ACTUAL -o ACTUAL +diff --strip-trailing-cr EXPECTED ACTUAL + +rm -fr DIR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-redirect.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-redirect.sh new file mode 100755 index 0000000..179cefd --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-directory-redirect.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# server-directory-redirect.sh - test jscoverage-server directory redirect +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +$VALGRIND jscoverage-server --document-root=recursive > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +echo 'HTTP/1.1 301 Moved Permanently' > EXPECTED +# curl -f doesn't seem to work with 3xx +! curl -D ACTUAL http://127.0.0.1:8080/1 2> /dev/null > /dev/null +cat ACTUAL | tr -d '\r' | head -1 | diff EXPECTED - diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-encoded-url.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-encoded-url.sh new file mode 100755 index 0000000..e205c18 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-encoded-url.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# server-encoded-url.sh - test jscoverage-server with encoded URL +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null +} + +cleanup() { + shutdown + # rm -fr DIR +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +mkdir DIR +$VALGRIND jscoverage-server --document-root=DIR & +server_pid=$! +server_port=8080 + +sleep $delay + +# make some funny files +echo x > 'DIR/1+2.txt' +echo x > 'DIR/1&2.txt' +echo x > 'DIR/1 2.txt' + +wget -q -O- 'http://127.0.0.1:8080/1%2B2.txt' | diff 'DIR/1+2.txt' - +wget -q -O- 'http://127.0.0.1:8080/1%2b2.txt' | diff 'DIR/1+2.txt' - +wget -q -O- 'http://127.0.0.1:8080/1%262.txt' | diff 'DIR/1&2.txt' - +wget -q -O- 'http://127.0.0.1:8080/1%202.txt' | diff 'DIR/1 2.txt' - diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-error.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-error.sh new file mode 100755 index 0000000..c2a47c4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-error.sh @@ -0,0 +1,61 @@ +#!/bin/sh +# server-error.sh - test jscoverage-server with invalid options +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +export PATH=.:..:$PATH + +! jscoverage-server --report-dir > OUT 2> ERR +test ! -s OUT +test -s ERR + +! jscoverage-server --document-root > OUT 2> ERR +test ! -s OUT +test -s ERR + +! jscoverage-server --ip-address > OUT 2> ERR +test ! -s OUT +test -s ERR + +! jscoverage-server --no-instrument > OUT 2> ERR +test ! -s OUT +test -s ERR + +! jscoverage-server --port > OUT 2> ERR +test ! -s OUT +test -s ERR + +! jscoverage-server --foo > OUT 2> ERR +test ! -s OUT +test -s ERR + +! jscoverage-server foo > OUT 2> ERR +test ! -s OUT +test -s ERR + +! jscoverage-server --port x > OUT 2> ERR +test ! -s OUT +test -s ERR + +! jscoverage-server --port 123456 > OUT 2> ERR +test ! -s OUT +test -s ERR + +! jscoverage-server --encoding > OUT 2> ERR +test ! -s OUT +test -s ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-help.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-help.sh new file mode 100755 index 0000000..b644549 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-help.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# server-help.sh - test jscoverage-server --help +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +export PATH=.:..:$PATH + +jscoverage-server --help > OUT 2> ERR +diff --strip-trailing-cr ../jscoverage-server-help.txt OUT +> TMP +diff TMP ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-ip-address.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-ip-address.sh new file mode 100755 index 0000000..b4a5770 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-ip-address.sh @@ -0,0 +1,68 @@ +#!/bin/sh +# server-ip-address.sh - test jscoverage-server --ip-address +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + # shutdown + : +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +$VALGRIND jscoverage-server --verbose --ip-address=0.0.0.0 > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +wget -q -O- http://127.0.0.1:${server_port}/ > /dev/null + +shutdown + +cat server-ip-address.expected.out | sed 's/@ADDRESS@/0.0.0.0/g' > EXPECTED +cat OUT | tr -d '\r' > ACTUAL +diff EXPECTED ACTUAL + +$VALGRIND jscoverage-server --verbose --ip-address 127.0.0.1 > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +wget -q -O- http://127.0.0.1:${server_port}/ > /dev/null + +shutdown + +cat server-ip-address.expected.out | sed 's/@ADDRESS@/127.0.0.1/g' > EXPECTED +cat OUT | tr -d '\r' > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown-bad-method.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown-bad-method.sh new file mode 100755 index 0000000..d6fa877 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown-bad-method.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# server-shutdown-bad-method.sh - test jscoverage-server --shutdown with GET +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +$VALGRIND jscoverage-server > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +echo 405 > EXPECTED +! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/jscoverage-shutdown 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown.expected.err new file mode 100644 index 0000000..5dd4646 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown.expected.err @@ -0,0 +1 @@ +POST /jscoverage-shutdown diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown.sh new file mode 100755 index 0000000..c91e6bd --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-shutdown.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# server-shutdown.sh - test jscoverage-server --shutdown +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +cleanup() { + kill -9 $origin_server_pid +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +perl server.pl > OUT 2> ERR & +origin_server_pid=$! + +sleep $delay + +$VALGRIND jscoverage-server --port 8000 --shutdown +cat ERR | cut -d'"' -f2 | diff --strip-trailing-cr server-shutdown.expected.err - diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-special-file.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-special-file.sh new file mode 100755 index 0000000..76196fb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-special-file.sh @@ -0,0 +1,62 @@ +#!/bin/sh +# server-special-file.sh - test jscoverage-server with special file +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +# skip on mingw +uname=`uname` +case "$uname" in + MINGW*) + exit 77 + ;; +esac + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + rm -f DIR/foo + rm -fr DIR + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +mkdir DIR +mkfifo DIR/foo +$VALGRIND jscoverage-server > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +echo 404 > EXPECTED +! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/DIR/foo 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-unreadable-directory.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-unreadable-directory.sh new file mode 100755 index 0000000..4de4ba8 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-unreadable-directory.sh @@ -0,0 +1,61 @@ +#!/bin/sh +# server-unreadable-directory.sh - test jscoverage-server with unreadable directory +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +# skip on windows +uname=`uname` +case "$uname" in + CYGWIN* | MINGW*) + exit 77 + ;; +esac + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + rmdir DIR + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +mkdir DIR +chmod 000 DIR +$VALGRIND jscoverage-server > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +echo 404 > EXPECTED +! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/DIR/ 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-unreadable-file.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-unreadable-file.sh new file mode 100755 index 0000000..20e1369 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-unreadable-file.sh @@ -0,0 +1,62 @@ +#!/bin/sh +# server-unreadable-file.sh - test jscoverage-server with unreadable file +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +# skip on windows +uname=`uname` +case "$uname" in + CYGWIN* | MINGW*) + exit 77 + ;; +esac + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + rm -fr DIR + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +mkdir DIR +echo Hello > DIR/index.html +chmod 000 DIR/index.html +$VALGRIND jscoverage-server > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +echo 404 > EXPECTED +! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/DIR/index.html 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-verbose.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-verbose.expected.err new file mode 100644 index 0000000..e578f28 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-verbose.expected.err @@ -0,0 +1,4 @@ +Starting HTTP server on 127.0.0.1:8080 +GET /index.html HTTP/1.0 +POST /jscoverage-shutdown HTTP/1.0 +Stopping HTTP server diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-verbose.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-verbose.sh new file mode 100755 index 0000000..174692e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-verbose.sh @@ -0,0 +1,54 @@ +#!/bin/sh +# server-verbose.sh - test jscoverage-server --verbose +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + # shutdown + : +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +$VALGRIND jscoverage-server --document-root=recursive --verbose > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +wget -q -O- http://127.0.0.1:8080/index.html | diff --strip-trailing-cr recursive/index.html - + +shutdown + +sleep $delay + +cat OUT | tr -d '\r' | diff server-verbose.expected.err - diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-version.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-version.sh new file mode 100755 index 0000000..c2a629f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server-version.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# server-version.sh - test jscoverage-server --version +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +export PATH=.:..:$PATH + +jscoverage-server --version > OUT 2> ERR +test -s OUT +test ! -s ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server.pl b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server.pl new file mode 100644 index 0000000..86064b1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server.pl @@ -0,0 +1,61 @@ +use strict; +use warnings; + +use HTTP::Daemon; +use HTTP::Status; + +$|++; + +my $d = HTTP::Daemon->new(LocalPort => 8000, ReuseAddr => 1) || die; +print "Please contact me at: url, ">\n"; +my $done = 0; +while (not $done and my $c = $d->accept) { + my $r = $c->get_request; + if (not defined($r)) { + print "Error: ", $c->reason, "\n"; + $c->close; + undef($c); + next; + } + print STDERR $r->method, ' ', $r->url, "\n"; + $c->force_last_request; + if ($r->method eq 'GET') { + my $file = substr($r->url->path, 1); + if (open FILE, $file) { + undef $/; + binmode FILE; + my $content = ; + close FILE; + my @headers = ('Connection' => 'close'); + if ($file =~ /\.js$/) { + push @headers, 'Content-Type' => 'text/javascript'; + } + elsif ($file =~ /\.[^\/]+$/) { + push @headers, 'Content-Type' => 'application/octet-stream'; + } + else { + # do nothing - no Content-Type + } + my $response = HTTP::Response->new(200, 'OK', \@headers, $content); + $c->send_response($response); + } + else { + my $response = HTTP::Response->new(404, 'Not found', ['Connection' => 'close'], 'Not found'); + $c->send_response($response); + } + } + elsif ($r->method eq 'POST') { + if ($r->url->path eq '/perl-shutdown') { + $done = 1; + } + my $content = $r->content; + my $response = HTTP::Response->new(200, 'OK', ['Connection' => 'close'], $content); + $c->send_response($response); + } + else { + $c->send_error(RC_FORBIDDEN); + } + $c->close; + undef($c); +} + diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server.sh new file mode 100755 index 0000000..e936fa1 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/server.sh @@ -0,0 +1,216 @@ +#!/bin/sh +# server.sh - test jscoverage-server +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + rm -fr EXPECTED ACTUAL DIR OUT + # kill $server_pid + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +if jscoverage-server --version | grep -q 'iconv\|MultiByteToWideChar' +then + character_encoding_support=yes +else + character_encoding_support=no +fi + +rm -fr EXPECTED ACTUAL DIR OUT +mkdir DIR +$VALGRIND jscoverage-server --no-highlight --document-root=recursive --report-dir=DIR & +server_pid=$! +server_port=8080 + +sleep $delay + +wget -q -O- http://127.0.0.1:8080/index.html | diff recursive/index.html - +wget -q -O- http://127.0.0.1:8080/style.css | diff recursive/style.css - +wget -q -O- http://127.0.0.1:8080/unix.txt | diff recursive/unix.txt - +wget -q -O- http://127.0.0.1:8080/windows.txt | diff recursive/windows.txt - +wget -q -O- http://127.0.0.1:8080/image.png | diff recursive/image.png - +wget -q -O- http://127.0.0.1:8080/x | diff recursive/x - +wget -q -O- http://127.0.0.1:8080/1/1.html | diff recursive/1/1.html - +wget -q -O- http://127.0.0.1:8080/1/1.css | diff recursive/1/1.css - +wget -q -O- http://127.0.0.1:8080/1/2/2.html | diff recursive/1/2/2.html - +wget -q -O- http://127.0.0.1:8080/1/2/2.css | diff recursive/1/2/2.css - + +# test query string +wget -q -O- http://127.0.0.1:8080/index.html?foo | diff recursive/index.html - + +# test javascript +wget -q -O- http://127.0.0.1:8080/script.js > OUT +cat ../report.js recursive.expected/script.js | sed 's/@PREFIX@/\//g' | diff --strip-trailing-cr - OUT +wget -q -O- http://127.0.0.1:8080/1/1.js > OUT +cat ../report.js recursive.expected/1/1.js | sed 's/@PREFIX@/\//g' | diff --strip-trailing-cr - OUT +wget -q -O- http://127.0.0.1:8080/1/2/2.js > OUT +cat ../report.js recursive.expected/1/2/2.js | sed 's/@PREFIX@/\//g' | diff --strip-trailing-cr - OUT + +# test jscoverage +wget -q -O- http://127.0.0.1:8080/jscoverage.html | diff ../jscoverage.html - +wget -q -O- http://127.0.0.1:8080/jscoverage.css | diff ../jscoverage.css - +wget -q -O- http://127.0.0.1:8080/jscoverage-throbber.gif | diff ../jscoverage-throbber.gif - +wget -q -O- http://127.0.0.1:8080/jscoverage.js > OUT +echo -e 'jscoverage_isServer = true;\r' | cat ../jscoverage.js - | diff - OUT + +# load/store +wget --post-data='{}' -q -O- http://127.0.0.1:8080/jscoverage-store > /dev/null +echo -n '{}' | diff - DIR/jscoverage.json +diff ../jscoverage.html DIR/jscoverage.html +diff ../jscoverage.css DIR/jscoverage.css +diff ../jscoverage-throbber.gif DIR/jscoverage-throbber.gif +echo -e 'jscoverage_isReport = true;\r' | cat ../jscoverage.js - | diff - DIR/jscoverage.js + +# 404 not found +echo 404 > EXPECTED +! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/missing 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL +echo 404 > EXPECTED +! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/jscoverage-missing 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL + +# 403 forbidden +echo 403 > EXPECTED +! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/../Makefile.am 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL + +## send it a proxy request +#echo 400 > EXPECTED +#! curl -f -w '%{http_code}\n' -x 127.0.0.1:8080 http://siliconforks.com/ 2> /dev/null > ACTUAL +#diff EXPECTED ACTUAL + +# kill $server_pid +shutdown + +rm -fr DIR +mkdir DIR +case `uname` in + MINGW*) + $VALGRIND jscoverage-server --no-highlight --port=8081 --document-root=recursive --report-dir=DIR --no-instrument=1/ & + ;; + *) + $VALGRIND jscoverage-server --no-highlight --port=8081 --document-root=recursive --report-dir=DIR --no-instrument=/1/ & + ;; +esac +server_pid=$! +server_port=8081 + +sleep $delay + +wget -q -O- http://127.0.0.1:8081/script.js > OUT +cat ../report.js recursive.expected/script.js | sed 's/@PREFIX@/\//g' | diff --strip-trailing-cr - OUT +wget -q -O- http://127.0.0.1:8081/1/1.js | diff --strip-trailing-cr recursive/1/1.js - +wget -q -O- http://127.0.0.1:8081/1/2/2.js | diff --strip-trailing-cr recursive/1/2/2.js - + +# kill $server_pid +shutdown + +$VALGRIND jscoverage-server --no-highlight --port 8082 --document-root recursive --report-dir DIR --no-instrument 1/ & +server_pid=$! +server_port=8082 + +sleep $delay + +wget -q -O- http://127.0.0.1:8082/script.js > OUT +cat ../report.js recursive.expected/script.js | sed 's/@PREFIX@/\//g' | diff --strip-trailing-cr - OUT +wget -q -O- http://127.0.0.1:8082/1/1.js | diff --strip-trailing-cr recursive/1/1.js - +wget -q -O- http://127.0.0.1:8082/1/2/2.js | diff --strip-trailing-cr recursive/1/2/2.js - + +# kill $server_pid +shutdown + +$VALGRIND jscoverage-server --port 8080 --encoding iso-8859-1 --document-root javascript & +server_pid=$! +server_port=8080 + +sleep $delay + +case "$character_encoding_support" in + yes) + wget -q -O- http://127.0.0.1:8080/javascript-iso-8859-1.js > OUT + cat ../report.js javascript.expected/javascript-iso-8859-1.js | sed 's/javascript-iso-8859-1.js/\/javascript-iso-8859-1.js/g' | diff --strip-trailing-cr - OUT + ;; + *) + echo 500 > EXPECTED + ! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/javascript-iso-8859-1.js 2> /dev/null > ACTUAL + diff EXPECTED ACTUAL + ;; +esac + +# kill $server_pid +shutdown + +$VALGRIND jscoverage-server --no-highlight --port=8080 --encoding=utf-8 --document-root=javascript-utf-8 & +server_pid=$! +server_port=8080 + +sleep $delay + +case "$character_encoding_support" in + yes) + wget -q -O- http://127.0.0.1:8080/javascript-utf-8.js > OUT + cat ../report.js javascript-utf-8.expected/javascript-utf-8.js | sed 's/javascript-utf-8.js/\/javascript-utf-8.js/g' | diff --strip-trailing-cr - OUT + ;; + *) + echo 500 > EXPECTED + ! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/javascript-utf-8.js 2> /dev/null > ACTUAL + diff EXPECTED ACTUAL + ;; +esac + +# kill $server_pid +shutdown + +$VALGRIND jscoverage-server --port 8080 --encoding BOGUS --document-root javascript & +server_pid=$! +server_port=8080 + +sleep $delay + +echo 500 > EXPECTED +! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/javascript-iso-8859-1.js 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL + +# kill $server_pid +shutdown + +$VALGRIND jscoverage-server --port 8080 --encoding utf-8 --document-root javascript & +server_pid=$! +server_port=8080 + +sleep $delay + +echo 500 > EXPECTED +! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/javascript-iso-8859-1.js 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/source-does-not-exist.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/source-does-not-exist.expected.err new file mode 100644 index 0000000..caf61ca --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/source-does-not-exist.expected.err @@ -0,0 +1,2 @@ +jscoverage: cannot stat file: foo +Try `jscoverage --help' for more information. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/source-is-file.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/source-is-file.expected.err new file mode 100644 index 0000000..b3fb0b6 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/source-is-file.expected.err @@ -0,0 +1,2 @@ +jscoverage: not a directory: foo +Try `jscoverage --help' for more information. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-json.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-json.sh new file mode 100755 index 0000000..5519514 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-json.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# store-bad-json.sh - test store with invalid JSON +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +$VALGRIND jscoverage-server --document-root=recursive --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +echo 400 > EXPECTED +! curl -d '!@#$%^&*()' -f -w '%{http_code}\n' http://127.0.0.1:8080/jscoverage-store 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-request-body.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-request-body.sh new file mode 100755 index 0000000..ef9883e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-request-body.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# store-bad-request-body.sh - test store with a bad request body +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +export PATH=.:..:$PATH + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +$VALGRIND jscoverage-server --document-root=recursive --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +./http-client-bad-body 8080 http://127.0.0.1:8080/jscoverage-store diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-response-headers.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-response-headers.sh new file mode 100755 index 0000000..28747b5 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-response-headers.sh @@ -0,0 +1,56 @@ +#!/bin/sh +# store-bad-response-headers.sh - test store with bad response headers +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +. common.sh + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown + kill -9 $origin_server_pid +} + +trap 'cleanup' 0 1 2 3 15 + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +$VALGRIND jscoverage-server --proxy --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 +./http-server-bad-headers & +origin_server_pid=$! + +sleep $delay + +# server sending malformed headers +cat store.json | sed "s/@PREFIX@/http:\\/\\/127.0.0.1:8000\\//g" > TMP +wget --post-file=TMP -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/jscoverage-store > /dev/null +json_cmp store-source-urls.expected.json DIR/jscoverage.json +sort ERR -o ERR +diff --strip-trailing-cr store-source-urls.expected.err ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-source-urls.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-source-urls.expected.err new file mode 100644 index 0000000..49fb754 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-source-urls.expected.err @@ -0,0 +1,3 @@ +Warning: cannot retrieve URL: 1/1.js +Warning: cannot retrieve URL: 1/2/2.js +Warning: cannot retrieve URL: script.js diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-source-urls.expected.json b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-source-urls.expected.json new file mode 100644 index 0000000..eb24c47 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-bad-source-urls.expected.json @@ -0,0 +1,14 @@ +{ + "script.js":{ + "coverage":[null,1,null,null,1,0], + "source":[] + }, + "1/1.js":{ + "coverage":[null,1], + "source":[] + }, + "1/2/2.js":{ + "coverage":[null,1], + "source":[] + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.expected.json b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.expected.json new file mode 100644 index 0000000..9546103 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.expected.json @@ -0,0 +1,6 @@ +{ + "/store-escaped-characters.js":{ + "coverage":[null,1,0,null,null,1,0,null,null,1,0], + "source":["function f() {","\treturn \'\\\'\';","}"," ","function g() {","\treturn \"\\\"\";","}","\f","function h() {","\treturn \'\\\\\';","}"] + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.js b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.js new file mode 100644 index 0000000..dc8ec36 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.js @@ -0,0 +1,11 @@ +function f() { + return '\''; +} + +function g() { + return "\""; +} + +function h() { + return '\\'; +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.json b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.json new file mode 100644 index 0000000..59cf4de --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.json @@ -0,0 +1,3 @@ +{ + "/store-escaped-characters.js":[null,1,0,null,null,1,0,null,null,1,0] +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.sh new file mode 100755 index 0000000..5eb9180 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-escaped-characters.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# store-escaped-characters.sh - test storing escaped characters in JavaScript source +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +. common.sh + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +$VALGRIND jscoverage-server --no-highlight --report-dir=DIR & +server_pid=$! +server_port=8080 + +sleep $delay + +wget --post-file=store-escaped-characters.json -q -O- http://127.0.0.1:8080/jscoverage-store > /dev/null +json_cmp store-escaped-characters.expected.json DIR/jscoverage.json +wget --post-file=store-escaped-characters.json -q -O- http://127.0.0.1:8080/jscoverage-store > /dev/null +cat store-escaped-characters.expected.json | sed s/1,/2,/g > TMP +json_cmp TMP DIR/jscoverage.json diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-server-bad-body.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-server-bad-body.sh new file mode 100755 index 0000000..b6ae810 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-server-bad-body.sh @@ -0,0 +1,59 @@ +#!/bin/sh +# store-server-bad-body.sh - test storing when server sends bad response body +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +. common.sh + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown + if [ "$origin_server_pid" != "" ] + then + kill -9 $origin_server_pid + fi +} + +trap 'cleanup' 0 1 2 3 15 + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +$VALGRIND jscoverage-server --proxy --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 +./http-server-bad-body & +origin_server_pid=$! + +sleep $delay + +# server sending malformed body +cat store.json | sed "s/@PREFIX@/http:\\/\\/127.0.0.1:8000\\//g" > TMP +wget --post-file=TMP -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/jscoverage-store > /dev/null +json_cmp store-source-urls.expected.json DIR/jscoverage.json +sort ERR -o ERR +diff --strip-trailing-cr store-source-urls.expected.err ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-server-closes-immediately.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-server-closes-immediately.sh new file mode 100755 index 0000000..a0ef9f9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-server-closes-immediately.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# store-server-closes-immediately.sh - test storing when server closes immediately +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +. common.sh + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown + if [ "$origin_server_pid" != "" ] + then + kill -9 $origin_server_pid + fi +} + +trap 'cleanup' 0 1 2 3 15 + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +$VALGRIND jscoverage-server --proxy --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 +./http-server-close-immediately & +origin_server_pid=$! + +sleep $delay + +cat store.json | sed "s/@PREFIX@/http:\\/\\/127.0.0.1:8000\\//g" > TMP +wget --post-file=TMP -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/jscoverage-store > /dev/null +json_cmp store-source-urls.expected.json DIR/jscoverage.json +sort ERR -o ERR +diff --strip-trailing-cr store-source-urls.expected.err ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.expected.err new file mode 100644 index 0000000..f00a540 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.expected.err @@ -0,0 +1 @@ +Warning: cannot open file: /missing.js diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.expected.json b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.expected.json new file mode 100644 index 0000000..3750b51 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.expected.json @@ -0,0 +1,6 @@ +{ + "/missing.js":{ + "coverage":[null,1,0], + "source":[] + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.json b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.json new file mode 100644 index 0000000..cfad0dd --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.json @@ -0,0 +1,3 @@ +{ + "/missing.js":[null, 1, 0] +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.sh new file mode 100755 index 0000000..aa2a1fa --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-not-found.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# store-source-not-found.sh - test store with JavaScript source not found +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +. common.sh + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +$VALGRIND jscoverage-server --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +wget --post-file=store-source-not-found.json -q -O- http://127.0.0.1:8080/jscoverage-store > /dev/null +json_cmp store-source-not-found.expected.json DIR/jscoverage.json +diff --strip-trailing-cr store-source-not-found.expected.err ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-urls.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-urls.expected.err new file mode 100644 index 0000000..90a2dd6 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-urls.expected.err @@ -0,0 +1,3 @@ +Warning: cannot retrieve URL: http://127.0.0.1:8000/1/1.js +Warning: cannot retrieve URL: http://127.0.0.1:8000/1/2/2.js +Warning: cannot retrieve URL: http://127.0.0.1:8000/script.js diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-urls.expected.json b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-urls.expected.json new file mode 100644 index 0000000..cb8d058 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-source-urls.expected.json @@ -0,0 +1,14 @@ +{ + "http://127.0.0.1:8000/script.js":{ + "coverage":[null,1,null,null,1,0], + "source":[] + }, + "http://127.0.0.1:8000/1/1.js":{ + "coverage":[null,1], + "source":[] + }, + "http://127.0.0.1:8000/1/2/2.js":{ + "coverage":[null,1], + "source":[] + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreachable-source-urls.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreachable-source-urls.expected.err new file mode 100644 index 0000000..96781cf --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreachable-source-urls.expected.err @@ -0,0 +1,3 @@ +Warning: cannot retrieve URL: http://127.0.0.1:1/1/1.js +Warning: cannot retrieve URL: http://127.0.0.1:1/1/2/2.js +Warning: cannot retrieve URL: http://127.0.0.1:1/script.js diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreachable-source-urls.expected.json b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreachable-source-urls.expected.json new file mode 100644 index 0000000..0885998 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreachable-source-urls.expected.json @@ -0,0 +1,14 @@ +{ + "http://127.0.0.1:1/script.js":{ + "coverage":[null,1,null,null,1,0], + "source":[] + }, + "http://127.0.0.1:1/1/1.js":{ + "coverage":[null,1], + "source":[] + }, + "http://127.0.0.1:1/1/2/2.js":{ + "coverage":[null,1], + "source":[] + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreadable-json.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreadable-json.sh new file mode 100755 index 0000000..026512b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unreadable-json.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# store-unreadable-json.sh - test store when jscoverage.json is not readable +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +. common.sh + +# skip on windows +uname=`uname` +case "$uname" in + CYGWIN* | MINGW*) + exit 77 + ;; +esac + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +$VALGRIND jscoverage-server --no-highlight --document-root=recursive --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +cat store.json | sed "s/@PREFIX@/\\//g" > TMP +wget --post-file=TMP -q -O- http://127.0.0.1:8080/jscoverage-store > /dev/null +cat store.expected.json | sed "s/@PREFIX@/\\//g" > TMP +json_cmp TMP DIR/jscoverage.json + +chmod -r DIR/jscoverage.json + +cat store.json | sed "s/@PREFIX@/\\//g" > TMP +echo 500 > EXPECTED +! curl -d @TMP -f -w '%{http_code}\n' http://127.0.0.1:8080/jscoverage-store 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unwritable-json.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unwritable-json.sh new file mode 100755 index 0000000..786e9bc --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store-unwritable-json.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# store-unwritable-json.sh - test store when jscoverage.json is not writable +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +. common.sh + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + shutdown +} + +trap 'cleanup' 0 1 2 3 15 + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +$VALGRIND jscoverage-server --no-highlight --document-root=recursive --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +cat store.json | sed "s/@PREFIX@/\\//g" > TMP +wget --post-file=TMP -q -O- http://127.0.0.1:8080/jscoverage-store > /dev/null +cat store.expected.json | sed "s/@PREFIX@/\\//g" > TMP +json_cmp TMP DIR/jscoverage.json + +chmod -w DIR/jscoverage.json + +cat store.json | sed "s/@PREFIX@/\\//g" > TMP +echo 500 > EXPECTED +! curl -d @TMP -f -w '%{http_code}\n' http://127.0.0.1:8080/jscoverage-store 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.expected.json b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.expected.json new file mode 100644 index 0000000..2aa393e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.expected.json @@ -0,0 +1,14 @@ +{ + "@PREFIX@script.js":{ + "coverage":[null,1,null,null,1,0], + "source":["alert(\"hello\");","","// test formatting &lt; &gt; &amp;","if ('a' < 'b' && 'a' > 'b') {"," alert(\"?\");","}"] + }, + "@PREFIX@1/1.js":{ + "coverage":[null,1], + "source":["alert(\"This is 1\");"] + }, + "@PREFIX@1/2/2.js":{ + "coverage":[null,1], + "source":["alert(\"This is 2\");"] + } +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.json b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.json new file mode 100644 index 0000000..942d686 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.json @@ -0,0 +1,5 @@ +{ + "@PREFIX@script.js":[null,1,null,null,1,0], + "@PREFIX@1/1.js":[null,1], + "@PREFIX@1/2/2.js":[null,1] +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.sh new file mode 100755 index 0000000..fb12574 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/store.sh @@ -0,0 +1,137 @@ +#!/bin/sh +# store.sh - test storing coverage reports with jscoverage-server +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +. common.sh + +shutdown() { + wget -q -O- --post-data= "http://127.0.0.1:${server_port}/jscoverage-shutdown" > /dev/null + wait $server_pid +} + +cleanup() { + # rm -fr DIR + # kill $server_pid + shutdown + if [ "$origin_server_pid" != "" ] + then + kill -9 $origin_server_pid + fi +} + +trap 'cleanup' 0 1 2 3 15 + +if [ -z "$VALGRIND" ] +then + delay=0.2 +else + delay=2 +fi + +rm -fr DIR +$VALGRIND jscoverage-server --no-highlight --document-root=recursive --report-dir=DIR & +server_pid=$! +server_port=8080 + +sleep $delay + +cat store.json | sed "s/@PREFIX@/\\//g" > TMP +wget --post-file=TMP -q -O- http://127.0.0.1:8080/jscoverage-store > /dev/null +cat store.expected.json | sed "s/@PREFIX@/\\//g" > TMP +json_cmp TMP DIR/jscoverage.json + +cat store.json | sed "s/@PREFIX@/\\//g" > TMP +wget --post-file=TMP -q -O- http://127.0.0.1:8080/jscoverage-store > /dev/null +cat store.expected.json | sed "s/@PREFIX@/\\//g" | sed "s/,1/,2/g" > TMP +json_cmp TMP DIR/jscoverage.json + +# try invalid method +echo 405 > EXPECTED +! curl -f -w '%{http_code}\n' http://127.0.0.1:8080/jscoverage-store 2> /dev/null > ACTUAL +diff EXPECTED ACTUAL + +# try with a path +cat store.json | sed "s/@PREFIX@/\\//g" > TMP +wget --post-file=TMP -q -O- http://127.0.0.1:8080/jscoverage-store/DIR > /dev/null +cat store.expected.json | sed "s/@PREFIX@/\\//g" > TMP +json_cmp TMP DIR/DIR/jscoverage.json + +shutdown + +cd recursive +perl ../server.pl > /dev/null 2> /dev/null & +origin_server_pid=$! +cd .. + +rm -fr DIR +$VALGRIND jscoverage-server --no-highlight --proxy --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +# test with proxy +cat store.json | sed "s/@PREFIX@/http:\\/\\/127.0.0.1:8000\\//g" > TMP +wget --post-file=TMP -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/jscoverage-store > /dev/null +cat store.expected.json | sed "s/@PREFIX@/http:\\/\\/127.0.0.1:8000\\//g" > TMP +json_cmp TMP DIR/jscoverage.json + +cat store.json | sed "s/@PREFIX@/http:\\/\\/127.0.0.1:8000\\//g" > TMP +wget --post-file=TMP -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/jscoverage-store > /dev/null +cat store.expected.json | sed "s/@PREFIX@/http:\\/\\/127.0.0.1:8000\\//g" | sed "s/,1/,2/g" > TMP +json_cmp TMP DIR/jscoverage.json + +# test cached source +rm -fr DIR +cat store.json | sed "s/@PREFIX@/http:\\/\\/127.0.0.1:8000\\//g" > TMP +wget --post-file=TMP -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/jscoverage-store > /dev/null +cat store.expected.json | sed "s/@PREFIX@/http:\\/\\/127.0.0.1:8000\\//g" > TMP +json_cmp TMP DIR/jscoverage.json + +shutdown + +rm -fr DIR +$VALGRIND jscoverage-server --no-highlight --proxy --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +# store JSON with bad source URLs +cat store.json | sed "s/@PREFIX@//g" > TMP +wget --post-file=TMP -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/jscoverage-store > /dev/null +json_cmp store-bad-source-urls.expected.json DIR/jscoverage.json +sort ERR -o ERR +diff --strip-trailing-cr store-bad-source-urls.expected.err ERR + +shutdown + +rm -fr DIR +$VALGRIND jscoverage-server --no-highlight --proxy --report-dir=DIR > OUT 2> ERR & +server_pid=$! +server_port=8080 + +sleep $delay + +# store JSON with unreachable source URLs +cat store.json | sed "s/@PREFIX@/http:\\/\\/127.0.0.1:1\\//g" > TMP +wget --post-file=TMP -q -O- -e 'http_proxy=http://127.0.0.1:8080/' http://127.0.0.1:8000/jscoverage-store > /dev/null +json_cmp store-unreachable-source-urls.expected.json DIR/jscoverage.json +sort ERR -o ERR +diff --strip-trailing-cr store-unreachable-source-urls.expected.err ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/streams.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/streams.c new file mode 100644 index 0000000..06389fb --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/streams.c @@ -0,0 +1,107 @@ +/* + streams.c - test `Stream' object + Copyright (C) 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include + +#include "stream.h" +#include "util.h" + +int main(void) { + Stream * stream; + + stream = Stream_new(0); + Stream_write_string(stream, "a"); + Stream_write_string(stream, "bc"); + assert(stream->length == 3); + assert(memcmp(stream->data, "abc", 3) == 0); + Stream_delete(stream); + + /* test writing chars to stream */ + stream = Stream_new(2); + Stream_write_char(stream, 'a'); + Stream_write_char(stream, 'b'); + Stream_write_char(stream, 'c'); + assert(stream->length == 3); + assert(memcmp(stream->data, "abc", 3) == 0); + Stream_reset(stream); + Stream_write_char(stream, 'x'); + Stream_write_char(stream, 'y'); + assert(stream->length == 2); + assert(memcmp(stream->data, "xy", 2) == 0); + Stream_delete(stream); + + /* test writing file to stream */ + stream = Stream_new(0); + FILE * f = xfopen("Makefile", "r"); + fseek(f, 0, SEEK_END); + long file_length = ftell(f); + fseek(f, 0, SEEK_SET); + uint8_t * file_contents = xmalloc(file_length); + fread(file_contents, 1, file_length, f); + fseek(f, 0, SEEK_SET); + Stream_write_file_contents(stream, f); + fclose(f); + assert(stream->length == (size_t) file_length); + assert(memcmp(stream->data, file_contents, file_length) == 0); + free(file_contents); + Stream_delete(stream); + + stream = Stream_new(0); + Stream_printf(stream, "%s %d\n", "abc", 123); + assert(stream->length == 8); + assert(memcmp(stream->data, "abc 123\n", 8) == 0); + Stream_delete(stream); + + stream = Stream_new(10); + size_t length = 0; + for (int i = 0; i < 100; i++) { + Stream_printf(stream, "%s %d\n", "abc", i); + if (i < 10) { + length += 6; + } + else { + length += 7; + } + } + assert(stream->length == length); + length = 0; + for (int i = 0; i < 100; i++) { + char buffer[8]; + int result = sprintf(buffer, "%s %d\n", "abc", i); + assert(memcmp(stream->data + length, buffer, result) == 0); + length += result; + } + assert(stream->length == length); + Stream_delete(stream); + + stream = Stream_new(10); + char buffer[100]; + for (int i = 0; i < 100; i++) { + buffer[i] = 'x'; + } + Stream_write(stream, buffer, 100); + assert(stream->length == 100); + for (int i = 0; i < 100; i++) { + assert(stream->data[i] == 'x'); + } + Stream_delete(stream); + + exit(EXIT_SUCCESS); +} diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/streams.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/streams.sh new file mode 100755 index 0000000..74cfebd --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/streams.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# streams.sh - test `Stream' object +# Copyright (C) 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +$VALGRIND ./streams diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/too-many-arguments.expected.err b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/too-many-arguments.expected.err new file mode 100644 index 0000000..4ab8b42 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/too-many-arguments.expected.err @@ -0,0 +1,2 @@ +jscoverage: too many arguments +Try `jscoverage --help' for more information. diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/valgrind.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/valgrind.sh new file mode 100755 index 0000000..c575324 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/valgrind.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +rm -f VALGRIND.* +export VALGRIND='valgrind --log-file=VALGRIND.%p' +make check +grep --color=always 'ERROR SUMMARY:' VALGRIND.* +grep --color=always 'definitely lost:' VALGRIND.* diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/version.sh b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/version.sh new file mode 100755 index 0000000..da0a26c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/tests/version.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# version.sh - test `--version' option +# Copyright (C) 2007, 2008 siliconforks.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +trap 'rm -fr OUT ERR' 1 2 3 15 + +export PATH=.:..:$PATH + +$VALGRIND jscoverage --version > OUT 2> ERR +test -s OUT +test ! -s ERR + +rm -fr OUT ERR diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/util.c b/bruml/lib/socket.io/support/expresso/deps/jscoverage/util.c new file mode 100644 index 0000000..40636ff --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/util.c @@ -0,0 +1,570 @@ +/* + util.c - general purpose utility routines + Copyright (C) 2007, 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#define _GNU_SOURCE + +#include + +#include "util.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +const char * program = NULL; + +void fatal(const char * format, ...) { + fprintf(stderr, "%s: ", program); + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fputc('\n', stderr); + exit(EXIT_FAILURE); +} + +void fatal_command_line(const char * format, ...) { + fprintf(stderr, "%s: ", program); + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fputc('\n', stderr); + fprintf(stderr, "Try `%s --help' for more information.\n", program); + exit(EXIT_FAILURE); +} + +void fatal_source(const char * source_file, unsigned int line_number, const char * format, ...) { + fprintf(stderr, "%s:%s:%u: ", program, source_file, line_number); + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fputc('\n', stderr); + exit(EXIT_FAILURE); +} + +void warn_source(const char * source_file, unsigned int line_number, const char * format, ...) { + fprintf(stderr, "%s:%s:%u: ", program, source_file, line_number); + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fputc('\n', stderr); +} + +void version(void) { + printf("%s %s\n", program, VERSION); + printf("Character encoding support: "); +#if HAVE_ICONV + printf("iconv\n"); +#elif HAVE_MULTIBYTETOWIDECHAR + printf("MultiByteToWideChar\n"); +#else + printf("none\n"); +#endif + exit(EXIT_SUCCESS); +} + +size_t addst(size_t x, size_t y) { + if (SIZE_MAX - x < y) { + fatal("integer overflow"); + } + return x + y; +} + +size_t mulst(size_t x, size_t y) { + if (x == 0 || y == 0) { + return 0; + } + if (SIZE_MAX / x < y) { + fatal("integer overflow"); + } + return x * y; +} + +void * xmalloc(size_t size) { + void * result = malloc(size); + if (result == NULL) { + fatal("out of memory"); + } + return result; +} + +void * xrealloc(void * p, size_t size) { + void * result = realloc(p, size); + if (result == NULL) { + fatal("out of memory"); + } + return result; +} + +char * xstrdup(const char * s) { + char * result = strdup(s); + if (result == NULL) { + fatal("out of memory"); + } + return result; +} + +char * xstrndup(const char * s, size_t size) { + char * result = strndup(s, size); + if (result == NULL) { + fatal("out of memory"); + } + return result; +} + +int xasprintf(char ** s, const char * template, ...) { + va_list a; + va_start(a, template); + int result = vasprintf(s, template, a); + va_end(a); + if (result < 0) { + fatal("out of memory"); + } + return result; +} + +char * xgetcwd(void) { + char * result = getcwd(NULL, 0); + if (result == NULL) { + fatal("out of memory"); + } + return result; +} + +FILE * xfopen(const char * file, const char * mode) { + FILE * result = fopen(file, mode); + if (result == NULL) { + fatal("cannot open file: %s", file); + } + return result; +} + +DIR * xopendir(const char * directory) { + DIR * result = opendir(directory); + if (result == NULL) { + fatal("cannot open directory: %s", directory); + } + return result; +} + +void xlstat(const char * file, struct stat * buf) { +#ifdef _WIN32 + return xstat(file, buf); +#else + if (lstat(file, buf) == -1) { + fatal("cannot stat file: %s", file); + } +#endif +} + +void xstat(const char * file, struct stat * buf) { + if (stat(file, buf) == -1) { + fatal("cannot stat file: %s", file); + } +} + +void xmkdir(const char * directory) { + int result; +#ifdef _WIN32 + result = mkdir(directory); +#else + result = mkdir(directory, 0755); +#endif + if (result == -1) { + fatal("cannot create directory: %s", directory); + } +} + +void mkdir_if_necessary(const char * directory) { + struct stat buf; + if (stat(directory, &buf) == 0) { + if (! S_ISDIR(buf.st_mode)) { + fatal("not a directory: %s", directory); + } + } + else { + if (errno == ENOENT) { + xmkdir(directory); + } + else { + fatal("cannot stat directory: %s", directory); + } + } +} + +void mkdirs(const char * directory) { + char * d = xmalloc(strlen(directory) + 1); + for (const char * p = directory; *p != '\0'; p++) { + if (*p == '/' && p > directory) { + strncpy(d, directory, p - directory); + d[p - directory] = '\0'; + mkdir_if_necessary(d); + } + } + mkdir_if_necessary(directory); + free(d); +} + +void xchdir(const char * directory) { + if (chdir(directory) == -1) { + fatal("cannot change directory: %s", directory); + } +} + +bool str_starts_with(const char * string, const char * prefix) { + const char * string_ptr = string; + const char * prefix_ptr = prefix; + while (*string_ptr != '\0' && *prefix_ptr != '\0') { + if (*string_ptr != *prefix_ptr) { + return false; + } + string_ptr++; + prefix_ptr++; + } + if (*string_ptr == '\0' && *prefix_ptr != '\0') { + return false; + } + return true; +} + +bool str_ends_with(const char * string, const char * suffix) { + size_t string_length = strlen(string); + size_t suffix_length = strlen(suffix); + if (string_length < suffix_length) { + return false; + } + return strcmp(string + string_length - suffix_length, suffix) == 0; +} + +char * make_path(const char * parent, const char * relative_path) { + size_t parent_length = strlen(parent); + size_t relative_path_length = strlen(relative_path); + size_t result_length = addst(parent_length, relative_path_length); + result_length = addst(result_length, 2); + char * result = xmalloc(result_length); + strcpy(result, parent); + result[parent_length] = '/'; + strcpy(result + parent_length + 1, relative_path); + return result; +} + +char * make_canonical_path(const char * relative_path) { + char * original_directory = xgetcwd(); + char * base = make_basename(relative_path); + char * dir = make_dirname(relative_path); + + xchdir(dir); + char * canonical_dir = xgetcwd(); + char * result = make_path(canonical_dir, base); + + free(canonical_dir); + free(base); + free(dir); + xchdir(original_directory); + free(original_directory); + + return result; +} + +char * make_basename(const char * path) { + char * copy = xstrdup(path); + char * result = xstrdup(basename(copy)); + free(copy); + return result; +} + +char * make_dirname(const char * path) { + char * copy = xstrdup(path); + char * result = xstrdup(dirname(copy)); + free(copy); + return result; +} + +int is_same_file(const char * file1, const char * file2) { +#ifdef _WIN32 +#define FILECMP strcasecmp +#else +#define FILECMP strcmp +#endif + if (FILECMP(file1, file2) == 0) { + return 1; + } + + char * canonical1 = make_canonical_path(file1); + char * canonical2 = make_canonical_path(file2); + int cmp = FILECMP(canonical1, canonical2); + free(canonical1); + free(canonical2); + if (cmp == 0) { + return 1; + } + +#ifndef _WIN32 + struct stat buf1; + if (stat(file1, &buf1) == -1) { + if (errno == ENOENT) { + return 0; + } + else { + fatal("cannot stat file: %s", file1); + } + } + struct stat buf2; + if (stat(file2, &buf2) == -1) { + if (errno == ENOENT) { + return 0; + } + else { + fatal("cannot stat file: %s", file2); + } + } + if (buf1.st_dev == buf2.st_dev && + buf1.st_ino == buf2.st_ino) { + return 1; + } +#endif + return 0; +#undef FILECMP +} + +int contains_file(const char * file1, const char * file2) { + int result = 0; + char * ancestor = make_canonical_path(file1); + char * d = make_canonical_path(file2); + char * parent = make_dirname(d); + while (strcmp(d, parent) != 0) { + if (is_same_file(ancestor, parent)) { + result = 1; + break; + } + free(d); + d = parent; + parent = make_dirname(d); + } + free(d); + free(parent); + free(ancestor); + return result; +} + +void copy_stream(FILE * source, FILE * destination) { + unsigned char buffer[8192]; + for (;;) { + int bytes_read = fread(buffer, 1, sizeof(buffer), source); + if (bytes_read == 0) { + break; + } + fwrite(buffer, 1, bytes_read, destination); + } +} + +void copy_file(const char * source_file, const char * destination_file) { + FILE * source = xfopen(source_file, "rb"); + FILE * destination = xfopen(destination_file, "wb"); + + copy_stream(source, destination); + +#ifndef _WIN32 + /* copy permissions */ + struct stat buf; + if (fstat(fileno(source), &buf) == -1) { + fatal("cannot stat file: %s", source_file); + } + fchmod(fileno(destination), buf.st_mode); +#endif + + fclose(source); + fclose(destination); +} + +bool directory_is_empty(const char * directory) { + bool result = true; + DIR * dir = xopendir(directory); + struct dirent * e; + while ((e = readdir(dir)) != NULL) { + if (strcmp(e->d_name, ".") != 0 && + strcmp(e->d_name, "..") != 0) { + result = false; + break; + } + } + closedir(dir); + return result; +} + +static struct DirListEntry * recursive_dir_list(const char * root, const char * directory_wrt_root, struct DirListEntry * head) { + char * directory = directory_wrt_root == NULL? xstrdup(root): make_path(root, directory_wrt_root); + DIR * dir = xopendir(directory); + struct dirent * e; + while ((e = readdir(dir)) != NULL) { + if (strcmp(e->d_name, ".") == 0 || + strcmp(e->d_name, "..") == 0) { + continue; + } + char * entry = make_path(directory, e->d_name); + char * entry_wrt_root = directory_wrt_root == NULL? xstrdup(e->d_name): make_path(directory_wrt_root, e->d_name); + struct stat buf; + xlstat(entry, &buf); + if (S_ISREG(buf.st_mode)) { + struct DirListEntry * p = xmalloc(sizeof(struct DirListEntry)); + p->name = entry_wrt_root; + p->next = head; + head = p; + } + else if (S_ISDIR(buf.st_mode)) { + head = recursive_dir_list(root, entry_wrt_root, head); + free(entry_wrt_root); + } +#ifndef _WIN32 + else if (S_ISLNK(buf.st_mode)) { + /* check what it points to */ + xstat(entry, &buf); + if (S_ISREG(buf.st_mode)) { + struct DirListEntry * p = xmalloc(sizeof(struct DirListEntry)); + p->name = entry_wrt_root; + p->next = head; + head = p; + } + else { + fatal("refusing to follow symbolic link: %s", entry); + } + } +#endif + else { + fatal("unknown file type: %s", entry); + } + free(entry); + } + closedir(dir); + free(directory); + return head; +} + +struct DirListEntry * make_recursive_dir_list(const char * directory) { + return recursive_dir_list(directory, NULL, NULL); +} + +void free_dir_list(struct DirListEntry * list) { + while (list != NULL) { + struct DirListEntry * next = list->next; + free(list->name); + free(list); + list = next; + } +} + +#ifndef HAVE_STRNDUP +char * strndup(const char * s, size_t size) { + size_t length = strlen(s); + if (length > size) { + char * result = xmalloc(size + 1); + strncpy(result, s, size); + result[size] = '\0'; + return result; + } + else { + char * result = xmalloc(length + 1); + strcpy(result, s); + return result; + } +} +#endif + +#ifndef HAVE_VASPRINTF +int vasprintf(char ** s, const char * template, va_list a) { + int size = 100; + *s = malloc(size); + if (*s == NULL) { + return -1; + } + + va_list copy; + va_copy(copy, a); + int result = vsnprintf(*s, size, template, copy); + if (result >= size) { + int new_size = result; + if (new_size == INT_MAX) { + free(*s); + return -1; + } + new_size++; + char * new_s = realloc(*s, new_size); + if (new_s == NULL) { + free(*s); + return -1; + } + *s = new_s; + size = new_size; + va_copy(copy, a); + result = vsnprintf(*s, size, template, copy); + assert(result == size - 1); + } + else if (result == -1) { + while (result == -1) { + if (size == INT_MAX) { + free(*s); + return -1; + } + int new_size; + if (size > INT_MAX / 2) { + new_size = INT_MAX; + } + else { + new_size = 2 * size; + } + char * new_s = realloc(*s, new_size); + if (new_s == NULL) { + free(*s); + return -1; + } + *s = new_s; + size = new_size; + va_copy(copy, a); + result = vsnprintf(*s, size, template, copy); + } + assert(result <= size - 1); + } + + return result; +} +#endif + +#ifndef HAVE_ASPRINTF +int asprintf(char ** s, const char * template, ...) { + va_list a; + va_start(a, template); + int result = vasprintf(s, template, a); + va_end(a); + return result; +} +#endif diff --git a/bruml/lib/socket.io/support/expresso/deps/jscoverage/util.h b/bruml/lib/socket.io/support/expresso/deps/jscoverage/util.h new file mode 100644 index 0000000..5cd063f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/deps/jscoverage/util.h @@ -0,0 +1,133 @@ +/* + util.h - general purpose utility routines + Copyright (C) 2007, 2008 siliconforks.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef UTIL_H_ +#define UTIL_H_ + +#ifndef HAVE_VASPRINTF +#include +#endif +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char * program; + +void fatal(const char * format, ...) + __attribute__((__noreturn__)) + __attribute__((__format__(printf, 1, 2))); + +void fatal_command_line(const char * format, ...) + __attribute__((__noreturn__)) + __attribute__((__format__(printf, 1, 2))); + +void fatal_source(const char * source_file, unsigned int line_number, const char * format, ...) + __attribute__((__noreturn__)) + __attribute__((__format__(printf, 3, 4))); + +void warn_source(const char * source_file, unsigned int line_number, const char * format, ...) + __attribute__((__format__(printf, 3, 4))); + +void version(void) + __attribute__((__noreturn__)); + +size_t addst(size_t x, size_t y); + +size_t mulst(size_t x, size_t y); + +void * xmalloc(size_t size); + +#define xnew(type, count) ((type *) xmalloc(mulst((count), sizeof(type)))) + +void * xrealloc(void * p, size_t size); + +char * xstrdup(const char * s); + +char * xstrndup(const char * s, size_t size); + +int xasprintf(char ** s, const char * format, ...) __attribute__((__format__(printf, 2, 3))); + +char * xgetcwd(void); + +FILE * xfopen(const char * file, const char * mode); + +void xstat(const char * file, struct stat * buf); + +void xlstat(const char * file, struct stat * buf); + +void xmkdir(const char * directory); + +void mkdir_if_necessary(const char * directory); + +void mkdirs(const char * path); + +bool str_starts_with(const char * string, const char * prefix); + +bool str_ends_with(const char * string, const char * suffix); + +char * make_path(const char * parent, const char * relative_path); + +char * make_canonical_path(const char * relative_path); + +char * make_basename(const char * path); + +char * make_dirname(const char * path); + +int is_same_file(const char * file1, const char * file2); + +int contains_file(const char * file1, const char * file2); + +void copy_stream(FILE * source, FILE * destination); + +void copy_file(const char * source_file, const char * destination_file); + +bool directory_is_empty(const char * directory); + +struct DirListEntry { + char * name; + struct DirListEntry * next; +}; + +struct DirListEntry * make_recursive_dir_list(const char * directory); + +void free_dir_list(struct DirListEntry * list); + +#ifndef HAVE_STRNDUP +char * strndup(const char * s, size_t size); +#endif + +#ifndef HAVE_VASPRINTF +int vasprintf(char ** s, const char * format, va_list a); +#endif + +#ifndef HAVE_ASPRINTF +int asprintf(char ** s, const char * format, ...) __attribute__((__format__(printf, 2, 3))); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* UTIL_H_ */ diff --git a/bruml/lib/socket.io/support/expresso/docs/api.html b/bruml/lib/socket.io/support/expresso/docs/api.html new file mode 100644 index 0000000..7b8fb2b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/docs/api.html @@ -0,0 +1,1080 @@ +Fork me on GitHub + + Expresso + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Expresso

Insanely fast TDD framework for node featuring code coverage reporting.

expresso

bin/expresso
+

!/usr/bin/env node

+
+

+ * Expresso
+ * Copyright(c) TJ Holowaychuk &lt;tj@vision-media.ca&gt;
+ * (MIT Licensed)
+ 
+
+

Module dependencies. +

+
+
var assert = require('assert'),
+    childProcess = require('child_process'),
+    http = require('http'),
+    path = require('path'),
+    sys = require('sys'),
+    cwd = process.cwd(),
+    fs = require('fs'),
+    defer;
+
+

Expresso version. +

+
+
var version = '0.6.4';
+
+

Failure count. +

+
+
var failures = 0;
+
+

Number of tests executed. +

+
+
var testcount = 0;
+
+

Whitelist of tests to run. +

+
+
var only = [];
+
+

Boring output. +

+
+
var boring = false;
+
+

Growl notifications. +

+
+
var growl = false;
+
+

Server port. +

+
+
var port = 5555;
+
+

Watch mode. +

+
+
var watch = false;
+
+

Execute serially. +

+
+
var serial = false;
+
+

Default timeout. +

+
+
var timeout = 2000;
+
+

Usage documentation. +

+
+
var usage = ''
+    + '[bold]{Usage}: expresso [options] <file ...>'
+    + '\n'
+    + '\n[bold]{Options}:'
+    + '\n  -w, --watch          Watch for modifications and re-execute tests'
+    + '\n  -g, --growl          Enable growl notifications'
+    + '\n  -c, --coverage       Generate and report test coverage'
+    + '\n  -t, --timeout MS     Timeout in milliseconds, defaults to 2000'
+    + '\n  -r, --require PATH   Require the given module path'
+    + '\n  -o, --only TESTS     Execute only the comma sperated TESTS (can be set several times)'
+    + '\n  -I, --include PATH   Unshift the given path to require.paths'
+    + '\n  -p, --port NUM       Port number for test servers, starts at 5555'
+    + '\n  -s, --serial         Execute tests serially'
+    + '\n  -b, --boring         Suppress ansi-escape colors'
+    + '\n  -v, --version        Output version number'
+    + '\n  -h, --help           Display help information'
+    + '\n';
+
+// Parse arguments
+
+var files = [],
+    args = process.argv.slice(2);
+
+while (args.length) {
+    var arg = args.shift();
+    switch (arg) {
+        case '-h':
+        case '--help':
+            print(usage + '\n');
+            process.exit(1);
+            break;
+        case '-v':
+        case '--version':
+            sys.puts(version);
+            process.exit(1);
+            break;
+        case '-i':
+        case '-I':
+        case '--include':
+            if (arg = args.shift()) {
+                require.paths.unshift(arg);
+            } else {
+                throw new Error('--include requires a path');
+            }
+            break;
+        case '-o':
+        case '--only':
+            if (arg = args.shift()) {
+                only = only.concat(arg.split(/ *, */));
+            } else {
+                throw new Error('--only requires comma-separated test names');
+            }
+            break;
+        case '-p':
+        case '--port':
+            if (arg = args.shift()) {
+                port = parseInt(arg, 10);
+            } else {
+                throw new Error('--port requires a number');
+            }
+            break;
+        case '-r':
+        case '--require':
+            if (arg = args.shift()) {
+                require(arg);
+            } else {
+                throw new Error('--require requires a path');
+            }
+            break;
+        case '-t':
+        case '--timeout':
+          if (arg = args.shift()) {
+            timeout = parseInt(arg, 10);
+          } else {
+            throw new Error('--timeout requires an argument');
+          }
+          break;
+        case '-c':
+        case '--cov':
+        case '--coverage':
+            defer = true;
+            childProcess.exec('rm -fr lib-cov && node-jscoverage lib lib-cov', function(err){
+                if (err) throw err;
+                require.paths.unshift('lib-cov');
+                run(files);
+            })
+            break;
+        case '-b':
+        case '--boring':
+        	boring = true;
+        	break;
+        case '-w':
+        case '--watch':
+            watch = true;
+            break;
+        case '-g':
+        case '--growl':
+            growl = true;
+            break;
+        case '-s':
+        case '--serial':
+            serial = true;
+            break;
+        default:
+            if (/\.js$/.test(arg)) {
+                files.push(arg);
+            }
+            break;
+    }
+}
+
+

Colorized sys.error().

+ +

+ +
  • param: String str

+
+
function print(str){
+    sys.error(colorize(str));
+}
+
+

Colorize the given string using ansi-escape sequences. +Disabled when --boring is set.

+ +

+ +
  • param: String str

  • return: String

+
+
function colorize(str){
+    var colors = { bold: 1, red: 31, green: 32, yellow: 33 };
+    return str.replace(/\[(\w+)\]\{([^]*?)\}/g, function(_, color, str){
+        return boring
+            ? str
+            : '\x1B[' + colors[color] + 'm' + str + '\x1B[0m';
+    });
+}
+
+// Alias deepEqual as eql for complex equality
+
+assert.eql = assert.deepEqual;
+
+

Assert that val is null.

+ +

+ +
  • param: Mixed val

  • param: String msg

+
+
assert.isNull = function(val, msg) {
+    assert.strictEqual(null, val, msg);
+};
+
+

Assert that val is not null.

+ +

+ +
  • param: Mixed val

  • param: String msg

+
+
assert.isNotNull = function(val, msg) {
+    assert.notStrictEqual(null, val, msg);
+};
+
+

Assert that val is undefined.

+ +

+ +
  • param: Mixed val

  • param: String msg

+
+
assert.isUndefined = function(val, msg) {
+    assert.strictEqual(undefined, val, msg);
+};
+
+

Assert that val is not undefined.

+ +

+ +
  • param: Mixed val

  • param: String msg

+
+
assert.isDefined = function(val, msg) {
+    assert.notStrictEqual(undefined, val, msg);
+};
+
+

Assert that obj is type.

+ +

+ +
  • param: Mixed obj

  • param: String type

  • api: public

+
+
assert.type = function(obj, type, msg){
+    var real = typeof obj;
+    msg = msg || 'typeof ' + sys.inspect(obj) + ' is ' + real + ', expected ' + type;
+    assert.ok(type === real, msg);
+};
+
+

Assert that str matches regexp.

+ +

+ +
  • param: String str

  • param: RegExp regexp

  • param: String msg

+
+
assert.match = function(str, regexp, msg) {
+    msg = msg || sys.inspect(str) + ' does not match ' + sys.inspect(regexp);
+    assert.ok(regexp.test(str), msg);
+};
+
+

Assert that val is within obj.

+ +

Examples

+ +

assert.includes('foobar', 'bar'); + assert.includes(['foo', 'bar'], 'foo');

+ +

+ +
  • param: String | Array obj

  • param: Mixed val

  • param: String msg

+
+
assert.includes = function(obj, val, msg) {
+    msg = msg || sys.inspect(obj) + ' does not include ' + sys.inspect(val);
+    assert.ok(obj.indexOf(val) &gt;= 0, msg);
+};
+
+

Assert length of val is n.

+ +

+ +
  • param: Mixed val

  • param: Number n

  • param: String msg

+
+
assert.length = function(val, n, msg) {
+    msg = msg || sys.inspect(val) + ' has length of ' + val.length + ', expected ' + n;
+    assert.equal(n, val.length, msg);
+};
+
+

Assert response from server with +the given req object and res assertions object.

+ +

+ +
  • param: Server server

  • param: Object req

  • param: Object | Function res

  • param: String msg

+
+
assert.response = function(server, req, res, msg){
+    // Callback as third or fourth arg
+    var callback = typeof res === 'function'
+        ? res
+        : typeof msg === 'function'
+            ? msg
+            : function(){};
+
+    // Default messate to test title
+    if (typeof msg === 'function') msg = null;
+    msg = msg || assert.testTitle;
+    msg += '. ';
+
+    // Pending responses
+    server.__pending = server.__pending || 0;
+    server.__pending++;
+
+    // Create client
+    if (!server.fd) {
+        server.listen(server.__port = port++, '127.0.0.1');
+        server.client = http.createClient(server.__port);
+    }
+
+    // Issue request
+    var timer,
+        client = server.client,
+        method = req.method || 'GET',
+        status = res.status || res.statusCode,
+        data = req.data || req.body,
+        requestTimeout = req.timeout || 0;
+
+    var request = client.request(method, req.url, req.headers);
+
+    // Timeout
+    if (requestTimeout) {
+        timer = setTimeout(function(){
+            --server.__pending || server.close();
+            delete req.timeout;
+            assert.fail(msg + 'Request timed out after ' + requestTimeout + 'ms.');
+        }, requestTimeout);
+    }
+
+    if (data) request.write(data);
+    request.addListener('response', function(response){
+        response.body = '';
+        response.setEncoding('utf8');
+        response.addListener('data', function(chunk){ response.body += chunk; });
+        response.addListener('end', function(){
+            --server.__pending || server.close();
+            if (timer) clearTimeout(timer);
+
+            // Assert response body
+            if (res.body !== undefined) {
+                var eql = res.body instanceof RegExp
+                  ? res.body.test(response.body)
+                  : res.body === response.body;
+                assert.ok(
+                    eql,
+                    msg + 'Invalid response body.\n'
+                        + '    Expected: ' + sys.inspect(res.body) + '\n'
+                        + '    Got: ' + sys.inspect(response.body)
+                );
+            }
+
+            // Assert response status
+            if (typeof status === 'number') {
+                assert.equal(
+                    response.statusCode,
+                    status,
+                    msg + colorize('Invalid response status code.\n'
+                        + '    Expected: [green]{' + status + '}\n'
+                        + '    Got: [red]{' + response.statusCode + '}')
+                );
+            }
+
+            // Assert response headers
+            if (res.headers) {
+                var keys = Object.keys(res.headers);
+                for (var i = 0, len = keys.length; i &lt; len; ++i) {
+                    var name = keys[i],
+                        actual = response.headers[name.toLowerCase()],
+                        expected = res.headers[name],
+                        eql = expected instanceof RegExp
+                          ? expected.test(actual)
+                          : expected == actual;
+                    assert.ok(
+                        eql,
+                        msg + colorize('Invalid response header [bold]{' + name + '}.\n'
+                            + '    Expected: [green]{' + expected + '}\n'
+                            + '    Got: [red]{' + actual + '}')
+                    );
+                }
+            }
+
+            // Callback
+            callback(response);
+        });
+    });
+    request.end();
+};
+
+

Pad the given string to the maximum width provided.

+ +

+ +
  • param: String str

  • param: Number width

  • return: String

+
+
function lpad(str, width) {
+    str = String(str);
+    var n = width - str.length;
+    if (n &lt; 1) return str;
+    while (n--) str = ' ' + str;
+    return str;
+}
+
+

Pad the given string to the maximum width provided.

+ +

+ +
  • param: String str

  • param: Number width

  • return: String

+
+
function rpad(str, width) {
+    str = String(str);
+    var n = width - str.length;
+    if (n &lt; 1) return str;
+    while (n--) str = str + ' ';
+    return str;
+}
+
+

Report test coverage.

+ +

+ +
  • param: Object cov

+
+
function reportCoverage(cov) {
+    populateCoverage(cov);
+    // Stats
+    print('\n   [bold]{Test Coverage}\n');
+    var sep = '   +------------------------------------------+----------+------+------+--------+',
+        lastSep = '                                              +----------+------+------+--------+';
+    sys.puts(sep);
+    sys.puts('   | filename                                 | coverage | LOC  | SLOC | missed |');
+    sys.puts(sep);
+    for (var name in cov) {
+        var file = cov[name];
+        if (Array.isArray(file)) {
+            sys.print('   | ' + rpad(name, 40));
+            sys.print(' | ' + lpad(file.coverage.toFixed(2), 8));
+            sys.print(' | ' + lpad(file.LOC, 4));
+            sys.print(' | ' + lpad(file.SLOC, 4));
+            sys.print(' | ' + lpad(file.totalMisses, 6));
+            sys.print(' |\n');
+        }
+    }
+    sys.puts(sep);
+    sys.print('     ' + rpad('', 40));
+    sys.print(' | ' + lpad(cov.coverage.toFixed(2), 8));
+    sys.print(' | ' + lpad(cov.LOC, 4));
+    sys.print(' | ' + lpad(cov.SLOC, 4));
+    sys.print(' | ' + lpad(cov.totalMisses, 6));
+    sys.print(' |\n');
+    sys.puts(lastSep);
+    // Source
+    for (var name in cov) {
+        if (name.match(/\.js$/)) {
+            var file = cov[name];
+            print('\n   [bold]{' + name + '}:');
+            print(file.source);
+            sys.print('\n');
+        }
+    }
+}
+
+

Populate code coverage data.

+ +

+ +
  • param: Object cov

+
+
function populateCoverage(cov) {
+    cov.LOC = 
+    cov.SLOC =
+    cov.totalFiles =
+    cov.totalHits =
+    cov.totalMisses = 
+    cov.coverage = 0;
+    for (var name in cov) {
+        var file = cov[name];
+        if (Array.isArray(file)) {
+            // Stats
+            ++cov.totalFiles;
+            cov.totalHits += file.totalHits = coverage(file, true);
+            cov.totalMisses += file.totalMisses = coverage(file, false);
+            file.totalLines = file.totalHits + file.totalMisses;
+            cov.SLOC += file.SLOC = file.totalLines;
+            if (!file.source) file.source = [];
+            cov.LOC += file.LOC = file.source.length;
+            file.coverage = (file.totalHits / file.totalLines) * 100;
+            // Source
+            var width = file.source.length.toString().length;
+            file.source = file.source.map(function(line, i){
+                ++i;
+                var hits = file[i] === 0 ? 0 : (file[i] || ' ');
+                if (!boring) {
+                    if (hits === 0) {
+                        hits = '\x1b[31m' + hits + '\x1b[0m';
+                        line = '\x1b[41m' + line + '\x1b[0m';
+                    } else {
+                        hits = '\x1b[32m' + hits + '\x1b[0m';
+                    }
+                }
+                return '\n     ' + lpad(i, width) + ' | ' + hits + ' | ' + line;
+            }).join('');
+        }
+    }
+    cov.coverage = (cov.totalHits / cov.SLOC) * 100;
+}
+
+

Total coverage for the given file data.

+ +

+ +
  • param: Array data

  • return: Type

+
+
function coverage(data, val) {
+    var n = 0;
+    for (var i = 0, len = data.length; i &lt; len; ++i) {
+        if (data[i] !== undefined &amp;&amp; data[i] == val) ++n;
+    }
+    return n;  
+}
+
+

Run the given test files, or try test/*.

+ +

+ +
  • param: Array files

+
+
function run(files) {
+    if (!files.length) {
+        try {
+            files = fs.readdirSync('test').map(function(file){
+                return 'test/' + file;
+            });
+        } catch (err) {
+            print('\n  failed to load tests in [bold]{./test}\n');
+            ++failures;
+            process.exit(1);
+        }
+    }
+    if (watch) watchFiles(files);
+    runFiles(files);
+}
+
+

Show the cursor when show is true, otherwise hide it.

+ +

+ +
  • param: Boolean show

+
+
function cursor(show) {
+    if (show) {
+        sys.print('\x1b[?25h');
+    } else {
+        sys.print('\x1b[?25l');
+    }
+}
+
+

Run the given test files.

+ +

+ +
  • param: Array files

+
+
function runFiles(files) {
+    if (serial) {
+        (function next(){
+            if (files.length) {
+                runFile(files.shift(), next);
+            }
+        })();
+    } else {
+      files.forEach(runFile);
+    }
+}
+
+

Run tests for the given file, callback fn() when finished.

+ +

+ +
  • param: String file

  • param: Function fn

+
+
function runFile(file, fn) {
+    if (file.match(/\.js$/)) {
+        var title = path.basename(file),
+            file = path.join(cwd, file),
+            mod = require(file.replace(/\.js$/, ''));
+        (function check(){
+           var len = Object.keys(mod).length;
+           if (len) {
+               runSuite(title, mod, fn);
+           } else {
+               setTimeout(check, 20);
+           }
+        })();
+    }
+}
+
+

Clear the module cache for the given file.

+ +

+ +
  • param: String file

+
+
function clearCache(file) {
+    var keys = Object.keys(module.moduleCache);
+    for (var i = 0, len = keys.length; i &lt; len; ++i) {
+        var key = keys[i];
+        if (key.indexOf(file) === key.length - file.length) {
+            delete module.moduleCache[key];
+        }
+    }
+}
+
+

Watch the given files for changes.

+ +

+ +
  • param: Array files

+
+
function watchFiles(files) {
+    var p = 0,
+        c = ['▫   ', '▫▫  ', '▫▫▫ ', ' ▫▫▫',
+             '  ▫▫', '   ▫', '   ▫', '  ▫▫',
+             '▫▫▫ ', '▫▫  ', '▫   '],
+        l = c.length;
+    cursor(false);
+    setInterval(function(){
+        sys.print(colorize('  [green]{' + c[p++ % l] + '} watching\r'));
+    }, 100);
+    files.forEach(function(file){
+        fs.watchFile(file, { interval: 100 }, function(curr, prev){
+            if (curr.mtime &gt; prev.mtime) {
+                print('  [yellow]{◦} ' + file);
+                clearCache(file);
+                runFile(file);
+            }
+        });
+    });
+}
+
+

Report err for the given test and suite.

+ +

+ +
  • param: String suite

  • param: String test

  • param: Error err

+
+
function error(suite, test, err) {
+    ++failures;
+    var name = err.name,
+        stack = err.stack.replace(err.name, ''),
+        label = test === 'uncaught'
+            ? test
+            : suite + ' ' + test;
+    print('\n   [bold]{' + label + '}: [red]{' + name + '}' + stack + '\n');
+    if (watch) notify(label + ' failed');
+}
+
+

Run the given tests, callback fn() when finished.

+ +

+ +
  • param: String title

  • param: Object tests

  • param: Function fn

+
+
var dots = 0;
+function runSuite(title, tests, fn) {
+    // Keys
+    var keys = only.length
+        ? only.slice(0)
+        : Object.keys(tests);
+
+    // Setup
+    var setup = tests.setup || function(fn){ fn(); };
+
+    // Iterate tests
+    (function next(){
+        if (keys.length) {
+            var key,
+                test = tests[key = keys.shift()];
+            // Non-tests
+            if (key === 'setup') return next();
+
+            // Run test
+            if (test) {
+                try {
+                    ++testcount;
+                    assert.testTitle = key;
+                    if (serial) {
+                        if (!watch) {
+                            sys.print('.');
+                            if (++dots % 25 === 0) sys.print('\n');
+                        }
+                        setup(function(){
+                            if (test.length &lt; 1) {
+                                test();
+                                next();
+                            } else {
+                                var id = setTimeout(function(){
+                                    throw new Error(&quot;'" + key + "' timed out&quot;);
+                                }, timeout);
+                                test(function(){
+                                    clearTimeout(id);
+                                    next();
+                                });
+                            } 
+                        });
+                    } else {
+                        test(function(fn){
+                            process.addListener('beforeExit', function(){
+                                try {
+                                    fn();
+                                } catch (err) {
+                                    error(title, key, err);
+                                }
+                            });
+                        });
+                    }
+                } catch (err) {
+                    error(title, key, err);
+                }
+            }
+            if (!serial) next();
+        } else if (serial) {
+          fn();
+        }
+    })();
+}
+
+

Report exceptions. +

+
+
function report() {
+    process.emit('beforeExit');
+    if (failures) {
+        print('\n   [bold]{Failures}: [red]{' + failures + '}\n\n');
+        notify('Failures: ' + failures);
+    } else {
+        if (serial) print('');
+        print('\n   [green]{100%} ' + testcount + ' tests\n');
+        notify('100% ok');
+    }
+    if (typeof _$jscoverage === 'object') {
+        reportCoverage(_$jscoverage);
+    }
+}
+
+

Growl notify the given msg.

+ +

+ +
  • param: String msg

+
+
function notify(msg) {
+    if (growl) {
+        childProcess.exec('growlnotify -name Expresso -m "' + msg + '"');
+    }
+}
+
+// Report uncaught exceptions
+
+process.addListener('uncaughtException', function(err){
+    error('uncaught', 'uncaught', err);
+});
+
+// Show cursor
+
+['INT', 'TERM', 'QUIT'].forEach(function(sig){
+    process.addListener('SIG' + sig, function(){
+        cursor(true);
+        process.exit(1);
+    });
+});
+
+// Report test coverage when available
+// and emit "beforeExit" event to perform
+// final assertions
+
+var orig = process.emit;
+process.emit = function(event){
+    if (event === 'exit') {
+        report();
+        process.reallyExit(failures);
+    }
+    orig.apply(this, arguments);
+};
+
+// Run test files
+
+if (!defer) run(files);
+
+
\ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/docs/index.html b/bruml/lib/socket.io/support/expresso/docs/index.html new file mode 100644 index 0000000..064313f --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/docs/index.html @@ -0,0 +1,377 @@ + + + Expresso - TDD Framework For Node + + + + + Fork me on GitHub + +
+

Expresso

+
+

NAME

+

+ index +

+

Expresso is a JavaScript TDD framework written for nodejs. Expresso is extremely fast, and is packed with features such as additional assertion methods, code coverage reporting, CI support, and more.

+ +

Features

+ +
    +
  • light-weight
  • +
  • intuitive async support
  • +
  • intuitive test runner executable
  • +
  • test coverage support and reporting via node-jscoverage
  • +
  • uses and extends the core assert module
  • +
  • assert.eql() alias of assert.deepEqual()
  • +
  • assert.response() http response utility
  • +
  • assert.includes()
  • +
  • assert.isNull()
  • +
  • assert.isUndefined()
  • +
  • assert.isNotNull()
  • +
  • assert.isDefined()
  • +
  • assert.match()
  • +
  • assert.length()
  • +
+ + +

Installation

+ +

To install both expresso and node-jscoverage run +the command below, which will first compile node-jscoverage:

+ +
$ make install
+
+ +

To install expresso alone without coverage reporting run:

+ +
$ make install-expresso
+
+ +

Install via npm:

+ +
$ npm install expresso
+
+ +

Examples

+ +

To define tests we simply export several functions:

+ +
exports['test String#length'] = function(){
+    assert.equal(6, 'foobar'.length);
+};
+
+ +

Alternatively for large numbers of tests you may want to +export your own object containing the tests, however this +is essentially the as above:

+ +
module.exports = {
+    'test String#length': function(){
+        assert.equal(6, 'foobar'.length);
+    }
+};
+
+ +

If you prefer not to use quoted keys:

+ +
exports.testsStringLength = function(){
+    assert.equal(6, 'foobar'.length);
+};
+
+ +

The argument passed to each callback is beforeExit, +which is typically used to assert that callbacks have been +invoked.

+ +
exports.testAsync = function(beforeExit){
+    var n = 0;
+    setTimeout(function(){
+        ++n;
+        assert.ok(true);
+    }, 200);
+    setTimeout(function(){
+        ++n;
+        assert.ok(true);
+    }, 200);
+    beforeExit(function(){
+        assert.equal(2, n, 'Ensure both timeouts are called');
+    });
+};
+
+ +

Assert Utilities

+ +

assert.isNull(val[, msg])

+ +

Asserts that the given val is null.

+ +
assert.isNull(null);
+
+ +

assert.isNotNull(val[, msg])

+ +

Asserts that the given val is not null.

+ +
assert.isNotNull(undefined);
+assert.isNotNull(false);
+
+ +

assert.isUndefined(val[, msg])

+ +

Asserts that the given val is undefined.

+ +
assert.isUndefined(undefined);
+
+ +

assert.isDefined(val[, msg])

+ +

Asserts that the given val is not undefined.

+ +
assert.isDefined(null);
+assert.isDefined(false);
+
+ +

assert.match(str, regexp[, msg])

+ +

Asserts that the given str matches regexp.

+ +
assert.match('foobar', /^foo(bar)?/);
+assert.match('foo', /^foo(bar)?/);
+
+ +

assert.length(val, n[, msg])

+ +

Assert that the given val has a length of n.

+ +
assert.length([1,2,3], 3);
+assert.length('foo', 3);
+
+ +

assert.type(obj, type[, msg])

+ +

Assert that the given obj is typeof type.

+ +
assert.type(3, 'number');
+
+ +

assert.eql(a, b[, msg])

+ +

Assert that object b is equal to object a. This is an +alias for the core assert.deepEqual() method which does complex +comparisons, opposed to assert.equal() which uses ==.

+ +
assert.eql('foo', 'foo');
+assert.eql([1,2], [1,2]);
+assert.eql({ foo: 'bar' }, { foo: 'bar' });
+
+ +

assert.includes(obj, val[, msg])

+ +

Assert that obj is within val. This method supports Array_s +and Strings_s.

+ +
assert.includes([1,2,3], 3);
+assert.includes('foobar', 'foo');
+assert.includes('foobar', 'bar');
+
+ +

assert.response(server, req, res|fn[, msg|fn])

+ +

Performs assertions on the given server, which should not call +listen(), as this is handled internally by expresso and the server +is killed after all responses have completed. This method works with +any http.Server instance, so Connect and Express servers will work +as well.

+ +

The req object may contain:

+ +
    +
  • url request url
  • +
  • timeout timeout in milliseconds
  • +
  • method HTTP method
  • +
  • data request body
  • +
  • headers headers object
  • +
+ + +

The res object may be a callback function which +receives the response for assertions, or an object +which is then used to perform several assertions +on the response with the following properties:

+ +
    +
  • body assert response body (regexp or string)
  • +
  • status assert response status code
  • +
  • header assert that all given headers match (unspecified are ignored, use a regexp or string)
  • +
+ + +

When providing res you may then also pass a callback function +as the fourth argument for additional assertions.

+ +

Below are some examples:

+ +
assert.response(server, {
+    url: '/', timeout: 500
+}, {
+    body: 'foobar'
+});
+
+assert.response(server, {
+    url: '/',
+    method: 'GET'
+},{
+    body: '{"name":"tj"}',
+    status: 200,
+    headers: {
+        'Content-Type': 'application/json; charset=utf8',
+        'X-Foo': 'bar'
+    }
+});
+
+assert.response(server, {
+    url: '/foo',
+    method: 'POST',
+    data: 'bar baz'
+},{
+    body: '/foo bar baz',
+    status: 200
+}, 'Test POST');
+
+assert.response(server, {
+    url: '/foo',
+    method: 'POST',
+    data: 'bar baz'
+},{
+    body: '/foo bar baz',
+    status: 200
+}, function(res){
+    // All done, do some more tests if needed
+});
+
+assert.response(server, {
+    url: '/'
+}, function(res){
+    assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback');
+});
+
+ +

expresso(1)

+ +

To run a single test suite (file) run:

+ +
$ expresso test/a.test.js
+
+ +

To run several suites we may simply append another:

+ +
$ expresso test/a.test.js test/b.test.js
+
+ +

We can also pass a whitelist of tests to run within all suites:

+ +
$ expresso --only "foo()" --only "bar()"
+
+ +

Or several with one call:

+ +
$ expresso --only "foo(), bar()"
+
+ +

Globbing is of course possible as well:

+ +
$ expresso test/*
+
+ +

When expresso is called without any files, test/* is the default, +so the following is equivalent to the command above:

+ +
$ expresso
+
+ +

If you wish to unshift a path to require.paths before +running tests, you may use the -I or --include flag.

+ +
$ expresso --include lib test/*
+
+ +

The previous example is typically what I would recommend, since expresso +supports test coverage via node-jscoverage (bundled with expresso), +so you will need to expose an instrumented version of you library.

+ +

To instrument your library, simply run node-jscoverage, +passing the src and dest directories:

+ +
$ node-jscoverage lib lib-cov
+
+ +

Now we can run our tests again, using the lib-cov directory that has been +instrumented with coverage statements:

+ +
$ expresso -I lib-cov test/*
+
+ +

The output will look similar to below, depending on your test coverage of course :)

+ +

node coverage

+ +

To make this process easier expresso has the -c or --cov which essentially +does the same as the two commands above. The following two commands will +run the same tests, however one will auto-instrument, and unshift lib-cov, +and the other will run tests normally:

+ +
$ expresso -I lib test/*
+$ expresso -I lib --cov test/*
+
+ +

Currently coverage is bound to the lib directory, however in the +future --cov will most likely accept a path.

+ +

Async Exports

+ +

Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the exports.foo = function(){}; syntax is supported for this:

+ +
setTimeout(function(){
+    exports['test async exports'] = function(){
+        assert.ok('wahoo');
+    };
+}, 100);
+
+ +
+
+ + \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/docs/index.md b/bruml/lib/socket.io/support/expresso/docs/index.md new file mode 100644 index 0000000..489f931 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/docs/index.md @@ -0,0 +1,290 @@ + +[Expresso](http://github.com/visionmedia/expresso) is a JavaScript [TDD](http://en.wikipedia.org/wiki/Test-driven_development) framework written for [nodejs](http://nodejs.org). Expresso is extremely fast, and is packed with features such as additional assertion methods, code coverage reporting, CI support, and more. + +## Features + + - light-weight + - intuitive async support + - intuitive test runner executable + - test coverage support and reporting via [node-jscoverage](http://github.com/visionmedia/node-jscoverage) + - uses and extends the core _assert_ module + - `assert.eql()` alias of `assert.deepEqual()` + - `assert.response()` http response utility + - `assert.includes()` + - `assert.isNull()` + - `assert.isUndefined()` + - `assert.isNotNull()` + - `assert.isDefined()` + - `assert.match()` + - `assert.length()` + +## Installation + +To install both expresso _and_ node-jscoverage run +the command below, which will first compile node-jscoverage: + + $ make install + +To install expresso alone without coverage reporting run: + + $ make install-expresso + +Install via npm: + + $ npm install expresso + +## Examples + +To define tests we simply export several functions: + + exports['test String#length'] = function(){ + assert.equal(6, 'foobar'.length); + }; + +Alternatively for large numbers of tests you may want to +export your own object containing the tests, however this +is essentially the as above: + + module.exports = { + 'test String#length': function(){ + assert.equal(6, 'foobar'.length); + } + }; + +If you prefer not to use quoted keys: + + exports.testsStringLength = function(){ + assert.equal(6, 'foobar'.length); + }; + +The argument passed to each callback is _beforeExit_, +which is typically used to assert that callbacks have been +invoked. + + exports.testAsync = function(beforeExit){ + var n = 0; + setTimeout(function(){ + ++n; + assert.ok(true); + }, 200); + setTimeout(function(){ + ++n; + assert.ok(true); + }, 200); + beforeExit(function(){ + assert.equal(2, n, 'Ensure both timeouts are called'); + }); + }; + +## Assert Utilities + +### assert.isNull(val[, msg]) + +Asserts that the given _val_ is _null_. + + assert.isNull(null); + +### assert.isNotNull(val[, msg]) + +Asserts that the given _val_ is not _null_. + + assert.isNotNull(undefined); + assert.isNotNull(false); + +### assert.isUndefined(val[, msg]) + +Asserts that the given _val_ is _undefined_. + + assert.isUndefined(undefined); + +### assert.isDefined(val[, msg]) + +Asserts that the given _val_ is not _undefined_. + + assert.isDefined(null); + assert.isDefined(false); + +### assert.match(str, regexp[, msg]) + +Asserts that the given _str_ matches _regexp_. + + assert.match('foobar', /^foo(bar)?/); + assert.match('foo', /^foo(bar)?/); + +### assert.length(val, n[, msg]) + +Assert that the given _val_ has a length of _n_. + + assert.length([1,2,3], 3); + assert.length('foo', 3); + +### assert.type(obj, type[, msg]) + +Assert that the given _obj_ is typeof _type_. + + assert.type(3, 'number'); + +### assert.eql(a, b[, msg]) + +Assert that object _b_ is equal to object _a_. This is an +alias for the core _assert.deepEqual()_ method which does complex +comparisons, opposed to _assert.equal()_ which uses _==_. + + assert.eql('foo', 'foo'); + assert.eql([1,2], [1,2]); + assert.eql({ foo: 'bar' }, { foo: 'bar' }); + +### assert.includes(obj, val[, msg]) + +Assert that _obj_ is within _val_. This method supports _Array_s +and _Strings_s. + + assert.includes([1,2,3], 3); + assert.includes('foobar', 'foo'); + assert.includes('foobar', 'bar'); + +### assert.response(server, req, res|fn[, msg|fn]) + +Performs assertions on the given _server_, which should _not_ call +listen(), as this is handled internally by expresso and the server +is killed after all responses have completed. This method works with +any _http.Server_ instance, so _Connect_ and _Express_ servers will work +as well. + +The _req_ object may contain: + + - _url_ request url + - _timeout_ timeout in milliseconds + - _method_ HTTP method + - _data_ request body + - _headers_ headers object + +The _res_ object may be a callback function which +receives the response for assertions, or an object +which is then used to perform several assertions +on the response with the following properties: + + - _body_ assert response body (regexp or string) + - _status_ assert response status code + - _header_ assert that all given headers match (unspecified are ignored, use a regexp or string) + +When providing _res_ you may then also pass a callback function +as the fourth argument for additional assertions. + +Below are some examples: + + assert.response(server, { + url: '/', timeout: 500 + }, { + body: 'foobar' + }); + + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8', + 'X-Foo': 'bar' + } + }); + + assert.response(server, { + url: '/foo', + method: 'POST', + data: 'bar baz' + },{ + body: '/foo bar baz', + status: 200 + }, 'Test POST'); + + assert.response(server, { + url: '/foo', + method: 'POST', + data: 'bar baz' + },{ + body: '/foo bar baz', + status: 200 + }, function(res){ + // All done, do some more tests if needed + }); + + assert.response(server, { + url: '/' + }, function(res){ + assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback'); + }); + + +## expresso(1) + +To run a single test suite (file) run: + + $ expresso test/a.test.js + +To run several suites we may simply append another: + + $ expresso test/a.test.js test/b.test.js + +We can also pass a whitelist of tests to run within all suites: + + $ expresso --only "foo()" --only "bar()" + +Or several with one call: + + $ expresso --only "foo(), bar()" + +Globbing is of course possible as well: + + $ expresso test/* + +When expresso is called without any files, _test/*_ is the default, +so the following is equivalent to the command above: + + $ expresso + +If you wish to unshift a path to `require.paths` before +running tests, you may use the `-I` or `--include` flag. + + $ expresso --include lib test/* + +The previous example is typically what I would recommend, since expresso +supports test coverage via [node-jscoverage](http://github.com/visionmedia/node-jscoverage) (bundled with expresso), +so you will need to expose an instrumented version of you library. + +To instrument your library, simply run [node-jscoverage](http://github.com/visionmedia/node-jscoverage), +passing the _src_ and _dest_ directories: + + $ node-jscoverage lib lib-cov + +Now we can run our tests again, using the _lib-cov_ directory that has been +instrumented with coverage statements: + + $ expresso -I lib-cov test/* + +The output will look similar to below, depending on your test coverage of course :) + +![node coverage](http://dl.dropbox.com/u/6396913/cov.png) + +To make this process easier expresso has the _-c_ or _--cov_ which essentially +does the same as the two commands above. The following two commands will +run the same tests, however one will auto-instrument, and unshift _lib-cov_, +and the other will run tests normally: + + $ expresso -I lib test/* + $ expresso -I lib --cov test/* + +Currently coverage is bound to the _lib_ directory, however in the +future `--cov` will most likely accept a path. + +## Async Exports + +Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the _exports.foo = function(){};_ syntax is supported for this: + + setTimeout(function(){ + exports['test async exports'] = function(){ + assert.ok('wahoo'); + }; + }, 100); diff --git a/bruml/lib/socket.io/support/expresso/docs/layout/foot.html b/bruml/lib/socket.io/support/expresso/docs/layout/foot.html new file mode 100644 index 0000000..44d85e9 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/docs/layout/foot.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/docs/layout/head.html b/bruml/lib/socket.io/support/expresso/docs/layout/head.html new file mode 100644 index 0000000..567f62e --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/docs/layout/head.html @@ -0,0 +1,42 @@ + + + Expresso - TDD Framework For Node + + + + + Fork me on GitHub + +
+

Expresso

diff --git a/bruml/lib/socket.io/support/expresso/lib/bar.js b/bruml/lib/socket.io/support/expresso/lib/bar.js new file mode 100644 index 0000000..e15aad4 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/lib/bar.js @@ -0,0 +1,4 @@ + +exports.bar = function(msg){ + return msg || 'bar'; +}; \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/lib/foo.js b/bruml/lib/socket.io/support/expresso/lib/foo.js new file mode 100644 index 0000000..15701a5 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/lib/foo.js @@ -0,0 +1,16 @@ + +exports.foo = function(msg){ + if (msg) { + return msg; + } else { + return generateFoo(); + } +}; + +function generateFoo() { + return 'foo'; +} + +function Foo(msg){ + this.msg = msg || 'foo'; +} diff --git a/bruml/lib/socket.io/support/expresso/package.json b/bruml/lib/socket.io/support/expresso/package.json new file mode 100644 index 0000000..569a54b --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/package.json @@ -0,0 +1,12 @@ +{ "name": "expresso", + "version": "0.7.2", + "description": "TDD framework, light-weight, fast, CI-friendly", + "author": "TJ Holowaychuk ", + "bin": { + "expresso": "./bin/expresso", + "node-jscoverage": "./deps/jscoverage/node-jscoverage" + }, + "scripts": { + "preinstall": "make deps/jscoverage/node-jscoverage" + } +} \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/test/assert.test.js b/bruml/lib/socket.io/support/expresso/test/assert.test.js new file mode 100644 index 0000000..f822595 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/test/assert.test.js @@ -0,0 +1,91 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert'); + +module.exports = { + 'assert.eql()': function(){ + assert.equal(assert.deepEqual, assert.eql); + }, + + 'assert.type()': function(){ + assert.type('foobar', 'string'); + assert.type(2, 'number'); + assert.throws(function(){ + assert.type([1,2,3], 'string'); + }); + }, + + 'assert.includes()': function(){ + assert.includes('some random string', 'dom'); + assert.throws(function(){ + assert.include('some random string', 'foobar'); + }); + + assert.includes(['foo', 'bar'], 'bar'); + assert.includes(['foo', 'bar'], 'foo'); + assert.includes([1,2,3], 3); + assert.includes([1,2,3], 2); + assert.includes([1,2,3], 1); + assert.throws(function(){ + assert.includes(['foo', 'bar'], 'baz'); + }); + + assert.throws(function(){ + assert.includes({ wrong: 'type' }, 'foo'); + }); + }, + + 'assert.isNull()': function(){ + assert.isNull(null); + assert.throws(function(){ + assert.isNull(undefined); + }); + assert.throws(function(){ + assert.isNull(false); + }); + }, + + 'assert.isUndefined()': function(){ + assert.isUndefined(undefined); + assert.throws(function(){ + assert.isUndefined(null); + }); + assert.throws(function(){ + assert.isUndefined(false); + }); + }, + + 'assert.isNotNull()': function(){ + assert.isNotNull(false); + assert.isNotNull(undefined); + assert.throws(function(){ + assert.isNotNull(null); + }); + }, + + 'assert.isDefined()': function(){ + assert.isDefined(false); + assert.isDefined(null); + assert.throws(function(){ + assert.isDefined(undefined); + }); + }, + + 'assert.match()': function(){ + assert.match('foobar', /foo(bar)?/); + assert.throws(function(){ + assert.match('something', /rawr/); + }); + }, + + 'assert.length()': function(){ + assert.length('test', 4); + assert.length([1,2,3,4], 4); + assert.throws(function(){ + assert.length([1,2,3], 4); + }); + } +}; \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/test/async.test.js b/bruml/lib/socket.io/support/expresso/test/async.test.js new file mode 100644 index 0000000..d1d2036 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/test/async.test.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert'); + +setTimeout(function(){ + exports['test async exports'] = function(){ + assert.ok('wahoo'); + }; +}, 100); \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/test/bar.test.js b/bruml/lib/socket.io/support/expresso/test/bar.test.js new file mode 100644 index 0000000..cfc2e11 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/test/bar.test.js @@ -0,0 +1,13 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , bar = require('bar'); + +module.exports = { + 'bar()': function(){ + assert.equal('bar', bar.bar()); + } +}; \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/test/foo.test.js b/bruml/lib/socket.io/support/expresso/test/foo.test.js new file mode 100644 index 0000000..ee5cff3 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/test/foo.test.js @@ -0,0 +1,14 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , foo = require('foo'); + +module.exports = { + 'foo()': function(){ + assert.equal('foo', foo.foo()); + assert.equal('foo', foo.foo()); + } +}; \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/test/http.test.js b/bruml/lib/socket.io/support/expresso/test/http.test.js new file mode 100644 index 0000000..1f9d249 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/test/http.test.js @@ -0,0 +1,146 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , http = require('http'); + +var server = http.createServer(function(req, res){ + if (req.method === 'GET') { + if (req.url === '/delay') { + setTimeout(function(){ + res.writeHead(200, {}); + res.end('delayed'); + }, 200); + } else { + var body = JSON.stringify({ name: 'tj' }); + res.writeHead(200, { + 'Content-Type': 'application/json; charset=utf8', + 'Content-Length': body.length + }); + res.end(body); + } + } else { + var body = ''; + req.setEncoding('utf8'); + req.on('data', function(chunk){ body += chunk }); + req.on('end', function(){ + res.writeHead(200, {}); + res.end(req.url + ' ' + body); + }); + } +}); + +var delayedServer = http.createServer(function(req, res){ + res.writeHead(200); + res.end('it worked'); +}); + +var oldListen = delayedServer.listen; +delayedServer.listen = function(){ + var args = arguments; + setTimeout(function(){ + oldListen.apply(delayedServer, args); + }, 100); +}; + +module.exports = { + 'test assert.response(req, res, fn)': function(beforeExit){ + var calls = 0; + + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8' + } + }, function(res){ + ++calls; + assert.ok(res); + }); + + beforeExit(function(){ + assert.equal(1, calls); + }) + }, + + 'test assert.response(req, fn)': function(beforeExit){ + var calls = 0; + + assert.response(server, { + url: '/foo' + }, function(res){ + ++calls; + assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback'); + }); + + beforeExit(function(){ + assert.equal(1, calls); + }); + }, + + 'test assert.response() delay': function(beforeExit){ + var calls = 0; + + assert.response(server, + { url: '/delay', timeout: 1500 }, + { body: 'delayed' }, + function(){ + ++calls; + }); + + beforeExit(function(){ + assert.equal(1, calls); + }); + }, + + 'test assert.response() regexp': function(beforeExit){ + var calls = 0; + + assert.response(server, + { url: '/foo', method: 'POST', data: 'foobar' }, + { body: /^\/foo foo(bar)?/ }, + function(){ + ++calls; + }); + + beforeExit(function(){ + assert.equal(1, calls); + }); + }, + + 'test assert.response() regexp headers': function(beforeExit){ + var calls = 0; + + assert.response(server, + { url: '/' }, + { body: '{"name":"tj"}', headers: { 'Content-Type': /^application\/json/ } }, + function(){ + ++calls; + }); + + beforeExit(function(){ + assert.equal(1, calls); + }); + }, + + // [!] if this test doesn't pass, an uncaught ECONNREFUSED will display + 'test assert.response() with deferred listen()': function(beforeExit){ + var calls = 0; + + assert.response(delayedServer, + { url: '/' }, + { body: 'it worked' }, + function(){ + ++calls; + }); + + beforeExit(function(){ + assert.equal(1, calls); + }); + } +}; diff --git a/bruml/lib/socket.io/support/expresso/test/serial/async.test.js b/bruml/lib/socket.io/support/expresso/test/serial/async.test.js new file mode 100644 index 0000000..c596d5c --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/test/serial/async.test.js @@ -0,0 +1,39 @@ + +var assert = require('assert') + , setup = 0 + , order = []; + +module.exports = { + setup: function(done){ + ++setup; + done(); + }, + + a: function(done){ + assert.equal(1, setup); + order.push('a'); + setTimeout(function(){ + done(); + }, 500); + }, + + b: function(done){ + assert.equal(2, setup); + order.push('b'); + setTimeout(function(){ + done(); + }, 200); + }, + + c: function(done){ + assert.equal(3, setup); + order.push('c'); + setTimeout(function(){ + done(); + }, 1000); + }, + + d: function(){ + assert.eql(order, ['a', 'b', 'c']); + } +}; \ No newline at end of file diff --git a/bruml/lib/socket.io/support/expresso/test/serial/http.test.js b/bruml/lib/socket.io/support/expresso/test/serial/http.test.js new file mode 100644 index 0000000..7783eb5 --- /dev/null +++ b/bruml/lib/socket.io/support/expresso/test/serial/http.test.js @@ -0,0 +1,48 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , http = require('http'); + +var server = http.createServer(function(req, res){ + if (req.method === 'GET') { + if (req.url === '/delay') { + setTimeout(function(){ + res.writeHead(200, {}); + res.end('delayed'); + }, 200); + } else { + var body = JSON.stringify({ name: 'tj' }); + res.writeHead(200, { + 'Content-Type': 'application/json; charset=utf8', + 'Content-Length': body.length + }); + res.end(body); + } + } else { + var body = ''; + req.setEncoding('utf8'); + req.addListener('data', function(chunk){ body += chunk }); + req.addListener('end', function(){ + res.writeHead(200, {}); + res.end(req.url + ' ' + body); + }); + } +}); + +module.exports = { + 'test assert.response()': function(done){ + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8' + } + }, done); + } +}; \ No newline at end of file diff --git a/bruml/lib/socket.io/support/node-websocket-client/LICENSE b/bruml/lib/socket.io/support/node-websocket-client/LICENSE new file mode 100644 index 0000000..f3c2eae --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2010, Peter Griess +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of node-websocket-client nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. diff --git a/bruml/lib/socket.io/support/node-websocket-client/Makefile b/bruml/lib/socket.io/support/node-websocket-client/Makefile new file mode 100644 index 0000000..6ec0947 --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/Makefile @@ -0,0 +1,8 @@ +# This makefile exists to help run tests. + +.PHONY: test + +test: + for f in `ls -1 test/test-*.js` ; do \ + node $$f ; \ + done diff --git a/bruml/lib/socket.io/support/node-websocket-client/README.md b/bruml/lib/socket.io/support/node-websocket-client/README.md new file mode 100644 index 0000000..8823a5c --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/README.md @@ -0,0 +1,41 @@ +A prototype [Web Socket](http://www.whatwg.org/specs/web-socket-protocol/) +client implementation for [node.js](http://nodejs.org). + +Tested with +[miksago/node-websocket-server](http://github.com/miksago/node-websocket-server) +v1.2.00. + +Requires [nodejs](http://nodejs.org) 0.1.98 or later. + +## Installation + +Install this using `npm` as follows + + npm install websocket-client + +... or just dump `lib/websocket.js` in your `$NODE_PATH`. + +## Usage + + var sys = require('sys'); + var WebSocket = require('websocket').WebSocket; + + var ws = new WebSocket('ws://localhost:8000/biff', 'borf'); + ws.addListener('data', function(buf) { + sys.debug('Got data: ' + sys.inspect(buf)); + }); + ws.onmessage = function(m) { + sys.debug('Got message: ' + m); + } + +## API + +This supports the `send()` and `onmessage()` APIs. The `WebSocket` object will +also emit `data` events that are node `Buffer` objects, in case you want to +work with something lower-level than strings. + +## Transports + +Multiple transports are supported, indicated by the scheme provided to the +`WebSocket` constructor. `ws://` is a standard TCP-based Web Socket; +`ws+unix://` allows connection to a UNIX socket at the given path. diff --git a/bruml/lib/socket.io/support/node-websocket-client/examples/client-unix.js b/bruml/lib/socket.io/support/node-websocket-client/examples/client-unix.js new file mode 100644 index 0000000..3bb23ba --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/examples/client-unix.js @@ -0,0 +1,12 @@ +var sys = require('sys'); +var WebSocket = require('../lib/websocket').WebSocket; + +var ws = new WebSocket('ws+unix://' + process.argv[2], 'boffo'); + +ws.addListener('message', function(d) { + sys.debug('Received message: ' + d.toString('utf8')); +}); + +ws.addListener('open', function() { + ws.send('This is a message', 1); +}); diff --git a/bruml/lib/socket.io/support/node-websocket-client/examples/client.js b/bruml/lib/socket.io/support/node-websocket-client/examples/client.js new file mode 100644 index 0000000..259bf6e --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/examples/client.js @@ -0,0 +1,10 @@ +var sys = require('sys'); +var WebSocket = require('../lib/websocket').WebSocket; + +var ws = new WebSocket('ws://localhost:8000/biff', 'borf'); +ws.addListener('data', function(buf) { + sys.debug('Got data: ' + sys.inspect(buf)); +}); +ws.onmessage = function(m) { + sys.debug('Got message: ' + m); +} diff --git a/bruml/lib/socket.io/support/node-websocket-client/examples/server-unix.js b/bruml/lib/socket.io/support/node-websocket-client/examples/server-unix.js new file mode 100644 index 0000000..912be0e --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/examples/server-unix.js @@ -0,0 +1,13 @@ +var sys = require('sys'); +var ws = require('websocket-server/ws'); + +var srv = ws.createServer({ debug : true}); +srv.addListener('connection', function(s) { + sys.debug('Got a connection!'); + + s._req.socket.addListener('fd', function(fd) { + sys.debug('Got an fd: ' + fd); + }); +}); + +srv.listen(process.argv[2]); diff --git a/bruml/lib/socket.io/support/node-websocket-client/lib/websocket.js b/bruml/lib/socket.io/support/node-websocket-client/lib/websocket.js new file mode 100644 index 0000000..06b2135 --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/lib/websocket.js @@ -0,0 +1,562 @@ +var assert = require('assert'); +var buffer = require('buffer'); +var crypto = require('crypto'); +var events = require('events'); +var http = require('http'); +var net = require('net'); +var urllib = require('url'); +var sys = require('sys'); + +var FRAME_NO = 0; +var FRAME_LO = 1; +var FRAME_HI = 2; + +// Values for readyState as per the W3C spec +var CONNECTING = 0; +var OPEN = 1; +var CLOSING = 2; +var CLOSED = 3; + +var debugLevel = parseInt(process.env.NODE_DEBUG, 16); +var debug = (debugLevel & 0x4) ? + function() { sys.error.apply(this, arguments); } : + function() { }; + +// Generate a Sec-WebSocket-* value +var createSecretKey = function() { + // How many spaces will we be inserting? + var numSpaces = 1 + Math.floor(Math.random() * 12); + assert.ok(1 <= numSpaces && numSpaces <= 12); + + // What is the numerical value of our key? + var keyVal = (Math.floor( + Math.random() * (4294967295 / numSpaces) + ) * numSpaces); + + // Our string starts with a string representation of our key + var s = keyVal.toString(); + + // Insert 'numChars' worth of noise in the character ranges + // [0x21, 0x2f] (14 characters) and [0x3a, 0x7e] (68 characters) + var numChars = 1 + Math.floor(Math.random() * 12); + assert.ok(1 <= numChars && numChars <= 12); + + for (var i = 0; i < numChars; i++) { + var pos = Math.floor(Math.random() * s.length + 1); + + var c = Math.floor(Math.random() * (14 + 68)); + c = (c <= 14) ? + String.fromCharCode(c + 0x21) : + String.fromCharCode((c - 14) + 0x3a); + + s = s.substring(0, pos) + c + s.substring(pos, s.length); + } + + // We shoudln't have any spaces in our value until we insert them + assert.equal(s.indexOf(' '), -1); + + // Insert 'numSpaces' worth of spaces + for (var i = 0; i < numSpaces; i++) { + var pos = Math.floor(Math.random() * (s.length - 1)) + 1; + s = s.substring(0, pos) + ' ' + s.substring(pos, s.length); + } + + assert.notEqual(s.charAt(0), ' '); + assert.notEqual(s.charAt(s.length), ' '); + + return s; +}; + +// Generate a challenge sequence +var createChallenge = function() { + var c = ''; + for (var i = 0; i < 8; i++) { + c += String.fromCharCode(Math.floor(Math.random() * 255)); + } + + return c; +}; + +// Get the value of a secret key string +// +// This strips non-digit values and divides the result by the number of +// spaces found. +var secretKeyValue = function(sk) { + var ns = 0; + var v = 0; + + for (var i = 0; i < sk.length; i++) { + var cc = sk.charCodeAt(i); + + if (cc == 0x20) { + ns++; + } else if (0x30 <= cc && cc <= 0x39) { + v = v * 10 + cc - 0x30; + } + } + + return Math.floor(v / ns); +} + +// Get the to-be-hashed value of a secret key string +// +// This takes the result of secretKeyValue() and encodes it in a big-endian +// byte string +var secretKeyHashValue = function(sk) { + var skv = secretKeyValue(sk); + + var hv = ''; + hv += String.fromCharCode((skv >> 24) & 0xff); + hv += String.fromCharCode((skv >> 16) & 0xff); + hv += String.fromCharCode((skv >> 8) & 0xff); + hv += String.fromCharCode((skv >> 0) & 0xff); + + return hv; +}; + +// Compute the secret key signature based on two secret key strings and some +// handshaking data. +var computeSecretKeySignature = function(s1, s2, hs) { + assert.equal(hs.length, 8); + + var hash = crypto.createHash('md5'); + + hash.update(secretKeyHashValue(s1)); + hash.update(secretKeyHashValue(s2)); + hash.update(hs); + + return hash.digest('binary'); +}; + +// Return a hex representation of the given binary string; used for debugging +var str2hex = function(str) { + var hexChars = [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' + ]; + + var out = ''; + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + out += hexChars[(c & 0xf0) >>> 4]; + out += hexChars[c & 0x0f]; + out += ' '; + } + + return out.trim(); +}; + +// Get the scheme for a URL, undefined if none is found +var getUrlScheme = function(url) { + var i = url.indexOf(':'); + if (i == -1) { + return undefined; + } + + return url.substring(0, i); +}; + +// Set a constant on the given object +var setConstant = function(obj, name, value) { + Object.defineProperty(obj, name, { + get : function() { + return value; + } + }); +}; + +// WebSocket object +// +// This is intended to conform (mostly) to http://dev.w3.org/html5/websockets/ +// +// N.B. Arguments are parsed in the anonymous function at the bottom of the +// constructor. +var WebSocket = function(url, proto, opts) { + events.EventEmitter.call(this); + + // Retain a reference to our object + var self = this; + + // State of the connection + var readyState = CONNECTING; + + // Our underlying net.Stream instance + var stream = undefined; + + opts = opts || { + origin : 'http://www.example.com' + }; + + // Frame parsing functions + // + // These read data from the given buffer starting at the given offset look + // for the end of the current frame. If found, the current frame is emitted + // and the function returns. Only a single frame is processed at a time. + // + // The number of bytes of completed frames read is returned, which the + // caller is to use to advance along its buffer. If 0 is returned, no + // completed frame bytes were found, and the caller should probably enqueue + // the buffer as a continuation of the current message. If a complete frame + // is read, the function is responsible fro resting 'frameType'. + + // Framing data + var frameType = FRAME_NO; + var bufs = []; + var bufsBytes = 0; + + // Frame-parsing functions + var frameFuncs = [ + // FRAME_NO + function(buf, off) { + if (buf[off] & 0x80) { + throw new Error('High-byte frames not yet supported'); + } + + frameType = FRAME_LO; + return 1; + }, + + // FRAME_LO + function(buf, off) { + assert.ok(bufs.length > 0 || bufsBytes == 0); + + debug('frame_lo(' + sys.inspect(buf) + ', ' + off + ')'); + + // Find the first instance of 0xff, our terminating byte + for (var i = off; i < buf.length && buf[i] != 0xff; i++) + ; + + // We didn't find a terminating byte + if (i >= buf.length) { + return 0; + } + + // We found a terminating byte; collect all bytes into a single buffer + // and emit it + var mb = null; + if (bufs.length == 0) { + mb = buf.slice(off, i); + } else { + mb = new buffer.Buffer(bufsBytes + i); + + var mbOff = 0; + bufs.forEach(function(b) { + b.copy(mb, mbOff, 0, b.length); + mbOff += b.length; + }); + + assert.equal(mbOff, bufsBytes); + + // Don't call Buffer.copy() if we're coping 0 bytes. Rather + // than being a no-op, this will trigger a range violation on + // the destination. + if (i > 0) { + buf.copy(mb, mbOff, off, i); + } + + // We consumed all of the buffers that we'd been saving; clear + // things out + bufs = []; + bufsBytes = 0; + } + + process.nextTick(function() { + var b = mb; + return function() { + var m = b.toString('utf8'); + + self.emit('data', b); + self.emit('message', m); // wss compat + + if (self.onmessage) { + self.onmessage({data: m}); + } + }; + }()); + + frameType = FRAME_NO; + return i - off + 1; + }, + + // FRAME_HI + function(buf, off) { + debug('High-byte framing not yet supported'); + + frameType = FRAME_NO; + return buf.length - off; + } + ]; + + // Handle data coming from our socket + var dataListener = function(buf) { + if (buf.length <= 0) { + return; + } + + debug('dataListener(' + sys.inspect(buf) + ')'); + + var off = 0; + var consumed = 0; + + do { + if (frameType < 0 || frameFuncs.length <= frameType) { + throw new Error('Unexpected frame type: ' + frameType); + } + + consumed = frameFuncs[frameType](buf, off); + off += consumed; + } while (consumed > 0 && off < buf.length); + + if (consumed == 0) { + bufs.push(buf.slice(off, buf.length)); + bufsBytes += buf.length - off; + } + }; + + // Handle incoming file descriptors + var fdListener = function(fd) { + self.emit('fd', fd); + }; + + // Handle errors from any source (HTTP client, stream, etc) + var errorListener = function(e) { + process.nextTick(function() { + self.emit('wserror', e); + + if (self.onerror) { + self.onerror(e); + } + }); + }; + + // External API + self.close = function() { + var f = function() { + readyState = CLOSED; + + if (stream) { + stream.end(); + stream.destroy(); + stream = undefined; + } + + process.nextTick(function() { + self.emit('close'); + + if (self.onclose) { + self.onclose(); + } + }); + }; + + switch (readyState) { + case CLOSED: + case CLOSING: + break; + + case CONNECTING: + f(); + break; + + default: + readyState = CLOSING; + + // XXX: Run f() on the next tick so that we conform a little + // closer to the spirit of the API in that the caller + // never sees us transition directly to CLOSED. Instead, we + // just seem to have an infinitely fast closing handshake. + if (stream.write('', 'binary')) { + process.nextTick(f); + } else { + stream.addListener('drain', f); + } + } + }; + + self.send = function(str, fd) { + if (readyState != OPEN) { + throw new Error('Cannot write to non-open WebSocket client'); + } + + stream.write('\x00', 'binary'); + stream.write(str, 'utf8', fd); + stream.write('\xff', 'binary'); + }; + + // wss compat + self.write = self.send; + + setConstant(self, 'url', url); + + Object.defineProperty(self, 'readyState', { + get : function() { + return readyState; + } + }); + + // Connect and perform handshaking with the server + (function() { + // Parse constructor arguments + if (!url) { + throw new Error('Url and must be specified.'); + } + + // Secrets used for handshaking + var key1 = createSecretKey(); + var key2 = createSecretKey(); + var challenge = createChallenge(); + + debug( + 'key1=\'' + str2hex(key1) + '\'; ' + + 'key2=\'' + str2hex(key2) + '\'; ' + + 'challenge=\'' + str2hex(challenge) + '\'' + ); + + var httpHeaders = { + 'Connection' : 'Upgrade', + 'Upgrade' : 'WebSocket', + 'Sec-WebSocket-Key1' : key1, + 'Sec-WebSocket-Key2' : key2 + }; + if (opts.origin) { + httpHeaders['Origin'] = opts.origin; + } + + var httpPath = '/'; + + if (proto) { + httpHeaders['Sec-WebSocket-Protocol'] = proto; + } + + // Create the HTTP client that we'll use for handshaking. We'll cannabalize + // its socket via the 'upgrade' event and leave it to rot. + // + // XXX: The ws+unix:// scheme makes use of the implementation detail + // that http.Client passes its constructor arguments through, + // un-inspected to net.Stream.connect(). The latter accepts a + // string as its first argument to connect to a UNIX socket. + var httpClient = undefined; + switch (getUrlScheme(url)) { + case 'ws': + var u = urllib.parse(url); + httpClient = http.createClient(u.port || 80, u.hostname); + httpPath = (u.pathname || '/') + (u.search || ''); + httpHeaders.Host = u.hostname; + break; + + case 'ws+unix': + var sockPath = url.substring('ws+unix://'.length, url.length); + httpClient = http.createClient(sockPath); + httpHeaders.Host = 'localhost'; + break; + + default: + throw new Error('Invalid URL scheme \'' + urlScheme + '\' specified.'); + } + + httpClient.addListener('upgrade', (function() { + var data = undefined; + + return function(req, s, head) { + stream = s; + + stream.addListener('data', function(d) { + if (!data) { + data = d; + } else { + var data2 = new buffer.Buffer(data.length + d.length); + + if (data.length) { + data.copy(data2, 0, 0, data.length); + } + if (data2.length) { + d.copy(data2, data.length, 0, d.length); + } + + data = data2; + } + + if (data.length >= 16) { + var expected = computeSecretKeySignature(key1, key2, challenge); + var actual = data.slice(0, 16).toString('binary'); + + // Handshaking fails; we're donezo + if (actual != expected) { + debug( + 'expected=\'' + str2hex(expected) + '\'; ' + + 'actual=\'' + str2hex(actual) + '\'' + ); + + process.nextTick(function() { + // XXX: Emit 'wserror' here, as 'error' is a reserved word in the + // EventEmitter world, and gets thrown. + self.emit( + 'wserror', + new Error('Invalid handshake from server:' + + 'expected \'' + str2hex(expected) + '\', ' + + 'actual \'' + str2hex(actual) + '\'' + ) + ); + + if (self.onerror) { + self.onerror(); + } + + self.close(); + }); + } + + // Un-register our data handler and add the one to be used + // for the normal, non-handshaking case. If we have extra + // data left over, manually fire off the handler on + // whatever remains. + // + // XXX: This is lame. We should only remove the listeners + // that we added. + httpClient.removeAllListeners('upgrade'); + stream.removeAllListeners('data'); + stream.addListener('data', dataListener); + + // Fire the 'open' event + process.nextTick(function() { + self.emit('open'); + + if (self.onopen) { + self.onopen(); + } + }); + + readyState = OPEN; + + if (data.length > 16) { + stream.emit('data', data.slice(16, data.length)); + } + } + }); + stream.addListener('fd', fdListener); + stream.addListener('error', errorListener); + + stream.emit('data', head); + }; + })()); + httpClient.addListener('error', function(e) { + httpClient.end(); + errorListener(e); + }); + + var httpReq = httpClient.request(httpPath, httpHeaders); + + httpReq.write(challenge, 'binary'); + httpReq.end(); + })(); +}; +sys.inherits(WebSocket, events.EventEmitter); +exports.WebSocket = WebSocket; + +// Add some constants to the WebSocket object +setConstant(WebSocket.prototype, 'CONNECTING', CONNECTING); +setConstant(WebSocket.prototype, 'OPEN', OPEN); +setConstant(WebSocket.prototype, 'CLOSING', CLOSING); +setConstant(WebSocket.prototype, 'CLOSED', CLOSED); + +// vim:ts=4 sw=4 et diff --git a/bruml/lib/socket.io/support/node-websocket-client/package.json b/bruml/lib/socket.io/support/node-websocket-client/package.json new file mode 100644 index 0000000..22df936 --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/package.json @@ -0,0 +1,22 @@ +{ + "name" : "websocket-client", + "version" : "0.9.5", + "description" : "An HTML5 Web Sockets client", + "author" : "Peter Griess ", + "engines" : { + "node" : ">=0.1.98" + }, + "repositories" : [ + { + "type" : "git", + "url" : "http://github.com/pgriess/node-websocket-client.git" + } + ], + "licenses" : [ + { + "type" : "BSD", + "url" : "http://github.com/pgriess/node-websocket-client/blob/master/LICENSE" + } + ], + "main" : "./lib/websocket" +} diff --git a/bruml/lib/socket.io/support/node-websocket-client/test/test-basic.js b/bruml/lib/socket.io/support/node-websocket-client/test/test-basic.js new file mode 100644 index 0000000..a420276 --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/test/test-basic.js @@ -0,0 +1,63 @@ +// Verify that we can connect to a WebSocket server, exchange messages, and +// shut down cleanly. + +var assert = require('assert'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws').Server; + +var PORT = 1024 + Math.floor(Math.random() * 4096); +var C_MSG = 'Client test: ' + (Math.random() * 100); +var S_MSG = 'Server test: ' + (Math.random() * 100); + +var serverGotConnection = false; +var clientGotOpen = false; +var clientGotData = false; +var clientGotMessage = false; +var serverGotMessage = false; +var serverGotClose = false; + +var wss = new WebSocketServer(); +wss.listen(PORT, 'localhost'); +wss.addListener('connection', function(c) { + serverGotConnection = true; + + c.write(S_MSG); + + c.addListener('message', function(m) { + assert.equal(m, C_MSG); + serverGotMessage = true; + }); + + c.addListener('close', function() { + serverGotClose = true; + wss.close(); + }); +}); + +var ws = new WebSocket('ws://localhost:' + PORT + '/', 'biff'); +ws.addListener('open', function() { + clientGotOpen = true; +}); +ws.addListener('data', function(buf) { + assert.equal(typeof buf, 'object'); + assert.equal(buf.toString('utf8'), S_MSG); + + clientGotData = true; + + ws.send(C_MSG); + ws.close(); +}); +ws.onmessage = function(m) { + assert.equal(m, S_MSG); + assert.equal(typeof m, 'string'); + clientGotMessage = true; +}; + +process.addListener('exit', function() { + assert.ok(serverGotConnection); + assert.ok(clientGotOpen); + assert.ok(clientGotData); + assert.ok(clientGotMessage); + assert.ok(serverGotMessage); + assert.ok(serverGotClose); +}); diff --git a/bruml/lib/socket.io/support/node-websocket-client/test/test-readonly-attrs.js b/bruml/lib/socket.io/support/node-websocket-client/test/test-readonly-attrs.js new file mode 100644 index 0000000..56162d5 --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/test/test-readonly-attrs.js @@ -0,0 +1,44 @@ +// Verify that some attributes of a WebSocket object are read-only. + +var assert = require('assert'); +var sys = require('sys'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws').Server; + +var PORT = 1024 + Math.floor(Math.random() * 4096); + +var wss = new WebSocketServer(); +wss.listen(PORT, 'localhost'); +wss.addListener('connection', function(c) { + wss.close(); +}); +var ws = new WebSocket('ws://localhost:' + PORT + '/', 'biff'); +ws.addListener('open', function() { + assert.equal(ws.CONNECTING, 0); + try { + ws.CONNECTING = 13; + assert.equal( + ws.CONNECTING, 0, + 'Should not have been able to set read-only CONNECTING attribute' + ); + } catch (e) { + assert.equal(e.type, 'no_setter_in_callback'); + } + + assert.equal(ws.OPEN, 1); + assert.equal(ws.CLOSING, 2); + assert.equal(ws.CLOSED, 3); + + assert.equal(ws.url, 'ws://localhost:' + PORT + '/'); + try { + ws.url = 'foobar'; + assert.equal( + ws.url, 'ws://localhost:' + PORT + '/', + 'Should not have been able to set read-only url attribute' + ); + } catch (e) { + assert.equal(e.type, 'no_setter_in_callback'); + } + + ws.close(); +}); diff --git a/bruml/lib/socket.io/support/node-websocket-client/test/test-ready-state.js b/bruml/lib/socket.io/support/node-websocket-client/test/test-ready-state.js new file mode 100644 index 0000000..3675bfb --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/test/test-ready-state.js @@ -0,0 +1,23 @@ +// Verify that readyState transitions are implemented correctly + +var assert = require('assert'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws').Server; + +var PORT = 1024 + Math.floor(Math.random() * 4096); + +var wss = new WebSocketServer(); +wss.listen(PORT, 'localhost'); + +var ws = new WebSocket('ws://localhost:' + PORT); +assert.equal(ws.readyState, ws.CONNECTING); +ws.onopen = function() { + assert.equal(ws.readyState, ws.OPEN); + + ws.close(); + assert.ok(ws.readyState == ws.CLOSING); +}; +ws.onclose = function() { + assert.equal(ws.readyState, ws.CLOSED); + wss.close(); +}; diff --git a/bruml/lib/socket.io/support/node-websocket-client/test/test-unix-send-fd.js b/bruml/lib/socket.io/support/node-websocket-client/test/test-unix-send-fd.js new file mode 100644 index 0000000..767b02b --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/test/test-unix-send-fd.js @@ -0,0 +1,63 @@ +// Verify that both sides of the WS connection can both send and receive file +// descriptors. + +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); +var sys = require('sys'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws').Server; + +var PATH = path.join(__dirname, 'sock.' + process.pid); +var C_MSG = 'Client test: ' + (Math.random() * 100); +var S_MSG = 'Server test: ' + (Math.random() * 100); + +var clientReceivedData = false; +var clientReceivedFD = false; +var serverReceivedData = false; +var serverReceivedFD = false; + +var wss = new WebSocketServer(); +wss.addListener('listening', function() { + var ws = new WebSocket('ws+unix://' + PATH); + ws.addListener('data', function(d) { + assert.equal(d.toString('utf8'), S_MSG); + + clientReceivedData = true; + + ws.send(C_MSG, 1); + ws.close(); + }); + ws.addListener('fd', function(fd) { + assert.ok(fd >= 0); + + clientReceivedFD = true; + }); +}); +wss.addListener('connection', function(c) { + c.write(S_MSG, 0); + c._req.socket.addListener('fd', function(fd) { + assert.ok(fd >= 0); + + serverReceivedFD = true; + }); + c.addListener('message', function(d) { + assert.equal(d, C_MSG); + + serverReceivedData = true; + + wss.close(); + }); +}); +wss.listen(PATH); + +process.addListener('exit', function() { + assert.ok(clientReceivedFD); + assert.ok(clientReceivedData); + assert.ok(serverReceivedFD); + assert.ok(serverReceivedData); + + try { + fs.unlinkSync(PATH); + } catch (e) { } +}); diff --git a/bruml/lib/socket.io/support/node-websocket-client/test/test-unix-sockets.js b/bruml/lib/socket.io/support/node-websocket-client/test/test-unix-sockets.js new file mode 100644 index 0000000..16e6274 --- /dev/null +++ b/bruml/lib/socket.io/support/node-websocket-client/test/test-unix-sockets.js @@ -0,0 +1,46 @@ +// Verify that we can connect to a server over UNIX domain sockets. + +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); +var sys = require('sys'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws').Server; + +var PATH = path.join(__dirname, 'sock.' + process.pid); +var S_MSG = 'Server test: ' + (Math.random() * 100); + +var serverGotConnection = false; +var clientGotOpen = false; +var clientGotData = false; + +var wss = new WebSocketServer(); +wss.addListener('listening', function() { + var ws = new WebSocket('ws+unix://' + PATH); + ws.addListener('open', function() { + clientGotOpen = true; + + ws.close(); + }); + ws.addListener('data', function(d) { + assert.equal(d.toString('utf8'), S_MSG); + clientGotData = true; + }); +}); +wss.addListener('connection', function(c) { + serverGotConnection = true; + + c.write(S_MSG); + wss.close(); +}); +wss.listen(PATH); + +process.addListener('exit', function() { + assert.ok(serverGotConnection); + assert.ok(clientGotOpen); + assert.ok(clientGotData); + + try { + fs.unlinkSync(PATH); + } catch(e) { } +}); diff --git a/bruml/lib/socket.io/support/socket.io-client/Makefile b/bruml/lib/socket.io/support/socket.io-client/Makefile new file mode 100644 index 0000000..3676e44 --- /dev/null +++ b/bruml/lib/socket.io/support/socket.io-client/Makefile @@ -0,0 +1,2 @@ +build: + ./bin/build \ No newline at end of file diff --git a/bruml/lib/socket.io/support/socket.io-client/README.md b/bruml/lib/socket.io/support/socket.io-client/README.md new file mode 100644 index 0000000..f052a46 --- /dev/null +++ b/bruml/lib/socket.io/support/socket.io-client/README.md @@ -0,0 +1,208 @@ +socket.io +========= + +#### Sockets for the rest of us + +The `socket.io` client is basically a simple HTTP Socket interface implementation. It allows you to establish a realtime connection with a server (see `socket.io` server [here](http://github.com/LearnBoost/Socket.IO-node)), hiding the complexity of the different transports (WebSocket, Flash, forever iframe, XHR long polling, XHR multipart encoded, etc), while retaining a WebSocket-like API: + + socket = new io.Socket('localhost'); + socket.connect(); + socket.on('connect', function(){ + // connected + }); + socket.on('message', function(data){ + // data here + }); + socket.send('some data'); + +### Features + +- Supports + - WebSocket + - Adobe Flash Socket + - ActiveX HTMLFile (IE) + - XHR with multipart encoding + - XHR with long-polling + - JSONP polling (for cross-domain) + +- Tested on + - Safari 4 + - Google Chrome 5 + - Internet Explorer 6 + - Internet Explorer 7 + - Internet Explorer 8 + - iPhone Safari + - iPad Safari + - Firefox 3 + - Firefox 4 (Minefield) + - Opera 10.61 + +- ActionScript Socket is known not to work behind proxies, as it doesn't have access to the user agent proxy settings to implement the CONNECT HTTP method. If it fails, `socket.io` will try something else. + +- On a successful connection, it remembers the transport for next time (stores it in a cookie). + +- Small. Closure Compiled with all deps: 5.82kb (gzipped). + +- Easy to use! See [socket.io-node](http://github.com/LearnBoost/Socket.IO-node) for the server to connect to. + +### How to use + + socket = new io.Socket('localhost'); + socket.connect(); + socket.send('some data'); + socket.on('message', function(data){ + alert('got some data' + data); + }); + +For an example, check out the chat [source](https://github.com/LearnBoost/Socket.IO-node/blob/master/test/chat.html). + +### Notes + +If you are serving you .swf from a other domain than socket.io.js you will need to change the WEB_SOCKET_SWF_LOCATION to the insecure version. + + + +The insecure version can be found [here](http://github.com/gimite/web-socket-js/blob/master/WebSocketMainInsecure.zip). + +IMPORTANT! When checking out the git repo, make sure to include the submodules. One way to do it is: + + git clone [repo] --recursive + +Another, once cloned + + git submodule update --init --recursive + +### Documentation + +#### io.Socket + + new io.Socket(host, [options]); + +Options: + +- *port* + + Current port or 80 + + The port `socket.io` server is attached to (defaults to the document.location port) + +- *resource* + + socket.io + + The resource is what allows the `socket.io` server to identify incoming connections by `socket.io` clients. In other words, any HTTP server can implement socket.io and still serve other normal, non-realtime HTTP requests. + +- *transports* + + ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling'] + + A list of the transports to attempt to utilize (in order of preference) + +- *transportOptions* + + { + someTransport: { + someOption: true + }, + ... + } + + An object containing (optional) options to pass to each transport. + +Properties: + +- *options* + + The passed in options combined with the defaults + +- *connected* + + Whether the socket is connected or not. + +- *connecting* + + Whether the socket is connecting or not. + +- *transport* + + The transport instance. + +Methods: + +- *connect* + + Establishes a connection + +- *send(message)* + + A string of data to send. + +- *disconnect* + + Closes the connection + +- *on(event, λ)* + + Adds a listener for the event *event* + +- *removeEvent(event, λ)* + + Removes the listener λ for the event *event* + +Events: + +- *connect* + + Fired when the connection is established and the handshake successful + +- *connecting(transport_type)* + + Fired when a connection is attempted, passing the transport name + +- *connect_failed* + + Fired when the connection timeout occurs after the last connection attempt. + This only fires if the `connectTimeout` option is set. + If the `tryTransportsOnConnectTimeout` option is set, this only fires once all + possible transports have been tried. + +- *message(message)* + + Fired when a message arrives from the server + +- *close* + + Fired when the connection is closed. Be careful with using this event, as some transports will fire it even under temporary, expected disconnections (such as XHR-Polling). + +- *disconnect* + + Fired when the connection is considered disconnected. + +### Credits + +Guillermo Rauch <guillermo@learnboost.com> + +### License + +(The MIT License) + +Copyright (c) 2010 LearnBoost <dev@learnboost.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bruml/lib/socket.io/support/socket.io-client/lib/io.js b/bruml/lib/socket.io/support/socket.io-client/lib/io.js new file mode 100644 index 0000000..e68446a --- /dev/null +++ b/bruml/lib/socket.io/support/socket.io-client/lib/io.js @@ -0,0 +1,25 @@ +/** + * Socket.IO client + * + * @author Guillermo Rauch + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost + */ + +this.io = { + version: '0.6.2', + + setPath: function(path){ + if (window.console && console.error) console.error('io.setPath will be removed. Please set the variable WEB_SOCKET_SWF_LOCATION pointing to WebSocketMain.swf'); + this.path = /\/$/.test(path) ? path : path + '/'; + WEB_SOCKET_SWF_LOCATION = path + 'lib/vendor/web-socket-js/WebSocketMain.swf'; + } +}; + +if ('jQuery' in this) jQuery.io = this.io; + +if (typeof window != 'undefined'){ + // WEB_SOCKET_SWF_LOCATION = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//cdn.socket.io/' + this.io.version + '/WebSocketMain.swf'; + if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') + WEB_SOCKET_SWF_LOCATION = '/socket.io/lib/vendor/web-socket-js/WebSocketMain.swf'; +} diff --git a/bruml/lib/socket.io/support/socket.io-client/lib/socket.js b/bruml/lib/socket.io/support/socket.io-client/lib/socket.js new file mode 100644 index 0000000..04cb393 --- /dev/null +++ b/bruml/lib/socket.io/support/socket.io-client/lib/socket.js @@ -0,0 +1,163 @@ +/** + * Socket.IO client + * + * @author Guillermo Rauch + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost + */ + +(function(){ + + var Socket = io.Socket = function(host, options){ + this.host = host || document.domain; + this.options = { + secure: false, + document: document, + port: document.location.port || 80, + resource: 'socket.io', + transports: ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling'], + transportOptions: { + 'xhr-polling': { + timeout: 25000 // based on polling duration default + }, + 'jsonp-polling': { + timeout: 25000 + } + }, + connectTimeout: 5000, + tryTransportsOnConnectTimeout: true, + rememberTransport: true + }; + io.util.merge(this.options, options); + this.connected = false; + this.connecting = false; + this._events = {}; + this.transport = this.getTransport(); + if (!this.transport && 'console' in window) console.error('No transport available'); + }; + + Socket.prototype.getTransport = function(override){ + var transports = override || this.options.transports, match; + if (this.options.rememberTransport && !override){ + match = this.options.document.cookie.match('(?:^|;)\\s*socketio=([^;]*)'); + if (match){ + this._rememberedTransport = true; + transports = [decodeURIComponent(match[1])]; + } + } + for (var i = 0, transport; transport = transports[i]; i++){ + if (io.Transport[transport] + && io.Transport[transport].check() + && (!this._isXDomain() || io.Transport[transport].xdomainCheck())){ + return new io.Transport[transport](this, this.options.transportOptions[transport] || {}); + } + } + return null; + }; + + Socket.prototype.connect = function(){ + if (this.transport && !this.connected){ + if (this.connecting) this.disconnect(); + this.connecting = true; + this.emit('connecting', [this.transport.type]); + this.transport.connect(); + if (this.options.connectTimeout){ + var self = this; + this.connectTimeoutTimer = setTimeout(function(){ + if (!self.connected){ + self.disconnect(); + if (self.options.tryTransportsOnConnectTimeout && !self._rememberedTransport){ + if(!self._remainingTransports) self._remainingTransports = self.options.transports.slice(0); + var transports = self._remainingTransports; + while(transports.length > 0 && transports.splice(0,1)[0] != self.transport.type){} + if(transports.length){ + self.transport = self.getTransport(transports); + self.connect(); + } + } + if(!self._remainingTransports || self._remainingTransports.length == 0) self.emit('connect_failed'); + } + if(self._remainingTransports && self._remainingTransports.length == 0) delete self._remainingTransports; + }, this.options.connectTimeout); + } + } + return this; + }; + + Socket.prototype.send = function(data){ + if (!this.transport || !this.transport.connected) return this._queue(data); + this.transport.send(data); + return this; + }; + + Socket.prototype.disconnect = function(){ + if (this.connectTimeoutTimer) clearTimeout(this.connectTimeoutTimer); + this.transport.disconnect(); + return this; + }; + + Socket.prototype.on = function(name, fn){ + if (!(name in this._events)) this._events[name] = []; + this._events[name].push(fn); + return this; + }; + + Socket.prototype.emit = function(name, args){ + if (name in this._events){ + var events = this._events[name].concat(); + for (var i = 0, ii = events.length; i < ii; i++) + events[i].apply(this, args === undefined ? [] : args); + } + return this; + }; + + Socket.prototype.removeEvent = function(name, fn){ + if (name in this._events){ + for (var a = 0, l = this._events[name].length; a < l; a++) + if (this._events[name][a] == fn) this._events[name].splice(a, 1); + } + return this; + }; + + Socket.prototype._queue = function(message){ + if (!('_queueStack' in this)) this._queueStack = []; + this._queueStack.push(message); + return this; + }; + + Socket.prototype._doQueue = function(){ + if (!('_queueStack' in this) || !this._queueStack.length) return this; + this.transport.send(this._queueStack); + this._queueStack = []; + return this; + }; + + Socket.prototype._isXDomain = function(){ + return this.host !== document.domain; + }; + + Socket.prototype._onConnect = function(){ + this.connected = true; + this.connecting = false; + this._doQueue(); + if (this.options.rememberTransport) this.options.document.cookie = 'socketio=' + encodeURIComponent(this.transport.type); + this.emit('connect'); + }; + + Socket.prototype._onMessage = function(data){ + this.emit('message', [data]); + }; + + Socket.prototype._onDisconnect = function(){ + var wasConnected = this.connected; + this.connected = false; + this.connecting = false; + this._queueStack = []; + if (wasConnected) this.emit('disconnect'); + }; + + Socket.prototype.fire = Socket.prototype.emit; + + Socket.prototype.addListener = Socket.prototype.addEvent = Socket.prototype.addEventListener = Socket.prototype.on; + +})(); diff --git a/bruml/lib/socket.io/support/socket.io-client/lib/transport.js b/bruml/lib/socket.io/support/socket.io-client/lib/transport.js new file mode 100644 index 0000000..8a13c8e --- /dev/null +++ b/bruml/lib/socket.io/support/socket.io-client/lib/transport.js @@ -0,0 +1,141 @@ +/** + * Socket.IO client + * + * @author Guillermo Rauch + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost + */ + +// abstract + +(function(){ + + var frame = '~m~', + + stringify = function(message){ + if (Object.prototype.toString.call(message) == '[object Object]'){ + if (!('JSON' in window)){ + if ('console' in window && console.error) console.error('Trying to encode as JSON, but JSON.stringify is missing.'); + return '{ "$error": "Invalid message" }'; + } + return '~j~' + JSON.stringify(message); + } else { + return String(message); + } + }; + + Transport = io.Transport = function(base, options){ + this.base = base; + this.options = { + timeout: 15000 // based on heartbeat interval default + }; + io.util.merge(this.options, options); + }; + + Transport.prototype.send = function(){ + throw new Error('Missing send() implementation'); + }; + + Transport.prototype.connect = function(){ + throw new Error('Missing connect() implementation'); + }; + + Transport.prototype.disconnect = function(){ + throw new Error('Missing disconnect() implementation'); + }; + + Transport.prototype._encode = function(messages){ + var ret = '', message, + messages = io.util.isArray(messages) ? messages : [messages]; + for (var i = 0, l = messages.length; i < l; i++){ + message = messages[i] === null || messages[i] === undefined ? '' : stringify(messages[i]); + ret += frame + message.length + frame + message; + } + return ret; + }; + + Transport.prototype._decode = function(data){ + var messages = [], number, n; + do { + if (data.substr(0, 3) !== frame) return messages; + data = data.substr(3); + number = '', n = ''; + for (var i = 0, l = data.length; i < l; i++){ + n = Number(data.substr(i, 1)); + if (data.substr(i, 1) == n){ + number += n; + } else { + data = data.substr(number.length + frame.length); + number = Number(number); + break; + } + } + messages.push(data.substr(0, number)); // here + data = data.substr(number); + } while(data !== ''); + return messages; + }; + + Transport.prototype._onData = function(data){ + this._setTimeout(); + var msgs = this._decode(data); + if (msgs && msgs.length){ + for (var i = 0, l = msgs.length; i < l; i++){ + this._onMessage(msgs[i]); + } + } + }; + + Transport.prototype._setTimeout = function(){ + var self = this; + if (this._timeout) clearTimeout(this._timeout); + this._timeout = setTimeout(function(){ + self._onTimeout(); + }, this.options.timeout); + }; + + Transport.prototype._onTimeout = function(){ + this._onDisconnect(); + }; + + Transport.prototype._onMessage = function(message){ + if (!this.sessionid){ + this.sessionid = message; + this._onConnect(); + } else if (message.substr(0, 3) == '~h~'){ + this._onHeartbeat(message.substr(3)); + } else if (message.substr(0, 3) == '~j~'){ + this.base._onMessage(JSON.parse(message.substr(3))); + } else { + this.base._onMessage(message); + } + }, + + Transport.prototype._onHeartbeat = function(heartbeat){ + this.send('~h~' + heartbeat); // echo + }; + + Transport.prototype._onConnect = function(){ + this.connected = true; + this.connecting = false; + this.base._onConnect(); + this._setTimeout(); + }; + + Transport.prototype._onDisconnect = function(){ + this.connecting = false; + this.connected = false; + this.sessionid = null; + this.base._onDisconnect(); + }; + + Transport.prototype._prepareUrl = function(){ + return (this.base.options.secure ? 'https' : 'http') + + '://' + this.base.host + + ':' + this.base.options.port + + '/' + this.base.options.resource + + '/' + this.type + + (this.sessionid ? ('/' + this.sessionid) : '/'); + }; + +})(); \ No newline at end of file diff --git a/bruml/lib/socket.io/support/socket.io-client/lib/transports/flashsocket.js b/bruml/lib/socket.io/support/socket.io-client/lib/transports/flashsocket.js new file mode 100644 index 0000000..fc72e2f --- /dev/null +++ b/bruml/lib/socket.io/support/socket.io-client/lib/transports/flashsocket.js @@ -0,0 +1,53 @@ +/** + * Socket.IO client + * + * @author Guillermo Rauch + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost + */ + +(function(){ + + var Flashsocket = io.Transport.flashsocket = function(){ + io.Transport.websocket.apply(this, arguments); + }; + + io.util.inherit(Flashsocket, io.Transport.websocket); + + Flashsocket.prototype.type = 'flashsocket'; + + Flashsocket.prototype.connect = function(){ + var self = this, args = arguments; + WebSocket.__addTask(function(){ + io.Transport.websocket.prototype.connect.apply(self, args); + }); + return this; + }; + + Flashsocket.prototype.send = function(){ + var self = this, args = arguments; + WebSocket.__addTask(function(){ + io.Transport.websocket.prototype.send.apply(self, args); + }); + return this; + }; + + Flashsocket.check = function(){ + if (typeof WebSocket == 'undefined' || !('__addTask' in WebSocket)) return false; + if (io.util.opera) return false; // opera is buggy with this transport + if ('navigator' in window && 'plugins' in navigator && navigator.plugins['Shockwave Flash']){ + return !!navigator.plugins['Shockwave Flash'].description; + } + if ('ActiveXObject' in window) { + try { + return !!new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); + } catch (e) {} + } + return false; + }; + + Flashsocket.xdomainCheck = function(){ + return true; + }; + +})(); \ No newline at end of file diff --git a/bruml/lib/socket.io/support/socket.io-client/lib/transports/htmlfile.js b/bruml/lib/socket.io/support/socket.io-client/lib/transports/htmlfile.js new file mode 100644 index 0000000..4e63786 --- /dev/null +++ b/bruml/lib/socket.io/support/socket.io-client/lib/transports/htmlfile.js @@ -0,0 +1,73 @@ +/** + * Socket.IO client + * + * @author Guillermo Rauch + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost + */ + +(function(){ + + var HTMLFile = io.Transport.htmlfile = function(){ + io.Transport.XHR.apply(this, arguments); + }; + + io.util.inherit(HTMLFile, io.Transport.XHR); + + HTMLFile.prototype.type = 'htmlfile'; + + HTMLFile.prototype._get = function(){ + var self = this; + this._open(); + window.attachEvent('onunload', function(){ self._destroy(); }); + }; + + HTMLFile.prototype._open = function(){ + this._doc = new ActiveXObject('htmlfile'); + this._doc.open(); + this._doc.write(''); + this._doc.parentWindow.s = this; + this._doc.close(); + + var _iframeC = this._doc.createElement('div'); + this._doc.body.appendChild(_iframeC); + this._iframe = this._doc.createElement('iframe'); + _iframeC.appendChild(this._iframe); + this._iframe.src = this._prepareUrl() + '/' + (+ new Date); + }; + + HTMLFile.prototype._ = function(data, doc){ + this._onData(data); + var script = doc.getElementsByTagName('script')[0]; + script.parentNode.removeChild(script); + }; + + HTMLFile.prototype._destroy = function(){ + if (this._iframe){ + this._iframe.src = 'about:blank'; + this._doc = null; + CollectGarbage(); + } + }; + + HTMLFile.prototype.disconnect = function(){ + this._destroy(); + return io.Transport.XHR.prototype.disconnect.call(this); + }; + + HTMLFile.check = function(){ + if ('ActiveXObject' in window){ + try { + var a = new ActiveXObject('htmlfile'); + return a && io.Transport.XHR.check(); + } catch(e){} + } + return false; + }; + + HTMLFile.xdomainCheck = function(){ + // we can probably do handling for sub-domains, we should test that it's cross domain but a subdomain here + return false; + }; + +})(); \ No newline at end of file diff --git a/bruml/lib/socket.io/support/socket.io-client/lib/transports/jsonp-polling.js b/bruml/lib/socket.io/support/socket.io-client/lib/transports/jsonp-polling.js new file mode 100644 index 0000000..33b78ac --- /dev/null +++ b/bruml/lib/socket.io/support/socket.io-client/lib/transports/jsonp-polling.js @@ -0,0 +1,116 @@ +/** + * Socket.IO client + * + * @author Guillermo Rauch + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost + */ + +io.JSONP = []; + +JSONPPolling = io.Transport['jsonp-polling'] = function(){ + io.Transport.XHR.apply(this, arguments); + this._insertAt = document.getElementsByTagName('script')[0]; + this._index = io.JSONP.length; + io.JSONP.push(this); +}; + +io.util.inherit(JSONPPolling, io.Transport['xhr-polling']); + +JSONPPolling.prototype.type = 'jsonp-polling'; + +JSONPPolling.prototype._send = function(data){ + var self = this; + if (!('_form' in this)){ + var form = document.createElement('FORM'), + area = document.createElement('TEXTAREA'), + id = this._iframeId = 'socket_io_iframe_' + this._index, + iframe; + + form.style.position = 'absolute'; + form.style.top = '-1000px'; + form.style.left = '-1000px'; + form.target = id; + form.method = 'POST'; + form.action = this._prepareUrl() + '/' + (+new Date) + '/' + this._index; + area.name = 'data'; + form.appendChild(area); + this._insertAt.parentNode.insertBefore(form, this._insertAt); + document.body.appendChild(form); + + this._form = form; + this._area = area; + } + + function complete(){ + initIframe(); + self._posting = false; + self._checkSend(); + }; + + function initIframe(){ + if (self._iframe){ + self._form.removeChild(self._iframe); + } + + try { + // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) + iframe = document.createElement('') + + compile_source() + + + + + + + + diff --git a/node_modules/jade/support/coffee-script/documentation/js/aliases.js b/node_modules/jade/support/coffee-script/documentation/js/aliases.js new file mode 100644 index 0000000..a3675d6 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/aliases.js @@ -0,0 +1,17 @@ +var volume, winner; +if (ignition === true) { + launch(); +} +if (band !== SpinalTap) { + volume = 10; +} +if (answer !== false) { + letTheWildRumpusBegin(); +} +if (car.speed < limit) { + accelerate(); +} +if ((47 === pick || 92 === pick || 13 === pick)) { + winner = true; +} +print(inspect("My name is " + this.name)); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/array_comprehensions.js b/node_modules/jade/support/coffee-script/documentation/js/array_comprehensions.js new file mode 100644 index 0000000..2260db7 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/array_comprehensions.js @@ -0,0 +1,20 @@ +var _i, _len, _len2, _ref, _result, food, lunch, pos, roid, roid2; +lunch = (function() { + _result = []; _ref = ['toast', 'cheese', 'wine']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + food = _ref[_i]; + _result.push(eat(food)); + } + return _result; +})(); +for (pos = 0, _len = asteroids.length; pos < _len; pos++) { + roid = asteroids[pos]; + for (_i = 0, _len2 = asteroids.length; _i < _len2; _i++) { + roid2 = asteroids[_i]; + if (roid !== roid2) { + if (roid.overlaps(roid2)) { + roid.explode(); + } + } + } +} \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/block_comment.js b/node_modules/jade/support/coffee-script/documentation/js/block_comment.js new file mode 100644 index 0000000..ae602e6 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/block_comment.js @@ -0,0 +1,4 @@ +/* +CoffeeScript Compiler v0.9.4 +Released under the MIT License +*/ \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/cake_tasks.js b/node_modules/jade/support/coffee-script/documentation/js/cake_tasks.js new file mode 100644 index 0000000..b1c0914 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/cake_tasks.js @@ -0,0 +1,10 @@ +var fs; +fs = require('fs'); +option('-o', '--output [DIR]', 'directory for compiled code'); +task('build:parser', 'rebuild the Jison parser', function(options) { + var code, dir; + require('jison'); + code = require('./lib/grammar').parser.generate(); + dir = options.output || 'lib'; + return fs.writeFile("" + dir + "/parser.js", code); +}); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/classes.js b/node_modules/jade/support/coffee-script/documentation/js/classes.js new file mode 100644 index 0000000..279885f --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/classes.js @@ -0,0 +1,42 @@ +var Animal, Horse, Snake, sam, tom; +var __extends = function(child, parent) { + var ctor = function() {}; + ctor.prototype = parent.prototype; + child.prototype = new ctor(); + child.prototype.constructor = child; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; +}; +Animal = (function() { + return function Animal(_arg) { + this.name = _arg; + return this; + }; +})(); +Animal.prototype.move = function(meters) { + return alert(this.name + " moved " + meters + "m."); +}; +Snake = (function() { + return function Snake() { + return Animal.apply(this, arguments); + }; +})(); +__extends(Snake, Animal); +Snake.prototype.move = function() { + alert("Slithering..."); + return Snake.__super__.move.call(this, 5); +}; +Horse = (function() { + return function Horse() { + return Animal.apply(this, arguments); + }; +})(); +__extends(Horse, Animal); +Horse.prototype.move = function() { + alert("Galloping..."); + return Horse.__super__.move.call(this, 45); +}; +sam = new Snake("Sammy the Python"); +tom = new Horse("Tommy the Palomino"); +sam.move(); +tom.move(); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/comparisons.js b/node_modules/jade/support/coffee-script/documentation/js/comparisons.js new file mode 100644 index 0000000..e1ce0cc --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/comparisons.js @@ -0,0 +1,3 @@ +var cholesterol, healthy; +cholesterol = 127; +healthy = (200 > cholesterol) && (cholesterol > 60); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/conditionals.js b/node_modules/jade/support/coffee-script/documentation/js/conditionals.js new file mode 100644 index 0000000..bee05fb --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/conditionals.js @@ -0,0 +1,12 @@ +var date, mood, options; +if (singing) { + mood = greatlyImproved; +} +if (happy && knowsIt) { + clapsHands(); + chaChaCha(); +} else { + showIt(); +} +date = friday ? sue : jill; +options || (options = defaults); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/embedded.js b/node_modules/jade/support/coffee-script/documentation/js/embedded.js new file mode 100644 index 0000000..3db2b0f --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/embedded.js @@ -0,0 +1,4 @@ +var hi; +hi = function() { + return [document.title, "Hello JavaScript"].join(": "); +}; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/existence.js b/node_modules/jade/support/coffee-script/documentation/js/existence.js new file mode 100644 index 0000000..6fc021b --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/existence.js @@ -0,0 +1,5 @@ +var solipsism, speed; +if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) { + solipsism = true; +} +(typeof speed !== "undefined" && speed !== null) ? speed : (speed = 140); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/expressions.js b/node_modules/jade/support/coffee-script/documentation/js/expressions.js new file mode 100644 index 0000000..6ea42bc --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/expressions.js @@ -0,0 +1,5 @@ +var eldest, grade; +grade = function(student) { + return student.excellentWork ? "A+" : (student.okayStuff ? (student.triedHard ? "B" : "B-") : "C"); +}; +eldest = 24 > 21 ? "Liz" : "Ike"; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/expressions_assignment.js b/node_modules/jade/support/coffee-script/documentation/js/expressions_assignment.js new file mode 100644 index 0000000..e75323d --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/expressions_assignment.js @@ -0,0 +1,2 @@ +var one, six, three, two; +six = (one = 1) + (two = 2) + (three = 3); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/expressions_comprehension.js b/node_modules/jade/support/coffee-script/documentation/js/expressions_comprehension.js new file mode 100644 index 0000000..771e67f --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/expressions_comprehension.js @@ -0,0 +1,10 @@ +var _result, globals, name; +var __hasProp = Object.prototype.hasOwnProperty; +globals = (function() { + _result = []; + for (name in window) { + if (!__hasProp.call(window, name)) continue; + _result.push(name); + } + return _result; +})().slice(0, 10); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/expressions_try.js b/node_modules/jade/support/coffee-script/documentation/js/expressions_try.js new file mode 100644 index 0000000..19a9506 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/expressions_try.js @@ -0,0 +1,7 @@ +alert((function() { + try { + return nonexistent / undefined; + } catch (error) { + return "And the error is ... " + error; + } +})()); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/fat_arrow.js b/node_modules/jade/support/coffee-script/documentation/js/fat_arrow.js new file mode 100644 index 0000000..9f8f50d --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/fat_arrow.js @@ -0,0 +1,11 @@ +var Account; +var __bind = function(func, context) { + return function() { return func.apply(context, arguments); }; +}; +Account = function(customer, cart) { + this.customer = customer; + this.cart = cart; + return $('.shopping_cart').bind('click', __bind(function(event) { + return this.customer.purchase(this.cart); + }, this)); +}; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/functions.js b/node_modules/jade/support/coffee-script/documentation/js/functions.js new file mode 100644 index 0000000..ec38bc7 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/functions.js @@ -0,0 +1,7 @@ +var cube, square; +square = function(x) { + return x * x; +}; +cube = function(x) { + return square(x) * x; +}; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/heredocs.js b/node_modules/jade/support/coffee-script/documentation/js/heredocs.js new file mode 100644 index 0000000..0cbcb2a --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/heredocs.js @@ -0,0 +1,2 @@ +var html; +html = '\n cup of coffeescript\n'; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/interpolation.js b/node_modules/jade/support/coffee-script/documentation/js/interpolation.js new file mode 100644 index 0000000..6b4e124 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/interpolation.js @@ -0,0 +1,3 @@ +var author, quote; +author = "Wittgenstein"; +quote = ("A picture is a fact. -- " + author); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/interpolation_expression.js b/node_modules/jade/support/coffee-script/documentation/js/interpolation_expression.js new file mode 100644 index 0000000..166e08d --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/interpolation_expression.js @@ -0,0 +1,4 @@ +var dates, sentence, sep; +sentence = ("" + (22 / 7) + " is a decent approximation of π"); +sep = "[.\\/\\- ]"; +dates = /\d+#{sep}\d+#{sep}\d+/g; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/multiple_return_values.js b/node_modules/jade/support/coffee-script/documentation/js/multiple_return_values.js new file mode 100644 index 0000000..e4bf1e6 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/multiple_return_values.js @@ -0,0 +1,5 @@ +var _ref, city, forecast, temp, weatherReport; +weatherReport = function(location) { + return [location, 72, "Mostly Sunny"]; +}; +_ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2]; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/object_comprehensions.js b/node_modules/jade/support/coffee-script/documentation/js/object_comprehensions.js new file mode 100644 index 0000000..8d719ed --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/object_comprehensions.js @@ -0,0 +1,16 @@ +var _result, age, ages, child, yearsOld; +var __hasProp = Object.prototype.hasOwnProperty; +yearsOld = { + max: 10, + ida: 9, + tim: 11 +}; +ages = (function() { + _result = []; + for (child in yearsOld) { + if (!__hasProp.call(yearsOld, child)) continue; + age = yearsOld[child]; + _result.push(child + " is " + age); + } + return _result; +})(); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/object_extraction.js b/node_modules/jade/support/coffee-script/documentation/js/object_extraction.js new file mode 100644 index 0000000..90eff3d --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/object_extraction.js @@ -0,0 +1,10 @@ +var _ref, _ref2, city, futurists, name, street; +futurists = { + sculptor: "Umberto Boccioni", + painter: "Vladimir Burliuk", + poet: { + name: "F.T. Marinetti", + address: ["Via Roma 42R", "Bellagio, Italy 22021"] + } +}; +_ref = futurists.poet, name = _ref.name, _ref2 = _ref.address, street = _ref2[0], city = _ref2[1]; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/objects_and_arrays.js b/node_modules/jade/support/coffee-script/documentation/js/objects_and_arrays.js new file mode 100644 index 0000000..57b544d --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/objects_and_arrays.js @@ -0,0 +1,17 @@ +var kids, matrix, singers, song; +song = ["do", "re", "mi", "fa", "so"]; +singers = { + Jagger: "Rock", + Elvis: "Roll" +}; +matrix = [1, 0, 1, 0, 0, 1, 1, 1, 0]; +kids = { + brother: { + name: "Max", + age: 11 + }, + sister: { + name: "Ida", + age: 9 + } +}; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/objects_reserved.js b/node_modules/jade/support/coffee-script/documentation/js/objects_reserved.js new file mode 100644 index 0000000..db54cf6 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/objects_reserved.js @@ -0,0 +1,3 @@ +$('.account').css({ + "class": 'active' +}); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/overview.js b/node_modules/jade/support/coffee-script/documentation/js/overview.js new file mode 100644 index 0000000..5bdbffa --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/overview.js @@ -0,0 +1,34 @@ +var _i, _len, _result, cubes, list, math, num, number, opposite, race, square; +var __slice = Array.prototype.slice; +number = 42; +opposite = true; +if (opposite) { + number = -42; +} +square = function(x) { + return x * x; +}; +list = [1, 2, 3, 4, 5]; +math = { + root: Math.sqrt, + square: square, + cube: function(x) { + return x * square(x); + } +}; +race = function(winner) { + var runners; + runners = __slice.call(arguments, 1); + return print(winner, runners); +}; +if (typeof elvis !== "undefined" && elvis !== null) { + alert("I knew it!"); +} +cubes = (function() { + _result = []; + for (_i = 0, _len = list.length; _i < _len; _i++) { + num = list[_i]; + _result.push(math.cube(num)); + } + return _result; +})(); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/parallel_assignment.js b/node_modules/jade/support/coffee-script/documentation/js/parallel_assignment.js new file mode 100644 index 0000000..a24e7f6 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/parallel_assignment.js @@ -0,0 +1,4 @@ +var _ref, theBait, theSwitch; +theBait = 1000; +theSwitch = 0; +_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1]; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/patterns_and_splats.js b/node_modules/jade/support/coffee-script/documentation/js/patterns_and_splats.js new file mode 100644 index 0000000..46b2260 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/patterns_and_splats.js @@ -0,0 +1,4 @@ +var _ref, close, contents, open, tag; +var __slice = Array.prototype.slice; +tag = ""; +_ref = tag.split(""), open = _ref[0], contents = __slice.call(_ref, 1, _ref.length - 1), close = _ref[_ref.length - 1]; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/prototypes.js b/node_modules/jade/support/coffee-script/documentation/js/prototypes.js new file mode 100644 index 0000000..418bc10 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/prototypes.js @@ -0,0 +1,3 @@ +String.prototype.dasherize = function() { + return this.replace(/_/g, "-"); +}; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/range_comprehensions.js b/node_modules/jade/support/coffee-script/documentation/js/range_comprehensions.js new file mode 100644 index 0000000..220d689 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/range_comprehensions.js @@ -0,0 +1,19 @@ +var _result, countdown, deliverEggs, num; +countdown = (function() { + _result = []; + for (num = 10; num >= 1; num--) { + _result.push(num); + } + return _result; +})(); +deliverEggs = function() { + var _ref, _result2, dozen, i; + _result2 = []; _ref = eggs.length; + for (i = 0; (0 <= _ref ? i < _ref : i > _ref); i += 12) { + _result2.push((function() { + dozen = eggs.slice(i, i + 12); + return deliver(new eggCarton(dozen)); + })()); + } + return _result2; +}; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/scope.js b/node_modules/jade/support/coffee-script/documentation/js/scope.js new file mode 100644 index 0000000..478badf --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/scope.js @@ -0,0 +1,8 @@ +var changeNumbers, inner, outer; +outer = 1; +changeNumbers = function() { + var inner; + inner = -1; + return (outer = 10); +}; +inner = changeNumbers(); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/slices.js b/node_modules/jade/support/coffee-script/documentation/js/slices.js new file mode 100644 index 0000000..064c502 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/slices.js @@ -0,0 +1,4 @@ +var copy, numbers, threeToSix; +numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; +threeToSix = numbers.slice(3, 6 + 1); +copy = numbers.slice(0, numbers.length); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/soaks.js b/node_modules/jade/support/coffee-script/documentation/js/soaks.js new file mode 100644 index 0000000..5cf887e --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/soaks.js @@ -0,0 +1,2 @@ +var _ref, _ref2; +(((_ref = lottery.drawWinner()) != null) ? (((_ref2 = _ref.address) != null) ? _ref2.zipcode : undefined) : undefined); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/splats.js b/node_modules/jade/support/coffee-script/documentation/js/splats.js new file mode 100644 index 0000000..3f16b83 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/splats.js @@ -0,0 +1,15 @@ +var awardMedals, contenders, gold, rest, silver; +var __slice = Array.prototype.slice; +gold = (silver = (rest = "unknown")); +awardMedals = function(first, second) { + var others; + others = __slice.call(arguments, 2); + gold = first; + silver = second; + return (rest = others); +}; +contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"]; +awardMedals.apply(awardMedals, contenders); +alert("Gold: " + gold); +alert("Silver: " + silver); +alert("The Field: " + rest); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/splices.js b/node_modules/jade/support/coffee-script/documentation/js/splices.js new file mode 100644 index 0000000..944f1e3 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/splices.js @@ -0,0 +1,3 @@ +var _ref, numbers; +numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; +([].splice.apply(numbers, [3, 6 - 3 + 1].concat(_ref = [-3, -4, -5, -6])), _ref); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/strings.js b/node_modules/jade/support/coffee-script/documentation/js/strings.js new file mode 100644 index 0000000..cfdf5d5 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/strings.js @@ -0,0 +1,2 @@ +var mobyDick; +mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world..."; \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/switch.js b/node_modules/jade/support/coffee-script/documentation/js/switch.js new file mode 100644 index 0000000..2449cb9 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/switch.js @@ -0,0 +1,23 @@ +switch (day) { + case "Mon": + go(work); + break; + case "Tue": + go(relax); + break; + case "Thu": + go(iceFishing); + break; + case "Fri": + case "Sat": + if (day === bingoDay) { + go(bingo); + go(dancing); + } + break; + case "Sun": + go(church); + break; + default: + go(work); +} \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/try.js b/node_modules/jade/support/coffee-script/documentation/js/try.js new file mode 100644 index 0000000..97b089f --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/try.js @@ -0,0 +1,8 @@ +try { + allHellBreaksLoose(); + catsAndDogsLivingTogether(); +} catch (error) { + print(error); +} finally { + cleanUp(); +} \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/documentation/js/while.js b/node_modules/jade/support/coffee-script/documentation/js/while.js new file mode 100644 index 0000000..910b839 --- /dev/null +++ b/node_modules/jade/support/coffee-script/documentation/js/while.js @@ -0,0 +1,17 @@ +var _result, lyrics, num; +if (this.studyingEconomics) { + while (supply > demand) { + buy(); + } + while (!(supply > demand)) { + sell(); + } +} +num = 6; +lyrics = (function() { + _result = []; + while (num -= 1) { + _result.push(num + " little monkeys, jumping on the bed. One fell out and bumped his head."); + } + return _result; +})(); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/examples/beautiful_code/binary_search.coffee b/node_modules/jade/support/coffee-script/examples/beautiful_code/binary_search.coffee new file mode 100644 index 0000000..6ad42c8 --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/beautiful_code/binary_search.coffee @@ -0,0 +1,16 @@ +# Beautiful Code, Chapter 6. +# The implementation of binary search that is tested. + +# Return the index of an element in a sorted list. (or -1, if not present) +index = (list, target) -> + [low, high] = [0, list.length] + while low < high + mid = (low + high) >> 1 + val = list[mid] + return mid if val is target + if val < target then low = mid + 1 else high = mid + return -1 + +puts 2 is index [10, 20, 30, 40, 50], 30 +puts 4 is index [-97, 35, 67, 88, 1200], 1200 +puts 0 is index [0, 45, 70], 0 \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/examples/beautiful_code/quicksort_runtime.coffee b/node_modules/jade/support/coffee-script/examples/beautiful_code/quicksort_runtime.coffee new file mode 100644 index 0000000..27794f4 --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/beautiful_code/quicksort_runtime.coffee @@ -0,0 +1,13 @@ +# Beautiful Code, Chapter 3. +# Produces the expected runtime of Quicksort, for every integer from 1 to N. + +runtime = (N) -> + [sum, t] = [0, 0] + for n in [1..N] + sum += 2 * t + t = n - 1 + sum / n + t + +puts runtime(3) is 2.6666666666666665 +puts runtime(5) is 7.4 +puts runtime(8) is 16.92142857142857 diff --git a/node_modules/jade/support/coffee-script/examples/beautiful_code/regular_expression_matcher.coffee b/node_modules/jade/support/coffee-script/examples/beautiful_code/regular_expression_matcher.coffee new file mode 100644 index 0000000..99ed0a1 --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/beautiful_code/regular_expression_matcher.coffee @@ -0,0 +1,34 @@ +# Beautiful Code, Chapter 1. +# Implements a regular expression matcher that supports character matches, +# '.', '^', '$', and '*'. + +# Search for the regexp anywhere in the text. +match = (regexp, text) -> + return match_here(regexp.slice(1), text) if regexp[0] is '^' + while text + return true if match_here(regexp, text) + text = text.slice(1) + false + +# Search for the regexp at the beginning of the text. +match_here = (regexp, text) -> + [cur, next] = [regexp[0], regexp[1]] + if regexp.length is 0 then return true + if next is '*' then return match_star(cur, regexp.slice(2), text) + if cur is '$' and not next then return text.length is 0 + if text and (cur is '.' or cur is text[0]) then return match_here(regexp.slice(1), text.slice(1)) + false + +# Search for a kleene star match at the beginning of the text. +match_star = (c, regexp, text) -> + loop + return true if match_here(regexp, text) + return false unless text and (text[0] is c or c is '.') + text = text.slice(1) + +puts match("ex", "some text") +puts match("s..t", "spit") +puts match("^..t", "buttercup") +puts match("i..$", "cherries") +puts match("o*m", "vrooooommm!") +puts match("^hel*o$", "hellllllo") \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/examples/blocks.coffee b/node_modules/jade/support/coffee-script/examples/blocks.coffee new file mode 100644 index 0000000..f9e67ff --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/blocks.coffee @@ -0,0 +1,54 @@ +# After wycats' http://yehudakatz.com/2010/02/07/the-building-blocks-of-ruby/ + +# Sinatra. +get '/hello', -> + 'Hello World' + + +# Append. +append = (location, data) -> + path = new Pathname location + throw new Error("Location does not exist") unless path.exists() + + File.open path, 'a', (file) -> + file.puts YAML.dump data + + data + + +# Rubinius' File.open implementation. +File.open = (path, mode, block) -> + io = new File path, mode + + return io unless block + + try + block io + finally + io.close() unless io.closed() + + +# Write. +write = (location, data) -> + path = new Pathname location + raise "Location does not exist" unless path.exists() + + File.open path, 'w', (file) -> + return false if Digest.MD5.hexdigest(file.read()) is data.hash() + file.puts YAML.dump data + true + + +# Rails' respond_to. +index = -> + people = Person.find 'all' + + respond_to (format) -> + format.html() + format.xml -> render xml: people.xml() + + +# Synchronization. +synchronize = (block) -> + lock() + try block() finally unlock() diff --git a/node_modules/jade/support/coffee-script/examples/code.coffee b/node_modules/jade/support/coffee-script/examples/code.coffee new file mode 100644 index 0000000..255feba --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/code.coffee @@ -0,0 +1,171 @@ +# Functions: +square = (x) -> x * x + +sum = (x, y) -> x + y + +odd = (x) -> x % 2 isnt 0 + +even = (x) -> x % 2 is 0 + +run_loop = -> + fire_events((e) -> e.stopPropagation()) + listen() + wait() + +# Objects: +dense_object_literal = {one: 1, two: 2, three: 3} + +spaced_out_multiline_object = + pi: 3.14159 + list: [1, 2, 3, 4] + regex: /match[ing](every|thing|\/)/gi + three: new Idea + + inner_obj: + freedom: -> _.freedom() + +# Arrays: +stooges = [{moe: 45}, {curly: 43}, {larry: 46}] + +exponents = [((x) -> x), ((x) -> x * x), ((x) -> x * x * x)] + +empty = [] + +multiline = [ + 'line one' + 'line two' +] + +# Conditionals and ternaries. +if submarine.shields_up + full_speed_ahead() + fire_torpedos() +else if submarine.sinking + abandon_ship() +else + run_away() + +eldest = if 25 > 21 then liz else marge + +decoration = medal_of_honor if war_hero + +go_to_sleep() unless coffee + +# Returning early: +race = -> + run() + walk() + crawl() + if tired then return sleep() + race() + +# Conditional assignment: +good or= evil +wine and= cheese + +# Nested property access and calls. +((moon.turn(360))).shapes[3].move({x: 45, y: 30}).position['top'].offset('x') + +a = b = c = 5 + +# Embedded JavaScript. +callback( + `function(e) { e.stop(); }` +) + +# Try/Catch/Finally/Throw. +try + all_hell_breaks_loose() + dogs_and_cats_living_together() + throw "up" +catch error + print(error) +finally + clean_up() + +try all_hell_breaks_loose() catch error then print(error) finally clean_up() + +# While loops, break and continue. +while demand > supply + sell() + restock() + +while supply > demand then buy() + +loop + break if broken + continue if continuing + +# Unary operators. +!!true + +# Lexical scoping. +v_1 = 5 +change_a_and_set_b = -> + v_1 = 10 + v_2 = 15 +v_2 = 20 + +# Array comprehensions. +supper = food.capitalize() for food in ['toast', 'cheese', 'wine'] + +drink bottle for bottle, i in ['soda', 'wine', 'lemonade'] when even i + +# Switch statements ("else" serves as a default). +activity = switch day + when "Tuesday" then eat_breakfast() + when "Sunday" then go_to_church() + when "Saturday" then go_to_the_park() + when "Wednesday" + if day is bingo_day + go_to_bingo() + else + eat_breakfast() + go_to_work() + eat_dinner() + else go_to_work() + +# Semicolons can optionally be used instead of newlines. +wednesday = -> eat_breakfast(); go_to_work(); eat_dinner() + +# Array slice literals. +zero_to_nine = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +three_to_six = zero_to_nine[3..6] + +# Multiline strings with inner quotes. +story = "Lorem ipsum dolor \"sit\" amet, consectetuer adipiscing elit, +sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna +aliquam erat volutpat. Ut wisi enim ad." + +# Inheritance and calling super. +class Animal + constructor: (@name) -> + + move: (meters) -> + alert this.name + " moved " + meters + "m." + +class Snake extends Animal + move: -> + alert 'Slithering...' + super 5 + +class Horse extends Animal + move: -> + alert 'Galloping...' + super 45 + +sam = new Snake "Sammy the Snake" +tom = new Horse "Tommy the Horse" + +sam.move() +tom.move() + +# Numbers. +a_googol = 1e100 +hex = 0xff0000 +negative = -1.0 +infinity = Infinity +nan = NaN + +# Deleting. +delete secret.identity \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/examples/computer_science/README b/node_modules/jade/support/coffee-script/examples/computer_science/README new file mode 100644 index 0000000..1046f9f --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/computer_science/README @@ -0,0 +1,4 @@ +Ported from Nicholas Zakas' collection of computer science fundamentals, written +in JavaScript. Originals available here: + +http://github.com/nzakas/computer-science-in-javascript diff --git a/node_modules/jade/support/coffee-script/examples/computer_science/binary_search.coffee b/node_modules/jade/support/coffee-script/examples/computer_science/binary_search.coffee new file mode 100644 index 0000000..69fc678 --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/computer_science/binary_search.coffee @@ -0,0 +1,25 @@ +# Uses a binary search algorithm to locate a value in the specified array. +binary_search = (items, value) -> + + start = 0 + stop = items.length - 1 + pivot = Math.floor (start + stop) / 2 + + while items[pivot] isnt value and start < stop + + # Adjust the search area. + stop = pivot - 1 if value < items[pivot] + start = pivot + 1 if value > items[pivot] + + # Recalculate the pivot. + pivot = Math.floor (stop + start) / 2 + + # Make sure we've found the correct value. + if items[pivot] is value then pivot else -1 + + +# Test the function. +puts 2 is binary_search [10, 20, 30, 40, 50], 30 +puts 4 is binary_search [-97, 35, 67, 88, 1200], 1200 +puts 0 is binary_search [0, 45, 70], 0 +puts(-1 is binary_search [0, 45, 70], 10) \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/examples/computer_science/bubble_sort.coffee b/node_modules/jade/support/coffee-script/examples/computer_science/bubble_sort.coffee new file mode 100644 index 0000000..4757c8e --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/computer_science/bubble_sort.coffee @@ -0,0 +1,11 @@ +# A bubble sort implementation, sorting the given array in-place. +bubble_sort = (list) -> + for i in [0...list.length] + for j in [0...list.length - i] + [list[j], list[j+1]] = [list[j+1], list[j]] if list[j] > list[j+1] + list + + +# Test the function. +puts bubble_sort([3, 2, 1]).join(' ') is '1 2 3' +puts bubble_sort([9, 2, 7, 0, 1]).join(' ') is '0 1 2 7 9' \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/examples/computer_science/linked_list.coffee b/node_modules/jade/support/coffee-script/examples/computer_science/linked_list.coffee new file mode 100644 index 0000000..95bb2ef --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/computer_science/linked_list.coffee @@ -0,0 +1,108 @@ +# "Classic" linked list implementation that doesn't keep track of its size. +class LinkedList + + constructor: -> + this._head = null # Pointer to the first item in the list. + + + # Appends some data to the end of the list. This method traverses the existing + # list and places the value at the end in a new node. + add: (data) -> + + # Create a new node object to wrap the data. + node = data: data, next: null + + current = this._head or= node + + if this._head isnt node + (current = current.next) while current.next + current.next = node + + this + + + # Retrieves the data at the given position in the list. + item: (index) -> + + # Check for out-of-bounds values. + return null if index < 0 + + current = this._head or null + i = -1 + + # Advance through the list. + (current = current.next) while current and index > (i += 1) + + # Return null if we've reached the end. + current and current.data + + + # Remove the item from the given location in the list. + remove: (index) -> + + # Check for out-of-bounds values. + return null if index < 0 + + current = this._head or null + i = -1 + + # Special case: removing the first item. + if index is 0 + this._head = current.next + else + + # Find the right location. + ([previous, current] = [current, current.next]) while index > (i += 1) + + # Skip over the item to remove. + previous.next = current.next + + # Return the value. + current and current.data + + + # Calculate the number of items in the list. + size: -> + current = this._head + count = 0 + + while current + count += 1 + current = current.next + + count + + + # Convert the list into an array. + toArray: -> + result = [] + current = this._head + + while current + result.push current.data + current = current.next + + result + + + # The string representation of the linked list. + toString: -> this.toArray().toString() + + +# Tests. +list = new LinkedList + +list.add("Hi") +puts list.size() is 1 +puts list.item(0) is "Hi" +puts list.item(1) is null + +list = new LinkedList +list.add("zero").add("one").add("two") +puts list.size() is 3 +puts list.item(2) is "two" +puts list.remove(1) is "one" +puts list.item(0) is "zero" +puts list.item(1) is "two" +puts list.size() is 2 +puts list.item(-10) is null diff --git a/node_modules/jade/support/coffee-script/examples/computer_science/luhn_algorithm.coffee b/node_modules/jade/support/coffee-script/examples/computer_science/luhn_algorithm.coffee new file mode 100644 index 0000000..db1c544 --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/computer_science/luhn_algorithm.coffee @@ -0,0 +1,36 @@ +# Use the Luhn algorithm to validate a numeric identifier, such as credit card +# numbers, national insurance numbers, etc. +# See: http://en.wikipedia.org/wiki/Luhn_algorithm + +is_valid_identifier = (identifier) -> + + sum = 0 + alt = false + + for i in [(identifier.length - 1)..0] + + # Get the next digit. + num = parseInt identifier.charAt(i), 10 + + # If it's not a valid number, abort. + return false if isNaN(num) + + # If it's an alternate number... + if alt + num *= 2 + num = (num % 10) + 1 if num > 9 + + # Flip the alternate bit. + alt = !alt + + # Add to the rest of the sum. + sum += num + + # Determine if it's valid. + sum % 10 is 0 + + +# Tests. +puts is_valid_identifier("49927398716") is true +puts is_valid_identifier("4408041234567893") is true +puts is_valid_identifier("4408041234567890") is false diff --git a/node_modules/jade/support/coffee-script/examples/computer_science/merge_sort.coffee b/node_modules/jade/support/coffee-script/examples/computer_science/merge_sort.coffee new file mode 100644 index 0000000..4fb6907 --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/computer_science/merge_sort.coffee @@ -0,0 +1,19 @@ +# Sorts an array in ascending natural order using merge sort. +merge_sort = (list) -> + + return list if list.length is 1 + + result = [] + pivot = Math.floor list.length / 2 + left = merge_sort list.slice 0, pivot + right = merge_sort list.slice pivot + + while left.length and right.length + result.push(if left[0] < right[0] then left.shift() else right.shift()) + + result.concat(left).concat(right) + + +# Test the function. +puts merge_sort([3, 2, 1]).join(' ') is '1 2 3' +puts merge_sort([9, 2, 7, 0, 1]).join(' ') is '0 1 2 7 9' \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/examples/computer_science/selection_sort.coffee b/node_modules/jade/support/coffee-script/examples/computer_science/selection_sort.coffee new file mode 100644 index 0000000..1e87d56 --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/computer_science/selection_sort.coffee @@ -0,0 +1,23 @@ +# An in-place selection sort. +selection_sort = (list) -> + len = list.length + + # For each item in the list. + for i in [0...len] + + # Set the minimum to this position. + min = i + + # Check the rest of the array to see if anything is smaller. + (min = j if list[j] < list[min]) for j in [(i+1)...len] + + # Swap if a smaller item has been found. + [list[i], list[min]] = [list[min], list[i]] if i isnt min + + # The list is now sorted. + list + + +# Test the function. +puts selection_sort([3, 2, 1]).join(' ') is '1 2 3' +puts selection_sort([9, 2, 7, 0, 1]).join(' ') is '0 1 2 7 9' \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/examples/poignant.coffee b/node_modules/jade/support/coffee-script/examples/poignant.coffee new file mode 100644 index 0000000..dc07ef8 --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/poignant.coffee @@ -0,0 +1,181 @@ +# Examples from the Poignant Guide. + +# ['toast', 'cheese', 'wine'].each { |food| print food.capitalize } + +['toast', 'wine', 'cheese'].each (food) -> print food.capitalize() + + + +# class LotteryTicket +# def picks; @picks; end +# def picks=(var); @picks = var; end +# def purchased; @purchased; end +# def purchased=(var); @purchased = var; end +# end + +LotteryTicket = + get_picks: -> @picks + set_picks: (@picks) -> + get_purchased: -> @purchase + set_purchased: (@purchased) -> + + + +# class << LotteryDraw +# def play +# result = LotteryTicket.new_random +# winners = {} +# @@tickets.each do |buyer, ticket_list| +# ticket_list.each do |ticket| +# score = ticket.score( result ) +# next if score.zero? +# winners[buyer] ||= [] +# winners[buyer] << [ ticket, score ] +# end +# end +# @@tickets.clear +# winners +# end +# end + +LotteryDraw = + play: -> + result = LotteryTicket.new_random() + winners = {} + this.tickets.each (buyer, ticket_list) -> + ticket_list.each (ticket) -> + score = ticket.score result + return if score is 0 + winners[buyer] or= [] + winners[buyer].push [ticket, score] + this.tickets = {} + winners + + + +# module WishScanner +# def scan_for_a_wish +# wish = self.read.detect do |thought| +# thought.index( 'wish: ' ) == 0 +# end +# wish.gsub( 'wish: ', '' ) +# end +# end + +WishScanner = + scan_for_a_wish: -> + wish = this.read().detect (thought) -> thought.index('wish: ') is 0 + wish.replace 'wish: ', '' + + + +# class Creature +# +# # This method applies a hit taken during a fight. +# def hit( damage ) +# p_up = rand( charisma ) +# if p_up % 9 == 7 +# @life += p_up / 4 +# puts "[#{ self.class } magick powers up #{ p_up }!]" +# end +# @life -= damage +# puts "[#{ self.class } has died.]" if @life <= 0 +# end +# +# # This method takes one turn in a fight. +# def fight( enemy, weapon ) +# if life <= 0 +# puts "[#{ self.class } is too dead to fight!]" +# return +# end +# +# # Attack the opponent +# your_hit = rand( strength + weapon ) +# puts "[You hit with #{ your_hit } points of damage!]" +# enemy.hit( your_hit ) +# +# # Retaliation +# p enemy +# if enemy.life > 0 +# enemy_hit = rand( enemy.strength + enemy.weapon ) +# puts "[Your enemy hit with #{ enemy_hit } points of damage!]" +# self.hit( enemy_hit ) +# end +# end +# +# end + +Creature = + + # This method applies a hit taken during a fight. + hit: (damage) -> + p_up = Math.rand this.charisma + if p_up % 9 is 7 + this.life += p_up / 4 + puts "[" + this.name + " magick powers up " + p_up + "!]" + this.life -= damage + if this.life <= 0 then puts "[" + this.name + " has died.]" + + # This method takes one turn in a fight. + fight: (enemy, weapon) -> + if this.life <= 0 then return puts "[" + this.name + "is too dead to fight!]" + + # Attack the opponent. + your_hit = Math.rand this.strength + weapon + puts "[You hit with " + your_hit + "points of damage!]" + enemy.hit your_hit + + # Retaliation. + puts enemy + if enemy.life > 0 + enemy_hit = Math.rand enemy.strength + enemy.weapon + puts "[Your enemy hit with " + enemy_hit + "points of damage!]" + this.hit enemy_hit + + + +# # Get evil idea and swap in code words +# print "Enter your new idea: " +# idea = gets +# code_words.each do |real, code| +# idea.gsub!( real, code ) +# end +# +# # Save the jibberish to a new file +# print "File encoded. Please enter a name for this idea: " +# idea_name = gets.strip +# File::open( "idea-" + idea_name + ".txt", "w" ) do |f| +# f << idea +# end + +# Get evil idea and swap in code words +print "Enter your new idea: " +idea = gets() +code_words.each (real, code) -> idea.replace(real, code) + +# Save the jibberish to a new file +print "File encoded. Please enter a name for this idea: " +idea_name = gets().strip() +File.open "idea-" + idea_name + '.txt', 'w', (file) -> file.write idea + + + +# def wipe_mutterings_from( sentence ) +# unless sentence.respond_to? :include? +# raise ArgumentError, +# "cannot wipe mutterings from a #{ sentence.class }" +# end +# while sentence.include? '(' +# open = sentence.index( '(' ) +# close = sentence.index( ')', open ) +# sentence[open..close] = '' if close +# end +# end + +wipe_mutterings_from = (sentence) -> + throw new Error "cannot wipe mutterings" unless sentence.indexOf + while sentence.indexOf('(') >= 0 + open = sentence.indexOf('(') - 1 + close = sentence.indexOf(')') + 1 + sentence = sentence[0..open] + sentence[close..sentence.length] + sentence diff --git a/node_modules/jade/support/coffee-script/examples/potion.coffee b/node_modules/jade/support/coffee-script/examples/potion.coffee new file mode 100644 index 0000000..66c126a --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/potion.coffee @@ -0,0 +1,206 @@ +# Examples from _why's Potion, the Readme and "Potion: A Short Pamphlet". + +# 5 times: "Odelay!" print. + +print "Odelay!" for [1..5] + + +# add = (x, y): x + y. +# add(2, 4) string print + +add = (x, y) -> x + y +print add 2, 4 + + +# loop: 'quaff' print. + +loop print 'quaff' + + +# ('cheese', 'bread', 'mayo') at (1) print + +print ['cheese', 'bread', 'mayo'][1] + + +# (language='Potion', pointless=true) at (key='language') print + +print {language: 'Potion', pointless: true}['language'] + + +# minus = (x, y): x - y. +# minus (y=10, x=6) + +minus = (x, y) -> x - y +minus 6, 10 + + +# foods = ('cheese', 'bread', 'mayo') +# foods (2) + +foods = ['cheese', 'bread', 'mayo'] +foods[2] + + +# (dog='canine', cat='feline', fox='vulpine') each (key, val): +# (key, ' is a ', val) join print. + +for key, val of {dog: 'canine', cat: 'feline', fox: 'vulpine'} + print key + ' is a ' + val + + +# Person = class: /name, /age, /sex. +# Person print = (): +# ('My name is ', /name, '.') join print. + +class Person + print: -> + print 'My name is ' + @name + '.' + + +# p = Person () +# p /name string print + +p = new Person +print p.name + + +# Policeman = Person class (rank): /rank = rank. +# Policeman print = (): +# ('My name is ', /name, ' and I'm a ', /rank, '.') join print. +# +# Policeman ('Constable') print + +class Policeman extends Person + constructor: (@rank) -> + + print: -> + print 'My name is ' + @name + " and I'm a " + @rank + '.' + +print new Policeman 'Constable' + + +# app = [window (width=200, height=400) +# [para 'Welcome.', button 'OK']] +# app first name + +app = + window: + width: 200 + height: 200 + para: 'Welcome.' + button: 'OK' + +app.window + + +# x = 1 +# y = 2 +# +# x = 1, y = 2 + +x = 1 +y = 2 + +x = 1; y = 2 + + +# table = (language='Potion' +# pointless=true) + +table = + language: 'Potion' + pointless: yes + + +# # this foul business... +# String length = (): 10. + +# this foul business... +String::length = -> 10 + + +# block = : +# 'potion' print. + +block = -> + print 'potion' + + +# if (age > 100): 'ancient'. + +if age > 100 then 'ancient' + + +# author = +# if (title == 'Jonathan Strange & Mr. Norrell'): +# 'Susanna Clarke'. +# elsif (title == 'The Star Diaries'): +# 'Stanislaw Lem'. +# elsif (title == 'The Slynx'): +# 'Tatyana Tolstaya'. +# else: +# '... probably Philip K. Dick'. + +switch author + when 'Jonathan Strange & Mr. Norrell' + 'Susanna Clarke' + when 'The Star Diaries' + 'Stanislaw Lem' + when 'The Slynx' + 'Tatyana Tolstaya' + else + '... probably Philip K. Dick' + + +# count = 8 +# while (count > 0): +# 'quaff' print +# count--. + +count = 8 +while count > 0 + print 'quaff' + count-- + + +# 1 to 5 (a): +# a string print. + +print a for a in [1..5] + + +# if (3 ?gender): +# "Huh? Numbers are sexed? That's amazing." print. + +if (3).gender? + print "Huh? Numbers are sexed? That's amazing." + + +# HomePage get = (url): +# session = url query ? at ('session'). + +HomePage::get = (url) -> + session = url.query.session if url.query? + + +# BTree = class: /left, /right. +# b = BTree () +# b /left = BTree () +# b /right = BTree () + +BTree = -> +b = new BTree +b.left = new BTree +b.right = new BTree + + +# BTree = class: /left, /right. +# b = BTree () +# +# if (b ? /left): +# 'left path found!' print. + +BTree = -> +b = new BTree + +print 'left path found!' if b.left? diff --git a/node_modules/jade/support/coffee-script/examples/underscore.coffee b/node_modules/jade/support/coffee-script/examples/underscore.coffee new file mode 100644 index 0000000..d6ef6b9 --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/underscore.coffee @@ -0,0 +1,684 @@ + + # **Underscore.coffee + # (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.** + # Underscore is freely distributable under the terms of the + # [MIT license](http://en.wikipedia.org/wiki/MIT_License). + # Portions of Underscore are inspired by or borrowed from + # [Prototype.js](http://prototypejs.org/api), Oliver Steele's + # [Functional](http://osteele.com), and John Resig's + # [Micro-Templating](http://ejohn.org). + # For all details and documentation: + # http://documentcloud.github.com/underscore/ + + + # Baseline setup + # -------------- + + # Establish the root object, `window` in the browser, or `global` on the server. + root = this + + + # Save the previous value of the `_` variable. + previousUnderscore = root._ + + + # Establish the object that gets thrown to break out of a loop iteration. + # `StopIteration` is SOP on Mozilla. + breaker = if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration + + + # Helper function to escape **RegExp** contents, because JS doesn't have one. + escapeRegExp = (string) -> string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1') + + + # Save bytes in the minified (but not gzipped) version: + ArrayProto = Array.prototype + ObjProto = Object.prototype + + + # Create quick reference variables for speed access to core prototypes. + slice = ArrayProto.slice + unshift = ArrayProto.unshift + toString = ObjProto.toString + hasOwnProperty = ObjProto.hasOwnProperty + propertyIsEnumerable = ObjProto.propertyIsEnumerable + + + # All **ECMA5** native implementations we hope to use are declared here. + nativeForEach = ArrayProto.forEach + nativeMap = ArrayProto.map + nativeReduce = ArrayProto.reduce + nativeReduceRight = ArrayProto.reduceRight + nativeFilter = ArrayProto.filter + nativeEvery = ArrayProto.every + nativeSome = ArrayProto.some + nativeIndexOf = ArrayProto.indexOf + nativeLastIndexOf = ArrayProto.lastIndexOf + nativeIsArray = Array.isArray + nativeKeys = Object.keys + + + # Create a safe reference to the Underscore object for use below. + _ = (obj) -> new wrapper(obj) + + + # Export the Underscore object for **CommonJS**. + if typeof(exports) != 'undefined' then exports._ = _ + + + # Export Underscore to global scope. + root._ = _ + + + # Current version. + _.VERSION = '1.1.0' + + + # Collection Functions + # -------------------- + + # The cornerstone, an **each** implementation. + # Handles objects implementing **forEach**, arrays, and raw objects. + _.each = (obj, iterator, context) -> + try + if nativeForEach and obj.forEach is nativeForEach + obj.forEach iterator, context + else if _.isNumber obj.length + iterator.call(context, obj[i], i, obj) for i in [0...obj.length] + else + iterator.call(context, val, key, obj) for key, val of obj + catch e + throw e if e isnt breaker + obj + + + # Return the results of applying the iterator to each element. Use JavaScript + # 1.6's version of **map**, if possible. + _.map = (obj, iterator, context) -> + return obj.map(iterator, context) if nativeMap and obj.map is nativeMap + results = [] + _.each obj, (value, index, list) -> + results.push iterator.call context, value, index, list + results + + + # **Reduce** builds up a single result from a list of values. Also known as + # **inject**, or **foldl**. Uses JavaScript 1.8's version of **reduce**, if possible. + _.reduce = (obj, iterator, memo, context) -> + if nativeReduce and obj.reduce is nativeReduce + iterator = _.bind iterator, context if context + return obj.reduce iterator, memo + _.each obj, (value, index, list) -> + memo = iterator.call context, memo, value, index, list + memo + + + # The right-associative version of **reduce**, also known as **foldr**. Uses + # JavaScript 1.8's version of **reduceRight**, if available. + _.reduceRight = (obj, iterator, memo, context) -> + if nativeReduceRight and obj.reduceRight is nativeReduceRight + iterator = _.bind iterator, context if context + return obj.reduceRight iterator, memo + reversed = _.clone(_.toArray(obj)).reverse() + _.reduce reversed, iterator, memo, context + + + # Return the first value which passes a truth test. + _.detect = (obj, iterator, context) -> + result = null + _.each obj, (value, index, list) -> + if iterator.call context, value, index, list + result = value + _.breakLoop() + result + + + # Return all the elements that pass a truth test. Use JavaScript 1.6's + # **filter**, if it exists. + _.filter = (obj, iterator, context) -> + return obj.filter iterator, context if nativeFilter and obj.filter is nativeFilter + results = [] + _.each obj, (value, index, list) -> + results.push value if iterator.call context, value, index, list + results + + + # Return all the elements for which a truth test fails. + _.reject = (obj, iterator, context) -> + results = [] + _.each obj, (value, index, list) -> + results.push value if not iterator.call context, value, index, list + results + + + # Determine whether all of the elements match a truth test. Delegate to + # JavaScript 1.6's **every**, if it is present. + _.every = (obj, iterator, context) -> + iterator ||= _.identity + return obj.every iterator, context if nativeEvery and obj.every is nativeEvery + result = true + _.each obj, (value, index, list) -> + _.breakLoop() unless (result = result and iterator.call(context, value, index, list)) + result + + + # Determine if at least one element in the object matches a truth test. Use + # JavaScript 1.6's **some**, if it exists. + _.some = (obj, iterator, context) -> + iterator ||= _.identity + return obj.some iterator, context if nativeSome and obj.some is nativeSome + result = false + _.each obj, (value, index, list) -> + _.breakLoop() if (result = iterator.call(context, value, index, list)) + result + + + # Determine if a given value is included in the array or object, + # based on `===`. + _.include = (obj, target) -> + return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf + for key, val of obj + return true if val is target + false + + + # Invoke a method with arguments on every item in a collection. + _.invoke = (obj, method) -> + args = _.rest arguments, 2 + (if method then val[method] else val).apply(val, args) for val in obj + + + # Convenience version of a common use case of **map**: fetching a property. + _.pluck = (obj, key) -> + _.map(obj, (val) -> val[key]) + + + # Return the maximum item or (item-based computation). + _.max = (obj, iterator, context) -> + return Math.max.apply(Math, obj) if not iterator and _.isArray(obj) + result = computed: -Infinity + _.each obj, (value, index, list) -> + computed = if iterator then iterator.call(context, value, index, list) else value + computed >= result.computed and (result = {value: value, computed: computed}) + result.value + + + # Return the minimum element (or element-based computation). + _.min = (obj, iterator, context) -> + return Math.min.apply(Math, obj) if not iterator and _.isArray(obj) + result = computed: Infinity + _.each obj, (value, index, list) -> + computed = if iterator then iterator.call(context, value, index, list) else value + computed < result.computed and (result = {value: value, computed: computed}) + result.value + + + # Sort the object's values by a criterion produced by an iterator. + _.sortBy = (obj, iterator, context) -> + _.pluck(((_.map obj, (value, index, list) -> + {value: value, criteria: iterator.call(context, value, index, list)} + ).sort((left, right) -> + a = left.criteria; b = right.criteria + if a < b then -1 else if a > b then 1 else 0 + )), 'value') + + + # Use a comparator function to figure out at what index an object should + # be inserted so as to maintain order. Uses binary search. + _.sortedIndex = (array, obj, iterator) -> + iterator ||= _.identity + low = 0 + high = array.length + while low < high + mid = (low + high) >> 1 + if iterator(array[mid]) < iterator(obj) then low = mid + 1 else high = mid + low + + + # Convert anything iterable into a real, live array. + _.toArray = (iterable) -> + return [] if (!iterable) + return iterable.toArray() if (iterable.toArray) + return iterable if (_.isArray(iterable)) + return slice.call(iterable) if (_.isArguments(iterable)) + _.values(iterable) + + + # Return the number of elements in an object. + _.size = (obj) -> _.toArray(obj).length + + + # Array Functions + # --------------- + + # Get the first element of an array. Passing `n` will return the first N + # values in the array. Aliased as **head**. The `guard` check allows it to work + # with **map**. + _.first = (array, n, guard) -> + if n and not guard then slice.call(array, 0, n) else array[0] + + + # Returns everything but the first entry of the array. Aliased as **tail**. + # Especially useful on the arguments object. Passing an `index` will return + # the rest of the values in the array from that index onward. The `guard` + # check allows it to work with **map**. + _.rest = (array, index, guard) -> + slice.call(array, if _.isUndefined(index) or guard then 1 else index) + + + # Get the last element of an array. + _.last = (array) -> array[array.length - 1] + + + # Trim out all falsy values from an array. + _.compact = (array) -> item for item in array when item + + + # Return a completely flattened version of an array. + _.flatten = (array) -> + _.reduce array, (memo, value) -> + return memo.concat(_.flatten(value)) if _.isArray value + memo.push value + memo + , [] + + + # Return a version of the array that does not contain the specified value(s). + _.without = (array) -> + values = _.rest arguments + val for val in _.toArray(array) when not _.include values, val + + + # Produce a duplicate-free version of the array. If the array has already + # been sorted, you have the option of using a faster algorithm. + _.uniq = (array, isSorted) -> + memo = [] + for el, i in _.toArray array + memo.push el if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el)) + memo + + + # Produce an array that contains every item shared between all the + # passed-in arrays. + _.intersect = (array) -> + rest = _.rest arguments + _.select _.uniq(array), (item) -> + _.all rest, (other) -> + _.indexOf(other, item) >= 0 + + + # Zip together multiple lists into a single array -- elements that share + # an index go together. + _.zip = -> + length = _.max _.pluck arguments, 'length' + results = new Array length + for i in [0...length] + results[i] = _.pluck arguments, String i + results + + + # If the browser doesn't supply us with **indexOf** (I'm looking at you, MSIE), + # we need this function. Return the position of the first occurence of an + # item in an array, or -1 if the item is not included in the array. + _.indexOf = (array, item) -> + return array.indexOf item if nativeIndexOf and array.indexOf is nativeIndexOf + i = 0; l = array.length + while l - i + if array[i] is item then return i else i++ + -1 + + + # Provide JavaScript 1.6's **lastIndexOf**, delegating to the native function, + # if possible. + _.lastIndexOf = (array, item) -> + return array.lastIndexOf(item) if nativeLastIndexOf and array.lastIndexOf is nativeLastIndexOf + i = array.length + while i + if array[i] is item then return i else i-- + -1 + + + # Generate an integer Array containing an arithmetic progression. A port of + # [the native Python **range** function](http://docs.python.org/library/functions.html#range). + _.range = (start, stop, step) -> + a = arguments + solo = a.length <= 1 + i = start = if solo then 0 else a[0] + stop = if solo then a[0] else a[1] + step = a[2] or 1 + len = Math.ceil((stop - start) / step) + return [] if len <= 0 + range = new Array len + idx = 0 + loop + return range if (if step > 0 then i - stop else stop - i) >= 0 + range[idx] = i + idx++ + i+= step + + + # Function Functions + # ------------------ + + # Create a function bound to a given object (assigning `this`, and arguments, + # optionally). Binding with arguments is also known as **curry**. + _.bind = (func, obj) -> + args = _.rest arguments, 2 + -> func.apply obj or root, args.concat arguments + + + # Bind all of an object's methods to that object. Useful for ensuring that + # all callbacks defined on an object belong to it. + _.bindAll = (obj) -> + funcs = if arguments.length > 1 then _.rest(arguments) else _.functions(obj) + _.each funcs, (f) -> obj[f] = _.bind obj[f], obj + obj + + + # Delays a function for the given number of milliseconds, and then calls + # it with the arguments supplied. + _.delay = (func, wait) -> + args = _.rest arguments, 2 + setTimeout((-> func.apply(func, args)), wait) + + + # Memoize an expensive function by storing its results. + _.memoize = (func, hasher) -> + memo = {} + hasher or= _.identity + -> + key = hasher.apply this, arguments + return memo[key] if key of memo + memo[key] = func.apply this, arguments + + + # Defers a function, scheduling it to run after the current call stack has + # cleared. + _.defer = (func) -> + _.delay.apply _, [func, 1].concat _.rest arguments + + + # Returns the first function passed as an argument to the second, + # allowing you to adjust arguments, run code before and after, and + # conditionally execute the original function. + _.wrap = (func, wrapper) -> + -> wrapper.apply wrapper, [func].concat arguments + + + # Returns a function that is the composition of a list of functions, each + # consuming the return value of the function that follows. + _.compose = -> + funcs = arguments + -> + args = arguments + for i in [(funcs.length - 1)..0] + args = [funcs[i].apply(this, args)] + args[0] + + + # Object Functions + # ---------------- + + # Retrieve the names of an object's properties. + _.keys = nativeKeys or (obj) -> + return _.range 0, obj.length if _.isArray(obj) + key for key, val of obj + + + # Retrieve the values of an object's properties. + _.values = (obj) -> + _.map obj, _.identity + + + # Return a sorted list of the function names available in Underscore. + _.functions = (obj) -> + _.filter(_.keys(obj), (key) -> _.isFunction(obj[key])).sort() + + + # Extend a given object with all of the properties in a source object. + _.extend = (obj) -> + for source in _.rest(arguments) + (obj[key] = val) for key, val of source + obj + + + # Create a (shallow-cloned) duplicate of an object. + _.clone = (obj) -> + return obj.slice 0 if _.isArray obj + _.extend {}, obj + + + # Invokes interceptor with the obj, and then returns obj. + # The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. + _.tap = (obj, interceptor) -> + interceptor obj + obj + + + # Perform a deep comparison to check if two objects are equal. + _.isEqual = (a, b) -> + # Check object identity. + return true if a is b + # Different types? + atype = typeof(a); btype = typeof(b) + return false if atype isnt btype + # Basic equality test (watch out for coercions). + return true if `a == b` + # One is falsy and the other truthy. + return false if (!a and b) or (a and !b) + # One of them implements an `isEqual()`? + return a.isEqual(b) if a.isEqual + # Check dates' integer values. + return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b) + # Both are NaN? + return false if _.isNaN(a) and _.isNaN(b) + # Compare regular expressions. + if _.isRegExp(a) and _.isRegExp(b) + return a.source is b.source and + a.global is b.global and + a.ignoreCase is b.ignoreCase and + a.multiline is b.multiline + # If a is not an object by this point, we can't handle it. + return false if atype isnt 'object' + # Check for different array lengths before comparing contents. + return false if a.length and (a.length isnt b.length) + # Nothing else worked, deep compare the contents. + aKeys = _.keys(a); bKeys = _.keys(b) + # Different object sizes? + return false if aKeys.length isnt bKeys.length + # Recursive comparison of contents. + (return false) for all key, val of a when !(key of b) or !_.isEqual(val, b[key]) + true + + + # Is a given array or object empty? + _.isEmpty = (obj) -> + return obj.length is 0 if _.isArray(obj) or _.isString(obj) + (return false) for key of obj when hasOwnProperty.call(obj, key) + true + + + # Is a given value a DOM element? + _.isElement = (obj) -> obj and obj.nodeType is 1 + + + # Is a given value an array? + _.isArray = nativeIsArray or (obj) -> !!(obj and obj.concat and obj.unshift and not obj.callee) + + + # Is a given variable an arguments object? + _.isArguments = (obj) -> obj and obj.callee + + + # Is the given value a function? + _.isFunction = (obj) -> !!(obj and obj.constructor and obj.call and obj.apply) + + + # Is the given value a string? + _.isString = (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr)) + + + # Is a given value a number? + _.isNumber = (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]' + + + # Is a given value a boolean? + _.isBoolean = (obj) -> obj is true or obj is false + + + # Is a given value a Date? + _.isDate = (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear) + + + # Is the given value a regular expression? + _.isRegExp = (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false)) + + + # Is the given value NaN -- this one is interesting. `NaN != NaN`, and + # `isNaN(undefined) == true`, so we make sure it's a number first. + _.isNaN = (obj) -> _.isNumber(obj) and window.isNaN(obj) + + + # Is a given value equal to null? + _.isNull = (obj) -> obj is null + + + # Is a given variable undefined? + _.isUndefined = (obj) -> typeof obj is 'undefined' + + + # Utility Functions + # ----------------- + + # Run Underscore.js in noConflict mode, returning the `_` variable to its + # previous owner. Returns a reference to the Underscore object. + _.noConflict = -> + root._ = previousUnderscore + this + + + # Keep the identity function around for default iterators. + _.identity = (value) -> value + + + # Run a function `n` times. + _.times = (n, iterator, context) -> + iterator.call(context, i) for i in [0...n] + + + # Break out of the middle of an iteration. + _.breakLoop = -> throw breaker + + + # Add your own custom functions to the Underscore object, ensuring that + # they're correctly added to the OOP wrapper as well. + _.mixin = (obj) -> + for name in _.functions(obj) + addToWrapper name, _[name] = obj[name] + + + # Generate a unique integer id (unique within the entire client session). + # Useful for temporary DOM ids. + idCounter = 0 + _.uniqueId = (prefix) -> + (prefix or '') + idCounter++ + + + # By default, Underscore uses **ERB**-style template delimiters, change the + # following template settings to use alternative delimiters. + _.templateSettings = { + start: '<%' + end: '%>' + interpolate: /<%=(.+?)%>/g + } + + + # JavaScript templating a-la **ERB**, pilfered from John Resig's + # *Secrets of the JavaScript Ninja*, page 83. + # Single-quote fix from Rick Strahl. + # With alterations for arbitrary delimiters, and to preserve whitespace. + _.template = (str, data) -> + c = _.templateSettings + endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g") + fn = new Function 'obj', + 'var p=[],print=function(){p.push.apply(p,arguments);};' + + 'with(obj||{}){p.push(\'' + + str.replace(/\r/g, '\\r') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + .replace(endMatch,"✄") + .split("'").join("\\'") + .split("✄").join("'") + .replace(c.interpolate, "',$1,'") + .split(c.start).join("');") + .split(c.end).join("p.push('") + + "');}return p.join('');" + if data then fn(data) else fn + + + # Aliases + # ------- + + _.forEach = _.each + _.foldl = _.inject = _.reduce + _.foldr = _.reduceRight + _.select = _.filter + _.all = _.every + _.any = _.some + _.contains = _.include + _.head = _.first + _.tail = _.rest + _.methods = _.functions + + + # Setup the OOP Wrapper + # --------------------- + + # If Underscore is called as a function, it returns a wrapped object that + # can be used OO-style. This wrapper holds altered versions of all the + # underscore functions. Wrapped objects may be chained. + wrapper = (obj) -> + this._wrapped = obj + this + + + # Helper function to continue chaining intermediate results. + result = (obj, chain) -> + if chain then _(obj).chain() else obj + + + # A method to easily add functions to the OOP wrapper. + addToWrapper = (name, func) -> + wrapper.prototype[name] = -> + args = _.toArray arguments + unshift.call args, this._wrapped + result func.apply(_, args), this._chain + + + # Add all of the Underscore functions to the wrapper object. + _.mixin _ + + + # Add all mutator Array functions to the wrapper. + _.each ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], (name) -> + method = Array.prototype[name] + wrapper.prototype[name] = -> + method.apply(this._wrapped, arguments) + result(this._wrapped, this._chain) + + + # Add all accessor Array functions to the wrapper. + _.each ['concat', 'join', 'slice'], (name) -> + method = Array.prototype[name] + wrapper.prototype[name] = -> + result(method.apply(this._wrapped, arguments), this._chain) + + + # Start chaining a wrapped Underscore object. + wrapper::chain = -> + this._chain = true + this + + + # Extracts the result from a wrapped and chained object. + wrapper::value = -> this._wrapped diff --git a/node_modules/jade/support/coffee-script/examples/web_server.coffee b/node_modules/jade/support/coffee-script/examples/web_server.coffee new file mode 100644 index 0000000..c2ee089 --- /dev/null +++ b/node_modules/jade/support/coffee-script/examples/web_server.coffee @@ -0,0 +1,13 @@ +# Contributed by Jason Huggins + +sys = require 'sys' +http = require 'http' + +server = http.createServer (req, res) -> + res.writeHeader 200, 'Content-Type': 'text/plain' + res.write 'Hello, World!' + res.end() + +server.listen 3000 + +sys.puts "Server running at http://localhost:3000/" diff --git a/node_modules/jade/support/coffee-script/extras/EXTRAS b/node_modules/jade/support/coffee-script/extras/EXTRAS new file mode 100644 index 0000000..79ec413 --- /dev/null +++ b/node_modules/jade/support/coffee-script/extras/EXTRAS @@ -0,0 +1,7 @@ +EXTRAS: + +"extras/coffee-script.js" is a concatenated and compressed version of the +CoffeeScript compiler. To use it in the browser, include the script after any +inline script tags of type "text/coffeescript" on the page. It will compile +and evaluate all of the scripts in order. + diff --git a/node_modules/jade/support/coffee-script/extras/coffee-script.js b/node_modules/jade/support/coffee-script/extras/coffee-script.js new file mode 100644 index 0000000..71b8181 --- /dev/null +++ b/node_modules/jade/support/coffee-script/extras/coffee-script.js @@ -0,0 +1,8 @@ +/** + * CoffeeScript Compiler v0.9.4 + * http://coffeescript.org + * + * Copyright 2010, Jeremy Ashkenas + * Released under the MIT License + */ +this.CoffeeScript=function(){function require(path){return require[path]}require["./helpers"]=new function(){var exports=this;(function(){var extend,flatten,indexOf;indexOf=(exports.indexOf=Array.indexOf||(Array.prototype.indexOf?function(array,item,from){return array.indexOf(item,from)}:function(array,item,from){var _len,index,other;for(index=0,_len=array.length;index<_len;index++){other=array[index];if(other===item&&(!from||(from<=index))){return index}}return -1}));exports.include=function(list,value){return indexOf(list,value)>=0};exports.starts=function(string,literal,start){return literal===string.substr(start,literal.length)};exports.ends=function(string,literal,back){var len;len=literal.length;return literal===string.substr(string.length-len-(back||0),len)};exports.compact=function(array){var _i,_len,_result,item;_result=[];for(_i=0,_len=array.length;_i<_len;_i++){item=array[_i];if(item){_result.push(item)}}return _result};exports.count=function(string,letter){var num,pos;num=(pos=0);while(pos=1+string.indexOf(letter,pos)){num++}return num};exports.merge=function(options,overrides){return extend(extend({},options),overrides)};extend=(exports.extend=function(object,properties){var key,val;for(key in properties){val=properties[key];object[key]=val}return object});exports.flatten=(flatten=function(array){var _i,_len,element,flattened;flattened=[];for(_i=0,_len=array.length;_i<_len;_i++){element=array[_i];if(element instanceof Array){flattened=flattened.concat(flatten(element))}else{flattened.push(element)}}return flattened});exports.del=function(obj,key){var val;val=obj[key];delete obj[key];return val};exports.last=function(array,back){return array[array.length-(back||0)-1]}}).call(this)};require["./rewriter"]=new function(){var exports=this;(function(){var BALANCED_PAIRS,EXPRESSION_CLOSE,EXPRESSION_END,EXPRESSION_START,IMPLICIT_BLOCK,IMPLICIT_CALL,IMPLICIT_END,IMPLICIT_FUNC,INVERSES,LINEBREAKS,SINGLE_CLOSERS,SINGLE_LINERS,_i,_len,_ref,include,left,rite;include=require("./helpers").include;exports.Rewriter=(function(){function Rewriter(){}return Rewriter})();exports.Rewriter.prototype.rewrite=function(_arg){this.tokens=_arg;this.adjustComments();this.removeLeadingNewlines();this.removeMidExpressionNewlines();this.closeOpenCalls();this.closeOpenIndexes();this.addImplicitIndentation();this.tagPostfixConditionals();this.addImplicitBraces();this.addImplicitParentheses();this.ensureBalance(BALANCED_PAIRS);this.rewriteClosingParens();return this.tokens};exports.Rewriter.prototype.scanTokens=function(block){var i,token,tokens;tokens=this.tokens;i=0;while(token=tokens[i]){i+=block.call(this,token,i,tokens)}return true};exports.Rewriter.prototype.detectEnd=function(i,condition,action){var levels,token,tokens;tokens=this.tokens;levels=0;while(token=tokens[i]){if(levels===0&&condition.call(this,token,i)){return action.call(this,token,i)}if(!token||levels<0){return action.call(this,token,i-1)}if(include(EXPRESSION_START,token[0])){levels+=1}else{if(include(EXPRESSION_END,token[0])){levels-=1}}i+=1}return i-1};exports.Rewriter.prototype.adjustComments=function(){return this.scanTokens(function(token,i,tokens){var _ref,after,before,post,prev;if(token[0]!=="HERECOMMENT"){return 1}before=tokens[i-2];prev=tokens[i-1];post=tokens[i+1];after=tokens[i+2];if(((after!=null)?after[0]:undefined)==="INDENT"){tokens.splice(i+2,1);if(((before!=null)?before[0]:undefined)==="OUTDENT"&&((post!=null)?post[0]:undefined)==="TERMINATOR"){tokens.splice(i-2,1)}else{tokens.splice(i,0,after)}}else{if(prev&&!((_ref=prev[0])==="TERMINATOR"||_ref==="INDENT"||_ref==="OUTDENT")){if(((post!=null)?post[0]:undefined)==="TERMINATOR"&&((after!=null)?after[0]:undefined)==="OUTDENT"){tokens.splice.apply(tokens,[i+2,0].concat(tokens.splice(i,2)));if(tokens[i+2][0]!=="TERMINATOR"){tokens.splice(i+2,0,["TERMINATOR","\n",prev[2]])}}else{tokens.splice(i,0,["TERMINATOR","\n",prev[2]])}return 2}}return 1})};exports.Rewriter.prototype.removeLeadingNewlines=function(){var _len,_ref,i,tag;for(i=0,_len=(_ref=this.tokens).length;i<_len;i++){tag=_ref[i][0];if(tag!=="TERMINATOR"){break}}return i?this.tokens.splice(0,i):undefined};exports.Rewriter.prototype.removeMidExpressionNewlines=function(){return this.scanTokens(function(token,i,tokens){if(!(token[0]==="TERMINATOR"&&include(EXPRESSION_CLOSE,this.tag(i+1)))){return 1}tokens.splice(i,1);return 0})};exports.Rewriter.prototype.closeOpenCalls=function(){var action,condition;condition=function(token,i){var _ref;return((_ref=token[0])===")"||_ref==="CALL_END")||token[0]==="OUTDENT"&&this.tag(i-1)===")"};action=function(token,i){return(this.tokens[token[0]==="OUTDENT"?i-1:i][0]="CALL_END")};return this.scanTokens(function(token,i){if(token[0]==="CALL_START"){this.detectEnd(i+1,condition,action)}return 1})};exports.Rewriter.prototype.closeOpenIndexes=function(){var action,condition;condition=function(token,i){var _ref;return((_ref=token[0])==="]"||_ref==="INDEX_END")};action=function(token,i){return(token[0]="INDEX_END")};return this.scanTokens(function(token,i){if(token[0]==="INDEX_START"){this.detectEnd(i+1,condition,action)}return 1})};exports.Rewriter.prototype.addImplicitBraces=function(){var action,condition,stack;stack=[];condition=function(token,i){var _ref,_ref2,one,tag,three,two;if(("HERECOMMENT"===this.tag(i+1)||"HERECOMMENT"===this.tag(i-1))){return false}_ref=this.tokens.slice(i+1,i+4),one=_ref[0],two=_ref[1],three=_ref[2];tag=token[0];return(tag==="TERMINATOR"||tag==="OUTDENT")&&!(((two!=null)?two[0]:undefined)===":"||((one!=null)?one[0]:undefined)==="@"&&((three!=null)?three[0]:undefined)===":")||tag===","&&!((_ref2=((one!=null)?one[0]:undefined))==="IDENTIFIER"||_ref2==="NUMBER"||_ref2==="STRING"||_ref2==="@"||_ref2==="TERMINATOR"||_ref2==="OUTDENT")};action=function(token,i){return this.tokens.splice(i,0,["}","}",token[2]])};return this.scanTokens(function(token,i,tokens){var idx,tag,tok;if(include(EXPRESSION_START,tag=token[0])){stack.push(tag==="INDENT"&&this.tag(i-1)==="{"?"{":tag);return 1}if(include(EXPRESSION_END,tag)){stack.pop();return 1}if(!(tag===":"&&stack[stack.length-1]!=="{")){return 1}stack.push("{");idx=this.tag(i-2)==="@"?i-2:i-1;if(this.tag(idx-2)==="HERECOMMENT"){idx-=2}tok=["{","{",token[2]];tok.generated=true;tokens.splice(idx,0,tok);this.detectEnd(i+2,condition,action);return 2})};exports.Rewriter.prototype.addImplicitParentheses=function(){var action,classLine;classLine=false;action=function(token,i){var idx;idx=token[0]==="OUTDENT"?i+1:i;return this.tokens.splice(idx,0,["CALL_END",")",token[2]])};return this.scanTokens(function(token,i,tokens){var callObject,next,prev,seenSingle,tag;tag=token[0];if(tag==="CLASS"){classLine=true}prev=tokens[i-1];next=tokens[i+1];callObject=!classLine&&tag==="INDENT"&&next&&next.generated&&next[0]==="{"&&prev&&include(IMPLICIT_FUNC,prev[0]);seenSingle=false;if(include(LINEBREAKS,tag)){classLine=false}if(prev&&!prev.spaced&&tag==="?"){token.call=true}if(!(callObject||((prev!=null)?prev.spaced:undefined)&&(prev.call||include(IMPLICIT_FUNC,prev[0]))&&include(IMPLICIT_CALL,tag))){return 1}tokens.splice(i,0,["CALL_START","(",token[2]]);this.detectEnd(i+(callObject?2:1),function(token,i){var post;if(!seenSingle&&token.fromThen){return true}tag=token[0];if((tag==="IF"||tag==="ELSE"||tag==="UNLESS"||tag==="->"||tag==="=>")){seenSingle=true}if(tag==="PROPERTY_ACCESS"&&this.tag(i-1)==="OUTDENT"){return true}return !token.generated&&this.tag(i-1)!==","&&include(IMPLICIT_END,tag)&&(tag!=="INDENT"||(this.tag(i-2)!=="CLASS"&&!include(IMPLICIT_BLOCK,this.tag(i-1))&&!((post=this.tokens[i+1])&&post.generated&&post[0]==="{")))},action);if(prev[0]==="?"){prev[0]="FUNC_EXIST"}return 2})};exports.Rewriter.prototype.addImplicitIndentation=function(){return this.scanTokens(function(token,i,tokens){var _ref,_ref2,action,condition,indent,outdent,starter,tag;tag=token[0];if(tag==="ELSE"&&this.tag(i-1)!=="OUTDENT"){tokens.splice.apply(tokens,[i,0].concat(this.indentation(token)));return 2}if(tag==="CATCH"&&((_ref=this.tag(i+2))==="TERMINATOR"||_ref==="FINALLY")){tokens.splice.apply(tokens,[i+2,0].concat(this.indentation(token)));return 4}if(include(SINGLE_LINERS,tag)&&this.tag(i+1)!=="INDENT"&&!(tag==="ELSE"&&this.tag(i+1)==="IF")){starter=tag;_ref2=this.indentation(token),indent=_ref2[0],outdent=_ref2[1];if(starter==="THEN"){indent.fromThen=true}indent.generated=(outdent.generated=true);tokens.splice(i+1,0,indent);condition=function(token,i){return token[1]!==";"&&include(SINGLE_CLOSERS,token[0])&&!(token[0]==="ELSE"&&!(starter==="IF"||starter==="THEN"))};action=function(token,i){return this.tokens.splice(this.tag(i-1)===","?i-1:i,0,outdent)};this.detectEnd(i+2,condition,action);if(tag==="THEN"){tokens.splice(i,1)}return 1}return 1})};exports.Rewriter.prototype.tagPostfixConditionals=function(){var condition;condition=function(token,i){var _ref;return((_ref=token[0])==="TERMINATOR"||_ref==="INDENT")};return this.scanTokens(function(token,i){var _ref,original;if(!((_ref=token[0])==="IF"||_ref==="UNLESS")){return 1}original=token;this.detectEnd(i+1,condition,function(token,i){return token[0]!=="INDENT"?(original[0]="POST_"+original[0]):undefined});return 1})};exports.Rewriter.prototype.ensureBalance=function(pairs){var _result,key,levels,open,openLine,unclosed,value;levels={};openLine={};this.scanTokens(function(token,i){var _i,_len,_ref,_ref2,close,open,tag;tag=token[0];for(_i=0,_len=(_ref=pairs).length;_i<_len;_i++){_ref2=_ref[_i],open=_ref2[0],close=_ref2[1];levels[open]|=0;if(tag===open){if(levels[open]===0){openLine[open]=token[2]}levels[open]+=1}else{if(tag===close){levels[open]-=1}}if(levels[open]<0){throw Error("too many "+(token[1])+" on line "+(token[2]+1))}}return 1});unclosed=(function(){_result=[];for(key in levels){value=levels[key];if(value>0){_result.push(key)}}return _result})();if(unclosed.length){throw Error("unclosed "+(open=unclosed[0])+" on line "+(openLine[open]+1))}};exports.Rewriter.prototype.rewriteClosingParens=function(){var debt,key,stack;stack=[];debt={};for(key in INVERSES){(debt[key]=0)}return this.scanTokens(function(token,i,tokens){var inv,match,mtag,oppos,tag,val;if(include(EXPRESSION_START,tag=token[0])){stack.push(token);return 1}if(!include(EXPRESSION_END,tag)){return 1}if(debt[(inv=INVERSES[tag])]>0){debt[inv]-=1;tokens.splice(i,1);return 0}match=stack.pop();mtag=match[0];oppos=INVERSES[mtag];if(tag===oppos){return 1}debt[mtag]+=1;val=[oppos,mtag==="INDENT"?match[1]:oppos];if(this.tag(i+2)===mtag){tokens.splice(i+3,0,val);stack.push(match)}else{tokens.splice(i,0,val)}return 1})};exports.Rewriter.prototype.indentation=function(token){return[["INDENT",2,token[2]],["OUTDENT",2,token[2]]]};exports.Rewriter.prototype.tag=function(i){var _ref;return(((_ref=this.tokens[i])!=null)?_ref[0]:undefined)};BALANCED_PAIRS=[["(",")"],["[","]"],["{","}"],["INDENT","OUTDENT"],["CALL_START","CALL_END"],["PARAM_START","PARAM_END"],["INDEX_START","INDEX_END"]];INVERSES={};EXPRESSION_START=[];EXPRESSION_END=[];for(_i=0,_len=BALANCED_PAIRS.length;_i<_len;_i++){_ref=BALANCED_PAIRS[_i],left=_ref[0],rite=_ref[1];EXPRESSION_START.push(INVERSES[rite]=left);EXPRESSION_END.push(INVERSES[left]=rite)}EXPRESSION_CLOSE=["CATCH","WHEN","ELSE","FINALLY"].concat(EXPRESSION_END);IMPLICIT_FUNC=["IDENTIFIER","SUPER",")","CALL_END","]","INDEX_END","@","THIS"];IMPLICIT_CALL=["IDENTIFIER","NUMBER","STRING","JS","REGEX","NEW","PARAM_START","CLASS","IF","UNLESS","TRY","SWITCH","THIS","BOOL","UNARY","@","->","=>","[","(","{"];IMPLICIT_BLOCK=["->","=>","{","[",","];IMPLICIT_END=["POST_IF","POST_UNLESS","FOR","WHILE","UNTIL","LOOP","TERMINATOR","INDENT"];SINGLE_LINERS=["ELSE","->","=>","TRY","FINALLY","THEN"];SINGLE_CLOSERS=["TERMINATOR","CATCH","FINALLY","ELSE","OUTDENT","LEADING_WHEN"];LINEBREAKS=["TERMINATOR","INDENT","OUTDENT"]}).call(this)};require["./lexer"]=new function(){var exports=this;(function(){var ASSIGNED,BOOL,CALLABLE,CODE,COFFEE_ALIASES,COFFEE_KEYWORDS,COMMENT,COMPARE,COMPOUND_ASSIGN,HEREDOC,HEREDOC_INDENT,HEREGEX,HEREGEX_OMIT,IDENTIFIER,INDEXABLE,JSTOKEN,JS_FORBIDDEN,JS_KEYWORDS,LEADING_SPACES,LINE_BREAK,LOGIC,Lexer,MATH,MULTILINER,MULTI_DENT,NEXT_CHARACTER,NEXT_ELLIPSIS,NOT_REGEX,NO_NEWLINE,NUMBER,OPERATOR,REGEX,RELATION,RESERVED,Rewriter,SHIFT,SIMPLESTR,TRAILING_SPACES,UNARY,WHITESPACE,_ref,compact,count,include,last,op,starts;Rewriter=require("./rewriter").Rewriter;_ref=require("./helpers"),include=_ref.include,count=_ref.count,starts=_ref.starts,compact=_ref.compact,last=_ref.last;exports.Lexer=(function(){Lexer=(function(){function Lexer(){}return Lexer})();Lexer.prototype.tokenize=function(code,options){var o;code=code.replace(/\r/g,"").replace(TRAILING_SPACES,"");o=options||{};this.code=code;this.i=0;this.line=o.line||0;this.indent=0;this.indebt=0;this.outdebt=0;this.seenFor=false;this.indents=[];this.tokens=[];while(this.chunk=code.slice(this.i)){this.identifierToken()||this.commentToken()||this.whitespaceToken()||this.lineToken()||this.heredocToken()||this.stringToken()||this.numberToken()||this.regexToken()||this.jsToken()||this.literalToken()}this.closeIndentation();if(o.rewrite===false){return this.tokens}return(new Rewriter).rewrite(this.tokens)};Lexer.prototype.identifierToken=function(){var colon,forcedIdentifier,id,input,match,tag;if(!(match=IDENTIFIER.exec(this.chunk))){return false}input=match[0],id=match[1],colon=match[2];this.i+=input.length;if(id==="all"&&this.tag()==="FOR"){this.token("ALL",id);return true}forcedIdentifier=colon||this.tagAccessor();tag="IDENTIFIER";if(include(JS_KEYWORDS,id)||!forcedIdentifier&&include(COFFEE_KEYWORDS,id)){tag=id.toUpperCase();if(tag==="WHEN"&&include(LINE_BREAK,this.tag())){tag="LEADING_WHEN"}else{if(tag==="FOR"){this.seenFor=true}else{if(include(UNARY,tag)){tag="UNARY"}else{if(include(RELATION,tag)){if(tag!=="INSTANCEOF"&&this.seenFor){this.seenFor=false;tag="FOR"+tag}else{tag="RELATION";if(this.value()==="!"){this.tokens.pop();id="!"+id}}}}}}}if(include(JS_FORBIDDEN,id)){if(forcedIdentifier){tag="IDENTIFIER";id=new String(id);id.reserved=true}else{if(include(RESERVED,id)){this.identifierError(id)}}}if(!forcedIdentifier){if(COFFEE_ALIASES.hasOwnProperty(id)){tag=(id=COFFEE_ALIASES[id])}if(id==="!"){tag="UNARY"}else{if(include(LOGIC,id)){tag="LOGIC"}else{if(include(BOOL,tag)){id=tag.toLowerCase();tag="BOOL"}}}}this.token(tag,id);if(colon){this.token(":",":")}return true};Lexer.prototype.numberToken=function(){var match,number;if(!(match=NUMBER.exec(this.chunk))){return false}number=match[0];if(this.tag()==="."&&number.charAt(0)==="."){return false}this.i+=number.length;this.token("NUMBER",number);return true};Lexer.prototype.stringToken=function(){var match,string;switch(this.chunk.charAt(0)){case"'":if(!(match=SIMPLESTR.exec(this.chunk))){return false}this.token("STRING",(string=match[0]).replace(MULTILINER,"\\\n"));break;case'"':if(!(string=this.balancedString(this.chunk,[['"','"'],["#{","}"]]))){return false}if(0body.indexOf("#{")){re=body.replace(HEREGEX_OMIT,"").replace(/\//g,"\\/");this.token("REGEX","/"+(re||"(?:)")+"/"+flags);return true}this.token("IDENTIFIER","RegExp");this.tokens.push(["CALL_START","("]);tokens=[];for(_i=0,_len=(_ref2=this.interpolateString(body,{regex:true})).length;_i<_len;_i++){_ref3=_ref2[_i],tag=_ref3[0],value=_ref3[1];if(tag==="TOKENS"){tokens.push.apply(tokens,value)}else{if(!(value=value.replace(HEREGEX_OMIT,""))){continue}value=value.replace(/\\/g,"\\\\");tokens.push(["STRING",this.makeString(value,'"',true)])}tokens.push(["+","+"])}tokens.pop();if((((_ref4=tokens[0])!=null)?_ref4[0]:undefined)!=="STRING"){this.tokens.push(["STRING",'""'],["+","+"])}(_this=this.tokens).push.apply(_this,tokens);if(flags){this.tokens.push([",",","],["STRING",'"'+flags+'"'])}this.token(")",")");return true};Lexer.prototype.lineToken=function(){var diff,indent,match,nextCharacter,noNewlines,prev,size;if(!(match=MULTI_DENT.exec(this.chunk))){return false}indent=match[0];this.line+=count(indent,"\n");this.i+=indent.length;prev=last(this.tokens,1);size=indent.length-1-indent.lastIndexOf("\n");nextCharacter=NEXT_CHARACTER.exec(this.chunk)[1];noNewlines=((nextCharacter==="."||nextCharacter===",")&&!NEXT_ELLIPSIS.test(this.chunk))||this.unfinished();if(size-this.indebt===this.indent){if(noNewlines){return this.suppressNewlines()}return this.newlineToken(indent)}else{if(size>this.indent){if(noNewlines){this.indebt=size-this.indent;return this.suppressNewlines()}diff=size-this.indent+this.outdebt;this.token("INDENT",diff);this.indents.push(diff);this.outdebt=(this.indebt=0)}else{this.indebt=0;this.outdentToken(this.indent-size,noNewlines)}}this.indent=size;return true};Lexer.prototype.outdentToken=function(moveOut,noNewlines,close){var dent,len;while(moveOut>0){len=this.indents.length-1;if(this.indents[len]===undefined){moveOut=0}else{if(this.indents[len]===this.outdebt){moveOut-=this.outdebt;this.outdebt=0}else{if(this.indents[len]doc.indexOf("\n")){return doc}if(!herecomment){while(match=HEREDOC_INDENT.exec(doc)){attempt=match[1];if(indent===null||(0<(_ref2=attempt.length))&&(_ref21){nested.unshift(["(","("]);nested.push([")",")"])}tokens.push(["TOKENS",nested])}i+=expr.length;pi=i+1}if((i>pi)&&(pi1){this.token("(","(")}for(i=0,_len=tokens.length;i<_len;i++){_ref3=tokens[i],tag=_ref3[0],value=_ref3[1];if(i){this.token("+","+")}if(tag==="TOKENS"){(_this=this.tokens).push.apply(_this,value)}else{this.token("STRING",this.makeString(value,'"',heredoc))}}if(interpolated){this.token(")",")")}return tokens};Lexer.prototype.token=function(tag,value){return this.tokens.push([tag,value,this.line])};Lexer.prototype.tag=function(index,tag){var tok;return(tok=last(this.tokens,index))&&((tag!=null)?(tok[0]=tag):tok[0])};Lexer.prototype.value=function(index,val){var tok;return(tok=last(this.tokens,index))&&((val!=null)?(tok[1]=val):tok[1])};Lexer.prototype.unfinished=function(){var prev,value;return(prev=last(this.tokens,1))&&prev[0]!=="."&&(value=this.value())&&!value.reserved&&NO_NEWLINE.test(value)&&!CODE.test(value)&&!ASSIGNED.test(this.chunk)};Lexer.prototype.escapeLines=function(str,heredoc){return str.replace(MULTILINER,heredoc?"\\n":"")};Lexer.prototype.makeString=function(body,quote,heredoc){if(!body){return quote+quote}body=body.replace(/\\([\s\S])/g,function(match,contents){return(contents==="\n"||contents===quote)?contents:match});body=body.replace(RegExp(""+quote,"g"),"\\$&");return quote+this.escapeLines(body,heredoc)+quote};return Lexer})();JS_KEYWORDS=["true","false","null","this","new","delete","typeof","in","instanceof","return","throw","break","continue","debugger","if","else","switch","for","while","try","catch","finally","class","extends","super"];COFFEE_KEYWORDS=["then","unless","until","loop","of","by","when"];for(op in (COFFEE_ALIASES={and:"&&",or:"||",is:"==",isnt:"!=",not:"!",yes:"TRUE",no:"FALSE",on:"TRUE",off:"FALSE"})){COFFEE_KEYWORDS.push(op)}COFFEE_ALIASES["==="]="==";RESERVED=["case","default","do","function","var","void","with","const","let","enum","export","import","native","__hasProp","__extends","__slice"];JS_FORBIDDEN=JS_KEYWORDS.concat(RESERVED);IDENTIFIER=/^([$A-Za-z_][$\w]*)([^\n\S]*:(?!:))?/;NUMBER=/^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;HEREDOC=/^("""|''')([\s\S]*?)(?:\n[ \t]*)?\1/;OPERATOR=/^(?:-[-=>]?|\+[+=]?|\.\.\.?|[*&|\/%=<>^:!?]+)/;WHITESPACE=/^[ \t]+/;COMMENT=/^###([^#][\s\S]*?)(?:###[ \t]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;CODE=/^[-=]>/;MULTI_DENT=/^(?:\n[ \t]*)+/;SIMPLESTR=/^'[^\\']*(?:\\.[^\\']*)*'/;JSTOKEN=/^`[^\\`]*(?:\\.[^\\`]*)*`/;REGEX=/^\/(?!\s)(?:[^[\/\n\\]+|\\[\s\S]|\[([^\]\n\\]+|\\[\s\S])*])+\/[imgy]{0,4}(?![A-Za-z])/;HEREGEX=/^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?![A-Za-z])/;HEREGEX_OMIT=/\s+(?:#.*)?/g;MULTILINER=/\n/g;HEREDOC_INDENT=/\n+([ \t]*)/g;ASSIGNED=/^\s*@?[$A-Za-z_][$\w]*[ \t]*?[:=][^:=>]/;NEXT_CHARACTER=/^\s*(\S?)/;NEXT_ELLIPSIS=/^\s*\.\.\.?/;LEADING_SPACES=/^\s+/;TRAILING_SPACES=/\s+$/;NO_NEWLINE=/^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;COMPOUND_ASSIGN=["-=","+=","/=","*=","%=","||=","&&=","?=","<<=",">>=",">>>=","&=","^=","|="];UNARY=["UMINUS","UPLUS","!","!!","~","NEW","TYPEOF","DELETE"];LOGIC=["&","|","^","&&","||"];SHIFT=["<<",">>",">>>"];COMPARE=["<=","<",">",">="];MATH=["*","/","%"];RELATION=["IN","OF","INSTANCEOF"];BOOL=["TRUE","FALSE","NULL"];NOT_REGEX=["NUMBER","REGEX","BOOL","++","--","]"];CALLABLE=["IDENTIFIER","STRING","REGEX",")","]","}","?","::","@","THIS","SUPER"];INDEXABLE=CALLABLE.concat("NUMBER","BOOL");LINE_BREAK=["INDENT","OUTDENT","TERMINATOR"]}).call(this)};require["./parser"]=new function(){var exports=this;var parser=(function(){var parser={trace:function trace(){},yy:{},symbols_:{error:2,Root:3,TERMINATOR:4,Body:5,Block:6,Line:7,Expression:8,Statement:9,Return:10,Throw:11,BREAK:12,CONTINUE:13,DEBUGGER:14,Value:15,Invocation:16,Code:17,Operation:18,Assign:19,If:20,Try:21,While:22,For:23,Switch:24,Extends:25,Class:26,Existence:27,Comment:28,INDENT:29,OUTDENT:30,Identifier:31,IDENTIFIER:32,AlphaNumeric:33,NUMBER:34,STRING:35,Literal:36,JS:37,REGEX:38,BOOL:39,Assignable:40,"=":41,AssignObj:42,ThisProperty:43,":":44,RETURN:45,HERECOMMENT:46,"?":47,PARAM_START:48,ParamList:49,PARAM_END:50,FuncGlyph:51,"->":52,"=>":53,OptComma:54,",":55,Param:56,PARAM:57,"@":58,"...":59,Splat:60,SimpleAssignable:61,Accessor:62,Array:63,Object:64,Parenthetical:65,Range:66,This:67,PROPERTY_ACCESS:68,PROTOTYPE_ACCESS:69,"::":70,SOAK_ACCESS:71,Index:72,Slice:73,INDEX_START:74,INDEX_END:75,INDEX_SOAK:76,INDEX_PROTO:77,"{":78,AssignList:79,"}":80,CLASS:81,EXTENDS:82,ClassBody:83,ClassAssign:84,OptFuncExist:85,Arguments:86,SUPER:87,FUNC_EXIST:88,CALL_START:89,CALL_END:90,ArgList:91,THIS:92,RangeDots:93,"..":94,"[":95,"]":96,Arg:97,SimpleArgs:98,TRY:99,Catch:100,FINALLY:101,CATCH:102,THROW:103,"(":104,")":105,WhileSource:106,WHILE:107,WHEN:108,UNTIL:109,Loop:110,LOOP:111,ForBody:112,FOR:113,ForStart:114,ForSource:115,ForVariables:116,ALL:117,ForValue:118,FORIN:119,FOROF:120,BY:121,SWITCH:122,Whens:123,ELSE:124,When:125,LEADING_WHEN:126,IfBlock:127,IF:128,UNLESS:129,POST_IF:130,POST_UNLESS:131,UNARY:132,"-":133,"+":134,"--":135,"++":136,"==":137,"!=":138,MATH:139,SHIFT:140,COMPARE:141,LOGIC:142,COMPOUND_ASSIGN:143,RELATION:144,"$accept":0,"$end":1},terminals_:{"2":"error","4":"TERMINATOR","12":"BREAK","13":"CONTINUE","14":"DEBUGGER","29":"INDENT","30":"OUTDENT","32":"IDENTIFIER","34":"NUMBER","35":"STRING","37":"JS","38":"REGEX","39":"BOOL","41":"=","44":":","45":"RETURN","46":"HERECOMMENT","47":"?","48":"PARAM_START","50":"PARAM_END","52":"->","53":"=>","55":",","57":"PARAM","58":"@","59":"...","68":"PROPERTY_ACCESS","69":"PROTOTYPE_ACCESS","70":"::","71":"SOAK_ACCESS","74":"INDEX_START","75":"INDEX_END","76":"INDEX_SOAK","77":"INDEX_PROTO","78":"{","80":"}","81":"CLASS","82":"EXTENDS","87":"SUPER","88":"FUNC_EXIST","89":"CALL_START","90":"CALL_END","92":"THIS","94":"..","95":"[","96":"]","99":"TRY","101":"FINALLY","102":"CATCH","103":"THROW","104":"(","105":")","107":"WHILE","108":"WHEN","109":"UNTIL","111":"LOOP","113":"FOR","117":"ALL","119":"FORIN","120":"FOROF","121":"BY","122":"SWITCH","124":"ELSE","126":"LEADING_WHEN","128":"IF","129":"UNLESS","130":"POST_IF","131":"POST_UNLESS","132":"UNARY","133":"-","134":"+","135":"--","136":"++","137":"==","138":"!=","139":"MATH","140":"SHIFT","141":"COMPARE","142":"LOGIC","143":"COMPOUND_ASSIGN","144":"RELATION"},productions_:[0,[3,0],[3,1],[3,1],[3,2],[5,1],[5,3],[5,2],[7,1],[7,1],[9,1],[9,1],[9,1],[9,1],[9,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[6,3],[6,2],[6,2],[31,1],[33,1],[33,1],[36,1],[36,1],[36,1],[36,1],[19,3],[19,5],[42,1],[42,1],[42,1],[42,3],[42,3],[42,5],[42,5],[42,1],[10,2],[10,1],[28,1],[27,2],[17,5],[17,2],[51,1],[51,1],[54,0],[54,1],[49,0],[49,1],[49,3],[56,1],[56,2],[56,2],[56,3],[60,2],[61,1],[61,2],[61,2],[61,1],[40,1],[40,1],[40,1],[15,1],[15,1],[15,1],[15,1],[15,1],[62,2],[62,2],[62,1],[62,2],[62,1],[62,1],[72,3],[72,2],[72,2],[64,4],[79,0],[79,1],[79,3],[79,4],[79,6],[26,2],[26,4],[26,5],[26,7],[26,4],[26,1],[26,3],[26,6],[84,1],[84,3],[84,5],[83,0],[83,1],[83,3],[83,3],[25,3],[16,3],[16,3],[16,1],[16,2],[85,0],[85,1],[86,2],[86,4],[67,1],[67,1],[93,1],[93,1],[43,2],[66,5],[73,5],[73,4],[73,4],[63,2],[63,4],[91,1],[91,3],[91,4],[91,4],[91,6],[97,1],[97,1],[98,1],[98,3],[21,2],[21,3],[21,4],[21,5],[100,3],[11,2],[65,3],[65,2],[106,2],[106,4],[106,2],[106,4],[22,2],[22,2],[22,2],[22,1],[110,2],[110,2],[23,2],[23,2],[23,2],[112,2],[112,2],[114,2],[114,3],[118,1],[118,1],[118,1],[116,1],[116,3],[115,2],[115,2],[115,4],[115,4],[115,4],[115,6],[115,6],[24,5],[24,7],[24,4],[24,6],[123,1],[123,2],[125,3],[125,4],[127,3],[127,3],[127,5],[127,3],[20,1],[20,3],[20,3],[20,3],[20,3],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,5],[18,3]],performAction:function anonymous(yytext,yyleng,yylineno,yy){var $$=arguments[5],$0=arguments[5].length;switch(arguments[4]){case 1:return this.$=new yy.Expressions;break;case 2:return this.$=new yy.Expressions;break;case 3:return this.$=$$[$0-1+1-1];break;case 4:return this.$=$$[$0-2+1-1];break;case 5:this.$=yy.Expressions.wrap([$$[$0-1+1-1]]);break;case 6:this.$=$$[$0-3+1-1].push($$[$0-3+3-1]);break;case 7:this.$=$$[$0-2+1-1];break;case 8:this.$=$$[$0-1+1-1];break;case 9:this.$=$$[$0-1+1-1];break;case 10:this.$=$$[$0-1+1-1];break;case 11:this.$=$$[$0-1+1-1];break;case 12:this.$=new yy.Literal($$[$0-1+1-1]);break;case 13:this.$=new yy.Literal($$[$0-1+1-1]);break;case 14:this.$=new yy.Literal($$[$0-1+1-1]);break;case 15:this.$=$$[$0-1+1-1];break;case 16:this.$=$$[$0-1+1-1];break;case 17:this.$=$$[$0-1+1-1];break;case 18:this.$=$$[$0-1+1-1];break;case 19:this.$=$$[$0-1+1-1];break;case 20:this.$=$$[$0-1+1-1];break;case 21:this.$=$$[$0-1+1-1];break;case 22:this.$=$$[$0-1+1-1];break;case 23:this.$=$$[$0-1+1-1];break;case 24:this.$=$$[$0-1+1-1];break;case 25:this.$=$$[$0-1+1-1];break;case 26:this.$=$$[$0-1+1-1];break;case 27:this.$=$$[$0-1+1-1];break;case 28:this.$=$$[$0-1+1-1];break;case 29:this.$=$$[$0-3+2-1];break;case 30:this.$=new yy.Expressions;break;case 31:this.$=yy.Expressions.wrap([$$[$0-2+2-1]]);break;case 32:this.$=new yy.Literal($$[$0-1+1-1]);break;case 33:this.$=new yy.Literal($$[$0-1+1-1]);break;case 34:this.$=new yy.Literal($$[$0-1+1-1]);break;case 35:this.$=$$[$0-1+1-1];break;case 36:this.$=new yy.Literal($$[$0-1+1-1]);break;case 37:this.$=new yy.Literal($$[$0-1+1-1]);break;case 38:this.$=new yy.Literal($$[$0-1+1-1]);break;case 39:this.$=new yy.Assign($$[$0-3+1-1],$$[$0-3+3-1]);break;case 40:this.$=new yy.Assign($$[$0-5+1-1],$$[$0-5+4-1]);break;case 41:this.$=new yy.Value($$[$0-1+1-1]);break;case 42:this.$=$$[$0-1+1-1];break;case 43:this.$=$$[$0-1+1-1];break;case 44:this.$=new yy.Assign(new yy.Value($$[$0-3+1-1]),$$[$0-3+3-1],"object");break;case 45:this.$=new yy.Assign(new yy.Value($$[$0-3+1-1]),$$[$0-3+3-1],"object");break;case 46:this.$=new yy.Assign(new yy.Value($$[$0-5+1-1]),$$[$0-5+4-1],"object");break;case 47:this.$=new yy.Assign(new yy.Value($$[$0-5+1-1]),$$[$0-5+4-1],"object");break;case 48:this.$=$$[$0-1+1-1];break;case 49:this.$=new yy.Return($$[$0-2+2-1]);break;case 50:this.$=new yy.Return;break;case 51:this.$=new yy.Comment($$[$0-1+1-1]);break;case 52:this.$=new yy.Existence($$[$0-2+1-1]);break;case 53:this.$=new yy.Code($$[$0-5+2-1],$$[$0-5+5-1],$$[$0-5+4-1]);break;case 54:this.$=new yy.Code([],$$[$0-2+2-1],$$[$0-2+1-1]);break;case 55:this.$="func";break;case 56:this.$="boundfunc";break;case 57:this.$=$$[$0-1+1-1];break;case 58:this.$=$$[$0-1+1-1];break;case 59:this.$=[];break;case 60:this.$=[$$[$0-1+1-1]];break;case 61:this.$=$$[$0-3+1-1].concat($$[$0-3+3-1]);break;case 62:this.$=new yy.Literal($$[$0-1+1-1]);break;case 63:this.$=new yy.Param($$[$0-2+2-1],true);break;case 64:this.$=new yy.Param($$[$0-2+1-1],false,true);break;case 65:this.$=new yy.Param($$[$0-3+2-1],true,true);break;case 66:this.$=new yy.Splat($$[$0-2+1-1]);break;case 67:this.$=new yy.Value($$[$0-1+1-1]);break;case 68:this.$=$$[$0-2+1-1].push($$[$0-2+2-1]);break;case 69:this.$=new yy.Value($$[$0-2+1-1],[$$[$0-2+2-1]]);break;case 70:this.$=$$[$0-1+1-1];break;case 71:this.$=$$[$0-1+1-1];break;case 72:this.$=new yy.Value($$[$0-1+1-1]);break;case 73:this.$=new yy.Value($$[$0-1+1-1]);break;case 74:this.$=$$[$0-1+1-1];break;case 75:this.$=new yy.Value($$[$0-1+1-1]);break;case 76:this.$=new yy.Value($$[$0-1+1-1]);break;case 77:this.$=new yy.Value($$[$0-1+1-1]);break;case 78:this.$=$$[$0-1+1-1];break;case 79:this.$=new yy.Accessor($$[$0-2+2-1]);break;case 80:this.$=new yy.Accessor($$[$0-2+2-1],"prototype");break;case 81:this.$=new yy.Accessor(new yy.Literal("prototype"));break;case 82:this.$=new yy.Accessor($$[$0-2+2-1],"soak");break;case 83:this.$=$$[$0-1+1-1];break;case 84:this.$=new yy.Slice($$[$0-1+1-1]);break;case 85:this.$=new yy.Index($$[$0-3+2-1]);break;case 86:this.$=(function(){$$[$0-2+2-1].soakNode=true;return $$[$0-2+2-1]}());break;case 87:this.$=(function(){$$[$0-2+2-1].proto=true;return $$[$0-2+2-1]}());break;case 88:this.$=new yy.ObjectLiteral($$[$0-4+2-1]);break;case 89:this.$=[];break;case 90:this.$=[$$[$0-1+1-1]];break;case 91:this.$=$$[$0-3+1-1].concat($$[$0-3+3-1]);break;case 92:this.$=$$[$0-4+1-1].concat($$[$0-4+4-1]);break;case 93:this.$=$$[$0-6+1-1].concat($$[$0-6+4-1]);break;case 94:this.$=new yy.Class($$[$0-2+2-1]);break;case 95:this.$=new yy.Class($$[$0-4+2-1],$$[$0-4+4-1]);break;case 96:this.$=new yy.Class($$[$0-5+2-1],null,$$[$0-5+4-1]);break;case 97:this.$=new yy.Class($$[$0-7+2-1],$$[$0-7+4-1],$$[$0-7+6-1]);break;case 98:this.$=new yy.Class("__temp__",null,$$[$0-4+3-1]);break;case 99:this.$=new yy.Class("__temp__",null,new yy.Expressions);break;case 100:this.$=new yy.Class("__temp__",$$[$0-3+3-1],new yy.Expressions);break;case 101:this.$=new yy.Class("__temp__",$$[$0-6+3-1],$$[$0-6+5-1]);break;case 102:this.$=$$[$0-1+1-1];break;case 103:this.$=new yy.Assign(new yy.Value($$[$0-3+1-1]),$$[$0-3+3-1],"this");break;case 104:this.$=new yy.Assign(new yy.Value($$[$0-5+1-1]),$$[$0-5+4-1],"this");break;case 105:this.$=[];break;case 106:this.$=[$$[$0-1+1-1]];break;case 107:this.$=$$[$0-3+1-1].concat($$[$0-3+3-1]);break;case 108:this.$=$$[$0-3+2-1];break;case 109:this.$=new yy.Extends($$[$0-3+1-1],$$[$0-3+3-1]);break;case 110:this.$=new yy.Call($$[$0-3+1-1],$$[$0-3+3-1],$$[$0-3+2-1]);break;case 111:this.$=new yy.Call($$[$0-3+1-1],$$[$0-3+3-1],$$[$0-3+2-1]);break;case 112:this.$=new yy.Call("super",[new yy.Splat(new yy.Literal("arguments"))]);break;case 113:this.$=new yy.Call("super",$$[$0-2+2-1]);break;case 114:this.$=false;break;case 115:this.$=true;break;case 116:this.$=[];break;case 117:this.$=$$[$0-4+2-1];break;case 118:this.$=new yy.Value(new yy.Literal("this"));break;case 119:this.$=new yy.Value(new yy.Literal("this"));break;case 120:this.$="inclusive";break;case 121:this.$="exclusive";break;case 122:this.$=new yy.Value(new yy.Literal("this"),[new yy.Accessor($$[$0-2+2-1])],"this");break;case 123:this.$=new yy.Range($$[$0-5+2-1],$$[$0-5+4-1],$$[$0-5+3-1]);break;case 124:this.$=new yy.Range($$[$0-5+2-1],$$[$0-5+4-1],$$[$0-5+3-1]);break;case 125:this.$=new yy.Range($$[$0-4+2-1],null,$$[$0-4+3-1]);break;case 126:this.$=new yy.Range(null,$$[$0-4+3-1],$$[$0-4+2-1]);break;case 127:this.$=new yy.ArrayLiteral([]);break;case 128:this.$=new yy.ArrayLiteral($$[$0-4+2-1]);break;case 129:this.$=[$$[$0-1+1-1]];break;case 130:this.$=$$[$0-3+1-1].concat($$[$0-3+3-1]);break;case 131:this.$=$$[$0-4+1-1].concat($$[$0-4+4-1]);break;case 132:this.$=$$[$0-4+2-1];break;case 133:this.$=$$[$0-6+1-1].concat($$[$0-6+4-1]);break;case 134:this.$=$$[$0-1+1-1];break;case 135:this.$=$$[$0-1+1-1];break;case 136:this.$=$$[$0-1+1-1];break;case 137:this.$=[].concat($$[$0-3+1-1],$$[$0-3+3-1]);break;case 138:this.$=new yy.Try($$[$0-2+2-1]);break;case 139:this.$=new yy.Try($$[$0-3+2-1],$$[$0-3+3-1][0],$$[$0-3+3-1][1]);break;case 140:this.$=new yy.Try($$[$0-4+2-1],null,null,$$[$0-4+4-1]);break;case 141:this.$=new yy.Try($$[$0-5+2-1],$$[$0-5+3-1][0],$$[$0-5+3-1][1],$$[$0-5+5-1]);break;case 142:this.$=[$$[$0-3+2-1],$$[$0-3+3-1]];break;case 143:this.$=new yy.Throw($$[$0-2+2-1]);break;case 144:this.$=new yy.Parens($$[$0-3+2-1]);break;case 145:this.$=new yy.Parens(new yy.Literal(""));break;case 146:this.$=new yy.While($$[$0-2+2-1]);break;case 147:this.$=new yy.While($$[$0-4+2-1],{guard:$$[$0-4+4-1]});break;case 148:this.$=new yy.While($$[$0-2+2-1],{invert:true});break;case 149:this.$=new yy.While($$[$0-4+2-1],{invert:true,guard:$$[$0-4+4-1]});break;case 150:this.$=$$[$0-2+1-1].addBody($$[$0-2+2-1]);break;case 151:this.$=$$[$0-2+2-1].addBody(yy.Expressions.wrap([$$[$0-2+1-1]]));break;case 152:this.$=$$[$0-2+2-1].addBody(yy.Expressions.wrap([$$[$0-2+1-1]]));break;case 153:this.$=$$[$0-1+1-1];break;case 154:this.$=new yy.While(new yy.Literal("true")).addBody($$[$0-2+2-1]);break;case 155:this.$=new yy.While(new yy.Literal("true")).addBody(yy.Expressions.wrap([$$[$0-2+2-1]]));break;case 156:this.$=new yy.For($$[$0-2+1-1],$$[$0-2+2-1],$$[$0-2+2-1].vars[0],$$[$0-2+2-1].vars[1]);break;case 157:this.$=new yy.For($$[$0-2+1-1],$$[$0-2+2-1],$$[$0-2+2-1].vars[0],$$[$0-2+2-1].vars[1]);break;case 158:this.$=new yy.For($$[$0-2+2-1],$$[$0-2+1-1],$$[$0-2+1-1].vars[0],$$[$0-2+1-1].vars[1]);break;case 159:this.$={source:new yy.Value($$[$0-2+2-1]),vars:[]};break;case 160:this.$=(function(){$$[$0-2+2-1].raw=$$[$0-2+1-1].raw;$$[$0-2+2-1].vars=$$[$0-2+1-1];return $$[$0-2+2-1]}());break;case 161:this.$=$$[$0-2+2-1];break;case 162:this.$=(function(){$$[$0-3+3-1].raw=true;return $$[$0-3+3-1]}());break;case 163:this.$=$$[$0-1+1-1];break;case 164:this.$=new yy.Value($$[$0-1+1-1]);break;case 165:this.$=new yy.Value($$[$0-1+1-1]);break;case 166:this.$=[$$[$0-1+1-1]];break;case 167:this.$=[$$[$0-3+1-1],$$[$0-3+3-1]];break;case 168:this.$={source:$$[$0-2+2-1]};break;case 169:this.$={source:$$[$0-2+2-1],object:true};break;case 170:this.$={source:$$[$0-4+2-1],guard:$$[$0-4+4-1]};break;case 171:this.$={source:$$[$0-4+2-1],guard:$$[$0-4+4-1],object:true};break;case 172:this.$={source:$$[$0-4+2-1],step:$$[$0-4+4-1]};break;case 173:this.$={source:$$[$0-6+2-1],guard:$$[$0-6+4-1],step:$$[$0-6+6-1]};break;case 174:this.$={source:$$[$0-6+2-1],step:$$[$0-6+4-1],guard:$$[$0-6+6-1]};break;case 175:this.$=new yy.Switch($$[$0-5+2-1],$$[$0-5+4-1]);break;case 176:this.$=new yy.Switch($$[$0-7+2-1],$$[$0-7+4-1],$$[$0-7+6-1]);break;case 177:this.$=new yy.Switch(null,$$[$0-4+3-1]);break;case 178:this.$=new yy.Switch(null,$$[$0-6+3-1],$$[$0-6+5-1]);break;case 179:this.$=$$[$0-1+1-1];break;case 180:this.$=$$[$0-2+1-1].concat($$[$0-2+2-1]);break;case 181:this.$=[[$$[$0-3+2-1],$$[$0-3+3-1]]];break;case 182:this.$=[[$$[$0-4+2-1],$$[$0-4+3-1]]];break;case 183:this.$=new yy.If($$[$0-3+2-1],$$[$0-3+3-1]);break;case 184:this.$=new yy.If($$[$0-3+2-1],$$[$0-3+3-1],{invert:true});break;case 185:this.$=$$[$0-5+1-1].addElse(new yy.If($$[$0-5+4-1],$$[$0-5+5-1]));break;case 186:this.$=$$[$0-3+1-1].addElse($$[$0-3+3-1]);break;case 187:this.$=$$[$0-1+1-1];break;case 188:this.$=new yy.If($$[$0-3+3-1],yy.Expressions.wrap([$$[$0-3+1-1]]),{statement:true});break;case 189:this.$=new yy.If($$[$0-3+3-1],yy.Expressions.wrap([$$[$0-3+1-1]]),{statement:true});break;case 190:this.$=new yy.If($$[$0-3+3-1],yy.Expressions.wrap([$$[$0-3+1-1]]),{statement:true,invert:true});break;case 191:this.$=new yy.If($$[$0-3+3-1],yy.Expressions.wrap([$$[$0-3+1-1]]),{statement:true,invert:true});break;case 192:this.$=new yy.Op($$[$0-2+1-1],$$[$0-2+2-1]);break;case 193:this.$=new yy.Op("-",$$[$0-2+2-1]);break;case 194:this.$=new yy.Op("+",$$[$0-2+2-1]);break;case 195:this.$=new yy.Op("--",$$[$0-2+2-1]);break;case 196:this.$=new yy.Op("++",$$[$0-2+2-1]);break;case 197:this.$=new yy.Op("--",$$[$0-2+1-1],null,true);break;case 198:this.$=new yy.Op("++",$$[$0-2+1-1],null,true);break;case 199:this.$=new yy.Op("+",$$[$0-3+1-1],$$[$0-3+3-1]);break;case 200:this.$=new yy.Op("-",$$[$0-3+1-1],$$[$0-3+3-1]);break;case 201:this.$=new yy.Op("==",$$[$0-3+1-1],$$[$0-3+3-1]);break;case 202:this.$=new yy.Op("!=",$$[$0-3+1-1],$$[$0-3+3-1]);break;case 203:this.$=new yy.Op($$[$0-3+2-1],$$[$0-3+1-1],$$[$0-3+3-1]);break;case 204:this.$=new yy.Op($$[$0-3+2-1],$$[$0-3+1-1],$$[$0-3+3-1]);break;case 205:this.$=new yy.Op($$[$0-3+2-1],$$[$0-3+1-1],$$[$0-3+3-1]);break;case 206:this.$=new yy.Op($$[$0-3+2-1],$$[$0-3+1-1],$$[$0-3+3-1]);break;case 207:this.$=new yy.Op($$[$0-3+2-1],$$[$0-3+1-1],$$[$0-3+3-1]);break;case 208:this.$=new yy.Op($$[$0-5+2-1],$$[$0-5+1-1],$$[$0-5+4-1]);break;case 209:this.$=$$[$0-3+2-1].charAt(0)==="!"?($$[$0-3+2-1]==="!in"?new yy.Op("!",new yy.In($$[$0-3+1-1],$$[$0-3+3-1])):new yy.Op("!",new yy.Parens(new yy.Op($$[$0-3+2-1].slice(1),$$[$0-3+1-1],$$[$0-3+3-1])))):($$[$0-3+2-1]==="in"?new yy.In($$[$0-3+1-1],$$[$0-3+3-1]):new yy.Op($$[$0-3+2-1],$$[$0-3+1-1],$$[$0-3+3-1]));break}},table:[{"1":[2,1],"3":1,"4":[1,2],"5":3,"6":4,"7":5,"8":7,"9":8,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,6],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[3]},{"1":[2,2],"28":77,"46":[1,49]},{"1":[2,3],"4":[1,78]},{"4":[1,79]},{"1":[2,5],"4":[2,5],"30":[2,5]},{"5":80,"7":5,"8":7,"9":8,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"30":[1,81],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,8],"4":[2,8],"30":[2,8],"47":[1,97],"105":[2,8],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,9],"4":[2,9],"30":[2,9],"105":[2,9],"106":100,"107":[1,66],"109":[1,67],"112":101,"113":[1,69],"114":70,"130":[1,98],"131":[1,99]},{"1":[2,15],"4":[2,15],"29":[2,15],"30":[2,15],"47":[2,15],"55":[2,15],"59":[2,15],"62":104,"68":[1,106],"69":[1,107],"70":[1,108],"71":[1,109],"72":110,"73":111,"74":[1,112],"75":[2,15],"76":[1,113],"77":[1,114],"80":[2,15],"85":102,"88":[1,105],"89":[2,114],"90":[2,15],"94":[2,15],"96":[2,15],"105":[2,15],"107":[2,15],"108":[2,15],"109":[2,15],"113":[2,15],"121":[2,15],"130":[2,15],"131":[2,15],"133":[2,15],"134":[2,15],"135":[2,15],"136":[2,15],"137":[2,15],"138":[2,15],"139":[2,15],"140":[2,15],"141":[2,15],"142":[2,15],"143":[1,103],"144":[2,15]},{"1":[2,16],"4":[2,16],"29":[2,16],"30":[2,16],"47":[2,16],"55":[2,16],"59":[2,16],"62":116,"68":[1,106],"69":[1,107],"70":[1,108],"71":[1,109],"72":110,"73":111,"74":[1,112],"75":[2,16],"76":[1,113],"77":[1,114],"80":[2,16],"85":115,"88":[1,105],"89":[2,114],"90":[2,16],"94":[2,16],"96":[2,16],"105":[2,16],"107":[2,16],"108":[2,16],"109":[2,16],"113":[2,16],"121":[2,16],"130":[2,16],"131":[2,16],"133":[2,16],"134":[2,16],"135":[2,16],"136":[2,16],"137":[2,16],"138":[2,16],"139":[2,16],"140":[2,16],"141":[2,16],"142":[2,16],"144":[2,16]},{"1":[2,17],"4":[2,17],"29":[2,17],"30":[2,17],"47":[2,17],"55":[2,17],"59":[2,17],"75":[2,17],"80":[2,17],"90":[2,17],"94":[2,17],"96":[2,17],"105":[2,17],"107":[2,17],"108":[2,17],"109":[2,17],"113":[2,17],"121":[2,17],"130":[2,17],"131":[2,17],"133":[2,17],"134":[2,17],"135":[2,17],"136":[2,17],"137":[2,17],"138":[2,17],"139":[2,17],"140":[2,17],"141":[2,17],"142":[2,17],"144":[2,17]},{"1":[2,18],"4":[2,18],"29":[2,18],"30":[2,18],"47":[2,18],"55":[2,18],"59":[2,18],"75":[2,18],"80":[2,18],"90":[2,18],"94":[2,18],"96":[2,18],"105":[2,18],"107":[2,18],"108":[2,18],"109":[2,18],"113":[2,18],"121":[2,18],"130":[2,18],"131":[2,18],"133":[2,18],"134":[2,18],"135":[2,18],"136":[2,18],"137":[2,18],"138":[2,18],"139":[2,18],"140":[2,18],"141":[2,18],"142":[2,18],"144":[2,18]},{"1":[2,19],"4":[2,19],"29":[2,19],"30":[2,19],"47":[2,19],"55":[2,19],"59":[2,19],"75":[2,19],"80":[2,19],"90":[2,19],"94":[2,19],"96":[2,19],"105":[2,19],"107":[2,19],"108":[2,19],"109":[2,19],"113":[2,19],"121":[2,19],"130":[2,19],"131":[2,19],"133":[2,19],"134":[2,19],"135":[2,19],"136":[2,19],"137":[2,19],"138":[2,19],"139":[2,19],"140":[2,19],"141":[2,19],"142":[2,19],"144":[2,19]},{"1":[2,20],"4":[2,20],"29":[2,20],"30":[2,20],"47":[2,20],"55":[2,20],"59":[2,20],"75":[2,20],"80":[2,20],"90":[2,20],"94":[2,20],"96":[2,20],"105":[2,20],"107":[2,20],"108":[2,20],"109":[2,20],"113":[2,20],"121":[2,20],"130":[2,20],"131":[2,20],"133":[2,20],"134":[2,20],"135":[2,20],"136":[2,20],"137":[2,20],"138":[2,20],"139":[2,20],"140":[2,20],"141":[2,20],"142":[2,20],"144":[2,20]},{"1":[2,21],"4":[2,21],"29":[2,21],"30":[2,21],"47":[2,21],"55":[2,21],"59":[2,21],"75":[2,21],"80":[2,21],"90":[2,21],"94":[2,21],"96":[2,21],"105":[2,21],"107":[2,21],"108":[2,21],"109":[2,21],"113":[2,21],"121":[2,21],"130":[2,21],"131":[2,21],"133":[2,21],"134":[2,21],"135":[2,21],"136":[2,21],"137":[2,21],"138":[2,21],"139":[2,21],"140":[2,21],"141":[2,21],"142":[2,21],"144":[2,21]},{"1":[2,22],"4":[2,22],"29":[2,22],"30":[2,22],"47":[2,22],"55":[2,22],"59":[2,22],"75":[2,22],"80":[2,22],"90":[2,22],"94":[2,22],"96":[2,22],"105":[2,22],"107":[2,22],"108":[2,22],"109":[2,22],"113":[2,22],"121":[2,22],"130":[2,22],"131":[2,22],"133":[2,22],"134":[2,22],"135":[2,22],"136":[2,22],"137":[2,22],"138":[2,22],"139":[2,22],"140":[2,22],"141":[2,22],"142":[2,22],"144":[2,22]},{"1":[2,23],"4":[2,23],"29":[2,23],"30":[2,23],"47":[2,23],"55":[2,23],"59":[2,23],"75":[2,23],"80":[2,23],"90":[2,23],"94":[2,23],"96":[2,23],"105":[2,23],"107":[2,23],"108":[2,23],"109":[2,23],"113":[2,23],"121":[2,23],"130":[2,23],"131":[2,23],"133":[2,23],"134":[2,23],"135":[2,23],"136":[2,23],"137":[2,23],"138":[2,23],"139":[2,23],"140":[2,23],"141":[2,23],"142":[2,23],"144":[2,23]},{"1":[2,24],"4":[2,24],"29":[2,24],"30":[2,24],"47":[2,24],"55":[2,24],"59":[2,24],"75":[2,24],"80":[2,24],"90":[2,24],"94":[2,24],"96":[2,24],"105":[2,24],"107":[2,24],"108":[2,24],"109":[2,24],"113":[2,24],"121":[2,24],"130":[2,24],"131":[2,24],"133":[2,24],"134":[2,24],"135":[2,24],"136":[2,24],"137":[2,24],"138":[2,24],"139":[2,24],"140":[2,24],"141":[2,24],"142":[2,24],"144":[2,24]},{"1":[2,25],"4":[2,25],"29":[2,25],"30":[2,25],"47":[2,25],"55":[2,25],"59":[2,25],"75":[2,25],"80":[2,25],"90":[2,25],"94":[2,25],"96":[2,25],"105":[2,25],"107":[2,25],"108":[2,25],"109":[2,25],"113":[2,25],"121":[2,25],"130":[2,25],"131":[2,25],"133":[2,25],"134":[2,25],"135":[2,25],"136":[2,25],"137":[2,25],"138":[2,25],"139":[2,25],"140":[2,25],"141":[2,25],"142":[2,25],"144":[2,25]},{"1":[2,26],"4":[2,26],"29":[2,26],"30":[2,26],"47":[2,26],"55":[2,26],"59":[2,26],"75":[2,26],"80":[2,26],"90":[2,26],"94":[2,26],"96":[2,26],"105":[2,26],"107":[2,26],"108":[2,26],"109":[2,26],"113":[2,26],"121":[2,26],"130":[2,26],"131":[2,26],"133":[2,26],"134":[2,26],"135":[2,26],"136":[2,26],"137":[2,26],"138":[2,26],"139":[2,26],"140":[2,26],"141":[2,26],"142":[2,26],"144":[2,26]},{"1":[2,27],"4":[2,27],"29":[2,27],"30":[2,27],"47":[2,27],"55":[2,27],"59":[2,27],"75":[2,27],"80":[2,27],"90":[2,27],"94":[2,27],"96":[2,27],"105":[2,27],"107":[2,27],"108":[2,27],"109":[2,27],"113":[2,27],"121":[2,27],"130":[2,27],"131":[2,27],"133":[2,27],"134":[2,27],"135":[2,27],"136":[2,27],"137":[2,27],"138":[2,27],"139":[2,27],"140":[2,27],"141":[2,27],"142":[2,27],"144":[2,27]},{"1":[2,28],"4":[2,28],"29":[2,28],"30":[2,28],"47":[2,28],"55":[2,28],"59":[2,28],"75":[2,28],"80":[2,28],"90":[2,28],"94":[2,28],"96":[2,28],"105":[2,28],"107":[2,28],"108":[2,28],"109":[2,28],"113":[2,28],"121":[2,28],"130":[2,28],"131":[2,28],"133":[2,28],"134":[2,28],"135":[2,28],"136":[2,28],"137":[2,28],"138":[2,28],"139":[2,28],"140":[2,28],"141":[2,28],"142":[2,28],"144":[2,28]},{"1":[2,10],"4":[2,10],"30":[2,10],"105":[2,10],"107":[2,10],"109":[2,10],"113":[2,10],"130":[2,10],"131":[2,10]},{"1":[2,11],"4":[2,11],"30":[2,11],"105":[2,11],"107":[2,11],"109":[2,11],"113":[2,11],"130":[2,11],"131":[2,11]},{"1":[2,12],"4":[2,12],"30":[2,12],"105":[2,12],"107":[2,12],"109":[2,12],"113":[2,12],"130":[2,12],"131":[2,12]},{"1":[2,13],"4":[2,13],"30":[2,13],"105":[2,13],"107":[2,13],"109":[2,13],"113":[2,13],"130":[2,13],"131":[2,13]},{"1":[2,14],"4":[2,14],"30":[2,14],"105":[2,14],"107":[2,14],"109":[2,14],"113":[2,14],"130":[2,14],"131":[2,14]},{"1":[2,74],"4":[2,74],"29":[2,74],"30":[2,74],"41":[1,117],"47":[2,74],"55":[2,74],"59":[2,74],"68":[2,74],"69":[2,74],"70":[2,74],"71":[2,74],"74":[2,74],"75":[2,74],"76":[2,74],"77":[2,74],"80":[2,74],"88":[2,74],"89":[2,74],"90":[2,74],"94":[2,74],"96":[2,74],"105":[2,74],"107":[2,74],"108":[2,74],"109":[2,74],"113":[2,74],"121":[2,74],"130":[2,74],"131":[2,74],"133":[2,74],"134":[2,74],"135":[2,74],"136":[2,74],"137":[2,74],"138":[2,74],"139":[2,74],"140":[2,74],"141":[2,74],"142":[2,74],"143":[2,74],"144":[2,74]},{"1":[2,75],"4":[2,75],"29":[2,75],"30":[2,75],"47":[2,75],"55":[2,75],"59":[2,75],"68":[2,75],"69":[2,75],"70":[2,75],"71":[2,75],"74":[2,75],"75":[2,75],"76":[2,75],"77":[2,75],"80":[2,75],"88":[2,75],"89":[2,75],"90":[2,75],"94":[2,75],"96":[2,75],"105":[2,75],"107":[2,75],"108":[2,75],"109":[2,75],"113":[2,75],"121":[2,75],"130":[2,75],"131":[2,75],"133":[2,75],"134":[2,75],"135":[2,75],"136":[2,75],"137":[2,75],"138":[2,75],"139":[2,75],"140":[2,75],"141":[2,75],"142":[2,75],"143":[2,75],"144":[2,75]},{"1":[2,76],"4":[2,76],"29":[2,76],"30":[2,76],"47":[2,76],"55":[2,76],"59":[2,76],"68":[2,76],"69":[2,76],"70":[2,76],"71":[2,76],"74":[2,76],"75":[2,76],"76":[2,76],"77":[2,76],"80":[2,76],"88":[2,76],"89":[2,76],"90":[2,76],"94":[2,76],"96":[2,76],"105":[2,76],"107":[2,76],"108":[2,76],"109":[2,76],"113":[2,76],"121":[2,76],"130":[2,76],"131":[2,76],"133":[2,76],"134":[2,76],"135":[2,76],"136":[2,76],"137":[2,76],"138":[2,76],"139":[2,76],"140":[2,76],"141":[2,76],"142":[2,76],"143":[2,76],"144":[2,76]},{"1":[2,77],"4":[2,77],"29":[2,77],"30":[2,77],"47":[2,77],"55":[2,77],"59":[2,77],"68":[2,77],"69":[2,77],"70":[2,77],"71":[2,77],"74":[2,77],"75":[2,77],"76":[2,77],"77":[2,77],"80":[2,77],"88":[2,77],"89":[2,77],"90":[2,77],"94":[2,77],"96":[2,77],"105":[2,77],"107":[2,77],"108":[2,77],"109":[2,77],"113":[2,77],"121":[2,77],"130":[2,77],"131":[2,77],"133":[2,77],"134":[2,77],"135":[2,77],"136":[2,77],"137":[2,77],"138":[2,77],"139":[2,77],"140":[2,77],"141":[2,77],"142":[2,77],"143":[2,77],"144":[2,77]},{"1":[2,78],"4":[2,78],"29":[2,78],"30":[2,78],"47":[2,78],"55":[2,78],"59":[2,78],"68":[2,78],"69":[2,78],"70":[2,78],"71":[2,78],"74":[2,78],"75":[2,78],"76":[2,78],"77":[2,78],"80":[2,78],"88":[2,78],"89":[2,78],"90":[2,78],"94":[2,78],"96":[2,78],"105":[2,78],"107":[2,78],"108":[2,78],"109":[2,78],"113":[2,78],"121":[2,78],"130":[2,78],"131":[2,78],"133":[2,78],"134":[2,78],"135":[2,78],"136":[2,78],"137":[2,78],"138":[2,78],"139":[2,78],"140":[2,78],"141":[2,78],"142":[2,78],"143":[2,78],"144":[2,78]},{"1":[2,112],"4":[2,112],"29":[2,112],"30":[2,112],"47":[2,112],"55":[2,112],"59":[2,112],"68":[2,112],"69":[2,112],"70":[2,112],"71":[2,112],"74":[2,112],"75":[2,112],"76":[2,112],"77":[2,112],"80":[2,112],"86":118,"88":[2,112],"89":[1,119],"90":[2,112],"94":[2,112],"96":[2,112],"105":[2,112],"107":[2,112],"108":[2,112],"109":[2,112],"113":[2,112],"121":[2,112],"130":[2,112],"131":[2,112],"133":[2,112],"134":[2,112],"135":[2,112],"136":[2,112],"137":[2,112],"138":[2,112],"139":[2,112],"140":[2,112],"141":[2,112],"142":[2,112],"144":[2,112]},{"49":120,"50":[2,59],"55":[2,59],"56":121,"57":[1,122],"58":[1,123]},{"4":[1,125],"6":124,"29":[1,6]},{"8":126,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":128,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":129,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":130,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":131,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,187],"4":[2,187],"29":[2,187],"30":[2,187],"47":[2,187],"55":[2,187],"59":[2,187],"75":[2,187],"80":[2,187],"90":[2,187],"94":[2,187],"96":[2,187],"105":[2,187],"107":[2,187],"108":[2,187],"109":[2,187],"113":[2,187],"121":[2,187],"124":[1,132],"130":[2,187],"131":[2,187],"133":[2,187],"134":[2,187],"135":[2,187],"136":[2,187],"137":[2,187],"138":[2,187],"139":[2,187],"140":[2,187],"141":[2,187],"142":[2,187],"144":[2,187]},{"4":[1,125],"6":133,"29":[1,6]},{"4":[1,125],"6":134,"29":[1,6]},{"1":[2,153],"4":[2,153],"29":[2,153],"30":[2,153],"47":[2,153],"55":[2,153],"59":[2,153],"75":[2,153],"80":[2,153],"90":[2,153],"94":[2,153],"96":[2,153],"105":[2,153],"107":[2,153],"108":[2,153],"109":[2,153],"113":[2,153],"121":[2,153],"130":[2,153],"131":[2,153],"133":[2,153],"134":[2,153],"135":[2,153],"136":[2,153],"137":[2,153],"138":[2,153],"139":[2,153],"140":[2,153],"141":[2,153],"142":[2,153],"144":[2,153]},{"4":[1,125],"6":135,"29":[1,6]},{"8":136,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,137],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,71],"4":[2,71],"29":[2,71],"30":[2,71],"41":[2,71],"47":[2,71],"55":[2,71],"59":[2,71],"68":[2,71],"69":[2,71],"70":[2,71],"71":[2,71],"74":[2,71],"75":[2,71],"76":[2,71],"77":[2,71],"80":[2,71],"82":[1,138],"88":[2,71],"89":[2,71],"90":[2,71],"94":[2,71],"96":[2,71],"105":[2,71],"107":[2,71],"108":[2,71],"109":[2,71],"113":[2,71],"121":[2,71],"130":[2,71],"131":[2,71],"133":[2,71],"134":[2,71],"135":[2,71],"136":[2,71],"137":[2,71],"138":[2,71],"139":[2,71],"140":[2,71],"141":[2,71],"142":[2,71],"143":[2,71],"144":[2,71]},{"1":[2,99],"4":[2,99],"15":142,"16":143,"29":[1,140],"30":[2,99],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":144,"43":72,"47":[2,99],"55":[2,99],"58":[1,61],"59":[2,99],"61":139,"63":52,"64":53,"65":30,"66":31,"67":32,"75":[2,99],"78":[1,73],"80":[2,99],"82":[1,141],"87":[1,33],"90":[2,99],"92":[1,60],"94":[2,99],"95":[1,59],"96":[2,99],"104":[1,58],"105":[2,99],"107":[2,99],"108":[2,99],"109":[2,99],"113":[2,99],"121":[2,99],"130":[2,99],"131":[2,99],"133":[2,99],"134":[2,99],"135":[2,99],"136":[2,99],"137":[2,99],"138":[2,99],"139":[2,99],"140":[2,99],"141":[2,99],"142":[2,99],"144":[2,99]},{"1":[2,51],"4":[2,51],"29":[2,51],"30":[2,51],"47":[2,51],"55":[2,51],"59":[2,51],"75":[2,51],"80":[2,51],"90":[2,51],"94":[2,51],"96":[2,51],"101":[2,51],"102":[2,51],"105":[2,51],"107":[2,51],"108":[2,51],"109":[2,51],"113":[2,51],"121":[2,51],"124":[2,51],"126":[2,51],"130":[2,51],"131":[2,51],"133":[2,51],"134":[2,51],"135":[2,51],"136":[2,51],"137":[2,51],"138":[2,51],"139":[2,51],"140":[2,51],"141":[2,51],"142":[2,51],"144":[2,51]},{"1":[2,50],"4":[2,50],"8":145,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"30":[2,50],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"105":[2,50],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"130":[2,50],"131":[2,50],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":146,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,72],"4":[2,72],"29":[2,72],"30":[2,72],"41":[2,72],"47":[2,72],"55":[2,72],"59":[2,72],"68":[2,72],"69":[2,72],"70":[2,72],"71":[2,72],"74":[2,72],"75":[2,72],"76":[2,72],"77":[2,72],"80":[2,72],"88":[2,72],"89":[2,72],"90":[2,72],"94":[2,72],"96":[2,72],"105":[2,72],"107":[2,72],"108":[2,72],"109":[2,72],"113":[2,72],"121":[2,72],"130":[2,72],"131":[2,72],"133":[2,72],"134":[2,72],"135":[2,72],"136":[2,72],"137":[2,72],"138":[2,72],"139":[2,72],"140":[2,72],"141":[2,72],"142":[2,72],"143":[2,72],"144":[2,72]},{"1":[2,73],"4":[2,73],"29":[2,73],"30":[2,73],"41":[2,73],"47":[2,73],"55":[2,73],"59":[2,73],"68":[2,73],"69":[2,73],"70":[2,73],"71":[2,73],"74":[2,73],"75":[2,73],"76":[2,73],"77":[2,73],"80":[2,73],"88":[2,73],"89":[2,73],"90":[2,73],"94":[2,73],"96":[2,73],"105":[2,73],"107":[2,73],"108":[2,73],"109":[2,73],"113":[2,73],"121":[2,73],"130":[2,73],"131":[2,73],"133":[2,73],"134":[2,73],"135":[2,73],"136":[2,73],"137":[2,73],"138":[2,73],"139":[2,73],"140":[2,73],"141":[2,73],"142":[2,73],"143":[2,73],"144":[2,73]},{"1":[2,35],"4":[2,35],"29":[2,35],"30":[2,35],"47":[2,35],"55":[2,35],"59":[2,35],"68":[2,35],"69":[2,35],"70":[2,35],"71":[2,35],"74":[2,35],"75":[2,35],"76":[2,35],"77":[2,35],"80":[2,35],"88":[2,35],"89":[2,35],"90":[2,35],"94":[2,35],"96":[2,35],"105":[2,35],"107":[2,35],"108":[2,35],"109":[2,35],"113":[2,35],"121":[2,35],"130":[2,35],"131":[2,35],"133":[2,35],"134":[2,35],"135":[2,35],"136":[2,35],"137":[2,35],"138":[2,35],"139":[2,35],"140":[2,35],"141":[2,35],"142":[2,35],"143":[2,35],"144":[2,35]},{"1":[2,36],"4":[2,36],"29":[2,36],"30":[2,36],"47":[2,36],"55":[2,36],"59":[2,36],"68":[2,36],"69":[2,36],"70":[2,36],"71":[2,36],"74":[2,36],"75":[2,36],"76":[2,36],"77":[2,36],"80":[2,36],"88":[2,36],"89":[2,36],"90":[2,36],"94":[2,36],"96":[2,36],"105":[2,36],"107":[2,36],"108":[2,36],"109":[2,36],"113":[2,36],"121":[2,36],"130":[2,36],"131":[2,36],"133":[2,36],"134":[2,36],"135":[2,36],"136":[2,36],"137":[2,36],"138":[2,36],"139":[2,36],"140":[2,36],"141":[2,36],"142":[2,36],"143":[2,36],"144":[2,36]},{"1":[2,37],"4":[2,37],"29":[2,37],"30":[2,37],"47":[2,37],"55":[2,37],"59":[2,37],"68":[2,37],"69":[2,37],"70":[2,37],"71":[2,37],"74":[2,37],"75":[2,37],"76":[2,37],"77":[2,37],"80":[2,37],"88":[2,37],"89":[2,37],"90":[2,37],"94":[2,37],"96":[2,37],"105":[2,37],"107":[2,37],"108":[2,37],"109":[2,37],"113":[2,37],"121":[2,37],"130":[2,37],"131":[2,37],"133":[2,37],"134":[2,37],"135":[2,37],"136":[2,37],"137":[2,37],"138":[2,37],"139":[2,37],"140":[2,37],"141":[2,37],"142":[2,37],"143":[2,37],"144":[2,37]},{"1":[2,38],"4":[2,38],"29":[2,38],"30":[2,38],"47":[2,38],"55":[2,38],"59":[2,38],"68":[2,38],"69":[2,38],"70":[2,38],"71":[2,38],"74":[2,38],"75":[2,38],"76":[2,38],"77":[2,38],"80":[2,38],"88":[2,38],"89":[2,38],"90":[2,38],"94":[2,38],"96":[2,38],"105":[2,38],"107":[2,38],"108":[2,38],"109":[2,38],"113":[2,38],"121":[2,38],"130":[2,38],"131":[2,38],"133":[2,38],"134":[2,38],"135":[2,38],"136":[2,38],"137":[2,38],"138":[2,38],"139":[2,38],"140":[2,38],"141":[2,38],"142":[2,38],"143":[2,38],"144":[2,38]},{"7":147,"8":7,"9":8,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"105":[1,148],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":149,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,153],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"91":151,"92":[1,60],"95":[1,59],"96":[1,150],"97":152,"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,118],"4":[2,118],"29":[2,118],"30":[2,118],"47":[2,118],"55":[2,118],"59":[2,118],"68":[2,118],"69":[2,118],"70":[2,118],"71":[2,118],"74":[2,118],"75":[2,118],"76":[2,118],"77":[2,118],"80":[2,118],"88":[2,118],"89":[2,118],"90":[2,118],"94":[2,118],"96":[2,118],"105":[2,118],"107":[2,118],"108":[2,118],"109":[2,118],"113":[2,118],"121":[2,118],"130":[2,118],"131":[2,118],"133":[2,118],"134":[2,118],"135":[2,118],"136":[2,118],"137":[2,118],"138":[2,118],"139":[2,118],"140":[2,118],"141":[2,118],"142":[2,118],"143":[2,118],"144":[2,118]},{"1":[2,119],"4":[2,119],"29":[2,119],"30":[2,119],"31":155,"32":[1,76],"47":[2,119],"55":[2,119],"59":[2,119],"68":[2,119],"69":[2,119],"70":[2,119],"71":[2,119],"74":[2,119],"75":[2,119],"76":[2,119],"77":[2,119],"80":[2,119],"88":[2,119],"89":[2,119],"90":[2,119],"94":[2,119],"96":[2,119],"105":[2,119],"107":[2,119],"108":[2,119],"109":[2,119],"113":[2,119],"121":[2,119],"130":[2,119],"131":[2,119],"133":[2,119],"134":[2,119],"135":[2,119],"136":[2,119],"137":[2,119],"138":[2,119],"139":[2,119],"140":[2,119],"141":[2,119],"142":[2,119],"143":[2,119],"144":[2,119]},{"4":[2,55],"29":[2,55]},{"4":[2,56],"29":[2,56]},{"8":156,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":157,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":158,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":159,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[1,125],"6":160,"8":161,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,6],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"31":166,"32":[1,76],"63":167,"64":168,"66":162,"78":[1,73],"95":[1,59],"116":163,"117":[1,164],"118":165},{"115":169,"119":[1,170],"120":[1,171]},{"1":[2,67],"4":[2,67],"29":[2,67],"30":[2,67],"41":[2,67],"47":[2,67],"55":[2,67],"59":[2,67],"68":[2,67],"69":[2,67],"70":[2,67],"71":[2,67],"74":[2,67],"75":[2,67],"76":[2,67],"77":[2,67],"80":[2,67],"82":[2,67],"88":[2,67],"89":[2,67],"90":[2,67],"94":[2,67],"96":[2,67],"105":[2,67],"107":[2,67],"108":[2,67],"109":[2,67],"113":[2,67],"121":[2,67],"130":[2,67],"131":[2,67],"133":[2,67],"134":[2,67],"135":[2,67],"136":[2,67],"137":[2,67],"138":[2,67],"139":[2,67],"140":[2,67],"141":[2,67],"142":[2,67],"143":[2,67],"144":[2,67]},{"1":[2,70],"4":[2,70],"29":[2,70],"30":[2,70],"41":[2,70],"47":[2,70],"55":[2,70],"59":[2,70],"68":[2,70],"69":[2,70],"70":[2,70],"71":[2,70],"74":[2,70],"75":[2,70],"76":[2,70],"77":[2,70],"80":[2,70],"82":[2,70],"88":[2,70],"89":[2,70],"90":[2,70],"94":[2,70],"96":[2,70],"105":[2,70],"107":[2,70],"108":[2,70],"109":[2,70],"113":[2,70],"121":[2,70],"130":[2,70],"131":[2,70],"133":[2,70],"134":[2,70],"135":[2,70],"136":[2,70],"137":[2,70],"138":[2,70],"139":[2,70],"140":[2,70],"141":[2,70],"142":[2,70],"143":[2,70],"144":[2,70]},{"4":[2,89],"28":177,"29":[2,89],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":173,"43":176,"46":[1,49],"55":[2,89],"58":[1,178],"79":172,"80":[2,89]},{"1":[2,33],"4":[2,33],"29":[2,33],"30":[2,33],"44":[2,33],"47":[2,33],"55":[2,33],"59":[2,33],"68":[2,33],"69":[2,33],"70":[2,33],"71":[2,33],"74":[2,33],"75":[2,33],"76":[2,33],"77":[2,33],"80":[2,33],"88":[2,33],"89":[2,33],"90":[2,33],"94":[2,33],"96":[2,33],"105":[2,33],"107":[2,33],"108":[2,33],"109":[2,33],"113":[2,33],"121":[2,33],"130":[2,33],"131":[2,33],"133":[2,33],"134":[2,33],"135":[2,33],"136":[2,33],"137":[2,33],"138":[2,33],"139":[2,33],"140":[2,33],"141":[2,33],"142":[2,33],"143":[2,33],"144":[2,33]},{"1":[2,34],"4":[2,34],"29":[2,34],"30":[2,34],"44":[2,34],"47":[2,34],"55":[2,34],"59":[2,34],"68":[2,34],"69":[2,34],"70":[2,34],"71":[2,34],"74":[2,34],"75":[2,34],"76":[2,34],"77":[2,34],"80":[2,34],"88":[2,34],"89":[2,34],"90":[2,34],"94":[2,34],"96":[2,34],"105":[2,34],"107":[2,34],"108":[2,34],"109":[2,34],"113":[2,34],"121":[2,34],"130":[2,34],"131":[2,34],"133":[2,34],"134":[2,34],"135":[2,34],"136":[2,34],"137":[2,34],"138":[2,34],"139":[2,34],"140":[2,34],"141":[2,34],"142":[2,34],"143":[2,34],"144":[2,34]},{"1":[2,32],"4":[2,32],"29":[2,32],"30":[2,32],"41":[2,32],"44":[2,32],"47":[2,32],"55":[2,32],"59":[2,32],"68":[2,32],"69":[2,32],"70":[2,32],"71":[2,32],"74":[2,32],"75":[2,32],"76":[2,32],"77":[2,32],"80":[2,32],"82":[2,32],"88":[2,32],"89":[2,32],"90":[2,32],"94":[2,32],"96":[2,32],"105":[2,32],"107":[2,32],"108":[2,32],"109":[2,32],"113":[2,32],"119":[2,32],"120":[2,32],"121":[2,32],"130":[2,32],"131":[2,32],"133":[2,32],"134":[2,32],"135":[2,32],"136":[2,32],"137":[2,32],"138":[2,32],"139":[2,32],"140":[2,32],"141":[2,32],"142":[2,32],"143":[2,32],"144":[2,32]},{"1":[2,31],"4":[2,31],"29":[2,31],"30":[2,31],"47":[2,31],"55":[2,31],"59":[2,31],"75":[2,31],"80":[2,31],"90":[2,31],"94":[2,31],"96":[2,31],"101":[2,31],"102":[2,31],"105":[2,31],"107":[2,31],"108":[2,31],"109":[2,31],"113":[2,31],"121":[2,31],"124":[2,31],"126":[2,31],"130":[2,31],"131":[2,31],"133":[2,31],"134":[2,31],"135":[2,31],"136":[2,31],"137":[2,31],"138":[2,31],"139":[2,31],"140":[2,31],"141":[2,31],"142":[2,31],"144":[2,31]},{"1":[2,7],"4":[2,7],"7":179,"8":7,"9":8,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"30":[2,7],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,4]},{"4":[1,78],"30":[1,180]},{"1":[2,30],"4":[2,30],"29":[2,30],"30":[2,30],"47":[2,30],"55":[2,30],"59":[2,30],"75":[2,30],"80":[2,30],"90":[2,30],"94":[2,30],"96":[2,30],"101":[2,30],"102":[2,30],"105":[2,30],"107":[2,30],"108":[2,30],"109":[2,30],"113":[2,30],"121":[2,30],"124":[2,30],"126":[2,30],"130":[2,30],"131":[2,30],"133":[2,30],"134":[2,30],"135":[2,30],"136":[2,30],"137":[2,30],"138":[2,30],"139":[2,30],"140":[2,30],"141":[2,30],"142":[2,30],"144":[2,30]},{"1":[2,197],"4":[2,197],"29":[2,197],"30":[2,197],"47":[2,197],"55":[2,197],"59":[2,197],"75":[2,197],"80":[2,197],"90":[2,197],"94":[2,197],"96":[2,197],"105":[2,197],"107":[2,197],"108":[2,197],"109":[2,197],"113":[2,197],"121":[2,197],"130":[2,197],"131":[2,197],"133":[2,197],"134":[2,197],"135":[2,197],"136":[2,197],"137":[2,197],"138":[2,197],"139":[2,197],"140":[2,197],"141":[2,197],"142":[2,197],"144":[2,197]},{"1":[2,198],"4":[2,198],"29":[2,198],"30":[2,198],"47":[2,198],"55":[2,198],"59":[2,198],"75":[2,198],"80":[2,198],"90":[2,198],"94":[2,198],"96":[2,198],"105":[2,198],"107":[2,198],"108":[2,198],"109":[2,198],"113":[2,198],"121":[2,198],"130":[2,198],"131":[2,198],"133":[2,198],"134":[2,198],"135":[2,198],"136":[2,198],"137":[2,198],"138":[2,198],"139":[2,198],"140":[2,198],"141":[2,198],"142":[2,198],"144":[2,198]},{"8":181,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":182,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":183,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":184,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":185,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":186,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":187,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":188,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":189,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":190,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":191,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,152],"4":[2,152],"29":[2,152],"30":[2,152],"47":[2,152],"55":[2,152],"59":[2,152],"75":[2,152],"80":[2,152],"90":[2,152],"94":[2,152],"96":[2,152],"105":[2,152],"107":[2,152],"108":[2,152],"109":[2,152],"113":[2,152],"121":[2,152],"130":[2,152],"131":[2,152],"133":[2,152],"134":[2,152],"135":[2,152],"136":[2,152],"137":[2,152],"138":[2,152],"139":[2,152],"140":[2,152],"141":[2,152],"142":[2,152],"144":[2,152]},{"1":[2,157],"4":[2,157],"29":[2,157],"30":[2,157],"47":[2,157],"55":[2,157],"59":[2,157],"75":[2,157],"80":[2,157],"90":[2,157],"94":[2,157],"96":[2,157],"105":[2,157],"107":[2,157],"108":[2,157],"109":[2,157],"113":[2,157],"121":[2,157],"130":[2,157],"131":[2,157],"133":[2,157],"134":[2,157],"135":[2,157],"136":[2,157],"137":[2,157],"138":[2,157],"139":[2,157],"140":[2,157],"141":[2,157],"142":[2,157],"144":[2,157]},{"1":[2,52],"4":[2,52],"29":[2,52],"30":[2,52],"47":[2,52],"55":[2,52],"59":[2,52],"75":[2,52],"80":[2,52],"90":[2,52],"94":[2,52],"96":[2,52],"105":[2,52],"107":[2,52],"108":[2,52],"109":[2,52],"113":[2,52],"121":[2,52],"130":[2,52],"131":[2,52],"133":[2,52],"134":[2,52],"135":[2,52],"136":[2,52],"137":[2,52],"138":[2,52],"139":[2,52],"140":[2,52],"141":[2,52],"142":[2,52],"144":[2,52]},{"8":192,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":193,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,151],"4":[2,151],"29":[2,151],"30":[2,151],"47":[2,151],"55":[2,151],"59":[2,151],"75":[2,151],"80":[2,151],"90":[2,151],"94":[2,151],"96":[2,151],"105":[2,151],"107":[2,151],"108":[2,151],"109":[2,151],"113":[2,151],"121":[2,151],"130":[2,151],"131":[2,151],"133":[2,151],"134":[2,151],"135":[2,151],"136":[2,151],"137":[2,151],"138":[2,151],"139":[2,151],"140":[2,151],"141":[2,151],"142":[2,151],"144":[2,151]},{"1":[2,156],"4":[2,156],"29":[2,156],"30":[2,156],"47":[2,156],"55":[2,156],"59":[2,156],"75":[2,156],"80":[2,156],"90":[2,156],"94":[2,156],"96":[2,156],"105":[2,156],"107":[2,156],"108":[2,156],"109":[2,156],"113":[2,156],"121":[2,156],"130":[2,156],"131":[2,156],"133":[2,156],"134":[2,156],"135":[2,156],"136":[2,156],"137":[2,156],"138":[2,156],"139":[2,156],"140":[2,156],"141":[2,156],"142":[2,156],"144":[2,156]},{"86":194,"89":[1,119]},{"8":195,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,196],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,68],"4":[2,68],"29":[2,68],"30":[2,68],"41":[2,68],"47":[2,68],"55":[2,68],"59":[2,68],"68":[2,68],"69":[2,68],"70":[2,68],"71":[2,68],"74":[2,68],"75":[2,68],"76":[2,68],"77":[2,68],"80":[2,68],"82":[2,68],"88":[2,68],"89":[2,68],"90":[2,68],"94":[2,68],"96":[2,68],"105":[2,68],"107":[2,68],"108":[2,68],"109":[2,68],"113":[2,68],"121":[2,68],"130":[2,68],"131":[2,68],"133":[2,68],"134":[2,68],"135":[2,68],"136":[2,68],"137":[2,68],"138":[2,68],"139":[2,68],"140":[2,68],"141":[2,68],"142":[2,68],"143":[2,68],"144":[2,68]},{"89":[2,115]},{"31":197,"32":[1,76]},{"31":198,"32":[1,76]},{"1":[2,81],"4":[2,81],"29":[2,81],"30":[2,81],"41":[2,81],"47":[2,81],"55":[2,81],"59":[2,81],"68":[2,81],"69":[2,81],"70":[2,81],"71":[2,81],"74":[2,81],"75":[2,81],"76":[2,81],"77":[2,81],"80":[2,81],"82":[2,81],"88":[2,81],"89":[2,81],"90":[2,81],"94":[2,81],"96":[2,81],"105":[2,81],"107":[2,81],"108":[2,81],"109":[2,81],"113":[2,81],"121":[2,81],"130":[2,81],"131":[2,81],"133":[2,81],"134":[2,81],"135":[2,81],"136":[2,81],"137":[2,81],"138":[2,81],"139":[2,81],"140":[2,81],"141":[2,81],"142":[2,81],"143":[2,81],"144":[2,81]},{"31":199,"32":[1,76]},{"1":[2,83],"4":[2,83],"29":[2,83],"30":[2,83],"41":[2,83],"47":[2,83],"55":[2,83],"59":[2,83],"68":[2,83],"69":[2,83],"70":[2,83],"71":[2,83],"74":[2,83],"75":[2,83],"76":[2,83],"77":[2,83],"80":[2,83],"82":[2,83],"88":[2,83],"89":[2,83],"90":[2,83],"94":[2,83],"96":[2,83],"105":[2,83],"107":[2,83],"108":[2,83],"109":[2,83],"113":[2,83],"121":[2,83],"130":[2,83],"131":[2,83],"133":[2,83],"134":[2,83],"135":[2,83],"136":[2,83],"137":[2,83],"138":[2,83],"139":[2,83],"140":[2,83],"141":[2,83],"142":[2,83],"143":[2,83],"144":[2,83]},{"1":[2,84],"4":[2,84],"29":[2,84],"30":[2,84],"41":[2,84],"47":[2,84],"55":[2,84],"59":[2,84],"68":[2,84],"69":[2,84],"70":[2,84],"71":[2,84],"74":[2,84],"75":[2,84],"76":[2,84],"77":[2,84],"80":[2,84],"82":[2,84],"88":[2,84],"89":[2,84],"90":[2,84],"94":[2,84],"96":[2,84],"105":[2,84],"107":[2,84],"108":[2,84],"109":[2,84],"113":[2,84],"121":[2,84],"130":[2,84],"131":[2,84],"133":[2,84],"134":[2,84],"135":[2,84],"136":[2,84],"137":[2,84],"138":[2,84],"139":[2,84],"140":[2,84],"141":[2,84],"142":[2,84],"143":[2,84],"144":[2,84]},{"8":200,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"59":[1,203],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"93":201,"94":[1,202],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"72":204,"74":[1,205],"76":[1,113],"77":[1,114]},{"72":206,"74":[1,205],"76":[1,113],"77":[1,114]},{"86":207,"89":[1,119]},{"1":[2,69],"4":[2,69],"29":[2,69],"30":[2,69],"41":[2,69],"47":[2,69],"55":[2,69],"59":[2,69],"68":[2,69],"69":[2,69],"70":[2,69],"71":[2,69],"74":[2,69],"75":[2,69],"76":[2,69],"77":[2,69],"80":[2,69],"82":[2,69],"88":[2,69],"89":[2,69],"90":[2,69],"94":[2,69],"96":[2,69],"105":[2,69],"107":[2,69],"108":[2,69],"109":[2,69],"113":[2,69],"121":[2,69],"130":[2,69],"131":[2,69],"133":[2,69],"134":[2,69],"135":[2,69],"136":[2,69],"137":[2,69],"138":[2,69],"139":[2,69],"140":[2,69],"141":[2,69],"142":[2,69],"143":[2,69],"144":[2,69]},{"8":208,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,209],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,113],"4":[2,113],"29":[2,113],"30":[2,113],"47":[2,113],"55":[2,113],"59":[2,113],"68":[2,113],"69":[2,113],"70":[2,113],"71":[2,113],"74":[2,113],"75":[2,113],"76":[2,113],"77":[2,113],"80":[2,113],"88":[2,113],"89":[2,113],"90":[2,113],"94":[2,113],"96":[2,113],"105":[2,113],"107":[2,113],"108":[2,113],"109":[2,113],"113":[2,113],"121":[2,113],"130":[2,113],"131":[2,113],"133":[2,113],"134":[2,113],"135":[2,113],"136":[2,113],"137":[2,113],"138":[2,113],"139":[2,113],"140":[2,113],"141":[2,113],"142":[2,113],"144":[2,113]},{"8":212,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,153],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"90":[1,210],"91":211,"92":[1,60],"95":[1,59],"97":152,"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"50":[1,213],"55":[1,214]},{"50":[2,60],"55":[2,60]},{"50":[2,62],"55":[2,62],"59":[1,215]},{"57":[1,216]},{"1":[2,54],"4":[2,54],"29":[2,54],"30":[2,54],"47":[2,54],"55":[2,54],"59":[2,54],"75":[2,54],"80":[2,54],"90":[2,54],"94":[2,54],"96":[2,54],"105":[2,54],"107":[2,54],"108":[2,54],"109":[2,54],"113":[2,54],"121":[2,54],"130":[2,54],"131":[2,54],"133":[2,54],"134":[2,54],"135":[2,54],"136":[2,54],"137":[2,54],"138":[2,54],"139":[2,54],"140":[2,54],"141":[2,54],"142":[2,54],"144":[2,54]},{"28":77,"46":[1,49]},{"1":[2,192],"4":[2,192],"29":[2,192],"30":[2,192],"47":[1,97],"55":[2,192],"59":[2,192],"75":[2,192],"80":[2,192],"90":[2,192],"94":[2,192],"96":[2,192],"105":[2,192],"106":95,"107":[2,192],"108":[2,192],"109":[2,192],"112":96,"113":[2,192],"114":70,"121":[2,192],"130":[2,192],"131":[2,192],"133":[2,192],"134":[2,192],"135":[1,82],"136":[1,83],"137":[2,192],"138":[2,192],"139":[2,192],"140":[2,192],"141":[2,192],"142":[2,192],"144":[2,192]},{"106":100,"107":[1,66],"109":[1,67],"112":101,"113":[1,69],"114":70,"130":[1,98],"131":[1,99]},{"1":[2,193],"4":[2,193],"29":[2,193],"30":[2,193],"47":[1,97],"55":[2,193],"59":[2,193],"75":[2,193],"80":[2,193],"90":[2,193],"94":[2,193],"96":[2,193],"105":[2,193],"106":95,"107":[2,193],"108":[2,193],"109":[2,193],"112":96,"113":[2,193],"114":70,"121":[2,193],"130":[2,193],"131":[2,193],"133":[2,193],"134":[2,193],"135":[1,82],"136":[1,83],"137":[2,193],"138":[2,193],"139":[2,193],"140":[2,193],"141":[2,193],"142":[2,193],"144":[2,193]},{"1":[2,194],"4":[2,194],"29":[2,194],"30":[2,194],"47":[1,97],"55":[2,194],"59":[2,194],"75":[2,194],"80":[2,194],"90":[2,194],"94":[2,194],"96":[2,194],"105":[2,194],"106":95,"107":[2,194],"108":[2,194],"109":[2,194],"112":96,"113":[2,194],"114":70,"121":[2,194],"130":[2,194],"131":[2,194],"133":[2,194],"134":[2,194],"135":[1,82],"136":[1,83],"137":[2,194],"138":[2,194],"139":[2,194],"140":[2,194],"141":[2,194],"142":[2,194],"144":[2,194]},{"1":[2,195],"4":[2,195],"29":[2,195],"30":[2,195],"47":[2,195],"55":[2,195],"59":[2,195],"75":[2,195],"80":[2,195],"90":[2,195],"94":[2,195],"96":[2,195],"105":[2,195],"106":95,"107":[2,195],"108":[2,195],"109":[2,195],"112":96,"113":[2,195],"114":70,"121":[2,195],"130":[2,195],"131":[2,195],"133":[2,195],"134":[2,195],"137":[2,195],"138":[2,195],"139":[2,195],"140":[2,195],"141":[2,195],"142":[2,195],"144":[2,195]},{"1":[2,196],"4":[2,196],"29":[2,196],"30":[2,196],"47":[2,196],"55":[2,196],"59":[2,196],"75":[2,196],"80":[2,196],"90":[2,196],"94":[2,196],"96":[2,196],"105":[2,196],"106":95,"107":[2,196],"108":[2,196],"109":[2,196],"112":96,"113":[2,196],"114":70,"121":[2,196],"130":[2,196],"131":[2,196],"133":[2,196],"134":[2,196],"137":[2,196],"138":[2,196],"139":[2,196],"140":[2,196],"141":[2,196],"142":[2,196],"144":[2,196]},{"4":[1,125],"6":218,"29":[1,6],"128":[1,217]},{"1":[2,138],"4":[2,138],"29":[2,138],"30":[2,138],"47":[2,138],"55":[2,138],"59":[2,138],"75":[2,138],"80":[2,138],"90":[2,138],"94":[2,138],"96":[2,138],"100":219,"101":[1,220],"102":[1,221],"105":[2,138],"107":[2,138],"108":[2,138],"109":[2,138],"113":[2,138],"121":[2,138],"130":[2,138],"131":[2,138],"133":[2,138],"134":[2,138],"135":[2,138],"136":[2,138],"137":[2,138],"138":[2,138],"139":[2,138],"140":[2,138],"141":[2,138],"142":[2,138],"144":[2,138]},{"1":[2,150],"4":[2,150],"29":[2,150],"30":[2,150],"47":[2,150],"55":[2,150],"59":[2,150],"75":[2,150],"80":[2,150],"90":[2,150],"94":[2,150],"96":[2,150],"105":[2,150],"107":[2,150],"108":[2,150],"109":[2,150],"113":[2,150],"121":[2,150],"130":[2,150],"131":[2,150],"133":[2,150],"134":[2,150],"135":[2,150],"136":[2,150],"137":[2,150],"138":[2,150],"139":[2,150],"140":[2,150],"141":[2,150],"142":[2,150],"144":[2,150]},{"1":[2,158],"4":[2,158],"29":[2,158],"30":[2,158],"47":[2,158],"55":[2,158],"59":[2,158],"75":[2,158],"80":[2,158],"90":[2,158],"94":[2,158],"96":[2,158],"105":[2,158],"107":[2,158],"108":[2,158],"109":[2,158],"113":[2,158],"121":[2,158],"130":[2,158],"131":[2,158],"133":[2,158],"134":[2,158],"135":[2,158],"136":[2,158],"137":[2,158],"138":[2,158],"139":[2,158],"140":[2,158],"141":[2,158],"142":[2,158],"144":[2,158]},{"29":[1,222],"47":[1,97],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"123":223,"125":224,"126":[1,225]},{"15":226,"16":143,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":144,"43":72,"58":[1,61],"61":227,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"87":[1,33],"92":[1,60],"95":[1,59],"104":[1,58]},{"1":[2,94],"4":[2,94],"29":[1,229],"30":[2,94],"47":[2,94],"55":[2,94],"59":[2,94],"68":[2,71],"69":[2,71],"70":[2,71],"71":[2,71],"74":[2,71],"75":[2,94],"76":[2,71],"77":[2,71],"80":[2,94],"82":[1,228],"88":[2,71],"89":[2,71],"90":[2,94],"94":[2,94],"96":[2,94],"105":[2,94],"107":[2,94],"108":[2,94],"109":[2,94],"113":[2,94],"121":[2,94],"130":[2,94],"131":[2,94],"133":[2,94],"134":[2,94],"135":[2,94],"136":[2,94],"137":[2,94],"138":[2,94],"139":[2,94],"140":[2,94],"141":[2,94],"142":[2,94],"144":[2,94]},{"4":[2,105],"28":177,"30":[2,105],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"78":[1,232],"83":230,"84":231},{"15":235,"16":143,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":144,"43":72,"58":[1,61],"61":227,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"87":[1,33],"92":[1,60],"95":[1,59],"104":[1,58]},{"62":104,"68":[1,106],"69":[1,107],"70":[1,108],"71":[1,109],"72":110,"73":111,"74":[1,112],"76":[1,113],"77":[1,114],"85":102,"88":[1,105],"89":[2,114]},{"62":116,"68":[1,106],"69":[1,107],"70":[1,108],"71":[1,109],"72":110,"73":111,"74":[1,112],"76":[1,113],"77":[1,114],"85":115,"88":[1,105],"89":[2,114]},{"1":[2,74],"4":[2,74],"29":[2,74],"30":[2,74],"47":[2,74],"55":[2,74],"59":[2,74],"68":[2,74],"69":[2,74],"70":[2,74],"71":[2,74],"74":[2,74],"75":[2,74],"76":[2,74],"77":[2,74],"80":[2,74],"88":[2,74],"89":[2,74],"90":[2,74],"94":[2,74],"96":[2,74],"105":[2,74],"107":[2,74],"108":[2,74],"109":[2,74],"113":[2,74],"121":[2,74],"130":[2,74],"131":[2,74],"133":[2,74],"134":[2,74],"135":[2,74],"136":[2,74],"137":[2,74],"138":[2,74],"139":[2,74],"140":[2,74],"141":[2,74],"142":[2,74],"144":[2,74]},{"1":[2,49],"4":[2,49],"30":[2,49],"47":[1,97],"105":[2,49],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[2,49],"131":[2,49],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,143],"4":[2,143],"30":[2,143],"47":[1,97],"105":[2,143],"106":95,"107":[2,143],"109":[2,143],"112":96,"113":[2,143],"114":70,"130":[2,143],"131":[2,143],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"105":[1,236]},{"1":[2,145],"4":[2,145],"29":[2,145],"30":[2,145],"47":[2,145],"55":[2,145],"59":[2,145],"68":[2,145],"69":[2,145],"70":[2,145],"71":[2,145],"74":[2,145],"75":[2,145],"76":[2,145],"77":[2,145],"80":[2,145],"88":[2,145],"89":[2,145],"90":[2,145],"94":[2,145],"96":[2,145],"105":[2,145],"107":[2,145],"108":[2,145],"109":[2,145],"113":[2,145],"121":[2,145],"130":[2,145],"131":[2,145],"133":[2,145],"134":[2,145],"135":[2,145],"136":[2,145],"137":[2,145],"138":[2,145],"139":[2,145],"140":[2,145],"141":[2,145],"142":[2,145],"143":[2,145],"144":[2,145]},{"4":[2,134],"29":[2,134],"47":[1,97],"55":[2,134],"59":[1,238],"93":237,"94":[1,202],"96":[2,134],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,127],"4":[2,127],"29":[2,127],"30":[2,127],"41":[2,127],"47":[2,127],"55":[2,127],"59":[2,127],"68":[2,127],"69":[2,127],"70":[2,127],"71":[2,127],"74":[2,127],"75":[2,127],"76":[2,127],"77":[2,127],"80":[2,127],"88":[2,127],"89":[2,127],"90":[2,127],"94":[2,127],"96":[2,127],"105":[2,127],"107":[2,127],"108":[2,127],"109":[2,127],"113":[2,127],"119":[2,127],"120":[2,127],"121":[2,127],"130":[2,127],"131":[2,127],"133":[2,127],"134":[2,127],"135":[2,127],"136":[2,127],"137":[2,127],"138":[2,127],"139":[2,127],"140":[2,127],"141":[2,127],"142":[2,127],"143":[2,127],"144":[2,127]},{"4":[2,57],"29":[2,57],"54":239,"55":[1,240],"96":[2,57]},{"4":[2,129],"29":[2,129],"30":[2,129],"55":[2,129],"90":[2,129],"96":[2,129]},{"8":212,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,153],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"91":241,"92":[1,60],"95":[1,59],"97":152,"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,135],"29":[2,135],"30":[2,135],"55":[2,135],"90":[2,135],"96":[2,135]},{"1":[2,122],"4":[2,122],"29":[2,122],"30":[2,122],"41":[2,122],"44":[2,122],"47":[2,122],"55":[2,122],"59":[2,122],"68":[2,122],"69":[2,122],"70":[2,122],"71":[2,122],"74":[2,122],"75":[2,122],"76":[2,122],"77":[2,122],"80":[2,122],"82":[2,122],"88":[2,122],"89":[2,122],"90":[2,122],"94":[2,122],"96":[2,122],"105":[2,122],"107":[2,122],"108":[2,122],"109":[2,122],"113":[2,122],"121":[2,122],"130":[2,122],"131":[2,122],"133":[2,122],"134":[2,122],"135":[2,122],"136":[2,122],"137":[2,122],"138":[2,122],"139":[2,122],"140":[2,122],"141":[2,122],"142":[2,122],"143":[2,122],"144":[2,122]},{"4":[1,125],"6":242,"29":[1,6],"47":[1,97],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"4":[1,125],"6":243,"29":[1,6],"47":[1,97],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,146],"4":[2,146],"29":[2,146],"30":[2,146],"47":[1,97],"55":[2,146],"59":[2,146],"75":[2,146],"80":[2,146],"90":[2,146],"94":[2,146],"96":[2,146],"105":[2,146],"106":95,"107":[1,66],"108":[1,244],"109":[1,67],"112":96,"113":[1,69],"114":70,"121":[2,146],"130":[2,146],"131":[2,146],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,148],"4":[2,148],"29":[2,148],"30":[2,148],"47":[1,97],"55":[2,148],"59":[2,148],"75":[2,148],"80":[2,148],"90":[2,148],"94":[2,148],"96":[2,148],"105":[2,148],"106":95,"107":[1,66],"108":[1,245],"109":[1,67],"112":96,"113":[1,69],"114":70,"121":[2,148],"130":[2,148],"131":[2,148],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,154],"4":[2,154],"29":[2,154],"30":[2,154],"47":[2,154],"55":[2,154],"59":[2,154],"75":[2,154],"80":[2,154],"90":[2,154],"94":[2,154],"96":[2,154],"105":[2,154],"107":[2,154],"108":[2,154],"109":[2,154],"113":[2,154],"121":[2,154],"130":[2,154],"131":[2,154],"133":[2,154],"134":[2,154],"135":[2,154],"136":[2,154],"137":[2,154],"138":[2,154],"139":[2,154],"140":[2,154],"141":[2,154],"142":[2,154],"144":[2,154]},{"1":[2,155],"4":[2,155],"29":[2,155],"30":[2,155],"47":[1,97],"55":[2,155],"59":[2,155],"75":[2,155],"80":[2,155],"90":[2,155],"94":[2,155],"96":[2,155],"105":[2,155],"106":95,"107":[1,66],"108":[2,155],"109":[1,67],"112":96,"113":[1,69],"114":70,"121":[2,155],"130":[2,155],"131":[2,155],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,159],"4":[2,159],"29":[2,159],"30":[2,159],"47":[2,159],"55":[2,159],"59":[2,159],"75":[2,159],"80":[2,159],"90":[2,159],"94":[2,159],"96":[2,159],"105":[2,159],"107":[2,159],"108":[2,159],"109":[2,159],"113":[2,159],"121":[2,159],"130":[2,159],"131":[2,159],"133":[2,159],"134":[2,159],"135":[2,159],"136":[2,159],"137":[2,159],"138":[2,159],"139":[2,159],"140":[2,159],"141":[2,159],"142":[2,159],"144":[2,159]},{"119":[2,161],"120":[2,161]},{"31":166,"32":[1,76],"63":167,"64":168,"78":[1,73],"95":[1,247],"116":246,"118":165},{"55":[1,248],"119":[2,166],"120":[2,166]},{"55":[2,163],"119":[2,163],"120":[2,163]},{"55":[2,164],"119":[2,164],"120":[2,164]},{"55":[2,165],"119":[2,165],"120":[2,165]},{"1":[2,160],"4":[2,160],"29":[2,160],"30":[2,160],"47":[2,160],"55":[2,160],"59":[2,160],"75":[2,160],"80":[2,160],"90":[2,160],"94":[2,160],"96":[2,160],"105":[2,160],"107":[2,160],"108":[2,160],"109":[2,160],"113":[2,160],"121":[2,160],"130":[2,160],"131":[2,160],"133":[2,160],"134":[2,160],"135":[2,160],"136":[2,160],"137":[2,160],"138":[2,160],"139":[2,160],"140":[2,160],"141":[2,160],"142":[2,160],"144":[2,160]},{"8":249,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":250,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,57],"29":[2,57],"54":251,"55":[1,252],"80":[2,57]},{"4":[2,90],"29":[2,90],"30":[2,90],"55":[2,90],"80":[2,90]},{"4":[2,41],"29":[2,41],"30":[2,41],"44":[1,253],"55":[2,41],"80":[2,41]},{"4":[2,42],"29":[2,42],"30":[2,42],"44":[1,254],"55":[2,42],"80":[2,42]},{"4":[2,43],"29":[2,43],"30":[2,43],"55":[2,43],"80":[2,43]},{"4":[2,48],"29":[2,48],"30":[2,48],"55":[2,48],"80":[2,48]},{"31":155,"32":[1,76]},{"1":[2,6],"4":[2,6],"30":[2,6]},{"1":[2,29],"4":[2,29],"29":[2,29],"30":[2,29],"47":[2,29],"55":[2,29],"59":[2,29],"75":[2,29],"80":[2,29],"90":[2,29],"94":[2,29],"96":[2,29],"101":[2,29],"102":[2,29],"105":[2,29],"107":[2,29],"108":[2,29],"109":[2,29],"113":[2,29],"121":[2,29],"124":[2,29],"126":[2,29],"130":[2,29],"131":[2,29],"133":[2,29],"134":[2,29],"135":[2,29],"136":[2,29],"137":[2,29],"138":[2,29],"139":[2,29],"140":[2,29],"141":[2,29],"142":[2,29],"144":[2,29]},{"1":[2,199],"4":[2,199],"29":[2,199],"30":[2,199],"47":[1,97],"55":[2,199],"59":[2,199],"75":[2,199],"80":[2,199],"90":[2,199],"94":[2,199],"96":[2,199],"105":[2,199],"106":95,"107":[2,199],"108":[2,199],"109":[2,199],"112":96,"113":[2,199],"114":70,"121":[2,199],"130":[2,199],"131":[2,199],"133":[2,199],"134":[2,199],"135":[1,82],"136":[1,83],"137":[2,199],"138":[2,199],"139":[1,88],"140":[2,199],"141":[2,199],"142":[2,199],"144":[2,199]},{"1":[2,200],"4":[2,200],"29":[2,200],"30":[2,200],"47":[1,97],"55":[2,200],"59":[2,200],"75":[2,200],"80":[2,200],"90":[2,200],"94":[2,200],"96":[2,200],"105":[2,200],"106":95,"107":[2,200],"108":[2,200],"109":[2,200],"112":96,"113":[2,200],"114":70,"121":[2,200],"130":[2,200],"131":[2,200],"133":[2,200],"134":[2,200],"135":[1,82],"136":[1,83],"137":[2,200],"138":[2,200],"139":[1,88],"140":[2,200],"141":[2,200],"142":[2,200],"144":[2,200]},{"1":[2,201],"4":[2,201],"29":[2,201],"30":[2,201],"47":[1,97],"55":[2,201],"59":[2,201],"75":[2,201],"80":[2,201],"90":[2,201],"94":[2,201],"96":[2,201],"105":[2,201],"106":95,"107":[2,201],"108":[2,201],"109":[2,201],"112":96,"113":[2,201],"114":70,"121":[2,201],"130":[2,201],"131":[2,201],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[2,201],"138":[2,201],"139":[1,88],"140":[1,89],"141":[1,90],"142":[2,201],"144":[1,92]},{"1":[2,202],"4":[2,202],"29":[2,202],"30":[2,202],"47":[1,97],"55":[2,202],"59":[2,202],"75":[2,202],"80":[2,202],"90":[2,202],"94":[2,202],"96":[2,202],"105":[2,202],"106":95,"107":[2,202],"108":[2,202],"109":[2,202],"112":96,"113":[2,202],"114":70,"121":[2,202],"130":[2,202],"131":[2,202],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[2,202],"138":[2,202],"139":[1,88],"140":[1,89],"141":[1,90],"142":[2,202],"144":[1,92]},{"1":[2,203],"4":[2,203],"29":[2,203],"30":[2,203],"47":[1,97],"55":[2,203],"59":[2,203],"75":[2,203],"80":[2,203],"90":[2,203],"94":[2,203],"96":[2,203],"105":[2,203],"106":95,"107":[2,203],"108":[2,203],"109":[2,203],"112":96,"113":[2,203],"114":70,"121":[2,203],"130":[2,203],"131":[2,203],"133":[2,203],"134":[2,203],"135":[1,82],"136":[1,83],"137":[2,203],"138":[2,203],"139":[2,203],"140":[2,203],"141":[2,203],"142":[2,203],"144":[2,203]},{"1":[2,204],"4":[2,204],"29":[2,204],"30":[2,204],"47":[1,97],"55":[2,204],"59":[2,204],"75":[2,204],"80":[2,204],"90":[2,204],"94":[2,204],"96":[2,204],"105":[2,204],"106":95,"107":[2,204],"108":[2,204],"109":[2,204],"112":96,"113":[2,204],"114":70,"121":[2,204],"130":[2,204],"131":[2,204],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[2,204],"138":[2,204],"139":[1,88],"140":[2,204],"141":[2,204],"142":[2,204],"144":[2,204]},{"1":[2,205],"4":[2,205],"29":[2,205],"30":[2,205],"47":[1,97],"55":[2,205],"59":[2,205],"75":[2,205],"80":[2,205],"90":[2,205],"94":[2,205],"96":[2,205],"105":[2,205],"106":95,"107":[2,205],"108":[2,205],"109":[2,205],"112":96,"113":[2,205],"114":70,"121":[2,205],"130":[2,205],"131":[2,205],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[2,205],"138":[2,205],"139":[1,88],"140":[1,89],"141":[2,205],"142":[2,205],"144":[2,205]},{"1":[2,206],"4":[2,206],"29":[2,206],"30":[2,206],"47":[1,97],"55":[2,206],"59":[2,206],"75":[2,206],"80":[2,206],"90":[2,206],"94":[2,206],"96":[2,206],"105":[2,206],"106":95,"107":[2,206],"108":[2,206],"109":[2,206],"112":96,"113":[2,206],"114":70,"121":[2,206],"130":[2,206],"131":[2,206],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[2,206],"144":[1,92]},{"1":[2,209],"4":[2,209],"29":[2,209],"30":[2,209],"47":[1,97],"55":[2,209],"59":[2,209],"75":[2,209],"80":[2,209],"90":[2,209],"94":[2,209],"96":[2,209],"105":[2,209],"106":95,"107":[2,209],"108":[2,209],"109":[2,209],"112":96,"113":[2,209],"114":70,"121":[2,209],"130":[2,209],"131":[2,209],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[2,209],"138":[2,209],"139":[1,88],"140":[1,89],"141":[1,90],"142":[2,209],"144":[2,209]},{"1":[2,189],"4":[2,189],"29":[2,189],"30":[2,189],"47":[1,97],"55":[2,189],"59":[2,189],"75":[2,189],"80":[2,189],"90":[2,189],"94":[2,189],"96":[2,189],"105":[2,189],"106":95,"107":[1,66],"108":[2,189],"109":[1,67],"112":96,"113":[1,69],"114":70,"121":[2,189],"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,191],"4":[2,191],"29":[2,191],"30":[2,191],"47":[1,97],"55":[2,191],"59":[2,191],"75":[2,191],"80":[2,191],"90":[2,191],"94":[2,191],"96":[2,191],"105":[2,191],"106":95,"107":[1,66],"108":[2,191],"109":[1,67],"112":96,"113":[1,69],"114":70,"121":[2,191],"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,188],"4":[2,188],"29":[2,188],"30":[2,188],"47":[1,97],"55":[2,188],"59":[2,188],"75":[2,188],"80":[2,188],"90":[2,188],"94":[2,188],"96":[2,188],"105":[2,188],"106":95,"107":[1,66],"108":[2,188],"109":[1,67],"112":96,"113":[1,69],"114":70,"121":[2,188],"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,190],"4":[2,190],"29":[2,190],"30":[2,190],"47":[1,97],"55":[2,190],"59":[2,190],"75":[2,190],"80":[2,190],"90":[2,190],"94":[2,190],"96":[2,190],"105":[2,190],"106":95,"107":[1,66],"108":[2,190],"109":[1,67],"112":96,"113":[1,69],"114":70,"121":[2,190],"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,110],"4":[2,110],"29":[2,110],"30":[2,110],"47":[2,110],"55":[2,110],"59":[2,110],"68":[2,110],"69":[2,110],"70":[2,110],"71":[2,110],"74":[2,110],"75":[2,110],"76":[2,110],"77":[2,110],"80":[2,110],"88":[2,110],"89":[2,110],"90":[2,110],"94":[2,110],"96":[2,110],"105":[2,110],"107":[2,110],"108":[2,110],"109":[2,110],"113":[2,110],"121":[2,110],"130":[2,110],"131":[2,110],"133":[2,110],"134":[2,110],"135":[2,110],"136":[2,110],"137":[2,110],"138":[2,110],"139":[2,110],"140":[2,110],"141":[2,110],"142":[2,110],"144":[2,110]},{"1":[2,207],"4":[2,207],"29":[2,207],"30":[2,207],"47":[1,97],"55":[2,207],"59":[2,207],"75":[2,207],"80":[2,207],"90":[2,207],"94":[2,207],"96":[2,207],"105":[2,207],"106":95,"107":[2,207],"108":[2,207],"109":[2,207],"112":96,"113":[2,207],"114":70,"121":[2,207],"130":[2,207],"131":[2,207],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"8":255,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,79],"4":[2,79],"29":[2,79],"30":[2,79],"41":[2,79],"47":[2,79],"55":[2,79],"59":[2,79],"68":[2,79],"69":[2,79],"70":[2,79],"71":[2,79],"74":[2,79],"75":[2,79],"76":[2,79],"77":[2,79],"80":[2,79],"82":[2,79],"88":[2,79],"89":[2,79],"90":[2,79],"94":[2,79],"96":[2,79],"105":[2,79],"107":[2,79],"108":[2,79],"109":[2,79],"113":[2,79],"121":[2,79],"130":[2,79],"131":[2,79],"133":[2,79],"134":[2,79],"135":[2,79],"136":[2,79],"137":[2,79],"138":[2,79],"139":[2,79],"140":[2,79],"141":[2,79],"142":[2,79],"143":[2,79],"144":[2,79]},{"1":[2,80],"4":[2,80],"29":[2,80],"30":[2,80],"41":[2,80],"47":[2,80],"55":[2,80],"59":[2,80],"68":[2,80],"69":[2,80],"70":[2,80],"71":[2,80],"74":[2,80],"75":[2,80],"76":[2,80],"77":[2,80],"80":[2,80],"82":[2,80],"88":[2,80],"89":[2,80],"90":[2,80],"94":[2,80],"96":[2,80],"105":[2,80],"107":[2,80],"108":[2,80],"109":[2,80],"113":[2,80],"121":[2,80],"130":[2,80],"131":[2,80],"133":[2,80],"134":[2,80],"135":[2,80],"136":[2,80],"137":[2,80],"138":[2,80],"139":[2,80],"140":[2,80],"141":[2,80],"142":[2,80],"143":[2,80],"144":[2,80]},{"1":[2,82],"4":[2,82],"29":[2,82],"30":[2,82],"41":[2,82],"47":[2,82],"55":[2,82],"59":[2,82],"68":[2,82],"69":[2,82],"70":[2,82],"71":[2,82],"74":[2,82],"75":[2,82],"76":[2,82],"77":[2,82],"80":[2,82],"82":[2,82],"88":[2,82],"89":[2,82],"90":[2,82],"94":[2,82],"96":[2,82],"105":[2,82],"107":[2,82],"108":[2,82],"109":[2,82],"113":[2,82],"121":[2,82],"130":[2,82],"131":[2,82],"133":[2,82],"134":[2,82],"135":[2,82],"136":[2,82],"137":[2,82],"138":[2,82],"139":[2,82],"140":[2,82],"141":[2,82],"142":[2,82],"143":[2,82],"144":[2,82]},{"47":[1,97],"59":[1,203],"75":[1,256],"93":257,"94":[1,202],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"8":258,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"12":[2,120],"13":[2,120],"14":[2,120],"32":[2,120],"34":[2,120],"35":[2,120],"37":[2,120],"38":[2,120],"39":[2,120],"45":[2,120],"46":[2,120],"48":[2,120],"52":[2,120],"53":[2,120],"58":[2,120],"75":[2,120],"78":[2,120],"81":[2,120],"87":[2,120],"92":[2,120],"95":[2,120],"99":[2,120],"103":[2,120],"104":[2,120],"107":[2,120],"109":[2,120],"111":[2,120],"113":[2,120],"122":[2,120],"128":[2,120],"129":[2,120],"132":[2,120],"133":[2,120],"134":[2,120],"135":[2,120],"136":[2,120]},{"12":[2,121],"13":[2,121],"14":[2,121],"32":[2,121],"34":[2,121],"35":[2,121],"37":[2,121],"38":[2,121],"39":[2,121],"45":[2,121],"46":[2,121],"48":[2,121],"52":[2,121],"53":[2,121],"58":[2,121],"75":[2,121],"78":[2,121],"81":[2,121],"87":[2,121],"92":[2,121],"95":[2,121],"99":[2,121],"103":[2,121],"104":[2,121],"107":[2,121],"109":[2,121],"111":[2,121],"113":[2,121],"122":[2,121],"128":[2,121],"129":[2,121],"132":[2,121],"133":[2,121],"134":[2,121],"135":[2,121],"136":[2,121]},{"1":[2,86],"4":[2,86],"29":[2,86],"30":[2,86],"41":[2,86],"47":[2,86],"55":[2,86],"59":[2,86],"68":[2,86],"69":[2,86],"70":[2,86],"71":[2,86],"74":[2,86],"75":[2,86],"76":[2,86],"77":[2,86],"80":[2,86],"82":[2,86],"88":[2,86],"89":[2,86],"90":[2,86],"94":[2,86],"96":[2,86],"105":[2,86],"107":[2,86],"108":[2,86],"109":[2,86],"113":[2,86],"121":[2,86],"130":[2,86],"131":[2,86],"133":[2,86],"134":[2,86],"135":[2,86],"136":[2,86],"137":[2,86],"138":[2,86],"139":[2,86],"140":[2,86],"141":[2,86],"142":[2,86],"143":[2,86],"144":[2,86]},{"8":259,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,87],"4":[2,87],"29":[2,87],"30":[2,87],"41":[2,87],"47":[2,87],"55":[2,87],"59":[2,87],"68":[2,87],"69":[2,87],"70":[2,87],"71":[2,87],"74":[2,87],"75":[2,87],"76":[2,87],"77":[2,87],"80":[2,87],"82":[2,87],"88":[2,87],"89":[2,87],"90":[2,87],"94":[2,87],"96":[2,87],"105":[2,87],"107":[2,87],"108":[2,87],"109":[2,87],"113":[2,87],"121":[2,87],"130":[2,87],"131":[2,87],"133":[2,87],"134":[2,87],"135":[2,87],"136":[2,87],"137":[2,87],"138":[2,87],"139":[2,87],"140":[2,87],"141":[2,87],"142":[2,87],"143":[2,87],"144":[2,87]},{"1":[2,111],"4":[2,111],"29":[2,111],"30":[2,111],"47":[2,111],"55":[2,111],"59":[2,111],"68":[2,111],"69":[2,111],"70":[2,111],"71":[2,111],"74":[2,111],"75":[2,111],"76":[2,111],"77":[2,111],"80":[2,111],"88":[2,111],"89":[2,111],"90":[2,111],"94":[2,111],"96":[2,111],"105":[2,111],"107":[2,111],"108":[2,111],"109":[2,111],"113":[2,111],"121":[2,111],"130":[2,111],"131":[2,111],"133":[2,111],"134":[2,111],"135":[2,111],"136":[2,111],"137":[2,111],"138":[2,111],"139":[2,111],"140":[2,111],"141":[2,111],"142":[2,111],"144":[2,111]},{"1":[2,39],"4":[2,39],"29":[2,39],"30":[2,39],"47":[1,97],"55":[2,39],"59":[2,39],"75":[2,39],"80":[2,39],"90":[2,39],"94":[2,39],"96":[2,39],"105":[2,39],"106":95,"107":[1,66],"108":[2,39],"109":[1,67],"112":96,"113":[1,69],"114":70,"121":[2,39],"130":[2,39],"131":[2,39],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"8":260,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,116],"4":[2,116],"29":[2,116],"30":[2,116],"47":[2,116],"55":[2,116],"59":[2,116],"68":[2,116],"69":[2,116],"70":[2,116],"71":[2,116],"74":[2,116],"75":[2,116],"76":[2,116],"77":[2,116],"80":[2,116],"88":[2,116],"89":[2,116],"90":[2,116],"94":[2,116],"96":[2,116],"105":[2,116],"107":[2,116],"108":[2,116],"109":[2,116],"113":[2,116],"121":[2,116],"130":[2,116],"131":[2,116],"133":[2,116],"134":[2,116],"135":[2,116],"136":[2,116],"137":[2,116],"138":[2,116],"139":[2,116],"140":[2,116],"141":[2,116],"142":[2,116],"144":[2,116]},{"4":[2,57],"29":[2,57],"54":261,"55":[1,240],"90":[2,57]},{"4":[2,134],"29":[2,134],"30":[2,134],"47":[1,97],"55":[2,134],"59":[1,262],"90":[2,134],"96":[2,134],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"51":263,"52":[1,62],"53":[1,63]},{"56":264,"57":[1,122],"58":[1,123]},{"50":[2,64],"55":[2,64]},{"50":[2,63],"55":[2,63],"59":[1,265]},{"8":266,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,186],"4":[2,186],"29":[2,186],"30":[2,186],"47":[2,186],"55":[2,186],"59":[2,186],"75":[2,186],"80":[2,186],"90":[2,186],"94":[2,186],"96":[2,186],"105":[2,186],"107":[2,186],"108":[2,186],"109":[2,186],"113":[2,186],"121":[2,186],"124":[2,186],"130":[2,186],"131":[2,186],"133":[2,186],"134":[2,186],"135":[2,186],"136":[2,186],"137":[2,186],"138":[2,186],"139":[2,186],"140":[2,186],"141":[2,186],"142":[2,186],"144":[2,186]},{"1":[2,139],"4":[2,139],"29":[2,139],"30":[2,139],"47":[2,139],"55":[2,139],"59":[2,139],"75":[2,139],"80":[2,139],"90":[2,139],"94":[2,139],"96":[2,139],"101":[1,267],"105":[2,139],"107":[2,139],"108":[2,139],"109":[2,139],"113":[2,139],"121":[2,139],"130":[2,139],"131":[2,139],"133":[2,139],"134":[2,139],"135":[2,139],"136":[2,139],"137":[2,139],"138":[2,139],"139":[2,139],"140":[2,139],"141":[2,139],"142":[2,139],"144":[2,139]},{"4":[1,125],"6":268,"29":[1,6]},{"31":269,"32":[1,76]},{"123":270,"125":224,"126":[1,225]},{"30":[1,271],"124":[1,272],"125":273,"126":[1,225]},{"30":[2,179],"124":[2,179],"126":[2,179]},{"8":275,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"98":274,"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,109],"4":[2,109],"29":[2,109],"30":[2,109],"47":[2,109],"55":[2,109],"59":[2,109],"62":104,"68":[1,106],"69":[1,107],"70":[1,108],"71":[1,109],"72":110,"73":111,"74":[1,112],"75":[2,109],"76":[1,113],"77":[1,114],"80":[2,109],"85":102,"88":[1,105],"89":[2,114],"90":[2,109],"94":[2,109],"96":[2,109],"105":[2,109],"107":[2,109],"108":[2,109],"109":[2,109],"113":[2,109],"121":[2,109],"130":[2,109],"131":[2,109],"133":[2,109],"134":[2,109],"135":[2,109],"136":[2,109],"137":[2,109],"138":[2,109],"139":[2,109],"140":[2,109],"141":[2,109],"142":[2,109],"144":[2,109]},{"1":[2,71],"4":[2,71],"29":[2,71],"30":[2,71],"47":[2,71],"55":[2,71],"59":[2,71],"68":[2,71],"69":[2,71],"70":[2,71],"71":[2,71],"74":[2,71],"75":[2,71],"76":[2,71],"77":[2,71],"80":[2,71],"88":[2,71],"89":[2,71],"90":[2,71],"94":[2,71],"96":[2,71],"105":[2,71],"107":[2,71],"108":[2,71],"109":[2,71],"113":[2,71],"121":[2,71],"130":[2,71],"131":[2,71],"133":[2,71],"134":[2,71],"135":[2,71],"136":[2,71],"137":[2,71],"138":[2,71],"139":[2,71],"140":[2,71],"141":[2,71],"142":[2,71],"144":[2,71]},{"15":276,"16":143,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":144,"43":72,"58":[1,61],"61":227,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"87":[1,33],"92":[1,60],"95":[1,59],"104":[1,58]},{"4":[2,105],"28":177,"30":[2,105],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"78":[1,232],"83":277,"84":231},{"4":[1,279],"30":[1,278]},{"4":[2,106],"30":[2,106],"80":[2,106]},{"4":[2,105],"28":177,"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"78":[1,232],"80":[2,105],"83":280,"84":231},{"4":[2,102],"30":[2,102],"80":[2,102]},{"4":[2,43],"30":[2,43],"44":[1,281],"80":[2,43]},{"1":[2,100],"4":[2,100],"29":[1,282],"30":[2,100],"47":[2,100],"55":[2,100],"59":[2,100],"62":104,"68":[1,106],"69":[1,107],"70":[1,108],"71":[1,109],"72":110,"73":111,"74":[1,112],"75":[2,100],"76":[1,113],"77":[1,114],"80":[2,100],"85":102,"88":[1,105],"89":[2,114],"90":[2,100],"94":[2,100],"96":[2,100],"105":[2,100],"107":[2,100],"108":[2,100],"109":[2,100],"113":[2,100],"121":[2,100],"130":[2,100],"131":[2,100],"133":[2,100],"134":[2,100],"135":[2,100],"136":[2,100],"137":[2,100],"138":[2,100],"139":[2,100],"140":[2,100],"141":[2,100],"142":[2,100],"144":[2,100]},{"1":[2,144],"4":[2,144],"29":[2,144],"30":[2,144],"47":[2,144],"55":[2,144],"59":[2,144],"68":[2,144],"69":[2,144],"70":[2,144],"71":[2,144],"74":[2,144],"75":[2,144],"76":[2,144],"77":[2,144],"80":[2,144],"88":[2,144],"89":[2,144],"90":[2,144],"94":[2,144],"96":[2,144],"105":[2,144],"107":[2,144],"108":[2,144],"109":[2,144],"113":[2,144],"121":[2,144],"130":[2,144],"131":[2,144],"133":[2,144],"134":[2,144],"135":[2,144],"136":[2,144],"137":[2,144],"138":[2,144],"139":[2,144],"140":[2,144],"141":[2,144],"142":[2,144],"143":[2,144],"144":[2,144]},{"8":283,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,66],"12":[2,121],"13":[2,121],"14":[2,121],"29":[2,66],"32":[2,121],"34":[2,121],"35":[2,121],"37":[2,121],"38":[2,121],"39":[2,121],"45":[2,121],"46":[2,121],"48":[2,121],"52":[2,121],"53":[2,121],"55":[2,66],"58":[2,121],"78":[2,121],"81":[2,121],"87":[2,121],"92":[2,121],"95":[2,121],"96":[2,66],"99":[2,121],"103":[2,121],"104":[2,121],"107":[2,121],"109":[2,121],"111":[2,121],"113":[2,121],"122":[2,121],"128":[2,121],"129":[2,121],"132":[2,121],"133":[2,121],"134":[2,121],"135":[2,121],"136":[2,121]},{"4":[1,285],"29":[1,286],"96":[1,284]},{"4":[2,58],"8":212,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[2,58],"30":[2,58],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"90":[2,58],"92":[1,60],"95":[1,59],"96":[2,58],"97":287,"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,57],"29":[2,57],"30":[2,57],"54":288,"55":[1,240]},{"1":[2,183],"4":[2,183],"29":[2,183],"30":[2,183],"47":[2,183],"55":[2,183],"59":[2,183],"75":[2,183],"80":[2,183],"90":[2,183],"94":[2,183],"96":[2,183],"105":[2,183],"107":[2,183],"108":[2,183],"109":[2,183],"113":[2,183],"121":[2,183],"124":[2,183],"130":[2,183],"131":[2,183],"133":[2,183],"134":[2,183],"135":[2,183],"136":[2,183],"137":[2,183],"138":[2,183],"139":[2,183],"140":[2,183],"141":[2,183],"142":[2,183],"144":[2,183]},{"1":[2,184],"4":[2,184],"29":[2,184],"30":[2,184],"47":[2,184],"55":[2,184],"59":[2,184],"75":[2,184],"80":[2,184],"90":[2,184],"94":[2,184],"96":[2,184],"105":[2,184],"107":[2,184],"108":[2,184],"109":[2,184],"113":[2,184],"121":[2,184],"124":[2,184],"130":[2,184],"131":[2,184],"133":[2,184],"134":[2,184],"135":[2,184],"136":[2,184],"137":[2,184],"138":[2,184],"139":[2,184],"140":[2,184],"141":[2,184],"142":[2,184],"144":[2,184]},{"8":289,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":290,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"119":[2,162],"120":[2,162]},{"8":212,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,153],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"91":151,"92":[1,60],"95":[1,59],"96":[1,150],"97":152,"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"31":166,"32":[1,76],"63":167,"64":168,"78":[1,73],"95":[1,247],"118":291},{"1":[2,168],"4":[2,168],"29":[2,168],"30":[2,168],"47":[1,97],"55":[2,168],"59":[2,168],"75":[2,168],"80":[2,168],"90":[2,168],"94":[2,168],"96":[2,168],"105":[2,168],"106":95,"107":[2,168],"108":[1,292],"109":[2,168],"112":96,"113":[2,168],"114":70,"121":[1,293],"130":[2,168],"131":[2,168],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,169],"4":[2,169],"29":[2,169],"30":[2,169],"47":[1,97],"55":[2,169],"59":[2,169],"75":[2,169],"80":[2,169],"90":[2,169],"94":[2,169],"96":[2,169],"105":[2,169],"106":95,"107":[2,169],"108":[1,294],"109":[2,169],"112":96,"113":[2,169],"114":70,"121":[2,169],"130":[2,169],"131":[2,169],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"4":[1,296],"29":[1,297],"80":[1,295]},{"4":[2,58],"28":177,"29":[2,58],"30":[2,58],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":298,"43":176,"46":[1,49],"58":[1,178],"80":[2,58]},{"8":299,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,300],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":301,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,302],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"30":[1,303],"47":[1,97],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,85],"4":[2,85],"29":[2,85],"30":[2,85],"41":[2,85],"47":[2,85],"55":[2,85],"59":[2,85],"68":[2,85],"69":[2,85],"70":[2,85],"71":[2,85],"74":[2,85],"75":[2,85],"76":[2,85],"77":[2,85],"80":[2,85],"82":[2,85],"88":[2,85],"89":[2,85],"90":[2,85],"94":[2,85],"96":[2,85],"105":[2,85],"107":[2,85],"108":[2,85],"109":[2,85],"113":[2,85],"121":[2,85],"130":[2,85],"131":[2,85],"133":[2,85],"134":[2,85],"135":[2,85],"136":[2,85],"137":[2,85],"138":[2,85],"139":[2,85],"140":[2,85],"141":[2,85],"142":[2,85],"143":[2,85],"144":[2,85]},{"8":304,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"75":[1,305],"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"47":[1,97],"75":[1,306],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"47":[1,97],"75":[1,256],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"30":[1,307],"47":[1,97],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"4":[1,285],"29":[1,286],"90":[1,308]},{"4":[2,66],"29":[2,66],"30":[2,66],"55":[2,66],"90":[2,66],"96":[2,66]},{"4":[1,125],"6":309,"29":[1,6]},{"50":[2,61],"55":[2,61]},{"50":[2,65],"55":[2,65]},{"4":[1,125],"6":310,"29":[1,6],"47":[1,97],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"4":[1,125],"6":311,"29":[1,6]},{"1":[2,140],"4":[2,140],"29":[2,140],"30":[2,140],"47":[2,140],"55":[2,140],"59":[2,140],"75":[2,140],"80":[2,140],"90":[2,140],"94":[2,140],"96":[2,140],"105":[2,140],"107":[2,140],"108":[2,140],"109":[2,140],"113":[2,140],"121":[2,140],"130":[2,140],"131":[2,140],"133":[2,140],"134":[2,140],"135":[2,140],"136":[2,140],"137":[2,140],"138":[2,140],"139":[2,140],"140":[2,140],"141":[2,140],"142":[2,140],"144":[2,140]},{"4":[1,125],"6":312,"29":[1,6]},{"30":[1,313],"124":[1,314],"125":273,"126":[1,225]},{"1":[2,177],"4":[2,177],"29":[2,177],"30":[2,177],"47":[2,177],"55":[2,177],"59":[2,177],"75":[2,177],"80":[2,177],"90":[2,177],"94":[2,177],"96":[2,177],"105":[2,177],"107":[2,177],"108":[2,177],"109":[2,177],"113":[2,177],"121":[2,177],"130":[2,177],"131":[2,177],"133":[2,177],"134":[2,177],"135":[2,177],"136":[2,177],"137":[2,177],"138":[2,177],"139":[2,177],"140":[2,177],"141":[2,177],"142":[2,177],"144":[2,177]},{"4":[1,125],"6":315,"29":[1,6]},{"30":[2,180],"124":[2,180],"126":[2,180]},{"4":[1,125],"6":316,"29":[1,6],"55":[1,317]},{"4":[2,136],"29":[2,136],"47":[1,97],"55":[2,136],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,95],"4":[2,95],"29":[1,318],"30":[2,95],"47":[2,95],"55":[2,95],"59":[2,95],"62":104,"68":[1,106],"69":[1,107],"70":[1,108],"71":[1,109],"72":110,"73":111,"74":[1,112],"75":[2,95],"76":[1,113],"77":[1,114],"80":[2,95],"85":102,"88":[1,105],"89":[2,114],"90":[2,95],"94":[2,95],"96":[2,95],"105":[2,95],"107":[2,95],"108":[2,95],"109":[2,95],"113":[2,95],"121":[2,95],"130":[2,95],"131":[2,95],"133":[2,95],"134":[2,95],"135":[2,95],"136":[2,95],"137":[2,95],"138":[2,95],"139":[2,95],"140":[2,95],"141":[2,95],"142":[2,95],"144":[2,95]},{"4":[1,279],"30":[1,319]},{"1":[2,98],"4":[2,98],"29":[2,98],"30":[2,98],"47":[2,98],"55":[2,98],"59":[2,98],"75":[2,98],"80":[2,98],"90":[2,98],"94":[2,98],"96":[2,98],"105":[2,98],"107":[2,98],"108":[2,98],"109":[2,98],"113":[2,98],"121":[2,98],"130":[2,98],"131":[2,98],"133":[2,98],"134":[2,98],"135":[2,98],"136":[2,98],"137":[2,98],"138":[2,98],"139":[2,98],"140":[2,98],"141":[2,98],"142":[2,98],"144":[2,98]},{"28":177,"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"84":320},{"4":[1,279],"80":[1,321]},{"8":322,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,323],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,105],"28":177,"30":[2,105],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"78":[1,232],"83":324,"84":231},{"47":[1,97],"96":[1,325],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,128],"4":[2,128],"29":[2,128],"30":[2,128],"41":[2,128],"47":[2,128],"55":[2,128],"59":[2,128],"68":[2,128],"69":[2,128],"70":[2,128],"71":[2,128],"74":[2,128],"75":[2,128],"76":[2,128],"77":[2,128],"80":[2,128],"88":[2,128],"89":[2,128],"90":[2,128],"94":[2,128],"96":[2,128],"105":[2,128],"107":[2,128],"108":[2,128],"109":[2,128],"113":[2,128],"119":[2,128],"120":[2,128],"121":[2,128],"130":[2,128],"131":[2,128],"133":[2,128],"134":[2,128],"135":[2,128],"136":[2,128],"137":[2,128],"138":[2,128],"139":[2,128],"140":[2,128],"141":[2,128],"142":[2,128],"143":[2,128],"144":[2,128]},{"8":212,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"97":326,"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":212,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,153],"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"91":327,"92":[1,60],"95":[1,59],"97":152,"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,130],"29":[2,130],"30":[2,130],"55":[2,130],"90":[2,130],"96":[2,130]},{"4":[1,285],"29":[1,286],"30":[1,328]},{"1":[2,147],"4":[2,147],"29":[2,147],"30":[2,147],"47":[1,97],"55":[2,147],"59":[2,147],"75":[2,147],"80":[2,147],"90":[2,147],"94":[2,147],"96":[2,147],"105":[2,147],"106":95,"107":[1,66],"108":[2,147],"109":[1,67],"112":96,"113":[1,69],"114":70,"121":[2,147],"130":[2,147],"131":[2,147],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,149],"4":[2,149],"29":[2,149],"30":[2,149],"47":[1,97],"55":[2,149],"59":[2,149],"75":[2,149],"80":[2,149],"90":[2,149],"94":[2,149],"96":[2,149],"105":[2,149],"106":95,"107":[1,66],"108":[2,149],"109":[1,67],"112":96,"113":[1,69],"114":70,"121":[2,149],"130":[2,149],"131":[2,149],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"119":[2,167],"120":[2,167]},{"8":329,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":330,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":331,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,88],"4":[2,88],"29":[2,88],"30":[2,88],"41":[2,88],"47":[2,88],"55":[2,88],"59":[2,88],"68":[2,88],"69":[2,88],"70":[2,88],"71":[2,88],"74":[2,88],"75":[2,88],"76":[2,88],"77":[2,88],"80":[2,88],"88":[2,88],"89":[2,88],"90":[2,88],"94":[2,88],"96":[2,88],"105":[2,88],"107":[2,88],"108":[2,88],"109":[2,88],"113":[2,88],"119":[2,88],"120":[2,88],"121":[2,88],"130":[2,88],"131":[2,88],"133":[2,88],"134":[2,88],"135":[2,88],"136":[2,88],"137":[2,88],"138":[2,88],"139":[2,88],"140":[2,88],"141":[2,88],"142":[2,88],"143":[2,88],"144":[2,88]},{"28":177,"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":332,"43":176,"46":[1,49],"58":[1,178]},{"4":[2,89],"28":177,"29":[2,89],"30":[2,89],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":173,"43":176,"46":[1,49],"55":[2,89],"58":[1,178],"79":333},{"4":[2,91],"29":[2,91],"30":[2,91],"55":[2,91],"80":[2,91]},{"4":[2,44],"29":[2,44],"30":[2,44],"47":[1,97],"55":[2,44],"80":[2,44],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"8":334,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,45],"29":[2,45],"30":[2,45],"47":[1,97],"55":[2,45],"80":[2,45],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"8":335,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,208],"4":[2,208],"29":[2,208],"30":[2,208],"47":[2,208],"55":[2,208],"59":[2,208],"75":[2,208],"80":[2,208],"90":[2,208],"94":[2,208],"96":[2,208],"105":[2,208],"107":[2,208],"108":[2,208],"109":[2,208],"113":[2,208],"121":[2,208],"130":[2,208],"131":[2,208],"133":[2,208],"134":[2,208],"135":[2,208],"136":[2,208],"137":[2,208],"138":[2,208],"139":[2,208],"140":[2,208],"141":[2,208],"142":[2,208],"144":[2,208]},{"47":[1,97],"75":[1,336],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,125],"4":[2,125],"29":[2,125],"30":[2,125],"41":[2,125],"47":[2,125],"55":[2,125],"59":[2,125],"68":[2,125],"69":[2,125],"70":[2,125],"71":[2,125],"74":[2,125],"75":[2,125],"76":[2,125],"77":[2,125],"80":[2,125],"82":[2,125],"88":[2,125],"89":[2,125],"90":[2,125],"94":[2,125],"96":[2,125],"105":[2,125],"107":[2,125],"108":[2,125],"109":[2,125],"113":[2,125],"121":[2,125],"130":[2,125],"131":[2,125],"133":[2,125],"134":[2,125],"135":[2,125],"136":[2,125],"137":[2,125],"138":[2,125],"139":[2,125],"140":[2,125],"141":[2,125],"142":[2,125],"143":[2,125],"144":[2,125]},{"1":[2,126],"4":[2,126],"29":[2,126],"30":[2,126],"41":[2,126],"47":[2,126],"55":[2,126],"59":[2,126],"68":[2,126],"69":[2,126],"70":[2,126],"71":[2,126],"74":[2,126],"75":[2,126],"76":[2,126],"77":[2,126],"80":[2,126],"82":[2,126],"88":[2,126],"89":[2,126],"90":[2,126],"94":[2,126],"96":[2,126],"105":[2,126],"107":[2,126],"108":[2,126],"109":[2,126],"113":[2,126],"121":[2,126],"130":[2,126],"131":[2,126],"133":[2,126],"134":[2,126],"135":[2,126],"136":[2,126],"137":[2,126],"138":[2,126],"139":[2,126],"140":[2,126],"141":[2,126],"142":[2,126],"143":[2,126],"144":[2,126]},{"1":[2,40],"4":[2,40],"29":[2,40],"30":[2,40],"47":[2,40],"55":[2,40],"59":[2,40],"75":[2,40],"80":[2,40],"90":[2,40],"94":[2,40],"96":[2,40],"105":[2,40],"107":[2,40],"108":[2,40],"109":[2,40],"113":[2,40],"121":[2,40],"130":[2,40],"131":[2,40],"133":[2,40],"134":[2,40],"135":[2,40],"136":[2,40],"137":[2,40],"138":[2,40],"139":[2,40],"140":[2,40],"141":[2,40],"142":[2,40],"144":[2,40]},{"1":[2,117],"4":[2,117],"29":[2,117],"30":[2,117],"47":[2,117],"55":[2,117],"59":[2,117],"68":[2,117],"69":[2,117],"70":[2,117],"71":[2,117],"74":[2,117],"75":[2,117],"76":[2,117],"77":[2,117],"80":[2,117],"88":[2,117],"89":[2,117],"90":[2,117],"94":[2,117],"96":[2,117],"105":[2,117],"107":[2,117],"108":[2,117],"109":[2,117],"113":[2,117],"121":[2,117],"130":[2,117],"131":[2,117],"133":[2,117],"134":[2,117],"135":[2,117],"136":[2,117],"137":[2,117],"138":[2,117],"139":[2,117],"140":[2,117],"141":[2,117],"142":[2,117],"144":[2,117]},{"1":[2,53],"4":[2,53],"29":[2,53],"30":[2,53],"47":[2,53],"55":[2,53],"59":[2,53],"75":[2,53],"80":[2,53],"90":[2,53],"94":[2,53],"96":[2,53],"105":[2,53],"107":[2,53],"108":[2,53],"109":[2,53],"113":[2,53],"121":[2,53],"130":[2,53],"131":[2,53],"133":[2,53],"134":[2,53],"135":[2,53],"136":[2,53],"137":[2,53],"138":[2,53],"139":[2,53],"140":[2,53],"141":[2,53],"142":[2,53],"144":[2,53]},{"1":[2,185],"4":[2,185],"29":[2,185],"30":[2,185],"47":[2,185],"55":[2,185],"59":[2,185],"75":[2,185],"80":[2,185],"90":[2,185],"94":[2,185],"96":[2,185],"105":[2,185],"107":[2,185],"108":[2,185],"109":[2,185],"113":[2,185],"121":[2,185],"124":[2,185],"130":[2,185],"131":[2,185],"133":[2,185],"134":[2,185],"135":[2,185],"136":[2,185],"137":[2,185],"138":[2,185],"139":[2,185],"140":[2,185],"141":[2,185],"142":[2,185],"144":[2,185]},{"1":[2,141],"4":[2,141],"29":[2,141],"30":[2,141],"47":[2,141],"55":[2,141],"59":[2,141],"75":[2,141],"80":[2,141],"90":[2,141],"94":[2,141],"96":[2,141],"105":[2,141],"107":[2,141],"108":[2,141],"109":[2,141],"113":[2,141],"121":[2,141],"130":[2,141],"131":[2,141],"133":[2,141],"134":[2,141],"135":[2,141],"136":[2,141],"137":[2,141],"138":[2,141],"139":[2,141],"140":[2,141],"141":[2,141],"142":[2,141],"144":[2,141]},{"1":[2,142],"4":[2,142],"29":[2,142],"30":[2,142],"47":[2,142],"55":[2,142],"59":[2,142],"75":[2,142],"80":[2,142],"90":[2,142],"94":[2,142],"96":[2,142],"101":[2,142],"105":[2,142],"107":[2,142],"108":[2,142],"109":[2,142],"113":[2,142],"121":[2,142],"130":[2,142],"131":[2,142],"133":[2,142],"134":[2,142],"135":[2,142],"136":[2,142],"137":[2,142],"138":[2,142],"139":[2,142],"140":[2,142],"141":[2,142],"142":[2,142],"144":[2,142]},{"1":[2,175],"4":[2,175],"29":[2,175],"30":[2,175],"47":[2,175],"55":[2,175],"59":[2,175],"75":[2,175],"80":[2,175],"90":[2,175],"94":[2,175],"96":[2,175],"105":[2,175],"107":[2,175],"108":[2,175],"109":[2,175],"113":[2,175],"121":[2,175],"130":[2,175],"131":[2,175],"133":[2,175],"134":[2,175],"135":[2,175],"136":[2,175],"137":[2,175],"138":[2,175],"139":[2,175],"140":[2,175],"141":[2,175],"142":[2,175],"144":[2,175]},{"4":[1,125],"6":337,"29":[1,6]},{"30":[1,338]},{"4":[1,339],"30":[2,181],"124":[2,181],"126":[2,181]},{"8":340,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,105],"28":177,"30":[2,105],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"78":[1,232],"83":341,"84":231},{"1":[2,96],"4":[2,96],"29":[2,96],"30":[2,96],"47":[2,96],"55":[2,96],"59":[2,96],"75":[2,96],"80":[2,96],"90":[2,96],"94":[2,96],"96":[2,96],"105":[2,96],"107":[2,96],"108":[2,96],"109":[2,96],"113":[2,96],"121":[2,96],"130":[2,96],"131":[2,96],"133":[2,96],"134":[2,96],"135":[2,96],"136":[2,96],"137":[2,96],"138":[2,96],"139":[2,96],"140":[2,96],"141":[2,96],"142":[2,96],"144":[2,96]},{"4":[2,107],"30":[2,107],"80":[2,107]},{"4":[2,108],"30":[2,108],"80":[2,108]},{"4":[2,103],"30":[2,103],"47":[1,97],"80":[2,103],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"8":342,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[1,279],"30":[1,343]},{"1":[2,123],"4":[2,123],"29":[2,123],"30":[2,123],"47":[2,123],"55":[2,123],"59":[2,123],"68":[2,123],"69":[2,123],"70":[2,123],"71":[2,123],"74":[2,123],"75":[2,123],"76":[2,123],"77":[2,123],"80":[2,123],"88":[2,123],"89":[2,123],"90":[2,123],"94":[2,123],"96":[2,123],"105":[2,123],"107":[2,123],"108":[2,123],"109":[2,123],"113":[2,123],"121":[2,123],"130":[2,123],"131":[2,123],"133":[2,123],"134":[2,123],"135":[2,123],"136":[2,123],"137":[2,123],"138":[2,123],"139":[2,123],"140":[2,123],"141":[2,123],"142":[2,123],"143":[2,123],"144":[2,123]},{"4":[2,131],"29":[2,131],"30":[2,131],"55":[2,131],"90":[2,131],"96":[2,131]},{"4":[2,57],"29":[2,57],"30":[2,57],"54":344,"55":[1,240]},{"4":[2,132],"29":[2,132],"30":[2,132],"55":[2,132],"90":[2,132],"96":[2,132]},{"1":[2,170],"4":[2,170],"29":[2,170],"30":[2,170],"47":[1,97],"55":[2,170],"59":[2,170],"75":[2,170],"80":[2,170],"90":[2,170],"94":[2,170],"96":[2,170],"105":[2,170],"106":95,"107":[2,170],"108":[2,170],"109":[2,170],"112":96,"113":[2,170],"114":70,"121":[1,345],"130":[2,170],"131":[2,170],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,172],"4":[2,172],"29":[2,172],"30":[2,172],"47":[1,97],"55":[2,172],"59":[2,172],"75":[2,172],"80":[2,172],"90":[2,172],"94":[2,172],"96":[2,172],"105":[2,172],"106":95,"107":[2,172],"108":[1,346],"109":[2,172],"112":96,"113":[2,172],"114":70,"121":[2,172],"130":[2,172],"131":[2,172],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,171],"4":[2,171],"29":[2,171],"30":[2,171],"47":[1,97],"55":[2,171],"59":[2,171],"75":[2,171],"80":[2,171],"90":[2,171],"94":[2,171],"96":[2,171],"105":[2,171],"106":95,"107":[2,171],"108":[2,171],"109":[2,171],"112":96,"113":[2,171],"114":70,"121":[2,171],"130":[2,171],"131":[2,171],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"4":[2,92],"29":[2,92],"30":[2,92],"55":[2,92],"80":[2,92]},{"4":[2,57],"29":[2,57],"30":[2,57],"54":347,"55":[1,252]},{"30":[1,348],"47":[1,97],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"30":[1,349],"47":[1,97],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,124],"4":[2,124],"29":[2,124],"30":[2,124],"41":[2,124],"47":[2,124],"55":[2,124],"59":[2,124],"68":[2,124],"69":[2,124],"70":[2,124],"71":[2,124],"74":[2,124],"75":[2,124],"76":[2,124],"77":[2,124],"80":[2,124],"82":[2,124],"88":[2,124],"89":[2,124],"90":[2,124],"94":[2,124],"96":[2,124],"105":[2,124],"107":[2,124],"108":[2,124],"109":[2,124],"113":[2,124],"121":[2,124],"130":[2,124],"131":[2,124],"133":[2,124],"134":[2,124],"135":[2,124],"136":[2,124],"137":[2,124],"138":[2,124],"139":[2,124],"140":[2,124],"141":[2,124],"142":[2,124],"143":[2,124],"144":[2,124]},{"30":[1,350]},{"1":[2,178],"4":[2,178],"29":[2,178],"30":[2,178],"47":[2,178],"55":[2,178],"59":[2,178],"75":[2,178],"80":[2,178],"90":[2,178],"94":[2,178],"96":[2,178],"105":[2,178],"107":[2,178],"108":[2,178],"109":[2,178],"113":[2,178],"121":[2,178],"130":[2,178],"131":[2,178],"133":[2,178],"134":[2,178],"135":[2,178],"136":[2,178],"137":[2,178],"138":[2,178],"139":[2,178],"140":[2,178],"141":[2,178],"142":[2,178],"144":[2,178]},{"30":[2,182],"124":[2,182],"126":[2,182]},{"4":[2,137],"29":[2,137],"47":[1,97],"55":[2,137],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"4":[1,279],"30":[1,351]},{"30":[1,352],"47":[1,97],"106":95,"107":[1,66],"109":[1,67],"112":96,"113":[1,69],"114":70,"130":[1,93],"131":[1,94],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,101],"4":[2,101],"29":[2,101],"30":[2,101],"47":[2,101],"55":[2,101],"59":[2,101],"75":[2,101],"80":[2,101],"90":[2,101],"94":[2,101],"96":[2,101],"105":[2,101],"107":[2,101],"108":[2,101],"109":[2,101],"113":[2,101],"121":[2,101],"130":[2,101],"131":[2,101],"133":[2,101],"134":[2,101],"135":[2,101],"136":[2,101],"137":[2,101],"138":[2,101],"139":[2,101],"140":[2,101],"141":[2,101],"142":[2,101],"144":[2,101]},{"4":[1,285],"29":[1,286],"30":[1,353]},{"8":354,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":355,"9":127,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":71,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":72,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":47,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,42],"103":[1,51],"104":[1,58],"106":43,"107":[1,66],"109":[1,67],"110":44,"111":[1,68],"112":45,"113":[1,69],"114":70,"122":[1,46],"127":41,"128":[1,64],"129":[1,65],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[1,296],"29":[1,297],"30":[1,356]},{"4":[2,46],"29":[2,46],"30":[2,46],"55":[2,46],"80":[2,46]},{"4":[2,47],"29":[2,47],"30":[2,47],"55":[2,47],"80":[2,47]},{"1":[2,176],"4":[2,176],"29":[2,176],"30":[2,176],"47":[2,176],"55":[2,176],"59":[2,176],"75":[2,176],"80":[2,176],"90":[2,176],"94":[2,176],"96":[2,176],"105":[2,176],"107":[2,176],"108":[2,176],"109":[2,176],"113":[2,176],"121":[2,176],"130":[2,176],"131":[2,176],"133":[2,176],"134":[2,176],"135":[2,176],"136":[2,176],"137":[2,176],"138":[2,176],"139":[2,176],"140":[2,176],"141":[2,176],"142":[2,176],"144":[2,176]},{"1":[2,97],"4":[2,97],"29":[2,97],"30":[2,97],"47":[2,97],"55":[2,97],"59":[2,97],"75":[2,97],"80":[2,97],"90":[2,97],"94":[2,97],"96":[2,97],"105":[2,97],"107":[2,97],"108":[2,97],"109":[2,97],"113":[2,97],"121":[2,97],"130":[2,97],"131":[2,97],"133":[2,97],"134":[2,97],"135":[2,97],"136":[2,97],"137":[2,97],"138":[2,97],"139":[2,97],"140":[2,97],"141":[2,97],"142":[2,97],"144":[2,97]},{"4":[2,104],"30":[2,104],"80":[2,104]},{"4":[2,133],"29":[2,133],"30":[2,133],"55":[2,133],"90":[2,133],"96":[2,133]},{"1":[2,173],"4":[2,173],"29":[2,173],"30":[2,173],"47":[1,97],"55":[2,173],"59":[2,173],"75":[2,173],"80":[2,173],"90":[2,173],"94":[2,173],"96":[2,173],"105":[2,173],"106":95,"107":[2,173],"108":[2,173],"109":[2,173],"112":96,"113":[2,173],"114":70,"121":[2,173],"130":[2,173],"131":[2,173],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"1":[2,174],"4":[2,174],"29":[2,174],"30":[2,174],"47":[1,97],"55":[2,174],"59":[2,174],"75":[2,174],"80":[2,174],"90":[2,174],"94":[2,174],"96":[2,174],"105":[2,174],"106":95,"107":[2,174],"108":[2,174],"109":[2,174],"112":96,"113":[2,174],"114":70,"121":[2,174],"130":[2,174],"131":[2,174],"133":[1,85],"134":[1,84],"135":[1,82],"136":[1,83],"137":[1,86],"138":[1,87],"139":[1,88],"140":[1,89],"141":[1,90],"142":[1,91],"144":[1,92]},{"4":[2,93],"29":[2,93],"30":[2,93],"55":[2,93],"80":[2,93]}],defaultActions:{"79":[2,4],"105":[2,115]},parseError:function parseError(str,hash){throw new Error(str)},parse:function parse(input){var self=this,stack=[0],vstack=[null],table=this.table,yytext="",yylineno=0,yyleng=0,shifts=0,reductions=0,recovering=0,TERROR=2,EOF=1;this.lexer.setInput(input);this.lexer.yy=this.yy;this.yy.lexer=this.lexer;var parseError=this.yy.parseError=typeof this.yy.parseError=="function"?this.yy.parseError:this.parseError;function popStack(n){stack.length=stack.length-2*n;vstack.length=vstack.length-n}function checkRecover(st){for(var p in table[st]){if(p==TERROR){return true}}return false}function lex(){var token;token=self.lexer.lex()||1;if(typeof token!=="number"){token=self.symbols_[token]||token}return token}var symbol,preErrorSymbol,state,action,a,r,yyval={},p,len,newState,expected,recovered=false;while(true){state=stack[stack.length-1];if(this.defaultActions[state]){action=this.defaultActions[state]}else{if(symbol==null){symbol=lex()}action=table[state]&&table[state][symbol]}if(typeof action==="undefined"||!action.length||!action[0]){if(!recovering){expected=[];for(p in table[state]){if(this.terminals_[p]&&p>2){expected.push("'"+this.terminals_[p]+"'")}}if(this.lexer.showPosition){parseError.call(this,"Parse error on line "+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(", "),{text:this.lexer.match,token:this.terminals_[symbol]||symbol,line:this.lexer.yylineno,expected:expected})}else{parseError.call(this,"Parse error on line "+(yylineno+1)+": Unexpected '"+(this.terminals_[symbol]||symbol)+"'",{text:this.lexer.match,token:this.terminals_[symbol]||symbol,line:this.lexer.yylineno,expected:expected})}}if(recovering==3){if(symbol==EOF){throw"Parsing halted."}yyleng=this.lexer.yyleng;yytext=this.lexer.yytext;yylineno=this.lexer.yylineno;symbol=lex()}while(1){if(checkRecover(state)){break}if(state==0){throw"Parsing halted."}popStack(1);state=stack[stack.length-1]}preErrorSymbol=symbol;symbol=TERROR;state=stack[stack.length-1];action=table[state]&&table[state][TERROR];recovering=3}if(action[0] instanceof Array&&action.length>1){throw new Error("Parse Error: multiple actions possible at state: "+state+", token: "+symbol)}a=action;switch(a[0]){case 1:shifts++;stack.push(symbol);vstack.push(this.lexer.yytext);stack.push(a[1]);symbol=null;if(!preErrorSymbol){yyleng=this.lexer.yyleng;yytext=this.lexer.yytext;yylineno=this.lexer.yylineno;if(recovering>0){recovering--}}else{symbol=preErrorSymbol;preErrorSymbol=null}break;case 2:reductions++;len=this.productions_[a[1]][1];yyval.$=vstack[vstack.length-len];r=this.performAction.call(yyval,yytext,yyleng,yylineno,this.yy,a[1],vstack);if(typeof r!=="undefined"){return r}if(len){stack=stack.slice(0,-1*len*2);vstack=vstack.slice(0,-1*len)}stack.push(this.productions_[a[1]][0]);vstack.push(yyval.$);newState=table[stack[stack.length-2]][stack[stack.length-1]];stack.push(newState);break;case 3:this.reductionCount=reductions;this.shiftCount=shifts;return true}}return true}};return parser})();if(typeof require!=="undefined"){exports.parser=parser;exports.parse=function(){return parser.parse.apply(parser,arguments)};exports.main=function commonjsMain(args){if(!args[1]){throw new Error("Usage: "+args[0]+" FILE")}if(typeof process!=="undefined"){var source=require("fs").readFileSync(require("path").join(process.cwd(),args[1]),"utf8")}else{var cwd=require("file").path(require("file").cwd());var source=cwd.join(args[1]).read({charset:"utf-8"})}return exports.parser.parse(source)};if(typeof module!=="undefined"&&require.main===module){exports.main(typeof process!=="undefined"?process.argv.slice(1):require("system").args)}}};require["./scope"]=new function(){var exports=this;(function(){var Scope,_ref,extend,last;var __hasProp=Object.prototype.hasOwnProperty;_ref=require("./helpers"),extend=_ref.extend,last=_ref.last;exports.Scope=(function(){Scope=(function(){function Scope(_arg,_arg2,_arg3){this.method=_arg3;this.expressions=_arg2;this.parent=_arg;this.variables={"arguments":"arguments"};if(this.parent){this.garbage=this.parent.garbage}else{this.garbage=[];Scope.root=this}return this}return Scope})();Scope.root=null;Scope.prototype.startLevel=function(){return this.garbage.push([])};Scope.prototype.endLevel=function(){var _i,_len,_ref2,_result,name,vars;vars=this.variables;_result=[];for(_i=0,_len=(_ref2=this.garbage.pop()).length;_i<_len;_i++){name=_ref2[_i];if(vars[name]==="var"){_result.push(vars[name]="reuse")}}return _result};Scope.prototype.find=function(name,options){if(this.check(name,options)){return true}this.variables[name]="var";return false};Scope.prototype.any=function(fn){var _ref2,k,v;for(v in _ref2=this.variables){if(!__hasProp.call(_ref2,v)){continue}k=_ref2[v];if(fn(v,k)){return true}}return false};Scope.prototype.parameter=function(name){return(this.variables[name]="param")};Scope.prototype.check=function(name,options){var _ref2,immediate;immediate=Object.prototype.hasOwnProperty.call(this.variables,name);if(immediate||((options!=null)?options.immediate:undefined)){return immediate}return !!(((_ref2=this.parent)!=null)?_ref2.check(name):undefined)};Scope.prototype.temporary=function(type,index){return type.length>1?"_"+type+(index>1?index:""):"_"+(index+parseInt(type,36)).toString(36).replace(/\d/g,"a")};Scope.prototype.freeVariable=function(type){var index,temp;index=0;while(this.check(temp=this.temporary(type,index))&&this.variables[temp]!=="reuse"){index++}this.variables[temp]="var";if(this.garbage.length){last(this.garbage).push(temp)}return temp};Scope.prototype.assign=function(name,value){return(this.variables[name]={value:value,assigned:true})};Scope.prototype.hasDeclarations=function(body){return body===this.expressions&&this.any(function(k,val){return(val==="var"||val==="reuse")})};Scope.prototype.hasAssignments=function(body){return body===this.expressions&&this.any(function(k,val){return val.assigned})};Scope.prototype.declaredVariables=function(){var _ref2,_result,key,val;return(function(){_result=[];for(key in _ref2=this.variables){if(!__hasProp.call(_ref2,key)){continue}val=_ref2[key];if((val==="var"||val==="reuse")){_result.push(key)}}return _result}).call(this).sort()};Scope.prototype.assignedVariables=function(){var _ref2,_result,key,val;_result=[];for(key in _ref2=this.variables){if(!__hasProp.call(_ref2,key)){continue}val=_ref2[key];if(val.assigned){_result.push(""+key+" = "+(val.value))}}return _result};Scope.prototype.compiledDeclarations=function(){return this.declaredVariables().join(", ")};Scope.prototype.compiledAssignments=function(){return this.assignedVariables().join(", ")};return Scope}).call(this)}).call(this)};require["./nodes"]=new function(){var exports=this;(function(){var Accessor,ArrayLiteral,Assign,Base,Call,Class,Closure,Code,Comment,Existence,Expressions,Extends,For,IDENTIFIER,IS_STRING,If,In,Index,Literal,NO,NUMBER,ObjectLiteral,Op,Param,Parens,Push,Range,Return,SIMPLENUM,Scope,Slice,Splat,Switch,TAB,THIS,TRAILING_WHITESPACE,Throw,Try,UTILITIES,Value,While,YES,_ref,compact,del,ends,flatten,include,last,merge,starts,utility;var __extends=function(child,parent){function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;if(typeof parent.extended==="function"){parent.extended(child)}child.__super__=parent.prototype};Scope=require("./scope").Scope;_ref=require("./helpers"),compact=_ref.compact,flatten=_ref.flatten,merge=_ref.merge,del=_ref.del,include=_ref.include,starts=_ref.starts,ends=_ref.ends,last=_ref.last;YES=function(){return true};NO=function(){return false};THIS=function(){return this};exports.Base=(function(){Base=(function(){function Base(){this.tags={};return this}return Base})();Base.prototype.compile=function(o){var closure,code,top;this.options=o?merge(o):{};this.tab=o.indent;top=this.topSensitive()?this.options.top:del(this.options,"top");closure=this.isStatement(o)&&!this.isPureStatement()&&!top&&!this.options.asStatement&&!(this instanceof Comment)&&!this.containsPureStatement();code=closure?this.compileClosure(this.options):this.compileNode(this.options);return code};Base.prototype.compileClosure=function(o){o.sharedScope=o.scope;return Closure.wrap(this).compile(o)};Base.prototype.compileReference=function(o,options){var _len,compiled,i,node,pair,reference;pair=(function(){if(!this.isComplex()){return[this,this]}else{reference=new Literal(o.scope.freeVariable("ref"));compiled=new Assign(reference,this);return[compiled,reference]}}).call(this);if(((options!=null)?options.precompile:undefined)){for(i=0,_len=pair.length;i<_len;i++){node=pair[i];(pair[i]=node.compile(o))}}return pair};Base.prototype.idt=function(tabs){var idt,num;idt=this.tab||"";num=(tabs||0)+1;while(num-=1){idt+=TAB}return idt};Base.prototype.makeReturn=function(){return new Return(this)};Base.prototype.contains=function(block){var contains;contains=false;this.traverseChildren(false,function(node){if(block(node)){contains=true;return false}});return contains};Base.prototype.containsType=function(type){return this instanceof type||this.contains(function(node){return node instanceof type})};Base.prototype.containsPureStatement=function(){return this.isPureStatement()||this.contains(function(node){return node.isPureStatement()})};Base.prototype.traverse=function(block){return this.traverseChildren(true,block)};Base.prototype.toString=function(idt,override){var _i,_len,_ref2,_result,child,children,klass;idt||(idt="");children=(function(){_result=[];for(_i=0,_len=(_ref2=this.collectChildren()).length;_i<_len;_i++){child=_ref2[_i];_result.push(child.toString(idt+TAB))}return _result}).call(this).join("");klass=override||this.constructor.name+(this.soakNode||this.exist?"?":"");return"\n"+idt+klass+children};Base.prototype.eachChild=function(func){var _i,_j,_len,_len2,_ref2,_ref3,_result,attr,child;if(!this.children){return}_result=[];for(_i=0,_len=(_ref2=this.children).length;_i<_len;_i++){attr=_ref2[_i];if(this[attr]){for(_j=0,_len2=(_ref3=flatten([this[attr]])).length;_j<_len2;_j++){child=_ref3[_j];if(func(child)===false){return}}}}return _result};Base.prototype.collectChildren=function(){var nodes;nodes=[];this.eachChild(function(node){return nodes.push(node)});return nodes};Base.prototype.traverseChildren=function(crossScope,func){return this.eachChild(function(child){if(func(child)===false){return false}return crossScope||!(child instanceof Code)?child.traverseChildren(crossScope,func):undefined})};Base.prototype.invert=function(){return new Op("!",this)};Base.prototype.children=[];Base.prototype.unwrap=THIS;Base.prototype.isStatement=NO;Base.prototype.isPureStatement=NO;Base.prototype.isComplex=YES;Base.prototype.topSensitive=NO;Base.prototype.assigns=NO;return Base})();exports.Expressions=(function(){Expressions=(function(){function Expressions(nodes){Expressions.__super__.constructor.call(this);this.expressions=compact(flatten(nodes||[]));return this}return Expressions})();__extends(Expressions,Base);Expressions.prototype.children=["expressions"];Expressions.prototype.isStatement=YES;Expressions.prototype.push=function(node){this.expressions.push(node);return this};Expressions.prototype.unshift=function(node){this.expressions.unshift(node);return this};Expressions.prototype.unwrap=function(){return this.expressions.length===1?this.expressions[0]:this};Expressions.prototype.empty=function(){return this.expressions.length===0};Expressions.prototype.makeReturn=function(){var end,idx;end=this.expressions[(idx=this.expressions.length-1)];if(end instanceof Comment){end=this.expressions[idx-=1]}if(end&&!(end instanceof Return)){this.expressions[idx]=end.makeReturn()}return this};Expressions.prototype.compile=function(o){o||(o={});return o.scope?Expressions.__super__.compile.call(this,o):this.compileRoot(o)};Expressions.prototype.compileNode=function(o){var _i,_len,_ref2,_result,node;return(function(){_result=[];for(_i=0,_len=(_ref2=this.expressions).length;_i<_len;_i++){node=_ref2[_i];_result.push(this.compileExpression(node,merge(o)))}return _result}).call(this).join("\n")};Expressions.prototype.compileRoot=function(o){var code;o.indent=(this.tab=o.bare?"":TAB);o.scope=new Scope(null,this,null);code=this.compileWithDeclarations(o);code=code.replace(TRAILING_WHITESPACE,"");return o.bare?code:("(function() {\n"+code+"\n}).call(this);\n")};Expressions.prototype.compileWithDeclarations=function(o){var code;code=this.compileNode(o);if(o.scope.hasAssignments(this)){code=(""+(this.tab)+"var "+(o.scope.compiledAssignments().replace(/\n/g,"$&"+this.tab))+";\n"+code)}if(!o.globals&&o.scope.hasDeclarations(this)){code=(""+(this.tab)+"var "+(o.scope.compiledDeclarations())+";\n"+code)}return code};Expressions.prototype.compileExpression=function(node,o){var compiledNode;this.tab=o.indent;node.tags.front=true;compiledNode=node.compile(merge(o,{top:true}));return node.isStatement(o)?compiledNode:(""+(this.idt())+compiledNode+";")};return Expressions})();Expressions.wrap=function(nodes){if(nodes.length===1&&nodes[0] instanceof Expressions){return nodes[0]}return new Expressions(nodes)};exports.Literal=(function(){Literal=(function(){function Literal(_arg){this.value=_arg;Literal.__super__.constructor.call(this);return this}return Literal})();__extends(Literal,Base);Literal.prototype.makeReturn=function(){return this.isStatement()?this:Literal.__super__.makeReturn.call(this)};Literal.prototype.isStatement=function(){var _ref2;return((_ref2=this.value)==="break"||_ref2==="continue"||_ref2==="debugger")};Literal.prototype.isPureStatement=Literal.prototype.isStatement;Literal.prototype.isComplex=NO;Literal.prototype.isReserved=function(){return !!this.value.reserved};Literal.prototype.assigns=function(name){return name===this.value};Literal.prototype.compileNode=function(o){var end,idt,val;idt=this.isStatement(o)?this.idt():"";end=this.isStatement(o)?";":"";val=this.isReserved()?('"'+(this.value)+'"'):this.value;return idt+val+end};Literal.prototype.toString=function(){return' "'+this.value+'"'};return Literal})();exports.Return=(function(){Return=(function(){function Return(_arg){this.expression=_arg;Return.__super__.constructor.call(this);return this}return Return})();__extends(Return,Base);Return.prototype.isStatement=YES;Return.prototype.isPureStatement=YES;Return.prototype.children=["expression"];Return.prototype.makeReturn=THIS;Return.prototype.compile=function(o){var _ref2,expr;expr=(((_ref2=this.expression)!=null)?_ref2.makeReturn():undefined);if(expr&&(!(expr instanceof Return))){return expr.compile(o)}return Return.__super__.compile.call(this,o)};Return.prototype.compileNode=function(o){var expr;expr="";if(this.expression){if(this.expression.isStatement(o)){o.asStatement=true}expr=" "+this.expression.compile(o)}return""+(this.tab)+"return"+expr+";"};return Return})();exports.Value=(function(){Value=(function(){function Value(_arg,_arg2,tag){this.properties=_arg2;this.base=_arg;Value.__super__.constructor.call(this);this.properties||(this.properties=[]);if(tag){this.tags[tag]=true}return this}return Value})();__extends(Value,Base);Value.prototype.children=["base","properties"];Value.prototype.push=function(prop){this.properties.push(prop);return this};Value.prototype.hasProperties=function(){return !!this.properties.length};Value.prototype.isArray=function(){return this.base instanceof ArrayLiteral&&!this.properties.length};Value.prototype.isObject=function(){return this.base instanceof ObjectLiteral&&!this.properties.length};Value.prototype.isSplice=function(){return last(this.properties) instanceof Slice};Value.prototype.isComplex=function(){return this.base.isComplex()||this.hasProperties()};Value.prototype.assigns=function(name){return !this.properties.length&&this.base.assigns(name)};Value.prototype.makeReturn=function(){return this.properties.length?Value.__super__.makeReturn.call(this):this.base.makeReturn()};Value.prototype.unwrap=function(){return this.properties.length?this:this.base};Value.prototype.isStatement=function(o){return this.base.isStatement(o)&&!this.properties.length};Value.prototype.isSimpleNumber=function(){return this.base instanceof Literal&&SIMPLENUM.test(this.base.value)};Value.prototype.cacheReference=function(o){var base,bref,name,nref;name=last(this.properties);if(!this.base.isComplex()&&this.properties.length<2&&!((name!=null)?name.isComplex():undefined)){return[this,this]}base=new Value(this.base,this.properties.slice(0,-1));if(base.isComplex()){bref=new Literal(o.scope.freeVariable("base"));base=new Value(new Parens(new Assign(bref,base)))}if(!name){return[base,bref]}if(name.isComplex()){nref=new Literal(o.scope.freeVariable("name"));name=new Index(new Assign(nref,name.index));nref=new Index(nref)}return[base.push(name),new Value(bref||base.base,[nref||name])]};Value.prototype.compile=function(o){this.base.tags.front=this.tags.front;return !o.top||this.properties.length?Value.__super__.compile.call(this,o):this.base.compile(o)};Value.prototype.compileNode=function(o){var _i,_len,code,ex,prop,props;if(ex=this.unfoldSoak(o)){return ex.compile(o)}props=this.properties;if(this.parenthetical&&!props.length){this.base.parenthetical=true}code=this.base.compile(o);if(props[0] instanceof Accessor&&this.isSimpleNumber()){code=("("+code+")")}for(_i=0,_len=props.length;_i<_len;_i++){prop=props[_i];(code+=prop.compile(o))}return code};Value.prototype.unfoldSoak=function(o){var _len,_ref2,fst,i,ifn,prop,ref,snd;if(this.base.soakNode){Array.prototype.push.apply(this.base.body.properties,this.properties);return this.base}for(i=0,_len=(_ref2=this.properties).length;i<_len;i++){prop=_ref2[i];if(prop.soakNode){prop.soakNode=false;fst=new Value(this.base,this.properties.slice(0,i));snd=new Value(this.base,this.properties.slice(i));if(fst.isComplex()){ref=new Literal(o.scope.freeVariable("ref"));fst=new Parens(new Assign(ref,fst));snd.base=ref}ifn=new If(new Existence(fst),snd,{operation:true});ifn.soakNode=true;return ifn}}return null};Value.unfoldSoak=function(o,parent,name){var ifnode,node;node=parent[name];if(node instanceof If&&node.soakNode){ifnode=node}else{if(node instanceof Value){ifnode=node.unfoldSoak(o)}}if(!ifnode){return}parent[name]=ifnode.body;ifnode.body=new Value(parent);return ifnode};return Value}).call(this);exports.Comment=(function(){Comment=(function(){function Comment(_arg){this.comment=_arg;Comment.__super__.constructor.call(this);return this}return Comment})();__extends(Comment,Base);Comment.prototype.isStatement=YES;Comment.prototype.makeReturn=THIS;Comment.prototype.compileNode=function(o){return this.tab+"/*"+this.comment.replace(/\n/g,"\n"+this.tab)+"*/"};return Comment})();exports.Call=(function(){Call=(function(){function Call(variable,_arg,_arg2){this.exist=_arg2;this.args=_arg;Call.__super__.constructor.call(this);this.isNew=false;this.isSuper=variable==="super";this.variable=this.isSuper?null:variable;this.args||(this.args=[]);return this}return Call})();__extends(Call,Base);Call.prototype.children=["variable","args"];Call.prototype.compileSplatArguments=function(o){return Splat.compileSplattedArray(this.args,o)};Call.prototype.newInstance=function(){this.isNew=true;return this};Call.prototype.prefix=function(){return this.isNew?"new ":""};Call.prototype.superReference=function(o){var method,name;method=o.scope.method;if(!method){throw Error("cannot call super outside of a function")}name=method.name;if(!name){throw Error("cannot call super on an anonymous function.")}return method.klass?(""+(method.klass)+".__super__."+name):(""+name+".__super__.constructor")};Call.prototype.unfoldSoak=function(o){var _i,_len,_ref2,call,list,node;call=this;list=[];while(true){if(call.variable instanceof Call){list.push(call);call=call.variable;continue}if(!(call.variable instanceof Value)){break}list.push(call);if(!((call=call.variable.base) instanceof Call)){break}}for(_i=0,_len=(_ref2=list.reverse()).length;_i<_len;_i++){call=_ref2[_i];if(node){if(call.variable instanceof Call){call.variable=node}else{call.variable.base=node}}node=Value.unfoldSoak(o,call,"variable")}return node};Call.prototype.compileNode=function(o){var _i,_j,_len,_len2,_ref2,_ref3,_ref4,_ref5,_result,arg,args,left,node,rite,val;if(node=this.unfoldSoak(o)){return node.compile(o)}(((_ref2=this.variable)!=null)?(_ref2.tags.front=this.tags.front):undefined);if(this.exist){if(val=this.variable){if(!(val instanceof Value)){val=new Value(val)}_ref3=val.cacheReference(o),left=_ref3[0],rite=_ref3[1];rite=new Call(rite,this.args)}else{left=new Literal(this.superReference(o));rite=new Call(new Value(left),this.args);rite.isNew=this.isNew}left=("typeof "+(left.compile(o))+' !== "function"');rite=rite.compile(o);return("("+left+" ? undefined : "+rite+")")}for(_i=0,_len=(_ref4=this.args).length;_i<_len;_i++){arg=_ref4[_i];if(arg instanceof Splat){return this.compileSplat(o)}}args=(function(){_result=[];for(_j=0,_len2=(_ref5=this.args).length;_j<_len2;_j++){arg=_ref5[_j];_result.push((arg.parenthetical=true)&&arg.compile(o))}return _result}).call(this).join(", ");return this.isSuper?this.compileSuper(args,o):(""+(this.prefix())+(this.variable.compile(o))+"("+args+")")};Call.prototype.compileSuper=function(args,o){return""+(this.superReference(o))+".call(this"+(args.length?", ":"")+args+")"};Call.prototype.compileSplat=function(o){var base,fun,idt,name,ref,splatargs;splatargs=this.compileSplatArguments(o);if(this.isSuper){return(""+(this.superReference(o))+".apply(this, "+splatargs+")")}if(!this.isNew){if(!((base=this.variable) instanceof Value)){base=new Value(base)}if((name=base.properties.pop())&&base.isComplex()){ref=o.scope.freeVariable("this");fun=("("+ref+" = "+(base.compile(o))+")"+(name.compile(o)))}else{fun=(ref=base.compile(o));if(name){fun+=name.compile(o)}}return(""+fun+".apply("+ref+", "+splatargs+")")}idt=this.idt(1);return"(function(func, args, ctor) {\n"+idt+"ctor.prototype = func.prototype;\n"+idt+"var child = new ctor, result = func.apply(child, args);\n"+idt+'return typeof result === "object" ? result : child;\n'+(this.tab)+"})("+(this.variable.compile(o))+", "+splatargs+", function() {})"};return Call})();exports.Extends=(function(){Extends=(function(){function Extends(_arg,_arg2){this.parent=_arg2;this.child=_arg;Extends.__super__.constructor.call(this);return this}return Extends})();__extends(Extends,Base);Extends.prototype.children=["child","parent"];Extends.prototype.compileNode=function(o){var ref;ref=new Value(new Literal(utility("extends")));return(new Call(ref,[this.child,this.parent])).compile(o)};return Extends})();exports.Accessor=(function(){Accessor=(function(){function Accessor(_arg,tag){this.name=_arg;Accessor.__super__.constructor.call(this);this.prototype=tag==="prototype"?".prototype":"";this.soakNode=tag==="soak";return this}return Accessor})();__extends(Accessor,Base);Accessor.prototype.children=["name"];Accessor.prototype.compileNode=function(o){var name,namePart;name=this.name.compile(o);namePart=name.match(IS_STRING)?("["+name+"]"):("."+name);return this.prototype+namePart};Accessor.prototype.isComplex=NO;return Accessor})();exports.Index=(function(){Index=(function(){function Index(_arg){this.index=_arg;Index.__super__.constructor.call(this);return this}return Index})();__extends(Index,Base);Index.prototype.children=["index"];Index.prototype.compileNode=function(o){var idx,prefix;idx=this.index.compile(o);prefix=this.proto?".prototype":"";return""+prefix+"["+idx+"]"};Index.prototype.isComplex=function(){return this.index.isComplex()};return Index})();exports.Range=(function(){Range=(function(){function Range(_arg,_arg2,tag){this.to=_arg2;this.from=_arg;Range.__super__.constructor.call(this);this.exclusive=tag==="exclusive";this.equals=this.exclusive?"":"=";return this}return Range})();__extends(Range,Base);Range.prototype.children=["from","to"];Range.prototype.compileVariables=function(o){var _ref2,_ref3,_ref4,parts;o=merge(o,{top:true});_ref2=this.from.compileReference(o,{precompile:true}),this.from=_ref2[0],this.fromVar=_ref2[1];_ref3=this.to.compileReference(o,{precompile:true}),this.to=_ref3[0],this.toVar=_ref3[1];_ref4=[this.fromVar.match(SIMPLENUM),this.toVar.match(SIMPLENUM)],this.fromNum=_ref4[0],this.toNum=_ref4[1];parts=[];if(this.from!==this.fromVar){parts.push(this.from)}return this.to!==this.toVar?parts.push(this.to):undefined};Range.prototype.compileNode=function(o){var compare,idx,incr,intro,step,stepPart,vars;this.compileVariables(o);if(!o.index){return this.compileArray(o)}if(this.fromNum&&this.toNum){return this.compileSimple(o)}idx=del(o,"index");step=del(o,"step");vars=(""+idx+" = "+(this.from))+(this.to!==this.toVar?(", "+(this.to)):"");intro=("("+(this.fromVar)+" <= "+(this.toVar)+" ? "+idx);compare=(""+intro+" <"+(this.equals)+" "+(this.toVar)+" : "+idx+" >"+(this.equals)+" "+(this.toVar)+")");stepPart=step?step.compile(o):"1";incr=step?(""+idx+" += "+stepPart):(""+intro+" += "+stepPart+" : "+idx+" -= "+stepPart+")");return""+vars+"; "+compare+"; "+incr};Range.prototype.compileSimple=function(o){var _ref2,from,idx,step,to;_ref2=[+this.fromNum,+this.toNum],from=_ref2[0],to=_ref2[1];idx=del(o,"index");step=del(o,"step");step&&(step=(""+idx+" += "+(step.compile(o))));return from<=to?(""+idx+" = "+from+"; "+idx+" <"+(this.equals)+" "+to+"; "+(step||(""+idx+"++"))):(""+idx+" = "+from+"; "+idx+" >"+(this.equals)+" "+to+"; "+(step||(""+idx+"--")))};Range.prototype.compileArray=function(o){var _i,_ref2,_ref3,_result,body,clause,i,idt,post,pre,range,result,vars;if(this.fromNum&&this.toNum&&(Math.abs(this.fromNum-this.toNum)<=20)){range=(function(){_result=[];for(var _i=_ref2=+this.fromNum,_ref3=+this.toNum;_ref2<=_ref3?_i<=_ref3:_i>=_ref3;_ref2<=_ref3?_i+=1:_i-=1){_result.push(_i)}return _result}).call(this);if(this.exclusive){range.pop()}return("["+(range.join(", "))+"]")}idt=this.idt(1);i=o.scope.freeVariable("i");result=o.scope.freeVariable("result");pre=("\n"+idt+result+" = [];");if(this.fromNum&&this.toNum){o.index=i;body=this.compileSimple(o)}else{vars=(""+i+" = "+(this.from))+(this.to!==this.toVar?(", "+(this.to)):"");clause=(""+(this.fromVar)+" <= "+(this.toVar)+" ?");body=("var "+vars+"; "+clause+" "+i+" <"+(this.equals)+" "+(this.toVar)+" : "+i+" >"+(this.equals)+" "+(this.toVar)+"; "+clause+" "+i+" += 1 : "+i+" -= 1")}post=("{ "+result+".push("+i+"); }\n"+idt+"return "+result+";\n"+(o.indent));return"(function() {"+pre+"\n"+idt+"for ("+body+")"+post+"}).call(this)"};return Range})();exports.Slice=(function(){Slice=(function(){function Slice(_arg){this.range=_arg;Slice.__super__.constructor.call(this);return this}return Slice})();__extends(Slice,Base);Slice.prototype.children=["range"];Slice.prototype.compileNode=function(o){var from,to;from=this.range.from?this.range.from.compile(o):"0";to=this.range.to?this.range.to.compile(o):"";to+=(!to||this.range.exclusive?"":" + 1");if(to){to=", "+to}return".slice("+from+to+")"};return Slice})();exports.ObjectLiteral=(function(){ObjectLiteral=(function(){function ObjectLiteral(props){ObjectLiteral.__super__.constructor.call(this);this.objects=(this.properties=props||[]);return this}return ObjectLiteral})();__extends(ObjectLiteral,Base);ObjectLiteral.prototype.children=["properties"];ObjectLiteral.prototype.compileNode=function(o){var _i,_len,_ref2,_result,i,indent,join,lastNoncom,nonComments,obj,prop,props,top;top=del(o,"top");o.indent=this.idt(1);nonComments=(function(){_result=[];for(_i=0,_len=(_ref2=this.properties).length;_i<_len;_i++){prop=_ref2[_i];if(!(prop instanceof Comment)){_result.push(prop)}}return _result}).call(this);lastNoncom=last(nonComments);props=(function(){_result=[];for(i=0,_len=(_ref2=this.properties).length;i<_len;i++){prop=_ref2[i];_result.push((function(){join=i===this.properties.length-1?"":(prop===lastNoncom||prop instanceof Comment?"\n":",\n");indent=prop instanceof Comment?"":this.idt(1);if(prop instanceof Value&&prop.tags["this"]){prop=new Assign(prop.properties[0].name,prop,"object")}else{if(!(prop instanceof Assign)&&!(prop instanceof Comment)){prop=new Assign(prop,prop,"object")}}return indent+prop.compile(o)+join}).call(this))}return _result}).call(this);props=props.join("");obj=("{"+(props?"\n"+props+"\n"+this.idt():"")+"}");return this.tags.front?("("+obj+")"):obj};ObjectLiteral.prototype.assigns=function(name){var _i,_len,_ref2,prop;for(_i=0,_len=(_ref2=this.properties).length;_i<_len;_i++){prop=_ref2[_i];if(prop.assigns(name)){return true}}return false};return ObjectLiteral})();exports.ArrayLiteral=(function(){ArrayLiteral=(function(){function ArrayLiteral(_arg){this.objects=_arg;ArrayLiteral.__super__.constructor.call(this);this.objects||(this.objects=[]);return this}return ArrayLiteral})();__extends(ArrayLiteral,Base);ArrayLiteral.prototype.children=["objects"];ArrayLiteral.prototype.compileSplatLiteral=function(o){return Splat.compileSplattedArray(this.objects,o)};ArrayLiteral.prototype.compileNode=function(o){var _i,_len,_len2,_ref2,_ref3,code,i,obj,objects;o.indent=this.idt(1);for(_i=0,_len=(_ref2=this.objects).length;_i<_len;_i++){obj=_ref2[_i];if(obj instanceof Splat){return this.compileSplatLiteral(o)}}objects=[];for(i=0,_len2=(_ref3=this.objects).length;i<_len2;i++){obj=_ref3[i];code=obj.compile(o);objects.push(obj instanceof Comment?("\n"+code+"\n"+(o.indent)):(i===this.objects.length-1?code:code+", "))}objects=objects.join("");return 0= "+this.arglength);end=this.trailings.length?(", "+len+" - "+(this.trailings.length)):undefined;for(idx=0,_len=(_ref2=this.trailings).length;idx<_len;idx++){trailing=_ref2[idx];if(trailing.attach){assign=trailing.assign;trailing=new Literal(o.scope.freeVariable("arg"));assign.value=trailing}pos=this.trailings.length-idx;o.scope.assign(trailing.compile(o),"arguments["+variadic+" ? "+len+" - "+pos+" : "+(this.index+idx)+"]")}}return""+name+" = "+(utility("slice"))+".call(arguments, "+(this.index)+end+")"};Splat.prototype.compileValue=function(o,name,index,trailings){var trail;trail=trailings?(", "+name+".length - "+trailings):"";return""+(utility("slice"))+".call("+name+", "+index+trail+")"};Splat.compileSplattedArray=function(list,o){var _len,arg,args,code,end,i,prev;args=[];end=-1;for(i=0,_len=list.length;i<_len;i++){arg=list[i];code=arg.compile(o);prev=args[end];if(!(arg instanceof Splat)){if(prev&&starts(prev,"[")&&ends(prev,"]")){args[end]=(""+(prev.slice(0,-1))+", "+code+"]");continue}if(prev&&starts(prev,".concat([")&&ends(prev,"])")){args[end]=(""+(prev.slice(0,-2))+", "+code+"])");continue}code=("["+code+"]")}args[++end]=i===0?code:(".concat("+code+")")}return args.join("")};return Splat}).call(this);exports.While=(function(){While=(function(){function While(condition,opts){While.__super__.constructor.call(this);this.condition=((opts!=null)?opts.invert:undefined)?condition.invert():condition;this.guard=((opts!=null)?opts.guard:undefined);return this}return While})();__extends(While,Base);While.prototype.children=["condition","guard","body"];While.prototype.isStatement=YES;While.prototype.addBody=function(body){this.body=body;return this};While.prototype.makeReturn=function(){this.returns=true;return this};While.prototype.topSensitive=YES;While.prototype.compileNode=function(o){var cond,post,pre,rvar,set,top;top=del(o,"top")&&!this.returns;o.indent=this.idt(1);this.condition.parenthetical=true;cond=this.condition.compile(o);o.top=true;set="";if(!top){rvar=o.scope.freeVariable("result");set=(""+(this.tab)+rvar+" = [];\n");if(this.body){this.body=Push.wrap(rvar,this.body)}}pre=(""+set+(this.tab)+"while ("+cond+")");if(this.guard){this.body=Expressions.wrap([new If(this.guard,this.body)])}if(this.returns){post="\n"+new Return(new Literal(rvar)).compile(merge(o,{indent:this.idt()}))}else{post=""}return""+pre+" {\n"+(this.body.compile(o))+"\n"+(this.tab)+"}"+post};return While})();exports.Op=(function(){Op=(function(){function Op(op,first,second,flip){if(op==="new"){if(first instanceof Call){return first.newInstance()}if(first instanceof Code&&first.bound){first=new Parens(first)}}Op.__super__.constructor.call(this);this.operator=this.CONVERSIONS[op]||op;(this.first=first).tags.operation=true;if(second){(this.second=second).tags.operation=true}this.flip=!!flip;return this}return Op})();__extends(Op,Base);Op.prototype.CONVERSIONS={"==":"===","!=":"!==",of:"in"};Op.prototype.INVERSIONS={"!==":"===","===":"!=="};Op.prototype.CHAINABLE=["<",">",">=","<=","===","!=="];Op.prototype.ASSIGNMENT=["||=","&&=","?="];Op.prototype.PREFIX_OPERATORS=["new","typeof","delete"];Op.prototype.children=["first","second"];Op.prototype.isUnary=function(){return !this.second};Op.prototype.isComplex=function(){return this.operator!=="!"||this.first.isComplex()};Op.prototype.isMutator=function(){var _ref2;return ends(this.operator,"=")&&!((_ref2=this.operator)==="==="||_ref2==="!==")};Op.prototype.isChainable=function(){return include(this.CHAINABLE,this.operator)};Op.prototype.invert=function(){var _ref2;if(((_ref2=this.operator)==="==="||_ref2==="!==")){this.operator=this.INVERSIONS[this.operator];return this}else{return this.second?new Parens(this).invert():Op.__super__.invert.call(this)}};Op.prototype.toString=function(idt){return Op.__super__.toString.call(this,idt,this.constructor.name+" "+this.operator)};Op.prototype.compileNode=function(o){if(this.second){this.first.tags.front=this.tags.front}if(this.isChainable()&&this.first.unwrap() instanceof Op&&this.first.unwrap().isChainable()){return this.compileChain(o)}if(include(this.ASSIGNMENT,this.operator)){return this.compileAssignment(o)}if(this.isUnary()){return this.compileUnary(o)}if(this.operator==="?"){return this.compileExistence(o)}if(this.first instanceof Op&&this.first.isMutator()){this.first=new Parens(this.first)}if(this.second instanceof Op&&this.second.isMutator()){this.second=new Parens(this.second)}return[this.first.compile(o),this.operator,this.second.compile(o)].join(" ")};Op.prototype.compileChain=function(o){var _ref2,_ref3,first,second,shared;shared=this.first.unwrap().second;_ref2=shared.compileReference(o),this.first.second=_ref2[0],shared=_ref2[1];_ref3=[this.first.compile(o),this.second.compile(o),shared.compile(o)],first=_ref3[0],second=_ref3[1],shared=_ref3[2];return"("+first+") && ("+shared+" "+(this.operator)+" "+second+")"};Op.prototype.compileAssignment=function(o){var _ref2,left,rite;_ref2=this.first.cacheReference(o),left=_ref2[0],rite=_ref2[1];rite=new Assign(rite,this.second);return new Op(this.operator.slice(0,-1),left,rite).compile(o)};Op.prototype.compileExistence=function(o){var fst,ref;if(this.first.isComplex()){ref=o.scope.freeVariable("ref");fst=new Parens(new Assign(new Literal(ref),this.first))}else{fst=this.first;ref=fst.compile(o)}return new Existence(fst).compile(o)+(" ? "+ref+" : "+(this.second.compile(o)))};Op.prototype.compileUnary=function(o){var parts,space;space=include(this.PREFIX_OPERATORS,this.operator)?" ":"";parts=[this.operator,space,this.first.compile(o)];return(this.flip?parts.reverse():parts).join("")};return Op})();exports.In=(function(){In=(function(){function In(_arg,_arg2){this.array=_arg2;this.object=_arg;In.__super__.constructor.call(this);return this}return In})();__extends(In,Base);In.prototype.children=["object","array"];In.prototype.isArray=function(){return this.array instanceof Value&&this.array.isArray()};In.prototype.compileNode=function(o){var _ref2;_ref2=this.object.compileReference(o,{precompile:true}),this.obj1=_ref2[0],this.obj2=_ref2[1];return this.isArray()?this.compileOrTest(o):this.compileLoopTest(o)};In.prototype.compileOrTest=function(o){var _len,_ref2,_result,i,item,tests;tests=(function(){_result=[];for(i=0,_len=(_ref2=this.array.base.objects).length;i<_len;i++){item=_ref2[i];_result.push(""+(i?this.obj2:this.obj1)+" === "+(item.compile(o)))}return _result}).call(this);return"("+(tests.join(" || "))+")"};In.prototype.compileLoopTest=function(o){var _ref2,_ref3,i,l,prefix;_ref2=this.array.compileReference(o,{precompile:true}),this.arr1=_ref2[0],this.arr2=_ref2[1];_ref3=[o.scope.freeVariable("i"),o.scope.freeVariable("len")],i=_ref3[0],l=_ref3[1];prefix=this.obj1!==this.obj2?this.obj1+"; ":"";return"(function(){ "+prefix+"for (var "+i+"=0, "+l+"="+(this.arr1)+".length; "+i+"<"+l+"; "+i+"++) { if ("+(this.arr2)+"["+i+"] === "+(this.obj2)+") return true; } return false; }).call(this)"};return In})();exports.Try=(function(){Try=(function(){function Try(_arg,_arg2,_arg3,_arg4){this.ensure=_arg4;this.recovery=_arg3;this.error=_arg2;this.attempt=_arg;Try.__super__.constructor.call(this);return this}return Try})();__extends(Try,Base);Try.prototype.children=["attempt","recovery","ensure"];Try.prototype.isStatement=YES;Try.prototype.makeReturn=function(){if(this.attempt){this.attempt=this.attempt.makeReturn()}if(this.recovery){this.recovery=this.recovery.makeReturn()}return this};Try.prototype.compileNode=function(o){var attemptPart,catchPart,errorPart,finallyPart;o.indent=this.idt(1);o.top=true;attemptPart=this.attempt.compile(o);errorPart=this.error?(" ("+(this.error.compile(o))+") "):" ";catchPart=this.recovery?(" catch"+errorPart+"{\n"+(this.recovery.compile(o))+"\n"+(this.tab)+"}"):(!(this.ensure||this.recovery)?" catch (_e) {}":"");finallyPart=(this.ensure||"")&&" finally {\n"+this.ensure.compile(merge(o))+("\n"+(this.tab)+"}");return""+(this.tab)+"try {\n"+attemptPart+"\n"+(this.tab)+"}"+catchPart+finallyPart};return Try})();exports.Throw=(function(){Throw=(function(){function Throw(_arg){this.expression=_arg;Throw.__super__.constructor.call(this);return this}return Throw})();__extends(Throw,Base);Throw.prototype.children=["expression"];Throw.prototype.isStatement=YES;Throw.prototype.makeReturn=THIS;Throw.prototype.compileNode=function(o){return""+(this.tab)+"throw "+(this.expression.compile(o))+";"};return Throw})();exports.Existence=(function(){Existence=(function(){function Existence(_arg){this.expression=_arg;Existence.__super__.constructor.call(this);return this}return Existence})();__extends(Existence,Base);Existence.prototype.children=["expression"];Existence.prototype.compileNode=function(o){var code;code=this.expression.compile(o);code=IDENTIFIER.test(code)&&!o.scope.check(code)?("typeof "+code+' !== "undefined" && '+code+" !== null"):(""+code+" != null");return this.parenthetical?code:("("+code+")")};return Existence})();exports.Parens=(function(){Parens=(function(){function Parens(_arg){this.expression=_arg;Parens.__super__.constructor.call(this);return this}return Parens})();__extends(Parens,Base);Parens.prototype.children=["expression"];Parens.prototype.isStatement=function(o){return this.expression.isStatement(o)};Parens.prototype.isComplex=function(){return this.expression.isComplex()};Parens.prototype.topSensitive=YES;Parens.prototype.makeReturn=function(){return this.expression.makeReturn()};Parens.prototype.compileNode=function(o){var code,top;top=del(o,"top");this.expression.parenthetical=true;code=this.expression.compile(o);if(top&&this.expression.isPureStatement(o)){return code}if(this.parenthetical||this.isStatement(o)){return top?this.tab+code+";":code}return"("+code+")"};return Parens})();exports.For=(function(){For=(function(){function For(_arg,source,_arg2,_arg3){var _ref2;this.index=_arg3;this.name=_arg2;this.body=_arg;For.__super__.constructor.call(this);this.source=source.source,this.guard=source.guard,this.step=source.step;this.raw=!!source.raw;this.object=!!source.object;if(this.object){_ref2=[this.index,this.name],this.name=_ref2[0],this.index=_ref2[1]}this.pattern=this.name instanceof Value;if(this.index instanceof Value){throw new Error("index cannot be a pattern matching expression")}this.returns=false;return this}return For})();__extends(For,Base);For.prototype.children=["body","source","guard"];For.prototype.isStatement=YES;For.prototype.topSensitive=YES;For.prototype.makeReturn=function(){this.returns=true;return this};For.prototype.compileReturnValue=function(val,o){if(this.returns){return"\n"+new Return(new Literal(val)).compile(o)}if(val){return"\n"+val}return""};For.prototype.compileNode=function(o){var body,codeInBody,forPart,guardPart,idt1,index,ivar,lvar,name,namePart,range,ref,resultPart,returnResult,rvar,scope,source,sourcePart,stepPart,svar,topLevel,varPart,vars;topLevel=del(o,"top")&&!this.returns;range=this.source instanceof Value&&this.source.base instanceof Range&&!this.source.properties.length;source=range?this.source.base:this.source;codeInBody=this.body.contains(function(node){return node instanceof Code});scope=o.scope;name=this.name&&this.name.compile(o);index=this.index&&this.index.compile(o);if(name&&!this.pattern&&(range||!codeInBody)){scope.find(name,{immediate:true})}if(index){scope.find(index,{immediate:true})}if(!topLevel){rvar=scope.freeVariable("result")}ivar=range?name:index;if(!ivar||codeInBody){ivar=scope.freeVariable("i")}varPart="";guardPart="";body=Expressions.wrap([this.body]);idt1=this.idt(1);if(range){forPart=source.compile(merge(o,{index:ivar,step:this.step}))}else{svar=(sourcePart=this.source.compile(o));if((name||!this.raw)&&!(IDENTIFIER.test(svar)&&scope.check(svar,{immediate:true}))){sourcePart=(""+(ref=scope.freeVariable("ref"))+" = "+svar);if(!this.object){sourcePart=("("+sourcePart+")")}svar=ref}namePart=this.pattern?new Assign(this.name,new Literal(""+svar+"["+ivar+"]")).compile(merge(o,{top:true})):(name?(""+name+" = "+svar+"["+ivar+"]"):undefined);if(!this.object){lvar=scope.freeVariable("len");stepPart=this.step?(""+ivar+" += "+(this.step.compile(o))):(""+ivar+"++");forPart=(""+ivar+" = 0, "+lvar+" = "+sourcePart+".length; "+ivar+" < "+lvar+"; "+stepPart)}}resultPart=rvar?(""+(this.tab)+rvar+" = [];\n"):"";returnResult=this.compileReturnValue(rvar,o);if(!topLevel){body=Push.wrap(rvar,body)}if(this.guard){body=Expressions.wrap([new If(this.guard,body)])}if(codeInBody){if(range){body.unshift(new Literal("var "+name+" = "+ivar))}if(namePart){body.unshift(new Literal("var "+namePart))}if(index){body.unshift(new Literal("var "+index+" = "+ivar))}body=Closure.wrap(body,true)}else{if(namePart){varPart=(""+idt1+namePart+";\n")}}if(this.object){forPart=(""+ivar+" in "+sourcePart);if(!this.raw){guardPart=("\n"+idt1+"if (!"+(utility("hasProp"))+".call("+svar+", "+ivar+")) continue;")}}body=body.compile(merge(o,{indent:idt1,top:true}));vars=range?name:(""+name+", "+ivar);return""+resultPart+(this.tab)+"for ("+forPart+") {"+guardPart+"\n"+varPart+body+"\n"+(this.tab)+"}"+returnResult};return For})();exports.Switch=(function(){Switch=(function(){function Switch(_arg,_arg2,_arg3){this.otherwise=_arg3;this.cases=_arg2;this.subject=_arg;Switch.__super__.constructor.call(this);this.tags.subjectless=!this.subject;this.subject||(this.subject=new Literal("true"));return this}return Switch})();__extends(Switch,Base);Switch.prototype.children=["subject","cases","otherwise"];Switch.prototype.isStatement=YES;Switch.prototype.makeReturn=function(){var _i,_len,_ref2,pair;for(_i=0,_len=(_ref2=this.cases).length;_i<_len;_i++){pair=_ref2[_i];pair[1].makeReturn()}if(this.otherwise){this.otherwise.makeReturn()}return this};Switch.prototype.compileNode=function(o){var _i,_j,_len,_len2,_ref2,_ref3,block,code,condition,conditions,exprs,idt,pair;idt=(o.indent=this.idt(2));o.top=true;code=(""+(this.tab)+"switch ("+(this.subject.compile(o))+") {");for(_i=0,_len=(_ref2=this.cases).length;_i<_len;_i++){pair=_ref2[_i];conditions=pair[0],block=pair[1];exprs=block.expressions;for(_j=0,_len2=(_ref3=flatten([conditions])).length;_j<_len2;_j++){condition=_ref3[_j];if(this.tags.subjectless){condition=new Op("!!",new Parens(condition))}code+=("\n"+(this.idt(1))+"case "+(condition.compile(o))+":")}code+=("\n"+(block.compile(o)));if(!(last(exprs) instanceof Return)){code+=("\n"+idt+"break;")}}if(this.otherwise){code+=("\n"+(this.idt(1))+"default:\n"+(this.otherwise.compile(o)))}code+=("\n"+(this.tab)+"}");return code};return Switch})();exports.If=(function(){If=(function(){function If(condition,_arg,_arg2){this.tags=_arg2;this.body=_arg;this.tags||(this.tags={});this.condition=this.tags.invert?condition.invert():condition;this.elseBody=null;this.isChain=false;return this}return If})();__extends(If,Base);If.prototype.children=["condition","body","elseBody","assigner"];If.prototype.topSensitive=YES;If.prototype.bodyNode=function(){var _ref2;return(((_ref2=this.body)!=null)?_ref2.unwrap():undefined)};If.prototype.elseBodyNode=function(){var _ref2;return(((_ref2=this.elseBody)!=null)?_ref2.unwrap():undefined)};If.prototype.addElse=function(elseBody){if(this.isChain){this.elseBodyNode().addElse(elseBody)}else{this.isChain=elseBody instanceof If;this.elseBody=this.ensureExpressions(elseBody)}return this};If.prototype.isStatement=function(o){var _ref2;return this.statement||(this.statement=((o!=null)?o.top:undefined)||this.bodyNode().isStatement(o)||(((_ref2=this.elseBodyNode())!=null)?_ref2.isStatement(o):undefined))};If.prototype.compileCondition=function(o){this.condition.parenthetical=true;return this.condition.compile(o)};If.prototype.compileNode=function(o){return this.isStatement(o)?this.compileStatement(o):this.compileExpression(o)};If.prototype.makeReturn=function(){if(this.isStatement()){this.body&&(this.body=this.ensureExpressions(this.body.makeReturn()));this.elseBody&&(this.elseBody=this.ensureExpressions(this.elseBody.makeReturn()));return this}else{return new Return(this)}};If.prototype.ensureExpressions=function(node){return node instanceof Expressions?node:new Expressions([node])};If.prototype.compileStatement=function(o){var child,condO,ifPart,top;top=del(o,"top");child=del(o,"chainChild");condO=merge(o);o.indent=this.idt(1);o.top=true;ifPart=("if ("+(this.compileCondition(condO))+") {\n"+(this.body.compile(o))+"\n"+(this.tab)+"}");if(!child){ifPart=this.tab+ifPart}if(!this.elseBody){return ifPart}return ifPart+(this.isChain?" else "+this.elseBodyNode().compile(merge(o,{indent:this.tab,chainChild:true})):(" else {\n"+(this.elseBody.compile(o))+"\n"+(this.tab)+"}"))};If.prototype.compileExpression=function(o){var code,elsePart,ifPart;this.bodyNode().tags.operation=(this.condition.tags.operation=true);if(this.elseBody){this.elseBodyNode().tags.operation=true}ifPart=this.condition.compile(o)+" ? "+this.bodyNode().compile(o);elsePart=this.elseBody?this.elseBodyNode().compile(o):"undefined";code=(""+ifPart+" : "+elsePart);return this.tags.operation?("("+code+")"):code};return If})();Push={wrap:function(name,expressions){if(expressions.empty()||expressions.containsPureStatement()){return expressions}return Expressions.wrap([new Call(new Value(new Literal(name),[new Accessor(new Literal("push"))]),[expressions.unwrap()])])}};Closure={wrap:function(expressions,statement){var args,call,func,mentionsArgs,meth;if(expressions.containsPureStatement()){return expressions}func=new Parens(new Code([],Expressions.wrap([expressions])));args=[];if((mentionsArgs=expressions.contains(this.literalArgs))||(expressions.contains(this.literalThis))){meth=new Literal(mentionsArgs?"apply":"call");args=[new Literal("this")];if(mentionsArgs){args.push(new Literal("arguments"))}func=new Value(func,[new Accessor(meth)])}call=new Call(func,args);return statement?Expressions.wrap([call]):call},literalArgs:function(node){return node instanceof Literal&&node.value==="arguments"},literalThis:function(node){return node instanceof Literal&&node.value==="this"||node instanceof Code&&node.bound}};UTILITIES={"extends":'function(child, parent) {\n function ctor() { this.constructor = child; }\n ctor.prototype = parent.prototype;\n child.prototype = new ctor;\n if (typeof parent.extended === "function") parent.extended(child);\n child.__super__ = parent.prototype;\n}',bind:"function(func, context) {\n return function() { return func.apply(context, arguments); };\n}",hasProp:"Object.prototype.hasOwnProperty",slice:"Array.prototype.slice"};TAB=" ";TRAILING_WHITESPACE=/[ \t]+$/gm;IDENTIFIER=/^[$A-Za-z_][$\w]*$/;NUMBER=/^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i;SIMPLENUM=/^[+-]?\d+$/;IS_STRING=/^['"]/;utility=function(name){var ref;ref=("__"+name);Scope.root.assign(ref,UTILITIES[name]);return ref}}).call(this)};require["./coffee-script"]=new function(){var exports=this;(function(){var Lexer,compile,fs,lexer,parser,path;path=require("path");Lexer=require("./lexer").Lexer;parser=require("./parser").parser;if(require.extensions){fs=require("fs");require.extensions[".coffee"]=function(module,filename){var content;content=compile(fs.readFileSync(filename,"utf8"));return module._compile(content,filename)}}else{if(require.registerExtension){require.registerExtension(".coffee",function(content){return compile(content)})}}exports.VERSION="0.9.4";exports.helpers=require("./helpers");exports.compile=(compile=function(code,options){options||(options={});try{return(parser.parse(lexer.tokenize(code))).compile(options)}catch(err){if(options.fileName){err.message=("In "+(options.fileName)+", "+(err.message))}throw err}});exports.tokens=function(code,options){return lexer.tokenize(code,options)};exports.nodes=function(code,options){return parser.parse(lexer.tokenize(code,options))};exports.run=function(code,options){var root;root=module;while(root.parent){root=root.parent}root.filename=options.fileName;if(root.moduleCache){root.moduleCache={}}return path.extname(root.filename)!==".coffee"||require.extensions?root._compile(exports.compile(code,options),root.filename):root._compile(code,root.filename)};exports.eval=function(code,options){var __dirname,__filename;__filename=options.fileName;__dirname=path.dirname(__filename);return eval(exports.compile(code,options))};lexer=new Lexer;parser.lexer={lex:function(){var token;token=this.tokens[this.pos]||[""];this.pos+=1;this.yylineno=token[2];this.yytext=token[1];return token[0]},setInput:function(tokens){this.tokens=tokens;return(this.pos=0)},upcomingInput:function(){return""}};parser.yy=require("./nodes")}).call(this)};require["./browser"]=new function(){var exports=this;(function(){var CoffeeScript,runScripts;CoffeeScript=require("./coffee-script");CoffeeScript.require=require;CoffeeScript.eval=function(code,options){return eval(CoffeeScript.compile(code,options))};CoffeeScript.run=function(code,options){((options!=null)?(options.bare=true):undefined);return Function(CoffeeScript.compile(code,options))()};if(!(typeof window!=="undefined"&&window!==null)){return}CoffeeScript.load=function(url,options){var xhr;xhr=new (window.ActiveXObject||XMLHttpRequest)("Microsoft.XMLHTTP");xhr.open("GET",url,true);if("overrideMimeType" in xhr){xhr.overrideMimeType("text/plain")}xhr.onreadystatechange=function(){return xhr.readyState===4?CoffeeScript.run(xhr.responseText,options):undefined};return xhr.send(null)};runScripts=function(){var _i,_len,_ref;for(_i=0,_len=(_ref=document.getElementsByTagName("script")).length;_i<_len;_i++){(function(){var script=_ref[_i];return script.type==="text/coffeescript"?(script.src?CoffeeScript.load(script.src):setTimeout(function(){return CoffeeScript.run(script.innerHTML)})):undefined})()}return null};if(window.addEventListener){addEventListener("DOMContentLoaded",runScripts,false)}else{attachEvent("onload",runScripts)}}).call(this)};return require["./coffee-script"]}(); \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/extras/jsl.conf b/node_modules/jade/support/coffee-script/extras/jsl.conf new file mode 100644 index 0000000..fb41a61 --- /dev/null +++ b/node_modules/jade/support/coffee-script/extras/jsl.conf @@ -0,0 +1,44 @@ +# JavaScriptLint configuration file for CoffeeScript. + ++no_return_value # function {0} does not always return a value ++duplicate_formal # duplicate formal argument {0} +-equal_as_assign # test for equality (==) mistyped as assignment (=)?{0} ++var_hides_arg # variable {0} hides argument ++redeclared_var # redeclaration of {0} {1} +-anon_no_return_value # anonymous function does not always return a value ++missing_semicolon # missing semicolon ++meaningless_block # meaningless block; curly braces have no impact +-comma_separated_stmts # multiple statements separated by commas (use semicolons?) ++unreachable_code # unreachable code ++missing_break # missing break statement ++missing_break_for_last_case # missing break statement for last case in switch +-comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==) +-inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement ++useless_void # use of the void type may be unnecessary (void is always undefined) ++multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs ++use_of_label # use of label +-block_without_braces # block statement without curly braces ++leading_decimal_point # leading decimal point may indicate a number or an object member ++trailing_decimal_point # trailing decimal point may indicate a number or an object member ++octal_number # leading zeros make an octal number ++nested_comment # nested comment ++misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma ++ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement ++empty_statement # empty statement or extra semicolon +-missing_option_explicit # the "option explicit" control comment is missing ++partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag ++dup_option_explicit # duplicate "option explicit" control comment ++useless_assign # useless assignment ++ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity ++ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent) +-missing_default_case # missing default case in switch statement ++duplicate_case_in_switch # duplicate case in switch statements ++default_not_at_end # the default case is not at the end of the switch statement ++legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax ++jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax ++useless_comparison # useless comparison; comparing identical expressions ++with_statement # with statement hides undeclared variables; use temporary variable instead ++trailing_comma_in_array # extra comma is not recommended in array initializers ++assign_to_function_call # assignment to a function call ++parseint_missing_radix # parseInt missing radix parameter ++lambda_assign_requires_semicolon diff --git a/node_modules/jade/support/coffee-script/index.html b/node_modules/jade/support/coffee-script/index.html new file mode 100644 index 0000000..5b28b8b --- /dev/null +++ b/node_modules/jade/support/coffee-script/index.html @@ -0,0 +1,2225 @@ + + + + + + + + CoffeeScript + + + + + + +
+ + + +
+ + +

+ CoffeeScript is a little language that compiles into JavaScript. Think + of it as JavaScript's less ostentatious kid brother — the same genes, + roughly the same height, but a different sense of style. Apart from a handful of + bonus goodies, statements in CoffeeScript correspond one-to-one with their + equivalent in JavaScript, it's just another way of saying it. +

+ +

+ Disclaimer: + CoffeeScript is just for fun. Until it reaches 1.0, there are no guarantees + that the syntax won't change between versions. That said, + it compiles into clean JavaScript (the good parts) that can use existing + JavaScript libraries seamlessly, and passes through + JSLint without warnings. The compiled + output is pretty-printed and quite readable. +

+ +

+ Latest Version: + 0.9.4 +

+ +

+ + Mini Overview +

+ +

CoffeeScript on the left, compiled JavaScript output on the right.

+ +
# Assignment:
+number   = 42
+opposite = true
+
+# Conditions:
+number = -42 if opposite
+
+# Functions:
+square = (x) -> x * x
+
+# Arrays:
+list = [1, 2, 3, 4, 5]
+
+# Objects:
+math =
+  root:   Math.sqrt
+  square: square
+  cube:   (x) -> x * square x
+
+# Splats:
+race = (winner, runners...) ->
+  print winner, runners
+
+# Existence:
+alert "I knew it!" if elvis?
+
+# Array comprehensions:
+cubes = math.cube num for num in list
+
var _i, _len, _result, cubes, list, math, num, number, opposite, race, square;
+var __slice = Array.prototype.slice;
+number = 42;
+opposite = true;
+if (opposite) {
+  number = -42;
+}
+square = function(x) {
+  return x * x;
+};
+list = [1, 2, 3, 4, 5];
+math = {
+  root: Math.sqrt,
+  square: square,
+  cube: function(x) {
+    return x * square(x);
+  }
+};
+race = function(winner) {
+  var runners;
+  runners = __slice.call(arguments, 1);
+  return print(winner, runners);
+};
+if (typeof elvis !== "undefined" && elvis !== null) {
+  alert("I knew it!");
+}
+cubes = (function() {
+  _result = [];
+  for (_i = 0, _len = list.length; _i < _len; _i++) {
+    num = list[_i];
+    _result.push(math.cube(num));
+  }
+  return _result;
+})();
+

+ +

+ For a longer CoffeeScript example, check out + Underscore.coffee, a port + of the Underscore.js + library of helper functions. Underscore.coffee can pass the entire Underscore.js + test suite. The CoffeeScript version is faster than the original for a number + of methods (in general, due to the speed of CoffeeScript's array comprehensions), and + after being minified and gzipped, is only 241 bytes larger than the original + JavaScript version. + Additional examples are included in the source repository, inside the + examples folder. +

+ +

+ + Installation and Usage +

+ +

+ The CoffeeScript compiler is written in pure CoffeeScript, using a + small DSL + on top of the Jison parser generator, and is available + as a Node.js utility. The core compiler however, + does not depend on Node, and can be run in other server-side-JavaScript environments, + or in the browser (see "Try CoffeeScript", above). +

+ +

+ To install, first make sure you have a working copy of the latest tagged version of + Node.js, currently 0.1.102 or higher. + Then clone the CoffeeScript + source repository + from GitHub, or download the latest + release: 0.9.4. + To install the CoffeeScript compiler system-wide + under /usr/local, open the directory and run: +

+ +
+sudo bin/cake install
+ +

+ Alternatively, if you already have the + Node Package Manager installed, + you can use that to grab the latest CoffeeScript: +

+ +
+sudo npm install coffee-script
+ +

+ Both of these provide the coffee command, which will execute CoffeeScripts + under Node.js by default, but is also used to compile CoffeeScript + .coffee files into JavaScript, or to run an an interactive REPL. + When compiling to JavaScript, coffee writes the output + as .js files in the same directory by default, but output + can be customized with the following options: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-c, --compile + Compile a .coffee script into a .js JavaScript file + of the same name. +
-i, --interactive + Launch an interactive CoffeeScript session to try short snippets. + More pleasant if wrapped with + rlwrap. +
-o, --output [DIR] + Write out all compiled JavaScript files into the specified directory. + Use in conjunction with --compile or --watch. +
-w, --watch + Watch the modification times of the coffee-scripts, recompiling as + soon as a change occurs. +
-p, --print + Instead of writing out the JavaScript as a file, print it + directly to stdout. +
-l, --lint + If the jsl + (JavaScript Lint) + command is installed, use it + to check the compilation of a CoffeeScript file. (Handy in + conjunction with
--watch) +
-s, --stdio + Pipe in CoffeeScript to STDIN and get back JavaScript over STDOUT. + Good for use with processes written in other languages. An example:
+ cat src/cake.coffee | coffee -sc +
-e, --eval + Compile and print a little snippet of CoffeeScript directly from the + command line. For example:
coffee -e "puts num for num in [10..1]" +
-r, --require + Load a library before compiling or executing your script. Can be used + to hook in to the compiler (to add Growl notifications, for example). +
-b, --bare + Compile the JavaScript without the top-level function safety wrapper. + (Used for CoffeeScript as a Node.js module.) +
-t, --tokens + Instead of parsing the CoffeeScript, just lex it, and print out the + token stream: [IDENTIFIER square] [ASSIGN =] [PARAM_START (] ... +
-n, --nodes + Instead of compiling the CoffeeScript, just lex and parse it, and print + out the parse tree: +
+Expressions
+  Assign
+    Value "square"
+    Code "x"
+      Op *
+        Value "x"
+        Value "x"
+
+ +

+ Examples: +

+ +
+coffee -c path/to/script.coffee
+coffee --interactive
+coffee --watch --lint experimental.coffee
+coffee --print app/scripts/*.coffee > concatenation.js
+ +

+ + Language Reference +

+ +

+ + This reference is structured so that it can be read from top to bottom, + if you like. Later sections use ideas and syntax previously introduced. + Familiarity with JavaScript is assumed. + In all of the following examples, the source CoffeeScript is provided on + the left, and the direct compilation into JavaScript is on the right. + +

+ +

+ + Many of the examples can be run (where it makes sense) by pressing the "run" + button towards the bottom right. You can also paste examples into + "Try CoffeeScript" in the toolbar, and play with them from there. + +

+ + Significant Whitespace + CoffeeScript uses Python-style significant whitespace: You don't need to + use semicolons ; to terminate expressions, ending + the line will do just as well. Semicolons can still be used to fit + multiple expressions onto a single line. Instead of using curly braces + { } to delimit blocks of code (like functions, + if-statements, + switch, and try/catch), + use indentation. +

+ +

+ You don't need to use parentheses to invoke a function if you're passing + arguments:
print "coffee". Implicit parentheses wrap forwards + to the end of the line, or block expression. +

+ +

+ You can use newlines to break up your expression into smaller pieces, + as long as CoffeeScript can determine that the line hasn't finished yet, + because it ends with an operator or a dot ... seen most commonly + in jQuery-chaining style JavaScript. +

+ +

+ + Functions and Invocation + Functions are defined by a list of parameters, an arrow, and the + function body. The empty function looks like this: -> +

+
square = (x) -> x * x
+cube   = (x) -> square(x) * x
+
var cube, square;
+square = function(x) {
+  return x * x;
+};
+cube = function(x) {
+  return square(x) * x;
+};
+

+ +

+ + Objects and Arrays + Object and Array literals look very similar to their JavaScript cousins. + When you spread out each property on a separate line, the commas are + optional. Implicit objects may be created with indentation instead of + brackets, winding up looking quite similar to YAML. +

+
song = ["do", "re", "mi", "fa", "so"]
+
+singers = {Jagger: "Rock", Elvis: "Roll"}
+
+matrix = [
+  1, 0, 1
+  0, 0, 1
+  1, 1, 0
+]
+
+kids =
+  brother:
+    name: "Max"
+    age:  11
+  sister:
+    name: "Ida"
+    age:  9
+
var kids, matrix, singers, song;
+song = ["do", "re", "mi", "fa", "so"];
+singers = {
+  Jagger: "Rock",
+  Elvis: "Roll"
+};
+matrix = [1, 0, 1, 0, 0, 1, 1, 1, 0];
+kids = {
+  brother: {
+    name: "Max",
+    age: 11
+  },
+  sister: {
+    name: "Ida",
+    age: 9
+  }
+};
+

+

+ In JavaScript, you can't use reserved words, like class, as properties + of an object, without quoting them as strings. CoffeeScript notices and quotes + them for you, so you don't have to worry about it (say, when using jQuery). +

+
$('.account').css class: 'active'
+
$('.account').css({
+  "class": 'active'
+});
+

+ +

+ + Lexical Scoping and Variable Safety + The CoffeeScript compiler takes care to make sure that all of your variables + are properly declared within lexical scope — you never need to write + var yourself. +

+
outer = 1
+changeNumbers = ->
+  inner = -1
+  outer = 10
+inner = changeNumbers()
+
var changeNumbers, inner, outer;
+outer = 1;
+changeNumbers = function() {
+  var inner;
+  inner = -1;
+  return (outer = 10);
+};
+inner = changeNumbers();
+

+

+ Notice how all of the variable declarations have been pushed up to + the top of the closest scope, the first time they appear. + outer is not redeclared within the inner function, because it's + already in scope; inner within the function, on the other hand, + should not be able to change the value of the external variable of the same name, and + therefore has a declaration of its own. +

+

+ This behavior is effectively identical to Ruby's scope for local variables. + Because you don't have direct access to the var keyword, + it's impossible to shadow an outer variable on purpose, you may only refer + to it. So be careful that you're not reusing the name of an external + variable accidentally, if you're writing a deeply nested function. +

+

+ Although suppressed within this documentation for clarity, all + CoffeeScript output is wrapped in an anonymous function: + (function(){ ... })(); This safety wrapper, combined with the + automatic generation of the var keyword, make it exceedingly difficult + to pollute the global namespace by accident. +

+

+ If you'd like to create top-level variables for other scripts to use, + attach them as properties on window, or on the exports + object in CommonJS. The existential operator (covered below), gives you a + reliable way to figure out where to add them, if you're targeting both + CommonJS and the browser: root = exports ? this +

+ +

+ + If, Else, Unless, and Conditional Assignment + If/else statements can be written without the use of parentheses and + curly brackets. As with functions and other block expressions, + multi-line conditionals are delimited by indentation. There's also a handy + postfix form, with the if or unless at the end. +

+

+ CoffeeScript can compile if statements into JavaScript expressions, + using the ternary operator when possible, and closure wrapping otherwise. There + is no explicit ternary statement in CoffeeScript — you simply use + a regular if statement inline. +

+
mood = greatlyImproved if singing
+
+if happy and knowsIt
+  clapsHands()
+  chaChaCha()
+else
+  showIt()
+
+date = if friday then sue else jill
+
+options or= defaults
+
var date, mood, options;
+if (singing) {
+  mood = greatlyImproved;
+}
+if (happy && knowsIt) {
+  clapsHands();
+  chaChaCha();
+} else {
+  showIt();
+}
+date = friday ? sue : jill;
+options || (options = defaults);
+

+ +

+ + Aliases + Because the == operator frequently causes undesirable coercion, + is intransitive, and has a different meaning than in other languages, + CoffeeScript compiles == into ===, and != into + !==. + In addition, is compiles into ===, + and isnt into !==. +

+

+ You can use not as an alias for !. +

+

+ For logic, and compiles to &&, and or + into ||. +

+

+ Instead of a newline or semicolon, then can be used to separate + conditions from expressions, in while, + if/else, and switch/when statements. +

+

+ As in YAML, on and yes + are the same as boolean true, while off and no are boolean false. +

+

+ For single-line statements, unless can be used as the inverse of if. +

+

+ As a shortcut for this.property, you can use @property. +

+

+ You can use in to test for array presence, and of to + test for JavaScript object-key presence. +

+
launch() if ignition is on
+
+volume = 10 if band isnt SpinalTap
+
+letTheWildRumpusBegin() unless answer is no
+
+if car.speed < limit then accelerate()
+
+winner = yes if pick in [47, 92, 13]
+
+print inspect "My name is " + @name
+
var volume, winner;
+if (ignition === true) {
+  launch();
+}
+if (band !== SpinalTap) {
+  volume = 10;
+}
+if (answer !== false) {
+  letTheWildRumpusBegin();
+}
+if (car.speed < limit) {
+  accelerate();
+}
+if ((47 === pick || 92 === pick || 13 === pick)) {
+  winner = true;
+}
+print(inspect("My name is " + this.name));
+

+ +

+ + Splats... + The JavaScript arguments object is a useful way to work with + functions that accept variable numbers of arguments. CoffeeScript provides + splats ..., both for function definition as well as invocation, + making variable numbers of arguments a little bit more palatable. +

+
gold = silver = rest = "unknown"
+
+awardMedals = (first, second, others...) ->
+  gold   = first
+  silver = second
+  rest   = others
+
+contenders = [
+  "Michael Phelps"
+  "Liu Xiang"
+  "Yao Ming"
+  "Allyson Felix"
+  "Shawn Johnson"
+  "Roman Sebrle"
+  "Guo Jingjing"
+  "Tyson Gay"
+  "Asafa Powell"
+  "Usain Bolt"
+]
+
+awardMedals contenders...
+
+alert "Gold: " + gold
+alert "Silver: " + silver
+alert "The Field: " + rest
+
var awardMedals, contenders, gold, rest, silver;
+var __slice = Array.prototype.slice;
+gold = (silver = (rest = "unknown"));
+awardMedals = function(first, second) {
+  var others;
+  others = __slice.call(arguments, 2);
+  gold = first;
+  silver = second;
+  return (rest = others);
+};
+contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"];
+awardMedals.apply(awardMedals, contenders);
+alert("Gold: " + gold);
+alert("Silver: " + silver);
+alert("The Field: " + rest);
+

+ +

+ + While, Until, and Loop + The only low-level loop that CoffeeScript provides is the while loop. The + main difference from JavaScript is that the while loop can be used + as an expression, returning an array containing the result of each iteration + through the loop. +

+
# Econ 101
+if this.studyingEconomics
+  buy()  while supply > demand
+  sell() until supply > demand
+
+# Nursery Rhyme
+num = 6
+lyrics = while num -= 1
+  num + " little monkeys, jumping on the bed.
+    One fell out and bumped his head."
+
var _result, lyrics, num;
+if (this.studyingEconomics) {
+  while (supply > demand) {
+    buy();
+  }
+  while (!(supply > demand)) {
+    sell();
+  }
+}
+num = 6;
+lyrics = (function() {
+  _result = [];
+  while (num -= 1) {
+    _result.push(num + " little monkeys, jumping on the bed.    One fell out and bumped his head.");
+  }
+  return _result;
+})();
+

+

+ For readability, the until keyword is equivalent to while not, + and the loop keyword is equivalent to while true. + Other JavaScript loops, such as for loops and do-while loops + can be mimicked by variations on loop, but the hope is that you + won't need to do that with CoffeeScript, either because you're using + each (forEach) style iterators, or... +

+ +

+ + Comprehensions (Arrays, Objects, and Ranges) + For your looping needs, CoffeeScript provides array comprehensions + similar to Python's. They replace (and compile into) for loops, with + optional guard clauses and the value of the current array index. + Unlike for loops, array comprehensions are expressions, and can be returned + and assigned. They should be able to handle most places where you otherwise + would use a loop, each/forEach, map, or select/filter. +

+
# Eat lunch.
+lunch = eat food for food in ['toast', 'cheese', 'wine']
+
+# Naive collision detection.
+for roid, pos in asteroids
+  for roid2 in asteroids when roid isnt roid2
+    roid.explode() if roid.overlaps roid2
+
var _i, _len, _len2, _ref, _result, food, lunch, pos, roid, roid2;
+lunch = (function() {
+  _result = []; _ref = ['toast', 'cheese', 'wine'];
+  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+    food = _ref[_i];
+    _result.push(eat(food));
+  }
+  return _result;
+})();
+for (pos = 0, _len = asteroids.length; pos < _len; pos++) {
+  roid = asteroids[pos];
+  for (_i = 0, _len2 = asteroids.length; _i < _len2; _i++) {
+    roid2 = asteroids[_i];
+    if (roid !== roid2) {
+      if (roid.overlaps(roid2)) {
+        roid.explode();
+      }
+    }
+  }
+}
+

+

+ If you know the start and end of your loop, or would like to step through + in fixed-size increments, you can use a range to specify the start and + end of your comprehension. +

+
countdown = num for num in [10..1]
+
+deliverEggs = ->
+  for i in [0...eggs.length] by 12
+    dozen = eggs[i...i+12]
+    deliver new eggCarton dozen
+
var _result, countdown, deliverEggs, num;
+countdown = (function() {
+  _result = [];
+  for (num = 10; num >= 1; num--) {
+    _result.push(num);
+  }
+  return _result;
+})();
+deliverEggs = function() {
+  var _ref, _result2, dozen, i;
+  _result2 = []; _ref = eggs.length;
+  for (i = 0; (0 <= _ref ? i < _ref : i > _ref); i += 12) {
+    _result2.push((function() {
+      dozen = eggs.slice(i, i + 12);
+      return deliver(new eggCarton(dozen));
+    })());
+  }
+  return _result2;
+};
+

+

+ Comprehensions can also be used to iterate over the keys and values in + an object. Use of to signal comprehension over the properties of + an object instead of the values in an array. +

+
yearsOld = max: 10, ida: 9, tim: 11
+
+ages = for child, age of yearsOld
+  child + " is " + age
+
var _result, age, ages, child, yearsOld;
+var __hasProp = Object.prototype.hasOwnProperty;
+yearsOld = {
+  max: 10,
+  ida: 9,
+  tim: 11
+};
+ages = (function() {
+  _result = [];
+  for (child in yearsOld) {
+    if (!__hasProp.call(yearsOld, child)) continue;
+    age = yearsOld[child];
+    _result.push(child + " is " + age);
+  }
+  return _result;
+})();
+

+

+ By default, object comprehensions are safe, and use a hasOwnProperty + check to make sure that you're dealing with properties on the current + object. If you'd like the regular JavaScript
for (key in obj) ... + loop, for speed or for another reason, you can use
+ for all key, value of object in CoffeeScript. +

+ +

+ + Array Slicing and Splicing with Ranges + CoffeeScript borrows Ruby's + range syntax + for extracting slices of arrays. With two dots (3..5), the range + is inclusive: the first argument is the index of the first element in + the slice, and the second is the index of the last one. Three dots signify + a range that excludes the end. +

+
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+threeToSix = numbers[3..6]
+
+copy = numbers[0...numbers.length]
+
+
var copy, numbers, threeToSix;
+numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+threeToSix = numbers.slice(3, 6 + 1);
+copy = numbers.slice(0, numbers.length);
+

+

+ The same syntax can be used with assignment to replace a segment of an + array with new values (to splice it). +

+
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+numbers[3..6] = [-3, -4, -5, -6]
+
+
+
var _ref, numbers;
+numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+([].splice.apply(numbers, [3, 6 - 3 + 1].concat(_ref = [-3, -4, -5, -6])), _ref);
+

+ +

+ + Everything is an Expression (at least, as much as possible) + You might have noticed how even though we don't add return statements + to CoffeeScript functions, they nonetheless return their final value. + The CoffeeScript compiler tries to make sure that all statements in the + language can be used as expressions. Watch how the return gets + pushed down into each possible branch of execution, in the function + below. +

+
grade = (student) ->
+  if student.excellentWork
+    "A+"
+  else if student.okayStuff
+    if student.triedHard then "B" else "B-"
+  else
+    "C"
+
+eldest = if 24 > 21 then "Liz" else "Ike"
+
var eldest, grade;
+grade = function(student) {
+  return student.excellentWork ? "A+" : (student.okayStuff ? (student.triedHard ? "B" : "B-") : "C");
+};
+eldest = 24 > 21 ? "Liz" : "Ike";
+

+

+ Even though functions will always return their final value, it's both possible + and encouraged to return early from a function body writing out the explicit + return (return value), when you know that you're done. +

+

+ Because variable declarations occur at the top of scope, assignment can + be used within expressions, even for variables that haven't been seen before: +

+
six = (one = 1) + (two = 2) + (three = 3)
+
var one, six, three, two;
+six = (one = 1) + (two = 2) + (three = 3);
+

+

+ Things that would otherwise be statements in JavaScript, when used + as part of an expression in CoffeeScript, are converted into expressions + by wrapping them in a closure. This lets you do useful things, like assign + the result of a comprehension to a variable: +

+
# The first ten global properties.
+
+globals = (name for name of window)[0...10]
+
var _result, globals, name;
+var __hasProp = Object.prototype.hasOwnProperty;
+globals = (function() {
+  _result = [];
+  for (name in window) {
+    if (!__hasProp.call(window, name)) continue;
+    _result.push(name);
+  }
+  return _result;
+})().slice(0, 10);
+

+

+ As well as silly things, like passing a try/catch statement directly + into a function call: +

+
alert(
+  try
+    nonexistent / undefined
+  catch error
+    "And the error is ... " + error
+)
+
alert((function() {
+  try {
+    return nonexistent / undefined;
+  } catch (error) {
+    return "And the error is ... " + error;
+  }
+})());
+

+

+ There are a handful of statements in JavaScript that can't be meaningfully + converted into expressions, namely break, continue, + and return. If you make use of them within a block of code, + CoffeeScript won't try to perform the conversion. +

+ +

+ + The Existential Operator + It's a little difficult to check for the existence of a variable in + JavaScript. if (variable) ... comes close, but fails for zero, + the empty string, and false. CoffeeScript's existential operator ? returns true unless + a variable is null or undefined, which makes it analogous + to Ruby's nil? +

+

+ It can also be used for safer conditional assignment than ||= + provides, for cases where you may be handling numbers or strings. +

+
solipsism = true if mind? and not world?
+
+speed ?= 140
+
+
+
+
+
+
var solipsism, speed;
+if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) {
+  solipsism = true;
+}
+(typeof speed !== "undefined" && speed !== null) ? speed : (speed = 140);
+

+

+ The accessor variant of the existential operator ?. can be used to soak + up null references in a chain of properties. Use it instead + of the dot accessor . in cases where the base value may be null + or undefined. If all of the properties exist then you'll get the expected + result, if the chain is broken, undefined is returned instead of + the TypeError that would be raised otherwise. +

+
lottery.drawWinner()?.address?.zipcode
+
var _ref, _ref2;
+(((_ref = lottery.drawWinner()) != null) ? (((_ref2 = _ref.address) != null) ? _ref2.zipcode : undefined) : undefined);
+

+

+ Soaking up nulls is similar to Ruby's + andand gem, and to the + safe navigation operator + in Groovy. +

+ +

+ + Classes, Inheritance, and Super + JavaScript's prototypal inheritance has always been a bit of a + brain-bender, with a whole family tree of libraries that provide a cleaner + syntax for classical inheritance on top of JavaScript's prototypes: + Base2, + Prototype.js, + JS.Class, etc. + The libraries provide syntactic sugar, but the built-in inheritance would + be completely usable if it weren't for a couple of small exceptions: + it's awkward to call super (the prototype object's + implementation of the current function), and it's awkward to correctly + set the prototype chain. +

+

+ Instead of repetitively attaching functions to a prototype, CoffeeScript + provides a basic class structure that allows you to name your class, + set the superclass, assign prototypal properties, and define the constructor, + in a single assignable expression. +

+
class Animal
+  constructor: (@name) ->
+
+  move: (meters) ->
+    alert @name + " moved " + meters + "m."
+
+class Snake extends Animal
+  move: ->
+    alert "Slithering..."
+    super 5
+
+class Horse extends Animal
+  move: ->
+    alert "Galloping..."
+    super 45
+
+sam = new Snake "Sammy the Python"
+tom = new Horse "Tommy the Palomino"
+
+sam.move()
+tom.move()
+
+
+
+
+
var Animal, Horse, Snake, sam, tom;
+var __extends = function(child, parent) {
+  var ctor = function() {};
+  ctor.prototype = parent.prototype;
+  child.prototype = new ctor();
+  child.prototype.constructor = child;
+  if (typeof parent.extended === "function") parent.extended(child);
+  child.__super__ = parent.prototype;
+};
+Animal = (function() {
+  return function Animal(_arg) {
+    this.name = _arg;
+    return this;
+  };
+})();
+Animal.prototype.move = function(meters) {
+  return alert(this.name + " moved " + meters + "m.");
+};
+Snake = (function() {
+  return function Snake() {
+    return Animal.apply(this, arguments);
+  };
+})();
+__extends(Snake, Animal);
+Snake.prototype.move = function() {
+  alert("Slithering...");
+  return Snake.__super__.move.call(this, 5);
+};
+Horse = (function() {
+  return function Horse() {
+    return Animal.apply(this, arguments);
+  };
+})();
+__extends(Horse, Animal);
+Horse.prototype.move = function() {
+  alert("Galloping...");
+  return Horse.__super__.move.call(this, 45);
+};
+sam = new Snake("Sammy the Python");
+tom = new Horse("Tommy the Palomino");
+sam.move();
+tom.move();
+

+

+ If structuring your prototypes classically isn't your cup of tea, CoffeeScript + provides a couple of lower-level conveniences. The extends operator + helps with proper prototype setup, :: gives you + quick access to an object's prototype, and super() + is converted into a call against the immediate ancestor's method of the same name. +

+
String::dasherize = ->
+  this.replace /_/g, "-"
+
String.prototype.dasherize = function() {
+  return this.replace(/_/g, "-");
+};
+

+

+ Finally, you may assign Class-level (static) properties within a class + definition by using
@property: value +

+ +

+ + Pattern Matching (Destructuring Assignment) + To make extracting values from complex arrays and objects more convenient, + CoffeeScript implements ECMAScript Harmony's proposed + destructuring assignment + syntax. When you assign an array or object literal to a value, CoffeeScript + breaks up and matches both sides against each other, assigning the values + on the right to the variables on the left. In the simplest case, it can be + used for parallel assignment: +

+
theBait   = 1000
+theSwitch = 0
+
+[theBait, theSwitch] = [theSwitch, theBait]
+
var _ref, theBait, theSwitch;
+theBait = 1000;
+theSwitch = 0;
+_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];
+

+

+ But it's also helpful for dealing with functions that return multiple + values. +

+
weatherReport = (location) ->
+  # Make an Ajax request to fetch the weather...
+  [location, 72, "Mostly Sunny"]
+
+[city, temp, forecast] = weatherReport "Berkeley, CA"
+
var _ref, city, forecast, temp, weatherReport;
+weatherReport = function(location) {
+  return [location, 72, "Mostly Sunny"];
+};
+_ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2];
+

+

+ Pattern matching can be used with any depth of array and object nesting, + to help pull out deeply nested properties. +

+
futurists =
+  sculptor: "Umberto Boccioni"
+  painter:  "Vladimir Burliuk"
+  poet:
+    name:   "F.T. Marinetti"
+    address: [
+      "Via Roma 42R"
+      "Bellagio, Italy 22021"
+    ]
+
+{poet: {name, address: [street, city]}} = futurists
+
var _ref, _ref2, city, futurists, name, street;
+futurists = {
+  sculptor: "Umberto Boccioni",
+  painter: "Vladimir Burliuk",
+  poet: {
+    name: "F.T. Marinetti",
+    address: ["Via Roma 42R", "Bellagio, Italy 22021"]
+  }
+};
+_ref = futurists.poet, name = _ref.name, _ref2 = _ref.address, street = _ref2[0], city = _ref2[1];
+

+

+ Pattern matching can even be combined with splats. +

+
tag = "<impossible>"
+
+[open, contents..., close] = tag.split("")
+
+
+
+
+
var _ref, close, contents, open, tag;
+var __slice = Array.prototype.slice;
+tag = "<impossible>";
+_ref = tag.split(""), open = _ref[0], contents = __slice.call(_ref, 1, _ref.length - 1), close = _ref[_ref.length - 1];
+

+ +

+ + Function binding + In JavaScript, the this keyword is dynamically scoped to mean the + object that the current function is attached to. If you pass a function as + as callback, or attach it to a different object, the original value of this + will be lost. If you're not familiar with this behavior, + this Digital Web article + gives a good overview of the quirks. +

+

+ The fat arrow => can be used to both define a function, and to bind + it to the current value of this, right on the spot. This is helpful + when using callback-based libraries like Prototype or jQuery, for creating + iterator functions to pass to each, or event-handler functions + to use with bind. Functions created with the fat arrow are able to access + properties of the this where they're defined. +

+
Account = (customer, cart) ->
+  @customer = customer
+  @cart = cart
+
+  $('.shopping_cart').bind 'click', (event) =>
+    @customer.purchase @cart
+
var Account;
+var __bind = function(func, context) {
+  return function() { return func.apply(context, arguments); };
+};
+Account = function(customer, cart) {
+  this.customer = customer;
+  this.cart = cart;
+  return $('.shopping_cart').bind('click', __bind(function(event) {
+    return this.customer.purchase(this.cart);
+  }, this));
+};
+

+

+ If we had used -> in the callback above, @customer would + have referred to the undefined "customer" property of the DOM element, + and trying to call purchase() on it would have raised an exception. +

+ +

+ + Embedded JavaScript + Hopefully, you'll never need to use it, but if you ever need to intersperse + snippets of JavaScript within your CoffeeScript, you can + use backticks to pass it straight through. +

+
hi = `function() {
+  return [document.title, "Hello JavaScript"].join(": ");
+}`
+
+
+
var hi;
+hi = function() {
+  return [document.title, "Hello JavaScript"].join(": ");
+};
+

+ +

+ + Switch/When/Else + Switch statements in JavaScript are a bit awkward. You need to + remember to break at the end of every case statement to + avoid accidentally falling through to the default case. + CoffeeScript prevents accidental fall-through, and can convert the switch + into a returnable, assignable expression. The format is: switch condition, + when clauses, else the default case. +

+

+ As in Ruby, switch statements in CoffeeScript can take multiple + values for each when clause. If any of the values match, the clause + runs. +

+
switch day
+  when "Mon" then go work
+  when "Tue" then go relax
+  when "Thu" then go iceFishing
+  when "Fri", "Sat"
+    if day is bingoDay
+      go bingo
+      go dancing
+  when "Sun" then go church
+  else go work
+
switch (day) {
+  case "Mon":
+    go(work);
+    break;
+  case "Tue":
+    go(relax);
+    break;
+  case "Thu":
+    go(iceFishing);
+    break;
+  case "Fri":
+  case "Sat":
+    if (day === bingoDay) {
+      go(bingo);
+      go(dancing);
+    }
+    break;
+  case "Sun":
+    go(church);
+    break;
+  default:
+    go(work);
+}
+

+ +

+ + Try/Catch/Finally + Try/catch statements are just about the same as JavaScript (although + they work as expressions). +

+
try
+  allHellBreaksLoose()
+  catsAndDogsLivingTogether()
+catch error
+  print error
+finally
+  cleanUp()
+
try {
+  allHellBreaksLoose();
+  catsAndDogsLivingTogether();
+} catch (error) {
+  print(error);
+} finally {
+  cleanUp();
+}
+

+ +

+ + Chained Comparisons + CoffeeScript borrows + chained comparisons + from Python — making it easy to test if a value falls within a + certain range. +

+
cholesterol = 127
+
+healthy = 200 > cholesterol > 60
+
+
+
var cholesterol, healthy;
+cholesterol = 127;
+healthy = (200 > cholesterol) && (cholesterol > 60);
+

+ +

+ + String and RegExp Interpolation + Ruby-style string interpolation is included in CoffeeScript. Double-quoted + strings allow for interpolated values, while single-quoted strings are literal. +

+
author = "Wittgenstein"
+quote  = "A picture is a fact. -- #{author}"
+
var author, quote;
+author = "Wittgenstein";
+quote = ("A picture is a fact. -- " + author);
+

+

+ And arbitrary expressions can be interpolated by using brackets #{ ... }
+ Interpolation works the same way within regular expressions. +

+
sentence = "#{ 22 / 7 } is a decent approximation of π"
+
+sep   = "[.\\/\\- ]"
+dates = /\d+#{sep}\d+#{sep}\d+/g
+
+
+
var dates, sentence, sep;
+sentence = ("" + (22 / 7) + " is a decent approximation of π");
+sep = "[.\\/\\- ]";
+dates = /\d+#{sep}\d+#{sep}\d+/g;
+

+ +

+ + Multiline Strings, Heredocs, and Block Comments + Multiline strings are allowed in CoffeeScript. +

+
mobyDick = "Call me Ishmael. Some years ago --
+ never mind how long precisely -- having little
+ or no money in my purse, and nothing particular
+ to interest me on shore, I thought I would sail
+ about a little and see the watery part of the
+ world..."
+
+
+
var mobyDick;
+mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...";
+

+

+ Heredocs can be used to hold formatted or indentation-sensitive text + (or, if you just don't feel like escaping quotes and apostrophes). The + indentation level that begins the heredoc is maintained throughout, so + you can keep it all aligned with the body of your code. +

+
html = '''
+       <strong>
+         cup of coffeescript
+       </strong>
+       '''
+
var html;
+html = '<strong>\n  cup of coffeescript\n</strong>';
+

+

+ Double-quoted heredocs, like double-quoted strings, allow interpolation. +

+

+ Sometimes you'd like to pass a block comment through to the generated + JavaScript. For example, when you need to embed a licensing header at + the top of a file. Block comments, which mirror the syntax for heredocs, + are preserved in the generated code. +

+
###
+CoffeeScript Compiler v0.9.4
+Released under the MIT License
+###
+
/*
+CoffeeScript Compiler v0.9.4
+Released under the MIT License
+*/
+

+ +

+ + Cake, and Cakefiles +

+ +

+ CoffeeScript includes a simple build system similar to + Make and + Rake. Naturally, + it's called Cake, and is used for the build and test tasks for the CoffeeScript + language itself. Tasks are defined in a file named Cakefile, and + can be invoked by running cake taskname from within the directory. + To print a list of all the tasks and options, just run cake. +

+ +

+ Task definitions are written in CoffeeScript, so you can put arbitrary code + in your Cakefile. Define a task with a name, a long description, and the + function to invoke when the task is run. If your task takes a command-line + option, you can define the option with short and long flags, and it will + be made available in the options object. Here's a task that uses + the Node.js API to rebuild CoffeeScript's parser: +

+
fs = require 'fs'
+
+option '-o', '--output [DIR]', 'directory for compiled code'
+
+task 'build:parser', 'rebuild the Jison parser', (options) ->
+  require 'jison'
+  code = require('./lib/grammar').parser.generate()
+  dir  = options.output or 'lib'
+  fs.writeFile "#{dir}/parser.js", code
+
var fs;
+fs = require('fs');
+option('-o', '--output [DIR]', 'directory for compiled code');
+task('build:parser', 'rebuild the Jison parser', function(options) {
+  var code, dir;
+  require('jison');
+  code = require('./lib/grammar').parser.generate();
+  dir = options.output || 'lib';
+  return fs.writeFile("" + dir + "/parser.js", code);
+});
+

+

+ If you need to invoke one task before another — for example, running + build before test, you can use the invoke function: + invoke 'build' +

+ +

+ + "text/coffeescript" Script Tags +

+ +

+ While it's not recommended for serious use, CoffeeScripts may be included + directly within the browser using <script type="text/coffeescript"> + tags. The source includes a compressed and minified version of the compiler + (Download current version here, 43k when gzipped) + as extras/coffee-script.js. Include this file on a page with + inline CoffeeScript tags, and it will compile and evaluate them in order. +

+ +

+ In fact, the little bit of glue script that runs "Try CoffeeScript" above, + as well as jQuery for the menu, is implemented in just this way. + View source and look at the bottom of the page to see the example. + Including the script also gives you access to CoffeeScript.compile() + so you can pop open Firebug and try compiling some strings. +

+ +

+ The usual caveats about CoffeeScript apply — your inline scripts will + run within a closure wrapper, so if you want to expose global variables or + functions, attach them to the window object. +

+ +

+ + Resources +

+ +
    +
  • + Source Code
    + Use bin/coffee to test your changes,
    + bin/cake test to run the test suite,
    + bin/cake build to rebuild the CoffeeScript compiler, and
    + bin/cake build:parser to regenerate the Jison parser if you're + working on the grammar.

    + git checkout lib && bin/cake build:full is a good command to run when you're working + on the core language. It'll refresh the lib directory + (in case you broke something), build your altered compiler, use that to + rebuild itself (a good sanity test) and then run all of the tests. If + they pass, there's a good chance you've made a successful change. +
  • +
  • + CoffeeScript Issues
    + Bugs reports, feature requests, and general discussion all belong here. +
  • +
  • + If you'd like to chat, stop by #coffeescript on Freenode in the + IRC client of your choice, or on + webchat.freenode.net. +
  • +
  • + yeungda's JCoffeeScript + — A Java Library that uses Rhino to compile CoffeeScript, allowing + compilation within Java projects or on systems that Node.js doesn't support. +
  • +
  • + defunkt's CoffeeScript Major Mode + — a Emacs major mode that provides syntax highlighting, indentation + support, and some bonus commands. +
  • +
  • + jashkenas's CoffeeScript TextMate Bundle + — which provides syntax highlighting, snippet expansion, and the + ability to run bits of CoffeeScript from within TextMate itself. +
  • +
  • + kchmck's Vim CoffeeScript + — which adds Vim syntax highlighting and indentation support. +
  • +
  • + wavded's gedit-coffeescript + — a CoffeeScript syntax highlighter for the gedit text editor. +
  • +
  • + yeungda's coffeescript-idea + — a plugin for IntelliJ IDEA and RubyMine providing syntax highlighting. +
  • +
  • + mattly's rack-coffee + — a small Rack middleware for serving CoffeeScript files as + compiled JavaScript on the fly. +
  • +
  • + jnicklas's BistroCar + — a plugin that serves and bundles CoffeeScript from within your + Rails application. +
  • +
  • + dsc's CoffeeCup + — a Python WSGI middleware that compiles CoffeeScript to JavaScript + on-demand during development. +
  • +
  • + sutto's Barista + — a BistroCar alternative that integrates well with + Jammit and Rails 3. +
  • +
  • + inem and gerad's coffee-haml-filter + — a custom filter for rendering CoffeeScript inline within + HAML templates. +
  • +
  • + chrislloyd's Roast + — a CoffeeScript compiler plug-in that allows you to include external + source files. +
  • +
  • + mauricemach's CoffeeKup + — Markup as CoffeeScript. After _why's + Markaby. +
  • +
  • + jashkenas's Docco + — a quick-and-dirty literate-programming-style documentation generator + for CoffeeScript. Used to produce the annotated source. +
  • +
+ +

+ + Web Chat (IRC) +

+ +

+ Quick help and advice can usually be found in the CoffeeScript IRC room. + Join #coffeescript on irc.freenode.net, or click the + button below to open a webchat session on this page. +

+ +

+ +

+ +

+ + Change Log +

+ +

+ 0.9.4 + CoffeeScript now uses appropriately-named temporary variables, and recycles + their references after use. Added require.extensions support for + Node.js 0.3. Loading CoffeeScript in the browser now adds just a + single CoffeeScript object to global scope. + Fixes for implicit object and block comment edge cases. +

+ +

+ 0.9.3 + CoffeeScript switch statements now compile into JS switch + statements — they previously compiled into if/else chains + for JavaScript 1.3 compatibility. + Soaking a function invocation is now supported. Users of the RubyMine + editor should now be able to use --watch mode. +

+ +

+ 0.9.2 + Specifying the start and end of a range literal is now optional, eg. array[3..]. + You can now say a not instanceof b. + Fixed important bugs with nested significant and non-significant indentation (Issue #637). + Added a --require flag that allows you to hook into the coffee command. + Added a custom jsl.conf file for our preferred JavaScriptLint setup. + Sped up Jison grammar compilation time by flattening rules for operations. + Block comments can now be used with JavaScript-minifier-friendly syntax. + Added JavaScript's compound assignment bitwise operators. Bugfixes to + implicit object literals with leading number and string keys, as the subject + of implicit calls, and as part of compound assignment. +

+ +

+ 0.9.1 + Bugfix release for 0.9.1. Greatly improves the handling of mixed + implicit objects, implicit function calls, and implicit indentation. + String and regex interpolation is now strictly #{ ... } (Ruby style). + The compiler now takes a --require flag, which specifies scripts + to run before compilation. +

+ +

+ 0.9.0 + The CoffeeScript 0.9 series is considered to be a release candidate + for 1.0; let's give her a shakedown cruise. 0.9.0 introduces a massive + backwards-incompatible change: Assignment now uses =, and object + literals use :, as in JavaScript. This allows us to have implicit + object literals, and YAML-style object definitions. Half assignments are + removed, in favor of +=, or=, and friends. + Interpolation now uses a hash mark # instead of the dollar sign + $ — because dollar signs may be part of a valid JS identifier. + Downwards range comprehensions are now safe again, and are optimized to + straight for loops when created with integer endpoints. + A fast, unguarded form of object comprehension was added: + for all key, value of object. Mentioning the super keyword + with no arguments now forwards all arguments passed to the function, + as in Ruby. If you extend class B from parent class A, if + A has an extended method defined, it will be called, passing in B — + this enables static inheritance, among other things. Cleaner output for + functions bound with the fat arrow. @variables can now be used + in parameter lists, with the parameter being automatically set as a property + on the object — useful in constructors and setter functions. + Constructor functions can now take splats. +

+ +

+ 0.7.2 + Quick bugfix (right after 0.7.1) for a problem that prevented coffee + command-line options from being parsed in some circumstances. +

+ +

+ 0.7.1 + Block-style comments are now passed through and printed as JavaScript block + comments -- making them useful for licenses and copyright headers. Better + support for running coffee scripts standalone via hashbangs. + Improved syntax errors for tokens that are not in the grammar. +

+ +

+ 0.7.0 + Official CoffeeScript variable style is now camelCase, as in JavaScript. + Reserved words are now allowed as object keys, and will be quoted for you. + Range comprehensions now generate cleaner code, but you have to specify by -1 + if you'd like to iterate downward. Reporting of syntax errors is greatly + improved from the previous release. Running coffee with no arguments + now launches the REPL, with Readline support. The <- bind operator + has been removed from CoffeeScript. The loop keyword was added, + which is equivalent to a while true loop. Comprehensions that contain + closures will now close over their variables, like the semantics of a forEach. + You can now use bound function in class definitions (bound to the instance). + For consistency, a in b is now an array presence check, and a of b + is an object-key check. Comments are no longer passed through to the generated + JavaScript. +

+ +

+ 0.6.2 + The coffee command will now preserve directory structure when + compiling a directory full of scripts. Fixed two omissions that were preventing + the CoffeeScript compiler from running live within Internet Explorer. + There's now a syntax for block comments, similar in spirit to CoffeeScript's heredocs. + ECMA Harmony DRY-style pattern matching is now supported, where the name + of the property is the same as the name of the value: {name, length}: func. + Pattern matching is now allowed within comprehension variables. unless + is now allowed in block form. until loops were added, as the inverse + of while loops. switch statements are now allowed without + switch object clauses. Compatible + with Node.js v0.1.95. +

+ +

+ 0.6.1 + Upgraded CoffeeScript for compatibility with the new Node.js v0.1.90 + series. +

+ +

+ 0.6.0 + Trailing commas are now allowed, a-la Python. Static + properties may be assigned directly within class definitions, + using @property notation. +

+ +

+ 0.5.6 + Interpolation can now be used within regular expressions and heredocs, as well as + strings. Added the <- bind operator. + Allowing assignment to half-expressions instead of special ||=-style + operators. The arguments object is no longer automatically converted into + an array. After requiring coffee-script, Node.js can now directly + load .coffee files, thanks to registerExtension. Multiple + splats can now be used in function calls, arrays, and pattern matching. +

+ +

+ 0.5.5 + String interpolation, contributed by + Stan Angeloff. + Since --run has been the default since 0.5.3, updating + --stdio and --eval to run by default, pass --compile + as well if you'd like to print the result. +

+ +

+ 0.5.4 + Bugfix that corrects the Node.js global constants __filename and + __dirname. Tweaks for more flexible parsing of nested function + literals and improperly-indented comments. Updates for the latest Node.js API. +

+ +

+ 0.5.3 + CoffeeScript now has a syntax for defining classes. Many of the core + components (Nodes, Lexer, Rewriter, Scope, Optparse) are using them. + Cakefiles can use optparse.coffee to define options for tasks. + --run is now the default flag for the coffee command, + use --compile to save JavaScripts. Bugfix for an ambiguity between + RegExp literals and chained divisions. +

+ +

+ 0.5.2 + Added a compressed version of the compiler for inclusion in web pages as +
extras/coffee-script.js. It'll automatically run any script tags + with type text/coffeescript for you. Added a --stdio option + to the coffee command, for piped-in compiles. +

+ + +

+ 0.5.1 + Improvements to null soaking with the existential operator, including + soaks on indexed properties. Added conditions to while loops, + so you can use them as filters with when, in the same manner as + comprehensions. +

+ +

+ 0.5.0 + CoffeeScript 0.5.0 is a major release, While there are no language changes, + the Ruby compiler has been removed in favor of a self-hosting + compiler written in pure CoffeeScript. +

+ +

+ 0.3.2 + @property is now a shorthand for this.property.
+ Switched the default JavaScript engine from Narwhal to Node.js. Pass + the --narwhal flag if you'd like to continue using it. +

+ +

+ 0.3.0 + CoffeeScript 0.3 includes major syntax changes: +
+ The function symbol was changed to + ->, and the bound function symbol is now =>. +
+ Parameter lists in function definitions must now be wrapped in parentheses. +
+ Added property soaking, with the ?. operator. +
+ Made parentheses optional, when invoking functions with arguments. +
+ Removed the obsolete block literal syntax. +

+ +

+ 0.2.6 + Added Python-style chained comparisons, the conditional existence + operator ?=, and some examples from Beautiful Code. + Bugfixes relating to statement-to-expression conversion, arguments-to-array + conversion, and the TextMate syntax highlighter. +

+ +

+ 0.2.5 + The conditions in switch statements can now take multiple values at once — + If any of them are true, the case will run. Added the long arrow ==>, + which defines and immediately binds a function to this. While loops can + now be used as expressions, in the same way that comprehensions can. Splats + can be used within pattern matches to soak up the rest of an array. +

+ +

+ 0.2.4 + Added ECMAScript Harmony style destructuring assignment, for dealing with + extracting values from nested arrays and objects. Added indentation-sensitive + heredocs for nicely formatted strings or chunks of code. +

+ +

+ 0.2.3 + Axed the unsatisfactory ino keyword, replacing it with of for + object comprehensions. They now look like: for prop, value of object. +

+ +

+ 0.2.2 + When performing a comprehension over an object, use ino, instead + of in, which helps us generate smaller, more efficient code at + compile time. +
+ Added :: as a shorthand for saying .prototype. +
+ The "splat" symbol has been changed from a prefix asterisk *, to + a postfix ellipsis ... +
+ Added JavaScript's in operator, + empty return statements, and empty while loops. +
+ Constructor functions that start with capital letters now include a + safety check to make sure that the new instance of the object is returned. +
+ The extends keyword now functions identically to goog.inherits + in Google's Closure Library. +

+ +

+ 0.2.1 + Arguments objects are now converted into real arrays when referenced. +

+ +

+ 0.2.0 + Major release. Significant whitespace. Better statement-to-expression + conversion. Splats. Splice literals. Object comprehensions. Blocks. + The existential operator. Many thanks to all the folks who posted issues, + with special thanks to + Liam O'Connor-Davis for whitespace + and expression help. +

+ +

+ 0.1.6 + Bugfix for running coffee --interactive and --run + from outside of the CoffeeScript directory. Bugfix for nested + function/if-statements. +

+ +

+ 0.1.5 + Array slice literals and array comprehensions can now both take Ruby-style + ranges to specify the start and end. JavaScript variable declaration is + now pushed up to the top of the scope, making all assignment statements into + expressions. You can use \ to escape newlines. + The coffee-script command is now called coffee. +

+ +

+ 0.1.4 + The official CoffeeScript extension is now .coffee instead of + .cs, which properly belongs to + C#. + Due to popular demand, you can now also use = to assign. Unlike + JavaScript, = can also be used within object literals, interchangeably + with :. Made a grammatical fix for chained function calls + like func(1)(2)(3)(4). Inheritance and super no longer use + __proto__, so they should be IE-compatible now. +

+ +

+ 0.1.3 + The coffee command now includes --interactive, + which launches an interactive CoffeeScript session, and --run, + which directly compiles and executes a script. Both options depend on a + working installation of Narwhal. + The aint keyword has been replaced by isnt, which goes + together a little smoother with is. + Quoted strings are now allowed as identifiers within object literals: eg. + {"5+5": 10}. + All assignment operators now use a colon: +:, -:, + *:, etc. +

+ +

+ 0.1.2 + Fixed a bug with calling super() through more than one level of + inheritance, with the re-addition of the extends keyword. + Added experimental Narwhal + support (as a Tusk package), contributed by + Tom Robinson, including + bin/cs as a CoffeeScript REPL and interpreter. + New --no-wrap option to suppress the safety function + wrapper. +

+ +

+ 0.1.1 + Added instanceof and typeof as operators. +

+ +

+ 0.1.0 + Initial CoffeeScript release. +

+ +
+ + + + + + + + diff --git a/node_modules/jade/support/coffee-script/lib/browser.js b/node_modules/jade/support/coffee-script/lib/browser.js new file mode 100644 index 0000000..c35d5fe --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/browser.js @@ -0,0 +1,46 @@ +(function() { + var CoffeeScript, runScripts; + CoffeeScript = require('./coffee-script'); + CoffeeScript.require = require; + CoffeeScript.eval = function(code, options) { + return eval(CoffeeScript.compile(code, options)); + }; + CoffeeScript.run = function(code, options) { + ((options != null) ? (options.bare = true) : undefined); + return Function(CoffeeScript.compile(code, options))(); + }; + if (!(typeof window !== "undefined" && window !== null)) { + return; + } + CoffeeScript.load = function(url, options) { + var xhr; + xhr = new (window.ActiveXObject || XMLHttpRequest)('Microsoft.XMLHTTP'); + xhr.open('GET', url, true); + if ('overrideMimeType' in xhr) { + xhr.overrideMimeType('text/plain'); + } + xhr.onreadystatechange = function() { + return xhr.readyState === 4 ? CoffeeScript.run(xhr.responseText, options) : undefined; + }; + return xhr.send(null); + }; + runScripts = function() { + var _i, _j, _len, _ref, script; + for (_i = 0, _len = (_ref = document.getElementsByTagName('script')).length; _i < _len; _i++) { + (function() { + var script = _ref[_i]; + _j = script; + return script.type === 'text/coffeescript' ? (script.src ? CoffeeScript.load(script.src) : setTimeout(function() { + return CoffeeScript.run(script.innerHTML); + })) : undefined; + })(); + script = _j; + } + return null; + }; + if (window.addEventListener) { + addEventListener('DOMContentLoaded', runScripts, false); + } else { + attachEvent('onload', runScripts); + } +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/cake.js b/node_modules/jade/support/coffee-script/lib/cake.js new file mode 100755 index 0000000..770a648 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/cake.js @@ -0,0 +1,73 @@ +(function() { + var CoffeeScript, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks; + fs = require('fs'); + path = require('path'); + helpers = require('./helpers'); + optparse = require('./optparse'); + CoffeeScript = require('./coffee-script'); + tasks = {}; + options = {}; + switches = []; + oparse = null; + helpers.extend(global, { + task: function(name, description, action) { + var _ref; + if (!action) { + _ref = [description, action], action = _ref[0], description = _ref[1]; + } + return (tasks[name] = { + name: name, + description: description, + action: action + }); + }, + option: function(letter, flag, description) { + return switches.push([letter, flag, description]); + }, + invoke: function(name) { + if (!tasks[name]) { + missingTask(name); + } + return tasks[name].action(options); + } + }); + exports.run = function() { + return path.exists('Cakefile', function(exists) { + var _i, _len, _ref, _result, arg, args; + if (!exists) { + throw new Error("Cakefile not found in " + (process.cwd())); + } + args = process.argv.slice(2); + CoffeeScript.run(fs.readFileSync('Cakefile').toString(), { + fileName: 'Cakefile' + }); + oparse = new optparse.OptionParser(switches); + if (!args.length) { + return printTasks(); + } + options = oparse.parse(args); + _result = []; + for (_i = 0, _len = (_ref = options.arguments).length; _i < _len; _i++) { + arg = _ref[_i]; + _result.push(invoke(arg)); + } + return _result; + }); + }; + printTasks = function() { + var _ref, desc, name, spaces, task; + puts(''); + for (name in _ref = tasks) { + task = _ref[name]; + spaces = 20 - name.length; + spaces = spaces > 0 ? Array(spaces + 1).join(' ') : ''; + desc = task.description ? ("# " + (task.description)) : ''; + puts("cake " + name + spaces + " " + desc); + } + return switches.length ? puts(oparse.help()) : undefined; + }; + missingTask = function(task) { + puts("No such task: \"" + task + "\""); + return process.exit(1); + }; +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/coffee-script.js b/node_modules/jade/support/coffee-script/lib/coffee-script.js new file mode 100755 index 0000000..7bd422c --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/coffee-script.js @@ -0,0 +1,74 @@ +(function() { + var Lexer, compile, fs, lexer, parser, path; + path = require('path'); + Lexer = require('./lexer').Lexer; + parser = require('./parser').parser; + if (require.extensions) { + fs = require('fs'); + require.extensions['.coffee'] = function(module, filename) { + var content; + content = compile(fs.readFileSync(filename, 'utf8')); + return module._compile(content, filename); + }; + } else if (require.registerExtension) { + require.registerExtension('.coffee', function(content) { + return compile(content); + }); + } + exports.VERSION = '0.9.4'; + exports.helpers = require('./helpers'); + exports.compile = (compile = function(code, options) { + options || (options = {}); + try { + return (parser.parse(lexer.tokenize(code))).compile(options); + } catch (err) { + if (options.fileName) { + err.message = ("In " + (options.fileName) + ", " + (err.message)); + } + throw err; + } + }); + exports.tokens = function(code, options) { + return lexer.tokenize(code, options); + }; + exports.nodes = function(code, options) { + return parser.parse(lexer.tokenize(code, options)); + }; + exports.run = function(code, options) { + var root; + root = module; + while (root.parent) { + root = root.parent; + } + root.filename = options.fileName; + if (root.moduleCache) { + root.moduleCache = {}; + } + return path.extname(root.filename) !== '.coffee' || require.extensions ? root._compile(exports.compile(code, options), root.filename) : root._compile(code, root.filename); + }; + exports.eval = function(code, options) { + var __dirname, __filename; + __filename = options.fileName; + __dirname = path.dirname(__filename); + return eval(exports.compile(code, options)); + }; + lexer = new Lexer; + parser.lexer = { + lex: function() { + var token; + token = this.tokens[this.pos] || [""]; + this.pos += 1; + this.yylineno = token[2]; + this.yytext = token[1]; + return token[0]; + }, + setInput: function(tokens) { + this.tokens = tokens; + return (this.pos = 0); + }, + upcomingInput: function() { + return ""; + } + }; + parser.yy = require('./nodes'); +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/command.js b/node_modules/jade/support/coffee-script/lib/command.js new file mode 100644 index 0000000..58a2774 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/command.js @@ -0,0 +1,227 @@ +(function() { + var BANNER, CoffeeScript, EventEmitter, SWITCHES, _ref, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printTokens, sources, spawn, usage, version, watch, writeJs; + fs = require('fs'); + path = require('path'); + optparse = require('./optparse'); + CoffeeScript = require('./coffee-script'); + helpers = require('./helpers'); + _ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec; + EventEmitter = require('events').EventEmitter; + helpers.extend(CoffeeScript, new EventEmitter); + global.CoffeeScript = CoffeeScript; + BANNER = 'coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee'; + SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-b', '--bare', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-n', '--nodes', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']]; + opts = {}; + sources = []; + optionParser = null; + exports.run = function() { + var flags, separator; + parseOptions(); + if (opts.help) { + return usage(); + } + if (opts.version) { + return version(); + } + if (opts.interactive) { + return require('./repl'); + } + if (opts.stdio) { + return compileStdio(); + } + if (opts.eval) { + return compileScript('console', sources[0]); + } + if (!sources.length) { + return require('./repl'); + } + separator = sources.indexOf('--'); + flags = []; + if (separator >= 0) { + flags = sources.splice(separator + 1); + sources.pop(); + } + if (opts.run) { + flags = sources.splice(1).concat(flags); + } + process.ARGV = (process.argv = flags); + return compileScripts(); + }; + compileScripts = function() { + var _i, _j, _len, _ref2, _result, base, compile, source; + _result = []; + for (_i = 0, _len = (_ref2 = sources).length; _i < _len; _i++) { + (function() { + var source = _ref2[_i]; + _j = source; + return _result.push((function() { + base = source; + compile = function(source, topLevel) { + return path.exists(source, function(exists) { + if (!exists) { + throw new Error("File not found: " + source); + } + return fs.stat(source, function(err, stats) { + if (stats.isDirectory()) { + return fs.readdir(source, function(err, files) { + var _k, _len2, _result2, file; + _result2 = []; + for (_k = 0, _len2 = files.length; _k < _len2; _k++) { + file = files[_k]; + _result2.push(compile(path.join(source, file))); + } + return _result2; + }); + } else if (topLevel || path.extname(source) === '.coffee') { + fs.readFile(source, function(err, code) { + return compileScript(source, code.toString(), base); + }); + return opts.watch ? watch(source, base) : undefined; + } + }); + }); + }; + return compile(source, true); + })()); + })(); + source = _j; + } + return _result; + }; + compileScript = function(file, input, base) { + var _i, _len, _ref2, o, options, req, t, task; + o = opts; + options = compileOptions(file); + if (o.require) { + for (_i = 0, _len = (_ref2 = o.require).length; _i < _len; _i++) { + req = _ref2[_i]; + require(helpers.starts(req, '.') ? fs.realpathSync(req) : req); + } + } + try { + t = (task = { + file: file, + input: input, + options: options + }); + CoffeeScript.emit('compile', task); + if (o.tokens) { + return printTokens(CoffeeScript.tokens(t.input)); + } else if (o.nodes) { + return puts(CoffeeScript.nodes(t.input).toString().trim()); + } else if (o.run) { + return CoffeeScript.run(t.input, t.options); + } else { + t.output = CoffeeScript.compile(t.input, t.options); + CoffeeScript.emit('success', task); + return o.print ? print(t.output) : (o.compile ? writeJs(t.file, t.output, base) : (o.lint ? lint(t.output) : undefined)); + } + } catch (err) { + CoffeeScript.emit('failure', err, task); + if (CoffeeScript.listeners('failure').length) { + return; + } + if (o.watch) { + return puts(err.message); + } + error(err.stack); + return process.exit(1); + } + }; + compileStdio = function() { + var code, stdin; + code = ''; + stdin = process.openStdin(); + stdin.on('data', function(buffer) { + return buffer ? code += buffer.toString() : undefined; + }); + return stdin.on('end', function() { + return compileScript('stdio', code); + }); + }; + watch = function(source, base) { + return fs.watchFile(source, { + persistent: true, + interval: 500 + }, function(curr, prev) { + if (curr.size === prev.size && curr.mtime.getTime() === prev.mtime.getTime()) { + return; + } + return fs.readFile(source, function(err, code) { + if (err) { + throw err; + } + return compileScript(source, code.toString(), base); + }); + }); + }; + writeJs = function(source, js, base) { + var baseDir, compile, dir, filename, jsPath, srcDir; + filename = path.basename(source, path.extname(source)) + '.js'; + srcDir = path.dirname(source); + baseDir = srcDir.substring(base.length); + dir = opts.output ? path.join(opts.output, baseDir) : srcDir; + jsPath = path.join(dir, filename); + compile = function() { + if (js.length <= 0) { + js = ' '; + } + return fs.writeFile(jsPath, js, function(err) { + return opts.compile && opts.watch ? puts("Compiled " + source) : undefined; + }); + }; + return path.exists(dir, function(exists) { + return exists ? compile() : exec("mkdir -p " + dir, compile); + }); + }; + lint = function(js) { + var conf, jsl, printIt; + printIt = function(buffer) { + return puts(buffer.toString().trim()); + }; + conf = __dirname + '/../extras/jsl.conf'; + jsl = spawn('jsl', ['-nologo', '-stdin', '-conf', conf]); + jsl.stdout.on('data', printIt); + jsl.stderr.on('data', printIt); + jsl.stdin.write(js); + return jsl.stdin.end(); + }; + printTokens = function(tokens) { + var _i, _len, _ref2, _result, strings, tag, token, value; + strings = (function() { + _result = []; + for (_i = 0, _len = tokens.length; _i < _len; _i++) { + token = tokens[_i]; + _result.push((function() { + _ref2 = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref2[0], value = _ref2[1]; + return "[" + tag + " " + value + "]"; + })()); + } + return _result; + })(); + return puts(strings.join(' ')); + }; + parseOptions = function() { + var o; + optionParser = new optparse.OptionParser(SWITCHES, BANNER); + o = (opts = optionParser.parse(process.argv.slice(2))); + o.compile || (o.compile = !!o.output); + o.run = !(o.compile || o.print || o.lint); + o.print = !!(o.print || (o.eval || o.stdio && o.compile)); + return (sources = o.arguments); + }; + compileOptions = function(fileName) { + return { + fileName: fileName, + bare: opts.bare + }; + }; + usage = function() { + puts(optionParser.help()); + return process.exit(0); + }; + version = function() { + puts("CoffeeScript version " + (CoffeeScript.VERSION)); + return process.exit(0); + }; +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/grammar.js b/node_modules/jade/support/coffee-script/lib/grammar.js new file mode 100644 index 0000000..e038a74 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/grammar.js @@ -0,0 +1,622 @@ +(function() { + var Parser, _i, _j, _len, _len2, _ref, _result, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap; + var __hasProp = Object.prototype.hasOwnProperty; + Parser = require('jison').Parser; + unwrap = /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/; + o = function(patternString, action, options) { + var match; + if (!action) { + return [patternString, '$$ = $1;', options]; + } + action = (match = (action + '').match(unwrap)) ? match[1] : ("(" + action + "())"); + action = action.replace(/\bnew (\w+)\b/g, 'new yy.$1').replace(/Expressions\.wrap/g, 'yy.Expressions.wrap'); + return [patternString, ("$$ = " + action + ";"), options]; + }; + grammar = { + Root: [ + o("", function() { + return new Expressions; + }), o("TERMINATOR", function() { + return new Expressions; + }), o("Body"), o("Block TERMINATOR") + ], + Body: [ + o("Line", function() { + return Expressions.wrap([$1]); + }), o("Body TERMINATOR Line", function() { + return $1.push($3); + }), o("Body TERMINATOR") + ], + Line: [o("Expression"), o("Statement")], + Statement: [ + o("Return"), o("Throw"), o("BREAK", function() { + return new Literal($1); + }), o("CONTINUE", function() { + return new Literal($1); + }), o("DEBUGGER", function() { + return new Literal($1); + }) + ], + Expression: [o("Value"), o("Invocation"), o("Code"), o("Operation"), o("Assign"), o("If"), o("Try"), o("While"), o("For"), o("Switch"), o("Extends"), o("Class"), o("Existence"), o("Comment")], + Block: [ + o("INDENT Body OUTDENT", function() { + return $2; + }), o("INDENT OUTDENT", function() { + return new Expressions; + }), o("TERMINATOR Comment", function() { + return Expressions.wrap([$2]); + }) + ], + Identifier: [ + o("IDENTIFIER", function() { + return new Literal($1); + }) + ], + AlphaNumeric: [ + o("NUMBER", function() { + return new Literal($1); + }), o("STRING", function() { + return new Literal($1); + }) + ], + Literal: [ + o("AlphaNumeric"), o("JS", function() { + return new Literal($1); + }), o("REGEX", function() { + return new Literal($1); + }), o("BOOL", function() { + return new Literal($1); + }) + ], + Assign: [ + o("Assignable = Expression", function() { + return new Assign($1, $3); + }), o("Assignable = INDENT Expression OUTDENT", function() { + return new Assign($1, $4); + }) + ], + AssignObj: [ + o("Identifier", function() { + return new Value($1); + }), o("AlphaNumeric"), o("ThisProperty"), o("Identifier : Expression", function() { + return new Assign(new Value($1), $3, 'object'); + }), o("AlphaNumeric : Expression", function() { + return new Assign(new Value($1), $3, 'object'); + }), o("Identifier : INDENT Expression OUTDENT", function() { + return new Assign(new Value($1), $4, 'object'); + }), o("AlphaNumeric : INDENT Expression OUTDENT", function() { + return new Assign(new Value($1), $4, 'object'); + }), o("Comment") + ], + Return: [ + o("RETURN Expression", function() { + return new Return($2); + }), o("RETURN", function() { + return new Return; + }) + ], + Comment: [ + o("HERECOMMENT", function() { + return new Comment($1); + }) + ], + Existence: [ + o("Expression ?", function() { + return new Existence($1); + }) + ], + Code: [ + o("PARAM_START ParamList PARAM_END FuncGlyph Block", function() { + return new Code($2, $5, $4); + }), o("FuncGlyph Block", function() { + return new Code([], $2, $1); + }) + ], + FuncGlyph: [ + o("->", function() { + return 'func'; + }), o("=>", function() { + return 'boundfunc'; + }) + ], + OptComma: [o(''), o(',')], + ParamList: [ + o("", function() { + return []; + }), o("Param", function() { + return [$1]; + }), o("ParamList , Param", function() { + return $1.concat($3); + }) + ], + Param: [ + o("PARAM", function() { + return new Literal($1); + }), o("@ PARAM", function() { + return new Param($2, true); + }), o("PARAM ...", function() { + return new Param($1, false, true); + }), o("@ PARAM ...", function() { + return new Param($2, true, true); + }) + ], + Splat: [ + o("Expression ...", function() { + return new Splat($1); + }) + ], + SimpleAssignable: [ + o("Identifier", function() { + return new Value($1); + }), o("Value Accessor", function() { + return $1.push($2); + }), o("Invocation Accessor", function() { + return new Value($1, [$2]); + }), o("ThisProperty") + ], + Assignable: [ + o("SimpleAssignable"), o("Array", function() { + return new Value($1); + }), o("Object", function() { + return new Value($1); + }) + ], + Value: [ + o("Assignable"), o("Literal", function() { + return new Value($1); + }), o("Parenthetical", function() { + return new Value($1); + }), o("Range", function() { + return new Value($1); + }), o("This") + ], + Accessor: [ + o("PROPERTY_ACCESS Identifier", function() { + return new Accessor($2); + }), o("PROTOTYPE_ACCESS Identifier", function() { + return new Accessor($2, 'prototype'); + }), o("::", function() { + return new Accessor(new Literal('prototype')); + }), o("SOAK_ACCESS Identifier", function() { + return new Accessor($2, 'soak'); + }), o("Index"), o("Slice", function() { + return new Slice($1); + }) + ], + Index: [ + o("INDEX_START Expression INDEX_END", function() { + return new Index($2); + }), o("INDEX_SOAK Index", function() { + $2.soakNode = true; + return $2; + }), o("INDEX_PROTO Index", function() { + $2.proto = true; + return $2; + }) + ], + Object: [ + o("{ AssignList OptComma }", function() { + return new ObjectLiteral($2); + }) + ], + AssignList: [ + o("", function() { + return []; + }), o("AssignObj", function() { + return [$1]; + }), o("AssignList , AssignObj", function() { + return $1.concat($3); + }), o("AssignList OptComma TERMINATOR AssignObj", function() { + return $1.concat($4); + }), o("AssignList OptComma INDENT AssignList OptComma OUTDENT", function() { + return $1.concat($4); + }) + ], + Class: [ + o("CLASS SimpleAssignable", function() { + return new Class($2); + }), o("CLASS SimpleAssignable EXTENDS Value", function() { + return new Class($2, $4); + }), o("CLASS SimpleAssignable INDENT ClassBody OUTDENT", function() { + return new Class($2, null, $4); + }), o("CLASS SimpleAssignable EXTENDS Value INDENT ClassBody OUTDENT", function() { + return new Class($2, $4, $6); + }), o("CLASS INDENT ClassBody OUTDENT", function() { + return new Class('__temp__', null, $3); + }), o("CLASS", function() { + return new Class('__temp__', null, new Expressions); + }), o("CLASS EXTENDS Value", function() { + return new Class('__temp__', $3, new Expressions); + }), o("CLASS EXTENDS Value INDENT ClassBody OUTDENT", function() { + return new Class('__temp__', $3, $5); + }) + ], + ClassAssign: [ + o("AssignObj", function() { + return $1; + }), o("ThisProperty : Expression", function() { + return new Assign(new Value($1), $3, 'this'); + }), o("ThisProperty : INDENT Expression OUTDENT", function() { + return new Assign(new Value($1), $4, 'this'); + }) + ], + ClassBody: [ + o("", function() { + return []; + }), o("ClassAssign", function() { + return [$1]; + }), o("ClassBody TERMINATOR ClassAssign", function() { + return $1.concat($3); + }), o("{ ClassBody }", function() { + return $2; + }) + ], + Extends: [ + o("SimpleAssignable EXTENDS Value", function() { + return new Extends($1, $3); + }) + ], + Invocation: [ + o("Value OptFuncExist Arguments", function() { + return new Call($1, $3, $2); + }), o("Invocation OptFuncExist Arguments", function() { + return new Call($1, $3, $2); + }), o("SUPER", function() { + return new Call('super', [new Splat(new Literal('arguments'))]); + }), o("SUPER Arguments", function() { + return new Call('super', $2); + }) + ], + OptFuncExist: [ + o("", function() { + return false; + }), o("FUNC_EXIST", function() { + return true; + }) + ], + Arguments: [ + o("CALL_START CALL_END", function() { + return []; + }), o("CALL_START ArgList OptComma CALL_END", function() { + return $2; + }) + ], + This: [ + o("THIS", function() { + return new Value(new Literal('this')); + }), o("@", function() { + return new Value(new Literal('this')); + }) + ], + RangeDots: [ + o("..", function() { + return 'inclusive'; + }), o("...", function() { + return 'exclusive'; + }) + ], + ThisProperty: [ + o("@ Identifier", function() { + return new Value(new Literal('this'), [new Accessor($2)], 'this'); + }) + ], + Range: [ + o("[ Expression RangeDots Expression ]", function() { + return new Range($2, $4, $3); + }) + ], + Slice: [ + o("INDEX_START Expression RangeDots Expression INDEX_END", function() { + return new Range($2, $4, $3); + }), o("INDEX_START Expression RangeDots INDEX_END", function() { + return new Range($2, null, $3); + }), o("INDEX_START RangeDots Expression INDEX_END", function() { + return new Range(null, $3, $2); + }) + ], + Array: [ + o("[ ]", function() { + return new ArrayLiteral([]); + }), o("[ ArgList OptComma ]", function() { + return new ArrayLiteral($2); + }) + ], + ArgList: [ + o("Arg", function() { + return [$1]; + }), o("ArgList , Arg", function() { + return $1.concat($3); + }), o("ArgList OptComma TERMINATOR Arg", function() { + return $1.concat($4); + }), o("INDENT ArgList OptComma OUTDENT", function() { + return $2; + }), o("ArgList OptComma INDENT ArgList OptComma OUTDENT", function() { + return $1.concat($4); + }) + ], + Arg: [o("Expression"), o("Splat")], + SimpleArgs: [ + o("Expression"), o("SimpleArgs , Expression", function() { + return [].concat($1, $3); + }) + ], + Try: [ + o("TRY Block", function() { + return new Try($2); + }), o("TRY Block Catch", function() { + return new Try($2, $3[0], $3[1]); + }), o("TRY Block FINALLY Block", function() { + return new Try($2, null, null, $4); + }), o("TRY Block Catch FINALLY Block", function() { + return new Try($2, $3[0], $3[1], $5); + }) + ], + Catch: [ + o("CATCH Identifier Block", function() { + return [$2, $3]; + }) + ], + Throw: [ + o("THROW Expression", function() { + return new Throw($2); + }) + ], + Parenthetical: [ + o("( Expression )", function() { + return new Parens($2); + }), o("( )", function() { + return new Parens(new Literal('')); + }) + ], + WhileSource: [ + o("WHILE Expression", function() { + return new While($2); + }), o("WHILE Expression WHEN Expression", function() { + return new While($2, { + guard: $4 + }); + }), o("UNTIL Expression", function() { + return new While($2, { + invert: true + }); + }), o("UNTIL Expression WHEN Expression", function() { + return new While($2, { + invert: true, + guard: $4 + }); + }) + ], + While: [ + o("WhileSource Block", function() { + return $1.addBody($2); + }), o("Statement WhileSource", function() { + return $2.addBody(Expressions.wrap([$1])); + }), o("Expression WhileSource", function() { + return $2.addBody(Expressions.wrap([$1])); + }), o("Loop", function() { + return $1; + }) + ], + Loop: [ + o("LOOP Block", function() { + return new While(new Literal('true')).addBody($2); + }), o("LOOP Expression", function() { + return new While(new Literal('true')).addBody(Expressions.wrap([$2])); + }) + ], + For: [ + o("Statement ForBody", function() { + return new For($1, $2, $2.vars[0], $2.vars[1]); + }), o("Expression ForBody", function() { + return new For($1, $2, $2.vars[0], $2.vars[1]); + }), o("ForBody Block", function() { + return new For($2, $1, $1.vars[0], $1.vars[1]); + }) + ], + ForBody: [ + o("FOR Range", function() { + return { + source: new Value($2), + vars: [] + }; + }), o("ForStart ForSource", function() { + $2.raw = $1.raw; + $2.vars = $1; + return $2; + }) + ], + ForStart: [ + o("FOR ForVariables", function() { + return $2; + }), o("FOR ALL ForVariables", function() { + $3.raw = true; + return $3; + }) + ], + ForValue: [ + o("Identifier"), o("Array", function() { + return new Value($1); + }), o("Object", function() { + return new Value($1); + }) + ], + ForVariables: [ + o("ForValue", function() { + return [$1]; + }), o("ForValue , ForValue", function() { + return [$1, $3]; + }) + ], + ForSource: [ + o("FORIN Expression", function() { + return { + source: $2 + }; + }), o("FOROF Expression", function() { + return { + source: $2, + object: true + }; + }), o("FORIN Expression WHEN Expression", function() { + return { + source: $2, + guard: $4 + }; + }), o("FOROF Expression WHEN Expression", function() { + return { + source: $2, + guard: $4, + object: true + }; + }), o("FORIN Expression BY Expression", function() { + return { + source: $2, + step: $4 + }; + }), o("FORIN Expression WHEN Expression BY Expression", function() { + return { + source: $2, + guard: $4, + step: $6 + }; + }), o("FORIN Expression BY Expression WHEN Expression", function() { + return { + source: $2, + step: $4, + guard: $6 + }; + }) + ], + Switch: [ + o("SWITCH Expression INDENT Whens OUTDENT", function() { + return new Switch($2, $4); + }), o("SWITCH Expression INDENT Whens ELSE Block OUTDENT", function() { + return new Switch($2, $4, $6); + }), o("SWITCH INDENT Whens OUTDENT", function() { + return new Switch(null, $3); + }), o("SWITCH INDENT Whens ELSE Block OUTDENT", function() { + return new Switch(null, $3, $5); + }) + ], + Whens: [ + o("When"), o("Whens When", function() { + return $1.concat($2); + }) + ], + When: [ + o("LEADING_WHEN SimpleArgs Block", function() { + return [[$2, $3]]; + }), o("LEADING_WHEN SimpleArgs Block TERMINATOR", function() { + return [[$2, $3]]; + }) + ], + IfBlock: [ + o("IF Expression Block", function() { + return new If($2, $3); + }), o("UNLESS Expression Block", function() { + return new If($2, $3, { + invert: true + }); + }), o("IfBlock ELSE IF Expression Block", function() { + return $1.addElse(new If($4, $5)); + }), o("IfBlock ELSE Block", function() { + return $1.addElse($3); + }) + ], + If: [ + o("IfBlock"), o("Statement POST_IF Expression", function() { + return new If($3, Expressions.wrap([$1]), { + statement: true + }); + }), o("Expression POST_IF Expression", function() { + return new If($3, Expressions.wrap([$1]), { + statement: true + }); + }), o("Statement POST_UNLESS Expression", function() { + return new If($3, Expressions.wrap([$1]), { + statement: true, + invert: true + }); + }), o("Expression POST_UNLESS Expression", function() { + return new If($3, Expressions.wrap([$1]), { + statement: true, + invert: true + }); + }) + ], + Operation: [ + o("UNARY Expression", function() { + return new Op($1, $2); + }), o("- Expression", function() { + return new Op('-', $2); + }, { + prec: 'UNARY' + }), o("+ Expression", function() { + return new Op('+', $2); + }, { + prec: 'UNARY' + }), o("-- SimpleAssignable", function() { + return new Op('--', $2); + }), o("++ SimpleAssignable", function() { + return new Op('++', $2); + }), o("SimpleAssignable --", function() { + return new Op('--', $1, null, true); + }), o("SimpleAssignable ++", function() { + return new Op('++', $1, null, true); + }), o("Expression + Expression", function() { + return new Op('+', $1, $3); + }), o("Expression - Expression", function() { + return new Op('-', $1, $3); + }), o("Expression == Expression", function() { + return new Op('==', $1, $3); + }), o("Expression != Expression", function() { + return new Op('!=', $1, $3); + }), o("Expression MATH Expression", function() { + return new Op($2, $1, $3); + }), o("Expression SHIFT Expression", function() { + return new Op($2, $1, $3); + }), o("Expression COMPARE Expression", function() { + return new Op($2, $1, $3); + }), o("Expression LOGIC Expression", function() { + return new Op($2, $1, $3); + }), o("SimpleAssignable COMPOUND_ASSIGN Expression", function() { + return new Op($2, $1, $3); + }), o("SimpleAssignable COMPOUND_ASSIGN INDENT Expression OUTDENT", function() { + return new Op($2, $1, $4); + }), o("Expression RELATION Expression", function() { + return $2.charAt(0) === '!' ? ($2 === '!in' ? new Op('!', new In($1, $3)) : new Op('!', new Parens(new Op($2.slice(1), $1, $3)))) : ($2 === 'in' ? new In($1, $3) : new Op($2, $1, $3)); + }) + ] + }; + operators = [["left", 'CALL_START', 'CALL_END'], ["nonassoc", '++', '--'], ["left", '?'], ["right", 'UNARY'], ["left", 'MATH'], ["left", '+', '-'], ["left", 'SHIFT'], ["left", 'COMPARE'], ["left", 'RELATION'], ["left", '==', '!='], ["left", 'LOGIC'], ["right", 'COMPOUND_ASSIGN'], ["left", '.'], ["nonassoc", 'INDENT', 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'FORIN', 'FOROF', 'BY', 'THROW'], ["right", 'IF', 'UNLESS', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'EXTENDS'], ["right", '=', ':', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'POST_IF', 'POST_UNLESS']]; + tokens = []; + for (name in grammar) { + if (!__hasProp.call(grammar, name)) continue; + alternatives = grammar[name]; + grammar[name] = (function() { + _result = []; + for (_i = 0, _len = alternatives.length; _i < _len; _i++) { + alt = alternatives[_i]; + _result.push((function() { + for (_j = 0, _len2 = (_ref = alt[0].split(' ')).length; _j < _len2; _j++) { + token = _ref[_j]; + if (!grammar[token]) { + tokens.push(token); + } + } + if (name === 'Root') { + alt[1] = ("return " + (alt[1])); + } + return alt; + })()); + } + return _result; + })(); + } + exports.parser = new Parser({ + tokens: tokens.join(' '), + bnf: grammar, + operators: operators.reverse(), + startSymbol: 'Root' + }); +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/helpers.js b/node_modules/jade/support/coffee-script/lib/helpers.js new file mode 100644 index 0000000..5983bf6 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/helpers.js @@ -0,0 +1,78 @@ +(function() { + var extend, flatten, indexOf; + indexOf = (exports.indexOf = Array.indexOf || (Array.prototype.indexOf ? function(array, item, from) { + return array.indexOf(item, from); + } : function(array, item, from) { + var _len, index, other; + for (index = 0, _len = array.length; index < _len; index++) { + other = array[index]; + if (other === item && (!from || (from <= index))) { + return index; + } + } + return -1; + })); + exports.include = function(list, value) { + return indexOf(list, value) >= 0; + }; + exports.starts = function(string, literal, start) { + return literal === string.substr(start, literal.length); + }; + exports.ends = function(string, literal, back) { + var len; + len = literal.length; + return literal === string.substr(string.length - len - (back || 0), len); + }; + exports.compact = function(array) { + var _i, _len, _result, item; + _result = []; + for (_i = 0, _len = array.length; _i < _len; _i++) { + item = array[_i]; + if (item) { + _result.push(item); + } + } + return _result; + }; + exports.count = function(string, letter) { + var num, pos; + num = (pos = 0); + while (pos = 1 + string.indexOf(letter, pos)) { + num++; + } + return num; + }; + exports.merge = function(options, overrides) { + return extend(extend({}, options), overrides); + }; + extend = (exports.extend = function(object, properties) { + var key, val; + for (key in properties) { + val = properties[key]; + object[key] = val; + } + return object; + }); + exports.flatten = (flatten = function(array) { + var _i, _len, element, flattened; + flattened = []; + for (_i = 0, _len = array.length; _i < _len; _i++) { + element = array[_i]; + if (element instanceof Array) { + flattened = flattened.concat(flatten(element)); + } else { + flattened.push(element); + } + } + return flattened; + }); + exports.del = function(obj, key) { + var val; + val = obj[key]; + delete obj[key]; + return val; + }; + exports.last = function(array, back) { + return array[array.length - (back || 0) - 1]; + }; +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/index.js b/node_modules/jade/support/coffee-script/lib/index.js new file mode 100644 index 0000000..dc5ab13 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/index.js @@ -0,0 +1,9 @@ +(function() { + var _ref, key, val; + var __hasProp = Object.prototype.hasOwnProperty; + for (key in _ref = require('./coffee-script')) { + if (!__hasProp.call(_ref, key)) continue; + val = _ref[key]; + (exports[key] = val); + } +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/lexer.js b/node_modules/jade/support/coffee-script/lib/lexer.js new file mode 100644 index 0000000..ce25616 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/lexer.js @@ -0,0 +1,638 @@ +(function() { + var ASSIGNED, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LEADING_SPACES, LINE_BREAK, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NEXT_CHARACTER, NEXT_ELLIPSIS, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, TRAILING_SPACES, UNARY, WHITESPACE, _ref, compact, count, include, last, op, starts; + Rewriter = require('./rewriter').Rewriter; + _ref = require('./helpers'), include = _ref.include, count = _ref.count, starts = _ref.starts, compact = _ref.compact, last = _ref.last; + exports.Lexer = (function() { + Lexer = (function() { + function Lexer() { + return this; + }; + return Lexer; + })(); + Lexer.prototype.tokenize = function(code, options) { + var o; + code = code.replace(/\r/g, '').replace(TRAILING_SPACES, ''); + o = options || {}; + this.code = code; + this.i = 0; + this.line = o.line || 0; + this.indent = 0; + this.indebt = 0; + this.outdebt = 0; + this.seenFor = false; + this.indents = []; + this.tokens = []; + while (this.chunk = code.slice(this.i)) { + this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken(); + } + this.closeIndentation(); + if (o.rewrite === false) { + return this.tokens; + } + return (new Rewriter).rewrite(this.tokens); + }; + Lexer.prototype.identifierToken = function() { + var colon, forcedIdentifier, id, input, match, tag; + if (!(match = IDENTIFIER.exec(this.chunk))) { + return false; + } + input = match[0], id = match[1], colon = match[2]; + this.i += input.length; + if (id === 'all' && this.tag() === 'FOR') { + this.token('ALL', id); + return true; + } + forcedIdentifier = colon || this.tagAccessor(); + tag = 'IDENTIFIER'; + if (include(JS_KEYWORDS, id) || !forcedIdentifier && include(COFFEE_KEYWORDS, id)) { + tag = id.toUpperCase(); + if (tag === 'WHEN' && include(LINE_BREAK, this.tag())) { + tag = 'LEADING_WHEN'; + } else if (tag === 'FOR') { + this.seenFor = true; + } else if (include(UNARY, tag)) { + tag = 'UNARY'; + } else if (include(RELATION, tag)) { + if (tag !== 'INSTANCEOF' && this.seenFor) { + this.seenFor = false; + tag = 'FOR' + tag; + } else { + tag = 'RELATION'; + if (this.value() === '!') { + this.tokens.pop(); + id = '!' + id; + } + } + } + } + if (include(JS_FORBIDDEN, id)) { + if (forcedIdentifier) { + tag = 'IDENTIFIER'; + id = new String(id); + id.reserved = true; + } else if (include(RESERVED, id)) { + this.identifierError(id); + } + } + if (!forcedIdentifier) { + if (COFFEE_ALIASES.hasOwnProperty(id)) { + tag = (id = COFFEE_ALIASES[id]); + } + if (id === '!') { + tag = 'UNARY'; + } else if (include(LOGIC, id)) { + tag = 'LOGIC'; + } else if (include(BOOL, tag)) { + id = tag.toLowerCase(); + tag = 'BOOL'; + } + } + this.token(tag, id); + if (colon) { + this.token(':', ':'); + } + return true; + }; + Lexer.prototype.numberToken = function() { + var match, number; + if (!(match = NUMBER.exec(this.chunk))) { + return false; + } + number = match[0]; + if (this.tag() === '.' && number.charAt(0) === '.') { + return false; + } + this.i += number.length; + this.token('NUMBER', number); + return true; + }; + Lexer.prototype.stringToken = function() { + var match, string; + switch (this.chunk.charAt(0)) { + case "'": + if (!(match = SIMPLESTR.exec(this.chunk))) { + return false; + } + this.token('STRING', (string = match[0]).replace(MULTILINER, '\\\n')); + break; + case '"': + if (!(string = this.balancedString(this.chunk, [['"', '"'], ['#{', '}']]))) { + return false; + } + if (0 < string.indexOf('#{', 1)) { + this.interpolateString(string.slice(1, -1)); + } else { + this.token('STRING', this.escapeLines(string)); + } + break; + default: + return false; + } + this.line += count(string, '\n'); + this.i += string.length; + return true; + }; + Lexer.prototype.heredocToken = function() { + var doc, heredoc, match, quote; + if (!(match = HEREDOC.exec(this.chunk))) { + return false; + } + heredoc = match[0]; + quote = heredoc.charAt(0); + doc = this.sanitizeHeredoc(match[2], { + quote: quote, + indent: null + }); + if (quote === '"' && (0 <= doc.indexOf('#{'))) { + this.interpolateString(doc, { + heredoc: true + }); + } else { + this.token('STRING', this.makeString(doc, quote, true)); + } + this.line += count(heredoc, '\n'); + this.i += heredoc.length; + return true; + }; + Lexer.prototype.commentToken = function() { + var comment, here, match; + if (!(match = this.chunk.match(COMMENT))) { + return false; + } + comment = match[0], here = match[1]; + this.line += count(comment, '\n'); + this.i += comment.length; + if (here) { + this.token('HERECOMMENT', this.sanitizeHeredoc(here, { + herecomment: true, + indent: Array(this.indent + 1).join(' ') + })); + this.token('TERMINATOR', '\n'); + } + return true; + }; + Lexer.prototype.jsToken = function() { + var match, script; + if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) { + return false; + } + this.token('JS', (script = match[0]).slice(1, -1)); + this.i += script.length; + return true; + }; + Lexer.prototype.regexToken = function() { + var match, regex; + if (this.chunk.charAt(0) !== '/') { + return false; + } + if (match = HEREGEX.exec(this.chunk)) { + return this.heregexToken(match); + } + if (include(NOT_REGEX, this.tag())) { + return false; + } + if (!(match = REGEX.exec(this.chunk))) { + return false; + } + regex = match[0]; + this.token('REGEX', regex === '//' ? '/(?:)/' : regex); + this.i += regex.length; + return true; + }; + Lexer.prototype.heregexToken = function(match) { + var _i, _len, _ref2, _ref3, _ref4, _this, body, flags, heregex, re, tag, tokens, value; + heregex = match[0], body = match[1], flags = match[2]; + this.i += heregex.length; + if (0 > body.indexOf('#{')) { + re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/'); + this.token('REGEX', "/" + (re || '(?:)') + "/" + flags); + return true; + } + this.token('IDENTIFIER', 'RegExp'); + this.tokens.push(['CALL_START', '(']); + tokens = []; + for (_i = 0, _len = (_ref2 = this.interpolateString(body, { + regex: true + })).length; _i < _len; _i++) { + _ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1]; + if (tag === 'TOKENS') { + tokens.push.apply(tokens, value); + } else { + if (!(value = value.replace(HEREGEX_OMIT, ''))) { + continue; + } + value = value.replace(/\\/g, '\\\\'); + tokens.push(['STRING', this.makeString(value, '"', true)]); + } + tokens.push(['+', '+']); + } + tokens.pop(); + if ((((_ref4 = tokens[0]) != null) ? _ref4[0] : undefined) !== 'STRING') { + this.tokens.push(['STRING', '""'], ['+', '+']); + } + (_this = this.tokens).push.apply(_this, tokens); + if (flags) { + this.tokens.push([',', ','], ['STRING', '"' + flags + '"']); + } + this.token(')', ')'); + return true; + }; + Lexer.prototype.lineToken = function() { + var diff, indent, match, nextCharacter, noNewlines, prev, size; + if (!(match = MULTI_DENT.exec(this.chunk))) { + return false; + } + indent = match[0]; + this.line += count(indent, '\n'); + this.i += indent.length; + prev = last(this.tokens, 1); + size = indent.length - 1 - indent.lastIndexOf('\n'); + nextCharacter = NEXT_CHARACTER.exec(this.chunk)[1]; + noNewlines = ((nextCharacter === '.' || nextCharacter === ',') && !NEXT_ELLIPSIS.test(this.chunk)) || this.unfinished(); + if (size - this.indebt === this.indent) { + if (noNewlines) { + return this.suppressNewlines(); + } + return this.newlineToken(indent); + } else if (size > this.indent) { + if (noNewlines) { + this.indebt = size - this.indent; + return this.suppressNewlines(); + } + diff = size - this.indent + this.outdebt; + this.token('INDENT', diff); + this.indents.push(diff); + this.outdebt = (this.indebt = 0); + } else { + this.indebt = 0; + this.outdentToken(this.indent - size, noNewlines); + } + this.indent = size; + return true; + }; + Lexer.prototype.outdentToken = function(moveOut, noNewlines, close) { + var dent, len; + while (moveOut > 0) { + len = this.indents.length - 1; + if (this.indents[len] === undefined) { + moveOut = 0; + } else if (this.indents[len] === this.outdebt) { + moveOut -= this.outdebt; + this.outdebt = 0; + } else if (this.indents[len] < this.outdebt) { + this.outdebt -= this.indents[len]; + moveOut -= this.indents[len]; + } else { + dent = this.indents.pop() - this.outdebt; + moveOut -= dent; + this.outdebt = 0; + this.token('OUTDENT', dent); + } + } + if (dent) { + this.outdebt -= moveOut; + } + if (!(this.tag() === 'TERMINATOR' || noNewlines)) { + this.token('TERMINATOR', '\n'); + } + return true; + }; + Lexer.prototype.whitespaceToken = function() { + var match, prev; + if (!(match = WHITESPACE.exec(this.chunk))) { + return false; + } + prev = last(this.tokens); + if (prev) { + prev.spaced = true; + } + this.i += match[0].length; + return true; + }; + Lexer.prototype.newlineToken = function(newlines) { + if (this.tag() !== 'TERMINATOR') { + this.token('TERMINATOR', '\n'); + } + return true; + }; + Lexer.prototype.suppressNewlines = function() { + if (this.value() === '\\') { + this.tokens.pop(); + } + return true; + }; + Lexer.prototype.literalToken = function() { + var _ref2, match, prev, tag, value; + if (match = OPERATOR.exec(this.chunk)) { + value = match[0]; + if (CODE.test(value)) { + this.tagParameters(); + } + } else { + value = this.chunk.charAt(0); + } + this.i += value.length; + tag = value; + prev = last(this.tokens); + if (value === '=' && prev) { + if (!prev[1].reserved && include(JS_FORBIDDEN, prev[1])) { + this.assignmentError(); + } + if (((_ref2 = prev[1]) === '||' || _ref2 === '&&')) { + prev[0] = 'COMPOUND_ASSIGN'; + prev[1] += '='; + return true; + } + } + if (';' === value) { + tag = 'TERMINATOR'; + } else if (include(LOGIC, value)) { + tag = 'LOGIC'; + } else if (include(MATH, value)) { + tag = 'MATH'; + } else if (include(COMPARE, value)) { + tag = 'COMPARE'; + } else if (include(COMPOUND_ASSIGN, value)) { + tag = 'COMPOUND_ASSIGN'; + } else if (include(UNARY, value)) { + tag = 'UNARY'; + } else if (include(SHIFT, value)) { + tag = 'SHIFT'; + } else if (value === '?' && ((prev != null) ? prev.spaced : undefined)) { + tag = 'LOGIC'; + } else if (prev && !prev.spaced) { + if (value === '(' && include(CALLABLE, prev[0])) { + if (prev[0] === '?') { + prev[0] = 'FUNC_EXIST'; + } + tag = 'CALL_START'; + } else if (value === '[' && include(INDEXABLE, prev[0])) { + tag = 'INDEX_START'; + switch (prev[0]) { + case '?': + prev[0] = 'INDEX_SOAK'; + break; + case '::': + prev[0] = 'INDEX_PROTO'; + break; + } + } + } + this.token(tag, value); + return true; + }; + Lexer.prototype.tagAccessor = function() { + var prev; + if (!(prev = last(this.tokens)) || prev.spaced) { + return false; + } + if (prev[1] === '::') { + this.tag(0, 'PROTOTYPE_ACCESS'); + } else if (prev[1] === '.' && this.value(1) !== '.') { + if (this.tag(1) === '?') { + this.tag(0, 'SOAK_ACCESS'); + this.tokens.splice(-2, 1); + } else { + this.tag(0, 'PROPERTY_ACCESS'); + } + } else { + return prev[0] === '@'; + } + return true; + }; + Lexer.prototype.sanitizeHeredoc = function(doc, options) { + var _ref2, attempt, herecomment, indent, match; + indent = options.indent, herecomment = options.herecomment; + if (herecomment && 0 > doc.indexOf('\n')) { + return doc; + } + if (!herecomment) { + while (match = HEREDOC_INDENT.exec(doc)) { + attempt = match[1]; + if (indent === null || (0 < (_ref2 = attempt.length)) && (_ref2 < indent.length)) { + indent = attempt; + } + } + } + if (indent) { + doc = doc.replace(RegExp("\\n" + indent, "g"), '\n'); + } + if (!herecomment) { + doc = doc.replace(/^\n/, ''); + } + return doc; + }; + Lexer.prototype.tagParameters = function() { + var i, tok; + if (this.tag() !== ')') { + return; + } + i = this.tokens.length; + while (tok = this.tokens[--i]) { + switch (tok[0]) { + case 'IDENTIFIER': + tok[0] = 'PARAM'; + break; + case ')': + tok[0] = 'PARAM_END'; + break; + case '(': + case 'CALL_START': + tok[0] = 'PARAM_START'; + return true; + } + } + return true; + }; + Lexer.prototype.closeIndentation = function() { + return this.outdentToken(this.indent); + }; + Lexer.prototype.identifierError = function(word) { + throw SyntaxError("Reserved word \"" + word + "\" on line " + (this.line + 1)); + }; + Lexer.prototype.assignmentError = function() { + throw SyntaxError("Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned"); + }; + Lexer.prototype.balancedString = function(str, delimited, options) { + var _i, _len, close, i, levels, open, pair, slen; + options || (options = {}); + levels = []; + i = 0; + slen = str.length; + while (i < slen) { + if (levels.length && str.charAt(i) === '\\') { + i += 1; + } else { + for (_i = 0, _len = delimited.length; _i < _len; _i++) { + pair = delimited[_i]; + open = pair[0], close = pair[1]; + if (levels.length && starts(str, close, i) && last(levels) === pair) { + levels.pop(); + i += close.length - 1; + if (!levels.length) { + i += 1; + } + break; + } + if (starts(str, open, i)) { + levels.push(pair); + i += open.length - 1; + break; + } + } + } + if (!levels.length) { + break; + } + i += 1; + } + if (levels.length) { + throw SyntaxError("Unterminated " + (levels.pop()[0]) + " starting on line " + (this.line + 1)); + } + return !i ? false : str.slice(0, i); + }; + Lexer.prototype.interpolateString = function(str, options) { + var _len, _ref2, _ref3, _this, expr, heredoc, i, inner, interpolated, letter, nested, pi, regex, tag, tokens, value; + _ref2 = options || (options = {}), heredoc = _ref2.heredoc, regex = _ref2.regex; + tokens = []; + pi = 0; + i = -1; + while (letter = str.charAt(i += 1)) { + if (letter === '\\') { + i += 1; + continue; + } + if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), [['{', '}']])))) { + continue; + } + if (pi < i) { + tokens.push(['TO_BE_STRING', str.slice(pi, i)]); + } + inner = expr.slice(1, -1).replace(LEADING_SPACES, '').replace(TRAILING_SPACES, ''); + if (inner.length) { + nested = new Lexer().tokenize(inner, { + line: this.line, + rewrite: false + }); + nested.pop(); + if (nested.length > 1) { + nested.unshift(['(', '(']); + nested.push([')', ')']); + } + tokens.push(['TOKENS', nested]); + } + i += expr.length; + pi = i + 1; + } + if ((i > pi) && (pi < str.length)) { + tokens.push(['TO_BE_STRING', str.slice(pi)]); + } + if (regex) { + return tokens; + } + if (!tokens.length) { + return this.token('STRING', '""'); + } + if (tokens[0][0] !== 'TO_BE_STRING') { + tokens.unshift(['', '']); + } + if (interpolated = tokens.length > 1) { + this.token('(', '('); + } + for (i = 0, _len = tokens.length; i < _len; i++) { + _ref3 = tokens[i], tag = _ref3[0], value = _ref3[1]; + if (i) { + this.token('+', '+'); + } + if (tag === 'TOKENS') { + (_this = this.tokens).push.apply(_this, value); + } else { + this.token('STRING', this.makeString(value, '"', heredoc)); + } + } + if (interpolated) { + this.token(')', ')'); + } + return tokens; + }; + Lexer.prototype.token = function(tag, value) { + return this.tokens.push([tag, value, this.line]); + }; + Lexer.prototype.tag = function(index, tag) { + var tok; + return (tok = last(this.tokens, index)) && ((tag != null) ? (tok[0] = tag) : tok[0]); + }; + Lexer.prototype.value = function(index, val) { + var tok; + return (tok = last(this.tokens, index)) && ((val != null) ? (tok[1] = val) : tok[1]); + }; + Lexer.prototype.unfinished = function() { + var prev, value; + return (prev = last(this.tokens, 1)) && prev[0] !== '.' && (value = this.value()) && !value.reserved && NO_NEWLINE.test(value) && !CODE.test(value) && !ASSIGNED.test(this.chunk); + }; + Lexer.prototype.escapeLines = function(str, heredoc) { + return str.replace(MULTILINER, heredoc ? '\\n' : ''); + }; + Lexer.prototype.makeString = function(body, quote, heredoc) { + if (!body) { + return quote + quote; + } + body = body.replace(/\\([\s\S])/g, function(match, contents) { + return (contents === '\n' || contents === quote) ? contents : match; + }); + body = body.replace(RegExp("" + quote, "g"), '\\$&'); + return quote + this.escapeLines(body, heredoc) + quote; + }; + return Lexer; + })(); + JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'try', 'catch', 'finally', 'class', 'extends', 'super']; + COFFEE_KEYWORDS = ['then', 'unless', 'until', 'loop', 'of', 'by', 'when']; + for (op in (COFFEE_ALIASES = { + and: '&&', + or: '||', + is: '==', + isnt: '!=', + not: '!', + yes: 'TRUE', + no: 'FALSE', + on: 'TRUE', + off: 'FALSE' + })) { + COFFEE_KEYWORDS.push(op); + } + RESERVED = ['case', 'default', 'do', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice']; + JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED); + IDENTIFIER = /^([$A-Za-z_][$\w]*)([^\n\S]*:(?!:))?/; + NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i; + HEREDOC = /^("""|''')([\s\S]*?)(?:\n[ \t]*)?\1/; + OPERATOR = /^(?:-[-=>]?|\+[+=]?|\.\.\.?|[*&|\/%=<>^:!?]+)/; + WHITESPACE = /^[ \t]+/; + COMMENT = /^###([^#][\s\S]*?)(?:###[ \t]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/; + CODE = /^[-=]>/; + MULTI_DENT = /^(?:\n[ \t]*)+/; + SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/; + JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/; + REGEX = /^\/(?!\s)[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?![A-Za-z])/; + HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?![A-Za-z])/; + HEREGEX_OMIT = /\s+(?:#.*)?/g; + MULTILINER = /\n/g; + HEREDOC_INDENT = /\n+([ \t]*)/g; + ASSIGNED = /^\s*@?[$A-Za-z_][$\w]*[ \t]*?[:=][^:=>]/; + NEXT_CHARACTER = /^\s*(\S?)/; + NEXT_ELLIPSIS = /^\s*\.\.\.?/; + LEADING_SPACES = /^\s+/; + TRAILING_SPACES = /\s+$/; + NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/; + COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|=']; + UNARY = ['UMINUS', 'UPLUS', '!', '!!', '~', 'NEW', 'TYPEOF', 'DELETE']; + LOGIC = ['&', '|', '^', '&&', '||']; + SHIFT = ['<<', '>>', '>>>']; + COMPARE = ['<=', '<', '>', '>=']; + MATH = ['*', '/', '%']; + RELATION = ['IN', 'OF', 'INSTANCEOF']; + BOOL = ['TRUE', 'FALSE', 'NULL']; + NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', '++', '--', ']']; + CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER']; + INDEXABLE = CALLABLE.concat('NUMBER', 'BOOL'); + LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR']; +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/nodes.js b/node_modules/jade/support/coffee-script/lib/nodes.js new file mode 100644 index 0000000..93d8012 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/nodes.js @@ -0,0 +1,1981 @@ +(function() { + var Accessor, ArrayLiteral, Assign, Base, Call, Class, Closure, Code, Comment, Existence, Expressions, Extends, For, IDENTIFIER, IS_STRING, If, In, Index, Literal, NO, NUMBER, ObjectLiteral, Op, Param, Parens, Push, Range, Return, SIMPLENUM, Scope, Slice, Splat, Switch, TAB, THIS, TRAILING_WHITESPACE, Throw, Try, UTILITIES, Value, While, YES, _ref, compact, del, ends, flatten, include, last, merge, starts, utility; + var __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }; + Scope = require('./scope').Scope; + _ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, merge = _ref.merge, del = _ref.del, include = _ref.include, starts = _ref.starts, ends = _ref.ends, last = _ref.last; + YES = function() { + return true; + }; + NO = function() { + return false; + }; + THIS = function() { + return this; + }; + exports.Base = (function() { + Base = (function() { + function Base() { + this.tags = {}; + return this; + }; + return Base; + })(); + Base.prototype.compile = function(o) { + var closure, code, top; + this.options = o ? merge(o) : {}; + this.tab = o.indent; + top = this.topSensitive() ? this.options.top : del(this.options, 'top'); + closure = this.isStatement(o) && !this.isPureStatement() && !top && !this.options.asStatement && !(this instanceof Comment); + code = closure ? this.compileClosure(this.options) : this.compileNode(this.options); + return code; + }; + Base.prototype.compileClosure = function(o) { + o.sharedScope = o.scope; + if (this.containsPureStatement()) { + throw new Error('cannot include a pure statement in an expression.'); + } + return Closure.wrap(this).compile(o); + }; + Base.prototype.compileReference = function(o, options) { + var _len, compiled, i, node, pair, reference; + pair = (function() { + if (!this.isComplex()) { + return [this, this]; + } else { + reference = new Literal(o.scope.freeVariable('ref')); + compiled = new Assign(reference, this); + return [compiled, reference]; + } + }).call(this); + if (((options != null) ? options.precompile : undefined)) { + for (i = 0, _len = pair.length; i < _len; i++) { + node = pair[i]; + (pair[i] = node.compile(o)); + } + } + return pair; + }; + Base.prototype.idt = function(tabs) { + var idt, num; + idt = this.tab || ''; + num = (tabs || 0) + 1; + while (num -= 1) { + idt += TAB; + } + return idt; + }; + Base.prototype.makeReturn = function() { + return new Return(this); + }; + Base.prototype.contains = function(block) { + var contains; + contains = false; + this.traverseChildren(false, function(node) { + if (block(node)) { + contains = true; + return false; + } + }); + return contains; + }; + Base.prototype.containsType = function(type) { + return this instanceof type || this.contains(function(node) { + return node instanceof type; + }); + }; + Base.prototype.containsPureStatement = function() { + return this.isPureStatement() || this.contains(function(node) { + return node.isPureStatement(); + }); + }; + Base.prototype.traverse = function(block) { + return this.traverseChildren(true, block); + }; + Base.prototype.toString = function(idt, override) { + var _i, _len, _ref2, _result, child, children, klass; + idt || (idt = ''); + children = (function() { + _result = []; + for (_i = 0, _len = (_ref2 = this.collectChildren()).length; _i < _len; _i++) { + child = _ref2[_i]; + _result.push(child.toString(idt + TAB)); + } + return _result; + }).call(this).join(''); + klass = override || this.constructor.name + (this.soakNode ? '?' : ''); + return '\n' + idt + klass + children; + }; + Base.prototype.eachChild = function(func) { + var _i, _j, _len, _len2, _ref2, _ref3, _result, attr, child; + if (!this.children) { + return; + } + _result = []; + for (_i = 0, _len = (_ref2 = this.children).length; _i < _len; _i++) { + attr = _ref2[_i]; + if (this[attr]) { + for (_j = 0, _len2 = (_ref3 = flatten([this[attr]])).length; _j < _len2; _j++) { + child = _ref3[_j]; + if (func(child) === false) { + return; + } + } + } + } + return _result; + }; + Base.prototype.collectChildren = function() { + var nodes; + nodes = []; + this.eachChild(function(node) { + return nodes.push(node); + }); + return nodes; + }; + Base.prototype.traverseChildren = function(crossScope, func) { + return this.eachChild(function(child) { + if (func(child) === false) { + return false; + } + return crossScope || !(child instanceof Code) ? child.traverseChildren(crossScope, func) : undefined; + }); + }; + Base.prototype.invert = function() { + return new Op('!', this); + }; + Base.prototype.children = []; + Base.prototype.unwrap = THIS; + Base.prototype.isStatement = NO; + Base.prototype.isPureStatement = NO; + Base.prototype.isComplex = YES; + Base.prototype.topSensitive = NO; + Base.prototype.unfoldSoak = NO; + Base.prototype.assigns = NO; + return Base; + })(); + exports.Expressions = (function() { + Expressions = (function() { + function Expressions(nodes) { + Expressions.__super__.constructor.call(this); + this.expressions = compact(flatten(nodes || [])); + return this; + }; + return Expressions; + })(); + __extends(Expressions, Base); + Expressions.prototype.children = ['expressions']; + Expressions.prototype.isStatement = YES; + Expressions.prototype.push = function(node) { + this.expressions.push(node); + return this; + }; + Expressions.prototype.unshift = function(node) { + this.expressions.unshift(node); + return this; + }; + Expressions.prototype.unwrap = function() { + return this.expressions.length === 1 ? this.expressions[0] : this; + }; + Expressions.prototype.empty = function() { + return this.expressions.length === 0; + }; + Expressions.prototype.makeReturn = function() { + var end, idx; + end = this.expressions[(idx = this.expressions.length - 1)]; + if (end instanceof Comment) { + end = this.expressions[idx -= 1]; + } + if (end && !(end instanceof Return)) { + this.expressions[idx] = end.makeReturn(); + } + return this; + }; + Expressions.prototype.compile = function(o) { + o || (o = {}); + return o.scope ? Expressions.__super__.compile.call(this, o) : this.compileRoot(o); + }; + Expressions.prototype.compileNode = function(o) { + var _i, _len, _ref2, _result, node; + return (function() { + _result = []; + for (_i = 0, _len = (_ref2 = this.expressions).length; _i < _len; _i++) { + node = _ref2[_i]; + _result.push(this.compileExpression(node, merge(o))); + } + return _result; + }).call(this).join('\n'); + }; + Expressions.prototype.compileRoot = function(o) { + var code; + o.indent = (this.tab = o.bare ? '' : TAB); + o.scope = new Scope(null, this, null); + code = this.compileWithDeclarations(o); + code = code.replace(TRAILING_WHITESPACE, ''); + return o.bare ? code : ("(function() {\n" + code + "\n}).call(this);\n"); + }; + Expressions.prototype.compileWithDeclarations = function(o) { + var code; + code = this.compileNode(o); + if (o.scope.hasAssignments(this)) { + code = ("" + (this.tab) + "var " + (o.scope.compiledAssignments().replace(/\n/g, '$&' + this.tab)) + ";\n" + code); + } + if (!o.globals && o.scope.hasDeclarations(this)) { + code = ("" + (this.tab) + "var " + (o.scope.compiledDeclarations()) + ";\n" + code); + } + return code; + }; + Expressions.prototype.compileExpression = function(node, o) { + var compiledNode; + this.tab = o.indent; + node.tags.front = true; + compiledNode = node.compile(merge(o, { + top: true + })); + return node.isStatement(o) ? compiledNode : ("" + (this.idt()) + compiledNode + ";"); + }; + return Expressions; + })(); + Expressions.wrap = function(nodes) { + if (nodes.length === 1 && nodes[0] instanceof Expressions) { + return nodes[0]; + } + return new Expressions(nodes); + }; + exports.Literal = (function() { + Literal = (function() { + function Literal(_arg) { + this.value = _arg; + Literal.__super__.constructor.call(this); + return this; + }; + return Literal; + })(); + __extends(Literal, Base); + Literal.prototype.makeReturn = function() { + return this.isStatement() ? this : Literal.__super__.makeReturn.call(this); + }; + Literal.prototype.isStatement = function() { + var _ref2; + return ((_ref2 = this.value) === 'break' || _ref2 === 'continue' || _ref2 === 'debugger'); + }; + Literal.prototype.isPureStatement = Literal.prototype.isStatement; + Literal.prototype.isComplex = NO; + Literal.prototype.isReserved = function() { + return !!this.value.reserved; + }; + Literal.prototype.assigns = function(name) { + return name === this.value; + }; + Literal.prototype.compileNode = function(o) { + var end, idt, val; + idt = this.isStatement(o) ? this.idt() : ''; + end = this.isStatement(o) ? ';' : ''; + val = this.isReserved() ? ("\"" + (this.value) + "\"") : this.value; + return idt + val + end; + }; + Literal.prototype.toString = function() { + return ' "' + this.value + '"'; + }; + return Literal; + })(); + exports.Return = (function() { + Return = (function() { + function Return(_arg) { + this.expression = _arg; + Return.__super__.constructor.call(this); + return this; + }; + return Return; + })(); + __extends(Return, Base); + Return.prototype.isStatement = YES; + Return.prototype.isPureStatement = YES; + Return.prototype.children = ['expression']; + Return.prototype.makeReturn = THIS; + Return.prototype.compile = function(o) { + var _ref2, expr; + expr = (((_ref2 = this.expression) != null) ? _ref2.makeReturn() : undefined); + if (expr && (!(expr instanceof Return))) { + return expr.compile(o); + } + return Return.__super__.compile.call(this, o); + }; + Return.prototype.compileNode = function(o) { + var expr; + expr = ''; + if (this.expression) { + if (this.expression.isStatement(o)) { + o.asStatement = true; + } + expr = ' ' + this.expression.compile(o); + } + return "" + (this.tab) + "return" + expr + ";"; + }; + return Return; + })(); + exports.Value = (function() { + Value = (function() { + function Value(_arg, _arg2, tag) { + this.properties = _arg2; + this.base = _arg; + Value.__super__.constructor.call(this); + this.properties || (this.properties = []); + if (tag) { + this.tags[tag] = true; + } + return this; + }; + return Value; + })(); + __extends(Value, Base); + Value.prototype.children = ['base', 'properties']; + Value.prototype.push = function(prop) { + this.properties.push(prop); + return this; + }; + Value.prototype.hasProperties = function() { + return !!this.properties.length; + }; + Value.prototype.isArray = function() { + return this.base instanceof ArrayLiteral && !this.properties.length; + }; + Value.prototype.isObject = function() { + return this.base instanceof ObjectLiteral && !this.properties.length; + }; + Value.prototype.isSplice = function() { + return last(this.properties) instanceof Slice; + }; + Value.prototype.isComplex = function() { + return this.base.isComplex() || this.hasProperties(); + }; + Value.prototype.assigns = function(name) { + return !this.properties.length && this.base.assigns(name); + }; + Value.prototype.makeReturn = function() { + return this.properties.length ? Value.__super__.makeReturn.call(this) : this.base.makeReturn(); + }; + Value.prototype.unwrap = function() { + return this.properties.length ? this : this.base; + }; + Value.prototype.isStatement = function(o) { + return this.base.isStatement(o) && !this.properties.length; + }; + Value.prototype.isSimpleNumber = function() { + return this.base instanceof Literal && SIMPLENUM.test(this.base.value); + }; + Value.prototype.cacheReference = function(o) { + var base, bref, name, nref; + name = last(this.properties); + if (!this.base.isComplex() && this.properties.length < 2 && !((name != null) ? name.isComplex() : undefined)) { + return [this, this]; + } + base = new Value(this.base, this.properties.slice(0, -1)); + if (base.isComplex()) { + bref = new Literal(o.scope.freeVariable('base')); + base = new Value(new Parens(new Assign(bref, base))); + } + if (!name) { + return [base, bref]; + } + if (name.isComplex()) { + nref = new Literal(o.scope.freeVariable('name')); + name = new Index(new Assign(nref, name.index)); + nref = new Index(nref); + } + return [base.push(name), new Value(bref || base.base, [nref || name])]; + }; + Value.prototype.compile = function(o) { + this.base.tags.front = this.tags.front; + return !o.top || this.properties.length ? Value.__super__.compile.call(this, o) : this.base.compile(o); + }; + Value.prototype.compileNode = function(o) { + var _i, _len, code, ifn, prop, props; + if (ifn = this.unfoldSoak(o)) { + return ifn.compile(o); + } + props = this.properties; + if (this.parenthetical && !props.length) { + this.base.parenthetical = true; + } + code = this.base.compile(o); + if (props[0] instanceof Accessor && this.isSimpleNumber()) { + code = ("(" + code + ")"); + } + for (_i = 0, _len = props.length; _i < _len; _i++) { + prop = props[_i]; + (code += prop.compile(o)); + } + return code; + }; + Value.prototype.unfoldSoak = function(o) { + var _len, _ref2, fst, i, ifn, prop, ref, snd; + if (ifn = this.base.unfoldSoak(o)) { + Array.prototype.push.apply(ifn.body.properties, this.properties); + return ifn; + } + for (i = 0, _len = (_ref2 = this.properties).length; i < _len; i++) { + prop = _ref2[i]; + if (prop.soakNode) { + prop.soakNode = false; + fst = new Value(this.base, this.properties.slice(0, i)); + snd = new Value(this.base, this.properties.slice(i)); + if (fst.isComplex()) { + ref = new Literal(o.scope.freeVariable('ref')); + fst = new Parens(new Assign(ref, fst)); + snd.base = ref; + } + ifn = new If(new Existence(fst), snd, { + soak: true + }); + return ifn; + } + } + return null; + }; + return Value; + })(); + exports.Comment = (function() { + Comment = (function() { + function Comment(_arg) { + this.comment = _arg; + Comment.__super__.constructor.call(this); + return this; + }; + return Comment; + })(); + __extends(Comment, Base); + Comment.prototype.isStatement = YES; + Comment.prototype.makeReturn = THIS; + Comment.prototype.compileNode = function(o) { + return this.tab + '/*' + this.comment.replace(/\n/g, '\n' + this.tab) + '*/'; + }; + return Comment; + })(); + exports.Call = (function() { + Call = (function() { + function Call(variable, _arg, _arg2) { + this.soakNode = _arg2; + this.args = _arg; + Call.__super__.constructor.call(this); + this.isNew = false; + this.isSuper = variable === 'super'; + this.variable = this.isSuper ? null : variable; + this.args || (this.args = []); + return this; + }; + return Call; + })(); + __extends(Call, Base); + Call.prototype.children = ['variable', 'args']; + Call.prototype.compileSplatArguments = function(o) { + return Splat.compileSplattedArray(this.args, o); + }; + Call.prototype.newInstance = function() { + this.isNew = true; + return this; + }; + Call.prototype.prefix = function() { + return this.isNew ? 'new ' : ''; + }; + Call.prototype.superReference = function(o) { + var method, name; + method = o.scope.method; + if (!method) { + throw Error("cannot call super outside of a function."); + } + name = method.name; + if (!name) { + throw Error("cannot call super on an anonymous function."); + } + return method.klass ? ("" + (method.klass) + ".__super__." + name) : ("" + name + ".__super__.constructor"); + }; + Call.prototype.unfoldSoak = function(o) { + var _i, _len, _ref2, _ref3, call, ifn, left, list, rite, val; + if (this.soakNode) { + if (val = this.variable) { + if (!(val instanceof Value)) { + val = new Value(val); + } + _ref2 = val.cacheReference(o), left = _ref2[0], rite = _ref2[1]; + } else { + left = new Literal(this.superReference(o)); + rite = new Value(left); + } + rite = new Call(rite, this.args); + rite.isNew = this.isNew; + left = new Literal("typeof " + (left.compile(o)) + " === \"function\""); + ifn = new If(left, new Value(rite), { + soak: true + }); + return ifn; + } + call = this; + list = []; + while (true) { + if (call.variable instanceof Call) { + list.push(call); + call = call.variable; + continue; + } + if (!(call.variable instanceof Value)) { + break; + } + list.push(call); + if (!((call = call.variable.base) instanceof Call)) { + break; + } + } + for (_i = 0, _len = (_ref3 = list.reverse()).length; _i < _len; _i++) { + call = _ref3[_i]; + if (ifn) { + if (call.variable instanceof Call) { + call.variable = ifn; + } else { + call.variable.base = ifn; + } + } + ifn = If.unfoldSoak(o, call, 'variable'); + } + return ifn; + }; + Call.prototype.compileNode = function(o) { + var _i, _j, _len, _len2, _ref2, _ref3, _ref4, _result, arg, args, ifn; + if (ifn = this.unfoldSoak(o)) { + return ifn.compile(o); + } + (((_ref2 = this.variable) != null) ? (_ref2.tags.front = this.tags.front) : undefined); + for (_i = 0, _len = (_ref3 = this.args).length; _i < _len; _i++) { + arg = _ref3[_i]; + if (arg instanceof Splat) { + return this.compileSplat(o); + } + } + args = (function() { + _result = []; + for (_j = 0, _len2 = (_ref4 = this.args).length; _j < _len2; _j++) { + arg = _ref4[_j]; + _result.push((arg.parenthetical = true) && arg.compile(o)); + } + return _result; + }).call(this).join(', '); + return this.isSuper ? this.compileSuper(args, o) : ("" + (this.prefix()) + (this.variable.compile(o)) + "(" + args + ")"); + }; + Call.prototype.compileSuper = function(args, o) { + return "" + (this.superReference(o)) + ".call(this" + (args.length ? ', ' : '') + args + ")"; + }; + Call.prototype.compileSplat = function(o) { + var base, fun, idt, name, ref, splatargs; + splatargs = this.compileSplatArguments(o); + if (this.isSuper) { + return ("" + (this.superReference(o)) + ".apply(this, " + splatargs + ")"); + } + if (!this.isNew) { + if (!((base = this.variable) instanceof Value)) { + base = new Value(base); + } + if ((name = base.properties.pop()) && base.isComplex()) { + ref = o.scope.freeVariable('this'); + fun = ("(" + ref + " = " + (base.compile(o)) + ")" + (name.compile(o))); + } else { + fun = (ref = base.compile(o)); + if (name) { + fun += name.compile(o); + } + } + return ("" + fun + ".apply(" + ref + ", " + splatargs + ")"); + } + idt = this.idt(1); + return "(function(func, args, ctor) {\n" + idt + "ctor.prototype = func.prototype;\n" + idt + "var child = new ctor, result = func.apply(child, args);\n" + idt + "return typeof result === \"object\" ? result : child;\n" + (this.tab) + "})(" + (this.variable.compile(o)) + ", " + splatargs + ", function() {})"; + }; + return Call; + })(); + exports.Extends = (function() { + Extends = (function() { + function Extends(_arg, _arg2) { + this.parent = _arg2; + this.child = _arg; + Extends.__super__.constructor.call(this); + return this; + }; + return Extends; + })(); + __extends(Extends, Base); + Extends.prototype.children = ['child', 'parent']; + Extends.prototype.compileNode = function(o) { + var ref; + ref = new Value(new Literal(utility('extends'))); + return (new Call(ref, [this.child, this.parent])).compile(o); + }; + return Extends; + })(); + exports.Accessor = (function() { + Accessor = (function() { + function Accessor(_arg, tag) { + this.name = _arg; + Accessor.__super__.constructor.call(this); + this.prototype = tag === 'prototype' ? '.prototype' : ''; + this.soakNode = tag === 'soak'; + return this; + }; + return Accessor; + })(); + __extends(Accessor, Base); + Accessor.prototype.children = ['name']; + Accessor.prototype.compileNode = function(o) { + var name, namePart; + name = this.name.compile(o); + namePart = name.match(IS_STRING) ? ("[" + name + "]") : ("." + name); + return this.prototype + namePart; + }; + Accessor.prototype.isComplex = NO; + return Accessor; + })(); + exports.Index = (function() { + Index = (function() { + function Index(_arg) { + this.index = _arg; + Index.__super__.constructor.call(this); + return this; + }; + return Index; + })(); + __extends(Index, Base); + Index.prototype.children = ['index']; + Index.prototype.compileNode = function(o) { + var idx, prefix; + idx = this.index.compile(o); + prefix = this.proto ? '.prototype' : ''; + return "" + prefix + "[" + idx + "]"; + }; + Index.prototype.isComplex = function() { + return this.index.isComplex(); + }; + return Index; + })(); + exports.Range = (function() { + Range = (function() { + function Range(_arg, _arg2, tag) { + this.to = _arg2; + this.from = _arg; + Range.__super__.constructor.call(this); + this.exclusive = tag === 'exclusive'; + this.equals = this.exclusive ? '' : '='; + return this; + }; + return Range; + })(); + __extends(Range, Base); + Range.prototype.children = ['from', 'to']; + Range.prototype.compileVariables = function(o) { + var _ref2, _ref3, _ref4, parts; + o = merge(o, { + top: true + }); + _ref2 = this.from.compileReference(o, { + precompile: true + }), this.from = _ref2[0], this.fromVar = _ref2[1]; + _ref3 = this.to.compileReference(o, { + precompile: true + }), this.to = _ref3[0], this.toVar = _ref3[1]; + _ref4 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref4[0], this.toNum = _ref4[1]; + parts = []; + if (this.from !== this.fromVar) { + parts.push(this.from); + } + return this.to !== this.toVar ? parts.push(this.to) : undefined; + }; + Range.prototype.compileNode = function(o) { + var compare, idx, incr, intro, step, stepPart, vars; + this.compileVariables(o); + if (!o.index) { + return this.compileArray(o); + } + if (this.fromNum && this.toNum) { + return this.compileSimple(o); + } + idx = del(o, 'index'); + step = del(o, 'step'); + vars = ("" + idx + " = " + (this.from)) + (this.to !== this.toVar ? (", " + (this.to)) : ''); + intro = ("(" + (this.fromVar) + " <= " + (this.toVar) + " ? " + idx); + compare = ("" + intro + " <" + (this.equals) + " " + (this.toVar) + " : " + idx + " >" + (this.equals) + " " + (this.toVar) + ")"); + stepPart = step ? step.compile(o) : '1'; + incr = step ? ("" + idx + " += " + stepPart) : ("" + intro + " += " + stepPart + " : " + idx + " -= " + stepPart + ")"); + return "" + vars + "; " + compare + "; " + incr; + }; + Range.prototype.compileSimple = function(o) { + var _ref2, from, idx, step, to; + _ref2 = [+this.fromNum, +this.toNum], from = _ref2[0], to = _ref2[1]; + idx = del(o, 'index'); + step = del(o, 'step'); + step && (step = ("" + idx + " += " + (step.compile(o)))); + return from <= to ? ("" + idx + " = " + from + "; " + idx + " <" + (this.equals) + " " + to + "; " + (step || ("" + idx + "++"))) : ("" + idx + " = " + from + "; " + idx + " >" + (this.equals) + " " + to + "; " + (step || ("" + idx + "--"))); + }; + Range.prototype.compileArray = function(o) { + var _i, _ref2, _ref3, _result, body, clause, i, idt, post, pre, range, result, vars; + if (this.fromNum && this.toNum && (Math.abs(this.fromNum - this.toNum) <= 20)) { + range = (function() { + _result = []; + for (var _i = _ref2 = +this.fromNum, _ref3 = +this.toNum; _ref2 <= _ref3 ? _i <= _ref3 : _i >= _ref3; _ref2 <= _ref3 ? _i += 1 : _i -= 1){ _result.push(_i); } + return _result; + }).call(this); + if (this.exclusive) { + range.pop(); + } + return ("[" + (range.join(', ')) + "]"); + } + idt = this.idt(1); + i = o.scope.freeVariable('i'); + result = o.scope.freeVariable('result'); + pre = ("\n" + idt + result + " = [];"); + if (this.fromNum && this.toNum) { + o.index = i; + body = this.compileSimple(o); + } else { + vars = ("" + i + " = " + (this.from)) + (this.to !== this.toVar ? (", " + (this.to)) : ''); + clause = ("" + (this.fromVar) + " <= " + (this.toVar) + " ?"); + body = ("var " + vars + "; " + clause + " " + i + " <" + (this.equals) + " " + (this.toVar) + " : " + i + " >" + (this.equals) + " " + (this.toVar) + "; " + clause + " " + i + " += 1 : " + i + " -= 1"); + } + post = ("{ " + result + ".push(" + i + "); }\n" + idt + "return " + result + ";\n" + (o.indent)); + return "(function() {" + pre + "\n" + idt + "for (" + body + ")" + post + "}).call(this)"; + }; + return Range; + })(); + exports.Slice = (function() { + Slice = (function() { + function Slice(_arg) { + this.range = _arg; + Slice.__super__.constructor.call(this); + return this; + }; + return Slice; + })(); + __extends(Slice, Base); + Slice.prototype.children = ['range']; + Slice.prototype.compileNode = function(o) { + var from, to; + from = this.range.from ? this.range.from.compile(o) : '0'; + to = this.range.to ? this.range.to.compile(o) : ''; + to += (!to || this.range.exclusive ? '' : ' + 1'); + if (to) { + to = ', ' + to; + } + return ".slice(" + from + to + ")"; + }; + return Slice; + })(); + exports.ObjectLiteral = (function() { + ObjectLiteral = (function() { + function ObjectLiteral(props) { + ObjectLiteral.__super__.constructor.call(this); + this.objects = (this.properties = props || []); + return this; + }; + return ObjectLiteral; + })(); + __extends(ObjectLiteral, Base); + ObjectLiteral.prototype.children = ['properties']; + ObjectLiteral.prototype.compileNode = function(o) { + var _i, _len, _ref2, _result, i, indent, join, lastNoncom, nonComments, obj, prop, props, top; + top = del(o, 'top'); + o.indent = this.idt(1); + nonComments = (function() { + _result = []; + for (_i = 0, _len = (_ref2 = this.properties).length; _i < _len; _i++) { + prop = _ref2[_i]; + if (!(prop instanceof Comment)) { + _result.push(prop); + } + } + return _result; + }).call(this); + lastNoncom = last(nonComments); + props = (function() { + _result = []; + for (i = 0, _len = (_ref2 = this.properties).length; i < _len; i++) { + prop = _ref2[i]; + _result.push((function() { + join = i === this.properties.length - 1 ? '' : (prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'); + indent = prop instanceof Comment ? '' : this.idt(1); + if (prop instanceof Value && prop.tags["this"]) { + prop = new Assign(prop.properties[0].name, prop, 'object'); + } else if (!(prop instanceof Assign) && !(prop instanceof Comment)) { + prop = new Assign(prop, prop, 'object'); + } + return indent + prop.compile(o) + join; + }).call(this)); + } + return _result; + }).call(this); + props = props.join(''); + obj = ("{" + (props ? '\n' + props + '\n' + this.idt() : '') + "}"); + return this.tags.front ? ("(" + obj + ")") : obj; + }; + ObjectLiteral.prototype.assigns = function(name) { + var _i, _len, _ref2, prop; + for (_i = 0, _len = (_ref2 = this.properties).length; _i < _len; _i++) { + prop = _ref2[_i]; + if (prop.assigns(name)) { + return true; + } + } + return false; + }; + return ObjectLiteral; + })(); + exports.ArrayLiteral = (function() { + ArrayLiteral = (function() { + function ArrayLiteral(_arg) { + this.objects = _arg; + ArrayLiteral.__super__.constructor.call(this); + this.objects || (this.objects = []); + return this; + }; + return ArrayLiteral; + })(); + __extends(ArrayLiteral, Base); + ArrayLiteral.prototype.children = ['objects']; + ArrayLiteral.prototype.compileSplatLiteral = function(o) { + return Splat.compileSplattedArray(this.objects, o); + }; + ArrayLiteral.prototype.compileNode = function(o) { + var _i, _len, _len2, _ref2, _ref3, code, i, obj, objects; + o.indent = this.idt(1); + for (_i = 0, _len = (_ref2 = this.objects).length; _i < _len; _i++) { + obj = _ref2[_i]; + if (obj instanceof Splat) { + return this.compileSplatLiteral(o); + } + } + objects = []; + for (i = 0, _len2 = (_ref3 = this.objects).length; i < _len2; i++) { + obj = _ref3[i]; + code = obj.compile(o); + objects.push(obj instanceof Comment ? ("\n" + code + "\n" + (o.indent)) : (i === this.objects.length - 1 ? code : code + ', ')); + } + objects = objects.join(''); + return 0 < objects.indexOf('\n') ? ("[\n" + (o.indent) + objects + "\n" + (this.tab) + "]") : ("[" + objects + "]"); + }; + ArrayLiteral.prototype.assigns = function(name) { + var _i, _len, _ref2, obj; + for (_i = 0, _len = (_ref2 = this.objects).length; _i < _len; _i++) { + obj = _ref2[_i]; + if (obj.assigns(name)) { + return true; + } + } + return false; + }; + return ArrayLiteral; + })(); + exports.Class = (function() { + Class = (function() { + function Class(variable, _arg, _arg2) { + this.properties = _arg2; + this.parent = _arg; + Class.__super__.constructor.call(this); + this.variable = variable === '__temp__' ? new Literal(variable) : variable; + this.properties || (this.properties = []); + this.returns = false; + return this; + }; + return Class; + })(); + __extends(Class, Base); + Class.prototype.children = ['variable', 'parent', 'properties']; + Class.prototype.isStatement = YES; + Class.prototype.makeReturn = function() { + this.returns = true; + return this; + }; + Class.prototype.compileNode = function(o) { + var _i, _len, _ref2, _ref3, _ref4, access, applied, apply, className, constScope, construct, constructor, extension, func, me, pname, prop, props, pvar, ref, returns, val, variable; + variable = this.variable; + if (variable.value === '__temp__') { + variable = new Literal(o.scope.freeVariable('ctor')); + } + extension = this.parent && new Extends(variable, this.parent); + props = new Expressions; + o.top = true; + me = null; + className = variable.compile(o); + constScope = null; + if (this.parent) { + applied = new Value(this.parent, [new Accessor(new Literal('apply'))]); + constructor = new Code([], new Expressions([new Call(applied, [new Literal('this'), new Literal('arguments')])])); + } else { + constructor = new Code([], new Expressions([new Return(new Literal('this'))])); + } + for (_i = 0, _len = (_ref2 = this.properties).length; _i < _len; _i++) { + prop = _ref2[_i]; + _ref3 = [prop.variable, prop.value], pvar = _ref3[0], func = _ref3[1]; + if (pvar && pvar.base.value === 'constructor') { + if (!(func instanceof Code)) { + _ref4 = func.compileReference(o), func = _ref4[0], ref = _ref4[1]; + if (func !== ref) { + props.push(func); + } + apply = new Call(new Value(ref, [new Accessor(new Literal('apply'))]), [new Literal('this'), new Literal('arguments')]); + func = new Code([], new Expressions([apply])); + } + if (func.bound) { + throw new Error("cannot define a constructor as a bound function."); + } + func.name = className; + func.body.push(new Return(new Literal('this'))); + variable = new Value(variable); + variable.namespaced = 0 < className.indexOf('.'); + constructor = func; + if (props.expressions[props.expressions.length - 1] instanceof Comment) { + constructor.comment = props.expressions.pop(); + } + continue; + } + if (func instanceof Code && func.bound) { + if (prop.context === 'this') { + func.context = className; + } else { + func.bound = false; + constScope || (constScope = new Scope(o.scope, constructor.body, constructor)); + me || (me = constScope.freeVariable('this')); + pname = pvar.compile(o); + if (constructor.body.empty()) { + constructor.body.push(new Return(new Literal('this'))); + } + constructor.body.unshift(new Literal("this." + pname + " = function(){ return " + className + ".prototype." + pname + ".apply(" + me + ", arguments); }")); + } + } + if (pvar) { + access = prop.context === 'this' ? pvar.base.properties[0] : new Accessor(pvar, 'prototype'); + val = new Value(variable, [access]); + prop = new Assign(val, func); + } + props.push(prop); + } + constructor.className = className.match(/[\w\d\$_]+$/); + if (me) { + constructor.body.unshift(new Literal("" + me + " = this")); + } + construct = this.idt() + new Assign(variable, constructor).compile(merge(o, { + sharedScope: constScope + })) + ';'; + props = !props.empty() ? '\n' + props.compile(o) : ''; + extension = extension ? '\n' + this.idt() + extension.compile(o) + ';' : ''; + returns = this.returns ? '\n' + new Return(variable).compile(o) : ''; + return construct + extension + props + returns; + }; + return Class; + })(); + exports.Assign = (function() { + Assign = (function() { + function Assign(_arg, _arg2, _arg3) { + this.context = _arg3; + this.value = _arg2; + this.variable = _arg; + Assign.__super__.constructor.call(this); + return this; + }; + return Assign; + })(); + __extends(Assign, Base); + Assign.prototype.METHOD_DEF = /^(?:(\S+)\.prototype\.)?([$A-Za-z_][$\w]*)$/; + Assign.prototype.children = ['variable', 'value']; + Assign.prototype.topSensitive = YES; + Assign.prototype.isValue = function() { + return this.variable instanceof Value; + }; + Assign.prototype.compileNode = function(o) { + var ifn, isValue, match, name, stmt, top, val; + if (isValue = this.isValue()) { + if (this.variable.isArray() || this.variable.isObject()) { + return this.compilePatternMatch(o); + } + if (this.variable.isSplice()) { + return this.compileSplice(o); + } + if (ifn = If.unfoldSoak(o, this, 'variable')) { + delete o.top; + return ifn.compile(o); + } + } + top = del(o, 'top'); + stmt = del(o, 'asStatement'); + name = this.variable.compile(o); + if (this.value instanceof Code && (match = this.METHOD_DEF.exec(name))) { + this.value.name = match[2]; + this.value.klass = match[1]; + } + val = this.value.compile(o); + if (this.context === 'object') { + return ("" + name + ": " + val); + } + if (!(isValue && (this.variable.hasProperties() || this.variable.namespaced))) { + o.scope.find(name); + } + val = ("" + name + " = " + val); + if (stmt) { + return ("" + (this.tab) + val + ";"); + } + return top || this.parenthetical ? val : ("(" + val + ")"); + }; + Assign.prototype.compilePatternMatch = function(o) { + var _len, _ref2, _ref3, accessClass, assigns, code, i, idx, isObject, obj, objects, olength, otop, ref, splat, top, val, valVar, value; + if ((value = this.value).isStatement(o)) { + value = Closure.wrap(value); + } + objects = this.variable.base.objects; + if (!(olength = objects.length)) { + return value.compile(o); + } + isObject = this.variable.isObject(); + if (o.top && olength === 1 && !((obj = objects[0]) instanceof Splat)) { + if (obj instanceof Assign) { + _ref2 = obj, idx = _ref2.variable.base, obj = _ref2.value; + } else { + idx = isObject ? (obj.tags["this"] ? obj.properties[0].name : obj) : new Literal(0); + } + if (!(value instanceof Value)) { + value = new Value(value); + } + accessClass = IDENTIFIER.test(idx.value) ? Accessor : Index; + value.properties.push(new accessClass(idx)); + return new Assign(obj, value).compile(o); + } + top = del(o, 'top'); + otop = merge(o, { + top: true + }); + valVar = value.compile(o); + assigns = []; + splat = false; + if (!IDENTIFIER.test(valVar) || this.variable.assigns(valVar)) { + assigns.push("" + (ref = o.scope.freeVariable('ref')) + " = " + valVar); + valVar = ref; + } + for (i = 0, _len = objects.length; i < _len; i++) { + obj = objects[i]; + idx = i; + if (isObject) { + if (obj instanceof Assign) { + _ref3 = obj, idx = _ref3.variable.base, obj = _ref3.value; + } else { + idx = obj.tags["this"] ? obj.properties[0].name : obj; + } + } + if (!(obj instanceof Value || obj instanceof Splat)) { + throw new Error('pattern matching must use only identifiers on the left-hand side.'); + } + accessClass = isObject && IDENTIFIER.test(idx.value) ? Accessor : Index; + if (!splat && obj instanceof Splat) { + val = new Literal(obj.compileValue(o, valVar, i, olength - i - 1)); + splat = true; + } else { + if (typeof idx !== 'object') { + idx = new Literal(splat ? ("" + valVar + ".length - " + (olength - idx)) : idx); + } + val = new Value(new Literal(valVar), [new accessClass(idx)]); + } + assigns.push(new Assign(obj, val).compile(otop)); + } + if (!top) { + assigns.push(valVar); + } + code = assigns.join(', '); + return top || this.parenthetical ? code : ("(" + code + ")"); + }; + Assign.prototype.compileSplice = function(o) { + var from, name, plus, range, ref, to, val; + range = this.variable.properties.pop().range; + name = this.variable.compile(o); + plus = range.exclusive ? '' : ' + 1'; + from = range.from ? range.from.compile(o) : '0'; + to = range.to ? range.to.compile(o) + ' - ' + from + plus : ("" + name + ".length"); + ref = o.scope.freeVariable('ref'); + val = this.value.compile(o); + return "([].splice.apply(" + name + ", [" + from + ", " + to + "].concat(" + ref + " = " + val + ")), " + ref + ")"; + }; + Assign.prototype.assigns = function(name) { + return this[this.context === 'object' ? 'value' : 'variable'].assigns(name); + }; + return Assign; + })(); + exports.Code = (function() { + Code = (function() { + function Code(_arg, _arg2, tag) { + this.body = _arg2; + this.params = _arg; + Code.__super__.constructor.call(this); + this.params || (this.params = []); + this.body || (this.body = new Expressions); + this.bound = tag === 'boundfunc'; + if (this.bound) { + this.context = 'this'; + } + return this; + }; + return Code; + })(); + __extends(Code, Base); + Code.prototype.children = ['params', 'body']; + Code.prototype.compileNode = function(o) { + var _i, _len, _len2, _ref2, _ref3, _result, close, code, comm, empty, func, i, open, param, params, sharedScope, splat, top, value; + sharedScope = del(o, 'sharedScope'); + top = del(o, 'top'); + o.scope = sharedScope || new Scope(o.scope, this.body, this); + o.top = true; + o.indent = this.idt(1); + empty = this.body.expressions.length === 0; + delete o.bare; + delete o.globals; + splat = undefined; + params = []; + for (i = 0, _len = (_ref2 = this.params).length; i < _len; i++) { + param = _ref2[i]; + if (splat) { + if (param.attach) { + param.assign = new Assign(new Value(new Literal('this'), [new Accessor(param.value)])); + this.body.expressions.splice(splat.index + 1, 0, param.assign); + } + splat.trailings.push(param); + } else { + if (param.attach) { + value = param.value; + _ref3 = [new Literal(o.scope.freeVariable('arg')), param.splat], param = _ref3[0], param.splat = _ref3[1]; + this.body.unshift(new Assign(new Value(new Literal('this'), [new Accessor(value)]), param)); + } + if (param.splat) { + splat = new Splat(param.value); + splat.index = i; + splat.trailings = []; + splat.arglength = this.params.length; + this.body.unshift(splat); + } else { + params.push(param); + } + } + } + o.scope.startLevel(); + params = (function() { + _result = []; + for (_i = 0, _len2 = params.length; _i < _len2; _i++) { + param = params[_i]; + _result.push(param.compile(o)); + } + return _result; + })(); + if (!(empty || this.noReturn)) { + this.body.makeReturn(); + } + for (_i = 0, _len2 = params.length; _i < _len2; _i++) { + param = params[_i]; + (o.scope.parameter(param)); + } + comm = this.comment ? this.comment.compile(o) + '\n' : ''; + if (this.className) { + o.indent = this.idt(2); + } + code = this.body.expressions.length ? ("\n" + (this.body.compileWithDeclarations(o)) + "\n") : ''; + open = this.className ? ("(function() {\n" + comm + (this.idt(1)) + "function " + (this.className) + "(") : "function("; + close = this.className ? ("" + (code && this.idt(1)) + "};\n" + (this.idt(1)) + "return " + (this.className) + ";\n" + (this.tab) + "})()") : ("" + (code && this.tab) + "}"); + func = ("" + open + (params.join(', ')) + ") {" + code + close); + o.scope.endLevel(); + if (this.bound) { + return ("" + (utility('bind')) + "(" + func + ", " + (this.context) + ")"); + } + return this.tags.front ? ("(" + func + ")") : func; + }; + Code.prototype.traverseChildren = function(crossScope, func) { + return crossScope ? Code.__super__.traverseChildren.call(this, crossScope, func) : undefined; + }; + return Code; + })(); + exports.Param = (function() { + Param = (function() { + function Param(_arg, _arg2, _arg3) { + this.splat = _arg3; + this.attach = _arg2; + this.name = _arg; + Param.__super__.constructor.call(this); + this.value = new Literal(this.name); + return this; + }; + return Param; + })(); + __extends(Param, Base); + Param.prototype.children = ['name']; + Param.prototype.compileNode = function(o) { + return this.value.compile(o); + }; + Param.prototype.toString = function() { + var name; + name = this.name; + if (this.attach) { + name = '@' + name; + } + if (this.splat) { + name += '...'; + } + return new Literal(name).toString(); + }; + return Param; + })(); + exports.Splat = (function() { + Splat = (function() { + function Splat(name) { + Splat.__super__.constructor.call(this); + this.name = name.compile ? name : new Literal(name); + return this; + }; + return Splat; + })(); + __extends(Splat, Base); + Splat.prototype.children = ['name']; + Splat.prototype.assigns = function(name) { + return this.name.assigns(name); + }; + Splat.prototype.compileNode = function(o) { + return (this.index != null) ? this.compileParam(o) : this.name.compile(o); + }; + Splat.prototype.compileParam = function(o) { + var _len, _ref2, assign, end, idx, len, name, pos, trailing, variadic; + name = this.name.compile(o); + o.scope.find(name); + end = ''; + if (this.trailings.length) { + len = o.scope.freeVariable('len'); + o.scope.assign(len, "arguments.length"); + variadic = o.scope.freeVariable('result'); + o.scope.assign(variadic, len + ' >= ' + this.arglength); + end = this.trailings.length ? (", " + len + " - " + (this.trailings.length)) : undefined; + for (idx = 0, _len = (_ref2 = this.trailings).length; idx < _len; idx++) { + trailing = _ref2[idx]; + if (trailing.attach) { + assign = trailing.assign; + trailing = new Literal(o.scope.freeVariable('arg')); + assign.value = trailing; + } + pos = this.trailings.length - idx; + o.scope.assign(trailing.compile(o), "arguments[" + variadic + " ? " + len + " - " + pos + " : " + (this.index + idx) + "]"); + } + } + return "" + name + " = " + (utility('slice')) + ".call(arguments, " + (this.index) + end + ")"; + }; + Splat.prototype.compileValue = function(o, name, index, trailings) { + var trail; + trail = trailings ? (", " + name + ".length - " + trailings) : ''; + return "" + (utility('slice')) + ".call(" + name + ", " + index + trail + ")"; + }; + Splat.compileSplattedArray = function(list, o) { + var _len, arg, args, code, end, i, prev; + args = []; + end = -1; + for (i = 0, _len = list.length; i < _len; i++) { + arg = list[i]; + code = arg.compile(o); + prev = args[end]; + if (!(arg instanceof Splat)) { + if (prev && starts(prev, '[') && ends(prev, ']')) { + args[end] = ("" + (prev.slice(0, -1)) + ", " + code + "]"); + continue; + } + if (prev && starts(prev, '.concat([') && ends(prev, '])')) { + args[end] = ("" + (prev.slice(0, -2)) + ", " + code + "])"); + continue; + } + code = ("[" + code + "]"); + } + args[++end] = i === 0 ? code : (".concat(" + code + ")"); + } + return args.join(''); + }; + return Splat; + }).call(this); + exports.While = (function() { + While = (function() { + function While(condition, opts) { + While.__super__.constructor.call(this); + this.condition = ((opts != null) ? opts.invert : undefined) ? condition.invert() : condition; + this.guard = ((opts != null) ? opts.guard : undefined); + return this; + }; + return While; + })(); + __extends(While, Base); + While.prototype.children = ['condition', 'guard', 'body']; + While.prototype.isStatement = YES; + While.prototype.addBody = function(body) { + this.body = body; + return this; + }; + While.prototype.makeReturn = function() { + this.returns = true; + return this; + }; + While.prototype.topSensitive = YES; + While.prototype.compileNode = function(o) { + var cond, post, pre, rvar, set, top; + top = del(o, 'top') && !this.returns; + o.indent = this.idt(1); + this.condition.parenthetical = true; + cond = this.condition.compile(o); + o.top = true; + set = ''; + if (!top) { + rvar = o.scope.freeVariable('result'); + set = ("" + (this.tab) + rvar + " = [];\n"); + if (this.body) { + this.body = Push.wrap(rvar, this.body); + } + } + pre = ("" + set + (this.tab) + "while (" + cond + ")"); + if (this.guard) { + this.body = Expressions.wrap([new If(this.guard, this.body)]); + } + if (this.returns) { + post = '\n' + new Return(new Literal(rvar)).compile(merge(o, { + indent: this.idt() + })); + } else { + post = ''; + } + return "" + pre + " {\n" + (this.body.compile(o)) + "\n" + (this.tab) + "}" + post; + }; + return While; + })(); + exports.Op = (function() { + Op = (function() { + function Op(op, first, second, flip) { + if (op === 'new') { + if (first instanceof Call) { + return first.newInstance(); + } + if (first instanceof Code && first.bound) { + first = new Parens(first); + } + } + Op.__super__.constructor.call(this); + this.operator = this.CONVERSIONS[op] || op; + (this.first = first).tags.operation = true; + if (second) { + (this.second = second).tags.operation = true; + } + this.flip = !!flip; + return this; + }; + return Op; + })(); + __extends(Op, Base); + Op.prototype.CONVERSIONS = { + '==': '===', + '!=': '!==', + of: 'in' + }; + Op.prototype.INVERSIONS = { + '!==': '===', + '===': '!==' + }; + Op.prototype.CHAINABLE = ['<', '>', '>=', '<=', '===', '!==']; + Op.prototype.ASSIGNMENT = ['||=', '&&=', '?=']; + Op.prototype.PREFIX_OPERATORS = ['new', 'typeof', 'delete']; + Op.prototype.children = ['first', 'second']; + Op.prototype.isUnary = function() { + return !this.second; + }; + Op.prototype.isComplex = function() { + return this.operator !== '!' || this.first.isComplex(); + }; + Op.prototype.isMutator = function() { + var _ref2; + return ends(this.operator, '=') && !((_ref2 = this.operator) === '===' || _ref2 === '!=='); + }; + Op.prototype.isChainable = function() { + return include(this.CHAINABLE, this.operator); + }; + Op.prototype.invert = function() { + var _ref2; + if (((_ref2 = this.operator) === '===' || _ref2 === '!==')) { + this.operator = this.INVERSIONS[this.operator]; + return this; + } else return this.second ? new Parens(this).invert() : Op.__super__.invert.call(this); + }; + Op.prototype.toString = function(idt) { + return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator); + }; + Op.prototype.compileNode = function(o) { + if (this.second) { + this.first.tags.front = this.tags.front; + } + if (this.isChainable() && this.first.unwrap() instanceof Op && this.first.unwrap().isChainable()) { + return this.compileChain(o); + } + if (include(this.ASSIGNMENT, this.operator)) { + return this.compileAssignment(o); + } + if (this.isUnary()) { + return this.compileUnary(o); + } + if (this.operator === '?') { + return this.compileExistence(o); + } + if (this.first instanceof Op && this.first.isMutator()) { + this.first = new Parens(this.first); + } + if (this.second instanceof Op && this.second.isMutator()) { + this.second = new Parens(this.second); + } + return [this.first.compile(o), this.operator, this.second.compile(o)].join(' '); + }; + Op.prototype.compileChain = function(o) { + var _ref2, _ref3, first, second, shared; + shared = this.first.unwrap().second; + _ref2 = shared.compileReference(o), this.first.second = _ref2[0], shared = _ref2[1]; + _ref3 = [this.first.compile(o), this.second.compile(o), shared.compile(o)], first = _ref3[0], second = _ref3[1], shared = _ref3[2]; + return "(" + first + ") && (" + shared + " " + (this.operator) + " " + second + ")"; + }; + Op.prototype.compileAssignment = function(o) { + var _ref2, left, rite; + _ref2 = this.first.cacheReference(o), left = _ref2[0], rite = _ref2[1]; + rite = new Assign(rite, this.second); + return new Op(this.operator.slice(0, -1), left, rite).compile(o); + }; + Op.prototype.compileExistence = function(o) { + var fst, ref; + if (this.first.isComplex()) { + ref = o.scope.freeVariable('ref'); + fst = new Parens(new Assign(new Literal(ref), this.first)); + } else { + fst = this.first; + ref = fst.compile(o); + } + return new Existence(fst).compile(o) + (" ? " + ref + " : " + (this.second.compile(o))); + }; + Op.prototype.compileUnary = function(o) { + var parts, space; + space = include(this.PREFIX_OPERATORS, this.operator) ? ' ' : ''; + parts = [this.operator, space, this.first.compile(o)]; + return (this.flip ? parts.reverse() : parts).join(''); + }; + return Op; + })(); + exports.In = (function() { + In = (function() { + function In(_arg, _arg2) { + this.array = _arg2; + this.object = _arg; + In.__super__.constructor.call(this); + return this; + }; + return In; + })(); + __extends(In, Base); + In.prototype.children = ['object', 'array']; + In.prototype.isArray = function() { + return this.array instanceof Value && this.array.isArray(); + }; + In.prototype.compileNode = function(o) { + return this.isArray() ? this.compileOrTest(o) : this.compileLoopTest(o); + }; + In.prototype.compileOrTest = function(o) { + var _len, _ref2, _ref3, _result, i, item, obj1, obj2, tests; + _ref2 = this.object.compileReference(o, { + precompile: true + }), obj1 = _ref2[0], obj2 = _ref2[1]; + tests = (function() { + _result = []; + for (i = 0, _len = (_ref3 = this.array.base.objects).length; i < _len; i++) { + item = _ref3[i]; + _result.push("" + (i ? obj2 : obj1) + " === " + (item.compile(o))); + } + return _result; + }).call(this); + return "(" + (tests.join(' || ')) + ")"; + }; + In.prototype.compileLoopTest = function(o) { + return "" + (utility('inArray')) + "(" + (this.object.compile(o)) + ", " + (this.array.compile(o)) + ")"; + }; + return In; + })(); + exports.Try = (function() { + Try = (function() { + function Try(_arg, _arg2, _arg3, _arg4) { + this.ensure = _arg4; + this.recovery = _arg3; + this.error = _arg2; + this.attempt = _arg; + Try.__super__.constructor.call(this); + return this; + }; + return Try; + })(); + __extends(Try, Base); + Try.prototype.children = ['attempt', 'recovery', 'ensure']; + Try.prototype.isStatement = YES; + Try.prototype.makeReturn = function() { + if (this.attempt) { + this.attempt = this.attempt.makeReturn(); + } + if (this.recovery) { + this.recovery = this.recovery.makeReturn(); + } + return this; + }; + Try.prototype.compileNode = function(o) { + var attemptPart, catchPart, errorPart, finallyPart; + o.indent = this.idt(1); + o.top = true; + attemptPart = this.attempt.compile(o); + errorPart = this.error ? (" (" + (this.error.compile(o)) + ") ") : ' '; + catchPart = this.recovery ? (" catch" + errorPart + "{\n" + (this.recovery.compile(o)) + "\n" + (this.tab) + "}") : (!(this.ensure || this.recovery) ? ' catch (_e) {}' : ''); + finallyPart = (this.ensure || '') && ' finally {\n' + this.ensure.compile(merge(o)) + ("\n" + (this.tab) + "}"); + return "" + (this.tab) + "try {\n" + attemptPart + "\n" + (this.tab) + "}" + catchPart + finallyPart; + }; + return Try; + })(); + exports.Throw = (function() { + Throw = (function() { + function Throw(_arg) { + this.expression = _arg; + Throw.__super__.constructor.call(this); + return this; + }; + return Throw; + })(); + __extends(Throw, Base); + Throw.prototype.children = ['expression']; + Throw.prototype.isStatement = YES; + Throw.prototype.makeReturn = THIS; + Throw.prototype.compileNode = function(o) { + return "" + (this.tab) + "throw " + (this.expression.compile(o)) + ";"; + }; + return Throw; + })(); + exports.Existence = (function() { + Existence = (function() { + function Existence(_arg) { + this.expression = _arg; + Existence.__super__.constructor.call(this); + return this; + }; + return Existence; + })(); + __extends(Existence, Base); + Existence.prototype.children = ['expression']; + Existence.prototype.compileNode = function(o) { + var code; + code = this.expression.compile(o); + code = IDENTIFIER.test(code) && !o.scope.check(code) ? ("typeof " + code + " !== \"undefined\" && " + code + " !== null") : ("" + code + " != null"); + return this.parenthetical ? code : ("(" + code + ")"); + }; + return Existence; + })(); + exports.Parens = (function() { + Parens = (function() { + function Parens(_arg) { + this.expression = _arg; + Parens.__super__.constructor.call(this); + return this; + }; + return Parens; + })(); + __extends(Parens, Base); + Parens.prototype.children = ['expression']; + Parens.prototype.isStatement = function(o) { + return this.expression.isStatement(o); + }; + Parens.prototype.isComplex = function() { + return this.expression.isComplex(); + }; + Parens.prototype.topSensitive = YES; + Parens.prototype.makeReturn = function() { + return this.expression.makeReturn(); + }; + Parens.prototype.compileNode = function(o) { + var code, top; + top = del(o, 'top'); + this.expression.parenthetical = true; + code = this.expression.compile(o); + if (top && this.expression.isPureStatement(o)) { + return code; + } + if (this.parenthetical || this.isStatement(o)) { + return top ? this.tab + code + ';' : code; + } + return "(" + code + ")"; + }; + return Parens; + })(); + exports.For = (function() { + For = (function() { + function For(_arg, source, _arg2, _arg3) { + var _ref2; + this.index = _arg3; + this.name = _arg2; + this.body = _arg; + For.__super__.constructor.call(this); + this.source = source.source, this.guard = source.guard, this.step = source.step; + this.raw = !!source.raw; + this.object = !!source.object; + if (this.object) { + _ref2 = [this.index, this.name], this.name = _ref2[0], this.index = _ref2[1]; + } + this.pattern = this.name instanceof Value; + if (this.index instanceof Value) { + throw new Error('index cannot be a pattern matching expression'); + } + this.returns = false; + return this; + }; + return For; + })(); + __extends(For, Base); + For.prototype.children = ['body', 'source', 'guard']; + For.prototype.isStatement = YES; + For.prototype.topSensitive = YES; + For.prototype.makeReturn = function() { + this.returns = true; + return this; + }; + For.prototype.compileReturnValue = function(val, o) { + if (this.returns) { + return '\n' + new Return(new Literal(val)).compile(o); + } + if (val) { + return '\n' + val; + } + return ''; + }; + For.prototype.compileNode = function(o) { + var body, codeInBody, forPart, guardPart, idt1, index, ivar, lastLine, lvar, name, namePart, nvar, range, ref, resultPart, returnResult, rvar, scope, source, sourcePart, stepPart, svar, topLevel, unstepPart, varPart, vars; + topLevel = del(o, 'top') && !this.returns; + range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length; + source = range ? this.source.base : this.source; + codeInBody = !this.body.containsPureStatement() && this.body.contains(function(node) { + return node instanceof Code; + }); + scope = o.scope; + name = this.name && this.name.compile(o); + index = this.index && this.index.compile(o); + if (name && !this.pattern && (range || !codeInBody)) { + scope.find(name, { + immediate: true + }); + } + if (index) { + scope.find(index, { + immediate: true + }); + } + if (!topLevel) { + rvar = scope.freeVariable('result'); + } + ivar = range ? name : index; + if (!ivar || codeInBody) { + ivar = scope.freeVariable('i'); + } + if (name && !range && codeInBody) { + nvar = scope.freeVariable('i'); + } + varPart = ''; + guardPart = ''; + unstepPart = ''; + body = Expressions.wrap([this.body]); + idt1 = this.idt(1); + if (range) { + forPart = source.compile(merge(o, { + index: ivar, + step: this.step + })); + } else { + svar = (sourcePart = this.source.compile(o)); + if ((name || !this.raw) && !(IDENTIFIER.test(svar) && scope.check(svar, { + immediate: true + }))) { + sourcePart = ("" + (ref = scope.freeVariable('ref')) + " = " + svar); + if (!this.object) { + sourcePart = ("(" + sourcePart + ")"); + } + svar = ref; + } + namePart = this.pattern ? new Assign(this.name, new Literal("" + svar + "[" + ivar + "]")).compile(merge(o, { + top: true + })) : (name ? ("" + name + " = " + svar + "[" + ivar + "]") : undefined); + if (!this.object) { + lvar = scope.freeVariable('len'); + stepPart = this.step ? ("" + ivar + " += " + (this.step.compile(o))) : ("" + ivar + "++"); + forPart = ("" + ivar + " = 0, " + lvar + " = " + sourcePart + ".length; " + ivar + " < " + lvar + "; " + stepPart); + } + } + resultPart = rvar ? ("" + (this.tab) + rvar + " = [];\n") : ''; + returnResult = this.compileReturnValue(rvar, o); + if (!topLevel) { + body = Push.wrap(rvar, body); + } + if (this.guard) { + body = Expressions.wrap([new If(this.guard, body)]); + } + if (codeInBody) { + if (range) { + body.unshift(new Literal("var " + name + " = " + ivar)); + } + if (namePart) { + body.unshift(new Literal("var " + namePart)); + } + if (index) { + body.unshift(new Literal("var " + index + " = " + ivar)); + } + lastLine = body.expressions.pop(); + if (index) { + body.push(new Assign(new Literal(ivar), new Literal(index))); + } + if (nvar) { + body.push(new Assign(new Literal(nvar), new Literal(name))); + } + body.push(lastLine); + o.indent = this.idt(1); + body = Expressions.wrap([new Literal(body.compile(o))]); + if (index) { + body.push(new Assign(new Literal(index), new Literal(ivar))); + } + if (name) { + body.push(new Assign(new Literal(name), new Literal(nvar || ivar))); + } + } else { + if (namePart) { + varPart = ("" + idt1 + namePart + ";\n"); + } + if (forPart && name === ivar) { + unstepPart = this.step ? ("" + name + " -= " + (this.step.compile(o)) + ";") : ("" + name + "--;"); + unstepPart = ("\n" + (this.tab)) + unstepPart; + } + } + if (this.object) { + forPart = ("" + ivar + " in " + sourcePart); + if (!this.raw) { + guardPart = ("\n" + idt1 + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + ivar + ")) continue;"); + } + } + body = body.compile(merge(o, { + indent: idt1, + top: true + })); + vars = range ? name : ("" + name + ", " + ivar); + return "" + resultPart + (this.tab) + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + (this.tab) + "}" + unstepPart + returnResult; + }; + return For; + })(); + exports.Switch = (function() { + Switch = (function() { + function Switch(_arg, _arg2, _arg3) { + this.otherwise = _arg3; + this.cases = _arg2; + this.subject = _arg; + Switch.__super__.constructor.call(this); + this.tags.subjectless = !this.subject; + this.subject || (this.subject = new Literal('true')); + return this; + }; + return Switch; + })(); + __extends(Switch, Base); + Switch.prototype.children = ['subject', 'cases', 'otherwise']; + Switch.prototype.isStatement = YES; + Switch.prototype.makeReturn = function() { + var _i, _len, _ref2, pair; + for (_i = 0, _len = (_ref2 = this.cases).length; _i < _len; _i++) { + pair = _ref2[_i]; + pair[1].makeReturn(); + } + if (this.otherwise) { + this.otherwise.makeReturn(); + } + return this; + }; + Switch.prototype.compileNode = function(o) { + var _i, _j, _len, _len2, _ref2, _ref3, block, code, condition, conditions, exprs, idt, pair; + idt = (o.indent = this.idt(2)); + o.top = true; + code = ("" + (this.tab) + "switch (" + (this.subject.compile(o)) + ") {"); + for (_i = 0, _len = (_ref2 = this.cases).length; _i < _len; _i++) { + pair = _ref2[_i]; + conditions = pair[0], block = pair[1]; + exprs = block.expressions; + for (_j = 0, _len2 = (_ref3 = flatten([conditions])).length; _j < _len2; _j++) { + condition = _ref3[_j]; + if (this.tags.subjectless) { + condition = new Op('!!', new Parens(condition)); + } + code += ("\n" + (this.idt(1)) + "case " + (condition.compile(o)) + ":"); + } + code += ("\n" + (block.compile(o))); + if (!(last(exprs) instanceof Return)) { + code += ("\n" + idt + "break;"); + } + } + if (this.otherwise) { + code += ("\n" + (this.idt(1)) + "default:\n" + (this.otherwise.compile(o))); + } + code += ("\n" + (this.tab) + "}"); + return code; + }; + return Switch; + })(); + exports.If = (function() { + If = (function() { + function If(condition, _arg, tags) { + this.body = _arg; + this.tags = tags || (tags = {}); + this.condition = tags.invert ? condition.invert() : condition; + this.soakNode = tags.soak; + this.elseBody = null; + this.isChain = false; + return this; + }; + return If; + })(); + __extends(If, Base); + If.prototype.children = ['condition', 'body', 'elseBody', 'assigner']; + If.prototype.topSensitive = YES; + If.prototype.bodyNode = function() { + var _ref2; + return (((_ref2 = this.body) != null) ? _ref2.unwrap() : undefined); + }; + If.prototype.elseBodyNode = function() { + var _ref2; + return (((_ref2 = this.elseBody) != null) ? _ref2.unwrap() : undefined); + }; + If.prototype.addElse = function(elseBody) { + if (this.isChain) { + this.elseBodyNode().addElse(elseBody); + } else { + this.isChain = elseBody instanceof If; + this.elseBody = this.ensureExpressions(elseBody); + } + return this; + }; + If.prototype.isStatement = function(o) { + var _ref2; + return this.statement || (this.statement = ((o != null) ? o.top : undefined) || this.bodyNode().isStatement(o) || (((_ref2 = this.elseBodyNode()) != null) ? _ref2.isStatement(o) : undefined)); + }; + If.prototype.compileCondition = function(o) { + this.condition.parenthetical = true; + return this.condition.compile(o); + }; + If.prototype.compileNode = function(o) { + return this.isStatement(o) ? this.compileStatement(o) : this.compileExpression(o); + }; + If.prototype.makeReturn = function() { + if (this.isStatement()) { + this.body && (this.body = this.ensureExpressions(this.body.makeReturn())); + this.elseBody && (this.elseBody = this.ensureExpressions(this.elseBody.makeReturn())); + return this; + } else { + return new Return(this); + } + }; + If.prototype.ensureExpressions = function(node) { + return node instanceof Expressions ? node : new Expressions([node]); + }; + If.prototype.compileStatement = function(o) { + var child, condO, ifPart, top; + top = del(o, 'top'); + child = del(o, 'chainChild'); + condO = merge(o); + o.indent = this.idt(1); + o.top = true; + ifPart = ("if (" + (this.compileCondition(condO)) + ") {\n" + (this.body.compile(o)) + "\n" + (this.tab) + "}"); + if (!child) { + ifPart = this.tab + ifPart; + } + if (!this.elseBody) { + return ifPart; + } + return ifPart + (this.isChain ? ' else ' + this.elseBodyNode().compile(merge(o, { + indent: this.tab, + chainChild: true + })) : (" else {\n" + (this.elseBody.compile(o)) + "\n" + (this.tab) + "}")); + }; + If.prototype.compileExpression = function(o) { + var code, elsePart, ifPart; + this.bodyNode().tags.operation = (this.condition.tags.operation = true); + if (this.elseBody) { + this.elseBodyNode().tags.operation = true; + } + ifPart = this.condition.compile(o) + ' ? ' + this.bodyNode().compile(o); + elsePart = this.elseBody ? this.elseBodyNode().compile(o) : 'undefined'; + code = ("" + ifPart + " : " + elsePart); + return this.tags.operation || this.soakNode ? ("(" + code + ")") : code; + }; + If.prototype.unfoldSoak = function() { + return this.soakNode && this; + }; + If.unfoldSoak = function(o, parent, name) { + var ifn; + if (!(ifn = parent[name].unfoldSoak(o))) { + return; + } + parent[name] = ifn.body; + ifn.body = new Value(parent); + return ifn; + }; + return If; + }).call(this); + Push = { + wrap: function(name, expressions) { + if (expressions.empty() || expressions.containsPureStatement()) { + return expressions; + } + return Expressions.wrap([new Call(new Value(new Literal(name), [new Accessor(new Literal('push'))]), [expressions.unwrap()])]); + } + }; + Closure = { + wrap: function(expressions, statement, noReturn) { + var args, call, func, mentionsArgs, meth; + if (expressions.containsPureStatement()) { + return expressions; + } + func = new Parens(new Code([], Expressions.wrap([expressions]))); + args = []; + if ((mentionsArgs = expressions.contains(this.literalArgs)) || (expressions.contains(this.literalThis))) { + meth = new Literal(mentionsArgs ? 'apply' : 'call'); + args = [new Literal('this')]; + if (mentionsArgs) { + args.push(new Literal('arguments')); + } + func = new Value(func, [new Accessor(meth)]); + func.noReturn = noReturn; + } + call = new Call(func, args); + return statement ? Expressions.wrap([call]) : call; + }, + literalArgs: function(node) { + return node instanceof Literal && node.value === 'arguments'; + }, + literalThis: function(node) { + return node instanceof Literal && node.value === 'this' || node instanceof Code && node.bound; + } + }; + UTILITIES = { + "extends": 'function(child, parent) {\n function ctor() { this.constructor = child; }\n ctor.prototype = parent.prototype;\n child.prototype = new ctor;\n if (typeof parent.extended === "function") parent.extended(child);\n child.__super__ = parent.prototype;\n}', + bind: 'function(func, context) {\n return function() { return func.apply(context, arguments); };\n}', + inArray: '(function() {\n var indexOf = Array.prototype.indexOf || function(item) {\n var i = this.length; while (i--) if (this[i] === item) return i;\n return -1;\n };\n return function(item, array) { return indexOf.call(array, item) > -1; };\n})();', + hasProp: 'Object.prototype.hasOwnProperty', + slice: 'Array.prototype.slice' + }; + TAB = ' '; + TRAILING_WHITESPACE = /[ \t]+$/gm; + IDENTIFIER = /^[$A-Za-z_][$\w]*$/; + NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i; + SIMPLENUM = /^[+-]?\d+$/; + IS_STRING = /^['"]/; + utility = function(name) { + var ref; + ref = ("__" + name); + Scope.root.assign(ref, UTILITIES[name]); + return ref; + }; +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/optparse.js b/node_modules/jade/support/coffee-script/lib/optparse.js new file mode 100755 index 0000000..4a9ae28 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/optparse.js @@ -0,0 +1,107 @@ +(function() { + var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments; + exports.OptionParser = (function() { + OptionParser = (function() { + function OptionParser(rules, banner) { + this.banner = banner; + this.rules = buildRules(rules); + return this; + }; + return OptionParser; + })(); + OptionParser.prototype.parse = function(args) { + var _i, _len, _len2, _ref, arg, i, isOption, matchedRule, options, rule, value; + options = { + arguments: [] + }; + args = normalizeArguments(args); + for (i = 0, _len = args.length; i < _len; i++) { + arg = args[i]; + isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG)); + matchedRule = false; + for (_i = 0, _len2 = (_ref = this.rules).length; _i < _len2; _i++) { + rule = _ref[_i]; + if (rule.shortFlag === arg || rule.longFlag === arg) { + value = rule.hasArgument ? args[i += 1] : true; + options[rule.name] = rule.isList ? (options[rule.name] || []).concat(value) : value; + matchedRule = true; + break; + } + } + if (isOption && !matchedRule) { + throw new Error("unrecognized option: " + arg); + } + if (!isOption) { + options.arguments = args.slice(i); + break; + } + } + return options; + }; + OptionParser.prototype.help = function() { + var _i, _len, _ref, letPart, lines, rule, spaces; + lines = ['Available options:']; + if (this.banner) { + lines.unshift("" + (this.banner) + "\n"); + } + for (_i = 0, _len = (_ref = this.rules).length; _i < _len; _i++) { + rule = _ref[_i]; + spaces = 15 - rule.longFlag.length; + spaces = spaces > 0 ? Array(spaces + 1).join(' ') : ''; + letPart = rule.shortFlag ? rule.shortFlag + ', ' : ' '; + lines.push(' ' + letPart + rule.longFlag + spaces + rule.description); + } + return "\n" + (lines.join('\n')) + "\n"; + }; + return OptionParser; + })(); + LONG_FLAG = /^(--\w[\w\-]+)/; + SHORT_FLAG = /^(-\w)/; + MULTI_FLAG = /^-(\w{2,})/; + OPTIONAL = /\[(\w+(\*?))\]/; + buildRules = function(rules) { + var _i, _len, _result, tuple; + _result = []; + for (_i = 0, _len = rules.length; _i < _len; _i++) { + tuple = rules[_i]; + _result.push((function() { + if (tuple.length < 3) { + tuple.unshift(null); + } + return buildRule.apply(buildRule, tuple); + })()); + } + return _result; + }; + buildRule = function(shortFlag, longFlag, description, options) { + var match; + match = longFlag.match(OPTIONAL); + longFlag = longFlag.match(LONG_FLAG)[1]; + options || (options = {}); + return { + name: longFlag.substr(2), + shortFlag: shortFlag, + longFlag: longFlag, + description: description, + hasArgument: !!(match && match[1]), + isList: !!(match && match[2]) + }; + }; + normalizeArguments = function(args) { + var _i, _j, _len, _len2, _ref, arg, l, match, result; + args = args.slice(0); + result = []; + for (_i = 0, _len = args.length; _i < _len; _i++) { + arg = args[_i]; + if (match = arg.match(MULTI_FLAG)) { + for (_j = 0, _len2 = (_ref = match[1].split('')).length; _j < _len2; _j++) { + l = _ref[_j]; + result.push('-' + l); + } + } else { + result.push(arg); + } + } + return result; + }; +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/parser.js b/node_modules/jade/support/coffee-script/lib/parser.js new file mode 100755 index 0000000..e77d3bc --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/parser.js @@ -0,0 +1,687 @@ +/* Jison generated parser */ +var parser = (function(){ +var parser = {trace: function trace() { }, +yy: {}, +symbols_: {"error":2,"Root":3,"TERMINATOR":4,"Body":5,"Block":6,"Line":7,"Expression":8,"Statement":9,"Return":10,"Throw":11,"BREAK":12,"CONTINUE":13,"DEBUGGER":14,"Value":15,"Invocation":16,"Code":17,"Operation":18,"Assign":19,"If":20,"Try":21,"While":22,"For":23,"Switch":24,"Extends":25,"Class":26,"Existence":27,"Comment":28,"INDENT":29,"OUTDENT":30,"Identifier":31,"IDENTIFIER":32,"AlphaNumeric":33,"NUMBER":34,"STRING":35,"Literal":36,"JS":37,"REGEX":38,"BOOL":39,"Assignable":40,"=":41,"AssignObj":42,"ThisProperty":43,":":44,"RETURN":45,"HERECOMMENT":46,"?":47,"PARAM_START":48,"ParamList":49,"PARAM_END":50,"FuncGlyph":51,"->":52,"=>":53,"OptComma":54,",":55,"Param":56,"PARAM":57,"@":58,"...":59,"Splat":60,"SimpleAssignable":61,"Accessor":62,"Array":63,"Object":64,"Parenthetical":65,"Range":66,"This":67,"PROPERTY_ACCESS":68,"PROTOTYPE_ACCESS":69,"::":70,"SOAK_ACCESS":71,"Index":72,"Slice":73,"INDEX_START":74,"INDEX_END":75,"INDEX_SOAK":76,"INDEX_PROTO":77,"{":78,"AssignList":79,"}":80,"CLASS":81,"EXTENDS":82,"ClassBody":83,"ClassAssign":84,"OptFuncExist":85,"Arguments":86,"SUPER":87,"FUNC_EXIST":88,"CALL_START":89,"CALL_END":90,"ArgList":91,"THIS":92,"RangeDots":93,"..":94,"[":95,"]":96,"Arg":97,"SimpleArgs":98,"TRY":99,"Catch":100,"FINALLY":101,"CATCH":102,"THROW":103,"(":104,")":105,"WhileSource":106,"WHILE":107,"WHEN":108,"UNTIL":109,"Loop":110,"LOOP":111,"ForBody":112,"FOR":113,"ForStart":114,"ForSource":115,"ForVariables":116,"ALL":117,"ForValue":118,"FORIN":119,"FOROF":120,"BY":121,"SWITCH":122,"Whens":123,"ELSE":124,"When":125,"LEADING_WHEN":126,"IfBlock":127,"IF":128,"UNLESS":129,"POST_IF":130,"POST_UNLESS":131,"UNARY":132,"-":133,"+":134,"--":135,"++":136,"==":137,"!=":138,"MATH":139,"SHIFT":140,"COMPARE":141,"LOGIC":142,"COMPOUND_ASSIGN":143,"RELATION":144,"$accept":0,"$end":1}, +terminals_: {"2":"error","4":"TERMINATOR","12":"BREAK","13":"CONTINUE","14":"DEBUGGER","29":"INDENT","30":"OUTDENT","32":"IDENTIFIER","34":"NUMBER","35":"STRING","37":"JS","38":"REGEX","39":"BOOL","41":"=","44":":","45":"RETURN","46":"HERECOMMENT","47":"?","48":"PARAM_START","50":"PARAM_END","52":"->","53":"=>","55":",","57":"PARAM","58":"@","59":"...","68":"PROPERTY_ACCESS","69":"PROTOTYPE_ACCESS","70":"::","71":"SOAK_ACCESS","74":"INDEX_START","75":"INDEX_END","76":"INDEX_SOAK","77":"INDEX_PROTO","78":"{","80":"}","81":"CLASS","82":"EXTENDS","87":"SUPER","88":"FUNC_EXIST","89":"CALL_START","90":"CALL_END","92":"THIS","94":"..","95":"[","96":"]","99":"TRY","101":"FINALLY","102":"CATCH","103":"THROW","104":"(","105":")","107":"WHILE","108":"WHEN","109":"UNTIL","111":"LOOP","113":"FOR","117":"ALL","119":"FORIN","120":"FOROF","121":"BY","122":"SWITCH","124":"ELSE","126":"LEADING_WHEN","128":"IF","129":"UNLESS","130":"POST_IF","131":"POST_UNLESS","132":"UNARY","133":"-","134":"+","135":"--","136":"++","137":"==","138":"!=","139":"MATH","140":"SHIFT","141":"COMPARE","142":"LOGIC","143":"COMPOUND_ASSIGN","144":"RELATION"}, +productions_: [0,[3,0],[3,1],[3,1],[3,2],[5,1],[5,3],[5,2],[7,1],[7,1],[9,1],[9,1],[9,1],[9,1],[9,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[6,3],[6,2],[6,2],[31,1],[33,1],[33,1],[36,1],[36,1],[36,1],[36,1],[19,3],[19,5],[42,1],[42,1],[42,1],[42,3],[42,3],[42,5],[42,5],[42,1],[10,2],[10,1],[28,1],[27,2],[17,5],[17,2],[51,1],[51,1],[54,0],[54,1],[49,0],[49,1],[49,3],[56,1],[56,2],[56,2],[56,3],[60,2],[61,1],[61,2],[61,2],[61,1],[40,1],[40,1],[40,1],[15,1],[15,1],[15,1],[15,1],[15,1],[62,2],[62,2],[62,1],[62,2],[62,1],[62,1],[72,3],[72,2],[72,2],[64,4],[79,0],[79,1],[79,3],[79,4],[79,6],[26,2],[26,4],[26,5],[26,7],[26,4],[26,1],[26,3],[26,6],[84,1],[84,3],[84,5],[83,0],[83,1],[83,3],[83,3],[25,3],[16,3],[16,3],[16,1],[16,2],[85,0],[85,1],[86,2],[86,4],[67,1],[67,1],[93,1],[93,1],[43,2],[66,5],[73,5],[73,4],[73,4],[63,2],[63,4],[91,1],[91,3],[91,4],[91,4],[91,6],[97,1],[97,1],[98,1],[98,3],[21,2],[21,3],[21,4],[21,5],[100,3],[11,2],[65,3],[65,2],[106,2],[106,4],[106,2],[106,4],[22,2],[22,2],[22,2],[22,1],[110,2],[110,2],[23,2],[23,2],[23,2],[112,2],[112,2],[114,2],[114,3],[118,1],[118,1],[118,1],[116,1],[116,3],[115,2],[115,2],[115,4],[115,4],[115,4],[115,6],[115,6],[24,5],[24,7],[24,4],[24,6],[123,1],[123,2],[125,3],[125,4],[127,3],[127,3],[127,5],[127,3],[20,1],[20,3],[20,3],[20,3],[20,3],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,5],[18,3]], +performAction: function anonymous(yytext,yyleng,yylineno,yy) { + +var $$ = arguments[5],$0=arguments[5].length; +switch(arguments[4]) { +case 1:return this.$ = new yy.Expressions; +break; +case 2:return this.$ = new yy.Expressions; +break; +case 3:return this.$ = $$[$0-1+1-1]; +break; +case 4:return this.$ = $$[$0-2+1-1]; +break; +case 5:this.$ = yy.Expressions.wrap([$$[$0-1+1-1]]); +break; +case 6:this.$ = $$[$0-3+1-1].push($$[$0-3+3-1]); +break; +case 7:this.$ = $$[$0-2+1-1]; +break; +case 8:this.$ = $$[$0-1+1-1]; +break; +case 9:this.$ = $$[$0-1+1-1]; +break; +case 10:this.$ = $$[$0-1+1-1]; +break; +case 11:this.$ = $$[$0-1+1-1]; +break; +case 12:this.$ = new yy.Literal($$[$0-1+1-1]); +break; +case 13:this.$ = new yy.Literal($$[$0-1+1-1]); +break; +case 14:this.$ = new yy.Literal($$[$0-1+1-1]); +break; +case 15:this.$ = $$[$0-1+1-1]; +break; +case 16:this.$ = $$[$0-1+1-1]; +break; +case 17:this.$ = $$[$0-1+1-1]; +break; +case 18:this.$ = $$[$0-1+1-1]; +break; +case 19:this.$ = $$[$0-1+1-1]; +break; +case 20:this.$ = $$[$0-1+1-1]; +break; +case 21:this.$ = $$[$0-1+1-1]; +break; +case 22:this.$ = $$[$0-1+1-1]; +break; +case 23:this.$ = $$[$0-1+1-1]; +break; +case 24:this.$ = $$[$0-1+1-1]; +break; +case 25:this.$ = $$[$0-1+1-1]; +break; +case 26:this.$ = $$[$0-1+1-1]; +break; +case 27:this.$ = $$[$0-1+1-1]; +break; +case 28:this.$ = $$[$0-1+1-1]; +break; +case 29:this.$ = $$[$0-3+2-1]; +break; +case 30:this.$ = new yy.Expressions; +break; +case 31:this.$ = yy.Expressions.wrap([$$[$0-2+2-1]]); +break; +case 32:this.$ = new yy.Literal($$[$0-1+1-1]); +break; +case 33:this.$ = new yy.Literal($$[$0-1+1-1]); +break; +case 34:this.$ = new yy.Literal($$[$0-1+1-1]); +break; +case 35:this.$ = $$[$0-1+1-1]; +break; +case 36:this.$ = new yy.Literal($$[$0-1+1-1]); +break; +case 37:this.$ = new yy.Literal($$[$0-1+1-1]); +break; +case 38:this.$ = new yy.Literal($$[$0-1+1-1]); +break; +case 39:this.$ = new yy.Assign($$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 40:this.$ = new yy.Assign($$[$0-5+1-1], $$[$0-5+4-1]); +break; +case 41:this.$ = new yy.Value($$[$0-1+1-1]); +break; +case 42:this.$ = $$[$0-1+1-1]; +break; +case 43:this.$ = $$[$0-1+1-1]; +break; +case 44:this.$ = new yy.Assign(new yy.Value($$[$0-3+1-1]), $$[$0-3+3-1], 'object'); +break; +case 45:this.$ = new yy.Assign(new yy.Value($$[$0-3+1-1]), $$[$0-3+3-1], 'object'); +break; +case 46:this.$ = new yy.Assign(new yy.Value($$[$0-5+1-1]), $$[$0-5+4-1], 'object'); +break; +case 47:this.$ = new yy.Assign(new yy.Value($$[$0-5+1-1]), $$[$0-5+4-1], 'object'); +break; +case 48:this.$ = $$[$0-1+1-1]; +break; +case 49:this.$ = new yy.Return($$[$0-2+2-1]); +break; +case 50:this.$ = new yy.Return; +break; +case 51:this.$ = new yy.Comment($$[$0-1+1-1]); +break; +case 52:this.$ = new yy.Existence($$[$0-2+1-1]); +break; +case 53:this.$ = new yy.Code($$[$0-5+2-1], $$[$0-5+5-1], $$[$0-5+4-1]); +break; +case 54:this.$ = new yy.Code([], $$[$0-2+2-1], $$[$0-2+1-1]); +break; +case 55:this.$ = 'func'; +break; +case 56:this.$ = 'boundfunc'; +break; +case 57:this.$ = $$[$0-1+1-1]; +break; +case 58:this.$ = $$[$0-1+1-1]; +break; +case 59:this.$ = []; +break; +case 60:this.$ = [$$[$0-1+1-1]]; +break; +case 61:this.$ = $$[$0-3+1-1].concat($$[$0-3+3-1]); +break; +case 62:this.$ = new yy.Literal($$[$0-1+1-1]); +break; +case 63:this.$ = new yy.Param($$[$0-2+2-1], true); +break; +case 64:this.$ = new yy.Param($$[$0-2+1-1], false, true); +break; +case 65:this.$ = new yy.Param($$[$0-3+2-1], true, true); +break; +case 66:this.$ = new yy.Splat($$[$0-2+1-1]); +break; +case 67:this.$ = new yy.Value($$[$0-1+1-1]); +break; +case 68:this.$ = $$[$0-2+1-1].push($$[$0-2+2-1]); +break; +case 69:this.$ = new yy.Value($$[$0-2+1-1], [$$[$0-2+2-1]]); +break; +case 70:this.$ = $$[$0-1+1-1]; +break; +case 71:this.$ = $$[$0-1+1-1]; +break; +case 72:this.$ = new yy.Value($$[$0-1+1-1]); +break; +case 73:this.$ = new yy.Value($$[$0-1+1-1]); +break; +case 74:this.$ = $$[$0-1+1-1]; +break; +case 75:this.$ = new yy.Value($$[$0-1+1-1]); +break; +case 76:this.$ = new yy.Value($$[$0-1+1-1]); +break; +case 77:this.$ = new yy.Value($$[$0-1+1-1]); +break; +case 78:this.$ = $$[$0-1+1-1]; +break; +case 79:this.$ = new yy.Accessor($$[$0-2+2-1]); +break; +case 80:this.$ = new yy.Accessor($$[$0-2+2-1], 'prototype'); +break; +case 81:this.$ = new yy.Accessor(new yy.Literal('prototype')); +break; +case 82:this.$ = new yy.Accessor($$[$0-2+2-1], 'soak'); +break; +case 83:this.$ = $$[$0-1+1-1]; +break; +case 84:this.$ = new yy.Slice($$[$0-1+1-1]); +break; +case 85:this.$ = new yy.Index($$[$0-3+2-1]); +break; +case 86:this.$ = (function () { + $$[$0-2+2-1].soakNode = true; + return $$[$0-2+2-1]; + }()); +break; +case 87:this.$ = (function () { + $$[$0-2+2-1].proto = true; + return $$[$0-2+2-1]; + }()); +break; +case 88:this.$ = new yy.ObjectLiteral($$[$0-4+2-1]); +break; +case 89:this.$ = []; +break; +case 90:this.$ = [$$[$0-1+1-1]]; +break; +case 91:this.$ = $$[$0-3+1-1].concat($$[$0-3+3-1]); +break; +case 92:this.$ = $$[$0-4+1-1].concat($$[$0-4+4-1]); +break; +case 93:this.$ = $$[$0-6+1-1].concat($$[$0-6+4-1]); +break; +case 94:this.$ = new yy.Class($$[$0-2+2-1]); +break; +case 95:this.$ = new yy.Class($$[$0-4+2-1], $$[$0-4+4-1]); +break; +case 96:this.$ = new yy.Class($$[$0-5+2-1], null, $$[$0-5+4-1]); +break; +case 97:this.$ = new yy.Class($$[$0-7+2-1], $$[$0-7+4-1], $$[$0-7+6-1]); +break; +case 98:this.$ = new yy.Class('__temp__', null, $$[$0-4+3-1]); +break; +case 99:this.$ = new yy.Class('__temp__', null, new yy.Expressions); +break; +case 100:this.$ = new yy.Class('__temp__', $$[$0-3+3-1], new yy.Expressions); +break; +case 101:this.$ = new yy.Class('__temp__', $$[$0-6+3-1], $$[$0-6+5-1]); +break; +case 102:this.$ = $$[$0-1+1-1]; +break; +case 103:this.$ = new yy.Assign(new yy.Value($$[$0-3+1-1]), $$[$0-3+3-1], 'this'); +break; +case 104:this.$ = new yy.Assign(new yy.Value($$[$0-5+1-1]), $$[$0-5+4-1], 'this'); +break; +case 105:this.$ = []; +break; +case 106:this.$ = [$$[$0-1+1-1]]; +break; +case 107:this.$ = $$[$0-3+1-1].concat($$[$0-3+3-1]); +break; +case 108:this.$ = $$[$0-3+2-1]; +break; +case 109:this.$ = new yy.Extends($$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 110:this.$ = new yy.Call($$[$0-3+1-1], $$[$0-3+3-1], $$[$0-3+2-1]); +break; +case 111:this.$ = new yy.Call($$[$0-3+1-1], $$[$0-3+3-1], $$[$0-3+2-1]); +break; +case 112:this.$ = new yy.Call('super', [new yy.Splat(new yy.Literal('arguments'))]); +break; +case 113:this.$ = new yy.Call('super', $$[$0-2+2-1]); +break; +case 114:this.$ = false; +break; +case 115:this.$ = true; +break; +case 116:this.$ = []; +break; +case 117:this.$ = $$[$0-4+2-1]; +break; +case 118:this.$ = new yy.Value(new yy.Literal('this')); +break; +case 119:this.$ = new yy.Value(new yy.Literal('this')); +break; +case 120:this.$ = 'inclusive'; +break; +case 121:this.$ = 'exclusive'; +break; +case 122:this.$ = new yy.Value(new yy.Literal('this'), [new yy.Accessor($$[$0-2+2-1])], 'this'); +break; +case 123:this.$ = new yy.Range($$[$0-5+2-1], $$[$0-5+4-1], $$[$0-5+3-1]); +break; +case 124:this.$ = new yy.Range($$[$0-5+2-1], $$[$0-5+4-1], $$[$0-5+3-1]); +break; +case 125:this.$ = new yy.Range($$[$0-4+2-1], null, $$[$0-4+3-1]); +break; +case 126:this.$ = new yy.Range(null, $$[$0-4+3-1], $$[$0-4+2-1]); +break; +case 127:this.$ = new yy.ArrayLiteral([]); +break; +case 128:this.$ = new yy.ArrayLiteral($$[$0-4+2-1]); +break; +case 129:this.$ = [$$[$0-1+1-1]]; +break; +case 130:this.$ = $$[$0-3+1-1].concat($$[$0-3+3-1]); +break; +case 131:this.$ = $$[$0-4+1-1].concat($$[$0-4+4-1]); +break; +case 132:this.$ = $$[$0-4+2-1]; +break; +case 133:this.$ = $$[$0-6+1-1].concat($$[$0-6+4-1]); +break; +case 134:this.$ = $$[$0-1+1-1]; +break; +case 135:this.$ = $$[$0-1+1-1]; +break; +case 136:this.$ = $$[$0-1+1-1]; +break; +case 137:this.$ = [].concat($$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 138:this.$ = new yy.Try($$[$0-2+2-1]); +break; +case 139:this.$ = new yy.Try($$[$0-3+2-1], $$[$0-3+3-1][0], $$[$0-3+3-1][1]); +break; +case 140:this.$ = new yy.Try($$[$0-4+2-1], null, null, $$[$0-4+4-1]); +break; +case 141:this.$ = new yy.Try($$[$0-5+2-1], $$[$0-5+3-1][0], $$[$0-5+3-1][1], $$[$0-5+5-1]); +break; +case 142:this.$ = [$$[$0-3+2-1], $$[$0-3+3-1]]; +break; +case 143:this.$ = new yy.Throw($$[$0-2+2-1]); +break; +case 144:this.$ = new yy.Parens($$[$0-3+2-1]); +break; +case 145:this.$ = new yy.Parens(new yy.Literal('')); +break; +case 146:this.$ = new yy.While($$[$0-2+2-1]); +break; +case 147:this.$ = new yy.While($$[$0-4+2-1], { + guard: $$[$0-4+4-1] + }); +break; +case 148:this.$ = new yy.While($$[$0-2+2-1], { + invert: true + }); +break; +case 149:this.$ = new yy.While($$[$0-4+2-1], { + invert: true, + guard: $$[$0-4+4-1] + }); +break; +case 150:this.$ = $$[$0-2+1-1].addBody($$[$0-2+2-1]); +break; +case 151:this.$ = $$[$0-2+2-1].addBody(yy.Expressions.wrap([$$[$0-2+1-1]])); +break; +case 152:this.$ = $$[$0-2+2-1].addBody(yy.Expressions.wrap([$$[$0-2+1-1]])); +break; +case 153:this.$ = $$[$0-1+1-1]; +break; +case 154:this.$ = new yy.While(new yy.Literal('true')).addBody($$[$0-2+2-1]); +break; +case 155:this.$ = new yy.While(new yy.Literal('true')).addBody(yy.Expressions.wrap([$$[$0-2+2-1]])); +break; +case 156:this.$ = new yy.For($$[$0-2+1-1], $$[$0-2+2-1], $$[$0-2+2-1].vars[0], $$[$0-2+2-1].vars[1]); +break; +case 157:this.$ = new yy.For($$[$0-2+1-1], $$[$0-2+2-1], $$[$0-2+2-1].vars[0], $$[$0-2+2-1].vars[1]); +break; +case 158:this.$ = new yy.For($$[$0-2+2-1], $$[$0-2+1-1], $$[$0-2+1-1].vars[0], $$[$0-2+1-1].vars[1]); +break; +case 159:this.$ = { + source: new yy.Value($$[$0-2+2-1]), + vars: [] + }; +break; +case 160:this.$ = (function () { + $$[$0-2+2-1].raw = $$[$0-2+1-1].raw; + $$[$0-2+2-1].vars = $$[$0-2+1-1]; + return $$[$0-2+2-1]; + }()); +break; +case 161:this.$ = $$[$0-2+2-1]; +break; +case 162:this.$ = (function () { + $$[$0-3+3-1].raw = true; + return $$[$0-3+3-1]; + }()); +break; +case 163:this.$ = $$[$0-1+1-1]; +break; +case 164:this.$ = new yy.Value($$[$0-1+1-1]); +break; +case 165:this.$ = new yy.Value($$[$0-1+1-1]); +break; +case 166:this.$ = [$$[$0-1+1-1]]; +break; +case 167:this.$ = [$$[$0-3+1-1], $$[$0-3+3-1]]; +break; +case 168:this.$ = { + source: $$[$0-2+2-1] + }; +break; +case 169:this.$ = { + source: $$[$0-2+2-1], + object: true + }; +break; +case 170:this.$ = { + source: $$[$0-4+2-1], + guard: $$[$0-4+4-1] + }; +break; +case 171:this.$ = { + source: $$[$0-4+2-1], + guard: $$[$0-4+4-1], + object: true + }; +break; +case 172:this.$ = { + source: $$[$0-4+2-1], + step: $$[$0-4+4-1] + }; +break; +case 173:this.$ = { + source: $$[$0-6+2-1], + guard: $$[$0-6+4-1], + step: $$[$0-6+6-1] + }; +break; +case 174:this.$ = { + source: $$[$0-6+2-1], + step: $$[$0-6+4-1], + guard: $$[$0-6+6-1] + }; +break; +case 175:this.$ = new yy.Switch($$[$0-5+2-1], $$[$0-5+4-1]); +break; +case 176:this.$ = new yy.Switch($$[$0-7+2-1], $$[$0-7+4-1], $$[$0-7+6-1]); +break; +case 177:this.$ = new yy.Switch(null, $$[$0-4+3-1]); +break; +case 178:this.$ = new yy.Switch(null, $$[$0-6+3-1], $$[$0-6+5-1]); +break; +case 179:this.$ = $$[$0-1+1-1]; +break; +case 180:this.$ = $$[$0-2+1-1].concat($$[$0-2+2-1]); +break; +case 181:this.$ = [[$$[$0-3+2-1], $$[$0-3+3-1]]]; +break; +case 182:this.$ = [[$$[$0-4+2-1], $$[$0-4+3-1]]]; +break; +case 183:this.$ = new yy.If($$[$0-3+2-1], $$[$0-3+3-1]); +break; +case 184:this.$ = new yy.If($$[$0-3+2-1], $$[$0-3+3-1], { + invert: true + }); +break; +case 185:this.$ = $$[$0-5+1-1].addElse(new yy.If($$[$0-5+4-1], $$[$0-5+5-1])); +break; +case 186:this.$ = $$[$0-3+1-1].addElse($$[$0-3+3-1]); +break; +case 187:this.$ = $$[$0-1+1-1]; +break; +case 188:this.$ = new yy.If($$[$0-3+3-1], yy.Expressions.wrap([$$[$0-3+1-1]]), { + statement: true + }); +break; +case 189:this.$ = new yy.If($$[$0-3+3-1], yy.Expressions.wrap([$$[$0-3+1-1]]), { + statement: true + }); +break; +case 190:this.$ = new yy.If($$[$0-3+3-1], yy.Expressions.wrap([$$[$0-3+1-1]]), { + statement: true, + invert: true + }); +break; +case 191:this.$ = new yy.If($$[$0-3+3-1], yy.Expressions.wrap([$$[$0-3+1-1]]), { + statement: true, + invert: true + }); +break; +case 192:this.$ = new yy.Op($$[$0-2+1-1], $$[$0-2+2-1]); +break; +case 193:this.$ = new yy.Op('-', $$[$0-2+2-1]); +break; +case 194:this.$ = new yy.Op('+', $$[$0-2+2-1]); +break; +case 195:this.$ = new yy.Op('--', $$[$0-2+2-1]); +break; +case 196:this.$ = new yy.Op('++', $$[$0-2+2-1]); +break; +case 197:this.$ = new yy.Op('--', $$[$0-2+1-1], null, true); +break; +case 198:this.$ = new yy.Op('++', $$[$0-2+1-1], null, true); +break; +case 199:this.$ = new yy.Op('+', $$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 200:this.$ = new yy.Op('-', $$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 201:this.$ = new yy.Op('==', $$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 202:this.$ = new yy.Op('!=', $$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 203:this.$ = new yy.Op($$[$0-3+2-1], $$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 204:this.$ = new yy.Op($$[$0-3+2-1], $$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 205:this.$ = new yy.Op($$[$0-3+2-1], $$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 206:this.$ = new yy.Op($$[$0-3+2-1], $$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 207:this.$ = new yy.Op($$[$0-3+2-1], $$[$0-3+1-1], $$[$0-3+3-1]); +break; +case 208:this.$ = new yy.Op($$[$0-5+2-1], $$[$0-5+1-1], $$[$0-5+4-1]); +break; +case 209:this.$ = $$[$0-3+2-1].charAt(0) === '!' ? ($$[$0-3+2-1] === '!in' ? new yy.Op('!', new yy.In($$[$0-3+1-1], $$[$0-3+3-1])) : new yy.Op('!', new yy.Parens(new yy.Op($$[$0-3+2-1].slice(1), $$[$0-3+1-1], $$[$0-3+3-1])))) : ($$[$0-3+2-1] === 'in' ? new yy.In($$[$0-3+1-1], $$[$0-3+3-1]) : new yy.Op($$[$0-3+2-1], $$[$0-3+1-1], $$[$0-3+3-1])); +break; +} +}, +table: [{"1":[2,1],"3":1,"4":[1,2],"5":3,"6":4,"7":5,"8":7,"9":8,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,6],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[3]},{"1":[2,2],"28":77,"46":[1,49]},{"1":[2,3],"4":[1,78]},{"4":[1,79]},{"1":[2,5],"4":[2,5],"30":[2,5]},{"5":80,"7":5,"8":7,"9":8,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"30":[1,81],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,8],"4":[2,8],"30":[2,8],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,9],"4":[2,9],"30":[2,9],"106":98,"107":[1,68],"109":[1,69],"112":99,"113":[1,71],"114":72,"130":[1,96],"131":[1,97]},{"1":[2,15],"4":[2,15],"29":[2,15],"30":[2,15],"47":[2,15],"55":[2,15],"59":[2,15],"62":101,"68":[1,103],"69":[1,104],"70":[1,105],"71":[1,106],"72":107,"73":108,"74":[1,109],"75":[2,15],"76":[1,110],"77":[1,111],"80":[2,15],"85":100,"88":[1,102],"89":[2,114],"90":[2,15],"94":[2,15],"96":[2,15],"105":[2,15],"107":[2,15],"108":[2,15],"109":[2,15],"113":[2,15],"121":[2,15],"130":[2,15],"131":[2,15],"133":[2,15],"134":[2,15],"137":[2,15],"138":[2,15],"139":[2,15],"140":[2,15],"141":[2,15],"142":[2,15],"144":[2,15]},{"1":[2,16],"4":[2,16],"29":[2,16],"30":[2,16],"47":[2,16],"55":[2,16],"59":[2,16],"62":113,"68":[1,103],"69":[1,104],"70":[1,105],"71":[1,106],"72":107,"73":108,"74":[1,109],"75":[2,16],"76":[1,110],"77":[1,111],"80":[2,16],"85":112,"88":[1,102],"89":[2,114],"90":[2,16],"94":[2,16],"96":[2,16],"105":[2,16],"107":[2,16],"108":[2,16],"109":[2,16],"113":[2,16],"121":[2,16],"130":[2,16],"131":[2,16],"133":[2,16],"134":[2,16],"137":[2,16],"138":[2,16],"139":[2,16],"140":[2,16],"141":[2,16],"142":[2,16],"144":[2,16]},{"1":[2,17],"4":[2,17],"29":[2,17],"30":[2,17],"47":[2,17],"55":[2,17],"59":[2,17],"75":[2,17],"80":[2,17],"90":[2,17],"94":[2,17],"96":[2,17],"105":[2,17],"107":[2,17],"108":[2,17],"109":[2,17],"113":[2,17],"121":[2,17],"130":[2,17],"131":[2,17],"133":[2,17],"134":[2,17],"137":[2,17],"138":[2,17],"139":[2,17],"140":[2,17],"141":[2,17],"142":[2,17],"144":[2,17]},{"1":[2,18],"4":[2,18],"29":[2,18],"30":[2,18],"47":[2,18],"55":[2,18],"59":[2,18],"75":[2,18],"80":[2,18],"90":[2,18],"94":[2,18],"96":[2,18],"105":[2,18],"107":[2,18],"108":[2,18],"109":[2,18],"113":[2,18],"121":[2,18],"130":[2,18],"131":[2,18],"133":[2,18],"134":[2,18],"137":[2,18],"138":[2,18],"139":[2,18],"140":[2,18],"141":[2,18],"142":[2,18],"144":[2,18]},{"1":[2,19],"4":[2,19],"29":[2,19],"30":[2,19],"47":[2,19],"55":[2,19],"59":[2,19],"75":[2,19],"80":[2,19],"90":[2,19],"94":[2,19],"96":[2,19],"105":[2,19],"107":[2,19],"108":[2,19],"109":[2,19],"113":[2,19],"121":[2,19],"130":[2,19],"131":[2,19],"133":[2,19],"134":[2,19],"137":[2,19],"138":[2,19],"139":[2,19],"140":[2,19],"141":[2,19],"142":[2,19],"144":[2,19]},{"1":[2,20],"4":[2,20],"29":[2,20],"30":[2,20],"47":[2,20],"55":[2,20],"59":[2,20],"75":[2,20],"80":[2,20],"90":[2,20],"94":[2,20],"96":[2,20],"105":[2,20],"107":[2,20],"108":[2,20],"109":[2,20],"113":[2,20],"121":[2,20],"130":[2,20],"131":[2,20],"133":[2,20],"134":[2,20],"137":[2,20],"138":[2,20],"139":[2,20],"140":[2,20],"141":[2,20],"142":[2,20],"144":[2,20]},{"1":[2,21],"4":[2,21],"29":[2,21],"30":[2,21],"47":[2,21],"55":[2,21],"59":[2,21],"75":[2,21],"80":[2,21],"90":[2,21],"94":[2,21],"96":[2,21],"105":[2,21],"107":[2,21],"108":[2,21],"109":[2,21],"113":[2,21],"121":[2,21],"130":[2,21],"131":[2,21],"133":[2,21],"134":[2,21],"137":[2,21],"138":[2,21],"139":[2,21],"140":[2,21],"141":[2,21],"142":[2,21],"144":[2,21]},{"1":[2,22],"4":[2,22],"29":[2,22],"30":[2,22],"47":[2,22],"55":[2,22],"59":[2,22],"75":[2,22],"80":[2,22],"90":[2,22],"94":[2,22],"96":[2,22],"105":[2,22],"107":[2,22],"108":[2,22],"109":[2,22],"113":[2,22],"121":[2,22],"130":[2,22],"131":[2,22],"133":[2,22],"134":[2,22],"137":[2,22],"138":[2,22],"139":[2,22],"140":[2,22],"141":[2,22],"142":[2,22],"144":[2,22]},{"1":[2,23],"4":[2,23],"29":[2,23],"30":[2,23],"47":[2,23],"55":[2,23],"59":[2,23],"75":[2,23],"80":[2,23],"90":[2,23],"94":[2,23],"96":[2,23],"105":[2,23],"107":[2,23],"108":[2,23],"109":[2,23],"113":[2,23],"121":[2,23],"130":[2,23],"131":[2,23],"133":[2,23],"134":[2,23],"137":[2,23],"138":[2,23],"139":[2,23],"140":[2,23],"141":[2,23],"142":[2,23],"144":[2,23]},{"1":[2,24],"4":[2,24],"29":[2,24],"30":[2,24],"47":[2,24],"55":[2,24],"59":[2,24],"75":[2,24],"80":[2,24],"90":[2,24],"94":[2,24],"96":[2,24],"105":[2,24],"107":[2,24],"108":[2,24],"109":[2,24],"113":[2,24],"121":[2,24],"130":[2,24],"131":[2,24],"133":[2,24],"134":[2,24],"137":[2,24],"138":[2,24],"139":[2,24],"140":[2,24],"141":[2,24],"142":[2,24],"144":[2,24]},{"1":[2,25],"4":[2,25],"29":[2,25],"30":[2,25],"47":[2,25],"55":[2,25],"59":[2,25],"75":[2,25],"80":[2,25],"90":[2,25],"94":[2,25],"96":[2,25],"105":[2,25],"107":[2,25],"108":[2,25],"109":[2,25],"113":[2,25],"121":[2,25],"130":[2,25],"131":[2,25],"133":[2,25],"134":[2,25],"137":[2,25],"138":[2,25],"139":[2,25],"140":[2,25],"141":[2,25],"142":[2,25],"144":[2,25]},{"1":[2,26],"4":[2,26],"29":[2,26],"30":[2,26],"47":[2,26],"55":[2,26],"59":[2,26],"75":[2,26],"80":[2,26],"90":[2,26],"94":[2,26],"96":[2,26],"105":[2,26],"107":[2,26],"108":[2,26],"109":[2,26],"113":[2,26],"121":[2,26],"130":[2,26],"131":[2,26],"133":[2,26],"134":[2,26],"137":[2,26],"138":[2,26],"139":[2,26],"140":[2,26],"141":[2,26],"142":[2,26],"144":[2,26]},{"1":[2,27],"4":[2,27],"29":[2,27],"30":[2,27],"47":[2,27],"55":[2,27],"59":[2,27],"75":[2,27],"80":[2,27],"90":[2,27],"94":[2,27],"96":[2,27],"105":[2,27],"107":[2,27],"108":[2,27],"109":[2,27],"113":[2,27],"121":[2,27],"130":[2,27],"131":[2,27],"133":[2,27],"134":[2,27],"137":[2,27],"138":[2,27],"139":[2,27],"140":[2,27],"141":[2,27],"142":[2,27],"144":[2,27]},{"1":[2,28],"4":[2,28],"29":[2,28],"30":[2,28],"47":[2,28],"55":[2,28],"59":[2,28],"75":[2,28],"80":[2,28],"90":[2,28],"94":[2,28],"96":[2,28],"105":[2,28],"107":[2,28],"108":[2,28],"109":[2,28],"113":[2,28],"121":[2,28],"130":[2,28],"131":[2,28],"133":[2,28],"134":[2,28],"137":[2,28],"138":[2,28],"139":[2,28],"140":[2,28],"141":[2,28],"142":[2,28],"144":[2,28]},{"1":[2,10],"4":[2,10],"30":[2,10],"107":[2,10],"109":[2,10],"113":[2,10],"130":[2,10],"131":[2,10]},{"1":[2,11],"4":[2,11],"30":[2,11],"107":[2,11],"109":[2,11],"113":[2,11],"130":[2,11],"131":[2,11]},{"1":[2,12],"4":[2,12],"30":[2,12],"107":[2,12],"109":[2,12],"113":[2,12],"130":[2,12],"131":[2,12]},{"1":[2,13],"4":[2,13],"30":[2,13],"107":[2,13],"109":[2,13],"113":[2,13],"130":[2,13],"131":[2,13]},{"1":[2,14],"4":[2,14],"30":[2,14],"107":[2,14],"109":[2,14],"113":[2,14],"130":[2,14],"131":[2,14]},{"1":[2,74],"4":[2,74],"29":[2,74],"30":[2,74],"41":[1,114],"47":[2,74],"55":[2,74],"59":[2,74],"68":[2,74],"69":[2,74],"70":[2,74],"71":[2,74],"74":[2,74],"75":[2,74],"76":[2,74],"77":[2,74],"80":[2,74],"88":[2,74],"89":[2,74],"90":[2,74],"94":[2,74],"96":[2,74],"105":[2,74],"107":[2,74],"108":[2,74],"109":[2,74],"113":[2,74],"121":[2,74],"130":[2,74],"131":[2,74],"133":[2,74],"134":[2,74],"137":[2,74],"138":[2,74],"139":[2,74],"140":[2,74],"141":[2,74],"142":[2,74],"144":[2,74]},{"1":[2,75],"4":[2,75],"29":[2,75],"30":[2,75],"47":[2,75],"55":[2,75],"59":[2,75],"68":[2,75],"69":[2,75],"70":[2,75],"71":[2,75],"74":[2,75],"75":[2,75],"76":[2,75],"77":[2,75],"80":[2,75],"88":[2,75],"89":[2,75],"90":[2,75],"94":[2,75],"96":[2,75],"105":[2,75],"107":[2,75],"108":[2,75],"109":[2,75],"113":[2,75],"121":[2,75],"130":[2,75],"131":[2,75],"133":[2,75],"134":[2,75],"137":[2,75],"138":[2,75],"139":[2,75],"140":[2,75],"141":[2,75],"142":[2,75],"144":[2,75]},{"1":[2,76],"4":[2,76],"29":[2,76],"30":[2,76],"47":[2,76],"55":[2,76],"59":[2,76],"68":[2,76],"69":[2,76],"70":[2,76],"71":[2,76],"74":[2,76],"75":[2,76],"76":[2,76],"77":[2,76],"80":[2,76],"88":[2,76],"89":[2,76],"90":[2,76],"94":[2,76],"96":[2,76],"105":[2,76],"107":[2,76],"108":[2,76],"109":[2,76],"113":[2,76],"121":[2,76],"130":[2,76],"131":[2,76],"133":[2,76],"134":[2,76],"137":[2,76],"138":[2,76],"139":[2,76],"140":[2,76],"141":[2,76],"142":[2,76],"144":[2,76]},{"1":[2,77],"4":[2,77],"29":[2,77],"30":[2,77],"47":[2,77],"55":[2,77],"59":[2,77],"68":[2,77],"69":[2,77],"70":[2,77],"71":[2,77],"74":[2,77],"75":[2,77],"76":[2,77],"77":[2,77],"80":[2,77],"88":[2,77],"89":[2,77],"90":[2,77],"94":[2,77],"96":[2,77],"105":[2,77],"107":[2,77],"108":[2,77],"109":[2,77],"113":[2,77],"121":[2,77],"130":[2,77],"131":[2,77],"133":[2,77],"134":[2,77],"137":[2,77],"138":[2,77],"139":[2,77],"140":[2,77],"141":[2,77],"142":[2,77],"144":[2,77]},{"1":[2,78],"4":[2,78],"29":[2,78],"30":[2,78],"47":[2,78],"55":[2,78],"59":[2,78],"68":[2,78],"69":[2,78],"70":[2,78],"71":[2,78],"74":[2,78],"75":[2,78],"76":[2,78],"77":[2,78],"80":[2,78],"88":[2,78],"89":[2,78],"90":[2,78],"94":[2,78],"96":[2,78],"105":[2,78],"107":[2,78],"108":[2,78],"109":[2,78],"113":[2,78],"121":[2,78],"130":[2,78],"131":[2,78],"133":[2,78],"134":[2,78],"137":[2,78],"138":[2,78],"139":[2,78],"140":[2,78],"141":[2,78],"142":[2,78],"144":[2,78]},{"1":[2,112],"4":[2,112],"29":[2,112],"30":[2,112],"47":[2,112],"55":[2,112],"59":[2,112],"68":[2,112],"69":[2,112],"70":[2,112],"71":[2,112],"74":[2,112],"75":[2,112],"76":[2,112],"77":[2,112],"80":[2,112],"86":115,"88":[2,112],"89":[1,116],"90":[2,112],"94":[2,112],"96":[2,112],"105":[2,112],"107":[2,112],"108":[2,112],"109":[2,112],"113":[2,112],"121":[2,112],"130":[2,112],"131":[2,112],"133":[2,112],"134":[2,112],"137":[2,112],"138":[2,112],"139":[2,112],"140":[2,112],"141":[2,112],"142":[2,112],"144":[2,112]},{"49":117,"50":[2,59],"55":[2,59],"56":118,"57":[1,119],"58":[1,120]},{"4":[1,122],"6":121,"29":[1,6]},{"8":123,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":125,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":126,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"15":128,"16":129,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":130,"43":65,"58":[1,61],"61":127,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"87":[1,33],"92":[1,60],"95":[1,59],"104":[1,58]},{"15":128,"16":129,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":130,"43":65,"58":[1,61],"61":131,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"87":[1,33],"92":[1,60],"95":[1,59],"104":[1,58]},{"1":[2,71],"4":[2,71],"29":[2,71],"30":[2,71],"41":[2,71],"47":[2,71],"55":[2,71],"59":[2,71],"68":[2,71],"69":[2,71],"70":[2,71],"71":[2,71],"74":[2,71],"75":[2,71],"76":[2,71],"77":[2,71],"80":[2,71],"82":[1,135],"88":[2,71],"89":[2,71],"90":[2,71],"94":[2,71],"96":[2,71],"105":[2,71],"107":[2,71],"108":[2,71],"109":[2,71],"113":[2,71],"121":[2,71],"130":[2,71],"131":[2,71],"133":[2,71],"134":[2,71],"135":[1,132],"136":[1,133],"137":[2,71],"138":[2,71],"139":[2,71],"140":[2,71],"141":[2,71],"142":[2,71],"143":[1,134],"144":[2,71]},{"1":[2,187],"4":[2,187],"29":[2,187],"30":[2,187],"47":[2,187],"55":[2,187],"59":[2,187],"75":[2,187],"80":[2,187],"90":[2,187],"94":[2,187],"96":[2,187],"105":[2,187],"107":[2,187],"108":[2,187],"109":[2,187],"113":[2,187],"121":[2,187],"124":[1,136],"130":[2,187],"131":[2,187],"133":[2,187],"134":[2,187],"137":[2,187],"138":[2,187],"139":[2,187],"140":[2,187],"141":[2,187],"142":[2,187],"144":[2,187]},{"4":[1,122],"6":137,"29":[1,6]},{"4":[1,122],"6":138,"29":[1,6]},{"1":[2,153],"4":[2,153],"29":[2,153],"30":[2,153],"47":[2,153],"55":[2,153],"59":[2,153],"75":[2,153],"80":[2,153],"90":[2,153],"94":[2,153],"96":[2,153],"105":[2,153],"107":[2,153],"108":[2,153],"109":[2,153],"113":[2,153],"121":[2,153],"130":[2,153],"131":[2,153],"133":[2,153],"134":[2,153],"137":[2,153],"138":[2,153],"139":[2,153],"140":[2,153],"141":[2,153],"142":[2,153],"144":[2,153]},{"4":[1,122],"6":139,"29":[1,6]},{"8":140,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,141],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,99],"4":[2,99],"15":128,"16":129,"29":[1,143],"30":[2,99],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":130,"43":65,"47":[2,99],"55":[2,99],"58":[1,61],"59":[2,99],"61":142,"63":52,"64":53,"65":30,"66":31,"67":32,"75":[2,99],"78":[1,73],"80":[2,99],"82":[1,144],"87":[1,33],"90":[2,99],"92":[1,60],"94":[2,99],"95":[1,59],"96":[2,99],"104":[1,58],"105":[2,99],"107":[2,99],"108":[2,99],"109":[2,99],"113":[2,99],"121":[2,99],"130":[2,99],"131":[2,99],"133":[2,99],"134":[2,99],"137":[2,99],"138":[2,99],"139":[2,99],"140":[2,99],"141":[2,99],"142":[2,99],"144":[2,99]},{"1":[2,51],"4":[2,51],"29":[2,51],"30":[2,51],"47":[2,51],"55":[2,51],"59":[2,51],"75":[2,51],"80":[2,51],"90":[2,51],"94":[2,51],"96":[2,51],"101":[2,51],"102":[2,51],"105":[2,51],"107":[2,51],"108":[2,51],"109":[2,51],"113":[2,51],"121":[2,51],"124":[2,51],"126":[2,51],"130":[2,51],"131":[2,51],"133":[2,51],"134":[2,51],"137":[2,51],"138":[2,51],"139":[2,51],"140":[2,51],"141":[2,51],"142":[2,51],"144":[2,51]},{"1":[2,50],"4":[2,50],"8":145,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"30":[2,50],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"130":[2,50],"131":[2,50],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":146,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,72],"4":[2,72],"29":[2,72],"30":[2,72],"41":[2,72],"47":[2,72],"55":[2,72],"59":[2,72],"68":[2,72],"69":[2,72],"70":[2,72],"71":[2,72],"74":[2,72],"75":[2,72],"76":[2,72],"77":[2,72],"80":[2,72],"88":[2,72],"89":[2,72],"90":[2,72],"94":[2,72],"96":[2,72],"105":[2,72],"107":[2,72],"108":[2,72],"109":[2,72],"113":[2,72],"121":[2,72],"130":[2,72],"131":[2,72],"133":[2,72],"134":[2,72],"137":[2,72],"138":[2,72],"139":[2,72],"140":[2,72],"141":[2,72],"142":[2,72],"144":[2,72]},{"1":[2,73],"4":[2,73],"29":[2,73],"30":[2,73],"41":[2,73],"47":[2,73],"55":[2,73],"59":[2,73],"68":[2,73],"69":[2,73],"70":[2,73],"71":[2,73],"74":[2,73],"75":[2,73],"76":[2,73],"77":[2,73],"80":[2,73],"88":[2,73],"89":[2,73],"90":[2,73],"94":[2,73],"96":[2,73],"105":[2,73],"107":[2,73],"108":[2,73],"109":[2,73],"113":[2,73],"121":[2,73],"130":[2,73],"131":[2,73],"133":[2,73],"134":[2,73],"137":[2,73],"138":[2,73],"139":[2,73],"140":[2,73],"141":[2,73],"142":[2,73],"144":[2,73]},{"1":[2,35],"4":[2,35],"29":[2,35],"30":[2,35],"47":[2,35],"55":[2,35],"59":[2,35],"68":[2,35],"69":[2,35],"70":[2,35],"71":[2,35],"74":[2,35],"75":[2,35],"76":[2,35],"77":[2,35],"80":[2,35],"88":[2,35],"89":[2,35],"90":[2,35],"94":[2,35],"96":[2,35],"105":[2,35],"107":[2,35],"108":[2,35],"109":[2,35],"113":[2,35],"121":[2,35],"130":[2,35],"131":[2,35],"133":[2,35],"134":[2,35],"137":[2,35],"138":[2,35],"139":[2,35],"140":[2,35],"141":[2,35],"142":[2,35],"144":[2,35]},{"1":[2,36],"4":[2,36],"29":[2,36],"30":[2,36],"47":[2,36],"55":[2,36],"59":[2,36],"68":[2,36],"69":[2,36],"70":[2,36],"71":[2,36],"74":[2,36],"75":[2,36],"76":[2,36],"77":[2,36],"80":[2,36],"88":[2,36],"89":[2,36],"90":[2,36],"94":[2,36],"96":[2,36],"105":[2,36],"107":[2,36],"108":[2,36],"109":[2,36],"113":[2,36],"121":[2,36],"130":[2,36],"131":[2,36],"133":[2,36],"134":[2,36],"137":[2,36],"138":[2,36],"139":[2,36],"140":[2,36],"141":[2,36],"142":[2,36],"144":[2,36]},{"1":[2,37],"4":[2,37],"29":[2,37],"30":[2,37],"47":[2,37],"55":[2,37],"59":[2,37],"68":[2,37],"69":[2,37],"70":[2,37],"71":[2,37],"74":[2,37],"75":[2,37],"76":[2,37],"77":[2,37],"80":[2,37],"88":[2,37],"89":[2,37],"90":[2,37],"94":[2,37],"96":[2,37],"105":[2,37],"107":[2,37],"108":[2,37],"109":[2,37],"113":[2,37],"121":[2,37],"130":[2,37],"131":[2,37],"133":[2,37],"134":[2,37],"137":[2,37],"138":[2,37],"139":[2,37],"140":[2,37],"141":[2,37],"142":[2,37],"144":[2,37]},{"1":[2,38],"4":[2,38],"29":[2,38],"30":[2,38],"47":[2,38],"55":[2,38],"59":[2,38],"68":[2,38],"69":[2,38],"70":[2,38],"71":[2,38],"74":[2,38],"75":[2,38],"76":[2,38],"77":[2,38],"80":[2,38],"88":[2,38],"89":[2,38],"90":[2,38],"94":[2,38],"96":[2,38],"105":[2,38],"107":[2,38],"108":[2,38],"109":[2,38],"113":[2,38],"121":[2,38],"130":[2,38],"131":[2,38],"133":[2,38],"134":[2,38],"137":[2,38],"138":[2,38],"139":[2,38],"140":[2,38],"141":[2,38],"142":[2,38],"144":[2,38]},{"8":147,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"105":[1,148],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":149,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,153],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"91":151,"92":[1,60],"95":[1,59],"96":[1,150],"97":152,"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,118],"4":[2,118],"29":[2,118],"30":[2,118],"47":[2,118],"55":[2,118],"59":[2,118],"68":[2,118],"69":[2,118],"70":[2,118],"71":[2,118],"74":[2,118],"75":[2,118],"76":[2,118],"77":[2,118],"80":[2,118],"88":[2,118],"89":[2,118],"90":[2,118],"94":[2,118],"96":[2,118],"105":[2,118],"107":[2,118],"108":[2,118],"109":[2,118],"113":[2,118],"121":[2,118],"130":[2,118],"131":[2,118],"133":[2,118],"134":[2,118],"137":[2,118],"138":[2,118],"139":[2,118],"140":[2,118],"141":[2,118],"142":[2,118],"144":[2,118]},{"1":[2,119],"4":[2,119],"29":[2,119],"30":[2,119],"31":155,"32":[1,76],"47":[2,119],"55":[2,119],"59":[2,119],"68":[2,119],"69":[2,119],"70":[2,119],"71":[2,119],"74":[2,119],"75":[2,119],"76":[2,119],"77":[2,119],"80":[2,119],"88":[2,119],"89":[2,119],"90":[2,119],"94":[2,119],"96":[2,119],"105":[2,119],"107":[2,119],"108":[2,119],"109":[2,119],"113":[2,119],"121":[2,119],"130":[2,119],"131":[2,119],"133":[2,119],"134":[2,119],"137":[2,119],"138":[2,119],"139":[2,119],"140":[2,119],"141":[2,119],"142":[2,119],"144":[2,119]},{"4":[2,55],"29":[2,55]},{"4":[2,56],"29":[2,56]},{"1":[2,67],"4":[2,67],"29":[2,67],"30":[2,67],"41":[2,67],"47":[2,67],"55":[2,67],"59":[2,67],"68":[2,67],"69":[2,67],"70":[2,67],"71":[2,67],"74":[2,67],"75":[2,67],"76":[2,67],"77":[2,67],"80":[2,67],"82":[2,67],"88":[2,67],"89":[2,67],"90":[2,67],"94":[2,67],"96":[2,67],"105":[2,67],"107":[2,67],"108":[2,67],"109":[2,67],"113":[2,67],"121":[2,67],"130":[2,67],"131":[2,67],"133":[2,67],"134":[2,67],"135":[2,67],"136":[2,67],"137":[2,67],"138":[2,67],"139":[2,67],"140":[2,67],"141":[2,67],"142":[2,67],"143":[2,67],"144":[2,67]},{"1":[2,70],"4":[2,70],"29":[2,70],"30":[2,70],"41":[2,70],"47":[2,70],"55":[2,70],"59":[2,70],"68":[2,70],"69":[2,70],"70":[2,70],"71":[2,70],"74":[2,70],"75":[2,70],"76":[2,70],"77":[2,70],"80":[2,70],"82":[2,70],"88":[2,70],"89":[2,70],"90":[2,70],"94":[2,70],"96":[2,70],"105":[2,70],"107":[2,70],"108":[2,70],"109":[2,70],"113":[2,70],"121":[2,70],"130":[2,70],"131":[2,70],"133":[2,70],"134":[2,70],"135":[2,70],"136":[2,70],"137":[2,70],"138":[2,70],"139":[2,70],"140":[2,70],"141":[2,70],"142":[2,70],"143":[2,70],"144":[2,70]},{"8":156,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":157,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":158,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":159,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[1,122],"6":160,"8":161,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,6],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"31":166,"32":[1,76],"63":167,"64":168,"66":162,"78":[1,73],"95":[1,59],"116":163,"117":[1,164],"118":165},{"115":169,"119":[1,170],"120":[1,171]},{"4":[2,89],"28":177,"29":[2,89],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":173,"43":176,"46":[1,49],"55":[2,89],"58":[1,178],"79":172,"80":[2,89]},{"1":[2,33],"4":[2,33],"29":[2,33],"30":[2,33],"44":[2,33],"47":[2,33],"55":[2,33],"59":[2,33],"68":[2,33],"69":[2,33],"70":[2,33],"71":[2,33],"74":[2,33],"75":[2,33],"76":[2,33],"77":[2,33],"80":[2,33],"88":[2,33],"89":[2,33],"90":[2,33],"94":[2,33],"96":[2,33],"105":[2,33],"107":[2,33],"108":[2,33],"109":[2,33],"113":[2,33],"121":[2,33],"130":[2,33],"131":[2,33],"133":[2,33],"134":[2,33],"137":[2,33],"138":[2,33],"139":[2,33],"140":[2,33],"141":[2,33],"142":[2,33],"144":[2,33]},{"1":[2,34],"4":[2,34],"29":[2,34],"30":[2,34],"44":[2,34],"47":[2,34],"55":[2,34],"59":[2,34],"68":[2,34],"69":[2,34],"70":[2,34],"71":[2,34],"74":[2,34],"75":[2,34],"76":[2,34],"77":[2,34],"80":[2,34],"88":[2,34],"89":[2,34],"90":[2,34],"94":[2,34],"96":[2,34],"105":[2,34],"107":[2,34],"108":[2,34],"109":[2,34],"113":[2,34],"121":[2,34],"130":[2,34],"131":[2,34],"133":[2,34],"134":[2,34],"137":[2,34],"138":[2,34],"139":[2,34],"140":[2,34],"141":[2,34],"142":[2,34],"144":[2,34]},{"1":[2,32],"4":[2,32],"29":[2,32],"30":[2,32],"41":[2,32],"44":[2,32],"47":[2,32],"55":[2,32],"59":[2,32],"68":[2,32],"69":[2,32],"70":[2,32],"71":[2,32],"74":[2,32],"75":[2,32],"76":[2,32],"77":[2,32],"80":[2,32],"82":[2,32],"88":[2,32],"89":[2,32],"90":[2,32],"94":[2,32],"96":[2,32],"105":[2,32],"107":[2,32],"108":[2,32],"109":[2,32],"113":[2,32],"119":[2,32],"120":[2,32],"121":[2,32],"130":[2,32],"131":[2,32],"133":[2,32],"134":[2,32],"135":[2,32],"136":[2,32],"137":[2,32],"138":[2,32],"139":[2,32],"140":[2,32],"141":[2,32],"142":[2,32],"143":[2,32],"144":[2,32]},{"1":[2,31],"4":[2,31],"29":[2,31],"30":[2,31],"47":[2,31],"55":[2,31],"59":[2,31],"75":[2,31],"80":[2,31],"90":[2,31],"94":[2,31],"96":[2,31],"101":[2,31],"102":[2,31],"105":[2,31],"107":[2,31],"108":[2,31],"109":[2,31],"113":[2,31],"121":[2,31],"124":[2,31],"126":[2,31],"130":[2,31],"131":[2,31],"133":[2,31],"134":[2,31],"137":[2,31],"138":[2,31],"139":[2,31],"140":[2,31],"141":[2,31],"142":[2,31],"144":[2,31]},{"1":[2,7],"4":[2,7],"7":179,"8":7,"9":8,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"30":[2,7],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,4]},{"4":[1,78],"30":[1,180]},{"1":[2,30],"4":[2,30],"29":[2,30],"30":[2,30],"47":[2,30],"55":[2,30],"59":[2,30],"75":[2,30],"80":[2,30],"90":[2,30],"94":[2,30],"96":[2,30],"101":[2,30],"102":[2,30],"105":[2,30],"107":[2,30],"108":[2,30],"109":[2,30],"113":[2,30],"121":[2,30],"124":[2,30],"126":[2,30],"130":[2,30],"131":[2,30],"133":[2,30],"134":[2,30],"137":[2,30],"138":[2,30],"139":[2,30],"140":[2,30],"141":[2,30],"142":[2,30],"144":[2,30]},{"8":181,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":182,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":183,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":184,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":185,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":186,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":187,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":188,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":189,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":190,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":191,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,152],"4":[2,152],"29":[2,152],"30":[2,152],"47":[2,152],"55":[2,152],"59":[2,152],"75":[2,152],"80":[2,152],"90":[2,152],"94":[2,152],"96":[2,152],"105":[2,152],"107":[2,152],"108":[2,152],"109":[2,152],"113":[2,152],"121":[2,152],"130":[2,152],"131":[2,152],"133":[2,152],"134":[2,152],"137":[2,152],"138":[2,152],"139":[2,152],"140":[2,152],"141":[2,152],"142":[2,152],"144":[2,152]},{"1":[2,157],"4":[2,157],"29":[2,157],"30":[2,157],"47":[2,157],"55":[2,157],"59":[2,157],"75":[2,157],"80":[2,157],"90":[2,157],"94":[2,157],"96":[2,157],"105":[2,157],"107":[2,157],"108":[2,157],"109":[2,157],"113":[2,157],"121":[2,157],"130":[2,157],"131":[2,157],"133":[2,157],"134":[2,157],"137":[2,157],"138":[2,157],"139":[2,157],"140":[2,157],"141":[2,157],"142":[2,157],"144":[2,157]},{"1":[2,52],"4":[2,52],"29":[2,52],"30":[2,52],"47":[2,52],"55":[2,52],"59":[2,52],"75":[2,52],"80":[2,52],"90":[2,52],"94":[2,52],"96":[2,52],"105":[2,52],"107":[2,52],"108":[2,52],"109":[2,52],"113":[2,52],"121":[2,52],"130":[2,52],"131":[2,52],"133":[2,52],"134":[2,52],"137":[2,52],"138":[2,52],"139":[2,52],"140":[2,52],"141":[2,52],"142":[2,52],"144":[2,52]},{"8":192,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":193,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,151],"4":[2,151],"29":[2,151],"30":[2,151],"47":[2,151],"55":[2,151],"59":[2,151],"75":[2,151],"80":[2,151],"90":[2,151],"94":[2,151],"96":[2,151],"105":[2,151],"107":[2,151],"108":[2,151],"109":[2,151],"113":[2,151],"121":[2,151],"130":[2,151],"131":[2,151],"133":[2,151],"134":[2,151],"137":[2,151],"138":[2,151],"139":[2,151],"140":[2,151],"141":[2,151],"142":[2,151],"144":[2,151]},{"1":[2,156],"4":[2,156],"29":[2,156],"30":[2,156],"47":[2,156],"55":[2,156],"59":[2,156],"75":[2,156],"80":[2,156],"90":[2,156],"94":[2,156],"96":[2,156],"105":[2,156],"107":[2,156],"108":[2,156],"109":[2,156],"113":[2,156],"121":[2,156],"130":[2,156],"131":[2,156],"133":[2,156],"134":[2,156],"137":[2,156],"138":[2,156],"139":[2,156],"140":[2,156],"141":[2,156],"142":[2,156],"144":[2,156]},{"86":194,"89":[1,116]},{"1":[2,68],"4":[2,68],"29":[2,68],"30":[2,68],"41":[2,68],"47":[2,68],"55":[2,68],"59":[2,68],"68":[2,68],"69":[2,68],"70":[2,68],"71":[2,68],"74":[2,68],"75":[2,68],"76":[2,68],"77":[2,68],"80":[2,68],"82":[2,68],"88":[2,68],"89":[2,68],"90":[2,68],"94":[2,68],"96":[2,68],"105":[2,68],"107":[2,68],"108":[2,68],"109":[2,68],"113":[2,68],"121":[2,68],"130":[2,68],"131":[2,68],"133":[2,68],"134":[2,68],"135":[2,68],"136":[2,68],"137":[2,68],"138":[2,68],"139":[2,68],"140":[2,68],"141":[2,68],"142":[2,68],"143":[2,68],"144":[2,68]},{"89":[2,115]},{"31":195,"32":[1,76]},{"31":196,"32":[1,76]},{"1":[2,81],"4":[2,81],"29":[2,81],"30":[2,81],"41":[2,81],"47":[2,81],"55":[2,81],"59":[2,81],"68":[2,81],"69":[2,81],"70":[2,81],"71":[2,81],"74":[2,81],"75":[2,81],"76":[2,81],"77":[2,81],"80":[2,81],"82":[2,81],"88":[2,81],"89":[2,81],"90":[2,81],"94":[2,81],"96":[2,81],"105":[2,81],"107":[2,81],"108":[2,81],"109":[2,81],"113":[2,81],"121":[2,81],"130":[2,81],"131":[2,81],"133":[2,81],"134":[2,81],"135":[2,81],"136":[2,81],"137":[2,81],"138":[2,81],"139":[2,81],"140":[2,81],"141":[2,81],"142":[2,81],"143":[2,81],"144":[2,81]},{"31":197,"32":[1,76]},{"1":[2,83],"4":[2,83],"29":[2,83],"30":[2,83],"41":[2,83],"47":[2,83],"55":[2,83],"59":[2,83],"68":[2,83],"69":[2,83],"70":[2,83],"71":[2,83],"74":[2,83],"75":[2,83],"76":[2,83],"77":[2,83],"80":[2,83],"82":[2,83],"88":[2,83],"89":[2,83],"90":[2,83],"94":[2,83],"96":[2,83],"105":[2,83],"107":[2,83],"108":[2,83],"109":[2,83],"113":[2,83],"121":[2,83],"130":[2,83],"131":[2,83],"133":[2,83],"134":[2,83],"135":[2,83],"136":[2,83],"137":[2,83],"138":[2,83],"139":[2,83],"140":[2,83],"141":[2,83],"142":[2,83],"143":[2,83],"144":[2,83]},{"1":[2,84],"4":[2,84],"29":[2,84],"30":[2,84],"41":[2,84],"47":[2,84],"55":[2,84],"59":[2,84],"68":[2,84],"69":[2,84],"70":[2,84],"71":[2,84],"74":[2,84],"75":[2,84],"76":[2,84],"77":[2,84],"80":[2,84],"82":[2,84],"88":[2,84],"89":[2,84],"90":[2,84],"94":[2,84],"96":[2,84],"105":[2,84],"107":[2,84],"108":[2,84],"109":[2,84],"113":[2,84],"121":[2,84],"130":[2,84],"131":[2,84],"133":[2,84],"134":[2,84],"135":[2,84],"136":[2,84],"137":[2,84],"138":[2,84],"139":[2,84],"140":[2,84],"141":[2,84],"142":[2,84],"143":[2,84],"144":[2,84]},{"8":198,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"59":[1,201],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"93":199,"94":[1,200],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"72":202,"74":[1,203],"76":[1,110],"77":[1,111]},{"72":204,"74":[1,203],"76":[1,110],"77":[1,111]},{"86":205,"89":[1,116]},{"1":[2,69],"4":[2,69],"29":[2,69],"30":[2,69],"41":[2,69],"47":[2,69],"55":[2,69],"59":[2,69],"68":[2,69],"69":[2,69],"70":[2,69],"71":[2,69],"74":[2,69],"75":[2,69],"76":[2,69],"77":[2,69],"80":[2,69],"82":[2,69],"88":[2,69],"89":[2,69],"90":[2,69],"94":[2,69],"96":[2,69],"105":[2,69],"107":[2,69],"108":[2,69],"109":[2,69],"113":[2,69],"121":[2,69],"130":[2,69],"131":[2,69],"133":[2,69],"134":[2,69],"135":[2,69],"136":[2,69],"137":[2,69],"138":[2,69],"139":[2,69],"140":[2,69],"141":[2,69],"142":[2,69],"143":[2,69],"144":[2,69]},{"8":206,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,207],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,113],"4":[2,113],"29":[2,113],"30":[2,113],"47":[2,113],"55":[2,113],"59":[2,113],"68":[2,113],"69":[2,113],"70":[2,113],"71":[2,113],"74":[2,113],"75":[2,113],"76":[2,113],"77":[2,113],"80":[2,113],"88":[2,113],"89":[2,113],"90":[2,113],"94":[2,113],"96":[2,113],"105":[2,113],"107":[2,113],"108":[2,113],"109":[2,113],"113":[2,113],"121":[2,113],"130":[2,113],"131":[2,113],"133":[2,113],"134":[2,113],"137":[2,113],"138":[2,113],"139":[2,113],"140":[2,113],"141":[2,113],"142":[2,113],"144":[2,113]},{"8":210,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,153],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"90":[1,208],"91":209,"92":[1,60],"95":[1,59],"97":152,"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"50":[1,211],"55":[1,212]},{"50":[2,60],"55":[2,60]},{"50":[2,62],"55":[2,62],"59":[1,213]},{"57":[1,214]},{"1":[2,54],"4":[2,54],"29":[2,54],"30":[2,54],"47":[2,54],"55":[2,54],"59":[2,54],"75":[2,54],"80":[2,54],"90":[2,54],"94":[2,54],"96":[2,54],"105":[2,54],"107":[2,54],"108":[2,54],"109":[2,54],"113":[2,54],"121":[2,54],"130":[2,54],"131":[2,54],"133":[2,54],"134":[2,54],"137":[2,54],"138":[2,54],"139":[2,54],"140":[2,54],"141":[2,54],"142":[2,54],"144":[2,54]},{"28":77,"46":[1,49]},{"1":[2,192],"4":[2,192],"29":[2,192],"30":[2,192],"47":[1,95],"55":[2,192],"59":[2,192],"75":[2,192],"80":[2,192],"90":[2,192],"94":[2,192],"96":[2,192],"105":[2,192],"106":93,"107":[2,192],"108":[2,192],"109":[2,192],"112":94,"113":[2,192],"114":72,"121":[2,192],"130":[2,192],"131":[2,192],"133":[2,192],"134":[2,192],"137":[2,192],"138":[2,192],"139":[2,192],"140":[2,192],"141":[2,192],"142":[2,192],"144":[2,192]},{"106":98,"107":[1,68],"109":[1,69],"112":99,"113":[1,71],"114":72,"130":[1,96],"131":[1,97]},{"1":[2,193],"4":[2,193],"29":[2,193],"30":[2,193],"47":[1,95],"55":[2,193],"59":[2,193],"75":[2,193],"80":[2,193],"90":[2,193],"94":[2,193],"96":[2,193],"105":[2,193],"106":93,"107":[2,193],"108":[2,193],"109":[2,193],"112":94,"113":[2,193],"114":72,"121":[2,193],"130":[2,193],"131":[2,193],"133":[2,193],"134":[2,193],"137":[2,193],"138":[2,193],"139":[2,193],"140":[2,193],"141":[2,193],"142":[2,193],"144":[2,193]},{"1":[2,194],"4":[2,194],"29":[2,194],"30":[2,194],"47":[1,95],"55":[2,194],"59":[2,194],"75":[2,194],"80":[2,194],"90":[2,194],"94":[2,194],"96":[2,194],"105":[2,194],"106":93,"107":[2,194],"108":[2,194],"109":[2,194],"112":94,"113":[2,194],"114":72,"121":[2,194],"130":[2,194],"131":[2,194],"133":[2,194],"134":[2,194],"137":[2,194],"138":[2,194],"139":[2,194],"140":[2,194],"141":[2,194],"142":[2,194],"144":[2,194]},{"1":[2,195],"4":[2,195],"29":[2,195],"30":[2,195],"47":[2,195],"55":[2,195],"59":[2,195],"68":[2,71],"69":[2,71],"70":[2,71],"71":[2,71],"74":[2,71],"75":[2,195],"76":[2,71],"77":[2,71],"80":[2,195],"88":[2,71],"89":[2,71],"90":[2,195],"94":[2,195],"96":[2,195],"105":[2,195],"107":[2,195],"108":[2,195],"109":[2,195],"113":[2,195],"121":[2,195],"130":[2,195],"131":[2,195],"133":[2,195],"134":[2,195],"137":[2,195],"138":[2,195],"139":[2,195],"140":[2,195],"141":[2,195],"142":[2,195],"144":[2,195]},{"62":101,"68":[1,103],"69":[1,104],"70":[1,105],"71":[1,106],"72":107,"73":108,"74":[1,109],"76":[1,110],"77":[1,111],"85":100,"88":[1,102],"89":[2,114]},{"62":113,"68":[1,103],"69":[1,104],"70":[1,105],"71":[1,106],"72":107,"73":108,"74":[1,109],"76":[1,110],"77":[1,111],"85":112,"88":[1,102],"89":[2,114]},{"1":[2,74],"4":[2,74],"29":[2,74],"30":[2,74],"47":[2,74],"55":[2,74],"59":[2,74],"68":[2,74],"69":[2,74],"70":[2,74],"71":[2,74],"74":[2,74],"75":[2,74],"76":[2,74],"77":[2,74],"80":[2,74],"88":[2,74],"89":[2,74],"90":[2,74],"94":[2,74],"96":[2,74],"105":[2,74],"107":[2,74],"108":[2,74],"109":[2,74],"113":[2,74],"121":[2,74],"130":[2,74],"131":[2,74],"133":[2,74],"134":[2,74],"137":[2,74],"138":[2,74],"139":[2,74],"140":[2,74],"141":[2,74],"142":[2,74],"144":[2,74]},{"1":[2,196],"4":[2,196],"29":[2,196],"30":[2,196],"47":[2,196],"55":[2,196],"59":[2,196],"68":[2,71],"69":[2,71],"70":[2,71],"71":[2,71],"74":[2,71],"75":[2,196],"76":[2,71],"77":[2,71],"80":[2,196],"88":[2,71],"89":[2,71],"90":[2,196],"94":[2,196],"96":[2,196],"105":[2,196],"107":[2,196],"108":[2,196],"109":[2,196],"113":[2,196],"121":[2,196],"130":[2,196],"131":[2,196],"133":[2,196],"134":[2,196],"137":[2,196],"138":[2,196],"139":[2,196],"140":[2,196],"141":[2,196],"142":[2,196],"144":[2,196]},{"1":[2,197],"4":[2,197],"29":[2,197],"30":[2,197],"47":[2,197],"55":[2,197],"59":[2,197],"75":[2,197],"80":[2,197],"90":[2,197],"94":[2,197],"96":[2,197],"105":[2,197],"107":[2,197],"108":[2,197],"109":[2,197],"113":[2,197],"121":[2,197],"130":[2,197],"131":[2,197],"133":[2,197],"134":[2,197],"137":[2,197],"138":[2,197],"139":[2,197],"140":[2,197],"141":[2,197],"142":[2,197],"144":[2,197]},{"1":[2,198],"4":[2,198],"29":[2,198],"30":[2,198],"47":[2,198],"55":[2,198],"59":[2,198],"75":[2,198],"80":[2,198],"90":[2,198],"94":[2,198],"96":[2,198],"105":[2,198],"107":[2,198],"108":[2,198],"109":[2,198],"113":[2,198],"121":[2,198],"130":[2,198],"131":[2,198],"133":[2,198],"134":[2,198],"137":[2,198],"138":[2,198],"139":[2,198],"140":[2,198],"141":[2,198],"142":[2,198],"144":[2,198]},{"8":215,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,216],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"15":217,"16":129,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":130,"43":65,"58":[1,61],"61":218,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"87":[1,33],"92":[1,60],"95":[1,59],"104":[1,58]},{"4":[1,122],"6":220,"29":[1,6],"128":[1,219]},{"1":[2,138],"4":[2,138],"29":[2,138],"30":[2,138],"47":[2,138],"55":[2,138],"59":[2,138],"75":[2,138],"80":[2,138],"90":[2,138],"94":[2,138],"96":[2,138],"100":221,"101":[1,222],"102":[1,223],"105":[2,138],"107":[2,138],"108":[2,138],"109":[2,138],"113":[2,138],"121":[2,138],"130":[2,138],"131":[2,138],"133":[2,138],"134":[2,138],"137":[2,138],"138":[2,138],"139":[2,138],"140":[2,138],"141":[2,138],"142":[2,138],"144":[2,138]},{"1":[2,150],"4":[2,150],"29":[2,150],"30":[2,150],"47":[2,150],"55":[2,150],"59":[2,150],"75":[2,150],"80":[2,150],"90":[2,150],"94":[2,150],"96":[2,150],"105":[2,150],"107":[2,150],"108":[2,150],"109":[2,150],"113":[2,150],"121":[2,150],"130":[2,150],"131":[2,150],"133":[2,150],"134":[2,150],"137":[2,150],"138":[2,150],"139":[2,150],"140":[2,150],"141":[2,150],"142":[2,150],"144":[2,150]},{"1":[2,158],"4":[2,158],"29":[2,158],"30":[2,158],"47":[2,158],"55":[2,158],"59":[2,158],"75":[2,158],"80":[2,158],"90":[2,158],"94":[2,158],"96":[2,158],"105":[2,158],"107":[2,158],"108":[2,158],"109":[2,158],"113":[2,158],"121":[2,158],"130":[2,158],"131":[2,158],"133":[2,158],"134":[2,158],"137":[2,158],"138":[2,158],"139":[2,158],"140":[2,158],"141":[2,158],"142":[2,158],"144":[2,158]},{"29":[1,224],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"123":225,"125":226,"126":[1,227]},{"1":[2,94],"4":[2,94],"29":[1,229],"30":[2,94],"47":[2,94],"55":[2,94],"59":[2,94],"68":[2,71],"69":[2,71],"70":[2,71],"71":[2,71],"74":[2,71],"75":[2,94],"76":[2,71],"77":[2,71],"80":[2,94],"82":[1,228],"88":[2,71],"89":[2,71],"90":[2,94],"94":[2,94],"96":[2,94],"105":[2,94],"107":[2,94],"108":[2,94],"109":[2,94],"113":[2,94],"121":[2,94],"130":[2,94],"131":[2,94],"133":[2,94],"134":[2,94],"137":[2,94],"138":[2,94],"139":[2,94],"140":[2,94],"141":[2,94],"142":[2,94],"144":[2,94]},{"4":[2,105],"28":177,"30":[2,105],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"78":[1,232],"83":230,"84":231},{"15":235,"16":129,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":130,"43":65,"58":[1,61],"61":218,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"87":[1,33],"92":[1,60],"95":[1,59],"104":[1,58]},{"1":[2,49],"4":[2,49],"30":[2,49],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[2,49],"131":[2,49],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,143],"4":[2,143],"30":[2,143],"47":[1,95],"106":93,"107":[2,143],"109":[2,143],"112":94,"113":[2,143],"114":72,"130":[2,143],"131":[2,143],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"47":[1,95],"105":[1,236],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,145],"4":[2,145],"29":[2,145],"30":[2,145],"47":[2,145],"55":[2,145],"59":[2,145],"68":[2,145],"69":[2,145],"70":[2,145],"71":[2,145],"74":[2,145],"75":[2,145],"76":[2,145],"77":[2,145],"80":[2,145],"88":[2,145],"89":[2,145],"90":[2,145],"94":[2,145],"96":[2,145],"105":[2,145],"107":[2,145],"108":[2,145],"109":[2,145],"113":[2,145],"121":[2,145],"130":[2,145],"131":[2,145],"133":[2,145],"134":[2,145],"137":[2,145],"138":[2,145],"139":[2,145],"140":[2,145],"141":[2,145],"142":[2,145],"144":[2,145]},{"4":[2,134],"29":[2,134],"47":[1,95],"55":[2,134],"59":[1,238],"93":237,"94":[1,200],"96":[2,134],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,127],"4":[2,127],"29":[2,127],"30":[2,127],"41":[2,127],"47":[2,127],"55":[2,127],"59":[2,127],"68":[2,127],"69":[2,127],"70":[2,127],"71":[2,127],"74":[2,127],"75":[2,127],"76":[2,127],"77":[2,127],"80":[2,127],"88":[2,127],"89":[2,127],"90":[2,127],"94":[2,127],"96":[2,127],"105":[2,127],"107":[2,127],"108":[2,127],"109":[2,127],"113":[2,127],"119":[2,127],"120":[2,127],"121":[2,127],"130":[2,127],"131":[2,127],"133":[2,127],"134":[2,127],"137":[2,127],"138":[2,127],"139":[2,127],"140":[2,127],"141":[2,127],"142":[2,127],"144":[2,127]},{"4":[2,57],"29":[2,57],"54":239,"55":[1,240],"96":[2,57]},{"4":[2,129],"29":[2,129],"30":[2,129],"55":[2,129],"90":[2,129],"96":[2,129]},{"8":210,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,153],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"91":241,"92":[1,60],"95":[1,59],"97":152,"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,135],"29":[2,135],"30":[2,135],"55":[2,135],"90":[2,135],"96":[2,135]},{"1":[2,122],"4":[2,122],"29":[2,122],"30":[2,122],"41":[2,122],"44":[2,122],"47":[2,122],"55":[2,122],"59":[2,122],"68":[2,122],"69":[2,122],"70":[2,122],"71":[2,122],"74":[2,122],"75":[2,122],"76":[2,122],"77":[2,122],"80":[2,122],"82":[2,122],"88":[2,122],"89":[2,122],"90":[2,122],"94":[2,122],"96":[2,122],"105":[2,122],"107":[2,122],"108":[2,122],"109":[2,122],"113":[2,122],"121":[2,122],"130":[2,122],"131":[2,122],"133":[2,122],"134":[2,122],"135":[2,122],"136":[2,122],"137":[2,122],"138":[2,122],"139":[2,122],"140":[2,122],"141":[2,122],"142":[2,122],"143":[2,122],"144":[2,122]},{"4":[1,122],"6":242,"29":[1,6],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"4":[1,122],"6":243,"29":[1,6],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,146],"4":[2,146],"29":[2,146],"30":[2,146],"47":[1,95],"55":[2,146],"59":[2,146],"75":[2,146],"80":[2,146],"90":[2,146],"94":[2,146],"96":[2,146],"105":[2,146],"106":93,"107":[1,68],"108":[1,244],"109":[1,69],"112":94,"113":[1,71],"114":72,"121":[2,146],"130":[2,146],"131":[2,146],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,148],"4":[2,148],"29":[2,148],"30":[2,148],"47":[1,95],"55":[2,148],"59":[2,148],"75":[2,148],"80":[2,148],"90":[2,148],"94":[2,148],"96":[2,148],"105":[2,148],"106":93,"107":[1,68],"108":[1,245],"109":[1,69],"112":94,"113":[1,71],"114":72,"121":[2,148],"130":[2,148],"131":[2,148],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,154],"4":[2,154],"29":[2,154],"30":[2,154],"47":[2,154],"55":[2,154],"59":[2,154],"75":[2,154],"80":[2,154],"90":[2,154],"94":[2,154],"96":[2,154],"105":[2,154],"107":[2,154],"108":[2,154],"109":[2,154],"113":[2,154],"121":[2,154],"130":[2,154],"131":[2,154],"133":[2,154],"134":[2,154],"137":[2,154],"138":[2,154],"139":[2,154],"140":[2,154],"141":[2,154],"142":[2,154],"144":[2,154]},{"1":[2,155],"4":[2,155],"29":[2,155],"30":[2,155],"47":[1,95],"55":[2,155],"59":[2,155],"75":[2,155],"80":[2,155],"90":[2,155],"94":[2,155],"96":[2,155],"105":[2,155],"106":93,"107":[1,68],"108":[2,155],"109":[1,69],"112":94,"113":[1,71],"114":72,"121":[2,155],"130":[2,155],"131":[2,155],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,159],"4":[2,159],"29":[2,159],"30":[2,159],"47":[2,159],"55":[2,159],"59":[2,159],"75":[2,159],"80":[2,159],"90":[2,159],"94":[2,159],"96":[2,159],"105":[2,159],"107":[2,159],"108":[2,159],"109":[2,159],"113":[2,159],"121":[2,159],"130":[2,159],"131":[2,159],"133":[2,159],"134":[2,159],"137":[2,159],"138":[2,159],"139":[2,159],"140":[2,159],"141":[2,159],"142":[2,159],"144":[2,159]},{"119":[2,161],"120":[2,161]},{"31":166,"32":[1,76],"63":167,"64":168,"78":[1,73],"95":[1,247],"116":246,"118":165},{"55":[1,248],"119":[2,166],"120":[2,166]},{"55":[2,163],"119":[2,163],"120":[2,163]},{"55":[2,164],"119":[2,164],"120":[2,164]},{"55":[2,165],"119":[2,165],"120":[2,165]},{"1":[2,160],"4":[2,160],"29":[2,160],"30":[2,160],"47":[2,160],"55":[2,160],"59":[2,160],"75":[2,160],"80":[2,160],"90":[2,160],"94":[2,160],"96":[2,160],"105":[2,160],"107":[2,160],"108":[2,160],"109":[2,160],"113":[2,160],"121":[2,160],"130":[2,160],"131":[2,160],"133":[2,160],"134":[2,160],"137":[2,160],"138":[2,160],"139":[2,160],"140":[2,160],"141":[2,160],"142":[2,160],"144":[2,160]},{"8":249,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":250,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,57],"29":[2,57],"54":251,"55":[1,252],"80":[2,57]},{"4":[2,90],"29":[2,90],"30":[2,90],"55":[2,90],"80":[2,90]},{"4":[2,41],"29":[2,41],"30":[2,41],"44":[1,253],"55":[2,41],"80":[2,41]},{"4":[2,42],"29":[2,42],"30":[2,42],"44":[1,254],"55":[2,42],"80":[2,42]},{"4":[2,43],"29":[2,43],"30":[2,43],"55":[2,43],"80":[2,43]},{"4":[2,48],"29":[2,48],"30":[2,48],"55":[2,48],"80":[2,48]},{"31":155,"32":[1,76]},{"1":[2,6],"4":[2,6],"30":[2,6]},{"1":[2,29],"4":[2,29],"29":[2,29],"30":[2,29],"47":[2,29],"55":[2,29],"59":[2,29],"75":[2,29],"80":[2,29],"90":[2,29],"94":[2,29],"96":[2,29],"101":[2,29],"102":[2,29],"105":[2,29],"107":[2,29],"108":[2,29],"109":[2,29],"113":[2,29],"121":[2,29],"124":[2,29],"126":[2,29],"130":[2,29],"131":[2,29],"133":[2,29],"134":[2,29],"137":[2,29],"138":[2,29],"139":[2,29],"140":[2,29],"141":[2,29],"142":[2,29],"144":[2,29]},{"1":[2,199],"4":[2,199],"29":[2,199],"30":[2,199],"47":[1,95],"55":[2,199],"59":[2,199],"75":[2,199],"80":[2,199],"90":[2,199],"94":[2,199],"96":[2,199],"105":[2,199],"106":93,"107":[2,199],"108":[2,199],"109":[2,199],"112":94,"113":[2,199],"114":72,"121":[2,199],"130":[2,199],"131":[2,199],"133":[2,199],"134":[2,199],"137":[2,199],"138":[2,199],"139":[1,86],"140":[2,199],"141":[2,199],"142":[2,199],"144":[2,199]},{"1":[2,200],"4":[2,200],"29":[2,200],"30":[2,200],"47":[1,95],"55":[2,200],"59":[2,200],"75":[2,200],"80":[2,200],"90":[2,200],"94":[2,200],"96":[2,200],"105":[2,200],"106":93,"107":[2,200],"108":[2,200],"109":[2,200],"112":94,"113":[2,200],"114":72,"121":[2,200],"130":[2,200],"131":[2,200],"133":[2,200],"134":[2,200],"137":[2,200],"138":[2,200],"139":[1,86],"140":[2,200],"141":[2,200],"142":[2,200],"144":[2,200]},{"1":[2,201],"4":[2,201],"29":[2,201],"30":[2,201],"47":[1,95],"55":[2,201],"59":[2,201],"75":[2,201],"80":[2,201],"90":[2,201],"94":[2,201],"96":[2,201],"105":[2,201],"106":93,"107":[2,201],"108":[2,201],"109":[2,201],"112":94,"113":[2,201],"114":72,"121":[2,201],"130":[2,201],"131":[2,201],"133":[1,83],"134":[1,82],"137":[2,201],"138":[2,201],"139":[1,86],"140":[1,87],"141":[1,88],"142":[2,201],"144":[1,90]},{"1":[2,202],"4":[2,202],"29":[2,202],"30":[2,202],"47":[1,95],"55":[2,202],"59":[2,202],"75":[2,202],"80":[2,202],"90":[2,202],"94":[2,202],"96":[2,202],"105":[2,202],"106":93,"107":[2,202],"108":[2,202],"109":[2,202],"112":94,"113":[2,202],"114":72,"121":[2,202],"130":[2,202],"131":[2,202],"133":[1,83],"134":[1,82],"137":[2,202],"138":[2,202],"139":[1,86],"140":[1,87],"141":[1,88],"142":[2,202],"144":[1,90]},{"1":[2,203],"4":[2,203],"29":[2,203],"30":[2,203],"47":[1,95],"55":[2,203],"59":[2,203],"75":[2,203],"80":[2,203],"90":[2,203],"94":[2,203],"96":[2,203],"105":[2,203],"106":93,"107":[2,203],"108":[2,203],"109":[2,203],"112":94,"113":[2,203],"114":72,"121":[2,203],"130":[2,203],"131":[2,203],"133":[2,203],"134":[2,203],"137":[2,203],"138":[2,203],"139":[2,203],"140":[2,203],"141":[2,203],"142":[2,203],"144":[2,203]},{"1":[2,204],"4":[2,204],"29":[2,204],"30":[2,204],"47":[1,95],"55":[2,204],"59":[2,204],"75":[2,204],"80":[2,204],"90":[2,204],"94":[2,204],"96":[2,204],"105":[2,204],"106":93,"107":[2,204],"108":[2,204],"109":[2,204],"112":94,"113":[2,204],"114":72,"121":[2,204],"130":[2,204],"131":[2,204],"133":[1,83],"134":[1,82],"137":[2,204],"138":[2,204],"139":[1,86],"140":[2,204],"141":[2,204],"142":[2,204],"144":[2,204]},{"1":[2,205],"4":[2,205],"29":[2,205],"30":[2,205],"47":[1,95],"55":[2,205],"59":[2,205],"75":[2,205],"80":[2,205],"90":[2,205],"94":[2,205],"96":[2,205],"105":[2,205],"106":93,"107":[2,205],"108":[2,205],"109":[2,205],"112":94,"113":[2,205],"114":72,"121":[2,205],"130":[2,205],"131":[2,205],"133":[1,83],"134":[1,82],"137":[2,205],"138":[2,205],"139":[1,86],"140":[1,87],"141":[2,205],"142":[2,205],"144":[2,205]},{"1":[2,206],"4":[2,206],"29":[2,206],"30":[2,206],"47":[1,95],"55":[2,206],"59":[2,206],"75":[2,206],"80":[2,206],"90":[2,206],"94":[2,206],"96":[2,206],"105":[2,206],"106":93,"107":[2,206],"108":[2,206],"109":[2,206],"112":94,"113":[2,206],"114":72,"121":[2,206],"130":[2,206],"131":[2,206],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[2,206],"144":[1,90]},{"1":[2,209],"4":[2,209],"29":[2,209],"30":[2,209],"47":[1,95],"55":[2,209],"59":[2,209],"75":[2,209],"80":[2,209],"90":[2,209],"94":[2,209],"96":[2,209],"105":[2,209],"106":93,"107":[2,209],"108":[2,209],"109":[2,209],"112":94,"113":[2,209],"114":72,"121":[2,209],"130":[2,209],"131":[2,209],"133":[1,83],"134":[1,82],"137":[2,209],"138":[2,209],"139":[1,86],"140":[1,87],"141":[1,88],"142":[2,209],"144":[2,209]},{"1":[2,189],"4":[2,189],"29":[2,189],"30":[2,189],"47":[1,95],"55":[2,189],"59":[2,189],"75":[2,189],"80":[2,189],"90":[2,189],"94":[2,189],"96":[2,189],"105":[2,189],"106":93,"107":[1,68],"108":[2,189],"109":[1,69],"112":94,"113":[1,71],"114":72,"121":[2,189],"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,191],"4":[2,191],"29":[2,191],"30":[2,191],"47":[1,95],"55":[2,191],"59":[2,191],"75":[2,191],"80":[2,191],"90":[2,191],"94":[2,191],"96":[2,191],"105":[2,191],"106":93,"107":[1,68],"108":[2,191],"109":[1,69],"112":94,"113":[1,71],"114":72,"121":[2,191],"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,188],"4":[2,188],"29":[2,188],"30":[2,188],"47":[1,95],"55":[2,188],"59":[2,188],"75":[2,188],"80":[2,188],"90":[2,188],"94":[2,188],"96":[2,188],"105":[2,188],"106":93,"107":[1,68],"108":[2,188],"109":[1,69],"112":94,"113":[1,71],"114":72,"121":[2,188],"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,190],"4":[2,190],"29":[2,190],"30":[2,190],"47":[1,95],"55":[2,190],"59":[2,190],"75":[2,190],"80":[2,190],"90":[2,190],"94":[2,190],"96":[2,190],"105":[2,190],"106":93,"107":[1,68],"108":[2,190],"109":[1,69],"112":94,"113":[1,71],"114":72,"121":[2,190],"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,110],"4":[2,110],"29":[2,110],"30":[2,110],"47":[2,110],"55":[2,110],"59":[2,110],"68":[2,110],"69":[2,110],"70":[2,110],"71":[2,110],"74":[2,110],"75":[2,110],"76":[2,110],"77":[2,110],"80":[2,110],"88":[2,110],"89":[2,110],"90":[2,110],"94":[2,110],"96":[2,110],"105":[2,110],"107":[2,110],"108":[2,110],"109":[2,110],"113":[2,110],"121":[2,110],"130":[2,110],"131":[2,110],"133":[2,110],"134":[2,110],"137":[2,110],"138":[2,110],"139":[2,110],"140":[2,110],"141":[2,110],"142":[2,110],"144":[2,110]},{"1":[2,79],"4":[2,79],"29":[2,79],"30":[2,79],"41":[2,79],"47":[2,79],"55":[2,79],"59":[2,79],"68":[2,79],"69":[2,79],"70":[2,79],"71":[2,79],"74":[2,79],"75":[2,79],"76":[2,79],"77":[2,79],"80":[2,79],"82":[2,79],"88":[2,79],"89":[2,79],"90":[2,79],"94":[2,79],"96":[2,79],"105":[2,79],"107":[2,79],"108":[2,79],"109":[2,79],"113":[2,79],"121":[2,79],"130":[2,79],"131":[2,79],"133":[2,79],"134":[2,79],"135":[2,79],"136":[2,79],"137":[2,79],"138":[2,79],"139":[2,79],"140":[2,79],"141":[2,79],"142":[2,79],"143":[2,79],"144":[2,79]},{"1":[2,80],"4":[2,80],"29":[2,80],"30":[2,80],"41":[2,80],"47":[2,80],"55":[2,80],"59":[2,80],"68":[2,80],"69":[2,80],"70":[2,80],"71":[2,80],"74":[2,80],"75":[2,80],"76":[2,80],"77":[2,80],"80":[2,80],"82":[2,80],"88":[2,80],"89":[2,80],"90":[2,80],"94":[2,80],"96":[2,80],"105":[2,80],"107":[2,80],"108":[2,80],"109":[2,80],"113":[2,80],"121":[2,80],"130":[2,80],"131":[2,80],"133":[2,80],"134":[2,80],"135":[2,80],"136":[2,80],"137":[2,80],"138":[2,80],"139":[2,80],"140":[2,80],"141":[2,80],"142":[2,80],"143":[2,80],"144":[2,80]},{"1":[2,82],"4":[2,82],"29":[2,82],"30":[2,82],"41":[2,82],"47":[2,82],"55":[2,82],"59":[2,82],"68":[2,82],"69":[2,82],"70":[2,82],"71":[2,82],"74":[2,82],"75":[2,82],"76":[2,82],"77":[2,82],"80":[2,82],"82":[2,82],"88":[2,82],"89":[2,82],"90":[2,82],"94":[2,82],"96":[2,82],"105":[2,82],"107":[2,82],"108":[2,82],"109":[2,82],"113":[2,82],"121":[2,82],"130":[2,82],"131":[2,82],"133":[2,82],"134":[2,82],"135":[2,82],"136":[2,82],"137":[2,82],"138":[2,82],"139":[2,82],"140":[2,82],"141":[2,82],"142":[2,82],"143":[2,82],"144":[2,82]},{"47":[1,95],"59":[1,201],"75":[1,255],"93":256,"94":[1,200],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"8":257,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"12":[2,120],"13":[2,120],"14":[2,120],"32":[2,120],"34":[2,120],"35":[2,120],"37":[2,120],"38":[2,120],"39":[2,120],"45":[2,120],"46":[2,120],"48":[2,120],"52":[2,120],"53":[2,120],"58":[2,120],"75":[2,120],"78":[2,120],"81":[2,120],"87":[2,120],"92":[2,120],"95":[2,120],"99":[2,120],"103":[2,120],"104":[2,120],"107":[2,120],"109":[2,120],"111":[2,120],"113":[2,120],"122":[2,120],"128":[2,120],"129":[2,120],"132":[2,120],"133":[2,120],"134":[2,120],"135":[2,120],"136":[2,120]},{"12":[2,121],"13":[2,121],"14":[2,121],"32":[2,121],"34":[2,121],"35":[2,121],"37":[2,121],"38":[2,121],"39":[2,121],"45":[2,121],"46":[2,121],"48":[2,121],"52":[2,121],"53":[2,121],"58":[2,121],"75":[2,121],"78":[2,121],"81":[2,121],"87":[2,121],"92":[2,121],"95":[2,121],"99":[2,121],"103":[2,121],"104":[2,121],"107":[2,121],"109":[2,121],"111":[2,121],"113":[2,121],"122":[2,121],"128":[2,121],"129":[2,121],"132":[2,121],"133":[2,121],"134":[2,121],"135":[2,121],"136":[2,121]},{"1":[2,86],"4":[2,86],"29":[2,86],"30":[2,86],"41":[2,86],"47":[2,86],"55":[2,86],"59":[2,86],"68":[2,86],"69":[2,86],"70":[2,86],"71":[2,86],"74":[2,86],"75":[2,86],"76":[2,86],"77":[2,86],"80":[2,86],"82":[2,86],"88":[2,86],"89":[2,86],"90":[2,86],"94":[2,86],"96":[2,86],"105":[2,86],"107":[2,86],"108":[2,86],"109":[2,86],"113":[2,86],"121":[2,86],"130":[2,86],"131":[2,86],"133":[2,86],"134":[2,86],"135":[2,86],"136":[2,86],"137":[2,86],"138":[2,86],"139":[2,86],"140":[2,86],"141":[2,86],"142":[2,86],"143":[2,86],"144":[2,86]},{"8":258,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,87],"4":[2,87],"29":[2,87],"30":[2,87],"41":[2,87],"47":[2,87],"55":[2,87],"59":[2,87],"68":[2,87],"69":[2,87],"70":[2,87],"71":[2,87],"74":[2,87],"75":[2,87],"76":[2,87],"77":[2,87],"80":[2,87],"82":[2,87],"88":[2,87],"89":[2,87],"90":[2,87],"94":[2,87],"96":[2,87],"105":[2,87],"107":[2,87],"108":[2,87],"109":[2,87],"113":[2,87],"121":[2,87],"130":[2,87],"131":[2,87],"133":[2,87],"134":[2,87],"135":[2,87],"136":[2,87],"137":[2,87],"138":[2,87],"139":[2,87],"140":[2,87],"141":[2,87],"142":[2,87],"143":[2,87],"144":[2,87]},{"1":[2,111],"4":[2,111],"29":[2,111],"30":[2,111],"47":[2,111],"55":[2,111],"59":[2,111],"68":[2,111],"69":[2,111],"70":[2,111],"71":[2,111],"74":[2,111],"75":[2,111],"76":[2,111],"77":[2,111],"80":[2,111],"88":[2,111],"89":[2,111],"90":[2,111],"94":[2,111],"96":[2,111],"105":[2,111],"107":[2,111],"108":[2,111],"109":[2,111],"113":[2,111],"121":[2,111],"130":[2,111],"131":[2,111],"133":[2,111],"134":[2,111],"137":[2,111],"138":[2,111],"139":[2,111],"140":[2,111],"141":[2,111],"142":[2,111],"144":[2,111]},{"1":[2,39],"4":[2,39],"29":[2,39],"30":[2,39],"47":[1,95],"55":[2,39],"59":[2,39],"75":[2,39],"80":[2,39],"90":[2,39],"94":[2,39],"96":[2,39],"105":[2,39],"106":93,"107":[1,68],"108":[2,39],"109":[1,69],"112":94,"113":[1,71],"114":72,"121":[2,39],"130":[2,39],"131":[2,39],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"8":259,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,116],"4":[2,116],"29":[2,116],"30":[2,116],"47":[2,116],"55":[2,116],"59":[2,116],"68":[2,116],"69":[2,116],"70":[2,116],"71":[2,116],"74":[2,116],"75":[2,116],"76":[2,116],"77":[2,116],"80":[2,116],"88":[2,116],"89":[2,116],"90":[2,116],"94":[2,116],"96":[2,116],"105":[2,116],"107":[2,116],"108":[2,116],"109":[2,116],"113":[2,116],"121":[2,116],"130":[2,116],"131":[2,116],"133":[2,116],"134":[2,116],"137":[2,116],"138":[2,116],"139":[2,116],"140":[2,116],"141":[2,116],"142":[2,116],"144":[2,116]},{"4":[2,57],"29":[2,57],"54":260,"55":[1,240],"90":[2,57]},{"4":[2,134],"29":[2,134],"30":[2,134],"47":[1,95],"55":[2,134],"59":[1,261],"90":[2,134],"96":[2,134],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"51":262,"52":[1,62],"53":[1,63]},{"56":263,"57":[1,119],"58":[1,120]},{"50":[2,64],"55":[2,64]},{"50":[2,63],"55":[2,63],"59":[1,264]},{"1":[2,207],"4":[2,207],"29":[2,207],"30":[2,207],"47":[1,95],"55":[2,207],"59":[2,207],"75":[2,207],"80":[2,207],"90":[2,207],"94":[2,207],"96":[2,207],"105":[2,207],"106":93,"107":[2,207],"108":[2,207],"109":[2,207],"112":94,"113":[2,207],"114":72,"121":[2,207],"130":[2,207],"131":[2,207],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"8":265,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,109],"4":[2,109],"29":[2,109],"30":[2,109],"47":[2,109],"55":[2,109],"59":[2,109],"62":101,"68":[1,103],"69":[1,104],"70":[1,105],"71":[1,106],"72":107,"73":108,"74":[1,109],"75":[2,109],"76":[1,110],"77":[1,111],"80":[2,109],"85":100,"88":[1,102],"89":[2,114],"90":[2,109],"94":[2,109],"96":[2,109],"105":[2,109],"107":[2,109],"108":[2,109],"109":[2,109],"113":[2,109],"121":[2,109],"130":[2,109],"131":[2,109],"133":[2,109],"134":[2,109],"137":[2,109],"138":[2,109],"139":[2,109],"140":[2,109],"141":[2,109],"142":[2,109],"144":[2,109]},{"1":[2,71],"4":[2,71],"29":[2,71],"30":[2,71],"47":[2,71],"55":[2,71],"59":[2,71],"68":[2,71],"69":[2,71],"70":[2,71],"71":[2,71],"74":[2,71],"75":[2,71],"76":[2,71],"77":[2,71],"80":[2,71],"88":[2,71],"89":[2,71],"90":[2,71],"94":[2,71],"96":[2,71],"105":[2,71],"107":[2,71],"108":[2,71],"109":[2,71],"113":[2,71],"121":[2,71],"130":[2,71],"131":[2,71],"133":[2,71],"134":[2,71],"137":[2,71],"138":[2,71],"139":[2,71],"140":[2,71],"141":[2,71],"142":[2,71],"144":[2,71]},{"8":266,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,186],"4":[2,186],"29":[2,186],"30":[2,186],"47":[2,186],"55":[2,186],"59":[2,186],"75":[2,186],"80":[2,186],"90":[2,186],"94":[2,186],"96":[2,186],"105":[2,186],"107":[2,186],"108":[2,186],"109":[2,186],"113":[2,186],"121":[2,186],"124":[2,186],"130":[2,186],"131":[2,186],"133":[2,186],"134":[2,186],"137":[2,186],"138":[2,186],"139":[2,186],"140":[2,186],"141":[2,186],"142":[2,186],"144":[2,186]},{"1":[2,139],"4":[2,139],"29":[2,139],"30":[2,139],"47":[2,139],"55":[2,139],"59":[2,139],"75":[2,139],"80":[2,139],"90":[2,139],"94":[2,139],"96":[2,139],"101":[1,267],"105":[2,139],"107":[2,139],"108":[2,139],"109":[2,139],"113":[2,139],"121":[2,139],"130":[2,139],"131":[2,139],"133":[2,139],"134":[2,139],"137":[2,139],"138":[2,139],"139":[2,139],"140":[2,139],"141":[2,139],"142":[2,139],"144":[2,139]},{"4":[1,122],"6":268,"29":[1,6]},{"31":269,"32":[1,76]},{"123":270,"125":226,"126":[1,227]},{"30":[1,271],"124":[1,272],"125":273,"126":[1,227]},{"30":[2,179],"124":[2,179],"126":[2,179]},{"8":275,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"98":274,"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"15":276,"16":129,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":130,"43":65,"58":[1,61],"61":218,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"87":[1,33],"92":[1,60],"95":[1,59],"104":[1,58]},{"4":[2,105],"28":177,"30":[2,105],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"78":[1,232],"83":277,"84":231},{"4":[1,279],"30":[1,278]},{"4":[2,106],"30":[2,106],"80":[2,106]},{"4":[2,105],"28":177,"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"78":[1,232],"80":[2,105],"83":280,"84":231},{"4":[2,102],"30":[2,102],"80":[2,102]},{"4":[2,43],"30":[2,43],"44":[1,281],"80":[2,43]},{"1":[2,100],"4":[2,100],"29":[1,282],"30":[2,100],"47":[2,100],"55":[2,100],"59":[2,100],"62":101,"68":[1,103],"69":[1,104],"70":[1,105],"71":[1,106],"72":107,"73":108,"74":[1,109],"75":[2,100],"76":[1,110],"77":[1,111],"80":[2,100],"85":100,"88":[1,102],"89":[2,114],"90":[2,100],"94":[2,100],"96":[2,100],"105":[2,100],"107":[2,100],"108":[2,100],"109":[2,100],"113":[2,100],"121":[2,100],"130":[2,100],"131":[2,100],"133":[2,100],"134":[2,100],"137":[2,100],"138":[2,100],"139":[2,100],"140":[2,100],"141":[2,100],"142":[2,100],"144":[2,100]},{"1":[2,144],"4":[2,144],"29":[2,144],"30":[2,144],"47":[2,144],"55":[2,144],"59":[2,144],"68":[2,144],"69":[2,144],"70":[2,144],"71":[2,144],"74":[2,144],"75":[2,144],"76":[2,144],"77":[2,144],"80":[2,144],"88":[2,144],"89":[2,144],"90":[2,144],"94":[2,144],"96":[2,144],"105":[2,144],"107":[2,144],"108":[2,144],"109":[2,144],"113":[2,144],"121":[2,144],"130":[2,144],"131":[2,144],"133":[2,144],"134":[2,144],"137":[2,144],"138":[2,144],"139":[2,144],"140":[2,144],"141":[2,144],"142":[2,144],"144":[2,144]},{"8":283,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,66],"12":[2,121],"13":[2,121],"14":[2,121],"29":[2,66],"32":[2,121],"34":[2,121],"35":[2,121],"37":[2,121],"38":[2,121],"39":[2,121],"45":[2,121],"46":[2,121],"48":[2,121],"52":[2,121],"53":[2,121],"55":[2,66],"58":[2,121],"78":[2,121],"81":[2,121],"87":[2,121],"92":[2,121],"95":[2,121],"96":[2,66],"99":[2,121],"103":[2,121],"104":[2,121],"107":[2,121],"109":[2,121],"111":[2,121],"113":[2,121],"122":[2,121],"128":[2,121],"129":[2,121],"132":[2,121],"133":[2,121],"134":[2,121],"135":[2,121],"136":[2,121]},{"4":[1,285],"29":[1,286],"96":[1,284]},{"4":[2,58],"8":210,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[2,58],"30":[2,58],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"90":[2,58],"92":[1,60],"95":[1,59],"96":[2,58],"97":287,"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,57],"29":[2,57],"30":[2,57],"54":288,"55":[1,240]},{"1":[2,183],"4":[2,183],"29":[2,183],"30":[2,183],"47":[2,183],"55":[2,183],"59":[2,183],"75":[2,183],"80":[2,183],"90":[2,183],"94":[2,183],"96":[2,183],"105":[2,183],"107":[2,183],"108":[2,183],"109":[2,183],"113":[2,183],"121":[2,183],"124":[2,183],"130":[2,183],"131":[2,183],"133":[2,183],"134":[2,183],"137":[2,183],"138":[2,183],"139":[2,183],"140":[2,183],"141":[2,183],"142":[2,183],"144":[2,183]},{"1":[2,184],"4":[2,184],"29":[2,184],"30":[2,184],"47":[2,184],"55":[2,184],"59":[2,184],"75":[2,184],"80":[2,184],"90":[2,184],"94":[2,184],"96":[2,184],"105":[2,184],"107":[2,184],"108":[2,184],"109":[2,184],"113":[2,184],"121":[2,184],"124":[2,184],"130":[2,184],"131":[2,184],"133":[2,184],"134":[2,184],"137":[2,184],"138":[2,184],"139":[2,184],"140":[2,184],"141":[2,184],"142":[2,184],"144":[2,184]},{"8":289,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":290,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"119":[2,162],"120":[2,162]},{"8":210,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,153],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"91":151,"92":[1,60],"95":[1,59],"96":[1,150],"97":152,"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"31":166,"32":[1,76],"63":167,"64":168,"78":[1,73],"95":[1,247],"118":291},{"1":[2,168],"4":[2,168],"29":[2,168],"30":[2,168],"47":[1,95],"55":[2,168],"59":[2,168],"75":[2,168],"80":[2,168],"90":[2,168],"94":[2,168],"96":[2,168],"105":[2,168],"106":93,"107":[2,168],"108":[1,292],"109":[2,168],"112":94,"113":[2,168],"114":72,"121":[1,293],"130":[2,168],"131":[2,168],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,169],"4":[2,169],"29":[2,169],"30":[2,169],"47":[1,95],"55":[2,169],"59":[2,169],"75":[2,169],"80":[2,169],"90":[2,169],"94":[2,169],"96":[2,169],"105":[2,169],"106":93,"107":[2,169],"108":[1,294],"109":[2,169],"112":94,"113":[2,169],"114":72,"121":[2,169],"130":[2,169],"131":[2,169],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"4":[1,296],"29":[1,297],"80":[1,295]},{"4":[2,58],"28":177,"29":[2,58],"30":[2,58],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":298,"43":176,"46":[1,49],"58":[1,178],"80":[2,58]},{"8":299,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,300],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":301,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,302],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,85],"4":[2,85],"29":[2,85],"30":[2,85],"41":[2,85],"47":[2,85],"55":[2,85],"59":[2,85],"68":[2,85],"69":[2,85],"70":[2,85],"71":[2,85],"74":[2,85],"75":[2,85],"76":[2,85],"77":[2,85],"80":[2,85],"82":[2,85],"88":[2,85],"89":[2,85],"90":[2,85],"94":[2,85],"96":[2,85],"105":[2,85],"107":[2,85],"108":[2,85],"109":[2,85],"113":[2,85],"121":[2,85],"130":[2,85],"131":[2,85],"133":[2,85],"134":[2,85],"135":[2,85],"136":[2,85],"137":[2,85],"138":[2,85],"139":[2,85],"140":[2,85],"141":[2,85],"142":[2,85],"143":[2,85],"144":[2,85]},{"8":303,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"75":[1,304],"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"47":[1,95],"75":[1,305],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"47":[1,95],"75":[1,255],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"30":[1,306],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"4":[1,285],"29":[1,286],"90":[1,307]},{"4":[2,66],"29":[2,66],"30":[2,66],"55":[2,66],"90":[2,66],"96":[2,66]},{"4":[1,122],"6":308,"29":[1,6]},{"50":[2,61],"55":[2,61]},{"50":[2,65],"55":[2,65]},{"30":[1,309],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"4":[1,122],"6":310,"29":[1,6],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"4":[1,122],"6":311,"29":[1,6]},{"1":[2,140],"4":[2,140],"29":[2,140],"30":[2,140],"47":[2,140],"55":[2,140],"59":[2,140],"75":[2,140],"80":[2,140],"90":[2,140],"94":[2,140],"96":[2,140],"105":[2,140],"107":[2,140],"108":[2,140],"109":[2,140],"113":[2,140],"121":[2,140],"130":[2,140],"131":[2,140],"133":[2,140],"134":[2,140],"137":[2,140],"138":[2,140],"139":[2,140],"140":[2,140],"141":[2,140],"142":[2,140],"144":[2,140]},{"4":[1,122],"6":312,"29":[1,6]},{"30":[1,313],"124":[1,314],"125":273,"126":[1,227]},{"1":[2,177],"4":[2,177],"29":[2,177],"30":[2,177],"47":[2,177],"55":[2,177],"59":[2,177],"75":[2,177],"80":[2,177],"90":[2,177],"94":[2,177],"96":[2,177],"105":[2,177],"107":[2,177],"108":[2,177],"109":[2,177],"113":[2,177],"121":[2,177],"130":[2,177],"131":[2,177],"133":[2,177],"134":[2,177],"137":[2,177],"138":[2,177],"139":[2,177],"140":[2,177],"141":[2,177],"142":[2,177],"144":[2,177]},{"4":[1,122],"6":315,"29":[1,6]},{"30":[2,180],"124":[2,180],"126":[2,180]},{"4":[1,122],"6":316,"29":[1,6],"55":[1,317]},{"4":[2,136],"29":[2,136],"47":[1,95],"55":[2,136],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,95],"4":[2,95],"29":[1,318],"30":[2,95],"47":[2,95],"55":[2,95],"59":[2,95],"62":101,"68":[1,103],"69":[1,104],"70":[1,105],"71":[1,106],"72":107,"73":108,"74":[1,109],"75":[2,95],"76":[1,110],"77":[1,111],"80":[2,95],"85":100,"88":[1,102],"89":[2,114],"90":[2,95],"94":[2,95],"96":[2,95],"105":[2,95],"107":[2,95],"108":[2,95],"109":[2,95],"113":[2,95],"121":[2,95],"130":[2,95],"131":[2,95],"133":[2,95],"134":[2,95],"137":[2,95],"138":[2,95],"139":[2,95],"140":[2,95],"141":[2,95],"142":[2,95],"144":[2,95]},{"4":[1,279],"30":[1,319]},{"1":[2,98],"4":[2,98],"29":[2,98],"30":[2,98],"47":[2,98],"55":[2,98],"59":[2,98],"75":[2,98],"80":[2,98],"90":[2,98],"94":[2,98],"96":[2,98],"105":[2,98],"107":[2,98],"108":[2,98],"109":[2,98],"113":[2,98],"121":[2,98],"130":[2,98],"131":[2,98],"133":[2,98],"134":[2,98],"137":[2,98],"138":[2,98],"139":[2,98],"140":[2,98],"141":[2,98],"142":[2,98],"144":[2,98]},{"28":177,"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"84":320},{"4":[1,279],"80":[1,321]},{"8":322,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,323],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,105],"28":177,"30":[2,105],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"78":[1,232],"83":324,"84":231},{"47":[1,95],"96":[1,325],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,128],"4":[2,128],"29":[2,128],"30":[2,128],"41":[2,128],"47":[2,128],"55":[2,128],"59":[2,128],"68":[2,128],"69":[2,128],"70":[2,128],"71":[2,128],"74":[2,128],"75":[2,128],"76":[2,128],"77":[2,128],"80":[2,128],"88":[2,128],"89":[2,128],"90":[2,128],"94":[2,128],"96":[2,128],"105":[2,128],"107":[2,128],"108":[2,128],"109":[2,128],"113":[2,128],"119":[2,128],"120":[2,128],"121":[2,128],"130":[2,128],"131":[2,128],"133":[2,128],"134":[2,128],"137":[2,128],"138":[2,128],"139":[2,128],"140":[2,128],"141":[2,128],"142":[2,128],"144":[2,128]},{"8":210,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"97":326,"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":210,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"29":[1,153],"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"60":154,"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"91":327,"92":[1,60],"95":[1,59],"97":152,"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,130],"29":[2,130],"30":[2,130],"55":[2,130],"90":[2,130],"96":[2,130]},{"4":[1,285],"29":[1,286],"30":[1,328]},{"1":[2,147],"4":[2,147],"29":[2,147],"30":[2,147],"47":[1,95],"55":[2,147],"59":[2,147],"75":[2,147],"80":[2,147],"90":[2,147],"94":[2,147],"96":[2,147],"105":[2,147],"106":93,"107":[1,68],"108":[2,147],"109":[1,69],"112":94,"113":[1,71],"114":72,"121":[2,147],"130":[2,147],"131":[2,147],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,149],"4":[2,149],"29":[2,149],"30":[2,149],"47":[1,95],"55":[2,149],"59":[2,149],"75":[2,149],"80":[2,149],"90":[2,149],"94":[2,149],"96":[2,149],"105":[2,149],"106":93,"107":[1,68],"108":[2,149],"109":[1,69],"112":94,"113":[1,71],"114":72,"121":[2,149],"130":[2,149],"131":[2,149],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"119":[2,167],"120":[2,167]},{"8":329,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":330,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":331,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"1":[2,88],"4":[2,88],"29":[2,88],"30":[2,88],"41":[2,88],"47":[2,88],"55":[2,88],"59":[2,88],"68":[2,88],"69":[2,88],"70":[2,88],"71":[2,88],"74":[2,88],"75":[2,88],"76":[2,88],"77":[2,88],"80":[2,88],"88":[2,88],"89":[2,88],"90":[2,88],"94":[2,88],"96":[2,88],"105":[2,88],"107":[2,88],"108":[2,88],"109":[2,88],"113":[2,88],"119":[2,88],"120":[2,88],"121":[2,88],"130":[2,88],"131":[2,88],"133":[2,88],"134":[2,88],"137":[2,88],"138":[2,88],"139":[2,88],"140":[2,88],"141":[2,88],"142":[2,88],"144":[2,88]},{"28":177,"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":332,"43":176,"46":[1,49],"58":[1,178]},{"4":[2,89],"28":177,"29":[2,89],"30":[2,89],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":173,"43":176,"46":[1,49],"55":[2,89],"58":[1,178],"79":333},{"4":[2,91],"29":[2,91],"30":[2,91],"55":[2,91],"80":[2,91]},{"4":[2,44],"29":[2,44],"30":[2,44],"47":[1,95],"55":[2,44],"80":[2,44],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"8":334,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,45],"29":[2,45],"30":[2,45],"47":[1,95],"55":[2,45],"80":[2,45],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"8":335,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"47":[1,95],"75":[1,336],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,125],"4":[2,125],"29":[2,125],"30":[2,125],"41":[2,125],"47":[2,125],"55":[2,125],"59":[2,125],"68":[2,125],"69":[2,125],"70":[2,125],"71":[2,125],"74":[2,125],"75":[2,125],"76":[2,125],"77":[2,125],"80":[2,125],"82":[2,125],"88":[2,125],"89":[2,125],"90":[2,125],"94":[2,125],"96":[2,125],"105":[2,125],"107":[2,125],"108":[2,125],"109":[2,125],"113":[2,125],"121":[2,125],"130":[2,125],"131":[2,125],"133":[2,125],"134":[2,125],"135":[2,125],"136":[2,125],"137":[2,125],"138":[2,125],"139":[2,125],"140":[2,125],"141":[2,125],"142":[2,125],"143":[2,125],"144":[2,125]},{"1":[2,126],"4":[2,126],"29":[2,126],"30":[2,126],"41":[2,126],"47":[2,126],"55":[2,126],"59":[2,126],"68":[2,126],"69":[2,126],"70":[2,126],"71":[2,126],"74":[2,126],"75":[2,126],"76":[2,126],"77":[2,126],"80":[2,126],"82":[2,126],"88":[2,126],"89":[2,126],"90":[2,126],"94":[2,126],"96":[2,126],"105":[2,126],"107":[2,126],"108":[2,126],"109":[2,126],"113":[2,126],"121":[2,126],"130":[2,126],"131":[2,126],"133":[2,126],"134":[2,126],"135":[2,126],"136":[2,126],"137":[2,126],"138":[2,126],"139":[2,126],"140":[2,126],"141":[2,126],"142":[2,126],"143":[2,126],"144":[2,126]},{"1":[2,40],"4":[2,40],"29":[2,40],"30":[2,40],"47":[2,40],"55":[2,40],"59":[2,40],"75":[2,40],"80":[2,40],"90":[2,40],"94":[2,40],"96":[2,40],"105":[2,40],"107":[2,40],"108":[2,40],"109":[2,40],"113":[2,40],"121":[2,40],"130":[2,40],"131":[2,40],"133":[2,40],"134":[2,40],"137":[2,40],"138":[2,40],"139":[2,40],"140":[2,40],"141":[2,40],"142":[2,40],"144":[2,40]},{"1":[2,117],"4":[2,117],"29":[2,117],"30":[2,117],"47":[2,117],"55":[2,117],"59":[2,117],"68":[2,117],"69":[2,117],"70":[2,117],"71":[2,117],"74":[2,117],"75":[2,117],"76":[2,117],"77":[2,117],"80":[2,117],"88":[2,117],"89":[2,117],"90":[2,117],"94":[2,117],"96":[2,117],"105":[2,117],"107":[2,117],"108":[2,117],"109":[2,117],"113":[2,117],"121":[2,117],"130":[2,117],"131":[2,117],"133":[2,117],"134":[2,117],"137":[2,117],"138":[2,117],"139":[2,117],"140":[2,117],"141":[2,117],"142":[2,117],"144":[2,117]},{"1":[2,53],"4":[2,53],"29":[2,53],"30":[2,53],"47":[2,53],"55":[2,53],"59":[2,53],"75":[2,53],"80":[2,53],"90":[2,53],"94":[2,53],"96":[2,53],"105":[2,53],"107":[2,53],"108":[2,53],"109":[2,53],"113":[2,53],"121":[2,53],"130":[2,53],"131":[2,53],"133":[2,53],"134":[2,53],"137":[2,53],"138":[2,53],"139":[2,53],"140":[2,53],"141":[2,53],"142":[2,53],"144":[2,53]},{"1":[2,208],"4":[2,208],"29":[2,208],"30":[2,208],"47":[2,208],"55":[2,208],"59":[2,208],"75":[2,208],"80":[2,208],"90":[2,208],"94":[2,208],"96":[2,208],"105":[2,208],"107":[2,208],"108":[2,208],"109":[2,208],"113":[2,208],"121":[2,208],"130":[2,208],"131":[2,208],"133":[2,208],"134":[2,208],"137":[2,208],"138":[2,208],"139":[2,208],"140":[2,208],"141":[2,208],"142":[2,208],"144":[2,208]},{"1":[2,185],"4":[2,185],"29":[2,185],"30":[2,185],"47":[2,185],"55":[2,185],"59":[2,185],"75":[2,185],"80":[2,185],"90":[2,185],"94":[2,185],"96":[2,185],"105":[2,185],"107":[2,185],"108":[2,185],"109":[2,185],"113":[2,185],"121":[2,185],"124":[2,185],"130":[2,185],"131":[2,185],"133":[2,185],"134":[2,185],"137":[2,185],"138":[2,185],"139":[2,185],"140":[2,185],"141":[2,185],"142":[2,185],"144":[2,185]},{"1":[2,141],"4":[2,141],"29":[2,141],"30":[2,141],"47":[2,141],"55":[2,141],"59":[2,141],"75":[2,141],"80":[2,141],"90":[2,141],"94":[2,141],"96":[2,141],"105":[2,141],"107":[2,141],"108":[2,141],"109":[2,141],"113":[2,141],"121":[2,141],"130":[2,141],"131":[2,141],"133":[2,141],"134":[2,141],"137":[2,141],"138":[2,141],"139":[2,141],"140":[2,141],"141":[2,141],"142":[2,141],"144":[2,141]},{"1":[2,142],"4":[2,142],"29":[2,142],"30":[2,142],"47":[2,142],"55":[2,142],"59":[2,142],"75":[2,142],"80":[2,142],"90":[2,142],"94":[2,142],"96":[2,142],"101":[2,142],"105":[2,142],"107":[2,142],"108":[2,142],"109":[2,142],"113":[2,142],"121":[2,142],"130":[2,142],"131":[2,142],"133":[2,142],"134":[2,142],"137":[2,142],"138":[2,142],"139":[2,142],"140":[2,142],"141":[2,142],"142":[2,142],"144":[2,142]},{"1":[2,175],"4":[2,175],"29":[2,175],"30":[2,175],"47":[2,175],"55":[2,175],"59":[2,175],"75":[2,175],"80":[2,175],"90":[2,175],"94":[2,175],"96":[2,175],"105":[2,175],"107":[2,175],"108":[2,175],"109":[2,175],"113":[2,175],"121":[2,175],"130":[2,175],"131":[2,175],"133":[2,175],"134":[2,175],"137":[2,175],"138":[2,175],"139":[2,175],"140":[2,175],"141":[2,175],"142":[2,175],"144":[2,175]},{"4":[1,122],"6":337,"29":[1,6]},{"30":[1,338]},{"4":[1,339],"30":[2,181],"124":[2,181],"126":[2,181]},{"8":340,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[2,105],"28":177,"30":[2,105],"31":174,"32":[1,76],"33":175,"34":[1,74],"35":[1,75],"42":233,"43":234,"46":[1,49],"58":[1,178],"78":[1,232],"83":341,"84":231},{"1":[2,96],"4":[2,96],"29":[2,96],"30":[2,96],"47":[2,96],"55":[2,96],"59":[2,96],"75":[2,96],"80":[2,96],"90":[2,96],"94":[2,96],"96":[2,96],"105":[2,96],"107":[2,96],"108":[2,96],"109":[2,96],"113":[2,96],"121":[2,96],"130":[2,96],"131":[2,96],"133":[2,96],"134":[2,96],"137":[2,96],"138":[2,96],"139":[2,96],"140":[2,96],"141":[2,96],"142":[2,96],"144":[2,96]},{"4":[2,107],"30":[2,107],"80":[2,107]},{"4":[2,108],"30":[2,108],"80":[2,108]},{"4":[2,103],"30":[2,103],"47":[1,95],"80":[2,103],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"8":342,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[1,279],"30":[1,343]},{"1":[2,123],"4":[2,123],"29":[2,123],"30":[2,123],"47":[2,123],"55":[2,123],"59":[2,123],"68":[2,123],"69":[2,123],"70":[2,123],"71":[2,123],"74":[2,123],"75":[2,123],"76":[2,123],"77":[2,123],"80":[2,123],"88":[2,123],"89":[2,123],"90":[2,123],"94":[2,123],"96":[2,123],"105":[2,123],"107":[2,123],"108":[2,123],"109":[2,123],"113":[2,123],"121":[2,123],"130":[2,123],"131":[2,123],"133":[2,123],"134":[2,123],"137":[2,123],"138":[2,123],"139":[2,123],"140":[2,123],"141":[2,123],"142":[2,123],"144":[2,123]},{"4":[2,131],"29":[2,131],"30":[2,131],"55":[2,131],"90":[2,131],"96":[2,131]},{"4":[2,57],"29":[2,57],"30":[2,57],"54":344,"55":[1,240]},{"4":[2,132],"29":[2,132],"30":[2,132],"55":[2,132],"90":[2,132],"96":[2,132]},{"1":[2,170],"4":[2,170],"29":[2,170],"30":[2,170],"47":[1,95],"55":[2,170],"59":[2,170],"75":[2,170],"80":[2,170],"90":[2,170],"94":[2,170],"96":[2,170],"105":[2,170],"106":93,"107":[2,170],"108":[2,170],"109":[2,170],"112":94,"113":[2,170],"114":72,"121":[1,345],"130":[2,170],"131":[2,170],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,172],"4":[2,172],"29":[2,172],"30":[2,172],"47":[1,95],"55":[2,172],"59":[2,172],"75":[2,172],"80":[2,172],"90":[2,172],"94":[2,172],"96":[2,172],"105":[2,172],"106":93,"107":[2,172],"108":[1,346],"109":[2,172],"112":94,"113":[2,172],"114":72,"121":[2,172],"130":[2,172],"131":[2,172],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,171],"4":[2,171],"29":[2,171],"30":[2,171],"47":[1,95],"55":[2,171],"59":[2,171],"75":[2,171],"80":[2,171],"90":[2,171],"94":[2,171],"96":[2,171],"105":[2,171],"106":93,"107":[2,171],"108":[2,171],"109":[2,171],"112":94,"113":[2,171],"114":72,"121":[2,171],"130":[2,171],"131":[2,171],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"4":[2,92],"29":[2,92],"30":[2,92],"55":[2,92],"80":[2,92]},{"4":[2,57],"29":[2,57],"30":[2,57],"54":347,"55":[1,252]},{"30":[1,348],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"30":[1,349],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,124],"4":[2,124],"29":[2,124],"30":[2,124],"41":[2,124],"47":[2,124],"55":[2,124],"59":[2,124],"68":[2,124],"69":[2,124],"70":[2,124],"71":[2,124],"74":[2,124],"75":[2,124],"76":[2,124],"77":[2,124],"80":[2,124],"82":[2,124],"88":[2,124],"89":[2,124],"90":[2,124],"94":[2,124],"96":[2,124],"105":[2,124],"107":[2,124],"108":[2,124],"109":[2,124],"113":[2,124],"121":[2,124],"130":[2,124],"131":[2,124],"133":[2,124],"134":[2,124],"135":[2,124],"136":[2,124],"137":[2,124],"138":[2,124],"139":[2,124],"140":[2,124],"141":[2,124],"142":[2,124],"143":[2,124],"144":[2,124]},{"30":[1,350]},{"1":[2,178],"4":[2,178],"29":[2,178],"30":[2,178],"47":[2,178],"55":[2,178],"59":[2,178],"75":[2,178],"80":[2,178],"90":[2,178],"94":[2,178],"96":[2,178],"105":[2,178],"107":[2,178],"108":[2,178],"109":[2,178],"113":[2,178],"121":[2,178],"130":[2,178],"131":[2,178],"133":[2,178],"134":[2,178],"137":[2,178],"138":[2,178],"139":[2,178],"140":[2,178],"141":[2,178],"142":[2,178],"144":[2,178]},{"30":[2,182],"124":[2,182],"126":[2,182]},{"4":[2,137],"29":[2,137],"47":[1,95],"55":[2,137],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"4":[1,279],"30":[1,351]},{"30":[1,352],"47":[1,95],"106":93,"107":[1,68],"109":[1,69],"112":94,"113":[1,71],"114":72,"130":[1,91],"131":[1,92],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,101],"4":[2,101],"29":[2,101],"30":[2,101],"47":[2,101],"55":[2,101],"59":[2,101],"75":[2,101],"80":[2,101],"90":[2,101],"94":[2,101],"96":[2,101],"105":[2,101],"107":[2,101],"108":[2,101],"109":[2,101],"113":[2,101],"121":[2,101],"130":[2,101],"131":[2,101],"133":[2,101],"134":[2,101],"137":[2,101],"138":[2,101],"139":[2,101],"140":[2,101],"141":[2,101],"142":[2,101],"144":[2,101]},{"4":[1,285],"29":[1,286],"30":[1,353]},{"8":354,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"8":355,"9":124,"10":23,"11":24,"12":[1,25],"13":[1,26],"14":[1,27],"15":9,"16":10,"17":11,"18":12,"19":13,"20":14,"21":15,"22":16,"23":17,"24":18,"25":19,"26":20,"27":21,"28":22,"31":64,"32":[1,76],"33":54,"34":[1,74],"35":[1,75],"36":29,"37":[1,55],"38":[1,56],"39":[1,57],"40":28,"43":65,"45":[1,50],"46":[1,49],"48":[1,34],"51":35,"52":[1,62],"53":[1,63],"58":[1,61],"61":41,"63":52,"64":53,"65":30,"66":31,"67":32,"78":[1,73],"81":[1,48],"87":[1,33],"92":[1,60],"95":[1,59],"99":[1,43],"103":[1,51],"104":[1,58],"106":44,"107":[1,68],"109":[1,69],"110":45,"111":[1,70],"112":46,"113":[1,71],"114":72,"122":[1,47],"127":42,"128":[1,66],"129":[1,67],"132":[1,36],"133":[1,37],"134":[1,38],"135":[1,39],"136":[1,40]},{"4":[1,296],"29":[1,297],"30":[1,356]},{"4":[2,46],"29":[2,46],"30":[2,46],"55":[2,46],"80":[2,46]},{"4":[2,47],"29":[2,47],"30":[2,47],"55":[2,47],"80":[2,47]},{"1":[2,176],"4":[2,176],"29":[2,176],"30":[2,176],"47":[2,176],"55":[2,176],"59":[2,176],"75":[2,176],"80":[2,176],"90":[2,176],"94":[2,176],"96":[2,176],"105":[2,176],"107":[2,176],"108":[2,176],"109":[2,176],"113":[2,176],"121":[2,176],"130":[2,176],"131":[2,176],"133":[2,176],"134":[2,176],"137":[2,176],"138":[2,176],"139":[2,176],"140":[2,176],"141":[2,176],"142":[2,176],"144":[2,176]},{"1":[2,97],"4":[2,97],"29":[2,97],"30":[2,97],"47":[2,97],"55":[2,97],"59":[2,97],"75":[2,97],"80":[2,97],"90":[2,97],"94":[2,97],"96":[2,97],"105":[2,97],"107":[2,97],"108":[2,97],"109":[2,97],"113":[2,97],"121":[2,97],"130":[2,97],"131":[2,97],"133":[2,97],"134":[2,97],"137":[2,97],"138":[2,97],"139":[2,97],"140":[2,97],"141":[2,97],"142":[2,97],"144":[2,97]},{"4":[2,104],"30":[2,104],"80":[2,104]},{"4":[2,133],"29":[2,133],"30":[2,133],"55":[2,133],"90":[2,133],"96":[2,133]},{"1":[2,173],"4":[2,173],"29":[2,173],"30":[2,173],"47":[1,95],"55":[2,173],"59":[2,173],"75":[2,173],"80":[2,173],"90":[2,173],"94":[2,173],"96":[2,173],"105":[2,173],"106":93,"107":[2,173],"108":[2,173],"109":[2,173],"112":94,"113":[2,173],"114":72,"121":[2,173],"130":[2,173],"131":[2,173],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"1":[2,174],"4":[2,174],"29":[2,174],"30":[2,174],"47":[1,95],"55":[2,174],"59":[2,174],"75":[2,174],"80":[2,174],"90":[2,174],"94":[2,174],"96":[2,174],"105":[2,174],"106":93,"107":[2,174],"108":[2,174],"109":[2,174],"112":94,"113":[2,174],"114":72,"121":[2,174],"130":[2,174],"131":[2,174],"133":[1,83],"134":[1,82],"137":[1,84],"138":[1,85],"139":[1,86],"140":[1,87],"141":[1,88],"142":[1,89],"144":[1,90]},{"4":[2,93],"29":[2,93],"30":[2,93],"55":[2,93],"80":[2,93]}], +defaultActions: {"79":[2,4],"102":[2,115]}, +parseError: function parseError(str, hash) { + throw new Error(str); +}, +parse: function parse(input) { + var self = this, + stack = [0], + vstack = [null], // semantic value stack + table = this.table, + yytext = '', + yylineno = 0, + yyleng = 0, + shifts = 0, + reductions = 0, + recovering = 0, + TERROR = 2, + EOF = 1; + + this.lexer.setInput(input); + this.lexer.yy = this.yy; + this.yy.lexer = this.lexer; + + var parseError = this.yy.parseError = typeof this.yy.parseError == 'function' ? this.yy.parseError : this.parseError; + + function popStack (n) { + stack.length = stack.length - 2*n; + vstack.length = vstack.length - n; + } + + function checkRecover (st) { + for (var p in table[st]) if (p == TERROR) { + return true; + } + return false; + } + + function lex() { + var token; + token = self.lexer.lex() || 1; // $end = 1 + // if token isn't its numeric value, convert + if (typeof token !== 'number') { + token = self.symbols_[token] || token; + } + return token; + }; + + var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected, recovered = false; + while (true) { + // retreive state number from top of stack + state = stack[stack.length-1]; + + // use default actions if available + if (this.defaultActions[state]) { + action = this.defaultActions[state]; + } else { + if (symbol == null) + symbol = lex(); + // read action for current state and first input + action = table[state] && table[state][symbol]; + } + + // handle parse error + if (typeof action === 'undefined' || !action.length || !action[0]) { + + if (!recovering) { + // Report error + expected = []; + for (p in table[state]) if (this.terminals_[p] && p > 2) { + expected.push("'"+this.terminals_[p]+"'"); + } + if (this.lexer.showPosition) { + parseError.call(this, 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+'\nExpecting '+expected.join(', '), + {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, expected: expected}); + } else { + parseError.call(this, 'Parse error on line '+(yylineno+1)+": Unexpected '"+(this.terminals_[symbol] || symbol)+"'", + {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, expected: expected}); + } + } + + // just recovered from another error + if (recovering == 3) { + if (symbol == EOF) { + throw 'Parsing halted.' + } + + // discard current lookahead and grab another + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + symbol = lex(); + } + + // try to recover from error + while (1) { + // check for error recovery rule in this state + if (checkRecover(state)) { + break; + } + if (state == 0) { + throw 'Parsing halted.' + } + popStack(1); + state = stack[stack.length-1]; + } + + preErrorSymbol = symbol; // save the lookahead token + symbol = TERROR; // insert generic error symbol as new lookahead + state = stack[stack.length-1]; + action = table[state] && table[state][TERROR]; + recovering = 3; // allow 3 real symbols to be shifted before reporting a new error + } + + // this shouldn't happen, unless resolve defaults are off + if (action[0] instanceof Array && action.length > 1) { + throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol); + } + + a = action; + + switch (a[0]) { + + case 1: // shift + shifts++; + + stack.push(symbol); + vstack.push(this.lexer.yytext); // semantic values or junk only, no terminals + stack.push(a[1]); // push state + symbol = null; + if (!preErrorSymbol) { // normal execution/no error + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + if (recovering > 0) + recovering--; + } else { // error just occurred, resume old lookahead f/ before error + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + + case 2: // reduce + reductions++; + + len = this.productions_[a[1]][1]; + + // perform semantic action + yyval.$ = vstack[vstack.length-len]; // default to $$ = $1 + r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, a[1], vstack); + + if (typeof r !== 'undefined') { + return r; + } + + // pop off stack + if (len) { + stack = stack.slice(0,-1*len*2); + vstack = vstack.slice(0, -1*len); + } + + stack.push(this.productions_[a[1]][0]); // push nonterminal (reduce) + vstack.push(yyval.$); + // goto new state = table[STATE][NONTERMINAL] + newState = table[stack[stack.length-2]][stack[stack.length-1]]; + stack.push(newState); + break; + + case 3: // accept + + this.reductionCount = reductions; + this.shiftCount = shifts; + return true; + } + + } + + return true; +}}; +return parser; +})(); +if (typeof require !== 'undefined') { +exports.parser = parser; +exports.parse = function () { return parser.parse.apply(parser, arguments); } +exports.main = function commonjsMain(args) { + if (!args[1]) + throw new Error('Usage: '+args[0]+' FILE'); + if (typeof process !== 'undefined') { + var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8"); + } else { + var cwd = require("file").path(require("file").cwd()); + var source = cwd.join(args[1]).read({charset: "utf-8"}); + } + return exports.parser.parse(source); +} +if (typeof module !== 'undefined' && require.main === module) { + exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args); +} +} \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/lib/repl.js b/node_modules/jade/support/coffee-script/lib/repl.js new file mode 100644 index 0000000..d30f756 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/repl.js @@ -0,0 +1,38 @@ +(function() { + var CoffeeScript, helpers, readline, repl, run, stdio; + CoffeeScript = require('./coffee-script'); + helpers = require('./helpers'); + readline = require('readline'); + stdio = process.openStdin(); + helpers.extend(global, { + quit: function() { + return process.exit(0); + } + }); + run = function(buffer) { + var val; + try { + val = CoffeeScript.eval(buffer.toString(), { + bare: true, + globals: true, + fileName: 'repl' + }); + if (val !== undefined) { + puts(inspect(val)); + } + } catch (err) { + puts(err.stack || err.toString()); + } + return repl.prompt(); + }; + repl = readline.createInterface(stdio); + repl.setPrompt('coffee> '); + stdio.on('data', function(buffer) { + return repl.write(buffer); + }); + repl.on('close', function() { + return stdio.destroy(); + }); + repl.on('line', run); + repl.prompt(); +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/rewriter.js b/node_modules/jade/support/coffee-script/lib/rewriter.js new file mode 100644 index 0000000..6999fc8 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/rewriter.js @@ -0,0 +1,378 @@ +(function() { + var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, _i, _len, _ref, include, left, rite; + include = require('./helpers').include; + exports.Rewriter = (function() { + function Rewriter() { + return this; + }; + return Rewriter; + })(); + exports.Rewriter.prototype.rewrite = function(_arg) { + this.tokens = _arg; + this.adjustComments(); + this.removeLeadingNewlines(); + this.removeMidExpressionNewlines(); + this.closeOpenCalls(); + this.closeOpenIndexes(); + this.addImplicitIndentation(); + this.tagPostfixConditionals(); + this.addImplicitBraces(); + this.addImplicitParentheses(); + this.ensureBalance(BALANCED_PAIRS); + this.rewriteClosingParens(); + return this.tokens; + }; + exports.Rewriter.prototype.scanTokens = function(block) { + var i, token, tokens; + tokens = this.tokens; + i = 0; + while (token = tokens[i]) { + i += block.call(this, token, i, tokens); + } + return true; + }; + exports.Rewriter.prototype.detectEnd = function(i, condition, action) { + var levels, token, tokens; + tokens = this.tokens; + levels = 0; + while (token = tokens[i]) { + if (levels === 0 && condition.call(this, token, i)) { + return action.call(this, token, i); + } + if (!token || levels < 0) { + return action.call(this, token, i - 1); + } + if (include(EXPRESSION_START, token[0])) { + levels += 1; + } else if (include(EXPRESSION_END, token[0])) { + levels -= 1; + } + i += 1; + } + return i - 1; + }; + exports.Rewriter.prototype.adjustComments = function() { + return this.scanTokens(function(token, i, tokens) { + var _ref, after, before, post, prev; + if (token[0] !== 'HERECOMMENT') { + return 1; + } + before = tokens[i - 2]; + prev = tokens[i - 1]; + post = tokens[i + 1]; + after = tokens[i + 2]; + if (((after != null) ? after[0] : undefined) === 'INDENT') { + tokens.splice(i + 2, 1); + if (((before != null) ? before[0] : undefined) === 'OUTDENT' && ((post != null) ? post[0] : undefined) === 'TERMINATOR') { + tokens.splice(i - 2, 1); + } else { + tokens.splice(i, 0, after); + } + } else if (prev && !((_ref = prev[0]) === 'TERMINATOR' || _ref === 'INDENT' || _ref === 'OUTDENT')) { + if (((post != null) ? post[0] : undefined) === 'TERMINATOR' && ((after != null) ? after[0] : undefined) === 'OUTDENT') { + tokens.splice.apply(tokens, [i + 2, 0].concat(tokens.splice(i, 2))); + if (tokens[i + 2][0] !== 'TERMINATOR') { + tokens.splice(i + 2, 0, ['TERMINATOR', '\n', prev[2]]); + } + } else { + tokens.splice(i, 0, ['TERMINATOR', '\n', prev[2]]); + } + return 2; + } + return 1; + }); + }; + exports.Rewriter.prototype.removeLeadingNewlines = function() { + var _len, _ref, i, tag; + for (i = 0, _len = (_ref = this.tokens).length; i < _len; i++) { + tag = _ref[i][0]; + if (tag !== 'TERMINATOR') { + break; + } + } + return i ? this.tokens.splice(0, i) : undefined; + }; + exports.Rewriter.prototype.removeMidExpressionNewlines = function() { + return this.scanTokens(function(token, i, tokens) { + if (!(token[0] === 'TERMINATOR' && include(EXPRESSION_CLOSE, this.tag(i + 1)))) { + return 1; + } + tokens.splice(i, 1); + return 0; + }); + }; + exports.Rewriter.prototype.closeOpenCalls = function() { + var action, condition; + condition = function(token, i) { + var _ref; + return ((_ref = token[0]) === ')' || _ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')'; + }; + action = function(token, i) { + return (this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END'); + }; + return this.scanTokens(function(token, i) { + if (token[0] === 'CALL_START') { + this.detectEnd(i + 1, condition, action); + } + return 1; + }); + }; + exports.Rewriter.prototype.closeOpenIndexes = function() { + var action, condition; + condition = function(token, i) { + var _ref; + return ((_ref = token[0]) === ']' || _ref === 'INDEX_END'); + }; + action = function(token, i) { + return (token[0] = 'INDEX_END'); + }; + return this.scanTokens(function(token, i) { + if (token[0] === 'INDEX_START') { + this.detectEnd(i + 1, condition, action); + } + return 1; + }); + }; + exports.Rewriter.prototype.addImplicitBraces = function() { + var action, condition, stack; + stack = []; + condition = function(token, i) { + var _ref, _ref2, one, tag, three, two; + if (('HERECOMMENT' === this.tag(i + 1) || 'HERECOMMENT' === this.tag(i - 1))) { + return false; + } + _ref = this.tokens.slice(i + 1, i + 4), one = _ref[0], two = _ref[1], three = _ref[2]; + tag = token[0]; + return (tag === 'TERMINATOR' || tag === 'OUTDENT') && !(((two != null) ? two[0] : undefined) === ':' || ((one != null) ? one[0] : undefined) === '@' && ((three != null) ? three[0] : undefined) === ':') || tag === ',' && !((_ref2 = ((one != null) ? one[0] : undefined)) === 'IDENTIFIER' || _ref2 === 'NUMBER' || _ref2 === 'STRING' || _ref2 === '@' || _ref2 === 'TERMINATOR' || _ref2 === 'OUTDENT'); + }; + action = function(token, i) { + return this.tokens.splice(i, 0, ['}', '}', token[2]]); + }; + return this.scanTokens(function(token, i, tokens) { + var idx, tag, tok; + if (include(EXPRESSION_START, tag = token[0])) { + stack.push(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag); + return 1; + } + if (include(EXPRESSION_END, tag)) { + stack.pop(); + return 1; + } + if (!(tag === ':' && stack[stack.length - 1] !== '{')) { + return 1; + } + stack.push('{'); + idx = this.tag(i - 2) === '@' ? i - 2 : i - 1; + if (this.tag(idx - 2) === 'HERECOMMENT') { + idx -= 2; + } + tok = ['{', '{', token[2]]; + tok.generated = true; + tokens.splice(idx, 0, tok); + this.detectEnd(i + 2, condition, action); + return 2; + }); + }; + exports.Rewriter.prototype.addImplicitParentheses = function() { + var action, classLine; + classLine = false; + action = function(token, i) { + var idx; + idx = token[0] === 'OUTDENT' ? i + 1 : i; + return this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]); + }; + return this.scanTokens(function(token, i, tokens) { + var callObject, next, prev, seenSingle, tag; + tag = token[0]; + if (tag === 'CLASS') { + classLine = true; + } + prev = tokens[i - 1]; + next = tokens[i + 1]; + callObject = !classLine && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && include(IMPLICIT_FUNC, prev[0]); + seenSingle = false; + if (include(LINEBREAKS, tag)) { + classLine = false; + } + if (prev && !prev.spaced && tag === '?') { + token.call = true; + } + if (!(callObject || ((prev != null) ? prev.spaced : undefined) && (prev.call || include(IMPLICIT_FUNC, prev[0])) && (include(IMPLICIT_CALL, tag) || include(IMPLICIT_UNSPACED_CALL, tag) && !token.spaced))) { + return 1; + } + tokens.splice(i, 0, ['CALL_START', '(', token[2]]); + this.detectEnd(i + (callObject ? 2 : 1), function(token, i) { + var post; + if (!seenSingle && token.fromThen) { + return true; + } + tag = token[0]; + if ((tag === 'IF' || tag === 'ELSE' || tag === 'UNLESS' || tag === '->' || tag === '=>')) { + seenSingle = true; + } + if (tag === 'PROPERTY_ACCESS' && this.tag(i - 1) === 'OUTDENT') { + return true; + } + return !token.generated && this.tag(i - 1) !== ',' && include(IMPLICIT_END, tag) && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && !include(IMPLICIT_BLOCK, this.tag(i - 1)) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{'))); + }, action); + if (prev[0] === '?') { + prev[0] = 'FUNC_EXIST'; + } + return 2; + }); + }; + exports.Rewriter.prototype.addImplicitIndentation = function() { + return this.scanTokens(function(token, i, tokens) { + var _ref, _ref2, action, condition, indent, outdent, starter, tag; + tag = token[0]; + if (tag === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') { + tokens.splice.apply(tokens, [i, 0].concat(this.indentation(token))); + return 2; + } + if (tag === 'CATCH' && ((_ref = this.tag(i + 2)) === 'TERMINATOR' || _ref === 'FINALLY')) { + tokens.splice.apply(tokens, [i + 2, 0].concat(this.indentation(token))); + return 4; + } + if (include(SINGLE_LINERS, tag) && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) { + starter = tag; + _ref2 = this.indentation(token), indent = _ref2[0], outdent = _ref2[1]; + if (starter === 'THEN') { + indent.fromThen = true; + } + indent.generated = (outdent.generated = true); + tokens.splice(i + 1, 0, indent); + condition = function(token, i) { + return token[1] !== ';' && include(SINGLE_CLOSERS, token[0]) && !(token[0] === 'ELSE' && !(starter === 'IF' || starter === 'THEN')); + }; + action = function(token, i) { + return this.tokens.splice(this.tag(i - 1) === ',' ? i - 1 : i, 0, outdent); + }; + this.detectEnd(i + 2, condition, action); + if (tag === 'THEN') { + tokens.splice(i, 1); + } + return 1; + } + return 1; + }); + }; + exports.Rewriter.prototype.tagPostfixConditionals = function() { + var condition; + condition = function(token, i) { + var _ref; + return ((_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT'); + }; + return this.scanTokens(function(token, i) { + var _ref, original; + if (!((_ref = token[0]) === 'IF' || _ref === 'UNLESS')) { + return 1; + } + original = token; + this.detectEnd(i + 1, condition, function(token, i) { + return token[0] !== 'INDENT' ? (original[0] = 'POST_' + original[0]) : undefined; + }); + return 1; + }); + }; + exports.Rewriter.prototype.ensureBalance = function(pairs) { + var _result, key, levels, open, openLine, unclosed, value; + levels = {}; + openLine = {}; + this.scanTokens(function(token, i) { + var _i, _len, _ref, _ref2, close, open, tag; + tag = token[0]; + for (_i = 0, _len = (_ref = pairs).length; _i < _len; _i++) { + _ref2 = _ref[_i], open = _ref2[0], close = _ref2[1]; + levels[open] |= 0; + if (tag === open) { + if (levels[open] === 0) { + openLine[open] = token[2]; + } + levels[open] += 1; + } else if (tag === close) { + levels[open] -= 1; + } + if (levels[open] < 0) { + throw Error("too many " + (token[1]) + " on line " + (token[2] + 1)); + } + } + return 1; + }); + unclosed = (function() { + _result = []; + for (key in levels) { + value = levels[key]; + if (value > 0) { + _result.push(key); + } + } + return _result; + })(); + if (unclosed.length) { + throw Error("unclosed " + (open = unclosed[0]) + " on line " + (openLine[open] + 1)); + } + }; + exports.Rewriter.prototype.rewriteClosingParens = function() { + var debt, key, stack; + stack = []; + debt = {}; + for (key in INVERSES) { + (debt[key] = 0); + } + return this.scanTokens(function(token, i, tokens) { + var inv, match, mtag, oppos, tag, val; + if (include(EXPRESSION_START, tag = token[0])) { + stack.push(token); + return 1; + } + if (!include(EXPRESSION_END, tag)) { + return 1; + } + if (debt[(inv = INVERSES[tag])] > 0) { + debt[inv] -= 1; + tokens.splice(i, 1); + return 0; + } + match = stack.pop(); + mtag = match[0]; + oppos = INVERSES[mtag]; + if (tag === oppos) { + return 1; + } + debt[mtag] += 1; + val = [oppos, mtag === 'INDENT' ? match[1] : oppos]; + if (this.tag(i + 2) === mtag) { + tokens.splice(i + 3, 0, val); + stack.push(match); + } else { + tokens.splice(i, 0, val); + } + return 1; + }); + }; + exports.Rewriter.prototype.indentation = function(token) { + return [['INDENT', 2, token[2]], ['OUTDENT', 2, token[2]]]; + }; + exports.Rewriter.prototype.tag = function(i) { + var _ref; + return (((_ref = this.tokens[i]) != null) ? _ref[0] : undefined); + }; + BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']]; + INVERSES = {}; + EXPRESSION_START = []; + EXPRESSION_END = []; + for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; _i++) { + _ref = BALANCED_PAIRS[_i], left = _ref[0], rite = _ref[1]; + EXPRESSION_START.push(INVERSES[rite] = left); + EXPRESSION_END.push(INVERSES[left] = rite); + } + EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END); + IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']; + IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', '@', '->', '=>', '[', '(', '{', '--', '++']; + IMPLICIT_UNSPACED_CALL = ['+', '-']; + IMPLICIT_BLOCK = ['->', '=>', '{', '[', ',']; + IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'TERMINATOR', 'INDENT']; + SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN']; + SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN']; + LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT']; +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/scope.js b/node_modules/jade/support/coffee-script/lib/scope.js new file mode 100644 index 0000000..b0f2a64 --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/scope.js @@ -0,0 +1,134 @@ +(function() { + var Scope, _ref, extend, last; + var __hasProp = Object.prototype.hasOwnProperty; + _ref = require('./helpers'), extend = _ref.extend, last = _ref.last; + exports.Scope = (function() { + Scope = (function() { + function Scope(_arg, _arg2, _arg3) { + this.method = _arg3; + this.expressions = _arg2; + this.parent = _arg; + this.variables = { + 'arguments': 'arguments' + }; + if (this.parent) { + this.garbage = this.parent.garbage; + } else { + this.garbage = []; + Scope.root = this; + } + return this; + }; + return Scope; + })(); + Scope.root = null; + Scope.prototype.startLevel = function() { + return this.garbage.push([]); + }; + Scope.prototype.endLevel = function() { + var _i, _len, _ref2, _result, name, vars; + vars = this.variables; + _result = []; + for (_i = 0, _len = (_ref2 = this.garbage.pop()).length; _i < _len; _i++) { + name = _ref2[_i]; + if (vars[name] === 'var') { + _result.push(vars[name] = 'reuse'); + } + } + return _result; + }; + Scope.prototype.find = function(name, options) { + if (this.check(name, options)) { + return true; + } + this.variables[name] = 'var'; + return false; + }; + Scope.prototype.any = function(fn) { + var _ref2, k, v; + for (v in _ref2 = this.variables) { + if (!__hasProp.call(_ref2, v)) continue; + k = _ref2[v]; + if (fn(v, k)) { + return true; + } + } + return false; + }; + Scope.prototype.parameter = function(name) { + return (this.variables[name] = 'param'); + }; + Scope.prototype.check = function(name, options) { + var _ref2, immediate; + immediate = Object.prototype.hasOwnProperty.call(this.variables, name); + if (immediate || ((options != null) ? options.immediate : undefined)) { + return immediate; + } + return !!(((_ref2 = this.parent) != null) ? _ref2.check(name) : undefined); + }; + Scope.prototype.temporary = function(type, index) { + return type.length > 1 ? '_' + type + (index > 1 ? index : '') : '_' + (index + parseInt(type, 36)).toString(36).replace(/\d/g, 'a'); + }; + Scope.prototype.freeVariable = function(type) { + var index, temp; + index = 0; + while (this.check(temp = this.temporary(type, index)) && this.variables[temp] !== 'reuse') { + index++; + } + this.variables[temp] = 'var'; + if (this.garbage.length) { + last(this.garbage).push(temp); + } + return temp; + }; + Scope.prototype.assign = function(name, value) { + return (this.variables[name] = { + value: value, + assigned: true + }); + }; + Scope.prototype.hasDeclarations = function(body) { + return body === this.expressions && this.any(function(k, val) { + return (val === 'var' || val === 'reuse'); + }); + }; + Scope.prototype.hasAssignments = function(body) { + return body === this.expressions && this.any(function(k, val) { + return val.assigned; + }); + }; + Scope.prototype.declaredVariables = function() { + var _ref2, _result, key, val; + return (function() { + _result = []; + for (key in _ref2 = this.variables) { + if (!__hasProp.call(_ref2, key)) continue; + val = _ref2[key]; + if ((val === 'var' || val === 'reuse')) { + _result.push(key); + } + } + return _result; + }).call(this).sort(); + }; + Scope.prototype.assignedVariables = function() { + var _ref2, _result, key, val; + _result = []; + for (key in _ref2 = this.variables) { + if (!__hasProp.call(_ref2, key)) continue; + val = _ref2[key]; + if (val.assigned) { + _result.push("" + key + " = " + (val.value)); + } + } + return _result; + }; + Scope.prototype.compiledDeclarations = function() { + return this.declaredVariables().join(', '); + }; + Scope.prototype.compiledAssignments = function() { + return this.assignedVariables().join(', '); + }; + return Scope; + }).call(this); +}).call(this); diff --git a/node_modules/jade/support/coffee-script/lib/utilities.js b/node_modules/jade/support/coffee-script/lib/utilities.js new file mode 100644 index 0000000..dacb61d --- /dev/null +++ b/node_modules/jade/support/coffee-script/lib/utilities.js @@ -0,0 +1,12 @@ +(function(){ + if (!((typeof process !== "undefined" && process !== null))) { + this.exports = this; + } + exports.utilities = { + extend: "function(child, parent) {\n var ctor = function(){ };\n ctor.prototype = parent.prototype;\n child.__superClass__ = parent.prototype;\n child.prototype = new ctor();\n child.prototype.constructor = child;\n }", + bind: "function(func, obj, args) {\n return function() {\n return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);\n };\n }", + range: "function(array, from, to, exclusive) {\n return [\n (from < 0 ? from + array.length : from || 0),\n (to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1)\n ];\n }", + hasProp: 'Object.prototype.hasOwnProperty', + slice: 'Array.prototype.slice' + }; +})(); diff --git a/node_modules/jade/support/coffee-script/package.json b/node_modules/jade/support/coffee-script/package.json new file mode 100644 index 0000000..89f7340 --- /dev/null +++ b/node_modules/jade/support/coffee-script/package.json @@ -0,0 +1,22 @@ +{ + "name": "coffee-script", + "description": "Unfancy JavaScript", + "keywords": ["javascript", "language", "coffeescript", "compiler"], + "author": "Jeremy Ashkenas", + "version": "0.9.4", + "licenses": [{ + "type": "MIT", + "url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE" + }], + "engines": { + "node": ">=0.1.99" + }, + "directories" : { + "lib" : "./lib" + }, + "main" : "./lib/coffee-script", + "bin": { + "coffee": "./bin/coffee", + "cake": "./bin/cake" + } +} diff --git a/node_modules/jade/support/coffee-script/src/browser.coffee b/node_modules/jade/support/coffee-script/src/browser.coffee new file mode 100644 index 0000000..ddb7a0f --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/browser.coffee @@ -0,0 +1,41 @@ +# Override exported methods for non-Node.js engines. + +CoffeeScript = require './coffee-script' +CoffeeScript.require = require + +# Use standard JavaScript `eval` to eval code. +CoffeeScript.eval = (code, options) -> + eval CoffeeScript.compile code, options + +# Running code does not provide access to this scope. +CoffeeScript.run = (code, options) -> + options?.bare = on + Function(CoffeeScript.compile code, options)() + +# If we're not in a browser environment, we're finished with the public API. +return unless window? + +# Load a remote script from the current domain via XHR. +CoffeeScript.load = (url, options) -> + xhr = new (window.ActiveXObject or XMLHttpRequest)('Microsoft.XMLHTTP') + xhr.open 'GET', url, true + xhr.overrideMimeType 'text/plain' if 'overrideMimeType' of xhr + xhr.onreadystatechange = -> + CoffeeScript.run xhr.responseText, options if xhr.readyState is 4 + xhr.send null + +# Activate CoffeeScript in the browser by having it compile and evaluate +# all script tags with a content-type of `text/coffeescript`. +# This happens on page load. +runScripts = -> + for script in document.getElementsByTagName 'script' + if script.type is 'text/coffeescript' + if script.src + CoffeeScript.load script.src + else + setTimeout -> CoffeeScript.run script.innerHTML + null +if window.addEventListener + addEventListener 'DOMContentLoaded', runScripts, no +else + attachEvent 'onload', runScripts diff --git a/node_modules/jade/support/coffee-script/src/cake.coffee b/node_modules/jade/support/coffee-script/src/cake.coffee new file mode 100644 index 0000000..61567bc --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/cake.coffee @@ -0,0 +1,69 @@ +# `cake` is a simplified version of [Make](http://www.gnu.org/software/make/) +# ([Rake](http://rake.rubyforge.org/), [Jake](http://github.com/280north/jake)) +# for CoffeeScript. You define tasks with names and descriptions in a Cakefile, +# and can call them from the command line, or invoke them from other tasks. +# +# Running `cake` with no arguments will print out a list of all the tasks in the +# current directory's Cakefile. + +# External dependencies. +fs = require 'fs' +path = require 'path' +helpers = require './helpers' +optparse = require './optparse' +CoffeeScript = require './coffee-script' + +# Keep track of the list of defined tasks, the accepted options, and so on. +tasks = {} +options = {} +switches = [] +oparse = null + +# Mixin the top-level Cake functions for Cakefiles to use directly. +helpers.extend global, + + # Define a Cake task with a short name, an optional sentence description, + # and the function to run as the action itself. + task: (name, description, action) -> + [action, description] = [description, action] unless action + tasks[name] = {name, description, action} + + # Define an option that the Cakefile accepts. The parsed options hash, + # containing all of the command-line options passed, will be made available + # as the first argument to the action. + option: (letter, flag, description) -> + switches.push [letter, flag, description] + + # Invoke another task in the current Cakefile. + invoke: (name) -> + missingTask name unless tasks[name] + tasks[name].action options + + +# Run `cake`. Executes all of the tasks you pass, in order. Note that Node's +# asynchrony may cause tasks to execute in a different order than you'd expect. +# If no tasks are passed, print the help screen. +exports.run = -> + path.exists 'Cakefile', (exists) -> + throw new Error("Cakefile not found in #{process.cwd()}") unless exists + args = process.argv.slice 2 + CoffeeScript.run fs.readFileSync('Cakefile').toString(), fileName: 'Cakefile' + oparse = new optparse.OptionParser switches + return printTasks() unless args.length + options = oparse.parse(args) + invoke arg for arg in options.arguments + +# Display the list of Cake tasks in a format similar to `rake -T` +printTasks = -> + puts '' + for all name, task of tasks + spaces = 20 - name.length + spaces = if spaces > 0 then Array(spaces + 1).join(' ') else '' + desc = if task.description then "# #{task.description}" else '' + puts "cake #{name}#{spaces} #{desc}" + puts oparse.help() if switches.length + +# Print an error and exit when attempting to all an undefined task. +missingTask = (task) -> + puts "No such task: \"#{task}\"" + process.exit 1 diff --git a/node_modules/jade/support/coffee-script/src/coffee-script.coffee b/node_modules/jade/support/coffee-script/src/coffee-script.coffee new file mode 100755 index 0000000..135788d --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/coffee-script.coffee @@ -0,0 +1,90 @@ +# CoffeeScript can be used both on the server, as a command-line compiler based +# on Node.js/V8, or to run CoffeeScripts directly in the browser. This module +# contains the main entry functions for tokenzing, parsing, and compiling source +# CoffeeScript into JavaScript. +# +# If included on a webpage, it will automatically sniff out, compile, and +# execute all scripts present in `text/coffeescript` tags. + +path = require 'path' +{Lexer} = require './lexer' +{parser} = require './parser' + +# TODO: Remove registerExtension when fully deprecated +if require.extensions + fs = require 'fs' + require.extensions['.coffee'] = (module, filename) -> + content = compile fs.readFileSync filename, 'utf8' + module._compile content, filename +else if require.registerExtension + require.registerExtension '.coffee', (content) -> compile content + +# The current CoffeeScript version number. +exports.VERSION = '0.9.4' + +# Expose helpers for testing. +exports.helpers = require './helpers' + +# Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison +# compiler. +exports.compile = compile = (code, options) -> + options or= {} + try + (parser.parse lexer.tokenize code).compile options + catch err + err.message = "In #{options.fileName}, #{err.message}" if options.fileName + throw err + +# Tokenize a string of CoffeeScript code, and return the array of tokens. +exports.tokens = (code, options) -> + lexer.tokenize code, options + +# Tokenize and parse a string of CoffeeScript code, and return the AST. You can +# then compile it by calling `.compile()` on the root, or traverse it by using +# `.traverse()` with a callback. +exports.nodes = (code, options) -> + parser.parse lexer.tokenize code, options + +# Compile and execute a string of CoffeeScript (on the server), correctly +# setting `__filename`, `__dirname`, and relative `require()`. +exports.run = (code, options) -> + # We want the root module. + root = module + while root.parent + root = root.parent + # Set the filename + root.filename = options.fileName + # Clear the module cache + root.moduleCache = {} if root.moduleCache + # Compile + if path.extname(root.filename) isnt '.coffee' or require.extensions + root._compile exports.compile(code, options), root.filename + else + root._compile code, root.filename + +# Compile and evaluate a string of CoffeeScript (in a Node.js-like environment). +# The CoffeeScript REPL uses this to run the input. +exports.eval = (code, options) -> + __filename = options.fileName + __dirname = path.dirname __filename + eval exports.compile(code, options) + +# Instantiate a Lexer for our use here. +lexer = new Lexer + +# The real Lexer produces a generic stream of tokens. This object provides a +# thin wrapper around it, compatible with the Jison API. We can then pass it +# directly as a "Jison lexer". +parser.lexer = + lex: -> + token = @tokens[@pos] or [""] + @pos += 1 + this.yylineno = token[2] + this.yytext = token[1] + token[0] + setInput: (tokens) -> + @tokens = tokens + @pos = 0 + upcomingInput: -> "" + +parser.yy = require './nodes' diff --git a/node_modules/jade/support/coffee-script/src/command.coffee b/node_modules/jade/support/coffee-script/src/command.coffee new file mode 100644 index 0000000..59cf5ef --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/command.coffee @@ -0,0 +1,195 @@ +# The `coffee` utility. Handles command-line compilation of CoffeeScript +# into various forms: saved into `.js` files or printed to stdout, piped to +# [JSLint](http://javascriptlint.com/) or recompiled every time the source is +# saved, printed as a token stream or as the syntax tree, or launch an +# interactive REPL. + +# External dependencies. +fs = require 'fs' +path = require 'path' +optparse = require './optparse' +CoffeeScript = require './coffee-script' +helpers = require './helpers' +{spawn, exec} = require 'child_process' +{EventEmitter} = require 'events' + +# Allow CoffeeScript to emit Node.js events, and add it to global scope. +helpers.extend CoffeeScript, new EventEmitter +global.CoffeeScript = CoffeeScript + +# The help banner that is printed when `coffee` is called without arguments. +BANNER = ''' + coffee compiles CoffeeScript source files into JavaScript. + + Usage: + coffee path/to/script.coffee + ''' + +# The list of all the valid option flags that `coffee` knows how to handle. +SWITCHES = [ + ['-c', '--compile', 'compile to JavaScript and save as .js files'] + ['-i', '--interactive', 'run an interactive CoffeeScript REPL'] + ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'] + ['-w', '--watch', 'watch scripts for changes, and recompile'] + ['-p', '--print', 'print the compiled JavaScript to stdout'] + ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'] + ['-s', '--stdio', 'listen for and compile scripts over stdio'] + ['-e', '--eval', 'compile a string from the command line'] + ['-r', '--require [FILE*]', 'require a library before executing your script'] + ['-b', '--bare', 'compile without the top-level function wrapper'] + ['-t', '--tokens', 'print the tokens that the lexer produces'] + ['-n', '--nodes', 'print the parse tree that Jison produces'] + ['-v', '--version', 'display CoffeeScript version'] + ['-h', '--help', 'display this help message'] +] + +# Top-level objects shared by all the functions. +opts = {} +sources = [] +optionParser = null + +# Run `coffee` by parsing passed options and determining what action to take. +# Many flags cause us to divert before compiling anything. Flags passed after +# `--` will be passed verbatim to your script as arguments in `process.argv` +exports.run = -> + parseOptions() + return usage() if opts.help + return version() if opts.version + return require './repl' if opts.interactive + return compileStdio() if opts.stdio + return compileScript 'console', sources[0] if opts.eval + return require './repl' unless sources.length + separator = sources.indexOf '--' + flags = [] + if separator >= 0 + flags = sources.splice separator + 1 + sources.pop() + if opts.run + flags = sources.splice(1).concat flags + process.ARGV = process.argv = flags + compileScripts() + +# Asynchronously read in each CoffeeScript in a list of source files and +# compile them. If a directory is passed, recursively compile all +# '.coffee' extension source files in it and all subdirectories. +compileScripts = -> + for source in sources + base = source + compile = (source, topLevel) -> + path.exists source, (exists) -> + throw new Error "File not found: #{source}" unless exists + fs.stat source, (err, stats) -> + if stats.isDirectory() + fs.readdir source, (err, files) -> + for file in files + compile path.join(source, file) + else if topLevel or path.extname(source) is '.coffee' + fs.readFile source, (err, code) -> compileScript(source, code.toString(), base) + watch source, base if opts.watch + compile source, true + +# Compile a single source script, containing the given code, according to the +# requested options. If evaluating the script directly sets `__filename`, +# `__dirname` and `module.filename` to be correct relative to the script's path. +compileScript = (file, input, base) -> + o = opts + options = compileOptions file + if o.require + require(if helpers.starts(req, '.') then fs.realpathSync(req) else req) for req in o.require + try + t = task = {file, input, options} + CoffeeScript.emit 'compile', task + if o.tokens then printTokens CoffeeScript.tokens t.input + else if o.nodes then puts CoffeeScript.nodes(t.input).toString().trim() + else if o.run then CoffeeScript.run t.input, t.options + else + t.output = CoffeeScript.compile t.input, t.options + CoffeeScript.emit 'success', task + if o.print then print t.output + else if o.compile then writeJs t.file, t.output, base + else if o.lint then lint t.output + catch err + # Avoid using 'error' as it is a special event -- if there is no handler, + # node will print a stack trace and exit the program. + CoffeeScript.emit 'failure', err, task + return if CoffeeScript.listeners('failure').length + return puts err.message if o.watch + error err.stack + process.exit 1 + +# Attach the appropriate listeners to compile scripts incoming over **stdin**, +# and write them back to **stdout**. +compileStdio = -> + code = '' + stdin = process.openStdin() + stdin.on 'data', (buffer) -> + code += buffer.toString() if buffer + stdin.on 'end', -> + compileScript 'stdio', code + +# Watch a source CoffeeScript file using `fs.watchFile`, recompiling it every +# time the file is updated. May be used in combination with other options, +# such as `--lint` or `--print`. +watch = (source, base) -> + fs.watchFile source, {persistent: true, interval: 500}, (curr, prev) -> + return if curr.size is prev.size and curr.mtime.getTime() is prev.mtime.getTime() + fs.readFile source, (err, code) -> + throw err if err + compileScript(source, code.toString(), base) + +# Write out a JavaScript source file with the compiled code. By default, files +# are written out in `cwd` as `.js` files with the same name, but the output +# directory can be customized with `--output`. +writeJs = (source, js, base) -> + filename = path.basename(source, path.extname(source)) + '.js' + srcDir = path.dirname source + baseDir = srcDir.substring base.length + dir = if opts.output then path.join opts.output, baseDir else srcDir + jsPath = path.join dir, filename + compile = -> + js = ' ' if js.length <= 0 + fs.writeFile jsPath, js, (err) -> + puts "Compiled #{source}" if opts.compile and opts.watch + path.exists dir, (exists) -> + if exists then compile() else exec "mkdir -p #{dir}", compile + +# Pipe compiled JS through JSLint (requires a working `jsl` command), printing +# any errors or warnings that arise. +lint = (js) -> + printIt = (buffer) -> puts buffer.toString().trim() + conf = __dirname + '/../extras/jsl.conf' + jsl = spawn 'jsl', ['-nologo', '-stdin', '-conf', conf] + jsl.stdout.on 'data', printIt + jsl.stderr.on 'data', printIt + jsl.stdin.write js + jsl.stdin.end() + +# Pretty-print a stream of tokens. +printTokens = (tokens) -> + strings = for token in tokens + [tag, value] = [token[0], token[1].toString().replace(/\n/, '\\n')] + "[#{tag} #{value}]" + puts strings.join(' ') + +# Use the [OptionParser module](optparse.html) to extract all options from +# `process.argv` that are specified in `SWITCHES`. +parseOptions = -> + optionParser = new optparse.OptionParser SWITCHES, BANNER + o = opts = optionParser.parse process.argv.slice 2 + o.compile or= !!o.output + o.run = not (o.compile or o.print or o.lint) + o.print = !! (o.print or (o.eval or o.stdio and o.compile)) + sources = o.arguments + +# The compile-time options to pass to the CoffeeScript compiler. +compileOptions = (fileName) -> {fileName, bare: opts.bare} + +# Print the `--help` usage message and exit. +usage = -> + puts optionParser.help() + process.exit 0 + +# Print the `--version` message and exit. +version = -> + puts "CoffeeScript version #{CoffeeScript.VERSION}" + process.exit 0 diff --git a/node_modules/jade/support/coffee-script/src/grammar.coffee b/node_modules/jade/support/coffee-script/src/grammar.coffee new file mode 100644 index 0000000..70f5632 --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/grammar.coffee @@ -0,0 +1,613 @@ +# The CoffeeScript parser is generated by [Jison](http://github.com/zaach/jison) +# from this grammar file. Jison is a bottom-up parser generator, similar in +# style to [Bison](http://www.gnu.org/software/bison), implemented in JavaScript. +# It can recognize [LALR(1), LR(0), SLR(1), and LR(1)](http://en.wikipedia.org/wiki/LR_grammar) +# type grammars. To create the Jison parser, we list the pattern to match +# on the left-hand side, and the action to take (usually the creation of syntax +# tree nodes) on the right. As the parser runs, it +# shifts tokens from our token stream, from left to right, and +# [attempts to match](http://en.wikipedia.org/wiki/Bottom-up_parsing) +# the token sequence against the rules below. When a match can be made, it +# reduces into the [nonterminal](http://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols) +# (the enclosing name at the top), and we proceed from there. +# +# If you run the `cake build:parser` command, Jison constructs a parse table +# from our rules and saves it into `lib/parser.js`. + +# The only dependency is on the **Jison.Parser**. +Parser = require('jison').Parser + +# Jison DSL +# --------- + +# Since we're going to be wrapped in a function by Jison in any case, if our +# action immediately returns a value, we can optimize by removing the function +# wrapper and just returning the value directly. +unwrap = /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/ + +# Our handy DSL for Jison grammar generation, thanks to +# [Tim Caswell](http://github.com/creationix). For every rule in the grammar, +# we pass the pattern-defining string, the action to run, and extra options, +# optionally. If no action is specified, we simply pass the value of the +# previous nonterminal. +o = (patternString, action, options) -> + return [patternString, '$$ = $1;', options] unless action + action = if match = (action + '').match(unwrap) then match[1] else "(#{action}())" + action = action.replace(/\bnew (\w+)\b/g, 'new yy.$1').replace(/Expressions\.wrap/g, 'yy.Expressions.wrap'); + [patternString, "$$ = #{action};", options] + +# Grammatical Rules +# ----------------- + +# In all of the rules that follow, you'll see the name of the nonterminal as +# the key to a list of alternative matches. With each match's action, the +# dollar-sign variables are provided by Jison as references to the value of +# their numeric position, so in this rule: +# +# "Expression UNLESS Expression" +# +# `$1` would be the value of the first `Expression`, `$2` would be the token +# for the `UNLESS` terminal, and `$3` would be the value of the second +# `Expression`. +grammar = + + # The **Root** is the top-level node in the syntax tree. Since we parse bottom-up, + # all parsing must end here. + Root: [ + o "", -> new Expressions + o "TERMINATOR", -> new Expressions + o "Body" + o "Block TERMINATOR" + ] + + # Any list of statements and expressions, seperated by line breaks or semicolons. + Body: [ + o "Line", -> Expressions.wrap [$1] + o "Body TERMINATOR Line", -> $1.push $3 + o "Body TERMINATOR" + ] + + # Expressions and statements, which make up a line in a body. + Line: [ + o "Expression" + o "Statement" + ] + + # Pure statements which cannot be expressions. + Statement: [ + o "Return" + o "Throw" + o "BREAK", -> new Literal $1 + o "CONTINUE", -> new Literal $1 + o "DEBUGGER", -> new Literal $1 + ] + + # All the different types of expressions in our language. The basic unit of + # CoffeeScript is the **Expression** -- everything that can be an expression + # is one. Expressions serve as the building blocks of many other rules, making + # them somewhat circular. + Expression: [ + o "Value" + o "Invocation" + o "Code" + o "Operation" + o "Assign" + o "If" + o "Try" + o "While" + o "For" + o "Switch" + o "Extends" + o "Class" + o "Existence" + o "Comment" + ] + + # An indented block of expressions. Note that the [Rewriter](rewriter.html) + # will convert some postfix forms into blocks for us, by adjusting the + # token stream. + Block: [ + o "INDENT Body OUTDENT", -> $2 + o "INDENT OUTDENT", -> new Expressions + o "TERMINATOR Comment", -> Expressions.wrap [$2] + ] + + # A literal identifier, a variable name or property. + Identifier: [ + o "IDENTIFIER", -> new Literal $1 + ] + + # Alphanumerics are separated from the other **Literal** matchers because + # they can also serve as keys in object literals. + AlphaNumeric: [ + o "NUMBER", -> new Literal $1 + o "STRING", -> new Literal $1 + ] + + # All of our immediate values. These can (in general), be passed straight + # through and printed to JavaScript. + Literal: [ + o "AlphaNumeric" + o "JS", -> new Literal $1 + o "REGEX", -> new Literal $1 + o "BOOL", -> new Literal $1 + ] + + # Assignment of a variable, property, or index to a value. + Assign: [ + o "Assignable = Expression", -> new Assign $1, $3 + o "Assignable = INDENT Expression OUTDENT", -> new Assign $1, $4 + ] + + # Assignment when it happens within an object literal. The difference from + # the ordinary **Assign** is that these allow numbers and strings as keys. + AssignObj: [ + o "Identifier", -> new Value $1 + o "AlphaNumeric" + o "ThisProperty" + o "Identifier : Expression", -> new Assign new Value($1), $3, 'object' + o "AlphaNumeric : Expression", -> new Assign new Value($1), $3, 'object' + o "Identifier : INDENT Expression OUTDENT", -> new Assign new Value($1), $4, 'object' + o "AlphaNumeric : INDENT Expression OUTDENT", -> new Assign new Value($1), $4, 'object' + o "Comment" + ] + + # A return statement from a function body. + Return: [ + o "RETURN Expression", -> new Return $2 + o "RETURN", -> new Return + ] + + # A block comment. + Comment: [ + o "HERECOMMENT", -> new Comment $1 + ] + + # [The existential operator](http://jashkenas.github.com/coffee-script/#existence). + Existence: [ + o "Expression ?", -> new Existence $1 + ] + + # The **Code** node is the function literal. It's defined by an indented block + # of **Expressions** preceded by a function arrow, with an optional parameter + # list. + Code: [ + o "PARAM_START ParamList PARAM_END FuncGlyph Block", -> new Code $2, $5, $4 + o "FuncGlyph Block", -> new Code [], $2, $1 + ] + + # CoffeeScript has two different symbols for functions. `->` is for ordinary + # functions, and `=>` is for functions bound to the current value of *this*. + FuncGlyph: [ + o "->", -> 'func' + o "=>", -> 'boundfunc' + ] + + # An optional, trailing comma. + OptComma: [ + o '' + o ',' + ] + + # The list of parameters that a function accepts can be of any length. + ParamList: [ + o "", -> [] + o "Param", -> [$1] + o "ParamList , Param", -> $1.concat $3 + ] + + # A single parameter in a function definition can be ordinary, or a splat + # that hoovers up the remaining arguments. + Param: [ + o "PARAM", -> new Literal $1 + o "@ PARAM", -> new Param $2, true + o "PARAM ...", -> new Param $1, false, true + o "@ PARAM ...", -> new Param $2, true, true + ] + + # A splat that occurs outside of a parameter list. + Splat: [ + o "Expression ...", -> new Splat $1 + ] + + # Variables and properties that can be assigned to. + SimpleAssignable: [ + o "Identifier", -> new Value $1 + o "Value Accessor", -> $1.push $2 + o "Invocation Accessor", -> new Value $1, [$2] + o "ThisProperty" + ] + + # Everything that can be assigned to. + Assignable: [ + o "SimpleAssignable" + o "Array", -> new Value $1 + o "Object", -> new Value $1 + ] + + # The types of things that can be treated as values -- assigned to, invoked + # as functions, indexed into, named as a class, etc. + Value: [ + o "Assignable" + o "Literal", -> new Value $1 + o "Parenthetical", -> new Value $1 + o "Range", -> new Value $1 + o "This" + ] + + # The general group of accessors into an object, by property, by prototype + # or by array index or slice. + Accessor: [ + o "PROPERTY_ACCESS Identifier", -> new Accessor $2 + o "PROTOTYPE_ACCESS Identifier", -> new Accessor $2, 'prototype' + o "::", -> new Accessor(new Literal('prototype')) + o "SOAK_ACCESS Identifier", -> new Accessor $2, 'soak' + o "Index" + o "Slice", -> new Slice $1 + ] + + # Indexing into an object or array using bracket notation. + Index: [ + o "INDEX_START Expression INDEX_END", -> new Index $2 + o "INDEX_SOAK Index", -> $2.soakNode = yes; $2 + o "INDEX_PROTO Index", -> $2.proto = yes; $2 + ] + + # In CoffeeScript, an object literal is simply a list of assignments. + Object: [ + o "{ AssignList OptComma }", -> new ObjectLiteral $2 + ] + + # Assignment of properties within an object literal can be separated by + # comma, as in JavaScript, or simply by newline. + AssignList: [ + o "", -> [] + o "AssignObj", -> [$1] + o "AssignList , AssignObj", -> $1.concat $3 + o "AssignList OptComma TERMINATOR AssignObj", -> $1.concat $4 + o "AssignList OptComma INDENT AssignList OptComma OUTDENT", -> $1.concat $4 + ] + + # Class definitions have optional bodies of prototype property assignments, + # and optional references to the superclass. + Class: [ + o "CLASS SimpleAssignable", -> new Class $2 + o "CLASS SimpleAssignable EXTENDS Value", -> new Class $2, $4 + o "CLASS SimpleAssignable INDENT ClassBody OUTDENT", -> new Class $2, null, $4 + o "CLASS SimpleAssignable EXTENDS Value INDENT ClassBody OUTDENT", -> new Class $2, $4, $6 + o "CLASS INDENT ClassBody OUTDENT", -> new Class '__temp__', null, $3 + o "CLASS", -> new Class '__temp__', null, new Expressions + o "CLASS EXTENDS Value", -> new Class '__temp__', $3, new Expressions + o "CLASS EXTENDS Value INDENT ClassBody OUTDENT", -> new Class '__temp__', $3, $5 + ] + + # Assignments that can happen directly inside a class declaration. + ClassAssign: [ + o "AssignObj", -> $1 + o "ThisProperty : Expression", -> new Assign new Value($1), $3, 'this' + o "ThisProperty : INDENT Expression OUTDENT", -> new Assign new Value($1), $4, 'this' + ] + + # A list of assignments to a class. + ClassBody: [ + o "", -> [] + o "ClassAssign", -> [$1] + o "ClassBody TERMINATOR ClassAssign", -> $1.concat $3 + o "{ ClassBody }", -> $2 + ] + + # Extending an object by setting its prototype chain to reference a parent + # object. + Extends: [ + o "SimpleAssignable EXTENDS Value", -> new Extends $1, $3 + ] + + # Ordinary function invocation, or a chained series of calls. + Invocation: [ + o "Value OptFuncExist Arguments", -> new Call $1, $3, $2 + o "Invocation OptFuncExist Arguments", -> new Call $1, $3, $2 + o "SUPER", -> new Call 'super', [new Splat(new Literal('arguments'))] + o "SUPER Arguments", -> new Call 'super', $2 + ] + + # An optional existence check on a function. + OptFuncExist: [ + o "", -> no + o "FUNC_EXIST", -> yes + ] + + # The list of arguments to a function call. + Arguments: [ + o "CALL_START CALL_END", -> [] + o "CALL_START ArgList OptComma CALL_END", -> $2 + ] + + # A reference to the *this* current object. + This: [ + o "THIS", -> new Value new Literal 'this' + o "@", -> new Value new Literal 'this' + ] + + RangeDots: [ + o "..", -> 'inclusive' + o "...", -> 'exclusive' + ] + + # A reference to a property on *this*. + ThisProperty: [ + o "@ Identifier", -> new Value new Literal('this'), [new Accessor($2)], 'this' + ] + + # The CoffeeScript range literal. + Range: [ + o "[ Expression RangeDots Expression ]", -> new Range $2, $4, $3 + ] + + # The slice literal. + Slice: [ + o "INDEX_START Expression RangeDots Expression INDEX_END", -> new Range $2, $4, $3 + o "INDEX_START Expression RangeDots INDEX_END", -> new Range $2, null, $3 + o "INDEX_START RangeDots Expression INDEX_END", -> new Range null, $3, $2 + ] + + # The array literal. + Array: [ + o "[ ]", -> new ArrayLiteral [] + o "[ ArgList OptComma ]", -> new ArrayLiteral $2 + ] + + # The **ArgList** is both the list of objects passed into a function call, + # as well as the contents of an array literal + # (i.e. comma-separated expressions). Newlines work as well. + ArgList: [ + o "Arg", -> [$1] + o "ArgList , Arg", -> $1.concat $3 + o "ArgList OptComma TERMINATOR Arg", -> $1.concat $4 + o "INDENT ArgList OptComma OUTDENT", -> $2 + o "ArgList OptComma INDENT ArgList OptComma OUTDENT", -> $1.concat $4 + ] + + # Valid arguments are Expressions or Splats. + Arg: [ + o "Expression" + o "Splat" + ] + + # Just simple, comma-separated, required arguments (no fancy syntax). We need + # this to be separate from the **ArgList** for use in **Switch** blocks, where + # having the newlines wouldn't make sense. + SimpleArgs: [ + o "Expression" + o "SimpleArgs , Expression", -> [].concat $1, $3 + ] + + # The variants of *try/catch/finally* exception handling blocks. + Try: [ + o "TRY Block", -> new Try $2 + o "TRY Block Catch", -> new Try $2, $3[0], $3[1] + o "TRY Block FINALLY Block", -> new Try $2, null, null, $4 + o "TRY Block Catch FINALLY Block", -> new Try $2, $3[0], $3[1], $5 + ] + + # A catch clause names its error and runs a block of code. + Catch: [ + o "CATCH Identifier Block", -> [$2, $3] + ] + + # Throw an exception object. + Throw: [ + o "THROW Expression", -> new Throw $2 + ] + + # Parenthetical expressions. Note that the **Parenthetical** is a **Value**, + # not an **Expression**, so if you need to use an expression in a place + # where only values are accepted, wrapping it in parentheses will always do + # the trick. + Parenthetical: [ + o "( Expression )", -> new Parens $2 + o "( )", -> new Parens new Literal '' + ] + + # The condition portion of a while loop. + WhileSource: [ + o "WHILE Expression", -> new While $2 + o "WHILE Expression WHEN Expression", -> new While $2, guard: $4 + o "UNTIL Expression", -> new While $2, invert: true + o "UNTIL Expression WHEN Expression", -> new While $2, invert: true, guard: $4 + ] + + # The while loop can either be normal, with a block of expressions to execute, + # or postfix, with a single expression. There is no do..while. + While: [ + o "WhileSource Block", -> $1.addBody $2 + o "Statement WhileSource", -> $2.addBody Expressions.wrap [$1] + o "Expression WhileSource", -> $2.addBody Expressions.wrap [$1] + o "Loop", -> $1 + ] + + Loop: [ + o "LOOP Block", -> new While(new Literal 'true').addBody $2 + o "LOOP Expression", -> new While(new Literal 'true').addBody Expressions.wrap [$2] + ] + + # Array, object, and range comprehensions, at the most generic level. + # Comprehensions can either be normal, with a block of expressions to execute, + # or postfix, with a single expression. + For: [ + o "Statement ForBody", -> new For $1, $2, $2.vars[0], $2.vars[1] + o "Expression ForBody", -> new For $1, $2, $2.vars[0], $2.vars[1] + o "ForBody Block", -> new For $2, $1, $1.vars[0], $1.vars[1] + ] + + ForBody: [ + o "FOR Range", -> source: new Value($2), vars: [] + o "ForStart ForSource", -> $2.raw = $1.raw; $2.vars = $1; $2 + ] + + ForStart: [ + o "FOR ForVariables", -> $2 + o "FOR ALL ForVariables", -> $3.raw = true; $3 + ] + + # An array of all accepted values for a variable inside the loop. This + # enables support for pattern matching. + ForValue: [ + o "Identifier" + o "Array", -> new Value $1 + o "Object", -> new Value $1 + ] + + # An array or range comprehension has variables for the current element and + # (optional) reference to the current index. Or, *key, value*, in the case + # of object comprehensions. + ForVariables: [ + o "ForValue", -> [$1] + o "ForValue , ForValue", -> [$1, $3] + ] + + # The source of a comprehension is an array or object with an optional guard + # clause. If it's an array comprehension, you can also choose to step through + # in fixed-size increments. + ForSource: [ + o "FORIN Expression", -> source: $2 + o "FOROF Expression", -> source: $2, object: true + o "FORIN Expression WHEN Expression", -> source: $2, guard: $4 + o "FOROF Expression WHEN Expression", -> source: $2, guard: $4, object: true + o "FORIN Expression BY Expression", -> source: $2, step: $4 + o "FORIN Expression WHEN Expression BY Expression", -> source: $2, guard: $4, step: $6 + o "FORIN Expression BY Expression WHEN Expression", -> source: $2, step: $4, guard: $6 + ] + + Switch: [ + o "SWITCH Expression INDENT Whens OUTDENT", -> new Switch $2, $4 + o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> new Switch $2, $4, $6 + o "SWITCH INDENT Whens OUTDENT", -> new Switch null, $3 + o "SWITCH INDENT Whens ELSE Block OUTDENT", -> new Switch null, $3, $5 + ] + + Whens: [ + o "When" + o "Whens When", -> $1.concat $2 + ] + + # An individual **When** clause, with action. + When: [ + o "LEADING_WHEN SimpleArgs Block", -> [[$2, $3]] + o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> [[$2, $3]] + ] + + # The most basic form of *if* is a condition and an action. The following + # if-related rules are broken up along these lines in order to avoid + # ambiguity. + IfBlock: [ + o "IF Expression Block", -> new If $2, $3 + o "UNLESS Expression Block", -> new If $2, $3, invert: true + o "IfBlock ELSE IF Expression Block", -> $1.addElse new If $4, $5 + o "IfBlock ELSE Block", -> $1.addElse $3 + ] + + # The full complement of *if* expressions, including postfix one-liner + # *if* and *unless*. + If: [ + o "IfBlock" + o "Statement POST_IF Expression", -> new If $3, Expressions.wrap([$1]), statement: true + o "Expression POST_IF Expression", -> new If $3, Expressions.wrap([$1]), statement: true + o "Statement POST_UNLESS Expression", -> new If $3, Expressions.wrap([$1]), statement: true, invert: true + o "Expression POST_UNLESS Expression", -> new If $3, Expressions.wrap([$1]), statement: true, invert: true + ] + + # Arithmetic and logical operators, working on one or more operands. + # Here they are grouped by order of precedence. The actual precedence rules + # are defined at the bottom of the page. It would be shorter if we could + # combine most of these rules into a single generic *Operand OpSymbol Operand* + # -type rule, but in order to make the precedence binding possible, separate + # rules are necessary. + Operation: [ + o "UNARY Expression", -> new Op $1, $2 + o "- Expression", (-> new Op '-', $2), prec: 'UNARY' + o "+ Expression", (-> new Op '+', $2), prec: 'UNARY' + + o "-- SimpleAssignable", -> new Op '--', $2 + o "++ SimpleAssignable", -> new Op '++', $2 + o "SimpleAssignable --", -> new Op '--', $1, null, true + o "SimpleAssignable ++", -> new Op '++', $1, null, true + + o "Expression + Expression", -> new Op '+', $1, $3 + o "Expression - Expression", -> new Op '-', $1, $3 + o "Expression == Expression", -> new Op '==', $1, $3 + o "Expression != Expression", -> new Op '!=', $1, $3 + + o "Expression MATH Expression", -> new Op $2, $1, $3 + o "Expression SHIFT Expression", -> new Op $2, $1, $3 + o "Expression COMPARE Expression", -> new Op $2, $1, $3 + o "Expression LOGIC Expression", -> new Op $2, $1, $3 + o "SimpleAssignable COMPOUND_ASSIGN Expression", -> new Op $2, $1, $3 + o "SimpleAssignable COMPOUND_ASSIGN INDENT Expression OUTDENT", -> new Op $2, $1, $4 + + o "Expression RELATION Expression", -> + if $2.charAt(0) is '!' + if $2 is '!in' + new Op '!', new In $1, $3 + else + new Op '!', new Parens new Op $2.slice(1), $1, $3 + else + if $2 is 'in' then new In $1, $3 else new Op $2, $1, $3 + ] + + +# Precedence +# ---------- + +# Operators at the top of this list have higher precedence than the ones lower +# down. Following these rules is what makes `2 + 3 * 4` parse as: +# +# 2 + (3 * 4) +# +# And not: +# +# (2 + 3) * 4 +operators = [ + ["left", 'CALL_START', 'CALL_END'] + ["nonassoc", '++', '--'] + ["left", '?'] + ["right", 'UNARY'] + ["left", 'MATH'] + ["left", '+', '-'] + ["left", 'SHIFT'] + ["left", 'COMPARE'] + ["left", 'RELATION'] + ["left", '==', '!='] + ["left", 'LOGIC'] + ["right", 'COMPOUND_ASSIGN'] + ["left", '.'] + ["nonassoc", 'INDENT', 'OUTDENT'] + ["right", 'WHEN', 'LEADING_WHEN', 'FORIN', 'FOROF', 'BY', 'THROW'] + ["right", 'IF', 'UNLESS', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'EXTENDS'] + ["right", '=', ':', 'RETURN'] + ["right", '->', '=>', 'UNLESS', 'POST_IF', 'POST_UNLESS'] +] + +# Wrapping Up +# ----------- + +# Finally, now what we have our **grammar** and our **operators**, we can create +# our **Jison.Parser**. We do this by processing all of our rules, recording all +# terminals (every symbol which does not appear as the name of a rule above) +# as "tokens". +tokens = [] +for name, alternatives of grammar + grammar[name] = for alt in alternatives + for token in alt[0].split ' ' + tokens.push token unless grammar[token] + alt[1] = "return #{alt[1]}" if name is 'Root' + alt + +# Initialize the **Parser** with our list of terminal **tokens**, our **grammar** +# rules, and the name of the root. Reverse the operators because Jison orders +# precedence from low to high, and we have it high to low +# (as in [Yacc](http://dinosaur.compilertools.net/yacc/index.html)). +exports.parser = new Parser + tokens: tokens.join ' ' + bnf: grammar + operators: operators.reverse() + startSymbol: 'Root' diff --git a/node_modules/jade/support/coffee-script/src/helpers.coffee b/node_modules/jade/support/coffee-script/src/helpers.coffee new file mode 100644 index 0000000..4d201de --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/helpers.coffee @@ -0,0 +1,72 @@ +# This file contains the common helper functions that we'd like to share among +# the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten +# arrays, count characters, that sort of thing. + +# Cross-engine `indexOf`, so that JScript can join the party. Use SpiderMonkey's +# functional-style `indexOf`, if it's available. +indexOf = exports.indexOf = Array.indexOf or + if Array::indexOf + (array, item, from) -> array.indexOf item, from + else + (array, item, from) -> + for other, index in array + if other is item and (not from or from <= index) + return index + -1 + +# Does a list include a value? +exports.include = (list, value) -> + indexOf(list, value) >= 0 + +# Peek at the beginning of a given string to see if it matches a sequence. +exports.starts = (string, literal, start) -> + literal is string.substr start, literal.length + +# Peek at the end of a given string to see if it matches a sequence. +exports.ends = (string, literal, back) -> + len = literal.length + literal is string.substr string.length - len - (back or 0), len + +# Trim out all falsy values from an array. +exports.compact = (array) -> + item for item in array when item + +# Count the number of occurences of a character in a string. +exports.count = (string, letter) -> + num = pos = 0 + num++ while pos = 1 + string.indexOf letter, pos + num + +# Merge objects, returning a fresh copy with attributes from both sides. +# Used every time `Base#compile` is called, to allow properties in the +# options hash to propagate down the tree without polluting other branches. +exports.merge = (options, overrides) -> + extend (extend {}, options), overrides + +# Extend a source object with the properties of another object (shallow copy). +# We use this to simulate Node's deprecated `process.mixin`. +extend = exports.extend = (object, properties) -> + for all key, val of properties + object[key] = val + object + +# Return a flattened version of an array. +# Handy for getting a list of `children` from the nodes. +exports.flatten = flatten = (array) -> + flattened = [] + for element in array + if element instanceof Array + flattened = flattened.concat flatten element + else + flattened.push element + flattened + +# Delete a key from an object, returning the value. Useful when a node is +# looking for a particular method in an options hash. +exports.del = (obj, key) -> + val = obj[key] + delete obj[key] + val + +# Gets the last item of an array(-like) object. +exports.last = (array, back) -> array[array.length - (back or 0) - 1] diff --git a/node_modules/jade/support/coffee-script/src/index.coffee b/node_modules/jade/support/coffee-script/src/index.coffee new file mode 100644 index 0000000..220f4e2 --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/index.coffee @@ -0,0 +1,2 @@ +# Loader for CoffeeScript as a Node.js library. +(exports[key] = val) for key, val of require './coffee-script' \ No newline at end of file diff --git a/node_modules/jade/support/coffee-script/src/lexer.coffee b/node_modules/jade/support/coffee-script/src/lexer.coffee new file mode 100644 index 0000000..0362eeb --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/lexer.coffee @@ -0,0 +1,635 @@ +# The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt +# matches against the beginning of the source code. When a match is found, +# a token is produced, we consume the match, and start again. Tokens are in the +# form: +# +# [tag, value, lineNumber] +# +# Which is a format that can be fed directly into [Jison](http://github.com/zaach/jison). + +{Rewriter} = require './rewriter' + +# Import the helpers we need. +{include, count, starts, compact, last} = require './helpers' + +# The Lexer Class +# --------------- + +# The Lexer class reads a stream of CoffeeScript and divvys it up into tagged +# tokens. Some potential ambiguity in the grammar has been avoided by +# pushing some extra smarts into the Lexer. +exports.Lexer = class Lexer + + # **tokenize** is the Lexer's main method. Scan by attempting to match tokens + # one at a time, using a regular expression anchored at the start of the + # remaining code, or a custom recursive token-matching method + # (for interpolations). When the next token has been recorded, we move forward + # within the code past the token, and begin again. + # + # Each tokenizing method is responsible for incrementing `@i` by the number of + # characters it has consumed. `@i` can be thought of as our finger on the page + # of source. + # + # Before returning the token stream, run it through the [Rewriter](rewriter.html) + # unless explicitly asked not to. + tokenize: (code, options) -> + code = code.replace(/\r/g, '').replace TRAILING_SPACES, '' + o = options or {} + @code = code # The remainder of the source code. + @i = 0 # Current character position we're parsing. + @line = o.line or 0 # The current line. + @indent = 0 # The current indentation level. + @indebt = 0 # The over-indentation at the current level. + @outdebt = 0 # The under-outdentation at the current level. + @seenFor = no # The flag for distinguishing FORIN/FOROF from IN/OF. + @indents = [] # The stack of all current indentation levels. + @tokens = [] # Stream of parsed tokens in the form ['TYPE', value, line] + # At every position, run through this list of attempted matches, + # short-circuiting if any of them succeed. Their order determines precedence: + # `@literalToken` is the fallback catch-all. + while @chunk = code.slice @i + @identifierToken() or + @commentToken() or + @whitespaceToken() or + @lineToken() or + @heredocToken() or + @stringToken() or + @numberToken() or + @regexToken() or + @jsToken() or + @literalToken() + @closeIndentation() + return @tokens if o.rewrite is off + (new Rewriter).rewrite @tokens + + # Tokenizers + # ---------- + + # Matches identifying literals: variables, keywords, method names, etc. + # Check to ensure that JavaScript reserved words aren't being used as + # identifiers. Because CoffeeScript reserves a handful of keywords that are + # allowed in JavaScript, we're careful not to tag them as keywords when + # referenced as property names here, so you can still do `jQuery.is()` even + # though `is` means `===` otherwise. + identifierToken: -> + return false unless match = IDENTIFIER.exec @chunk + [input, id, colon] = match + @i += input.length + if id is 'all' and @tag() is 'FOR' + @token 'ALL', id + return true + forcedIdentifier = colon or @tagAccessor() + tag = 'IDENTIFIER' + if include(JS_KEYWORDS, id) or + not forcedIdentifier and include(COFFEE_KEYWORDS, id) + tag = id.toUpperCase() + if tag is 'WHEN' and include LINE_BREAK, @tag() + tag = 'LEADING_WHEN' + else if tag is 'FOR' + @seenFor = yes + else if include UNARY, tag + tag = 'UNARY' + else if include RELATION, tag + if tag isnt 'INSTANCEOF' and @seenFor + @seenFor = no + tag = 'FOR' + tag + else + tag = 'RELATION' + if @value() is '!' + @tokens.pop() + id = '!' + id + if include JS_FORBIDDEN, id + if forcedIdentifier + tag = 'IDENTIFIER' + id = new String id + id.reserved = yes + else if include RESERVED, id + @identifierError id + unless forcedIdentifier + tag = id = COFFEE_ALIASES[id] if COFFEE_ALIASES.hasOwnProperty id + if id is '!' + tag = 'UNARY' + else if include LOGIC, id + tag = 'LOGIC' + else if include BOOL, tag + id = tag.toLowerCase() + tag = 'BOOL' + @token tag, id + @token ':', ':' if colon + true + + # Matches numbers, including decimals, hex, and exponential notation. + # Be careful not to interfere with ranges-in-progress. + numberToken: -> + return false unless match = NUMBER.exec @chunk + number = match[0] + return false if @tag() is '.' and number.charAt(0) is '.' + @i += number.length + @token 'NUMBER', number + true + + # Matches strings, including multi-line strings. Ensures that quotation marks + # are balanced within the string's contents, and within nested interpolations. + stringToken: -> + switch @chunk.charAt 0 + when "'" + return false unless match = SIMPLESTR.exec @chunk + @token 'STRING', (string = match[0]).replace MULTILINER, '\\\n' + when '"' + return false unless string = @balancedString @chunk, [['"', '"'], ['#{', '}']] + if 0 < string.indexOf '#{', 1 + @interpolateString string.slice 1, -1 + else + @token 'STRING', @escapeLines string + else + return false + @line += count string, '\n' + @i += string.length + true + + # Matches heredocs, adjusting indentation to the correct level, as heredocs + # preserve whitespace, but ignore indentation to the left. + heredocToken: -> + return false unless match = HEREDOC.exec @chunk + heredoc = match[0] + quote = heredoc.charAt 0 + doc = @sanitizeHeredoc match[2], {quote, indent: null} + if quote is '"' and 0 <= doc.indexOf '#{' + @interpolateString doc, heredoc: yes + else + @token 'STRING', @makeString doc, quote, yes + @line += count heredoc, '\n' + @i += heredoc.length + true + + # Matches and consumes comments. + commentToken: -> + return false unless match = @chunk.match COMMENT + [comment, here] = match + @line += count comment, '\n' + @i += comment.length + if here + @token 'HERECOMMENT', @sanitizeHeredoc here, + herecomment: true, indent: Array(@indent + 1).join(' ') + @token 'TERMINATOR', '\n' + true + + # Matches JavaScript interpolated directly into the source via backticks. + jsToken: -> + return false unless @chunk.charAt(0) is '`' and match = JSTOKEN.exec @chunk + @token 'JS', (script = match[0]).slice 1, -1 + @i += script.length + true + + # Matches regular expression literals. Lexing regular expressions is difficult + # to distinguish from division, so we borrow some basic heuristics from + # JavaScript and Ruby. + regexToken: -> + return false if @chunk.charAt(0) isnt '/' + return @heregexToken match if match = HEREGEX.exec @chunk + return false if include NOT_REGEX, @tag() + return false unless match = REGEX.exec @chunk + [regex] = match + @token 'REGEX', if regex is '//' then '/(?:)/' else regex + @i += regex.length + true + + # Matches experimental, multiline and extended regular expression literals. + heregexToken: (match) -> + [heregex, body, flags] = match + @i += heregex.length + if 0 > body.indexOf '#{' + re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/') + @token 'REGEX', "/#{ re or '(?:)' }/#{flags}" + return true + @token 'IDENTIFIER', 'RegExp' + @tokens.push ['CALL_START', '('] + tokens = [] + for [tag, value] in @interpolateString(body, regex: yes) + if tag is 'TOKENS' + tokens.push value... + else + continue unless value = value.replace HEREGEX_OMIT, '' + value = value.replace /\\/g, '\\\\' + tokens.push ['STRING', @makeString(value, '"', yes)] + tokens.push ['+', '+'] + tokens.pop() + @tokens.push ['STRING', '""'], ['+', '+'] unless tokens[0]?[0] is 'STRING' + @tokens.push tokens... + @tokens.push [',', ','], ['STRING', '"' + flags + '"'] if flags + @token ')', ')' + true + + # Matches newlines, indents, and outdents, and determines which is which. + # If we can detect that the current line is continued onto the the next line, + # then the newline is suppressed: + # + # elements + # .each( ... ) + # .map( ... ) + # + # Keeps track of the level of indentation, because a single outdent token + # can close multiple indents, so we need to know how far in we happen to be. + lineToken: -> + return false unless match = MULTI_DENT.exec @chunk + indent = match[0] + @line += count indent, '\n' + @i += indent.length + prev = last @tokens, 1 + size = indent.length - 1 - indent.lastIndexOf '\n' + nextCharacter = NEXT_CHARACTER.exec(@chunk)[1] + noNewlines = (nextCharacter in ['.', ','] and not NEXT_ELLIPSIS.test(@chunk)) or @unfinished() + if size - @indebt is @indent + return @suppressNewlines() if noNewlines + return @newlineToken indent + else if size > @indent + if noNewlines + @indebt = size - @indent + return @suppressNewlines() + diff = size - @indent + @outdebt + @token 'INDENT', diff + @indents.push diff + @outdebt = @indebt = 0 + else + @indebt = 0 + @outdentToken @indent - size, noNewlines + @indent = size + true + + # Record an outdent token or multiple tokens, if we happen to be moving back + # inwards past several recorded indents. + outdentToken: (moveOut, noNewlines, close) -> + while moveOut > 0 + len = @indents.length - 1 + if @indents[len] is undefined + moveOut = 0 + else if @indents[len] is @outdebt + moveOut -= @outdebt + @outdebt = 0 + else if @indents[len] < @outdebt + @outdebt -= @indents[len] + moveOut -= @indents[len] + else + dent = @indents.pop() - @outdebt + moveOut -= dent + @outdebt = 0 + @token 'OUTDENT', dent + @outdebt -= moveOut if dent + @token 'TERMINATOR', '\n' unless @tag() is 'TERMINATOR' or noNewlines + true + + # Matches and consumes non-meaningful whitespace. Tag the previous token + # as being "spaced", because there are some cases where it makes a difference. + whitespaceToken: -> + return false unless match = WHITESPACE.exec @chunk + prev = last @tokens + prev.spaced = true if prev + @i += match[0].length + true + + # Generate a newline token. Consecutive newlines get merged together. + newlineToken: (newlines) -> + @token 'TERMINATOR', '\n' unless @tag() is 'TERMINATOR' + true + + # Use a `\` at a line-ending to suppress the newline. + # The slash is removed here once its job is done. + suppressNewlines: -> + @tokens.pop() if @value() is '\\' + true + + # We treat all other single characters as a token. Eg.: `( ) , . !` + # Multi-character operators are also literal tokens, so that Jison can assign + # the proper order of operations. There are some symbols that we tag specially + # here. `;` and newlines are both treated as a `TERMINATOR`, we distinguish + # parentheses that indicate a method call from regular parentheses, and so on. + literalToken: -> + if match = OPERATOR.exec @chunk + [value] = match + @tagParameters() if CODE.test value + else + value = @chunk.charAt 0 + @i += value.length + tag = value + prev = last @tokens + if value is '=' and prev + @assignmentError() if not prev[1].reserved and include JS_FORBIDDEN, prev[1] + if prev[1] in ['||', '&&'] + prev[0] = 'COMPOUND_ASSIGN' + prev[1] += '=' + return true + if ';' is value then tag = 'TERMINATOR' + else if include LOGIC , value then tag = 'LOGIC' + else if include MATH , value then tag = 'MATH' + else if include COMPARE , value then tag = 'COMPARE' + else if include COMPOUND_ASSIGN, value then tag = 'COMPOUND_ASSIGN' + else if include UNARY , value then tag = 'UNARY' + else if include SHIFT , value then tag = 'SHIFT' + else if value is '?' and prev?.spaced then tag = 'LOGIC' + else if prev and not prev.spaced + if value is '(' and include CALLABLE, prev[0] + prev[0] = 'FUNC_EXIST' if prev[0] is '?' + tag = 'CALL_START' + else if value is '[' and include INDEXABLE, prev[0] + tag = 'INDEX_START' + switch prev[0] + when '?' then prev[0] = 'INDEX_SOAK' + when '::' then prev[0] = 'INDEX_PROTO' + @token tag, value + true + + # Token Manipulators + # ------------------ + + # As we consume a new `IDENTIFIER`, look at the previous token to determine + # if it's a special kind of accessor. Return `true` if any type of accessor + # is the previous token. + tagAccessor: -> + return false if not (prev = last @tokens) or prev.spaced + if prev[1] is '::' + @tag 0, 'PROTOTYPE_ACCESS' + else if prev[1] is '.' and @value(1) isnt '.' + if @tag(1) is '?' + @tag 0, 'SOAK_ACCESS' + @tokens.splice(-2, 1) + else + @tag 0, 'PROPERTY_ACCESS' + else + return prev[0] is '@' + true + + # Sanitize a heredoc or herecomment by + # erasing all external indentation on the left-hand side. + sanitizeHeredoc: (doc, options) -> + {indent, herecomment} = options + return doc if herecomment and 0 > doc.indexOf '\n' + unless herecomment + while match = HEREDOC_INDENT.exec doc + attempt = match[1] + indent = attempt if indent is null or 0 < attempt.length < indent.length + doc = doc.replace /// \n #{indent} ///g, '\n' if indent + doc = doc.replace /^\n/, '' unless herecomment + doc + + # A source of ambiguity in our grammar used to be parameter lists in function + # definitions versus argument lists in function calls. Walk backwards, tagging + # parameters specially in order to make things easier for the parser. + tagParameters: -> + return if @tag() isnt ')' + i = @tokens.length + while tok = @tokens[--i] + switch tok[0] + when 'IDENTIFIER' then tok[0] = 'PARAM' + when ')' then tok[0] = 'PARAM_END' + when '(', 'CALL_START' then tok[0] = 'PARAM_START'; return true + true + + # Close up all remaining open blocks at the end of the file. + closeIndentation: -> + @outdentToken @indent + + # The error for when you try to use a forbidden word in JavaScript as + # an identifier. + identifierError: (word) -> + throw SyntaxError "Reserved word \"#{word}\" on line #{@line + 1}" + + # The error for when you try to assign to a reserved word in JavaScript, + # like "function" or "default". + assignmentError: -> + throw SyntaxError "Reserved word \"#{@value()}\" on line #{@line + 1} can't be assigned" + + # Matches a balanced group such as a single or double-quoted string. Pass in + # a series of delimiters, all of which must be nested correctly within the + # contents of the string. This method allows us to have strings within + # interpolations within strings, ad infinitum. + balancedString: (str, delimited, options) -> + options or= {} + levels = [] + i = 0 + slen = str.length + while i < slen + if levels.length and str.charAt(i) is '\\' + i += 1 + else + for pair in delimited + [open, close] = pair + if levels.length and starts(str, close, i) and last(levels) is pair + levels.pop() + i += close.length - 1 + i += 1 unless levels.length + break + if starts str, open, i + levels.push(pair) + i += open.length - 1 + break + break if not levels.length + i += 1 + if levels.length + throw SyntaxError "Unterminated #{levels.pop()[0]} starting on line #{@line + 1}" + if not i then false else str[0...i] + + # Expand variables and expressions inside double-quoted strings using + # Ruby-like notation for substitution of arbitrary expressions. + # + # "Hello #{name.capitalize()}." + # + # If it encounters an interpolation, this method will recursively create a + # new Lexer, tokenize the interpolated contents, and merge them into the + # token stream. + interpolateString: (str, options) -> + {heredoc, regex} = options or= {} + tokens = [] + pi = 0 + i = -1 + while letter = str.charAt i += 1 + if letter is '\\' + i += 1 + continue + unless letter is '#' and str.charAt(i+1) is '{' and + (expr = @balancedString str.slice(i+1), [['{', '}']]) + continue + tokens.push ['TO_BE_STRING', str.slice(pi, i)] if pi < i + inner = expr.slice(1, -1).replace(LEADING_SPACES, '').replace(TRAILING_SPACES, '') + if inner.length + nested = new Lexer().tokenize inner, line: @line, rewrite: off + nested.pop() + if nested.length > 1 + nested.unshift ['(', '('] + nested.push [')', ')'] + tokens.push ['TOKENS', nested] + i += expr.length + pi = i + 1 + tokens.push ['TO_BE_STRING', str.slice pi] if i > pi < str.length + return tokens if regex + return @token 'STRING', '""' unless tokens.length + tokens.unshift ['', ''] unless tokens[0][0] is 'TO_BE_STRING' + @token '(', '(' if interpolated = tokens.length > 1 + for [tag, value], i in tokens + @token '+', '+' if i + if tag is 'TOKENS' + @tokens.push value... + else + @token 'STRING', @makeString value, '"', heredoc + @token ')', ')' if interpolated + tokens + + # Helpers + # ------- + + # Add a token to the results, taking note of the line number. + token: (tag, value) -> + @tokens.push [tag, value, @line] + + # Peek at a tag/value in the current token stream. + tag : (index, tag) -> + (tok = last @tokens, index) and if tag? then tok[0] = tag else tok[0] + value: (index, val) -> + (tok = last @tokens, index) and if val? then tok[1] = val else tok[1] + + # Are we in the midst of an unfinished expression? + unfinished: -> + (prev = last @tokens, 1) and prev[0] isnt '.' and + (value = @value()) and not value.reserved and + NO_NEWLINE.test(value) and not CODE.test(value) and not ASSIGNED.test(@chunk) + + # Converts newlines for string literals. + escapeLines: (str, heredoc) -> + str.replace MULTILINER, if heredoc then '\\n' else '' + + # Constructs a string token by escaping quotes and newlines. + makeString: (body, quote, heredoc) -> + return quote + quote unless body + body = body.replace /\\([\s\S])/g, (match, contents) -> + if contents in ['\n', quote] then contents else match + body = body.replace /// #{quote} ///g, '\\$&' + quote + @escapeLines(body, heredoc) + quote + +# Constants +# --------- + +# Keywords that CoffeeScript shares in common with JavaScript. +JS_KEYWORDS = [ + 'true', 'false', 'null', 'this' + 'new', 'delete', 'typeof', 'in', 'instanceof' + 'return', 'throw', 'break', 'continue', 'debugger' + 'if', 'else', 'switch', 'for', 'while', 'try', 'catch', 'finally' + 'class', 'extends', 'super' +] + +# CoffeeScript-only keywords. +COFFEE_KEYWORDS = ['then', 'unless', 'until', 'loop', 'of', 'by', 'when'] +COFFEE_KEYWORDS.push op for all op of COFFEE_ALIASES = + and : '&&' + or : '||' + is : '==' + isnt : '!=' + not : '!' + yes : 'TRUE' + no : 'FALSE' + on : 'TRUE' + off : 'FALSE' + +# The list of keywords that are reserved by JavaScript, but not used, or are +# used by CoffeeScript internally. We throw an error when these are encountered, +# to avoid having a JavaScript error at runtime. +RESERVED = [ + 'case', 'default', 'do', 'function', 'var', 'void', 'with' + 'const', 'let', 'enum', 'export', 'import', 'native' + '__hasProp', '__extends', '__slice' +] + +# The superset of both JavaScript keywords and reserved words, none of which may +# be used as identifiers or properties. +JS_FORBIDDEN = JS_KEYWORDS.concat RESERVED + +# Token matching regexes. +IDENTIFIER = /// ^ + ( [$A-Za-z_][$\w]* ) + ( [^\n\S]* : (?!:) )? # Is this a property name? +/// +NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i +HEREDOC = /^("""|''')([\s\S]*?)(?:\n[ \t]*)?\1/ +OPERATOR = /// ^ (?: -[-=>]? | \+[+=]? | \.\.\.? | [*&|/%=<>^:!?]+ ) /// +WHITESPACE = /^[ \t]+/ +COMMENT = /^###([^#][\s\S]*?)(?:###[ \t]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/ +CODE = /^[-=]>/ +MULTI_DENT = /^(?:\n[ \t]*)+/ +SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/ +JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/ + +# Regex-matching-regexes. +REGEX = /// ^ + / (?! \s ) # disallow leading whitespace + [^ [ / \n \\ ]* # every other thing + (?: + (?: \\[\s\S] # anything escaped + | \[ # character class + [^ \] \n \\ ]* + (?: \\[\s\S] [^ \] \n \\ ]* )* + ] + ) [^ [ / \n \\ ]* + )* + / [imgy]{0,4} (?![A-Za-z]) +/// +HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?![A-Za-z])/ +HEREGEX_OMIT = /\s+(?:#.*)?/g + +# Token cleaning regexes. +MULTILINER = /\n/g +HEREDOC_INDENT = /\n+([ \t]*)/g +ASSIGNED = /^\s*@?[$A-Za-z_][$\w]*[ \t]*?[:=][^:=>]/ +NEXT_CHARACTER = /^\s*(\S?)/ +NEXT_ELLIPSIS = /^\s*\.\.\.?/ +LEADING_SPACES = /^\s+/ +TRAILING_SPACES = /\s+$/ +NO_NEWLINE = /// ^ + (?: # non-capturing... + [-+*&|/%=<>!.\\][<>=&|]* | # symbol operators + and | or | is(?:nt)? | n(?:ot|ew) | # word operators + delete | typeof | instanceof + )$ +/// + + +# Compound assignment tokens. +COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='] + +# Unary tokens. +UNARY = ['UMINUS', 'UPLUS', '!', '!!', '~', 'NEW', 'TYPEOF', 'DELETE'] + +# Logical tokens. +LOGIC = ['&', '|', '^', '&&', '||'] + +# Bit-shifting tokens. +SHIFT = ['<<', '>>', '>>>'] + +# Comparison tokens. +COMPARE = ['<=', '<', '>', '>='] + +# Mathmatical tokens. +MATH = ['*', '/', '%'] + +# Relational tokens that are negatable with `not` prefix. +RELATION = ['IN', 'OF', 'INSTANCEOF'] + +# Boolean tokens. +BOOL = ['TRUE', 'FALSE', 'NULL'] + +# Tokens which a regular expression will never immediately follow, but which +# a division operator might. +# +# See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions +# +# Our list is shorter, due to sans-parentheses method calls. +NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', '++', '--', ']'] + +# Tokens which could legitimately be invoked or indexed. A opening +# parentheses or bracket following these tokens will be recorded as the start +# of a function invocation or indexing operation. +CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER'] +INDEXABLE = CALLABLE.concat 'NUMBER', 'BOOL' + +# Tokens that, when immediately preceding a `WHEN`, indicate that the `WHEN` +# occurs at the start of a line. We disambiguate these from trailing whens to +# avoid an ambiguity in the grammar. +LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR'] diff --git a/node_modules/jade/support/coffee-script/src/nodes.coffee b/node_modules/jade/support/coffee-script/src/nodes.coffee new file mode 100644 index 0000000..99e372a --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/nodes.coffee @@ -0,0 +1,1710 @@ +# `nodes.coffee` contains all of the node classes for the syntax tree. Most +# nodes are created as the result of actions in the [grammar](grammar.html), +# but some are created by other nodes as a method of code generation. To convert +# the syntax tree into a string of JavaScript code, call `compile()` on the root. + +{Scope} = require './scope' + +# Import the helpers we plan to use. +{compact, flatten, merge, del, include, starts, ends, last} = require './helpers' + +# Constant functions for nodes that don't need customization. +YES = -> yes +NO = -> no +THIS = -> this + +#### Base + +# The **Base** is the abstract base class for all nodes in the syntax tree. +# Each subclass implements the `compileNode` method, which performs the +# code generation for that node. To compile a node to JavaScript, +# call `compile` on it, which wraps `compileNode` in some generic extra smarts, +# to know when the generated code needs to be wrapped up in a closure. +# An options hash is passed and cloned throughout, containing information about +# the environment from higher in the tree (such as if a returned value is +# being requested by the surrounding function), information about the current +# scope, and indentation level. +exports.Base = class Base + + constructor: -> + @tags = {} + + # Common logic for determining whether to wrap this node in a closure before + # compiling it, or to compile directly. We need to wrap if this node is a + # *statement*, and it's not a *pureStatement*, and we're not at + # the top level of a block (which would be unnecessary), and we haven't + # already been asked to return the result (because statements know how to + # return results). + # + # If a Node is *topSensitive*, that means that it needs to compile differently + # depending on whether it's being used as part of a larger expression, or is a + # top-level statement within the function body. + compile: (o) -> + @options = if o then merge o else {} + @tab = o.indent + top = if @topSensitive() then @options.top else del @options, 'top' + closure = @isStatement(o) and not @isPureStatement() and not top and + not @options.asStatement and this not instanceof Comment + code = if closure then @compileClosure(@options) else @compileNode(@options) + code + + # Statements converted into expressions via closure-wrapping share a scope + # object with their parent closure, to preserve the expected lexical scope. + compileClosure: (o) -> + o.sharedScope = o.scope + throw new Error 'cannot include a pure statement in an expression.' if @containsPureStatement() + Closure.wrap(this).compile o + + # If the code generation wishes to use the result of a complex expression + # in multiple places, ensure that the expression is only ever evaluated once, + # by assigning it to a temporary variable. + compileReference: (o, options) -> + pair = unless @isComplex() + [this, this] + else + reference = new Literal o.scope.freeVariable 'ref' + compiled = new Assign reference, this + [compiled, reference] + (pair[i] = node.compile o) for node, i in pair if options?.precompile + pair + + # Convenience method to grab the current indentation level, plus tabbing in. + idt: (tabs) -> + idt = @tab or '' + num = (tabs or 0) + 1 + idt += TAB while num -= 1 + idt + + # Construct a node that returns the current node's result. + # Note that this is overridden for smarter behavior for + # many statement nodes (eg If, For)... + makeReturn: -> + new Return this + + # Does this node, or any of its children, contain a node of a certain kind? + # Recursively traverses down the *children* of the nodes, yielding to a block + # and returning true when the block finds a match. `contains` does not cross + # scope boundaries. + contains: (block) -> + contains = false + @traverseChildren false, (node) -> + if block(node) + contains = true + return false + contains + + # Is this node of a certain type, or does it contain the type? + containsType: (type) -> + this instanceof type or @contains (node) -> node instanceof type + + # Convenience for the most common use of contains. Does the node contain + # a pure statement? + containsPureStatement: -> + @isPureStatement() or @contains (node) -> node.isPureStatement() + + # Perform an in-order traversal of the AST. Crosses scope boundaries. + traverse: (block) -> @traverseChildren true, block + + # `toString` representation of the node, for inspecting the parse tree. + # This is what `coffee --nodes` prints out. + toString: (idt, override) -> + idt or= '' + children = (child.toString idt + TAB for child in @collectChildren()).join('') + klass = override or @constructor.name + if @soakNode then '?' else '' + '\n' + idt + klass + children + + eachChild: (func) -> + return unless @children + for attr in @children when this[attr] + for child in flatten [this[attr]] + return if func(child) is false + + collectChildren: -> + nodes = [] + @eachChild (node) -> nodes.push node + nodes + + traverseChildren: (crossScope, func) -> + @eachChild (child) -> + return false if func(child) is false + if crossScope or child not instanceof Code + child.traverseChildren crossScope, func + + invert: -> new Op '!', this + + # Default implementations of the common node properties and methods. Nodes + # will override these with custom logic, if needed. + children: [] + + unwrap : THIS + isStatement : NO + isPureStatement : NO + isComplex : YES + topSensitive : NO + unfoldSoak : NO + + # Is this node used to assign a certain variable? + assigns: NO + +#### Expressions + +# The expressions body is the list of expressions that forms the body of an +# indented block of code -- the implementation of a function, a clause in an +# `if`, `switch`, or `try`, and so on... +exports.Expressions = class Expressions extends Base + + children: ['expressions'] + isStatement: YES + + constructor: (nodes) -> + super() + @expressions = compact flatten nodes or [] + + # Tack an expression on to the end of this expression list. + push: (node) -> + @expressions.push(node) + this + + # Add an expression at the beginning of this expression list. + unshift: (node) -> + @expressions.unshift(node) + this + + # If this Expressions consists of just a single node, unwrap it by pulling + # it back out. + unwrap: -> + if @expressions.length is 1 then @expressions[0] else this + + # Is this an empty block of code? + empty: -> + @expressions.length is 0 + + # An Expressions node does not return its entire body, rather it + # ensures that the final expression is returned. + makeReturn: -> + end = @expressions[idx = @expressions.length - 1] + end = @expressions[idx -= 1] if end instanceof Comment + if end and end not instanceof Return + @expressions[idx] = end.makeReturn() + this + + # An **Expressions** is the only node that can serve as the root. + compile: (o) -> + o or= {} + if o.scope then super(o) else @compileRoot(o) + + compileNode: (o) -> + (@compileExpression node, merge o for node in @expressions).join '\n' + + # If we happen to be the top-level **Expressions**, wrap everything in + # a safety closure, unless requested not to. + # It would be better not to generate them in the first place, but for now, + # clean up obvious double-parentheses. + compileRoot: (o) -> + o.indent = @tab = if o.bare then '' else TAB + o.scope = new Scope null, this, null + code = @compileWithDeclarations o + code = code.replace TRAILING_WHITESPACE, '' + if o.bare then code else "(function() {\n#{code}\n}).call(this);\n" + + # Compile the expressions body for the contents of a function, with + # declarations of all inner variables pushed up to the top. + compileWithDeclarations: (o) -> + code = @compileNode(o) + if o.scope.hasAssignments this + code = "#{@tab}var #{ o.scope.compiledAssignments().replace /\n/g, '$&' + @tab };\n#{code}" + if not o.globals and o.scope.hasDeclarations this + code = "#{@tab}var #{o.scope.compiledDeclarations()};\n#{code}" + code + + # Compiles a single expression within the expressions body. If we need to + # return the result, and it's an expression, simply return it. If it's a + # statement, ask the statement to do so. + compileExpression: (node, o) -> + @tab = o.indent + node.tags.front = true + compiledNode = node.compile merge o, top: true + if node.isStatement(o) then compiledNode else "#{@idt()}#{compiledNode};" + +# Wrap up the given nodes as an **Expressions**, unless it already happens +# to be one. +Expressions.wrap = (nodes) -> + return nodes[0] if nodes.length is 1 and nodes[0] instanceof Expressions + new Expressions(nodes) + +#### Literal + +# Literals are static values that can be passed through directly into +# JavaScript without translation, such as: strings, numbers, +# `true`, `false`, `null`... +exports.Literal = class Literal extends Base + + constructor: (@value) -> + super() + + makeReturn: -> + if @isStatement() then this else super() + + # Break and continue must be treated as pure statements -- they lose their + # meaning when wrapped in a closure. + isStatement: -> + @value in ['break', 'continue', 'debugger'] + isPureStatement: Literal::isStatement + + isComplex: NO + + isReserved: -> + !!@value.reserved + + assigns: (name) -> name is @value + + compileNode: (o) -> + idt = if @isStatement(o) then @idt() else '' + end = if @isStatement(o) then ';' else '' + val = if @isReserved() then "\"#{@value}\"" else @value + idt + val + end + + toString: -> ' "' + @value + '"' + +#### Return + +# A `return` is a *pureStatement* -- wrapping it in a closure wouldn't +# make sense. +exports.Return = class Return extends Base + + isStatement: YES + isPureStatement: YES + children: ['expression'] + + constructor: (@expression) -> + super() + + makeReturn: THIS + + compile: (o) -> + expr = @expression?.makeReturn() + return expr.compile o if expr and (expr not instanceof Return) + super o + + compileNode: (o) -> + expr = '' + if @expression + o.asStatement = true if @expression.isStatement(o) + expr = ' ' + @expression.compile(o) + "#{@tab}return#{expr};" + +#### Value + +# A value, variable or literal or parenthesized, indexed or dotted into, +# or vanilla. +exports.Value = class Value extends Base + + children: ['base', 'properties'] + + # A **Value** has a base and a list of property accesses. + constructor: (@base, @properties, tag) -> + super() + @properties or= [] + @tags[tag] = yes if tag + + # Add a property access to the list. + push: (prop) -> + @properties.push(prop) + this + + hasProperties: -> + !!@properties.length + + # Some boolean checks for the benefit of other nodes. + + isArray: -> + @base instanceof ArrayLiteral and not @properties.length + + isObject: -> + @base instanceof ObjectLiteral and not @properties.length + + isSplice: -> + last(@properties) instanceof Slice + + isComplex: -> + @base.isComplex() or @hasProperties() + + assigns: (name) -> + not @properties.length and @base.assigns name + + makeReturn: -> + if @properties.length then super() else @base.makeReturn() + + + # The value can be unwrapped as its inner node, if there are no attached + # properties. + unwrap: -> + if @properties.length then this else @base + + # Values are considered to be statements if their base is a statement. + isStatement: (o) -> + @base.isStatement(o) and not @properties.length + + isSimpleNumber: -> + @base instanceof Literal and SIMPLENUM.test @base.value + + # A reference has base part (`this` value) and name part. + # We cache them separately for compiling complex expressions. + # `a()[b()] ?= c` -> `(_base = a())[_name = b()] ? _base[_name] = c` + cacheReference: (o) -> + name = last @properties + if not @base.isComplex() and @properties.length < 2 and + not name?.isComplex() + return [this, this] # `a` `a.b` + base = new Value @base, @properties.slice 0, -1 + if base.isComplex() # `a().b` + bref = new Literal o.scope.freeVariable 'base' + base = new Value new Parens new Assign bref, base + return [base, bref] unless name # `a()` + if name.isComplex() # `a[b()]` + nref = new Literal o.scope.freeVariable 'name' + name = new Index new Assign nref, name.index + nref = new Index nref + [base.push(name), new Value(bref or base.base, [nref or name])] + + # Override compile to unwrap the value when possible. + compile: (o) -> + @base.tags.front = @tags.front + if not o.top or @properties.length then super(o) else @base.compile(o) + + # We compile a value to JavaScript by compiling and joining each property. + # Things get much more insteresting if the chain of properties has *soak* + # operators `?.` interspersed. Then we have to take care not to accidentally + # evaluate a anything twice when building the soak chain. + compileNode: (o) -> + return ifn.compile o if ifn = @unfoldSoak o + props = @properties + @base.parenthetical = yes if @parenthetical and not props.length + code = @base.compile o + code = "(#{code})" if props[0] instanceof Accessor and @isSimpleNumber() + (code += prop.compile o) for prop in props + return code + + # Unfold a soak into an `If`: `a?.b` -> `a.b if a?` + unfoldSoak: (o) -> + if ifn = @base.unfoldSoak o + Array::push.apply ifn.body.properties, @properties + return ifn + for prop, i in @properties when prop.soakNode + prop.soakNode = off + fst = new Value @base, @properties.slice 0, i + snd = new Value @base, @properties.slice i + if fst.isComplex() + ref = new Literal o.scope.freeVariable 'ref' + fst = new Parens new Assign ref, fst + snd.base = ref + ifn = new If new Existence(fst), snd, soak: yes + return ifn + null + +#### Comment + +# CoffeeScript passes through block comments as JavaScript block comments +# at the same position. +exports.Comment = class Comment extends Base + + isStatement: YES + + constructor: (@comment) -> + super() + + makeReturn: THIS + + compileNode: (o) -> + @tab + '/*' + @comment.replace(/\n/g, '\n' + @tab) + '*/' + +#### Call + +# Node for a function invocation. Takes care of converting `super()` calls into +# calls against the prototype's function of the same name. +exports.Call = class Call extends Base + + children: ['variable', 'args'] + + constructor: (variable, @args, @soakNode) -> + super() + @isNew = false + @isSuper = variable is 'super' + @variable = if @isSuper then null else variable + @args or= [] + + compileSplatArguments: (o) -> + Splat.compileSplattedArray @args, o + + # Tag this invocation as creating a new instance. + newInstance: -> + @isNew = true + this + + prefix: -> + if @isNew then 'new ' else '' + + # Grab the reference to the superclass' implementation of the current method. + superReference: (o) -> + {method} = o.scope + throw Error "cannot call super outside of a function." unless method + {name} = method + throw Error "cannot call super on an anonymous function." unless name + if method.klass + "#{method.klass}.__super__.#{name}" + else + "#{name}.__super__.constructor" + + # Soaked chained invocations unfold into if/else ternary structures. + unfoldSoak: (o) -> + if @soakNode + if val = @variable + val = new Value val unless val instanceof Value + [left, rite] = val.cacheReference o + else + left = new Literal @superReference o + rite = new Value left + rite = new Call rite, @args + rite.isNew = @isNew + left = new Literal "typeof #{ left.compile o } === \"function\"" + ifn = new If left, new Value(rite), soak: yes + return ifn + call = this + list = [] + loop + if call.variable instanceof Call + list.push call + call = call.variable + continue + break unless call.variable instanceof Value + list.push call + break unless (call = call.variable.base) instanceof Call + for call in list.reverse() + if ifn + if call.variable instanceof Call + call.variable = ifn + else + call.variable.base = ifn + ifn = If.unfoldSoak o, call, 'variable' + ifn + + # Compile a vanilla function call. + compileNode: (o) -> + return ifn.compile o if ifn = @unfoldSoak o + @variable?.tags.front = @tags.front + for arg in @args when arg instanceof Splat + return @compileSplat o + args = ((arg.parenthetical = on) and arg.compile o for arg in @args).join ', ' + if @isSuper + @compileSuper args, o + else + "#{@prefix()}#{@variable.compile o}(#{args})" + + # `super()` is converted into a call against the superclass's implementation + # of the current function. + compileSuper: (args, o) -> + "#{@superReference(o)}.call(this#{ if args.length then ', ' else '' }#{args})" + + # If you call a function with a splat, it's converted into a JavaScript + # `.apply()` call to allow an array of arguments to be passed. + # If it's a constructor, then things get real tricky. We have to inject an + # inner constructor in order to be able to pass the varargs. + compileSplat: (o) -> + splatargs = @compileSplatArguments o + return "#{ @superReference o }.apply(this, #{splatargs})" if @isSuper + unless @isNew + base = new Value base unless (base = @variable) instanceof Value + if (name = base.properties.pop()) and base.isComplex() + ref = o.scope.freeVariable 'this' + fun = "(#{ref} = #{ base.compile o })#{ name.compile o }" + else + fun = ref = base.compile o + fun += name.compile o if name + return "#{fun}.apply(#{ref}, #{splatargs})" + idt = @idt 1 + """ + (function(func, args, ctor) { + #{idt}ctor.prototype = func.prototype; + #{idt}var child = new ctor, result = func.apply(child, args); + #{idt}return typeof result === "object" ? result : child; + #{@tab}})(#{ @variable.compile o }, #{splatargs}, function() {}) + """ + +#### Extends + +# Node to extend an object's prototype with an ancestor object. +# After `goog.inherits` from the +# [Closure Library](http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.html). +exports.Extends = class Extends extends Base + + children: ['child', 'parent'] + + constructor: (@child, @parent) -> + super() + + # Hooks one constructor into another's prototype chain. + compileNode: (o) -> + ref = new Value new Literal utility 'extends' + (new Call ref, [@child, @parent]).compile o + +#### Accessor + +# A `.` accessor into a property of a value, or the `::` shorthand for +# an accessor into the object's prototype. +exports.Accessor = class Accessor extends Base + + children: ['name'] + + constructor: (@name, tag) -> + super() + @prototype = if tag is 'prototype' then '.prototype' else '' + @soakNode = tag is 'soak' + + compileNode: (o) -> + name = @name.compile o + namePart = if name.match(IS_STRING) then "[#{name}]" else ".#{name}" + @prototype + namePart + + isComplex: NO + +#### Index + +# A `[ ... ]` indexed accessor into an array or object. +exports.Index = class Index extends Base + + children: ['index'] + + constructor: (@index) -> + super() + + compileNode: (o) -> + idx = @index.compile o + prefix = if @proto then '.prototype' else '' + "#{prefix}[#{idx}]" + + isComplex: -> @index.isComplex() + +#### Range + +# A range literal. Ranges can be used to extract portions (slices) of arrays, +# to specify a range for comprehensions, or as a value, to be expanded into the +# corresponding array of integers at runtime. +exports.Range = class Range extends Base + + children: ['from', 'to'] + + constructor: (@from, @to, tag) -> + super() + @exclusive = tag is 'exclusive' + @equals = if @exclusive then '' else '=' + + # Compiles the range's source variables -- where it starts and where it ends. + # But only if they need to be cached to avoid double evaluation. + compileVariables: (o) -> + o = merge(o, top: true) + [@from, @fromVar] = @from.compileReference o, precompile: yes + [@to, @toVar] = @to.compileReference o, precompile: yes + [@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)] + parts = [] + parts.push @from if @from isnt @fromVar + parts.push @to if @to isnt @toVar + + # When compiled normally, the range returns the contents of the *for loop* + # needed to iterate over the values in the range. Used by comprehensions. + compileNode: (o) -> + @compileVariables o + return @compileArray(o) unless o.index + return @compileSimple(o) if @fromNum and @toNum + idx = del o, 'index' + step = del o, 'step' + vars = "#{idx} = #{@from}" + if @to isnt @toVar then ", #{@to}" else '' + intro = "(#{@fromVar} <= #{@toVar} ? #{idx}" + compare = "#{intro} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar})" + stepPart = if step then step.compile(o) else '1' + incr = if step then "#{idx} += #{stepPart}" else "#{intro} += #{stepPart} : #{idx} -= #{stepPart})" + "#{vars}; #{compare}; #{incr}" + + # Compile a simple range comprehension, with integers. + compileSimple: (o) -> + [from, to] = [+@fromNum, +@toNum] + idx = del o, 'index' + step = del o, 'step' + step and= "#{idx} += #{step.compile(o)}" + if from <= to + "#{idx} = #{from}; #{idx} <#{@equals} #{to}; #{step or "#{idx}++"}" + else + "#{idx} = #{from}; #{idx} >#{@equals} #{to}; #{step or "#{idx}--"}" + + # When used as a value, expand the range into the equivalent array. + compileArray: (o) -> + if @fromNum and @toNum and Math.abs(@fromNum - @toNum) <= 20 + range = [+@fromNum..+@toNum] + range.pop() if @exclusive + return "[#{ range.join(', ') }]" + idt = @idt 1 + i = o.scope.freeVariable 'i' + result = o.scope.freeVariable 'result' + pre = "\n#{idt}#{result} = [];" + if @fromNum and @toNum + o.index = i + body = @compileSimple o + else + vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else '' + clause = "#{@fromVar} <= #{@toVar} ?" + body = "var #{vars}; #{clause} #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1" + post = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}" + "(function() {#{pre}\n#{idt}for (#{body})#{post}}).call(this)" + +#### Slice + +# An array slice literal. Unlike JavaScript's `Array#slice`, the second parameter +# specifies the index of the end of the slice, just as the first parameter +# is the index of the beginning. +exports.Slice = class Slice extends Base + + children: ['range'] + + constructor: (@range) -> + super() + + compileNode: (o) -> + from = if @range.from then @range.from.compile(o) else '0' + to = if @range.to then @range.to.compile(o) else '' + to += if not to or @range.exclusive then '' else ' + 1' + to = ', ' + to if to + ".slice(#{from}#{to})" + +#### ObjectLiteral + +# An object literal, nothing fancy. +exports.ObjectLiteral = class ObjectLiteral extends Base + + children: ['properties'] + + constructor: (props) -> + super() + @objects = @properties = props or [] + + compileNode: (o) -> + top = del o, 'top' + o.indent = @idt 1 + nonComments = prop for prop in @properties when prop not instanceof Comment + lastNoncom = last nonComments + props = for prop, i in @properties + join = if i is @properties.length - 1 + '' + else if prop is lastNoncom or prop instanceof Comment + '\n' + else + ',\n' + indent = if prop instanceof Comment then '' else @idt 1 + if prop instanceof Value and prop.tags.this + prop = new Assign prop.properties[0].name, prop, 'object' + else if prop not instanceof Assign and prop not instanceof Comment + prop = new Assign prop, prop, 'object' + indent + prop.compile(o) + join + props = props.join('') + obj = "{#{ if props then '\n' + props + '\n' + @idt() else '' }}" + if @tags.front then "(#{obj})" else obj + + assigns: (name) -> + for prop in @properties when prop.assigns name then return yes + no + +#### ArrayLiteral + +# An array literal. +exports.ArrayLiteral = class ArrayLiteral extends Base + + children: ['objects'] + + constructor: (@objects) -> + super() + @objects or= [] + + compileSplatLiteral: (o) -> + Splat.compileSplattedArray @objects, o + + compileNode: (o) -> + o.indent = @idt 1 + for obj in @objects when obj instanceof Splat + return @compileSplatLiteral o + objects = [] + for obj, i in @objects + code = obj.compile o + objects.push (if obj instanceof Comment + "\n#{code}\n#{o.indent}" + else if i is @objects.length - 1 + code + else + code + ', ' + ) + objects = objects.join '' + if 0 < objects.indexOf '\n' + "[\n#{o.indent}#{objects}\n#{@tab}]" + else + "[#{objects}]" + + assigns: (name) -> + for obj in @objects when obj.assigns name then return yes + no + +#### Class + +# The CoffeeScript class definition. +exports.Class = class Class extends Base + + children: ['variable', 'parent', 'properties'] + isStatement: YES + + # Initialize a **Class** with its name, an optional superclass, and a + # list of prototype property assignments. + constructor: (variable, @parent, @properties) -> + super() + @variable = if variable is '__temp__' then new Literal variable else variable + @properties or= [] + @returns = false + + makeReturn: -> + @returns = true + this + + # Instead of generating the JavaScript string directly, we build up the + # equivalent syntax tree and compile that, in pieces. You can see the + # constructor, property assignments, and inheritance getting built out below. + compileNode: (o) -> + {variable} = this + variable = new Literal o.scope.freeVariable 'ctor' if variable.value is '__temp__' + extension = @parent and new Extends variable, @parent + props = new Expressions + o.top = true + me = null + className = variable.compile o + constScope = null + + if @parent + applied = new Value @parent, [new Accessor new Literal 'apply'] + constructor = new Code([], new Expressions([ + new Call applied, [new Literal('this'), new Literal('arguments')] + ])) + else + constructor = new Code [], new Expressions [new Return new Literal 'this'] + + for prop in @properties + [pvar, func] = [prop.variable, prop.value] + if pvar and pvar.base.value is 'constructor' + if func not instanceof Code + [func, ref] = func.compileReference o + props.push func if func isnt ref + apply = new Call(new Value(ref, [new Accessor new Literal 'apply']), [new Literal('this'), new Literal('arguments')]) + func = new Code [], new Expressions([apply]) + throw new Error "cannot define a constructor as a bound function." if func.bound + func.name = className + func.body.push new Return new Literal 'this' + variable = new Value variable + variable.namespaced = 0 < className.indexOf '.' + constructor = func + constructor.comment = props.expressions.pop() if props.expressions[props.expressions.length - 1] instanceof Comment + continue + if func instanceof Code and func.bound + if prop.context is 'this' + func.context = className + else + func.bound = false + constScope or= new Scope(o.scope, constructor.body, constructor) + me or= constScope.freeVariable 'this' + pname = pvar.compile(o) + constructor.body.push new Return new Literal 'this' if constructor.body.empty() + constructor.body.unshift new Literal "this.#{pname} = function(){ return #{className}.prototype.#{pname}.apply(#{me}, arguments); }" + if pvar + access = if prop.context is 'this' then pvar.base.properties[0] else new Accessor(pvar, 'prototype') + val = new Value variable, [access] + prop = new Assign(val, func) + props.push prop + + constructor.className = className.match /[\w\d\$_]+$/ + constructor.body.unshift new Literal "#{me} = this" if me + construct = @idt() + new Assign(variable, constructor).compile(merge o, sharedScope: constScope) + ';' + props = if !props.empty() then '\n' + props.compile(o) else '' + extension = if extension then '\n' + @idt() + extension.compile(o) + ';' else '' + returns = if @returns then '\n' + new Return(variable).compile(o) else '' + construct + extension + props + returns + +#### Assign + +# The **Assign** is used to assign a local variable to value, or to set the +# property of an object -- including within object literals. +exports.Assign = class Assign extends Base + + # Matchers for detecting class/method names + METHOD_DEF: /^(?:(\S+)\.prototype\.)?([$A-Za-z_][$\w]*)$/ + + children: ['variable', 'value'] + + constructor: (@variable, @value, @context) -> + super() + + topSensitive: YES + + isValue: -> + @variable instanceof Value + + # Compile an assignment, delegating to `compilePatternMatch` or + # `compileSplice` if appropriate. Keep track of the name of the base object + # we've been assigned to, for correct internal references. If the variable + # has not been seen yet within the current scope, declare it. + compileNode: (o) -> + if isValue = @isValue() + return @compilePatternMatch(o) if @variable.isArray() or @variable.isObject() + return @compileSplice(o) if @variable.isSplice() + if ifn = If.unfoldSoak o, this, 'variable' + delete o.top + return ifn.compile o + top = del o, 'top' + stmt = del o, 'asStatement' + name = @variable.compile(o) + if @value instanceof Code and match = @METHOD_DEF.exec name + @value.name = match[2] + @value.klass = match[1] + val = @value.compile o + return "#{name}: #{val}" if @context is 'object' + o.scope.find name unless isValue and (@variable.hasProperties() or @variable.namespaced) + val = "#{name} = #{val}" + return "#{@tab}#{val};" if stmt + if top or @parenthetical then val else "(#{val})" + + # Brief implementation of recursive pattern matching, when assigning array or + # object literals to a value. Peeks at their properties to assign inner names. + # See the [ECMAScript Harmony Wiki](http://wiki.ecmascript.org/doku.php?id=harmony:destructuring) + # for details. + compilePatternMatch: (o) -> + if (value = @value).isStatement o then value = Closure.wrap value + {objects} = @variable.base + return value.compile o unless olength = objects.length + isObject = @variable.isObject() + if o.top and olength is 1 and (obj = objects[0]) not instanceof Splat + # Unroll simplest cases: `{v} = x` -> `v = x.v` + if obj instanceof Assign + {variable: {base: idx}, value: obj} = obj + else + idx = if isObject + if obj.tags.this then obj.properties[0].name else obj + else new Literal 0 + value = new Value value unless value instanceof Value + accessClass = if IDENTIFIER.test idx.value then Accessor else Index + value.properties.push new accessClass idx + return new Assign(obj, value).compile o + top = del o, 'top' + otop = merge o, top: yes + valVar = value.compile o + assigns = [] + splat = false + if not IDENTIFIER.test(valVar) or @variable.assigns(valVar) + assigns.push "#{ ref = o.scope.freeVariable 'ref' } = #{valVar}" + valVar = ref + for obj, i in objects + # A regular array pattern-match. + idx = i + if isObject + if obj instanceof Assign + # A regular object pattern-match. + {variable: {base: idx}, value: obj} = obj + else + # A shorthand `{a, b, @c} = val` pattern-match. + idx = if obj.tags.this then obj.properties[0].name else obj + unless obj instanceof Value or obj instanceof Splat + throw new Error 'pattern matching must use only identifiers on the left-hand side.' + accessClass = if isObject and IDENTIFIER.test(idx.value) then Accessor else Index + if not splat and obj instanceof Splat + val = new Literal obj.compileValue o, valVar, i, olength - i - 1 + splat = true + else + idx = new Literal(if splat then "#{valVar}.length - #{olength - idx}" else idx) if typeof idx isnt 'object' + val = new Value new Literal(valVar), [new accessClass idx] + assigns.push new Assign(obj, val).compile otop + assigns.push valVar unless top + code = assigns.join ', ' + if top or @parenthetical then code else "(#{code})" + + # Compile the assignment from an array splice literal, using JavaScript's + # `Array#splice` method. + compileSplice: (o) -> + {range} = @variable.properties.pop() + name = @variable.compile o + plus = if range.exclusive then '' else ' + 1' + from = if range.from then range.from.compile(o) else '0' + to = if range.to then range.to.compile(o) + ' - ' + from + plus else "#{name}.length" + ref = o.scope.freeVariable 'ref' + val = @value.compile(o) + "([].splice.apply(#{name}, [#{from}, #{to}].concat(#{ref} = #{val})), #{ref})" + + assigns: (name) -> + @[if @context is 'object' then 'value' else 'variable'].assigns name + +#### Code + +# A function definition. This is the only node that creates a new Scope. +# When for the purposes of walking the contents of a function body, the Code +# has no *children* -- they're within the inner scope. +exports.Code = class Code extends Base + + children: ['params', 'body'] + + constructor: (@params, @body, tag) -> + super() + @params or= [] + @body or= new Expressions + @bound = tag is 'boundfunc' + @context = 'this' if @bound + + # Compilation creates a new scope unless explicitly asked to share with the + # outer scope. Handles splat parameters in the parameter list by peeking at + # the JavaScript `arguments` objects. If the function is bound with the `=>` + # arrow, generates a wrapper that saves the current value of `this` through + # a closure. + compileNode: (o) -> + sharedScope = del o, 'sharedScope' + top = del o, 'top' + o.scope = sharedScope or new Scope(o.scope, @body, this) + o.top = true + o.indent = @idt(1) + empty = @body.expressions.length is 0 + delete o.bare + delete o.globals + splat = undefined + params = [] + for param, i in @params + if splat + if param.attach + param.assign = new Assign new Value new Literal('this'), [new Accessor param.value] + @body.expressions.splice splat.index + 1, 0, param.assign + splat.trailings.push param + else + if param.attach + {value} = param + [param, param.splat] = [new Literal(o.scope.freeVariable 'arg'), param.splat] + @body.unshift new Assign new Value(new Literal('this'), [new Accessor value]), param + if param.splat + splat = new Splat param.value + splat.index = i + splat.trailings = [] + splat.arglength = @params.length + @body.unshift(splat) + else + params.push param + o.scope.startLevel() + params = (param.compile(o) for param in params) + @body.makeReturn() unless empty or @noReturn + (o.scope.parameter(param)) for param in params + comm = if @comment then @comment.compile(o) + '\n' else '' + o.indent = @idt 2 if @className + code = if @body.expressions.length then "\n#{ @body.compileWithDeclarations(o) }\n" else '' + open = if @className then "(function() {\n#{comm}#{@idt(1)}function #{@className}(" else "function(" + close = if @className then "#{code and @idt(1)}};\n#{@idt(1)}return #{@className};\n#{@tab}})()" else "#{code and @tab}}" + func = "#{open}#{ params.join(', ') }) {#{code}#{close}" + o.scope.endLevel() + return "#{utility 'bind'}(#{func}, #{@context})" if @bound + if @tags.front then "(#{func})" else func + + # Short-circuit traverseChildren method to prevent it from crossing scope boundaries + # unless crossScope is true + traverseChildren: (crossScope, func) -> super(crossScope, func) if crossScope + +#### Param + +# A parameter in a function definition. Beyond a typical Javascript parameter, +# these parameters can also attach themselves to the context of the function, +# as well as be a splat, gathering up a group of parameters into an array. +exports.Param = class Param extends Base + + children: ['name'] + + constructor: (@name, @attach, @splat) -> + super() + @value = new Literal @name + + compileNode: (o) -> + @value.compile o + + toString: -> + {name} = @ + name = '@' + name if @attach + name += '...' if @splat + new Literal(name).toString() + +#### Splat + +# A splat, either as a parameter to a function, an argument to a call, +# or as part of a destructuring assignment. +exports.Splat = class Splat extends Base + + children: ['name'] + + constructor: (name) -> + super() + @name = if name.compile then name else new Literal name + + assigns: (name) -> @name.assigns name + + compileNode: (o) -> + if @index? then @compileParam(o) else @name.compile(o) + + # Compiling a parameter splat means recovering the parameters that succeed + # the splat in the parameter list, by slicing the arguments object. + compileParam: (o) -> + name = @name.compile(o) + o.scope.find name + end = '' + if @trailings.length + len = o.scope.freeVariable 'len' + o.scope.assign len, "arguments.length" + variadic = o.scope.freeVariable 'result' + o.scope.assign variadic, len + ' >= ' + @arglength + end = if @trailings.length then ", #{len} - #{@trailings.length}" + for trailing, idx in @trailings + if trailing.attach + assign = trailing.assign + trailing = new Literal o.scope.freeVariable 'arg' + assign.value = trailing + pos = @trailings.length - idx + o.scope.assign(trailing.compile(o), "arguments[#{variadic} ? #{len} - #{pos} : #{@index + idx}]") + "#{name} = #{utility('slice')}.call(arguments, #{@index}#{end})" + + # A compiling a splat as a destructuring assignment means slicing arguments + # from the right-hand-side's corresponding array. + compileValue: (o, name, index, trailings) -> + trail = if trailings then ", #{name}.length - #{trailings}" else '' + "#{utility 'slice'}.call(#{name}, #{index}#{trail})" + + # Utility function that converts arbitrary number of elements, mixed with + # splats, to a proper array + @compileSplattedArray: (list, o) -> + args = [] + end = -1 + for arg, i in list + code = arg.compile o + prev = args[end] + if arg not instanceof Splat + if prev and starts(prev, '[') and ends(prev, ']') + args[end] = "#{prev.slice 0, -1}, #{code}]" + continue + if prev and starts(prev, '.concat([') and ends(prev, '])') + args[end] = "#{prev.slice 0, -2}, #{code}])" + continue + code = "[#{code}]" + args[++end] = if i is 0 then code else ".concat(#{code})" + args.join '' + +#### While + +# A while loop, the only sort of low-level loop exposed by CoffeeScript. From +# it, all other loops can be manufactured. Useful in cases where you need more +# flexibility or more speed than a comprehension can provide. +exports.While = class While extends Base + + children: ['condition', 'guard', 'body'] + isStatement: YES + + constructor: (condition, opts) -> + super() + @condition = if opts?.invert then condition.invert() else condition + @guard = opts?.guard + + addBody: (body) -> + @body = body + this + + makeReturn: -> + @returns = true + this + + topSensitive: YES + + # The main difference from a JavaScript *while* is that the CoffeeScript + # *while* can be used as a part of a larger expression -- while loops may + # return an array containing the computed result of each iteration. + compileNode: (o) -> + top = del(o, 'top') and not @returns + o.indent = @idt 1 + @condition.parenthetical = yes + cond = @condition.compile(o) + o.top = true + set = '' + unless top + rvar = o.scope.freeVariable 'result' + set = "#{@tab}#{rvar} = [];\n" + @body = Push.wrap(rvar, @body) if @body + pre = "#{set}#{@tab}while (#{cond})" + @body = Expressions.wrap([new If(@guard, @body)]) if @guard + if @returns + post = '\n' + new Return(new Literal rvar).compile(merge(o, indent: @idt())) + else + post = '' + "#{pre} {\n#{ @body.compile(o) }\n#{@tab}}#{post}" + +#### Op + +# Simple Arithmetic and logical operations. Performs some conversion from +# CoffeeScript operations into their JavaScript equivalents. +exports.Op = class Op extends Base + + # The map of conversions from CoffeeScript to JavaScript symbols. + CONVERSIONS: + '==': '===' + '!=': '!==' + of: 'in' + + # The map of invertible operators. + INVERSIONS: + '!==': '===' + '===': '!==' + + # The list of operators for which we perform + # [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin). + CHAINABLE: ['<', '>', '>=', '<=', '===', '!=='] + + # Our assignment operators that have no JavaScript equivalent. + ASSIGNMENT: ['||=', '&&=', '?='] + + # Operators must come before their operands with a space. + PREFIX_OPERATORS: ['new', 'typeof', 'delete'] + + children: ['first', 'second'] + + constructor: (op, first, second, flip) -> + if op is 'new' + return first.newInstance() if first instanceof Call + first = new Parens first if first instanceof Code and first.bound + super() + @operator = @CONVERSIONS[op] or op + (@first = first ).tags.operation = yes + (@second = second).tags.operation = yes if second + @flip = !!flip + + isUnary: -> + not @second + + isComplex: -> @operator isnt '!' or @first.isComplex() + + isMutator: -> + ends(@operator, '=') and @operator not in ['===', '!=='] + + isChainable: -> + include(@CHAINABLE, @operator) + + invert: -> + if @operator in ['===', '!=='] + @operator = @INVERSIONS[@operator] + this + else if @second + new Parens(this).invert() + else + super() + + toString: (idt) -> + super(idt, @constructor.name + ' ' + @operator) + + compileNode: (o) -> + @first.tags.front = @tags.front if @second + return @compileChain(o) if @isChainable() and @first.unwrap() instanceof Op and @first.unwrap().isChainable() + return @compileAssignment(o) if include @ASSIGNMENT, @operator + return @compileUnary(o) if @isUnary() + return @compileExistence(o) if @operator is '?' + @first = new Parens @first if @first instanceof Op and @first.isMutator() + @second = new Parens @second if @second instanceof Op and @second.isMutator() + [@first.compile(o), @operator, @second.compile(o)].join ' ' + + # Mimic Python's chained comparisons when multiple comparison operators are + # used sequentially. For example: + # + # bin/coffee -e "puts 50 < 65 > 10" + # true + compileChain: (o) -> + shared = @first.unwrap().second + [@first.second, shared] = shared.compileReference o + [first, second, shared] = [@first.compile(o), @second.compile(o), shared.compile(o)] + "(#{first}) && (#{shared} #{@operator} #{second})" + + # When compiling a conditional assignment, take care to ensure that the + # operands are only evaluated once, even though we have to reference them + # more than once. + compileAssignment: (o) -> + [left, rite] = @first.cacheReference o + rite = new Assign rite, @second + return new Op(@operator.slice(0, -1), left, rite).compile o + + compileExistence: (o) -> + if @first.isComplex() + ref = o.scope.freeVariable 'ref' + fst = new Parens new Assign new Literal(ref), @first + else + fst = @first + ref = fst.compile o + new Existence(fst).compile(o) + " ? #{ref} : #{ @second.compile o }" + + # Compile a unary **Op**. + compileUnary: (o) -> + space = if include @PREFIX_OPERATORS, @operator then ' ' else '' + parts = [@operator, space, @first.compile(o)] + (if @flip then parts.reverse() else parts).join '' + +#### In +exports.In = class In extends Base + + children: ['object', 'array'] + + constructor: (@object, @array) -> + super() + + isArray: -> + @array instanceof Value and @array.isArray() + + compileNode: (o) -> + if @isArray() then @compileOrTest(o) else @compileLoopTest(o) + + compileOrTest: (o) -> + [obj1, obj2] = @object.compileReference o, precompile: yes + tests = for item, i in @array.base.objects + "#{if i then obj2 else obj1} === #{item.compile(o)}" + "(#{tests.join(' || ')})" + + compileLoopTest: (o) -> + "#{utility 'inArray'}(#{@object.compile o}, #{@array.compile o})" + +#### Try + +# A classic *try/catch/finally* block. +exports.Try = class Try extends Base + + children: ['attempt', 'recovery', 'ensure'] + isStatement: YES + + constructor: (@attempt, @error, @recovery, @ensure) -> + super() + + makeReturn: -> + @attempt = @attempt.makeReturn() if @attempt + @recovery = @recovery.makeReturn() if @recovery + this + + # Compilation is more or less as you would expect -- the *finally* clause + # is optional, the *catch* is not. + compileNode: (o) -> + o.indent = @idt 1 + o.top = true + attemptPart = @attempt.compile(o) + errorPart = if @error then " (#{ @error.compile(o) }) " else ' ' + catchPart = if @recovery + " catch#{errorPart}{\n#{ @recovery.compile(o) }\n#{@tab}}" + else unless @ensure or @recovery then ' catch (_e) {}' else '' + finallyPart = (@ensure or '') and ' finally {\n' + @ensure.compile(merge(o)) + "\n#{@tab}}" + "#{@tab}try {\n#{attemptPart}\n#{@tab}}#{catchPart}#{finallyPart}" + +#### Throw + +# Simple node to throw an exception. +exports.Throw = class Throw extends Base + + children: ['expression'] + isStatement: YES + + constructor: (@expression) -> + super() + + # A **Throw** is already a return, of sorts... + makeReturn: THIS + + compileNode: (o) -> + "#{@tab}throw #{@expression.compile(o)};" + +#### Existence + +# Checks a variable for existence -- not *null* and not *undefined*. This is +# similar to `.nil?` in Ruby, and avoids having to consult a JavaScript truth +# table. +exports.Existence = class Existence extends Base + + children: ['expression'] + + constructor: (@expression) -> + super() + + compileNode: (o) -> + code = @expression.compile o + code = if IDENTIFIER.test(code) and not o.scope.check code + "typeof #{code} !== \"undefined\" && #{code} !== null" + else + "#{code} != null" + if @parenthetical then code else "(#{code})" + +#### Parens + +# An extra set of parentheses, specified explicitly in the source. At one time +# we tried to clean up the results by detecting and removing redundant +# parentheses, but no longer -- you can put in as many as you please. +# +# Parentheses are a good way to force any statement to become an expression. +exports.Parens = class Parens extends Base + + children: ['expression'] + + constructor: (@expression) -> + super() + + isStatement: (o) -> + @expression.isStatement(o) + isComplex: -> + @expression.isComplex() + + topSensitive: YES + + makeReturn: -> + @expression.makeReturn() + + compileNode: (o) -> + top = del o, 'top' + @expression.parenthetical = true + code = @expression.compile(o) + return code if top and @expression.isPureStatement o + if @parenthetical or @isStatement o + return if top then @tab + code + ';' else code + "(#{code})" + +#### For + +# CoffeeScript's replacement for the *for* loop is our array and object +# comprehensions, that compile into *for* loops here. They also act as an +# expression, able to return the result of each filtered iteration. +# +# Unlike Python array comprehensions, they can be multi-line, and you can pass +# the current index of the loop as a second parameter. Unlike Ruby blocks, +# you can map and filter in a single pass. +exports.For = class For extends Base + + children: ['body', 'source', 'guard'] + isStatement: YES + + constructor: (@body, source, @name, @index) -> + super() + {@source, @guard, @step} = source + @raw = !!source.raw + @object = !!source.object + [@name, @index] = [@index, @name] if @object + @pattern = @name instanceof Value + throw new Error('index cannot be a pattern matching expression') if @index instanceof Value + @returns = false + + topSensitive: YES + + makeReturn: -> + @returns = true + this + + compileReturnValue: (val, o) -> + return '\n' + new Return(new Literal val).compile(o) if @returns + return '\n' + val if val + '' + + # Welcome to the hairiest method in all of CoffeeScript. Handles the inner + # loop, filtering, stepping, and result saving for array, object, and range + # comprehensions. Some of the generated code can be shared in common, and + # some cannot. + compileNode: (o) -> + topLevel = del(o, 'top') and not @returns + range = @source instanceof Value and @source.base instanceof Range and not @source.properties.length + source = if range then @source.base else @source + codeInBody = not @body.containsPureStatement() and @body.contains (node) -> node instanceof Code + scope = o.scope + name = @name and @name.compile o + index = @index and @index.compile o + scope.find(name, immediate: yes) if name and not @pattern and (range or not codeInBody) + scope.find(index, immediate: yes) if index + rvar = scope.freeVariable 'result' unless topLevel + ivar = if range then name else index + ivar = scope.freeVariable 'i' if not ivar or codeInBody + nvar = scope.freeVariable 'i' if name and not range and codeInBody + varPart = '' + guardPart = '' + unstepPart = '' + body = Expressions.wrap([@body]) + idt1 = @idt 1 + if range + forPart = source.compile merge o, {index: ivar, @step} + else + svar = sourcePart = @source.compile o + if (name or not @raw) and + not (IDENTIFIER.test(svar) and scope.check svar, immediate: on) + sourcePart = "#{ref = scope.freeVariable 'ref'} = #{svar}" + sourcePart = "(#{sourcePart})" unless @object + svar = ref + namePart = if @pattern + new Assign(@name, new Literal "#{svar}[#{ivar}]").compile merge o, top: on + else if name + "#{name} = #{svar}[#{ivar}]" + unless @object + lvar = scope.freeVariable 'len' + stepPart = if @step then "#{ivar} += #{ @step.compile(o) }" else "#{ivar}++" + forPart = "#{ivar} = 0, #{lvar} = #{sourcePart}.length; #{ivar} < #{lvar}; #{stepPart}" + resultPart = if rvar then "#{@tab}#{rvar} = [];\n" else '' + returnResult = @compileReturnValue(rvar, o) + body = Push.wrap(rvar, body) unless topLevel + if @guard + body = Expressions.wrap([new If(@guard, body)]) + if codeInBody + body.unshift new Literal "var #{name} = #{ivar}" if range + body.unshift new Literal "var #{namePart}" if namePart + body.unshift new Literal "var #{index} = #{ivar}" if index + lastLine = body.expressions.pop() + body.push new Assign new Literal(ivar), new Literal index if index + body.push new Assign new Literal(nvar), new Literal name if nvar + body.push lastLine + o.indent = @idt 1 + body = Expressions.wrap [new Literal body.compile o] + body.push new Assign new Literal(index), new Literal ivar if index + body.push new Assign new Literal(name), new Literal nvar or ivar if name + else + varPart = "#{idt1}#{namePart};\n" if namePart + if forPart and name is ivar + unstepPart = if @step then "#{name} -= #{ @step.compile(o) };" else "#{name}--;" + unstepPart = "\n#{@tab}" + unstepPart + if @object + forPart = "#{ivar} in #{sourcePart}" + guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw + body = body.compile merge o, indent: idt1, top: true + vars = if range then name else "#{name}, #{ivar}" + """ + #{resultPart}#{@tab}for (#{forPart}) {#{guardPart} + #{varPart}#{body} + #{@tab}}#{unstepPart}#{returnResult} + """ + +#### Switch + +# A JavaScript *switch* statement. Converts into a returnable expression on-demand. +exports.Switch = class Switch extends Base + + children: ['subject', 'cases', 'otherwise'] + + isStatement: YES + + constructor: (@subject, @cases, @otherwise) -> + super() + @tags.subjectless = !@subject + @subject or= new Literal 'true' + + makeReturn: -> + pair[1].makeReturn() for pair in @cases + @otherwise.makeReturn() if @otherwise + this + + compileNode: (o) -> + idt = o.indent = @idt 2 + o.top = yes + code = "#{ @tab }switch (#{ @subject.compile o }) {" + for pair in @cases + [conditions, block] = pair + exprs = block.expressions + for condition in flatten [conditions] + condition = new Op '!!', new Parens condition if @tags.subjectless + code += "\n#{ @idt(1) }case #{ condition.compile o }:" + code += "\n#{ block.compile o }" + code += "\n#{ idt }break;" unless last(exprs) instanceof Return + if @otherwise + code += "\n#{ @idt(1) }default:\n#{ @otherwise.compile o }" + code += "\n#{ @tab }}" + code + +#### If + +# *If/else* statements. Acts as an expression by pushing down requested returns +# to the last line of each clause. +# +# Single-expression **Ifs** are compiled into conditional operators if possible, +# because ternaries are already proper expressions, and don't need conversion. +exports.If = class If extends Base + + children: ['condition', 'body', 'elseBody', 'assigner'] + + topSensitive: YES + + constructor: (condition, @body, tags) -> + @tags = tags or= {} + @condition = if tags.invert then condition.invert() else condition + @soakNode = tags.soak + @elseBody = null + @isChain = false + + bodyNode: -> @body?.unwrap() + elseBodyNode: -> @elseBody?.unwrap() + + # Rewrite a chain of **Ifs** to add a default case as the final *else*. + addElse: (elseBody) -> + if @isChain + @elseBodyNode().addElse elseBody + else + @isChain = elseBody instanceof If + @elseBody = @ensureExpressions elseBody + this + + # The **If** only compiles into a statement if either of its bodies needs + # to be a statement. Otherwise a conditional operator is safe. + isStatement: (o) -> + @statement or= o?.top or @bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o) + + compileCondition: (o) -> + @condition.parenthetical = yes + @condition.compile o + + compileNode: (o) -> + if @isStatement o then @compileStatement o else @compileExpression o + + makeReturn: -> + if @isStatement() + @body and= @ensureExpressions(@body.makeReturn()) + @elseBody and= @ensureExpressions(@elseBody.makeReturn()) + this + else + new Return this + + ensureExpressions: (node) -> + if node instanceof Expressions then node else new Expressions [node] + + # Compile the **If** as a regular *if-else* statement. Flattened chains + # force inner *else* bodies into statement form. + compileStatement: (o) -> + top = del o, 'top' + child = del o, 'chainChild' + condO = merge o + o.indent = @idt 1 + o.top = true + ifPart = "if (#{ @compileCondition condO }) {\n#{ @body.compile o }\n#{@tab}}" + ifPart = @tab + ifPart unless child + return ifPart unless @elseBody + ifPart + if @isChain + ' else ' + @elseBodyNode().compile merge o, indent: @tab, chainChild: true + else + " else {\n#{ @elseBody.compile(o) }\n#{@tab}}" + + # Compile the If as a conditional operator. + compileExpression: (o) -> + @bodyNode().tags.operation = @condition.tags.operation = yes + @elseBodyNode().tags.operation = yes if @elseBody + ifPart = @condition.compile(o) + ' ? ' + @bodyNode().compile(o) + elsePart = if @elseBody then @elseBodyNode().compile(o) else 'undefined' + code = "#{ifPart} : #{elsePart}" + if @tags.operation or @soakNode then "(#{code})" else code + + unfoldSoak: -> @soakNode and this + + # Unfold a node's child if soak, then tuck the node under created `If` + @unfoldSoak: (o, parent, name) -> + return unless ifn = parent[name].unfoldSoak o + parent[name] = ifn.body + ifn.body = new Value parent + ifn + +# Faux-Nodes +# ---------- +# Faux-nodes are never created by the grammar, but are used during code +# generation to generate other combinations of nodes. + +#### Push + +# The **Push** creates the tree for `array.push(value)`, +# which is helpful for recording the result arrays from comprehensions. +Push = + wrap: (name, expressions) -> + return expressions if expressions.empty() or expressions.containsPureStatement() + Expressions.wrap [new Call( + new Value new Literal(name), [new Accessor new Literal 'push'] + [expressions.unwrap()] + )] + +#### Closure + +# A faux-node used to wrap an expressions body in a closure. +Closure = + + # Wrap the expressions body, unless it contains a pure statement, + # in which case, no dice. If the body mentions `this` or `arguments`, + # then make sure that the closure wrapper preserves the original values. + wrap: (expressions, statement, noReturn) -> + return expressions if expressions.containsPureStatement() + func = new Parens new Code [], Expressions.wrap [expressions] + args = [] + if (mentionsArgs = expressions.contains @literalArgs) or + ( expressions.contains @literalThis) + meth = new Literal if mentionsArgs then 'apply' else 'call' + args = [new Literal 'this'] + args.push new Literal 'arguments' if mentionsArgs + func = new Value func, [new Accessor meth] + func.noReturn = noReturn + call = new Call func, args + if statement then Expressions.wrap [call] else call + + literalArgs: (node) -> node instanceof Literal and node.value is 'arguments' + literalThis: (node) -> node instanceof Literal and node.value is 'this' or + node instanceof Code and node.bound + +# Constants +# --------- + +UTILITIES = + + # Correctly set up a prototype chain for inheritance, including a reference + # to the superclass for `super()` calls. See: + # [goog.inherits](http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.source.html#line1206). + extends: ''' + function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + } + ''' + + # Create a function bound to the current value of "this". + bind: ''' + function(func, context) { + return function() { return func.apply(context, arguments); }; + } + ''' + + # Discover if an item is in an array. + inArray: ''' + (function() { + var indexOf = Array.prototype.indexOf || function(item) { + var i = this.length; while (i--) if (this[i] === item) return i; + return -1; + }; + return function(item, array) { return indexOf.call(array, item) > -1; }; + })(); + ''' + + # Shortcuts to speed up the lookup time for native functions. + hasProp: 'Object.prototype.hasOwnProperty' + slice: 'Array.prototype.slice' + +# Tabs are two spaces for pretty printing. +TAB = ' ' + +# Trim out all trailing whitespace, so that the generated code plays nice +# with Git. +TRAILING_WHITESPACE = /[ \t]+$/gm + +IDENTIFIER = /^[$A-Za-z_][$\w]*$/ +NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i +SIMPLENUM = /^[+-]?\d+$/ + +# Is a literal value a string? +IS_STRING = /^['"]/ + +# Utility Functions +# ----------------- + +# Helper for ensuring that utility functions are assigned at the top level. +utility = (name) -> + ref = "__#{name}" + Scope.root.assign ref, UTILITIES[name] + ref diff --git a/node_modules/jade/support/coffee-script/src/optparse.coffee b/node_modules/jade/support/coffee-script/src/optparse.coffee new file mode 100644 index 0000000..5a6c9ee --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/optparse.coffee @@ -0,0 +1,96 @@ +# A simple **OptionParser** class to parse option flags from the command-line. +# Use it like so: +# +# parser = new OptionParser switches, helpBanner +# options = parser.parse process.argv +# +# The first non-option is considered to be the start of the file (and file +# option) list, and all subsequent arguments are left unparsed. +exports.OptionParser = class OptionParser + + # Initialize with a list of valid options, in the form: + # + # [short-flag, long-flag, description] + # + # Along with an an optional banner for the usage help. + constructor: (rules, banner) -> + @banner = banner + @rules = buildRules rules + + # Parse the list of arguments, populating an `options` object with all of the + # specified options, and returning it. `options.arguments` will be an array + # containing the remaning non-option arguments. This is a simpler API than + # many option parsers that allow you to attach callback actions for every + # flag. Instead, you're responsible for interpreting the options object. + parse: (args) -> + options = arguments: [] + args = normalizeArguments args + for arg, i in args + isOption = !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG)) + matchedRule = no + for rule in @rules + if rule.shortFlag is arg or rule.longFlag is arg + value = if rule.hasArgument then args[i += 1] else true + options[rule.name] = if rule.isList then (options[rule.name] or []).concat value else value + matchedRule = yes + break + throw new Error "unrecognized option: #{arg}" if isOption and not matchedRule + if not isOption + options.arguments = args.slice i + break + options + + # Return the help text for this **OptionParser**, listing and describing all + # of the valid options, for `--help` and such. + help: -> + lines = ['Available options:'] + lines.unshift "#{@banner}\n" if @banner + for rule in @rules + spaces = 15 - rule.longFlag.length + spaces = if spaces > 0 then Array(spaces + 1).join(' ') else '' + letPart = if rule.shortFlag then rule.shortFlag + ', ' else ' ' + lines.push ' ' + letPart + rule.longFlag + spaces + rule.description + "\n#{ lines.join('\n') }\n" + +# Helpers +# ------- + +# Regex matchers for option flags. +LONG_FLAG = /^(--\w[\w\-]+)/ +SHORT_FLAG = /^(-\w)/ +MULTI_FLAG = /^-(\w{2,})/ +OPTIONAL = /\[(\w+(\*?))\]/ + +# Build and return the list of option rules. If the optional *short-flag* is +# unspecified, leave it out by padding with `null`. +buildRules = (rules) -> + for tuple in rules + tuple.unshift null if tuple.length < 3 + buildRule tuple... + +# Build a rule from a `-o` short flag, a `--output [DIR]` long flag, and the +# description of what the option does. +buildRule = (shortFlag, longFlag, description, options) -> + match = longFlag.match(OPTIONAL) + longFlag = longFlag.match(LONG_FLAG)[1] + options or= {} + { + name: longFlag.substr 2 + shortFlag: shortFlag + longFlag: longFlag + description: description + hasArgument: !!(match and match[1]) + isList: !!(match and match[2]) + } + +# Normalize arguments by expanding merged flags into multiple flags. This allows +# you to have `-wl` be the same as `--watch --lint`. +normalizeArguments = (args) -> + args = args.slice 0 + result = [] + for arg in args + if match = arg.match MULTI_FLAG + result.push '-' + l for l in match[1].split '' + else + result.push arg + result diff --git a/node_modules/jade/support/coffee-script/src/repl.coffee b/node_modules/jade/support/coffee-script/src/repl.coffee new file mode 100644 index 0000000..294146b --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/repl.coffee @@ -0,0 +1,35 @@ +# A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript +# and evaluates it. Good for simple tests, or poking around the **Node.js** API. +# Using it looks like this: +# +# coffee> puts "#{num} bottles of beer" for num in [99..1] + +# Require the **coffee-script** module to get access to the compiler. +CoffeeScript = require './coffee-script' +helpers = require './helpers' +readline = require 'readline' + +# Start by opening up **stdio**. +stdio = process.openStdin() + +# Quick alias for quitting the REPL. +helpers.extend global, quit: -> process.exit(0) + +# The main REPL function. **run** is called every time a line of code is entered. +# Attempt to evaluate the command. If there's an exception, print it out instead +# of exiting. +run = (buffer) -> + try + val = CoffeeScript.eval buffer.toString(), bare: on, globals: on, fileName: 'repl' + puts inspect val if val isnt undefined + catch err + puts err.stack or err.toString() + repl.prompt() + +# Create the REPL by listening to **stdin**. +repl = readline.createInterface stdio +repl.setPrompt 'coffee> ' +stdio.on 'data', (buffer) -> repl.write buffer +repl.on 'close', -> stdio.destroy() +repl.on 'line', run +repl.prompt() diff --git a/node_modules/jade/support/coffee-script/src/rewriter.coffee b/node_modules/jade/support/coffee-script/src/rewriter.coffee new file mode 100644 index 0000000..5ea0298 --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/rewriter.coffee @@ -0,0 +1,349 @@ +# The CoffeeScript language has a good deal of optional syntax, implicit syntax, +# and shorthand syntax. This can greatly complicate a grammar and bloat +# the resulting parse table. Instead of making the parser handle it all, we take +# a series of passes over the token stream, using this **Rewriter** to convert +# shorthand into the unambiguous long form, add implicit indentation and +# parentheses, balance incorrect nestings, and generally clean things up. + +# Import the helpers we need. +{include} = require './helpers' + +# The **Rewriter** class is used by the [Lexer](lexer.html), directly against +# its internal array of tokens. +class exports.Rewriter + + # Helpful snippet for debugging: + # puts (t[0] + '/' + t[1] for t in @tokens).join ' ' + + # Rewrite the token stream in multiple passes, one logical filter at + # a time. This could certainly be changed into a single pass through the + # stream, with a big ol' efficient switch, but it's much nicer to work with + # like this. The order of these passes matters -- indentation must be + # corrected before implicit parentheses can be wrapped around blocks of code. + rewrite: (@tokens) -> + @adjustComments() + @removeLeadingNewlines() + @removeMidExpressionNewlines() + @closeOpenCalls() + @closeOpenIndexes() + @addImplicitIndentation() + @tagPostfixConditionals() + @addImplicitBraces() + @addImplicitParentheses() + @ensureBalance BALANCED_PAIRS + @rewriteClosingParens() + @tokens + + # Rewrite the token stream, looking one token ahead and behind. + # Allow the return value of the block to tell us how many tokens to move + # forwards (or backwards) in the stream, to make sure we don't miss anything + # as tokens are inserted and removed, and the stream changes length under + # our feet. + scanTokens: (block) -> + {tokens} = this + i = 0 + i += block.call this, token, i, tokens while token = tokens[i] + true + + detectEnd: (i, condition, action) -> + {tokens} = this + levels = 0 + while token = tokens[i] + return action.call this, token, i if levels is 0 and condition.call this, token, i + return action.call this, token, i - 1 if not token or levels < 0 + if include EXPRESSION_START, token[0] + levels += 1 + else if include EXPRESSION_END, token[0] + levels -= 1 + i += 1 + i - 1 + + # Massage newlines and indentations so that comments don't have to be + # correctly indented, or appear on a line of their own. + adjustComments: -> + @scanTokens (token, i, tokens) -> + return 1 unless token[0] is 'HERECOMMENT' + before = tokens[i - 2] + prev = tokens[i - 1] + post = tokens[i + 1] + after = tokens[i + 2] + if after?[0] is 'INDENT' + tokens.splice i + 2, 1 + if before?[0] is 'OUTDENT' and post?[0] is 'TERMINATOR' + tokens.splice i - 2, 1 + else + tokens.splice i, 0, after + else if prev and prev[0] not in ['TERMINATOR', 'INDENT', 'OUTDENT'] + if post?[0] is 'TERMINATOR' and after?[0] is 'OUTDENT' + tokens.splice i + 2, 0, tokens.splice(i, 2)... + if tokens[i + 2][0] isnt 'TERMINATOR' + tokens.splice i + 2, 0, ['TERMINATOR', '\n', prev[2]] + else + tokens.splice i, 0, ['TERMINATOR', '\n', prev[2]] + return 2 + 1 + + # Leading newlines would introduce an ambiguity in the grammar, so we + # dispatch them here. + removeLeadingNewlines: -> + break for [tag], i in @tokens when tag isnt 'TERMINATOR' + @tokens.splice 0, i if i + + # Some blocks occur in the middle of expressions -- when we're expecting + # this, remove their trailing newlines. + removeMidExpressionNewlines: -> + @scanTokens (token, i, tokens) -> + return 1 unless token[0] is 'TERMINATOR' and include EXPRESSION_CLOSE, @tag(i + 1) + tokens.splice i, 1 + 0 + + # The lexer has tagged the opening parenthesis of a method call. Match it with + # its paired close. We have the mis-nested outdent case included here for + # calls that close on the same line, just before their outdent. + closeOpenCalls: -> + condition = (token, i) -> + token[0] in [')', 'CALL_END'] or + token[0] is 'OUTDENT' and @tag(i - 1) is ')' + action = (token, i) -> + @tokens[if token[0] is 'OUTDENT' then i - 1 else i][0] = 'CALL_END' + @scanTokens (token, i) -> + @detectEnd i + 1, condition, action if token[0] is 'CALL_START' + 1 + + # The lexer has tagged the opening parenthesis of an indexing operation call. + # Match it with its paired close. + closeOpenIndexes: -> + condition = (token, i) -> token[0] in [']', 'INDEX_END'] + action = (token, i) -> token[0] = 'INDEX_END' + @scanTokens (token, i) -> + @detectEnd i + 1, condition, action if token[0] is 'INDEX_START' + 1 + + # Object literals may be written with implicit braces, for simple cases. + # Insert the missing braces here, so that the parser doesn't have to. + addImplicitBraces: -> + stack = [] + condition = (token, i) -> + return false if 'HERECOMMENT' in [@tag(i + 1), @tag(i - 1)] + [one, two, three] = @tokens.slice i + 1, i + 4 + [tag] = token + tag in ['TERMINATOR', 'OUTDENT'] and not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':') or + tag is ',' and one?[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT'] + action = (token, i) -> @tokens.splice i, 0, ['}', '}', token[2]] + @scanTokens (token, i, tokens) -> + if include EXPRESSION_START, tag = token[0] + stack.push if tag is 'INDENT' and @tag(i - 1) is '{' then '{' else tag + return 1 + if include EXPRESSION_END, tag + stack.pop() + return 1 + return 1 unless tag is ':' and stack[stack.length - 1] isnt '{' + stack.push '{' + idx = if @tag(i - 2) is '@' then i - 2 else i - 1 + idx -= 2 if @tag(idx - 2) is 'HERECOMMENT' + tok = ['{', '{', token[2]] + tok.generated = yes + tokens.splice idx, 0, tok + @detectEnd i + 2, condition, action + 2 + + # Methods may be optionally called without parentheses, for simple cases. + # Insert the implicit parentheses here, so that the parser doesn't have to + # deal with them. + addImplicitParentheses: -> + classLine = no + action = (token, i) -> + idx = if token[0] is 'OUTDENT' then i + 1 else i + @tokens.splice idx, 0, ['CALL_END', ')', token[2]] + @scanTokens (token, i, tokens) -> + tag = token[0] + classLine = yes if tag is 'CLASS' + prev = tokens[i - 1] + next = tokens[i + 1] + callObject = not classLine and tag is 'INDENT' and + next and next.generated and next[0] is '{' and + prev and include(IMPLICIT_FUNC, prev[0]) + seenSingle = no + classLine = no if include LINEBREAKS, tag + token.call = yes if prev and not prev.spaced and tag is '?' + return 1 unless callObject or + prev?.spaced and (prev.call or include(IMPLICIT_FUNC, prev[0])) and + (include(IMPLICIT_CALL, tag) or include(IMPLICIT_UNSPACED_CALL, tag) and not token.spaced) + tokens.splice i, 0, ['CALL_START', '(', token[2]] + @detectEnd i + (if callObject then 2 else 1), (token, i) -> + return yes if not seenSingle and token.fromThen + [tag] = token + seenSingle = yes if tag in ['IF', 'ELSE', 'UNLESS', '->', '=>'] + return yes if tag is 'PROPERTY_ACCESS' and @tag(i - 1) is 'OUTDENT' + not token.generated and @tag(i - 1) isnt ',' and include(IMPLICIT_END, tag) and + (tag isnt 'INDENT' or + (@tag(i - 2) isnt 'CLASS' and not include(IMPLICIT_BLOCK, @tag(i - 1)) and + not ((post = @tokens[i + 1]) and post.generated and post[0] is '{'))) + , action + prev[0] = 'FUNC_EXIST' if prev[0] is '?' + 2 + + # Because our grammar is LALR(1), it can't handle some single-line + # expressions that lack ending delimiters. The **Rewriter** adds the implicit + # blocks, so it doesn't need to. ')' can close a single-line block, + # but we need to make sure it's balanced. + addImplicitIndentation: -> + @scanTokens (token, i, tokens) -> + [tag] = token + if tag is 'ELSE' and @tag(i - 1) isnt 'OUTDENT' + tokens.splice i, 0, @indentation(token)... + return 2 + if tag is 'CATCH' and @tag(i + 2) in ['TERMINATOR', 'FINALLY'] + tokens.splice i + 2, 0, @indentation(token)... + return 4 + if include(SINGLE_LINERS, tag) and @tag(i + 1) isnt 'INDENT' and + not (tag is 'ELSE' and @tag(i + 1) is 'IF') + starter = tag + [indent, outdent] = @indentation token + indent.fromThen = true if starter is 'THEN' + indent.generated = outdent.generated = true + tokens.splice i + 1, 0, indent + condition = (token, i) -> + token[1] isnt ';' and include(SINGLE_CLOSERS, token[0]) and + not (token[0] is 'ELSE' and starter not in ['IF', 'THEN']) + action = (token, i) -> + @tokens.splice (if @tag(i - 1) is ',' then i - 1 else i), 0, outdent + @detectEnd i + 2, condition, action + tokens.splice i, 1 if tag is 'THEN' + return 1 + return 1 + + # Tag postfix conditionals as such, so that we can parse them with a + # different precedence. + tagPostfixConditionals: -> + condition = (token, i) -> token[0] in ['TERMINATOR', 'INDENT'] + @scanTokens (token, i) -> + return 1 unless token[0] in ['IF', 'UNLESS'] + original = token + @detectEnd i + 1, condition, (token, i) -> + original[0] = 'POST_' + original[0] if token[0] isnt 'INDENT' + 1 + + # Ensure that all listed pairs of tokens are correctly balanced throughout + # the course of the token stream. + ensureBalance: (pairs) -> + levels = {} + openLine = {} + @scanTokens (token, i) -> + [tag] = token + for [open, close] in pairs + levels[open] |= 0 + if tag is open + openLine[open] = token[2] if levels[open] is 0 + levels[open] += 1 + else if tag is close + levels[open] -= 1 + throw Error "too many #{token[1]} on line #{token[2] + 1}" if levels[open] < 0 + 1 + unclosed = key for all key, value of levels when value > 0 + if unclosed.length + throw Error "unclosed #{ open = unclosed[0] } on line #{openLine[open] + 1}" + + # We'd like to support syntax like this: + # + # el.click((event) -> + # el.hide()) + # + # In order to accomplish this, move outdents that follow closing parens + # inwards, safely. The steps to accomplish this are: + # + # 1. Check that all paired tokens are balanced and in order. + # 2. Rewrite the stream with a stack: if you see an `EXPRESSION_START`, add it + # to the stack. If you see an `EXPRESSION_END`, pop the stack and replace + # it with the inverse of what we've just popped. + # 3. Keep track of "debt" for tokens that we manufacture, to make sure we end + # up balanced in the end. + # 4. Be careful not to alter array or parentheses delimiters with overzealous + # rewriting. + rewriteClosingParens: -> + stack = [] + debt = {} + (debt[key] = 0) for all key of INVERSES + @scanTokens (token, i, tokens) -> + if include EXPRESSION_START, tag = token[0] + stack.push token + return 1 + return 1 unless include EXPRESSION_END, tag + if debt[inv = INVERSES[tag]] > 0 + debt[inv] -= 1 + tokens.splice i, 1 + return 0 + match = stack.pop() + mtag = match[0] + oppos = INVERSES[mtag] + return 1 if tag is oppos + debt[mtag] += 1 + val = [oppos, if mtag is 'INDENT' then match[1] else oppos] + if @tag(i + 2) is mtag + tokens.splice i + 3, 0, val + stack.push match + else + tokens.splice i, 0, val + 1 + + # Generate the indentation tokens, based on another token on the same line. + indentation: (token) -> + [['INDENT', 2, token[2]], ['OUTDENT', 2, token[2]]] + + # Look up a tag by token index. + tag: (i) -> @tokens[i]?[0] + +# Constants +# --------- + +# List of the token pairs that must be balanced. +BALANCED_PAIRS = [ + ['(', ')'] + ['[', ']'] + ['{', '}'] + ['INDENT', 'OUTDENT'], + ['CALL_START', 'CALL_END'] + ['PARAM_START', 'PARAM_END'] + ['INDEX_START', 'INDEX_END'] +] + +# The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can +# look things up from either end. +INVERSES = {} + +# The tokens that signal the start/end of a balanced pair. +EXPRESSION_START = [] +EXPRESSION_END = [] + +for [left, rite] in BALANCED_PAIRS + EXPRESSION_START.push INVERSES[rite] = left + EXPRESSION_END .push INVERSES[left] = rite + +# Tokens that indicate the close of a clause of an expression. +EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat EXPRESSION_END + +# Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation. +IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'] + +# If preceded by an `IMPLICIT_FUNC`, indicates a function invocation. +IMPLICIT_CALL = [ + 'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS' + 'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', + '@', '->', '=>', '[', '(', '{', '--', '++' +] + +IMPLICIT_UNSPACED_CALL = ['+', '-'] + +# Tokens indicating that the implicit call must enclose a block of expressions. +IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','] + +# Tokens that always mark the end of an implicit call for single-liners. +IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'TERMINATOR', 'INDENT'] + +# Single-line flavors of block expressions that have unclosed endings. +# The grammar can't disambiguate them, so we insert the implicit indentation. +SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'] +SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'] + +# Tokens that end a line. +LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT'] diff --git a/node_modules/jade/support/coffee-script/src/scope.coffee b/node_modules/jade/support/coffee-script/src/scope.coffee new file mode 100644 index 0000000..3a1aad3 --- /dev/null +++ b/node_modules/jade/support/coffee-script/src/scope.coffee @@ -0,0 +1,109 @@ +# The **Scope** class regulates lexical scoping within CoffeeScript. As you +# generate code, you create a tree of scopes in the same shape as the nested +# function bodies. Each scope knows about the variables declared within it, +# and has a reference to its parent enclosing scope. In this way, we know which +# variables are new and need to be declared with `var`, and which are shared +# with the outside. + +# Import the helpers we plan to use. +{extend, last} = require './helpers' + +exports.Scope = class Scope + + # The top-level **Scope** object. + @root: null + + # Initialize a scope with its parent, for lookups up the chain, + # as well as a reference to the **Expressions** node is belongs to, which is + # where it should declare its variables, and a reference to the function that + # it wraps. + constructor: (@parent, @expressions, @method) -> + @variables = {'arguments'} + if @parent + @garbage = @parent.garbage + else + @garbage = [] + Scope.root = this + + # Create a new garbage level + startLevel: -> + @garbage.push [] + + # Return to the previous garbage level and erase referenced temporary + # variables in current level from scope. + endLevel: -> + vars = @variables + (vars[name] = 'reuse') for name in @garbage.pop() when vars[name] is 'var' + + # Look up a variable name in lexical scope, and declare it if it does not + # already exist. + find: (name, options) -> + return true if @check name, options + @variables[name] = 'var' + false + + # Test variables and return true the first time fn(v, k) returns true + any: (fn) -> + for v, k of @variables when fn(v, k) + return true + return false + + # Reserve a variable name as originating from a function parameter for this + # scope. No `var` required for internal references. + parameter: (name) -> + @variables[name] = 'param' + + # Just check to see if a variable has already been declared, without reserving, + # walks up to the root scope. + check: (name, options) -> + immediate = Object::hasOwnProperty.call @variables, name + return immediate if immediate or options?.immediate + !!@parent?.check name + + # Generate a temporary variable name at the given index. + temporary: (type, index) -> + if type.length > 1 + '_' + type + if index > 1 then index else '' + else + '_' + (index + parseInt type, 36).toString(36).replace /\d/g, 'a' + + # If we need to store an intermediate result, find an available name for a + # compiler-generated variable. `_var`, `_var2`, and so on... + freeVariable: (type) -> + index = 0 + index++ while @check(temp = @temporary type, index) and @variables[temp] isnt 'reuse' + @variables[temp] = 'var' + last(@garbage).push temp if @garbage.length + temp + + # Ensure that an assignment is made at the top of this scope + # (or at the top-level scope, if requested). + assign: (name, value) -> + @variables[name] = value: value, assigned: true + + # Does this scope reference any variables that need to be declared in the + # given function body? + hasDeclarations: (body) -> + body is @expressions and @any (k, val) -> val in ['var', 'reuse'] + + # Does this scope reference any assignments that need to be declared at the + # top of the given function body? + hasAssignments: (body) -> + body is @expressions and @any (k, val) -> val.assigned + + # Return the list of variables first declared in this scope. + declaredVariables: -> + (key for key, val of @variables when val in ['var', 'reuse']).sort() + + # Return the list of assignments that are supposed to be made at the top + # of this scope. + assignedVariables: -> + "#{key} = #{val.value}" for key, val of @variables when val.assigned + + # Compile the JavaScript for all of the variable declarations in this scope. + compiledDeclarations: -> + @declaredVariables().join ', ' + + # Compile the JavaScript forall of the variable assignments in this scope. + compiledAssignments: -> + @assignedVariables().join ', ' diff --git a/node_modules/jade/support/coffee-script/test/test.html b/node_modules/jade/support/coffee-script/test/test.html new file mode 100644 index 0000000..fff780c --- /dev/null +++ b/node_modules/jade/support/coffee-script/test/test.html @@ -0,0 +1,95 @@ + + + + + CoffeeScript Test Suite + + + + + +

CoffeeScript Test Suite

+

+
+  
+
+
+
\ No newline at end of file
diff --git a/node_modules/jade/support/coffee-script/test/test_arguments.coffee b/node_modules/jade/support/coffee-script/test/test_arguments.coffee
new file mode 100644
index 0000000..a45044b
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_arguments.coffee
@@ -0,0 +1,43 @@
+area = (x, y, x1, y1) ->
+  (x - x1) * (x - y1)
+
+x  = y  = 10
+x1 = y1 = 20
+
+ok area(x, y, x1, y1) is 100
+
+# ok(area(x, y,
+#            x1, y1) is 100)
+
+ok(area(
+  x
+  y
+  x1
+  y1
+) is 100)
+
+
+sumOfArgs = ->
+  sum = 0
+  sum += val for val in arguments
+  sum
+
+ok sumOfArgs(1, 2, 3, 4, 5) is 15
+
+
+((@arg) ->).call context = {}, 1
+ok context.arg is 1
+
+((splat..., @arg) ->).call context, 1, 2, 3
+ok context.arg is 3
+
+((@arg...) ->).call context, 1, 2, 3
+ok context.arg.join ' ' is '1 2 3'
+
+class Klass
+  constructor: (@one, @two) ->
+
+obj = new Klass 1, 2
+
+ok obj.one is 1
+ok obj.two is 2
\ No newline at end of file
diff --git a/node_modules/jade/support/coffee-script/test/test_assignment.coffee b/node_modules/jade/support/coffee-script/test/test_assignment.coffee
new file mode 100644
index 0000000..00d3e10
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_assignment.coffee
@@ -0,0 +1,33 @@
+# Can assign the result of a try/catch block.
+result = try
+  nonexistent * missing
+catch error
+  true
+
+result2 = try nonexistent * missing catch error then true
+
+ok result is true and result2 is true
+
+
+# Can assign a conditional statement.
+getX = -> 10
+
+if x = getX() then 100
+
+ok x is 10
+
+x = if getX() then 100
+
+ok x is 100
+
+
+# This-assignment.
+tester = ->
+  @example = -> 'example function'
+  this
+
+ok tester().example() is 'example function'
+
+
+try throw CoffeeScript.tokens 'in = 1'
+catch e then eq e.message, 'Reserved word "in" on line 1 can\'t be assigned'
diff --git a/node_modules/jade/support/coffee-script/test/test_break.coffee b/node_modules/jade/support/coffee-script/test/test_break.coffee
new file mode 100644
index 0000000..7a6219f
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_break.coffee
@@ -0,0 +1,28 @@
+# Test with break at the top level.
+array = [1,2,3]
+callWithLambda = (l) -> null
+for i in array
+  result = callWithLambda(->)
+  if i == 2
+    puts "i = 2"
+  else
+    break
+
+ok result is null
+
+
+# Test with break *not* at the top level.
+someFunc = (input) ->
+  takesLambda = (l) -> null
+  for i in [1,2]
+    result = takesLambda(->)
+    if input == 1
+      return 1
+    else
+      break
+
+  return 2
+
+ok someFunc(1) is 1
+ok someFunc(2) is 2
+
diff --git a/node_modules/jade/support/coffee-script/test/test_chaining.coffee b/node_modules/jade/support/coffee-script/test/test_chaining.coffee
new file mode 100644
index 0000000..7154a83
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_chaining.coffee
@@ -0,0 +1,56 @@
+# Basic chained function calls.
+identityWrap = (x) ->
+  -> x
+
+result = identityWrap(identityWrap(true))()()
+
+ok result
+
+
+# Chained accesses split on period/newline, backwards and forwards.
+str = 'god'
+
+result = str.
+  split('').
+  reverse().
+  reverse().
+  reverse()
+
+ok result.join('') is 'dog'
+
+result = str
+  .split('')
+  .reverse()
+  .reverse()
+  .reverse()
+
+ok result.join('') is 'dog'
+
+
+# Newline suppression for operators.
+six =
+  1 +
+  2 +
+  3
+
+ok six is 6
+
+
+# Ensure that indented array literals don't trigger whitespace rewriting.
+func = () ->
+  ok arguments.length is 1
+
+func(
+  [[[[[],
+                []],
+              [[]]]],
+    []])
+
+id = (x) -> x
+
+greeting = id(
+              """
+              Hello
+              """)
+
+ok greeting is "Hello"
diff --git a/node_modules/jade/support/coffee-script/test/test_classes.coffee b/node_modules/jade/support/coffee-script/test/test_classes.coffee
new file mode 100644
index 0000000..ea1df23
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_classes.coffee
@@ -0,0 +1,291 @@
+# Test classes with a four-level inheritance chain.
+class Base
+  func: (string) ->
+    "zero/#{string}"
+
+  @static: (string) ->
+    "static/#{string}"
+
+class FirstChild extends Base
+  func: (string) ->
+    super('one/') + string
+
+SecondChild = class extends FirstChild
+  func: (string) ->
+    super('two/') + string
+
+thirdCtor = ->
+  @array = [1, 2, 3]
+
+class ThirdChild extends SecondChild
+  constructor: thirdCtor
+
+  # Gratuitous comment for testing.
+  func: (string) ->
+    super('three/') + string
+
+result = (new ThirdChild).func 'four'
+
+ok result is 'zero/one/two/three/four'
+ok Base.static('word') is 'static/word'
+
+FirstChild::func = (string) ->
+  super('one/').length + string
+
+result = (new ThirdChild).func 'four'
+
+ok result is '9two/three/four'
+
+ok (new ThirdChild).array.join(' ') is '1 2 3'
+
+
+class TopClass
+  constructor: (arg) ->
+    @prop = 'top-' + arg
+
+class SuperClass extends TopClass
+  constructor: (arg) ->
+    super 'super-' + arg
+
+class SubClass extends SuperClass
+  constructor: ->
+    super 'sub'
+
+ok (new SubClass).prop is 'top-super-sub'
+
+
+class OneClass
+  @new: 'new'
+  function: 'function'
+  constructor: (name) -> @name = name
+
+class TwoClass extends OneClass
+
+Function.prototype.new = -> new this arguments...
+
+ok (TwoClass.new('three')).name is 'three'
+ok (new OneClass).function is 'function'
+ok OneClass.new is 'new'
+
+delete Function.prototype.new
+
+
+# And now the same tests, but written in the manual style:
+Base = ->
+Base::func = (string) ->
+  'zero/' + string
+Base::['func-func'] = (string) ->
+  "dynamic-#{string}"
+
+FirstChild = ->
+FirstChild extends Base
+FirstChild::func = (string) ->
+  super('one/') + string
+
+SecondChild = ->
+SecondChild extends FirstChild
+SecondChild::func = (string) ->
+  super('two/') + string
+
+ThirdChild = ->
+  @array = [1, 2, 3]
+  this
+ThirdChild extends SecondChild
+ThirdChild::func = (string) ->
+  super('three/') + string
+
+result = (new ThirdChild).func 'four'
+
+ok result is 'zero/one/two/three/four'
+
+ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
+
+
+TopClass = (arg) ->
+  @prop = 'top-' + arg
+  this
+
+SuperClass = (arg) ->
+  super 'super-' + arg
+  this
+
+SubClass = ->
+  super 'sub'
+  this
+
+SuperClass extends TopClass
+SubClass extends SuperClass
+
+ok (new SubClass).prop is 'top-super-sub'
+
+
+# '@' referring to the current instance, and not being coerced into a call.
+class ClassName
+  amI: ->
+    @ instanceof ClassName
+
+obj = new ClassName
+ok obj.amI()
+
+
+# super() calls in constructors of classes that are defined as object properties.
+class Hive
+  constructor: (name) -> @name = name
+
+class Hive.Bee extends Hive
+  constructor: (name) -> super
+
+maya = new Hive.Bee 'Maya'
+ok maya.name is 'Maya'
+
+
+# Class with JS-keyword properties.
+class Class
+  class: 'class'
+  name: -> @class
+
+instance = new Class
+ok instance.class is 'class'
+ok instance.name() is 'class'
+
+
+# Classes with methods that are pre-bound to the instance.
+# ... or statically, to the class.
+class Dog
+
+  constructor: (name) ->
+    @name = name
+
+  bark: =>
+    "#{@name} woofs!"
+
+  @static: =>
+    new this('Dog')
+
+spark = new Dog('Spark')
+fido  = new Dog('Fido')
+fido.bark = spark.bark
+
+ok fido.bark() is 'Spark woofs!'
+
+obj = func: Dog.static
+
+ok obj.func().name is 'Dog'
+
+
+# Testing a bound function in a bound function.
+class Mini
+  num: 10
+  generate: =>
+    for i in [1..3]
+      =>
+        @num
+
+m = new Mini
+ok (func() for func in m.generate()).join(' ') is '10 10 10'
+
+
+# Testing a contructor called with varargs.
+class Connection
+  constructor: (one, two, three) ->
+    [@one, @two, @three] = [one, two, three]
+
+  out: ->
+    "#{@one}-#{@two}-#{@three}"
+
+list = [3, 2, 1]
+conn = new Connection list...
+ok conn instanceof Connection
+ok conn.out() is '3-2-1'
+
+
+# Test calling super and passing along all arguments.
+class Parent
+  method: (args...) -> @args = args
+
+class Child extends Parent
+  method: -> super
+
+c = new Child
+c.method 1, 2, 3, 4
+ok c.args.join(' ') is '1 2 3 4'
+
+
+# Test `extended` callback.
+class Base
+  @extended: (subclass) ->
+    for key, value of @
+      subclass[key] = value
+
+class Element extends Base
+  @fromHTML: (html) ->
+    node = "..."
+    new @(node)
+
+  constructor: (node) ->
+    @node = node
+
+ok Element.extended is Base.extended
+ok Element.__super__ is Base.prototype
+
+class MyElement extends Element
+
+ok MyElement.extended is Base.extended
+ok MyElement.fromHTML is Element.fromHTML
+ok MyElement.__super__ is Element.prototype
+
+
+# Test classes wrapped in decorators.
+func = (klass) ->
+  klass::prop = 'value'
+  klass
+
+func class Test
+  prop2: 'value2'
+
+ok (new Test).prop  is 'value'
+ok (new Test).prop2 is 'value2'
+
+
+# Test anonymous classes.
+obj =
+  klass: class
+    method: -> 'value'
+
+instance = new obj.klass
+ok instance.method() is 'value'
+
+
+# Implicit objects as static properties.
+class Static
+  @static:
+    one: 1
+    two: 2
+
+ok Static.static.one is 1
+ok Static.static.two is 2
+
+
+# Nothing classes.
+c = class
+ok c instanceof Function
+
+
+# Classes with value'd constructors.
+counter = 0
+classMaker = ->
+  counter += 1
+  inner = counter
+  ->
+    @value = inner
+
+class One
+  constructor: classMaker()
+
+class Two
+  constructor: classMaker()
+
+ok (new One).value is 1
+ok (new Two).value is 2
+ok (new One).value is 1
+ok (new Two).value is 2
diff --git a/node_modules/jade/support/coffee-script/test/test_comments.coffee b/node_modules/jade/support/coffee-script/test/test_comments.coffee
new file mode 100644
index 0000000..7743e1b
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_comments.coffee
@@ -0,0 +1,166 @@
+# comment before a ...
+
+###
+... block comment.
+###
+
+
+  # comment
+func = ->
+# comment
+  false
+  false   # comment
+  false
+
+# comment
+  true
+
+switch 'string'
+  # comment
+  when false then something()
+  # comment
+  when null
+    somethingElse()
+
+->
+  code()
+  # comment
+
+ok func()
+
+func
+func
+# Line3
+
+obj = {
+# comment
+  # comment
+    # comment
+  one: 1
+# comment
+  two: 2
+    # comment
+}
+
+result = if true # comment
+  false
+
+ok not result
+
+result = if false
+  false
+else # comment
+  45
+
+ok result is 45
+
+
+test =
+  'test ' +
+  'test ' + # comment
+  'test'
+
+ok test is 'test test test'
+
+###
+  This is a here-comment.
+  Kind of like a heredoc.
+###
+
+func = ->
+  ###
+  Another block comment.
+  ###
+  code
+
+func = ->
+  one = ->
+    two = ->
+      three = ->
+  ###
+  block.
+  ###
+  four = ->
+
+fn1 = ->
+  oneLevel = null
+###
+This isn't fine.
+###
+
+ok ok
+
+obj = {
+  a: 'b'
+  ###
+  comment
+  ###
+  c: 'd'
+}
+
+arr = [
+  1, 2, 3,
+  ###
+  four
+  ###
+  5, 6, 7
+]
+
+# Spaced comments in if / elses.
+result = if false
+  1
+
+# comment
+else if false
+  2
+
+# comment
+else
+  3
+
+ok result is 3
+
+
+result = switch 'z'
+  when 'z' then 7
+# comment
+ok result is 7
+
+
+# Trailing-line comment before an outdent.
+func = ->
+  if true
+    true # comment
+  7
+
+ok func() is 7
+
+
+# Trailing herecomment in a function.
+fn = ->
+  code
+  ###
+  debug code commented
+  ###
+
+fn2 = ->
+
+
+class A
+  b: ->
+
+  ###
+  Comment
+  ###
+  c: ->
+
+ok A.prototype.c instanceof Function
+
+class A
+  ###
+  Comment
+  ###
+  b: ->
+  c: ->
+
+ok A.prototype.b instanceof Function
diff --git a/node_modules/jade/support/coffee-script/test/test_compilation.coffee b/node_modules/jade/support/coffee-script/test/test_compilation.coffee
new file mode 100644
index 0000000..ad8c65b
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_compilation.coffee
@@ -0,0 +1,11 @@
+# Ensure that carriage returns don't break compilation on Windows.
+eq CoffeeScript.compile('one\r\ntwo', bare: on), 'one;\ntwo;'
+
+# `globals: on` removes `var`s
+eq CoffeeScript.compile('x = y', bare: on, globals: on), 'x = y;'
+
+ok 'passed' is CoffeeScript.eval '"passed"', bare: on, fileName: 'test'
+
+#750
+try ok not CoffeeScript.nodes 'f(->'
+catch e then eq e.message, 'unclosed CALL_START on line 1'
diff --git a/node_modules/jade/support/coffee-script/test/test_compound_assignment.coffee b/node_modules/jade/support/coffee-script/test/test_compound_assignment.coffee
new file mode 100644
index 0000000..cc2fe58
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_compound_assignment.coffee
@@ -0,0 +1,26 @@
+num = 10
+num -= 5
+eq num, 5
+
+num *= 10
+eq num, 50
+
+num /= 10
+eq num, 5
+
+num %= 3
+eq num, 2
+
+val = false
+val ||= 'value'
+val ||= 'eulav'
+eq val, 'value'
+
+val &&= 'rehto'
+val &&= 'other'
+eq val, 'other'
+
+val = null
+val ?= 'value'
+val ?= 'eulav'
+eq val, 'value'
diff --git a/node_modules/jade/support/coffee-script/test/test_comprehensions.coffee b/node_modules/jade/support/coffee-script/test/test_comprehensions.coffee
new file mode 100644
index 0000000..2aff0bf
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_comprehensions.coffee
@@ -0,0 +1,172 @@
+# Basic array comprehensions.
+nums =    n * n for n in [1, 2, 3] when n % 2 isnt 0
+results = n * 2 for n in nums
+
+ok results.join(',') is '2,18'
+
+
+# Basic object comprehensions.
+obj   = {one: 1, two: 2, three: 3}
+names = prop + '!' for prop of obj
+odds  = prop + '!' for prop, value of obj when value % 2 isnt 0
+
+ok names.join(' ') is "one! two! three!"
+ok odds.join(' ')  is "one! three!"
+
+
+# Basic range comprehensions.
+nums = i * 3 for i in [1..3]
+
+negs = x for x in [-20..-5*2]
+negs = negs[0..2]
+
+result = nums.concat(negs).join(', ')
+
+ok result is '3, 6, 9, -20, -19, -18'
+ok i is 3
+ok x is -10
+
+
+# With range comprehensions, you can loop in steps.
+results = x for x in [0...15] by 5
+ok results.join(' ') is '0 5 10'
+
+results = x for x in [0..100] by 10
+ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100'
+
+
+# And can loop downwards, with a negative step.
+results = x for x in [5..1]
+
+ok results.join(' ') is '5 4 3 2 1'
+ok results.join(' ') is [(10-5)..(-2+3)].join(' ')
+
+results = x for x in [10..1]
+ok results.join(' ') is [10..1].join(' ')
+
+results = x for x in [10...0] by -2
+ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')
+
+
+# Multiline array comprehension with filter.
+evens = for num in [1, 2, 3, 4, 5, 6] when num % 2 is 0
+           num *= -1
+           num -= 2
+           num * -1
+
+ok evens.join(', ') is '4, 6, 8'
+
+
+# The in operator still works, standalone.
+ok 2 of evens
+
+
+# Ensure that the closure wrapper preserves local variables.
+obj = {}
+
+for method in ['one', 'two', 'three']
+  obj[method] = ->
+    "I'm " + method
+
+ok obj.one()   is "I'm one"
+ok obj.two()   is "I'm two"
+ok obj.three() is "I'm three"
+
+i = 0
+for i in [1..3]
+  -> 'func'
+  break if false
+ok i is 3
+
+
+# Ensure that local variables are closed over for range comprehensions.
+funcs = for i in [1..3]
+  -> -i
+
+ok (func() for func in funcs).join(' ') is '-1 -2 -3'
+ok i is 3
+
+
+# Ensure that closing over local variables doesn't break scoping laws.
+for i in [0]
+  count = 0
+  i = 50
+  ->
+ok count is 0
+ok i is 50
+
+
+# Even when referenced in the filter.
+list = ['one', 'two', 'three']
+
+methods = for num, i in list when num isnt 'two' and i isnt 1
+  -> num + ' ' + i
+
+ok methods.length is 2
+ok methods[0]() is 'one 0'
+ok methods[1]() is 'three 2'
+
+
+# Naked ranges are expanded into arrays.
+array = [0..10]
+ok(num % 2 is 0 for num in array by 2)
+
+
+# Nested comprehensions.
+multiLiner =
+  for x in [3..5]
+    for y in [3..5]
+      [x, y]
+
+singleLiner =
+  [x, y] for y in [3..5] for x in [3..5]
+
+ok multiLiner.length is singleLiner.length
+ok 5 is multiLiner[2][2][1]
+ok 5 is singleLiner[2][2][1]
+
+
+# Comprehensions within parentheses.
+result = null
+store = (obj) -> result = obj
+store (x * 2 for x in [3, 2, 1])
+
+ok result.join(' ') is '6 4 2'
+
+
+# Closure-wrapped comprehensions that refer to the "arguments" object.
+expr = ->
+  result = item * item for item in arguments
+
+ok expr(2, 4, 8).join(' ') is '4 16 64'
+
+
+# Fast object comprehensions over all properties, including prototypal ones.
+class Cat
+  constructor: -> @name = 'Whiskers'
+  breed: 'tabby'
+  hair:  'cream'
+
+whiskers = new Cat
+own = value for key, value of whiskers
+all = value for all key, value of whiskers
+
+ok own.join(' ') is 'Whiskers'
+ok all.sort().join(' ') is 'Whiskers cream tabby'
+
+
+# Optimized range comprehensions.
+exxes = 'x' for [0...10]
+ok exxes.join(' ') is 'x x x x x x x x x x'
+
+
+# Comprehensions safely redeclare parameters if they're not present in closest
+# scope.
+rule = (x) -> x
+
+learn = ->
+  rule for rule in [1, 2, 3]
+
+ok learn().join(' ') is '1 2 3'
+
+ok rule(101) is 101
\ No newline at end of file
diff --git a/node_modules/jade/support/coffee-script/test/test_existence.coffee b/node_modules/jade/support/coffee-script/test/test_existence.coffee
new file mode 100644
index 0000000..e0687bf
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_existence.coffee
@@ -0,0 +1,145 @@
+ok(if mySpecialVariable? then false else true)
+
+mySpecialVariable = false
+
+ok(if mySpecialVariable? then true else false)
+
+
+# Existential assignment.
+a = 5
+a = null
+a ?= 10
+b ?= 10
+
+ok a is 10 and b is 10
+
+
+# The existential operator.
+z = null
+x = z ? "EX"
+ok z is null and x is "EX"
+
+i = 9
+func = -> i += 1
+result = func() ? 101
+ok result is 10
+
+# Only evaluate once.
+counter = 0
+getNextNode = ->
+  throw "up" if counter
+  counter++
+
+ok(if getNextNode()? then true else false)
+
+
+# Existence chains, soaking up undefined properties:
+obj =
+  prop: "hello"
+
+eq obj?.prop, "hello"
+eq obj?['prop'], "hello"
+eq obj.prop?.length, 5
+eq obj?.prop?['length'], 5
+eq obj?.prop?.non?.existent?.property, undefined
+
+
+# Soaks and caches method calls as well.
+arr = ["--", "----"]
+
+eq arr.pop()?.length, 4
+eq arr.pop()?.length, 2
+eq arr.pop()?.length, undefined
+eq arr.pop()?.length?.non?.existent()?.property, undefined
+
+
+# Soaks method calls safely.
+value = null
+eq value?.toString().toLowerCase(), undefined
+
+value = 10
+eq value?.toString().toLowerCase(), '10'
+
+eq 0.nothing?.property() or 101, 101
+
+counter = 0
+func = ->
+  counter += 1
+  'prop'
+obj =
+  prop: -> this
+  value: 25
+
+ok obj[func()]()[func()]()[func()]()?.value is 25
+ok counter is 3
+
+
+ident = (obj) -> obj
+eq ident(non?.existent().method()), undefined, 'soaks inner values'
+
+
+# Soaks constructor invocations.
+a = 0
+class Foo
+  constructor: -> a += 1
+  bar: "bat"
+
+ok (new Foo())?.bar is 'bat'
+ok a is 1
+
+
+ok not value?.property?, 'safely checks existence on soaks'
+
+
+eq nothing?.value, undefined, 'safely calls values off of non-existent variables'
+eq !nothing?.value and 1, 1,  'corresponding operators work as expected'
+
+
+# Assign to the result of an exsitential operation with a minus.
+x = null ? - 1
+ok x is - 1
+
+
+# Things that compile to ternaries should force parentheses, like operators do.
+duration = if options?.animated then 150 else 0
+ok duration is 0
+
+
+# Function soaks.
+plus1 = (x) -> x + 1
+count = 0
+obj = {
+  counter: -> count += 1; this
+  returnThis: -> this
+}
+
+eq plus1?(41), 42
+eq (plus1? 41), 42
+eq plus2?(41), undefined
+eq (plus2? 41), undefined
+eq obj.returnThis?(), obj
+eq obj.returnSelf?(), undefined
+eq obj.returnThis?().flag = on, on
+eq obj.returnSelf?().flag = on, undefined
+eq obj.counter().counter().returnThis?(), obj
+eq count, 2
+
+maybe_close = (f, arg) -> if typeof f is 'function' then () -> f(arg) else -1
+
+eq maybe_close(plus1, 41)?(), 42
+eq (maybe_close plus1, 41)?(), 42
+eq (maybe_close 'string', 41)?(), undefined
+
+eq 2?(3), undefined
+eq new Number?(42) | 0, 42
+eq new Bumper?(42) | 0, 0
+
+#726
+eq calendar?[Date()], undefined
+
+#733
+a = b: {c: null}
+eq a.b?.c?(), undefined
+a.b?.c or= (it) -> it
+eq a.b?.c?(1), 1
+eq a.b?.c?([2, 3]...), 2
diff --git a/node_modules/jade/support/coffee-script/test/test_expressions.coffee b/node_modules/jade/support/coffee-script/test/test_expressions.coffee
new file mode 100644
index 0000000..9572a6c
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_expressions.coffee
@@ -0,0 +1,40 @@
+# Ensure that we don't wrap Nodes that are "pureStatement" in a closure.
+items = [1, 2, 3, "bacon", 4, 5]
+
+for item in items
+  break if item is "bacon"
+
+findit = (items) ->
+  for item in items
+    return item if item is "bacon"
+
+ok findit(items) is "bacon"
+
+
+# When when a closure wrapper is generated for expression conversion, make sure
+# that references to "this" within the wrapper are safely converted as well.
+obj = {
+  num: 5
+  func: ->
+    this.result = if false
+      10
+    else
+      "a"
+      "b"
+      this.num
+}
+
+ok obj.num is obj.func()
+ok obj.num is obj.result
+
+
+# Should be able to look at prototypes on keywords.
+obj =
+  withAt:   -> @::prop
+  withThis: -> this::prop
+  proto:
+    prop: 100
+
+obj.prototype = obj.proto
+ok obj.withAt() is 100
+ok obj.withThis() is 100
\ No newline at end of file
diff --git a/node_modules/jade/support/coffee-script/test/test_functions.coffee b/node_modules/jade/support/coffee-script/test/test_functions.coffee
new file mode 100644
index 0000000..c39e6c0
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_functions.coffee
@@ -0,0 +1,346 @@
+x = 1
+y = {}
+y.x = -> 3
+
+ok x is 1
+ok typeof(y.x) is 'function'
+ok y.x instanceof Function
+ok y.x() is 3
+
+
+# The empty function should not cause a syntax error.
+->
+() ->
+
+
+# Multiple nested function declarations mixed with implicit calls should not
+# cause a syntax error.
+(one) -> (two) -> three four, (five) -> six seven, eight, (nine) ->
+
+
+obj = {
+  name: 'Fred'
+
+  bound: ->
+    (=> eq this, obj)()
+
+  unbound: ->
+    (-> ok this isnt obj)()
+
+  nested: ->
+    (=>
+      (=>
+        (=>
+          eq this, obj
+        )()
+      )()
+    )()
+}
+
+obj.unbound()
+obj.bound()
+obj.nested()
+
+
+# Python decorator style wrapper that memoizes any function
+memoize = (fn) ->
+  cache = {}
+  self  = this
+  (args...) ->
+    key = args.toString()
+    return cache[key] if cache[key]
+    cache[key] = fn.apply(self, args)
+
+Math = {
+  Add: (a, b) -> a + b
+  AnonymousAdd: ((a, b) -> a + b)
+  FastAdd: memoize (a, b) -> a + b
+}
+
+ok Math.Add(5, 5) is 10
+ok Math.AnonymousAdd(10, 10) is 20
+ok Math.FastAdd(20, 20) is 40
+
+
+# Parens are optional on simple function calls.
+ok 100 > 1 if 1 > 0
+ok true unless false
+ok true for i in [1..3]
+
+okFunc = (f) -> ok(f())
+okFunc -> true
+
+# Optional parens can be used in a nested fashion.
+call = (func) -> func()
+
+result = call ->
+  inner = call ->
+    Math.Add(5, 5)
+
+ok result is 10
+
+
+# More fun with optional parens.
+fn = (arg) -> arg
+
+ok fn(fn {prop: 101}).prop is 101
+
+
+# Multi-blocks with optional parens.
+result = fn( ->
+  fn ->
+    "Wrapped"
+)
+
+ok result()() is 'Wrapped'
+
+
+# And even with strange things like this:
+funcs  = [((x) -> x), ((x) -> x * x)]
+result = funcs[1] 5
+
+ok result is 25
+
+result = ("hello".slice) 3
+
+ok result is 'lo'
+
+
+# And with multiple single-line functions on the same line.
+func = (x) -> (x) -> (x) -> x
+ok func(1)(2)(3) is 3
+
+
+# Ensure that functions with the same name don't clash with helper functions.
+del = -> 5
+ok del() is 5
+
+# Ensure that functions can have a trailing comma in their argument list
+mult = (x, mids..., y) ->
+  x *= n for n in mids
+  x *= y
+
+ok mult(1, 2,) is 2
+ok mult(1, 2, 3,) is 6
+ok mult(10,[1..6]...,) is 7200
+
+
+# Test for inline functions with parentheses and implicit calls.
+combine = (func, num) -> func() * num
+result  = combine (-> 1 + 2), 3
+
+ok result is 9
+
+
+# Test for calls/parens/multiline-chains.
+f = (x) -> x
+result = (f 1).toString()
+  .length
+
+ok result is 1
+
+
+# Test implicit calls in functions in parens:
+result = ((val) ->
+  [].push val
+  val
+)(10)
+
+ok result is 10
+
+
+# More paren compilation tests:
+reverse = (obj) -> obj.reverse()
+ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
+
+# Passing multiple functions without paren-wrapping is legal, and should compile.
+sum = (one, two) -> one() + two()
+result = sum ->
+  7 + 9
+, ->
+  1 + 3
+
+ok result is 20
+
+
+# Implicit call with a trailing if statement as a param.
+func = -> arguments[1]
+result = func 'one', if false then 100 else 13
+ok result is 13
+
+
+# Test more function passing:
+result = sum( ->
+  1 + 2
+, ->
+  2 + 1
+)
+ok result is 6
+
+sum = (a, b) -> a + b
+result = sum(1
+, 2)
+
+ok result is 3
+
+
+# This is a crazy one.
+x = (obj, func) -> func obj
+ident = (x) -> x
+
+result = x {one: ident 1}, (obj) ->
+  inner = ident(obj)
+  ident inner
+
+ok result.one is 1
+
+
+# Assignment to a Object.prototype-named variable should not leak to outer scope.
+# FIXME: fails on IE
+(->
+  constructor = 'word'
+)()
+
+ok constructor isnt 'word'
+
+
+# Trying an implicit object call with a trailing function.
+a = null
+meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
+
+meth 'apple', b: 1, a: 13, ->
+  'orange'
+
+ok a is '13 apple orange'
+
+
+# Ensure that empty functions don't return mistaken values.
+obj =
+  func: (@param, @rest...) ->
+
+ok obj.func(101, 102, 103, 104) is undefined
+ok obj.param is 101
+ok obj.rest.join(' ') is '102 103 104'
+
+
+# `@` and `this` should both be able to invoke a method.
+func          = (arg) -> ok arg is true
+func.withAt   = -> @ true
+func.withThis = -> this true
+
+func.withAt()
+func.withThis()
+
+
+# Ensure that constructors invoked with splats return a new object.
+args = [1, 2, 3]
+Type = (@args) ->
+type = new Type args
+
+ok type and type instanceof Type
+ok type.args and type.args instanceof Array
+ok v is args[i] for v, i in type.args
+
+Type1 = (@a, @b, @c) ->
+type1 = new Type1 args...
+
+ok type1 instanceof   Type1
+eq type1.constructor, Type1
+ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
+
+
+# Ensure that constructors invoked with splats cache the function.
+called = 0
+get = -> if called++ then false else class Type
+new get() args...
+
+
+# Chained blocks, with proper indentation levels:
+counter =
+  results: []
+  tick: (func) ->
+    @results.push func()
+    this
+
+counter
+  .tick ->
+    3
+  .tick ->
+    2
+  .tick ->
+    1
+
+eq counter.results.join(' '), '3 2 1'
+
+
+# Make incorrect indentation safe.
+func = ->
+  obj = {
+          key: 10
+        }
+  obj.key - 5
+
+eq func(), 5
+
+
+# Ensure that chained calls with indented implicit object literals below are
+# alright.
+result = null
+obj =
+  method: (val)  -> this
+  second: (hash) -> result = hash.three
+
+
+obj
+  .method(
+    101
+  ).second(
+    one:
+      two: 2
+    three: 3
+  )
+
+eq result, 3
+
+
+# Test newline-supressed call chains with nested functions.
+obj  =
+  call: -> this
+func = ->
+  obj
+    .call ->
+      one two
+    .call ->
+      three four
+  101
+
+eq func(), 101
+
+
+# `new` shouldn't add extra parens
+ok new Date().constructor is Date
+
+
+# `new` works against bare function
+eq Date, new ->
+  eq this, new => this
+  Date
+
+
+# Implicit objects with number arguments.
+func = (x, y) -> y
+obj =
+  prop: func "a", 1
+
+ok obj.prop is 1
+
+
+# Non-spaced unary and binary operators should cause a function call.
+func = (val) -> val + 1
+ok (func +5) is 6
+ok (func -5) is -4
+
+
+# Prefix unary assignment operators are allowed in parenless calls.
+val = 5
+ok (func --val) is 5
diff --git a/node_modules/jade/support/coffee-script/test/test_helpers.coffee b/node_modules/jade/support/coffee-script/test/test_helpers.coffee
new file mode 100644
index 0000000..56a8017
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_helpers.coffee
@@ -0,0 +1,49 @@
+{indexOf, include, starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
+
+array  = [0..4]
+string = array.join ''
+object = {}
+
+# Test `indexOf`
+eq 0, indexOf array, 0
+eq 2, indexOf array, 2
+eq 4, indexOf array, 4
+eq(-1, indexOf array, 6)
+
+# Test `include`
+ok include array, 0
+ok include array, 2
+ok include array, 4
+ok not include array, 6
+
+# Test `starts`
+ok starts string, '012'
+ok starts string, '34', 3
+ok not starts string, '42'
+ok not starts string, '42', 6
+
+# Test `ends`
+ok ends string, '234'
+ok ends string, '01', 3
+ok not ends string, '42'
+ok not ends string, '42', 6
+
+# Test `merge`
+merged = merge object, array
+ok merged isnt object
+eq merged[3], 3
+
+# Test `extend`
+ok object is extend object, array
+eq object[3], 3
+
+# Test `flatten`
+eq "#{ flatten [0, [1, 2], 3, [4]] }", "#{ array }"
+
+# Test `del`
+eq 1, del object, 1
+ok 1 not of object
+
+# Test `last`
+eq 4, last array
+eq 2, last array, 2
diff --git a/node_modules/jade/support/coffee-script/test/test_heredocs.coffee b/node_modules/jade/support/coffee-script/test/test_heredocs.coffee
new file mode 100644
index 0000000..330ecdf
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_heredocs.coffee
@@ -0,0 +1,111 @@
+a = """
+    basic heredoc
+    on two lines
+    """
+
+ok a is "basic heredoc\non two lines"
+
+
+a = '''
+    a
+      "b
+    c
+    '''
+
+ok a is "a\n  \"b\nc"
+
+
+a = """
+a
+ b
+  c
+"""
+
+ok a is "a\n b\n  c"
+
+
+a = '''one-liner'''
+
+ok a is 'one-liner'
+
+
+a = """
+      out
+      here
+"""
+
+ok a is "out\nhere"
+
+
+a = '''
+       a
+     b
+   c
+    '''
+
+ok a is "    a\n  b\nc"
+
+
+a = '''
+a
+
+
+b c
+'''
+
+ok a is "a\n\n\nb c"
+
+
+a = '''more"than"one"quote'''
+
+ok a is 'more"than"one"quote'
+
+
+val = 10
+
+a = """
+    basic heredoc #{val}
+    on two lines
+    """
+
+b = '''
+    basic heredoc #{val}
+    on two lines
+    '''
+
+ok a is "basic heredoc 10\non two lines"
+ok b is "basic heredoc \#{val}\non two lines"
+
+
+a = '''here's an apostrophe'''
+ok a is "here's an apostrophe"
+
+
+# The indentation detector ignores blank lines without trailing whitespace
+a = """
+    one
+    two
+
+    """
+ok a is "one\ntwo\n"
+
+eq ''' line 0
+  should not be relevant
+    to the indent level
+''', '
+ line 0\n
+should not be relevant\n
+  to the indent level
+'
+
+eq ''' '\\\' ''', " '\\' "
+eq """ "\\\" """, ' "\\" '
+
+eq '''  <- keep these spaces ->  ''', '  <- keep these spaces ->  '
+
+eq 'multiline nested "interpolations" work', """multiline #{
+  "nested #{(->
+    ok yes
+    "\"interpolations\""
+  )()}"
+} work"""
diff --git a/node_modules/jade/support/coffee-script/test/test_if.coffee b/node_modules/jade/support/coffee-script/test/test_if.coffee
new file mode 100644
index 0000000..42ba54b
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_if.coffee
@@ -0,0 +1,146 @@
+a = b = d = true
+c = false
+
+result = if a
+  if b
+    if c then false else
+      if d
+        true
+
+ok result
+
+
+first = if false then false else second = if false then false else true
+
+ok first
+ok second
+
+
+result = if false
+  false
+else if NaN
+  false
+else
+  true
+
+ok result
+
+
+# Testing unless.
+result = unless true
+  10
+else
+  11
+
+ok result is 11
+
+
+# Nested inline if statements.
+echo = (x) -> x
+result = if true then echo((if false then 'xxx' else 'y') + 'a')
+ok result is 'ya'
+
+
+# Testing inline funcs with inline if-elses.
+func = -> if 1 < 0.5 then 1 else -1
+ok func() is -1
+
+
+# Testing empty or commented if statements ... should compile:
+result = if false
+else if false
+else
+
+ok result is undefined
+
+result = if false
+  # comment
+else if true
+  # comment
+else
+
+ok result is undefined
+
+
+# Return an if with no else.
+func = ->
+  return if false then callback()
+
+ok func() is undefined
+
+func = ->
+  return unless false then 100 else -100
+
+ok func() is 100
+
+ident = (x) -> x
+result = ident if false then 300 else 100
+
+ok result is 100
+
+
+# If-to-ternary with instanceof requires parentheses (no comment).
+if {} instanceof Object
+  ok yes
+else
+  ok no
+
+try
+  {} + {}
+  ok yes
+catch e
+  ok no
+
+
+# If-to-ternary as part of a larger operation requires parens.
+x = 1
+result = x + if false then 10 else 1
+ok result is 2
+
+
+# If/else indented within an assignment.
+func = ->
+  a =
+    if false
+      3
+    else
+      5
+  101
+  a
+
+ok func() is 5
+
+
+# Unmatched 'then' should catch implicit calls.
+i = 1
+isTrue = (x) -> x is true
+
+if isTrue yes then i += 1
+
+ok i is 2
+
+# If/else with a suppressed indentation via assignment.
+result =
+  if      false then 10
+  else if no    then 20
+  else if 0     then 30
+  else if NaN   then 40
+  else               50 +
+       if false then 10
+       else          20
+
+ok result is 70
+
+
+# Issue #738
+func = if true then -> 1
+eq func(), 1
+
+
+# Issue #748. Trailing reserved identifiers.
+obj = delete: true
+
+result = if obj.delete
+  101
+
+ok result is 101
diff --git a/node_modules/jade/support/coffee-script/test/test_importing.coffee b/node_modules/jade/support/coffee-script/test/test_importing.coffee
new file mode 100644
index 0000000..e069938
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_importing.coffee
@@ -0,0 +1,3 @@
+# Check if we can import and execute a CoffeeScript-only module successfully.
+if require?.extensions? or require?.registerExtension?
+  ok require('./test_module').func() is "from over there"
diff --git a/node_modules/jade/support/coffee-script/test/test_literals.coffee b/node_modules/jade/support/coffee-script/test/test_literals.coffee
new file mode 100644
index 0000000..b753b45
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_literals.coffee
@@ -0,0 +1,247 @@
+a = [((x) -> x), ((x) -> x * x)]
+
+ok a.length is 2
+
+
+neg = (3 -4)
+
+ok neg is -1
+
+
+# Decimal number literals.
+value = .25 + .75
+ok value is 1
+value = 0.0 + -.25 - -.75 + 0.0
+ok value is 0.5
+
+# Decimals don't interfere with ranges.
+ok [0..10].join(' ') is  '0 1 2 3 4 5 6 7 8 9 10'
+ok [0...10].join(' ') is '0 1 2 3 4 5 6 7 8 9'
+
+
+# Can call methods directly on numbers.
+4.valueOf() is 4
+
+
+func = ->
+  return if true
+
+ok func() is undefined
+
+
+trailingComma = [1, 2, 3,]
+ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
+
+trailingComma = [
+  1, 2, 3,
+  4, 5, 6
+  7, 8, 9,
+]
+(sum = (sum or 0) + n) for n in trailingComma
+
+trailingComma = {k1: "v1", k2: 4, k3: (-> true),}
+ok trailingComma.k3() and (trailingComma.k2 is 4) and (trailingComma.k1 is "v1")
+
+
+ok {a: (num) -> num is 10 }.a 10
+
+
+moe = {
+  name:  'Moe'
+  greet: (salutation) ->
+    salutation + " " + @name
+  hello: ->
+    @['greet'] "Hello"
+  10: 'number'
+}
+
+ok moe.hello() is "Hello Moe"
+ok moe[10] is 'number'
+
+moe.hello = ->
+  this['greet'] "Hello"
+
+ok moe.hello() is 'Hello Moe'
+
+
+obj = {
+  is:     -> yes,
+  'not':  -> no,
+}
+
+ok obj.is()
+ok not obj.not()
+
+
+# Top-level object literal doesn't break things.
+obj: 1
+
+
+# Funky indentation within non-comma-seperated arrays.
+result = [['a']
+ {b: 'c'}]
+
+ok result[0][0] is 'a'
+ok result[1]['b'] is 'c'
+
+
+# Object literals should be able to include keywords.
+obj = {class: 'höt'}
+obj.function = 'dog'
+
+ok obj.class + obj.function is 'hötdog'
+
+
+# But keyword assignment should be smart enough not to stringify variables.
+func = ->
+  this == 'this'
+
+ok func() is false
+
+
+# New fancy implicit objects:
+config =
+  development:
+    server: 'localhost'
+    timeout: 10
+
+  production:
+    server: 'dreamboat'
+    timeout: 1000
+
+ok config.development.server  is 'localhost'
+ok config.production.server   is 'dreamboat'
+ok config.development.timeout is 10
+ok config.production.timeout  is 1000
+
+obj =
+  a: 1
+  b: 2
+
+ok obj.a is 1
+ok obj.b is 2
+
+obj =
+  a: 1,
+  b: 2,
+
+ok obj.a is 1
+ok obj.b is 2
+
+
+# Implicit objects nesting.
+obj =
+  options:
+    value: yes
+
+  fn: ->
+    {}
+    null
+
+ok obj.options.value is yes
+ok obj.fn() is null
+
+
+# Implicit arguments to function calls:
+func = (obj) -> obj.a
+
+result = func
+  a: 10
+
+ok result is 10
+
+result = func
+  "a": 20
+
+ok result is 20
+
+third = (a, b, c) -> c
+obj =
+  one: 'one'
+  two: third 'one', 'two', 'three'
+
+ok obj.one is 'one'
+ok obj.two is 'three'
+
+
+# Implicit objects with wacky indentation:
+obj =
+  'reverse': (obj) ->
+    Array.prototype.reverse.call obj
+  abc: ->
+    @reverse(
+      @reverse @reverse ['a', 'b', 'c'].reverse()
+    )
+  one: [1, 2,
+    a: 'b'
+  3, 4]
+  red:
+    orange:
+          yellow:
+                  green: 'blue'
+    indigo: 'violet'
+  misdent: [[],
+  [],
+                  [],
+      []]
+
+ok obj.abc().join(' ') is 'a b c'
+ok obj.one.length is 5
+ok obj.one[4] is 4
+ok obj.one[2].a is 'b'
+ok (key for key of obj.red).length is 2
+ok obj.red.orange.yellow.green is 'blue'
+ok obj.red.indigo is 'violet'
+ok obj.misdent.toString() is ',,,'
+
+second = (x, y) -> y
+obj = then second 'the',
+  1: 1
+  two:
+    three: ->
+      four five,
+        six: seven
+  three: 3
+
+ok obj[1] is 1
+ok obj.three is 3
+
+
+# Implicit objects as part of chained calls.
+identity = (x) -> x.a
+
+b = identity identity identity
+  a:
+    a:
+      a: 100
+
+ok b is 100
+
+
+# Inline JS
+eq '\\`', `
+  "\\\`"
+`
+
+
+# Shorthand objects with property references.
+obj =
+  one: 1
+  two: 2
+  object: -> {@one, @two}
+  list:   -> [@one, @two]
+
+
+result = obj.object()
+eq result.one, 1
+eq result.two, 2
+eq result.two, obj.list()[1]
+
+
+#542: Objects leading expression statement should be parenthesized.
+{f: -> ok yes }.f() + 1
+
+
+#764: Boolean/Number should be indexable.
+ok 42['toString']
+ok on['toString']
diff --git a/node_modules/jade/support/coffee-script/test/test_module.coffee b/node_modules/jade/support/coffee-script/test/test_module.coffee
new file mode 100644
index 0000000..c6f1f1b
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_module.coffee
@@ -0,0 +1,4 @@
+# This file is imported by `testImporting.coffee`
+if exports?
+  local = "from over there"
+  exports.func = -> local
diff --git a/node_modules/jade/support/coffee-script/test/test_operations.coffee b/node_modules/jade/support/coffee-script/test/test_operations.coffee
new file mode 100644
index 0000000..0ba5cd6
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_operations.coffee
@@ -0,0 +1,154 @@
+# CoffeeScript's operations should be chainable, like Python's.
+ok 500 > 50 > 5 > -5
+
+ok true is not false is true is not false
+
+ok 0 is 0 isnt 50 is 50
+
+ok 10 < 20 > 10
+
+ok 50 > 10 > 5 is parseInt('5', 10)
+
+i = 0
+ok 1 > i++ < 1, 'chained operations should evaluate each value only once'
+
+
+# `==` and `is` should be interchangeable.
+a = b = 1
+
+ok a is 1 and b is 1
+ok a == b
+ok a is b
+
+
+# Allow "if x not in y"
+obj = {a: true}
+ok 'a' of obj
+ok 'b' not of obj
+
+# And for "a in b" with array presence.
+ok 200 in [100, 200, 300]
+array = [100, 200, 300]
+ok 200 in array
+ok 1 not in array
+ok array[0]++ in [99, 100], 'should cache testee'
+
+# And with array presence on an instance variable.
+obj = {
+  list: [1, 2, 3, 4, 5]
+  in_list: (value) -> value in @list
+}
+ok obj.in_list 4
+ok not obj.in_list 0
+
+# Non-spaced values still work.
+x = 10
+y = -5
+
+ok x*-y is 50
+ok x*+y is -50
+
+
+# Compound operators.
+one  = 1
+two  = 0
+one or= 2
+two or= 2
+
+eq one, 1
+eq two, 2
+
+zero = 0
+
+zero and= 'one'
+one  and= 'one'
+
+eq zero, 0
+eq one , 'one'
+
+
+# Compound assignment should be careful about caching variables.
+count = 0
+list = []
+
+list[++count] or= 1
+eq list[1], 1
+eq count, 1
+
+list[++count] ?= 2
+eq list[2], 2
+eq count, 2
+
+list[count++] and= 'two'
+eq list[2], 'two'
+eq count, 3
+
+base = -> ++count; base
+
+base().four or= 4
+eq base.four, 4
+eq count, 4
+
+base().five ?= 5
+eq base.five, 5
+eq count, 5
+
+
+# Ensure that RHS is treated as a group.
+a = b = false
+a and= b or true
+ok a is false
+
+
+# Bitwise operators:
+ok (10 &   3) is 2
+ok (10 |   3) is 11
+ok (10 ^   3) is 9
+ok (10 <<  3) is 80
+ok (10 >>  3) is 1
+ok (10 >>> 3) is 1
+
+num = 10; ok (num <<=  3) is 80
+num = 10; ok (num >>=  3) is 1
+num = 10; ok (num >>>= 3) is 1
+num = 10; ok (num &=   3) is 2
+num = 10; ok (num ^=   3) is 9
+num = 10; ok (num |=   3) is 11
+
+
+# Compound assignment with implicit objects.
+obj = undefined
+obj ?=
+  one: 1
+
+ok obj.one is 1
+
+obj and=
+  two: 2
+
+ok not obj.one
+ok obj.two is 2
+
+
+# Compound assignment as a sub expression.
+[a, b, c] = [1, 2, 3]
+ok (a + b += c) is 6
+ok a is 1
+ok b is 5
+ok c is 3
+
+
+# Instanceof.
+ok new String instanceof String
+ok new Number not instanceof String
+
+
+#737: `in` should have higher precedence than logical operators
+eq 1, 1 in [1] and 1
+
+#768: `in` should preserve evaluation order
+share = 0
+a = -> share++ if share is 0
+b = -> share++ if share is 1
+c = -> share++ if share is 2
+ok a() not in [b(),c()] and share is 3 
diff --git a/node_modules/jade/support/coffee-script/test/test_option_parser.coffee b/node_modules/jade/support/coffee-script/test/test_option_parser.coffee
new file mode 100644
index 0000000..2f66623
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_option_parser.coffee
@@ -0,0 +1,27 @@
+# Ensure that the OptionParser handles arguments correctly.
+return unless require?
+{OptionParser} = require './../lib/optparse'
+
+opt = new OptionParser [
+  ['-r', '--required [DIR]',  'desc required']
+  ['-o', '--optional',        'desc optional']
+  ['-l', '--list [FILES*]',   'desc list']
+]
+
+result = opt.parse ['one', 'two', 'three', '-r', 'dir']
+
+ok result.arguments.length is 5
+ok result.arguments[3] is '-r'
+
+result = opt.parse ['--optional', '-r', 'folder', 'one', 'two']
+
+ok result.optional is true
+ok result.required is 'folder'
+ok result.arguments.join(' ') is 'one two'
+
+result = opt.parse ['-l', 'one.txt', '-l', 'two.txt', 'three']
+
+ok result.list instanceof Array
+ok result.list.join(' ') is 'one.txt two.txt'
+ok result.arguments.join(' ') is 'three'
+
diff --git a/node_modules/jade/support/coffee-script/test/test_pattern_matching.coffee b/node_modules/jade/support/coffee-script/test/test_pattern_matching.coffee
new file mode 100644
index 0000000..e323814
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_pattern_matching.coffee
@@ -0,0 +1,160 @@
+# Simple variable swapping.
+a = -1
+b = -2
+
+[a, b] = [b, a]
+
+eq a, -2
+eq b, -1
+
+func = ->
+  [a, b] = [b, a]
+
+eq func().join(' '), '-1 -2'
+eq a, -1
+eq b, -2
+
+#713
+eq (onetwo = [1, 2]), [a, b] = [c, d] = onetwo
+ok a is c is 1 and b is d is 2
+
+
+# Array destructuring, including splats.
+[x,y...,z] = [1,2,3,4,5]
+
+ok x is 1
+ok y.length is 3
+ok z is 5
+
+[x, [y, mids..., last], z..., end] = [1, [10, 20, 30, 40], 2,3,4, 5]
+
+ok x is 1
+ok y is 10
+ok mids.length is 2 and mids[1] is 30
+ok last is 40
+ok z.length is 3 and z[2] is 4
+ok end is 5
+
+
+# Object destructuring.
+obj = {x: 10, y: 20, z: 30}
+
+{x: a, y: b, z: c} = obj
+
+ok a is 10
+ok b is 20
+ok c is 30
+
+person = {
+  name: "Moe"
+  family: {
+    'elder-brother': {
+      addresses: [
+        "first"
+        {
+          street: "101 Deercreek Ln."
+          city:   "Moquasset NY, 10021"
+        }
+      ]
+    }
+  }
+}
+
+{name: a, family: {'elder-brother': {addresses: [one, {city: b}]}}} = person
+
+ok a is "Moe"
+ok b is "Moquasset NY, 10021"
+
+test = {
+  person: {
+    address: [
+      "------"
+      "Street 101"
+      "Apt 101"
+      "City 101"
+    ]
+  }
+}
+
+{person: {address: [ignore, addr...]}} = test
+
+ok addr.join(', ') is "Street 101, Apt 101, City 101"
+
+
+# Pattern matching against an expression.
+[a, b] = if true then [2, 1] else [1, 2]
+
+ok a is 2
+ok b is 1
+
+
+# Pattern matching with object shorthand.
+
+person = {
+  name: "Bob"
+  age:  26
+  dogs: ["Prince", "Bowie"]
+}
+
+{name, age, dogs: [first, second]} = person
+
+ok name   is "Bob"
+ok age    is 26
+ok first  is "Prince"
+ok second is "Bowie"
+
+# Pattern matching within for..loops
+
+persons = {
+  George: { name: "Bob" },
+  Bob: { name: "Alice" }
+  Christopher: { name: "Stan" }
+}
+
+join1 = "#{key}: #{name}" for key, { name } of persons
+
+eq join1.join(' / '), "George: Bob / Bob: Alice / Christopher: Stan"
+
+persons = [
+  { name: "Bob", parent: { name: "George" } },
+  { name: "Alice", parent: { name: "Bob" } },
+  { name: "Stan", parent: { name: "Christopher" } }
+]
+
+join2 = "#{parent}: #{name}" for { name, parent: { name: parent } } in persons
+
+eq join1.join(' '), join2.join(' ')
+
+persons = [['Bob', ['George']], ['Alice', ['Bob']], ['Stan', ['Christopher']]]
+join3 = "#{parent}: #{name}" for [name, [parent]] in persons
+
+eq join2.join(' '), join3.join(' ')
+
+
+# Pattern matching doesn't clash with implicit block objects.
+obj = a: 101
+func = -> true
+
+if func func
+  {a} = obj
+
+ok a is 101
+
+[x] = {0: y} = {'0': z} = [Math.random()]
+ok x is y is z, 'destructuring in multiple'
+
+
+# Destructuring into an object.
+obj =
+  func: (list, object) ->
+    [@one, @two] = list
+    {@a, @b} = object
+    {@a} = object  # must not unroll this
+    null
+
+obj.func [1, 2], a: 'a', b: 'b'
+
+eq obj.one, 1
+eq obj.two, 2
+eq obj.a, 'a'
+eq obj.b, 'b'
diff --git a/node_modules/jade/support/coffee-script/test/test_ranges_slices_and_splices.coffee b/node_modules/jade/support/coffee-script/test/test_ranges_slices_and_splices.coffee
new file mode 100644
index 0000000..3e07f8c
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_ranges_slices_and_splices.coffee
@@ -0,0 +1,75 @@
+# Slice.
+array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+a = array[7..9]
+b = array[2...4]
+
+result = a.concat(b).join(' ')
+
+ok result is "7 8 9 2 3"
+
+a = [0, 1, 2, 3, 4, 5, 6, 7]
+eq a[2...6].join(' '), '2 3 4 5'
+
+
+# Ranges.
+countdown = [10..1].join(' ')
+ok countdown is "10 9 8 7 6 5 4 3 2 1"
+
+a = 1
+b = 5
+nums = [a...b]
+ok nums.join(' ') is '1 2 3 4'
+
+b = -5
+nums = [a..b]
+ok nums.join(' ') is '1 0 -1 -2 -3 -4 -5'
+
+
+# Expression-based range.
+array = [(1+5)..1+9]
+ok array.join(' ') is "6 7 8 9 10"
+
+array = [5..1]
+ok array.join(' ') is '5 4 3 2 1'
+
+array = [30...0]
+ok (len = array.length) is 30
+ok array[len - 1] is 1
+
+
+
+# String slicing (at least on Node).
+hello = "Hello World"
+
+ok hello[1...1] is ""
+ok hello[1..1] is "e"
+ok hello[1...5] is "ello"
+ok hello[0..4] is "Hello"
+
+
+# Splice literals.
+array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+
+array[5..10] = [0, 0, 0]
+
+ok array.join(' ') is '0 1 2 3 4 0 0 0'
+
+
+# Slices and splices that omit their beginning or end.
+array = [0..10]
+
+ok array[7..].join(' ')  is '7 8 9 10'
+ok array[-2..].join(' ') is '9 10'
+
+ok array[...3].join(' ') is '0 1 2'
+ok array[..-5].join(' ') is '0 1 2 3 4 5 6'
+
+array[3..] = [9, 8, 7]
+
+ok array.join(' ') is '0 1 2 9 8 7'
+
+array[...3] = [7, 8, 9]
+
+ok array.join(' ') is '7 8 9 9 8 7'
+
diff --git a/node_modules/jade/support/coffee-script/test/test_regexps.coffee b/node_modules/jade/support/coffee-script/test/test_regexps.coffee
new file mode 100644
index 0000000..709709a
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_regexps.coffee
@@ -0,0 +1,45 @@
+# Regular expression literals.
+ok 'x'.match(/x/g)
+ok 'x'.match /x/g
+ok 'x'.match(/x/)
+ok 'x'.match /x/
+
+ok 4 / 2 / 1 is 2
+
+y = 4
+x = 2
+g = 1
+
+ok y / x/g is 2
+
+obj = {
+  width:  -> 10
+  height: -> 20
+}
+id = 2
+
+ok (obj.width()/id - obj.height()/id) is -5
+
+eq /\\/.source, "\\\\"
+
+
+eq /^I'm\s+Heregex?\/\/\//gim + '', ///
+  ^ I'm \s+ Heregex? / // # or not
+///gim + ''
+eq '\\\\#{}\\\\\\\"', ///
+ #{
+   "#{ '\\' }" # normal comment
+ }
+ # regex comment
+ \#{}
+ \\ \"
+///.source
+eq ///  /// + '', '/(?:)/'
+
+
+#584: Unescaped slashes in character classes.
+ok /:\/[/]goog/.test 'http://google.com'
+
+
+#764: Should be indexable.
+eq /0/['source'], ///#{0}///['source']
diff --git a/node_modules/jade/support/coffee-script/test/test_returns.coffee b/node_modules/jade/support/coffee-script/test/test_returns.coffee
new file mode 100644
index 0000000..92f5ab0
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_returns.coffee
@@ -0,0 +1,33 @@
+# Expression conversion under explicit returns.
+first = ->
+  return 'do' for x in [1,2,3]
+
+second = ->
+  return ['re' for x in [1,2,3]]
+
+third = ->
+  return ('mi' for x in [1,2,3])
+
+ok first().join(' ')     is 'do do do'
+ok second()[0].join(' ') is 're re re'
+ok third().join(' ')     is 'mi mi mi'
+
+
+# Testing returns with multiple branches.
+func = ->
+  if false
+    for a in b
+      return c if d
+  else
+    "word"
+
+ok func() is 'word'
+
+
+# And with switches.
+func = ->
+  switch 'a'
+    when 'a' then 42
+    else return 23
+
+ok func() is 42
\ No newline at end of file
diff --git a/node_modules/jade/support/coffee-script/test/test_splats.coffee b/node_modules/jade/support/coffee-script/test/test_splats.coffee
new file mode 100644
index 0000000..006c80f
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_splats.coffee
@@ -0,0 +1,125 @@
+func = (first, second, rest...) ->
+  rest.join ' '
+
+result = func 1, 2, 3, 4, 5
+
+ok result is "3 4 5"
+
+
+gold = silver = bronze = theField = last = null
+
+medalists = (first, second, third, rest..., unlucky) ->
+  gold     = first
+  silver   = second
+  bronze   = third
+  theField = rest.concat([last])
+  last     = unlucky
+
+contenders = [
+  "Michael Phelps"
+  "Liu Xiang"
+  "Yao Ming"
+  "Allyson Felix"
+  "Shawn Johnson"
+  "Roman Sebrle"
+  "Guo Jingjing"
+  "Tyson Gay"
+  "Asafa Powell"
+  "Usain Bolt"
+]
+
+medalists "Mighty Mouse", contenders...
+
+ok gold is "Mighty Mouse"
+ok silver is "Michael Phelps"
+ok bronze is "Liu Xiang"
+ok last is "Usain Bolt"
+ok theField.length is 8
+
+contenders.reverse()
+medalists contenders[0...2]..., "Mighty Mouse", contenders[2...contenders.length]...
+
+ok gold is "Usain Bolt"
+ok silver is "Asafa Powell"
+ok bronze is "Mighty Mouse"
+ok last is "Michael Phelps"
+ok theField.length is 8
+
+medalists contenders..., 'Tim', 'Moe', 'Jim'
+ok last is 'Jim'
+
+
+obj =
+  name: 'moe'
+  accessor: (args...) ->
+    [@name].concat(args).join(' ')
+  getNames: ->
+    args = ['jane', 'ted']
+    @accessor(args...)
+  index: 0
+  0: {method: -> this is obj[0]}
+
+ok obj.getNames() is 'moe jane ted'
+ok obj[obj.index++].method([]...), 'should cache base value'
+
+crowd = [
+  contenders...
+  "Mighty Mouse"
+]
+
+bests = [
+  "Mighty Mouse"
+  contenders[0..3]...
+]
+
+ok crowd[0] is contenders[0]
+ok crowd[10] is "Mighty Mouse"
+
+ok bests[1] is contenders[0]
+ok bests[4] is contenders[3]
+
+
+# Finally, splats with super() within classes.
+
+class Parent
+  meth: (args...) ->
+    args
+
+class Child extends Parent
+  meth: ->
+    nums = [3, 2, 1]
+    super nums...
+
+ok (new Child).meth().join(' ') is '3 2 1'
+
+
+# Functions with splats being called with too few arguments.
+pen = null
+method = (first, variable..., penultimate, ultimate) ->
+  pen = penultimate
+
+method 1, 2, 3, 4, 5, 6, 7, 8, 9
+ok pen is 8
+
+method 1, 2, 3
+ok pen is 2
+
+method 1, 2
+ok pen is 2
+
+
+# Array splat expansions with assigns.
+nums = [1, 2, 3]
+list = [a = 0, nums..., b = 4]
+ok a is 0
+ok b is 4
+ok list.join(' ') is '0 1 2 3 4'
+
+
+# Splat on a line by itself is invalid.
+failed = true
+try
+  CoffeeScript.compile "x 'a'\n...\n"
+  failed = false
+catch err
+ok failed
diff --git a/node_modules/jade/support/coffee-script/test/test_strings.coffee b/node_modules/jade/support/coffee-script/test/test_strings.coffee
new file mode 100644
index 0000000..51d32dc
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_strings.coffee
@@ -0,0 +1,101 @@
+eq '(((dollars)))', '\(\(\(dollars\)\)\)'
+eq 'one two three', "one
+ two
+ three"
+eq "four five", 'four
+
+ five'
+
+#647
+eq "''Hello, World\\''", '''
+'\'Hello, World\\\''
+'''
+eq '""Hello, World\\""', """
+"\"Hello, World\\\""
+"""
+eq 'Hello, World\n', '''
+Hello, World\
+
+'''
+
+
+hello = 'Hello'
+world = 'World'
+ok '#{hello} #{world}!' is '#{hello} #{world}!'
+ok "#{hello} #{world}!" is 'Hello World!'
+ok "[#{hello}#{world}]" is '[HelloWorld]'
+ok "#{hello}##{world}" is 'Hello#World'
+ok "Hello #{ 1 + 2 } World" is 'Hello 3 World'
+ok "#{hello} #{ 1 + 2 } #{world}" is "Hello 3 World"
+
+
+[s, t, r, i, n, g] = ['s', 't', 'r', 'i', 'n', 'g']
+ok "#{s}#{t}#{r}#{i}#{n}#{g}" is 'string'
+ok "\#{s}\#{t}\#{r}\#{i}\#{n}\#{g}" is '#{s}#{t}#{r}#{i}#{n}#{g}'
+ok "\#{string}" is '#{string}'
+
+
+ok "\#{Escaping} first" is '#{Escaping} first'
+ok "Escaping \#{in} middle" is 'Escaping #{in} middle'
+ok "Escaping \#{last}" is 'Escaping #{last}'
+
+
+ok "##" is '##'
+ok "#{}" is ''
+ok "#{}A#{} #{} #{}B#{}" is 'A  B'
+ok "\\\#{}" is '\\#{}'
+
+
+ok "I won ##{20} last night." is 'I won #20 last night.'
+ok "I won ##{'#20'} last night." is 'I won ##20 last night.'
+
+
+ok "#{hello + world}" is 'HelloWorld'
+ok "#{hello + ' ' + world + '!'}" is 'Hello World!'
+
+
+list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ok "values: #{list.join(', ')}, length: #{list.length}." is 'values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, length: 10.'
+ok "values: #{list.join ' '}" is 'values: 0 1 2 3 4 5 6 7 8 9'
+
+
+obj = {
+  name: 'Joe'
+  hi: -> "Hello #{@name}."
+  cya: -> "Hello #{@name}.".replace('Hello','Goodbye')
+}
+ok obj.hi() is "Hello Joe."
+ok obj.cya() is "Goodbye Joe."
+
+
+ok "With #{"quotes"}" is 'With quotes'
+ok 'With #{"quotes"}' is 'With #{"quotes"}'
+
+ok "Where is #{obj["name"] + '?'}" is 'Where is Joe?'
+
+ok "Where is #{"the nested #{obj["name"]}"}?" is 'Where is the nested Joe?'
+ok "Hello #{world ? "#{hello}"}" is 'Hello World'
+
+ok "Hello #{"#{"#{obj["name"]}" + '!'}"}" is 'Hello Joe!'
+
+
+a = """
+    Hello #{ "Joe" }
+    """
+ok a is "Hello Joe"
+
+
+a = 1
+b = 2
+c = 3
+ok "#{a}#{b}#{c}" is '123'
+
+
+result = null
+stash = (str) -> result = str
+stash "a #{ ('aa').replace /a/g, 'b' } c"
+ok result is 'a bb c'
+
+
+foo = "hello"
+ok "#{foo.replace("\"", "")}" is 'hello'
diff --git a/node_modules/jade/support/coffee-script/test/test_switch.coffee b/node_modules/jade/support/coffee-script/test/test_switch.coffee
new file mode 100644
index 0000000..f3307d9
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_switch.coffee
@@ -0,0 +1,98 @@
+num = 10
+
+result = switch num
+  when 5 then false
+  when 'a'
+    true
+    true
+    false
+  when 10 then true
+
+
+  # Mid-switch comment with whitespace
+  # and multi line
+  when 11 then false
+  else false
+
+ok result
+
+
+func = (num) ->
+  switch num
+    when 2, 4, 6
+      true
+    when 1, 3, 5
+      false
+    else false
+
+ok func(2)
+ok func(6)
+ok !func(3)
+ok !func(8)
+
+
+# Should cache the switch value, if anything fancier than a literal.
+num = 5
+result = switch num += 5
+  when 5 then false
+  when 15 then false
+  when 10 then true
+  else false
+
+ok result
+
+
+# Ensure that trailing switch elses don't get rewritten.
+result = false
+switch "word"
+  when "one thing"
+    doSomething()
+  else
+    result = true unless false
+
+ok result
+
+result = false
+switch "word"
+  when "one thing"
+    doSomething()
+  when "other thing"
+    doSomething()
+  else
+    result = true unless false
+
+ok result
+
+
+# Should be able to handle switches sans-condition.
+result = switch
+  when null then 1
+  when 'truthful string' then 2
+  else 3
+
+ok result is 2
+
+
+# Should be able to use "@properties" within the switch clause.
+obj = {
+  num: 101
+  func: ->
+    switch @num
+      when 101 then '101!'
+      else 'other'
+}
+
+ok obj.func() is '101!'
+
+
+# Should be able to use "@properties" within the switch cases.
+obj = {
+  num: 101
+  func: (yesOrNo) ->
+    result = switch yesOrNo
+      when yes then @num
+      else 'other'
+    result
+}
+
+ok obj.func(yes) is 101
diff --git a/node_modules/jade/support/coffee-script/test/test_try_catch.coffee b/node_modules/jade/support/coffee-script/test/test_try_catch.coffee
new file mode 100644
index 0000000..e98657b
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_try_catch.coffee
@@ -0,0 +1,45 @@
+# Basic exception throwing.
+block = -> throw 'up'
+throws block, 'up'
+
+
+# Basic try/catch.
+result = try
+  10
+finally
+  15
+
+ok result is 10
+
+result = try
+  throw 'up'
+catch err
+  err.length
+
+ok result is 2
+
+
+result = try throw 'error' catch err then err.length
+
+ok result is 5
+
+try throw 'catch is optional'
+
+# try/catch with empty clauses still compiles.
+try
+
+try
+  # nothing
+catch err
+  # nothing
+
+try
+  # nothing
+finally
+  # nothing
+
+try
+catch err
+finally
+
+ok yes
diff --git a/node_modules/jade/support/coffee-script/test/test_while.coffee b/node_modules/jade/support/coffee-script/test/test_while.coffee
new file mode 100644
index 0000000..3e3a83f
--- /dev/null
+++ b/node_modules/jade/support/coffee-script/test/test_while.coffee
@@ -0,0 +1,53 @@
+i = 5
+list = while i -= 1
+  i * 2
+
+ok list.join(' ') is "8 6 4 2"
+
+
+i = 5
+list = (i * 3 while i -= 1)
+
+ok list.join(' ') is "12 9 6 3"
+
+
+i = 5
+func   = (num) -> i -= num
+assert = -> ok i < 5 > 0
+
+results = while func 1
+  assert()
+  i
+
+ok results.join(' ') is '4 3 2 1'
+
+
+i = 10
+results = while i -= 1 when i % 2 is 0
+  i * 2
+
+ok results.join(' ') is '16 12 8 4'
+
+
+value = false
+i = 0
+results = until value
+  value = true if i is 5
+  i += 1
+
+ok i is 6
+
+
+# And, the loop form of while.
+i = 5
+list = []
+loop
+  i -= 1
+  break if i is 0
+  list.push i * 2
+
+ok list.join(' ') is '8 6 4 2'
+
+
+#759: `if` within `while` condition
+2 while if 1 then 0
diff --git a/node_modules/jade/support/compile.js b/node_modules/jade/support/compile.js
new file mode 100644
index 0000000..4a70058
--- /dev/null
+++ b/node_modules/jade/support/compile.js
@@ -0,0 +1,173 @@
+
+/**
+ * Module dependencies.
+ */
+
+var fs = require('fs');
+
+/**
+ * Arguments.
+ */
+
+var args = process.argv.slice(2)
+  , pending = args.length
+  , files = {};
+
+console.log('');
+
+// parse arguments
+
+args.forEach(function(file){
+  var mod = file.replace('lib/', '');
+  fs.readFile(file, 'utf8', function(err, js){
+    if (err) throw err;
+    console.log('  \033[90mcompile : \033[0m\033[36m%s\033[0m', file);
+    files[file] = parse(js);
+    --pending || compile();
+  });
+});
+
+/**
+ * Parse the given `js`.
+ */
+
+function parse(js) {
+  return parseInheritance(parseConditionals(js));
+}
+
+/**
+ * Parse __proto__.
+ */
+
+function parseInheritance(js) {
+  return js
+    .replace(/^ *(\w+)\.prototype\.__proto__ * = *(\w+)\.prototype *;?/gm, function(_, child, parent){
+      return child + '.prototype = new ' + parent + ';\n'
+        + child + '.prototype.constructor = '+ child + ';\n';
+    });
+}
+
+/**
+ * Parse the given `js`, currently supporting:
+ * 
+ *    'if' ['node' | 'browser']
+ *    'end'
+ * 
+ */
+
+function parseConditionals(js) {
+  var lines = js.split('\n')
+    , len = lines.length
+    , buffer = true
+    , browser = false
+    , buf = []
+    , line
+    , cond;
+
+  for (var i = 0; i < len; ++i) {
+    line = lines[i];
+    if (/^ *\/\/ *if *(node|browser)/gm.exec(line)) {
+      cond = RegExp.$1;
+      buffer = browser = 'browser' == cond;
+    } else if (/^ *\/\/ *end/.test(line)) {
+      buffer = true;
+      browser = false;
+    } else if (browser) {
+      buf.push(line.replace(/^( *)\/\//, '$1'));
+    } else if (buffer) {
+      buf.push(line);
+    }
+  }
+
+  return buf.join('\n');
+}
+
+/**
+ * Compile the files.
+ */
+
+function compile() {
+  var buf = '';
+  buf += '\n// CommonJS require()\n\n';
+  buf += browser.require + '\n\n';
+  buf += 'require.modules = {};\n\n';
+  buf += 'require.resolve = ' + browser.resolve + ';\n\n';
+  buf += 'require.register = ' + browser.register + ';\n\n';
+  buf += 'require.relative = ' + browser.relative + ';\n\n';
+  args.forEach(function(file){
+    var js = files[file];
+    file = file.replace('lib/', '');
+    buf += '\nrequire.register("' + file + '", function(module, exports, require){\n';
+    buf += js;
+    buf += '\n}); // module: ' + file + '\n';
+  });
+  fs.writeFile('jade.js', buf, function(err){
+    if (err) throw err;
+    console.log('  \033[90m create : \033[0m\033[36m%s\033[0m', 'jade.js');
+    console.log();
+  });
+}
+
+// refactored version of weepy's
+// https://github.com/weepy/brequire/blob/master/browser/brequire.js
+
+var browser = {
+  
+  /**
+   * Require a module.
+   */
+  
+  require: function require(p){
+    var path = require.resolve(p)
+      , mod = require.modules[path];
+    if (!mod) throw new Error('failed to require "' + p + '"');
+    if (!mod.exports) {
+      mod.exports = {};
+      mod.call(mod.exports, mod, mod.exports, require.relative(path));
+    }
+    return mod.exports;
+  },
+  
+  /**
+   * Resolve module path.
+   */
+
+  resolve: function(path){
+    var orig = path
+      , reg = path + '.js'
+      , index = path + '/index.js';
+    return require.modules[reg] && reg
+      || require.modules[index] && index
+      || orig;
+  },
+  
+  /**
+   * Return relative require().
+   */
+
+  relative: function(parent) {
+    return function(p){
+      if ('.' != p[0]) return require(p);
+      
+      var path = parent.split('/')
+        , segs = p.split('/');
+      path.pop();
+      
+      for (var i = 0; i < segs.length; i++) {
+        var seg = segs[i];
+        if ('..' == seg) path.pop();
+        else if ('.' != seg) path.push(seg);
+      }
+
+      return require(path.join('/'));
+    };
+  },
+  
+  /**
+   * Register a module.
+   */
+
+  register: function(path, fn){
+    require.modules[path] = fn;
+  }
+};
\ No newline at end of file
diff --git a/node_modules/jade/support/expresso/History.md b/node_modules/jade/support/expresso/History.md
new file mode 100644
index 0000000..1989eca
--- /dev/null
+++ b/node_modules/jade/support/expresso/History.md
@@ -0,0 +1,97 @@
+
+0.6.2 / 2010-09-17 
+==================
+
+  * Added _node-jsocoverage_ to package.json (aka will respect npm's binroot)
+  * Added _-t, --timeout_ MS option, defaulting to 2000 ms
+  * Added _-s, --serial_
+  * __PREFIX__ clobberable
+  * Fixed `assert.response()` for latest node
+  * Fixed cov reporting from exploding on empty files
+
+0.6.2 / 2010-08-03
+==================
+
+  * Added `assert.type()`
+  * Renamed `assert.isNotUndefined()` to `assert.isDefined()`
+  * Fixed `assert.includes()` param ordering
+
+0.6.0 / 2010-07-31
+==================
+
+  * Added _docs/api.html_
+  * Added -w, --watch
+  * Added `Array` support to `assert.includes()`
+  * Added; outputting exceptions immediately. Closes #19
+  * Fixed `assert.includes()` param ordering
+  * Fixed `assert.length()` param ordering
+  * Fixed jscoverage links
+
+0.5.0 / 2010-07-16
+==================
+
+  * Added support for async exports
+  * Added timeout support to `assert.response()`. Closes #3
+  * Added 4th arg callback support to `assert.response()`
+  * Added `assert.length()`
+  * Added `assert.match()`
+  * Added `assert.isUndefined()`
+  * Added `assert.isNull()`
+  * Added `assert.includes()`
+  * Added growlnotify support via -g, --growl
+  * Added -o, --only TESTS. Ex: --only "test foo()" --only "test foo(), test bar()"
+  * Removed profanity
+
+0.4.0 / 2010-07-09
+==================
+
+  * Added reporting source coverage (respects --boring for color haters)
+  * Added callback to assert.response(). Closes #12
+  * Fixed; putting exceptions to stderr. Closes #13
+
+0.3.1 / 2010-06-28
+==================
+
+  * Faster assert.response()
+
+0.3.0 / 2010-06-28
+==================
+
+  * Added -p, --port NUM flags
+  * Added assert.response(). Closes #11
+
+0.2.1 / 2010-06-25
+==================
+
+  * Fixed issue with reporting object assertions
+
+0.2.0 / 2010-06-21
+==================
+
+  * Added `make uninstall`
+  * Added better readdir() failure message
+  * Fixed `make install` for kiwi
+
+0.1.0 / 2010-06-15
+==================
+
+  * Added better usage docs via --help
+  * Added better conditional color support
+  * Added pre exit assertion support
+
+0.0.3 / 2010-06-02
+==================
+
+  * Added more room for filenames in test coverage
+  * Added boring output support via --boring (suppress colored output)
+  * Fixed async failure exit status
+
+0.0.2 / 2010-05-30
+==================
+
+  * Fixed exit status for CI support
+
+0.0.1 / 2010-05-30
+==================
+
+  * Initial release
\ No newline at end of file
diff --git a/node_modules/jade/support/expresso/Makefile b/node_modules/jade/support/expresso/Makefile
new file mode 100644
index 0000000..8acfe56
--- /dev/null
+++ b/node_modules/jade/support/expresso/Makefile
@@ -0,0 +1,53 @@
+
+PREFIX ?= /usr/local
+BIN = bin/expresso
+JSCOV = deps/jscoverage/node-jscoverage
+DOCS = docs/index.md
+HTMLDOCS = $(DOCS:.md=.html)
+
+test: $(BIN)
+	@./$(BIN) -I lib --growl $(TEST_FLAGS) test/*.test.js
+
+test-cov:
+	@./$(BIN) -I lib --cov $(TEST_FLAGS) test/*.test.js
+
+test-serial:
+	@./$(BIN) --serial -I lib $(TEST_FLAGS) test/serial/*.test.js
+
+install: install-jscov install-expresso
+
+uninstall:
+	rm -f $(PREFIX)/bin/expresso
+	rm -f $(PREFIX)/bin/node-jscoverage
+
+install-jscov: $(JSCOV)
+	install $(JSCOV) $(PREFIX)/bin
+
+install-expresso:
+	install $(BIN) $(PREFIX)/bin
+
+$(JSCOV):
+	cd deps/jscoverage && ./configure && make && mv jscoverage node-jscoverage
+
+clean:
+	@cd deps/jscoverage && git clean -fd
+
+docs: docs/api.html $(HTMLDOCS)
+
+%.html: %.md
+	@echo "... $< > $@"
+	@ronn -5 --pipe --fragment $< \
+		| cat docs/layout/head.html - docs/layout/foot.html \
+		> $@
+
+docs/api.html: bin/expresso
+	dox \
+		--title "Expresso" \
+		--ribbon "http://github.com/visionmedia/expresso" \
+		--desc "Insanely fast TDD framework for [node](http://nodejs.org) featuring code coverage reporting." \
+		$< > $@
+
+docclean:
+	rm -f docs/*.html
+
+.PHONY: test test-cov install uninstall install-expresso install-jscov clean docs docclean
\ No newline at end of file
diff --git a/node_modules/jade/support/expresso/Readme.md b/node_modules/jade/support/expresso/Readme.md
new file mode 100644
index 0000000..dcc1c85
--- /dev/null
+++ b/node_modules/jade/support/expresso/Readme.md
@@ -0,0 +1,39 @@
+
+# Expresso
+
+  TDD framework for [nodejs](http://nodejs.org).
+  
+## Features
+
+  - light-weight
+  - intuitive async support
+  - intuitive test runner executable
+  - test coverage support and reporting
+  - uses the _assert_ module
+  - `assert.eql()` alias of `assert.deepEqual()`
+  - `assert.response()` http response utility
+  - `assert.includes()`
+  - `assert.type()`
+  - `assert.isNull()`
+  - `assert.isUndefined()`
+  - `assert.isNotNull()`
+  - `assert.isDefined()`
+  - `assert.match()`
+  - `assert.length()`
+
+## Installation
+
+To install both expresso _and_ node-jscoverage run:
+
+    $ make install
+
+To install expresso alone (no build required) run:
+
+    $ make install-expresso
+
+Install via npm:
+
+	$ npm install expresso
+
+
+
diff --git a/node_modules/jade/support/expresso/bin/expresso b/node_modules/jade/support/expresso/bin/expresso
new file mode 100755
index 0000000..8366c61
--- /dev/null
+++ b/node_modules/jade/support/expresso/bin/expresso
@@ -0,0 +1,837 @@
+#!/usr/bin/env node
+
+/*!
+ * Expresso
+ * Copyright(c) TJ Holowaychuk 
+ * (MIT Licensed)
+ */
+ 
+/**
+ * Module dependencies.
+ */
+
+var assert = require('assert'),
+    childProcess = require('child_process'),
+    http = require('http'),
+    path = require('path'),
+    sys = require('sys'),
+    cwd = process.cwd(),
+    fs = require('fs'),
+    defer;
+
+/**
+ * Expresso version.
+ */
+
+var version = '0.6.2';
+
+/**
+ * Failure count.
+ */
+
+var failures = 0;
+
+
+/**
+ * Number of tests executed.
+ */
+
+var testcount = 0;
+
+/**
+ * Whitelist of tests to run.
+ */
+ 
+var only = [];
+
+/**
+ * Boring output.
+ */
+ 
+var boring = false;
+
+/**
+ * Growl notifications.
+ */
+
+var growl = false;
+
+/**
+ * Server port.
+ */
+
+var port = 5555;
+
+/**
+ * Watch mode.
+ */
+
+var watch = false;
+
+/**
+ * Execute serially.
+ */
+
+var serial = false;
+
+/**
+ * Default timeout.
+ */
+
+var timeout = 2000;
+
+/**
+ * Usage documentation.
+ */
+
+var usage = ''
+    + '[bold]{Usage}: expresso [options] '
+    + '\n'
+    + '\n[bold]{Options}:'
+    + '\n  -w, --watch          Watch for modifications and re-execute tests'
+    + '\n  -g, --growl          Enable growl notifications'
+    + '\n  -c, --coverage       Generate and report test coverage'
+    + '\n  -t, --timeout MS     Timeout in milliseconds, defaults to 2000'
+    + '\n  -r, --require PATH   Require the given module path'
+    + '\n  -o, --only TESTS     Execute only the comma sperated TESTS (can be set several times)'
+    + '\n  -I, --include PATH   Unshift the given path to require.paths'
+    + '\n  -p, --port NUM       Port number for test servers, starts at 5555'
+    + '\n  -s, --serial         Execute tests serially'
+    + '\n  -b, --boring         Suppress ansi-escape colors'
+    + '\n  -v, --version        Output version number'
+    + '\n  -h, --help           Display help information'
+    + '\n';
+
+// Parse arguments
+
+var files = [],
+    args = process.argv.slice(2);
+
+while (args.length) {
+    var arg = args.shift();
+    switch (arg) {
+        case '-h':
+        case '--help':
+            print(usage + '\n');
+            process.exit(1);
+            break;
+        case '-v':
+        case '--version':
+            sys.puts(version);
+            process.exit(1);
+            break;
+        case '-i':
+        case '-I':
+        case '--include':
+            if (arg = args.shift()) {
+                require.paths.unshift(arg);
+            } else {
+                throw new Error('--include requires a path');
+            }
+            break;
+        case '-o':
+        case '--only':
+            if (arg = args.shift()) {
+                only = only.concat(arg.split(/ *, */));
+            } else {
+                throw new Error('--only requires comma-separated test names');
+            }
+            break;
+        case '-p':
+        case '--port':
+            if (arg = args.shift()) {
+                port = parseInt(arg, 10);
+            } else {
+                throw new Error('--port requires a number');
+            }
+            break;
+        case '-r':
+        case '--require':
+            if (arg = args.shift()) {
+                require(arg);
+            } else {
+                throw new Error('--require requires a path');
+            }
+            break;
+        case '-t':
+        case '--timeout':
+          if (arg = args.shift()) {
+            timeout = parseInt(arg, 10);
+          } else {
+            throw new Error('--timeout requires an argument');
+          }
+          break;
+        case '-c':
+        case '--cov':
+        case '--coverage':
+            defer = true;
+            childProcess.exec('rm -fr lib-cov && node-jscoverage lib lib-cov', function(err){
+                if (err) throw err;
+                require.paths.unshift('lib-cov');
+                run(files);
+            })
+            break;
+        case '-b':
+        case '--boring':
+        	boring = true;
+        	break;
+        case '-w':
+        case '--watch':
+            watch = true;
+            break;
+        case '-g':
+        case '--growl':
+            growl = true;
+            break;
+        case '-s':
+        case '--serial':
+            serial = true;
+            break;
+        default:
+            if (/\.js$/.test(arg)) {
+                files.push(arg);
+            }
+            break;
+    }
+}
+
+/**
+ * Colorized sys.error().
+ *
+ * @param {String} str
+ */
+
+function print(str){
+    sys.error(colorize(str));
+}
+
+/**
+ * Colorize the given string using ansi-escape sequences.
+ * Disabled when --boring is set.
+ *
+ * @param {String} str
+ * @return {String}
+ */
+
+function colorize(str){
+    var colors = { bold: 1, red: 31, green: 32, yellow: 33 };
+    return str.replace(/\[(\w+)\]\{([^]*?)\}/g, function(_, color, str){
+        return boring
+            ? str
+            : '\x1B[' + colors[color] + 'm' + str + '\x1B[0m';
+    });
+}
+
+// Alias deepEqual as eql for complex equality
+
+assert.eql = assert.deepEqual;
+
+/**
+ * Assert that `val` is null.
+ *
+ * @param {Mixed} val
+ * @param {String} msg
+ */
+
+assert.isNull = function(val, msg) {
+    assert.strictEqual(null, val, msg);
+};
+
+/**
+ * Assert that `val` is not null.
+ *
+ * @param {Mixed} val
+ * @param {String} msg
+ */
+
+assert.isNotNull = function(val, msg) {
+    assert.notStrictEqual(null, val, msg);
+};
+
+/**
+ * Assert that `val` is undefined.
+ *
+ * @param {Mixed} val
+ * @param {String} msg
+ */
+
+assert.isUndefined = function(val, msg) {
+    assert.strictEqual(undefined, val, msg);
+};
+
+/**
+ * Assert that `val` is not undefined.
+ *
+ * @param {Mixed} val
+ * @param {String} msg
+ */
+
+assert.isDefined = function(val, msg) {
+    assert.notStrictEqual(undefined, val, msg);
+};
+
+/**
+ * Assert that `obj` is `type`.
+ *
+ * @param {Mixed} obj
+ * @param {String} type
+ * @api public
+ */
+
+assert.type = function(obj, type, msg){
+    var real = typeof obj;
+    msg = msg || 'typeof ' + sys.inspect(obj) + ' is ' + real + ', expected ' + type;
+    assert.ok(type === real, msg);
+};
+
+/**
+ * Assert that `str` matches `regexp`.
+ *
+ * @param {String} str
+ * @param {RegExp} regexp
+ * @param {String} msg
+ */
+
+assert.match = function(str, regexp, msg) {
+    msg = msg || sys.inspect(str) + ' does not match ' + sys.inspect(regexp);
+    assert.ok(regexp.test(str), msg);
+};
+
+/**
+ * Assert that `val` is within `obj`.
+ *
+ * Examples:
+ *
+ *    assert.includes('foobar', 'bar');
+ *    assert.includes(['foo', 'bar'], 'foo');
+ *
+ * @param {String|Array} obj
+ * @param {Mixed} val
+ * @param {String} msg
+ */
+
+assert.includes = function(obj, val, msg) {
+    msg = msg || sys.inspect(obj) + ' does not include ' + sys.inspect(val);
+    assert.ok(obj.indexOf(val) >= 0, msg);
+};
+
+/**
+ * Assert length of `val` is `n`.
+ *
+ * @param {Mixed} val
+ * @param {Number} n
+ * @param {String} msg
+ */
+
+assert.length = function(val, n, msg) {
+    msg = msg || sys.inspect(val) + ' has length of ' + val.length + ', expected ' + n;
+    assert.equal(n, val.length, msg);
+};
+
+/**
+ * Assert response from `server` with
+ * the given `req` object and `res` assertions object.
+ *
+ * @param {Server} server
+ * @param {Object} req
+ * @param {Object|Function} res
+ * @param {String} msg
+ */
+
+assert.response = function(server, req, res, msg){
+    // Callback as third or fourth arg
+    var callback = typeof res === 'function'
+        ? res
+        : typeof msg === 'function'
+            ? msg
+            : function(){};
+
+    // Default messate to test title
+    if (typeof msg === 'function') msg = null;
+    msg = msg || assert.testTitle;
+    msg += '. ';
+
+    // Pending responses
+    server.__pending = server.__pending || 0;
+    server.__pending++;
+
+    // Create client
+    if (!server.fd) {
+        server.listen(server.__port = port++, '127.0.0.1');
+        server.client = http.createClient(server.__port);
+    }
+
+    // Issue request
+    var timer,
+        client = server.client,
+        method = req.method || 'GET',
+        status = res.status || res.statusCode,
+        data = req.data || req.body,
+        timeout = req.timeout || 0;
+
+    var request = client.request(method, req.url, req.headers);
+
+    // Timeout
+    if (timeout) {
+        timer = setTimeout(function(){
+            --server.__pending || server.close();
+            delete req.timeout;
+            assert.fail(msg + 'Request timed out after ' + timeout + 'ms.');
+        }, timeout);
+    }
+
+    if (data) request.write(data);
+    request.addListener('response', function(response){
+        response.body = '';
+        response.setEncoding('utf8');
+        response.addListener('data', function(chunk){ response.body += chunk; });
+        response.addListener('end', function(){
+            --server.__pending || server.close();
+            if (timer) clearTimeout(timer);
+
+            // Assert response body
+            if (res.body !== undefined) {
+                var eql = res.body instanceof RegExp
+                  ? res.body.test(response.body)
+                  : res.body === response.body;
+                assert.ok(
+                    eql,
+                    msg + 'Invalid response body.\n'
+                        + '    Expected: ' + sys.inspect(res.body) + '\n'
+                        + '    Got: ' + sys.inspect(response.body)
+                );
+            }
+
+            // Assert response status
+            if (typeof status === 'number') {
+                assert.equal(
+                    response.statusCode,
+                    status,
+                    msg + colorize('Invalid response status code.\n'
+                        + '    Expected: [green]{' + status + '}\n'
+                        + '    Got: [red]{' + response.statusCode + '}')
+                );
+            }
+
+            // Assert response headers
+            if (res.headers) {
+                var keys = Object.keys(res.headers);
+                for (var i = 0, len = keys.length; i < len; ++i) {
+                    var name = keys[i],
+                        actual = response.headers[name.toLowerCase()],
+                        expected = res.headers[name];
+                    assert.equal(
+                        actual,
+                        expected,
+                        msg + colorize('Invalid response header [bold]{' + name + '}.\n'
+                            + '    Expected: [green]{' + expected + '}\n'
+                            + '    Got: [red]{' + actual + '}')
+                    );
+                }
+            }
+
+            // Callback
+            callback(response);
+        });
+    });
+    request.end();
+};
+
+/**
+ * Pad the given string to the maximum width provided.
+ *
+ * @param  {String} str
+ * @param  {Number} width
+ * @return {String}
+ */
+
+function lpad(str, width) {
+    str = String(str);
+    var n = width - str.length;
+    if (n < 1) return str;
+    while (n--) str = ' ' + str;
+    return str;
+}
+
+/**
+ * Pad the given string to the maximum width provided.
+ *
+ * @param  {String} str
+ * @param  {Number} width
+ * @return {String}
+ */
+
+function rpad(str, width) {
+    str = String(str);
+    var n = width - str.length;
+    if (n < 1) return str;
+    while (n--) str = str + ' ';
+    return str;
+}
+
+/**
+ * Report test coverage.
+ *
+ * @param  {Object} cov
+ */
+
+function reportCoverage(cov) {
+    populateCoverage(cov);
+    // Stats
+    print('\n   [bold]{Test Coverage}\n');
+    var sep = '   +------------------------------------------+----------+------+------+--------+',
+        lastSep = '                                              +----------+------+------+--------+';
+    sys.puts(sep);
+    sys.puts('   | filename                                 | coverage | LOC  | SLOC | missed |');
+    sys.puts(sep);
+    for (var name in cov) {
+        var file = cov[name];
+        if (Array.isArray(file)) {
+            sys.print('   | ' + rpad(name, 40));
+            sys.print(' | ' + lpad(file.coverage.toFixed(2), 8));
+            sys.print(' | ' + lpad(file.LOC, 4));
+            sys.print(' | ' + lpad(file.SLOC, 4));
+            sys.print(' | ' + lpad(file.totalMisses, 6));
+            sys.print(' |\n');
+        }
+    }
+    sys.puts(sep);
+    sys.print('     ' + rpad('', 40));
+    sys.print(' | ' + lpad(cov.coverage.toFixed(2), 8));
+    sys.print(' | ' + lpad(cov.LOC, 4));
+    sys.print(' | ' + lpad(cov.SLOC, 4));
+    sys.print(' | ' + lpad(cov.totalMisses, 6));
+    sys.print(' |\n');
+    sys.puts(lastSep);
+    // Source
+    for (var name in cov) {
+        if (name.match(/\.js$/)) {
+            var file = cov[name];
+            print('\n   [bold]{' + name + '}:');
+            print(file.source);
+            sys.print('\n');
+        }
+    }
+}
+
+/**
+ * Populate code coverage data.
+ *
+ * @param  {Object} cov
+ */
+
+function populateCoverage(cov) {
+    cov.LOC = 
+    cov.SLOC =
+    cov.totalFiles =
+    cov.totalHits =
+    cov.totalMisses = 
+    cov.coverage = 0;
+    for (var name in cov) {
+        var file = cov[name];
+        if (Array.isArray(file)) {
+            // Stats
+            ++cov.totalFiles;
+            cov.totalHits += file.totalHits = coverage(file, true);
+            cov.totalMisses += file.totalMisses = coverage(file, false);
+            file.totalLines = file.totalHits + file.totalMisses;
+            cov.SLOC += file.SLOC = file.totalLines;
+            if (!file.source) file.source = [];
+            cov.LOC += file.LOC = file.source.length;
+            file.coverage = (file.totalHits / file.totalLines) * 100;
+            // Source
+            var width = file.source.length.toString().length;
+            file.source = file.source.map(function(line, i){
+                ++i;
+                var hits = file[i] === 0 ? 0 : (file[i] || ' ');
+                if (!boring) {
+                    if (hits === 0) {
+                        hits = '\x1b[31m' + hits + '\x1b[0m';
+                        line = '\x1b[41m' + line + '\x1b[0m';
+                    } else {
+                        hits = '\x1b[32m' + hits + '\x1b[0m';
+                    }
+                }
+                return '\n     ' + lpad(i, width) + ' | ' + hits + ' | ' + line;
+            }).join('');
+        }
+    }
+    cov.coverage = (cov.totalHits / cov.SLOC) * 100;
+}
+
+/**
+ * Total coverage for the given file data.
+ *
+ * @param  {Array} data
+ * @return {Type}
+ */
+
+function coverage(data, val) {
+    var n = 0;
+    for (var i = 0, len = data.length; i < len; ++i) {
+        if (data[i] !== undefined && data[i] == val) ++n;
+    }
+    return n;  
+}
+
+/**
+ * Run the given test `files`, or try _test/*_.
+ *
+ * @param  {Array} files
+ */
+
+function run(files) {
+    if (!files.length) {
+        try {
+            files = fs.readdirSync('test').map(function(file){
+                return 'test/' + file;
+            });
+        } catch (err) {
+            print('\n  failed to load tests in [bold]{./test}\n');
+            ++failures;
+            process.exit(1);
+        }
+    }
+    if (watch) watchFiles(files);
+    runFiles(files);
+}
+
+/**
+ * Show the cursor when `show` is true, otherwise hide it.
+ *
+ * @param {Boolean} show
+ */
+
+function cursor(show) {
+    if (show) {
+        sys.print('\x1b[?25h');
+    } else {
+        sys.print('\x1b[?25l');
+    }
+}
+
+/**
+ * Run the given test `files`.
+ *
+ * @param {Array} files
+ */
+
+function runFiles(files) {
+    files.forEach(runFile);
+}
+
+/**
+ * Run tests for the given `file`.
+ *
+ * @param {String} file
+ */
+
+function runFile(file) {
+    if (file.match(/\.js$/)) {
+        var title = path.basename(file),
+            file = path.join(cwd, file),
+            mod = require(file.replace(/\.js$/, ''));
+        (function check(){
+           var len = Object.keys(mod).length;
+           if (len) {
+               runSuite(title, mod);
+           } else {
+               setTimeout(check, 20);
+           }
+        })();
+    }
+}
+
+/**
+ * Clear the module cache for the given `file`.
+ *
+ * @param {String} file
+ */
+
+function clearCache(file) {
+    var keys = Object.keys(module.moduleCache);
+    for (var i = 0, len = keys.length; i < len; ++i) {
+        var key = keys[i];
+        if (key.indexOf(file) === key.length - file.length) {
+            delete module.moduleCache[key];
+        }
+    }
+}
+
+/**
+ * Watch the given `files` for changes.
+ *
+ * @param {Array} files
+ */
+
+function watchFiles(files) {
+    var p = 0,
+        c = ['▫   ', '▫▫  ', '▫▫▫ ', ' ▫▫▫',
+             '  ▫▫', '   ▫', '   ▫', '  ▫▫',
+             '▫▫▫ ', '▫▫  ', '▫   '],
+        l = c.length;
+    cursor(false);
+    setInterval(function(){
+        sys.print(colorize('  [green]{' + c[p++ % l] + '} watching\r'));
+    }, 100);
+    files.forEach(function(file){
+        fs.watchFile(file, { interval: 100 }, function(curr, prev){
+            if (curr.mtime > prev.mtime) {
+                print('  [yellow]{◦} ' + file);
+                clearCache(file);
+                runFile(file);
+            }
+        });
+    });
+}
+
+/**
+ * Report `err` for the given `test` and `suite`.
+ *
+ * @param {String} suite
+ * @param {String} test
+ * @param {Error} err
+ */
+
+function error(suite, test, err) {
+    ++failures;
+    var name = err.name,
+        stack = err.stack.replace(err.name, ''),
+        label = test === 'uncaught'
+            ? test
+            : suite + ' ' + test;
+    print('\n   [bold]{' + label + '}: [red]{' + name + '}' + stack + '\n');
+    if (watch) notify(label + ' failed');
+}
+
+/**
+ * Run the given tests.
+ *
+ * @param  {String} title
+ * @param  {Object} tests
+ */
+
+var dots = 0;
+function runSuite(title, tests) {
+    // Keys
+    var keys = only.length
+        ? only.slice(0)
+        : Object.keys(tests);
+
+    // Setup
+    var setup = tests.setup || function(fn){ fn(); };
+    
+    // Iterate tests
+    (function next(){
+        if (keys.length) {
+            var key,
+                test = tests[key = keys.shift()];
+            // Non-tests
+            if (key === 'setup') return next();
+
+            // Run test
+            if (test) {
+                try {
+                    ++testcount;
+                    assert.testTitle = key;
+                    if (serial) {
+                        if (!watch) {
+                            sys.print('.');
+                            if (++dots % 25 === 0) sys.print('\n');
+                        }
+                        setup(function(){
+                            if (test.length < 2) {
+                                test(assert);
+                                next();
+                            } else {
+                                var id = setTimeout(function(){
+                                    throw new Error("'" + key + "' timed out");
+                                }, timeout);
+                                test(assert, function(){
+                                    clearTimeout(id);
+                                    next();
+                                });
+                            } 
+                        });
+                    } else {
+                        test(assert, function(fn){
+                            process.addListener('beforeExit', function(){
+                                try {
+                                    fn();
+                                } catch (err) {
+                                    error(title, key, err);
+                                }
+                            });
+                        });
+                    }
+                } catch (err) {
+                    error(title, key, err);
+                }
+            }
+            if (!serial) next();
+        }
+    })();
+}
+
+/**
+ * Report exceptions.
+ */
+
+function report() {
+    process.emit('beforeExit');
+    if (failures) {
+        print('\n   [bold]{Failures}: [red]{' + failures + '}\n\n');
+        notify('Failures: ' + failures);
+    } else {
+        if (serial) print('');
+        print('\n   [green]{100%} ' + testcount + ' tests\n');
+        notify('100% ok');
+    }
+    if (typeof _$jscoverage === 'object') {
+        reportCoverage(_$jscoverage);
+    }
+}
+
+/**
+ * Growl notify the given `msg`.
+ *
+ * @param {String} msg
+ */
+
+function notify(msg) {
+    if (growl) {
+        childProcess.exec('growlnotify -name Expresso -m "' + msg + '"');
+    }
+}
+
+// Report uncaught exceptions
+
+process.addListener('uncaughtException', function(err){
+    error('uncaught', 'uncaught', err);
+});
+
+// Show cursor
+
+['INT', 'TERM', 'QUIT'].forEach(function(sig){
+    process.addListener('SIG' + sig, function(){
+        cursor(true);
+        process.exit(1);
+    });
+});
+
+// Report test coverage when available
+// and emit "beforeExit" event to perform
+// final assertions
+
+var orig = process.emit;
+process.emit = function(event){
+    if (event === 'exit') {
+        report();
+        process.reallyExit(failures);
+    }
+    orig.apply(this, arguments);
+};
+
+// Run test files
+
+if (!defer) run(files);
diff --git a/node_modules/jade/support/expresso/docs/api.html b/node_modules/jade/support/expresso/docs/api.html
new file mode 100644
index 0000000..8718732
--- /dev/null
+++ b/node_modules/jade/support/expresso/docs/api.html
@@ -0,0 +1,1048 @@
+Fork me on GitHub
+	
+		Expresso
+		
+		
+		
+	
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Expresso

Insanely fast TDD framework for node featuring code coverage reporting.

expresso

bin/expresso
+

!/usr/bin/env node

+
+
!
+ * Expresso
+ * Copyright(c) TJ Holowaychuk &lt;tj@vision-media.ca&gt;
+ * (MIT Licensed)
+ 
+
+

Module dependencies. +

+
+
var assert = require('assert'),
+    childProcess = require('child_process'),
+    http = require('http'),
+    path = require('path'),
+    sys = require('sys'),
+    cwd = process.cwd(),
+    fs = require('fs'),
+    defer;
+
+

Expresso version. +

+
+
var version = '0.6.1';
+
+

Failure count. +

+
+
var failures = 0;
+
+

Number of tests executed. +

+
+
var testcount = 0;
+
+

Whitelist of tests to run. +

+
+
var only = [];
+
+

Boring output. +

+
+
var boring = false;
+
+

Growl notifications. +

+
+
var growl = false;
+
+

Server port. +

+
+
var port = 5555;
+
+

Watch mode. +

+
+
var watch = false;
+
+

Execute serially. +

+
+
var serial = false;
+
+

Usage documentation. +

+
+
var usage = ''
+    + '[bold]{Usage}: expresso [options] <file ...>'
+    + '\n'
+    + '\n[bold]{Options}:'
+    + '\n  -w, --watch          Watch for modifications and re-execute tests'
+    + '\n  -g, --growl          Enable growl notifications'
+    + '\n  -c, --coverage       Generate and report test coverage'
+    + '\n  -r, --require PATH   Require the given module path'
+    + '\n  -o, --only TESTS     Execute only the comma sperated TESTS (can be set several times)'
+    + '\n  -I, --include PATH   Unshift the given path to require.paths'
+    + '\n  -p, --port NUM       Port number for test servers, starts at 5555'
+    + '\n  -s, --serial         Execute tests serially'
+    + '\n  -b, --boring         Suppress ansi-escape colors'
+    + '\n  -v, --version        Output version number'
+    + '\n  -h, --help           Display help information'
+    + '\n';
+
+// Parse arguments
+
+var files = [],
+    args = process.argv.slice(2);
+
+while (args.length) {
+    var arg = args.shift();
+    switch (arg) {
+        case '-h':
+        case '--help':
+            print(usage + '\n');
+            process.exit(1);
+            break;
+        case '-v':
+        case '--version':
+            sys.puts(version);
+            process.exit(1);
+            break;
+        case '-i':
+        case '-I':
+        case '--include':
+            if (arg = args.shift()) {
+                require.paths.unshift(arg);
+            } else {
+                throw new Error('--include requires a path');
+            }
+            break;
+        case '-o':
+        case '--only':
+            if (arg = args.shift()) {
+                only = only.concat(arg.split(/ *, */));
+            } else {
+                throw new Error('--only requires comma-separated test names');
+            }
+            break;
+        case '-p':
+        case '--port':
+            if (arg = args.shift()) {
+                port = parseInt(arg, 10);
+            } else {
+                throw new Error('--port requires a number');
+            }
+            break;
+        case '-r':
+        case '--require':
+            if (arg = args.shift()) {
+                require(arg);
+            } else {
+                throw new Error('--require requires a path');
+            }
+            break;
+        case '-c':
+        case '--cov':
+        case '--coverage':
+            defer = true;
+            childProcess.exec('rm -fr lib-cov && node-jscoverage lib lib-cov', function(err){
+                if (err) throw err;
+                require.paths.unshift('lib-cov');
+                run(files);
+            })
+            break;
+        case '-b':
+        case '--boring':
+        	boring = true;
+        	break;
+        case '-w':
+        case '--watch':
+            watch = true;
+            break;
+        case '-g':
+        case '--growl':
+            growl = true;
+            break;
+        case '-s':
+        case '--serial':
+            serial = true;
+            break;
+        default:
+            if (/\.js$/.test(arg)) {
+                files.push(arg);
+            }
+            break;
+    }
+}
+
+

Colorized sys.error().

+ +

+ +
  • param: String str

+
+
function print(str){
+    sys.error(colorize(str));
+}
+
+

Colorize the given string using ansi-escape sequences. +Disabled when --boring is set.

+ +

+ +
  • param: String str

  • return: String

+
+
function colorize(str){
+    var colors = { bold: 1, red: 31, green: 32, yellow: 33 };
+    return str.replace(/\[(\w+)\]\{([^]*?)\}/g, function(_, color, str){
+        return boring
+            ? str
+            : '\x1B[' + colors[color] + 'm' + str + '\x1B[0m';
+    });
+}
+
+// Alias deepEqual as eql for complex equality
+
+assert.eql = assert.deepEqual;
+
+

Assert that val is null.

+ +

+ +
  • param: Mixed val

  • param: String msg

+
+
assert.isNull = function(val, msg) {
+    assert.strictEqual(null, val, msg);
+};
+
+

Assert that val is not null.

+ +

+ +
  • param: Mixed val

  • param: String msg

+
+
assert.isNotNull = function(val, msg) {
+    assert.notStrictEqual(null, val, msg);
+};
+
+

Assert that val is undefined.

+ +

+ +
  • param: Mixed val

  • param: String msg

+
+
assert.isUndefined = function(val, msg) {
+    assert.strictEqual(undefined, val, msg);
+};
+
+

Assert that val is not undefined.

+ +

+ +
  • param: Mixed val

  • param: String msg

+
+
assert.isDefined = function(val, msg) {
+    assert.notStrictEqual(undefined, val, msg);
+};
+
+

Assert that obj is type.

+ +

+ +
  • param: Mixed obj

  • param: String type

  • api: public

+
+
assert.type = function(obj, type, msg){
+    var real = typeof obj;
+    msg = msg || 'typeof ' + sys.inspect(obj) + ' is ' + real + ', expected ' + type;
+    assert.ok(type === real, msg);
+};
+
+

Assert that str matches regexp.

+ +

+ +
  • param: String str

  • param: RegExp regexp

  • param: String msg

+
+
assert.match = function(str, regexp, msg) {
+    msg = msg || sys.inspect(str) + ' does not match ' + sys.inspect(regexp);
+    assert.ok(regexp.test(str), msg);
+};
+
+

Assert that val is within obj.

+ +

Examples

+ +

assert.includes('foobar', 'bar'); + assert.includes(['foo', 'bar'], 'foo');

+ +

+ +
  • param: String | Array obj

  • param: Mixed val

  • param: String msg

+
+
assert.includes = function(obj, val, msg) {
+    msg = msg || sys.inspect(obj) + ' does not include ' + sys.inspect(val);
+    assert.ok(obj.indexOf(val) &gt;= 0, msg);
+};
+
+

Assert length of val is n.

+ +

+ +
  • param: Mixed val

  • param: Number n

  • param: String msg

+
+
assert.length = function(val, n, msg) {
+    msg = msg || sys.inspect(val) + ' has length of ' + val.length + ', expected ' + n;
+    assert.equal(n, val.length, msg);
+};
+
+

Assert response from server with +the given req object and res assertions object.

+ +

+ +
  • param: Server server

  • param: Object req

  • param: Object | Function res

  • param: String msg

+
+
assert.response = function(server, req, res, msg){
+    // Callback as third or fourth arg
+    var callback = typeof res === 'function'
+        ? res
+        : typeof msg === 'function'
+            ? msg
+            : function(){};
+
+    // Default messate to test title
+    if (typeof msg === 'function') msg = null;
+    msg = msg || assert.testTitle;
+    msg += '. ';
+
+    // Pending responses
+    server.__pending = server.__pending || 0;
+    server.__pending++;
+
+    // Create client
+    if (!server.fd) {
+        server.listen(server.__port = port++, '127.0.0.1');
+        server.client = http.createClient(server.__port);
+    }
+
+    // Issue request
+    var timer,
+        client = server.client,
+        method = req.method || 'GET',
+        status = res.status || res.statusCode,
+        data = req.data || req.body,
+        timeout = req.timeout || 0;
+
+    var request = client.request(method, req.url, req.headers);
+
+    // Timeout
+    if (timeout) {
+        timer = setTimeout(function(){
+            --server.__pending || server.close();
+            delete req.timeout;
+            assert.fail(msg + 'Request timed out after ' + timeout + 'ms.');
+        }, timeout);
+    }
+
+    if (data) request.write(data);
+    request.addListener('response', function(response){
+        response.body = '';
+        response.setEncoding('utf8');
+        response.addListener('data', function(chunk){ response.body += chunk; });
+        response.addListener('end', function(){
+            --server.__pending || server.close();
+            if (timer) clearTimeout(timer);
+
+            // Assert response body
+            if (res.body !== undefined) {
+                assert.equal(
+                    response.body,
+                    res.body,
+                    msg + 'Invalid response body.\n'
+                        + '    Expected: ' + sys.inspect(res.body) + '\n'
+                        + '    Got: ' + sys.inspect(response.body)
+                );
+            }
+
+            // Assert response status
+            if (typeof status === 'number') {
+                assert.equal(
+                    response.statusCode,
+                    status,
+                    msg + colorize('Invalid response status code.\n'
+                        + '    Expected: [green]{' + status + '}\n'
+                        + '    Got: [red]{' + response.statusCode + '}')
+                );
+            }
+
+            // Assert response headers
+            if (res.headers) {
+                var keys = Object.keys(res.headers);
+                for (var i = 0, len = keys.length; i &lt; len; ++i) {
+                    var name = keys[i],
+                        actual = response.headers[name.toLowerCase()],
+                        expected = res.headers[name];
+                    assert.equal(
+                        actual,
+                        expected,
+                        msg + colorize('Invalid response header [bold]{' + name + '}.\n'
+                            + '    Expected: [green]{' + expected + '}\n'
+                            + '    Got: [red]{' + actual + '}')
+                    );
+                }
+            }
+
+            // Callback
+            callback(response);
+        });
+    });
+    request.end();
+};
+
+

Pad the given string to the maximum width provided.

+ +

+ +
  • param: String str

  • param: Number width

  • return: String

+
+
function lpad(str, width) {
+    str = String(str);
+    var n = width - str.length;
+    if (n &lt; 1) return str;
+    while (n--) str = ' ' + str;
+    return str;
+}
+
+

Pad the given string to the maximum width provided.

+ +

+ +
  • param: String str

  • param: Number width

  • return: String

+
+
function rpad(str, width) {
+    str = String(str);
+    var n = width - str.length;
+    if (n &lt; 1) return str;
+    while (n--) str = str + ' ';
+    return str;
+}
+
+

Report test coverage.

+ +

+ +
  • param: Object cov

+
+
function reportCoverage(cov) {
+    populateCoverage(cov);
+    // Stats
+    print('\n   [bold]{Test Coverage}\n');
+    var sep = '   +------------------------------------------+----------+------+------+--------+',
+        lastSep = '                                              +----------+------+------+--------+';
+    sys.puts(sep);
+    sys.puts('   | filename                                 | coverage | LOC  | SLOC | missed |');
+    sys.puts(sep);
+    for (var name in cov) {
+        var file = cov[name];
+        if (Array.isArray(file)) {
+            sys.print('   | ' + rpad(name, 40));
+            sys.print(' | ' + lpad(file.coverage.toFixed(2), 8));
+            sys.print(' | ' + lpad(file.LOC, 4));
+            sys.print(' | ' + lpad(file.SLOC, 4));
+            sys.print(' | ' + lpad(file.totalMisses, 6));
+            sys.print(' |\n');
+        }
+    }
+    sys.puts(sep);
+    sys.print('     ' + rpad('', 40));
+    sys.print(' | ' + lpad(cov.coverage.toFixed(2), 8));
+    sys.print(' | ' + lpad(cov.LOC, 4));
+    sys.print(' | ' + lpad(cov.SLOC, 4));
+    sys.print(' | ' + lpad(cov.totalMisses, 6));
+    sys.print(' |\n');
+    sys.puts(lastSep);
+    // Source
+    for (var name in cov) {
+        if (name.match(/\.js$/)) {
+            var file = cov[name];
+            print('\n   [bold]{' + name + '}:');
+            print(file.source);
+            sys.print('\n');
+        }
+    }
+}
+
+

Populate code coverage data.

+ +

+ +
  • param: Object cov

+
+
function populateCoverage(cov) {
+    cov.LOC = 
+    cov.SLOC =
+    cov.totalFiles =
+    cov.totalHits =
+    cov.totalMisses = 
+    cov.coverage = 0;
+    for (var name in cov) {
+        var file = cov[name];
+        if (Array.isArray(file)) {
+            // Stats
+            ++cov.totalFiles;
+            cov.totalHits += file.totalHits = coverage(file, true);
+            cov.totalMisses += file.totalMisses = coverage(file, false);
+            file.totalLines = file.totalHits + file.totalMisses;
+            cov.SLOC += file.SLOC = file.totalLines;
+            if (!file.source) file.source = [];
+            cov.LOC += file.LOC = file.source.length;
+            file.coverage = (file.totalHits / file.totalLines) * 100;
+            // Source
+            var width = file.source.length.toString().length;
+            file.source = file.source.map(function(line, i){
+                ++i;
+                var hits = file[i] === 0 ? 0 : (file[i] || ' ');
+                if (!boring) {
+                    if (hits === 0) {
+                        hits = '\x1b[31m' + hits + '\x1b[0m';
+                        line = '\x1b[41m' + line + '\x1b[0m';
+                    } else {
+                        hits = '\x1b[32m' + hits + '\x1b[0m';
+                    }
+                }
+                return '\n     ' + lpad(i, width) + ' | ' + hits + ' | ' + line;
+            }).join('');
+        }
+    }
+    cov.coverage = (cov.totalHits / cov.SLOC) * 100;
+}
+
+

Total coverage for the given file data.

+ +

+ +
  • param: Array data

  • return: Type

+
+
function coverage(data, val) {
+    var n = 0;
+    for (var i = 0, len = data.length; i &lt; len; ++i) {
+        if (data[i] !== undefined &amp;&amp; data[i] == val) ++n;
+    }
+    return n;  
+}
+
+

Run the given test files, or try test/*.

+ +

+ +
  • param: Array files

+
+
function run(files) {
+    if (!files.length) {
+        try {
+            files = fs.readdirSync('test').map(function(file){
+                return 'test/' + file;
+            });
+        } catch (err) {
+            print('\n  failed to load tests in [bold]{./test}\n');
+            ++failures;
+            process.exit(1);
+        }
+    }
+    if (watch) watchFiles(files);
+    runFiles(files);
+}
+
+

Show the cursor when show is true, otherwise hide it.

+ +

+ +
  • param: Boolean show

+
+
function cursor(show) {
+    if (show) {
+        sys.print('\x1b[?25h');
+    } else {
+        sys.print('\x1b[?25l');
+    }
+}
+
+

Run the given test files.

+ +

+ +
  • param: Array files

+
+
function runFiles(files) {
+    files.forEach(runFile);
+}
+
+

Run tests for the given file.

+ +

+ +
  • param: String file

+
+
function runFile(file) {
+    if (file.match(/\.js$/)) {
+        var title = path.basename(file),
+            file = path.join(cwd, file),
+            mod = require(file.replace(/\.js$/, ''));
+        (function check(){
+           var len = Object.keys(mod).length;
+           if (len) {
+               runSuite(title, mod);
+           } else {
+               setTimeout(check, 20);
+           }
+        })();
+    }
+}
+
+

Clear the module cache for the given file.

+ +

+ +
  • param: String file

+
+
function clearCache(file) {
+    var keys = Object.keys(module.moduleCache);
+    for (var i = 0, len = keys.length; i &lt; len; ++i) {
+        var key = keys[i];
+        if (key.indexOf(file) === key.length - file.length) {
+            delete module.moduleCache[key];
+        }
+    }
+}
+
+

Watch the given files for changes.

+ +

+ +
  • param: Array files

+
+
function watchFiles(files) {
+    var p = 0,
+        c = ['▫   ', '▫▫  ', '▫▫▫ ', ' ▫▫▫',
+             '  ▫▫', '   ▫', '   ▫', '  ▫▫',
+             '▫▫▫ ', '▫▫  ', '▫   '],
+        l = c.length;
+    cursor(false);
+    setInterval(function(){
+        sys.print(colorize('  [green]{' + c[p++ % l] + '} watching\r'));
+    }, 100);
+    files.forEach(function(file){
+        fs.watchFile(file, { interval: 100 }, function(curr, prev){
+            if (curr.mtime &gt; prev.mtime) {
+                print('  [yellow]{◦} ' + file);
+                clearCache(file);
+                runFile(file);
+            }
+        });
+    });
+}
+
+

Report err for the given test and suite.

+ +

+ +
  • param: String suite

  • param: String test

  • param: Error err

+
+
function error(suite, test, err) {
+    ++failures;
+    var name = err.name,
+        stack = err.stack.replace(err.name, ''),
+        label = test === 'uncaught'
+            ? test
+            : suite + ' ' + test;
+    print('\n   [bold]{' + label + '}: [red]{' + name + '}' + stack + '\n');
+    if (watch) notify(label + ' failed');
+}
+
+

Run the given tests.

+ +

+ +
  • param: String title

  • param: Object tests

+
+
var dots = 0;
+function runSuite(title, tests) {
+    // Keys
+    var keys = only.length
+        ? only.slice(0)
+        : Object.keys(tests);
+
+    // Setup
+    var setup = tests.setup || function(fn){ fn(); };
+    
+    // Iterate tests
+    (function next(){
+        if (keys.length) {
+            var key,
+                test = tests[key = keys.shift()];
+            // Non-tests
+            if (key === 'setup') return next();
+
+            // Run test
+            if (test) {
+                try {
+                    ++testcount;
+                    assert.testTitle = key;
+                    if (serial) {
+                        if (!watch) {
+                            sys.print('.');
+                            if (++dots % 25 === 0) sys.print('\n');
+                        }
+                        setup(function(){
+                            if (test.length &lt; 2) {
+                                test(assert);
+                                next();
+                            } else {
+                                var id = setTimeout(function(){
+                                    throw new Error(&quot;'" + key + "' timed out&quot;);
+                                }, 2000);
+                                test(assert, function(){
+                                    clearTimeout(id);
+                                    next();
+                                });
+                            } 
+                        });
+                    } else {
+                        test(assert, function(fn){
+                            process.addListener('beforeExit', function(){
+                                try {
+                                    fn();
+                                } catch (err) {
+                                    error(title, key, err);
+                                }
+                            });
+                        });
+                    }
+                } catch (err) {
+                    error(title, key, err);
+                }
+            }
+            if (!serial) next();
+        }
+    })();
+}
+
+

Report exceptions. +

+
+
function report() {
+    process.emit('beforeExit');
+    if (failures) {
+        print('\n   [bold]{Failures}: [red]{' + failures + '}\n\n');
+        notify('Failures: ' + failures);
+    } else {
+        if (serial) print('');
+        print('\n   [green]{100%} ' + testcount + ' tests\n');
+        notify('100% ok');
+    }
+    if (typeof _$jscoverage === 'object') {
+        reportCoverage(_$jscoverage);
+    }
+}
+
+

Growl notify the given msg.

+ +

+ +
  • param: String msg

+
+
function notify(msg) {
+    if (growl) {
+        childProcess.exec('growlnotify -name Expresso -m "' + msg + '"');
+    }
+}
+
+// Report uncaught exceptions
+
+process.addListener('uncaughtException', function(err){
+    error('uncaught', 'uncaught', err);
+});
+
+// Show cursor
+
+['INT', 'TERM', 'QUIT'].forEach(function(sig){
+    process.addListener('SIG' + sig, function(){
+        cursor(true);
+        process.exit(1);
+    });
+});
+
+// Report test coverage when available
+// and emit "beforeExit" event to perform
+// final assertions
+
+var orig = process.emit;
+process.emit = function(event){
+    if (event === 'exit') {
+        report();
+        process.reallyExit(failures);
+    }
+    orig.apply(this, arguments);
+};
+
+// Run test files
+
+if (!defer) run(files);
+
+
\ No newline at end of file diff --git a/node_modules/jade/support/expresso/docs/index.html b/node_modules/jade/support/expresso/docs/index.html new file mode 100644 index 0000000..49d8148 --- /dev/null +++ b/node_modules/jade/support/expresso/docs/index.html @@ -0,0 +1,373 @@ + + + Expresso - TDD Framework For Node + + + + + Fork me on GitHub + +
+

Expresso

+
+

Expresso is a JavaScript TDD framework written for nodejs. Expresso is extremely fast, and is packed with features such as additional assertion methods, code coverage reporting, CI support, and more.

+ +

Features

+ +
    +
  • light-weight
  • +
  • intuitive async support
  • +
  • intuitive test runner executable
  • +
  • test coverage support and reporting via node-jscoverage
  • +
  • uses and extends the core assert module
  • +
  • assert.eql() alias of assert.deepEqual()
  • +
  • assert.response() http response utility
  • +
  • assert.includes()
  • +
  • assert.isNull()
  • +
  • assert.isUndefined()
  • +
  • assert.isNotNull()
  • +
  • assert.isDefined()
  • +
  • assert.match()
  • +
  • assert.length()
  • +
+ + +

Installation

+ +

To install both expresso and node-jscoverage run +the command below, which will first compile node-jscoverage:

+ +
$ make install
+
+ +

To install expresso alone without coverage reporting run:

+ +
$ make install-expresso
+
+ +

Install via npm:

+ +
$ npm install expresso
+
+ +

Examples

+ +

To define tests we simply export several functions:

+ +
exports['test String#length'] = function(assert){
+    assert.equal(6, 'foobar'.length);
+};
+
+ +

Alternatively for large numbers of tests you may want to +export your own object containing the tests, however this +is essentially the as above:

+ +
module.exports = {
+    'test String#length': function(assert){
+        assert.equal(6, 'foobar'.length);
+    }
+};
+
+ +

If you prefer not to use quoted keys:

+ +
exports.testsStringLength = function(assert){
+    assert.equal(6, 'foobar'.length);
+};
+
+ +

The second argument passed to each callback is beforeExit, +which is typically used to assert that callbacks have been +invoked.

+ +
exports.testAsync = function(assert, beforeExit){
+    var n = 0;
+    setTimeout(function(){
+        ++n;
+        assert.ok(true);
+    }, 200);
+    setTimeout(function(){
+        ++n;
+        assert.ok(true);
+    }, 200);
+    beforeExit(function(){
+        assert.equal(2, n, 'Ensure both timeouts are called');
+    });
+};
+
+ +

Assert Utilities

+ +

assert.isNull(val[, msg])

+ +

Asserts that the given val is null.

+ +
assert.isNull(null);
+
+ +

assert.isNotNull(val[, msg])

+ +

Asserts that the given val is not null.

+ +
assert.isNotNull(undefined);
+assert.isNotNull(false);
+
+ +

assert.isUndefined(val[, msg])

+ +

Asserts that the given val is undefined.

+ +
assert.isUndefined(undefined);
+
+ +

assert.isDefined(val[, msg])

+ +

Asserts that the given val is not undefined.

+ +
assert.isDefined(null);
+assert.isDefined(false);
+
+ +

assert.match(str, regexp[, msg])

+ +

Asserts that the given str matches regexp.

+ +
assert.match('foobar', /^foo(bar)?/);
+assert.match('foo', /^foo(bar)?/);
+
+ +

assert.length(val, n[, msg])

+ +

Assert that the given val has a length of n.

+ +
assert.length([1,2,3], 3);
+assert.length('foo', 3);
+
+ +

assert.type(obj, type[, msg])

+ +

Assert that the given obj is typeof type.

+ +
assert.type(3, 'number');
+
+ +

assert.eql(a, b[, msg])

+ +

Assert that object b is equal to object a. This is an +alias for the core assert.deepEqual() method which does complex +comparisons, opposed to assert.equal() which uses ==.

+ +
assert.eql('foo', 'foo');
+assert.eql([1,2], [1,2]);
+assert.eql({ foo: 'bar' }, { foo: 'bar' });
+
+ +

assert.includes(obj, val[, msg])

+ +

Assert that obj is within val. This method supports Array_s +and Strings_s.

+ +
assert.includes([1,2,3], 3);
+assert.includes('foobar', 'foo');
+assert.includes('foobar', 'bar');
+
+ +

assert.response(server, req, res|fn[, msg|fn])

+ +

Performs assertions on the given server, which should not call +listen(), as this is handled internally by expresso and the server +is killed after all responses have completed. This method works with +any http.Server instance, so Connect and Express servers will work +as well.

+ +

The req object may contain:

+ +
    +
  • url request url
  • +
  • timeout timeout in milliseconds
  • +
  • method HTTP method
  • +
  • data request body
  • +
  • headers headers object
  • +
+ + +

The res object may be a callback function which +receives the response for assertions, or an object +which is then used to perform several assertions +on the response with the following properties:

+ +
    +
  • body assert response body
  • +
  • status assert response status code
  • +
  • header assert that all given headers match (unspecified are ignored)
  • +
+ + +

When providing res you may then also pass a callback function +as the fourth argument for additional assertions.

+ +

Below are some examples:

+ +
assert.response(server, {
+    url: '/', timeout: 500
+}, {
+    body: 'foobar'
+});
+
+assert.response(server, {
+    url: '/',
+    method: 'GET'
+},{
+    body: '{"name":"tj"}',
+    status: 200,
+    headers: {
+        'Content-Type': 'application/json; charset=utf8',
+        'X-Foo': 'bar'
+    }
+});
+
+assert.response(server, {
+    url: '/foo',
+    method: 'POST',
+    data: 'bar baz'
+},{
+    body: '/foo bar baz',
+    status: 200
+}, 'Test POST');
+
+assert.response(server, {
+    url: '/foo',
+    method: 'POST',
+    data: 'bar baz'
+},{
+    body: '/foo bar baz',
+    status: 200
+}, function(res){
+    // All done, do some more tests if needed
+});
+
+assert.response(server, {
+    url: '/'
+}, function(res){
+    assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback');
+});
+
+ +

expresso(1)

+ +

To run a single test suite (file) run:

+ +
$ expresso test/a.test.js
+
+ +

To run several suites we may simply append another:

+ +
$ expresso test/a.test.js test/b.test.js
+
+ +

We can also pass a whitelist of tests to run within all suites:

+ +
$ expresso --only "foo()" --only "bar()"
+
+ +

Or several with one call:

+ +
$ expresso --only "foo(), bar()"
+
+ +

Globbing is of course possible as well:

+ +
$ expresso test/*
+
+ +

When expresso is called without any files, test/* is the default, +so the following is equivalent to the command above:

+ +
$ expresso
+
+ +

If you wish to unshift a path to require.paths before +running tests, you may use the -I or --include flag.

+ +
$ expresso --include lib test/*
+
+ +

The previous example is typically what I would recommend, since expresso +supports test coverage via node-jscoverage (bundled with expresso), +so you will need to expose an instrumented version of you library.

+ +

To instrument your library, simply run node-jscoverage, +passing the src and dest directories:

+ +
$ node-jscoverage lib lib-cov
+
+ +

Now we can run our tests again, using the lib-cov directory that has been +instrumented with coverage statements:

+ +
$ expresso -I lib-cov test/*
+
+ +

The output will look similar to below, depending on your test coverage of course :)

+ +

node coverage

+ +

To make this process easier expresso has the -c or --cov which essentially +does the same as the two commands above. The following two commands will +run the same tests, however one will auto-instrument, and unshift lib-cov, +and the other will run tests normally:

+ +
$ expresso -I lib test/*
+$ expresso -I lib --cov test/*
+
+ +

Currently coverage is bound to the lib directory, however in the +future --cov will most likely accept a path.

+ +

Async Exports

+ +

Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the exports.foo = function(){}; syntax is supported for this:

+ +
setTimeout(function(){
+    exports['test async exports'] = function(assert){
+        assert.ok('wahoo');
+    };
+}, 100);
+
+ +
+
+ + \ No newline at end of file diff --git a/node_modules/jade/support/expresso/docs/index.md b/node_modules/jade/support/expresso/docs/index.md new file mode 100644 index 0000000..5376e59 --- /dev/null +++ b/node_modules/jade/support/expresso/docs/index.md @@ -0,0 +1,290 @@ + +[Expresso](http://github.com/visionmedia/expresso) is a JavaScript [TDD](http://en.wikipedia.org/wiki/Test-driven_development) framework written for [nodejs](http://nodejs.org). Expresso is extremely fast, and is packed with features such as additional assertion methods, code coverage reporting, CI support, and more. + +## Features + + - light-weight + - intuitive async support + - intuitive test runner executable + - test coverage support and reporting via [node-jscoverage](http://github.com/visionmedia/node-jscoverage) + - uses and extends the core _assert_ module + - `assert.eql()` alias of `assert.deepEqual()` + - `assert.response()` http response utility + - `assert.includes()` + - `assert.isNull()` + - `assert.isUndefined()` + - `assert.isNotNull()` + - `assert.isDefined()` + - `assert.match()` + - `assert.length()` + +## Installation + +To install both expresso _and_ node-jscoverage run +the command below, which will first compile node-jscoverage: + + $ make install + +To install expresso alone without coverage reporting run: + + $ make install-expresso + +Install via npm: + + $ npm install expresso + +## Examples + +To define tests we simply export several functions: + + exports['test String#length'] = function(assert){ + assert.equal(6, 'foobar'.length); + }; + +Alternatively for large numbers of tests you may want to +export your own object containing the tests, however this +is essentially the as above: + + module.exports = { + 'test String#length': function(assert){ + assert.equal(6, 'foobar'.length); + } + }; + +If you prefer not to use quoted keys: + + exports.testsStringLength = function(assert){ + assert.equal(6, 'foobar'.length); + }; + +The second argument passed to each callback is _beforeExit_, +which is typically used to assert that callbacks have been +invoked. + + exports.testAsync = function(assert, beforeExit){ + var n = 0; + setTimeout(function(){ + ++n; + assert.ok(true); + }, 200); + setTimeout(function(){ + ++n; + assert.ok(true); + }, 200); + beforeExit(function(){ + assert.equal(2, n, 'Ensure both timeouts are called'); + }); + }; + +## Assert Utilities + +### assert.isNull(val[, msg]) + +Asserts that the given _val_ is _null_. + + assert.isNull(null); + +### assert.isNotNull(val[, msg]) + +Asserts that the given _val_ is not _null_. + + assert.isNotNull(undefined); + assert.isNotNull(false); + +### assert.isUndefined(val[, msg]) + +Asserts that the given _val_ is _undefined_. + + assert.isUndefined(undefined); + +### assert.isDefined(val[, msg]) + +Asserts that the given _val_ is not _undefined_. + + assert.isDefined(null); + assert.isDefined(false); + +### assert.match(str, regexp[, msg]) + +Asserts that the given _str_ matches _regexp_. + + assert.match('foobar', /^foo(bar)?/); + assert.match('foo', /^foo(bar)?/); + +### assert.length(val, n[, msg]) + +Assert that the given _val_ has a length of _n_. + + assert.length([1,2,3], 3); + assert.length('foo', 3); + +### assert.type(obj, type[, msg]) + +Assert that the given _obj_ is typeof _type_. + + assert.type(3, 'number'); + +### assert.eql(a, b[, msg]) + +Assert that object _b_ is equal to object _a_. This is an +alias for the core _assert.deepEqual()_ method which does complex +comparisons, opposed to _assert.equal()_ which uses _==_. + + assert.eql('foo', 'foo'); + assert.eql([1,2], [1,2]); + assert.eql({ foo: 'bar' }, { foo: 'bar' }); + +### assert.includes(obj, val[, msg]) + +Assert that _obj_ is within _val_. This method supports _Array_s +and _Strings_s. + + assert.includes([1,2,3], 3); + assert.includes('foobar', 'foo'); + assert.includes('foobar', 'bar'); + +### assert.response(server, req, res|fn[, msg|fn]) + +Performs assertions on the given _server_, which should _not_ call +listen(), as this is handled internally by expresso and the server +is killed after all responses have completed. This method works with +any _http.Server_ instance, so _Connect_ and _Express_ servers will work +as well. + +The _req_ object may contain: + + - _url_ request url + - _timeout_ timeout in milliseconds + - _method_ HTTP method + - _data_ request body + - _headers_ headers object + +The _res_ object may be a callback function which +receives the response for assertions, or an object +which is then used to perform several assertions +on the response with the following properties: + + - _body_ assert response body + - _status_ assert response status code + - _header_ assert that all given headers match (unspecified are ignored) + +When providing _res_ you may then also pass a callback function +as the fourth argument for additional assertions. + +Below are some examples: + + assert.response(server, { + url: '/', timeout: 500 + }, { + body: 'foobar' + }); + + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8', + 'X-Foo': 'bar' + } + }); + + assert.response(server, { + url: '/foo', + method: 'POST', + data: 'bar baz' + },{ + body: '/foo bar baz', + status: 200 + }, 'Test POST'); + + assert.response(server, { + url: '/foo', + method: 'POST', + data: 'bar baz' + },{ + body: '/foo bar baz', + status: 200 + }, function(res){ + // All done, do some more tests if needed + }); + + assert.response(server, { + url: '/' + }, function(res){ + assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback'); + }); + + +## expresso(1) + +To run a single test suite (file) run: + + $ expresso test/a.test.js + +To run several suites we may simply append another: + + $ expresso test/a.test.js test/b.test.js + +We can also pass a whitelist of tests to run within all suites: + + $ expresso --only "foo()" --only "bar()" + +Or several with one call: + + $ expresso --only "foo(), bar()" + +Globbing is of course possible as well: + + $ expresso test/* + +When expresso is called without any files, _test/*_ is the default, +so the following is equivalent to the command above: + + $ expresso + +If you wish to unshift a path to `require.paths` before +running tests, you may use the `-I` or `--include` flag. + + $ expresso --include lib test/* + +The previous example is typically what I would recommend, since expresso +supports test coverage via [node-jscoverage](http://github.com/visionmedia/node-jscoverage) (bundled with expresso), +so you will need to expose an instrumented version of you library. + +To instrument your library, simply run [node-jscoverage](http://github.com/visionmedia/node-jscoverage), +passing the _src_ and _dest_ directories: + + $ node-jscoverage lib lib-cov + +Now we can run our tests again, using the _lib-cov_ directory that has been +instrumented with coverage statements: + + $ expresso -I lib-cov test/* + +The output will look similar to below, depending on your test coverage of course :) + +![node coverage](http://dl.dropbox.com/u/6396913/cov.png) + +To make this process easier expresso has the _-c_ or _--cov_ which essentially +does the same as the two commands above. The following two commands will +run the same tests, however one will auto-instrument, and unshift _lib-cov_, +and the other will run tests normally: + + $ expresso -I lib test/* + $ expresso -I lib --cov test/* + +Currently coverage is bound to the _lib_ directory, however in the +future `--cov` will most likely accept a path. + +## Async Exports + +Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the _exports.foo = function(){};_ syntax is supported for this: + + setTimeout(function(){ + exports['test async exports'] = function(assert){ + assert.ok('wahoo'); + }; + }, 100); diff --git a/node_modules/jade/support/expresso/docs/layout/foot.html b/node_modules/jade/support/expresso/docs/layout/foot.html new file mode 100644 index 0000000..44d85e9 --- /dev/null +++ b/node_modules/jade/support/expresso/docs/layout/foot.html @@ -0,0 +1,3 @@ +
+ + \ No newline at end of file diff --git a/node_modules/jade/support/expresso/docs/layout/head.html b/node_modules/jade/support/expresso/docs/layout/head.html new file mode 100644 index 0000000..567f62e --- /dev/null +++ b/node_modules/jade/support/expresso/docs/layout/head.html @@ -0,0 +1,42 @@ + + + Expresso - TDD Framework For Node + + + + + Fork me on GitHub + +
+

Expresso

diff --git a/node_modules/jade/support/expresso/lib/bar.js b/node_modules/jade/support/expresso/lib/bar.js new file mode 100644 index 0000000..e15aad4 --- /dev/null +++ b/node_modules/jade/support/expresso/lib/bar.js @@ -0,0 +1,4 @@ + +exports.bar = function(msg){ + return msg || 'bar'; +}; \ No newline at end of file diff --git a/node_modules/jade/support/expresso/lib/foo.js b/node_modules/jade/support/expresso/lib/foo.js new file mode 100644 index 0000000..15701a5 --- /dev/null +++ b/node_modules/jade/support/expresso/lib/foo.js @@ -0,0 +1,16 @@ + +exports.foo = function(msg){ + if (msg) { + return msg; + } else { + return generateFoo(); + } +}; + +function generateFoo() { + return 'foo'; +} + +function Foo(msg){ + this.msg = msg || 'foo'; +} diff --git a/node_modules/jade/support/expresso/package.json b/node_modules/jade/support/expresso/package.json new file mode 100644 index 0000000..572935f --- /dev/null +++ b/node_modules/jade/support/expresso/package.json @@ -0,0 +1,12 @@ +{ "name": "expresso", + "version": "0.6.2", + "description": "TDD framework, light-weight, fast, CI-friendly", + "author": "TJ Holowaychuk ", + "bin": { + "expresso": "./bin/expresso", + "node-jscoverage": "./deps/jscoverage/node-jscoverage" + }, + "scripts": { + "preinstall": "make deps/jscoverage/node-jscoverage" + } +} \ No newline at end of file diff --git a/node_modules/jade/support/expresso/test/assert.test.js b/node_modules/jade/support/expresso/test/assert.test.js new file mode 100644 index 0000000..6a5e764 --- /dev/null +++ b/node_modules/jade/support/expresso/test/assert.test.js @@ -0,0 +1,84 @@ +module.exports = { + 'assert.eql()': function(assert){ + assert.equal(assert.deepEqual, assert.eql); + }, + + 'assert.type()': function(assert){ + assert.type('foobar', 'string'); + assert.type(2, 'number'); + assert.throws(function(){ + assert.type([1,2,3], 'string'); + }); + }, + + 'assert.includes()': function(assert){ + assert.includes('some random string', 'dom'); + assert.throws(function(){ + assert.include('some random string', 'foobar'); + }); + + assert.includes(['foo', 'bar'], 'bar'); + assert.includes(['foo', 'bar'], 'foo'); + assert.includes([1,2,3], 3); + assert.includes([1,2,3], 2); + assert.includes([1,2,3], 1); + assert.throws(function(){ + assert.includes(['foo', 'bar'], 'baz'); + }); + + assert.throws(function(){ + assert.includes({ wrong: 'type' }, 'foo'); + }); + }, + + 'assert.isNull()': function(assert){ + assert.isNull(null); + assert.throws(function(){ + assert.isNull(undefined); + }); + assert.throws(function(){ + assert.isNull(false); + }); + }, + + 'assert.isUndefined()': function(assert){ + assert.isUndefined(undefined); + assert.throws(function(){ + assert.isUndefined(null); + }); + assert.throws(function(){ + assert.isUndefined(false); + }); + }, + + 'assert.isNotNull()': function(assert){ + assert.isNotNull(false); + assert.isNotNull(undefined); + assert.throws(function(){ + assert.isNotNull(null); + }); + }, + + 'assert.isDefined()': function(assert){ + assert.isDefined(false); + assert.isDefined(null); + assert.throws(function(){ + assert.isDefined(undefined); + }); + }, + + 'assert.match()': function(assert){ + assert.match('foobar', /foo(bar)?/); + assert.throws(function(){ + assert.match('something', /rawr/); + }); + }, + + 'assert.length()': function(assert){ + assert.length('test', 4); + assert.length([1,2,3,4], 4); + assert.throws(function(){ + assert.length([1,2,3], 4); + }); + } +}; \ No newline at end of file diff --git a/node_modules/jade/support/expresso/test/async.test.js b/node_modules/jade/support/expresso/test/async.test.js new file mode 100644 index 0000000..0dc9016 --- /dev/null +++ b/node_modules/jade/support/expresso/test/async.test.js @@ -0,0 +1,6 @@ + +setTimeout(function(){ + exports['test async exports'] = function(assert){ + assert.ok('wahoo'); + }; +}, 100); \ No newline at end of file diff --git a/node_modules/jade/support/expresso/test/bar.test.js b/node_modules/jade/support/expresso/test/bar.test.js new file mode 100644 index 0000000..68e8d48 --- /dev/null +++ b/node_modules/jade/support/expresso/test/bar.test.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var bar = require('bar'); + +module.exports = { + 'bar()': function(assert){ + assert.equal('bar', bar.bar()); + } +}; \ No newline at end of file diff --git a/node_modules/jade/support/expresso/test/foo.test.js b/node_modules/jade/support/expresso/test/foo.test.js new file mode 100644 index 0000000..5d9d94e --- /dev/null +++ b/node_modules/jade/support/expresso/test/foo.test.js @@ -0,0 +1,13 @@ + +/** + * Module dependencies. + */ + +var foo = require('foo'); + +module.exports = { + 'foo()': function(assert){ + assert.equal('foo', foo.foo()); + assert.equal('foo', foo.foo()); + } +}; \ No newline at end of file diff --git a/node_modules/jade/support/expresso/test/http.test.js b/node_modules/jade/support/expresso/test/http.test.js new file mode 100644 index 0000000..3a44bec --- /dev/null +++ b/node_modules/jade/support/expresso/test/http.test.js @@ -0,0 +1,82 @@ + +/** + * Module dependencies. + */ + +var http = require('http'); + +var server = http.createServer(function(req, res){ + if (req.method === 'GET') { + if (req.url === '/delay') { + setTimeout(function(){ + res.writeHead(200, {}); + res.end('delayed'); + }, 200); + } else { + var body = JSON.stringify({ name: 'tj' }); + res.writeHead(200, { + 'Content-Type': 'application/json; charset=utf8', + 'Content-Length': body.length + }); + res.end(body); + } + } else { + var body = ''; + req.setEncoding('utf8'); + req.addListener('data', function(chunk){ body += chunk }); + req.addListener('end', function(){ + res.writeHead(200, {}); + res.end(req.url + ' ' + body); + }); + } +}); + +module.exports = { + 'test assert.response()': function(assert, beforeExit){ + var called = 0; + + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8' + } + }); + + assert.response(server, { + url: '/foo', + method: 'POST', + data: 'bar baz' + },{ + body: '/foo bar baz', + status: 200 + }, function(res){ + ++called; + assert.ok(res); + }); + + assert.response(server, { + url: '/foo' + }, function(res){ + ++called; + assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback'); + }); + + assert.response(server, + { url: '/delay', timeout: 300 }, + { body: 'delayed' }); + + beforeExit(function(){ + assert.equal(2, called); + }); + }, + + 'test assert.response() regexp': function(assert){ + assert.response(server, + { url: '/foo', method: 'POST', data: 'foobar' }, + { body: /^\/foo foo(bar)?/ }); + } +}; \ No newline at end of file diff --git a/node_modules/jade/support/expresso/test/serial/async.test.js b/node_modules/jade/support/expresso/test/serial/async.test.js new file mode 100644 index 0000000..292f96c --- /dev/null +++ b/node_modules/jade/support/expresso/test/serial/async.test.js @@ -0,0 +1,38 @@ + +var setup = 0, + order = []; + +module.exports = { + setup: function(done){ + ++setup; + done(); + }, + + a: function(assert, done){ + assert.equal(1, setup); + order.push('a'); + setTimeout(function(){ + done(); + }, 500); + }, + + b: function(assert, done){ + assert.equal(2, setup); + order.push('b'); + setTimeout(function(){ + done(); + }, 200); + }, + + c: function(assert, done){ + assert.equal(3, setup); + order.push('c'); + setTimeout(function(){ + done(); + }, 1000); + }, + + d: function(assert){ + assert.eql(order, ['a', 'b', 'c']); + } +}; \ No newline at end of file diff --git a/node_modules/jade/support/expresso/test/serial/http.test.js b/node_modules/jade/support/expresso/test/serial/http.test.js new file mode 100644 index 0000000..3d19557 --- /dev/null +++ b/node_modules/jade/support/expresso/test/serial/http.test.js @@ -0,0 +1,47 @@ + +/** + * Module dependencies. + */ + +var http = require('http'); + +var server = http.createServer(function(req, res){ + if (req.method === 'GET') { + if (req.url === '/delay') { + setTimeout(function(){ + res.writeHead(200, {}); + res.end('delayed'); + }, 200); + } else { + var body = JSON.stringify({ name: 'tj' }); + res.writeHead(200, { + 'Content-Type': 'application/json; charset=utf8', + 'Content-Length': body.length + }); + res.end(body); + } + } else { + var body = ''; + req.setEncoding('utf8'); + req.addListener('data', function(chunk){ body += chunk }); + req.addListener('end', function(){ + res.writeHead(200, {}); + res.end(req.url + ' ' + body); + }); + } +}); + +module.exports = { + 'test assert.response()': function(assert, done){ + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8' + } + }, done); + } +}; \ No newline at end of file diff --git a/node_modules/jade/support/sass/History.md b/node_modules/jade/support/sass/History.md new file mode 100644 index 0000000..01992cf --- /dev/null +++ b/node_modules/jade/support/sass/History.md @@ -0,0 +1,42 @@ + +0.4.2 / 2010-06-21 +================== + + * Added lib directory to package.json for npm to work + +0.4.1 / 2010-06-21 +================== + + * Addex index.js for npm support + +0.4.0 / 2010-04-02 +================== + + * Added "cache" option + +0.3.0 / 2010-02-22 +================== + + * Added mixin support. Closes #1 + +0.2.0 / 2010-02-05 +================== + + * Added alternate variable syntax back ("var: val") + * Added a method to extract variables. Closes #3 + +0.1.0 / 2010-02-05 +================== + + * Added continuation support. Closes #15 + +0.0.2 / 2010-02-02 +================== + + * Fixed complex selectors + * Removed "var: val" syntax for variables + +0.0.1 / 2010-01-12 +================== + + * Initial release diff --git a/node_modules/jade/support/sass/Makefile b/node_modules/jade/support/sass/Makefile new file mode 100644 index 0000000..f7e6985 --- /dev/null +++ b/node_modules/jade/support/sass/Makefile @@ -0,0 +1,11 @@ + +all: test + +test: spec/node.js + @node spec/node.js + +benchmark: + @node benchmarks/large.js + +.PHONY: test benchmark + \ No newline at end of file diff --git a/node_modules/jade/support/sass/Readme.md b/node_modules/jade/support/sass/Readme.md new file mode 100644 index 0000000..93a5ab6 --- /dev/null +++ b/node_modules/jade/support/sass/Readme.md @@ -0,0 +1,167 @@ + +# Sass.js + + JavaScript implementation of Sass. Great for **node.js** and other + frameworks supporting the CommonJS module system. + +## Installation + + Install the [Kiwi package manager for nodejs](http://github.com/visionmedia/kiwi) + and run: + + $ kiwi install sass + +Or npm: + + $ npm install sass + +## Usage + + var sass = require('sass') + sass.render('... string of sass ...') + // => '... string of css ...' + + sass.collect('... string of sass ...') + // => { selectors: [...], variables: { ... }, mixins: { ... }} + +## Comments + + // foo + body + // bar + a + :color #fff + +compiles to + + body a { + color: #fff;} + +## Variables + + !red = #ff0000 + body + :color !red + +and + + red: #ff0000 + body + :color !red + +compile to + + body { + color: #ff0000;} + +## Selector Continuations + + a + :color #fff + &:hover + :color #000 + &.active + :background #888 + &:hover + :color #fff + +compiles to + + a { + color: #fff;} + + a:hover { + color: #000;} + + a.active { + background: #888;} + + a.active:hover { + color: #fff;} + +## Literal JavaScript + + type: "solid" + size: 1 + input + :border { parseInt(size) + 1 }px {type} #000 + +compiles to + + input { + border: 2px "solid" #000;} + +## Property Expansion + + div + =border-radius 5px + +compiles to + + div { + -webkit-border-radius: 5px; + -moz-border-radius: 5px;} + +## Mixins + + +large + :font-size 15px + +striped + tr + :background #fff + +large + &:odd + :background #000 + table + +striped + :border none + +compiles to + + table { + border: none;} + table tr { + background: #fff;} + table tr { + font-size: 15px;} + table tr:odd { + background: #000;} + + +## Testing + +Update Git submodules and execute: + $ make test +or + $ node spec/node.js +or + $ jspec --node + +## More Information + +* Featured in [Advanced JavaScript e-book](http://www.dev-mag.com/2010/02/18/advanced-javascript/) for only $4 + +## License + +(The MIT License) + +Copyright (c) 2009 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/jade/support/sass/index.js b/node_modules/jade/support/sass/index.js new file mode 120000 index 0000000..7fb84a5 --- /dev/null +++ b/node_modules/jade/support/sass/index.js @@ -0,0 +1 @@ +lib/sass.js \ No newline at end of file diff --git a/node_modules/jade/support/sass/lib/sass.js b/node_modules/jade/support/sass/lib/sass.js new file mode 100644 index 0000000..a72e49d --- /dev/null +++ b/node_modules/jade/support/sass/lib/sass.js @@ -0,0 +1,299 @@ + +// Sass - Core - Copyright TJ Holowaychuk (MIT Licensed) + +/** + * Library version. + */ + +exports.version = '0.4.3' + +/** + * Compiled sass cache. + */ + +var cache = {} + +/** + * Sass grammar tokens. + */ + +var tokens = [ + ['indent', /^\n +/], + ['space', /^ +/], + ['nl', /^\n/], + ['js', /^{(.*?)}/], + ['comment', /^\/\/(.*)/], + ['string', /^(?:'(.*?)'|"(.*?)")/], + ['variable', /^!([\w\-]+) *= *([^\n]+)/], + ['variable.alternate', /^([\w\-]+): +([^\n]+)/], + ['property.expand', /^=([\w\-]+) *([^\n]+)/], + ['property', /^:([\w\-]+) *([^\n]+)/], + ['continuation', /^&(.+)/], + ['mixin', /^\+([\w\-]+)/], + ['selector', /^(.+)/] +] + +/** + * Vendor-specific expansion prefixes. + */ + +exports.expansions = ['-moz-', '-webkit-'] + +/** + * Tokenize the given _str_. + * + * @param {string} str + * @return {array} + * @api private + */ + +function tokenize(str) { + var token, captures, stack = [] + while (str.length) { + for (var i = 0, len = tokens.length; i < len; ++i) + if (captures = tokens[i][1].exec(str)) { + token = [tokens[i][0], captures], + str = str.replace(tokens[i][1], '') + break + } + if (token) + stack.push(token), + token = null + else + throw new Error("SyntaxError: near `" + str.slice(0, 25).replace('\n', '\\n') + "'") + } + return stack +} + +/** + * Parse the given _tokens_, returning + * and hash containing the properties below: + * + * selectors: array of top-level selectors + * variables: hash of variables defined + * + * @param {array} tokens + * @return {hash} + * @api private + */ + +function parse(tokens) { + var token, selector, + data = { variables: {}, mixins: {}, selectors: [] }, + line = 1, + lastIndents = 0, + indents = 0 + + /** + * Output error _msg_ in context to the current line. + */ + + function error(msg) { + throw new Error('ParseError: on line ' + line + '; ' + msg) + } + + /** + * Reset parents until the indentation levels match. + */ + + function reset() { + if (indents === 0) + return selector = null + while (lastIndents-- > indents) + selector = selector.parent + } + + // Parse tokens + + while (token = tokens.shift()) + switch (token[0]) { + case 'mixin': + if (indents) { + var mixin = data.mixins[token[1][1]] + if (!mixin) error("mixin `" + token[1][1] + "' does not exist") + mixin.parent = selector + selector.children.push(mixin) + } + else + data.mixins[token[1][1]] = selector = new Selector(token[1][1], null, 'mixin') + break + case 'continuation': + reset() + selector = new Selector(token[1][1], selector, 'continuation') + break + case 'selector': + reset() + selector = new Selector(token[1][1], selector) + if (!selector.parent) + data.selectors.push(selector) + break + case 'property': + reset() + if (!selector) error('properties must be nested within a selector') + var val = token[1][2] + .replace(/!([\w\-]+)/g, function(orig, name){ + return data.variables[name] || orig + }) + .replace(/\{(.*?)\}/g, function(_, js){ + with (data.variables){ return eval(js) } + }) + selector.properties.push(new Property(token[1][1], val)) + break + case 'property.expand': + exports.expansions.forEach(function(prefix){ + tokens.unshift(['property', [, prefix + token[1][1], token[1][2]]]) + }) + break + case 'variable': + case 'variable.alternate': + data.variables[token[1][1]] = token[1][2] + break + case 'js': + with (data.variables){ eval(token[1][1]) } + break + case 'nl': + ++line, indents = 0 + break + case 'comment': + break + case 'indent': + ++line + lastIndents = indents, + indents = (token[1][0].length - 1) / 2 + if (indents > lastIndents && + indents - 1 > lastIndents) + error('invalid indentation, to much nesting') + } + return data +} + +/** + * Compile _selectors_ to a string of css. + * + * @param {array} selectors + * @return {string} + * @api private + */ + +function compile(selectors) { + return selectors.join('\n') +} + +/** + * Collect data by parsing _sass_. + * Returns a hash containing the following properties: + * + * selectors: array of top-level selectors + * variables: hash of variables defined + * + * @param {string} sass + * @return {hash} + * @api public + */ + +exports.collect = function(sass) { + return parse(tokenize(sass)) +} + +/** + * Render a string of _sass_. + * + * Options: + * + * - filename Optional filename to aid in error reporting + * - cache Optional caching of compiled content. Requires "filename" option + * + * @param {string} sass + * @param {object} options + * @return {string} + * @api public + */ + +exports.render = function(sass, options) { + options = options || {} + if (options.cache && !options.filename) + throw new Error('filename option must be passed when cache is enabled') + if (options.cache) + return cache[options.filename] + ? cache[options.filename] + : cache[options.filename] = compile(exports.collect(sass).selectors) + return compile(exports.collect(sass).selectors) +} + +// --- Selector + +/** + * Initialize a selector with _string_ and + * optional _parent_. + * + * @param {string} string + * @param {Selector} parent + * @param {string} type + * @api private + */ + +function Selector(string, parent, type) { + this.string = string + this.parent = parent + this.properties = [] + this.children = [] + if (type) this[type] = true + if (parent) parent.children.push(this) +} + +/** + * Return selector string. + * + * @return {string} + * @api private + */ + +Selector.prototype.selector = function() { + var selector = this.string + if (this.parent) + selector = this.continuation + ? this.parent.selector() + selector + : this.mixin + ? this.parent.selector() + : this.parent.selector() + ' ' + selector + return selector +} + +/** + * Return selector and nested selectors as CSS. + * + * @return {string} + * @api private + */ + +Selector.prototype.toString = function() { + return (this.properties.length + ? this.selector() + ' {\n' + this.properties.join('\n') + '}\n' + : '') + this.children.join('') +} + +// --- Property + +/** + * Initialize property with _name_ and _val_. + * + * @param {string} name + * @param {string} val + * @api private + */ + +function Property(name, val) { + this.name = name + this.val = val +} + +/** + * Return CSS string representing a property. + * + * @return {string} + * @api private + */ + +Property.prototype.toString = function() { + return ' ' + this.name + ': ' + this.val + ';' +} diff --git a/node_modules/jade/support/sass/package.json b/node_modules/jade/support/sass/package.json new file mode 100644 index 0000000..250e3bc --- /dev/null +++ b/node_modules/jade/support/sass/package.json @@ -0,0 +1,10 @@ +{ + "name": "sass", + "description": "Syntactically Awesome Stylesheets (compiles to css)", + "version": "0.4.3", + "keywords": ["sass", "template", "css", "view"], + "author": "TJ Holowaychuk ", + "directories": { + "lib": "." + } +} \ No newline at end of file diff --git a/node_modules/jade/support/sass/seed.yml b/node_modules/jade/support/sass/seed.yml new file mode 100644 index 0000000..7f95bf5 --- /dev/null +++ b/node_modules/jade/support/sass/seed.yml @@ -0,0 +1,4 @@ +--- + name: Sass + description: Syntactically Awesome Stylesheets (compiles to css) + version: 0.4.3 diff --git a/node_modules/jade/support/sass/spec/fixtures/collect.sass b/node_modules/jade/support/sass/spec/fixtures/collect.sass new file mode 100644 index 0000000..ad7d202 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/collect.sass @@ -0,0 +1,3 @@ + +!red = #ff0000 +!black = #000 \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/comment.css b/node_modules/jade/support/sass/spec/fixtures/comment.css new file mode 100644 index 0000000..e81583f --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/comment.css @@ -0,0 +1,2 @@ +body a { + color: #fff;} diff --git a/node_modules/jade/support/sass/spec/fixtures/comment.sass b/node_modules/jade/support/sass/spec/fixtures/comment.sass new file mode 100644 index 0000000..eaad554 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/comment.sass @@ -0,0 +1,6 @@ + +// foo +body + // bar + a + :color #fff diff --git a/node_modules/jade/support/sass/spec/fixtures/continuation.css b/node_modules/jade/support/sass/spec/fixtures/continuation.css new file mode 100644 index 0000000..6958788 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/continuation.css @@ -0,0 +1,8 @@ +a { + color: #fff;} +a:hover { + color: #000;} +a.active { + background: #888;} +a.active:hover { + color: #fff;} diff --git a/node_modules/jade/support/sass/spec/fixtures/continuation.sass b/node_modules/jade/support/sass/spec/fixtures/continuation.sass new file mode 100644 index 0000000..d07b101 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/continuation.sass @@ -0,0 +1,8 @@ +a + :color #fff + &:hover + :color #000 + &.active + :background #888 + &:hover + :color #fff \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/literal.css b/node_modules/jade/support/sass/spec/fixtures/literal.css new file mode 100644 index 0000000..cc4d5a6 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/literal.css @@ -0,0 +1,2 @@ +input { + border: 2px "solid" #000;} diff --git a/node_modules/jade/support/sass/spec/fixtures/literal.sass b/node_modules/jade/support/sass/spec/fixtures/literal.sass new file mode 100644 index 0000000..c207d37 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/literal.sass @@ -0,0 +1,4 @@ +!type = "solid" +!size = 1 +input + :border { parseInt(size) + 1 }px {type} #000 \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/mixin.css b/node_modules/jade/support/sass/spec/fixtures/mixin.css new file mode 100644 index 0000000..6ddc778 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/mixin.css @@ -0,0 +1,8 @@ +table { + border: none;} +table tr { + background: #fff;} +table tr { + font-size: 15px;} +table tr:odd { + background: #000;} diff --git a/node_modules/jade/support/sass/spec/fixtures/mixin.sass b/node_modules/jade/support/sass/spec/fixtures/mixin.sass new file mode 100644 index 0000000..a27a945 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/mixin.sass @@ -0,0 +1,11 @@ ++large + :font-size 15px ++striped + tr + :background #fff + +large + &:odd + :background #000 +table + +striped + :border none \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/mixin.undefined.sass b/node_modules/jade/support/sass/spec/fixtures/mixin.undefined.sass new file mode 100644 index 0000000..4026d54 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/mixin.undefined.sass @@ -0,0 +1,2 @@ +body + +large \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/properties.css b/node_modules/jade/support/sass/spec/fixtures/properties.css new file mode 100644 index 0000000..ccc4b21 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/properties.css @@ -0,0 +1,3 @@ +body { + font-size: 13px; + color: #fff;} diff --git a/node_modules/jade/support/sass/spec/fixtures/properties.expand.css b/node_modules/jade/support/sass/spec/fixtures/properties.expand.css new file mode 100644 index 0000000..b95a347 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/properties.expand.css @@ -0,0 +1,3 @@ +div { + -webkit-border-radius: 5px; + -moz-border-radius: 5px;} diff --git a/node_modules/jade/support/sass/spec/fixtures/properties.expand.sass b/node_modules/jade/support/sass/spec/fixtures/properties.expand.sass new file mode 100644 index 0000000..9ae954c --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/properties.expand.sass @@ -0,0 +1,2 @@ +div + =border-radius 5px \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/properties.invalid.sass b/node_modules/jade/support/sass/spec/fixtures/properties.invalid.sass new file mode 100644 index 0000000..b724ff6 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/properties.invalid.sass @@ -0,0 +1,2 @@ +:color #fff +body \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/properties.nested.css b/node_modules/jade/support/sass/spec/fixtures/properties.nested.css new file mode 100644 index 0000000..3542a2a --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/properties.nested.css @@ -0,0 +1,13 @@ +body { + padding: 0;} +body ul { + margin: 0;} +body ul li { + list-style: none;} +body ul li a { + color: #fff;} +body form label { + display: none;} + +a { + color: #cc0000;} diff --git a/node_modules/jade/support/sass/spec/fixtures/properties.nested.invalid.sass b/node_modules/jade/support/sass/spec/fixtures/properties.nested.invalid.sass new file mode 100644 index 0000000..614aee4 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/properties.nested.invalid.sass @@ -0,0 +1,5 @@ +body + ul + :margin 0 + li + :padding 0 \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/properties.nested.sass b/node_modules/jade/support/sass/spec/fixtures/properties.nested.sass new file mode 100644 index 0000000..aa1a930 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/properties.nested.sass @@ -0,0 +1,13 @@ +body + ul + :margin 0 + li + a + :color #fff + :list-style none + :padding 0 + form + label + :display none +a + :color #cc0000 \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/properties.sass b/node_modules/jade/support/sass/spec/fixtures/properties.sass new file mode 100644 index 0000000..603653a --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/properties.sass @@ -0,0 +1,3 @@ +body + :font-size 13px + :color #fff \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/selectors.css b/node_modules/jade/support/sass/spec/fixtures/selectors.css new file mode 100644 index 0000000..62532b4 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/selectors.css @@ -0,0 +1,6 @@ +body input.field#email ~ label { + display: none;} +body form:nth-child(1) legend { + font-size: 15px;} +body ul li:first-child a { + display: none;} diff --git a/node_modules/jade/support/sass/spec/fixtures/selectors.sass b/node_modules/jade/support/sass/spec/fixtures/selectors.sass new file mode 100644 index 0000000..3aa6ca6 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/selectors.sass @@ -0,0 +1,10 @@ +body + input.field#email ~ label + :display none + form:nth-child(1) + legend + :font-size 15px + ul + li:first-child + a + :display none diff --git a/node_modules/jade/support/sass/spec/fixtures/variables.alternate.css b/node_modules/jade/support/sass/spec/fixtures/variables.alternate.css new file mode 100644 index 0000000..dd2d6bc --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/variables.alternate.css @@ -0,0 +1,2 @@ +body { + background: #ff0000 url('foo.png');} diff --git a/node_modules/jade/support/sass/spec/fixtures/variables.alternate.sass b/node_modules/jade/support/sass/spec/fixtures/variables.alternate.sass new file mode 100644 index 0000000..b022082 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/variables.alternate.sass @@ -0,0 +1,4 @@ +color: #ff0000 +image: url('foo.png') +body + :background !color !image \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/variables.css b/node_modules/jade/support/sass/spec/fixtures/variables.css new file mode 100644 index 0000000..904bdbc --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/variables.css @@ -0,0 +1,2 @@ +body { + color: #ff0000;} diff --git a/node_modules/jade/support/sass/spec/fixtures/variables.regular.css b/node_modules/jade/support/sass/spec/fixtures/variables.regular.css new file mode 100644 index 0000000..904bdbc --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/variables.regular.css @@ -0,0 +1,2 @@ +body { + color: #ff0000;} diff --git a/node_modules/jade/support/sass/spec/fixtures/variables.regular.sass b/node_modules/jade/support/sass/spec/fixtures/variables.regular.sass new file mode 100644 index 0000000..82ae128 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/variables.regular.sass @@ -0,0 +1,3 @@ +!red = #ff0000 +body + :color !red \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/fixtures/variables.sass b/node_modules/jade/support/sass/spec/fixtures/variables.sass new file mode 100644 index 0000000..c9f3388 --- /dev/null +++ b/node_modules/jade/support/sass/spec/fixtures/variables.sass @@ -0,0 +1,5 @@ + +red: #ff0000 + +body + :color !red diff --git a/node_modules/jade/support/sass/spec/lib/images/bg.png b/node_modules/jade/support/sass/spec/lib/images/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..947804ff6acaaf93986a0a11d205df3113656816 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^j0_CS3LH#8R&M_M3qVS;#5JNMI6tkVJh3R1!7(L2 zDOJHUH!(dmC^a#qvhZZ84N#Gdr;B4q#jT`Y|Nq+yGczC7kaMcgIDRvs>~})ZZHL{d z3*N|ke!F!0+{6dRCuY6RkTi>G?|T$zbHu=*fssL9)snBgXWIv$ISihzelF{r5}E+; Cx;4N6 literal 0 HcmV?d00001 diff --git a/node_modules/jade/support/sass/spec/lib/images/hr.png b/node_modules/jade/support/sass/spec/lib/images/hr.png new file mode 100644 index 0000000000000000000000000000000000000000..4a94d12fd8405c32b4c20abe777c1a9a7e6a30cb GIT binary patch literal 321 zcmV-H0lxl;P)A5E2-vx}KFiT96$Z17UamL`af0P}@7%Vq>XUIGjN-4D7? ThAmXZ00000NkvXXu0mjfvYCee literal 0 HcmV?d00001 diff --git a/node_modules/jade/support/sass/spec/lib/images/loading.gif b/node_modules/jade/support/sass/spec/lib/images/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..c69e937232b24ea30f01c68bbd2ebc798dcecfcb GIT binary patch literal 2608 zcmdVcdr(tX9tZGC9yiG~=H_*Q-0%n(kWqP*D#hw{AQu8;1%gl-Hrf&{2?48KX;hHy z3Ze*zEz4t3XdUFyLbNPUYlA`|B}P=N1fqtL1*}S;87#|-W9v<#G;ul(e%d3)N(^9c$d2Dz{7}?ErjNd;{EMKkCsk21~b9Gvg zDo<7L=3Z5HNbVlZUcm1eg#o#CZCJU`3IYHwM->zCd?uYrF3vKFeM}v?f+%s?E>ly|3W25ry9#NNbTx-}0ON58dTrs^ix{_1O0Wh~SVSBlH)Ajn zPn^Gbjz}PCtN@#keR&hK&Dhl-b$kZ8^S)x#dh0{7X=X%CCJk7P1PSO>T&S8I4{#Lg zb5#)o=;!ZP*1nM{cI4@(x7o27*SA()NHmrn67aN@Pmi~(i_SnrjYnwh36aG%!@i0d zqbvfa44f|?OG4ntP|nbjhEl1)Yp6ZN@yjy zy4==QmLy%t;ps3R?~f2KfTTI|2?q8dFd6^z5GF+Xa&Y)sjG)hxit80pPcOP zJ z*LW{SyGHD%hUotV+W%I}fBLAIx!8|7#}$;clKQ+{&FjDqGQ2ZNx(lYM3*%~}ILnao zM`aui55~ZFJlu^!5rdA9Q_7H68H_;##u{x(Yn-vSfIRCb^Nqsg zGRS!Egm>h+o<}LeV4&CLReo9FrDjDvs}8?JwC)#Qs|ie=r?~xUh)&*d`Fx>FG}%X# zNdtDHBKhLPC0wpooFDAQKL%*6T|ULH$=wX!NhcasgD3d;-d$I6yRK3yN+E~C1335_iLOt+*9uvSZ`>*KA}vm}08wRq=>5l|t*Na&jR z-C1&C`nkEk#sB|@yyt-#fXngP04My zm7u$Q%EJbHp`>~`5W&L{W!6`y&}LMS;jfUpgO~7TLVMRZ9IC)IZp0A${`yp0{&wco z#1nx@XMkhqeK%7?RE7JdLr1^nwFfaJ0Q&Lv?WNJ%9}VSJsNY2+UYs2%EU0J~ayFXv zi*?7KCXQHkD)O6!0Q%4N+HTODHxJ{kQSuQX$l-rSwkwh(zMkdfzxyGwl@yHC)C4p< z&n2%8#M?)Q@mgHL1ot8`SFdSEj9ye|jHy+U8#@HoUExG=@AVkRAe_qYm4EpzK6L*& zh`)26?V#f4#_h^P9G^%>h2-H3)$QP zQovu6J9qDvsxqweDdNNa!Lb?L4_UF{tLX_nN7r0U_vF14YKcGR-*Gl} zx3oG)bzf|65dBxD-;2ZCp??K;+TuQ9onnK?==5hzbkb^r_g>z4#D8mcv8(+XdoszA zCx-qhdgxMNMotj}SiL_6V(tLcsK7(M(r(%u<}QrVfOvyK6_;~NOTlPGfX@M7S5YQF z&*$(ylJMHJt^_aQeu{C6NaTE$G3HNN@_SnN8YcaKn%`)F@~L1x+ah7-gEJPpc6w%3 zyX}r+Qk$4RHZzfH){e~F*qJ{d*L8a6n4;U?+{de0-t)mal#TVxe)3F}^UBh+zd T)6_**#cgp_+?JL9(ew3BlNF>u literal 0 HcmV?d00001 diff --git a/node_modules/jade/support/sass/spec/lib/images/sprites.bg.png b/node_modules/jade/support/sass/spec/lib/images/sprites.bg.png new file mode 100644 index 0000000000000000000000000000000000000000..dc8790f338c4fce6611e0c2d2f811882a4136b32 GIT binary patch literal 4876 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 literal 0 HcmV?d00001 diff --git a/node_modules/jade/support/sass/spec/lib/images/sprites.png b/node_modules/jade/support/sass/spec/lib/images/sprites.png new file mode 100644 index 0000000000000000000000000000000000000000..010b98eeef699c0d0f4d0136d7d2d352b2b51d4c GIT binary patch literal 3629 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 NJsl%$+{J5={{f-$rB(m{ literal 0 HcmV?d00001 diff --git a/node_modules/jade/support/sass/spec/lib/images/vr.png b/node_modules/jade/support/sass/spec/lib/images/vr.png new file mode 100644 index 0000000000000000000000000000000000000000..b2e76175d3e8a4b5092757c9cbbfb81802804bc6 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0y~yVEzDPGjgy2$;wJseIO-S;u=vBoS#-wo>-L1;Fyx1 zl&avFo0y&&l$w}QS$Hzl2B^r`)5S5Q;?|q%hN29LJggh+4ZdAv`VrpRF7+Vg&V(H& syf&pj3kwA*Y^eWvZr(dP{{}_|Ay#%3&0R090!0}-UHx3vIVCg!0D1l{cmMzZ literal 0 HcmV?d00001 diff --git a/node_modules/jade/support/sass/spec/lib/jspec.css b/node_modules/jade/support/sass/spec/lib/jspec.css new file mode 100644 index 0000000..629d41c --- /dev/null +++ b/node_modules/jade/support/sass/spec/lib/jspec.css @@ -0,0 +1,149 @@ +body.jspec { + margin: 45px 0; + font: 12px "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; + background: #efefef url(images/bg.png) top left repeat-x; + text-align: center; +} +#jspec { + margin: 0 auto; + padding-top: 30px; + width: 1008px; + background: url(images/vr.png) top left repeat-y; + text-align: left; +} +#jspec-top { + position: relative; + margin: 0 auto; + width: 1008px; + height: 40px; + background: url(images/sprites.bg.png) top left no-repeat; +} +#jspec-bottom { + margin: 0 auto; + width: 1008px; + height: 15px; + background: url(images/sprites.bg.png) bottom left no-repeat; +} +#jspec .loading { + margin-top: -45px; + width: 1008px; + height: 80px; + background: url(images/loading.gif) 50% 50% no-repeat; +} +#jspec-title { + position: absolute; + top: 15px; + left: 20px; + width: 160px; + font-size: 22px; + font-weight: normal; + background: url(images/sprites.png) 0 -126px no-repeat; + text-align: center; +} +#jspec-title em { + font-size: 10px; + font-style: normal; + color: #BCC8D1; +} +#jspec-report * { + margin: 0; + padding: 0; + background: none; + border: none; +} +#jspec-report { + padding: 15px 40px; + font: 11px "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; + color: #7B8D9B; +} +#jspec-report.has-failures { + padding-bottom: 30px; +} +#jspec-report .hidden { + display: none; +} +#jspec-report .heading { + margin-bottom: 15px; +} +#jspec-report .heading span { + padding-right: 10px; +} +#jspec-report .heading .passes em { + color: #0ea0eb; +} +#jspec-report .heading .failures em { + color: #FA1616; +} +#jspec-report table { + font-size: 11px; + border-collapse: collapse; +} +#jspec-report td { + padding: 8px; + text-indent: 30px; + color: #7B8D9B; +} +#jspec-report tr.body { + display: none; +} +#jspec-report tr.body pre { + margin: 0; + padding: 0 0 5px 25px; +} +#jspec-report tr.even:hover + tr.body, +#jspec-report tr.odd:hover + tr.body { + display: block; +} +#jspec-report tr td:first-child em { + display: block; + clear: both; + font-style: normal; + font-weight: normal; + color: #7B8D9B; +} +#jspec-report tr.even:hover, +#jspec-report tr.odd:hover { + text-shadow: 1px 1px 1px #fff; + background: #F2F5F7; +} +#jspec-report td + td { + padding-right: 0; + width: 15px; +} +#jspec-report td.pass { + background: url(images/sprites.png) 3px -7px no-repeat; +} +#jspec-report td.fail { + background: url(images/sprites.png) 3px -158px no-repeat; + font-weight: bold; + color: #FC0D0D; +} +#jspec-report td.requires-implementation { + background: url(images/sprites.png) 3px -333px no-repeat; +} +#jspec-report tr.description td { + margin-top: 25px; + padding-top: 25px; + font-size: 12px; + font-weight: bold; + text-indent: 0; + color: #1a1a1a; +} +#jspec-report tr.description:first-child td { + border-top: none; +} +#jspec-report .assertion { + display: block; + float: left; + margin: 0 0 0 1px; + padding: 0; + width: 1px; + height: 5px; + background: #7B8D9B; +} +#jspec-report .assertion.failed { + background: red; +} +.jspec-sandbox { + display: none; +} \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/lib/jspec.growl.js b/node_modules/jade/support/sass/spec/lib/jspec.growl.js new file mode 100644 index 0000000..a150257 --- /dev/null +++ b/node_modules/jade/support/sass/spec/lib/jspec.growl.js @@ -0,0 +1,115 @@ + +// JSpec - Growl - Copyright TJ Holowaychuk (MIT Licensed) + +;(function(){ + + Growl = { + + // --- Version + + version: '1.0.0', + + /** + * Execute the given _cmd_, returning an array of lines from stdout. + * + * Examples: + * + * Growl.exec('growlnotify', '-m', msg) + * + * @param {string ...} cmd + * @return {array} + * @api public + */ + + exec: function(cmd) { + var lines = [], line + with (JavaImporter(java.lang, java.io)) { + var proccess = Runtime.getRuntime().exec(Array.prototype.slice.call(arguments)) + var stream = new DataInputStream(proccess.getInputStream()) + while (line = stream.readLine()) + lines.push(line + '') + stream.close() + } + return lines + }, + + /** + * Return the extension of the given _path_ or null. + * + * @param {string} path + * @return {string} + * @api private + */ + + extname: function(path) { + return path.lastIndexOf('.') != -1 ? + path.slice(path.lastIndexOf('.') + 1, path.length) : + null + }, + + /** + * Version of the 'growlnotify' binary. + * + * @return {string} + * @api private + */ + + binVersion: function() { + try { return this.exec('growlnotify', '-v')[0].split(' ')[1] } catch (e) {} + }, + + /** + * Send growl notification _msg_ with _options_. + * + * Options: + * + * - title Notification title + * - sticky Make the notification stick (defaults to false) + * - name Application name (defaults to growlnotify) + * - image + * - path to an icon sets --iconpath + * - path to an image sets --image + * - capitalized word sets --appIcon + * - filename uses extname as --icon + * - otherwise treated as --icon + * + * Examples: + * + * Growl.notify('New email') + * Growl.notify('5 new emails', { title: 'Thunderbird' }) + * + * @param {string} msg + * @param {options} hash + * @api public + */ + + notify: function(msg, options) { + options = options || {} + var args = ['growlnotify', '-m', msg] + if (!this.binVersion()) throw new Error('growlnotify executable is required') + if (image = options.image) { + var flag, ext = this.extname(image) + flag = flag || ext == 'icns' && 'iconpath' + flag = flag || /^[A-Z]/.test(image) && 'appIcon' + flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image' + flag = flag || ext && (image = ext) && 'icon' + flag = flag || 'icon' + args.push('--' + flag, image) + } + if (options.sticky) args.push('--sticky') + if (options.name) args.push('--name', options.name) + if (options.title) args.push(options.title) + this.exec.apply(this, args) + } + } + + JSpec.include({ + name: 'Growl', + reporting: function(options){ + var stats = JSpec.stats + if (stats.failures) Growl.notify('failed ' + stats.failures + ' assertions', { title: 'JSpec'}) + else Growl.notify('passed ' + stats.passes + ' assertions', { title: 'JSpec' }) + } + }) + +})() \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/lib/jspec.jquery.js b/node_modules/jade/support/sass/spec/lib/jspec.jquery.js new file mode 100644 index 0000000..46422ec --- /dev/null +++ b/node_modules/jade/support/sass/spec/lib/jspec.jquery.js @@ -0,0 +1,79 @@ + +// JSpec - jQuery - Copyright TJ Holowaychuk (MIT Licensed) + +JSpec +.requires('jQuery', 'when using jspec.jquery.js') +.include({ + name: 'jQuery', + + // --- Initialize + + init : function() { + jQuery.ajaxSetup({ async: false }) + }, + + // --- Utilities + + utilities : { + element: jQuery, + elements: jQuery, + sandbox : function() { + return jQuery('
') + } + }, + + // --- Matchers + + matchers : { + have_tag : "jQuery(expected, actual).length === 1", + have_one : "alias have_tag", + have_tags : "jQuery(expected, actual).length > 1", + have_many : "alias have_tags", + have_any : "alias have_tags", + have_child : "jQuery(actual).children(expected).length === 1", + have_children : "jQuery(actual).children(expected).length > 1", + have_text : "jQuery(actual).text() === expected", + have_value : "jQuery(actual).val() === expected", + be_enabled : "!jQuery(actual).attr('disabled')", + have_class : "jQuery(actual).hasClass(expected)", + be_animated : "jQuery(actual).queue().length > 0", + + be_visible : function(actual) { + return jQuery(actual).css('display') != 'none' && + jQuery(actual).css('visibility') != 'hidden' && + jQuery(actual).attr('type') != 'hidden' + }, + + be_hidden : function(actual) { + return !JSpec.does(actual, 'be_visible') + }, + + have_classes : function(actual) { + return !JSpec.any(JSpec.toArray(arguments, 1), function(arg){ + return !JSpec.does(actual, 'have_class', arg) + }) + }, + + have_attr : function(actual, attr, value) { + return value ? jQuery(actual).attr(attr) == value: + jQuery(actual).attr(attr) + }, + + have_event_handlers : function(actual, expected) { + return jQuery(actual).data('events') ? + jQuery(actual).data('events').hasOwnProperty(expected) : + false + }, + + 'be disabled selected checked' : function(attr) { + return 'jQuery(actual).attr("' + attr + '")' + }, + + 'have type id title alt href src sel rev name target' : function(attr) { + return function(actual, value) { + return JSpec.does(actual, 'have_attr', attr, value) + } + } + } +}) + diff --git a/node_modules/jade/support/sass/spec/lib/jspec.js b/node_modules/jade/support/sass/spec/lib/jspec.js new file mode 100644 index 0000000..131c745 --- /dev/null +++ b/node_modules/jade/support/sass/spec/lib/jspec.js @@ -0,0 +1,1893 @@ + +// JSpec - Core - Copyright TJ Holowaychuk (MIT Licensed) + +;(function(){ + + JSpec = { + version : '4.3.2', + assert : true, + cache : {}, + suites : [], + modules : [], + allSuites : [], + sharedBehaviors: [], + matchers : {}, + stubbed : [], + options : {}, + request : 'XMLHttpRequest' in this ? XMLHttpRequest : null, + stats : { specs: 0, assertions: 0, failures: 0, passes: 0, specsFinished: 0, suitesFinished: 0 }, + + /** + * Default context in which bodies are evaluated. + * + * Replace context simply by setting JSpec.context + * to your own like below: + * + * JSpec.context = { foo : 'bar' } + * + * Contexts can be changed within any body, this can be useful + * in order to provide specific helper methods to specific suites. + * + * To reset (usually in after hook) simply set to null like below: + * + * JSpec.context = null + * + */ + + defaultContext : { + + /** + * Return an object used for proxy assertions. + * This object is used to indicate that an object + * should be an instance of _object_, not the constructor + * itself. + * + * @param {function} constructor + * @return {hash} + * @api public + */ + + an_instance_of : function(constructor) { + return { an_instance_of : constructor } + }, + + /** + * Load fixture at _path_. + * + * Fixtures are resolved as: + * + * - + * - .html + * + * @param {string} path + * @return {string} + * @api public + */ + + fixture : function(path) { + if (JSpec.cache[path]) return JSpec.cache[path] + return JSpec.cache[path] = + JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) || + JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.html') + }, + + /** + * Load json fixture at _path_. + * + * JSON fixtures are resolved as: + * + * - + * - .json + * + * @param {string} path + * @return {object} + * @api public + */ + + json_fixture: function(path) { + if (!JSpec.cache['json:' + path]) + JSpec.cache['json:' + path] = + JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) || + JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.json') + try { + return eval('(' + JSpec.cache['json:' + path] + ')') + } catch (e) { + throw 'json_fixture("' + path + '"): ' + e + } + } + }, + + // --- Objects + + reporters : { + + /** + * Report to server. + * + * Options: + * - uri specific uri to report to. + * - verbose weither or not to output messages + * - failuresOnly output failure messages only + * + * @api public + */ + + Server : function(results, options) { + var uri = options.uri || 'http://' + window.location.host + '/results' + JSpec.post(uri, { + stats: JSpec.stats, + options: options, + results: map(results.allSuites, function(suite) { + if (suite.isExecutable()) + return { + description: suite.description, + specs: map(suite.specs, function(spec) { + return { + description: spec.description, + message: !spec.passed() ? spec.failure().message : null, + status: spec.requiresImplementation() ? 'pending' : + spec.passed() ? 'pass' : + 'fail', + assertions: map(spec.assertions, function(assertion){ + return { + passed: assertion.passed + } + }) + } + }) + } + }) + }) + if ('close' in main) main.close() + }, + + /** + * Default reporter, outputting to the DOM. + * + * Options: + * - reportToId id of element to output reports to, defaults to 'jspec' + * - failuresOnly displays only suites with failing specs + * + * @api public + */ + + DOM : function(results, options) { + var id = option('reportToId') || 'jspec', + report = document.getElementById(id), + failuresOnly = option('failuresOnly'), + classes = results.stats.failures ? 'has-failures' : '' + if (!report) throw 'JSpec requires the element #' + id + ' to output its reports' + + function bodyContents(body) { + return JSpec. + escape(JSpec.contentsOf(body)). + replace(/^ */gm, function(a){ return (new Array(Math.round(a.length / 3))).join(' ') }). + replace(/\r\n|\r|\n/gm, '
') + } + + report.innerHTML = '
\ + Passes: ' + results.stats.passes + ' \ + Failures: ' + results.stats.failures + ' \ + Duration: ' + results.duration + ' ms \ +
' + map(results.allSuites, function(suite) { + var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran + if (displaySuite && suite.isExecutable()) + return '' + + map(suite.specs, function(i, spec) { + return '' + + (spec.requiresImplementation() ? + '' : + (spec.passed() && !failuresOnly) ? + '' : + !spec.passed() ? + '' : + '') + + '' + }).join('') + '' + }).join('') + '
' + escape(suite.description) + '
' + escape(spec.description) + '' + escape(spec.description)+ '' + spec.assertionsGraph() + '' + escape(spec.description) + + map(spec.failures(), function(a){ return '' + escape(a.message) + '' }).join('') + + '' + spec.assertionsGraph() + '
' + bodyContents(spec.body) + '
' + }, + + /** + * Terminal reporter. + * + * @api public + */ + + Terminal : function(results, options) { + var failuresOnly = option('failuresOnly') + print(color("\n Passes: ", 'bold') + color(results.stats.passes, 'green') + + color(" Failures: ", 'bold') + color(results.stats.failures, 'red') + + color(" Duration: ", 'bold') + color(results.duration, 'green') + " ms \n") + + function indent(string) { + return string.replace(/^(.)/gm, ' $1') + } + + each(results.allSuites, function(suite) { + var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran + if (displaySuite && suite.isExecutable()) { + print(color(' ' + suite.description, 'bold')) + each(suite.specs, function(spec){ + var assertionsGraph = inject(spec.assertions, '', function(graph, assertion){ + return graph + color('.', assertion.passed ? 'green' : 'red') + }) + if (spec.requiresImplementation()) + print(color(' ' + spec.description, 'blue') + assertionsGraph) + else if (spec.passed() && !failuresOnly) + print(color(' ' + spec.description, 'green') + assertionsGraph) + else if (!spec.passed()) + print(color(' ' + spec.description, 'red') + assertionsGraph + + "\n" + indent(map(spec.failures(), function(a){ return a.message }).join("\n")) + "\n") + }) + print("") + } + }) + + quit(results.stats.failures) + } + }, + + Assertion : function(matcher, actual, expected, negate) { + extend(this, { + message: '', + passed: false, + actual: actual, + negate: negate, + matcher: matcher, + expected: expected, + + // Report assertion results + + report : function() { + if (JSpec.assert) + this.passed ? JSpec.stats.passes++ : JSpec.stats.failures++ + return this + }, + + // Run the assertion + + run : function() { + // TODO: remove unshifting + expected.unshift(actual) + this.result = matcher.match.apply(this, expected) + this.passed = negate ? !this.result : this.result + if (!this.passed) this.message = matcher.message.call(this, actual, expected, negate, matcher.name) + return this + } + }) + }, + + ProxyAssertion : function(object, method, times, negate) { + var self = this, + old = object[method] + + // Proxy + + object[method] = function(){ + var args = toArray(arguments), + result = old.apply(object, args) + self.calls.push({ args : args, result : result }) + return result + } + + // Times + + this.times = { + once : 1, + twice : 2 + }[times] || times || 1 + + extend(this, { + calls: [], + message: '', + defer: true, + passed: false, + negate: negate, + object: object, + method: method, + + // Proxy return value + + and_return : function(result) { + this.expectedResult = result + return this + }, + + // Proxy arguments passed + + with_args : function() { + this.expectedArgs = toArray(arguments) + return this + }, + + // Check if any calls have failing results + + anyResultsFail : function() { + return any(this.calls, function(call){ + return self.expectedResult.an_instance_of ? + call.result.constructor != self.expectedResult.an_instance_of: + !equal(self.expectedResult, call.result) + }) + }, + + // Check if any calls have passing results + + anyResultsPass : function() { + return any(this.calls, function(call){ + return self.expectedResult.an_instance_of ? + call.result.constructor == self.expectedResult.an_instance_of: + equal(self.expectedResult, call.result) + }) + }, + + // Return the passing result + + passingResult : function() { + return this.anyResultsPass().result + }, + + // Return the failing result + + failingResult : function() { + return this.anyResultsFail().result + }, + + // Check if any arguments fail + + anyArgsFail : function() { + return any(this.calls, function(call){ + return any(self.expectedArgs, function(i, arg){ + if (arg == null) return call.args[i] == null + return arg.an_instance_of ? + call.args[i].constructor != arg.an_instance_of: + !equal(arg, call.args[i]) + + }) + }) + }, + + // Check if any arguments pass + + anyArgsPass : function() { + return any(this.calls, function(call){ + return any(self.expectedArgs, function(i, arg){ + return arg.an_instance_of ? + call.args[i].constructor == arg.an_instance_of: + equal(arg, call.args[i]) + + }) + }) + }, + + // Return the passing args + + passingArgs : function() { + return this.anyArgsPass().args + }, + + // Return the failing args + + failingArgs : function() { + return this.anyArgsFail().args + }, + + // Report assertion results + + report : function() { + if (JSpec.assert) + this.passed ? ++JSpec.stats.passes : ++JSpec.stats.failures + return this + }, + + // Run the assertion + + run : function() { + var methodString = 'expected ' + object.toString() + '.' + method + '()' + (negate ? ' not' : '' ) + + function times(n) { + return n > 2 ? n + ' times' : { 1: 'once', 2: 'twice' }[n] + } + + if (this.expectedResult != null && (negate ? this.anyResultsPass() : this.anyResultsFail())) + this.message = methodString + ' to return ' + puts(this.expectedResult) + + ' but ' + (negate ? 'it did' : 'got ' + puts(this.failingResult())) + + if (this.expectedArgs && (negate ? !this.expectedResult && this.anyArgsPass() : this.anyArgsFail())) + this.message = methodString + ' to be called with ' + puts.apply(this, this.expectedArgs) + + ' but was' + (negate ? '' : ' called with ' + puts.apply(this, this.failingArgs())) + + if (negate ? !this.expectedResult && !this.expectedArgs && this.calls.length >= this.times : this.calls.length != this.times) + this.message = methodString + ' to be called ' + times(this.times) + + ', but ' + (this.calls.length == 0 ? ' was not called' : ' was called ' + times(this.calls.length)) + + if (!this.message.length) + this.passed = true + + return this + } + }) + }, + + /** + * Specification Suite block object. + * + * @param {string} description + * @param {function} body + * @api private + */ + + Suite : function(description, body, isShared) { + var self = this + extend(this, { + body: body, + description: description, + suites: [], + sharedBehaviors: [], + specs: [], + ran: false, + shared: isShared, + hooks: { 'before' : [], 'after' : [], + 'before_each' : [], 'after_each' : [], + 'before_nested' : [], 'after_nested' : []}, + + // Add a spec to the suite + + addSpec : function(description, body) { + var spec = new JSpec.Spec(description, body) + this.specs.push(spec) + JSpec.stats.specs++ // TODO: abstract + spec.suite = this + }, + + // Add a before hook to the suite + + addBefore : function(options, body) { + body.options = options || {} + this.befores.push(body) + }, + + // Add an after hook to the suite + + addAfter : function(options, body) { + body.options = options || {} + this.afters.unshift(body) + }, + + // Add a hook to the suite + + addHook : function(hook, body) { + this.hooks[hook].push(body) + }, + + // Add a nested suite + + addSuite : function(description, body, isShared) { + var suite = new JSpec.Suite(description, body, isShared) + JSpec.allSuites.push(suite) + suite.name = suite.description + suite.description = this.description + ' ' + suite.description + this.suites.push(suite) + suite.suite = this + }, + + // Invoke a hook in context to this suite + + hook : function(hook) { + if (hook != 'before' && hook != 'after') + if (this.suite) this.suite.hook(hook) + + each(this.hooks[hook], function(body) { + JSpec.evalBody(body, "Error in hook '" + hook + "', suite '" + self.description + "': ") + }) + }, + + // Check if nested suites are present + + hasSuites : function() { + return this.suites.length + }, + + // Check if this suite has specs + + hasSpecs : function() { + return this.specs.length + }, + + // Check if the entire suite passed + + passed : function() { + return !any(this.specs, function(spec){ + return !spec.passed() + }) + }, + + isShared : function(){ + return this.shared + }, + + isExecutable : function() { + return !this.isShared() && this.hasSpecs() + } + }) + }, + + /** + * Specification block object. + * + * @param {string} description + * @param {function} body + * @api private + */ + + Spec : function(description, body) { + extend(this, { + body: body, + description: description, + assertions: [], + + // Add passing assertion + + pass : function(message) { + this.assertions.push({ passed: true, message: message }) + if (JSpec.assert) ++JSpec.stats.passes + }, + + // Add failing assertion + + fail : function(message) { + this.assertions.push({ passed: false, message: message }) + if (JSpec.assert) ++JSpec.stats.failures + }, + + // Run deferred assertions + + runDeferredAssertions : function() { + each(this.assertions, function(assertion){ + if (assertion.defer) assertion.run().report(), hook('afterAssertion', assertion) + }) + }, + + // Find first failing assertion + + failure : function() { + return find(this.assertions, function(assertion){ + return !assertion.passed + }) + }, + + // Find all failing assertions + + failures : function() { + return select(this.assertions, function(assertion){ + return !assertion.passed + }) + }, + + // Weither or not the spec passed + + passed : function() { + return !this.failure() + }, + + // Weither or not the spec requires implementation (no assertions) + + requiresImplementation : function() { + return this.assertions.length == 0 + }, + + // Sprite based assertions graph + + assertionsGraph : function() { + return map(this.assertions, function(assertion){ + return '' + }).join('') + } + }) + }, + + Module : function(methods) { + extend(this, methods) + }, + + JSON : { + + /** + * Generic sequences. + */ + + meta : { + '\b' : '\\b', + '\t' : '\\t', + '\n' : '\\n', + '\f' : '\\f', + '\r' : '\\r', + '"' : '\\"', + '\\' : '\\\\' + }, + + /** + * Escapable sequences. + */ + + escapable : /[\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + + /** + * JSON encode _object_. + * + * @param {mixed} object + * @return {string} + * @api private + */ + + encode : function(object) { + var self = this + if (object == undefined || object == null) return 'null' + if (object === true) return 'true' + if (object === false) return 'false' + switch (typeof object) { + case 'number': return object + case 'string': return this.escapable.test(object) ? + '"' + object.replace(this.escapable, function (a) { + return typeof self.meta[a] === 'string' ? self.meta[a] : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4) + }) + '"' : + '"' + object + '"' + case 'object': + if (object.constructor == Array) + return '[' + map(object, function(val){ + return self.encode(val) + }).join(', ') + ']' + else if (object) + return '{' + map(object, function(key, val){ + return self.encode(key) + ':' + self.encode(val) + }).join(', ') + '}' + } + return 'null' + } + }, + + // --- DSLs + + DSLs : { + snake : { + expect : function(actual){ + return JSpec.expect(actual) + }, + + describe : function(description, body) { + return JSpec.currentSuite.addSuite(description, body, false) + }, + + it : function(description, body) { + return JSpec.currentSuite.addSpec(description, body) + }, + + before : function(body) { + return JSpec.currentSuite.addHook('before', body) + }, + + after : function(body) { + return JSpec.currentSuite.addHook('after', body) + }, + + before_each : function(body) { + return JSpec.currentSuite.addHook('before_each', body) + }, + + after_each : function(body) { + return JSpec.currentSuite.addHook('after_each', body) + }, + + before_nested : function(body) { + return JSpec.currentSuite.addHook('before_nested', body) + }, + + after_nested : function(body){ + return JSpec.currentSuite.addhook('after_nested', body) + }, + + shared_behaviors_for : function(description, body){ + return JSpec.currentSuite.addSuite(description, body, true) + }, + + should_behave_like : function(description) { + return JSpec.shareBehaviorsOf(description) + } + } + }, + + // --- Methods + + /** + * Check if _value_ is 'stop'. For use as a + * utility callback function. + * + * @param {mixed} value + * @return {bool} + * @api public + */ + + haveStopped : function(value) { + return value === 'stop' + }, + + /** + * Include _object_ which may be a hash or Module instance. + * + * @param {hash, Module} object + * @return {JSpec} + * @api public + */ + + include : function(object) { + var module = object.constructor == JSpec.Module ? object : new JSpec.Module(object) + this.modules.push(module) + if ('init' in module) module.init() + if ('utilities' in module) extend(this.defaultContext, module.utilities) + if ('matchers' in module) this.addMatchers(module.matchers) + if ('reporters' in module) extend(this.reporters, module.reporters) + if ('DSLs' in module) + each(module.DSLs, function(name, methods){ + JSpec.DSLs[name] = JSpec.DSLs[name] || {} + extend(JSpec.DSLs[name], methods) + }) + return this + }, + + /** + * Add a module hook _name_, which is immediately + * called per module with the _args_ given. An array of + * hook return values is returned. + * + * @param {name} string + * @param {...} args + * @return {array} + * @api private + */ + + hook : function(name, args) { + args = toArray(arguments, 1) + return inject(JSpec.modules, [], function(results, module){ + if (typeof module[name] == 'function') + results.push(JSpec.evalHook(module, name, args)) + }) + }, + + /** + * Eval _module_ hook _name_ with _args_. Evaluates in context + * to the module itself, JSpec, and JSpec.context. + * + * @param {Module} module + * @param {string} name + * @param {array} args + * @return {mixed} + * @api private + */ + + evalHook : function(module, name, args) { + hook('evaluatingHookBody', module, name) + return module[name].apply(module, args) + }, + + /** + * Same as hook() however accepts only one _arg_ which is + * considered immutable. This function passes the arg + * to the first module, then passes the return value of the last + * module called, to the following module. + * + * @param {string} name + * @param {mixed} arg + * @return {mixed} + * @api private + */ + + hookImmutable : function(name, arg) { + return inject(JSpec.modules, arg, function(result, module){ + if (typeof module[name] == 'function') + return JSpec.evalHook(module, name, [result]) + }) + }, + + /** + * Find a shared example suite by its description or name. + * First searches parent tree of suites for shared behavior + * before falling back to global scoped nested behaviors. + * + * @param {string} description + * @return {Suite} + * @api private + */ + + findSharedBehavior : function(description) { + var behavior + return (behavior = JSpec.findLocalSharedBehavior(description)) + ? behavior + : JSpec.findGlobalSharedBehavior(description) + }, + + /** + * Find a shared example suite within the current suite's + * parent tree by its description or name. + * + * @param {string} description + * @return {Suite} + * @api private + */ + + findLocalSharedBehavior : function(description) { + var behavior, + currentSuite = JSpec.currentSuite.suite + while (currentSuite) + if (behavior = find(currentSuite.suites, JSpec.suiteDescriptionPredicate(description))) + return behavior + else + currentSuite = currentSuite.suite + }, + + /** + * Find a shared example suite within the global + * scope by its description or name. + * + * @param {string} description + * @return {Suite} + * @api private + */ + + findGlobalSharedBehavior : function(description) { + return find(JSpec.suites, JSpec.suiteDescriptionPredicate(description)) + }, + + /** + * Build a predicate that will match a suite based on name or description + * + * @param {string} description + * @return {function} + * @api private + */ + + suiteDescriptionPredicate : function(description) { + return function(suite){ + return suite.name === description || + suite.description === description + } + }, + + /** + * Share behaviors (specs) of the given suite with + * the current suite. + * + * @param {string} description + * @api public + */ + + shareBehaviorsOf : function(description) { + var suite = JSpec.findSharedBehavior(description) + if (suite) + JSpec.evalBody(suite.body) + else + throw new Error("failed to find shared behaviors named `" + description + "'") + }, + + + /** + * Convert arguments to an array. + * + * @param {object} arguments + * @param {int} offset + * @return {array} + * @api public + */ + + toArray : function(arguments, offset) { + return Array.prototype.slice.call(arguments, offset || 0) + }, + + /** + * Return ANSI-escaped colored string. + * + * @param {string} string + * @param {string} color + * @return {string} + * @api public + */ + + color : function(string, color) { + if (option('disableColors')) { + return string + } else { + return "\u001B[" + { + bold : 1, + black : 30, + red : 31, + green : 32, + yellow : 33, + blue : 34, + magenta : 35, + cyan : 36, + white : 37 + }[color] + 'm' + string + "\u001B[0m" + } + }, + + /** + * Default matcher message callback. + * + * @api private + */ + + defaultMatcherMessage : function(actual, expected, negate, name) { + return 'expected ' + puts(actual) + ' to ' + + (negate ? 'not ' : '') + + name.replace(/_/g, ' ') + + ' ' + (expected.length > 1 ? + puts.apply(this, expected.slice(1)) : + '') + }, + + /** + * Normalize a matcher message. + * + * When no messge callback is present the defaultMatcherMessage + * will be assigned, will suffice for most matchers. + * + * @param {hash} matcher + * @return {hash} + * @api public + */ + + normalizeMatcherMessage : function(matcher) { + if (typeof matcher.message != 'function') + matcher.message = this.defaultMatcherMessage + return matcher + }, + + /** + * Normalize a matcher body + * + * This process allows the following conversions until + * the matcher is in its final normalized hash state. + * + * - '==' becomes 'actual == expected' + * - 'actual == expected' becomes 'return actual == expected' + * - function(actual, expected) { return actual == expected } becomes + * { match : function(actual, expected) { return actual == expected }} + * + * @param {mixed} body + * @return {hash} + * @api public + */ + + normalizeMatcherBody : function(body) { + var captures + switch (body.constructor) { + case String: + if (captures = body.match(/^alias (\w+)/)) return JSpec.matchers[last(captures)] + if (body.length < 4) body = 'actual ' + body + ' expected' + return { match: function(actual, expected) { return eval(body) }} + + case Function: + return { match: body } + + default: + return body + } + }, + + /** + * Get option value. This method first checks if + * the option key has been set via the query string, + * otherwise returning the options hash value. + * + * @param {string} key + * @return {mixed} + * @api public + */ + + option : function(key) { + return (value = query(key)) !== null ? value : + JSpec.options[key] || null + }, + + /** + * Check if object _a_, is equal to object _b_. + * + * @param {object} a + * @param {object} b + * @return {bool} + * @api private + */ + + equal: function(a, b) { + if (typeof a != typeof b) return + if (a === b) return true + if (a instanceof RegExp) + return a.toString() === b.toString() + if (a instanceof Date) + return Number(a) === Number(b) + if (typeof a != 'object') return + if (a.length !== undefined) + if (a.length !== b.length) return + else + for (var i = 0, len = a.length; i < len; ++i) + if (!equal(a[i], b[i])) + return + for (var key in a) + if (!equal(a[key], b[key])) + return + return true + }, + + /** + * Return last element of an array. + * + * @param {array} array + * @return {object} + * @api public + */ + + last : function(array) { + return array[array.length - 1] + }, + + /** + * Convert object(s) to a print-friend string. + * + * @param {...} object + * @return {string} + * @api public + */ + + puts : function(object) { + if (arguments.length > 1) + return map(toArray(arguments), function(arg){ + return puts(arg) + }).join(', ') + if (object === undefined) return 'undefined' + if (object === null) return 'null' + if (object === true) return 'true' + if (object === false) return 'false' + if (object.an_instance_of) return 'an instance of ' + object.an_instance_of.name + if (object.jquery && object.selector.length > 0) return 'selector ' + puts(object.selector) + if (object.jquery) return object.get(0).outerHTML + if (object.nodeName) return object.outerHTML + switch (object.constructor) { + case Function: return object.name || object + case String: + return '"' + object + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + + '"' + case Array: + return inject(object, '[', function(b, v){ + return b + ', ' + puts(v) + }).replace('[,', '[') + ' ]' + case Object: + object.__hit__ = true + return inject(object, '{', function(b, k, v) { + if (k == '__hit__') return b + return b + ', ' + k + ': ' + (v && v.__hit__ ? '' : puts(v)) + }).replace('{,', '{') + ' }' + default: + return object.toString() + } + }, + + /** + * Parse an XML String and return a 'document'. + * + * @param {string} text + * @return {document} + * @api public + */ + + parseXML : function(text) { + var xmlDoc + if (window.DOMParser) + xmlDoc = (new DOMParser()).parseFromString(text, "text/xml") + else { + xmlDoc = new ActiveXObject("Microsoft.XMLDOM") + xmlDoc.async = "false" + xmlDoc.loadXML(text) + } + return xmlDoc + }, + + /** + * Escape HTML. + * + * @param {string} html + * @return {string} + * @api public + */ + + escape : function(html) { + return html.toString() + .replace(/&/gmi, '&') + .replace(/"/gmi, '"') + .replace(/>/gmi, '>') + .replace(/ current) while (++current <= end) values.push(current) + else while (--current >= end) values.push(current) + return '[' + values + ']' + }, + + /** + * Report on the results. + * + * @api public + */ + + report : function() { + this.duration = Number(new Date) - this.start + hook('reporting', JSpec.options) + new (JSpec.options.reporter || JSpec.reporters.DOM)(JSpec, JSpec.options) + }, + + /** + * Run the spec suites. Options are merged + * with JSpec options when present. + * + * @param {hash} options + * @return {JSpec} + * @api public + */ + + run : function(options) { + if (any(hook('running'), haveStopped)) return this + if (options) extend(this.options, options) + this.start = Number(new Date) + each(this.suites, function(suite) { JSpec.runSuite(suite) }) + return this + }, + + /** + * Run a suite. + * + * @param {Suite} suite + * @api public + */ + + runSuite : function(suite) { + if (!suite.isShared()) + { + this.currentSuite = suite + this.evalBody(suite.body) + suite.ran = true + hook('beforeSuite', suite), suite.hook('before'), suite.hook('before_nested') + each(suite.specs, function(spec) { + hook('beforeSpec', spec) + suite.hook('before_each') + JSpec.runSpec(spec) + hook('afterSpec', spec) + suite.hook('after_each') + }) + if (suite.hasSuites()) { + each(suite.suites, function(suite) { + JSpec.runSuite(suite) + }) + } + hook('afterSuite', suite), suite.hook('after_nested'), suite.hook('after') + this.stats.suitesFinished++ + } + }, + + /** + * Report a failure for the current spec. + * + * @param {string} message + * @api public + */ + + fail : function(message) { + JSpec.currentSpec.fail(message) + }, + + /** + * Report a passing assertion for the current spec. + * + * @param {string} message + * @api public + */ + + pass : function(message) { + JSpec.currentSpec.pass(message) + }, + + /** + * Run a spec. + * + * @param {Spec} spec + * @api public + */ + + runSpec : function(spec) { + this.currentSpec = spec + try { this.evalBody(spec.body) } + catch (e) { fail(e) } + spec.runDeferredAssertions() + destub() + this.stats.specsFinished++ + this.stats.assertions += spec.assertions.length + }, + + /** + * Require a dependency, with optional message. + * + * @param {string} dependency + * @param {string} message (optional) + * @return {JSpec} + * @api public + */ + + requires : function(dependency, message) { + hook('requiring', dependency, message) + try { eval(dependency) } + catch (e) { throw 'JSpec depends on ' + dependency + ' ' + message } + return this + }, + + /** + * Query against the current query strings keys + * or the queryString specified. + * + * @param {string} key + * @param {string} queryString + * @return {string, null} + * @api private + */ + + query : function(key, queryString) { + var queryString = (queryString || (main.location ? main.location.search : null) || '').substring(1) + return inject(queryString.split('&'), null, function(value, pair){ + parts = pair.split('=') + return parts[0] == key ? parts[1].replace(/%20|\+/gmi, ' ') : value + }) + }, + + /** + * Ad-hoc POST request for JSpec server usage. + * + * @param {string} uri + * @param {string} data + * @api private + */ + + post : function(uri, data) { + if (any(hook('posting', uri, data), haveStopped)) return + var request = this.xhr() + request.open('POST', uri, false) + request.setRequestHeader('Content-Type', 'application/json') + request.send(JSpec.JSON.encode(data)) + }, + + /** + * Instantiate an XMLHttpRequest. + * + * Here we utilize IE's lame ActiveXObjects first which + * allow IE access serve files via the file: protocol, otherwise + * we then default to XMLHttpRequest. + * + * @return {XMLHttpRequest, ActiveXObject} + * @api private + */ + + xhr : function() { + return this.ieXhr() || new JSpec.request + }, + + /** + * Return Microsoft piece of crap ActiveXObject. + * + * @return {ActiveXObject} + * @api public + */ + + ieXhr : function() { + function object(str) { + try { return new ActiveXObject(str) } catch(e) {} + } + return object('Msxml2.XMLHTTP.6.0') || + object('Msxml2.XMLHTTP.3.0') || + object('Msxml2.XMLHTTP') || + object('Microsoft.XMLHTTP') + }, + + /** + * Check for HTTP request support. + * + * @return {bool} + * @api private + */ + + hasXhr : function() { + return JSpec.request || 'ActiveXObject' in main + }, + + /** + * Try loading _file_ returning the contents + * string or null. Chain to locate / read a file. + * + * @param {string} file + * @return {string} + * @api public + */ + + tryLoading : function(file) { + try { return JSpec.load(file) } catch (e) {} + }, + + /** + * Load a _file_'s contents. + * + * @param {string} file + * @param {function} callback + * @return {string} + * @api public + */ + + load : function(file, callback) { + if (any(hook('loading', file), haveStopped)) return + if ('readFile' in main) + return readFile(file) + else if (this.hasXhr()) { + var request = this.xhr() + request.open('GET', file, false) + request.send(null) + if (request.readyState == 4 && + (request.status == 0 || + request.status.toString().charAt(0) == 2)) + return request.responseText + } + else + throw new Error("failed to load `" + file + "'") + }, + + /** + * Load, pre-process, and evaluate a file. + * + * @param {string} file + * @param {JSpec} + * @api public + */ + + exec : function(file) { + if (any(hook('executing', file), haveStopped)) return this + eval('with (JSpec){' + this.preprocess(this.load(file)) + '}') + return this + } + } + + // --- Node.js support + + if (typeof GLOBAL === 'object' && typeof exports === 'object') { + var fs = require('fs') + quit = process.exit + print = require('sys').puts + readFile = function(file){ + return fs.readFileSync(file).toString('utf8') + } + } + + // --- Utility functions + + var main = this, + find = JSpec.any, + utils = 'haveStopped stub hookImmutable hook destub map any last pass fail range each option inject select \ + error escape extend puts query strip color does addMatchers callIterator toArray equal'.split(/\s+/) + while (utils.length) eval('var ' + utils[0] + ' = JSpec.' + utils.shift()) + if (!main.setTimeout) main.setTimeout = function(callback){ callback() } + + // --- Matchers + + addMatchers({ + equal : "===", + eql : "equal(actual, expected)", + be : "alias equal", + be_greater_than : ">", + be_less_than : "<", + be_at_least : ">=", + be_at_most : "<=", + be_a : "actual.constructor == expected", + be_an : "alias be_a", + be_an_instance_of : "actual instanceof expected", + be_null : "actual == null", + be_true : "actual == true", + be_false : "actual == false", + be_undefined : "typeof actual == 'undefined'", + be_type : "typeof actual == expected", + match : "typeof actual == 'string' ? actual.match(expected) : false", + respond_to : "typeof actual[expected] == 'function'", + have_length : "actual.length == expected", + be_within : "actual >= expected[0] && actual <= last(expected)", + have_length_within : "actual.length >= expected[0] && actual.length <= last(expected)", + + receive : { defer : true, match : function(actual, method, times) { + var proxy = new JSpec.ProxyAssertion(actual, method, times, this.negate) + JSpec.currentSpec.assertions.push(proxy) + return proxy + }}, + + be_empty : function(actual) { + if (actual.constructor == Object && actual.length == undefined) + for (var key in actual) + return false; + return !actual.length + }, + + include : function(actual) { + for (var state = true, i = 1; i < arguments.length; i++) { + var arg = arguments[i] + switch (actual.constructor) { + case String: + case Number: + case RegExp: + case Function: + state = actual.toString().indexOf(arg) !== -1 + break + + case Object: + state = arg in actual + break + + case Array: + state = any(actual, function(value){ return equal(value, arg) }) + break + } + if (!state) return false + } + return true + }, + + throw_error : { match : function(actual, expected, message) { + try { actual() } + catch (e) { + this.e = e + var assert = function(arg) { + switch (arg.constructor) { + case RegExp : return arg.test(e.message || e.toString()) + case String : return arg == (e.message || e.toString()) + case Function : return e instanceof arg || e.name == arg.name + } + } + return message ? assert(expected) && assert(message) : + expected ? assert(expected) : + true + } + }, message : function(actual, expected, negate) { + // TODO: refactor when actual is not in expected [0] + var message_for = function(i) { + if (expected[i] == undefined) return 'exception' + switch (expected[i].constructor) { + case RegExp : return 'exception matching ' + puts(expected[i]) + case String : return 'exception of ' + puts(expected[i]) + case Function : return expected[i].name || 'Error' + } + } + var exception = message_for(1) + (expected[2] ? ' and ' + message_for(2) : '') + return 'expected ' + exception + (negate ? ' not ' : '' ) + + ' to be thrown, but ' + (this.e ? 'got ' + puts(this.e) : 'nothing was') + }}, + + have : function(actual, length, property) { + return actual[property] == null ? false : actual[property].length == length + }, + + have_at_least : function(actual, length, property) { + return actual[property] == null ? (length === 0) : actual[property].length >= length + }, + + have_at_most :function(actual, length, property) { + return actual[property] == null || actual[property].length <= length + }, + + have_within : function(actual, range, property) { + var length = actual[property] == undefined ? 0 : actual[property].length + return length >= range.shift() && length <= range.pop() + }, + + have_prop : function(actual, property, value) { + var actualVal = actual[property], actualType = typeof actualVal + return (actualType == 'function' || actualType == 'undefined') ? false : + typeof value === 'undefined' || + does(actual[property],'eql',value) + }, + + have_property : function(actual, property, value) { + var actualVal = actual[property], actualType = typeof actualVal + return (actualType == 'function' || actualType == 'undefined') ? false : + typeof value === 'undefined' || + value === actualVal + } + }) + +})() diff --git a/node_modules/jade/support/sass/spec/lib/jspec.nodejs.js b/node_modules/jade/support/sass/spec/lib/jspec.nodejs.js new file mode 100644 index 0000000..6765273 --- /dev/null +++ b/node_modules/jade/support/sass/spec/lib/jspec.nodejs.js @@ -0,0 +1,18 @@ + +// JSpec - node - Copyright TJ Holowaychuk (MIT Licensed) + +JSpec +.include({ + name: 'node', + + // --- Matchers + + matchers : { + have_enumerable_property: 'actual.propertyIsEnumerable(expected)', + have_writable_property: 'Object.getOwnPropertyDescriptor(actual, expected).writable === true', + have_configurable_property: 'Object.getOwnPropertyDescriptor(actual, expected).configurable === true', + have_keys: 'does(Object.keys(actual), "eql", expected)', + have_prototype: 'Object.getPrototypeOf(actual) === expected' + } +}) + diff --git a/node_modules/jade/support/sass/spec/lib/jspec.shell.js b/node_modules/jade/support/sass/spec/lib/jspec.shell.js new file mode 100644 index 0000000..cb19c69 --- /dev/null +++ b/node_modules/jade/support/sass/spec/lib/jspec.shell.js @@ -0,0 +1,39 @@ + +// JSpec - Shell - Copyright TJ Holowaychuk (MIT Licensed) + +;(function(){ + + var _quit = quit + + Shell = { + + // --- Global + + main: this, + + // --- Commands + + commands: { + quit: ['Terminate the shell', function(){ _quit() }], + exit: ['Terminate the shell', function(){ _quit() }], + p: ['Inspect an object', function(o){ return o.toSource() }] + }, + + /** + * Start the interactive shell. + * + * @api public + */ + + start : function() { + for (var name in this.commands) + if (this.commands.hasOwnProperty(name)) + this.commands[name][1].length ? + this.main[name] = this.commands[name][1] : + this.main.__defineGetter__(name, this.commands[name][1]) + } + } + + Shell.start() + +})() \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/lib/jspec.timers.js b/node_modules/jade/support/sass/spec/lib/jspec.timers.js new file mode 100644 index 0000000..c88d10b --- /dev/null +++ b/node_modules/jade/support/sass/spec/lib/jspec.timers.js @@ -0,0 +1,90 @@ + +// JSpec - Mock Timers - Copyright TJ Holowaychuk (MIT Licensed) + +;(function(){ + + /** + * Version. + */ + + mockTimersVersion = '1.0.2' + + /** + * Localized timer stack. + */ + + var timers = [] + + /** + * Set mock timeout with _callback_ and timeout of _ms_. + * + * @param {function} callback + * @param {int} ms + * @return {int} + * @api public + */ + + setTimeout = function(callback, ms) { + var id + return id = setInterval(function(){ + callback() + clearInterval(id) + }, ms) + } + + /** + * Set mock interval with _callback_ and interval of _ms_. + * + * @param {function} callback + * @param {int} ms + * @return {int} + * @api public + */ + + setInterval = function(callback, ms) { + callback.step = ms, callback.current = callback.last = 0 + return timers[timers.length] = callback, timers.length + } + + /** + * Destroy timer with _id_. + * + * @param {int} id + * @return {bool} + * @api public + */ + + clearInterval = clearTimeout = function(id) { + return delete timers[--id] + } + + /** + * Reset timers. + * + * @return {array} + * @api public + */ + + resetTimers = function() { + return timers = [] + } + + /** + * Increment each timers internal clock by _ms_. + * + * @param {int} ms + * @api public + */ + + tick = function(ms) { + for (var i = 0, len = timers.length; i < len; ++i) + if (timers[i] && (timers[i].current += ms)) + if (timers[i].current - timers[i].last >= timers[i].step) { + var times = Math.floor((timers[i].current - timers[i].last) / timers[i].step) + var remainder = (timers[i].current - timers[i].last) % timers[i].step + timers[i].last = timers[i].current - remainder + while (times-- && timers[i]) timers[i]() + } + } + +})() \ No newline at end of file diff --git a/node_modules/jade/support/sass/spec/lib/jspec.xhr.js b/node_modules/jade/support/sass/spec/lib/jspec.xhr.js new file mode 100644 index 0000000..3b96310 --- /dev/null +++ b/node_modules/jade/support/sass/spec/lib/jspec.xhr.js @@ -0,0 +1,210 @@ + +// JSpec - XHR - Copyright TJ Holowaychuk (MIT Licensed) + +(function(){ + + var lastRequest + + // --- Original XMLHttpRequest + + var OriginalXMLHttpRequest = 'XMLHttpRequest' in this ? + XMLHttpRequest : + function(){} + var OriginalActiveXObject = 'ActiveXObject' in this ? + ActiveXObject : + undefined + + // --- MockXMLHttpRequest + + var MockXMLHttpRequest = function() { + this.requestHeaders = {} + } + + MockXMLHttpRequest.prototype = { + status: 0, + async: true, + readyState: 0, + responseXML: null, + responseText: '', + abort: function(){}, + onreadystatechange: function(){}, + + /** + * Return response headers hash. + */ + + getAllResponseHeaders : function(){ + return JSpec.inject(this.responseHeaders, '', function(buf, key, val){ + return buf + key + ': ' + val + '\r\n' + }) + }, + + /** + * Return case-insensitive value for header _name_. + */ + + getResponseHeader : function(name) { + return this.responseHeaders[name.toLowerCase()] + }, + + /** + * Set case-insensitive _value_ for header _name_. + */ + + setRequestHeader : function(name, value) { + this.requestHeaders[name.toLowerCase()] = value + }, + + /** + * Open mock request. + */ + + open : function(method, url, async, user, password) { + this.user = user + this.password = password + this.url = url + this.readyState = 1 + this.method = method.toUpperCase() + if (async != undefined) this.async = async + if (this.async) this.onreadystatechange() + }, + + /** + * Send request _data_. + */ + + send : function(data) { + var self = this + this.data = data + this.readyState = 4 + if (this.method == 'HEAD') this.responseText = null + this.responseHeaders['content-length'] = (this.responseText || '').length + if(this.async) this.onreadystatechange() + this.populateResponseXML() + lastRequest = function(){ + return self + } + }, + + /** + * Parse request body and populate responseXML if response-type is xml + * Based on the standard specification : http://www.w3.org/TR/XMLHttpRequest/ + */ + populateResponseXML: function() { + var type = this.getResponseHeader("content-type") + if (!type || !this.responseText || !type.match(/(text\/xml|application\/xml|\+xml$)/g)) + return + this.responseXML = JSpec.parseXML(this.responseText) + } + } + + // --- Response status codes + + JSpec.statusCodes = { + 100: 'Continue', + 101: 'Switching Protocols', + 200: 'OK', + 201: 'Created', + 202: 'Accepted', + 203: 'Non-Authoritative Information', + 204: 'No Content', + 205: 'Reset Content', + 206: 'Partial Content', + 300: 'Multiple Choice', + 301: 'Moved Permanently', + 302: 'Found', + 303: 'See Other', + 304: 'Not Modified', + 305: 'Use Proxy', + 307: 'Temporary Redirect', + 400: 'Bad Request', + 401: 'Unauthorized', + 402: 'Payment Required', + 403: 'Forbidden', + 404: 'Not Found', + 405: 'Method Not Allowed', + 406: 'Not Acceptable', + 407: 'Proxy Authentication Required', + 408: 'Request Timeout', + 409: 'Conflict', + 410: 'Gone', + 411: 'Length Required', + 412: 'Precondition Failed', + 413: 'Request Entity Too Large', + 414: 'Request-URI Too Long', + 415: 'Unsupported Media Type', + 416: 'Requested Range Not Satisfiable', + 417: 'Expectation Failed', + 422: 'Unprocessable Entity', + 500: 'Internal Server Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Gateway Timeout', + 505: 'HTTP Version Not Supported' + } + + /** + * Mock XMLHttpRequest requests. + * + * mockRequest().and_return('some data', 'text/plain', 200, { 'X-SomeHeader' : 'somevalue' }) + * + * @return {hash} + * @api public + */ + + function mockRequest() { + return { and_return : function(body, type, status, headers) { + XMLHttpRequest = MockXMLHttpRequest + ActiveXObject = false + status = status || 200 + headers = headers || {} + headers['content-type'] = type + JSpec.extend(XMLHttpRequest.prototype, { + responseText: body, + responseHeaders: headers, + status: status, + statusText: JSpec.statusCodes[status] + }) + }} + } + + /** + * Unmock XMLHttpRequest requests. + * + * @api public + */ + + function unmockRequest() { + XMLHttpRequest = OriginalXMLHttpRequest + ActiveXObject = OriginalActiveXObject + } + + JSpec.include({ + name: 'Mock XHR', + + // --- Utilities + + utilities : { + mockRequest: mockRequest, + unmockRequest: unmockRequest + }, + + // --- Hooks + + afterSpec : function() { + unmockRequest() + }, + + // --- DSLs + + DSLs : { + snake : { + mock_request: mockRequest, + unmock_request: unmockRequest, + last_request: function(){ return lastRequest() } + } + } + + }) +})() diff --git a/node_modules/jade/support/sass/spec/node.js b/node_modules/jade/support/sass/spec/node.js new file mode 100644 index 0000000..07d9934 --- /dev/null +++ b/node_modules/jade/support/sass/spec/node.js @@ -0,0 +1,9 @@ + +require.paths.unshift('spec', 'spec/lib', 'lib') +require('jspec') +sass = require('sass') + +JSpec + .exec('spec/spec.core.js') + .run({ reporter: JSpec.reporters.Terminal, fixturePath: 'spec/fixtures', failuresOnly: true }) + .report() diff --git a/node_modules/jade/support/sass/spec/spec.core.js b/node_modules/jade/support/sass/spec/spec.core.js new file mode 100644 index 0000000..5ee3cb7 --- /dev/null +++ b/node_modules/jade/support/sass/spec/spec.core.js @@ -0,0 +1,134 @@ + +describe 'Sass' + before + render = function(path, options) { + return sass.render(fixture(path + '.sass'), options) + } + + expected = function(path) { + return fixture(path + '.css') + } + + assert = function(path, options) { + render(path, options).should.eql expected(path) + } + end + + describe '.version' + it 'should be a triplet' + sass.version.should.match(/^\d+\.\d+\.\d+$/) + end + end + + describe '.render()' + describe 'with "cache" enabled' + describe 'without "filename"' + it 'should throw an error' + -{ assert('selectors', { cache: true }) }.should.throw_error 'filename option must be passed when cache is enabled' + end + end + + describe 'with "filename"' + it 'should still work' + assert('selectors', { cache: true, filename: 'style.sass' }) + end + end + end + + it 'should support complex selectors' + assert('selectors') + end + + describe '// ...' + it 'should be a sass-specific comment' + assert('comment') + end + end + + describe '& ...' + it 'should continue a selector' + assert('continuation') + end + end + + describe '{...}' + it 'should have access to variables' + assert('literal') + end + end + + describe ':key val' + it 'should define a property' + assert('properties') + end + + describe 'when nested' + it 'should traverse correctly' + assert('properties.nested') + end + + describe 'incorrectly' + it 'should throw an error' + try { assert('properties.nested.invalid') } + catch (e) { + e.message.should.eql 'ParseError: on line 3; invalid indentation, to much nesting' + } + end + end + end + + describe 'when at the top level' + it 'should throw an error' + try { assert('properties.invalid') } + catch (e) { + e.message.should.eql 'ParseError: on line 1; properties must be nested within a selector' + } + end + end + end + + describe '=:key val' + it 'should expand to -{moz, webkit}-border-radius' + assert('properties.expand') + end + end + + describe '!key = val' + it 'should define a variable' + assert('variables.regular') + end + end + + describe 'key: val' + it 'should define a variable' + assert('variables.alternate') + end + end + end + + describe '+mixin' + it 'should create a mixin' + assert('mixin') + end + + describe 'when the mixin does not exist' + try { assert('mixin.undefined') } + catch (e) { + e.message.should.eql 'ParseError: on line 2; mixin `large\' does not exist' + } + end + end + + describe '.collect()' + it 'should return variables defined' + var collected = sass.collect(fixture('collect.sass')) + collected.variables.should.eql { red: '#ff0000', black: '#000' } + end + + it 'should return mixins defined' + var collected = sass.collect(fixture('mixin.sass')) + collected.mixins.should.have_property 'large' + collected.mixins.should.have_property 'striped' + end + end +end \ No newline at end of file diff --git a/node_modules/jade/support/stylus/.npmignore b/node_modules/jade/support/stylus/.npmignore new file mode 100644 index 0000000..2ce29aa --- /dev/null +++ b/node_modules/jade/support/stylus/.npmignore @@ -0,0 +1,5 @@ +test +support +testing +docs +examples diff --git a/node_modules/jade/support/stylus/History.md b/node_modules/jade/support/stylus/History.md new file mode 100644 index 0000000..3c186ae --- /dev/null +++ b/node_modules/jade/support/stylus/History.md @@ -0,0 +1,231 @@ + +0.9.2 / 2011-03-21 +================== + + * Removed a `console.log()` call + +0.9.1 / 2011-03-18 +================== + + * Fixed connect middleware `@import` support. Closes #168 + The middleware is now smart enough to know when imports + change, and will re-compile the target file. + + * Changed middleware `compile` function to return the `Renderer` (API change) + +0.9.0 / 2011-03-18 +================== + + * Added `-i, --interactive` for the Stylus REPL (eval stylus expressions, tab-completion etc) + * Added link to vim syntax + * Changed `p()` built-in to display parens + * Changed `--compress -C` to `-c`, and `-css -c` is now `-C` + * Fixed; preserve rest-arg expressions. Closes #194 + * Fixed `*=` in selector, ex `[class*="foo"]` + * Fixed `--watch` issue with growl, updated to 1.1.0. Closes #188 + * Fixed negative floats when compressed. Closes #193 [reported by ludicco] + +0.8.0 / 2011-03-14 +================== + + * Added postfix `for`-loop support. + Ex: `return n if n % 2 == 0 for n in nums` + * Added support for several postfix operators + Ex: `border-radius: 5px if true unless false;` + * Added `last(expr)` built-in function + * Added `sum(nums)` built-in function + * Added `avg(nums)` built-in function + * Added `join(delim, vals)` built-in function + * Added `Evaluator#{currentScope,currentBlock}` + * Added multi-line function paramter definition support + * Changed; `0` is falsey, `0%`, `0em`, `0px` etc truthy. Closes #160 + * Fixed `for` implicit __return__ value + * Fixed `for` explicit __return__ value + * Fixed mixin property ordering + +0.7.4 / 2011-03-10 +================== + + * Added `RGBA` node + * Added `is a "color"` special-case, true for `HSLA` and `RGBA` nodes. +Closes #180 + * Performance; 2.5x faster compiles due to removing use of getters in `Parser` and `Lexer` (yes, they are really slow). + * Removed `Color` node + * Fixed stylus(1) `--watch` support due to dynamic __@import__ support. Closes #176 + +0.7.3 / 2011-03-09 +================== + + * Fixed; allow semi-colons for non-css syntax for one-liners + +0.7.2 / 2011-03-08 +================== + + * Added `isnt` operator, same as `is not`, and `!=` + * Added support for dynamic `@import` expressions + * Added `@import` index resolution support + * Added `light()` / `dark()` BIFs + * Added `compress` option for connect middleware [disfated] + * Changed; most built-in functions defined in stylus (`./lib/functions/index.styl`) + * Fixed dynamic expressions in `url()`. Closes #105 + +0.7.1 / 2011-03-07 +================== + + * Fixed connect middleware for 0.4.x + +0.7.0 / 2011-03-02 +================== + + * Added `is` and `is not` aliases for `==` and `!=` + * Added __@keyframes__ dynamic name support + * Fixed units in interpolation + * Fixed clamping of HSLA degrees / percentages + +0.6.7 / 2011-03-01 +================== + + * Fixed __RGBA__ -> __HSLA__ conversion due to typo + +0.6.6 / 2011-03-01 +================== + + * Added string -> unit type coercion support aka `5px + "10"` will give `15px` + * Added `warn` option Closes #152 + Currently this only reports on re-definition of functions + * Added '$' as a valid identifier character + * Added `mixin` local variable for function introspection capabilities. Closes #162 + * Fixed typo, `Unit#toBoolean()` is now correct + * Fixed interpolation function calls. Closes #156 + * Fixed mixins within Media node. Closes #153 + * Fixed function call in ret val. Closes #154 + +0.6.5 / 2011-02-24 +================== + + * Fixed parent ref `&` mid-selector bug. Closes #148 [reported by visnu] + +0.6.4 / 2011-02-24 +================== + + * Fixed for within brackets. Closes #146 + +0.6.3 / 2011-02-22 +================== + + * Fixed single-ident selectors. Closes #142 + * Fixed cyclic __@import__ with file of the same name. Closes #143 + +0.6.2 / 2011-02-21 +================== + + * Added stylus(1) growl support when using `--watch` + * Added __@import__ watching support to stylus(1). Closes #134 + * Changed; stylus(1) only throws when `--watch` is not used + * Fixed `darken-by()` BIF + * Fixed __@import__ literal semi-colon. Closes #140 + +0.6.1 / 2011-02-18 +================== + + * Fixed evaluation of nodes after a return. Closes #139 + +0.6.0 / 2011-02-18 +================== + + * Added `stylus(1)` direct css to stylus file conversion [Mario] + For example instead of `$ stylus --css < foo.css > foo.styl` + you may now either `$ stylus --css foo.css` or provide + a destination path `$ stylus --css foo.css /tmp/out.styl`. + + * Added postfix conditionals. Closes #74 + Expressive ruby-ish syntax, ex: `padding 5px if allow-padding`. + +0.5.3 / 2011-02-17 +================== + + * Added `in` operator. `3 in nums`, `padding in props` etc + * Added `Expression#hash`, hashing all of the nodes in order + * Added tests for conditionals with braces. Closes #136 + * Fixed ids that are also valid colors. Closes #137 + +0.5.2 / 2011-02-15 +================== + + * Fixed spaces after "}" with css-style. Closes #131 + * Fixed single-line css-style support. Closes #130 + +0.5.1 / 2011-02-11 +================== + + * Fixed mixin property ordering. Closes #125 + +0.5.0 / 2011-02-09 +================== + + * Added `lighten-by()` BIF + * Added `darken-by()` BIF + +0.4.1 / 2011-02-09 +================== + + * Added support for function definition braces + * Fixed issue with invalid color output. Closes #127 + +0.4.0 / 2011-02-07 +================== + + * Added css-style syntax support + * Fixed support for `*` selector within __@media__ blocks + +0.3.1 / 2011-02-04 +================== + + * Fixed property disambiguation logic. Closes #117 + You no longer need to add a trailing comma when + chaining selectors such as 'td:nth-child(2)\ntd:nth-child(3)' + +0.3.0 / 2011-02-04 +================== + + * Added more assignment operators. Closes #77 + +=, -=, *=, /=, and %= + +0.2.1 / 2011-02-02 +================== + + * Fixed `--compress` when passing files for stylus(1). Closes #115 + * Fixed bug preventing absolute paths from being passed to `@import` + * Fixed `opposite-position()` with nested expressions, unwrapping + * Fixed a couple global var leaks [aheckmann] + +0.2.0 / 2011-02-01 +================== + + * Added; `url()` utilizing general lookup paths. + This means that `{ paths: [] }` is optional now, as lookups + will be relative to the file being rendered by default. + + * Added `-w, --watch` support to stylus(1). Closes #113 + +0.1.0 / 2011-02-01 +================== + + * Added `opposite-position(positions)` built-in function + * Added `image-lookup(path)` built-in function + * Added `-o, --out ` support to stylus(1) + * Added `stylus [file|dir ...]` support + * Added; defaulting paths to `[CWD]` for stylus(1) + * Changed; `unquote()` using `Literal` node + * Changed; utilizing `Literal` in place of some `Ident`s + +0.0.2 / 2011-01-31 +================== + + * Added optional property colon support. Closes #110 + * Added `--version` to stylus(1) + +0.0.1 / 2011-01-31 +================== + + * Initial release \ No newline at end of file diff --git a/node_modules/jade/support/stylus/LICENSE b/node_modules/jade/support/stylus/LICENSE new file mode 100644 index 0000000..a206b68 --- /dev/null +++ b/node_modules/jade/support/stylus/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2010 LearnBoost + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/jade/support/stylus/Makefile b/node_modules/jade/support/stylus/Makefile new file mode 100644 index 0000000..40a5dc8 --- /dev/null +++ b/node_modules/jade/support/stylus/Makefile @@ -0,0 +1,20 @@ + +SRC = $(shell find lib -name "*.js") +TM_BUNDLE = editors/Stylus.tmbundle +TM_BUNDLE_DEST = ~/Library/Application\ Support/TextMate/Bundles + +test: test-integration + +test-integration: + @node test/run.js + +install-bundle: + cp -fr $(TM_BUNDLE) $(TM_BUNDLE_DEST) + +update-bundle: + cp -fr $(TM_BUNDLE_DEST)/Stylus.tmbundle editors + +benchmark: + @node bm.js + +.PHONY: test test-integration install-bundle update-bundle benchmark \ No newline at end of file diff --git a/node_modules/jade/support/stylus/Readme.md b/node_modules/jade/support/stylus/Readme.md new file mode 100644 index 0000000..d2e57a9 --- /dev/null +++ b/node_modules/jade/support/stylus/Readme.md @@ -0,0 +1,118 @@ + +# Stylus + + Stylus is a revolutionary new language, providing an efficient, dynamic, and expressive way to generate CSS. + +## Installation + + $ npm install stylus + +### Example + + border-radius() + -webkit-border-radius arguments + -moz-border-radius arguments + border-radius arguments + + body a + font 12px/1.4 "Lucida Grande", Arial, sans-serif + background black + color #ccc + + form input + padding 5px + border 1px solid + border-radius 5px + +compiles to: + + body a { + font: 12px/1.4 "Lucida Grande", Arial, sans-serif; + background: #000; + color: #ccc; + } + form input { + padding: 5px; + border: 1px solid; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + } + +### Features + + Stylus has _many_ features, click the links below for detailed documentation. + + - [css syntax](stylus/blob/master/docs/css-style.md) support + - [mixins](stylus/blob/master/docs/mixins.md) + - [variables](stylus/blob/master/docs/variables.md) + - [interpolation](stylus/blob/master/docs/interpolation.md) + - arithmetic, logical, and equality [operators](stylus/blob/master/docs/operators.md) + - [importing](stylus/blob/master/docs/import.md) of other stylus sheets + - [introspection api](stylus/blob/master/docs/introspection.md) + - type coercion + - [conditionals](stylus/blob/master/docs/conditionals.md) + - [iteration](stylus/blob/master/docs/iteration.md) + - nested [selectors](stylus/blob/master/docs/selectors.md) + - parent reference + - in-language [functions](stylus/blob/master/docs/functions.md) + - [variable arguments](stylus/blob/master/docs/vargs.md) + - built-in [functions](stylus/blob/master/docs/bifs.md) (over 25) + - optional [image inlining](stylus/blob/master/docs/functions.url.md) + - optional compression + - JavaScript [API](stylus/blob/master/docs/js.md) + - extremely terse syntax + - stylus [executable](stylus/blob/master/docs/executable.md) + - [error reporting](stylus/blob/master/docs/error-reporting.md) + - single-line and multi-line [comments](stylus/blob/master/docs/comments.md) + - css [literal](stylus/blob/master/docs/literal.md) + - character [escaping](stylus/blob/master/docs/escape.md) + - [@keyframes](stylus/blob/master/docs/keyframes.md) support + - [@font-face](stylus/blob/master/docs/font-face.md) support + - [@media](stylus/blob/master/docs/media.md) support + - Connect [Middleware](stylus/blob/master/docs/middleware.md) + - TextMate [bundle](stylus/blob/master/docs/textmates.md) + - VIM [Syntax](https://github.com/wavded/vim-stylus) + +### Framework Support + + - [Connect](stylus/blob/master/docs/middleware.md) + - [Ruby On Rails](https://github.com/lucasmazza/stylus_rails) + +### Screencasts + + - [Stylus Intro](http://screenr.com/bNY) + - [CSS Syntax & Postfix Conditionals](http://screenr.com/A8v) + +### Authors + + - [TJ Holowaychuk (visionmedia)](http://github.com/visionmedia) + +### More Information + + - Language [comparisons](stylus/blob/master/docs/compare.md) + +## License + +(The MIT License) + +Copyright (c) 2010 LearnBoost <dev@learnboost.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/jade/support/stylus/bin/stylus b/node_modules/jade/support/stylus/bin/stylus new file mode 100755 index 0000000..f9a5008 --- /dev/null +++ b/node_modules/jade/support/stylus/bin/stylus @@ -0,0 +1,456 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var fs = require('fs') + , stylus = require('../') + , basename = require('path').basename + , dirname = require('path').dirname + , join = require('path').join + , growl = require('growl'); + +/** + * Arguments. + */ + +var args = process.argv.slice(2); + +/** + * Compare flag. + */ + +var compare = false; + +/** + * Compress flag. + */ + +var compress = false; + +/** + * CSS conversion flag. + */ + +var convertCSS = false; + +/** + * Files to processes. + */ + +var files = []; + +/** + * Destination directory. + */ + +var dest; + +/** + * Watcher hash. + */ + +var watchers; + +/** + * Enable REPL. + */ + +var interactive; + +/** + * Usage docs. + */ + +var usage = [ + '' + , ' Usage: stylus [options] [command] [< in [> out]]' + , ' [file|dir ...]' + , '' + , ' Commands:' + , '' + , ' help Opens help info for in' + , ' your default browser. (osx only)' + , '' + , ' Options:' + , '' + , ' -i, --interactive Start interactive REPL' + , ' -w, --watch Watch file(s) for changes and re-compile' + , ' -o, --out Output to when passing files' + , ' -C, --css [dest] Convert css input to stylus' + , ' -c, --compress Compress css output' + , ' -d, --compare Display input along with output' + , ' -V, --version Display the version of stylus' + , ' -h, --help Display help information' + , '' +].join('\n'); + +/** + * Handle arguments. + */ + +var arg; +while (args.length) { + arg = args.shift(); + switch (arg) { + case '-h': + case '--help': + console.log(usage); + process.exit(1); + case '-d': + case '--compare': + compare = true; + break; + case '-c': + case '--compress': + compress = true; + break; + case '-C': + case '--css': + convertCSS = true; + break; + case '-V': + case '--version': + console.log(stylus.version); + process.exit(0); + break; + case '-o': + case '--out': + dest = args.shift(); + if (!dest) throw new Error('--out required'); + break; + case 'help': + var name = args.shift(); + if (!name) throw new Error('help required'); + help(name); + break; + case '-i': + case '--repl': + case '--interactive': + interactive = true; + break; + case '-w': + case '--watch': + watchers = {}; + break; + default: + files.push(arg); + } +} + +// if --watch is used, assume we are +// not working with stdio + +if (watchers && !files.length) { + files = fs.readdirSync(process.cwd()) + .filter(function(file){ + return file.match(/\.styl$/); + }); +} + +/** + * Open the default browser to the CSS property `name`. + * + * @param {String} name + */ + +function help(name) { + var url = 'https://developer.mozilla.org/en/CSS/' + name + , exec = require('child_process').exec; + exec('open "' + url + '"', function(){ + process.exit(0); + }); +} + +// Compilation options + +var options = { + filename: 'stdin' + , compress: compress + , paths: [process.cwd()] +}; + +// Buffer stdin + +var str = ''; + +// Convert css to stylus + +if (convertCSS) { + switch (files.length) { + case 2: + compileCSSFile(files[0], files[1]); + break; + case 1: + compileCSSFile(files[0], files[0].replace('.css', '.styl')); + break; + default: + var stdin = process.openStdin(); + stdin.setEncoding('utf8'); + stdin.on('data', function(chunk){ str += chunk; }); + stdin.on('end', function(){ + var out = stylus.convertCSS(str); + console.log(out); + }); + } +} else if (interactive) { + repl(); +} else { + if (files.length) { + compileFiles(files); + } else { + compileStdio(); + } +} + +/** + * Start stylus REPL. + */ + +function repl() { + var options = { filename: 'stdin', imports: [__dirname + '/../lib/functions'] } + , parser = new stylus.Parser('', options) + , evaluator = new stylus.Evaluator(parser.parse(), options) + , rl = require('readline') + , repl = rl.createInterface(process.stdin, process.stdout, true) + , global = evaluator.global.scope; + + // expose BIFs + evaluator.evaluate(); + + // readline + repl.setPrompt('> '); + repl.prompt(); + + // HACK: flat-list auto-complete + repl._tabComplete = function(){ + var out = this.output + , line = this.line + , keys = Object.keys(global.locals) + , len = keys.length + , words = line.split(/\s+/) + , word = words.pop() + , names = [] + , name + , obj + , key; + + // find words that match + for (var i = 0; i < len; ++i) { + key = keys[i]; + if (0 == key.indexOf(word)) { + names.push(key); + } + } + + // several candidates + if (names.length > 1) { + out.write('\r\n\r\n\033[90m'); + names.forEach(function(name){ + var node = global.lookup(name); + switch (node.nodeName) { + case 'function': + out.write(' - ' + node + '\r\n'); + break; + default: + out.write(' - ' + name + '\r\n'); + } + }); + out.write('\r\n\033[0m'); + this._refreshLine(); + // single candidate + } else if (names.length) { + name = names.pop(); + obj = global.lookup(name); + name = name.replace(word, ''); + switch (obj.nodeName) { + case 'function': + this._insertString(name + '()'); + this.cursor--; + break; + default: + this._insertString(name); + } + this._refreshLine(); + } + }; + + repl.on('line', function(line){ + if (!line.trim().length) return repl.prompt(); + parser = new stylus.Parser(line, options); + parser.state.push('expression'); + evaluator.return = true; + try { + var expr = parser.parse(); + var ret = evaluator.visit(expr); + ret = ret.nodes[ret.nodes.length - 1]; + ret = ret.toString(); + if ('(' == ret[0]) ret = ret.replace(/^\(|\)$/g, ''); + console.log('\033[90m=> \033[0m' + highlight(ret)); + repl.prompt(); + } catch (err) { + console.error('\033[31merror: %s\033[0m', err.message || err.stack); + repl.prompt(); + } + }); + + repl.on('SIGINT', function(){ + console.log(); + process.exit(0); + }); +} + +/** + * Highlight the given string of stylus. + */ + +function highlight(str) { + return str + .replace(/(#)?(\d+(\.\d+)?)/g, function($0, $1, $2){ + return $1 ? $0 : '\033[36m' + $2 + '\033[0m'; + }) + .replace(/(#[\da-fA-F]+)/g, '\033[33m$1\033[0m') + .replace(/('.*?'|".*?")/g, '\033[32m$1\033[0m'); +} + +/** + * Convert a CSS file to a Styl file + */ + +function compileCSSFile(file, fileOut) { + fs.lstat(file, function(err, stat){ + if (err) throw err; + if (stat.isFile()) { + fs.readFile(file, 'utf8', function(err, str){ + if (err) throw err; + var styl = stylus.convertCSS(str); + fs.writeFile(fileOut, styl, function(err){ + if (err) throw err; + }); + }); + } + }); +} + +/** + * Compile with stdio. + */ + +function compileStdio() { + var stdin = process.openStdin(); + stdin.setEncoding('utf8'); + stdin.on('data', function(chunk){ str += chunk; }); + stdin.on('end', function(){ + // Compile to css + stylus(str, options).render(function(err, css){ + if (err) throw err; + if (compare) { + console.log('\n\x1b[1mInput:\x1b[0m'); + console.log(str); + console.log('\n\x1b[1mOutput:\x1b[0m'); + } + console.log(css); + if (compare) console.log(); + }); + }); +} + +/** + * Compile the given files. + */ + +function compileFiles(files) { + files.forEach(compileFile); +} + +/** + * Compile the given file. + */ + +function compileFile(file) { + // ensure file exists + fs.lstat(file, function(err, stat){ + if (err) throw err; + // file + if (stat.isFile()) { + fs.readFile(file, 'utf8', function(err, str){ + if (err) throw err; + options.filename = file; + options._imports = []; + stylus(str, options).render(function(err, css){ + watchImports(file, options._imports); + if (err) { + if (watchers) { + console.error(err.stack || err.message); + growl.notify(err.message, { title: 'Stylus error' }); + } else { + throw err; + } + } else { + writeFile(file, css); + } + }); + }); + // directory + } else if (stat.isDirectory()) { + fs.readdir(file, function(err, files){ + if (err) throw err; + files.filter(function(path){ + return path.match(/\.styl$/); + }).map(function(path){ + return file + '/' + path; + }).forEach(compileFile); + }); + } + }); +} + +/** + * Write the given css output. + */ + +function writeFile(file, css) { + // --out support + var path = dest + ? dest + '/' + basename(file, '.styl') + '.css' + : file.replace('.styl', '.css'); + fs.writeFile(path, css, function(err){ + if (err) throw err; + console.log(' \033[90mcompiled\033[0m %s', path); + // --watch support + watch(file, compileFile); + }); +} + +/** + * Watch the given `file` and invoke `fn` when modified. + */ + +function watch(file, fn) { + // not watching + if (!watchers) return; + + // already watched + if (watchers[file]) return; + + // watch the file itself + watchers[file] = true; + console.log(' \033[90mwatching\033[0m %s', file); + fs.watchFile(file, { interval: 50 }, function(curr, prev){ + if (curr.mtime > prev.mtime) fn(file); + }); +} + +/** + * Watch `imports`, re-compiling `file` when they change. + */ + +function watchImports(file, imports) { + imports.forEach(function(import){ + if (!import.path) return; + watch(import.path, function(){ + compileFile(file); + }); + }); +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/bin/stylus-tutorial b/node_modules/jade/support/stylus/bin/stylus-tutorial new file mode 100755 index 0000000..5ab1c61 --- /dev/null +++ b/node_modules/jade/support/stylus/bin/stylus-tutorial @@ -0,0 +1,287 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +try { + var stylus = require('stylus'); +} catch (err) { + var stylus = require('../lib/stylus'); +} + +/** + * Banner. + */ + +var banner = '\n\ + \n\ + _ _ \n\ + ___| |_ _ _| |_ _ ___ \n\ + / __| __| | | | | | | / __| \n\ + \\__ \\ |_| |_| | | |_| \\__ \\ \n\ + |___/\\__|\\__, |_|\\__,_|___/ \n\ + |___/ \n\ + \n\ +'; + +/** + * Steps. + */ + +var steps = []; + +/** + * Clear the screen and move the cursor up. + */ + +function clear() { + console.log('\x1b[1J\x1b[H'); +} + +/** + * Output "press enter" message. + */ + +function enter() { + process.stdout.write('\x1b[90mpress enter to continue:\x1b[0m '); +} + +/** + * Initialize a `Step` with the given data. + * + * @param {String} title + * @param {String} desc + * @param {String} src + * @param {Function} fn + */ + +function Step(title, desc, src, fn) { + var self = this; + this.n = steps.length; + this.src = src; + desc = desc.replace(/\_([^_]+)\_/g, '\x1b[33m$1\x1b[90m'); + + this.next = function(){ + var step = steps[self.n + 1]; + if (step) { + step.display(); + } else { + console.log(' THE END\n'); + process.exit(0); + } + }; + + this.display = function(retry){ + if (!retry) { + console.log(' %d) \x1b[1m%s\x1b[0m\n', self.n, title); + console.log(' \x1b[90m%s\x1b[0m', desc); + } + console.log('\n%s\n', src); + console.log('\x1b[90m--------------------\x1b[0m \n'); + this.input(); + }; + + this.input = function(){ + stdin.resume(); + var buf = ''; + stdin.on('data', function callback(chunk){ + if (0 == chunk.indexOf('quit')) process.exit(1); + var dot = '.' == chunk[0] && '\n' == chunk[1] + , equal = buf.trim() == self.src.trim(); + if (dot || equal) { + stdin.pause(); + stdin.removeListener('data', callback); + stylus.render(buf, { filename: 'stdin' }, function(err, css){ + if (err) { + console.log('\n\x1b[31mError: ' + err.message + '\x1b[0m\n'); + self.display(true); + return; + } + clear(); + console.log('\x1b[90m-------------------- stylus\x1b[0m \n'); + console.log(buf.replace(/^/gm, ' ')); + console.log('\x1b[90m-------------------- css\x1b[0m \n'); + console.log(css.replace(/^/gm, ' ')); + console.log(); + enter(); + stdin.resume(); + stdin.once('data', function(){ + clear(); + self.next(); + }); + }); + return; + } + buf += chunk; + }); + }; +} + +/** + * Step definitions. + */ + +steps.push(new Step( + 'Selector Properties' + , 'The Stylus grammar has indentation-based blocks,\n' + + ' meaning one does not surround selector properties\n' + + ' using braces _{_ _}_, but uses an indent of two \n' + + ' spaces, or a single tab.\n' + + '\n' + + ' To get started, type the stylus you see below\n' + + ' and then press return a few times or type _"."_ to render.' + , 'body\n color black')); + +steps.push(new Step( + 'Multiple Selectors' + , 'Blocks can be applied to several selectors at once\n' + + ' by separating them via comma, or newline.\n' + + '\n' + + ' Both examples shown below are equivalent.' + + , 'a.button, input[type=button]\n' + + ' border 1px solid #eee\n' + + ' padding 5px\n\n' + + 'a.button\n' + + 'input[type=button]\n' + + ' border 1px solid #eee\n' + + ' padding 5px' + )); + +steps.push(new Step( + 'Nested Selectors' + , 'Selectors may also be nested.\n' + + , 'ul\n' + + ' li\n' + + ' a\n' + + ' color black\n' + )); + +steps.push(new Step( + 'Variables' + , 'Stylus allows you to define variables by utilizing\n' + + ' the _=_ operator, much like you would in any other language.\n' + + '\n' + + ' These variables may be assigned to _numbers_, _strings_, _booleans_,\n' + + ' and virtually everything else you see in css.' + + , 'size = 14px\n\n' + + 'body\n' + + ' font size Arial, sans-serif' + )); + +steps.push(new Step( + 'Conditional Assignment' + , 'The conditional assignment operator _?=_ may be used to\n' + + ' define a variable only when previously undefined.' + + , 'size = 14px\n\n' + + 'body\n' + + ' size ?= 22px\n' + + ' font size Arial, sans-serif' + )); + +steps.push(new Step( + 'Arithmetic' + , 'A variety of binary arithmetic operators are supported\n' + + ' as well as unary operators such as _-_, _+_, and _~_.' + + , 'size = 14px\n' + + 'large-size = size * 2\n' + + '\n' + + 'body\n' + + ' font large-size\n' + + '\n' + + 'p\n' + + ' margin-left -(size - 2)' + )); + +steps.push(new Step( + 'Coercion' + , 'Arithmetic operations coerce the right-hand operand when\n' + + ' applicable, for example converting _2s_ in _1000ms + 2s_\n' + + ' into _2000ms_ before evaluating the expression.\n' + + '\n' + + ' Examples:\n' + + ' _15px_ - _5_\n' + + ' _#000_ + _#eee_\n' + + ' _#fff_ - rgba(_0_,_0_,_0_,_.5_)\n' + + ' _#fff_ / _2_\n' + + ' _5in_ - _3cm_\n' + + , 'duration = 2s\n\n' + + '.fade\n' + + ' -webkit-transition opacity duration - 1500ms linear' + )); + +steps.push(new Step( + 'Functions' + , 'Stylus functions may act as mixins or have a return value.\n' + + 'For example here we use the unit() built-in function to.\n' + + 'forcing both unit\'s type to _px_, and then add them.\n' + + '\n' + + 'Note that we may also use the _return_ keyword, however it\n' + + 'is optional in most cases.' + + , 'add(a, b)\n' + + ' a = unit(a, "px")\n' + + ' b = unit(b, "px")\n' + + ' a + b\n' + + '\n' + + 'body\n' + + ' padding add(5px, 10px)\n' + + ' margin add(5, 10)' + )); + +steps.push(new Step( + 'Mixins' + , 'Mixins are defined in the same manner as functions\n' + + 'with return values, however they "mix in" their properties\n' + + 'and selectors into the caller.\n' + + '\n' + + 'Mixin parens are optional in most cases, so we may apply\n' + + 'the transparently.' + + , 'border-radius(n)\n' + + ' -webkit-border-radius n\n' + + ' -moz-border-radius n\n' + + ' border-radius n\n' + + '\n' + + 'body\n' + + ' border-radius(5px)\n' + + '\n' + + 'form input\n' + + ' border-radius 5px' + )); + +/** + * Start tutorial. + */ + +clear(); +console.log('\x1b[1m' + banner + '\x1b[0m'); +console.log('\n Welcome to the stylus interactive tutorial.\n'); +console.log(' - To quit at any time type \x1b[1mquit\x1b[0m.'); +console.log(' - To force rendering type "." and press enter,'); +console.log(' however source will be automatically rendered'); +console.log(' when it matches the step\'s source.'); +console.log(); +enter(); + +var stdin = process.openStdin(); +stdin.setEncoding('utf8'); + +stdin.once = function(event, fn){ + this.on(event, function callback(chunk){ + stdin.removeListener(event, callback); + fn(chunk); + }); +}; + +stdin.once('data', function(chunk){ + stdin.pause(); + clear(); + steps[0].display(); +}); diff --git a/node_modules/jade/support/stylus/bm.js b/node_modules/jade/support/stylus/bm.js new file mode 100644 index 0000000..ce1acfa --- /dev/null +++ b/node_modules/jade/support/stylus/bm.js @@ -0,0 +1,22 @@ + +/** + * Module dependencies. + */ + +var stylus = require('./'); + +var times = 200 + , n = times + , start = new Date; + +console.log('compiling %d times', times); + +while (n--) { + stylus('body\n color: white;\n background: url(/images/foo.png)\n a\n &:hover\n text-decoration: underline;') + .render(function(err, css){}); +} + +var duration = new Date - start; +console.log(' duration: %dms', duration); +console.log(' average: %dms', duration / times); +console.log(' per second: %d', (times / (duration / 1000)).toFixed(1)); diff --git a/node_modules/jade/support/stylus/docs/bifs.md b/node_modules/jade/support/stylus/docs/bifs.md new file mode 100644 index 0000000..75e599f --- /dev/null +++ b/node_modules/jade/support/stylus/docs/bifs.md @@ -0,0 +1,453 @@ + +## Built-in Functions + +### red(color) + +Return the red component of the given `color`. + + red(#c00) + // => 204 + +### green(color) + +Return the green component of the given `color`. + + green(#0c0) + // => 204 + +### blue(color) + +Return the blue component of the given `color`. + + red(#00c) + // => 204 + +### alpha(color) + +Return the alpha component of the given `color`. + + alpha(#fff) + // => 1 + + alpha(rgba(0,0,0,0.3)) + // => 0.3 + +### dark(color) + +Check if `color` is dark: + + dark(black) + // => true + + dark(#005716) + // => true + + dark(white) + // => false + + +### light(color) + +Check if `color` is light: + + light(black) + // => false + + light(white) + // => true + + light(#00FF40) + // => true + +### hue(color) + +Return the hue of the given `color`. + + hue(hsla(50deg, 100%, 80%)) + // => 50deg + +### saturation(color) + +Return the saturation of the given `color`. + + hue(hsla(50deg, 100%, 80%)) + // => 100% + +### lightness(color) + +Return the lightness of the given `color`. + + hue(hsla(50deg, 100%, 80%)) + // => 80% + +### typeof(node) + +Return type of `node` as a string. + + type(12) + // => 'unit' + + typeof(12) + // => 'unit' + + typeof(#fff) + // => 'rgba' + + type-of(#fff) + // => 'rgba' + +Aliased as `type-of` and `type`. + +### unit(unit[, type]) + +Return a string for the type of `unit` or an empty string, +or assign the given `type` without unit conversion. + + unit(10) + // => '' + + unit(15in) + // => 'in' + + unit(15%, 'px') + // => 15px + + unit(15%, px) + // => 15px + +### match(pattern, string) + +Test if `string` matches the given `pattern`. + + match('^foo(bar)?', foo) + match('^foo(bar)?', foobar) + // => true + + match('^foo(bar)?', 'foo') + match('^foo(bar)?', 'foobar') + // => true + + match('^foo(bar)?', 'bar') + // => false + +### abs(unit) + + abs(-5px) + // => 5px + + abs(5px) + // => 5px + +### ceil(unit) + + ceil(5.5in) + // => 6in + +### floor(unit) + + floor(5.6px) + // => 5px + +### round(unit) + + round(5.5px) + // => 6px + + round(5.4px) + // => 5px + +### min(a, b) + + min(1, 5) + // => 1 + +### max(a, b) + + max(1, 5) + // => 5 + +### even(unit) + + even(6px) + // => true + +### odd(unit) + + odd(5mm) + // => true + +### sum(nums) + + sum(1 2 3) + // => 6 + +### avg(nums) + + avg(1 2 3) + // => 2 + +### join(delim, vals...) + + Join the given `vals` with `delim`. + + join(' ', 1 2 3) + // => "1 2 3" + + join(',', 1 2 3) + // => "1,2,3" + + join(', ', foo bar baz) + // => "foo, bar, baz" + + join(', ', foo, bar, baz) + // => "foo, bar, baz" + +### hsla(color | h[, s, l, a]) + +Convert the given `color` to an `HSLA` node, +or h,s,l,a component values. + + hslaa(10deg, 50%, 30%, 0.5) + // => HSLA + + hslaa(#ffcc00) + // => HSLA + +### hsla(color | h[, s, l]) + +Convert the given `color` to an `HSLA` node, +or h,s,l component values. + + hsla(10, 50, 30) + // => HSLA + + hsla(#ffcc00) + // => HSLA + +### rgba(color | r[, g, b, a]) + +Return `RGBA` from the r,g,b,a channels or provide a `color` to tweak the alpha. + + rgba(255,0,0,0.5) + // => rgba(255,0,0,0.5) + + rgba(255,0,0,1) + // => #ff0000 + + rgba(#ffcc00, 0.5) + // rgba(255,204,0,0.5) + +### rgb(color | r[, g, b]) + +Return a `RGBA` from the r,g,b channels or cast to an `RGBA` node. + + rgb(255,204,0) + // => #ffcc00 + + rgb(#fff) + // => #fff + +### lighten(color, amount) + +Lighten the given `color` by `amount`. + + lighten(black, 50%) + // => #808080 + +### darken(color, amount) + +Darken the given `color` by `amount`. + + darken(white, 50%) + // => #808080 + +### lighten-by(color, amount) + + Lighten by `amount` of the current lightness value. + + lighten-by(black, 50%) + // => #808080 + + lighten-by(lighten-by(black, 50%), 50%) + // => #bfbfbf + + lighten-by(lighten-by(lighten-by(black, 50%), 50%), 50%) + // => #fff + +essentially the same as: + + black + hsla(0,0,50%) + black + hsla(0,0,75%) + black + hsla(0,0,100%) + +### darken-by(color, amount) + + Darken by `amount` of the current lightness value. + + darken-by(white, 50%) + // => #808080 + + darken-by(darken-by(white, 50%), 50%) + // => #404040 + + darken-by(darken-by(darken-by(white, 50%), 50%), 50%) + // => #202020 + +### desaturate(color, amount) + +Desaturate the given `color` by `amount`. + + desaturate(#f00, 40%) + // => #c33 + +### saturate(color, amount) + +Saturate the given `color` by `amount`. + + saturate(#c33, 40%) + // => #f00 + +### unquote(str | ident) + + Unquote the given `str` and returned as a `Literal` node. + + unquote("sans-serif") + // => sans-serif + + unquote(sans-serif) + // => sans-serif + + unquote('1px / 2px') + // => 1px / 2px + +### operate(op, left, right) + + Perform the given `op` on the `left` and `right` operands: + + op = '+' + operate(op, 15, 5) + // => 20 + +### length([expr]) + + Parenthesized expressions may act as tuples, the `length()` function returns the length of such expressions. + + length((1 2 3 4)) + // => 4 + + length((1 2)) + // => 2 + + length((1)) + // => 1 + + length(()) + // => 0 + + length(1 2 3) + // => 3 + + length(1) + // => 1 + + length() + // => 0 + +### warn(msg) + + Warn with the given error `msg`, does not exit. + + warn("oh noes!") + +### error(msg) + + Exits with the given error `msg`. + + add(a, b) + unless a is a 'unit' and b is a 'unit' + error('add() expects units') + a + b + +### last(expr) + + Return the _last_ value in the given `expr`: + + nums = 1 2 3 + last(nums) + last(1 2 3) + // => 3 + + list = (one 1) (two 2) (three 3) + last(list) + // => (three 3) + +### p(expr) + + Inspect the given `expr`: + + fonts = Arial, sans-serif + p('test') + p(123) + p((1 2 3)) + p(fonts) + p(#fff) + p(rgba(0,0,0,0.2)) + + add(a, b) + a + b + + p(add) + +stdout: + + inspect: "test" + inspect: 123 + inspect: 1 2 3 + inspect: Arial, sans-serif + inspect: #fff + inspect: rgba(0,0,0,0.2) + inspect: add(a, b) + +### opposite-position(positions) + + Return the opposites of the given `positions`. + + opposite-position(right) + // => left + + opposite-position(top left) + // => bottom right + + opposite-position('top' 'left') + // => bottom right + +### image-size(path) + + Returns the `width` and `height` of the image found at `path`. Lookups are performed in the same manner as `@import`, altered by the `paths` setting. + + width(img) + return image-size(img)[0] + + height(img) + return image-size(img)[1] + + image-size('tux.png') + // => 405px 250px + + image-size('tux.png')[0] == width('tux.png') + // => true + +### Undefined Functions + + Undefined functions will output as literals, so for example + we may call `rgba-stop(50%, #fff)` within our css, and it will + output as you would expect. We can use this within helpers as well. + + In the example below we simply define the function `stop()` which + returns the literal `rgba-stop()` call. + + stop(pos, rgba) + rgba-stop(pos, rgba) + + stop(50%, orange) + // => rgba-stop(50%, #ffa500) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/comments.md b/node_modules/jade/support/stylus/docs/comments.md new file mode 100644 index 0000000..37e9be2 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/comments.md @@ -0,0 +1,17 @@ + +## Comments + + Stylus supports two kinds of comments, single-line, and multi-line comments, using the same syntax found in JavaScript. + + + // I'm a comment! + body + padding 5px // some awesome padding + + + /* + * Adds the given numbers together. + */ + + add(a, b) + a + b \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/compare.md b/node_modules/jade/support/stylus/docs/compare.md new file mode 100644 index 0000000..e823b3d --- /dev/null +++ b/node_modules/jade/support/stylus/docs/compare.md @@ -0,0 +1,81 @@ + +## Implementation Comparisons + +Below we go head to head with other implementations. + +### Variables + +SCSS: + + $main-color: #006; + color: $main-color; + +Less: + + @main-color: #006; + color: @main-color; + +Stylus: + + main-color = #006 + color main-color + +### Mixins + +SCSS: + + @mixin pad($x, $y) { + padding: $y $x; + } + + .msg { + @include pad(5px, 10px); + } + +Less: + + .pad(@x, @y) { + padding: @y @x; + } + + .msg { + .pad(5px, 10px); + } + +Stylus: + + pad(x, y) + padding y x + + .msg + pad(5px, 10px) + +### Larger Example + +Less: + + .box-shadow (@x: 0, @y: 0, @blur: 1px, @alpha) { + @val: @x @y @blur rgba(0, 0, 0, @alpha); + box-shadow: @val; + -webkit-box-shadow: @val; + -moz-box-shadow: @val; + } + .box { + @base: #f938ab; + color: saturate(@base, 5%); + border-color: lighten(@base, 30%); + div { .box-shadow(0, 0, 5px, 0.4) } + } + +Stylus: + box-shadow() + -webkit-box-shadow arguments + -moz-box-shadow arguments + box-shadow arguments + + .box + base = #f938ab + color saturate(base, 5%) + border-color lighten(base, 30%) + div + box-shadow 0 0 5px 0.4 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/conditionals.md b/node_modules/jade/support/stylus/docs/conditionals.md new file mode 100644 index 0000000..8d6d322 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/conditionals.md @@ -0,0 +1,107 @@ + +## Conditionals + + Conditionals provide control flow to a language which is otherwise static, providing conditional imports, mixins, functions, and more. The examples below are simply examples, and not recommended :) + +### if / else if / else + + The `if` conditional works as you would expect, simply accepting an expression, evaluating the following block when `true`. Along with `if` are the typical `else if` and `else` tokens, acting as fallbacks. + + The example below would conditionally overload the `padding` property, swapping it for margin. + + overload-padding = true + + if overload-padding + padding(y, x) + margin y x + + body + padding 5px 10px + +Another example: + + box(x, y, margin = false) + padding y x + if margin + margin y x + + body + box(5px, 10px, true) + +Another `box()` helper: + + box(x, y, margin-only = false) + if margin-only + margin y x + else + padding y x + +### unless + + For users familiar with the ruby programming language, we have the `unless` conditional, which is essentially the opposite of `if`, essentially `if (!(expr))`. + +In the example below, if `disable-padding-override` is undefined or `false` padding will be overridden, displaying `margin` instead. However when `true` padding will remain outputting `padding 5px 10px` as expected. + + disable-padding-override = true + + unless disable-padding-override is defined and disable-padding-override + padding(x, y) + margin y x + + body + padding 5px 10px + +### Postfix Conditionals + + Stylus supports postfix conditionals, meaning the `if` and `unless` act as operators, evaluating the left-hand operand, when the right-hand expression is truthy. + + + For example let's define `negative()`, performing some basic type checking. Below we use block-style conditionals: + + negative(n) + unless n is a 'unit' + error('invalid number') + if n < 0 + yes + else + no + + Next we utilize postfix conditionals to keep our function terse. + + negative(n) + error('invalid number') unless n is a 'unit' + return yes if n < 0 + no + + Of course we could take this further, and utilize `n < 0 ? yes : no`, or simply stick with booleans, and use only `n < 0`. + + Postfix conditionals may be applied to most single-line statements, for example `@import`, `@charset`, mixins, and of course properties as shown below: + + + pad(types = margin padding, n = 5px) + padding unit(n, px) if padding in types + margin unit(n, px) if margin in types + + body + pad() + + body + pad(margin) + + body + apply-mixins = true + pad(padding, 10) if apply-mixins + +yielding: + + body { + padding: 5px; + margin: 5px; + } + body { + margin: 5px; + } + body { + padding: 10px; + } + diff --git a/node_modules/jade/support/stylus/docs/css-style.md b/node_modules/jade/support/stylus/docs/css-style.md new file mode 100644 index 0000000..3d433c4 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/css-style.md @@ -0,0 +1,77 @@ + +## CSS Style + + Stylus transparently supports a regular css-style syntax, meaning you do not need to use an alternative parser, or specify that a certain file is using a specific style. + +### Example + + Below is a small style using the indented approach: + + border-radius() + -webkit-border-radius arguments + -moz-border-radius arguments + border-radius arguments + + body a + font 12px/1.4 "Lucida Grande", Arial, sans-serif + background black + color #ccc + + form input + padding 5px + border 1px solid + border-radius 5px + + Since braces, colons, and semi-colons are optional, we could write this example just as we would with normal css: + + border-radius() { + -webkit-border-radius: arguments; + -moz-border-radius: arguments; + border-radius: arguments; + } + + body a { + font: 12px/1.4 "Lucida Grande", Arial, sans-serif; + background: black; + color: #ccc; + } + + form input { + padding: 5px; + border: 1px solid; + border-radius: 5px; + } + + Since we may mix and match the two variants, the following is valid as well: + + border-radius() + -webkit-border-radius: arguments; + -moz-border-radius: arguments; + border-radius: arguments; + + body a { + font: 12px/1.4 "Lucida Grande", Arial, sans-serif; + background: black; + color: #ccc; + } + + form input + padding: 5px; + border: 1px solid; + border-radius: 5px; + + Variables, functions, mixins, and all of the other features that Stylus provides still work as expected: + + main-color = white + main-hover-color = black + + body a { + color: main-color; + &:hover { color: main-hover-color; } + } + + body a { color: main-color; &:hover { color: main-hover-color; }} + + There are currently a few exceptions to this rule, since the two styles may be mixed and matched some indentation rules still apply. So although not _every_ plain-css stylesheet will work without modification this feature still allows those who prefer css syntax may still utilize the other powerful features provided by Stylus. + + diff --git a/node_modules/jade/support/stylus/docs/error-reporting.md b/node_modules/jade/support/stylus/docs/error-reporting.md new file mode 100644 index 0000000..5b2def2 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/error-reporting.md @@ -0,0 +1,50 @@ + +## Error Reporting + + Stylus has fantastic error reporting built in for syntax, parse, and evaluation errors, complete with stack traces, line numbers, and filenames. + +### Parse Error + +Parse error example: + + body + form input + == padding 5px + +yielding: + + Error: /Users/tj/Projects/stylus/testing/test.styl:4 + 3: ' form input' + 4: ' == padding 5px' + + illegal unary == + +### Evaluation Error + + This "runtime" or evaluation error is caused due to passing a string to `border-radius()` instead of the expected `Unit` by using our helper `ensure(n, 'unit')`. + + ensure(val, type) + unless val is a type + error('expected a ' + type + ', but got ' + typeof(val)) + + border-radius(n) + ensure(n, 'unit') + -webkit-border-radius n + -moz-border-radius n + border-radius n + + body + border-radius '5px' + +yielding: + + Error: /Users/tj/Projects/stylus/examples/error.styl:12 + 11: '' + 12: 'body' + 13: ' border-radius \'5px\'' + 14: '' + + expected a unit, but got string + at ensure() (/Users/tj/Projects/stylus/examples/error.styl:2) + at border-radius() (/Users/tj/Projects/stylus/examples/error.styl:5) + at "body" (/Users/tj/Projects/stylus/examples/error.styl:10) diff --git a/node_modules/jade/support/stylus/docs/escape.md b/node_modules/jade/support/stylus/docs/escape.md new file mode 100644 index 0000000..f2d7348 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/escape.md @@ -0,0 +1,27 @@ + +## Escaping + + Stylus allows you to escape characters, effectively turning them into identifiers, so that they can be rendered as literals. For example: + + body + padding 1 \+ 2 + +will compile to: + + body { + padding: 1 + 2; + } + + +Not that Stylus requires that `/` is parenthesized when used in a property: + + body + font 14px/1.4 + font (14px/1.4) + +yields: + + body { + font: 14px/1.4; + font: 10px; + } \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/executable.md b/node_modules/jade/support/stylus/docs/executable.md new file mode 100644 index 0000000..2303a6d --- /dev/null +++ b/node_modules/jade/support/stylus/docs/executable.md @@ -0,0 +1,92 @@ + +## Stylus Executable + +Stylus ships with the `stylus` executable for converting stylus to css. + + Usage: stylus [options] [command] [< in [> out]] + [file|dir ...] + + Commands: + + help Opens help info for in + your default browser. (osx only) + + Options: + + -i, --interactive Start interactive REPL + -w, --watch Watch file(s) for changes and re-compile + -o, --out Output to when passing files + -C, --css [dest] Convert css input to stylus + -c, --compress Compress css output + -d, --compare Display input along with output + -V, --version Display the version of stylus + -h, --help Display help information + +### STDIO Compilation Example + + `stylus` reads from _stdin_ and outputs to _stdout_, so for example: + + $ stylus --compress < some.styl > some.css + +Try stylus some in the terminal, type below and press CTRL-D for __EOF__: + + $ stylus + body + color red + font 14px Arial, sans-serif + +### Compiling Files Example + + `stylus` also accepts files and directories, for example a directory named `css` will compile and output the `.css` files in the same directory. + + $ stylus css + + The following will output to `./public/stylesheets`: + + $ stylus css --out public/stylesheets + + Or a few files: + + $ stylus one.styl two.styl + +### Converting CSS + + If we wish to convert css to the terse Stylus syntax, we can utilize the `--css` flag. + + Via stdio: + + $ stylus --css < test.css > test.styl + + Output a `.styl` file of the same basename: + + $ stylus --css test.css + + Output to a specific destination: + + $ stylus --css test.css /tmp/out.styl + +### CSS Property Help + + On osx `stylus help ` will open your default browser and display help documentation for the given ``. + + $ stylus help box-shadow + +### Interactive Shell + + The Stylus REPL (Read-Eval-Print-Loop) or "interactive shell" allows you to + play around with Stylus expressions directly from your terminal. Note that this works only for expressions, not selectors etc. To use simple add the `-i`, or `--interactive` flag: + + $ stylus -i + > color = white + => #fff + > color - rgb(200,50,0) + => #37cdff + > color + => #fff + > color -= rgb(200,50,0) + => #37cdff + > color + => #37cdff + > rgba(color, 0.5) + => rgba(55,205,255,0.5) + \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/font-face.md b/node_modules/jade/support/stylus/docs/font-face.md new file mode 100644 index 0000000..408b491 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/font-face.md @@ -0,0 +1,26 @@ + +## @font-face + + The `@font-face` at-rule expects as you would expect, simply followed by a block of properties: + + + @font-face + font-family Geo + font-style normal + src url(fonts/geo_sans_light/GensansLight.ttf) + + .ingeo + font-family Geo + +yielding: + + + @font-face { + font-family: Geo; + font-style: normal; + src: url("fonts/geo_sans_light/GensansLight.ttf"); + } + .ingeo { + font-family: Geo; + } + diff --git a/node_modules/jade/support/stylus/docs/functions.md b/node_modules/jade/support/stylus/docs/functions.md new file mode 100644 index 0000000..d762104 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/functions.md @@ -0,0 +1,192 @@ + +## Functions + + Stylus features powerful in-language function definition. Function definition appears identical to mixins, however functions may return a value. + +### Return Values + + Let's try a trivial example, creating a function that adds two numbers. + + add(a, b) + a + b + + We may then utilize this function in conditions, as property values, etc. + + body + padding add(10px, 5) + + Rendering + + body { + padding: 15px; + } + +### Argument Defaults + + Optional arguments may default to a given expression. With Stylus we may even default arguments to leading arguments! For example: + + + add(a, b = a) + a + b + + add(10, 5) + // => 15 + + add(10) + // => 20 + +note that since argument defaults are assignments, we can also utilize function calls for defaults: + + add(a, b = unit(a, px)) + a + b + +### Function Bodies + + We can take our simple `add()` function further, by casting all units passed as `px` via the `unit()` built-in. Re-assigning each argument and providing a unit type string (or identifier), which disregards unit conversion. + + add(a, b = a) + a = unit(a, px) + b = unit(b, px) + a + b + + add(15%, 10deg) + // => 25 + +### Multiple Return Values + + Stylus functions can return several values, just as you can assign several values to a variable. For example the following is a valid assignment: + + sizes = 15px 10px + + sizes[0] + // => 15px + +Similarly we may return several values: + + sizes() + 15px 10px + + sizes()[0] + // => 15px + +One slight exception is when return values are identifiers, for example the following looks like a property assignment to Stylus since no operators are present. + + swap(a, b) + b a + +To disambiguate we may either wrap in parens, or utilize the `return` keyword. + + swap(a, b) + (b a) + + swap(a, b) + return b a + +### Conditionals + + Let's say we want to create a function named `stringish()` to see if the value given can be transformed to a string. We check if `val` is a string, or an ident which is string-like. Because undefined identifiers yield themselves as the value, we may compare them to them-selves as shown below, where `yes` and `no` are used in place of `true` and `false`. + + + stringish(val) + if val is a 'string' or val is a 'ident' + yes + else + no + +usage: + + stringish('yay') == yes + // => true + + stringish(yay) == yes + // => true + + stringish(0) == no + // => true + +__note__: `yes` and `no` are not boolean literals, they are simply undefined identifiers in this case. + +Another example: + + + compare(a, b) + if a > b + higher + else if a < b + lower + else + equal + +usage: + + compare(5, 2) + // => higher + + compare(1, 5) + // => lower + + compare(10, 10) + // => equal + +### Aliasing + + To alias a function we can simply assign a function's name to a new identifier. For example our previous `add()` function could be exposed as `plus()` as well, simply by: + + plus = add + + plus(1, 2) + // => 3 + +### Variable Functions + + In the same way that we can "alias" a function, we can pass a function as well, here our `invoke()` function accepts a function, so we can pass it `add()` or `sub()`. + + invoke(a, b, fn) + fn(a, b) + + add(a, b) + a + b + + body + padding invoke(5, 10, add) + padding invoke(5, 10, sub) + +yielding: + + body { + padding: 15; + padding: -5; + } + +### arguments + + The `arguments` local is available to all function bodies, and contains all the arguments passed. For example: + + sum() + n = 0 + for num in arguments + n = n + num + + sum(1,2,3,4,5) + // => 15 + +### Hash Example + + Below we define the `get(hash, key)` function, which will return the + value of `key`, or `null`. We iterate each `pair` in `hash`, returning the pair's second node when the first (the `key`) matches. + + get(hash, key) + return pair[1] if pair[0] == key for pair in hash + +As you can see below, in-language functions paired with robust stylus expressions can provide great flexibility. + + hash = (one 1) (two 2) (three 3) + + get(hash, two) + // => 2 + + get(hash, three) + // => 3 + + get(hash, something) + // => null diff --git a/node_modules/jade/support/stylus/docs/functions.url.md b/node_modules/jade/support/stylus/docs/functions.url.md new file mode 100644 index 0000000..693bbaa --- /dev/null +++ b/node_modules/jade/support/stylus/docs/functions.url.md @@ -0,0 +1,30 @@ +## Data URI Image Inlining + +Stylus is bundled with an optional function named `url()`, which replaces the literal `url()` calls, and conditionally inlines them using base64 [Data URIs](http://en.wikipedia.org/wiki/Data_URI_scheme). + +### Example + +The function itself is available via `require('stylus').url`, and accepts an options object, returning a function that Stylus calls internally when it sees `url()`. + +The `.define(name, callback)` method assigned a JavaScript function that can be called from stylus source. In this case we have our images in `./css/images` then we can ignore the `paths` option, since image lookups are performed relative to the file being rendered (by default), we may alter this with the option. + + stylus(str) + .set('filename', __dirname + '/css/test.styl') + .define('url', stylus.url()) + .render(function(err, css){ + + }); + +For example if our images live in `./public/images` and we wish to use `url(images/tobi.png)`, we can pass `paths` with our public directory, which will become part of the lookup process. Like-wise if we wanted `url(tobi.png)` instead, we would pass `paths: [__dirname + '/public/images']`. + + stylus(str) + .set('filename', __dirname + '/css/test.styl') + .define('url', stylus.url({ paths: [__dirname + '/public'] })) + .render(function(err, css){ + + }); + +### Options + + - `limit` bytesize limit defaulting to 30Kb (30000) + - `paths` image resolution path(s) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/import.md b/node_modules/jade/support/stylus/docs/import.md new file mode 100644 index 0000000..1db388a --- /dev/null +++ b/node_modules/jade/support/stylus/docs/import.md @@ -0,0 +1,73 @@ + +## Import + + Stylus supports both literal __@import__ for CSS, as well as dynamic importing of other Stylus sheets. + +### Literal CSS + + Any filename with the extension `.css` will become a literal, for example: + + @import "reset.css" + +will render to the literal css __@import__ shown below: + + @import "reset.css" + +### Stylus Import + + When using __@import__ without the `.css` extension, it is assumed to be a Stylus sheet, for example `@import "mixins/border-radius"`. + + __@import__ works by iterating an array of directories, and seeing if this file lives in any of them, similar to node's `require.paths`. This array defaults to a single path which is derived from the `filename` option's dirname. So if your filename is `/tmp/testing/stylus/main.styl`, then import will look in `/tmp/testing/stylus/`. + + __@import__ also supports index styles, meaning if you `@import blueprint`, it will resolve either `blueprint.styl` or `blueprint/index.styl`, useful for libraries to expose all of their features, but still allow a subset of the library to be imported. For example a common lib structure might be: + + ./tablet + |-- index.styl + |-- vendor.styl + |-- buttons.styl + |-- images.styl + + In the example below we set the `paths` options to provide additional paths to Stylus. Within `./test.styl` we could then `@import "mixins/border-radius"` or `@import "border-radius"` since `./mixins` is exposed to Stylus. + + /** + * Module dependencies. + */ + + var stylus = require('../') + , str = require('fs').readFileSync(__dirname + '/test.styl', 'utf8'); + + var paths = [ + __dirname + , __dirname + '/mixins' + ]; + + stylus(str) + .set('filename', __dirname + '/test.styl') + .set('paths', paths) + .render(function(err, css){ + if (err) throw err; + console.log(css); + }); + +### JavaScript Import API + + When using the `.import(path)` method, these imports are deferred until evaluation: + + var stylus = require('../') + , str = require('fs').readFileSync(__dirname + '/test.styl', 'utf8'); + + stylus(str) + .set('filename', __dirname + '/test.styl') + .import('mixins/vendor') + .render(function(err, css){ + if (err) throw err; + console.log(css); + }); + + The following are essentially equivalent: + + @import 'mixins/vendor' + +and + .import('mixins/vendor') + \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/interpolation.md b/node_modules/jade/support/stylus/docs/interpolation.md new file mode 100644 index 0000000..c59bd9b --- /dev/null +++ b/node_modules/jade/support/stylus/docs/interpolation.md @@ -0,0 +1,43 @@ + +## Interpolation + + Stylus supports interpolation by using the `{}` characters to surround an expression, which then becomes part of the identifier. For example `-webkit-{'border' + '-radius'}` would evaluate to `-webkit-border-radius`. + + A great example use-case for this is expanding properties with vendor prefixes. + + vendor(prop, args) + -webkit-{prop} args + -moz-{prop} args + {prop} args + + border-radius() + vendor('border-radius', arguments) + + box-shadow() + vendor('box-shadow', arguments) + + button + border-radius 1px 2px / 3px 4px + +yielding: + + button { + -webkit-border-radius: 1px 2px / 3px 4px; + -moz-border-radius: 1px 2px / 3px 4px; + border-radius: 1px 2px / 3px 4px; + } + +## Property Hacks + +Interpolation can be used for property hacks as well, since all string values +within the delimiters are transformed to literals. For example: + + body + {'*foo-bar'} baz + +yields: + + body { + *foo-bar: baz; + } + \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/introspection.md b/node_modules/jade/support/stylus/docs/introspection.md new file mode 100644 index 0000000..06d7c49 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/introspection.md @@ -0,0 +1,39 @@ + +## Introspection API + + Stylus supports an introspection API, allowing mixins and functions to reflect relative to the caller etc. + + +## mixin + + The `mixin` local variable is automatically assigned within function bodies, + containing the string "root" indicating the function is called at the root + level, or "block" indicating otherwise, and finally `false` if the function + is invoked expecting a return value. + + In the following example we define `reset()` altering its behaviour when mixed in to root, another block, or a return value as used in the `foo` property below. + + reset() + if mixin == 'root' + got + root true + else if mixin + got 'a mixin' + else + 'not a mixin' + + reset() + + body + reset() + foo reset() + +compiles to: + + got { + root: true; + } + body { + foo: "not a mixin"; + got: "a mixin"; + } diff --git a/node_modules/jade/support/stylus/docs/iteration.md b/node_modules/jade/support/stylus/docs/iteration.md new file mode 100644 index 0000000..b309840 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/iteration.md @@ -0,0 +1,100 @@ + +## Iteration + + Stylus allows you to iterate expressions via the `for/in` construct, taking the form of: + + for [, ] in + +For example: + + body + for num in 1 2 3 + foo num + +yields: + + body { + foo: 1; + foo: 2; + foo: 3; + } + +The example below shows how to use the ``: + + body + fonts = Impact Arial sans-serif + for font, i in fonts + foo i font + +yielding: + + body { + foo: 0 Impact; + foo: 1 Arial; + foo: 2 sans-serif; + } + +### Mixins + + We may utilize iteration within mixins to produce powerful functionality, for example we can apply expression pairs as properties using interpolation and iteration. Below we define `apply()`, conditionally utilizing all the `arguments` so that comma-delimited _and_ expression lists are supported: + + apply(props) + props = arguments if length(arguments) > 1 + for prop in props + {prop[0]} prop[1] + + body + apply(one 1, two 2, three 3) + + body + list = (one 1) (two 2) (three 3) + apply(list) + +### Functions + + Stylus functions may also contain for-loops, below are some example use-cases: + +sum: + + sum(nums) + sum = 0 + for n in nums + sum += n + + sum(1 2 3) + // => 6 + +join: + + join(delim, args) + buf = '' + for arg, index in args + if index + buf += delim + arg + else + buf += arg + + join(', ', foo bar baz) + // => "foo, bar, baz" + +### Postfix + + Much like `if` / `unless` may be utilized post-statement, the same can be done with `for`. Below are the same examples as above utilizing the postfix syntax: + + sum(nums) + sum = 0 + sum += n for n in nums + + + join(delim, args) + buf = '' + buf += i ? delim + arg : arg for arg, i in args + + We can also __return__ from within a loop, below is an example returning the + number when `n % 2 == 0` evaluates to __true__. + + first-even(nums) + return n if n % 2 == 0 for n in nums + + first-even(1 3 5 5 6 3 2) + // => 6 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/js.md b/node_modules/jade/support/stylus/docs/js.md new file mode 100644 index 0000000..2bcacaf --- /dev/null +++ b/node_modules/jade/support/stylus/docs/js.md @@ -0,0 +1,108 @@ +## JavaScript API + +Simply require the module, and call `render()` with the given string of stylus code, and (optional) options object. Frameworks utilizing stylus should pass the `filename` option to provide better error reporting. + + var stylus = require('stylus'); + + stylus.render(str, { filename: 'nesting.css' }, function(err, css){ + if (err) throw err; + console.log(css); + }); + +We can also do the same thing in a more progressive manner: + + var stylus = require('stylus'); + + stylus(str) + .set('filename', 'nesting.css') + .render(function(err, css){ + // logic + }); + +### .set(setting, value) + + Apply a setting such as a `filename`, or import `paths`: + + .set('filename', __dirname + '/test.styl') + .set('paths', [__dirname, __dirname + '/mixins']) + +### .import(path) + +Defer importing of the given `path` until evaluation is performed. The example below is essentially the same as doing `@import 'mixins/vendor'` within your Stylus sheet. + + var stylus = require('../') + , str = require('fs').readFileSync(__dirname + '/test.styl', 'utf8'); + + stylus(str) + .set('filename', __dirname + '/test.styl') + .import('mixins/vendor') + .render(function(err, css){ + if (err) throw err; + console.log(css); + }); + +### .define(name, fn) + + This method allows you to provide a JavaScript-defined function to Stylus, think of these as you would JavaScript to C++ bindings. When you have something you cannot do within Stylus, you define it in JavaScript. + +In our example we define four functions `add()`, `sub()`, `image-width()`, and `image-height()`. These functions must return a `Node`, this constructor and the other nodes are available via `stylus.nodes`. + + var stylus = require('../') + , nodes = stylus.nodes + , utils = stylus.utils + , fs = require('fs'); + + function add(a, b) { + return a.operate('+', b); + } + + function sub(a, b) { + return a.operate('-', b); + } + + function imageDimensions(img) { + // assert that the node (img) is a String node, passing + // the param name for error reporting + utils.assertType(img, nodes.String, 'img'); + var path = img.val; + + // Grab bytes necessary to retrieve dimensions. + // if this was real you would do this per format, + // instead of reading the entire image :) + var data = fs.readFileSync(__dirname + '/' + path); + + // GIF + // of course you would support.. more :) + if ('GIF' == data.slice(0, 3).toString()) { + var w = data.slice(6, 8) + , h = data.slice(8, 10); + w = w[1] << 8 | w[0]; + h = h[1] << 8 | h[0]; + } + + return [w, h]; + } + + function imageWidth(img) { + return new nodes.Unit(imageDimensions(img)[0]); + } + + function imageHeight(img) { + return new nodes.Unit(imageDimensions(img)[1]); + } + + stylus(str) + .set('filename', 'js-functions.styl') + .define('add', add) + .define('sub', sub) + .define('image-width', imageWidth) + .define('image-height', imageHeight) + .render(function(err, css){ + if (err) throw err; + console.log(css); + }); + + For further reference until documentation is complete please reference the following files: + + - lib/nodes/* + - lib/utils.js \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/keyframes.md b/node_modules/jade/support/stylus/docs/keyframes.md new file mode 100644 index 0000000..48ee6c4 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/keyframes.md @@ -0,0 +1,52 @@ + +## @keyframes + + Stylus supports the `@keyframes` at-rule, which is converted to `@-webkit-keyframes` when compiled: + + + @keyframes pulse + 0% + background-color red + opacity 1.0 + -webkit-transform scale(1.0) rotate(0deg) + 33% + background-color blue + opacity 0.75 + -webkit-transform scale(1.1) rotate(-5deg) + 67% + background-color green + opacity 0.5 + -webkit-transform scale(1.1) rotate(5deg) + 100% + background-color red + opacity 1.0 + -webkit-transform scale(1.0) rotate(0deg) + +yielding: + + @-webkit-keyframes pulse { + 0% { + background-color: red; + opacity: 1; + -webkit-transform: scale(1) rotate(0deg); + } + + 33% { + background-color: blue; + opacity: 0.75; + -webkit-transform: scale(1.1) rotate(-5deg); + } + + 67% { + background-color: green; + opacity: 0.5; + -webkit-transform: scale(1.1) rotate(5deg); + } + + 100% { + background-color: red; + opacity: 1; + -webkit-transform: scale(1) rotate(0deg); + } + + } diff --git a/node_modules/jade/support/stylus/docs/literal.md b/node_modules/jade/support/stylus/docs/literal.md new file mode 100644 index 0000000..52f84c7 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/literal.md @@ -0,0 +1,16 @@ +## Literal CSS + + If for any reason Stylus cannot accommodate a specific need, you can always resort to literal css via `@css`: + + + @css { + body { + font: 14px; + } + } + +compiling to: + + body { + font: 14px; + } \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/media.md b/node_modules/jade/support/stylus/docs/media.md new file mode 100644 index 0000000..5603c4f --- /dev/null +++ b/node_modules/jade/support/stylus/docs/media.md @@ -0,0 +1,18 @@ + +## @media + + The `@media` works just as it does within regular css, however with Stylus block notation: + + @media print + #header + #footer + display none + +yielding: + + @media print { + #header, + #footer { + display: none; + } + } diff --git a/node_modules/jade/support/stylus/docs/middleware.md b/node_modules/jade/support/stylus/docs/middleware.md new file mode 100644 index 0000000..1aa414e --- /dev/null +++ b/node_modules/jade/support/stylus/docs/middleware.md @@ -0,0 +1,55 @@ + +## Connect Middleware + + Stylus ships with Connect middleware for auto-compiling Stylus sheets when modified. + +## stylus.middleware(options) + + Return Connect middleware with the given `options`. + +#### Options + + `force` When __true__ styles will always re-compile + `src` Source directory used to find .styl files + `dest` Destination directory used to output .css files + when undefined defaults to `src`. + `compress` Whether the output .css files should be compressed + `compile` Custom compile function, accepting the arguments + `(str, path)` returning the renderer. + +#### Examples + + Here we set up the custom compile function so that we may + alter the renderer by providing additional settings. + + By default the compile function simply sets the `filename` + and renders the CSS. + + function compile(str, path) { + return stylus(str) + .import(__dirname + '/css/mixins/blueprint') + .import(__dirname + '/css/mixins/css3') + .set('filename', path) + .set('warn', true) + .set('compress', true); + } + + Pass the middleware to Connect, grabbing .styl files from this directory + and saving .css files to _./public_. Also supplying our custom `compile` function. + + Following that we have a `staticProvider` layer setup to serve the .css + files generated by Stylus. + + var stylus = require('stylus'); + + var server = connect.createServer( + stylus.middleware({ + src: __dirname + , dest: __dirname + '/public' + , compile: compile + }) + , connect.staticProvider(__dirname + '/public') + ); + + When `force` is used, the styles will be unconditionally re-compiled, however + even without this option the Stylus middleware is smart enough to detect changes in `@import`ed files. \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/mixins.md b/node_modules/jade/support/stylus/docs/mixins.md new file mode 100644 index 0000000..5ec7a73 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/mixins.md @@ -0,0 +1,132 @@ + +## Mixins + +Both mixins and functions are defined in the same manor, however they are applied in different ways. For example we have a `border-radius(n)` function defined below, which is invoked as a _mixin_, aka a statement rather than part of an expression. + +When `border-radius()` is invoked within a selector, the properties are expanded and copied into the selector. + + border-radius(n) + -webkit-border-radius n + -moz-border-radius n + border-radius n + + form input[type=button] + border-radius(5px) + +compiles to: + + form input[type=button] { + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + } + +When utilizing mixins, we can omit the parens all together, providing is with fantastic transparent vendor property support: + + border-radius(n) + -webkit-border-radius n + -moz-border-radius n + border-radius n + + form input[type=button] + border-radius 5px + +Note that the `border-radius` within our mixin is treated as a property, and not a recursive function invocation. To take this further we we may utilize the automatic `arguments` local variable, containing the expression passed, allowing more than one value to be passed: + + border-radius() + -webkit-border-radius arguments + -moz-border-radius arguments + border-radius arguments + +now allowing us to pass values such as `border-radius 1px 2px / 3px 4px`. + +Another great example of this, is adding transparent support for vendor specifics such as `opacity` support for IE: + + support-for-ie ?= true + + opacity(n) + opacity n + if support-for-ie + filter unquote('progid:DXImageTransform.Microsoft.Alpha(Opacity=' + round(n * 100) + ')') + + #logo + &:hover + opacity 0.5 + +rendering: + + #logo:hover { + opacity: 0.5; + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50); + } + +### Parent References + + Mixins may utilize the parent reference character `&`, acting on the parent instead of further nesting. For example lets say we wish to create a `stripe(even, odd)` mixin for striping table row, we provide both `even` and `odd` with default color values, and assign the `background-color` property on the row. Nested within the `tr` we use `&` to reference the `tr`, providing the `even` color. + + stripe(even = #fff, odd = #eee) + tr + background-color odd + &.even + &:nth-child(even) + background-color even + +We may then utilize the mixin as shown below: + + table + stripe() + td + padding 4px 10px + + table#users + stripe(#303030, #494848) + td + color white + +Another way to define the `stripe()` mixin without parent reference: + + stripe(even = #fff, odd = #eee) + tr + background-color odd + tr.even + tr:nth-child(even) + background-color even + +If we wished, we could invoke `stripe()` as if it were a property: + + stripe #fff #000 + +### Mixing Mixins in Mixins + + Mixins can of course utilize other mixins, to build up their own selector's and properties. For example, below we create `comma-list()` to inline (via `inline-list()`) and comma-separate an un-ordered list. + + + inline-list() + li + display inline + + comma-list() + inline-list() + li + &:after + content ', ' + &:last-child:after + content '' + + ul + comma-list() + +rendering: + + ul li:after { + content: ", "; + } + ul li:last-child:after { + content: ""; + } + ul li { + display: inline; + } + diff --git a/node_modules/jade/support/stylus/docs/operators.md b/node_modules/jade/support/stylus/docs/operators.md new file mode 100644 index 0000000..b2a22d2 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/operators.md @@ -0,0 +1,418 @@ + +## Operator Precedence + +Below is the operator precedence table, highest to lowest: + + [] + ! ~ + - + is defined + ** * / % + + - + ... .. + <= >= < > + in + == is != is not + is a + && and || or + ?: + = ?= += -= *= /= %= + not + if unless + +## Unary Operators + +The following unary operators are available, `!`, `not`, `-`, `+`, and `~`. + + !0 + // => true + + !!0 + // => false + + !1 + // => false + + !!5px + // => true + + -5px + // => -5px + + --5px + // => 5px + + not true + // => false + + not not true + // => true + +The logical `not` operator has low precedence, therefore the following example could be replaced with + + a = 0 + b = 1 + + !a and !b + // => false + // pased as: (!a) and (!b) + +with: + + not a or b + // => false + // parsed as: not (a or b) + +## Binary Operators + +### Subscript [] + + The subscript operator allows us to grab a value in an expression via index. Parenthesized expressions may act as tuples, so for example `(15px 5px)`, `(1 2 3)`. + + Below is an example where we utilize tuples for error handling, showing the versatility of such a construct. As + + add(a, b) + if a is a 'unit' and b is a 'unit' + a + b + else + (error 'a and b must be units!') + + body + padding add(1,'5') + // => padding: error "a and b must be units"; + + padding add(1,'5')[0] + // => padding: error; + + padding add(1,'5')[0] == error + // => padding: true; + + padding add(1,'5')[1] + // => padding: "a and b must be units"; + + A more complex example, invoking the `error()` built-in function with the error message returned, when the ident (the first value) equals `error`. + + + if (val = add(1,'5'))[0] == error + error(val[1]) + +## Range .. ... + + Both the inclusive (`..`) and exclusive (`...`) range operators are provided, expanding to expressions: + + 1..5 + // => 1 2 3 4 5 + + 1...5 + // => 1 2 3 4 + +### Additive: + - + +multiplicative and additive binary operators work as expected, and type conversion is applied within unit type classes, or default to the literal value. For example if we perform `5s - 2px` we will get `3s`. + + 15px - 5px + // => 10px + + 5 - 2 + // => 3 + + 5in - 50mm + // => 3.031in + + 5s - 1000ms + // => 4s + + 20mm + 4in + // => 121.6mm + + "foo " + "bar" + // => "foo bar" + + "num " + 15 + // => "num 15" + +We can also operator on colors, and values are clamped appropriately. + + #fff - #111 + => #eee + + #111 + #fco + // => #fd1 + + #fff - rgba(255,0,0,0.3) + // => rgba(0,255,255,0.7) + + #fff / 2 + // => #808080 + + #fff / rgb(2,0,4) + // #80ff40 + +### Multiplicative: / * % + + 2000ms + (1s * 2) + // => 4ms + + 5s / 2 + // => 2.5s + + 4 % 2 + // => 0 + +When using `/` within a property value you must wrap with parens. The following for example is taken literally, to support css line-height: + + font: 14px/1.5; + +whereas the following is evaluated, dividing `14px` by `1.5`: + + font: (14px/1.5); + +this exception is _only_ required for the `/` operator. + +### Exponent: ** + +The Exponent operator: + + 2 ** 8 + // => 256 + +### Equality: == != >= <= > < + +Equality operators can be used to equate units, colors, strings, and even identifiers. This is a powerful concept, as even arbitrary identifiers such as as `wahoo` can be utilized as atoms, a function could return `yes` or `no` instead of `true` or `false` (although not advised). + + 5 == 5 + // => true + + 10 < 5 + // => true + + #fff == #fff + // => true + + true == false + // => false + + wahoo == yay + // => false + + wahoo == wahoo + // => true + + "test" == "test" + // => true + + true is true + // => true + + 'hey' is not 'bye' + // => true + + 'hey' isnt 'bye' + // => true + +Only exact values match, for example `0 == false`, and `null == false` are both `false`. + +Aliases: + + == is + != is not + != isnt + +## Truthfulness + + Nearly everything within Stylus resolves to `true`, including units with a suffix, for example even `0%`, `0px`, etc will resolve to `true`, since commonly in Stylus a mixin or function may accept such units as valid, however `0` itself is `false` in terms of arithmetic. + +`true` examples: + + 0% + 0px + 1px + -1 + -1px + hey + 'hey' + +`false` examples: + + 0 + null + false + '' + +### Logical Operators: && || and or + +Logical operators `&&` and `||` are aliased `and` / `or` which apply the same precedence. + + 5 && 3 + // => 3 + + 0 || 5 + // => 5 + + 0 && 5 + // => 0 + + #fff is a 'rgba' and 15 is a 'unit' + // => true + +### Existence Operator: in + + Checks for the existence of the _left-hand_ operand within the _right-hand_ expression. + +Simple examples: + + nums = 1 2 3 + 1 in nums + // => true + + 5 in nums + // => false + +Some undefined identifiers: + + words = foo bar baz + bar in words + // => true + + HEY in words + // => false + +Works with tuples too: + + vals = (error 'one') (error 'two') + error in vals + // => false + + (error 'one') in vals + // => true + + (error 'two') in vals + // => true + + (error 'something') in vals + // => false + +Example usage in mixin: + + pad(types = padding, n = 5px) + if padding in types + padding n + if margin in types + margin n + + body + pad() + + body + pad(margin) + + body + pad(padding margin, 10px) + +yielding: + + body { + padding: 5px; + } + body { + margin: 5px; + } + body { + padding: 10px; + margin: 10px; + } + +### Conditional Assignment: ?= + +The conditional assignment operator `?=` lets us define variables without clobbering old values (when present). This operator expands to an `is defined` binary operation within a ternary, for example the following are equivalent: + + color ?= white + color = color is defined ? color : white + +For example when using `=` we simply re-assign: + + color = white + color = black + + color + // => black + +However when using `?=` our second attempt fails since the variable is already defined: + + color = white + color ?= black + + color + // => white + +### Instance Check: is a + +Stylus provides a binary operator named `is a` used to type check. + + 15 is a 'unit' + // => true + + #fff is a 'rgba' + // => true + + 15 is a 'rgba' + // => false + +Alternatively we could use the `type()` BIF: + + type(#fff) == 'rgba' + // => true + +'color' is the one special-case, evaluating to true when the +left-hand operand is an `RGBA` or `HSLA` node. + +### Variable Definition: is defined + +This pseudo binary operator does not accept a right-hand operator, and does _not_ evaluate the left. This allows us to check if a variable has a value assigned to it. + + foo is defined + // => false + + foo = 15px + foo is defined + // => true + + #fff is defined + // => 'invalid "is defined" check on non-variable #fff' + +Alternatively one can use the `lookup(name)` built-in function to do this, or to perform dynamic lookups: + + name = 'blue' + lookup('light-' + name) + // => null + + light-blue = #80e2e9 + lookup('light-' + name) + // => #80e2e9 + +This operator is essential, as an undefined identifier is still a truthy value. For example: + + body + if ohnoes + padding 5px + +_will_ yield the following css when undefined: + + body { + padding: 5px; + } + +however this will be safe: + + body + if ohnoes is defined + padding 5px + +## Ternary + +The ternary operator works as we would expect in most languages, being the only operator with three operands, the _condition_ expression, the _truth_ expression and the _false_ expression. + + num = 15 + num ? unit(num, 'px') : 20px + // => 15px + + diff --git a/node_modules/jade/support/stylus/docs/selectors.md b/node_modules/jade/support/stylus/docs/selectors.md new file mode 100644 index 0000000..4afb073 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/selectors.md @@ -0,0 +1,132 @@ + +## Selectors + +### Indentation + +Stylus is "pythonic" aka indentation-based. Whitespace is significant, so we substitute { and } with an _indent_, and an _outdent_ as shown below: + + body + color white + +which compiles to: + + body { + color: #fff; + } + +Optionally if preferred we may utilize colons to separate properties and their values: + + body + color: white + +### Rule Sets + +Stylus, just like css allows you to define properties for several selectors at once through comma separation. + + textarea, input + border 1px solid #eee + +The same can be done with a newline: + + textarea + input + border 1px solid #eee + +both compiling to: + + textarea, + input { + border: 1px solid #eee; + } + +The one exception to this rule, are selectors that look like properties, for example `foo bar baz` in the following may be a property, or a selector: + + foo bar baz + > input + border 1px solid + +so for this reason, or if simply preferred we may trail with a comma: + + foo bar baz, + form input, + > a + border 1px solid + +### Parent Reference + +The `&` character references the parent selector(s). In the example below our two selectors `textarea`, and `input` both alter the `color` on the `:hover` pseudo selector. + + textarea + input + color #A7A7A7 + &:hover + color #000 + +compiles to: + + textarea, + input { + color: #a7a7a7; + } + textarea:hover, + input:hover { + color: #000; + } + +below is an example providing a simple `2px` border for internet exploder utilizing the parent reference within a mixin: + + box-shadow() + -webkit-box-shadow arguments + -moz-box-shadow arguments + box-shadow arguments + html.ie8 &, + html.ie7 &, + html.ie6 & + border 2px solid arguments[length(arguments) - 1] + + body + #login + box-shadow 1px 1px 3px #eee + +yielding: + + body #login { + -webkit-box-shadow: 1px 1px 3px #eee; + -moz-box-shadow: 1px 1px 3px #eee; + box-shadow: 1px 1px 3px #eee; + } + html.ie8 body #login, + html.ie7 body #login, + html.ie6 body #login { + border: 1px solid #eee; + } + +### Disambiguation + +Expressions such as `padding - n` could be interpreted both as a subtraction operation, as well as a property with an unary minus. To disambiguate we can wrap the expression with parens: + + pad(n) + padding (- n) + + body + pad(5px) + +compiles to: + + body { + padding: -5px; + } + +however this is only true in functions, since functions act both as mixins, or calls with return values. For example this is fine, and will yield the same results as above: + + body + padding -5px + +Have weird property values that Stylus cannot process? `unquote()` can help you out: + + filter unquote('progid:DXImageTransform.Microsoft.BasicImage(rotation=1)') + +yields: + + filter progid:DXImageTransform.Microsoft.BasicImage(rotation=1) + \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/textmate.md b/node_modules/jade/support/stylus/docs/textmate.md new file mode 100644 index 0000000..b29e148 --- /dev/null +++ b/node_modules/jade/support/stylus/docs/textmate.md @@ -0,0 +1,7 @@ + +## TextMate Bundle + + Stylus ships with a TextMate bundle, located within `./editors`. To install simply execute `make install-bundle`, or place `./editors/Stylus.tmbundle` in the appropriate location. + + + ![Stylus TextMate Bundle](http://cl.ly/4CA7) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/docs/vargs.md b/node_modules/jade/support/stylus/docs/vargs.md new file mode 100644 index 0000000..fba09cb --- /dev/null +++ b/node_modules/jade/support/stylus/docs/vargs.md @@ -0,0 +1,84 @@ + +## Rest Parameters + + Stylus supports rest parameters in the form of `name...`. These params consume the remaining arguments passed to a mixin or function. This is useful for example when utilizing the implicit function call support to apply vendor prefixes like `-webkit` or `-moz`. + + +In the example below we consume all the arguments passed and simply apply them to multiple properties. + + box-shadow(args...) + -webkit-box-shadow args + -moz-box-shadow args + box-shadow args + + #login + box-shadow 1px 2px 5px #eee + +yielding: + + #login { + -webkit-box-shadow: 1px 2px 5px #eee; + -moz-box-shadow: 1px 2px 5px #eee; + box-shadow: 1px 2px 5px #eee; + } + +If we wanted to peek at a specific argument, for example the x-offset we could simply use `args[0]`, or for example we may wish to re-define the mixin: + + box-shadow(offset-x, args...) + got-offset-x offset-x + -webkit-box-shadow offset-x args + -moz-box-shadow offset-x args + box-shadow offset-x args + + #login + box-shadow 1px 2px 5px #eee + +yielding: + + #login { + got-offset-x: 1px; + -webkit-box-shadow: 1px 2px 5px #eee; + -moz-box-shadow: 1px 2px 5px #eee; + box-shadow: 1px 2px 5px #eee; + } + +### arguments + + The `arguments` variable is injected into mixin and function bodies, containing the exact expression passed. This is useful for several reasons, primarily for vendor support, as you get the _exact_ expression, commas and all. + + For example, if we use a rest param, the comma is simply consumed since it is an expression delimiter: + + box-shadow(args...) + -webkit-box-shadow args + -moz-box-shadow args + box-shadow args + + #login + box-shadow #ddd 1px 1px, #eee 2px 2px + +yielding slightly unexpected results: + + #login { + -webkit-box-shadow: #ddd 1px 1px #eee 2px 2px; + -moz-box-shadow: #ddd 1px 1px #eee 2px 2px; + box-shadow: #ddd 1px 1px #eee 2px 2px; + } + +Let's redefine the mixin using `arguments`: + + box-shadow() + -webkit-box-shadow arguments + -moz-box-shadow arguments + box-shadow arguments + + body + box-shadow #ddd 1px 1px, #eee 2px 2px + +now yielding the desired result: + + body { + -webkit-box-shadow: #ddd 1px 1px, #eee 2px 2px; + -moz-box-shadow: #ddd 1px 1px, #eee 2px 2px; + box-shadow: #ddd 1px 1px, #eee 2px 2px; + } + diff --git a/node_modules/jade/support/stylus/docs/variables.md b/node_modules/jade/support/stylus/docs/variables.md new file mode 100644 index 0000000..28d595f --- /dev/null +++ b/node_modules/jade/support/stylus/docs/variables.md @@ -0,0 +1,29 @@ + +## Variables + +We may assign expressions to variables and use them throughout our stylesheet: + + font-size = 14px + + body + font font-size Arial, sans-serif + +compiles to: + + body { + font: 14px Arial, sans-serif; + } + +Variables can even consist of an expression list: + + font-size = 14px + font = font-size "Lucida Grande", Arial + + body + font font sans-serif + +compiles to: + + body { + font: 14px "Lucida Grande", Arial sans-serif; + } \ No newline at end of file diff --git a/node_modules/jade/support/stylus/editors/Stylus.tmbundle/Syntaxes/Stylus.tmLanguage b/node_modules/jade/support/stylus/editors/Stylus.tmbundle/Syntaxes/Stylus.tmLanguage new file mode 100644 index 0000000..749ee49 --- /dev/null +++ b/node_modules/jade/support/stylus/editors/Stylus.tmbundle/Syntaxes/Stylus.tmLanguage @@ -0,0 +1,166 @@ + + + + + fileTypes + + styl + stylus + + name + Stylus + patterns + + + match + ^ *(&|) + name + variable.language.stylus + + + match + (arguments) + name + variable.language.stylus + + + match + @([-\w]+) + name + keyword.stylus + + + captures + + 1 + + name + punctuation.definition.entity.stylus + + + match + (\.)[a-zA-Z0-9_-]+ + name + entity.other.attribute-name.class.stylus + + + captures + + 1 + + name + punctuation.definition.entity.stylus + + + match + (:+)\b(after|before|first-child|first-letter|first-line|selection)\b + name + entity.other.attribute-name.pseudo-element.stylus + + + captures + + 1 + + name + punctuation.definition.entity.stylus + + + match + (:)\b(active|hover|link|visited|focus)\b + name + entity.other.attribute-name.pseudo-class.stylus + + + captures + + 1 + + name + punctuation.definition.entity.css + + + match + (#)[a-zA-Z][a-zA-Z0-9_-]* + name + entity.other.attribute-name.id.stylus + + + match + \b(!important|for|in|return|true|false|null|if|else|unless|return)\b + name + keyword.control.stylus + + + begin + " + end + " + name + string.quoted.double.stylus + + + begin + ' + end + ' + name + string.quoted.single.stylus + + + begin + /\* + captures + + 0 + + name + punctuation.definition.comment.js + + + end + \*/ + name + comment.block.js + + + match + (?:\b(\d+))|(#[a-fA-F0-9]+) + name + constant.numeric.stylus + + + captures + + 1 + + name + punctuation.definition.comment.stylus + + + match + (?:^[ \t]+)?(\/\/).*$\n? + name + comment.line.stylus + + + captures + + 1 + + name + entity.name.function.stylus + + + match + ([-a-zA-Z_][-\w]*)?(\() + name + meta.function.stylus + + + scopeName + source.stylus + uuid + 60519324-6A3A-4382-9E0B-546993A3869A + + diff --git a/node_modules/jade/support/stylus/editors/Stylus.tmbundle/info.plist b/node_modules/jade/support/stylus/editors/Stylus.tmbundle/info.plist new file mode 100644 index 0000000..e0e962b --- /dev/null +++ b/node_modules/jade/support/stylus/editors/Stylus.tmbundle/info.plist @@ -0,0 +1,10 @@ + + + + + name + Stylus + uuid + DD7889E4-2ACA-4DF5-838F-FC9D7AEAF3F1 + + diff --git a/node_modules/jade/support/stylus/examples/arithmetic.js b/node_modules/jade/support/stylus/examples/arithmetic.js new file mode 100644 index 0000000..9658fae --- /dev/null +++ b/node_modules/jade/support/stylus/examples/arithmetic.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/arithmetic.styl', 'utf8'); + +css.render(str, { filename: 'arithmetic.styl' }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/arithmetic.styl b/node_modules/jade/support/stylus/examples/arithmetic.styl new file mode 100644 index 0000000..4c9cbd1 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/arithmetic.styl @@ -0,0 +1,29 @@ + +font-families = "Lucida Grande", Arial, sans-serif +font-size = 14px +primary-color = #3a3a3a +width = 800px +pad = 20px + +body + font font-size/1.5 font-families + background white + color primary-color + +h1 + font-size font-size * (5 - 3) + color primary-color + #030303 + +h2 + color primary-color - rgba(0,0,0,0.5) + +#wrapper + width width + +.side-bar + padding pad + width (width / 3) - pad + // 6 + height 3 - - - - 3 + // 7 + height 1 + 2 * 3 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/basic.js b/node_modules/jade/support/stylus/examples/basic.js new file mode 100644 index 0000000..a20e5ee --- /dev/null +++ b/node_modules/jade/support/stylus/examples/basic.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/basic.styl', 'utf8'); + +css.render(str, { filename: 'basic.styl' }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/basic.styl b/node_modules/jade/support/stylus/examples/basic.styl new file mode 100644 index 0000000..353ef05 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/basic.styl @@ -0,0 +1,8 @@ +body a + font 12px/1.3 "Lucida Grande", Arial, sans-serif + background black + color #ccc + +form input + padding 5px + border 1px solid diff --git a/node_modules/jade/support/stylus/examples/builtins.js b/node_modules/jade/support/stylus/examples/builtins.js new file mode 100644 index 0000000..ba37808 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/builtins.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/builtins.styl', 'utf8'); + +css.render(str, { filename: 'builtins.styl' }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/builtins.styl b/node_modules/jade/support/stylus/examples/builtins.styl new file mode 100644 index 0000000..91e043a --- /dev/null +++ b/node_modules/jade/support/stylus/examples/builtins.styl @@ -0,0 +1,56 @@ + + +// color manipulation + +body + color darken(#eee, 50%) + color darken-by(#eee, 50%) + color #eee - rgba(100,0,0,0.5) + color rgba(#eee,.5) + +// expression node access + +body + list = (one 1) (two 2) (three 3) + foo last(list) + +// pseudo hashes + +get(hash, key) + return pair[1] if pair[0] == key for pair in hash + +body + hash = (one 1) (two 2) (three 3) + foo get(hash, two) + foo get(hash, one) + foo get(hash, none) == null + foo length(hash) + +// color components + +body + foo red(#c00) + foo lightness(#c00) + +// units + +body + foo unit(15%) + foo unit(15%, px) + foo unit(15px, '%') + +// math + +body + foo abs(-5) + foo sum(1 2 3 4) + foo avg(1 2 3 4) + +// literals + +body + foo unquote('X::MessedUp::IE.crap(here)') + +// inspection + +p(1 + 5 / 10) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/comments.js b/node_modules/jade/support/stylus/examples/comments.js new file mode 100644 index 0000000..f28270a --- /dev/null +++ b/node_modules/jade/support/stylus/examples/comments.js @@ -0,0 +1,11 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/comments.styl', 'utf8'); + +css.render(str, { filename: 'comments.styl' }, function(err, css){ + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/comments.styl b/node_modules/jade/support/stylus/examples/comments.styl new file mode 100644 index 0000000..9f9ace4 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/comments.styl @@ -0,0 +1,15 @@ + +// This is a comment +body + color white + // You can nest them as you wish + // and have more comments + // and more! + +/* +We can also use multi-line comments +like this, which are native to css +*/ + +form + /* color black */ diff --git a/node_modules/jade/support/stylus/examples/compress.js b/node_modules/jade/support/stylus/examples/compress.js new file mode 100644 index 0000000..e9b570f --- /dev/null +++ b/node_modules/jade/support/stylus/examples/compress.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/basic.styl', 'utf8'); + +css.render(str, { filename: 'basic.styl', compress: true }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/conversions.js b/node_modules/jade/support/stylus/examples/conversions.js new file mode 100644 index 0000000..b48e510 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/conversions.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/conversions.styl', 'utf8'); + +css.render(str, { filename: 'conversions.styl' }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/conversions.styl b/node_modules/jade/support/stylus/examples/conversions.styl new file mode 100644 index 0000000..ec3488b --- /dev/null +++ b/node_modules/jade/support/stylus/examples/conversions.styl @@ -0,0 +1,34 @@ + +seconds(n) + 0s + n + +body + foo 15px - 5px + foo 15px - 5 + + // 60.8mm + foo 5cm - 2mm + foo 10mm + 2in + + // 3.54cm + foo 1cm + 1in + + // 3in + foo 5in - 5.08cm + + // 0.8s + foo 1s - 200ms + + // 3500ms + foo 1500ms + 2s + + // 3000Hz + foo 1000Hz + 2kHz + + // 1kHz + foo 3kHz - (1000Hz * 2) + + n = 30% + foo unit(n, 'px') + + foo seconds(1500ms) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/functions.js b/node_modules/jade/support/stylus/examples/functions.js new file mode 100644 index 0000000..db4c88a --- /dev/null +++ b/node_modules/jade/support/stylus/examples/functions.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/functions.styl', 'utf8'); + +css.render(str, { filename: 'functions.styl' }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/functions.styl b/node_modules/jade/support/stylus/examples/functions.styl new file mode 100644 index 0000000..fa576fa --- /dev/null +++ b/node_modules/jade/support/stylus/examples/functions.styl @@ -0,0 +1,30 @@ + + +// ?= would allow us to define the images global before @importing +// the file if we were to distribute this + +images ?= '/images' + +image(path) + url(join('/', images path)) + +// or + +image(path) + url(images + '/' + path) + +body + background image('foo.png') + +// functions can act as both mixins +// or have a return value + +image(path) + if mixin + background image(path) + else + url(images + '/' + path) + +body + image('something.png') + background image('something.png') \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/images.js b/node_modules/jade/support/stylus/examples/images.js new file mode 100644 index 0000000..4f5f9ed --- /dev/null +++ b/node_modules/jade/support/stylus/examples/images.js @@ -0,0 +1,20 @@ + +/** + * Module dependencies. + */ + +var stylus = require('../') + , nodes = stylus.nodes + , path = __dirname + '/images.styl' + , str = require('fs').readFileSync(path, 'utf8'); + +// the paths option is merged with the general options +// so it is completely optional, however this now allows us to use +// url(sprite.gif) instead of url(images/sprite.gif) +stylus(str) + .set('filename', path) + .define('url', stylus.url({ paths: [__dirname + '/images'] })) + .render(function(err, css){ + if (err) throw err; + console.log(css); + }); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/images.styl b/node_modules/jade/support/stylus/examples/images.styl new file mode 100644 index 0000000..b84b699 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/images.styl @@ -0,0 +1,12 @@ + +body + background url("http://foo.com/bar.png") + +#wrapper + background url(/images/gopher.jpg) + +.sprite + // both work due to the additional paths option + // passed to stylus.url() + background url(/images/sprite.gif) + background url(sprite.gif) diff --git a/node_modules/jade/support/stylus/examples/images/gopher.jpg b/node_modules/jade/support/stylus/examples/images/gopher.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9f7f12b4750a6cb0be25611389e591a0a4d5b2b5 GIT binary patch literal 50615 zcma%iWpEo!w5-gDDQ0FnW@e_u%*@Qp%p9Z45MyFy%goHo%reBxOwZq~y06~PH!JOK z&6GwX)t>FseR@BZKehoV(&AF$00>9`!1Qwie4GMMf4Z62cmW^)&;S5{|Fi2HfGlF_ zU~C33?f&e6_*esk0$`z`p<$q5VPIgt!hXIHzQDqMK|q9uM}UV%L_z$YhJuLv4doj$ zB04$-20A(cK0ZDH@&9cQaBy%)h)6gnC^&eSsF-;Fci{i`C)!AWtT=SS=>tW|hjQi(<5v)n*@M_fAOH84ZaUru1m(^guGTU;qwfPidy*~d;x-oN!8;+udSgsi%SUKy zlY8V=J=JRt>+pR*q*&}Kp-HVz)c0OMA&b;Ry6jCXoCHnVkyKt64^+pBmT@|*$iSWj>n-Uv49ni86g<_yn|#R% z>bX#usoq$A$ip@T;QlWjI(OKeQmtY}$}4_GCSv#j_`p0BQo>YT1m$`Y!=m|mtX0lb zQPiMmr6L_Ue3ecSpZuuqvE6+h00LAc5|7tVPC(7R!t#V&>@6_c+3jxhC@ad?<6K{! z&uK;C+5JSJx+(1DX264y^g)(o&3REP`sTIJiT@i@)?zTF=~db9%uQaZZ;zY0&5C7R!zx&p(!cIH4`oLyL4sNP<4Hwo_Q&d53X}U{sV9)S zQ-7y@MtwR3cQ+ZKZj{EaQdtjVE?hXAeXvr4Tx{uH0_%p;sk|Wl`jG+7y8VKL^w6S) zL`S>>c2pehq6g4^5QJ6w-bLlJywuf2P)*w3L>HdB0OdZ-aU@fnadYQb(ar-Z^fXtl zDC);M9D8kbeLx?T88RD6LTRIc2J)%>)C74L_z^iEbL*2-{T-awR?-{*u4iB{JS$rs z;Y8CD7}Ne6Z(OzJJ+x+!iEeiGeCNsUoE0nA_a4;mRI|<5Nn*Sl=7OaxbKBQQ!bvn9 ztfdHyzQw9!L`0mB-17s`K;A{DjPCzTkY@|Dl_IppM)HZ9a4EgXD`;(c=N3ttq<5Ai zSDJ1NF3-q6VhOk)XeXdRDTi}eSkm@e9ZUJf#$1sqXL0^yw)J=f_XxvOi>U$O=8h zMyMH&eODFWev>AB8W(^j$m%u{PbXPio$czfIbPv_r5D8yMD)F#WAjO zbJ#;*}dvw~e?EHa7W+x2!N^`=yj?PtW#f;!-&5`w88*hDwNi|5v-iWzR7)3G6@>g6YnGN@2SoLf)7C92jHM1 zwr^$4zmu!M>bP%htV+Wq1*CRefEN`wxoVWDh+9*DLl!7(Bg-H*jjQD7>!_@QW*t6(SF_MB+MVd;oEoRg4tNj09md zJgeE<1N?O3Wo0%%61WOntU1}|Xn+1=?$0}=`v*tmoJ+?Q!ysm03N%T6b#FLkdB90t zc}z7pHP@x5$32p_y~+Q@=%Lp1IhfQ~$V|xJ$lLmWxh=M4Xa$_>HW+l8`qn@gP!s@v z_`39@?D7F1e%G3uV5)^4aydp4oO5_<2>SrYIS5UmD(oUZOZhGD4l(WeU3>rr^Q-HN z1yywdPwmf!#%-%~FwSGNS@7ut*Tx1Lz;9^cdargU5x)-|S})J%5p}Gm`CyKB_u*e~8^L4vq6kU&dy*y~&A@C@n8&;V8LfPj#*iw@GIn zV7;&RmbP@182u zuim4jPScfx;Hi8Zao0!QvX(rT#t!qsMNhDn^>}W*o`Cln^aB-NM_hpB#>ft1^2{HT zgb8DG7Gt9cY+cpDquZ1;$B_E4Dv3EY@9MaO0m;EtQEA1L5?$}vQrGfpH*DO4xAsWK z7tGWof71O<53VI%pG+ufekTvOs%p7O>G7#CNPcx#^=vNS4JGo1&*^k#$}KEYpn814 zQ+;S|LM~t2u;IBL*t{ch>A&*i`yQB8^&5z%=j;bex~M{W-4no-dQqfqqh71*CCgoylqC!de<&eKE`r z$rotnNb9xlQIM5o+l)hFg65?^UkOsSmg;sLKr44xXVlJ4^`cp<$c{|NL^cLgHUPt1 zeHj`eR{3%S<^RRofoeM3cxpIo}0lgQpD4<4!=@HboDs#^Uh`8HS295M0Wd*jX1O=D?Q zm#p$wKl9{849GQMI>j$h5HNXcje)~hd2B|XK@5e(4lA6;W(}bosQ#HSLys8dt2kss z_qK9O^weDD?YR&S>y7Z^jzs`THF$Ll@S+zv?qtt4*^+Q(#tU8&b(}8C(^S&yhk97z zW$2)&VkH8ku(_MAvKVI~uRs6XOyVM#s}I1hrQEv@fd9L|x3s5%H_g1B?tvJ7CyBW7 zJDCR6Z<#EZLl@rfdW25ns!zai;y7+A(`c&9D5>}qPp6Q{-c4hYfWdr;+O~ubfb$0c z_}AwLaCkBYtpL6(;Gy=nw?ORB2f#(|m-ejTwNvRklRf2Iugv=>TumePTlYItwgVM8 zCsTSZo>|j)Uec>&{<6cj>ol;xFa(^VVd9qb2uWm@SnAM&qD#Tmr2Dxf(WF29Cb{WM zix3_0y*lCNtoE+W^bhEEU1H)Y?~wW4s#&?aj+ZW&3BjfecgXpUk5FnCYJN&SwWMqO zunKgc&{lC!QV5#CxWWH?@5-M%8qz%XYTqSC#tnA>*ewP`MXj3uHmN)w-1UjpZRJ2~ zv;9g^25E3DK3y!$BjN*crcDa3R?;d;Z4XzI8g@|R`1yq2CaZt{{)2w>7-GE)G?bn( z9o)Vp%ck-HcaesjHG8foj~>-z8px<)D_Nv?MCC%gfcl2-MA-DC2)~vefaU9;ed-tz zU?~AeHCFZw9*wL#LS$?vqYqTgKH0ujSF<3?vqIZt!h-m4u`8<4R)Kc5_9tZ?M>uk3 z*n27^EjMlFIYL_|&E>f?kyisC(*v=eF_X!k%Su7t#Q^>MwyW0&Mp8N==9;Sp*E5$* zPn8b<>GkWZk+vE&zK9(yL;0>_*viJbBez#BC1t|dKh6%-^S_rx&KqM)bR#^Ly^yO= zJ6axd@`5G;U6T_7#EuLXw{uUoIn52zd@fzciYOyE=2XSn|DNvqssa5yy<>lA}7gr;HM#vR!*A$sCd%9T4i&O&Mb z_O-EX3sVm|ikZemXGV#^n!2%Ct+BYF8(1ZjnR#I08Ck;1sxv! zuirFc3t@1Kv_kLfyZ#@5^Tx;Xh6wGL-)k@YjGP>G8L{=BF>GN6X#AamqVjn{GK@Ee zIQpGdvoO+jCehT5u`7a34W9vbz%VI{Jr=7uuCXvFw84H53b-yBZrt7h8K&7V3l zua-EA+m#b%bH&B`-k{L@`8*m1A8NeJR~oHtqko`-^brEb`dKoz)}ZDJt8zB0JOgwI zE+Kglu2cO(eI~eMeKIR29+HcgBjVD08Kg6#Bj{}Y=XtmLeNQNU7ZJ`Cr~wM|@v3q7 zgv+u+8a+Ke;x?ZUV1^Dt;_$B%LsN7899cQNC(&%Rp_VQRj{uJDeJ9*O9;c4^fVNmp zkeZ%q(4YCu+^NIw*o6j7%})mj&K7*e>r!xsg*NkM3$EO4t-iVj#wcHu%xWr*ZqzS^ z((U8ra%mGdMLKtRp}bQ<{0)0TxI$8NH#P5Ib2&H;XqIehpU~*?(t+aY#C?@&$c4QH zUIg}RvJzqKbOj#gyK{&LiiiC`_$>4D50fd{%`xrsQ<7xHdBjRBmHv7r zf`{Q7o;w#iI~cim3l zo3@q44IfwB@F;pReox0Kt)KP_l8JEzN`;~2-_mRW6A=^)MDs$*MR8r6afUq{a)1N2|#&Uq_FUiLdEZP3_JUh8wyuj{_cmkYb-|2 z&6*Qwkpfp1%=sgw>$p`2x_H|k0EMom2!){%zHtu?W9I^jR7K>&*Sqn%)=3Tz^ ztrOcjVeGoLwvNg+EA4?QKJnZ)K>C*ZX_7px^HwKFIcac6#K(Wt_dWGdv#y0;UCVeV zdMPs5owq57h^vwexZ|u;PC(^XhJTEymaSuw84<_t_K+sZm9$u>v~c<4&-G%@YCKvH z4-=*!UE#q67d_(SOj?H}Doo_Q7zs5(I5XrI!IlyS6AY@Ue3XO#;S4A2+Mz|COqs+K@(ZTwVs6-gR zBK6eMiO{j>BU(fT-!XvuO7^NR%irsR+J!4nbt zRkuq(wEERl*Ff^+;u%8z) z4PGZwZElfJ42T;;?Ya0882Q@C?y({njb|#8>npK7?n`rZkY9~JBxLEVjG0TZc|Y6A zv!8wB-7^Yq^MDZCX=KwptK>rUEpqbPh!`=$G2+5*IDR})GVbRPqSZ>FUkxz|gQ%<) zwuLF7oq%?*v&2)xMX3CY)&B|N|J|WzL-AQbHk1bc7t2V=`YDKK1qgP4N^1z^KQ%{^ znB262_WGO@-vodB0z(az3X0Y~za1j^3*oP&n%|s^Kd^M~lEHnKc->Ur7z5&d0PgU+ zn}R);BHwdwH_x_)s^0@{yqPqA0CzmoSfxQCkhrX@6n2dOy^N`Bqrm{AwhJQD*S;rj z|MLlc4}8*)MyKCbB=h^cxp$v@p6U7{3_AZ0=u^RsbUhaZsj9; z^_)q^^2hv&>*nNH&8%Nv!(oW9GJAdfR+kcL2;+hv5izpKRxxDAzLT?(r<1v#XOfHS zo1i>CEtb3lVZUvmbSR1T?%NL}k@Dzw1oVb+gT-Mys3Sp(!E6ip8v=KHR-o%p;Xs)h z>Sb*UfjhBXdOy`HjhgBc-$|P>8AnQH?}9R%z_w2yQqGuTll>rl`29R5D3U{Whk7*8_t z|NGUA>;nX52(AqT0IaKdOBZ>%9Q}E6ao=_@r*)UG=VIJkHV14{#zu#Fn9DG08gtuz;k2kd>N>^rZ2sIWKW>+1}@HaQ9(QE$buYF|HwZJgO zs`{*k(|2WEdl8mDqLX+_LcF=TT3Qc;V~E3#|0d}rmk#wfPw)clNQ6JxWCx&eS}nG9 zTKq&<$I6nSK1dO_f#eemwd3hjg5o)f|0LFzm@i@kY2Olh3_D2%9sqBG=_-MK1T=|WIVg9=AGN^K0)2h?uK`^b+aveuU`PZHe9C1-{BS_+lPBM|fR`5kju)Q%(LxUEIb6J#@O42o zWypv055RF@v;dLf+MRbvw>N#cWe2V8*Q-&S+so2!NAZcf6yvkR zHWC|OAw{OHpiQo4sIfdh0O2Cw#!qlP+1Ef&P`_UzIn zyQdhLUY?7yk8-Hp8SeEG`S8D;VEIRwYYD_{kpLe6qAs^|gv>1!=^zzq+5T9V`%L}6 zA$rrgFJ`ae!PU9l5X4Kelvf8UB(IkAgh}d%ND;AOg&~g4+*SjusI6*v#0)e>hD20s zLK~+UE8AT&;*9Vn#se7%t&}V9cX{4z#D*T`*!cbY{?FwS!gqwb0gNUGlaKq1{@Hgf zCt6!sq9f;9AAptSfq!le*}5;RT@<$ZHor#>7@O{G{QXy_s*~~zcMhiTMp)+T9C()m z_QrLqSe*?lY-(o9P)?UYraw&*7zH=|%3}HzLaxZgR{kM$Y8$)i$>ig>U}P-wqAl~lwDi=hMlQl6f9GMn72&(5Azs>IruO)Jn6Tr>FHEsRS!(FN%)Vnz z+#hcB835;IPa=obvJN2x#T96VMl;Ykk80hqW2mp)I=l#9D_VdyhxZ2)OVqE?TPwc( zAAnWRchAS+`gmAS_Nz=lyq5}i|2XHpa}?eF$(K&gEPTYSs}kBO(@r8)d|lAh>! zAt1NccS~@BKA>+c!je#YyKP9if@D(TN?ew$ZdZ~bTu%V`c2!?7dhM7@yh@jqqHeq z?CGyK32}IPrt7~^$GH(NL7tntAw)+0LdgcTQ!%%6482_AEEqe&IR?Q8o>lvMEV$`K zL_Y>`TYyTRWf=sp; zlbNyCnQRGYP^M#k<~+)pBZtBhXn$Yu znzK&-pw&M>LnweFm06VGZg!#SB=vfA2}2~t?xyU%w|BV{!v~Rsny4bd8vOf$&5#jbR8b8NKYnIgveHpXmMxx#g#R#`zzdfak`lLO z5%iZ_QIgL_3bxqEmtu}^7O8YekGA@5Zls&LnUC^I{kp1A%*d+*!oUOvKzM`_;9@{>f zpVraZ+jzG&yWDRS=L0~)^-s=jOt5@PDETo0%vUB-XD#(6%urlCwxjj%?RU9I(mxQf z+?l3koBI2Z)%8ntXiq4b#b|VKSUSfCz_7g2aA2#GuMW+AXJ3b)T#QjQlK{mYd&cK= zerAeB-HCO3IBhMlTj)y7i1eCeAeNk#WAPb}*;3qH>=a}9mFBsA-fES{afL8$XEy6s zHtjW2X+%Qhc0;{WPW?|1?b96OMgu#GDX~X!n1W&eoe&*`IRq_<`)c35usr@ET)8X z(vdxKX8Kg69VMgNl#sRfW>3PqtFjn31ff7(n|>WvhyBI+5Ow5$7HylbV`vkk({AcOZDIiHnXzDl8u zqVtjB-_M(MY4`jbqW0~lqQ=!&uKamX!z{)k-B06uCh}O}?y4~i#iLm`>Ks45FyOId z*Vh}_{hf&^X&_mRr_+yx#)yK&jAaQEW@yU88ilaUV`(y&oe$^f+DHCW4p3`%l;;BN z=@<`M1@%m(R+gQ?ZDPEbba%SiExapw>vzanCE39S!AWLYuC-qM+b z-JPj&-JD&Ox}hkurjiu&ZOWAQ=b@Upw4K~$OX7J08p9#BWhiT&Z8Qc!UD*bz&P`_b z8ukZ4AZ$HW!F+l?>T|;a(1n=X z1+m%s#4_MN08_oiYfdvsgDHE3UNessSss>VkwHX%NMTpiu`}_c8=crp?+x(ZPFTm* zaWC8X8S#%OSXxt(7}bu8?Gv^tk9_wRYsXd75=Y&IPc@_UfO_7WP3@q@FL82z)wn=J z>@~JVUR1;JiEHgg!#QQh=3eHUbGdU5U&x&IEF)e=10i*| zu>`$U!n&89mZ+a<$-8=*yaIU)s{}eq$h@tc^%SO>C}-j~oy>)TQ)d2r87q;hj=G*} zSST`ZT`3+4lF8C>A{*)CkTW781`t1rhxvMiHei(BU;A?fIA$zIa(-H)lz!std_f9$tnOGQ>hCo{9;0C-e5aOSEJlmqg6=8;YSW8OC=xO}3 zydA}&&x(@Wp)d)5DXgs}jEOLv*EE7dU76ryJ3|C087h?c9v9%%xO>N=My{Y;INF|sp$UtbyeoE)WR&mpZX_1 zHyHDt{WS`gc%8vvH=gSu&UI45?TPzs`dVh+v)da4iGK9vFTtGl#9;!gnrH847gxB^ zctdV0TNi!=#a;Z`SF5thmRO$^(yvEUh&0ojT$~#X35UlzSq!n9@pLUl=1PL+i16PD zpfw`?1gr7yts&AWuCMaGPH!C)q8v_Snwk0wR0O^5XwsAH>-}qYdDX|}sA6jYpH3*S zl+p>XcijL#Y4r*>KTZO)*!`&7zuM@m7qa$LkTxJJU(~G>vJ92*DzY}mbURI2;EgB* z>m>33hn07`MgFJ}Y3pnhuj^JibNa{hU1+dx50+dWGgH_>9BA?L^fNCEFp8se*9wU~ zQCMIRO5d%$QlB;ile)MPzD#K@)X{WxQnjw#W z7axmG2OEt@F8SyCZu>F83a(8QcQ`p_Ee z;4?+Zo_;QN;Ki}w05Mx9_*s>4og{63m5eU;iHbE`tkndjHguu)(U+y|M?|xQqZH6C zU$&;jk$5n}Df$x^Vj*K=*SwPNF2 z>hq)T25f3F^d?5)IkzmSzdx12oangR{~d2Ls~D9PI;u_XUDZ-d*dyAiS{uGa2 zQ@k0}aO}97gT9_Nx9f^wq_oW4grhTV%1z#zm|yzNcK*KIi)w5Veh&e{x~VuTOxSwd z+)mY;mlXJk@OtbAoYy88wtyj?RfsjHXVMOtynZCmr>nny@d*#V^$|Hy)#8g-8OS81 zv`SPcTH=5o{(Hsk<$EYNw?D3ivY~#T_oi1JGch#KE9=}-L5~M?cV?rnl~rgmH$c67 zvs{3(xZk9oeYrqd|MW1zl^yb}x==uX9#Sdq;d+DelrEo|ZHcV*gcV{L%7$quEjaGG zjrJ@4i2t(lhJ{oZ_wY2|`bG3i$Rs>Z{giVQZYWNplM7RmSGKkKxr7#-;vrI zP@1lErw~(e8~!SvuUJ`E>moMzTd_c}YeFN3)zl(+b`XOQUvvYKcIOb}c6!3o8xz%asRYJG&=MjHG0hvrn2>4xBZ| zZk?X!?3rNbYl2@YV}%;S6;x{yzf$!?1$om)LHFtU>INmmB}mkY)#>VYpKNn(rj_cK zZB1S)%B=pJ+-#`@O)?9p<)@f(lAt%uDdd6>dS43#+aiuvkzTL+`EGqjLH7i^vFwM@xMP8AGRgB9t(YC4<-v`4!Z_9aU^bttH?0 zDPFtjXHnmn87L@rVzel&SNusVHG{HKvqI{T+a>N!8!Zv$4E1+8APZ1@O*`K0c&Hm4*>CrlBAk(>*!i&GCijPg{Z3#!3q=0q&4hkLdHfKojqQw| zoz|AR;^T+L;Pmp~0dKd8OJfPlO=kH;h?MrS`WkPdf9|A+^rQU#76b9SPgG)AMBpR!#2N(F`$*|0xjh*G9RCC@g5MoIplt3&%~4g(K=dL7IVTfBSu)o zyL@8W+9ffh(G_S0#o|$5e(c+*%x}+oHP?!At^`eIQ_tRg8v#E)#hnE|EXLvlzcqwj zoQq4>Ed7uGO`1tX(E4&}R!JiqQQn4&CZUq0a4; z7iXD6_qapd^x3ix3($7YVMxbHBm^0?4o%nKbG#wBJnT22XyAW~yf@>47HthE>1@1N zwc#_-qQ-K^Mqa?je<`U3z;-jP4xOSmRy28$oHgl7Ig z>nG+qu`b=v$YXzcJ)LSKVr32QN1Jd_dyBjcX5RI%cQF|omXF^B1CNYg>A&8Pr95Li z4N1LvZStS0#AulijU=ri=55~J&P>feKPl|2J2}6-awLQe>$E<;mOEI*v|Oo9ji5-p z0m&?bFI+ie+u18@yl)^eg8D#P#yBY?lCDb*WE&jc@z44a52iE5IZIKZN-FCrc_|GSQ@rS?j#x8U!f&2sF@BhW8OYhvJHN6y&KqBrNwF{~%<( zgvcmO=tk{!t^s&YH1c6Q{f+H~NQmD#pTjVWClcUrr~cA%2bQ#SCf67eIoK5_qe5pc z@UE62eoG%id!gl>tufwO=7w*fOQ7lOb9z?SQ#{$|*u({yHgzrz$XF?n?tTCwCY^Xd zaB*hJz7Y9p$27mj8e&w=y9Q&4{^%BC6O$3)epfTOJ&^@z^`EtHSN&`QI&&VGi2PfW zu)kVyPhL(vQIQ#?*r0=T*lGC3l`nl1A7@B2M+#6Ig z{`$a#XkpK0-e;Y3H@WUAj z{4=;JBzkaMcm)-ehFEbnJw@qUcXDUj*&z_fNIf4S+DLgnnT{*q5gF&(mQ7l&g&+Q>6e7Fl_4DaTrVU4ZGn?`d?3mmnNZz#i|_IEa=zGPV%Xg z{a9h?zxekR&bJ>^m3W>4jU8O610^utpWa;f-qdhg>S=Wh$Oec&YNYW0IGH3$14IL$ z^3&=EKTioNJhJNdZ69{ZXXSz1B&KD5vx)N8J(p}D;2H`AjLJ6<`VkTfC4~<4TA1>% zl+JJFZ*(H(aPi^CZLpi_{NccgVPuQb4P$KqDKmISb!sq*911jJQEnW-1y&RvKWlit zbKzcTHp40{-c{siS|n-l%Zqgkt2IVH&ob|B@m7`XaSdI035P@ZO;n&=1hC95q#QMo zo%L9-0e1bf5hHD02h4mNCYjsSeeuT==n(XR66^zH76toIS(|vvB{|EyIg7%Vy3(`- z!to9Kw=>cQTj@=8*A8X0H{}P&D>|c-v07Q?UrXloRkQ@py)dBwWgb}n7hnzkfPj8wyJQ(!|9^4N|S<4-APYC`EE>&ai7+R~}X}R)-|moe8Jc26Moq zG#=TF+9NSqHq8D#hxQDW4KsL*S~J+vegWNHTQsxm>~U)?D(v6p5~uKp#lbL&?i@}; zq#gYN!RzSJ{K6!*yIRT09HU!>a7H5kk(M|xgiGKZI4l_66qrYYdqOi}Qo5v&q6+yq zjr%tk&8|H#KwA&fm49-wf5*p(1okhcz(ZsOO7gR>~}+ECLOuq`k!pMuXYR9g*-_ zCQ1@-vV0AbsOL&%i*CD){^0tZ1-7MjM`~qy=t-JiiwD7*o7BcbHXtx^< zAM{fX;&bimpWXF(m{sx}R*!N;pS4ngLln5$(oMuS1pP3tk{mdgoGnU zZTo8T{SFDf921lMqG|V$cP#iK*pKsc%RcD93=Hq!>dU6|!ud;q-I1^e*1-xD8;-_v zY-q35B2}I8ZvkMR0q(J1TdzL~#ho{w&38+VVrz3Q$jjv~h^PV#JyD{$q2 z-M^RIlE3(04P*jQgU&|tASHko`IyCRHf+C!BS>o(ua8y#$>EST`?$*+OHm9c2p_$V zvR?{3PRhh&AdZUWd%jX{;BXB;6p4$I?eYc4srUHOI_|;t@3S>qh5NH-%G@bk6&u#0 zr;Uv7I~R;4h|t?F7Q;rM+IP_I!|p+7qF&DCf_{yp%To(C&XpAYp$gQbOot_Ei}qi2 zkMKDoqH8hT749KlgOa188+FGWJtKP0WLrmPEgYG>tvOV5h}z*R#tdmxVH+y_;U_0g z*E^a$GA4$jb%n4d>aS`zoC3##AEp5`A%>*Mn41(Mx+ZH;@`*wZ!*-!a&@BacqKc=L z@wa5T+hCaZ+$l3s&m0G(t!8mbts9C{4bBfH3xup~JKP6ndcsTmdHQr&dln;;-zKs* z&~p$AT``edbJfu_ob%qkB|`{uUCAbZt2=ep2|3t}zM9=nDi8wbzO@FrHvIe2{OGIG z+9=K^dN{0|n$do~;coo+^zE$aQ6=ct3pp)W2C5m)?4IsiZ{M;Pi{U=Ri0Bltf^#%1 zBaUx`&3-R=gncLUY+s-9CAYKvJ-*p1oHPOsFv4>eV2aY$dypEkJe6E9knHhu6*Aza z=+in=RP#3F;kDwoIJ=Y&mABeKmAqv4S*@~N{m*Duf~btR8YrwCZwqszsACD!7!<>~ zaBQWLHJ#&;hT}PI%$3=#y19CD# ziPjGMdw7*plexvKn|1Y{o#X$Uint(jQJNm{qOZ!{ zdoyrFe4U}He;(uSSvznCERXYyd?grvdq5gO!#hd~Zo95S>iJ{755G zCfZ#Kr$VZE{Iz<6t`B34zp|SyhrvtoKB{Ns6I>IK(KyM*+4kwELGHHj`*RdZp}U{K zortz*a>pI-{S8^}i3wDg|NFPZnP}@g&Yo`s-_FQU@-K`;`dRxrf4CNA6Dg=T&!(x1 z*o9!CgW)vcsN+mLmA>>*C+WpQZ$}uLd~n`!i0ZKU5bX8UaeX77!eCz>(DId6g#}T$ zwrG$LHhEiiXNBd7f}Xv(h$#4!=q3&S+ghAJZ_&JFr}2Zz@V`owy1O@P26{{e{E`Hf zdASdO9l5b=FnL#P<+CDte|%pOE)rV)BS(pPnHK?*^N&&NA;U}b+oT=gh5T=@R>n%~ z(lOq*W&Ot*_qHN;VJfe^G5GRXL;@1ejWsuAz1JJxcggX!-Mac`LdGnHdVJWO=?seM zYwl40{*r2F^+d5!sx*uIlMHwdnRYA1OVERYd)MBK0wz%w5X3-29_;~}Hs_Fx`a`DRRhzkQp<@ZB5gAx+?n4xKdyvy2l2ozE zP@hyn)cf@fjvqsJ6XQS4cCV%ElgZlk&O(%sSF&+^s*Oeg)}P7?)m+nU9&dJe*UCPN zwLlPZy$>C}UA{QhDtoluXNg@r2SrCIA9pr2iMS9@{fA1Jng`Hwe!0t?LPuX_+BD~_ z4%X*ZbqOFvERFA8BegH8Jt=y<3>tA!GG%5lg)_POe6Hx&ggiTm=$n>`jg3-q)C0q& zy4?}ci5rKn94%bt6C)pnDnxg~8CcEVqL`a$^dg#6s%mu8UoCt4&bjY3VL(1JrbiGq ztwdtql3Ajecv2a&*ic6QwH9R-10hDMXi|qw)&LAY?wO z$yZt!nqH?rFtw{`R`Vh1AISNVs5gd8&$Wsh=s~gN*6xq-CbR6(f$3t?N(7 zEOU&WIvi|P_hj28j-MJeII0L%e4V$rzglB))c*h<$%n_rubB$GX|Co2TU1k((6K)t zVCJhufeOSB5J(h-xEOe>9#LnOPz;@DIpsfw=3>E&VW<(5({(FO_-8AS&30g!p;f#u zMvZWf$T)8YFz(InZ#OI|`Mv_JrN)(b55pl%L8cP1CqH(C>#np1X#7{n;r-;8`78ps z^o=yAu$?jZI3{rT^Oa$$>sjEz2>$@M;={F=Fkc(fG*{+%0(PpO*+2*G4sW_4!f7$0 zH&J`gJ)F^hH1n8TkX*0^(`H(DJ)-5t{%XR_RYhCN@THWnaQBvOLZH|{ZibAb4oS#6 zCij%?JyaTM11*yCj6U^@Q<~G656Gj%K^AdLkCex06#a&Ovj2a97 z0OX!W7GWNITUPenMi|x~c750NVvsy-(_WOU26HmGIV3W``gvZb00wt)^ElZmvNJ|6 zZNsHh3l=|dWj`Jq&+eObssXt?_IsPF`hGN1)EvpB$&cJwSV%h9(!rrqw;>S*{^Wij z(S=&c4356)jjVOBr-1$+C6J@qlI*9z(!ibXqYFlOJQ+Rh z;07Ky=qo;|`C6emDiRPK0S8m^P--k`Psxj%uzR0xkm-9C*tQ>|5PxOrZ_oJ?>HH!8 z0BRY8vPML<{{Th7R{7~udc{dA0}m%2EuG-wM1fSCf``G89>2g?a=~KV5H24_D6I&yHwghZz)s ztFu`_H_(!ND;vu7ddBQ*PEQV3pIKxA({8eh_$Vh)QZ)YnU~r#j%x#7RGGoe3lyxe4 z8}+?kDX&HGI5_4nc|h1k=+~y(^{t~i5zONt%wKJFDiMl{-sbfkQi_*%rq$9wo+R6w}o@{T^y;M{{X;8 z$Z_(N^vxK!VheQm3aQX}d%2^|8InOFoythiTCP;oJ{ydhT%?H?bGP`>YH@0QH@G9n zj|4>4Yc8K38k1Y3?5@YB*-&ANmp>ZI9FCKv^+!=U7%lCtYoN zSOlcV!OX?9${C3LY2XS>X)%?)+#hfGde8u}pOHB&)i2;^0z7JGE|Q^SZyEwtL?>Yj zb3iqW&i92!uj4>Ti-~jfFRQ@Pq-X5s`;Tu+-|DRN-ioz)FFOj<3@cE0%>{*e29*G< zK*Bl;(0Io0g#m)zl5Nvk3cS_%ue!v*@zjuT?FJx52*DA`@!>lVyK_SbLzJSsg~ z`zu*F`57$FD-utgITKM{QGIEa9*-h2wmSJxc*p>^z|bRKVK;o~`yLz^pwyN%D3O!r zK*LS7zH|nO3x?b@)})t?-ob({Ip@iJp{^6pL0I+Im2zR_h_ex9@&$&6{AtS8#<=ow zQ_SAYgQll#_b~F@NvigUyrtu3W?|$Bec6np6-bT3k1=%{+NR=f7ygd%eC9Ke{oP(5 zqSlAkBY!AZnRkAsm!wv;=fAbg-sT=LQMTeKWLA54v#Q%|R#aCj?x*0aP8H-JpMKtUrdjl%8lw_deW3h=yZK|G0&raYLfWP61-=tYf3QBKYH+m?&& z1_v)IBr<}rHqyW~v?|v=HH8|xcDD;QFFPa|Ae@VmCG!XAVOPQ0>M@yNju7A>3+n^? zD@$@FPblywyzeuvg@9kuvzJFe-SlxWxJj~QgYGj5nDJr$E$5-|>057xQ}xcfJ1dq) zn-?T(E4EK+;FK-;_|#gf9VY`WR*ufPj}m|KtorF(rlhDX>es{?!>2?wl{_Az#=wgj zn0V&>&Dof_vrRHWvb%$`KsEg;w5(D%AIJQrKQZn}7*LII`)TT9wQwD+fax6hF)K_z zir!UmG|%L2-^%3pk&A*YZ7eDDIjTNhFD1g@VnSj&)qp0|C$59Uv6GIDSB#QY{VB** zI}k-H59!36OWAmQ-{jQ5*W7^1YBN#EV;PLEuC2pjV&5uBa_2PHz_PUXwV+~{0%Dz(_0>= z{{SjrE0CT^#p7!*@TUS4Jlv?lDM<{z6u|!g7tG_8w3i3MmIbc}q`2zne{~><+#FU$ zL>}}C1dHM-Z$T3hO#En6PhtQ7iamg|6Jiw%ZMcnAiAvNdY15fW@c`I@}TGr3GG9 z{Nupp;`ao(MNhRQ$RJXyQsDZ|N>x75-J z11reT8a$hipT>aDb<&li6EPt7qzVPeBT9=#FZeu5%^WzN>6aQ3FZ(?@cMYHD5h296f-ii-K-HZ{A~q z3$C|~O~=lcU4Zy8v3WnYe9T|@guHUeAEmCQ+Jn}n^wfKS!W?Y=sTg{JRAF=?_XQ95 zikcm>hJrlITs}nGd~xhzJiG_SuZRY@X|#<%{-d}A`CMF4)d>-pC7gJ}68;8Z{mjHmXHuGxE#C%p*dlz>!N&1987A^EnxQ+=+M_LT^m*$v-K} z4o507BT%KuEoyv>QOkOI)|52dPs)*q@WtDafB}2Br9-qQA1TF-MtzB4VmvM@9)W?2 zn*;8Sa_R6oQwUjEoQzV3iO#)60PGx-PS<1VA5z|^9)p|0if^}=S-kH-3%4hWCL5wK z-g;1I*wQSRtdkutp`ZuyoxhDXIiDQ=08_|N6#4n?bBfCyN-m$WfVptJ*%u`O{ls@* zH8fxq$dd__7?V@yMgTmR98bJPKqsxJ4WEa}ko%Df3UD5NBNdc9%01!ZOc)VDt?k?| zk)SLbR%lFbXvi)Pq=QpHtP*B2*Td-nqw=Sgns%IbMJBYdlonIsA>E?6JC?e!k}SVfrUWEZ$K&o6bvc` z6$1#+F<9?z%fap(2_lv-Wh-TW8bWi956b@l+xImWyDmSd3zc7mENeS+o@cUo?lxvg zv6uz;8cUsM6!;lY{{X2QFX(AohiWm6l-vAtrR+4C2O{>POxDR1^rJ?%Sq&O<$@GzW z6Gp2NV^g?zikn6a@d6)s9*jI{Edz69#;#T8lW`+(Q_x$bg=bgHFo%vak9IjSAr?N< zHH&;SrRy3|o;7ihiE%Oh+D(13iG99f+;%7SQ^qweTn_D;EwXYMu;9qs!m0MR->*S( zK6LyiRw%oxnd2}-lQC!zEI5jnHn*ngJbrbbskh|+03qWJ9~x}wAAUMXtadvb{VYMf z{xx$^aXSOJIG*C|zC9J~lb0XdF7CI8=&kWIPO5Qb?Vcwa8d8Wi<4S}hjX>Nk1!doA z^#RB25eFwZb=up?s68+L0G(^kS~{3J#CGm4vhYrVNnkJSvHm1JtNxW*jafT63>R!Z?;W9LQjET&W9GG|oG%8rNhZPN+9jGvAeFz;dzDha z8;kk;X-;)Lema*I9M2L+r*P=Qz*Wv+N--udk|WR&(0pj?!%5{>=J@PsqhQ4Db+eJJ zs&wy%GRy5~(s@0VI+O9ePfC|Un~s%BW0ff028dK6Cx_WGg&S*rWMZhOr*+R zbx6NKRmjzOf~t%4wNPphvWrjz_)#P|(K-5VEKN^TYkj%r`0~bqb2TIHI?;@NB z6UpuN*>@r9dS!w+d>Y0Hm2Krf#d>}MA(8H+yL`uqt4k8_oOV$pKlMkA3HCKFY-Pj) z#W5g!YGqmIa5CB;hJRN=DS=pcE=4h}kGNZ)H3V>7spcMg-E@@MZsVS={G!=ook8bf9_xqf5VthyxgjPAP#ND%>5m5r8 z9)&>v0Cg)5+0Xf}`*em$S@9eJ;1B-*N?3EHH=Fzm+!#vF0QVGh1FcPqojKnx+Z?wU zBS)2v$W+?oQpL`J+6KO=LHSU))WCmQdS_#IQ>`il_>&{#0KZW;6%-CgvbItrS9jZB zH2qEOQqz%c-r^>i_bdx24YbJD+zIP#YA;IZ(>rg0!orbd$j51UIWf4O7y@irMZLd~@u;<2ti7w>l0HI6ztWN? zF;9$i@U_M3lj$pdd37~>ZdV`f;Q=NHtW(4~oBqR9^X)zIhm?jsLmnUsFkSvZnV2ab zt?PYd>M_K#B#h{`+PaJX06Lrg`mbWdjBKCi&c&<=Sc3d_{{Xs)(8j#ZQB03%4v@ug zd^a`4W%TK%FgG(BA^6x)NoSA|yQRx$MNbpTdvcCfwc8h&5v#0XRT^CS)L(axQhHZr zOlReA?YwLmkzmPSWrp6==Tgeu0r^_8(HDL;HH8YsK(X~NO+4yvO(!R^nC&cv{(cpm z?Q$zz(j#HaWGts?Af@#Em0Z*AI7cV>2bJQvR)u|Vt5_3$m+`CW4oq@?kv-{zs+M9k zB8dvLgYradf;nyo@v0#RdyfWpMo9vb*7O*H_fp3u#yin^FrYS0^TLJLvuJg-01uz< zJQ-o#j%_NNf;!L~{{Xpp*W}q9v}MxOPy!3M9}1w5hi=RMv<0gV8XTM`nO4rEYAQND zR=jTFP6jlLuHhgAlUYS{-2P4wz2aLBg;5)y@@&}*q3%WXpds=-;+wajr=?&z_eNZk zF^b~-DAZUh#&?cM^h(Ef@|u+hXLETih9-e_xH=nkqu2{}$8hsYl>6mCP9BF~jPy@Trh3949gT#~EOmHi6LmzI1g8jOX*ofdWArYPR`NB1SR! z%q-kUT1~OYw)N4{qBr-fPw&3xyZt?zcX(d)m$#F8I>Nmjap71|qYA=}7*-T$!my)8 z6@?lwtSHfiVMdHA3N&F_)LIJWkRd_FZ9%Y99<&w^08lZ8MPX(apkNm_**p&}g>rGw zvGE{Lik=i6Z}1lhksG!-2vHP;RW2XDOjC~_rJ}$@kMNd(rtIrPx z4-@S>C;InjCVQEjk<;7$5%D#TQndYDyJ9T)J=vK1o0uxdz=cq~PhSd>#f$9BShKr0 z_oM@98rXbEpuJl`G*Bwz*s){yA1HKef?2lBXhQq3G$ zNCG$^au;2U7V1y?X*huG@$YcTFNKsX zJaLkC&fF>LbWPGGp8W+Tk`8m@X(<6e62{0ZXEd71a2IyH1l ztgnSJsur6L0U(Z*SZ&tq$~^6@7;dB4yfIv8%(i5ER(&gzeeuW2`O)J*npgp9j$!n# z@_n(N$6_u{LJw`aA1bUyf%}5`T8uqAis>xB)ixCdvSGo;GboG#YIPLkTs%vg?ywtb zJ?X5l;XX`a1yDzU6yYrWwZ)D;GbDr(dM#D3$=iR-Jv)6aRx&3^rUaPM~%2WcN6#%FOKq>)H3V>9>T7XmtRE($v zKq>)H8nqOvJkdnr%z%%TAr;<#v-l212K$V37wT=TD;FFu@(&Nh@JoC|ATt#{9Y^n| zk)*0$50&<<_gj73fNzW&RFA`TkBv`v%UI}rnZ`#vU)?jruPZn&ET2x@-%LR3rDJPI z>3nQ~aGg)8P}hzW7W9+jddirb{`8pehfs$5rctGr|UOTx_B($Aj$@Jy4U=+VudKl^j{6AXC_B~HD&&STt zmT$L^kf8Kmm&T{vbA(y)CP{*^-ve|ybUtQ@(@#)tL7v4dJ+N*qskK)EU0 z<cixE=!T&QBkyhiLg zikZoW@txN;G=&+D#MNOek@q}#7+?v?NDoR1MSHpVc=AcV%F>My{dgiyA^dXDgjUmfK&pY6#%FOKq>?(W>kSt z3V>7spcMgvG@_g`>PDm+d5T7-cYk)^ad?tEvJ0ruIul4d!QMT`o6mCILqDTXyaX z<6QdN)pX-BuK~6|$;eZ;CnZPp_kSXr_fh8p;`kg_%gb{$j6|RvF_WSg_-c_M2-FYOwv)m?kZ2M)c^`GG53?Iy=Jz9|XP#BigjoLo)M+0{ z8b)GAg4)CPQ^f0B<%uJf=RzEhfEEIk<{av|-#wTTD8y%M$k5D(uh;c;@)gZ*mqg}b zR%a_DSrduXUmw{UoqB=|$I6w0M7jBh=i-+nHu8Ww0)K?)e`RM^A`|E6s8~E~1F0%X z{H`?>QWmo!v#**Fsqh~GPo35O01Cfx;)TYMt+{m-*UfWw;+*_z7F>!4U2CV9%7fW$ zb5#>sKH6Z>xjIt~fn^%eft8U@S}=^rZgi$GfG#M|K@Nm<6lsg_d9y<}3vv&YD+HoE zj8n>F$Z=)X*Qm@rS4_Iv{V5YqbokQ@42_MTrwdn(%j9$Cid5Cr1;DKO0a>|{eeCG! zz+d#D7;{2iOQY*n7mm{5A;`j#NyxYd$6l44AP(u`9}}nQ)wje+)UEpE6J*zOICIbMVpvB zYn4z)L#CAZgsWw_?k;Hz=V}(Q`F@qAVx7mb_?|nD zwH6xE>Oms4h?seRW8~v|OgbHEaacJY7smS`Oe*&l8dJikvvzzteb|%RJw>lU32;94 zEP-WmJO${{gZ}_^C%J2mm)%cBIu&&}%79b?pcMe91wbkRPzr$xgDL@DfLEXu0JNYH zB7oO+wyCET9{cb7KHbBSKoVrKHqd&4J`}a2k1lsdbaK45T$AKTN4iN!?rfv=srK@} zMROEnZ)3P9W((8QPm+$Ns`k0_AK{FuND`_|b9o!0cwC=_>zCuh;%;st=C zl=PK^t0pw6>QZR#u7j#;^?Z#wAl7zMMZw4%gSH_fH-Q7K{#CsENAiirOOKf>GseHu zn1@e*O)Dw-u7snNh*57-vpM+-)gV8c63c^_K(Yi_!T$i%8R=7wOU?3XIaqMp{T6tg z50ZjZ{@UfguBrH+%yU@q@(v^)^4WuImbJ#3ex8~s#+Xtf!y-n^VUuK#5w6xZ(2wOJ z^_6QN+Tz1Fjn{N)`l}{@5#ZOVMS?h3Gf5FvQtF*pX@8BYZh2*TR=bl8))^E7wA@;? z4o|#;Wets)=d1(+mle9+cp2W^CFzspq29p4Z5e2xz58MnC;&^fY@r7l@I>frqc_sgExEie2baW`SKpR(*nBHHN~??8aNvP7k$@k<)UQ<|d$qJByCb#vAOUjZNwF1#qzV%%t2HA0v8` z6vg6W^z76R-&GS+@?&L(Yb}5my{N)huUk8TF<5N=DgG19G4-?^HWI>Rf0A?=0mrk7vfDt zu8v}r$bGPOF5&cz=8u1}p5|n$u~>`jkE<2(G;2v4K^{>Xq$N;j zch~|yO3$Ogh`BPbY>01dECPUl4;$8YG?6D4Ip&(vOj0Hz+?M*AYo$dy9V@gse3phc zh99%TbM4|cSs7GWiNBo;dXAIEpq~)4pQ%Vy`iM|E+s>-8pP=)>watMI9D+T*d%7Q$ zV`Oj2!NcN~iHaL2TPPhxjm;k@&*&4~a1)s()9G|jQM!j7oBqnbr~d#5cn6VI|IA7^RW7V-YZFV_$wS+zj(c}NMGs# z_xaacW7TsUk4%JlR+2K)1-u0@tq3=&gG$HFj2gwSMh$Hmkk_LIr1(*X4gUZg7;Cp< z;7cPJ5Q3!Yw5T2L&N@NC?;lO-D099yfXK`n<2NHh4J*Fv^B4-b^X=MngFqe#r_VmJLc95XF+0fzx^&RQ0u7Cd*@# zs3G;IRRgW5>1x5oz9?cc546N+r%F}^{IoN?NYWd^K7u@{5Oi@gISDQ~-6IdD#*6@c z+sAX+5-hVNlpjd)qCne(hu)4jW|&6H=i^rb!N&6V7`aW0DGcN2VbYbM6Sy91ajL^CgaOpvrvzK$ z{GXM@g^)0KudcVJ_;xQmXXO6e<*?)TWK@)mMd;G?siJ&I)XRk`w~4XVkj6gkw*5cU z^Y~CP(DzqIRnM{{Ys5gdJ>kAGU)tHf}Uac9lRKbrh*s3(5D71&I?hnMf`EVS1Xrcyhk! z{JV)PbK_yjxSNf@_*Q*4HjG{KK#Q4J~USpJZ?Jd|EyjjcI&Kefn9OLZt0qDOSi#gF8nHBcGW8ha?UIrzp>#2_ zh9_Oa>9sFiRO)+7kbNReq5W*fa7ku1=vFLK91o|0={{R}F3dV6dcX2F= zj~$iwInm^`+D4ICSE$tV6z@4a7qhZ(D~Qfv*cDl<`+5Mv`U=n5{{X_ZeBkgQh7;*F zu-XXeT^vtlUG>T>Ta7=pJIx@3urj=*O$ZeEuS_oqE;& zxqo}%d&?!3`#}xyuI_u*J@De(t{X>^;?>a@<_DOF@Tw*@Q-OlC!37uAfZu5Fpb;cc zs8J2>7si8K`xho$Jl%|iw|zcUG%a1{lO{(B@i^L7)D%=u=6F2Zm@cLc|Wz5F&gUYcIkSkNqBsb#pDKLi@jfi9U!+-l(ENEypWhtS8y zrc=Q@E?IZBb_O$VzV3Hbw>y5C47lC zpqBpt{{Svc_I(Gx)8RnJs6FcRvE}J|!i)v)(SutFg{Z-;T65Bj8q<3nD8a05BU*Sg zg2lub-6TNSICAffV&;Vy570^Ysz5?yFmr7`@Dr`T1Zz28JkiDgTns+ z%USf&83;|}HXch+Tk}ka$d}e^DJv4O4bJP>4L&BKszrm1#0&!w=)KMQpM^ygXUEBq zHsW?hc7mg;06il07P09ohMYcFg^lHzgGf4TL4Qj5ReIVbl6iKH-^79rG6A;R(3_tf z-5C5ubxwRat@4;7g{6_BH)R89J#?&bTBt`1vrVW88|194Z~RC|wHR89#bL?)%1J=K zwKSVQ;kW*EQ&Ua17-c=;a#?BdiJ2Gb_1a0?!^8N4)g z5-fxT2kqDno7HYK^E7S*-ai2wGI_S`WeBb<)YS9Wkzx;UWIjI|ma#cmq=|8(Alk-L zw4cy5Vg9eIk-z!*+NX10kN70*Ib+AgNV8&qu$@Jni5{)Q4Q^}8_pAMI=AN?O$`t-gZKNnN^AIF@2eiWPCpq|F;mnul} z2A|LUH=cc&cR9Bl8}cXPoX#JP%;coWfjGixH{{Z4P>rrVhQA)hm8XtNqD%)uS`c_tlH0Lq? z&oR-Cq?20ks2A=pP-?I=c^r{yEHt0%dsn}OA+LAbSF4X7TJEC;mg+ERZ=(-O+!SH5 z8s>}*hgw0BY%fUT20);*8z}KKVXJ+~-<&@U3z=tDkPQGnG^x&a!-{uj=B`&UoiLx< zi^9gnrnH|tb529Md2G2$%aGdj)YL8n&&cFTZqgEdH>T1fnF;D|dJeH`>p>fJv8lab zRGdP0fzaQrF1u7&vD0j7O714$AC0REb+0Eksw#nYdupWG$Iha)jg*FnweCqa`HGsj zWlp<}sJi@14J}b(MUICVd8Tmc>477thzB}%w50b zUZ>(~Ix%hhcZ=5IW~hADc}(5XAA%~^ll`bXu+syll{LTq($8p#(fC- zq&oi1DNc@zWpaU1Qd-Rz^)LK3WBS#5B*SIJB!1~2*l0X1-G6mPuL7jy_}F92_a}}& zb0kZ4D{-|zxV;m|#e0+d+1cC*G*KD3Jc7lfSb#lGi{90*&*S9r0|&li?(7e|gA?t@ z&W9d27~J}S+FIWl^Zx+Z^Yf0+gwHF+W+clB!;i)RD)7+FxlKg}*`etG7lX7F9@$wP_Ba@kn?cO%C; zPk^w7boDKaQjd<_wdVEk$!31N4u0}@Vovn#_%RRn2%&+>Z4C?irHLQIrh>V7{{Ril z)%VxOJbt*xc;)BG9#jo8G+8bro-_PRI&MD-_5Ob@WRpJ}J^gL{P#F&MZ`tMhYqHqq zo=7R_Ytfi94H%l_*wAgGSG}xnQ&U7RxS8^Uw!^hYTT!GPlL<#?_4J!liilzs-(gJF z9^RFrZ~;9SeV7Xgl4SdYv#{!`@SxN9Uf|8ciHF;j9T-!T;P)BaQt}0Y9jv|vmGY$g z&TbrhR>sZ(PjFaNSQLI=fK1TR;lX6;K6K;?4>u-!68jTILav(A^$jBK4D1l57P9z@ z(wqSPW0RMWm)>D!BDVFy3=%NXj2hh~Vr@#nsULQB?V|?0>$<%>d5t$wfuC_`z+0A# z3>g-H$dN$30EE}35qVByAC1Ipss5B3sdaK3jw9b6o8*&zKNxH}78TFeZjLx|4p+GI z`4?$2W@!(VFK-QJIYQ;iB}M$HYLQH%sikN%(+>(-8hg|R!fFEzAw4NlsoZpBr;HtS z`f6$NwQnWSNw8j{;aPO(<)o~uby0oiK~mB)AaKbV>hEIz00jbrYdnPrSpNWs4WF`r zbsa>6KkyC5=W0}Gov$kwZ7-<#Qe3CkJK2isq;@CvA5ZNymt6T8d;6^3%UoOehn4zP zcjmd$Ulrawmk?T9Vk5|e2aWpmweMYj4zbDpub;E7{y+SKo0;5l`=w`&assjR4{)fh zI-0`s>le1}Og8Ri!JH~g(X6l*`dT;9mi{|lvifu6bJ5P@z<0!v;m(wJ|U8oR&sJS(F=@HV^_{RcKhs|-3%!4R<8BjE2Fb@lkgjbpW0Q5eYcmDvd z;o1IfolaxQ&4^xHX5W<(yRkb$PapB$%S!Tj>(|SEWVOV*>yyTVymIoPcZW9|2XrHH zwm}vJYuf(+2mb($xWCo&+RtzH{!esq66ApG$ibNlz_BT5Cz0CBehR)dx61zj7GRUrxkQ6MWqXKVj+TZo5wLqC2vyYI{M0Fan+x?%mmnpGP=6?|5=CcoT zZN`J+TOxzwegMV~{b??5`>R-*BHw~INYrjNJ#R}&HebTswG3sP?r4*zwkOIiibH~NagEWzqRwCOfEg0q; zvQHGR7&}*YrRk_!7dU-@$8o)xXf<<{+s2*jb|X`~6QB1tG;^o+;cr6eM?8ez$J`em zpUSLx#=_SXr8hy&;V{-uV*^!ApmeCAANyuZ6Dp`Grq&~^>I$w;?!&_(E0TYRp0pHJ zv*(wLkuo-xicjHh8gW7x{Eh}*9FnXmk}}vYnW?2!xG{6nBs>>FTU8XIQ{=$P%gkT8 zl-wN@)x%kFI85^ZINqQ%G{8SM+1XhUJh>R*z9Yhc9Osto*-;(f*KO{Va;Z$88zMI- z>$Hywy-hXkKT}4N0^_YJahvISN_)rNYV~pDlRHot^-+P6&1x_*yQsjyl>xEqKx6I^ zNWOxQ0Pom_S8n7gJ*W(+2^urAmx&y3PSMsi(@u>9rYSKBloR^5`orzg;|=eW0uOF&3#@ zVEc_D9~L2R{$CmmnHn)Fx%CLNj1HxSf`Ho#12$>yAeKcsn=4q8uZ1LxVRmnDW`=Zu zapS(8>#C4GKgIiKRH?uIJIE32%FKy18~v~9XgXY-D?5CZsgZVH3L5j~dy9LUoukvI z@YO_KlYg-Gq)OI@-ym%)5W8Qfv1+b)#e0S3MUjm(GjWm26wtT15pSfC{0+9Np8T`3 z*&7$VyM;L%cID(*GWg){jIZ@ci0|q`-_IRuX2w&MkG#JpKXUP~aNJC}7@fe*xmXhJ z+Y|e3sx@cC)^d3UkG^rTHqDubBl41Ni;>3?tZ0(0fo*&q*QmA8%{9t*&K5JQ1B$|B zkwNz)X)+4mUr_)Gk7m>H4(re06y22Ii@_Xb8@+n-bhT26!;LP)$II#@#72a&zEBS6^$M?6uBKO z9*4}+;`wuZdhqTEGHm+2M1l{_)!8qH9l8*Cm}7EXuLrtgWB&jahO_VK8u7>@%)f0m zE2$3ykSs1j+?0RcSYGwNt{smcnElJE6x+VW`>bqDE@~`GX$JPxf~TSKJu9L!=;V7_ zQq{C)TFjv68?7uThWv0h_3Fb)UZw+=k)4AuDmSW~Dt{`c;EepV#{{z*Ga)D|C8RzzV9snAd_*E*%+jy=bi#w({neGp zGQ|Fpx-!<1gbp9Jd0hA!c;I4#_^7ljd>0X$gOrnq%Cd_Zn?nBp+dp@bGE5QPMjD@$ zNjg_&_U;t8d$L!2*Vo`_;%z_7_Ob{YVp$hZXu_YaQ`{V$K1`>N{{ZHM*$2j=v}c6E zl_lAdZ2DMJDn4^~tQ^?m$V(IT8ge9RZq?)S2+qW9;kEfw1AHC?m{2zTK^h7I24-BT zE5^xq+x@hu#WT2jX)O78kN#(hoT^aspx~yFjzn7=Xx}<^fbZ;lCQExzumz2QG_F}m+bFAvM>SN1o_bWyQ-uzxv*K1QE(2O;an*?iZ z*FF?#qyri99FqPQ(v4OLV&(}4s+B7NKOtjhWcKvY;Qs)qRNM-S3!m4NxxOot!pVQT zjggBRn;RPD?mD^XB+LM{u4;8t^wYRL7NJJTG^`raTkHB!g{4dI=ay1M4lF@FLXA8W zi-zShLX1o)=40TIw!g1RJ&MJXhU_lv-M&mewgbj;tN#GotxZ%|@jFIwb;!&}+oL!I ztPho|E~81-38!Z8skJ4_o^S{70GIu`)^;v^1aWu{+<+*H1jk zla0nj$YLiqCNoFNBr&Au08lOJW!vITwO!p$9N>xV4ih&YjnBy|10a$oh-i0`%^mzJ z3fofR;UW8sc>*BFaU3X0skX?7U2Xg$T9_+N6NzW#21?pUWoKf}JtQd#Ncfu4BDUmA zTz(%RHgguyqJhWMcRj)n*ehAVM;*?}pF5D7HRWSJySPeDqiwc;f67Lcq~%t4b&eOf z@_Fthf4b+ixpNsHO-(GKDJnLP*KELr-`(KNiIb_C;KYgAvu>Sy% zpXtBM+PB?h)3SDl+i^H}Skgzd%uIW&dy)xiagR%`K7H}xn2~f*8*BVZK^lCi+KI?s zUQ|DIn~ke(_T{~_1x~l9wR40>GD+ox&wZen*jm5_@ie77&L$+D-aN5C)P;!K{88Lk zimfbV!%VK|dVM$Q2gbDGqqq|;R%B}1WVu@E<;;fKN9lEnI2YSSyG%r zUwZdUQO2Y>kd^eUTwHT3XmU9W*O60o+T_}uq1!(ka`@P|ryh9KV^A(nQff3eq zKH1`>7kKXTH8(UN2%zSG2G9|V#foe%6}CvRM0)=eOP;4TD_N; z!IfwRTQVi_>ETi$EWCrg!e}W~;kSso?k{swqC;B>9ePl_I*RA%xS~?A4=B zel?`$QB`%aROuC7wh!v`EkY0Q7@gT}-aN ze*~~U9CyzpWX9mKg1<>-0u>)J_Nmn@+;9EAcg9c;ktQY>A5yf2Rv-IE`)PI2$g^?( z0QS`YRg;tF7?brbJV8G|&T2i?=rxV_Gx7E#FTEB{VIDI`NH+6Tu%&v@>w{QaA7t?Z zZa))=06=Xcssn!yuJt;2ji26KzlRWxPD>gE)R@tM{mLlvJSw@p``hx!$qe#j>!P3n z{{X3~fFCElBiwzAG5-J*jdTA1+eb$^)ERrjmyx!_V~i-#Q7(RWHJx1GKQEo;T;22M zA%?0LC?B8{L-azDdCMtz-PBmN=3-6H#M8m*fbqsBkdFpnw8KV#+!oOsSdrp>H1s6J zyh4KBp>o5<%ht1_PqrG&@Dc$>i~;&FsJ5;|tQfOB+KxQDe zOPhB`FD`%dA$`jVyz{;P0Eiu<_qA&&$fxo6O(e>xtbXF{x5HoYs_U-@`m^@`03LZP z&OaSi$t#4Abh@+MiTwp-WUVd8>s`6qu*b~hK0dItp<`jD)m5+`C8?aV_8gZR8g5cG zM-s<~3;@+YD!)-3c5h`R+fNaCRuWDe`BB2KO14?2W>y^)HU-wA(}yLSe7S9X!yxS5 zEo+CpzjaNjl+y;^I9oHBH;|{LlvHZ3l#x6}`hm1)IC zaKpim_eBW$#^646=zRRgA5F&-j8yw#%~fF|NyQrwt9J9HgHYz;^HL@oE)PRfVxSyd zx0{iWUEBpx(*FP&UZKOkC1J@2KPtYqCe>WUMJ8vpX$=1W9hdA*vO4Zt-qfgc9uJg{ zkY$AsC^`?FB0b347`84;8{F86&cKbv%$U4_Ga+~zt6Gd2E0dRll#(nf?X+g$YEq~7 zS&mraWpH2l0jrCP2jdgPM-z<10b8rJO$+uX1;H!4`1wh(wcC1-Bapm4FCF~})H8iT zc53zX!tC*|YC4QQ88>Szmx1D}hF0a@FALy#86q#5tt;myb4#4^N0PxP873GF=B z#o|jMk?xM7v#k0{o5|u_J;u<$3}bT>(x)(}iY_-IizMl_&syG6RC|-Mc}(p4<3^Wu#ipaAG*mk-vz3 z+6SsU*%obNwe;&#X-;X@n;sZ>3lXTwfr>F)t_H!jc3Q9j42X!+@oqQrM1@mZfhU?kNCgo{{X2uJZBM@ z88Tno+iMZ&AG(+R*HHfe_4%Rm9?0TQhDd?&Gcw!%0Jw@*{XKNA>5v;U@^9nrHFhpm zGLUbwA#;C{15y6~l^GxxC;8*F(jqa;(=qT^_Wt&@KTAf%TQ~FTmbMQZcJu~WH2s2$ z@~~_`{{ZsOb7q|kIEvrIi+25_()9lTqx(PLM>*YH#Xd7QHSEa z{v*Ivb}2VIFC*@K{6;Oh%`zcjbzM})aj6TTp(9Cf%%aM5@I5J23ziaQeS?clilY0C!=!`MDky8tB$)8Q5paTF zM3VUn*a7ktJf?v8_@WOcmj*^d zwE*}UlC^2$B##doId-rbmQ>Y@jj8_t+j>}wPsame;pguR!PLsH)305>?KNM)YcP^t zD9ACXfl7;$teTU5g{vzx^)TGBc@;Lb7=F#pZJ4E+_W++NFn*uP`uUrW zy2O!}iAC+wx~E#s@D%?5k)9dMQbBL?T8%G6ullX|7+7QI;2H*Ek(J!s{s$y|#cybx zbT;cjxyR&=Q8T$QF5RqdN%_-(Mv)fxww`rxni~$3slRl1q~tCnru+ep}Z%=X;hzPu<}{xkqx&f&o{ZD_#N0O@K6gS;m&Ambv% z1z7aHno_B$d92)YFOXv{9BvG~D?W-q48C4@AY7Fe-QjvtEuiFsL>R8;we9h$gIVJQ znYpo~$WRm1iwa}ec9VgHG0Q}wdW{L`N}R1QJ^0;y;s9R{3Poacyo*dESledN)|$Dh z#JuM%B*qzk(^Kgu#8pZtcX9F98Th{GkViU=MaNpXN=HBY5BaU0=ce}EMvPtaKP>W6 zNxC6r@~=a%1Y7hF#>M?0O#b_-eLOE)k_iP?%r1}!hGkAdT0s#;->1S zQM`Pw7Z%xFni`j>f8`xLD|Lia(No|V{_ zHa=%t{{ZUiRXC8n?Ll^*CQGO-@EX(DNb<;4_K~kjdRQ&nykFns1%F8JCbR46bDb6C zdt*NmOTl(eKMK#^OE4=nbFq`#oLDzXJz8^3K)-E{WG$PMSY;pv#w}Yi#mnf>9>JD1MsDEx60AmSTIMM2+NGg3OA}m^%U0MNb~WmI<>Do zL9To8^Wo?J0CeKySz?`w#)H$e9d#a67pl^A6|ur+Vr2r+JUBULM;9?*k8QOmqz&exn5S~QX@QR{$|QV! zV^jQXVAi*fN?gi|Vx7p&+%!28WCA&C#NO(CR%uVtzE%~l@FZ4OiOMkyytQv^leB#; zBb#lpKN@nyx>s%XWHHB&KP6+6C_iq z_*R_8HmuLWwolqaii#C(?nahT^p+lGwVZ1^)J^6%80Us4BO5)@vQ4K|MIhLGS*rg4 zti7NXdPRuMCQx$?#2BilpoCq%cQub+I|s0STi=n0`ir8O78BvUf7w~yS2{v|N)NPx zFx!29A}g(1IT=~L>t(bmZ_WJwTRws){TTM7RF`-Ln&X86vTPJzbPTLvS>oaB4r zPD&(G6;c@(TKz@EW!H+o*r{)cd0C>~V^%t&XjGr}S8o@?3!&Y~!}74E_)t2YjpJ6I zU@j~B))rU2IWeI>Ax==etk|5MAopTcbsD%7!<2qg;_=}2<%n3{T5vhmLnw#=*41Ga zCmX#~tt_J4bS8N}rrQd1BBrh__^X#M9=CGu8PoKni)u#?+S7BHE*ej6Vf5d|jYYLy z?oJCoi_Li0lF{`dq(oSoV#g%PPtJytrR9{197}LSpSq~B1t^<&o*;d(9j;1#Lsp=>mRt^axem&qIvw_m3KBK%h_Q?3@A(G88xY~Rvj8gd@ ze-|N^2|XK$BJ`@{6vgh0$uLGFgh?MlPPG;)#AMFJNkWneb=qmjoHvuo#~inb2B$$x zVBCGcvZNo;Slw(lf#XQ>59adO3yO@aY(UUbw2*(ihJmY_x~xX$xL9&B-fS4{5G3hU&t+mS7-qqkFl`r7DC!Pk-v@EQ zlM2Ml68cFJ#yoNX9ze7&E{bjZ1fGpoIq;oyf5%X9Qs>CroKkVw(2dbRby=_c zjC8fBdKa^#Z{t!}V`MU5$ajNqBn@kAxa(N`J}T$vkb6@ee1Ct6m`ez|BrGpsy5&v$ zYm2Ti*~icelI=V^tdz``9e(3)vy?6Ms`R({mZRCXvMB9H+2cDIvC0Uhn|IK=eJp(S zquDg}Paia~K`9}57y!k|QS{7-a*l`NTUyRF<@oV5Db3>EIb+6bdGz%epZS5Ie{Y=^6$0&ii#*d0;fXbCeCxN49Q{lLa$&H~i-)TDOv)~j~SC*2h zf8F@$^QX#y9g&Z23}MtqvdAs|X4a?GSD~IiktP+DhWvmel3RGmxGMqr5l5kW3hg)7pApP+CtP+n z483o9>iJEKyNO~hO9fLM{{XI6LXY(ig?0L{{!jCLv;EtKJ0K9`{{Ro2Mjfh)cK-l( zcHDn_%9&V;)-&Z*B7K#9_r#l?#aD(hk^#A*9d)Jrp7?XQ`!|s(c;R;op}0C#bbQe4 zj^5;P$ybGtu7q1kh1z!$6PATfwF8nm*-6rZ)xWj4&SxVQSN6yXbp%wE8iR-KoGBMB zG$|4ITJ$2Soz2Pe@^UUGL+cun4Lm6tar}IlPzdrp8~&0-7`Xy@EL^-fj52O$m!_U| zSe$E(K1;;dxTshiSlgu-Fkg-38y+9F`*XO08HlBaAd~QN$AI~6HmTGPolT37-vQ1= z$HOud-y!J7<5PuVH2j=zI9=shM%Ks9j7}tSJT_!-r0z+IPo&dn0ox?R#u&z@sijnA zDA>z)Ym#ky^t~ua&y3-Q)(6U%SvYPqWMXY%75vRjO%lSw$qIeu-x3>N!lI<^dt2wxwl#1*@+BG87N~zFq*`IHH z{a#hB_&;Z;W8ix}2KVwYqx+nT6890XzfTISXHufWgWXn-Dg=CgcJQL1j!3`#%j4VHAsC8>j=WhMcFYzhp(t@oJg4 z*zF>M`FO{e|!a#HZ*yyxJK6EaM!oEaMuG+>GV-56_-LH_{MDb1gvsrkQxyNVka zCP|68TLLZzkhNdDPAj~R;|}=33exfNHsfFuUyn*Xq59B~#Bx}q{pKvO1?pW$r|%AO zFT~(usAYF_|y!17b$Dtn#L-M;d7|*+URIk=C@A{)jUNZnN=? zl^YgxI*%%qA>{JVv%sH&cZk74R~@P{HyWz@-$7rK$Y zn~7qg_qUZlaq(byF{}jjRdi80IS<@&>Nn#zp%0_ycc7%$L(@4WLU~vJiA)b zD_m$r_L0}dv%g;|^%2VAf3@R6yp#|2(7o`o1@8+Jq-;jM+3^1Wb!pFb{xiHTy|FGn zYEO@xp4Lt)C@>JAibyW52qjNms!bmM0QHpS>D$ZOyoo60PA4p=B%2tfV`aG=19|kW zf2LPo5Jw|3-bBoX%^QMp5OoZ{RdU$g8^y{v^7~GqkhS*z05UgQ(IT}YkmBQWwgK&c zF9>dmS6gZP!}r#ao$48zg=FJog&3cC)FiA!<8l>S-*Ic+!F9M%TJc$QXChts(&RebVT?S4 zbu2}~50L9!KGltgQRZ?IV$CZ?J@@(t@T!t555(zFdN~5}xJ2c1qFlE!h=_UQW;;WT zLaOwzsg@l??oQvwpC%|6C6@li<7<=RM@xSCR~5>;4{AYY3Gt)!tX1=2KKaOI*zuB= zZEbJ%8sYlSF5ivtF~)DlXmesx?4xvm8IZ?CENd4=;|019yxFBgcxmMIKSAcohGfEp88S)-a8pW2)bbV-dYH<_B@fYkX`Yu2yX zyiODa@nc11vXpWzPmYvd0kG_zC^}2Ip~#RD@y6C$oplvDH7z)i_KAy?A$VhJM<}=N z@uO2h^Lsyw&-X};B}kgv$n_CXri+`|cyEe}1R*6x>Mh~$qiVJs%Iyv=JSc{|jbyC(){IR}RfM$k33#sFeGh3!vh(2nBbyIYIm(Gwk?HP~HT*}*^M>skA* zL--w)&ht3whYH6YDNB}eNo$QQPFikvo7kPvkH}4l_Cy7C9^gKb2aj6No8W#r=1kl2 zLam6fz0c?>ZG~f^W%gGinZe^@yvnM&ZUfazP6N;Q!;a(e;-4(bl^d`O(F>KoTh!YW zD<|Wg&Wj1oLz_sKh1B|iJvvb-G+)Dbi3i+8ktvKQWMkuh3U{ape;?xvQ|;zFQVzSW zDt)4C6vON`7|NqE;0@2aOOMu+P9DnbXp>}22~NBG4KqT{?SzmQ$Nrw(HqzJwn-4Pz zCXmGEXtCO)+)zgGuqB$tOm_Qr)vh(xiv-w{{{Tl|`@Zk8+dAyAssbIy!2V0*Abf00 zq=DmI<(wdS4%>Ql(^~20sGBQ~_djj-ZxcHVuer%#b(TaD1sDEO4RmvPXLzAl{O59U zp`(jCGZh}kXS*T-N7G<#E-LRF)_%Q3&xri<-k6FLIdQo}Sj0>BO3J`=yF6t}RA2K6 z-Y#8>{{V7{#Bp)pa-3w7Dm$`Ck0$eH)DP=5{U)dSY(MQ-J4^E4W98!HKr&kir+q<`uW4KHe3mw3e{acN zOvtXHe;X&!y*lnbVu?mn3{EG5e11YMP6wG)jIo)NKKC&HFcoGNq2Vu#PHt05^K%fHJ1_#GV&rclx0G9l9+!#~7Nkx!#_SLoh zhSX_TuwoVC`$~LSuvs%?Ury!geS$hO=vV}zw4f=S57dEAe zRbq8E456>o_}k9(u!itsj!2o@5}RzAlhek+qV&_4v2ob)N3R($MV)NVksXxWdGyk- z>#r?m9uKDr$W1AEu^^nXktvQ(Yhw$Garpe4DAzxBR!%LF6CJk|7V5`t zgQXwXo5UHy>}*(gbC<^?-_ntO`5C>5s#!k9GRKiIBPWYK%(*e& zamQonF1~3+=^m>Dc{n_e6jwIWtEaJ$S55IT^vDOmR&}pF0Qe|!@bYKjGN#`u5|PRL z;2rU~{{V?Ts*bs9s{jzUwH%6LkuMwHuE4&UIpk=+80$73=^Og78#!);qa-Q#T}^N3 z%KnOD#FFv;<83plNC~(k2+j5X0McpLs)q&!Do9<>1~3@ehz977y83z6czTT4;$5&I zxkf4n{63vNRP>m6_6ZP6x=VX%G}CsMrG=(oS(bTRz0fRSSRSU=+xw`HtsTY5l!1Fh z6$=#}V@{ts+lGA!#fvnU`xNbW1AB{jYTaw2_+?sV%D9-q6$ff5^|0#ap+C0OpH$=q z6SPb0MxsVha*L@OzlfimWqQSW=xmYXNhJ9aMp{^#dY9;?> z8p4u&?*px#LwMw2pfvdrE%KUduVQU-6?I|=&<{S8^w7CnESAPFME;fxOp1D3dDQhs zsAmMwaB7&QStd!%o7}(ERXgxKMrY(@k2WV%jpKyxbT$UwK-Am(j0KCBg}L0M&BJI$ zJFK{yj*@QbFG^h)GnvdGRmjD}cYW58MZF`(Lr-FGBQx?RYVo|n;N~!rIn#FCE{Dec zRBRZT#&eucE+)yxWOx+WcCb)?WhG)4a`911$1CB;@#OA16<*BSx^=3;#@(06b3A17 zV)EGI>?4nPGQQ>(_?nz7Nt2Z0^K#7C@a&D{42=V8Vd6zS7-uJq;rV1oi1=A}@h&`>YVsGm#6^Kq@TtR< znSZlIG*E;JS%H;W#YKluO&EGL3&ZRje0+e`8~2R^H3h508y06VP^kKR3Z-s$yeBoHE7MGbj3Y>VHaB6iAnj%H~u= zf$?(jz_#t>8ZPHs zYILfC)PMTJ3)%aRYEQSf)$Na>-&LrvN1t#^cKk10;;r{>??9LyY!QOND z{G3&dLpx0qC{RzNu_D6$6#eBz`1K=BGn(YEa#te*I&5r^cL`#Vm97Sz4Ht<~C5z`D z`S-tY;f_3($K(u3K%XKoW$UfvLJvyH{Nm@*tT>V_O`f1Oo-Z$p2#+-z>!VXcPnz2G(aH)i>v2=h6&f^1Kfv$mH;_PYz!thkv@mW=D~dOA#X4{*VuaXVg^dQ`3yW zGA1kG{{YKHaqY@B+$h(rOkaRZjw6r3_wpf*SzO&d)qwV+0_3{%s7iW*8YGD&FRsn6A5hJ#K1xgJJAk zj!%kNXLVUi%Cj;6df#2)df0eWdY(bP54sX;%-OP_Fvb`c*bVGO_W|eUOV$@$t=w-T z4t5f=NV6)NZ(pm^&>xj)&(g;~T-A5DIQ5mMn;T-yHI?@dOn@Jyhk>gouVBd{V9$)( zLnZAK=*p|sG4M1UH-nhdWCNTH|iYaA?u=gSix}7Y>_q9FL$wDE`La&ls1!Ckfj+Zy1)}Qcga#&8%M`cez zQrhk>azz?gn-?RDF{0Y0&f(tvJ3-oi_fw^U99~`A7G)t@+j4rItjG0gzB-8N55deV z`97;h9AIu2wfyw0uX7P1CoiA(b3qGwQJgU#^;I{l?@FA99F@o8i>d{iCQ<(YwOFtp zs1?oh?lt3|D3d(#aq{NQcB|_=VCoc`3s*h1wvf&fV-+nPR^&iK#x)i`CZnxh#QE8= z5gA;#1P#~yYJ93*-r6qBjrYFzW_{t&n(0Uo)`Bwu@=3x1bJ0+$y<>w zCH5hYHyoA6uxsCSf$BaY_0`O-YvfpFqss)+M0QJ}8|Y1RN}J1fV)HsP*xu`NVlClR ziw;g!BhWOQH!Z47gektD>R#^*1cIqwTN2z-t;k*!J zWe#5A0BspP8GZy-TbCzEe zkeL$2Br(_>x>^4KT2VHpCOoA~XymgZ5?B#?e5uGSManCW z1ab+RYLFQ;B%9TEg(X7gI6bCKU&!=KzugT-)cki=Cz$%fBLFuQ!H zv2r>u-(_U5m_$-_)6>w4c~bH(frr84mkw9Po!csO1(;j_bhx!Rn{`v>xQOD*k1}cH zO}|Wv#3=dEVMCmJ8BNF}kx3`nuq4iIY}Wq(3Y@BIg_kBST(D!W-bjSV0U&*U#qz3= zH1Xq_~7zCV5qzCiWN^LK~=X zPM1DItyUULoK7bAWs!fW6B$+15X82c*!1{OkTuGKiq2Rgn+>P?W-S>&(VLA0$hFNY zKj70-Vn>ko`?-<-Du5Jx~z!8PvKh1{ljfL`~=&J*d>1e%jxT>}S^!s@&J$zVyZ9GGXGeUoQ?8+Z^o5uPTm&c^`#W{=`T0 zDm=eucXt;f#mI4!M9Kc5fE=hI+Srj-&(c)il@7q<^YAlQFOHq@a!?c##>HI$7AtXM zua#+e=CkXI7LFV92jngm3E;uy1|c4<`m( z8M(RS$DJA}N2D_&{X=ja2-2teWnAkLI4{c__ZPupaI#~;nTdzEV!WY*(V-xS#EL;G zz89kWPx}Y3zwQ^Fi548}2yvq>d^bL0g_S#%UMcK-lv z;^W~(p0edhw|tB}MF{ln+6{rOKCS*2Alvu9Y^*7ak1k~EcU)ypZ2`HsEOj)zmE+0$ ze)GeU7KR=jfjC*ROPXa{tdlRiWAPF~R5%|3qT;7o`ibFk zML6HJd3}6*?9qkm?T=Xf^l0@)%+D5*bRnDEo@l}U0QUx${gky*Ed9UBiLlL+YUD6h zzw)AQY9;c|xCzB`d0eD0<%ZfbpWA0WRZN86^a8Gar#vOb(_r935Mrw^-zM#PANN)D z(Q^;Ul-nbUIX1M}G3{=;5vlzJXFBq~QF$|QXO!9Y#EL{}1+D+ zbdcCW`f7a5ELY$+*)(~(B1eRc3>VyrJc0O9!KOKGClYBO$QC(K{{W`MS&I0LD8)5_ zvN2r7Tq_nOZ{zSZU`&IM6JuUw5oJh9#*O1|AC+81W>B+0s$o|kfjL`R=g!q~L|&_W zE-o*B+=^CtAvgAo#mV^8sVgRQ`@baOx5|%W^$*JC_{V>=$VSHdfw;W7 zF5$0V(v2(>%FUV_2p$PclfqTDt%+#*P)IoZCKuQg#%Wq0?U1lJw%2oZu_l$cab4v* zv!8&&gM)=3o7^ECS?X!jC;0S6^*V5tvxf!ebk@GoQEsI zW5>*KnPooQG7NiMFgjk;7wG>0V|OXa?d&P!4D)0ivKAHqoqTCi!JNt4b3-BtV>jBY zE-7e6%wX8jh$VR8U7|w_Eg$<-~P9Y?QQnY{m0+`0QlP*cHgUi%Gy%X#kH}f$C0ImXDx3| zInq1Zs~)x|;ab|xa^H-DD>D&BRAUz)8->S^x|8Fn7pcYMOp}KZ+BlnRaxpn0djc#x z>a?3dg)TboizSb^03q7@ZK(Yy2f}0(W{pPcU5Bc~UtX7^NV1Q+v>Aja$8EIJ#-FjP z9Hvit;kZS{hm+#fh)FTZ#WI2|dAGWQ*Z56ESE|j%H0_M1ClOKHnGr+p0S&d>3Dncn z<6d(+j^ksD<}raLHikfiu9}d{2A{1~hPb?*23XyRG;)ZTt4NHjq!2HtBxzH5h3`zu z2OXJ>ksL%Eg4b+=W4ToPX>KZNgWbP|`#YM*Ss{^l?nfXqIfBfMV{O(`wzQqtI_6*3 zF7DsK9nHaE9NZU+lg16VY#^pZiLfR%>ONJcKX3Yr@QQ4mjoqV;%;Z~($&VL~*mGUc zl*T0_Au857l|3tY^^EVwKM}`m_c}ncuN{zKX#_ijOn<1|7pGHtbLkQ3P4c`aImYKU z4=I5*CStDt0A^^}953@&j+I{0r>-oac@iywRJPDTE$TM}Yw*2Cg<;q-o;NH7o9SEW z)So(iNF#KdB)TY(fwiB{$E9Ur_zWm=4sARdUUVH9g%~`%KX+`a!1DF-EkF# zm(U4qyS}cURbQ-U*U@8(zI!Jp24vvIFW&(ycp^}@nd1bI4Yx2hr+#@gk6&7)_NV3U zA3u=ClJwixrRe^V*VDkCHzyU7jVO~L5#CR=%ZbQVNrBOjc^ZG! zM;}EqB0+=8h@@qe(6jCYU)80w_*XZjcFPT6XDG~<-ET=}W@}jOxfVCIFI)cr55b?l zY4epVeW8uLj?xFD8l0mrQVwacyJkrdw#qT3c>V@KxAxhpx#gEt3$}8K_SQTocFl@( z_>gSh<4>-#mMk6N$iozH`%(kGB~@GW3`jJ$RmVO4WvNLkQ=IxjaN07P+|EcY0QhMjw9{^ z{3(3___3|0SjOOQaCiJ%d@*5$4Ix#MU4#?4?f}rz>x)mBh#XgWad}*KBL^ydwu=^7 zqRdgVV}N!I!0WGtX~)FAovUAte<5-ZNZAt;Hd)%TG=x|vxesGkc#x*993SQEn6h(u zzD^C8h7V}tuh8kU1BN~gYn0UVquQ2?V`r-~0P7=aTW-5+PIjX86JR-S z6n2Q1@~)A}Mwj^3o~XSd^86-mvLjd8$?F6Qf_^u#sIgO|ScJ%kvPZUEx7>8O@uEZ2 zh~sIZR*pLbBr>?U{V2SRF$7V}yV*z9!bD-x+G$Z~2f@1mY;!KZcmRnO$#%7h;$u2UmMz~8Y<8Sj53SL4(-Z( z2-d3$*e^Q4R@xANbhRx49BaGI;baRS z)_5M;6a2UErgkgb{{U-daZG3vpDLIWi_9h?e`_vr=iH+ioY@PX;rLM~ z>MoprData>3!+TW0q(1H4Q*^kg*0KFGcGn5y zU+QDJ2Ts7R@5aY3)TuE``han?~ys3}vn8{{3-E_D<6iZ5T1Ek^k z99-d-#Nf{cK|-Xsa~Nh8xKhUFT2`+nF$nyb!*HB`AC31}b0}$M$;wFL$A#KU`$JvK z3i;NY^^7`{MLXtf&Sm80IP8orI4D^M9FIItE$qVmRQTyd@?J*yZt0RjIP6|U@$lV2 zXk^B_Ng2^p@6_rjn+qzm+)sD$*+ZA%GBPCLGT|>QGALC!C~kkIPT)@7wVz#d=;w%w z%l4-=-4NmO+>w)$$i`jLV$L?pwQgBVqf(;!3OM?82dr3O{9oATvmr@1oL1#TC+;#K zX&j*@<9uvGRsR5OEP?!2;*Q$mbK5xM!I#Hng@$Zt5Xwt1B<%kH^!{R>y`$0vzu|r& zJ~xxV_EB==n15~MB`;{>lV4aJLj5%V0Jg#XaZAknA>50X4i_CX8JWztmlt?hlm@o& zgxrH#^YxYw>xjJfQpv z&k4DIp1JNvBaz6({{WNSAF+ps&At>y^pm#AyNL3t=j7&`^ymG(4sqx4q=8H_$12SW zUuvNz)oYt5s_VHtHs|H8jhTTg95V8JcLSG~$gXsgN1qgBqjF8azn1SR$Ju>wlY!X% z?aaab$GP({I3py6e^7aHSd(ylw73=?bbA*(pX2kQk2SM+?gDOJc-W+qGU!znFxyLYwSlMoy#D~kc2Ist@Yf%mpEgGW${srt zA`=nD%0^<0P0rRA(#D^xr#{*V%l-}TnBo|?d02T^Kn44cciSaGi*8ar8q&WN&gBjN z0HQndgvQ%18~2BMNFNZ1MVYT+2EG-Cd>pVN3%7g6pXQ{&i;9*Ughbg6U-WJR62)1x zG^Yyokj73IaYN5ZftSVP@4`bHEOE21xDTWT0>`Zv;ytJ8Pa%=qow)0V%JJC{PLQnW zbSyQ!g~i3S=~MkG_RtPDxbmMRqylL&vaFA2*t2W9Xw$^$TK@n~hJ8l;$K4&r!e-5Z z$#K)+%`&X56sp0UpG0em`atL^`T6)`*EoTb*`4bB!n{GnEt@*UEYb_QA~*~SxYIz@ zazl$(FZct#Vd8RM50u2tSYr1i#EG3+Lb{NlhP`UH8Qy)I!-wO$hx^nRCMj`prFDsn z$jGUEH$BJFD^9ZpSnrAWeth2EQN(iT&(Ds_E=Czq3_?J*e{KH&i&gQch1XJvb{`Ag z*;w3~ayZ63RVcXpdobGwPveXq6Rqk#+|HNs>he=@eA&v}G38?$`dO1kRu&*1Fhy|p z^RC}{Rt^>nj9hs`#_{^Zg-9m$t$5*weI62h#Om@ycCoT)dlBMmTgxe0^B~0p(&EBh z*49L@XSedw^*vOi<-5%H1aM>V3iuK#pSdKX3ypVP-6?vUnz4H`Vk?ap^p)UPOglgnb~W9CiAy3AsBKp1WJE=eYy;(ZVEZQXf&xi1^VWGYDv>5~IB#HdxS z$Um4GFLs>y#Q3|DlK$5lXTJQywIvaY5;|VSm$?46a(OJwSynux890u<>~jJHiU-4~ zquhEXVs{@CEC^!BAM+pSD_w3!QLS9MoHH(Z3B+qKvs}7(jXdhTN3l9P$qbl3^D#<& zxs;P|egn#<4_a}&PFE3yn;uj^ywVrgqQcg=ury%RXOwPD^C6uQNLae>+_xnMTYPEY zS=XP3i;fkMWyp^wMPyRtPsY^rtZkVflN@AO%uZ}c1X}+9I(Ut5E7c1PvW-B%%pb#(7kkoY=b4O$3Ga<|SS(-B=lX!9W^Qh{c z&cMh7%ZwpOfF7n$bf^fo{4r9&AR5ziD*pbU2rs0Y*6{AiGB8SQ=_IZI^X zZ;loZxZmpss5MuS?4I~MS`j8UrH#GP4^TSN!Kb2=*~cI;F-kz&;4E}MzMO+W`Ht(t zz?pF4m`>8TX9xk<2A5(rpv7k6vH1wF`Bk0O68lQEu20H<$G0E3vwL3G_dkpF)B}0u zS4dY12>$6~)zz#UX|$4gZWQoqYx3HeY<0%amTxAxcVI4_tKV?Ig^9QXE66( z2+UUYki@Nht##L~l)Rki?<6Ic5%8mL>!K`?OrQWKxj#phH0n1WiOfR)la-z>1E%%nQ**BE)6!0J~9+72z{77Ns zxKzl^GQ@33eoK z$plf)?_1N8?zPQ_m-y7%wC7{Jv%qBI`;q?u)EQ3@}kbROZLTMc*DcP{3$3H@96V!rT7N5n=V-72K9%l`nzd~8o!*1O@29D$G64uZ;5pRE4?nyYeYVVE$d z!Gqc}$vVE`hEJ-@f5Mj9JU7ddI3QoRP3gRPMx=aoto-V>8=D7nB#9W0-PS2}zwEs+ zr*W_*go&J%Zvx(Cm4&4=AiQP+w1cT18mZv7MDj9oq2gN&h&b#w78)@p!u3|@`~YlR z%zTuYW^cDZz~d*V8;x&LH7_10vUv5$P2y5b;UwrhG^&GJaM&Do-c0hv8ats5%m=IC ztvv}jx%hA*MjP9OewABo)5r>+V+#KOsrX;H{{UTf?)Lis02Q}e_E0eI9{Fn%M>6k# zU)YsGsrJv;{6+LX3IObF3CBX~VtT86L&|`DcMXMU5fTvM&FL}|`Wyc0DZsq%vmw39 z1L^k3>w22CcREQEBnTlhW^5aaGb(Mrk3oBRQiVh?B*|nup>%-%0Hf--8hVDlA3C%w zTyDj~Phb~7q@}D0*HNtj7b$X@Ry%?MquT%zWAU{Do_6&hi7eqPcHeIfKeIc2F{U|D&ipMz|ysGybVLqk!daNiY-!d{xs|>EY zukJm8Wp9P`{epus?~tmI%^Ytnh4Lh1Q~E8x#)uAVL4bl;0mj}eLZR1p#EmcTrV@;J zNs^`+l3=de*J~;;Jwd*L-#S#_ZzU8hnDR98MgTyt?YJmd?K_93O?KXc3(tcT@f?ts zBP?fA~(x1E-W`W61hUj2iM#QPS-%itNUiS8K^MT5Zl)oyLpudN^W zuNeOGd!r+KasoDyW>fl)SMI2Tr09y7g2=9+Q`GBgvGC|v+w`hubUO)9M<91%+m6;y z{{T(;9R*D|%H5}LXLM`2>wC9`qJu!eJV?(i#;hkHT>Z)t`N6QwXMG_w87e$*-> zWq5D54Isl8N170o#R0DXA^ZV`bpt-V9|OO^5Y)Wrw! zUvAk@zBowA%HGUsO9#L6n`v(g){qEK7yQeJ+b#bJjjx=9pO5%w|>-e?(HtK#p->Y#4h1HR^0_G`;~tsSg`@asL9P5#cIo3-aESurZC&LGAK7haMg2F1xWS|_ zvNS~KtSm$P3F|_mT#576Mls_f#tw?Cpp)|^!m1|zr$hIx0vwyBF>MvBNN<>+9-G+I zH(P4Q{nwz3po|3}uN}^sj|u^}eXWnQ`ZsHOW^zz2q!WEEw$tH2LY?wMFi62|y>2?z zMG>&n39Y+#i?O)%d05j>o>JhPEwZsy{%{G`;0Cnjl0-k=S`1M8(jkAhZls|3Ypp*x zNc`c-3U&*%L;Q$P#)={064=SMUXK?ZLNpKi{TGFvmY=ZcId9 z$W?Mo=B5^#oLCcWz})LmPBq9xA{)pQ{{Zn=F{wW(F^$+q-(r*8?dnCpN@Aep%g99^ z{EQ-Z>21Mv^YvPR4Q5Hn%Z8tQ53t*Y?@(X|{)^L!MB_1e1d>*RG)WPf=!}vAG}K*y zrUs@Aao1tm_Vw-5{_0c%%q2#Zl(e8PqCS`XO@&1`1)4q1JbTR~Gm!rPRmd86Z3dT> gIk)!SGk^a8_8;B*oBsf#k+T2T-OrNnD_FO0;QmjAM9^-}TVI#OTnJ_?R2`m{fjrrX(*}U9wh7KFx!lXeO0z zrk?65o$jPjXf9J?u3mImrr23MJ3_tQQnSWihh%Ax;bNTOak<#qpv1+b#M7P>Xi5rl z%8WC~OmHd=G%E>lEJ`vhjdvo2`lZJQ5tHMJ!~9C(g36L(o1D$+g3TI&oEolMHpRJg z1z2^5x^_if>WO!24EJqJ2xv@>=?eGlP4e$fjvkG39!m+hOVFyz&?rf>%}Na-r6rbT z29}WG?&b&IExg`v+odrhurWQpxj3+~JhneQxIgQ9Z)tFUY23pa_uj_15xm!Udgw%U z>{waIL`lL@TKH1-_0^)}kw&-i#^A|@`038jv96Tot=E>Dk{A0Tmb;Vo?%vEIrRC&j z-YF|7%+4q-%qlA@tf;sH#=>hgw$VN*jk_7SXb8Hn%du3GTcoZ z>M3q&scUTSyx-Z@*4@+JQrF+pJovD;Z+P_a$lXWOq2bZ-(L1=w^3;*LMN4;ZtL3S0 z?~$h(GbS5L#|KDL4~y0sNNcS{EB#q7`bs8R>!${qriOY~AJnW3HZBeK?Np@gHDvC# z7HoIt?Dds>YAO8MU-oXO?qgrWvx$;F8>@YLGk5pL zoA+mW_g*ybzU==z-TZZ~`|EPs*BAXC_WGx1C#Ii1f4VsTbZKdIcKpTi%=*i2u78PclH51uf%Av2PJ8P%zU<|YP%)9Dl3M4MKc+7Ow&y^_n%~qIqH$1(o5p(o< zrn~XkJ!~pHzeP`z-R+-$MLk=3B$sP#Yb}hAdL$p;a{lpWxuqy%so8rhOLW@dc(vPQ zxyJbTdfP_7ep$PtW&DTN?bh2zZ?rF8eRJywfMm2vINNMYVU^Y^i@mxXOT$>^S|uv& zQDd0p-_HN=^?Qhyr75dFR5@I3kmL-!+uwcsg5ly725au#)0KX6o5>0e`IAj5-7E*{ z$G3r7QxktKFQjOGdfz0E4CEh9dcQqkS@Ns@k*3D`&7xa0rvE$=zZ`}o#UJy^_L6fxPtjNvwLc)8oVtd~Sl(GYjxs}~x(r4nnqpjdryW{Xk zeTj~qUsc%wx5ZJXaCL88OglF7eQ}Hbe-M&^0I68zI|3@;c#9Adlc!@+>^(3LRsSF2|Jk*%Wd6^+Q+ERbF$^* z&m;OChlZFp-Ya%G82T8O!<-HI>nC4Tbf9f0Rs~PJtt~Tj*+%!j;jvHJUkAn%)ac*m zFsO|tu+U9hvmMNo+N|#DoH9!;cJdb72z&qRcgyQf3)21JUl(3kJ^H*d8cUeC@9C6( z^*K*=`IndIPII?MjULU{*vroizAn7&Xk$=&wRc}#_d^0rxnF%wCg!QC!>|0zexEB! z!FjATrwN9$#SI?a_D-PdV*O1yw>Q_(A9CNWI|wJKj-oGp-D*TGbj!b)^of$p&Ukgc z+rz8!V2`GPq%XQQWqqzX`X&0d`c2mM{)1&J!{3M6F)`L#4f3f^w;#oY%t)ThE<~N) zNks`r*c)LgX%o@*1p}j>@jNp^2q40 z>IIgr<=KtYm`#W@mxd4Akj=HJm|ZL&)A9EM7r~RaOSH&-dd-MKhIjOn3RUrX%bova zHiq3p333fc!P+@T28jIQ0kRg?&oVHmnyKNbx;|Hf6bF*wVfZw5MVC42T23wd{q=0m z*EOu)3-Ih;;t|f+CeM(U8C>F{g((ik7IA;S6AJ^t@y63zX;5DH3- zVDjNU$On0ru%BR}bopof?n)NHo7{|UPCuBOK20PSNE2m*qb_Qnj}{M|2gped>S>0u zlnznr1;I@7M?Nq)2|T}+zLjShE4NeH&Vo$Hgtu>O<#9MfF=8Y`s*nm*rs#_l9y<6| zi`K6?G{-I&md7ZxUyKdO_GKz#HI{qNUUG268;k*yb9*cMG>-Xh&0_CWU2ZzsJHWio zBo6JU2Dd~`q^uL|73u982F;&dMYldf&~5~FmM3O9dHQ6U4Ohd8tnrsNxRKrTtBog? z(#Tc~Lw~MXuE>AO4Q7VxZ7D*fsmF}^omoM{qp4V(cVWvcQr*96`3KBz`vge~mbk5& z0UZ$BCEZ!(M%geq7kuOtPxjyTWv(alB1UEFYt{{{+_Tg=#Wi!(0iyv^M@MR8Z?+pG zf@F4|9dq~R$2$pi&_^4Hs3fF&U9r~Wqa16t#He_BbE`O*^rF0hCNMkql>z4@I#fPR zW+rPbsycGjSmp~BCNBY`_c|Np{sbUl*+$Vl36W{yGE3^i_#qCCC7)esqaI4hnDa*k z(qKWkU}yHl6IGOD2y(MHn4QMwaUa<0TYr{JiPh;b05^57S+*Mo3~xio$F&?J*=Bqv#T@jAbuHS}I?on5m|d_5MB@ zp?Z8jr>*<)>XY9EqClcmv`18?*&?oMIHsB~s} zhTTsq=|u18qpr{v39|)ch#(yQ4hsPFRY#_4tpMMMD&Pg`i!R#GA%?l*`0h^T9Qgot z51s%f6~4W>_7mc<)gH(>qU>+vzN zi$Gy-kTe>s^#!I2xk)kLd|m5Ul5z7WKK1B3a+H$#OO4@KM`G0rjKM+TxoMzKLsGXP z3nWdd9*rwB4(fXW3BdZBi$!~*VV)gOHwl<88s-7GfoMWbV^KIX%$Nds^$psMMMfGU zQ@;@(W%yslf%q4JQUioUV`)8SA@XGg1qgesd2|sgS#8mfJ@r9lb~Pi=c=a!kACFgu_G7TE=Jg%(S-uw>9(i|0D^c19p!@9Vqj}q3{zw}k5YfTE${^eApaTgIte5J zfDY3^=Sk2DivUJ6kcR>k?f@xKoISe`%G{}c6V&eEc{cOty>|-Ayy+Uuqv8XvqG8Bd zcBJWGE^$5AYLLEDli>tYq`<0tLRHw?O6C3J5TegA=)|+zNiXhzcy5pk;|5ABLhK?T z28$8>2V^EqJP`}`!9Y|pP#ZW@szQh_75a?!1BeCyFDzEPCftzHgu38BjOelg$=hO! z#$|(L0n23@8WmHDq?Rs3eF&YaEi8aSrq_&b(JVCKMvYKX&CBQ+%jsLrkhYRVDy+(C zwF=ALv8iSPzw!6@svRHDiN>%X6ih%ui}@F}Dom+h9bCjkbVv^=!T|u-8Ab zHxHqY;vwQ4amIAzBK)e^ju?+|4BS7FJ%iP^>TY|^+`hDQFCPnz zH39M9YOJ@Qb{!FN-|24I!Y62C6mMB2Gd$jxihQ%kFa=0KmHJyn#y!o1qStVV-Z3$y zbr!RA@`(B(0R1}nn$o$(&kzjo@Lv7PdY4G3odV2{O6)47TQEUBcJp{JX!5lnwJ${V z14cPUi$R-9p@n?yN#Z@>sQUA2`VxSch((Z)LX&=0vCmNnkrP&?g-@rz;<#Z^jmWjL z>0GFgx}R0~k{}W9vei=2lp1=K!|IPUj%VL*>xR(v zhPK*Kp?+llu66%(K!B|YQpeHIwNMi=#yC047#nK1DMH@@K(#`>V80X%zubD5DsJOK zmgNR=;2{1~|Le3yn5RoZ;+cOs7M=!xN507ZP>Z|}3?Ij$KJdUlXTkh2gxC_gR0VjA z7U&oKJ^944$4cUr`8-KkGB~q}g7e$p0)#7C&aMMudDh{f&}sb*Z{3&Pi|cf(qYQ14 z9G8_&BGrYGkyQZtX74Uu1GQlvGfY$g@TGVmmi+Q(6(ay>))8K??~kXZKlFy<6yig@ zdx*9Xj|UhgI|g+uJ%gxFbQmlU6P=ER+wr#48@G@V_h_?(9wqUtT~q#tx&q1-bsvR% zjw$7~ebzXLX(Yt51L^^Q1(8#-vIZCS+k0%0lhn&nm(@RDnbwlkXUmNt-H3>zHg48y zpJ-iO^U?GvAo^=)@GLhl#~rA0moELxBOQ=3I}MF>hBFkS#?f#uG;*5CFpEXv&irrB zqGr(jkKK^Hkv#>llsH>D(XEHSXY0f$G2LOJ9pDNNbEyYEg;aNt0u=~nGKi!(EXWye z8Q5L0=5LFPSV|8X#p+NmYrUp2tdosLFvvJEq8!`xq{D5>E-Y;$Y5XJKmbbim7ordY zmL}gn;sw4-gaiSQJ+>%LRfoqd$mo~e(SzP|YC3aR&w{`wvkH^5wp6$W>hZ%tTx5_O zxej&q&?yY0h?RDX)=lK80E;}HV(x3)8mS>8T(D4U^sp5gsv34xykb<1_Nyl<=qdrL zF=|`*=ei~D210Xq>@i^At3&;EGW*MFzLrSgAwTG>X48KN;7N9nrpaX6{Ort`M`uU) z+#4XNEi%;DHKC>FKfUOf`Y>F9MKMK+eVkT2|Rwf%Z+}5dW_3=EvMJ@!Wb% zia!oEOdlZX`C%Au47E}SE7e|fyHjot~)(t z(OubgRxx|lnnKq@_T#*cDpi@xwU~HTkEE)@HIFL$Jy51Y6T=?JXvA}NZGRU95TosU z1S_7+%{hRH8MC zJz!($Gq|~yVY`8ppG+D{?(n*CtJnE|bAm4OJ!h|+V75jzYY$FFGHCN7W2V~2u}J$H zlW6M_qV3hVttw;(fdBMCR=;Ucjn&CcMv&jLMndKuxuKs-`rzO<5#Zri=iOr)Z4QIF zE2L;+V8QGc_lA*`kqjf$j(-o>8cO1VmW-z*vs-|{{Y8%VD1jESESu!2WpAtxv-yt#CpQ6D>xOr8Ed^hRB^)0 zn<9T#RyH_^W^8vb0G?{w`SboJadGovD@@3A!tD{m5Fp~Xd=!WZXpMlsFoy@; zt_yjz_WJ#rC+G#2$+Ibgo6QZ^)S7ONui6E!UdDHOA4A|?)EYtt(AFEZIEQ-cxp2@% zcjahdce=q`om6~#n?0&vD8>X1@e{*r{w@bWd8iQ^n}4n0p=8)KLxuvdq;X$Ur|{IZ_*~Ex2~qtmJ0qc@WO2VUZu%#*M^BERU-L zEwJ$#ut()RsLn{}faz{!M?+b~TL+6QLz<4})M3~%;r_ih00zLn3lkSaX|lfAJ>y&( z8PbD(bcyqQYsm)D2Mvq+0aYnav8;mK!oaRmA!EPaeYp>mD$N*ubFr;{w>IAEVZi^ldUP%{&r{e4X(R|w|5sq_n8In>)pJ9y;+lk zJmmGB_M#H4^g=8bh~5BLLp#ho?CMjFhFa~Az>btF6#U^|XbAbg+Q-TK9RRwm4LR=p z{%AS*1HL8vX@=0{Kl{hR#|Wu62s{j#qVO@r_C&2eJe~s{)B(}y2!0gb7o6NTvH@|% zoR%pZ{3SGA%sEc0n;MKk{2*WpX+@7eGaM@OLMOG44*o*xhM;Z~$P^ML77s)I=&AU_rG&C4eTKhwFFwsVGppJD=|mEC&t<-VOeKdK zxY9wAKF0Tb)V57ouLK5t2Z~2R>})^zlgA`(?f&HS;vd;nq)EvPjPuxjW>^F!*sLqG z5H}{Hb*ND5N$C2c^RZ+QzYS0a6Y;?f9(V?2<&H7(&U52}{w!Yu$d4$LWq8^M^ok`` zdGLHXKkmZh?nwk+s|rsmrt?>TKK}0)gr_vq379RGKb8zxaQ*aQ9#Of4c*A>B&o^KY9dC#w6&g(GF|`FYg#%+RmcDbXVk7@MIWTLr zkSpil^9z+0RETHp&&k&h06wGRSzL;NizNS$)r(QI`9GH5nKm!ppvicRm)h-` zwBqkDp&n&zU1jtG^v&v>VIiw|z6wIIUL&$m!nIn_kBG$!326j(c;mrH@f1Eud!tOW zfKFkgU}`!lpNSo1m;k_ocE-_synnY!kR^&9g@7N-MkE#y2_YGc4jdlLz++S)5KNxr zwQQ$G{CQEdLvw!B8?ib0R55%! zdc|g5(B$9X#9nm7c|u~9-ha!*@op@A%c-)my7)eVnP+P6f}q0QZJjWo1Mf6ubQ-mTKF5WSEt_`k(=DtQ2~c^?7l|P(*=FmfbH805?|mU4 zbxrL{U|pxl>u-4yeVtCBhoWWa((MSbTr7|%OePs18Y_6{vxIB3N9iOxYx5^57cM?ng4 z2}7Wx2?PT`16r6KJEU|e1}v%u8Ko1oou&Z62E4b8Sgm=@j5+Ql-WTMG(Ya>j=p1le zP5CltO1(sjSq>@FP9h-KE^U2%h`RX{J1g1P#xlg(u01k++9fiUYo&#_Hk`hgqv*)H zy1~rnyq?|+`<4yLij}haUDc|0oCoDs?RN|@|>P4oC-7$Ohbbh`I2#sHH4{F#bU^AE62*Rb>zNgSvH+es>T9frBEN&*2 z24x294J93Wu6`7(n%fq*8v^GvDfJ8&yoxALOo#=2WvHbppsGHEW%wo<12a!+YAj+L z{|?@LKkN$S8Bc@d+7IJliY|D#8Ch#}CIC3{3&*t53w}Vn?GfEs>8k`F(sUxX!8xw; zzAWJ3aepe(A7c-le5VHMS-jjJh)1-bGaSgN$s5OIrS1J=kA9pAo(4~8t>GDjIHI_B zmjA&g^1x?(iyN$wLN9jIpZG^K2C6To{p}Ib<+rwStiGJtcZnIn)3z1doIE$M7cG9l zs5(p}#T&-%hZi;yjDmNef1;Fu2*3kSoCk>BL4uRxp@K&PHy*LGm3@7G+X+Oh9ck##52WCz=^c-KOo)jj02-4Cj zSoEl-S1NxFX+m;ly7W&zTu}sj32*xfjI|%T0JOO~urQ$@i0~PW8Z})(WnpO?9SA=H z$jPt?wPLbDhQ})IsN~z~?4@#zw%2LIDq&k||%S#Ol)7O}v z?`bvYKTC$~ats|nm68-Kbg84QNz;bdyCRE^OIPYl41!r(a72wr1Y7gg>o-kBwJEPz zMD>N|q@8>awE-%nqp{v#Jsd+*UDky>xNe{a3QiHC*xrICth!slY!HZEzGq4m(cnS_j~)4 zknP3sw{ZgqmqaC^t!V~g^dWMEMz#(8<=Xi$V%0+`r$P+)_nITnzpES`49y{g)keFz zK~92z-a*q!z8Z!Cxw@nqp#-tY0b_*&OQatY2wnVg)W5^CTG(S7o3^C-FB5&mGF|hU z_;ydLYQ*RI!;J%uW;5dt7IP}khFB{o=G;e%th-kFnwP)NGy&g&eZIak)9JhLG`Md~ zu-k3B{X+%glk+#>%?LK91lIP=9UOywYW2ot}s5Q z4u;8l+zn+vQhQ8){a$6sG_+7uMVHuAG*mfTY#Oi5)tgUWQu^A-8U2f#fT}O@nxfO) z(wc#_tc$YgoH$UfvO84LjESwI?5Ha$U)x1@3XMG6OK`v34wSz?RE`K?Y;s#oi#M3t z3$RIVBFY7iJiD<3`iPf+VAOif6?3*BLa|oMI;!uIjB)h+XT}Pnrbe5Wgp=}98YA?d zIq2u6+t$Fbv z`N&0S%iw~nZl;HRfJ@CKT9V9IeLU+CL3W*d;U5W-fEboS-KZn33J_lfh$=i)2u;8k zaVk*RmuD&8J{PX;^un76>;)Hn&Sf{FxoVDudN-ahfoq4%p}-1+yIu2|bdGKd+N=}J zw9ZtxjUOjqX|i{*M;5(SixuX{T$h^-{+s1`9-`z(hVW4E1FcLxS|iuo?z3d#Ak6@_ zj)!t*1ch}n|2Yt|NRYP$pIrtkoP%V~@fQYweCK#G2v~6dB$6=Pp+9P1H>%}hAU@o9 zmS zZBwPUDibwj*-=w0c%)4;$dybiOddVshGitGK5I2}9hRld2^1xy`v71z_MIHseA-Q5 znoKZZ;k;=lO4rhkko(1~CLxz>q$?W*e)@yx=mLEKc%14n&~9&Te8-jIb9XfT&aS2&9My)B!cp}`Fu}~NQYRh)hs`J zR34q$07+BE5m*LFlJR6lcuC7jFI_c=lehc+YhwFvVq580p@P|%h~@DJ2Tf(W48v0+ z)YX_GB-hr1Na;rGml7t!bmVY^JACwy=kvv=Anj7H^*O{^f{6UBEAnetvCKpz1n%r& zWsv}mC7rUIWMam|$}*GR|mAZm`X* zY*J)v0dzgTBME?1N?1!spjv$jXABo#`18QAK<%wGtu64)8hP4zfvtTR$D6{s&hf>g zGSw>AIUg=Qnkbe`y>sY8K=!L(&^rJlu0*ch;)O@K5jXxH z{?B71mje3q_i$z+KRaO*}UO?lNq_0iJ|K`Rx>7f4m7M?hf~ zzqKtlMb7MpN~QGW5{!?3_vZ~}hcnDbQV9}GsVt{yAx#;H3F(d!(;~c&Eh69(ZE02! zRqWn2R1gE$o5!a41t(c{$ZD8%py!UCnlMPoG;a)S!zYy7Ssi*N4HQDJtx& z*yLTOtGz|;)u3N5i=G;d?)VjSNj?8G86--n;2jU2JwC-+{I{mF{G;u zSvx1doD-ni0UBBrRld4j8@T==m&_|oS??pHwM*ZEPICOXJx`{+P9vW0mJ*tG!AfJW z1ad|KhVH(^i)me}SVx4T%ZqNa?D^~2*|nRAMOMFwZz7ife$5gB-iY2w+NR+yL;K?B@2!~1$qW~w=~t-DbecwRt40U=Yj+=x z$y$hrs#f-bSoI|(ijOondx=)EtW3L6&d2zlf9d z)%aoPd3O_x!9o6dXxX{7>xwXw(XgW{QgJ1AjHVU5C9>Zd96kWVu)Io<@AMam)MMzc zpRyUhiKcJv{c$Dz=a5N@_U!LJeV2E3*L$_t+IwCd6Uc?bvq<2X2VUs)p{1CMhrjfP zh-HPUT{e6Si}R*4ntbk3$9xm8^I{;)!uv(|>q+R()|d5Hz%K8tV4ka1F73Ju2yXnf zy!RS{z{XzR2XEfX>fu0JJ4X6=T--YsiQqQ3^e{|~V0rq!=%ZV~2ks_AQ#UT}?7qvI zgu6Msb#G`gW3-o+2qZHeK3@$Bs$mgWSG;2tG7_=Sti0?p5LjyBZ>)FaT3;~cD#@Pf zy*lZR#oxn$1CMHfqq^&!bsyZ8(fBKFp$%eqHd292`wQ2nJF;HyTTI>=`E2dOHK|A) z|MSo!sTyk`x?jr2G*gqXtGT32HLv~;BxlLDJ5RUl(N@#@2izKg*JV{0U z>-Ga`F=fWvlALDss7V6Z(1J2rT?l_4_M}$K`xytG5y1H){f$Tp`kFh>yjKtqjiaUi zNB=L!M-0;RDMZMVbd@RCHI06?YiIG;?l*AO6R}>=JjQ5|y<)xKKUpDh19ul%M^QF+Tp$n3dac(}FfmB_-fDdw@;k>7Aegtcub}N_vjjG^eTjG~CKM4#mxPH+(ohl7 zQg5!Yvpdf~+zM9px{|q2t@DDEBl%Xqy1<#zWX~048|)CW2+20WGrLGW{@{0lE9bhE zUzGcWr|L^6DdcUIh_CS``fhKA?F$=u-=Emp$Rhw{Kd5>?NPNl^6!(S^9^!ll5D5&p zk*+|aiQxd`1RyrRv0XTNKGnq~Jz@)X&HJsyRVtX^{}&K=v+(<1ZdVub2u5%4LB(AoI0W~7yy1Q@$Oov!an1+xL59~^lovj2Bv3XDBDrxKMsa0d#z~79W0Hv&?m2zij>B0|< z4zqjWA&``N^^x1x-@i5R`q|JQD}{RY8Wd!C9V*26Dx&Uvn(ERj^ZDifl5Upq8xLNg z!OPya9Qp@i7zikCbKL@#oB$YPYG zvx*uFeuD;MkqM5(Jidik{^J+?;ljYJRw?5oLqii3tB^|MiG+a>f`O4o#oHT4H7`VR zsE`2LqVuK9La|MnzJ6(W415|SiVtLwQS*Y1%itC;4bCBB6dbwq4{QSAwxVbsNSVuA zd&KcW6t_#q++;rgM(d0Ao*_c#AJG%e*ACIQbfujccP={99Ntave%v-pKVqY?=mnoE z?2Kn|D!=`1vo(5)Y2s1zJBw9G@4Yo^;d;qS95UAS6)vIG23GX!PR<=?+r4*$txB<( zO7*z{dVSGfqs8v?XvggdWfi<8cVO|^f~;}p4-&@b^4bDr?+BZbL_)e+EQ*=M ztXyum?azPV2~_hQ><)ZdhUQ_@%~~1FWW7+Xr;4Ls9g!+|MA^PC(NC3z4!W`xr@6Yb zT^Jkcv*n<#SS)3raYA#lBXH$;6~X+mOS<1*k3GBihbunI=qC5~MNJy2*w!HDWrA?7 zrk;t5KNB9j5YXClnK7v9B{Lm|GX_6OXX%IqLfD!nU)evnfxa7VwVv)yOCN;qx~sk_ zRDP<={O0Roj|>_m}`Go#mOx?mzgwIHFmj!Yi{?2 z6trb-l!tZjN3|DUCg*Kj9aZ^!x72@!y)-(dAFzc>D?x1UM_(gCK=EF8Rj=q{v= z=lIB^jvF8sdgfWo1QHLPD=#J;w3L6U!5XOQulKnk z3iZ56Y$swr`L#c7_|v&miEVsP)$zwVAVPh6j|xK6y*{&Gx}y$+ah-IeGU=t@^r5U2 zb;)|O5eLb`rbdB{24=3JXduAh9e~C8H7xcS?kr`J+c#mG$TchfjL3OB3EFmgfmydy z2ot<*tx8qp55M>kH^#Z@z$C!DHYMpU-|acHd9s7DJEo^;{x0Pocoi=G<6A@2-EX%B zFGb45>g#)+?A+aKsJ@NXt+h%sWW94zKLBT()La2gN&j_3WZN=o>l|jnmDCAed)~)L z;4P+Pj0Kio%3Xipx^hCwFMp{|(czk=GA2;Q)(_}FNZhPBWJ|k61psy7@)976r|%`= zk?uGU+r0tkL8VXd5Z9dAK(+BzZ$qx&k*XzwI);SvS))JjE1Iw=&erXEjYB_@H~r_w znmY%POH#Sg^F9~7BTcw!rj0mW_0|1-1j9Mza}~oAc-^?0xSvucL5;wi&(?DqZkA?u z85`v%9Y2|3wTPlp2C2vAhpCu(k4sLzqm6YP>FhKrfaxkHFK3@zx?LCGxXwsmDF8>; znEmcFcX8|j$PNH%vH)8|j!UkaWVt8Qu%wZ-M6r2D|LHMIEFRS!8^F8P{Z{F50!O_k znD^DXBlolEJ1Y5xw{Ivqi30s*;7grVq^NnZ%Fne4|Gc*+-cu@{ILrTp(0j1e-Yq&Q zHhX0RR8KzM7~(k3an$J0aLuNONlu&Jblhhvp^(`96%_JHqs8^23Z=M<^9?5I;;4o7 zNZ0Qc^o5NjS~71KVw%R5q55z=T>?|--k3rCe5r$vIbFE|RIH9M>(bX|bju;JIwXeM z^>vN<3?V17;hoGbn~5eKe8&rD8Tu}Gibf_G_xicAxth4;QgSo{o?QBhH(YP0F z_(CX~O2LC|g|Ga3ehZ`(ohUj{0I`x|GiN5xgj_W{pnw056kzmdf6$)+hTHi1z1A<9_A@H|;q6 zz^H%&aw*3$Pcw!8liGFzWA1Jo!19Mi7~ZGXKV;8>UWoNW_QrnYSwc^$tShc1QB#MW z0bn}&BX^Q?jO4@9E{QJF)%Lf?=a%jHYn_-f>cJe?$`?1;|ITjywK#c#l=bHSq_71F zJLW`O-6CurY#BR8b}b$rh|2jO%vZb%xx^0XY+hBdfD}a~1n<{-g=lXZT%Xi){Frr% z;^uho(xi%-szaH#QoaZV2tKO-(0^4}%W*+mk@$z3s&m>gFL_^5VH!^iJfZAOfx3Rq zc(#?*V+$~^Te_+0L%ut-5F@a_QS2+v>EyQ7K~?LBn^%%=v*vY~D@Bef*mJa#-|K%E z^uPZ3^BaI{uscS9^OogZDJR7~zv_OkNS)l6Eu)t2&r+azoE&xtFn1I9M!txw7sg1=2g~xTv-*-*Oy-+oO-f zDY4|0_SDM;S=@uujK@R~r$GA!+_w%DQ0qtPVG>|fi0n1cQS~v)PTtQMS^eccofN%P z$Ki!IIiQH<3@Dfd$Vj0gQ#D{p!=H-0T!Lq@cP3=w;?l*`nCZPDC6`vzs>|#>q+Jzsg$q9T7_9j*M1Zl7M+)7nxdVP2`ewep} zDN_P1cYa$XJX-=%L6vohs+ifHDHwfOq#;oyT?ndwG{S2;h1#15{AiTq;*|@`N+({j zZ!XA= zEea2T7yymHLjrO}>a(q+M;(r|dczk=X9*R?y`8CF12%N1hAJB1wE$0@FNV53;EVip zt7Mxir5AoGreP_hpNg=U>4HDQo3A3W#pd;c=Xu|(@`mqa7}PUHu)PpC-+T+DTse85c+uJy8jkTZ+2#j!!mNKU33=S=f$j3 zfT*DyB7oDqTj7r|^gnTJGZY4%35%_&11@GJ&^<-2RJlc~r_(u$aBG1T{ZAUt*%Y@` z^?eGBxfRRluWRye{l2X;ZK&DXyRE-+p{$hpsy@%o3wOO-Z|3>gNPkqvvszU(_^%3Io z>~uN|b+%G9Skk>HK0h=s@p98;HTh)?m$+5cYd35dQb;dX1SL~Ob$v%zRYvqa`Q1Zs zJO&D}#g1TEYV?0H0IwQs$<`P%RtR?$Whby0|IC&uB#3$#1(s3iQK*rM6|*$jB{R@- zxdz+ub86FlA?ZFL`o|cVcK^^NUxa~v_{naB{sgdz#W5ief&p@qN7%eCV<4l7Fj4LV zeO3dY?L_)#AVF};%I4whvjhEWCO+v0Am1n^N%H8|5wMV3qYlV~AmgXqJePj(1`5D^?x7aUGB$$;wbV1thSw>)8jmsFZo}?{X&oBeb?$;N}<<`-Q&YqIJ zLmKuF#Z|~SzOekNuvrs?3O2%oxX%wr=<$GXJ!fmO6gUuBT+xrDr-|F1l9>`lxFH}} zNNvG45m^-I+4+8qiQtpdN!4IOIr8YTrlCX%K^c-!Z0)H@HPp!RN%#cT`~qDiU&-#U zGw68NfwD~Qd;jv$s@6l-n9_P3y)pTfM*gE9*0Uh}k1xGP3YoBZ*bn+bX`>Q3269F% z|7H`z8AvKL0o|G!OeE6WYDDQ@6JZ`wE(CV}G(;&bgC_@GAr-fmMj{l4r!UO-do+Eu z&oW_`j>EUd;X@u)S>{uuT556@CYfWYpb9cDSOA=I$pTYk|3^aE7~jJv9`!btB^=MS z2P9%rl{83lY=(;1=0cV`&qUs}x=bs18!G3FZl-`$=V_vn*wj+rjnzEnOrxjV6JzD} z3=+Q$C7T?tuuW~xA6{H+*7!Zd^UH0kG^Y=(ixk(Lj zLPU~hCKHxjHDaXw!;x}tQ)CgPqc8aI`Q)`j#)OquqcSM^cV6^5BdjO8gLRBdDOCB7 zRA!?Q?s0?ECJRLg@xmp7AOJK7dMYqHOZ!StGXvKdjHw5YdF%QeOARmm(>IIurk~_S=GG+^x6-o z{voo((MdR~&1HJ(q9B%wiu6-7_e%hQSK_5{AUwotK_??6EbIOAyq0_8|k6BgnY$w92 zHH-V6|H-Wdf@86WSO8tmrC<{vw?as&f?1%(QW3f2d>cFIeYT$7|wdq(RS#Wa&=E{$J6_2 zMc`F8gSjdbh{r;t%1Vdw9*8miR8MTh`)hq>wF^@Ufc3S0A@fIl3vhjY8}Bp~HIHSG ziDK3M$WD`!2sileXZwsmxn~E>P+Nl`K5tCS0gou8axNRC)a6SA-Z#&48f=SV)hpnY zw-ZQtz$p?DawNr{q0eD+b=avRP-&U>Bf3-K8F1-;cl(GKI zXr-*WiN7%1Tlfn&luG4v zu6lQUJv@#hS!5z?da}oahUabkVyAXTKjRu-JkU_NhfAU7`_a+&8XQy6L0j=bP`-b_ zfBXN+opL7+mSo?5$2XW-;oEMy{yyi7jP%FdPjWoc!}v&=^pjrkAH^>1A}af^}j7*qELLoWXhXh4_0 z12xRF9N+} zR{z5o`e`(Xt{8;^9MpGlx{zRHti}$(YxFnBh5{}aq@xbFCbU9502KU{!?lq))Cq1X zQ!oW*c!ggu1&ca7Km#en0SkachwF|3Tr@~#+?6l^w5qsfUvlzr_KG)87*O)AQ}Q4D z`Xq}%W}g8W9KpD-hHCuJYCuVSKtQy@wyXFixf1*GG@%k40gBn;6f6<=CiL^&fi>fT zVrc^eOG7pkw;aI1yGZ{7fsw)^{T(-o)uvZNG(bUQWfTaL8lON0TzxMYfz}&=)my-%WE`~G#xnxVB?l)Hx~6EVR%}Fp zae*%zE9!030UsQsHfX~rghDe&uph|56NtOh;R4=M!-2IzD?q~-Y5MkE-#KNtukgw{ z2)3{II|p;{HxmE+oI7=$A8dLvMnc5MU2Jtbqz%MtOP0d{8Ax=Y_ZO1NQdCLPYcRpa zdwetS-6+6;9DKrtYnh4At4~9NeBZm7`~L4|aE9-77J7OG7rwU4CGLyD9F)KZb-)M0 z`V$Zxv=SZhIA?G6Ch@d*)BnNJtAWx7@Dcv{832N?b9>Kl!2m(Q5&&0gZN2L0nL z|H}PqC-whdynp!q@%yLmUstbRul`f_&)h$7S^u$f_N&^omNRqtsY3>e54%2g>k6NtGUgwM}Jm;M|Ob3lOp zh{^6n3_{>`p+uRZr?=aVEcV&nvm3>E%HiNb`5_$g7KFoAN!2ag>e0Q}2~g91Tl zkU+e!OE0_hlVS=u>L`htY^2eMBV6EkLXKQUvQV045NidRnyQJ(8EB@NhPBRa;wd$B zati-yD58EUil2DM0p_1)o{DO!sjR|EE3m-g3afOWs;Vlreo1i}ZA22rmbs$fudluG z;^8jvwt%7s4+3L?4qR|)21HUmS?rTg=E&tGdEiOynO0Vs$*s;(J4vL}O5+Tj(^Ok6 zwA7%P$(d=``9y``5krjY zNX_F6FQOPIiUI5L;XL$`I6_xlwLAhpCUgZ>SG+JN7K0B2)ZF20;*dhOi zN2i?fQAr_*1PiON$`U6mCZ|EM8fhNRg^c^iyK=8BdjJnG!G>rf7c+A~EX_Ia2!*i{ zbE3>#Lm~EzHI77bt0m6djW^IhWkxBrU*dqF0|z3Y4T2J|=*?(K^QZ&UOg%*oRZX1( zmAdOPZB=T76q?ox;A*|qy!4V#LWw1gFrwG}cmQyM3fNv7gB`*n@YF%1PH=}}D=-$o z5cqBbmu<1tmRmU_Dyf-J{1^pf!*V%sMRp!uNu&|^r1|F5T*3*apEfV5pP<@_3g9Gx z469(TjQj`5sI205t%lu#Sejg>sJ+&}u;eS_A$T962j2<%IAoFWkfY=@IV}HC9>`r2 zWu?m?u7)F+C$E{$%b|%EG|ea{agGSUr!9gfa_PmEL~Kdl7Nqk~w$n=C*YxVE;g33x zJq%39i#qCpV!*6za?wP-3&B0>j_SX0>peB zr5#pbM~|ptl_8xjEC@48R$SK#Cp}Cgwy2#Krmzqn2qrLFdI%Jx0EOQ9t_^kIknl#a z7&*+rBaML#JC@fLG&%1w&X^wcnjsR=SPpwNN;ltvy2LO}`TxfR&LwuB`N&}=*q8xJtRwqyAq z3S_7tbf9y=0r`M|9rPgEIKY7q+<_x`q{b-xz@fv*!CSb93k*Rdu8N3cPuhS6Vw_j`RiiOh0I(7d2g@q8b zI7A4i9AGL}nVtiVjcg3s+Hc4p99KbyR{7aM11Atxv965+5C}miv_XxT91{6inhVOcE$$WTWFRW41Uhtw0$g-svpdf?-HWdg-crO9Dzyu&ZWqpF|4$M$FSnK~o%ydGwN(N!O`XO;41CbpwoR|%B zm?j?<5i~ly!_l~?Ch(X?J$OOq)m?4%#U|mQJ$&=iWPz z(QV}W^;in-ZlROuG>SCA;k9>I48ED$mTB-?6R-I1lU50W*t#_JQEN09je4vC}d)SVE5DGWypDHj`j-#b7cxK|4?m${|Ezy-4D zs^|Gx$gnBr{~<;`M~N&f2*`JpCfsYvZyh z`;2lEPx5m1Jkowrs<>TAa6eMEDU0q7B}MK@O8)N0%I(}ZNt4VCA@HZiBBCS^uN4qS z4j6AS91jm>YEA6Po=D;G3}fp+q_6)VZllOdH5vxlwrPh*40A~1W=QXjvLS^=&}8Jm zllGuD&?kM^kLyOkTQs6fvSAdMAO!ee4+cRD9wO!5EBFWqzS86Pv>?-z;DEH`=Kv%N z7YGA>j{2(a`pW79@PK-f&JEfmg>c~sUZD0gFl4Ci{G`j*J|qOUj_VGLBd{s{dh5;j z$o}9Yb6z4XNavm439`zfLo*^>`P#6pl$bL)^62aUk@!U>@0r##Aq@WJ0<)Y}s z1}_i~GLY9whC@71Ohy_&EIlc41a=;eTqzPMlu4k!auEpPG$K;Q#b zevZ|^(5yaz3_}JE;6Rz00S;cE4Kz?A;;iZ(%$Z`UujsH2eT_rZO4u;(%`|VsS_E=3 zXR)YaD*R6@k_4T&4K@bwz#MUX{w@zBu@WmW*UQO6hLGDjbo;2RxwU_-BE_%7FsRfr5zxUcjZu zCE(=14gSVV?%)NSKm-2|!~D+AnP6(J%)~GNvj;=QgfuMu_OM;Z3`XF@1*t+{7IG|D zrz+rK^6X?9B+`5a;Q=iYBNK2CH0~lhk`F$n6>=dZ)F{d@&?G$q>PS!&d95X3Gd5RI z4#~_iXF`u=@wa~KMdsyCZYCFVQ3gAsnq_Sj7kFo(5oL~xi0U3B951=5_ zz@RFFujQ~3l`L&5L2U_y0G8h7Y{c>i5~3VC2rb1*ErZDol&P;i1`ir+qx|3nUO@aN z>BVfF74AMPD;EVG}0(s$E3lHg$-^bQ3k^B`1E< z;DU2S=r66DEFh6ndPXE8gfJWG^A4;*I(cpzuM<0~(Fm@Q3F!+Ak`LwlLobd%KbYVH zm_QGvz%D{4J*%(igh>uS20)w6a1O@_?vvLH194U|Tlh0v@GV}N5*wir5@Bv6@iT#p6GM~~M)WlCpf^g= zMP1XGT9nr^4n|w@C8sNT4vb~UZZ~&RUj76p03}a&5;#4IGoI^Zc56+IiFynSN)$&L za`6sAAQAtfQx~Li3%1}3uoJ#`fJzH!8m~0@xIhWQ^KOa-Sr+00qF@lbpkll*E!R>7 zLSh6TE-qdG4?rdjCK(&qsaP(w3v68E4a+v>we;TL?t6BfghMwJglQ8gnZB|{;~cx`19fmLDh zWA@15Vsb@t^fcn7#CQ}2XZ5$32O56SM#b(%Q{zt9^`6^(FGos$6$E^VF__z4^c87b^vX&x~4?CDz*XX zfRi{=wUWu$JQif_fY4CXMN<@2Q`SXUmQ`JnUz^Lo0?wFhvNLQJHMD_Vm@QE5=yl-* zG&tkHy6(+fQ8l0|7rr4ET0jo)j2rlXAc6x+v6Wg~No-bW8@C`^opx%u76-J12eilw zVu63mHiSGN=&Uc82uuY9G;W^&!g4_lidRp~j~LxI4(&?L_LeB8PG9R+4rS6U6q6mM zp-_+LP$NrG8B)gL0UaLKNe)bM>);?N7E|%Z-1^S%a!@0TtrbK;6H*UC9IqrZR&@XU zU=hrubXRs|QTJt6SFQAyW_9yVEN6Ce@^WrBN3F?*9L}$TmT(`2Tbh9$nvN9Q!5ywa z50okjm^b(|ZECG`Y~~AEuheO&^?I!^JdU6arer*}=u6PngUE^l$VUYOj!Z(K4x9ib zLq-nn(|uR7PWRRg^E7@1GrI7X4qufudPsRD^M74p{}wkau%dAf_;C*H6YM+;hqj7q(R@46s$O_#f z1HvOryBCYM2zsNl~xQ#h1q%a3g zQUrh_Gb$GHL8~H=A<|Ib!WLqoc7SXn1>saIRuD9a4;CS03`LSPm>oCEp@IsNmu!S9 znUi0XRsZu^UTV66lxI!ZGe#pPA!jGQjFo>2kW?^-V^EJs0R}!n8-jQjus}Yx#tgPK z)97mntdRJmF_@E?mE7Yh59kP%APV##7O<#ddVreI7MMC<4q(xq&KGfB;10k!P63mg zb4`v9gX;WN757oj{4;-N^p0=BEeaJL1d*NhwuLYdJr&`palUD z5W(D3D-?L48R&##KS2}j01nD114-8LNOj4qp&4jT{3yDUVN_oSGZ$w^qgnW)O~YpS zB%E9VHGGt$JL9=(f(C=um;{nS(u$dyiypAS4w_&JuwX!_P?c`_fQAn{uha~Z&ww%@ z1FBU$ctBT(dJt*{sg-*Au34Bq0TwSzKo{YKoB$5cuj#~ZPS^Mz+nB5U6XNz2ti$@E z{VKRh#D7&|j}fw-88+>HK@{NnHg7W*e1pgCU=k&<5qRMd5@D|yVXrfG4{QOjOEV<~ zTN8w;j2vpmh>B!WkI5XH@lKMHJ(+Ph#Imn$;B>Pm<|SS{TPOcD)mZ=;0Qcpb6#zR1l=Vqs#CT8pPo zxq}G>Lg6!3f;3?&x9n;yWcol+?OxMdqhl%9mK39 z1W_T^`u_kK9U?hmZPT85;RyL4q3pXuHI5Pbd+z`|uLc}VNCpmus#G(U4u&zPn2Zwf2CbR~0t1#TZ37^Kw+fUHH5~TJ%;~H{AtrpyW79oWt^nGgdkm?twEpp$VP< z3+jUmV4)UjVHRlo#&;mcpB8F`8B3|~$1xxSj38HxV95WYxt~HHFsK=PgNbdO{KG-8T+GM3%u%&^K4WGEuq6aotxsoReMH4D7_K80dW4}9 zh>F}MkPUP(e@dCid{+k_9=nU1o;bZFCi z;Y>SmO;j>(v^ValnY&a}Y|USJBIpaqI57PjFU=*H8k(B-rM z*ln8T%z&o1H3>4{0*1X>mw-KtfYzgV3Y=gFviM5^g9E0|i%$eJ=)?`ruMKXkB>cd5 z9t@d?@w=sqyWx-yLr~7jp4@%So;>d}?5-LF@x}k%oFM@j9^!ofSw>3keGl?I<1#a^ z^%@cOpbOf7$*f_}3*5kKM`JaqBo)4`7Qqh~Kiwp}B_(^}ImEy$9>Z&P!+AC*J$@H= zbB~bCSKZ3QOK(EVL=+E0KC^)yzJV0f@Clae8qB8`b|LrkzzkgOfN0Lfv-am}T=|5a z0*XFt*y99foos8T>HSHIza)gH{;97%%3D(FL++uzJZ}@H+e5JYy!`9EpR3Q0%=fjg z*q*dgBi-4Y#Rw6y&VgZ7ti9#^y=S7{>p<`J08=kDQ_W4U0YcCoI#TE)k|r%zt5&2w z&B3Fo&XhKHD(=}+kq@7Wb?z(*<)p~Z|DE_(Z#8N-Fk5+fNXT*$y9$q^$bPLP4cN8%JILx%LY z?7_na%^o_yaRz!}t6aHS;#vg92_8SV@W@#m3Zx&jt4G{z*q4)?wtvJ(4D0u(O@lYF2P-GECcktoW9UU#=$3}OQL{dr``mvHr zFv&y{b2&BD(@#MSMHD+oDMgJ;F78x~PSijJQ){7ogG(sQj56C;tIhTs9z6PyOEzUu zMO7~qE`tmiQ22mB21zW@7hhwHQ6(2j7=Zx=6d-2AVvUh8NMvnH=0s(e^^jScAK)Pk zfuil!(n@zYA%{z}^)?%Ae&BYSZaK>KTcA}5M`&-zd8nLC2uTA?HPA#iT{+ja^G|i% zbr+sG|D2O4c0@U&o-^#Z_g*Y@@Il8O`q`J?e*MwWDlY;OXrLT&%<+U13|?5#gAxwA zNFo+qh~b7Qb@);SZ zJ@nurhaXdgl89Sg9ATFcOK^eZUVmYE#u;NQk%V1_WspIbM>JMPERp>u1!b0D)+Prb z_%W$yqq#&Og-*b+BU**>Mq6!w=0@6}C@ty|qAT}iC~3+)3Mn;{no6B@|6sZ)ci)9K zUU`^~Dhg<)y0?ric?^=r9uV&Or+p%ehd>xS-_36KBC@ zTc1CkjPh>9#b#*ByoK_KaUiiQv!jsSjB_>U>>O&(+jUCbKjMfAk29p0dNgRu#F9rW zdkpgQAcI6Lb=7=WlQl!1pmhfvFMu6(M|ji$2ibV&H#TIIWNpi8$=j*{E@@3`fjYq( zJBpGmzp+RgN{JRO;D86h!D&b2YKAtl5sEh8LMzVNN=$H~qii5f8rHBzFZket4`kp7 z{362{(13<3k->(5*%A*fV3;WJpme7zpX%BWF*Si;iEQ$~6Gjo5IpqQuyf{e+osf$@ zA;))xI#i%Yb3Fe=6%SF!Qy%exqZ{Qo10m3W-gK&=v+P(;J3kXosD=iQXnc=7?Rn4m z%D0F5)JJ`>Y9Fm^0Y8Oojec#oA05Irto`+`4nJ~`05Kx6lc-HY9m++E5GXeW!l)?@ zgrEdjB#op@g)}YN5jDOM3YYkS8eI9tyFf-2T*w4*MpB_4j1&q_D#shwI06KCzy%zl zK@Vu)LKHlA1~LF5v|q!0yyJ|PDfyx>H>fd+ zZ%k1d-;f3zPB(=nGyw}(sDmA1u?tv4A)0%!%LTBBu!Je0E_$# zfQLjWN>Njh=AswLgKhbP+o>hOKX-5zNgeVUIJ97;>uRY>VcI`r0rrs%8lZ+YnNyco zV=Dp9OliyhI3+<`2Z9AkPyTscCmGG zEF3~2GT>15B=@}Rp{imWD{?kvLrU?VzSyXNjuuswLTL3C`VUWy=b^2YD0^a?VcPD& zws{c5A8?D?inPkN&iI9a;IOMFgaCiWeJOG~a*^fQ6eAfziF4WJHtM$Vx@69VD0jkL z?q($>&g$SRsUojY)m9x_R4Gw|?&UU-8Z5JLZm zHt4|(Tc98cQJ{;#f`~94gwDa{i*QIMe3=mR-~&>CoQ4-`n-2Sd4)J;oY>pG+5--9~ zn*HpGr^p*C!VHZumhl>CY+Cco(L3O=qeDgY3{voMJ>uIf9|S_=BO_T5$XY~KNi#nv z%i#r6mTA~@)lynLGRrlEWU`XQwplxi8f(O=Ps#k#p>9_yGkWh-tbwFgN=05(`38=_ zWt(qgLrBUI_>8h~JHkn06i=YwoI`OF3>qmH8MMcY>~W1)Fo6uu3|*Hn&0xL`Vh>~! zH$fyegb;Wj1R_nyV%3@Im6(Lpt_d+$=EpnXoQBpe299NARxUHfEXMAM(}4fjLme9{ z)Oy%kZ97`~4D~#R+0J<39-e&>K@^#zQKPm=!mHT%=?V@Z2ti0&iuQ1yo!rbdciOs~ z(~pcW8|_xgitHXiyaQFcMLprX+!@|xSc4bTm~OM=#Z{~P=_Tpak$hVuliL;C4{gW> zX#@^vL4#G$^q5IZq+tstPPoJ;ZDJ7VVpjtQ0h7N_=7BT-_)?jVZML4+- z8((!^AaOgEhhbF}6EZPH)({gCmkV6QRfo23c!m{(LlsVd0!*+3rUyg^lUJdW0jn}B zCMQ^xp>ndLR4<1c6jBi=(KR-QJoZFuI#+zf5i@BNbSdU@jN&K+)nwo^4dtM8!&YoM zmObSFQPnpM*Jn}A)_q9!efJ>{tf5r6piW{Z7BBDtPJn*QrGA0cep&`e&DC68Mj^kk zQ*4A2dFMCVa%N_+9O=?Aynt_7*k>-0LU@J}P~|N2@PG(s6~gyQdblI@z;CvJ6K?ZW z&O&iyPzO;^7+ykx2tybr7#R^JZY!8_AMgaYAPuz_gO)TKx?=xxqcA@t7Eqb>5`!We zUo?Ix<5_2+B5xEFhuBqCcbE->*M=>z2PT;(=7VtF_HAmIBeKc9uD<%zd#Dn zFbzIg4WmU{{6S>=frVLEk1dlcV!;F-V0Pt}jp)aIS+@UNQ0a}pVi78l5+lTae`AhW zAwk$R6@unLQW07$bUTQ!2vf5MZ6Gg%b{f{ELQvH;7la3)Ko4K_h>b;6-Czyfa3R*f zA-6LXR)Hh(vLns#4c!1k7%%~kc}*A~nFxacM(|(~5mKL+L{3n4c(6*R7Dl1aHR}=< z81!ns@grPeS%C5q0EI@M`4TNwC_&gfQ$d8k@C)GMi#9fF`w)G?$PV#9Dtv?#1a(mu zHDt`lQMe_3#sd~|&<30t0z+VOVZ&-lHkA%iomVM9S;-+=2|q?vj$j#<6f|(T@Cl?q zLd`&s1i4#?fDw!ENW9Pu-GB?dC2#^KgL2jtX7>L<_2yWAnGF}Bhi!-wZzeBV)sD7M z2R;Cq5)herWqPWoDigtew30+AHw5ycShg2NA>nOdF_JEpn)fscz!!X>88e@`8!54C zLKu_FXHe5nlhosjH(6}uu|1X&57QtD(eNBdF%8JriA8B--p32kNHSqzjUiAF-Kb>c zW`=g)(d;!4c^d>f~gahZzIsd7&GAKkc}>lac~ z8nn&ootz}CNlUG%G%jL_6Sib=uEGCaJ0+O$xCpk;3x?VaZ1I;ZWDSX63t&r-d{Cc^ zsfXLp4co8{$bby@@lh91paul4Q}IZN@Cbtd1r_iBk14R&gaecbsmS0K6*3Tlb*W`{ z2Muc*of;D0q-~)ps(s>$Et9b&wzy-|u`SxFvE(5l>uU1Ic=|-2vnrAkL3j1Hl5(~q>mJ|Q>vXs>vqnX605NYNh_^O`zWwPai0JUI)QK% z;g&mvBQF)Uz0eK3pbKjImuTA!$AApSFbK%74T;b~et8VXpbLW_23~LmfiMV$&IK1|jeQ>_U5ClsqT_ zolo$%>+-RZyLiTfqLw>Gfd@un#A}`_W27-4x>+43tb`2pDgQ7IEL#o|MG7%Hq|-oK z>cdeR#UFvhQSB*%|6#jMN~u6=mAt#GR+)yDbRin@71o9j?IjgW?8N1m6fluNrFfUs zAaGmp6^I8yeqbzvpbLpG2-bkM+t5Phs|$^g2jE-2xI@ ztZdpsfQ1OOf(U;s1*7Hxe0xm+i&v6~0a4Hve#HmmcBxYE0#86Bh@~h%(j#9p7OE(! zqxw6Rby;I{s*3ZOR3ZOHC)R7W2^xr1!h9sU)>B8GQXZyTlM*EgyUHG^^g<8fQH`)s zP2(z!z{7N;5$fje>bo zFmg+i#$CV!Y_bC$&;vf;146h9l4Vsx2esP z1X_UKe+~cGb)DCFO$30Q-+?{Y0E`1Za0cbOTPxVuqP8ZL@gzIozmIC!P0$OOJsU;b zNN}*YHz;xB+bq^aEdAZJO&YgNlPLUru)KsUtUcu5+rWJ) zKgJ&U^%k};)a_|3e!vU8(4rCh1V4N~P+g_hEd^&6rJ0%C4FZlOVN-G@!k*h*&G9JA zacF~9ik|=jau7^MkqcNXa0U_z+t3JsAO=Nn&-(oZb3W&R-Pd)k-}!CVIKbyPFabiq zy^1X{Jun0yFa)`4TMtgz5?%pJ&ghTsMD zjnDs0=X4(6cmCJ-edm0B12`Z77!V7~;Js~78OLt7kFZ-^U>Q&V1@$}u5UR+Q%>=t( z4Yp7rQBJAuWFTUP=`OXv841#UpwTH-GQUyct~%<)lj68WJS^Vgs-6qCZ7Mh(DoZ!h zwR+EKQGV=EDdo&emCU}ZUxEMS zcPKNpNxX(bOQS$RkERXqKo2^hPG%_$*KqTIpaefa_I|zYbspepujh7+*L-dRH}IHU zU<}@SA-eSlh)~d=b{X^BzmF;56L18G#PA18sZV~FzT;9%s&XGN$(@coin8&XThht# z@c|X`!gK1nA;O?BekGjpD-Vn{9_u)s)0&_jQ5X#`e2l^nT8}asG6SMd0Q5oc1VcaF z)4g0s1m!~8k`A;9Ck1d`%CYuRm4me;?;RzU?z#|k=oT)}MZM31sn`^QG0s|bz z%;C!~yX?}o+;EfN;R%$`MVCbQn5zpf>>T1a5Z24H2lhS?83R8jfS`_UZ1ID;9Ot4V zyhYo1!U<_qfy!6y+;nDxLq(%p&5Q%In_@UUeIf^i^I;n)=RoJ=!wdsu=Aps+=|J?OIg zPUVhs&N=8Zm_RxRrm&`$L<$W|qDA45ndV1dXdzPea^ATi_Ys`#>Zqi8^7UUjP%6F2f;^R4r*2E>?z%tu!th)SzHyfW{C$;DHae5CaBofCJ6dhI6v< z+-%5HriR&IbQ6dI>aaBgDX^|}uM^qGdSfylB*On1+gaIQ_8<|?%q)11f|fyW_5z(9 z?^4R65A#$~lIKBBRYs#;M_2-xl8_=7*;5eJxQDd}ZH+?Uu+TF|5r;~MLKNsD$4%Df z3~0pB8S)d4dF-ba{N-<3)Y6+={Kpp?{cSG;^w!}1<_85{WD$#GB&m$lk|N~-h~`m< z%yh;O@?3B)fY`wWKo~;Lxu%2*16^)ZD1iq&fQ5tLLmlX%oEXlqIeLmz1vqfS8$zH0 zQ^*boJ=cz0}(-R@>Lw(#*Ubm0~t z0|_p{_-&vz$`K+R!$^nZ@gn2U-ec+hLoRkwLN1pja zH8B;*RHpQ!H0X6|dQ?SKs+uMiEs8TLT{NdpAf&Ykb!}He%9)XY51TFO zHlWZO5PlGpD*arULU&43KHvjWpu_(ZZrTGK#5T4bqwRXAb6W`H_5roq#pzU5mM5q{ z1vMnD$dey#aYz~d|cbrGsgA{ zO}rrv>UF0m@->YRi9!?48t#fhu-E%iE06p8>p=yZm&6v9kcFI4ViDy~#-_`$i}c8L zS0+_*!G$wAyMr%ViHthzU;-bsfoMldTHA!~2BSme1eoB3DY!P4v3*@^LC`S|aDb<` z%;j!p8U-@cp$=v-W(Q<^Oye$<1IR2va+T`_BrkWF%{(4`q+3-_N%yKBSy`2ZrV;Iu zL?-d;Zu@pc*0P=zSO0j1E1v%WjIpWW6LF|Qo84T6<>s>mDky<)YpB;D@YO~BoR)H` z71(XPD1QPzEMg73SVbn-u_@sXlce#D2~v=P+NfwnN5YGiSmPVs@Wu`Ykq0Gg_)MQX zDVI{p(k+3`Og7jJDkY#x9ItLUv#o8O)+1wEnryeZt&WXle2`xUTi8DaatT5(w->-b z*)T{lbDNCaCr8`L)r_L1mWO34YB`JXqvtcqnG^6fNWAIHl`CAa3RQ6V6LN-u3*1fT z62#lM2eGgH^sC=#rKM&Eoy)Z1WZ(cAmcVy8lz|bINQ^A{F)hJGD4J2EmMp>#fCSHD zG;NP=SmSn~7=$f2Njm>DnJI)KEG@%y!)lrC)(5iQ*y}*Hp5oq?IuO`(Zf#EURM!0F zJKs46EP%6P6SD=(7KpPqHEo|Q?^5x3@`HBt9*a-#+%6TKVI5w+J}Ug5&MrjLpb`RWg!L$RQyT9?u;X z(F~3AeGz<+Ssg55i#iNq5TBI*ZbEm`mag=Kp*{I2Q#pZ^t2l4d;E8R3p;S{LdNU@I7g*@1ShiMqg)0`jp0ham!5HhV*^E_4h049(E(Nm6& zfq>rdnBua4USmC*V?7b%zzU!M)N4JS%dH<%ffjgzBU7>q(mmdLrc05ksZx|6dXy&s z8Y?Rrrr|Q>8>{Upt6JGQacBy3`#P|jgM5m&rHVpiS`nZNzkpH;d=tOBAV0Slv>Pdm z^i#jYvYVH2zxQLLje3knk_d;Jzlm!DwUB~6XohTP2L5|NT=<4-=mlNS10k3I3Fxqf zAvGLmKtlfvtqT~PoWlSgfC7Jlr5FO4o+B<0Or-@_y%8kA*VCn$!$h77HXw6B7)&xZ zXan5KJ>APa&2X-05)a=Io?~-@N`badVVZ4=pQ^J7=GzJ9L#Lz|qi0w`u#2DhsRBBS z!XcZ&w5Y=S3aC6|5qvw38HuI7Iw-*rL%hHnw=g_}TQCJum9n^(QIG@m7y>$21Z$|Y ziDQd9fS}uHr9BV>A4o(&%#GVPL{h^IKukH%gMuz#Io63W-P*O&dw@&y#1te!Uh6~^ zggts&5f_}BdVxV0G{xhAw(xkaX4=S1+QGDN!565M>8hR)Nj`d#nsPEitl63|D>JVH zJ2n4m7VFDCAtSD3tU}g-#I znp=Q_%(=T%K~2O&3OK=p6hV4J0Td9rWDA~&G`bvQ2qxRe&0rLPc!IoA5s(zgDqW+(LgVO1St!FcibMQlun$DI$nWE;sN& zt0KwE6gsoBulQ65 zAMBZ0Y?T1*E(F=kFw2@TTLpAmLQz<{`GNt|j8JCer)K1@^S~Qt^vS#7P{RMfM!)i> zo@@if;JXB)!75ugk2n&KkO(JuF*!^Z#W*~Tdbmj=iC(~k)8PUQ8=XW9#6b+L4ok$( z>j5Z$f+29kn_`{U@d1(PwFQ6x3;0VLYtjjz0AEe5CapP{vr-Ef%%NL0WfPubl)_@8 z$=MUGVcJq>!Y+=m#hDO7HuW}eOGyJoCkkjCx@H$nfQ-{z5P0$QCXn{OcO+K~4 z^79?^pwKM*$v&!04<)GmnwB=$gG6goM^y|gatuX41YWQP{-Xm2@&l}l(QlX^Jcz&S z7z8g60+LaaeKget)D04wfF2NnR>i41ak(C-A)LciDOJc|l>lF*0AT+O))lllVT*v= ziU6CnSqI43n~eZwr9Eif(r1#g&(I=l%~mpFzNC25q6nXVSOsw<*9H9qP1wkI$e|hr3_e!DixV%21R&;ML-cc&=H++piyWB z&H$Q~7zJLKSa~EFR~sEx6GYS^9Ug#!E$9MQZ8;cX9UY({lTAGfKtYvlQkL~q^bFQb zq*9%OfCgv)yA0h1fPkGnU7lSkpN&@Av%%oYl%iF>sUXni>(-*!x>xuIRTx*VGuKa8 zMR+mB5s*Tx#WTR#pTtTJNwLD8q)h_KSA7*UXFSIdmAHWAi2nZ=5JYGL7}5(mKwHH) z$GL3-JP;C$%7q=`1q1AY9zf3(B3uc$fKru!9asW?`p1nyj>lz=xvZrSMA?(w#9-}J zU*+7+9Y~%F-O&wQ2S8nB?SR!CCS_ADXZqbIi(Rrg8`|B8cHm4gJ3;@#FLIHgEsiiJeGV50;QIYFcp}R}x;u zBun8Ht~V^~FRd-Vw|IdVE1ns)*Be@)|9ReN5WaoG>XAa|&^-DMQ zTup?4zEtBi=D?G+IhqyS1@LA#Zs0lAKJ0^5Vwy-j=9#5~5BJL8qs@s9K8mAI$=i)S zMfN%pp4t}!6gk(r2ggx5a-mjW3z+S30^Me3LC1P+BtZq?gEB)PN%ct z%+Ab}+$Gmk00pUSCKPTr;X+MjteJ)$=xv!9gOK4oOK2M2(80+@P`*u3j+2U`=m*n1 z`I81A0YKx-3p?=(@Q{lTxPxYBocyE1O1rEF>IK}P11xBQ5BN)6Vgi|-X)-L1S&Ok4 zo+TLD>1ZzC+(N;dYf?_cW&>V9nyt(5BwgBefY2Rh2#&X>cEPBYYR3HSPiW^~INF}r z3GcxgdPXY>0c$x`g;D?oP^bhaJnOPs)(`(sfn(#VhDMLAg^MX*0^+$ZJi8MNoPveE zi~ss${gKV}h9R_-xJ4KR5=BM%vxZ!-tVNiM7{VWyv6FKIK>MacYoLa2C=xix)I?yc zJ!qvUU;-3aZ4ThJd!p*$(HN z6=!nRZ52oX7m#r(pn^ApvpC4{s}62b7@MQ@wp@vjq8JLVK01ng{V}VDyC$(i{QUFc|<9ogFdhm zIm9%?bK+ah20zG3AyM#FN-;c`0uBFygQD6jDbO*$&>z+D;@t9pB8?QD`rjwDTsI!i z*P{UWeOdC>eOATI;Oo6kZ~7)0XNHW9oGa=NCk2wZV*0-d^jf} zKjbj7XLLISP_TqbsDyn+YdZT`ry5j(ev2yqog*zCCfF<2bb=J~^1isue~L?MVT%w@ zRKKo40b(AV;fe5rrkuYuhr_t67Q10=YXCr(XcviaV&IfGagk|0fP-B4)ECu`wkRrc z>B5_W4iA`s^(ei9+^tC8T-R$-OXrOeFJoO284%R1qz3ic7WGjtb+bct7jQE-VD(DS zgiU}auWMRar}clR^;$3TujUD-<#i?huY@37*J5HASKPt7vb7DL9KBo0Q;b zk?;F6Lvm<+uXgs<*AS2bMB0e8t-+wd=*QrN6t%B7snihA3tV_nI@hw1@Pj9?3_6Td zMAED}h<7IdJY2AbP}q(kxPwISp<{+2<6u=E@PHHd0NP1G3djJ2-?iR2Uht@gH_h>%*p znyc|@pBT49PWe*sbxCOXChzT{E4m%?otbf}6nlc4cLM$VfEHkj;Q4t@4nv2=3o!R9 z{MqXkNqYIV-UmyRP08EF(73t(RS_8uD5O98%X&D;$Ob0i`cQy0?tf9k^8>vw&L`l? z#NY)7;sv%y1aA=+e*$e;YU9^iy(iuK+`=W#O-R5eae#Ora3Dbl5ClT_z@!Ni6dVpN zSkPdi1A`GRHgKTv;zbQ2K9(@C!Uf3{Gpblg`6f~%N|h>E+63xfseh{ex%vn0pSgee zeE!?_Zz$2CMvLP6r;g`8aXSC4Qg!N5B}sAIRLNS!4V!d}9 z4<%tJPUtLp(#D=NJh&F& z+T({#h&_Ag+}VRz3LPm!q(JGR9m52J-X{>GfZ+o82L>lhpg_UkK=uSBT!>$uAbs-( z&7+9&gvp184zV4-DJSyObC)(b7D;1*m?JV94s zcmd|uVABN_Akfi_HLQV_OE%u5 z2FDZ4Xrqm5quhr73z>_w5hh>RNaM$9i`>x$9oJDt$8*+Q2k8*op*KMV=usfSK;n^y z5CoV~&|Q1(2?Sq!nbubjdk|E>L|Xj$7obH1cJM(52}aOC2MdzWpo25aKm!dcNn*(* zmtb=2KbUy9Q%*bWw3JXImRRjjDgJZLKjS==lT?>jLdlJlXi}~wm*Fvo9B{bdhL2MK z$?g+Fs!&=8Ets_=lY;#frN4*iMdevBnyN+01$6eC72*2w`THupbMf4zZc3O}vO`zsZjAZMaEeO&zCGqfKue z<5^}lt6v=G9n=i}FfL&}7s3#U&_Od`q1)`i4j5pM{m%nQfIX@bNMQ8QtCG6(1Q!gg zG<{gJ8pRYkbC9%mT65rmTm5mMtF9rfutE&MS|JjXKo%-c!3tKq;uYXv(N0+L4^%v* zCw%MwNm8hlw-TKwDHCi;w;p&3P=I0+FA>*`ZqzQsoiK&&f&mO7$HK{}Wl4#t-1I_M zLz{W-bCTj*lL#XP)2VDrs$-p)I%6iz@M2=CJIryKk&V_ou^F~d%qZybjn8BQdDQSs zGe&U-I^e>1)YxLiq7$Yeut_@6lLF2nHK`t4FMC4++R`wPf$xD&J>!E~`ND_33#`X! z@~glH;DtZ=Wld}LD~+u>FoF@3pae1qU?ehxiBc4B6$V70i*~{yZn-FKdqdGE?RG)D zB}IdM>)2(LR>SdQ4O?G1GCxa4Jp*hR@w!_80u?D)Y~BrJ*OAyjm~n4X~Q1> zgeW^NEetbcGU94FqeSVnfft4%*~nlMIVUVai-e-a6>-swMdSiHqFLP-ZMVGDEe8Zc zkPdZ@89E=Jc{)mXzC$iu}JO{16)$RQW>z=brZ;fK$lrVYyh&hb!&G2VPJ5l-j<%=Y5{#?XC0 zjy%{Wss`du3G9&L{(u{ z$^wHSDK&ETf~pOrAXP|}#%6h$l46{II<6{=bzurCoF+Cgm@UE@PRz!eI@5+kB;pQI zu&5lek&7+j0W_VF!Xliohvmta8UbD%F4V~!C-7wmZJ-_#puit}E_OV0d;kR)d(iY$ z00W_N52*r*zI}G5e1q&P8K7Vgi6)Xj74-lJz)&{vHQ<_Fa6|GEeDXP5OW#O{!+^b2ujq{oWmt!YMU2&&62tQ%qQ?vQ%GXfYfUqDEL75?NjSjFW(`tCJ2LfkF zV@^D4D8j^>J@7$Ie8Fl6wBrLN_`od~-e;#aN&~Y3t^kdix`5#2CEh$@?6eTaYw@h(z2iazAC~GpL1uVrS zxecyKyrjqC_HvkOWCg9Tur6mtGk2+1ni{9Ms&grgoabC;*5SGTn!MQaal$m;Y{)Jf zxCp^y3|*bMwBZ{9w}yM8w}=o>Y&F?9>nQM08D88W5q0>$b$Vd49(>@_p-yawGr)tz z0x~>y#AA9euxb*!8a^1{L9A!JP@(xC)ZLi?2f9PQ`q8+?P^HTYc6=dB06DfpRyI?# zmE_z41=`SV=~8Sbv1>vnI{OboEBBbJU9(i6!xzN^F=lzL8d32>djQ*n`0jqo{63+%dce)Wah_3I*pP z6p{Jr9r&<^`b}yGp|+oPKA>tlo}95NzhkK+>vC3`C+6t?LwTq+oHU&K00Zag`OjzU zYw_ZxEN+N{v0e+(13HjJEGn{6njLkiLpy_{wEAtS?GzW~B)DzkI&;e|qqCEHsB52r z3}V27^Rpn`a-m%4oM*2dfIvI)k2iz~Hg6|jX3m!(Vq^9Vct;>Y0QNy;NCya56m=xR zBOpQ_z>H~(LR=|aE(Dq%Ko1>gQ)-MtHb_&Y^Ao;Y%LCqY^k%y>^O3R&G3!30)`QGncN5Nc&@VNm@T+${v z(9$vA(>)*bO`Wu%)Q3EUQ&1cB{Z00164)J!_e}!-_?=xOyumHifE%P?yO3FBL=Rtl zj=T9V#dL9n8)nX%6^sD}T^%~lctO}*EJk$LTi=0+axB6lEJ6U{qar9m zAFP1^`XeGHARRh%?jLlW5nAMio{9bCtoghDfrO#Y36!ox2Z*^MK~WY$_|Xok;)oRlh}jVePJsPX6wvjeFGdNxz(Ge5V<{Zp(j{Z_ zL0vNnB~eJ4>^~kymEU9a@LIl%-kjMP9_&T24k=s%KsH zfn3hzA=D)uuz~03Wg;@d0>TV)Z~!^ol^tAzHz30xM1kpj02I_gEbzgfrN)+wg68o- zB7_>Npx~;RoDtkncZkOdo*d1Q3Tg&Y3VP-%o}_uC+sffDu^edZb4UZfI$qq=$OPYL;MYdP<3IsEDrI&uGn8GI;P%E|O&>AG7BRB$l(!mRcc6y}Hf%+?#f#1%{Kcr1)WN9YflMHmNa3ieG9#-Vr>nXu ztdeZ=$trYSU5h|jNbRaAgb=V=+;hN;=O_xX5-VaHYrIWqUll>3X&@ege6E2L;N~5Oj5Oo|3LHVzF2NGqDG-2x5(q&Qgqjabfh}AEGSq9X&72Zo zK+seuqTZ1n{VSsC-l~Ko50Hl~*5GHZ+8!Y+dR&0Qo~R6}#|i49TgYF~&Ec=zonO#F z9o)ejWUQ&8D$_AvP=YM03WdlfXXciyjxr~7`b`2snN*g7D1gEzd;*<)(b0mcJicLH z6ij%5C0`VlV)*R;dM=>Qax2jit+!(9Apqc9BEozcOx1);Hqb*S*y){W!SZr}7ThV; z(rF=ytu91?2?A`WoLCYh0nO==KOw5Zwjg_;CZ-1NXJ)_&fTjtu52p035hQ_yl5gII z%4R}r+^q?W4%3v5^_LG|O!r*^X9j0Z&WjV(#WPUvu`v=Wd@=ib4dRE+^*a z=U{7{*{rcr6@*=B!9W<7?t##fsqR{<=di(<#^so@!HrcEF3>}5An(;GfebIN4Bu(h z-j5F)f$3EM+hXs`X)pJxhxd9U4{YxpVNHfE)}TVc*5@gFe&aGT!#Oaf|PaaN)d1Yt1(d=Fy<=fGd7t{fCH{VnN&n@1Z!TS%&h0o z!2o{Im&gImGKu1TC4{|Ydx|gv7VWh%GSbE+U3M!Pg@8ph!wb6u9~?mxVC|jGa1C>E z)rJ~DS&9)G0nhl85pOT~Qt|dyF%n0r9a*USHZl5|UYI{ zwHt5NZ1jk+>3)JJq{2<)#PZP=<*sow8^z^nZmcdaG=c*-Y@bb$LN_-k1-~I5`!SfT z3t0?uetPFzI0`-rt<5qrBkSb}1Mfa|tGAXG2NWbdc!M|Cff7Uk7hG*X*YGCa@Dapv zhaG|c5|lCpoEQ-3GN~~%6)SWSDD;J*M+(}}5iC~T+L04GF&1O-K;iPCey@o2@~WL6 z6V$=X80+O|j_eX^=OME)n=#!ya~ex?P8S6=|L8RnsW#V?D&ztwuu#kH?7_!JSg{5+p&}s>h<aQ_>i60;{DcIECI0YI%n@)rFQ6%v6(N+WN#4|j@D*S>_Z^m(?XLrtQ8z{B^ zA6Oi^gauhtNmP5K&$2TEUNu%{wF$Q;B8+JyztJS)g19CoS^u+IJNMP1bz8snowhCN z&2TBlhh59C46~*Qs^DMmQ(zA^3WT6xPwEU}Pla-_5fC;OpP&dbfvZe`lQ_xE#qC}?&7|0Fbrc7V5PHDgP2&JAii!!K+GXUGogBDHKw2D)5ESd0ZsLx*H5${zH# z%>s9D%d;XB_g%VM2uOo+F9Q}t!5BFAibwZ$AA!jo!PQ#miJ6>?%MrS=H9*r`1%xyW z@&FQ8=x17hV4naAAOZRoxqF+S9jW)#9>EC+x!}G12~2tuI6+#>MUw1nS6uAk5+Il7_m+@CD=>2e zjd__X``z@kwouzNKm(f#SeIb1%{E43ROFWIUsq~*TYd?2uqSM{?p@+#8>p_I|M~4A zb^fXV9$2zF*g_PL0U0EEy{kB*ueCv=Yjm?Wqu%w^9`U|ra&ss8r`KTrVVm!zk2;i} zuaTpAsyi_f961)BFKNbjKr8eJ()tDzc?zIF3V?hQxIhz-d=oqY7GS}}s=Q@*o)|M| zH~)h(s5u8I<7Y3sfKxNoF-1B21365?&!+}w97ls!d-UwVV`Tf5_yHeS+?RlG--Yl| zXL(2Zx)USn37G4z?$Eijh$yaHLn|Vcs1#|| ztV)@7ZAu4hSg~REAX0P|(H=T&*tU_X1vL`YNSa*1@)`>j)v`sK zR=p(3;K5g-s7@go_`(#!7or#;x&%UnC5AV|62}h3P@<-4jP~!@KXL!e{kusrW_a=A z$;YfY66e2mJa_&CI+f_Cqg%U%8Y*?@s8CvwCQ8I#sinLc(5t1ux?_(-7J0-dKfVI1 z4YA;8BNTY(sY{qL`udAQ#suSSH6)f81C27SFigbF#$arW!c^O=GrdauEX36|BLj;o zn%L1bEVB49HY%==ZMDf%^l-N(YFv#WDs~(W$|zI+aDhrHs>mV^JVGJmqF*-pXPSS= z;VwP!$~zOyG+{cAq@31cr>B3UnNukEMv-r;J@D`&s9gGtucA_ulhaPymk;PR#EVdX8jFrvNSiSWB*wwWd{n8M%yzIy%6HZiC8822}E7?_G zVZ-9pS2K~hj9^QCtusATj&)gMdyEZRAcM5Film>5BaS&V;r2^##Uzv5bFIF5yz}Bw z7oLCE1@qlH@4It9KSGg)8am&LN?-Z<6&UWg{V@1oT(ZJrK!zoPM;>^z!KM>CRvw&X zJ34z=SCvUN`PG$UbT#EpB=1D!OqPAkXuTBoH4BtIzq#{FfXt$^#s>#ISj;)k;^dow zU7hndGSP(gr=y;FCvnlkn)lvU+J`3ew%)pHZQ^uK8hGJjJCsqHp(dNO@4c_>eaq%A zP@@8^%51Z7;RWAj0JUnOJ^lD36g)ovx#u2s*qKHXPA2aJ7RgUHJVwDOH=Oj=2d~*? zlJkToIw1=Kazb>zdKKg(=epKqqJb!D9k60%y7^TOe*mo6=REg7*?CSAo7jXWGy#f# z00T@Z%pKKy*FqPTL~H*T-aoqbwJ^~MUsJh{pP+|BvB~RB`q^F(iC9FkjY2B+nqJ$u zx1T_f;uE>3M?KiF4q-^nfLWX$eWkI>mbz*>7yu~fbh(Hdaj1!(H z{5Je(I@sCD&DNOBxQ+K+P6EnRK zlU8e!4F6FNPS!9^?UIJO?j<(=B~DL=Q{j>kgGiL+v5jp=JS8fbSP}hjiA$oWMm^rK zj%oP96Km{a9|_3CmC2Efo{HVk%Y`9 z0h=j{H40M}#he@=zbT4Tq#~T}q^2+aLC;4{Z5>|I=XxxeNq=6ABqZU-C-wQYc2Pr4 z2_5B}7@9n1q*9f*lqi=VT2YAFOM0k`C`B)l3of++9=u$~Fm54=YMv9Nek5cxsd>j# z%yXW%xT8s7O3h$Mlby}1=1gfyO?Y|&p8xQKQ2%j@qSh0s^ppirhuTy}K9!!S_=i+c zSk)8$Llyt<(wOoICpc~YEhjhm=UB}p&`uK6tN$=wyV?~dgt9fE9N~zU==u***cGq2 z_=jHQ`lY`1b(9BH=$G_bSgjt`OZWK4JN_|@q&}9ONFFhU4mGk!wd_$di$X6s zcC%8IY9lin)v0Rsu$h%=X^|?7f4G*ltA*@Uw>q^kdG@N|DkvwnCRVckHcbN^s3(a> zLw&9_PR2v-4gLD1x<0qL3mxnzzok~|GMBo|{i{A1o6pa_7O|Q?h)&#zYXrekgDe+;xAw}v%))D>u56FQRt0RTHmPIhnr literal 0 HcmV?d00001 diff --git a/node_modules/jade/support/stylus/examples/images/sprite.gif b/node_modules/jade/support/stylus/examples/images/sprite.gif new file mode 100644 index 0000000000000000000000000000000000000000..d6b7d396156317206d172c20040ff8554bd2064d GIT binary patch literal 935 zcmV;Y16ce=Nk%w1VITk)0OkMy+q+Bj$}KLDRXU+kNQQ><^Yil1aXza|CRUQDtgKd& zb<^F{#MH*Q#oL>xq)Tj=-r?-;)|N(TrnAMgm8ZpAifQ%s_*HYQth2dSt7Bq)w2GU% z>+JIW{r+r)wjD>4a)`LX$=7M8b=u_HXpW~je0ajk;_veBGmK(*nUwzLsoCW4cZ8)V za(3eC;!$j+DRMWbwb-z|+9-Q!D}ZWaw`+`?$DpaanZ2BOlD6UEY-Qs)%f_;*v)y0z6 z(7wXIo8GuIU!`j8@b~iX`Mkiy>h1TkxX#qPZt}}YKY2#>`1_Bnhn=B`)ZFn4I*vwl zUX`4K=98I9gS6D0l@(VZW%%^4-YIGIWHT71!p={hbsWWYCaicHZMa6 z;0QxKgKY^87&|%zy@C^C0BUa)0zrCB4H`od2u>tggR~?d07XcOED6r+*pXn47dbFs z1o862LJklOmR#tPYETsn1nRWtV#Ej*0(nwYh{&eGmlp+0Y-!^`2^KsH2vu=#XGV?{ zOUg)~fdmSPBNUh@fwQH^lq5|+Y*f$*S{4*X{#-%ejRXY=Q!H@tP(X%+KQ?;&_@Dug zh@6A}TmT_5MQa=lD@^R+Lg9~uEm}4F@sOs&6A}V=Fd)Pr0}&g7KxDnJK}v`+A3Xfg z0K$X>D~@Fu=+a862ST0v|CDApi{n05O3M!%1=i5C_m8K>=pSfW-rY32*=qb`+q>A9PHB zg93QqQ347A9039i8BB1(hlQNL0EDR_fC3P3!Dz?{6ObXm9XPzGBO?p=FhPSuGBN@L Jl1T;v06X@Tu89Bu literal 0 HcmV?d00001 diff --git a/node_modules/jade/support/stylus/examples/implicit-functions.js b/node_modules/jade/support/stylus/examples/implicit-functions.js new file mode 100644 index 0000000..c2df4ea --- /dev/null +++ b/node_modules/jade/support/stylus/examples/implicit-functions.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/implicit-functions.styl', 'utf8'); + +css.render(str, { filename: 'implicit-functions.styl' }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/implicit-functions.styl b/node_modules/jade/support/stylus/examples/implicit-functions.styl new file mode 100644 index 0000000..3921052 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/implicit-functions.styl @@ -0,0 +1,23 @@ + +border-radius() + -webkit-border-radius arguments + -moz-border-radius arguments + border-radius arguments + +form + border-radius 5px + +a.button + border-radius 10px + + +support-for-ie ?= true + +opacity(n) + opacity n + if support-for-ie + filter unquote('progid:DXImageTransform.Microsoft.Alpha(Opacity=' + round(n * 100) + ')') + +#logo + &:hover + opacity 0.5 diff --git a/node_modules/jade/support/stylus/examples/import.js b/node_modules/jade/support/stylus/examples/import.js new file mode 100644 index 0000000..a514721 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/import.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/import.styl', 'utf8'); + +css.render(str, { filename: __dirname + '/import.styl' }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/import.styl b/node_modules/jade/support/stylus/examples/import.styl new file mode 100644 index 0000000..69b1d8d --- /dev/null +++ b/node_modules/jade/support/stylus/examples/import.styl @@ -0,0 +1,11 @@ + +@import "mixins/box" + +body + pad 10px 5px + +body + pad 5px + +body + pad-x 5px \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/js-functions.js b/node_modules/jade/support/stylus/examples/js-functions.js new file mode 100644 index 0000000..9076d30 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/js-functions.js @@ -0,0 +1,55 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , nodes = css.nodes + , str = require('fs').readFileSync(__dirname + '/js-functions.styl', 'utf8') + , fs = require('fs'); + +function add(a, b) { + return a.operate('+', b); +} + +function sub(a, b) { + return a.operate('-', b); +} + +function imageSize(img) { + // assert that the node (img) is a String node, passing + // the param name for error reporting + css.utils.assertType(img, nodes.String, 'img'); + var path = img.val; + + // Grab bytes necessary to retrieve dimensions. + // if this was real you would do this per format, + // instead of reading the entire image :) + var data = fs.readFileSync(__dirname + '/' + path); + + // GIF + // of course you would support.. more :) + if ('GIF' == data.slice(0, 3).toString()) { + var w = data.slice(6, 8) + , h = data.slice(8, 10); + w = w[1] << 8 | w[0]; + h = h[1] << 8 | h[0]; + } + + // Return (w h) + var expr = new nodes.Expression; + expr.push(new nodes.Unit(w)); + expr.push(new nodes.Unit(h)); + + return expr; +} + +css(str) + .set('filename', 'js-functions.styl') + .define('add', add) + .define('sub', sub) + .define('image-size', imageSize) + .render(function(err, css){ + if (err) throw err; + console.log(css); + }); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/js-functions.styl b/node_modules/jade/support/stylus/examples/js-functions.styl new file mode 100644 index 0000000..8460b3c --- /dev/null +++ b/node_modules/jade/support/stylus/examples/js-functions.styl @@ -0,0 +1,23 @@ + +image-width(path) + return image-size(path)[0] + +image-height(path) + return image-size(path)[1] + +body + font add(5px, 10px) + font sub(5px, 10px) + +#jesus + width image-width('images/jesus.gif') + height image-height('images/jesus.gif') + +#jesus-2 + width image-size('images/jesus.gif')[0] + height image-size('images/jesus.gif')[1] + +#jesus-3 + size = image-size('images/jesus.gif') + width size[0] + height size[1] \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/literal.js b/node_modules/jade/support/stylus/examples/literal.js new file mode 100644 index 0000000..5b80b10 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/literal.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/literal.styl', 'utf8'); + +css.render(str, { filename: 'literal.styl' }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/literal.styl b/node_modules/jade/support/stylus/examples/literal.styl new file mode 100644 index 0000000..e9a45ee --- /dev/null +++ b/node_modules/jade/support/stylus/examples/literal.styl @@ -0,0 +1,8 @@ + +@css { + body { + font: 14px; + } + + a { text-decoration: none; } +} diff --git a/node_modules/jade/support/stylus/examples/middleware.js b/node_modules/jade/support/stylus/examples/middleware.js new file mode 100644 index 0000000..8a500f9 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/middleware.js @@ -0,0 +1,22 @@ + +/** + * Module dependencies. + */ + +var connect = require('connect') + , stylus = require('../'); + +// Setup server +// $ curl http://localhost:3000/functions.css + +var server = connect.createServer( + stylus.middleware({ + src: __dirname + , dest: __dirname + '/public' + , compress: true + }), + connect.static(__dirname + '/public') +); + +server.listen(3000); +console.log('server listening on port 3000'); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/mixins/box.styl b/node_modules/jade/support/stylus/examples/mixins/box.styl new file mode 100644 index 0000000..6004d86 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/mixins/box.styl @@ -0,0 +1,14 @@ + +pad(x, y = x) + if y == x + padding y + else + padding y x y x + +pad-x(n) + padding-left n + padding-right n + +pad-y(n) + padding-top n + padding-bottom n diff --git a/node_modules/jade/support/stylus/examples/nesting.js b/node_modules/jade/support/stylus/examples/nesting.js new file mode 100644 index 0000000..ef3e968 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/nesting.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/nesting.styl', 'utf8'); + +css.render(str, { filename: 'nesting.styl' }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/nesting.styl b/node_modules/jade/support/stylus/examples/nesting.styl new file mode 100644 index 0000000..df0206d --- /dev/null +++ b/node_modules/jade/support/stylus/examples/nesting.styl @@ -0,0 +1,14 @@ + +body + background #ccc + color #000 + +form + .buttons + margin 10px 0 + padding 5px + [type=submit] + padding 5px + border none + input + border 1px solid #ccc diff --git a/node_modules/jade/support/stylus/examples/variables.js b/node_modules/jade/support/stylus/examples/variables.js new file mode 100644 index 0000000..cd55b88 --- /dev/null +++ b/node_modules/jade/support/stylus/examples/variables.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var css = require('../') + , str = require('fs').readFileSync(__dirname + '/variables.styl', 'utf8'); + +css.render(str, { filename: 'variables.styl' }, function(err, css){ + if (err) throw err; + console.log(css); +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/examples/variables.styl b/node_modules/jade/support/stylus/examples/variables.styl new file mode 100644 index 0000000..319330c --- /dev/null +++ b/node_modules/jade/support/stylus/examples/variables.styl @@ -0,0 +1,24 @@ + +font-families = "Lucida Grande", Arial +main-width = 80% +main-color = #fff +sidebar-width = main-width / 2 + +// Mixins can use conditionals +// to supply defaults +unless font-families is defined + font-families = 'WAHOO' + +// Alternatively we may use ?= +font-families ?= 'WAHOO' + +body + size = 12px + font size font-families, sans-serif + color main-color + +#wrapper + width main-width + +.sidebar + width sidebar-width \ No newline at end of file diff --git a/node_modules/jade/support/stylus/index.js b/node_modules/jade/support/stylus/index.js new file mode 100644 index 0000000..bd486f6 --- /dev/null +++ b/node_modules/jade/support/stylus/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/stylus'); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/colors.js b/node_modules/jade/support/stylus/lib/colors.js new file mode 100644 index 0000000..9f465a2 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/colors.js @@ -0,0 +1,156 @@ + +/*! + * Stylus - colors + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +module.exports = { + aliceblue: [240, 248, 255] + , antiquewhite: [250, 235, 215] + , aqua: [0, 255, 255] + , aquamarine: [127, 255, 212] + , azure: [240, 255, 255] + , beige: [245, 245, 220] + , bisque: [255, 228, 196] + , black: [0, 0, 0] + , blanchedalmond: [255, 235, 205] + , blue: [0, 0, 255] + , blueviolet: [138, 43, 226] + , brown: [165, 42, 42] + , burlywood: [222, 184, 135] + , cadetblue: [95, 158, 160] + , chartreuse: [127, 255, 0] + , chocolate: [210, 105, 30] + , coral: [255, 127, 80] + , cornflowerblue: [100, 149, 237] + , cornsilk: [255, 248, 220] + , crimson: [220, 20, 60] + , cyan: [0, 255, 255] + , darkblue: [0, 0, 139] + , darkcyan: [0, 139, 139] + , darkgoldenrod: [184, 132, 11] + , darkgray: [169, 169, 169] + , darkgreen: [0, 100, 0] + , darkgrey: [169, 169, 169] + , darkkhaki: [189, 183, 107] + , darkmagenta: [139, 0, 139] + , darkolivegreen: [85, 107, 47] + , darkorange: [255, 140, 0] + , darkorchid: [153, 50, 204] + , darkred: [139, 0, 0] + , darksalmon: [233, 150, 122] + , darkseagreen: [143, 188, 143] + , darkslateblue: [72, 61, 139] + , darkslategray: [47, 79, 79] + , darkslategrey: [47, 79, 79] + , darkturquoise: [0, 206, 209] + , darkviolet: [148, 0, 211] + , deeppink: [255, 20, 147] + , deepskyblue: [0, 191, 255] + , dimgray: [105, 105, 105] + , dimgrey: [105, 105, 105] + , dodgerblue: [30, 144, 255] + , firebrick: [178, 34, 34] + , floralwhite: [255, 255, 240] + , forestgreen: [34, 139, 34] + , fuchsia: [255, 0, 255] + , gainsboro: [220, 220, 220] + , ghostwhite: [248, 248, 255] + , gold: [255, 215, 0] + , goldenrod: [218, 165, 32] + , gray: [128, 128, 128] + , green: [0, 128, 0] + , greenyellow: [173, 255, 47] + , grey: [128, 128, 128] + , honeydew: [240, 255, 240] + , hotpink: [255, 105, 180] + , indianred: [205, 92, 92] + , indigo: [75, 0, 130] + , ivory: [255, 255, 240] + , khaki: [240, 230, 140] + , lavender: [230, 230, 250] + , lavenderblush: [255, 240, 245] + , lawngreen: [124, 252, 0] + , lemonchiffon: [255, 250, 205] + , lightblue: [173, 216, 230] + , lightcoral: [240, 128, 128] + , lightcyan: [224, 255, 255] + , lightgoldenrodyellow: [250, 250, 210] + , lightgray: [211, 211, 211] + , lightgreen: [144, 238, 144] + , lightgrey: [211, 211, 211] + , lightpink: [255, 182, 193] + , lightsalmon: [255, 160, 122] + , lightseagreen: [32, 178, 170] + , lightskyblue: [135, 206, 250] + , lightslategray: [119, 136, 153] + , lightslategrey: [119, 136, 153] + , lightsteelblue: [176, 196, 222] + , lightyellow: [255, 255, 224] + , lime: [0, 255, 0] + , limegreen: [50, 205, 50] + , linen: [250, 240, 230] + , magenta: [255, 0, 255] + , maroon: [128, 0, 0] + , mediumaquamarine: [102, 205, 170] + , mediumblue: [0, 0, 205] + , mediumorchid: [186, 85, 211] + , mediumpurple: [147, 112, 219] + , mediumseagreen: [60, 179, 113] + , mediumslateblue: [123, 104, 238] + , mediumspringgreen: [0, 250, 154] + , mediumturquoise: [72, 209, 204] + , mediumvioletred: [199, 21, 133] + , midnightblue: [25, 25, 112] + , mintcream: [245, 255, 250] + , mistyrose: [255, 228, 225] + , moccasin: [255, 228, 181] + , navajowhite: [255, 222, 173] + , navy: [0, 0, 128] + , oldlace: [253, 245, 230] + , olive: [128, 128, 0] + , olivedrab: [107, 142, 35] + , orange: [255, 165, 0] + , orangered: [255, 69, 0] + , orchid: [218, 112, 214] + , palegoldenrod: [238, 232, 170] + , palegreen: [152, 251, 152] + , paleturquoise: [175, 238, 238] + , palevioletred: [219, 112, 147] + , papayawhip: [255, 239, 213] + , peachpuff: [255, 218, 185] + , peru: [205, 133, 63] + , pink: [255, 192, 203] + , plum: [221, 160, 203] + , powderblue: [176, 224, 230] + , purple: [128, 0, 128] + , red: [255, 0, 0] + , rosybrown: [188, 143, 143] + , royalblue: [65, 105, 225] + , saddlebrown: [139, 69, 19] + , salmon: [250, 128, 114] + , sandybrown: [244, 164, 96] + , seagreen: [46, 139, 87] + , seashell: [255, 245, 238] + , sienna: [160, 82, 45] + , silver: [192, 192, 192] + , skyblue: [135, 206, 235] + , slateblue: [106, 90, 205] + , slategray: [119, 128, 144] + , slategrey: [119, 128, 144] + , snow: [255, 255, 250] + , springgreen: [0, 255, 127] + , steelblue: [70, 130, 180] + , tan: [210, 180, 140] + , teal: [0, 128, 128] + , thistle: [216, 191, 216] + , tomato: [255, 99, 71] + , turquoise: [64, 224, 208] + , violet: [238, 130, 238] + , wheat: [245, 222, 179] + , white: [255, 255, 255] + , whitesmoke: [245, 245, 245] + , yellow: [255, 255, 0] + , yellowgreen: [154, 205, 5] +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/convert/css.js b/node_modules/jade/support/stylus/lib/convert/css.js new file mode 100644 index 0000000..a1bb89f --- /dev/null +++ b/node_modules/jade/support/stylus/lib/convert/css.js @@ -0,0 +1,130 @@ + +/*! + * Stylus - css to stylus conversion + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Convert the given `css` to stylus source. + * + * @param {String} css + * @return {String} + * @api public + */ + +module.exports = function(css){ + return new Converter(css).stylus(); +}; + +/** + * Initialize a new `Converter` with the given `css`. + * + * @param {String} css + * @api private + */ + +function Converter(css) { + var cssom = require('cssom'); + this.css = css; + this.types = cssom.CSSRule; + this.root = cssom.parse(css); + this.indents = 0; +} + +/** + * Convert to stylus. + * + * @return {String} + * @api private + */ + +Converter.prototype.stylus = function(){ + return this.visitRules(this.root.cssRules); +}; + +/** + * Return indent string. + * + * @return {String} + * @api private + */ + +Converter.prototype.__defineGetter__('indent', function(){ + return Array(this.indents + 1).join(' '); +}); + +/** + * Visit `node`. + * + * @param {CSSRule} node + * @return {String} + * @api private + */ + +Converter.prototype.visit = function(node){ + switch (node.type) { + case this.types.STYLE_RULE: + return this.visitStyle(node); + case this.types.MEDIA_RULE: + return this.visitMedia(node); + } +}; + +/** + * Visit the rules on `node`. + * + * @param {CSSRule} node + * @return {String} + * @api private + */ + +Converter.prototype.visitRules = function(node){ + var buf = ''; + for (var i = 0, len = node.length; i < len; ++i) { + buf += this.visit(node[i]); + } + return buf; +}; + +/** + * Visit CSSMediaRule `node`. + * + * @param {CSSMediaRule} node + * @return {String} + * @api private + */ + +Converter.prototype.visitMedia = function(node){ + var buf = this.indent + '@media '; + for (var i = 0, len = node.media.length; i < len; ++i) { + buf += node.media[i]; + } + buf += '\n'; + ++this.indents; + buf += this.visitRules(node.cssRules); + --this.indents; + return buf; +}; + +/** + * Visit CSSStyleRule `node`.` + * + * @param {CSSStyleRule} node + * @return {String} + * @api private + */ + +Converter.prototype.visitStyle = function(node){ + var buf = this.indent + node.selectorText + '\n'; + ++this.indents; + for (var i = 0, len = node.style.length; i < len; ++i) { + var prop = node.style[i] + , val = node.style[prop]; + if (prop) { + buf += this.indent + prop + ' ' + val + '\n'; + } + } + --this.indents; + return buf + '\n'; +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/functions/image.js b/node_modules/jade/support/stylus/lib/functions/image.js new file mode 100644 index 0000000..ba37f1b --- /dev/null +++ b/node_modules/jade/support/stylus/lib/functions/image.js @@ -0,0 +1,120 @@ + + +/*! + * Stylus - plugin - url + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , nodes = require('../nodes') + , fs = require('fs'); + +/** + * Initialize a new `Image` with the given `ctx` and `path. + * + * @param {Evaluator} ctx + * @param {String} path + * @api private + */ + +var Image = module.exports = function Image(ctx, path) { + this.ctx = ctx; + this.path = utils.lookup(path, ctx.paths); + if (!this.path) throw new Error('failed to locate file ' + path); +}; + +/** + * Open the image for reading. + * + * @api private + */ + +Image.prototype.open = function(){ + this.fd = fs.openSync(this.path, 'r'); +}; + +/** + * Close the file. + * + * @api private + */ + +Image.prototype.close = function(){ + if (this.fd) fs.closeSync(this.fd); +}; + +/** + * Return the type of image, supports: + * + * - gif + * - png + * - jpeg + * + * @return {String} + * @api private + */ + +Image.prototype.type = function(){ + var type + , buf = new Buffer(4); + + fs.readSync(this.fd, buf, 0, 4, 0); + + // GIF + if (0x47 == buf[0] && 0x49 == buf[1] && 0x46 == buf[2]) type = 'gif'; + + // PNG + else if (0x50 == buf[1] && 0x4E == buf[2] && 0x47 == buf[3]) type = 'png'; + + // JPEG + else if (0xff == buf[0] && 0xd8 == buf[1]) type = 'jpeg'; + + return type; +}; + +/** + * Return image dimensions `[width, height]`. + * + * @return {Array} + * @api private + */ + +Image.prototype.size = function(){ + var width + , height + , type = this.type(); + + function uint16(b) { return b[1] << 8 | b[0]; } + function uint32(b) { return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; } + + // Determine dimensions + switch (type) { + case 'jpeg': + throw new Error('image-size() jpeg support not yet implemented'); + break; + case 'png': + var buf = new Buffer(8); + // IHDR chunk width / height uint32_t big-endian + fs.readSync(this.fd, buf, 0, 8, 16); + width = uint32(buf); + height = uint32(buf.slice(4, 8)); + break; + case 'gif': + var buf = new Buffer(4); + // width / height uint16_t little-endian + fs.readSync(this.fd, buf, 0, 4, 6); + width = uint16(buf); + height = uint16(buf.slice(2, 4)); + break; + } + + if ('number' != typeof width) throw new Error('failed to find width of "' + this.path + '"'); + if ('number' != typeof height) throw new Error('failed to find height of "' + this.path + '"'); + + return [width, height]; +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/functions/index.js b/node_modules/jade/support/stylus/lib/functions/index.js new file mode 100644 index 0000000..cd3f61c --- /dev/null +++ b/node_modules/jade/support/stylus/lib/functions/index.js @@ -0,0 +1,554 @@ + +/*! + * Stylus - Evaluator - built-in functions + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var nodes = require('../nodes') + , utils = require('../utils') + , Image = require('./image'); + +/** + * Color component name map. + */ + +var componentMap = { + red: 'r' + , green: 'g' + , blue: 'b' + , alpha: 'a' + , hue: 'h' + , saturation: 's' + , lightness: 'l' +}; + +/** + * Color component type map. + */ + +var typeMap = { + hue: 'deg' + , saturation: '%' + , lightness: '%' +}; + +/** + * Convert the given `color` to an `HSLA` node, + * or h,s,l,a component values. + * + * Examples: + * + * hsla(10deg, 50%, 30%, 0.5) + * // => HSLA + * + * hsla(#ffcc00) + * // => HSLA + * + * @param {RGBA|HSLA|Unit} h + * @param {Unit} s + * @param {Unit} l + * @param {Unit} a + * @return {HSLA} + * @api public + */ + +exports.hsla = function(h,s,l,a){ + switch (arguments.length) { + case 1: + utils.assertColor(h); + return h.hsla; + default: + utils.assertType(h, nodes.Unit, 'hue'); + utils.assertType(s, nodes.Unit, 'saturation'); + utils.assertType(l, nodes.Unit, 'lightness'); + utils.assertType(a, nodes.Unit, 'alpha'); + return new nodes.HSLA(h.val,s.val,l.val,a.val); + } +}; + +/** + * Convert the given `color` to an `HSLA` node, + * or h,s,l component values. + * + * Examples: + * + * hsl(10, 50, 30) + * // => HSLA + * + * hsl(#ffcc00) + * // => HSLA + * + * @param {Unit|HSLA|RGBA} h + * @param {Unit} s + * @param {Unit} l + * @return {HSLA} + * @api public + */ + +exports.hsl = function(h,s,l){ + if (arguments.length > 1) { + return exports.hsla(h,s,l,new nodes.Unit(1)); + } + utils.assertColor(h, 'color'); + return h.hsla; +}; + +/** + * Return type of `node`. + * + * Examples: + * + * type(12) + * // => 'unit' + * + * type(#fff) + * // => 'color' + * + * type(type) + * // => 'function' + * + * type(unbound) + * typeof(unbound) + * type-of(unbound) + * // => 'ident' + * + * @param {Node} node + * @return {String} + * @api public + */ + +exports.type = +exports.typeof = +exports['type-of'] = function(node){ + utils.assertPresent(node, 'expression'); + var type = node.nodeName; + return new nodes.String(type); +}; + +/** + * Return component `name` for the given `color`. + * + * @param {RGBA|HSLA} color + * @param {String} na,e + * @return {Unit} + * @api public + */ + +exports.component = function(color, name) { + utils.assertColor(color, 'color'); + utils.assertString(name, 'name'); + var name = name.string + , type = typeMap[name] + , name = componentMap[name]; + if (!name) throw new Error('invalid color component "' + name + '"'); + return new nodes.Unit(color[name], type); +}; + +/** + * Return the red component of the given `color`. + * + * Examples: + * + * red(#c00) + * // => 204 + * + * @param {RGBA|HSLA} color + * @return {Unit} + * @api public + */ + +exports.red = function(color){ + return exports.component(color, new nodes.String('red')); +}; + +/** + * Return the green component of the given `color`. + * + * Examples: + * + * green(#0c0) + * // => 204 + * + * @param {RGBA|HSLA} color + * @return {Unit} + * @api public + */ + +exports.green = function(color){ + return exports.component(color, new nodes.String('green')); +}; + +/** + * Return the blue component of the given `color`. + * + * Examples: + * + * blue(#00c) + * // => 204 + * + * @param {RGBA|HSLA} color + * @return {Unit} + * @api public + */ + +exports.blue = function(color){ + return exports.component(color, new nodes.String('blue')); +}; + +/** + * Return a `RGBA` from the r,g,b,a channels. + * + * Examples: + * + * rgba(255,0,0,0.5) + * // => rgba(255,0,0,0.5) + * + * rgba(255,0,0,1) + * // => #ff0000 + * + * rgba(#ffcc00, 0.5) + * // rgba(255,204,0,0.5) + * + * @param {Unit|RGBA|HSLA} r + * @param {Unit} g + * @param {Unit} b + * @param {Unit} a + * @return {RGBA} + * @api public + */ + +exports.rgba = function(r,g,b,a){ + switch (arguments.length) { + case 1: + utils.assertColor(r); + var color = r.rgba; + return new nodes.RGBA( + color.r + , color.g + , color.b + , color.a); + case 2: + utils.assertColor(r); + var color = r.rgba; + utils.assertType(g, nodes.Unit); + return new nodes.RGBA( + color.r + , color.g + , color.b + , g.val); + default: + utils.assertType(r, nodes.Unit, 'red'); + utils.assertType(g, nodes.Unit, 'green'); + utils.assertType(b, nodes.Unit, 'blue'); + utils.assertType(a, nodes.Unit, 'alpha'); + return new nodes.RGBA( + r.val + , g.val + , b.val + , a.val); + } +}; + +/** + * Return a `RGBA` from the r,g,b channels. + * + * Examples: + * + * rgb(255,204,0) + * // => #ffcc00 + * + * rgb(#fff) + * // => #fff + * + * @param {Unit|RGBA|HSLA} r + * @param {Unit} g + * @param {Unit} b + * @return {RGBA} + * @api public + */ + +exports.rgb = function(r,g,b){ + switch (arguments.length) { + case 1: + utils.assertColor(r); + var color = r.rgba; + return new nodes.RGBA( + color.r + , color.g + , color.b + , 1); + default: + return exports.rgba(r,g,b,new nodes.Unit(1)); + } +}; + +/** + * Unquote the given `str`. + * + * Examples: + * + * unquote("sans-serif") + * // => sans-serif + * + * unquote(sans-serif) + * // => sans-serif + * + * @param {String|Ident} val + * @return {Literal} + * @api public + */ + +exports.unquote = function(val){ + utils.assertString(val, 'string'); + return new nodes.Literal(val.string); +}; + +/** + * Assign `type` to the given `unit` or return `unit`'s type. + * + * @param {Unit} unit + * @param {String|Ident} type + * @return {Unit} + * @api public + */ + +exports.unit = function(unit, type){ + utils.assertType(unit, nodes.Unit, 'unit'); + + // Assign + if (type) { + utils.assertString(type, 'type'); + return new nodes.Unit(unit.val, type.string); + } else { + return new nodes.String(unit.type || ''); + } +}; + +/** + * Lookup variable `name` or return Null. + * + * @param {String} name + * @return {Mixed} + * @api public + */ + +exports.lookup = function(name){ + utils.assertType(name, nodes.String, 'name'); + var node = this.lookup(name.val); + if (!node) return nodes.null; + return this.visit(node); +}; + +/** + * Perform `op` on the `left` and `right` operands. + * + * @param {String} op + * @param {Node} left + * @param {Node} right + * @return {Node} + * @api public + */ + +exports.operate = function(op, left, right){ + utils.assertType(op, nodes.String, 'op'); + utils.assertPresent(left, 'left'); + utils.assertPresent(right, 'right'); + return left.operate(op.val, right); +}; + +/** + * Test if `val` matches the given `pattern`. + * + * Examples: + * + * match('^foo(bar)?', foo) + * match('^foo(bar)?', foobar) + * match('^foo(bar)?', 'foo') + * match('^foo(bar)?', 'foobar') + * // => true + * + * match('^foo(bar)?', 'bar') + * // => false + * + * @param {String} pattern + * @param {String|Ident} val + * @return {Boolean} + * @api public + */ + +exports.match = function(pattern, val){ + utils.assertType(pattern, nodes.String, 'pattern'); + utils.assertString(val, 'val'); + var re = new RegExp(pattern.val); + return nodes.Boolean(re.test(val.string)); +}; + +/** + * Return length of the given `expr`. + * + * @param {Expression} expr + * @return {Unit} + * @api public + */ + +(exports.length = function(expr){ + if (expr) { + if (expr.nodes) { + return new nodes.Unit(utils.unwrap(expr).nodes.length); + } else { + return new nodes.Unit(1); + } + } + return new nodes.Unit(0); +}).raw = true; + +/** + * Inspect the given `expr`. + * + * @param {Expression} expr + * @api public + */ + +(exports.p = function(expr){ + expr = utils.unwrap(expr); + console.log('\033[90minspect:\033[0m %s' + , expr.toString().replace(/^\(|\)$/g, '')); + return nodes.null; +}).raw = true; + +/** + * Throw an error with the given `msg`. + * + * @param {String} msg + * @api public + */ + +exports.error = function(msg){ + utils.assertType(msg, nodes.String, 'msg'); + throw new Error(msg.val); +}; + +/** + * Warn with the given `msg` prefixed by "Warning: ". + * + * @param {String} msg + * @api public + */ + +exports.warn = function(msg){ + utils.assertType(msg, nodes.String, 'msg'); + console.warn('Warning: %s', msg.val); + return nodes.null; +}; + +/** + * Output stack trace. + * + * @api public + */ + +exports.trace = function(){ + console.log(this.stack); + return nodes.null; +}; + +/** + * Return the opposites of the given `positions`. + * + * Examples: + * + * opposite-position(top left) + * // => bottom right + * + * @param {Expression} positions + * @return {Expression} + * @api public + */ + +(exports['opposite-position'] = function(positions){ + var expr = new nodes.Expression; + utils.unwrap(positions).nodes.forEach(function(pos, i){ + utils.assertString(pos, 'position ' + i); + pos = (function(){ switch (pos.string) { + case 'top': return 'bottom'; + case 'bottom': return 'top'; + case 'left': return 'right'; + case 'right': return 'left'; + default: throw new Error('invalid position ' + pos); + }})(); + expr.push(new nodes.Literal(pos)); + }); + return expr; +}).raw = true; + +/** + * Return the width and height of the given `img` path. + * + * Examples: + * + * image-size('foo.png') + * // => 200px 100px + * + * image-size('foo.png')[0] + * // => 200px + * + * image-size('foo.png')[1] + * // => 100px + * + * @param {String} img + * @return {Expression} + * @api public + */ + +exports['image-size'] = function(img) { + utils.assertType(img, nodes.String, 'img'); + var img = new Image(this, img.string); + + // Read size + img.open(); + var size = img.size(); + img.close(); + + // Return (w h) + var expr = new nodes.Expression; + expr.push(new nodes.Unit(size[0], 'px')); + expr.push(new nodes.Unit(size[1], 'px')); + + return expr; +}; + +/** + * Apply Math `fn` to `n` + * + * @param {Unit} n + * @param {String} fn + * @return {Unit} + * @api private + */ + +exports['-math'] = function(n, fn){ + return new nodes.Unit(Math[fn.string](n.val), n.type); +}; + +/** + * Adjust HSL `color` `prop` by `amount`. + * + * @param {RGBA|HSLA} color + * @param {String} prop + * @param {Unit} amount + * @return {HSLA} + * @api private + */ + +exports['-adjust'] = function(color, prop, amount){ + var hsl = color.hsla; + prop = { hue: 'h', saturation: 's', lightness: 'l' }[prop.string]; + if (!prop) throw new Error('invalid adjustment property'); + hsl[prop] = hsl[prop] + amount.val; + return hsl.clone(); +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/functions/index.styl b/node_modules/jade/support/stylus/lib/functions/index.styl new file mode 100644 index 0000000..66e656a --- /dev/null +++ b/node_modules/jade/support/stylus/lib/functions/index.styl @@ -0,0 +1,131 @@ + +// stringify the given arg + +-string(arg) + type(arg) + ' ' + arg + +// require a color + +require-color(color) + unless color is a 'color' + error('RGB or HSL value expected, got a ' + -string(color)) + +// require a unit + +require-unit(n) + unless n is a 'unit' + error('unit expected, got a ' + -string(n)) + +// require a string + +require-string(str) + unless str is a 'string' or str is a 'ident' + error('string expected, got a ' + -string(str)) + +// apply js Math function + +math(n, fn) + require-unit(n) + require-string(fn) + -math(n, fn) + +// adjust the given color's property by amount + +adjust(color, prop, amount) + require-color(color) + require-string(prop) + require-unit(amount) + -adjust(color, prop, amount) + +// Math functions + +abs(n) { math(n, 'abs') } +ceil(n) { math(n, 'ceil') } +floor(n) { math(n, 'floor') } +round(n) { math(n, 'round') } +min(a, b) { a < b ? a : b } +max(a, b) { a > b ? a : b } + +// return the sum of the given numbers + +sum(nums) + sum = 0 + sum += n for n in nums + +// return the average of the given numbers + +avg(nums) + sum(nums) / length(nums) + +// color components + +alpha(color) { component(hsl(color), 'alpha') } +hue(color) { component(hsl(color), 'hue') } +saturation(color) { component(hsl(color), 'saturation') } +lightness(color) { component(hsl(color), 'lightness') } + +// check if n is an odd number + +odd(n) + 1 == n % 2 + +// check if n is an even number + +even(n) + 0 == n % 2 + +// check if color is light + +light(color) + lightness(color) >= 50% + +// check if color is dark + +dark(color) + lightness(color) < 50% + +// desaturate color by amount + +desaturate(color, amount) + adjust(color, 'saturation', - amount) + +// saturate color by amount + +saturate(color, amount) + adjust(color, 'saturation', amount) + +// darken by the given amount + +darken(color, amount) + adjust(color, 'lightness', - amount) + +// lighten by the given amount + +lighten(color, amount) + adjust(color, 'lightness', amount) + +// increase the current lightness value by the given amount + +lighten-by(color, amount) + l = lightness(color) + l = 100 if 0 == l + adjust(color, 'lightness', l * amount / 100) + +// decrease the current lightness value by the given amount + +darken-by(color, amount) + l = lightness(color) + adjust(color, 'lightness', - (l * amount / 100)) + +// return the last value in the given expr + +last(expr) + expr[length(expr) - 1] + +// join values with the given delimiter + +join(delim, vals...) + buf = '' + vals = vals[0] if length(vals) == 1 + for val, i in vals + buf += i ? delim + val : val diff --git a/node_modules/jade/support/stylus/lib/functions/url.js b/node_modules/jade/support/stylus/lib/functions/url.js new file mode 100644 index 0000000..66a2832 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/functions/url.js @@ -0,0 +1,97 @@ + +/*! + * Stylus - plugin - url + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Compiler = require('../visitor/compiler') + , nodes = require('../nodes') + , parse = require('url').parse + , extname = require('path').extname + , utils = require('../utils') + , fs = require('fs'); + +/** + * Mime table. + */ + +var mimes = { + '.gif': 'image/gif' + , '.png': 'image/png' + , '.jpg': 'image/jpeg' + , '.jpeg': 'image/jpeg' +}; + +/** + * Return a url() function with the given `options`. + * + * Options: + * + * - `limit` bytesize limit defaulting to 30Kb + * - `paths` image resolution path(s), merged with general lookup paths + * + * Examples: + * + * stylus(str) + * .set('filename', __dirname + '/css/test.styl') + * .define('url', stylus.url({ paths: [__dirname + '/public'] })) + * .render(function(err, css){ ... }) + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function(options) { + options = options || {}; + + var sizeLimit = options.limit || 30000 + , _paths = options.paths || []; + + function url(url){ + // Compile the url + var compiler = new Compiler(url); + compiler.isURL = true; + var url = url.nodes.map(function(node){ + return compiler.visit(node); + }).join(''); + + // Parse literal + var url = parse(url) + , ext = extname(url.pathname) + , mime = mimes[ext] + , literal = new nodes.Literal('url("' + url.href + '")') + , paths = _paths.concat(this.paths) + , founds + , buf; + + // Not supported + if (!mime) return literal; + + // Absolute + if (url.protocol) return literal; + + // Lookup + found = utils.lookup(url.pathname, paths); + + // Failed to lookup + if (!found) return literal; + + // Read data + buf = fs.readFileSync(found); + + // To large + if (buf.length > sizeLimit) return literal; + + // Encode + return new nodes.Literal('url("data:' + mime + ';base64,' + buf.toString('base64') + '")'); + }; + + url.raw = true; + return url; +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/lexer.js b/node_modules/jade/support/stylus/lib/lexer.js new file mode 100644 index 0000000..0ca2e1d --- /dev/null +++ b/node_modules/jade/support/stylus/lib/lexer.js @@ -0,0 +1,672 @@ + +/*! + * Stylus - Lexer + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Token = require('./token') + , nodes = require('./nodes'); + +/** + * Operator aliases. + */ + +var alias = { + 'and': '&&' + , 'or': '||' + , 'is': '==' + , 'isnt': '!=' + , 'is not': '!=' +}; + +/** + * Units. + */ + +var units = [ + 'em' + , 'ex' + , 'px' + , 'mm' + , 'cm' + , 'in' + , 'pt' + , 'pc' + , 'deg' + , 'rad' + , 'grad' + , 'ms' + , 's' + , 'Hz' + , 'kHz' + , '%'].join('|'); + +/** + * Unit RegExp. + */ + +var unit = new RegExp('^(-)?(\\d+\\.\\d+|\\d+|\\.\\d+)(' + units + ')? *'); + +/** + * Initialize a new `Lexer` with the given `str` and `options`. + * + * @param {String} str + * @param {Object} options + * @api private + */ + +var Lexer = module.exports = function Lexer(str, options) { + options = options || {}; + this.str = str.replace(/\r\n?/g, '\n'); + this.stash = []; + this.indentStack = []; + this.indentRe = null; + this.lineno = 0; +}; + +/** + * Lexer prototype. + */ + +Lexer.prototype = { + + /** + * Custom inspect. + */ + + inspect: function(){ + var tok + , tmp = this.str + , buf = []; + while ('eos' != (tok = this.next()).type) { + buf.push(tok.inspect()); + } + this.str = tmp; + this.prevIndents = 0; + return buf.concat(tok.inspect()).join('\n'); + }, + + /** + * Lookahead `n` tokens. + * + * @param {Number} n + * @return {Object} + * @api private + */ + + lookahead: function(n){ + var fetch = n - this.stash.length; + while (fetch-- > 0) this.stash.push(this.advance()); + return this.stash[--n]; + }, + + /** + * Consume the given `len`. + * + * @param {Number|Array} len + * @api private + */ + + skip: function(len){ + this.str = this.str.substr(Array.isArray(len) + ? len[0].length + : len); + }, + + /** + * Fetch next token including those stashed by peek. + * + * @return {Token} + * @api private + */ + + next: function() { + var tok = this.stashed() || this.advance(); + switch (tok.type) { + case 'newline': + case 'selector': + case 'indent': + ++this.lineno; + } + tok.lineno = this.lineno; + return tok; + }, + + /** + * Fetch next token. + * + * @return {Token} + * @api private + */ + + advance: function() { + return this.eos() + || this.null() + || this.sep() + || this.keyword() + || this.urlchars() + || this.atrule() + || this.media() + || this.comment() + || this.newline() + || this.escaped() + || this.important() + || this.literal() + || this.function() + || this.brace() + || this.paren() + || this.color() + || this.string() + || this.unit() + || this.namedop() + || this.boolean() + || this.ident() + || this.op() + || this.space() + || this.selector(); + }, + + /** + * Lookahead a single token. + * + * @return {Token} + * @api private + */ + + peek: function() { + return this.lookahead(1); + }, + + /** + * Return the next possibly stashed token. + * + * @return {Token} + * @api private + */ + + stashed: function() { + return this.stash.shift(); + }, + + /** + * EOS | trailing outdents. + */ + + eos: function() { + if (this.str.length) return; + if (this.indentStack.length) { + this.indentStack.shift(); + return new Token('outdent'); + } else { + return new Token('eos'); + } + }, + + /** + * url char + */ + + urlchars: function() { + var captures; + if (!this.isURL) return; + if (captures = /^[\/:@.;?&=*!,<>#%0-9]+/.exec(this.str)) { + this.skip(captures); + return new Token('literal', new nodes.Literal(captures[0])); + } + }, + + /** + * ';' ' '* + */ + + sep: function() { + var captures; + if (captures = /^; */.exec(this.str)) { + this.skip(captures); + return new Token(';'); + } + }, + + /** + * ' '+ + */ + + space: function() { + var captures; + if (captures = /^( +)/.exec(this.str)) { + this.skip(captures); + return new Token('space'); + } + }, + + /** + * '\\' . ' '* + */ + + escaped: function() { + var captures; + if (captures = /^\\(.) */.exec(this.str)) { + var c = captures[1]; + this.skip(captures); + return new Token('ident', new nodes.Literal(c)); + } + }, + + /** + * '@css' ' '* '{' .* '}' ' '* + */ + + literal: function() { + // HACK attack !!! + var captures; + if (captures = /^@css *\{/.exec(this.str)) { + this.skip(captures); + var c + , braces = 1 + , css = ''; + while (c = this.str[0]) { + this.str = this.str.substr(1); + switch (c) { + case '{': ++braces; break; + case '}': --braces; break; + } + css += c; + if (!braces) break; + } + css = css.replace(/\s*}$/, ''); + return new Token('literal', new nodes.Literal(css)); + } + }, + + /** + * '!important' ' '* + */ + + important: function() { + var captures; + if (captures = /^!important */.exec(this.str)) { + this.skip(captures); + return new Token('ident', new nodes.Literal('!important')); + } + }, + + /** + * '{' | '}' + */ + + brace: function() { + var captures; + if (captures = /^([{}])/.exec(this.str)) { + this.skip(1); + var brace = captures[1]; + return new Token(brace, brace); + } + }, + + /** + * '(' | ')' ' '* + */ + + paren: function() { + var captures; + if (captures = /^([()]) */.exec(this.str)) { + var paren = captures[1]; + this.skip(captures); + if (')' == paren) this.isURL = false; + return new Token(paren, paren); + } + }, + + /** + * 'null' + */ + + null: function() { + var captures; + if (captures = /^(null)\b */.exec(this.str)) { + this.skip(captures); + return new Token('null', nodes.null); + } + }, + + /** + * 'if' + * | 'else' + * | 'unless' + * | 'return' + * | 'for' + * | 'in' + */ + + keyword: function() { + var captures; + if (captures = /^(return|if|else|unless|for|in)\b */.exec(this.str)) { + var keyword = captures[1]; + this.skip(captures); + return new Token(keyword, keyword); + } + }, + + /** + * 'not' + * | 'and' + * | 'or' + * | 'is' + * | 'is not' + * | 'isnt' + * | 'is a' + * | 'is defined' + */ + + namedop: function() { + var captures; + if (captures = /^(not|and|or|is a|is defined|isnt|is not|is)\b( *)/.exec(this.str)) { + var op = captures[1]; + this.skip(captures); + op = alias[op] || op; + var tok = new Token(op, op); + tok.space = captures[2]; + return tok; + } + }, + + /** + * ',' + * | '+' + * | '+=' + * | '-' + * | '-=' + * | '*' + * | '*=' + * | '/' + * | '/=' + * | '%' + * | '%=' + * | '**' + * | '!' + * | '&' + * | '&&' + * | '||' + * | '>' + * | '>=' + * | '<' + * | '<=' + * | '=' + * | '==' + * | '!=' + * | '!' + * | '~' + * | '?=' + * | '?' + * | ':' + * | '[' + * | ']' + * | '..' + * | '...' + */ + + op: function() { + var captures; + if (captures = /^([.]{2,3}|&&|\|\||[!<>=?]=|\*\*|[-+*\/%]=?|[,=?:!~<>&\[\]])( *)/.exec(this.str)) { + var op = captures[1]; + this.skip(captures); + op = alias[op] || op; + var tok = new Token(op, op); + tok.space = captures[2]; + return tok; + } + }, + + /** + * '@media' ([^{\n]+) + */ + + media: function() { + var captures; + if (captures = /^@media *([^{\n]+)/.exec(this.str)) { + this.skip(captures); + return new Token('media', captures[1].trim()); + } + }, + + /** + * '@' ('import' | 'keyframes' | 'charset' | 'page') + */ + + atrule: function() { + var captures; + if (captures = /^@(import|keyframes|charset|page) */.exec(this.str)) { + this.skip(captures); + return new Token(captures[1]); + } + }, + + /** + * '//' * + */ + + comment: function() { + // Single line + if ('/' == this.str[0] && '/' == this.str[1]) { + var end = this.str.indexOf('\n'); + if (-1 == end) end = this.str.length; + this.skip(end); + return this.advance(); + } + + // Multi-line + if ('/' == this.str[0] && '*' == this.str[1]) { + var end = this.str.indexOf('*/'); + if (-1 == end) end = this.str.length; + var str = this.str.substr(0, end + 2) + , lines = str.split('\n').length - 1; + this.lineno += lines; + this.skip(end + 2); + return this.allowComments + ? new Token('comment', str) + : this.advance(); + } + }, + + /** + * 'true' | 'false' + */ + + boolean: function() { + var captures; + if (captures = /^(true|false)\b( *)/.exec(this.str)) { + var val = 'true' == captures[1] + ? nodes.true + : nodes.false; + this.skip(captures); + var tok = new Token('boolean', val); + tok.space = captures[2]; + return tok; + } + }, + + /** + * -?[a-zA-Z$] [-\w\d$]* '(' + */ + + function: function() { + var captures; + if (captures = /^(-?[a-zA-Z$][-\w\d$]*)\(( *)/.exec(this.str)) { + var name = captures[1]; + this.skip(captures); + this.isURL = 'url' == name; + var tok = new Token('function', new nodes.Ident(name)); + tok.space = captures[2]; + return tok; + } + }, + + /** + * -?[a-zA-Z$] [-\w\d$]* + */ + + ident: function() { + var captures; + if (captures = /^(-?[a-zA-Z$][-\w\d$]*)/.exec(this.str)) { + var name = captures[1]; + this.skip(captures); + return new Token('ident', new nodes.Ident(name)); + } + }, + + /** + * '\n' ' '+ + */ + + newline: function() { + var captures, re; + + // we have established the indentation regexp + if (this.indentRe){ + captures = this.indentRe.exec(this.str); + // figure out if we are using tabs or spaces + } else { + // try tabs + re = /^\n([\t]*) */; + captures = re.exec(this.str); + + // nope, try spaces + if (captures && !captures[1].length) { + re = /^\n( *)/; + captures = re.exec(this.str); + } + + // established + if (captures && captures[1].length) this.indentRe = re; + } + + + if (captures) { + var tok + , indents = captures[1].length; + + this.skip(captures); + if (this.str[0] === ' ' || this.str[0] === '\t') { + throw new Error('Invalid indentation, you can use tabs or spaces to indent but not both'); + } + + // Reset state + this.isVariable = false; + + // Blank line + if ('\n' == this.str[0]) { + ++this.lineno; + return this.advance(); + } + + // Outdent + if (this.indentStack.length && indents < this.indentStack[0]) { + while (this.indentStack.length && this.indentStack[0] > indents) { + this.stash.push(new Token('outdent')); + this.indentStack.shift(); + } + tok = this.stash.pop(); + // Indent + } else if (indents && indents != this.indentStack[0]) { + this.indentStack.unshift(indents); + tok = new Token('indent'); + // Newline + } else { + tok = new Token('newline'); + } + + return tok; + } + }, + + /** + * '-'? (digit+ | digit* '.' digit+) unit + */ + + unit: function() { + var captures; + if (captures = unit.exec(this.str)) { + this.skip(captures); + var n = parseFloat(captures[2]); + if ('-' == captures[1]) n = -n; + var node = new nodes.Unit(n, captures[3]); + return new Token('unit', node); + } + }, + + /** + * '"' [^"]+ '"' | "'"" [^']+ "'" + */ + + string: function() { + var captures; + if (captures = /^("[^"]*"|'[^']*') */.exec(this.str)) { + var str = captures[1]; + this.skip(captures); + return new Token('string', new nodes.String(str.slice(1,-1))); + } + }, + + /** + * #nnnnnn | #nnn + */ + + color: function() { + return this.hex6() + || this.hex3(); + }, + + /** + * #nnn + */ + + hex3: function() { + var captures; + if (captures = /^#([a-fA-F0-9]{3}) */.exec(this.str)) { + this.skip(captures); + var rgb = captures[1] + , r = parseInt(rgb[0] + rgb[0], 16) + , g = parseInt(rgb[1] + rgb[1], 16) + , b = parseInt(rgb[2] + rgb[2], 16) + , color = new nodes.RGBA(r, g, b, 1); + color.raw = captures[0]; + return new Token('color', color); + } + }, + + /** + * #nnnnnn + */ + + hex6: function() { + var captures; + if (captures = /^#([a-fA-F0-9]{6}) */.exec(this.str)) { + this.skip(captures); + var rgb = captures[1] + , r = parseInt(rgb.substr(0, 2), 16) + , g = parseInt(rgb.substr(2, 2), 16) + , b = parseInt(rgb.substr(4, 2), 16) + , color = new nodes.RGBA(r, g, b, 1); + color.raw = captures[0]; + return new Token('color', color); + } + }, + + /** + * [^\n,;]+ + */ + + selector: function() { + var captures; + if (captures = /^[^{\n,]+/.exec(this.str)) { + var selector = captures[0]; + this.skip(captures); + return new Token('selector', selector); + } + } +}; diff --git a/node_modules/jade/support/stylus/lib/middleware.js b/node_modules/jade/support/stylus/lib/middleware.js new file mode 100644 index 0000000..fdd890d --- /dev/null +++ b/node_modules/jade/support/stylus/lib/middleware.js @@ -0,0 +1,198 @@ +/*! + * Stylus - middleware + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var stylus = require('./stylus') + , fs = require('fs') + , url = require('url') + , basename = require('path').basename + , join = require('path').join + , ENOENT; + +// COMPAT: + +try { + ENOENT = require('constants').ENOENT; +} catch (err) { + ENOENT = process.ENOENT; +} + +/** + * Import map. + */ + +var imports = {}; + +/** + * Return Connect middleware with the given `options`. + * + * Options: + * + * `force` Always re-compile + * `src` Source directory used to find .styl files + * `dest` Destination directory used to output .css files + * when undefined defaults to `src`. + * `compile` Custom compile function, accepting the arguments + * `(str, path)`. + * `compress` Whether the output .css files should be compressed + * + * Examples: + * + * Here we set up the custom compile function so that we may + * set the `compress` option, or define additional functions. + * + * By default the compile function simply sets the `filename` + * and renders the CSS. + * + * function compile(str, path) { + * return stylus(str) + * .set('filename', path) + * .set('compress', true); + * } + * + * Pass the middleware to Connect, grabbing .styl files from this directory + * and saving .css files to _./public_. Also supplying our custom `compile` function. + * + * Following that we have a `staticProvider` layer setup to serve the .css + * files generated by Stylus. + * + * var server = connect.createServer( + * stylus.middleware({ + * src: __dirname + * , dest: __dirname + '/public' + * , compile: compile + * }) + * , connect.static(__dirname + '/public') + * ); + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function(options){ + options = options || {}; + + // Accept src/dest dir + if ('string' == typeof options) { + options = { src: options }; + } + + // Force compilation + var force = options.force; + + // Source dir required + var src = options.src; + if (!src) throw new Error('stylus.middleware() requires "src" directory'); + + // Default dest dir to source + var dest = options.dest + ? options.dest + : src; + + // Default compile callback + options.compile = options.compile || function(str, path){ + return stylus(str) + .set('filename', path) + .set('compress', options.compress); + }; + + // Middleware + return function(req, res, next){ + if ('GET' != req.method && 'HEAD' != req.method) return next(); + var path = url.parse(req.url).pathname; + if (/\.css$/.test(path)) { + var cssPath = join(dest, path) + , stylusPath = join(src, path.replace('.css', '.styl')); + + // Ignore ENOENT to fall through as 404 + function error(err) { + next(ENOENT == err.errno + ? null + : err); + } + + // Force + if (force) return compile(); + + // Compile to cssPath + function compile() { + fs.readFile(stylusPath, 'utf8', function(err, str){ + if (err) return error(err); + var style = options.compile(str, stylusPath); + var paths = style.options._imports = []; + style.render(function(err, css){ + imports[stylusPath] = imports[stylusPath] || paths; + if (err) return next(err); + fs.writeFile(cssPath, css, 'utf8', function(err){ + next(err); + }); + }); + }); + } + + // Compare mtimes + fs.stat(stylusPath, function(err, stylusStats){ + if (err) return error(err); + fs.stat(cssPath, function(err, cssStats){ + // CSS has not been compiled, compile it! + if (err) { + if (ENOENT == err.errno) { + compile(); + } else { + next(err); + } + } else { + // Source has changed, compile it + if (stylusStats.mtime > cssStats.mtime) { + compile(); + // Already compiled, check imports + } else { + checkImports(stylusPath, function(changed){ + changed ? compile() : next(); + }); + } + } + }); + }); + } else { + next(); + } + } +}; + +/** + * Check `path`'s imports to see if they have been altered. + * + * @param {String} path + * @param {Function} fn + * @api private + */ + +function checkImports(path, fn) { + var nodes = imports[path]; + if (!nodes) return fn(); + if (!nodes.length) return fn(); + var pending = nodes.length + , changed = false; + nodes.forEach(function(import){ + fs.stat(import.path, function(err, stat){ + if (err) { + --pending || fn(changed); + } else if (import.mtime) { + changed = changed || stat.mtime > import.mtime; + import.mtime = stat.mtime; + --pending || fn(changed); + } else { + import.mtime = stat.mtime; + --pending || fn(changed = true); + } + }); + }); +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/nodes/binop.js b/node_modules/jade/support/stylus/lib/nodes/binop.js new file mode 100644 index 0000000..3dbe4b2 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/binop.js @@ -0,0 +1,52 @@ + +/*! + * Stylus - BinOp + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `BinOp` with `op`, `left` and `right`. + * + * @param {String} op + * @param {Node} left + * @param {Node} right + * @api public + */ + +var BinOp = module.exports = function BinOp(op, left, right){ + Node.call(this); + this.op = op; + this.left = left; + this.right = right; +}; + +/** + * Inherit from `Node.prototype`. + */ + +BinOp.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +BinOp.prototype.clone = function(){ + var clone = new BinOp( + this.op + , this.left.clone() + , this.right ? + this.right.clone() + : null); + clone.lineno = this.lineno; + return clone; +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/nodes/block.js b/node_modules/jade/support/stylus/lib/nodes/block.js new file mode 100644 index 0000000..7db0d62 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/block.js @@ -0,0 +1,98 @@ + +/*! + * Stylus - Block + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Block` node with `parent` Block. + * + * @param {Block} parent + * @api public + */ + +var Block = module.exports = function Block(parent, node){ + Node.call(this); + this.nodes = []; + this.parent = parent; + this.node = node; + this.scope = true; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Block.prototype.__proto__ = Node.prototype; + +/** + * Check if this block has properties.. + * + * @return {Boolean} + * @api public + */ + +Block.prototype.__defineGetter__('hasProperties', function(){ + for (var i = 0, len = this.nodes.length; i < len; ++i) { + if ('property' == this.nodes[i].nodeName) { + return true; + } + } +}); + +/** + * Check if this block is empty. + * + * @return {Boolean} + * @api public + */ + +Block.prototype.__defineGetter__('isEmpty', function(){ + return !this.nodes.length; +}); + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Block.prototype.clone = function(){ + var clone = new Block(this.parent, this.node); + clone.lineno = this.lineno; + clone.scope = this.scope; + this.nodes.forEach(function(node){ + node = node.clone(); + switch (node.nodeName) { + case 'each': + case 'group': + node.block.parent = clone; + break; + case 'ident': + if ('function' == node.val.nodeName) { + node.val.block.parent = clone; + } + } + clone.push(node); + }); + return clone; +}; + +/** + * Push a `node` to this block. + * + * @param {Node} node + * @api public + */ + +Block.prototype.push = function(node){ + this.nodes.push(node); +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/boolean.js b/node_modules/jade/support/stylus/lib/nodes/boolean.js new file mode 100644 index 0000000..a71c327 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/boolean.js @@ -0,0 +1,83 @@ + +/*! + * Stylus - Boolean + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Boolean` node with the given `val`. + * + * @param {Boolean} val + * @api public + */ + +var Boolean = module.exports = function Boolean(val){ + Node.call(this); + if (this instanceof Boolean) { + this.val = !!val; + } else { + return val ? nodes.true : nodes.false; + } +}; + +/** + * Inherit from `Node.prototype`. + */ + +Boolean.prototype.__proto__ = Node.prototype; + +/** + * Return `this` node. + * + * @return {Boolean} + * @api public + */ + +Boolean.prototype.toBoolean = function(){ + return this; +}; + +/** + * Negate the value. + * + * @return {Boolean} + * @api public + */ + +Boolean.prototype.negate = function(){ + return this.val + ? nodes.false + : nodes.true; +}; + +/** + * Return 'Boolean'. + * + * @return {String} + * @api public + */ + +Boolean.prototype.inspect = function(){ + return '[Boolean ' + this.val + ']'; +}; + +/** + * Return 'true' or 'false'. + * + * @return {String} + * @api public + */ + +Boolean.prototype.toString = function(){ + return this.val + ? 'true' + : 'false'; +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/nodes/call.js b/node_modules/jade/support/stylus/lib/nodes/call.js new file mode 100644 index 0000000..b0d20f5 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/call.js @@ -0,0 +1,56 @@ + +/*! + * Stylus - Call + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Call` with `name` and `args`. + * + * @param {String} name + * @param {Expression} args + * @api public + */ + +var Call = module.exports = function Call(name, args){ + Node.call(this); + this.name = name; + this.args = args; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Call.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Call.prototype.clone = function(){ + var clone = new Call(this.name, this.args.clone()); + clone.lineno = this.lineno; + return clone; +}; + +/** + * Return (). + * + * @return {String} + * @api public + */ + +Call.prototype.toString = function(){ + return this.name + '()'; +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/charset.js b/node_modules/jade/support/stylus/lib/nodes/charset.js new file mode 100644 index 0000000..2e95c34 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/charset.js @@ -0,0 +1,42 @@ + +/*! + * Stylus - Charset + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Charset` with the given `val` + * + * @param {String} val + * @api public + */ + +var Charset = module.exports = function Charset(val){ + Node.call(this); + this.val = val; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Charset.prototype.__proto__ = Node.prototype; + +/** + * Return @charset "val". + * + * @return {String} + * @api public + */ + +Charset.prototype.toString = function(){ + return '@charset ' + this.val; +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/each.js b/node_modules/jade/support/stylus/lib/nodes/each.js new file mode 100644 index 0000000..7268dec --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/each.js @@ -0,0 +1,55 @@ + +/*! + * Stylus - Each + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Each` node with the given `val` name, + * `key` name, `expr`, and `block`. + * + * @param {String} val + * @param {String} key + * @param {Expression} expr + * @param {Block} block + * @api public + */ + +var Each = module.exports = function Each(val, key, expr, block){ + Node.call(this); + this.val = val; + this.key = key; + this.expr = expr; + this.block = block; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Each.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Each.prototype.clone = function(){ + var clone = new Each( + this.val + , this.key + , this.expr.clone() + , this.block.clone()); + clone.lineno = this.lineno; + return clone; +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/nodes/expression.js b/node_modules/jade/support/stylus/lib/nodes/expression.js new file mode 100644 index 0000000..ae7205f --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/expression.js @@ -0,0 +1,143 @@ + +/*! + * Stylus - Expression + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('../nodes') + , utils = require('../utils'); + +/** + * Initialize a new `Expression`. + * + * @param {Boolean} isList + * @api public + */ + +var Expression = module.exports = function Expression(isList){ + Node.call(this); + this.nodes = []; + this.isList = isList; +}; + +/** + * Check if the variable has a value. + * + * @return {Boolean} + * @api public + */ + +Expression.prototype.__defineGetter__('isEmpty', function(){ + return !this.nodes.length; +}); + +/** + * Return the first node in this expression. + * + * @return {Node} + * @api public + */ + +Expression.prototype.__defineGetter__('first', function(){ + return this.nodes[0] + ? this.nodes[0].first + : nodes.null; +}); + +/** + * Hash all the nodes in order. + * + * @return {String} + * @api public + */ + +Expression.prototype.__defineGetter__('hash', function(){ + return this.nodes.map(function(node){ + return node.hash; + }).join('::'); +}); + +/** + * Inherit from `Node.prototype`. + */ + +Expression.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Expression.prototype.clone = function(){ + var clone = new Expression(this.isList); + clone.preserve = this.preserve; + clone.lineno = this.lineno; + for (var i = 0; i < this.nodes.length; ++i) { + clone.push(this.nodes[i].clone()); + } + return clone; +}; + +/** + * Push the given `node`. + * + * @param {Node} node + * @api public + */ + +Expression.prototype.push = function(node){ + this.nodes.push(node); +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +Expression.prototype.operate = function(op, right){ + switch (op) { + case '[]': + var expr = new nodes.Expression + , vals = utils.unwrap(this).nodes + , range = utils.unwrap(right).nodes; + range.forEach(function(unit){ + if ('unit' == unit.nodeName) { + var node = vals[unit.val]; + if (node) expr.push(node); + } + }); + return expr.isEmpty + ? nodes.null + : expr; + default: + return Node.prototype.operate.call(this, op, right); + } +}; + +/** + * Return " " or ", , " if + * the expression represents a list. + * + * @return {String} + * @api public + */ + +Expression.prototype.toString = function(){ + return '(' + this.nodes.map(function(node){ + return node.toString(); + }).join(this.isList ? ', ' : ' ') + ')'; +}; + + diff --git a/node_modules/jade/support/stylus/lib/nodes/function.js b/node_modules/jade/support/stylus/lib/nodes/function.js new file mode 100644 index 0000000..ba0c214 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/function.js @@ -0,0 +1,92 @@ + +/*! + * Stylus - Function + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Function` with `name`, `params`, and `body`. + * + * @param {String} name + * @param {Params|Function} params + * @param {Block} body + * @api public + */ + +var Function = module.exports = function Function(name, params, body){ + Node.call(this); + this.name = name; + this.params = params; + this.block = body; + if ('function' == typeof params) this.fn = params; +}; + +/** + * Check function arity. + * + * @return {Boolean} + * @api public + */ + +Function.prototype.__defineGetter__('arity', function(){ + return this.params.length; +}); + +/** + * Inherit from `Node.prototype`. + */ + +Function.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Function.prototype.clone = function(){ + if (this.fn) { + var clone = new Function( + this.name + , this.fn); + } else { + var clone = new Function( + this.name + , this.params.clone() + , this.block.clone()); + } + clone.lineno = this.lineno; + return clone; +}; + +/** + * Return (param1, param2, ...). + * + * @return {String} + * @api public + */ + +Function.prototype.toString = function(){ + if (this.fn) { + return this.name + + '(' + + this.fn.toString() + .match(/^function *\((.*?)\)/) + .slice(1) + .join(', ') + + ')'; + } else { + return this.name + + '(' + + this.params.nodes.join(', ') + + ')'; + } +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/group.js b/node_modules/jade/support/stylus/lib/nodes/group.js new file mode 100644 index 0000000..1d36b81 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/group.js @@ -0,0 +1,78 @@ + +/*! + * Stylus - Group + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Group`. + * + * @api public + */ + +var Group = module.exports = function Group(){ + Node.call(this); + this.nodes = []; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Group.prototype.__proto__ = Node.prototype; + +/** + * Push the given `selector` node. + * + * @param {Selector} selector + * @api public + */ + +Group.prototype.push = function(selector){ + this.nodes.push(selector); +}; + +/** + * Return this set's `Block`. + */ + +Group.prototype.__defineGetter__('block', function(){ + return this.nodes[0].block; +}); + +/** + * Assign `block` to each selector in this set. + * + * @param {Block} block + * @api public + */ + +Group.prototype.__defineSetter__('block', function(block){ + for (var i = 0, len = this.nodes.length; i < len; ++i) { + this.nodes[i].block = block; + } +}); + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Group.prototype.clone = function(){ + var clone = new Group; + clone.lineno = this.lineno; + this.nodes.forEach(function(node){ + clone.push(node.clone()); + }); + clone.block = this.block.clone(); + return clone; +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/hsla.js b/node_modules/jade/support/stylus/lib/nodes/hsla.js new file mode 100644 index 0000000..9be887d --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/hsla.js @@ -0,0 +1,230 @@ + +/*! + * Stylus - HSLA + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `HSLA` with the given h,s,l,a component values. + * + * @param {Number} h + * @param {Number} s + * @param {Number} l + * @param {Number} a + * @api public + */ + +var HSLA = exports = module.exports = function HSLA(h,s,l,a){ + Node.call(this); + this.h = clampDegrees(h); + this.s = clampPercentage(s); + this.l = clampPercentage(l); + this.a = clampAlpha(a); + this.hsla = this; +}; + +/** + * Inherit from `Node.prototype`. + */ + +HSLA.prototype.__proto__ = Node.prototype; + +/** + * Return hsla(n,n,n,n). + * + * @return {String} + * @api public + */ + +HSLA.prototype.toString = function(){ + return 'hsla(' + + this.h + ',' + + this.s + ',' + + this.l + ',' + + this.a + ')'; +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +HSLA.prototype.clone = function(){ + var clone = new HSLA( + this.h + , this.s + , this.l + , this.a); + clone.lineno = this.lineno; + return clone; +}; + +/** + * Return rgba `RGBA` representation. + * + * @return {RGBA} + * @api public + */ + +HSLA.prototype.__defineGetter__('rgba', function(){ + return nodes.RGBA.fromHSLA(this); +}); + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +HSLA.prototype.__defineGetter__('hash', function(){ + return this.rgba.toString(); +}); + +/** + * Coerce RGBA to HSLA. + * + * @param {Node} other + * @return {Node} + * @api public + */ + +HSLA.prototype.coerce = function(other){ + if (other instanceof nodes.RGBA) { + return other.hsla; + } else { + return Node.prototype.coerce.call(this, other); + } +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +HSLA.prototype.operate = function(op, right){ + switch (op) { + case '+': + return new HSLA( + this.h + right.h + , this.s + right.s + , this.l + right.l + , 1 == right.a ? this.a : (this.a + right.a) + ); + case '-': + return new HSLA( + this.h - right.h + , this.s - right.s + , this.l - right.l + , 1 == right.a ? this.a : (this.a - right.a) + ); + case '*': + return new HSLA( + this.h * right.h + , this.s * right.s + , this.l * right.l + , this.a * right.a + ); + case '/': + return new HSLA( + this.h / right.h + , this.s / right.s + , this.l / right.l + , this.a / right.a + ); + default: + return Node.prototype.operate.call(this, op, right); + } +}; + +/** + * Return `HSLA` representation of the given `color`. + * + * @param {RGBA} color + * @return {HSLA} + * @api public + */ + +exports.fromRGBA = function(rgba){ + var r = rgba.r / 255 + , g = rgba.g / 255 + , b = rgba.b / 255 + , a = rgba.a; + + var min = Math.min(r,g,b) + , max = Math.max(r,g,b) + , l = (max + min) / 2 + , d = max - min + , h, s; + + switch (max) { + case min: h = 0; break; + case r: h = 60 * (g-b) / d; break; + case g: h = 60 * (b-r) / d + 120; break; + case b: h = 60 * (r-g) / d + 240; break; + } + + if (max == min) { + s = 0; + } else if (l < .5) { + s = d / (2 * l); + } else { + s = d / (2 - 2 * l); + } + + h %= 360; + s *= 100; + l *= 100; + + return new HSLA(h,s,l,a); +}; + +/** + * Clamp degree `n` >= 0 and <= 360. + * + * @param {Number} n + * @return {Number} + * @api private + */ + +function clampDegrees(n) { + return Math.max(0, Math.min(n, 360)); +} + +/** + * Clamp percentage `n` >= 0 and <= 100. + * + * @param {Number} n + * @return {Number} + * @api private + */ + +function clampPercentage(n) { + return Math.max(0, Math.min(n, 100)); +} + +/** + * Clamp alpha `n` >= 0 and <= 1. + * + * @param {Number} n + * @return {Number} + * @api private + */ + +function clampAlpha(n) { + return Math.max(0, Math.min(n, 1)); +} diff --git a/node_modules/jade/support/stylus/lib/nodes/ident.js b/node_modules/jade/support/stylus/lib/nodes/ident.js new file mode 100644 index 0000000..e307bc8 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/ident.js @@ -0,0 +1,97 @@ + +/*! + * Stylus - Ident + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Ident` by `name` with the given `val` node. + * + * @param {String} name + * @param {Node} val + * @api public + */ + +var Ident = module.exports = function Ident(name, val){ + Node.call(this); + this.name = name; + this.string = name; + this.val = val || nodes.null; +}; + +/** + * Check if the variable has a value. + * + * @return {Boolean} + * @api public + */ + +Ident.prototype.__defineGetter__('isEmpty', function(){ + return undefined == this.val; +}); + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +Ident.prototype.__defineGetter__('hash', function(){ + return this.name; +}); + +/** + * Inherit from `Node.prototype`. + */ + +Ident.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Ident.prototype.clone = function(){ + var clone = new Ident(this.name, this.val.clone()); + clone.lineno = this.lineno; + return clone; +}; + +/** + * Return . + * + * @return {String} + * @api public + */ + +Ident.prototype.toString = function(){ + return this.name; +}; + +/** + * Coerce `other` to an ident. + * + * @param {Node} other + * @return {String} + * @api public + */ + +Ident.prototype.coerce = function(other){ + if (other instanceof nodes.Literal || + other instanceof Ident) { + return other; + } else { + return Node.prototype.coerce.call(this, other); + } +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/if.js b/node_modules/jade/support/stylus/lib/nodes/if.js new file mode 100644 index 0000000..ec7a977 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/if.js @@ -0,0 +1,54 @@ + +/*! + * Stylus - If + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `If` with the given `cond`. + * + * @param {Expression} cond + * @param {Boolean|Block} negate, block + * @api public + */ + +var If = module.exports = function If(cond, negate){ + Node.call(this); + this.cond = cond; + this.elses = []; + if (negate instanceof Node) { + this.block = negate; + } else { + this.negate = negate; + } +}; + +/** + * Inherit from `Node.prototype`. + */ + +If.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +If.prototype.clone = function(){ + var cond = this.cond.clone() + , block = this.block.clone(); + var clone = new If(cond, block); + clone.elses = this.elses.map(function(node){ return node.clone(); }); + clone.negate = this.negate; + clone.lineno = this.lineno; + return clone; +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/import.js b/node_modules/jade/support/stylus/lib/nodes/import.js new file mode 100644 index 0000000..9356c30 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/import.js @@ -0,0 +1,30 @@ + +/*! + * Stylus - Import + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Import` with the given `expr`. + * + * @param {Expression} expr + * @api public + */ + +var Import = module.exports = function Import(expr){ + Node.call(this); + this.path = expr; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Import.prototype.__proto__ = Node.prototype; diff --git a/node_modules/jade/support/stylus/lib/nodes/index.js b/node_modules/jade/support/stylus/lib/nodes/index.js new file mode 100644 index 0000000..671344c --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/index.js @@ -0,0 +1,48 @@ + +/*! + * Stylus - nodes + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Constructors + */ + +exports.Node = require('./node'); +exports.Root = require('./root'); +exports.Null = require('./null'); +exports.Each = require('./each'); +exports.If = require('./if'); +exports.Call = require('./call'); +exports.Page = require('./page'); +exports.UnaryOp = require('./unaryop'); +exports.BinOp = require('./binop'); +exports.Ternary = require('./ternary'); +exports.Block = require('./block'); +exports.Unit = require('./unit'); +exports.String = require('./string'); +exports.HSLA = require('./hsla'); +exports.RGBA = require('./rgba'); +exports.Ident = require('./ident'); +exports.Group = require('./group'); +exports.Literal = require('./literal'); +exports.Boolean = require('./boolean'); +exports.Return = require('./return'); +exports.Media = require('./media'); +exports.Params = require('./params'); +exports.Keyframes = require('./keyframes'); +exports.Charset = require('./charset'); +exports.Import = require('./import'); +exports.Function = require('./function'); +exports.Property = require('./property'); +exports.Selector = require('./selector'); +exports.Expression = require('./expression'); + +/** + * Singletons. + */ + +exports.true = new exports.Boolean(true); +exports.false = new exports.Boolean(false); +exports.null = new exports.Null; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/nodes/keyframes.js b/node_modules/jade/support/stylus/lib/nodes/keyframes.js new file mode 100644 index 0000000..cd15604 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/keyframes.js @@ -0,0 +1,57 @@ + +/*! + * Stylus - Keyframes + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Keyframes` with the given `name`. + * + * @param {String} name + * @api public + */ + +var Keyframes = module.exports = function Keyframes(name){ + Node.call(this); + this.name = name; + this.frames = []; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Keyframes.prototype.__proto__ = Node.prototype; + +/** + * Push the given `block` at `pos`. + * + * @param {Unit} pos + * @param {Block} block + * @api public + */ + +Keyframes.prototype.push = function(pos, block){ + this.frames.push({ + pos: pos + , block: block + }); +}; + +/** + * Return `@keyframes name`. + * + * @return {String} + * @api public + */ + +Keyframes.prototype.toString = function(){ + return '@keyframes ' + this.name; +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/literal.js b/node_modules/jade/support/stylus/lib/nodes/literal.js new file mode 100644 index 0000000..1b94867 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/literal.js @@ -0,0 +1,70 @@ + +/*! + * Stylus - Literal + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Literal` with the given `str`. + * + * @param {String} str + * @api public + */ + +var Literal = module.exports = function Literal(str){ + Node.call(this); + this.val = str; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Literal.prototype.__proto__ = Node.prototype; + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +Literal.prototype.__defineGetter__('hash', function(){ + return this.val; +}); + +/** + * Return literal value. + * + * @return {String} + * @api public + */ + +Literal.prototype.toString = function(){ + return this.val; +}; + +/** + * Coerce `other` to a literal. + * + * @param {Node} other + * @return {String} + * @api public + */ + +Literal.prototype.coerce = function(other){ + if (other instanceof Literal || + other instanceof nodes.Ident) { + return other; + } else { + return Node.prototype.coerce.call(this, other); + } +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/media.js b/node_modules/jade/support/stylus/lib/nodes/media.js new file mode 100644 index 0000000..142fb24 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/media.js @@ -0,0 +1,42 @@ + +/*! + * Stylus - Media + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Media` with the given `val` + * + * @param {String} val + * @api public + */ + +var Media = module.exports = function Media(val){ + Node.call(this); + this.val = val; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Media.prototype.__proto__ = Node.prototype; + +/** + * Return @media "val". + * + * @return {String} + * @api public + */ + +Media.prototype.toString = function(){ + return '@media ' + this.val; +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/node.js b/node_modules/jade/support/stylus/lib/nodes/node.js new file mode 100644 index 0000000..266c118 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/node.js @@ -0,0 +1,175 @@ + +/*! + * Stylus - Node + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Evaluator = require('../visitor/evaluator') + , utils = require('../utils') + , nodes = require('./'); + +/** + * Node constructor. + * + * @api public + */ + +var Node = module.exports = function Node(){ + this.lineno = nodes.lineno; + Object.defineProperty(this, 'filename', { value: nodes.filename }); + Object.defineProperty(this, 'source', { value: nodes.source }); +}; + +/** + * Return this node. + * + * @return {Node} + * @api public + */ + +Node.prototype.__defineGetter__('first', function(){ + return this; +}); + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +Node.prototype.__defineGetter__('hash', function(){ + return this.val; +}); + +/** + * Return node name. + * + * @return {String} + * @api public + */ + +Node.prototype.__defineGetter__('nodeName', function(){ + return this.constructor.name.toLowerCase(); +}); + +/** + * Return this node. + * + * @return {Node} + * @api public + */ + +Node.prototype.clone = function(){ + return this; +}; + +/** + * Nodes by default evaluate to themselves. + * + * @return {Node} + * @api public + */ + +Node.prototype.eval = function(){ + return new Evaluator(this).evaluate(); +}; + +/** + * Return true. + * + * @return {Boolean} + * @api public + */ + +Node.prototype.toBoolean = function(){ + return nodes.true; +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +Node.prototype.operate = function(op, right){ + switch (op) { + case 'is a': + if ('string' == right.nodeName) { + if ('color' == right.string) { + return nodes.Boolean('rgba' == this.nodeName || 'hsla' == this.nodeName); + } else { + return nodes.Boolean(this.nodeName == right.val); + } + } else { + throw new Error('"is a" expects a string, got ' + right.nodeName); + } + case '==': + return nodes.Boolean(this.hash == right.hash); + case '!=': + return nodes.Boolean(this.hash != right.hash); + case '>=': + return nodes.Boolean(this.hash >= right.hash); + case '<=': + return nodes.Boolean(this.hash <= right.hash); + case '>': + return nodes.Boolean(this.hash > right.hash); + case '<': + return nodes.Boolean(this.hash < right.hash); + case '||': + return nodes.true == this.toBoolean() + ? this + : right; + case 'in': + var vals = utils.unwrap(right).nodes + , hash = this.hash; + if (!vals) throw new Error('"in" given invalid right-hand operand, expecting an expression'); + for (var i = 0, len = vals.length; i < len; ++i) { + if (hash == vals[i].hash) { + return nodes.true; + } + } + return nodes.false; + case '&&': + var a = this.toBoolean() + , b = right.toBoolean(); + return nodes.true == a && nodes.true == b + ? right + : nodes.false == a + ? this + : right; + default: + if ('[]' == op) { + var msg = 'cannot perform ' + + this + + '[' + right + ']'; + } else { + var msg = 'cannot perform' + + ' ' + this + + ' ' + op + + ' ' + right; + } + throw new Error(msg); + } +}; + +/** + * Default coercion throws. + * + * @param {Node} other + * @return {Node} + * @api public + */ + +Node.prototype.coerce = function(other){ + if (other.nodeName == this.nodeName) return other; + throw new Error('cannot coerce ' + other + ' to ' + this.nodeName); +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/null.js b/node_modules/jade/support/stylus/lib/nodes/null.js new file mode 100644 index 0000000..579e4c3 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/null.js @@ -0,0 +1,61 @@ + +/*! + * Stylus - Null + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Null` node. + * + * @api public + */ + +var Null = module.exports = function Null(){}; + +/** + * Inherit from `Node.prototype`. + */ + +Null.prototype.__proto__ = Node.prototype; + +/** + * Return 'Null'. + * + * @return {String} + * @api public + */ + +Null.prototype.inspect = +Null.prototype.toString = function(){ + return '[Null]'; +}; + +/** + * Return false. + * + * @return {Boolean} + * @api public + */ + +Null.prototype.toBoolean = function(){ + return nodes.false; +}; + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +Null.prototype.__defineGetter__('hash', function(){ + return null; +}); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/nodes/page.js b/node_modules/jade/support/stylus/lib/nodes/page.js new file mode 100644 index 0000000..e60648e --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/page.js @@ -0,0 +1,43 @@ + +/*! + * Stylus - Page + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Page` with the given `selector` and `block`. + * + * @param {Selector} selector + * @param {Block} block + * @api public + */ + +var Page = module.exports = function Page(selector, block){ + Node.call(this); + this.selector = selector; + this.block = block; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Page.prototype.__proto__ = Node.prototype; + +/** + * Return `@oage name`. + * + * @return {String} + * @api public + */ + +Page.prototype.toString = function(){ + return '@page ' + this.selector; +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/params.js b/node_modules/jade/support/stylus/lib/nodes/params.js new file mode 100644 index 0000000..9bbe9cb --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/params.js @@ -0,0 +1,71 @@ + +/*! + * Stylus - Params + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Params` with `name`, `params`, and `body`. + * + * @param {String} name + * @param {Params} params + * @param {Expression} body + * @api public + */ + +var Params = module.exports = function Params(){ + Node.call(this); + this.nodes = []; +}; + +/** + * Check function arity. + * + * @return {Boolean} + * @api public + */ + +Params.prototype.__defineGetter__('length', function(){ + return this.nodes.length; +}); + +/** + * Inherit from `Node.prototype`. + */ + +Params.prototype.__proto__ = Node.prototype; + +/** + * Push the given `node`. + * + * @param {Node} node + * @api public + */ + +Params.prototype.push = function(node){ + this.nodes.push(node); +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Params.prototype.clone = function(){ + var clone = new Params; + clone.lineno = this.lineno; + this.nodes.forEach(function(node){ + clone.push(node.clone()); + }); + return clone; +}; + diff --git a/node_modules/jade/support/stylus/lib/nodes/property.js b/node_modules/jade/support/stylus/lib/nodes/property.js new file mode 100644 index 0000000..6d3167c --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/property.js @@ -0,0 +1,47 @@ + +/*! + * Stylus - Property + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Property` with the given `segs` and optional `expr`. + * + * @param {Array} segs + * @param {Expression} expr + * @api public + */ + +var Property = module.exports = function Property(segs, expr){ + Node.call(this); + this.segments = segs; + this.expr = expr; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Property.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Property.prototype.clone = function(){ + var clone = new Property(this.segments); + clone.lineno = this.lineno; + this.segments = this.segments.map(function(node){ return node.clone(); }); + if (this.expr) clone.expr = this.expr.clone(); + return clone; +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/return.js b/node_modules/jade/support/stylus/lib/nodes/return.js new file mode 100644 index 0000000..86ca751 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/return.js @@ -0,0 +1,43 @@ + +/*! + * Stylus - Return + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Return` node with the given `expr`. + * + * @param {Expression} expr + * @api public + */ + +var Return = module.exports = function Return(expr){ + this.expr = expr || nodes.null; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Return.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Return.prototype.clone = function(){ + var clone = new Return(this.expr.clone()); + clone.lineno = this.lineno; + return clone; +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/nodes/rgba.js b/node_modules/jade/support/stylus/lib/nodes/rgba.js new file mode 100644 index 0000000..8648db9 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/rgba.js @@ -0,0 +1,243 @@ + +/*! + * Stylus - RGBA + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , HSLA = require('./hsla') + , nodes = require('./'); + +/** + * Initialize a new `RGBA` with the given r,g,b,a component values. + * + * @param {Number} r + * @param {Number} g + * @param {Number} b + * @param {Number} a + * @api public + */ + +var RGBA = exports = module.exports = function RGBA(r,g,b,a){ + Node.call(this); + this.r = clamp(r); + this.g = clamp(g); + this.b = clamp(b); + this.a = clampAlpha(a); + this.rgba = this; +}; + +/** + * Inherit from `Node.prototype`. + */ + +RGBA.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +RGBA.prototype.clone = function(){ + var clone = new RGBA( + this.r + , this.g + , this.b + , this.a); + clone.lineno = this.lineno; + return clone; +}; + +/** + * Return true. + * + * @return {Boolean} + * @api public + */ + +RGBA.prototype.toBoolean = function(){ + return nodes.true; +}; + +/** + * Return `HSLA` representation. + * + * @return {HSLA} + * @api public + */ + +RGBA.prototype.__defineGetter__('hsla', function(){ + return HSLA.fromRGBA(this); +}); + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +RGBA.prototype.__defineGetter__('hash', function(){ + return this.toString(); +}); + +/** + * Coerce HSLA and Unit to RGBA. + * + * @param {Node} other + * @return {Node} + * @api public + */ + +RGBA.prototype.coerce = function(other){ + if (other instanceof nodes.HSLA) { + return other.rgba; + } else if (other instanceof nodes.Unit) { + var n = other.val; + return new RGBA(n,n,n,1); + } else { + return Node.prototype.coerce.call(this, other); + } +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +RGBA.prototype.operate = function(op, right){ + switch (op) { + case '+': + return new RGBA( + this.r + right.r + , this.g + right.g + , this.b + right.b + , 1 == right.a ? this.a : (this.a + right.a) + ); + case '-': + return new RGBA( + this.r - right.r + , this.g - right.g + , this.b - right.b + , 1 == right.a ? this.a : (this.a - right.a) + ); + case '*': + return new RGBA( + this.r * right.r + , this.g * right.g + , this.b * right.b + , this.a * right.a + ); + case '/': + return new RGBA( + this.r / right.r + , this.g / right.g + , this.b / right.b + , this.a / right.a + ); + default: + return Node.prototype.operate.call(this, op, right); + } +}; + +/** + * Return #nnnnnn, #nnn, or rgba(n,n,n,n) string representation of the color. + * + * @return {String} + * @api public + */ + +RGBA.prototype.toString = function(){ + function pad(n) { + return n < 16 + ? '0' + n.toString(16) + : n.toString(16); + } + + if (1 == this.a) { + var r = pad(this.r) + , g = pad(this.g) + , b = pad(this.b); + + // Compress + if (r[0] == r[1] && g[0] == g[1] && b[0] == b[1]) { + return '#' + r[0] + g[0] + b[0]; + } else { + return '#' + r + g + b; + } + } else { + return 'rgba(' + + this.r + ',' + + this.g + ',' + + this.b + ',' + + this.a + ')'; + } +}; + +/** + * Return a `RGBA` from the given `hsla`. + * + * @param {HSLA} hsla + * @return {RGBA} + * @api public + */ + +exports.fromHSLA = function(hsla){ + var h = hsla.h / 360 + , s = hsla.s / 100 + , l = hsla.l / 100 + , a = hsla.a; + + var m2 = l <= .5 ? l * (s + 1) : l + s - l * s + , m1 = l * 2 - m2; + + var r = hue(h + 1/3) * 0xff + , g = hue(h) * 0xff + , b = hue(h - 1/3) * 0xff; + + function hue(h) { + if (h < 0) ++h; + if (h > 1) --h; + if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; + if (h * 2 < 1) return m2; + if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; + return m1; + } + + return new RGBA(r,g,b,a); +}; + +/** + * Clamp `n` >= 0 and <= 255. + * + * @param {Number} n + * @return {Number} + * @api private + */ + +function clamp(n) { + return Math.max(0, Math.min(n.toFixed(0), 255)); +} + +/** + * Clamp alpha `n` >= 0 and <= 1. + * + * @param {Number} n + * @return {Number} + * @api private + */ + +function clampAlpha(n) { + return Math.max(0, Math.min(n, 1)); +} diff --git a/node_modules/jade/support/stylus/lib/nodes/root.js b/node_modules/jade/support/stylus/lib/nodes/root.js new file mode 100644 index 0000000..d5e14c5 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/root.js @@ -0,0 +1,50 @@ + +/*! + * Stylus - Root + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Root` node. + * + * @api public + */ + +var Root = module.exports = function Root(){ + this.nodes = []; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Root.prototype.__proto__ = Node.prototype; + +/** + * Push a `node` to this block. + * + * @param {Node} node + * @api public + */ + +Root.prototype.push = function(node){ + this.nodes.push(node); +}; + +/** + * Return "root". + * + * @return {String} + * @api public + */ + +Root.prototype.toString = function(){ + return '[Root]'; +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/selector.js b/node_modules/jade/support/stylus/lib/nodes/selector.js new file mode 100644 index 0000000..c7d308f --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/selector.js @@ -0,0 +1,55 @@ + +/*! + * Stylus - Selector + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Block = require('./block') + , Node = require('./node'); + +/** + * Initialize a new `Selector` with the given `val`. + * + * @param {String} val + * @api public + */ + +var Selector = module.exports = function Selector(val){ + Node.call(this); + this.val = val.replace(/ +$/, ''); +}; + +/** + * Inherit from `Node.prototype`. + */ + +Selector.prototype.__proto__ = Node.prototype; + +/** + * Return the selector string. + * + * @return {String} + * @api public + */ + +Selector.prototype.toString = function(){ + return this.val; +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Selector.prototype.clone = function(){ + var clone = new Selector(this.val); + clone.lineno = this.lineno; + return clone; +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/string.js b/node_modules/jade/support/stylus/lib/nodes/string.js new file mode 100644 index 0000000..2e9e6e6 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/string.js @@ -0,0 +1,101 @@ + +/*! + * Stylus - String + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `String` with the given `val`. + * + * @param {String} val + * @api public + */ + +var String = module.exports = function String(val){ + Node.call(this); + this.val = val; + this.string = val; +}; + +/** + * Inherit from `Node.prototype`. + */ + +String.prototype.__proto__ = Node.prototype; + +/** + * Return quoted string. + * + * @return {String} + * @api public + */ + +String.prototype.toString = function(){ + return '"' + this.val + '"'; +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +String.prototype.clone = function(){ + var clone = new String(this.val); + clone.lineno = this.lineno; + return clone; +}; + +/** + * Return Boolean based on the length of this string. + * + * @return {Boolean} + * @api public + */ + +String.prototype.toBoolean = function(){ + return nodes.Boolean(this.val.length); +}; + +/** + * Coerce `other` to a string. + * + * @param {Node} other + * @return {String} + * @api public + */ + +String.prototype.coerce = function(other){ + if (other instanceof String) { + return other; + } else { + return new String(other.toString()); + } +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +String.prototype.operate = function(op, right){ + switch (op) { + case '+': + return new String(this.val + right.val); + default: + return Node.prototype.operate.call(this, op, right); + } +}; diff --git a/node_modules/jade/support/stylus/lib/nodes/ternary.js b/node_modules/jade/support/stylus/lib/nodes/ternary.js new file mode 100644 index 0000000..f82157e --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/ternary.js @@ -0,0 +1,50 @@ + +/*! + * Stylus - Ternary + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Ternary` with `cond`, `trueExpr` and `falseExpr`. + * + * @param {Expression} cond + * @param {Expression} trueExpr + * @param {Expression} falseExpr + * @api public + */ + +var Ternary = module.exports = function Ternary(cond, trueExpr, falseExpr){ + Node.call(this); + this.cond = cond; + this.trueExpr = trueExpr; + this.falseExpr = falseExpr; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Ternary.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Ternary.prototype.clone = function(){ + var clone = new Ternary( + this.cond.clone() + , this.trueExpr.clone() + , this.falseExpr.clone()); + clone.lineno = this.lineno; + return clone; +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/nodes/unaryop.js b/node_modules/jade/support/stylus/lib/nodes/unaryop.js new file mode 100644 index 0000000..a409fc6 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/unaryop.js @@ -0,0 +1,45 @@ + +/*! + * Stylus - UnaryOp + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `UnaryOp` with `op`, and `expr`. + * + * @param {String} op + * @param {Node} expr + * @api public + */ + +var UnaryOp = module.exports = function UnaryOp(op, expr){ + Node.call(this); + this.op = op; + this.expr = expr; +}; + +/** + * Inherit from `Node.prototype`. + */ + +UnaryOp.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +UnaryOp.prototype.clone = function(){ + var clone = new UnaryOp(this.op, this.expr.clone()); + clone.lineno = this.lineno; + return clone; +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/nodes/unit.js b/node_modules/jade/support/stylus/lib/nodes/unit.js new file mode 100644 index 0000000..5e4e342 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/nodes/unit.js @@ -0,0 +1,188 @@ + +/*! + * Stylus - Unit + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Unit` with the given `val` and unit `type` + * such as "px", "pt", "in", etc. + * + * @param {String} val + * @param {String} type + * @api public + */ + +var Unit = module.exports = function Unit(val, type){ + Node.call(this); + this.val = val; + this.type = type; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Unit.prototype.__proto__ = Node.prototype; + +/** + * Return Boolean based on the unit value. + * + * @return {Boolean} + * @api public + */ + +Unit.prototype.toBoolean = function(){ + return nodes.Boolean(this.type + ? true + : this.val); +}; + +/** + * Return unit string. + * + * @return {String} + * @api public + */ + +Unit.prototype.toString = function(){ + var n = this.val; + if ('px' == this.type) n = n.toFixed(0); + return n + (this.type || ''); +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Unit.prototype.clone = function(){ + var clone = new Unit(this.val, this.type); + clone.lineno = this.lineno; + return clone; +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +Unit.prototype.operate = function(op, right){ + switch (op) { + case '-': + return new Unit(this.val - right.val, this.type); + case '+': + return new Unit(this.val + right.val, this.type); + case '/': + return new Unit(this.val / right.val, this.type); + case '*': + return new Unit(this.val * right.val, this.type); + case '%': + return new Unit(this.val % right.val, this.type); + case '**': + return new Unit(Math.pow(this.val, right.val), this.type); + case '..': + case '...': + var start = this.val + , end = right.val + , expr = new nodes.Expression + , inclusive = '..' == op; + do { + expr.push(new nodes.Unit(start)); + } while (inclusive ? ++start <= end : ++start < end); + return expr; + default: + return Node.prototype.operate.call(this, op, right); + } +}; + +/** + * Coerce `other` unit to the same type as `this` unit. + * + * Supports: + * + * mm -> cm | in + * cm -> mm | in + * in -> mm | cm + * + * ms -> s + * s -> ms + * + * Hz -> kHz + * kHz -> Hz + * + * @param {Unit} other + * @return {Unit} + * @api public + */ + +Unit.prototype.coerce = function(other){ + if (other instanceof Unit) { + var a = this + , b = other; + switch (a.type) { + case 'mm': + switch (b.type) { + case 'cm': + return new nodes.Unit(b.val * 2.54, 'mm'); + case 'in': + return new nodes.Unit(b.val * 25.4, 'mm'); + } + case 'cm': + switch (b.type) { + case 'mm': + return new nodes.Unit(b.val / 10, 'cm'); + case 'in': + return new nodes.Unit(b.val * 2.54, 'cm'); + } + case 'in': + switch (b.type) { + case 'mm': + return new nodes.Unit(b.val / 25.4, 'in'); + case 'cm': + return new nodes.Unit(b.val / 2.54, 'in'); + } + case 'ms': + switch (b.type) { + case 's': + return new nodes.Unit(b.val * 1000, 'ms'); + } + case 's': + switch (b.type) { + case 'ms': + return new nodes.Unit(b.val / 1000, 's'); + } + case 'Hz': + switch (b.type) { + case 'kHz': + return new nodes.Unit(b.val * 1000, 'Hz'); + } + case 'kHz': + switch (b.type) { + case 'Hz': + return new nodes.Unit(b.val / 1000, 'kHz'); + } + } + return new nodes.Unit(b.val, a.type); + } else if (other instanceof nodes.String) { + var val = parseInt(other.val, 10); + if (isNaN(val)) Node.prototype.coerce.call(this, other); + return new nodes.Unit(val); + } else { + return Node.prototype.coerce.call(this, other); + } +}; diff --git a/node_modules/jade/support/stylus/lib/parser.js b/node_modules/jade/support/stylus/lib/parser.js new file mode 100644 index 0000000..73ec075 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/parser.js @@ -0,0 +1,1360 @@ + +/*! + * Stylus - Parser + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Lexer = require('./lexer') + , nodes = require('./nodes') + , inspect = require('sys').inspect; + +/** + * Selector composite tokens. + */ + +var selectorTokens = [ + 'ident' + , 'string' + , 'selector' + , 'function' + , 'comment' + , 'space' + , 'color' + , 'unit' + , 'for' + , '[' + , ']' + , '(' + , ')' + , '+' + , '-' + , '*' + , '*=' + , '<' + , '>' + , '=' + , ':' + , '&' + , '~' +]; + +/** + * CSS3 pseudo-selectors. + */ + +var pseudoSelectors = [ + 'root' + , 'nth-child' + , 'nth-last-child' + , 'nth-of-type' + , 'nth-last-of-type' + , 'first-child' + , 'last-child' + , 'first-of-type' + , 'last-of-type' + , 'only-child' + , 'only-of-type' + , 'empty' + , 'link' + , 'visited' + , 'active' + , 'hover' + , 'focus' + , 'target' + , 'lang' + , 'enabled' + , 'disabled' + , 'checked' + , 'not' +]; + +/** + * Initialize a new `Parser` with the given `str` and `options`. + * + * @param {String} str + * @param {Object} options + * @api private + */ + +var Parser = module.exports = function Parser(str, options) { + var self = this; + options = options || {}; + this.str = nodes.source = str; + this.lexer = new Lexer(str, options); + this.root = options.root || new nodes.Root; + this.state = ['root']; + this.state.pop = function(){ + self.prevState = [].pop.call(this); + }; +}; + +/** + * Parser prototype. + */ + +Parser.prototype = { + + /** + * Constructor. + */ + + constructor: Parser, + + /** + * Return current state. + * + * @return {String} + * @api private + */ + + currentState: function() { + return this.state[this.state.length - 1]; + }, + + /** + * Parse the input, then return the root node. + * + * @return {Node} + * @api private + */ + + parse: function(){ + var block = this.parent = this.root; + while ('eos' != this.peek().type) { + if (this.accept('newline')) continue; + var stmt = this.statement(); + this.accept(';'); + if (!stmt) this.error('unexpected token {peek}, not allowed at the root level'); + block.push(stmt); + } + return block; + }, + + /** + * Throw an `Error` with the given `msg`. + * + * @param {String} msg + * @api private + */ + + error: function(msg){ + var type = this.peek().type + , val = undefined == this.peek().val + ? '' + : ' ' + this.peek().toString(); + if (val.trim() == type.trim()) val = ''; + throw new Error(msg.replace('{peek}', type + val)); + }, + + /** + * Accept the given token `type`, and return it, + * otherwise return `undefined`. + * + * @param {String} type + * @return {Token} + * @api private + */ + + accept: function(type){ + if (type == this.peek().type) { + return this.next(); + } + }, + + /** + * Expect token `type` and return it, throw otherwise. + * + * @param {String} type + * @return {Token} + * @api private + */ + + expect: function(type){ + if (type != this.peek().type) { + throw new Error('expected ' + type + ', got ' + this.peek()); + } + return this.next(); + }, + + /** + * Get the next token. + * + * @return {Token} + * @api private + */ + + next: function() { + var tok = this.lexer.next(); + nodes.lineno = tok.lineno; + return tok; + }, + + /** + * Peek with lookahead(1). + * + * @return {Token} + * @api private + */ + + peek: function() { + return this.lexer.peek(); + }, + + /** + * Lookahead `n` tokens. + * + * @param {Number} n + * @return {Token} + * @api private + */ + + lookahead: function(n){ + return this.lexer.lookahead(n); + }, + + /** + * Check if the token at `n` is a valid selector token. + * + * @param {Number} n + * @return {Boolean} + * @api private + */ + + isSelectorToken: function(n) { + var la = this.lookahead(n).type; + switch (la) { + case 'for': + return this.bracketed; + case '[': + this.bracketed = true; + return true; + case ']': + this.bracketed = false; + return true; + default: + return ~selectorTokens.indexOf(la); + } + }, + + /** + * Check if the token at `n` is a pseudo selector. + * + * @param {Number} n + * @return {Boolean} + * @api private + */ + + isPseudoSelector: function(n){ + return ~pseudoSelectors.indexOf(this.lookahead(n).val.name); + }, + + /** + * Valid selector tokens. + */ + + selectorToken: function() { + if (this.isSelectorToken(1)) return this.next(); + }, + + /** + * Consume whitespace. + */ + + skipWhitespace: function() { + while (~['space', 'indent', 'outdent', 'newline'].indexOf(this.peek().type)) + this.next(); + }, + + /** + * Consume spaces. + */ + + skipSpaces: function() { + while ('space' == this.peek().type) + this.next(); + }, + + /** + * Check if the following sequence of tokens + * forms a function definition, ie trailing + * `{` or indentation. + */ + + looksLikeFunctionDefinition: function(i) { + return 'indent' == this.lookahead(i).type + || '{' == this.lookahead(i).type; + }, + + /** + * Check if the following sequence of tokens + * forms a selector. + */ + + looksLikeSelector: function() { + var i = 1; + + // Assume selector when an ident is + // followed by a selector + while ('ident' == this.lookahead(i).type + && 'newline' == this.lookahead(i + 1).type) i += 2; + + // Assume pseudo selectors are NOT properties + // as 'td:th-child(1)' may look like a property + // and function call to the parser otherwise + while (this.isSelectorToken(i)) { + if (':' == this.lookahead(i++).type + && this.isPseudoSelector(i)) + return true; + } + + // Trailing comma + if (',' == this.lookahead(i).type + && 'newline' == this.lookahead(i + 1).type) + return true; + + // Trailing brace + if ('{' == this.lookahead(i).type + && 'newline' == this.lookahead(i + 1).type) + return true; + + // css-style mode, false on ; } + if (this.css) { + if (';' == this.lookahead(i) || + '}' == this.lookahead(i)) + return false; + } + + // Trailing separators + while (!~[ + 'newline' + , 'indent' + , 'outdent' + , 'for' + , 'if' + , ';' + , '}'].indexOf(this.lookahead(i).type)) + ++i; + + if ('indent' == this.lookahead(i).type) + return true; + }, + + /** + * statement + * | statement 'if' expression + * | statement 'unless' expression + */ + + statement: function() { + var stmt = this.stmt() + , state = this.prevState + , block + , op; + + // special-case statements since it + // is not an expression. We could + // implement postfix conditionals at + // the expression level, however they + // would then fail to enclose properties + if (this.allowPostfix) { + delete this.allowPostfix; + state = 'expression'; + } + + switch (state) { + case 'assignment': + case 'expression': + case 'function arguments': + while (op = + this.accept('if') + || this.accept('unless') + || this.accept('for')) { + switch (op.type) { + case 'if': + case 'unless': + stmt = new nodes.If(this.expression(), stmt); + stmt.postfix = true; + stmt.negate = 'unless' == op.type; + this.accept(';'); + break; + case 'for': + var key + , val = this.id().name; + if (this.accept(',')) key = this.id().name; + this.expect('in'); + var each = new nodes.Each(val, key, this.expression()); + block = new nodes.Block; + block.push(stmt); + each.block = block; + stmt = each; + } + } + } + + return stmt; + }, + + /** + * ident + * | selector + * | literal + * | charset + * | import + * | media + * | keyframes + * | page + * | for + * | if + * | unless + * | expression + * | 'return' expression + */ + + stmt: function() { + var type = this.peek().type; + switch (type) { + case 'selector': + case 'literal': + case 'keyframes': + case 'charset': + case 'import': + case 'media': + case 'page': + case 'ident': + case 'unless': + case 'function': + case 'for': + case 'if': + return this[type](); + case 'return': + return this.return(); + case '{': + return this.property(); + default: + // Contextual selectors + switch (this.currentState()) { + case 'root': + case 'selector': + case 'conditional': + case 'keyframe': + case 'function': + case 'media': + case 'for': + switch (type) { + case 'color': + case '~': + case '+': + case '>': + case '<': + case '*': + case ':': + case '&': + case '[': + return this.selector(); + } + } + + // Expression fallback + var expr = this.expression(); + if (expr.isEmpty) this.error('unexpected {peek}'); + return expr; + } + }, + + /** + * indent (!outdent)+ outdent + */ + + block: function(node, scope) { + var delim + , stmt + , _ = this.css + , block = this.parent = new nodes.Block(this.parent, node); + + if (false === scope) block.scope = false; + + // css-style + if (this.css = this.accept('{')) { + delim = '}'; + this.skipWhitespace(); + } else { + delim = 'outdent'; + this.expect('indent'); + } + + while (delim != this.peek().type) { + // css-style + if (this.css) { + if (this.accept('newline')) continue; + stmt = this.statement(); + this.accept(';'); + this.skipWhitespace(); + } else { + if (this.accept('newline')) continue; + stmt = this.statement(); + this.accept(';'); + } + if (!stmt) this.error('unexpected token {peek} in block'); + block.push(stmt); + } + + // css-style + if (this.css) { + this.skipWhitespace(); + this.expect('}'); + this.skipSpaces(); + this.css = _; + } else { + this.expect('outdent'); + } + + this.parent = block.parent; + return block; + }, + + /** + * for val (',' key) in expr + */ + + for: function() { + this.expect('for'); + var key + , val = this.id().name; + if (this.accept(',')) key = this.id().name; + this.expect('in'); + var each = new nodes.Each(val, key, this.expression()); + this.state.push('for'); + each.block = this.block(each, false); + this.state.pop(); + return each; + }, + + /** + * return expression + */ + + return: function() { + this.expect('return'); + var expr = this.expression(); + return expr.isEmpty + ? new nodes.Return + : new nodes.Return(expr); + }, + + /** + * unless expression block + */ + + unless: function() { + this.expect('unless'); + var node = new nodes.If(this.expression(), true); + this.state.push('conditional'); + node.block = this.block(node, false); + this.state.pop(); + return node; + }, + + /** + * if expression block (else block)? + */ + + if: function() { + this.expect('if'); + var node = new nodes.If(this.expression()); + this.state.push('conditional'); + node.block = this.block(node, false); + while (this.accept('else')) { + if (this.accept('if')) { + var cond = this.expression() + , block = this.block(node, false); + node.elses.push(new nodes.If(cond, block)); + } else { + node.elses.push(this.block(node, false)); + break; + } + } + this.state.pop(); + return node; + }, + + /** + * media + */ + + media: function() { + var val = this.expect('media').val + , media = new nodes.Media(val); + this.state.push('media'); + media.block = this.block(media); + this.state.pop(); + return media; + }, + + /** + * import expression + */ + + import: function() { + this.expect('import'); + this.allowPostfix = true; + return new nodes.Import(this.expression()); + }, + + /** + * charset string + */ + + charset: function() { + this.expect('charset'); + var str = this.expect('string').val; + this.allowPostfix = true; + return new nodes.Charset(str); + }, + + /** + * page selector? block + */ + + page: function() { + var selector; + this.expect('page'); + if (this.accept(':')) { + var str = this.expect('ident').val.name; + selector = new nodes.Literal(':' + str); + } + var page = new nodes.Page(selector); + this.state.push('page'); + page.block = this.block(page); + this.state.pop(); + return page; + }, + + /** + * keyframes name ((unit | from | to) block)+ + */ + + keyframes: function() { + this.expect('keyframes'); + var pos + , _ = this.css + , keyframes = new nodes.Keyframes(this.id()); + + // css-sty;e + if (this.css = this.accept('{')) { + this.skipWhitespace(); + } else { + this.expect('indent'); + } + + while (pos = this.accept('unit') || this.accept('ident')) { + // from | to + if ('ident' == pos.type) { + this.accept('space'); + switch (pos.val.name) { + case 'from': + pos = new nodes.Unit(0, '%'); + break; + case 'to': + pos = new nodes.Unit(100, '%'); + break; + default: + throw new Error('invalid ident "' + pos.val.name + '" in selector'); + } + } else { + pos = pos.val; + } + + // block + this.state.push('keyframe'); + var block = this.block(keyframes); + keyframes.push(pos, block); + this.state.pop(); + if (this.css) this.skipWhitespace(); + } + + // css-style + if (this.css) { + this.skipWhitespace(); + this.expect('}'); + this.css = _; + } else { + this.expect('outdent'); + } + + return keyframes; + }, + + /** + * literal + */ + + literal: function() { + return this.expect('literal').val; + }, + + /** + * ident space? + */ + + id: function() { + var tok = this.expect('ident'); + this.accept('space'); + return tok.val; + }, + + /** + * ident + * | assignment + * | property + * | selector + */ + + ident: function() { + var i = 2 + , la = this.lookahead(i).type; + + while ('space' == la) la = this.lookahead(++i).type; + + switch (la) { + // Assignment + case '=': + case '?=': + case '-=': + case '+=': + case '*=': + case '/=': + case '%=': + return this.assignment(); + // Operation + case '-': + case '+': + case '/': + case '*': + case '%': + case '**': + case 'and': + case 'or': + case '&&': + case '||': + case '>': + case '<': + case '>=': + case '<=': + case '!=': + case '==': + case '[': + case '?': + case 'in': + case 'is a': + case 'is defined': + // Prevent cyclic .ident, return literal + if (this._ident == this.peek()) { + return this.id(); + } else { + this._ident = this.peek(); + switch (this.currentState()) { + // unary op or selector in property / for + case 'for': + case 'selector': + return this.property(); + // Part of a selector + case 'root': + return this.selector(); + // Do not disrupt the ident when an operand + default: + return this.operand + ? this.id() + : this.expression(); + } + } + // Selector or property + default: + switch (this.currentState()) { + case 'root': + return this.selector(); + case 'for': + case 'page': + case 'media': + case 'selector': + case 'function': + case 'keyframe': + case 'conditional': + return this.property(); + default: + return this.id(); + } + } + }, + + /** + * (ident | '{' expression '}')+ + */ + + interpolate: function() { + var node + , segs = []; + while (true) { + if (this.accept('{')) { + this.state.push('interpolation'); + segs.push(this.expression()); + this.expect('}'); + this.state.pop(); + } else if (node = this.accept('ident')){ + segs.push(node.val); + } else { + break; + } + } + if (!segs.length) this.expect('ident'); + return segs; + }, + + /** + * property ':'? expression + * | ident + */ + + property: function() { + if (this.looksLikeSelector()) return this.selector(); + + // property + var ident = this.interpolate() + , ret = prop = new nodes.Property(ident); + + // optional ':' + this.accept('space'); + if (this.accept(':')) this.accept('space'); + + this.state.push('property'); + this.inProperty = true; + prop.expr = this.list(); + if (prop.expr.isEmpty) ret = ident[0]; + this.inProperty = false; + this.allowPostfix = true; + this.state.pop(); + + // optional ';' + this.accept(';'); + + return ret; + }, + + /** + * selector ',' selector + * | selector newline selector + * | selector block + */ + + selector: function() { + var tok + , arr + , val + , prev + , parent + , group = new nodes.Group; + + // Allow comments in selectors + // for hacks + this.lexer.allowComments = true; + + do { + val = prev = null; + arr = []; + + // Clobber newline after , + this.accept('newline'); + + // Selector candidates, + // stitched together to + // form a selector. + while (tok = this.selectorToken()) { + // Selector component + switch (tok.type) { + case 'unit': val = tok.val.val; break; + case 'ident': val = tok.val.name; break; + case 'function': val = tok.val.name + '('; break; + case 'string': val = tok.val.toString(); break; + case 'color': val = tok.val.raw; break; + case 'space': val = ' '; break; + default: val = tok.val; + } + + // Whitespace support + if (!prev || prev.space) { + arr.push(val); + } else { + arr[arr.length-1] += val; + } + prev = tok; + } + + // Push the selector + group.push(new nodes.Selector(arr.join(' '), parent)); + } while (this.accept(',') || this.accept('newline')); + + this.lexer.allowComments = false; + this.state.push('selector'); + group.block = this.block(group); + this.state.pop(); + + + return group; + }, + + /** + * ident ('=' | '?=') expression + */ + + assignment: function() { + var op + , node + , name = this.id().name; + + if (op = + this.accept('=') + || this.accept('?=') + || this.accept('+=') + || this.accept('-=') + || this.accept('*=') + || this.accept('/=') + || this.accept('%=')) { + this.state.push('assignment'); + var expr = this.list(); + if (expr.isEmpty) this.error('invalid right-hand side operand in assignment, got {peek}') + node = new nodes.Ident(name, expr); + this.state.pop(); + + switch (op.type) { + case '?=': + var defined = new nodes.BinOp('is defined', node) + , lookup = new nodes.Ident(name); + node = new nodes.Ternary(defined, lookup, node); + break; + case '+=': + case '-=': + case '*=': + case '/=': + case '%=': + node.val = new nodes.BinOp(op.type[0], new nodes.Ident(name), expr); + break; + } + } + + return node; + }, + + /** + * definition + * | call + */ + + function: function() { + var parens = 1 + , i = 2 + , tok; + + // Lookahead and determine if we are dealing + // with a function call or definition. Here + // we pair parens to prevent false negatives + out: + while (tok = this.lookahead(i++)) { + switch (tok.type) { + case 'function': case '(': ++parens; break; + case ')': if (!--parens) break out; + } + } + + // Definition or call + switch (this.currentState()) { + case 'expression': + return this.functionCall(); + default: + return this.looksLikeFunctionDefinition(i) + ? this.functionDefinition() + : this.expression(); + } + }, + + /** + * url '(' (expression | urlchars)+ ')' + */ + + url: function() { + this.expect('function'); + this.state.push('function arguments'); + var args = this.args(); + this.expect(')'); + this.state.pop(); + return new nodes.Call('url', args); + }, + + /** + * ident '(' expression ')' + */ + + functionCall: function() { + if ('url' == this.peek().val.name) return this.url(); + var name = this.expect('function').val.name; + this.state.push('function arguments'); + var args = this.args(); + this.expect(')'); + this.state.pop(); + return new nodes.Call(name, args); + }, + + /** + * ident '(' params ')' block + */ + + functionDefinition: function() { + var name = this.expect('function').val.name; + + // params + this.state.push('function params'); + this.skipWhitespace(); + var params = this.params(); + this.skipWhitespace(); + this.expect(')'); + this.state.pop(); + + // Body + this.state.push('function'); + var fn = new nodes.Function(name, params); + fn.block = this.block(fn); + this.state.pop(); + return new nodes.Ident(name, fn); + }, + + /** + * ident + * | ident '...' + * | ident '=' expression + * | ident ',' ident + */ + + params: function() { + var tok + , node + , params = new nodes.Params; + while (tok = this.accept('ident')) { + this.accept('space'); + params.push(node = tok.val); + if (this.accept('...')) { + node.rest = true; + } else if (this.accept('=')) { + node.val = this.expression(); + } + this.skipWhitespace(); + this.accept(','); + this.skipWhitespace(); + } + return params; + }, + + /** + * expression (',' expression)* + */ + + args: function() { + var args = new nodes.Expression; + do { + args.push(this.expression()); + } while (this.accept(',')); + return args; + }, + + /** + * expression (',' expression)* + */ + + list: function() { + var node = this.expression(); + while (this.accept(',')) { + if (node.isList) { + list.push(this.expression()); + } else { + var list = new nodes.Expression(true); + list.push(node); + list.push(this.expression()); + node = list; + } + } + return node; + }, + + /** + * negation+ + */ + + expression: function() { + var node + , expr = new nodes.Expression; + this.state.push('expression'); + while (node = this.negation()) { + if (!node) this.error('unexpected token {peek} in expression'); + expr.push(node); + } + this.state.pop(); + return expr; + }, + + /** + * 'not' ternary + * | ternary + */ + + negation: function() { + if (this.accept('not')) { + return new nodes.UnaryOp('!', this.negation()); + } + return this.ternary(); + }, + + /** + * logical ('?' expression ':' expression)? + */ + + ternary: function() { + var node = this.logical(); + if (this.accept('?')) { + var trueExpr = this.expression(); + this.expect(':'); + var falseExpr = this.expression(); + node = new nodes.Ternary(node, trueExpr, falseExpr); + } + return node; + }, + + /** + * typecheck (('&&' | '||') typecheck)* + */ + + logical: function() { + var op + , node = this.typecheck(); + while (op = this.accept('&&') || this.accept('||')) { + node = new nodes.BinOp(op.type, node, this.typecheck()); + } + return node; + }, + + /** + * equality ('is a' equality)* + */ + + typecheck: function() { + var op + , node = this.equality(); + while (op = this.accept('is a')) { + this.operand = true; + if (!node) throw new Error('illegal unary ' + op); + node = new nodes.BinOp(op.type, node, this.equality()); + this.operand = false; + } + return node; + }, + + /** + * in (('==' | '!=') in)* + */ + + equality: function() { + var op + , node = this.in(); + while (op = this.accept('==') || this.accept('!=')) { + this.operand = true; + if (!node) throw new Error('illegal unary ' + op); + node = new nodes.BinOp(op.type, node, this.in()); + this.operand = false; + } + return node; + }, + + /** + * relational ('in' relational)* + */ + + in: function() { + var node = this.relational(); + while (this.accept('in')) { + this.operand = true; + if (!node) throw new Error('illegal unary in'); + node = new nodes.BinOp('in', node, this.relational()); + this.operand = false; + } + return node; + }, + + /** + * range (('>=' | '<=' | '>' | '<') range)* + */ + + relational: function() { + var op + , node = this.range(); + while (op = + this.accept('>=') + || this.accept('<=') + || this.accept('<') + || this.accept('>') + ) { + this.operand = true; + if (!node) throw new Error('illegal unary ' + op); + node = new nodes.BinOp(op.type, node, this.range()); + this.operand = false; + } + return node; + }, + + /** + * additive (('..' | '...') additive)* + */ + + range: function() { + var op + , node = this.additive(); + if (op = this.accept('...') || this.accept('..')) { + this.operand = true; + if (!node) throw new Error('illegal unary ' + op); + node = new nodes.BinOp(op.val, node, this.additive()); + this.operand = false; + } + return node; + }, + + /** + * multiplicative (('+' | '-') multiplicative)* + */ + + additive: function() { + var op + , node = this.multiplicative(); + while (op = this.accept('+') || this.accept('-')) { + this.operand = true; + node = new nodes.BinOp(op.type, node, this.multiplicative()); + this.operand = false; + } + return node; + }, + + /** + * defined (('**' | '*' | '/' | '%') defined)* + */ + + multiplicative: function() { + var op + , node = this.defined(); + while (op = + this.accept('**') + || this.accept('*') + || this.accept('/') + || this.accept('%')) { + this.operand = true; + if ('/' == op && this.inProperty && !this.parens) { + var expr = new nodes.Expression; + expr.push(node); + expr.push(new nodes.Literal('/')); + return expr; + } else { + if (!node) throw new Error('illegal unary ' + op); + node = new nodes.BinOp(op.type, node, this.defined()); + this.operand = false; + } + } + return node; + }, + + /** + * unary 'is defined' + * | unary + */ + + defined: function() { + var node = this.unary(); + if (this.accept('is defined')) { + if (!node) throw new Error('illegal use of "is defined"'); + node = new nodes.BinOp('is defined', node); + } + return node; + }, + + /** + * ('!' | '~' | '+' | '-') unary + * | subscript + */ + + unary: function() { + var op + , node; + if (op = + this.accept('!') + || this.accept('~') + || this.accept('+') + || this.accept('-')) { + this.operand = true; + node = new nodes.UnaryOp(op.type, this.unary()); + this.operand = false; + return node; + } + return this.subscript(); + }, + + /** + * primary ('[' expression ']')+ + * | primary + */ + + subscript: function() { + var node = this.primary(); + while (this.accept('[')) { + node = new nodes.BinOp('[]', node, this.expression()); + this.expect(']'); + } + return node; + }, + + /** + * unit + * | null + * | color + * | string + * | ident + * | boolean + * | literal + * | '(' expression ')' + */ + + primary: function() { + var op + , node; + + // Parenthesis + if (this.accept('(')) { + this.parens = true; + var expr = this.expression(); + this.expect(')'); + this.parens = false; + return expr; + } + + // Primitive + switch (this.peek().type) { + case 'null': + case 'unit': + case 'color': + case 'string': + case 'literal': + case 'boolean': + return this.next().val; + case 'ident': + return this.ident(); + case 'function': + return this.functionCall(); + } + } +}; diff --git a/node_modules/jade/support/stylus/lib/renderer.js b/node_modules/jade/support/stylus/lib/renderer.js new file mode 100644 index 0000000..db98bf7 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/renderer.js @@ -0,0 +1,103 @@ + +/*! + * Stylus - Renderer + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Parser = require('./parser') + , Compiler = require('./visitor/compiler') + , Evaluator = require('./visitor/evaluator') + , utils = require('./utils') + , nodes = require('./nodes'); + +/** + * Initialize a new `Renderer` with the given `str` and `options`. + * + * @param {String} str + * @param {Object} options + * @api public + */ + +var Renderer = module.exports = function Renderer(str, options) { + options = options || {}; + options.functions = {}; + options.imports = [__dirname + '/functions']; + options.filename = options.filename || 'stylus'; + this.str = str; + this.options = options; + this.parser = new Parser(str, options); +}; + +/** + * Parse and evaluate AST, then callback `fn(err, css)`. + * + * @param {Function} fn + * @api public + */ + +Renderer.prototype.render = function(fn){ + try { + var ast = this.parser.parse() + , expr; + this.evaluator = new Evaluator(ast, this.options); + ast = this.evaluator.evaluate(); + new Compiler(ast, this.options).compile(fn); + } catch (err) { + fn(utils.formatException( + this + , err + , this.options)); + } + nodes.source = null; +}; + +/** + * Set option `key` to `val`. + * + * @param {String} key + * @param {Mixed} val + * @return {Renderer} for chaining + * @api public + */ + +Renderer.prototype.set = function(key, val){ + this.options[key] = val; + return this; +}; + +/** + * Define function with the given `name`. Optionally + * the function may accept full expressions, by setting `raw` + * to `true`. + * + * @param {String} name + * @param {Function} fn + * @return {Renderer} for chaining + * @api public + */ + +Renderer.prototype.define = function(name, fn, raw){ + this.options.functions[name] = fn; + if (undefined != raw) fn.raw = raw; + return this; +}; + +/** + * Import the given `file`. + * + * @param {String} file + * @return {Renderer} for chaining + * @api public + */ + +Renderer.prototype.import = function(file){ + this.options.imports.push(file); + return this; +}; + + diff --git a/node_modules/jade/support/stylus/lib/stack/frame.js b/node_modules/jade/support/stylus/lib/stack/frame.js new file mode 100644 index 0000000..580f9cb --- /dev/null +++ b/node_modules/jade/support/stylus/lib/stack/frame.js @@ -0,0 +1,66 @@ + +/*! + * Stylus - stack - Frame + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Scope = require('./scope') + , blocks = require('../nodes'); + +/** + * Initialize a new `Frame` with the given `block`. + * + * @param {Block} block + * @api private + */ + +var Frame = module.exports = function Frame(block) { + this._scope = false === block.scope + ? null + : new Scope; + this.block = block; +}; + +/** + * Return this frame's scope or the parent scope + * for scope-less blocks. + * + * @return {Scope} + * @api public + */ + +Frame.prototype.__defineGetter__('scope', function(){ + return this._scope || this.parent.scope; +}); + +/** + * Lookup the given local variable `name`. + * + * @param {String} name + * @return {Node} + * @api private + */ + +Frame.prototype.lookup = function(name){ + return this.scope.lookup(name) +}; + +/** + * Custom inspect. + * + * @return {String} + * @api public + */ + +Frame.prototype.inspect = function(){ + return '[Frame ' + + (false === this.block.scope + ? 'scope-less' + : this.scope.inspect()) + + ']'; +}; diff --git a/node_modules/jade/support/stylus/lib/stack/index.js b/node_modules/jade/support/stylus/lib/stack/index.js new file mode 100644 index 0000000..fc6fa53 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/stack/index.js @@ -0,0 +1,146 @@ + +/*! + * Stylus - Stack + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Frame = require('./frame'); + +/** + * Initialize a new `Stack`. + * + * @api private + */ + +var Stack = module.exports = function Stack() { + Array.apply(this, arguments); +}; + +/** + * Inherit from `Array.prototype`. + */ + +Stack.prototype.__proto__ = Array.prototype; + +/** + * Push the given `frame`. + * + * @param {Frame} frame + * @api public + */ + +Stack.prototype.push = function(frame){ + frame.stack = this; + frame.parent = this.currentFrame; + return [].push.apply(this, arguments); +}; + +/** + * Return the current stack `Frame`. + * + * @return {Frame} + * @api private + */ + +Stack.prototype.__defineGetter__('currentFrame', function(){ + return this[this.length - 1]; +}); + +/** + * Lookup stack frame for the given `block`. + * + * @param {Block} block + * @return {Frame} + * @api private + */ + +Stack.prototype.getBlockFrame = function(block){ + for (var i = 0; i < this.length; ++i) { + if (block == this[i].block) { + return this[i]; + } + } +}; + +/** + * Lookup the given local variable `name`, relative + * to the lexical scope of the current frame's `Block`. + * + * When the result of a lookup is an identifier + * a recursive lookup is performed, defaulting to + * returning the identifier itself. + * + * @param {String} name + * @return {Node} + * @api private + */ + +Stack.prototype.lookup = function(name){ + var block = this.currentFrame.block + , val + , ret; + + do { + var frame = this.getBlockFrame(block); + if (frame && (val = frame.lookup(name))) { + switch (val.first.nodeName) { + case 'ident': + return this.lookup(val.first.name) || val; + default: + return val; + } + } + } while (block = block.parent); +}; + +/** + * Custom inspect. + * + * @return {String} + * @api private + */ + +Stack.prototype.inspect = function(){ + return this.reverse().map(function(frame){ + return frame.inspect(); + }).join('\n'); +}; + +/** + * Return stack string formatted as: + * + * at (:) + * + * @return {String} + * @api private + */ + +Stack.prototype.toString = function(){ + var block + , node + , buf = [] + , location + , len = this.length; + + while (len--) { + block = this[len].block; + if (node = block.node) { + location = '(' + node.filename + ':' + node.lineno + ')'; + switch (node.nodeName) { + case 'function': + buf.push(' at ' + node.name + '() ' + location); + break; + case 'group': + buf.push(' at "' + node.nodes[0].val + '" ' + location); + break; + } + } + } + + return buf.join('\n'); +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/stack/scope.js b/node_modules/jade/support/stylus/lib/stack/scope.js new file mode 100644 index 0000000..e2dc4da --- /dev/null +++ b/node_modules/jade/support/stylus/lib/stack/scope.js @@ -0,0 +1,53 @@ + +/*! + * Stylus - stack - Scope + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Initialize a new `Scope`. + * + * @api private + */ + +var Scope = module.exports = function Scope() { + this.locals = {}; +}; + +/** + * Add `ident` node to the current scope. + * + * @param {Ident} ident + * @api private + */ + +Scope.prototype.add = function(ident){ + this.locals[ident.name] = ident.val; +}; + +/** + * Lookup the given local variable `name`. + * + * @param {String} name + * @return {Node} + * @api private + */ + +Scope.prototype.lookup = function(name){ + return this.locals[name]; +}; + +/** + * Custom inspect. + * + * @return {String} + * @api public + */ + +Scope.prototype.inspect = function(){ + var keys = Object.keys(this.locals).map(function(key){ return '@' + key; }); + return '[Scope' + + (keys.length ? ' ' + keys.join(', ') : '') + + ']'; +}; diff --git a/node_modules/jade/support/stylus/lib/stylus.js b/node_modules/jade/support/stylus/lib/stylus.js new file mode 100644 index 0000000..8349248 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/stylus.js @@ -0,0 +1,132 @@ + +/*! + * Stylus + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Renderer = require('./renderer') + , nodes = require('./nodes') + , utils = require('./utils'); + +/** + * Export render as the module. + */ + +exports = module.exports = render; + +/** + * Library version. + */ + +exports.version = '0.9.2'; + +/** + * Expose nodes. + */ + +exports.nodes = nodes; + +/** + * Expose BIFs. + */ + +exports.functions = require('./functions'); + +/** + * Expose utils. + */ + +exports.utils = require('./utils'); + +/** + * Expose middleware. + */ + +exports.middleware = require('./middleware'); + +/** + * Expose constructors. + */ + +exports.Parser = require('./parser'); +exports.Evaluator = require('./visitor/evaluator'); + +/** + * Convert the given `css` to `stylus` source. + * + * @param {String} css + * @return {String} + * @api public + */ + +exports.convertCSS = require('./convert/css'); + +/** + * Parse the given `str` with `options` and return the AST. + * + * Examples: + * + * css.parse(str); + * // raw ast comprised of nodes + * + * css.parse(str).toObject(); + * // plain object representation + * + * css.parse(str).toJSON(); + * // JSON representation + * + * @param {String} str + * @param {Object} options + * @return {Object} + * @api public + */ + +exports.parse = function(str, options){ + var renderer = new Renderer(str, options); + try { + return renderer.parser.parse(); + } catch (err) { + throw utils.formatException( + renderer + , err + , options); + } +}; + +/** + * Render the given `str` with `options` and callback `fn(err, css)`. + * + * @param {String} str + * @param {Object|Function} options + * @param {Function} fn + * @api public + */ + +exports.render = function(str, options, fn){ + if ('function' == typeof options) fn = options, options = {}; + new Renderer(str, options).render(fn); +}; + +/** + * Return a new `Renderer` for the given `str` and `options`. + * + * @param {String} str + * @param {Object} options + * @return {Renderer} + * @api public + */ + +function render(str, options) { + return new Renderer(str, options); +} + +/** + * Expose optional functions. + */ + +exports.url = require('./functions/url'); diff --git a/node_modules/jade/support/stylus/lib/token.js b/node_modules/jade/support/stylus/lib/token.js new file mode 100644 index 0000000..80f2a34 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/token.js @@ -0,0 +1,53 @@ + +/*! + * Stylus - Token + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var inspect = require('sys').inspect; + +/** + * Initialize a new `Token` with the given `type` and `val`. + * + * @param {String} type + * @param {Mixed} val + * @api private + */ + +var Token = exports = module.exports = function Token(type, val) { + this.type = type; + this.val = val; +}; + +/** + * Custom inspect. + * + * @return {String} + * @api public + */ + +Token.prototype.inspect = function(){ + var val = ' ' + inspect(this.val); + return '[Token:' + this.lineno + ' ' + + '\x1b[32m' + this.type + '\x1b[0m' + + '\x1b[33m' + (this.val ? val : '') + '\x1b[0m' + + ']'; +}; + +/** + * Return type or val. + * + * @return {String} + * @api public + */ + +Token.prototype.toString = function(){ + return (undefined === this.val + ? this.type + : this.val).toString(); +}; diff --git a/node_modules/jade/support/stylus/lib/utils.js b/node_modules/jade/support/stylus/lib/utils.js new file mode 100644 index 0000000..aa06b31 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/utils.js @@ -0,0 +1,175 @@ + +/*! + * Stylus - utils + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var nodes = require('./nodes') + , inspect = require('sys').inspect + , fs = require('fs'); + +/** + * Attempt to lookup `path` within `paths` from tail to head. + * Optionally a path to `ignore` may be passed. + * + * @param {String} path + * @param {String} paths + * @param {String} ignore + * @return {String} + * @api private + */ + +exports.lookup = function(path, paths, ignore){ + var lookup + , i = paths.length; + + // Absolute + if ('/' == path[0]) { + try { + fs.statSync(path); + return path; + } catch (err) { + // Ignore, continue on + // to trying relative lookup. + // Needed for url(/images/foo.png) + // for example + } + } + + // Relative + while (i--) { + try { + lookup = paths[i] + '/' + path; + if (ignore == lookup) continue; + fs.statSync(lookup); + return lookup; + } catch (err) { + // Ignore + } + } +}; + +/** + * Format the given `err` in context to `renderer`. + * + * @param {Renderer} renderer + * @param {Error} err + * @param {Object} options + * @return {Error} + * @api private + */ + +exports.formatException = function(renderer, err, options){ + var lineno = renderer.evaluator + ? renderer.evaluator.lineno + : renderer.parser.lexer.lineno + , contextLineno = lineno - 2 + , contextLines = options.context || 8 + , lastWidth = (contextLineno + contextLines).toString().length; + + var src = (err.str || renderer.str).split('\n') + .slice(contextLineno, contextLineno + contextLines) + .map(function(line){ + var n = ++contextLineno + , width = n.toString().length + , pad = Array(lastWidth - width + 1).join(' '); + return ' ' + pad + n + ': ' + inspect(line); + }).join('\n'); + + err.message = renderer.options.filename + + ':' + lineno + + '\n' + src + + '\n\n' + err.message + '\n' + + (err.stylusStack ? err.stylusStack + '\n' : ''); + + return err; +}; + +/** + * Assert that `node` is of the given `type`, or throw. + * + * @param {Node} node + * @param {Function} type + * @param {String} param + * @api public + */ + +exports.assertType = function(node, type, param){ + exports.assertPresent(node, param); + if (node instanceof type) return; + var actual = node.constructor.name + , msg = 'expected ' + type.name + ', but got ' + actual + ':' + node; + throw new Error('TypeError: ' + msg); +}; + +/** + * Assert that `node` is a `String` or `Ident`. + * + * @param {Node} node + * @param {String} param + * @api public + */ + +exports.assertString = function(node, param){ + exports.assertPresent(node, param); + if (node instanceof nodes.String) return; + if (node instanceof nodes.Ident) return; + var actual = node.constructor.name + , msg = 'expected String or Ident, but got ' + actual + ':' + node; + throw new Error('TypeError: ' + msg); +}; + +/** + * Assert that `node` is a `RGBA` or `HSLA`. + * + * @param {Node} node + * @param {String} param + * @api public + */ + +exports.assertColor = function(node, param){ + exports.assertPresent(node, param); + if (node instanceof nodes.RGBA) return; + if (node instanceof nodes.HSLA) return; + var actual = node.constructor.name + , msg = 'expected RGBA or HSLA, but got ' + actual + ':' + node; + throw new Error('TypeError: ' + msg); +}; + +/** + * Assert that param `name` is given, aka the `node` is passed. + * + * @param {Node} node + * @param {String} name + * @api public + */ + +exports.assertPresent = function(node, name){ + if (node) return; + if (name) throw new Error('ArgumentError: argument ' + name + ' required'); + throw new Error('ArgumentError: argument missing'); +}; + +/** + * Unwrap `expr`. + * + * Takes an expressions with length of 1 + * such as `((1 2 3))` and unwraps it to `(1 2 3)`. + * + * @param {Expression} expr + * @return {Node} + * @api public + */ + +exports.unwrap = function(expr){ + if (expr.preserve) return expr; + if ('expression' != expr.nodeName) return expr; + if (1 != expr.nodes.length) return expr; + if ('expression' != expr.nodes[0].nodeName) return expr; + return exports.unwrap(expr.nodes[0]); +}; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/lib/visitor/compiler.js b/node_modules/jade/support/stylus/lib/visitor/compiler.js new file mode 100644 index 0000000..f39ee04 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/visitor/compiler.js @@ -0,0 +1,370 @@ + +/*! + * Stylus - Compiler + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Visitor = require('./') + , nodes = require('../nodes'); + +/** + * Initialize a new `Compiler` with the given `root` Node + * and the following `options`. + * + * Options: + * + * - `compress` Compress the css output, defaults to false + * + * @param {Node} root + * @api public + */ + +var Compiler = module.exports = function Compiler(root, options) { + options = options || {}; + this.compress = options.compress; + this.indents = 1; + Visitor.call(this, root); + this.tree = []; +}; + +/** + * Inherit from `Visitor.prototype`. + */ + +Compiler.prototype.__proto__ = Visitor.prototype; + +/** + * Compile to css, and callback `fn(err, css)`. + * + * @param {Function} fn + * @api public + */ + +Compiler.prototype.compile = function(fn){ + this.callback = fn; + this.css = this.visit(this.root); + fn(null, this.css); +}; + +/** + * Return indentation string. + * + * @return {String} + * @api private + */ + +Compiler.prototype.__defineGetter__('indent', function(){ + return this.compress + ? '' + : new Array(this.indents).join(' '); +}); + +/** + * Visit Root. + */ + +Compiler.prototype.visitRoot = function(block){ + this.buf = ''; + for (var i = 0, len = block.nodes.length; i < len; ++i) { + var node = block.nodes[i]; + if (node instanceof nodes.Null + || node instanceof nodes.Expression + || node instanceof nodes.Function + || node instanceof nodes.Unit) continue; + var ret = this.visit(node); + if (ret) this.buf += ret + '\n'; + } + return this.buf; +}; + +/** + * Visit Block. + */ + +Compiler.prototype.visitBlock = function(block){ + if (block.hasProperties) { + var arr = [this.compress ? '{' : ' {']; + ++this.indents; + for (var i = 0, len = block.nodes.length; i < len; ++i) { + this.last = len - 1 == i; + var node = block.nodes[i]; + if (node instanceof nodes.Null + || node instanceof nodes.Expression + || node instanceof nodes.Function + || node instanceof nodes.Group + || node instanceof nodes.Unit) continue; + arr.push(this.visit(node)); + } + --this.indents; + arr.push(this.indent + '}'); + this.buf += arr.join(this.compress ? '' : '\n'); + this.buf += '\n'; + } + + // Nesting + for (var i = 0, len = block.nodes.length; i < len; ++i) { + this.visit(block.nodes[i]); + } +}; + +/** + * Visit Keyframes. + */ + +Compiler.prototype.visitKeyframes = function(node){ + this.buf += '@-webkit-keyframes ' + + this.visit(node.name) + + (this.compress ? '{' : ' {'); + ++this.indents; + node.frames.forEach(function(frame){ + if (!this.compress) this.buf += '\n '; + this.buf += this.visit(frame.pos); + this.visit(frame.block); + }, this); + --this.indents; + this.buf += '}' + (this.compress ? '' : '\n'); +}; + +/** + * Visit Media. + */ + +Compiler.prototype.visitMedia = function(media){ + this.buf += '@media ' + media.val; + this.buf += this.compress ? '{' : ' {\n'; + ++this.indents; + this.visit(media.block); + --this.indents; + this.buf += '}' + (this.compress ? '' : '\n'); +}; + +/** + * Visit Page. + */ + +Compiler.prototype.visitPage = function(page){ + this.buf += this.indent + '@page'; + this.buf += page.selector ? ' ' + page.selector : ''; + this.visit(page.block); +}; + +/** + * Visit Function. + */ + +Compiler.prototype.visitFunction = function(fn){ + return fn.name; +}; + +/** + * Visit Variable. + */ + +Compiler.prototype.visitVariable = function(variable){ + return ''; +}; + +/** + * Visit Charset. + */ + +Compiler.prototype.visitCharset = function(charset){ + return '@charset ' + this.visit(charset.val); +}; + +/** + * Visit Literal. + */ + +Compiler.prototype.visitLiteral = function(lit){ + return lit.val.trim().replace(/^ /gm, ''); +}; + +/** + * Visit Boolean. + */ + +Compiler.prototype.visitBoolean = function(bool){ + return bool.toString(); +}; + +/** + * Visit RGBA. + */ + +Compiler.prototype.visitRGBA = function(rgba){ + return rgba.toString(); +}; + +/** + * Visit HSLA. + */ + +Compiler.prototype.visitHSLA = function(hsla){ + return hsla.rgba.toString(); +}; + +/** + * Visit Unit. + */ + +Compiler.prototype.visitUnit = function(unit){ + var type = unit.type || '' + , n = unit.val + , float = n != (n | 0); + + // Int + if ('px' == type) n = n.toFixed(0); + // Compress + if (this.compress) { + // Zero is always '0' + if (0 == n) return '0'; + // Omit leading '0' on floats + if (float && n < 1 && n > -1) { + return n.toString().replace('0.', '.') + type; + } + } + + return n.toString() + type; +}; + +/** + * Visit Group. + */ + +Compiler.prototype.visitGroup = function(group){ + var self = this + , tree = this.tree + , prev = tree[tree.length - 1] + , curr = []; + + // Construct an array of arrays + // representing the selector hierarchy + group.nodes.forEach(function(node){ + curr.push(node.parent + ? node + : node.val); + }); + + tree.push(curr); + + // Reverse recurse the + // hierarchy array to build + // up the selector permutations. + // When we reach root, we have our + // selector string built + var selectors = [] + , buf = []; + function join(arr, i) { + if (i) { + arr[i].forEach(function(str){ + buf.unshift(str); + join(arr, i - 1); + buf.shift(); + }); + } else { + arr[0].forEach(function(selector){ + var str = selector; + if (buf.length) { + for (var i = 0, len = buf.length; i < len; ++i) { + if (~buf[i].indexOf('&')) { + str = buf[i].replace('&', str); + } else { + str += ' ' + buf[i]; + } + } + } + selectors.push(self.indent + str); + }); + } + } + + // Join selectors + if (group.block.hasProperties) { + join(tree, tree.length - 1); + this.buf += selectors.join(this.compress ? ',' : ',\n'); + } + + // Output blocks + this.visit(group.block); + tree.pop(); +}; + +/** + * Visit Ident. + */ + +Compiler.prototype.visitIdent = function(ident){ + return ident.name; +}; + +/** + * Visit String. + */ + +Compiler.prototype.visitString = function(string){ + return this.isURL + ? string.val + : string.toString(); +}; + +/** + * Visit Null. + */ + +Compiler.prototype.visitNull = function(node){ + return ''; +}; + +/** + * Visit Call. + */ + +Compiler.prototype.visitCall = function(call){ + this.isURL = 'url' == call.name; + var args = call.args.nodes.map(function(arg){ + return this.visit(arg); + }, this).join(this.compress ? ',' : ', '); + if (this.isURL) args = '"' + args + '"'; + delete this.isURL; + return call.name + '(' + args + ')'; +}; + +/** + * Visit Import. + */ + +Compiler.prototype.visitImport = function(import){ + return '@import ' + this.visit(import.path) + ';'; +}; + +/** + * Visit Expression. + */ + +Compiler.prototype.visitExpression = function(expr){ + return expr.nodes.map(function(node){ + return this.visit(node); + }, this).join(expr.isList + ? (this.compress ? ',' : ', ') + : (this.isURL ? '' : ' ')); +}; + +/** + * Visit Property. + */ + +Compiler.prototype.visitProperty = function(prop){ + var self = this + , val = this.visit(prop.expr); + return this.indent + (prop.name || prop.segments.join('')) + + (this.compress ? ':' + val : ': ' + val) + + (this.compress + ? (this.last ? '' : ';') + : ';'); +}; diff --git a/node_modules/jade/support/stylus/lib/visitor/evaluator.js b/node_modules/jade/support/stylus/lib/visitor/evaluator.js new file mode 100644 index 0000000..1b166b4 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/visitor/evaluator.js @@ -0,0 +1,911 @@ + +/*! + * Stylus - Evaluator + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Visitor = require('./') + , nodes = require('../nodes') + , Stack = require('../stack') + , Frame = require('../stack/frame') + , Scope = require('../stack/scope') + , utils = require('../utils') + , bifs = require('../functions') + , dirname = require('path').dirname + , colors = require('../colors') + , fs = require('fs'); + +/** + * Initialize a new `Evaluator` with the given `root` Node + * and the following `options`. + * + * Options: + * + * - `compress` Compress the css output, defaults to false + * - `warn` Warn the user of duplicate function definitions etc + * + * @param {Node} root + * @api private + */ + +var Evaluator = module.exports = function Evaluator(root, options) { + options = options || {}; + Visitor.call(this, root); + this.stack = new Stack; + this.imports = options.imports || []; + this.functions = options.functions || {}; + this.paths = options.paths || []; + this.filename = options.filename; + this.paths.push(dirname(options.filename || '.')); + this.stack.push(this.global = new Frame(root)); + this.warnings = options.warn; + this.options = options; + this.calling = []; // TODO: remove, use stack +}; + +/** + * Inherit from `Visitor.prototype`. + */ + +Evaluator.prototype.__proto__ = Visitor.prototype; + +/** + * Proxy visit to expose node line numbers. + * + * @param {Node} node + * @return {Node} + * @api private + */ + +var visit = Visitor.prototype.visit; +Evaluator.prototype.visit = function(node){ + try { + return visit.call(this, node); + } catch (err) { + // TODO: less-lame hack to reference + // the origin node source input + this.lineno = this.lineno || node.lineno; + err.str = err.str || node.source; + err.stylusStack = err.stylusStack || this.stack.toString(); + throw err; + } +}; + +/** + * Perform evaluation setup: + * + * - populate global scope + * - iterate imports + * + * @api private + */ + +Evaluator.prototype.setup = function(){ + this.populateGlobalScope(); + this.imports.forEach(function(file){ + var expr = new nodes.Expression; + expr.push(new nodes.String(file)); + this.visit(new nodes.Import(expr)); + }, this); +}; + +/** + * Populate the global scope with: + * + * - css colors + * + * @api private + */ + +Evaluator.prototype.populateGlobalScope = function(){ + var scope = this.global.scope; + Object.keys(colors).forEach(function(name){ + var rgb = colors[name] + , rgba = new nodes.RGBA(rgb[0], rgb[1], rgb[2], 1) + , node = new nodes.Ident(name, rgba); + scope.add(node); + }); +}; + +/** + * Evaluate the tree. + * + * @return {Node} + * @api private + */ + +Evaluator.prototype.evaluate = function(){ + this.setup(); + return this.visit(this.root); +}; + +/** + * Visit Group. + */ + +Evaluator.prototype.visitGroup = function(group){ + group.block = this.visit(group.block); + return group; +}; + +/** + * Visit Charset. + */ + +Evaluator.prototype.visitCharset = function(charset){ + return charset; +}; + +/** + * Visit Return. + */ + +Evaluator.prototype.visitReturn = function(ret){ + ret.expr = this.visit(ret.expr); + throw ret; +}; + +/** + * Visit Media. + */ + +Evaluator.prototype.visitMedia = function(media){ + media.block = this.visit(media.block); + return media; +}; + +/** + * Visit Keyframes. + */ + +Evaluator.prototype.visitKeyframes = function(keyframes){ + keyframes.name = this.visit(keyframes.name).first.name; + return keyframes; +}; + +/** + * Visit Function. + */ + +Evaluator.prototype.visitFunction = function(fn){ + // check local + var local = this.stack.currentFrame.scope.lookup(fn.name); + if (local) this.warn('local ' + local.nodeName + ' "' + fn.name + '" previously defined in this scope'); + + // user-defined + var user = this.functions[fn.name]; + if (user) this.warn('user-defined function "' + fn.name + '" is already defined'); + + // BIF + var bif = bifs[fn.name]; + if (bif) this.warn('built-in function "' + fn.name + '" is already defined'); + + return fn; +}; + +/** + * Visit Each. + */ + +Evaluator.prototype.visitEach = function(each){ + var expr = utils.unwrap(this.visit(utils.unwrap(each.expr))) + , len = expr.nodes.length + , val = new nodes.Ident(each.val) + , key = new nodes.Ident(each.key || '__index__') + , scope = this.currentScope + , block = this.currentBlock + , vals = [] + , body; + + each.block.scope = false; + for (var i = 0; i < len; ++i) { + val.val = expr.nodes[i]; + key.val = new nodes.Unit(i); + scope.add(val); + scope.add(key); + body = this.visit(each.block.clone()); + vals = vals.concat(body.nodes); + } + + this.mixin(vals, block); + return vals[vals.length - 1] || nodes.null; +}; + +/** + * Visit Call. + */ + +Evaluator.prototype.visitCall = function(call){ + var fn = this.lookup(call.name) + , ret; + + // Variable function + if (fn && 'expression' == fn.nodeName) { + fn = fn.nodes[0]; + } + + // Not a function? try user-defined or built-ins + if (fn && 'function' != fn.nodeName) { + fn = this.lookupFunction(call.name); + } + + // Undefined function, render literal css + if (!fn || fn.nodeName != 'function') return this.literalCall(call); + this.calling.push(call.name); + + // Massive stack + if (this.calling.length > 200) { + throw new RangeError('Maximum call stack size exceeded'); + } + + // First node in expression + if (fn instanceof nodes.Expression) fn = fn.first; + + // Evaluate arguments + var _ = this.return; + this.return = true; + var args = this.visit(call.args); + this.return = _; + + // Built-in + if (fn.fn) { + ret = this.invokeBuiltin(fn.fn, args); + // User-defined + } else if (fn instanceof nodes.Function) { + ret = this.invokeFunction(fn, args); + } + + this.calling.pop(); + return ret; +}; + +/** + * Visit Ident. + */ + +Evaluator.prototype.visitIdent = function(ident){ + // Lookup + if (nodes.null == ident.val) { + var val = this.lookup(ident.name); + return val ? this.visit(val) : ident; + // Assign + } else { + var _ = this.return; + this.return = true; + ident.val = this.visit(ident.val); + this.return = _; + this.currentScope.add(ident); + return ident.val; + } +}; + +/** + * Visit BinOp. + */ + +Evaluator.prototype.visitBinOp = function(binop){ + // Special-case "is defined" pseudo binop + if ('is defined' == binop.op) return this.isDefined(binop.left); + + var _ = this.return; + this.return = true; + // Visit operands + var op = binop.op + , ident = 'ident' == binop.left.nodeName + , left = this.visit(binop.left) + , right = this.visit(binop.right); + this.return = _; + + // First node in expression + if (!~['[]', 'in'].indexOf(op)) { + left = left.first; + right = right.first; + } + + // Coercion + switch (op) { + case '[]': + case 'in': + case '||': + case '&&': + case 'is a': + break; + default: + // Special-case '-' against ident + if ('-' == op + && 'ident' == left.nodeName + && 'unit' == right.nodeName) { + var expr = new nodes.Expression; + right.val = -right.val; + expr.push(left); + expr.push(right); + return expr; + } + + // Attempt coercion + try { + right = left.coerce(right); + } catch (err) { + // Disgregard coercion issues + // and simply return false + if ('==' == op || '!=' == op) { + return nodes.false; + } else { + throw err; + } + } + } + + // Operate + return this.visit(left.operate(op, right)); +}; + +/** + * Visit UnaryOp. + */ + +Evaluator.prototype.visitUnaryOp = function(unary){ + var op = unary.op + , node = this.visit(unary.expr).first; + + if ('!' != op) utils.assertType(node, nodes.Unit); + + switch (op) { + case '-': + node.val = -node.val; + break; + case '+': + node.val = +node.val; + break; + case '~': + node.val = ~node.val; + break; + case '!': + return node.toBoolean().negate(); + } + + return node; +}; + +/** + * Visit TernaryOp. + */ + +Evaluator.prototype.visitTernary = function(ternary){ + var ok = this.visit(ternary.cond).toBoolean(); + return nodes.true == ok + ? this.visit(ternary.trueExpr) + : this.visit(ternary.falseExpr); +}; + +/** + * Visit Expression. + */ + +Evaluator.prototype.visitExpression = function(expr){ + for (var i = 0, len = expr.nodes.length; i < len; ++i) { + expr.nodes[i] = this.visit(expr.nodes[i]); + } + return expr; +}; + +/** + * Visit Property. + */ + +Evaluator.prototype.visitProperty = function(prop){ + var name = this.interpolate(prop) + , fn = this.lookup(name) + , call = fn instanceof nodes.Function + , literal = ~this.calling.indexOf(name); + + // Function of the same name + if (call && !literal && !prop.literal) { + this.calling.push(name); + var ret = this.visit(new nodes.Call(name, prop.expr)); + this.calling.pop(); + return ret; + // Regular property + } else { + var _ = this.return; + this.return = true; + prop.expr = this.visit(prop.expr); + prop.name = name; + prop.literal = true; + this.return = _; + return prop; + } +}; + +/** + * Visit Root. + */ + +Evaluator.prototype.visitRoot = function(block){ + for (var i = 0; i < block.nodes.length; ++i) { + block.index = this.rootIndex = i; + block.nodes[i] = this.visit(block.nodes[i]); + } + return block; +}; + +/** + * Visit Block. + */ + +Evaluator.prototype.visitBlock = function(block){ + this.stack.push(new Frame(block)); + for (var i = 0; i < block.nodes.length; ++i) { + block.index = i; + try { + block.nodes[i] = this.visit(block.nodes[i]); + } catch (err) { + if (err instanceof nodes.Return) { + if (this.return) { + this.stack.pop(); + throw err; + } else { + block.nodes[i] = err; + break; + } + } else { + throw err; + } + } + } + this.stack.pop(); + return block; +}; + +/** + * Visit If. + */ + +Evaluator.prototype.visitIf = function(node){ + var ret + , _ = this.return + , block = this.currentBlock + , negate = node.negate; + + this.return = true; + var ok = this.visit(node.cond).first.toBoolean(); + this.return = _; + + // Evaluate body + if (negate) { + // unless + if (nodes.false == ok) { + ret = this.visit(node.block); + } + } else { + // if + if (nodes.true == ok) { + ret = this.visit(node.block); + // else + } else if (node.elses.length) { + var elses = node.elses + , len = elses.length; + for (var i = 0; i < len; ++i) { + // else if + if (elses[i].cond) { + if (nodes.true == this.visit(elses[i].cond).first.toBoolean()) { + ret = this.visit(elses[i].block); + break; + } + // else + } else { + ret = this.visit(elses[i]); + } + } + } + } + + // mixin conditional statements within a selector group + if (ret && !node.postfix && block.node && 'group' == block.node.nodeName) { + this.mixin(ret.nodes, block); + return nodes.null; + } + + return ret || nodes.null; +}; + +/** + * Visit Import. + */ + +Evaluator.prototype.visitImport = function(import){ + var found + , root = this.root + , i = this.rootIndex + , stylus = require('../stylus') + , path = this.visit(import.path).first + , relative = this.importPath; + + // Enusre string + if (!path.string) throw new Error('@import string expected'); + var name = path = path.string; + + // Literal + if (/\.css$/.test(path)) return import; + path += '.styl'; + + // Lookup + if (relative) this.paths.push(relative); + found = utils.lookup(path, this.paths, this.filename); + found = found || utils.lookup(name + '/index.styl', this.paths, this.filename); + if (relative) this.paths.pop(); + + // Expose imports + import.path = found; + if (this.options._imports) this.options._imports.push(import); + + // Throw if import failed + if (!found) throw new Error('failed to locate @import file ' + path); + this.importPath = dirname(found); + + // Parse the file + var str = fs.readFileSync(found, 'utf8') + , rest = root.nodes.splice(++i, root.nodes.length); + + stylus.parse(str, { + filename: found + , root: root + }); + + rest.forEach(function(node){ + root.push(node); + }); + + return nodes.null; +}; + +/** + * Invoke `fn` with `args`. + * + * @param {Function} fn + * @param {Array} args + * @return {Node} + * @api private + */ + +Evaluator.prototype.invokeFunction = function(fn, args){ + var block = new nodes.Block(fn.block.parent); + fn.block.parent = block; + + // Clone the function body + // to prevent mutation of subsequent calls + // inject argument scope + var body = fn.block.clone(); + + // mixin block + var mixinBlock = this.stack.currentFrame.block; + + // new block scope + this.stack.push(new Frame(block)); + var scope = this.currentScope; + + // arguments local + scope.add(new nodes.Ident('arguments', args)); + + // mixin scope introspection + scope.add(new nodes.Ident('mixin', this.return + ? nodes.false + : new nodes.String(mixinBlock.nodeName))); + + // inject arguments as locals + fn.params.nodes.forEach(function(node, i){ + // rest param support + if (node.rest) { + node.val = new nodes.Expression; + for (var len = args.nodes.length; i < len; ++i) { + node.val.push(args.nodes[i]); + } + node.val.preserve = true; + // argument default support + } else { + var arg = args.nodes[i]; + var val = arg && !arg.isEmpty + ? args.nodes[i] + : node.val; + node = node.clone(); + node.val = val; + // required argument not satisfied + if (node.val instanceof nodes.Null) { + throw new Error('argument ' + node + ' required for ' + fn); + } + } + + scope.add(node); + }); + + // invoke + return this.invoke(body, true); +}; + +/** + * Invoke built-in `fn` with `args`. + * + * @param {Function} fn + * @param {Array} args + * @return {Node} + * @api private + */ + +Evaluator.prototype.invokeBuiltin = function(fn, args){ + // Map arguments to first node + // providing a nicer js api for + // BIFs. Functions may specify that + // they wish to accept full expressions + // via .raw + if (fn.raw) { + args = args.nodes; + } else { + args = args.nodes.map(function(node){ + return node.first; + }); + } + + // Invoke the BIF + var body = fn.apply(this, args); + + // Always wrapping allows js functions + // to return several values with a single + // Expression node + var expr = new nodes.Expression; + expr.push(body); + body = expr; + + // Invoke + return this.invoke(body); +}; + +/** + * Invoke the given function `body`. + * + * @param {Block} body + * @return {Node} + * @api private + */ + +Evaluator.prototype.invoke = function(body, stack){ + var self = this + , ret; + + // Return + if (this.return) { + ret = this.eval(body.nodes); + if (stack) this.stack.pop(); + // Mixin + } else { + body = this.visit(body); + if (stack) this.stack.pop(); + this.mixin(body.nodes, this.currentBlock); + ret = nodes.null; + } + + return ret; +}; + +/** + * Mixin the given `nodes` to the given `block`. + * + * @param {Array} nodes + * @param {Block} block + * @api private + */ + +Evaluator.prototype.mixin = function(nodes, block){ + var len = block.nodes.length + , head = block.nodes.slice(0, block.index) + , tail = block.nodes.slice(block.index + 1, len); + this._mixin(nodes, head); + block.nodes = head.concat(tail); +}; + +/** + * Mixin the given `nodes` to the `dest` array. + * + * @param {Array} nodes + * @param {Array} dest + * @api private + */ + +Evaluator.prototype._mixin = function(nodes, dest){ + var node + , len = nodes.length; + for (var i = 0; i < len; ++i) { + switch ((node = nodes[i]).nodeName) { + case 'return': + return; + case 'block': + this._mixin(node.nodes, dest); + break; + default: + dest.push(node); + } + } +}; + +/** + * Evaluate the given `vals`. + * + * @param {Array} vals + * @return {Node} + * @api private + */ + +Evaluator.prototype.eval = function(vals){ + if (!vals) return nodes.null; + var len = vals.length + , node = nodes.null; + + try { + for (var i = 0; i < len; ++i) { + node = vals[i]; + switch (node.nodeName) { + case 'if': + if ('block' != node.block.nodeName) { + node = this.visit(node); + break; + } + case 'each': + case 'block': + node = this.visit(node); + if (node.nodes) node = this.eval(node.nodes); + break; + default: + node = this.visit(node); + } + } + } catch (err) { + if (err instanceof nodes.Return) { + return err.expr; + } else { + throw err; + } + } + + return node; +}; + +/** + * Literal function `call`. + * + * @param {Call} call + * @return {call} + * @api private + */ + +Evaluator.prototype.literalCall = function(call){ + call.args = this.visit(call.args); + return call; +}; + +/** + * Lookup `name`, with support for JavaScript + * functions, and BIFs. + * + * @param {String} name + * @return {Node} + * @api private + */ + +Evaluator.prototype.lookup = function(name){ + var val; + if (val = this.stack.lookup(name)) { + return utils.unwrap(val); + } else { + return this.lookupFunction(name); + } +}; + +/** + * Map segments in `node` returning a string. + * + * @param {Node} node + * @return {String} + * @api private + */ + +Evaluator.prototype.interpolate = function(node){ + var self = this; + return node.segments.map(function(node){ + function toString(node) { + switch (node.nodeName) { + case 'function': + case 'ident': + return node.name; + case 'literal': + case 'string': + case 'unit': + return node.val; + case 'expression': + var _ = self.return; + self.return = true; + var ret = toString(self.visit(node).first); + self.return = _; + return ret; + } + } + return toString(node); + }).join(''); +}; + +/** + * Lookup JavaScript user-defined or built-in function. + * + * @param {String} name + * @return {Function} + * @api private + */ + +Evaluator.prototype.lookupFunction = function(name){ + var fn = this.functions[name] || bifs[name]; + if (fn) return new nodes.Function(name, fn); +}; + +/** + * Check if the given `node` is an ident, and if it is defined. + * + * @param {Node} node + * @return {Boolean} + * @api private + */ + +Evaluator.prototype.isDefined = function(node){ + if (node instanceof nodes.Ident) { + return nodes.Boolean(this.lookup(node.name)); + } else { + throw new Error('invalid "is defined" check on non-variable ' + node); + } +}; + +/** + * Warn with the given `msg`. + * + * @param {String} msg + * @api private + */ + +Evaluator.prototype.warn = function(msg){ + if (!this.warnings) return; + console.warn('\033[33mWarning:\033[0m ' + msg); +}; + +/** + * Return the current `Block`. + * + * @return {Block} + * @api private + */ + +Evaluator.prototype.__defineGetter__('currentBlock', function(){ + return this.stack.currentFrame.block; +}); + +/** + * Return the current frame `Scope`. + * + * @return {Scope} + * @api private + */ + +Evaluator.prototype.__defineGetter__('currentScope', function(){ + return this.stack.currentFrame.scope; +}); + +/** + * Return the current `Frame`. + * + * @return {Frame} + * @api private + */ + +Evaluator.prototype.__defineGetter__('currentFrame', function(){ + return this.stack.currentFrame; +}); diff --git a/node_modules/jade/support/stylus/lib/visitor/index.js b/node_modules/jade/support/stylus/lib/visitor/index.js new file mode 100644 index 0000000..d7f9207 --- /dev/null +++ b/node_modules/jade/support/stylus/lib/visitor/index.js @@ -0,0 +1,32 @@ + +/*! + * Stylus - Visitor + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Initialize a new `Visitor` with the given `root` Node. + * + * @param {Node} root + * @api private + */ + +var Visitor = module.exports = function Visitor(root) { + this.root = root; +}; + +/** + * Visit the given `node`. + * + * @param {Node|Array} node + * @api public + */ + +Visitor.prototype.visit = function(node, fn){ + var method = 'visit' + node.constructor.name + , cons = this.constructor.name; + if (this[method]) return this[method](node); + return node; +}; + diff --git a/node_modules/jade/support/stylus/package.json b/node_modules/jade/support/stylus/package.json new file mode 100644 index 0000000..55f36ed --- /dev/null +++ b/node_modules/jade/support/stylus/package.json @@ -0,0 +1,16 @@ +{ "name": "stylus" + , "description": "Robust, expressive language which compiles to CSS" + , "version": "0.9.2" + , "author": "TJ Holowaychuk " + , "keywords": ["css", "parser", "style", "stylesheets", "jade", "language"] + , "main": "./index.js" + , "engines": { "node": ">= 0.2.4" } + , "bin": { + "stylus": "./bin/stylus" + , "stylus-tutorial": "./bin/stylus-tutorial" + } + , "dependencies": { + "cssom": "0.2.0" + , "growl": "1.1.0" + } +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/arithmetic.color.css b/node_modules/jade/support/stylus/test/cases/arithmetic.color.css new file mode 100644 index 0000000..d6fe9f0 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/arithmetic.color.css @@ -0,0 +1,7 @@ +body { + background: rgba(0,255,255,0.5); + color: #0c0; +} +a { + color: #808080; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/arithmetic.color.styl b/node_modules/jade/support/stylus/test/cases/arithmetic.color.styl new file mode 100644 index 0000000..e27ead0 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/arithmetic.color.styl @@ -0,0 +1,7 @@ + +body + background #fff - (rgba(250,0,0,0.5) + rgba(5,0,0,0)) + color #ffcc00 - #f00 + +a + color (#fff / 2) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/arithmetic.css b/node_modules/jade/support/stylus/test/cases/arithmetic.css new file mode 100644 index 0000000..9bc514d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/arithmetic.css @@ -0,0 +1,12 @@ +body { + font-size: 12px; +} +h1 { + font-size: 36px; +} +h2 { + font-size: 24px; + font: 2px; + font: 0px; + font: 16px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/arithmetic.styl b/node_modules/jade/support/stylus/test/cases/arithmetic.styl new file mode 100644 index 0000000..a4ddbf4 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/arithmetic.styl @@ -0,0 +1,18 @@ + +size = 12px +large = size * (3 - 1) +huge = size * 3 + +body + font-size size + +h1 + font-size huge + +h2 + font-size large + font 5px % 3 + font 5px % 5 + font 2px ** 4 + y = 10 + x = 15 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/arithmetic.unary.css b/node_modules/jade/support/stylus/test/cases/arithmetic.unary.css new file mode 100644 index 0000000..5766529 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/arithmetic.unary.css @@ -0,0 +1,16 @@ +h1#logo { + margin-top: -15px; + margin-left: 3px; + foo: false; + foo: false; + foo: false; + foo: false; + foo: false; + foo: false; + foo: 0px -2px -3px; + foo: 1px; +} +body { + text-indent: -99999px; + background: #fff url("/some/image.png") no-repeat -29px 1px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/arithmetic.unary.styl b/node_modules/jade/support/stylus/test/cases/arithmetic.unary.styl new file mode 100644 index 0000000..fc5aa6f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/arithmetic.unary.styl @@ -0,0 +1,16 @@ + +h1#logo + margin-top - - - 15px + margin-left ~ - 4px + foo !true + foo !!0 + foo !-1 + foo !99 + foo !((99)) + foo not not 0 + foo 0px -2px -3px + foo -2px --3px + +body + text-indent -99999px + background #fff url('/some/image.png') no-repeat -29px 1px diff --git a/node_modules/jade/support/stylus/test/cases/bifs.components.css b/node_modules/jade/support/stylus/test/cases/bifs.components.css new file mode 100644 index 0000000..dc77fa4 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.components.css @@ -0,0 +1,9 @@ +body { + background: 255; + background: 204; + background: 0; + background: 0.4; + background: 15deg; + background: 100%; + background: 60%; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.components.styl b/node_modules/jade/support/stylus/test/cases/bifs.components.styl new file mode 100644 index 0000000..dc8b9a6 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.components.styl @@ -0,0 +1,9 @@ +body + background red(#fc0) + background green(#fc0) + background blue(#fc0) + background alpha(#fff - rgba(0,0,0,.6)) + + background hue(hsl(15deg,100%,60%)) + background saturation(hsl(15deg,100%,60%)) + background lightness(hsl(15deg,100%,60%)) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.dark.css b/node_modules/jade/support/stylus/test/cases/bifs.dark.css new file mode 100644 index 0000000..a336a0f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.dark.css @@ -0,0 +1,5 @@ +body { + foo: true; + foo: true; + foo: true; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.dark.styl b/node_modules/jade/support/stylus/test/cases/bifs.dark.styl new file mode 100644 index 0000000..fe9a18e --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.dark.styl @@ -0,0 +1,4 @@ +body + foo dark(black) == true + foo dark(#005716) == true + foo dark(white) == false diff --git a/node_modules/jade/support/stylus/test/cases/bifs.darken-by.css b/node_modules/jade/support/stylus/test/cases/bifs.darken-by.css new file mode 100644 index 0000000..ef30453 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.darken-by.css @@ -0,0 +1,5 @@ +body { + background: #808080; + background: #404040; + background: #202020; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.darken-by.styl b/node_modules/jade/support/stylus/test/cases/bifs.darken-by.styl new file mode 100644 index 0000000..85e5fea --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.darken-by.styl @@ -0,0 +1,4 @@ +body + background: darken-by(white, 50%) + background: darken-by(darken-by(white, 50%), 50%) + background: darken-by(darken-by(darken-by(white, 50%), 50%), 50%) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.image-size.css b/node_modules/jade/support/stylus/test/cases/bifs.image-size.css new file mode 100644 index 0000000..e26d4ac --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.image-size.css @@ -0,0 +1,9 @@ +body { + foo: 315px 450px; + foo: true; + foo: true; +} +body { + foo: 400px 479px; + foo: 400px 479px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.image-size.styl b/node_modules/jade/support/stylus/test/cases/bifs.image-size.styl new file mode 100644 index 0000000..d981a31 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.image-size.styl @@ -0,0 +1,19 @@ + +width(img) + return image-size(img)[0] + +height(img) + return image-size(img)[1] + +body + foo image-size('gif') + foo image-size('gif')[0] == width('gif') + foo image-size('gif')[1] == height('gif') + +body + foo image-size('tux.png') + foo image-size('tux.png') +/* +body + foo image-size('jpeg') + diff --git a/node_modules/jade/support/stylus/test/cases/bifs.join.css b/node_modules/jade/support/stylus/test/cases/bifs.join.css new file mode 100644 index 0000000..17097cf --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.join.css @@ -0,0 +1,11 @@ +body { + foo: "1 2 3"; + foo: "1, 2, 3"; + foo: "1,2,3"; + foo: "1"; + foo: true; +} +body { + foo: "1, 2, 3"; + foo: "one, two, three"; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.join.styl b/node_modules/jade/support/stylus/test/cases/bifs.join.styl new file mode 100644 index 0000000..6599124 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.join.styl @@ -0,0 +1,11 @@ + +body + foo join(' ', 1 2 3) + foo join(', ', 1 2 3) + foo join(',', 1 2 3) + foo join(',', 1) + foo join(',') == null + +body + foo join(', ', 1, 2, 3) + foo join(', ', one 1, two 2, three 3) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.last.css b/node_modules/jade/support/stylus/test/cases/bifs.last.css new file mode 100644 index 0000000..a336a0f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.last.css @@ -0,0 +1,5 @@ +body { + foo: true; + foo: true; + foo: true; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.last.styl b/node_modules/jade/support/stylus/test/cases/bifs.last.styl new file mode 100644 index 0000000..ef13055 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.last.styl @@ -0,0 +1,6 @@ + +body + nums = 1 2 3 4 + foo last(nums) == 4 + foo last(foo bar baz) == baz + foo last(()) == null \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.length.css b/node_modules/jade/support/stylus/test/cases/bifs.length.css new file mode 100644 index 0000000..670982d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.length.css @@ -0,0 +1,10 @@ +body { + foo: 0; + foo: 1; + foo: 1; + foo: 2; + foo: 3; + foo: 4; + foo: 5; + foo: 6; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.length.styl b/node_modules/jade/support/stylus/test/cases/bifs.length.styl new file mode 100644 index 0000000..762beb6 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.length.styl @@ -0,0 +1,18 @@ +args(n = null) + length(n) + +vargs(args...) + length(args) + +arguments() + length(arguments) + +body + foo length() + foo length(args()) + foo length(1) + foo length((1 2) (3 4)) + foo length(1 2 3) + foo vargs(1, 2, 3, 4) + foo args(1 2 3 4 5) + foo arguments(1,2,3,4,5,6) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.light.css b/node_modules/jade/support/stylus/test/cases/bifs.light.css new file mode 100644 index 0000000..a336a0f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.light.css @@ -0,0 +1,5 @@ +body { + foo: true; + foo: true; + foo: true; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.light.styl b/node_modules/jade/support/stylus/test/cases/bifs.light.styl new file mode 100644 index 0000000..162cfe7 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.light.styl @@ -0,0 +1,4 @@ +body + foo light(black) == false + foo light(white) == true + foo light(#00FF40) == true \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.lighten-by.css b/node_modules/jade/support/stylus/test/cases/bifs.lighten-by.css new file mode 100644 index 0000000..da74b89 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.lighten-by.css @@ -0,0 +1,6 @@ +body { + background: #808080; + background: #bfbfbf; + background: #fff; + foo: #7fbfee; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.lighten-by.styl b/node_modules/jade/support/stylus/test/cases/bifs.lighten-by.styl new file mode 100644 index 0000000..8f448e7 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.lighten-by.styl @@ -0,0 +1,6 @@ +body + background: lighten-by(black, 50%) + background: lighten-by(lighten-by(black, 50%), 50%) + background: lighten-by(lighten-by(lighten-by(black, 50%), 50%), 50%) + foo lighten(#52a8e8, 10%) + // => #7fbfee diff --git a/node_modules/jade/support/stylus/test/cases/bifs.lookup.complex.css b/node_modules/jade/support/stylus/test/cases/bifs.lookup.complex.css new file mode 100644 index 0000000..cbb003b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.lookup.complex.css @@ -0,0 +1,4 @@ +body { + color: #80e2e9; + border: 1px solid #f00; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.lookup.complex.styl b/node_modules/jade/support/stylus/test/cases/bifs.lookup.complex.styl new file mode 100644 index 0000000..cddf1fa --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.lookup.complex.styl @@ -0,0 +1,11 @@ + +border-type = solid +dark-blue = #006269 +light-blue = dark-blue + hsl(0,0,50%) + +light(color-name) + lookup('light-' + color-name) + +body + color light('blue') + border 1px lookup('border-type') red \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.lookup.css b/node_modules/jade/support/stylus/test/cases/bifs.lookup.css new file mode 100644 index 0000000..a5209ce --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.lookup.css @@ -0,0 +1,3 @@ +body { + color: #006269; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.lookup.styl b/node_modules/jade/support/stylus/test/cases/bifs.lookup.styl new file mode 100644 index 0000000..7f404f0 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.lookup.styl @@ -0,0 +1,8 @@ + +dark-blue = #006269 + +dark(color-name) + lookup('dark-' + color-name) + +body + color dark('blue') \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.match.css b/node_modules/jade/support/stylus/test/cases/bifs.match.css new file mode 100644 index 0000000..70483e0 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.match.css @@ -0,0 +1,4 @@ +body { + margin: 5px; + padding: 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.match.styl b/node_modules/jade/support/stylus/test/cases/bifs.match.styl new file mode 100644 index 0000000..eb2c7b9 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.match.styl @@ -0,0 +1,9 @@ +pad(type = padding) + if match('^pad', type) + padding 5px + else + margin 5px + +body + pad(margin) + pad(padding) diff --git a/node_modules/jade/support/stylus/test/cases/bifs.opposite-position.css b/node_modules/jade/support/stylus/test/cases/bifs.opposite-position.css new file mode 100644 index 0000000..dc41fa6 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.opposite-position.css @@ -0,0 +1,8 @@ +body { + foo: ; + foo: true; + foo: true; + foo: true; + foo: true; + foo: bottom right; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.opposite-position.styl b/node_modules/jade/support/stylus/test/cases/bifs.opposite-position.styl new file mode 100644 index 0000000..1809da5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.opposite-position.styl @@ -0,0 +1,9 @@ + +body + foo opposite-position() + foo opposite-position(top) == bottom + foo opposite-position(left) == right + foo opposite-position(top left)[0] == bottom + foo opposite-position(top left)[1] == right + val = top left + foo opposite-position(val) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.rgba.css b/node_modules/jade/support/stylus/test/cases/bifs.rgba.css new file mode 100644 index 0000000..15da40d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.rgba.css @@ -0,0 +1,5 @@ +body { + background: #ff0800; + background: rgba(255,255,0,0.2); + background: rgba(255,204,0,0.5); +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.rgba.styl b/node_modules/jade/support/stylus/test/cases/bifs.rgba.styl new file mode 100644 index 0000000..9c50ca4 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.rgba.styl @@ -0,0 +1,4 @@ +body + background rgba(255,8,0,1) + background rgba(255,255,0,0.2) + background rgba(#fc0, 0.5) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.type.css b/node_modules/jade/support/stylus/test/cases/bifs.type.css new file mode 100644 index 0000000..647b227 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.type.css @@ -0,0 +1,11 @@ +body { + background: "string"; + background: "unit"; + background: "unit"; + background: "hsla"; + background: "rgba"; + background: "ident"; + background: "unit"; + background: "function"; + background: "ident"; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.type.styl b/node_modules/jade/support/stylus/test/cases/bifs.type.styl new file mode 100644 index 0000000..e67eec3 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.type.styl @@ -0,0 +1,12 @@ +body + border-type = solid + size = 15px + background type('test') + background type(12px) + background type(12) + background type(hsl(100deg, 50%, 50%)) + background type(#fff) + background type(something) + background type(size) + background type(type) + background type(border-type) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.unit.css b/node_modules/jade/support/stylus/test/cases/bifs.unit.css new file mode 100644 index 0000000..35febfd --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.unit.css @@ -0,0 +1,6 @@ +body { + foo: 20px; + foo: 20px; + foo: 20px; + foo: 20%; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.unit.styl b/node_modules/jade/support/stylus/test/cases/bifs.unit.styl new file mode 100644 index 0000000..336dabc --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.unit.styl @@ -0,0 +1,5 @@ +body + foo unit(20, 'px') + foo unit(20, px) + foo unit(20%, px) + foo unit(20, '%') \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.unquote.css b/node_modules/jade/support/stylus/test/cases/bifs.unquote.css new file mode 100644 index 0000000..1a3643f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.unquote.css @@ -0,0 +1,5 @@ +body { + background: testing; + background: testing; + font: 14px / 1.5; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.unquote.styl b/node_modules/jade/support/stylus/test/cases/bifs.unquote.styl new file mode 100644 index 0000000..d101806 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.unquote.styl @@ -0,0 +1,8 @@ + +line-height(n) + unquote('/ ' + n) + +body + background unquote(testing) + background unquote('testing') + font 14px line-height(1.5) diff --git a/node_modules/jade/support/stylus/test/cases/bifs.url.css b/node_modules/jade/support/stylus/test/cases/bifs.url.css new file mode 100644 index 0000000..ab4a9f4 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.url.css @@ -0,0 +1,11 @@ +body { + background: url("/images/foo.png"); + background: url("/images/foo.png"); + background: url("/images/foo.png"); + background: url("/images/foo.png"); + background: url("/images/foo.png"); + background: url("/images/foo.png"); + background: url("/images/foo.png"); + background: url("/images/foo.png"); + background: url("http://foo.com/images/bar.png"); +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/bifs.url.styl b/node_modules/jade/support/stylus/test/cases/bifs.url.styl new file mode 100644 index 0000000..691d33c --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/bifs.url.styl @@ -0,0 +1,15 @@ +body + background url("/images/foo.png") + background url(/images/foo.png) + + dir = '/images' + img = 'foo.png' + background url(dir/foo.png) + background url(dir/img) + + background url('/images/' + img) + background url(dir'/foo.png') + background url(dir + '/foo.png') + background url(dir + '/' + img) + + background url(http://foo.com/images/bar.png) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/coercion.css b/node_modules/jade/support/stylus/test/cases/coercion.css new file mode 100644 index 0000000..1c54cd5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/coercion.css @@ -0,0 +1,6 @@ +body { + foo: 10px; + foo: 6px; + foo: "foo bar"; + foo: "value: 5px"; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/coercion.styl b/node_modules/jade/support/stylus/test/cases/coercion.styl new file mode 100644 index 0000000..8925fc1 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/coercion.styl @@ -0,0 +1,5 @@ +body + foo 5px + '5' + foo 5px + '1 23' + foo 'foo ' + 'bar' + foo 'value: ' + 5px \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/comments.css b/node_modules/jade/support/stylus/test/cases/comments.css new file mode 100644 index 0000000..a11dd7a --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/comments.css @@ -0,0 +1,11 @@ +body { + color: #f00; +} +form { + background: #fff; +} +html>/**/body select, +x:-moz-any-link, +x:default select { + font-weight: bold !important; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/comments.styl b/node_modules/jade/support/stylus/test/cases/comments.styl new file mode 100644 index 0000000..82cb469 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/comments.styl @@ -0,0 +1,28 @@ + +// foo = 'bar' + +body + color red + // lots of stuff + // wahoo + + // super cool + + // background green + +form + background white + +/* + +body + a + color blue + +*/ +// rawr + +html>/**/body select +x:-moz-any-link +x:default select + font-weight bold !important \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/compress.units.css b/node_modules/jade/support/stylus/test/cases/compress.units.css new file mode 100644 index 0000000..d07704f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/compress.units.css @@ -0,0 +1,2 @@ +body{foo:0;foo:0;foo:15;foo:-15;foo:15px;foo:-15px} +body{foo:.1;foo:-.1;foo:1.1;foo:-1.1;foo:.1;foo:-.1;foo:10.1;foo:-10.1} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/compress.units.styl b/node_modules/jade/support/stylus/test/cases/compress.units.styl new file mode 100644 index 0000000..3f3bf28 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/compress.units.styl @@ -0,0 +1,18 @@ +body + foo 0 + foo 0px + foo 15 + foo -15 + foo 15px + foo -15px + +body + foo 0.1 + foo -0.1 + foo 1.1 + foo -1.1 + foo 0.1 + foo -0.1 + foo 10.1 + foo -10.1 + \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/conditional-assignment.css b/node_modules/jade/support/stylus/test/cases/conditional-assignment.css new file mode 100644 index 0000000..e02b387 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/conditional-assignment.css @@ -0,0 +1,4 @@ +a.button { + font: 14px; + background: #fff; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/conditional-assignment.styl b/node_modules/jade/support/stylus/test/cases/conditional-assignment.styl new file mode 100644 index 0000000..4431b33 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/conditional-assignment.styl @@ -0,0 +1,9 @@ + +color ?= white +color ?= black + +font-size ?= 14px + +a.button + font font-size + background color diff --git a/node_modules/jade/support/stylus/test/cases/css.functions.single-line.css b/node_modules/jade/support/stylus/test/cases/css.functions.single-line.css new file mode 100644 index 0000000..08b9e7c --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.functions.single-line.css @@ -0,0 +1,9 @@ +body { + foo: false; + foo: true; +} +body { + foo: false; + foo: true; + foo: ; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.functions.single-line.styl b/node_modules/jade/support/stylus/test/cases/css.functions.single-line.styl new file mode 100644 index 0000000..4ac7a65 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.functions.single-line.styl @@ -0,0 +1,13 @@ + +large(n){ n > 100 } + +body + foo large(5) + foo large(300) + +large(n){ n > 100 if n is a 'unit' } + +body + foo large(5) + foo large(300) + foo large('test') \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.if.css b/node_modules/jade/support/stylus/test/cases/css.if.css new file mode 100644 index 0000000..5ed0353 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.if.css @@ -0,0 +1,8 @@ +body { + color: #fff; + color: #fff; +} +body { + padding: 5px; + margin: 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.if.styl b/node_modules/jade/support/stylus/test/cases/css.if.styl new file mode 100644 index 0000000..2ff1b4f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.if.styl @@ -0,0 +1,21 @@ + +body + if true { + color: white; + } + unless (false) { + color: white; + } + +mixin(pad, margin) { + if (pad) { + padding: 5px; + } + if (margin) { + margin: 5px; + } +} + +body + mixin(true, true) + diff --git a/node_modules/jade/support/stylus/test/cases/css.keyframes.css b/node_modules/jade/support/stylus/test/cases/css.keyframes.css new file mode 100644 index 0000000..be727ff --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.keyframes.css @@ -0,0 +1,48 @@ +@-webkit-keyframes bouce { + 0% { + foo: bar; + } + + 50% { + foo: bar; + } + + 100% { + foo: bar; + } +} +@-webkit-keyframes bouce { + 0% { + foo: bar; + } + + 50% { + foo: bar; + } + + 100% { + foo: bar; + } +} +@-webkit-keyframes bouce { + 0% { + foo: bar; + } + + 50% { + foo: bar; + } + + 100% { + foo: bar; + } +} +@-webkit-keyframes something { + 0% { + color: red; + } + + 100% { + color: blue; + } +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.keyframes.styl b/node_modules/jade/support/stylus/test/cases/css.keyframes.styl new file mode 100644 index 0000000..7ce1c3f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.keyframes.styl @@ -0,0 +1,39 @@ + +@keyframes bouce { + from { + foo: bar; + } + + 50% { + foo: bar; + } + + to { + foo: bar; + } +} + +@keyframes bouce { + from { foo: bar; } + 50% { foo: bar; } + to { foo: bar; } +} + + +@keyframes bouce { + from { foo: bar; } + + + 50% { foo: bar; } + + to { foo: bar; } +} + +animate(name) { + @keyframes name { + from { color: red; } + to { color: blue; } + } +} + +animate(something) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.large.css b/node_modules/jade/support/stylus/test/cases/css.large.css new file mode 100644 index 0000000..b63459b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.large.css @@ -0,0 +1,172 @@ +html { + background: #dadada; + background: -moz-linear-gradient(-90deg, #fff, #dadada) fixed; + background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dadada)) fixed; +} +body { + padding: 120px 150px; + font: 14px / 1.4 "helvetica neue", helvetica, arial, sans-serif; + color: #484848; +} +h1, +h2, +h3 { + color: #222; +} +h1 a, +h2 a, +h3 a { + color: #222; +} +h1 a:hover, +h2 a:hover, +h3 a:hover { + text-decoration: none; +} +h1 { + margin: 10px 0 15px 0; + font-weight: bold; + font-size: 60px; +} +h2 { + margin: 0; + font-size: 18px; +} +h3 { + font-size: 14px; +} +a { + text-decoration: none; + color: #b90101; +} +a:hover { + text-decoration: underline; +} +strong { + color: #a00; +} +ul { + margin: 0; + padding: 0 25px; +} +ul li { + list-style: square; +} +.tagline { + margin: 0; + padding: 0; +} +.tagline em { + font-style: normal; +} +.tagline em.expressive { + color: #222; +} +.tagline em.dynamic { + color: #555; +} +.tagline em.robust { + color: #888; +} +.tagline em.css { + color: #bbb; +} +#container { + text-align: center; +} +#container #content { + margin: 0 auto; + padding-top: 40px; + width: 300px; + text-align: left; +} +#menu { + position: fixed; + top: -5px; + right: 60px; + margin: 0; + padding: 15px 0 10px 5px; + background: rgba(255,255,255,0.3); + border: 1px solid #ddd; + text-align: left; + -moz-box-shadow: inset rgba(34,34,34,0.1) 0 4px 4px; + -webkit-box-shadow: inset rgba(34,34,34,0.1) 0 4px 4px; + box-shadow: inset rgba(34,34,34,0.1) 0 4px 4px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +#menu li { + list-style: none; +} +#menu li a { + display: block; + width: 150px; + padding: 1px 10px; + color: #7b7b7b; + font-size: 13px; +} +#menu li a:hover { + color: #000; + text-decoration: none; +} +.example { + margin-top: 25px; +} +pre { + width: 300px; + padding: 30px; + color: #8d8d8d; + font: 12px / 1.4 monaco, "helvetica neue", helvetica; + overflow-x: auto; + background: #fff; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + -moz-box-shadow: rgba(34,34,34,0.1) -1px -1px; + -webkit-box-shadow: rgba(34,34,34,0.1) -1px -1px; + box-shadow: rgba(34,34,34,0.1) -1px -1px; +} +pre.terminal { + width: 340px; + padding: 10px; + background: #2b2b2b; + color: #dadada; + -moz-box-shadow: #fff -1px -1px; + -webkit-box-shadow: #fff -1px -1px; + box-shadow: #fff -1px -1px; +} +p code { + padding: 2px 4px; + color: #626262; + font-size: 85%; + background: #fff; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + -moz-box-shadow: rgba(34,34,34,0.1) -1px -1px; + -webkit-box-shadow: rgba(34,34,34,0.1) -1px -1px; + box-shadow: rgba(34,34,34,0.1) -1px -1px; +} +#ribbon { + position: absolute; + top: 2.5em; + left: -3.75em; + background-color: #a00; + padding: 1px 0; + overflow: hidden; + -webkit-transform: rotate(-45deg); + -moz-transform: rotate(-45deg); + -moz-box-shadow: 1px 1px 3px rgba(0,0,0,0.3); + -webkit-box-shadow: 1px 1px 3px rgba(0,0,0,0.3); + box-shadow: 1px 1px 3px rgba(0,0,0,0.3); +} +#ribbon a { + color: #fff; + border: 1px solid #f18585; + display: block; + margin: 0.05em 0; + padding: 0.5em 3.5em; + text-align: center; + text-decoration: none; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.large.styl b/node_modules/jade/support/stylus/test/cases/css.large.styl new file mode 100644 index 0000000..ee87684 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.large.styl @@ -0,0 +1,172 @@ +html { + background: #dadada; + background: -moz-linear-gradient(-90deg, #fff, #dadada) fixed; + background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dadada)) fixed; +} +body { + padding: 120px 150px; + font: 14px / 1.4 "helvetica neue", helvetica, arial, sans-serif; + color: #484848; +} +h1, +h2, +h3 { + color: #222; +} +h1 a, +h2 a, +h3 a { + color: #222; +} +h1 a:hover, +h2 a:hover, +h3 a:hover { + text-decoration: none; +} +h1 { + margin: 10px 0 15px 0; + font-weight: bold; + font-size: 60px; +} +h2 { + margin: 0; + font-size: 18px; +} +h3 { + font-size: 14px; +} +a { + text-decoration: none; + color: #b90101; +} +a:hover { + text-decoration: underline; +} +strong { + color: #a00; +} +ul { + margin: 0; + padding: 0 25px; +} +ul li { + list-style: square; +} +.tagline { + margin: 0; + padding: 0; +} +.tagline em { + font-style: normal; +} +.tagline em.expressive { + color: #222; +} +.tagline em.dynamic { + color: #555; +} +.tagline em.robust { + color: #888; +} +.tagline em.css { + color: #bbb; +} +#container { + text-align: center; +} +#container #content { + margin: 0 auto; + padding-top: 40px; + width: 300px; + text-align: left; +} +#menu { + position: fixed; + top: -5px; + right: 60px; + margin: 0; + padding: 15px 0 10px 5px; + background: rgba(255,255,255,0.3); + border: 1px solid #ddd; + text-align: left; + -moz-box-shadow: inset rgba(34,34,34,0.1) 0 4px 4px; + -webkit-box-shadow: inset rgba(34,34,34,0.1) 0 4px 4px; + box-shadow: inset rgba(34,34,34,0.1) 0 4px 4px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +#menu li { + list-style: none; +} +#menu li a { + display: block; + width: 150px; + padding: 1px 10px; + color: #7b7b7b; + font-size: 13px; +} +#menu li a:hover { + color: #000; + text-decoration: none; +} +.example { + margin-top: 25px; +} +pre { + width: 300px; + padding: 30px; + color: #8d8d8d; + font: 12px / 1.4 monaco, "helvetica neue", helvetica; + overflow-x: auto; + background: #fff; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + -moz-box-shadow: rgba(34,34,34,0.1) -1px -1px; + -webkit-box-shadow: rgba(34,34,34,0.1) -1px -1px; + box-shadow: rgba(34,34,34,0.1) -1px -1px; +} +pre.terminal { + width: 340px; + padding: 10px; + background: #2b2b2b; + color: #dadada; + -moz-box-shadow: #fff -1px -1px; + -webkit-box-shadow: #fff -1px -1px; + box-shadow: #fff -1px -1px; +} +p code { + padding: 2px 4px; + color: #626262; + font-size: 85%; + background: #fff; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + -moz-box-shadow: rgba(34,34,34,0.1) -1px -1px; + -webkit-box-shadow: rgba(34,34,34,0.1) -1px -1px; + box-shadow: rgba(34,34,34,0.1) -1px -1px; +} +#ribbon { + position: absolute; + top: 2.5em; + left: -3.75em; + background-color: #a00; + padding: 1px 0; + overflow: hidden; + -webkit-transform: rotate(-45deg); + -moz-transform: rotate(-45deg); + -moz-box-shadow: 1px 1px 3px rgba(0,0,0,0.3); + -webkit-box-shadow: 1px 1px 3px rgba(0,0,0,0.3); + box-shadow: 1px 1px 3px rgba(0,0,0,0.3); +} +#ribbon a { + color: #fff; + border: 1px solid #f18585; + display: block; + margin: 0.05em 0; + padding: 0.5em 3.5em; + text-align: center; + text-decoration: none; +} diff --git a/node_modules/jade/support/stylus/test/cases/css.media.css b/node_modules/jade/support/stylus/test/cases/css.media.css new file mode 100644 index 0000000..f7ab06b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.media.css @@ -0,0 +1,15 @@ +@media print { + body { + margin: 5px; + padding: 5px; + } +} +@media print { + body { + margin: 5px; + padding: 5px; + } + .no-print { + display: none; + } +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.media.styl b/node_modules/jade/support/stylus/test/cases/css.media.styl new file mode 100644 index 0000000..2403566 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.media.styl @@ -0,0 +1,17 @@ + +@media print { + body { + margin: 5px; + padding: 5px; + } +} + +@media print { + body { + margin: 5px; + padding: 5px; + } + .no-print { + display: none; + } +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.mixins.braces.css b/node_modules/jade/support/stylus/test/cases/css.mixins.braces.css new file mode 100644 index 0000000..7ffe13c --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.mixins.braces.css @@ -0,0 +1,31 @@ +button, +a.button { + display: block; + text-decoration: none; + background: #e3e3e3; + border: 1px solid #bdbdbd; + border-radius: 3px; + box-shadow: inset 0 0 1px 1px rgba(255,255,255,0.8); + color: #333; + font-family: "helvetica neue", helvetica, arial, sans-serif; + font-size: 12px; + font-weight: bold; + line-height: 1; + padding: 8px 0 9px; + text-align: center; + text-shadow: 0 1px 0 #fff; + width: 150px; +} +button:hover, +a.button:hover { + background: #dbdbdb; + box-shadow: inset 0 0 1px 1px rgba(255,255,255,0.5); + color: #222; + cursor: pointer; +} +button:active, +a.button:active { + background: #d6d6d6; + box-shadow: inset 0 0 1px 1px rgba(255,255,255,0.2); + color: #000; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.mixins.braces.styl b/node_modules/jade/support/stylus/test/cases/css.mixins.braces.styl new file mode 100644 index 0000000..ca8f737 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.mixins.braces.styl @@ -0,0 +1,53 @@ + +/* + * Reset button related properties so that + * a, button, and input's are supported. + */ + +-reset() { + display: block; + text-decoration: none; +} + +// just testing stuff + +get-width() { 150px; } + +/* + * Minimalistic flat button with white inset. + */ + +minimal-button(bg = #e3e3e3, intensity = 1) { + -reset(); + background: bg; + border: 1px solid darken(bg, 15% * intensity); + border-radius: 3px; + box-shadow: inset 0 0 1px 1px rgba(white, 0.8 * intensity); + color: #333; + font-family: 'helvetica neue', helvetica, arial, sans-serif; + font-size: 12px; + font-weight: bold; + line-height: 1; + padding: 8px 0 9px; + text-align: center; + text-shadow: 0 1px 0 rgba(white, 1 * intensity); + width: get-width(); + + &:hover { + background: darken(bg, 3%); + box-shadow: inset 0 0 1px 1px rgba(white, 0.5 * intensity); + color: #222; + cursor: pointer; + } + + &:active { + background: darken(bg, 5%); + box-shadow: inset 0 0 1px 1px rgba(white, 0.2 * intensity); + color: #000; + } +} + +button, +a.button { + minimal-button(); +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.mixins.css b/node_modules/jade/support/stylus/test/cases/css.mixins.css new file mode 100644 index 0000000..7ffe13c --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.mixins.css @@ -0,0 +1,31 @@ +button, +a.button { + display: block; + text-decoration: none; + background: #e3e3e3; + border: 1px solid #bdbdbd; + border-radius: 3px; + box-shadow: inset 0 0 1px 1px rgba(255,255,255,0.8); + color: #333; + font-family: "helvetica neue", helvetica, arial, sans-serif; + font-size: 12px; + font-weight: bold; + line-height: 1; + padding: 8px 0 9px; + text-align: center; + text-shadow: 0 1px 0 #fff; + width: 150px; +} +button:hover, +a.button:hover { + background: #dbdbdb; + box-shadow: inset 0 0 1px 1px rgba(255,255,255,0.5); + color: #222; + cursor: pointer; +} +button:active, +a.button:active { + background: #d6d6d6; + box-shadow: inset 0 0 1px 1px rgba(255,255,255,0.2); + color: #000; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.mixins.root.css b/node_modules/jade/support/stylus/test/cases/css.mixins.root.css new file mode 100644 index 0000000..5d9922d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.mixins.root.css @@ -0,0 +1,26 @@ +button, +a.button, +input[type=submit], +input[type=button] { + padding: 5px 10px; +} +button:hover, +a.button:hover, +input[type=submit]:hover, +input[type=button]:hover { + color: #fff; + background: #000; +} +button:hover em, +a.button:hover em, +input[type=submit]:hover em, +input[type=button]:hover em { + color: #808080; +} +button:active, +a.button:active, +input[type=submit]:active, +input[type=button]:active { + color: #000; + background: #fff; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.mixins.root.styl b/node_modules/jade/support/stylus/test/cases/css.mixins.root.styl new file mode 100644 index 0000000..b03ff8e --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.mixins.root.styl @@ -0,0 +1,25 @@ + +hover() + &:hover { + color: white; + background: black; + em { + color: gray; + } + } + &:active { + color: black; + background: white; + } + + +button(pad) + button, + a.button, + input[type=submit], + input[type=button] { + padding: pad; + hover(); + } + +button(5px 10px); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.mixins.root.wonky.css b/node_modules/jade/support/stylus/test/cases/css.mixins.root.wonky.css new file mode 100644 index 0000000..5d9922d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.mixins.root.wonky.css @@ -0,0 +1,26 @@ +button, +a.button, +input[type=submit], +input[type=button] { + padding: 5px 10px; +} +button:hover, +a.button:hover, +input[type=submit]:hover, +input[type=button]:hover { + color: #fff; + background: #000; +} +button:hover em, +a.button:hover em, +input[type=submit]:hover em, +input[type=button]:hover em { + color: #808080; +} +button:active, +a.button:active, +input[type=submit]:active, +input[type=button]:active { + color: #000; + background: #fff; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.mixins.root.wonky.styl b/node_modules/jade/support/stylus/test/cases/css.mixins.root.wonky.styl new file mode 100644 index 0000000..e7bb7e0 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.mixins.root.wonky.styl @@ -0,0 +1,17 @@ + +hover() + &:hover { color: white; background: black; + em { + color: gray; + } + } + &:active { color: black; background: white; } + + +button(pad) + button, + a.button, + input[type=submit], + input[type=button] { padding: pad; hover(); } + +button(5px 10px); \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.mixins.styl b/node_modules/jade/support/stylus/test/cases/css.mixins.styl new file mode 100644 index 0000000..fd4ceb8 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.mixins.styl @@ -0,0 +1,47 @@ + +/* + * Reset button related properties so that + * a, button, and input's are supported. + */ + +-reset() + display: block; + text-decoration: none; + +/* + * Minimalistic flat button with white inset. + */ + +minimal-button(bg = #e3e3e3, intensity = 1) + -reset() + background: bg; + border: 1px solid darken(bg, 15% * intensity); + border-radius: 3px; + box-shadow: inset 0 0 1px 1px rgba(white, 0.8 * intensity); + color: #333; + font-family: 'helvetica neue', helvetica, arial, sans-serif; + font-size: 12px; + font-weight: bold; + line-height: 1; + padding: 8px 0 9px; + text-align: center; + text-shadow: 0 1px 0 rgba(white, 1 * intensity); + width: 150px; + + &:hover { + background: darken(bg, 3%); + box-shadow: inset 0 0 1px 1px rgba(white, 0.5 * intensity); + color: #222; + cursor: pointer; + } + + &:active { + background: darken(bg, 5%); + box-shadow: inset 0 0 1px 1px rgba(white, 0.2 * intensity); + color: #000; + } + +button, +a.button { + minimal-button(); +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.selectors.css b/node_modules/jade/support/stylus/test/cases/css.selectors.css new file mode 100644 index 0000000..3ea3a18 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.selectors.css @@ -0,0 +1,37 @@ +body { + margin: 0; + padding: 5px; +} +body ul { + margin: 0; +} +body ul li:first-child { + border-top: none; +} +body ul li:last-child { + border-bottom: none; +} +ul li:first-child, +ul li:last-child { + display: none; +} +foo { + border-radius: 5px; +} +foo bar baz { + border-radius: 5px; +} +foo, +bar, +baz { + border-radius: 5px; +} +input[type=button] { + border-radius: 5px; +} +button, +input[type=button], +input[type=submit], +a.button { + border-radius: 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.selectors.styl b/node_modules/jade/support/stylus/test/cases/css.selectors.styl new file mode 100644 index 0000000..c42cbc8 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.selectors.styl @@ -0,0 +1,53 @@ + +body { + margin: 0; + padding: 5px; + ul { + /* test */ + margin: 0; + li:first-child { + border-top: none; + // test + } + // test + li:last-child { + border-bottom: none; + } + } +} + +ul { + li { + &:first-child, + &:last-child { + display: none; + } + } +} + + +foo { + border-radius: 5px; +} + +foo bar baz { + border-radius: 5px; +} + +foo +bar +baz { + border-radius: 5px; +} + +input[type=button] { + border-radius: 5px; +} + + +button +input[type=button] +input[type=submit] +a.button { + border-radius: 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.whitespace.css b/node_modules/jade/support/stylus/test/cases/css.whitespace.css new file mode 100644 index 0000000..146a653 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.whitespace.css @@ -0,0 +1,37 @@ +body { + padding: 5px; +} +body { + padding: 5px; +} +body { + padding: 5px; + margin: 0; +} +body { + padding: 5px; + margin: 0; +} +body { + padding: 5px; + margin: 0; +} +body { + padding: 5px; + margin: 0; +} +body { + padding: 5px; +} +ul li { + padding: 5px; +} +body { + padding: 5px; +} +body { + padding: 5px; +} +input { + foo: "bar"; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/css.whitespace.styl b/node_modules/jade/support/stylus/test/cases/css.whitespace.styl new file mode 100644 index 0000000..13ea87a --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/css.whitespace.styl @@ -0,0 +1,36 @@ + +body + padding 5px + +body + padding 5px + +body + padding: 5px; margin: 0; + +body + padding: 5px; + margin: 0; + +body { + padding: 5px; + margin: 0; +} + +body { + padding: 5px; margin: 0; +} + +body { +padding: 5px; +} + +ul { + li { + padding: 5px; +} +} + + +body{padding: 5px;} +body{padding: 5px}input{foo:'bar'} diff --git a/node_modules/jade/support/stylus/test/cases/escape.css b/node_modules/jade/support/stylus/test/cases/escape.css new file mode 100644 index 0000000..1eda758 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/escape.css @@ -0,0 +1,4 @@ +body { + font: 14px + 1.2; + border-radius: 5px 2px ( 5px 1px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/escape.styl b/node_modules/jade/support/stylus/test/cases/escape.styl new file mode 100644 index 0000000..bbc614f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/escape.styl @@ -0,0 +1,4 @@ + +body + font 14px \+ 1.2 + border-radius 5px 2px \( 5px 1px diff --git a/node_modules/jade/support/stylus/test/cases/for.complex.css b/node_modules/jade/support/stylus/test/cases/for.complex.css new file mode 100644 index 0000000..e0259a8 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/for.complex.css @@ -0,0 +1,44 @@ +body { + foo: a; + foo: b; + foo: c; + foo: d; + foo: e; + foo: f; + foo: g; +} +body { + foo: a; +} +body { + foo: 0 : b; + foo: 1 : c; + foo: 2 : d; +} +body { + foo: error test "test"; + foo: error test "foo"; +} +body { + foo: 0 a; + foo: 1 a; + foo: 2 a; + foo: 3 a; + foo: 0 b; + foo: 1 b; + foo: 2 b; + foo: 3 b; + foo: 0 c; + foo: 1 c; + foo: 2 c; + foo: 3 c; + foo: 0 d; + foo: 1 d; + foo: 2 d; + foo: 3 d; +} +body { + foo: helvetica; + foo: arial; + foo: sans-serif; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/for.complex.styl b/node_modules/jade/support/stylus/test/cases/for.complex.styl new file mode 100644 index 0000000..d3d442a --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/for.complex.styl @@ -0,0 +1,28 @@ +vals = a b c d e f g + +body + for val in vals + foo val + +body + for val in vals[0] + foo val + +body + for val, i in vals[1..3] + foo i unquote(':') val + +body + for msg in (error 'test') (error 'foo') + foo msg[0] test msg[1] + +body + for char in a b c d + for num in 0 1 2 3 + foo num char + +fonts = helvetica, arial, sans-serif + +body + for font in fonts + foo font diff --git a/node_modules/jade/support/stylus/test/cases/for.css b/node_modules/jade/support/stylus/test/cases/for.css new file mode 100644 index 0000000..f8129ff --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/for.css @@ -0,0 +1,52 @@ +body { + test-args: 1 2 3; + foo: 1; + foo: 2; + foo: 3; + test-args: 1 2 3 4 5; + foo: 1 2; + foo: 3 4; + foo: 5; + test-args: 1 2 3 4; + foo: 1 2; + foo: 3 4; +} +body { + foo: 1 2; + foo: 3 4; +} +body { + foo: 1; + foo: 2; + foo: 3; + foo: 4; + foo: 5; +} +body { + foo: 1; + foo: 2; + foo: 3; +} +body foo { + bar: 1; +} +body foo { + bar: 2; +} +body foo { + bar: 3; +} +body foo bar { + baz: 1; +} +body foo bar { + baz: 2; +} +body foo bar { + baz: 3; +} +body { + foo: 0 foo; + foo: 1 bar; + foo: 2 baz; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/for.function.css b/node_modules/jade/support/stylus/test/cases/for.function.css new file mode 100644 index 0000000..5613a7a --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/for.function.css @@ -0,0 +1,20 @@ +body { + foo: 10; + foo: 20; + foo: 10; +} +body { + foo: "foo bar baz"; + foo: "foo, bar, baz"; + foo: "1 2 3"; + foo: "1, 2, 3"; +} +body { + foo: 0 Impact; + foo: 1 Arial; + foo: 2 sans-serif; +} +body { + foo: 24; + foo: 30; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/for.function.styl b/node_modules/jade/support/stylus/test/cases/for.function.styl new file mode 100644 index 0000000..84a5a21 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/for.function.styl @@ -0,0 +1,51 @@ + +sum(nums...) + sum = 0 + for n in nums + sum += n + +sum2(nums...) + sum = 0 + for n in nums + sum += n + sum * 2 + +sum3(nums...) + sum = 0 + sum += n for n in nums + +body + foo sum(1,2,3,4) + foo sum2(1,2,3,4) + foo sum3(1,2,3,4) + +join(delim, args) + buf = '' + for arg, i in args + buf += i ? delim + arg : arg + +join2(delim, args) + buf = '' + buf += i ? delim + arg : arg for arg, i in args + +body + foo join(' ', foo bar baz) + foo join(', ', foo bar baz) + foo join2(' ', 1 2 3) + foo join2(', ', 1 2 3) + +body + fonts = Impact Arial sans-serif + for font, i in fonts + foo i font + +last-even(nums...) + ret = n if n % 2 == 0 for n in nums + ret + +first-even(nums...) + return n if n % 2 == 0 for n in nums + +body + foo last-even(1,3,30,5,6,12,2,24,3) + foo first-even(1,3,30,5,6,12,2,24,3) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/for.styl b/node_modules/jade/support/stylus/test/cases/for.styl new file mode 100644 index 0000000..44617e4 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/for.styl @@ -0,0 +1,44 @@ + +test(args...) + test-args args + for arg in args + foo arg + +size(a, b) + return a b + +body + test 1 2 3 + test (1 2) (3 4) 5 + test size(1, 2) size(3, 4) + +body + sizes = size(1, 2) size(3, 4) + for size in sizes + foo size + +body + for n in 1..5 + foo n + +body + for n in 1 2 3 + foo n + +body + for n in 1 2 3 + foo + bar n + +test(args...) + foo + for arg in args + bar + baz arg + +body + test 1 2 3 + +body + for val, index in foo bar baz + foo index val \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/function.arguments.css b/node_modules/jade/support/stylus/test/cases/function.arguments.css new file mode 100644 index 0000000..1a3a83b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/function.arguments.css @@ -0,0 +1,4 @@ +body { + padding: 15; + padding: 1 2; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/function.arguments.styl b/node_modules/jade/support/stylus/test/cases/function.arguments.styl new file mode 100644 index 0000000..9cb7285 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/function.arguments.styl @@ -0,0 +1,14 @@ + +sum() + n = 0 + for num in arguments + n = n + num + n + +test(a, b) + a = b + (arguments[0] a) + +body + padding sum(1,2,3,4,5) + padding test(1,2) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/function.literals.css b/node_modules/jade/support/stylus/test/cases/function.literals.css new file mode 100644 index 0000000..30ad857 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/function.literals.css @@ -0,0 +1,6 @@ +body { + foo: bar(1px, baz(5px)); + bar: baz(5px) baz(5px); + foo: recurse; + foo: recurse; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/function.literals.styl b/node_modules/jade/support/stylus/test/cases/function.literals.styl new file mode 100644 index 0000000..d1179b9 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/function.literals.styl @@ -0,0 +1,12 @@ + +something(arg) + bar arg arg + +recurse() + foo recurse + foo recurse + +body + foo bar(1px, baz(5px)) + something(baz(5px)) + recurse() \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.arg-calls.css b/node_modules/jade/support/stylus/test/cases/functions.arg-calls.css new file mode 100644 index 0000000..8e0891f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.arg-calls.css @@ -0,0 +1,3 @@ +form input { + padding: 10px 5px 10px 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.arg-calls.styl b/node_modules/jade/support/stylus/test/cases/functions.arg-calls.styl new file mode 100644 index 0000000..f2739eb --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.arg-calls.styl @@ -0,0 +1,9 @@ +add(a, b) + a + b + +pad(x, y = x) + padding y x y x + +form input + n = 5 + pad(5px, unit(add(n, n), 'px')) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.call.css b/node_modules/jade/support/stylus/test/cases/functions.call.css new file mode 100644 index 0000000..9dbadae --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.call.css @@ -0,0 +1,4 @@ +body { + foo: 15; + foo: 7; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.call.styl b/node_modules/jade/support/stylus/test/cases/functions.call.styl new file mode 100644 index 0000000..c85adb1 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.call.styl @@ -0,0 +1,7 @@ + +add(a, b) + a + b + +body + foo add(5, 10) + foo add(5, 2) diff --git a/node_modules/jade/support/stylus/test/cases/functions.css b/node_modules/jade/support/stylus/test/cases/functions.css new file mode 100644 index 0000000..e3c22b2 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.css @@ -0,0 +1,11 @@ +body { + padding: 10px 5px 10px 5px; +} +form .button { + padding-left: 15px; +} +body { + foo: bottom; + foo: right; + foo: bottom right; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.defaults.css b/node_modules/jade/support/stylus/test/cases/functions.defaults.css new file mode 100644 index 0000000..19f7e77 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.defaults.css @@ -0,0 +1,15 @@ +body { + padding: 15px 5px 15px 5px; +} +a.button { + padding: 10px 10px 10px 10px; +} +a.button-2 { + padding: 2px 10px 2px 10px; +} +body { + padding: 10px; +} +.button { + padding: 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.defaults.styl b/node_modules/jade/support/stylus/test/cases/functions.defaults.styl new file mode 100644 index 0000000..2946141 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.defaults.styl @@ -0,0 +1,30 @@ + +size = 15px +small = 5 + +pad-var(x, y = size) + padding y x y x + +pad-arg(x, y = x) + padding y x y x + +body + pad-var(5px) + +a.button + pad-arg(10px) + +a.button-2 + pad-arg(10px, 2px) + +add(a, b) + a + b + +pad-call(n = unit(add(small, small), 'px')) + padding n + +body + pad-call() + +.button + pad-call(5px) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.multi-line.css b/node_modules/jade/support/stylus/test/cases/functions.multi-line.css new file mode 100644 index 0000000..0818fca --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.multi-line.css @@ -0,0 +1,9 @@ +body { + padding: 2 1; +} +body { + padding: 2 1; +} +body { + padding: 3 2; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.multi-line.styl b/node_modules/jade/support/stylus/test/cases/functions.multi-line.styl new file mode 100644 index 0000000..b17195c --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.multi-line.styl @@ -0,0 +1,25 @@ + +pad( + x = 5 +, y = 10 +) + padding y x + +body + pad 1 2 + +pad( + x = 5 + , y = 10 +) + padding y x + +body + pad 1 2 + +body + pad(x + , y + ) + padding y x + pad 2 3 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.multiple-calls.css b/node_modules/jade/support/stylus/test/cases/functions.multiple-calls.css new file mode 100644 index 0000000..d860a55 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.multiple-calls.css @@ -0,0 +1,13 @@ +body { + padding: 5px; + padding: 100px; + padding: 10px; + padding: 1px; + padding: 100px; +} +form { + padding-left: 5px; + padding-right: 5px; + padding-top: 10px; + padding-bottom: 10px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.multiple-calls.styl b/node_modules/jade/support/stylus/test/cases/functions.multiple-calls.styl new file mode 100644 index 0000000..9e7353b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.multiple-calls.styl @@ -0,0 +1,26 @@ + +pad(y = 100px) + padding unit(y, 'px') + +body + pad(5px) + pad() + pad(10px) + pad(1) + pad() + +pad-x(n) + n = unit(n, 'px') + padding-left n + padding-right n + +pad-y(y) + padding-top n = unit(y, 'px') + padding-bottom n + +pad(x, y) + pad-x(x) + pad-y(y) + +form + pad(5, 10) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.nested-calls.css b/node_modules/jade/support/stylus/test/cases/functions.nested-calls.css new file mode 100644 index 0000000..104ae05 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.nested-calls.css @@ -0,0 +1,3 @@ +body { + foo: 13; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.nested-calls.styl b/node_modules/jade/support/stylus/test/cases/functions.nested-calls.styl new file mode 100644 index 0000000..eda05a3 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.nested-calls.styl @@ -0,0 +1,9 @@ + +sub(a, b) + a - b + +add(a, b) + a + b + +body + foo add(5, add(5, sub(5, 2))) diff --git a/node_modules/jade/support/stylus/test/cases/functions.nested.css b/node_modules/jade/support/stylus/test/cases/functions.nested.css new file mode 100644 index 0000000..6a3c670 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.nested.css @@ -0,0 +1,10 @@ +body { + padding: 3.5; +} +body { + padding: 3.5; +} +body { + padding: 10; + padding: 0; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.nested.styl b/node_modules/jade/support/stylus/test/cases/functions.nested.styl new file mode 100644 index 0000000..4f9a2f5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.nested.styl @@ -0,0 +1,37 @@ + +add(a, b) + div(a, b) + a / b + a + div(b, 2) + +body + padding add(1,5) + // => 3.5 + +add(a, b) + half() + b / 2 + a + half() + +body + padding add(1,5) + // => 3.5 + +getFunction(name) + if name == 'add' + add(a, b) + a + b + else + sub(a, b) + a - b + +body + fn = getFunction('add') + padding fn(5, 5) + // => 10 + + fn = getFunction('sub') + fn2 = fn + fn3 = fn2 + padding fn3(5, 5) + // => 0 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.property.css b/node_modules/jade/support/stylus/test/cases/functions.property.css new file mode 100644 index 0000000..3495051 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.property.css @@ -0,0 +1,10 @@ +form { + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +a.button { + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.property.styl b/node_modules/jade/support/stylus/test/cases/functions.property.styl new file mode 100644 index 0000000..cf584ae --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.property.styl @@ -0,0 +1,11 @@ + +border-radius(size) + -webkit-border-radius size + -moz-border-radius size + border-radius size + +form + border-radius 5px + +a.button + border-radius 5px \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.return.css b/node_modules/jade/support/stylus/test/cases/functions.return.css new file mode 100644 index 0000000..37706f0 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.return.css @@ -0,0 +1,15 @@ +body { + foo: no; + foo: yes; + foo: false; + foo: yes; + foo: "a is not a unit"; + foo: 2; +} +body { + foo: five; + foo: something; +} +body { + foo: 3; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.return.each.css b/node_modules/jade/support/stylus/test/cases/functions.return.each.css new file mode 100644 index 0000000..1c38717 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.return.each.css @@ -0,0 +1,10 @@ +body { + foo: "1 2 3"; + foo: "1, 2, 3"; + foo: "1,2,3"; +} +body { + foo: "1 2 3"; + foo: "1, 2, 3"; + foo: "1,2,3"; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.return.each.styl b/node_modules/jade/support/stylus/test/cases/functions.return.each.styl new file mode 100644 index 0000000..0f2f1f8 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.return.each.styl @@ -0,0 +1,23 @@ + +join1(delim, vals) + buf = '' + for val, i in vals + if i + buf += delim + val + else + buf += val + +join2(delim, vals) + buf = '' + for val, i in vals + buf += i ? delim + val : val + +body + foo join1(' ', 1 2 3) + foo join1(', ', 1 2 3) + foo join1(',', 1 2 3) + +body + foo join2(' ', 1 2 3) + foo join2(', ', 1 2 3) + foo join2(',', 1 2 3) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.return.styl b/node_modules/jade/support/stylus/test/cases/functions.return.styl new file mode 100644 index 0000000..6aab55b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.return.styl @@ -0,0 +1,86 @@ + +large(n) + unless n is a 'unit' + return false + if n > 100 + yes + else + no + +awesome() + yes + +nested(a = 5) + if a is a 'unit' + b = 10 + if a + c = 100 + c = 100 + c = 100 + c = 100 + awesome() + else + 'b is not a unit' + else + 'a is not a unit' + +set() + 1 + return 2 + 3 + +body + // no + foo large(15) + + // yes + foo large(150) + + // false + foo large('string') + + // yes + foo nested() + + // 'a is not a unit' + foo nested('wahoo') + + // 2 + foo set() + +deep-implicit() + one + if false + two + else + if true + something + three + else + four + five + +deep-explicit() + one + if false + two + else + if true + return something + three + else + four + five + +body + foo deep-implicit() + foo deep-explicit() + +test() + return 1 if false + return 2 if false + return 3 if true + return 4 + +body + foo test() \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.styl b/node_modules/jade/support/stylus/test/cases/functions.styl new file mode 100644 index 0000000..8106c2f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.styl @@ -0,0 +1,34 @@ + +add(a, b) + a + b + +pad(x, y) + padding y x y x + +body + pad(5px, 10px) + +form .button + padding-left add(10px, 5px) + +-opposite-position(pos) + if pos == top + bottom + else if pos == bottom + top + else if pos == left + right + else if pos == right + left + else + error('Invalid position ' + pos) + +opposite(positions) + for pos in positions + pos = -opposite-position(pos) + ret = ret is defined ? ret pos : pos + +body + foo opposite(top) + foo opposite(left) + foo opposite(top left) diff --git a/node_modules/jade/support/stylus/test/cases/functions.variable.css b/node_modules/jade/support/stylus/test/cases/functions.variable.css new file mode 100644 index 0000000..99fd5ba --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.variable.css @@ -0,0 +1,9 @@ +body { + font: 28px; + padding-left: 5px; + padding-right: 5px; +} +form { + padding-top: 10px; + padding-bottom: 10px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.variable.ident.css b/node_modules/jade/support/stylus/test/cases/functions.variable.ident.css new file mode 100644 index 0000000..b7cdff3 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.variable.ident.css @@ -0,0 +1,3 @@ +body { + font: 28px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.variable.ident.styl b/node_modules/jade/support/stylus/test/cases/functions.variable.ident.styl new file mode 100644 index 0000000..abc45ee --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.variable.ident.styl @@ -0,0 +1,11 @@ + +add(a, b) + a + b + +size-function = add + +size(n) + size-function(n, n) + +body + font size(14px) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/functions.variable.styl b/node_modules/jade/support/stylus/test/cases/functions.variable.styl new file mode 100644 index 0000000..c3d6a66 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/functions.variable.styl @@ -0,0 +1,27 @@ + +add(a, b) + a + b + +size-function = add + +size(n) + size-function(n, n) + +padding-x(n) + padding-left n + padding-right n + +padding-y(n) + padding-top n + padding-bottom n + +mixin(name, n) + name(n) + +body + fn = padding-x + font size(14px) + fn(5px) + +form + mixin(padding-y, 10px) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/if.css b/node_modules/jade/support/stylus/test/cases/if.css new file mode 100644 index 0000000..41a12f5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/if.css @@ -0,0 +1,43 @@ +body { + padding: 100; +} +body { + padding: false; +} +body { + padding: 150; +} +body { + padding: 75; +} +body { + padding: -1; +} +body { + padding: 1; +} +body { + foo: yes; + foo: no; + foo: zero; + foo: invalid; +} +body .input { + padding: 5px; + no: margin; +} +body form input { + foo: no; + foo: bar; + bar: baz; +} +body something { + foo: bar; + bar: baz; +} +body .nested { + foo: bar; +} +body .nested .hidden { + display: none; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/if.else.css b/node_modules/jade/support/stylus/test/cases/if.else.css new file mode 100644 index 0000000..5d48da0 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/if.else.css @@ -0,0 +1,6 @@ +body { + foo: string; + foo: unit; + foo: color; + foo: unknown; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/if.else.styl b/node_modules/jade/support/stylus/test/cases/if.else.styl new file mode 100644 index 0000000..bddded5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/if.else.styl @@ -0,0 +1,16 @@ + +naive-type(val = null) + if val is a 'unit' + unit + else if val is a 'color' + color + else if val is a 'string' + string + else + unknown + +body + foo naive-type('test') + foo naive-type(12) + foo naive-type(#fff) + foo naive-type() diff --git a/node_modules/jade/support/stylus/test/cases/if.mixin.css b/node_modules/jade/support/stylus/test/cases/if.mixin.css new file mode 100644 index 0000000..a83dec6 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/if.mixin.css @@ -0,0 +1,7 @@ +body { + got: above; + got: below; + got: empty; + yup: just lots of empty; + padding: 10px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/if.mixin.styl b/node_modules/jade/support/stylus/test/cases/if.mixin.styl new file mode 100644 index 0000000..3d36fe3 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/if.mixin.styl @@ -0,0 +1,24 @@ + +test(n) + if n < 0 + got below + else + got above + +test-nested(a, b) + if a > 1 + if unit(-5) == '' + got empty + yup just lots of empty + else + got unit(-5px) + +test-unless(n = 0) + unless n + padding 10px + +body + test(5px) + test(-5px) + test-nested(5px, -5) + test-unless() diff --git a/node_modules/jade/support/stylus/test/cases/if.postfix.css b/node_modules/jade/support/stylus/test/cases/if.postfix.css new file mode 100644 index 0000000..d775ffc --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/if.postfix.css @@ -0,0 +1,61 @@ +body { + foo: 1; + foo: 2; + foo: 3; + foo: 4; + foo: 5; + foo: 6; + foo: 7; +} +body { + foo: 3; +} +body { + foo: true; + foo: true; +} +body { + foo: true; + foo: true; +} +body { + foo: 5; +} +body { + foo: bar; + foo: baz; +} +body { + foo: bar; + foo: baz; +} +@import "foo.css"; +body { + foo: 5; +} +body { + foo: string; + foo: number; + foo: unknown; +} +body { + foo: true; + foo: true; + foo: false; +} +body { + fonts: arial, sans-serif; +} +body { + foo: yes; + foo: yes; + foo: yes; + foo: ; + foo: ; +} +body { + foo: yes; + foo: no; + foo: zero; + foo: invalid; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/if.postfix.styl b/node_modules/jade/support/stylus/test/cases/if.postfix.styl new file mode 100644 index 0000000..9639d4f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/if.postfix.styl @@ -0,0 +1,110 @@ + +mixin() + if true + foo 6 + foo 7 if true + foo 8 unless true + +body + foo 1 + foo 2 if true + foo 3 unless false + if true + foo 4 + foo 5 + mixin() + +body + foo 1 if false + foo 2 unless true + foo 3 + +above-5(n) + true if n > 5 + +body + foo above-5(2) == null + foo above-5(6) == true + +below-5(n) + return true unless n > 5 + false + +body + foo below-5(3) == true + foo below-5(7) == false + +body + foo 5 unless 5 + 5 == 10 + +body + foo 5 if 5 + 5 == 10 and true + +mixin() + foo bar + foo baz + +body + mixin() if true + mixin() unless true + +body + mixin test if true + + +@import 'foo.css' if true +@charset 'foo' if false + +num = 5 unless num is defined + +body + foo num + +type(arg = null) + return string if arg is a 'string' + return number if arg is a 'unit' + unknown + +body + foo type('test') + foo type(12) + foo type() + +is-a-string(arg = null) + arg is a 'string' unless arg == null + +body + foo is-a-string() == null + foo is-a-string('test') + foo is-a-string(12) if true + +empty(expr) + 0 == length(expr) + +font-list = arial, sans-serif +body + fonts font-list unless empty(font-list) + font-list = () + fonts font-list unless empty(font-list) + +truthy(val) + yes if 1 == val or 'yes' == val or 'y' == val + +body + foo truthy(1) + foo truthy('yes') + foo truthy('y') + foo truthy(0) + foo truthy('no') + +negative(n) + return invalid unless n is a 'unit' + return yes if n < 0 + return no if n > 0 + zero + +body + foo negative(-5) + foo negative(5) + foo negative(0) + foo negative('asdf') \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/if.selectors.css b/node_modules/jade/support/stylus/test/cases/if.selectors.css new file mode 100644 index 0000000..51e1118 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/if.selectors.css @@ -0,0 +1,6 @@ +form input { + border: 1px solid #eee; +} +body { + font: 12px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/if.selectors.styl b/node_modules/jade/support/stylus/test/cases/if.selectors.styl new file mode 100644 index 0000000..f63848d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/if.selectors.styl @@ -0,0 +1,12 @@ + +if false + something + with a-prop + +if true + form + input + border 1px solid #eee + if true + body + font 12px \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/if.styl b/node_modules/jade/support/stylus/test/cases/if.styl new file mode 100644 index 0000000..f2f9746 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/if.styl @@ -0,0 +1,99 @@ +n = false + +if !n + n = 100 + +body + padding n + +n = false + +if not not n + n = 50 + +body + padding n + +if not n + n = 150 + +body + padding n + +if n + n = n / 2 +else + n = 10000 + +body + padding n + +if n > 100 + n = n * 2 +else + n = -1 + +body + padding n + +n = 75 + +if n < 50 + n = n +else + if n > 50 and n < 100 + n = 1 + else + n = -1 + +body + padding n + +negative(n) + unless n is a 'unit' + return invalid + if n < 0 + yes + else if n > 0 + no + else + zero + +body + foo negative(-5) + foo negative(5) + foo negative(0) + foo negative('asdf') + +body + .input + pad = true + margin = false + if pad + padding 5px + if margin + margin 5px + else + no unquote('margin') + +mixin() + foo bar + bar baz + +body + form input + if true + foo negative(5) + mixin() + something + mixin() + +body + .nested + if true + if true + if true + foo bar + .hidden + if true + display none \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.basic.css b/node_modules/jade/support/stylus/test/cases/import.basic.css new file mode 100644 index 0000000..2f2a6d9 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.basic.css @@ -0,0 +1,9 @@ +.a { + color: #f00; +} +.b { + color: #008000; +} +.c { + color: #00f; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.basic.styl b/node_modules/jade/support/stylus/test/cases/import.basic.styl new file mode 100644 index 0000000..f8850e3 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.basic.styl @@ -0,0 +1,2 @@ + +@import "a" diff --git a/node_modules/jade/support/stylus/test/cases/import.basic/a.styl b/node_modules/jade/support/stylus/test/cases/import.basic/a.styl new file mode 100644 index 0000000..c6aee44 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.basic/a.styl @@ -0,0 +1,5 @@ + +.a + color red + +@import "b" \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.basic/b.styl b/node_modules/jade/support/stylus/test/cases/import.basic/b.styl new file mode 100644 index 0000000..c514e75 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.basic/b.styl @@ -0,0 +1,5 @@ + +.b + color green + +@import "c" \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.basic/c.styl b/node_modules/jade/support/stylus/test/cases/import.basic/c.styl new file mode 100644 index 0000000..abc49ca --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.basic/c.styl @@ -0,0 +1,3 @@ + +.c + color blue \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.complex.css b/node_modules/jade/support/stylus/test/cases/import.complex.css new file mode 100644 index 0000000..3ba73e8 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.complex.css @@ -0,0 +1,9 @@ +one { + foo: bar; +} +two { + foo: bar; +} +three { + foo: bar; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.complex.styl b/node_modules/jade/support/stylus/test/cases/import.complex.styl new file mode 100644 index 0000000..8d4e813 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.complex.styl @@ -0,0 +1 @@ +@import "./import.complex/a" \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.complex/a.styl b/node_modules/jade/support/stylus/test/cases/import.complex/a.styl new file mode 100644 index 0000000..4c4e68b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.complex/a.styl @@ -0,0 +1,4 @@ +one + foo bar + +@import "./nested/b" \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.complex/c.styl b/node_modules/jade/support/stylus/test/cases/import.complex/c.styl new file mode 100644 index 0000000..c400d08 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.complex/c.styl @@ -0,0 +1,2 @@ +three + foo bar \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.complex/nested/b.styl b/node_modules/jade/support/stylus/test/cases/import.complex/nested/b.styl new file mode 100644 index 0000000..1316242 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.complex/nested/b.styl @@ -0,0 +1,4 @@ +two + foo bar + +@import "../c" \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.index.css b/node_modules/jade/support/stylus/test/cases/import.index.css new file mode 100644 index 0000000..f34b6a0 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.index.css @@ -0,0 +1,9 @@ +body { + one: 1; +} +body { + two: 2; +} +body { + three: 3; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.index.styl b/node_modules/jade/support/stylus/test/cases/import.index.styl new file mode 100644 index 0000000..4ef8282 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.index.styl @@ -0,0 +1,2 @@ + +@import 'import.index/vendor' \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.index/vendor/a.styl b/node_modules/jade/support/stylus/test/cases/import.index/vendor/a.styl new file mode 100644 index 0000000..a80eaac --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.index/vendor/a.styl @@ -0,0 +1,2 @@ +body + one 1 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.index/vendor/b.styl b/node_modules/jade/support/stylus/test/cases/import.index/vendor/b.styl new file mode 100644 index 0000000..ed6a757 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.index/vendor/b.styl @@ -0,0 +1,2 @@ +body + two 2 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.index/vendor/c.styl b/node_modules/jade/support/stylus/test/cases/import.index/vendor/c.styl new file mode 100644 index 0000000..0b63b12 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.index/vendor/c.styl @@ -0,0 +1,2 @@ +body + three 3 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.index/vendor/index.styl b/node_modules/jade/support/stylus/test/cases/import.index/vendor/index.styl new file mode 100644 index 0000000..fb919a9 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.index/vendor/index.styl @@ -0,0 +1,4 @@ + +@import 'a' +@import 'b' +@import 'c' \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.literal.css b/node_modules/jade/support/stylus/test/cases/import.literal.css new file mode 100644 index 0000000..54fd5ca --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.literal.css @@ -0,0 +1,2 @@ +@import "foo/bar.css"; +@import "bar/baz.css"; \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.literal.styl b/node_modules/jade/support/stylus/test/cases/import.literal.styl new file mode 100644 index 0000000..d39dfa3 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.literal.styl @@ -0,0 +1,3 @@ + +@import "foo/bar.css" +@import 'bar/baz.css' \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.mixins.css b/node_modules/jade/support/stylus/test/cases/import.mixins.css new file mode 100644 index 0000000..b526a7f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.mixins.css @@ -0,0 +1,7 @@ +body { + padding: 10px 5px 10px 5px; +} +form { + padding-left: 5px; + padding-right: 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.mixins.styl b/node_modules/jade/support/stylus/test/cases/import.mixins.styl new file mode 100644 index 0000000..8819d7b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.mixins.styl @@ -0,0 +1,9 @@ + +if true + @import "mixins/box" + +body + pad 5px 10px + +form + pad-x 5px \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.ordering.css b/node_modules/jade/support/stylus/test/cases/import.ordering.css new file mode 100644 index 0000000..dfae959 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.ordering.css @@ -0,0 +1,15 @@ +one { + foo: bar; +} +two { + foo: bar; +} +three { + foo: bar; +} +four { + foo: bar; +} +five { + foo: bar; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.ordering.styl b/node_modules/jade/support/stylus/test/cases/import.ordering.styl new file mode 100644 index 0000000..afec87d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.ordering.styl @@ -0,0 +1,12 @@ + +dir = 'import.ordering' + +one + foo bar + +@import dir + "/two" + +three + foo bar + +@import dir + '/four' diff --git a/node_modules/jade/support/stylus/test/cases/import.ordering/five.styl b/node_modules/jade/support/stylus/test/cases/import.ordering/five.styl new file mode 100644 index 0000000..05ee8a9 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.ordering/five.styl @@ -0,0 +1,2 @@ +five + foo bar \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.ordering/four.styl b/node_modules/jade/support/stylus/test/cases/import.ordering/four.styl new file mode 100644 index 0000000..58392a1 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.ordering/four.styl @@ -0,0 +1,4 @@ +four + foo bar + +@import "import.ordering/five" \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/import.ordering/two.styl b/node_modules/jade/support/stylus/test/cases/import.ordering/two.styl new file mode 100644 index 0000000..15f8e04 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/import.ordering/two.styl @@ -0,0 +1,2 @@ +two + foo bar \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/important.css b/node_modules/jade/support/stylus/test/cases/important.css new file mode 100644 index 0000000..a7c144a --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/important.css @@ -0,0 +1,6 @@ +a { + color: #f00 !important; +} +a.button { + color: #00f; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/important.styl b/node_modules/jade/support/stylus/test/cases/important.styl new file mode 100644 index 0000000..8500932 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/important.styl @@ -0,0 +1,6 @@ + +a + color red !important + +a.button + color blue \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/interpolation.properties.css b/node_modules/jade/support/stylus/test/cases/interpolation.properties.css new file mode 100644 index 0000000..801c157 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/interpolation.properties.css @@ -0,0 +1,40 @@ +#login { + -webkit-border-radius: 1px 2px / 3px 4px; + -moz-border-radius: 1px 2px / 3px 4px; + border-radius: 1px 2px / 3px 4px; +} +body { + foo: bar; + foo-something: foo; + foo-something-bar: foo; + something-foo: foo; + something: foo; +} +body { + test-stuff-yup: awesome; + -webkit-border-radius: awesome; + -webkit-box-shadow: awesome; +} +body { + foo: "one"; + foo: "two"; +} +body { + -webkit-something: foo; + something: foo; +} +body form input { + -webkit-something: foo; + something: foo; +} +body form input p { + something: foo; +} +body { + foo-test-baz: bar; + foo-test: bar; + test: bar; + position: absolute; + top: 0; + right: 0; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/interpolation.properties.styl b/node_modules/jade/support/stylus/test/cases/interpolation.properties.styl new file mode 100644 index 0000000..b33dc2b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/interpolation.properties.styl @@ -0,0 +1,56 @@ + +vendor(prop, args) + -webkit-{prop} args + -moz-{prop} args + {prop} args + +border-radius() + vendor('border-radius', arguments) + +#login + border-radius 1px 2px / 3px 4px + +body + prop = 'something' + foo bar + foo-{prop} foo + foo-{prop}-bar foo + {prop}-foo foo + {prop} foo + +body + {'test' + '-stuff'}-yup awesome + -webkit-{border-radius} awesome + -webkit-{box-shadow} awesome + +testing(var, one, two) + {var} + +body + foo testing('one', 1, 2) + foo testing('two', 1, 2) + +body + nested(prop) + -webkit-{prop} foo + {prop} foo + form input + -webkit-{prop} foo + {prop} foo + p + {prop} foo + nested('something') + +top-right() + position absolute + top 0 + right 0 + +foo(ret) + ret + +body + foo-{foo('test')}-baz bar + foo-{foo('test')} bar + {foo('test')} bar + {foo('top')}-right bar diff --git a/node_modules/jade/support/stylus/test/cases/introspection.css b/node_modules/jade/support/stylus/test/cases/introspection.css new file mode 100644 index 0000000..ce4a1d6 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/introspection.css @@ -0,0 +1,7 @@ +got { + root: true; +} +body { + got: "a mixin"; + foo: "not a mixin"; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/introspection.styl b/node_modules/jade/support/stylus/test/cases/introspection.styl new file mode 100644 index 0000000..8433995 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/introspection.styl @@ -0,0 +1,14 @@ +reset() + if mixin == 'root' + got + root true + else if mixin + got 'a mixin' + else + 'not a mixin' + +reset() + +body + reset() + foo reset() \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/jquery.css b/node_modules/jade/support/stylus/test/cases/jquery.css new file mode 100644 index 0000000..6562ed2 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/jquery.css @@ -0,0 +1,3 @@ +body { + padding: 10px 10px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/jquery.styl b/node_modules/jade/support/stylus/test/cases/jquery.styl new file mode 100644 index 0000000..36feb65 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/jquery.styl @@ -0,0 +1,5 @@ +pad( x , y = x ) + padding x y + +body + pad( 10px ) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/list.css b/node_modules/jade/support/stylus/test/cases/list.css new file mode 100644 index 0000000..6c1c179 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/list.css @@ -0,0 +1,3 @@ +body { + font: 12px "Lucida Grande", Arial, sans-serif; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/list.styl b/node_modules/jade/support/stylus/test/cases/list.styl new file mode 100644 index 0000000..08da49c --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/list.styl @@ -0,0 +1,3 @@ + +body + font 12px "Lucida Grande", Arial, sans-serif \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/literal.css b/node_modules/jade/support/stylus/test/cases/literal.css new file mode 100644 index 0000000..ecaf916 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/literal.css @@ -0,0 +1,5 @@ +body { + font: 14px; +} + +a { text-decoration: none; } \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/literal.styl b/node_modules/jade/support/stylus/test/cases/literal.styl new file mode 100644 index 0000000..94b071f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/literal.styl @@ -0,0 +1,7 @@ +@css { + body { + font: 14px; + } + + a { text-decoration: none; } +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/media.css b/node_modules/jade/support/stylus/test/cases/media.css new file mode 100644 index 0000000..0175743 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/media.css @@ -0,0 +1,14 @@ +@media print and (width: 21cm) and (height: 29cm) { + body { + margin: 3cm; + padding: 0; + } +} +@media print { + @page :left { + margin-left: 5px; + } + @page :right { + margin-right: 5px; + } +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/media.styl b/node_modules/jade/support/stylus/test/cases/media.styl new file mode 100644 index 0000000..da17def --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/media.styl @@ -0,0 +1,11 @@ + +@media print and (width: 21cm) and (height: 29cm) + body + margin 3cm + padding 0 + +@media print + @page :left + margin-left 5px + @page :right + margin-right 5px \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixin.conditional.css b/node_modules/jade/support/stylus/test/cases/mixin.conditional.css new file mode 100644 index 0000000..574ff68 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixin.conditional.css @@ -0,0 +1,19 @@ +body { + padding: 20px; + padding: 10px; + padding: 3px; +} +form input { + foo: bar; + bar: baz; +} +form input .two { + level: two; +} +form input .two:hover { + level: three; +} +body { + foo: bar; + bar: baz; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixin.conditional.styl b/node_modules/jade/support/stylus/test/cases/mixin.conditional.styl new file mode 100644 index 0000000..2ff9cac --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixin.conditional.styl @@ -0,0 +1,36 @@ + +pad(size = small) + if large == size + padding 20px + if medium == size + padding 10px + if small == size + padding 3px + +body + pad(large) + pad(medium) + pad() + pad(invalid) + +nested(val) + if val + foo bar + bar baz + .two + level two + &:hover + level three + +form input + nested(true) + nested(false) + +break() + foo bar + bar baz + return + baz raz + +body + break() \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixin.order.conditional.css b/node_modules/jade/support/stylus/test/cases/mixin.order.conditional.css new file mode 100644 index 0000000..1bf23eb --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixin.order.conditional.css @@ -0,0 +1,11 @@ +body { + one: 1; + two: 2; + three: 3; + four: 4; + five: 5; + six: 6; + seven: 7; + eight: 8; + nine: 9; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixin.order.conditional.styl b/node_modules/jade/support/stylus/test/cases/mixin.order.conditional.styl new file mode 100644 index 0000000..cacc666 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixin.order.conditional.styl @@ -0,0 +1,20 @@ +mixin2() + four 4 + if true + five 5 + +mixin() + mixin2() + if true + six 6 + if true + seven 7 + eight 8 if true + +body + one 1 + two 2 + three 3 + if true + mixin() + nine 9 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixin.order.css b/node_modules/jade/support/stylus/test/cases/mixin.order.css new file mode 100644 index 0000000..3e4ab4d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixin.order.css @@ -0,0 +1,9 @@ +body { + one: 1; + two: 2; + three: 3; + four: 4; + five: 5; + six: 6; + seven: 7; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixin.order.nested.css b/node_modules/jade/support/stylus/test/cases/mixin.order.nested.css new file mode 100644 index 0000000..3e4ab4d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixin.order.nested.css @@ -0,0 +1,9 @@ +body { + one: 1; + two: 2; + three: 3; + four: 4; + five: 5; + six: 6; + seven: 7; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixin.order.nested.styl b/node_modules/jade/support/stylus/test/cases/mixin.order.nested.styl new file mode 100644 index 0000000..6a5e9fa --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixin.order.nested.styl @@ -0,0 +1,21 @@ + +mixin2() + three 3 + +mixin3() + four 4 + mixin4() + +mixin4() + five 5 + +mixin() + two 2 + mixin2() + mixin3() + six 6 + +body + one 1 + mixin() + seven 7 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixin.order.styl b/node_modules/jade/support/stylus/test/cases/mixin.order.styl new file mode 100644 index 0000000..a873878 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixin.order.styl @@ -0,0 +1,20 @@ +mixin2() + three 3 + +mixin3() + four 4 + mixin4() + +mixin4() + five 5 + +mixin() + two 2 + mixin2() + mixin3() + six 6 + +body + one 1 + mixin() + seven 7 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.complex.css b/node_modules/jade/support/stylus/test/cases/mixins.complex.css new file mode 100644 index 0000000..134973e --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.complex.css @@ -0,0 +1,30 @@ +ul li { + list-style-image: none; + list-style-type: none; + margin-left: 0; + display: -moz-inline-box; + -moz-box-orient: vertical; + display: inline-block; + vertical-align: middle; +} +ul li:first-child { + list-style-image: none; + list-style-type: none; + margin-left: 0; + display: -moz-inline-box; + -moz-box-orient: vertical; + display: inline-block; + vertical-align: middle; + padding-left: 5px; + padding-right: 5px; +} +body { + did: nothing; +} +body { + padding: 5px; +} +body { + padding: 5px; + margin: 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.complex.fix-to.css b/node_modules/jade/support/stylus/test/cases/mixins.complex.fix-to.css new file mode 100644 index 0000000..f104b4d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.complex.fix-to.css @@ -0,0 +1,15 @@ +.button { + position: fixed; + bottom: 0; + left: 0; +} +.button { + position: fixed; + bottom: 0; + left: 0; +} +.button { + position: fixed; + bottom: 5px; + left: 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.complex.fix-to.styl b/node_modules/jade/support/stylus/test/cases/mixins.complex.fix-to.styl new file mode 100644 index 0000000..0609fbc --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.complex.fix-to.styl @@ -0,0 +1,28 @@ + +fix-to(a, b) + position fixed + {a} 0 + {b} 0 + +.button + fix-to bottom left + + +fix-to(pos...) + position fixed + if length(pos) == 2 + {pos[0]} 0 + {pos[1]} 0 + else if length(pos) == 4 + a = pos[0..1] + b = pos[2..3] + {a[0]} a[1] + {b[0]} b[1] + else + error('invalid arguments. fix-to: [n] [n];') + +.button + fix-to bottom left + +.button + fix-to bottom 5px left 5px \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.complex.styl b/node_modules/jade/support/stylus/test/cases/mixins.complex.styl new file mode 100644 index 0000000..f92bda4 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.complex.styl @@ -0,0 +1,41 @@ +no-bullet() + list-style-image none + list-style-type none + margin-left 0 + +inline-block() + display -moz-inline-box + -moz-box-orient vertical + display inline-block + vertical-align middle + +inline-block-list-item(padding = false) + no-bullet() + inline-block() + if padding + padding-left 5px + padding-right 5px + +ul + li + inline-block-list-item() + +ul li:first-child + inline-block-list-item(true) + +pad(pad = false, margin = false) + if pad + padding 5px + if margin + margin 5px + unless pad or margin + did nothing + +body + pad() + +body + pad(true) + +body + pad(true, true) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.conditional.css b/node_modules/jade/support/stylus/test/cases/mixins.conditional.css new file mode 100644 index 0000000..f2f733b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.conditional.css @@ -0,0 +1,3 @@ +body { + margin: 5px 10px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.conditional.styl b/node_modules/jade/support/stylus/test/cases/mixins.conditional.styl new file mode 100644 index 0000000..07275b5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.conditional.styl @@ -0,0 +1,8 @@ +overload-padding = true + +if overload-padding + padding(y, x) + margin y x + +body + padding 5px 10px \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.nested.css b/node_modules/jade/support/stylus/test/cases/mixins.nested.css new file mode 100644 index 0000000..1af8585 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.nested.css @@ -0,0 +1,7 @@ +body { + one: 1; + two: 1 2; + three: 1 2 3; + -three: 1 2 c; + -two: 1 b c; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.nested.selectors.css b/node_modules/jade/support/stylus/test/cases/mixins.nested.selectors.css new file mode 100644 index 0000000..ba2f23b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.nested.selectors.css @@ -0,0 +1,21 @@ +body { + padding: 5px; + color: "bar"; +} +body .foo { + color: "bar"; +} +body .foo .bar { + color: "bar"; +} +body { + one: 1; + two: 2; + three: 3; +} +body with some nesting { + four: 4; +} +body with some nesting even more { + five: 5; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.nested.selectors.styl b/node_modules/jade/support/stylus/test/cases/mixins.nested.selectors.styl new file mode 100644 index 0000000..d828786 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.nested.selectors.styl @@ -0,0 +1,31 @@ + +mixin(n) + padding n + var = 'bar' + color var + .foo + color var + .bar + color var + +body + foo = 'foo' + mixin(5px) + +three(n) + three n + with some nesting + four n = n + 1 + even more + five n + 1 + +two(n) + two n + three(n + 1) + +one(n) + one n + two(n + 1) + +body + one(1) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.nested.styl b/node_modules/jade/support/stylus/test/cases/mixins.nested.styl new file mode 100644 index 0000000..045e3a1 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.nested.styl @@ -0,0 +1,14 @@ + +one(a) + one a + two(b) + two a b + three(c) + three a b c + three(3) + -three a b c + two(2) + -two a b c + +body + one(1) diff --git a/node_modules/jade/support/stylus/test/cases/mixins.order.2.css b/node_modules/jade/support/stylus/test/cases/mixins.order.2.css new file mode 100644 index 0000000..1bf23eb --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.order.2.css @@ -0,0 +1,11 @@ +body { + one: 1; + two: 2; + three: 3; + four: 4; + five: 5; + six: 6; + seven: 7; + eight: 8; + nine: 9; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.order.2.styl b/node_modules/jade/support/stylus/test/cases/mixins.order.2.styl new file mode 100644 index 0000000..6cbe4e1 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.order.2.styl @@ -0,0 +1,16 @@ +test-nested() + two 2 + if true + three 3 + if true + four 4 + if true + five 5 + six 6 + seven 7 + eight 8 + +body + one 1 + test-nested() + nine 9 diff --git a/node_modules/jade/support/stylus/test/cases/mixins.return.css b/node_modules/jade/support/stylus/test/cases/mixins.return.css new file mode 100644 index 0000000..5f2b54e --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.return.css @@ -0,0 +1,4 @@ +body { + foo: bar; + bar: baz; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.return.styl b/node_modules/jade/support/stylus/test/cases/mixins.return.styl new file mode 100644 index 0000000..b37c764 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.return.styl @@ -0,0 +1,8 @@ +another() + foo bar + bar baz + return + baz raz + +body + another() \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.root.css b/node_modules/jade/support/stylus/test/cases/mixins.root.css new file mode 100644 index 0000000..7f8f806 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.root.css @@ -0,0 +1,3 @@ +body { + padding: 5px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins.root.styl b/node_modules/jade/support/stylus/test/cases/mixins.root.styl new file mode 100644 index 0000000..11e1378 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins.root.styl @@ -0,0 +1,5 @@ +foo() + body + padding 5px + +foo() \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/mixins/box.styl b/node_modules/jade/support/stylus/test/cases/mixins/box.styl new file mode 100644 index 0000000..fd9085b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/mixins/box.styl @@ -0,0 +1,11 @@ + +pad(x, y = x) + padding y x y x + +pad-x(n) + padding-left n + padding-right n + +pad-y(n) + padding-top n + padding-bottom n diff --git a/node_modules/jade/support/stylus/test/cases/operator.range.css b/node_modules/jade/support/stylus/test/cases/operator.range.css new file mode 100644 index 0000000..81f45cb --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operator.range.css @@ -0,0 +1,15 @@ +body { + foo: 1 2 3 4 5; + foo: 1 2 3 4 5 6 7 8 9 10; + foo: 1; + foo: 1 2 3 4 5; + foo: 5; + foo: 2; + foo: 5; + foo: 6 7 8 9 10; + foo: true; + foo: true; +} +body { + foo: 1 2 3; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operator.range.styl b/node_modules/jade/support/stylus/test/cases/operator.range.styl new file mode 100644 index 0000000..4b3cdc1 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operator.range.styl @@ -0,0 +1,23 @@ +body + small = 1..5 + large = (1..5) (6..10) + + foo small + foo large + + foo small[0] + foo large[0] + + foo length(small) + foo length(large) + + foo small[length(small) - 1] + foo large[length(large) - 1] + + foo small[-1] == null + foo small[123123] == null + +body + start = 1 + end = 3 + foo start..end \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.assignment.function.css b/node_modules/jade/support/stylus/test/cases/operators.assignment.function.css new file mode 100644 index 0000000..b4169d6 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.assignment.function.css @@ -0,0 +1,15 @@ +body { + foo: 20; +} +body { + foo: 5; +} +body { + foo: 20; +} +body { + foo: 2.5; +} +body { + foo: 1; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.assignment.function.styl b/node_modules/jade/support/stylus/test/cases/operators.assignment.function.styl new file mode 100644 index 0000000..eda512f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.assignment.function.styl @@ -0,0 +1,34 @@ + +test(n) + n += 5 + n += 5 + +body + foo test(10) + +test(n) + n -= 2 + n -= 3 + +body + foo test(10) + +test(n) + n *= 2 + n *= 2 + +body + foo test(5) + +test(n) + n /= 2 + n /= 4 + +body + foo test(20) + +test(n) + n %= 2 + +body + foo test(5) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.assignment.mixin.css b/node_modules/jade/support/stylus/test/cases/operators.assignment.mixin.css new file mode 100644 index 0000000..b4169d6 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.assignment.mixin.css @@ -0,0 +1,15 @@ +body { + foo: 20; +} +body { + foo: 5; +} +body { + foo: 20; +} +body { + foo: 2.5; +} +body { + foo: 1; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.assignment.mixin.styl b/node_modules/jade/support/stylus/test/cases/operators.assignment.mixin.styl new file mode 100644 index 0000000..6cbba10 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.assignment.mixin.styl @@ -0,0 +1,39 @@ + +test(n) + n += 5 + n += 5 + foo n + +body + test(10) + +test(n) + n -= 2 + n -= 3 + foo n + +body + test(10) + +test(n) + n *= 2 + n *= 2 + foo n + +body + test(5) + +test(n) + n /= 2 + n /= 4 + foo n + +body + test(20) + +test(n) + n %= 2 + foo n + +body + test(5) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.assignment.root.css b/node_modules/jade/support/stylus/test/cases/operators.assignment.root.css new file mode 100644 index 0000000..0bcf506 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.assignment.root.css @@ -0,0 +1,19 @@ +body { + foo: 20; + foo: 21; +} +body { + foo: 20; +} +body { + foo: 5; +} +body { + foo: 20; +} +body { + foo: 2.5; +} +body { + foo: 1; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.assignment.root.styl b/node_modules/jade/support/stylus/test/cases/operators.assignment.root.styl new file mode 100644 index 0000000..63b2e17 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.assignment.root.styl @@ -0,0 +1,43 @@ + + +n = 10 +a = n = n + 10 +a += 1 + +body + foo n + foo a + +n = 10 +n += 5 +n += 5 + +body + foo n + +n = 10 +n -= 2 +n -= 3 + +body + foo n + +n = 5 +n *= 2 +n *= 2 + +body + foo n + +n = 20 +n /= 2 +n /= 4 + +body + foo n + +n = 5 +n %= 2 + +body + foo n \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.complex.css b/node_modules/jade/support/stylus/test/cases/operators.complex.css new file mode 100644 index 0000000..0e3319c --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.complex.css @@ -0,0 +1,9 @@ +body { + foo: yes; + foo: true; + foo: yay; + foo: nah; + foo: nah; + foo: true; + foo: false; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.complex.styl b/node_modules/jade/support/stylus/test/cases/operators.complex.styl new file mode 100644 index 0000000..ffdc6cb --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.complex.styl @@ -0,0 +1,32 @@ + +ensure-unit(n) + foo bar + foo bar + foo bar + n is a 'unit' + +body + a = 15 + b = 15 + + // yes + foo a == b and (b == 15 ? 1 : 0) ? yes : no + + // true + foo a == b and b == a + + // yay + foo 15px is a 'unit' and #fff is a 'color'?yay:nah + + // nah + foo 15px is a 'color' and #fff is a 'color'?yay:nah + + // nah + foo 15px is a 'unit' and #fff is a 'unit'? yay : nah + + // true + foo ensure-unit(15) + + // false + foo ensure-unit(#fff) + diff --git a/node_modules/jade/support/stylus/test/cases/operators.css b/node_modules/jade/support/stylus/test/cases/operators.css new file mode 100644 index 0000000..7e87857 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.css @@ -0,0 +1,32 @@ +body { + foo: 5px; + foo: 0px; + foo: 0px; + foo: false; + foo: true; + foo: 5px; + foo: 1px; + foo: 0; + foo: false; + foo: 10; + foo: #fff; + foo: 1; + foo: true; + foo: true; + foo: false; + foo: true; + foo: true; + foo: true; + foo: false; + foo: wahoo; + foo: nope; + foo: "got 15px"; + foo: 1; + foo: 5; + foo: true; + foo: true; + foo: true; + foo: false; + foo: false; + foo: false; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.equality.css b/node_modules/jade/support/stylus/test/cases/operators.equality.css new file mode 100644 index 0000000..a0c3bb4 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.equality.css @@ -0,0 +1,12 @@ +body { + foo: true; + foo: true; + foo: false; + foo: true; + foo: true; + foo: true; + foo: true; + foo: true; + foo: false; + foo: true; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.equality.styl b/node_modules/jade/support/stylus/test/cases/operators.equality.styl new file mode 100644 index 0000000..452a7ad --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.equality.styl @@ -0,0 +1,31 @@ +body + + // true + foo 1 != 5 + + // true + foo wahoo == wahoo + + // false + foo wahoo == something + + // true + foo wahoo != something + foo wahoo is not something + + // true + foo = yay + foo yes == (foo is defined ? yes : nope) + + // true + rawr = 'asdfasdf' + foo yes == (rawr is defined ? yes : nope) + + // true + foo 1000ms == 1s + + // false + foo 1ms == 1s + + // true + foo 5 < 10 and 10 > 5 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.in.css b/node_modules/jade/support/stylus/test/cases/operators.in.css new file mode 100644 index 0000000..77a7dcd --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.in.css @@ -0,0 +1,36 @@ +body { + foo: true; + foo: true; + foo: false; +} +body { + foo: true; +} +body { + foo: true; + foo: true; + foo: false; +} +body { + foo: false; + foo: true; + foo: true; + foo: false; +} +body { + foo: false; + foo: false; + foo: true; + foo: false; + foo: true; +} +body { + foo: true; + foo: false; +} +body { + foo: true; + foo: false; + foo: true; + foo: true; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.in.styl b/node_modules/jade/support/stylus/test/cases/operators.in.styl new file mode 100644 index 0000000..3d4e35a --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.in.styl @@ -0,0 +1,50 @@ + + +body + nums = 1 2 3 + foo 1 in nums + foo 3 in nums + foo 5 in nums + +body + nums = 1 + foo 1 in nums == true + +body + words = foo bar baz + foo bar in words + foo baz in words + foo HEY in words + +body + tuples = (error 'one') (error 'two') + foo error in tuples + foo (error 'one') in tuples + foo (error 'two') in tuples + foo (error 'something') in tuples + +fn(args...) + 2 in args + +body + foo fn() + foo fn(1) + foo fn(2) + foo fn(3 2) + foo fn(1,2,3) + +fn(args...) + (3 2) in args + +body + foo fn(3 2) + foo fn(3,2) + +fn() + test in arguments + +body + foo fn(test) + foo fn(a, b, c) + foo fn(a, test, c) + foo fn(a test c) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.mixins.css b/node_modules/jade/support/stylus/test/cases/operators.mixins.css new file mode 100644 index 0000000..fd2479b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.mixins.css @@ -0,0 +1,10 @@ +body { + foo: false; + foo: true; + foo: true; + foo: false; + foo: false; + foo: "something"; + foo: "something"; + foo: "12"; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.mixins.styl b/node_modules/jade/support/stylus/test/cases/operators.mixins.styl new file mode 100644 index 0000000..829f696 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.mixins.styl @@ -0,0 +1,25 @@ + +stringish(val = false) + 'string' == type(val) or 'ident' == type(val) + +string(val) + '' + val + +body + // false + foo stringish(12) + + // true + foo stringish('12') + + // true + foo stringish(wahoo) + + // false + num = 12 + foo stringish(num) + foo stringish() + + foo string(something) + foo string('something') + foo string(12) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.precedence.css b/node_modules/jade/support/stylus/test/cases/operators.precedence.css new file mode 100644 index 0000000..e4959ce --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.precedence.css @@ -0,0 +1,51 @@ +body { + foo: 4; + foo: 4; + foo: -5px; + foo: 2; + foo: 2; +} +body { + foo: true; + foo: true; +} +body { + foo: 5; + foo: 5; +} +body { + foo: true; + foo: true; + foo: true; + foo: true; + foo: 2; +} +body { + foo: true; + foo: true; +} +body { + foo: 2.5; + foo: 2.5; +} +body { + foo: true; + foo: true; + foo: false; + foo: wahoo; + foo: fail; +} +body { + foo: true; + foo: true; +} +body { + foo: true; + foo: 1; +} +body { + foo: true; + foo: true; + foo: false; + foo: true; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.precedence.styl b/node_modules/jade/support/stylus/test/cases/operators.precedence.styl new file mode 100644 index 0000000..c228c58 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.precedence.styl @@ -0,0 +1,82 @@ +body + // 4 + foo (--- 0) or 4 + // 4 + foo --- 0 or 4 + // -5px + foo ---5px + // 2 + foo (!!!5) or 2 + foo !!!5 or 2 + + +body + // true + foo !(! 5) + foo !!5 + +body + // 5 + foo (! false) and (! false) and 5 + foo ! false and ! false and 5 + +body + // true + foo (!!5 == true) or (!!0 == false) + foo !!5 == true or !!0 == false + foo (!!5 == false) or (!!0 == false) + foo !!5 == false or !!0 == false + // 2 + foo 5 < 10 and !!5 and 2 + +body + // true + foo (!!true) and (!!true) + foo !!true and !!true + +body + test() + 5 * 2 - 15 / 2 + // 2.5 + foo test() + foo (5 * 2) - (15 / 2) + +body + // true + foo not 5 < 10 ? 0 : 1 + // true + foo !(5 < 10 ? 0 : 1) + // false + foo !(5 > 10 ? 0 : 1) + // wahoo + foo !! 1 ? wahoo : fail + // fail + foo !1 ? wahoo : fail + +body + foo = 'test' + bar = 'test' + // true + foo (foo is defined) and (bar is defined) + foo foo is defined and bar is defined + +body + // true + foo 5 > 4 is a 'boolean' + + foo = type is a 'unit' ? type : 1 + // 1 + foo foo + +body + padding = false + margin = false + + // true + foo !padding or !margin + foo not padding or margin + + // false + foo not padding or margin == !padding or !margin + // true + foo (not padding or margin) == !padding or !margin diff --git a/node_modules/jade/support/stylus/test/cases/operators.styl b/node_modules/jade/support/stylus/test/cases/operators.styl new file mode 100644 index 0000000..b0fa171 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.styl @@ -0,0 +1,86 @@ +body + // 5px + foo 0 || 5px + + // 0px + foo 0px || 5px + + // 0px + foo 0px || 0px + + // false + foo 0 or false + + // true + foo 0 || 0 || true + + // 5px + foo 1px && 5px + + // 1px + foo 0px && 1px + + // 0 + foo 1px && 0 + + // false + foo 1px and false + + // 10 + foo 5px && 5px && 10 + + // #fff + foo #000 && #fff + + // 1 + foo 8 && (4 && 1) + + // true + type = "color" + foo #fff is a type + foo #fff is a 'color' + + // false + foo 15px is a 'color' + // true + foo 15px is a 'unit' + + // true + foo 15px is a 'unit' and #fff is a 'color' + + // true + foo = 'bar' + + // true + bar = 'baz' + foo foo is defined and bar is defined + + // false + foo baz is defined + + // wahoo + foo bar is defined ? wahoo : nope + + // nope + foo rawr is defined ? yes : nope + + // "got 15px" + foo "got " + 15px + + // 1 + foo true and 1 or 5 + + // 5 + foo !false and !false and 5 + + // true + foo !!5 is true or !!0 is false + foo !!5 == false or !!0 == false + + // true + foo wahoo == wahoo + + // false + foo 0 == true + foo true == 0 + foo #fff == undefined diff --git a/node_modules/jade/support/stylus/test/cases/operators.subscript.css b/node_modules/jade/support/stylus/test/cases/operators.subscript.css new file mode 100644 index 0000000..5d5eac5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.subscript.css @@ -0,0 +1,59 @@ +body { + foo: true; + foo: 3 4 5; + foo: true; + foo: true; + foo: false; + foo: -5; +} +body { + foo: 1 2 3 4; + foo: 1; + foo: 2 3 4; + foo: 2; + foo: 3 4; + foo: 3; + foo: 4; + foo: ; +} +body { + foo: error; + foo: "message"; +} +body { + foo: 5; + foo: 10; +} +body { + foo: 5; + foo: 10; +} +body { + foo: 1 2; + foo: 3 4; + foo: 4; +} +body { + foo: 100 200; + foo: 100; + foo: 200; + foo: 2; +} +body { + foo: 100 200; + foo: 100; + foo: 200; + foo: 2; +} +body { + foo: 100 200; + foo: 100; + foo: 200; + foo: 2; +} +body { + foo: 100 200; + foo: 100; + foo: 200; + foo: 2; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.subscript.range.css b/node_modules/jade/support/stylus/test/cases/operators.subscript.range.css new file mode 100644 index 0000000..e4c6b28 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.subscript.range.css @@ -0,0 +1,14 @@ +body { + foo: a b; + foo: a b c; + foo: d e f; + foo: c d e; +} +body { + foo: 1 2 3 4; +} +body { + foo: ; + foo: ; + foo: ; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.subscript.range.styl b/node_modules/jade/support/stylus/test/cases/operators.subscript.range.styl new file mode 100644 index 0000000..913a64b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.subscript.range.styl @@ -0,0 +1,15 @@ +body + vals = a b c d e f g + foo vals[0...2] + foo vals[0..2] + foo vals[3..5] + foo vals[2 3 4] + +body + vals = (1 2) (3 4) + foo vals[0..1] + +body + foo ()[] + foo ()[1] + foo ()[1..3] \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/operators.subscript.styl b/node_modules/jade/support/stylus/test/cases/operators.subscript.styl new file mode 100644 index 0000000..5d69430 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/operators.subscript.styl @@ -0,0 +1,81 @@ +body + foo ()[0] == null + foo (1(2(3 4 5)))[1][1] + foo (1 2 3)['test'] == null + foo !(1 0)[1] + foo !(1 0)[0] + foo - - -(1 2 3 4 5)[4] + +body + foo (1 (2 (3 4))) + foo (1 (2 (3 4)))[0] + foo (1 (2 (3 4)))[1] + foo (1 (2 (3 4)))[1][0] + foo (1 (2 (3 4)))[1][1] + foo (1 (2 (3 4)))[1][1][0] + foo (1 (2 (3 4)))[1][1][1] + foo (1 (2 (3 4)))[1][1][3] + +body + foo (error 'message')[0] + foo (error 'message')[1] + +size(a, b) + return a b + +body + foo size(5, 10)[0] + foo size(5, 10)[1] + +size(a, b) + (a b) + +body + foo size(5, 10)[0] + foo size(5, 10)[1] + +size() + (1 2) (3 4) + +body + foo size()[0] + foo size()[1] + foo size()[1][1] + +image-size(path) + w = 100 + h = 200 + return w h + +body + size = image-size('test.png') + foo size + foo size[0] + foo size[1] + foo length(size) + +image-size(path) + 100 200 + +body + size = image-size('test.png') + foo size + foo size[0] + foo size[1] + foo length(size) + +size = 100 200 + +body + foo size + foo size[0] + foo size[1] + foo length(size) + +size = (100 200) + +body + foo size + foo size[0] + foo size[1] + foo length(size) diff --git a/node_modules/jade/support/stylus/test/cases/page.css b/node_modules/jade/support/stylus/test/cases/page.css new file mode 100644 index 0000000..9adf972 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/page.css @@ -0,0 +1,13 @@ +@page { + margin: 2.5cm; +} +@page :left { + margin-left: 5cm; +} +@page :right { + margin-right: 5cm; +} +@page :first { + margin-top: 8cm; + background: white; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/page.styl b/node_modules/jade/support/stylus/test/cases/page.styl new file mode 100644 index 0000000..d088a29 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/page.styl @@ -0,0 +1,13 @@ + +@page + margin 2.5cm + +@page :left + margin-left 5cm + +@page :right + margin-right 5cm + +@page :first + margin-top 8cm + background white diff --git a/node_modules/jade/support/stylus/test/cases/parent.css b/node_modules/jade/support/stylus/test/cases/parent.css new file mode 100644 index 0000000..ba03b37 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/parent.css @@ -0,0 +1,32 @@ +.button { + padding: 5px; + -webkit-transition: opacity 1s ease-out; +} +.button:hover { + opacity: 2; +} +textarea, +input { + color: #a7a7a7; +} +textarea:hover, +input:hover { + color: #000; +} +.dim { + opacity: 0.2; +} +.dim:hover, +.dim.show { + opacity: 1; +} +body #login { + -webkit-box-shadow: 1px 1px 3px #eee; + -moz-box-shadow: 1px 1px 3px #eee; + box-shadow: 1px 1px 3px #eee; +} +html.ie8 body #login, +html.ie7 body #login foo, +html.ie6 body #login { + border: solid 1px #eee; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/parent.styl b/node_modules/jade/support/stylus/test/cases/parent.styl new file mode 100644 index 0000000..405c79c --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/parent.styl @@ -0,0 +1,33 @@ +dim-on-hover() + -webkit-transition opacity 1s ease-out + &:hover + opacity 2 + +.button + padding 5px + dim-on-hover() + +textarea +input + color #A7A7A7 + &:hover + color #000 + +.dim + opacity .2 + &:hover + &.show + opacity 1 + +box-shadow() + -webkit-box-shadow arguments + -moz-box-shadow arguments + box-shadow arguments + html.ie8 &, + html.ie7 & foo, + html.ie6 & + border solid 1px arguments[length(arguments) - 1] + +body + #login + box-shadow 1px 1px 3px #eee \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/properties.colons.css b/node_modules/jade/support/stylus/test/cases/properties.colons.css new file mode 100644 index 0000000..beb90bb --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/properties.colons.css @@ -0,0 +1,8 @@ +body { + margin: 5px; + padding: 5px; + foo: 5px; +} +body something { + here: whoop; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/properties.colons.styl b/node_modules/jade/support/stylus/test/cases/properties.colons.styl new file mode 100644 index 0000000..d932bc6 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/properties.colons.styl @@ -0,0 +1,10 @@ + +mixin() + foo: 5px + something + here: whoop + +body + margin: 5px + padding: 5px + mixin() \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/properties.css b/node_modules/jade/support/stylus/test/cases/properties.css new file mode 100644 index 0000000..12e1ccb --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/properties.css @@ -0,0 +1,4 @@ +#wrapper { + padding: 5px; + white-space: nowrap; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/properties.one-line.css b/node_modules/jade/support/stylus/test/cases/properties.one-line.css new file mode 100644 index 0000000..f881297 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/properties.one-line.css @@ -0,0 +1,10 @@ +body { + background: #00f; + width: 100px; + height: 50px; +} +body { + background: #00f; + width: 100px; + height: 50px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/properties.one-line.styl b/node_modules/jade/support/stylus/test/cases/properties.one-line.styl new file mode 100644 index 0000000..834fd93 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/properties.one-line.styl @@ -0,0 +1,11 @@ +bg() + background: blue; + +body { + bg(); width: 100px; + height: 50px; +} + +body + bg(); width 100px; + height 50px \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/properties.styl b/node_modules/jade/support/stylus/test/cases/properties.styl new file mode 100644 index 0000000..944256f --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/properties.styl @@ -0,0 +1,4 @@ + +#wrapper + padding 5px + white-space nowrap \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.107.lookup-failure.css b/node_modules/jade/support/stylus/test/cases/regression.107.lookup-failure.css new file mode 100644 index 0000000..1d81a68 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.107.lookup-failure.css @@ -0,0 +1,12 @@ +button { + background: #e3e3e3; +} +button:hover { + background: #dbdbdb; +} +button:active { + background: #d6d6d6; +} +button nested really-nested with-even-more-nesting { + background: #e3e3e3; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.107.lookup-failure.styl b/node_modules/jade/support/stylus/test/cases/regression.107.lookup-failure.styl new file mode 100644 index 0000000..cd55bc8 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.107.lookup-failure.styl @@ -0,0 +1,13 @@ +minimal-button(bg = #e3e3e3) + background bg + &:hover + background darken(bg, 3%) + &:active + background darken(bg, 5%) + nested + really-nested + with-even-more-nesting + background bg + +button + minimal-button() \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.127.css b/node_modules/jade/support/stylus/test/cases/regression.127.css new file mode 100644 index 0000000..3a27438 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.127.css @@ -0,0 +1,3 @@ +body { + background: #c3210d; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.127.styl b/node_modules/jade/support/stylus/test/cases/regression.127.styl new file mode 100644 index 0000000..f0128c7 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.127.styl @@ -0,0 +1,2 @@ +body + background #c3210d \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.130.css b/node_modules/jade/support/stylus/test/cases/regression.130.css new file mode 100644 index 0000000..42dfaa6 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.130.css @@ -0,0 +1,16 @@ +body { + font: 13px / 1.231; +} +body { + font: 13px / 1.231; +} +body { + font: 13px / 1.231; +} +body { + font: 13px / 1.231; +} +body { + font: 13px / 1.231; + background: #fff; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.130.styl b/node_modules/jade/support/stylus/test/cases/regression.130.styl new file mode 100644 index 0000000..0285947 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.130.styl @@ -0,0 +1,6 @@ + +body { font: 13px / 1.231; } +body {font: 13px / 1.231;} +body {font: 13px / 1.231} +body { font : 13px / 1.231 } +body { font : 13px / 1.231; background: white } \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.131.css b/node_modules/jade/support/stylus/test/cases/regression.131.css new file mode 100644 index 0000000..4a7e264 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.131.css @@ -0,0 +1,6 @@ +body { + font-weight: normal; +} +body { + color: #fff; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.131.styl b/node_modules/jade/support/stylus/test/cases/regression.131.styl new file mode 100644 index 0000000..feb1768 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.131.styl @@ -0,0 +1,2 @@ +body { font-weight: normal; } /* foo */ +body { color: #fff; } // foo \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.137.css b/node_modules/jade/support/stylus/test/cases/regression.137.css new file mode 100644 index 0000000..01f1085 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.137.css @@ -0,0 +1,7 @@ +#fea-ca { + padding: 5px; +} +#ffffff { + padding: 5px; + foo: #fea -ca; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.137.styl b/node_modules/jade/support/stylus/test/cases/regression.137.styl new file mode 100644 index 0000000..5b7e560 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.137.styl @@ -0,0 +1,7 @@ + +#fea-ca + padding 5px + +#ffffff + padding 5px + foo #fea-ca \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.139.css b/node_modules/jade/support/stylus/test/cases/regression.139.css new file mode 100644 index 0000000..0101baf --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.139.css @@ -0,0 +1,5 @@ +body { + foo: bottom; + foo: right; + foo: bottom right; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.139.styl b/node_modules/jade/support/stylus/test/cases/regression.139.styl new file mode 100644 index 0000000..12791e9 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.139.styl @@ -0,0 +1,21 @@ + +opposite-position(pos) { + return bottom if pos == top; + return top if pos == bottom; + return right if pos == left; + return left if pos == right; + error('Invalid position ' + pos) +} + +opposite(positions) { + for pos in positions { + pos = opposite-position(pos); + ret = ret is defined ? ret pos : pos; + } +} + +body { + foo: opposite(top); + foo: opposite(left); + foo: opposite(top left); +} diff --git a/node_modules/jade/support/stylus/test/cases/regression.142.css b/node_modules/jade/support/stylus/test/cases/regression.142.css new file mode 100644 index 0000000..b5a45ee --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.142.css @@ -0,0 +1,39 @@ +foo, +bar, +baz { + display: none; +} +foo, +bar, +baz { + display: none; +} +body :nth-child(2), +body foo bar, +body bar, +body baz { + display: none; +} +body { + foo: bar; +} +body bar, +body baz { + display: none; +} +body foo, +body bar, +body baz { + display: none; +} +body foo, +body :nth-child(2), +body bar { + display: none; +} +body { + foo: bar; +} +body { + foo: 3; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.142.styl b/node_modules/jade/support/stylus/test/cases/regression.142.styl new file mode 100644 index 0000000..f27c86d --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.142.styl @@ -0,0 +1,54 @@ + +foo, bar, baz + display none + +foo +bar +baz + display none + +body + :nth-child(2) + foo bar + bar + baz + display none + +body + foo bar + bar + baz + display none + +body + foo + bar + baz + display none + +body + foo + :nth-child(2) + bar + display none + +fn() + bar if true; + +something() + one + two + fn() + +body + foo something() + +something() + nums = 1 2 3 + one + two + for n in nums + n + +body + foo something() \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.146.css b/node_modules/jade/support/stylus/test/cases/regression.146.css new file mode 100644 index 0000000..b18dfbc --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.146.css @@ -0,0 +1,30 @@ +input[for=name] { + width: 200px; +} +body { + foo: 1; +} +body { + foo: 2; +} +body { + foo: 3; +} +body foo { + bar: 1; + bar: 2; + bar: 3; +} +#login foo, +#login input[for=name] { + foo: bar; +} +#login foo input[for=name] { + bar: 1; +} +#login foo input[for=name] { + bar: 2; +} +#login foo input[for=name] { + bar: 3; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.146.styl b/node_modules/jade/support/stylus/test/cases/regression.146.styl new file mode 100644 index 0000000..b4ecdf6 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.146.styl @@ -0,0 +1,31 @@ +input[for=name] + width 200px + +nums = 1 2 3 +for n in nums + body + foo n + +body + foo + for n in nums + bar n + +something() + nums = 1 2 3 + foo + input[for=name] + foo bar + +#login + something() + +something() + nums = 1 2 3 + foo + for n in nums + input[for=name] + bar n + +#login + something() \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.153.css b/node_modules/jade/support/stylus/test/cases/regression.153.css new file mode 100644 index 0000000..1e76441 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.153.css @@ -0,0 +1,8 @@ +#content { + width: 960px; +} +@media screen { + #content { + width: 640px; + } +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.153.styl b/node_modules/jade/support/stylus/test/cases/regression.153.styl new file mode 100644 index 0000000..1691e85 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.153.styl @@ -0,0 +1,9 @@ +cols(n) + width 160px * n + +#content + cols 6 + +@media screen + #content + cols 4 \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.154.css b/node_modules/jade/support/stylus/test/cases/regression.154.css new file mode 100644 index 0000000..ffa182a --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.154.css @@ -0,0 +1,8 @@ +body { + foo: true; + foo: false; +} +body { + foo: false; + foo: true; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.154.styl b/node_modules/jade/support/stylus/test/cases/regression.154.styl new file mode 100644 index 0000000..40587a5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.154.styl @@ -0,0 +1,14 @@ + +light(color) + lightness(color) >= 50% + +dark(color) + lightness(color) < 50% + +body + foo light(white) + foo light(black) + +body + foo dark(white) + foo dark(black) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.156.css b/node_modules/jade/support/stylus/test/cases/regression.156.css new file mode 100644 index 0000000..b418755 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.156.css @@ -0,0 +1,4 @@ +body { + padding-right: 0; + float: right; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/regression.156.styl b/node_modules/jade/support/stylus/test/cases/regression.156.styl new file mode 100644 index 0000000..81de24b --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/regression.156.styl @@ -0,0 +1,6 @@ +body + mixin() + +body + padding-{opposite-position(left)} 0 + float opposite-position(left) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/rule.charset.css b/node_modules/jade/support/stylus/test/cases/rule.charset.css new file mode 100644 index 0000000..b98ffb5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/rule.charset.css @@ -0,0 +1 @@ +@charset "utf-8" \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/rule.charset.styl b/node_modules/jade/support/stylus/test/cases/rule.charset.styl new file mode 100644 index 0000000..6cc76dd --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/rule.charset.styl @@ -0,0 +1,2 @@ + +@charset "utf-8" \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/rulset.css b/node_modules/jade/support/stylus/test/cases/rulset.css new file mode 100644 index 0000000..be7adab --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/rulset.css @@ -0,0 +1,4 @@ +textarea, +input { + border: 1px solid #eee; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/rulset.newline.css b/node_modules/jade/support/stylus/test/cases/rulset.newline.css new file mode 100644 index 0000000..4249e51 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/rulset.newline.css @@ -0,0 +1,5 @@ +textarea, +input, +.text { + border: 1px solid #eee; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/rulset.newline.styl b/node_modules/jade/support/stylus/test/cases/rulset.newline.styl new file mode 100644 index 0000000..b4b4a20 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/rulset.newline.styl @@ -0,0 +1,5 @@ + +textarea +input +.text + border 1px solid #eee \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/rulset.styl b/node_modules/jade/support/stylus/test/cases/rulset.styl new file mode 100644 index 0000000..6a2ad9a --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/rulset.styl @@ -0,0 +1,3 @@ + +textarea, input + border 1px solid #eee \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/scope.complex.css b/node_modules/jade/support/stylus/test/cases/scope.complex.css new file mode 100644 index 0000000..e59bd0e --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/scope.complex.css @@ -0,0 +1,10 @@ +body { + margin: 24px; + padding: 12px 5px 12px 5px; + font-size: 50px; +} +form input { + border: 3px solid #000; + margin: 24px; + padding: 2px 1px 2px 1px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/scope.complex.styl b/node_modules/jade/support/stylus/test/cases/scope.complex.styl new file mode 100644 index 0000000..c743dca --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/scope.complex.styl @@ -0,0 +1,16 @@ + +size = 12px +size-large = size * 2 + +pad(x, y = size) + margin size-large + padding y x y x + +body + size = 50px + pad(5px) + font-size size + +form input + border (size / 4) solid black + pad(1px, 2px) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/scope.css b/node_modules/jade/support/stylus/test/cases/scope.css new file mode 100644 index 0000000..385c11c --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/scope.css @@ -0,0 +1,5 @@ +body { + margin: 24px; + padding: 12px 5px 12px 5px; + font-size: 50px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/scope.nested.css b/node_modules/jade/support/stylus/test/cases/scope.nested.css new file mode 100644 index 0000000..68e058a --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/scope.nested.css @@ -0,0 +1,9 @@ +body { + font: 5; +} +body .large { + font: 10; +} +body .other { + font: 15; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/scope.nested.styl b/node_modules/jade/support/stylus/test/cases/scope.nested.styl new file mode 100644 index 0000000..9f4f602 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/scope.nested.styl @@ -0,0 +1,10 @@ + +body + size = 5 + font size + .large + large = size * 2 + font large + .other + large ?= size * 3 + font large \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/scope.styl b/node_modules/jade/support/stylus/test/cases/scope.styl new file mode 100644 index 0000000..9ff2dd3 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/scope.styl @@ -0,0 +1,12 @@ + +size = 12px +size-large = size * 2 + +pad(x, y = size) + margin size-large + padding y x y x + +body + size = 50px + pad(5px) + font-size size diff --git a/node_modules/jade/support/stylus/test/cases/selectors.complex.css b/node_modules/jade/support/stylus/test/cases/selectors.complex.css new file mode 100644 index 0000000..8bd00cb --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/selectors.complex.css @@ -0,0 +1,28 @@ +body form input.hide, +body foo bar, +body .hidden, +body:hover, +body:focus { + display: none; +} +body form input, +body .hidden { + display: none; +} +ul > li { + padding: 5px; + border: 1px solid #eee; +} +ul > li:first-child, +ul > li:last-child { + border: none; +} +ul > li:first-child { + padding-top: 0; +} +ul > li:last-child { + padding-bottom: 0; +} +body form > input:nth-child(2) { + border: 1px solid #eee; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/selectors.complex.styl b/node_modules/jade/support/stylus/test/cases/selectors.complex.styl new file mode 100644 index 0000000..397f5b5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/selectors.complex.styl @@ -0,0 +1,27 @@ +body + form input.hide, + foo bar, + .hidden + &:hover + &:focus + display none + +body + form input, .hidden + display none + +ul + > li + padding 5px + border 1px solid #eee + &:first-child, + &:last-child + border none + &:first-child + padding-top 0 + &:last-child + padding-bottom 0 + +body + form > input:nth-child(2) + border 1px solid #eee \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/selectors.css b/node_modules/jade/support/stylus/test/cases/selectors.css new file mode 100644 index 0000000..a95cbdf --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/selectors.css @@ -0,0 +1,44 @@ +foo bar baz { + foo: bar; +} +foo > bar { + foo: bar; +} +input[type=text] { + foo: bar; +} +input[type="text"] { + foo: bar; +} +* { + foo: bar; +} +* .foo-bar { + foo: bar; +} +body > #container * { + foo: bar; +} +#foo > #bar + .baz { + foo: bar; +} +#foo>#bar { + foo: bar; +} +p + p ~ p { + foo: bar; +} +ul :odd { + foo: bar; +} +ul > li:last-child { + foo: bar; +} +ul > li:nth-child(2n) { + foo: bar; +} +*, +p + p, +ul > li { + foo: bar; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/selectors.nested.comma.css b/node_modules/jade/support/stylus/test/cases/selectors.nested.comma.css new file mode 100644 index 0000000..e2a4da8 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/selectors.nested.comma.css @@ -0,0 +1,9 @@ +#container .hide, +#footer .hide { + display: none; +} +#foo .hide .stuff, +#bar .hide .stuff, +#baz .hide .stuff { + display: none; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/selectors.nested.comma.styl b/node_modules/jade/support/stylus/test/cases/selectors.nested.comma.styl new file mode 100644 index 0000000..38a1ccf --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/selectors.nested.comma.styl @@ -0,0 +1,8 @@ +#container, #footer + .hide + display none + +#foo, #bar, #baz + .hide + .stuff + display none diff --git a/node_modules/jade/support/stylus/test/cases/selectors.nested.css b/node_modules/jade/support/stylus/test/cases/selectors.nested.css new file mode 100644 index 0000000..54f17f1 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/selectors.nested.css @@ -0,0 +1,34 @@ +form .foo { + color: #000; +} +form .foo .bar { + padding: 5px; + color: #f00; +} +body .foo .bar { + display: none; +} +body .foo .baz, +body .bar .baz, +body .foo .sdf, +body .bar .sdf { + display: none; +} +.foo .baz, +.bar .baz, +.foo .raz, +.bar .raz { + something: "else"; +} +.foo .baz, +.bar .baz, +.foo .raz, +.bar .raz { + background: #f00; +} +.foo .baz .ASDF, +.bar .baz .ASDF, +.foo .raz .ASDF, +.bar .raz .ASDF { + background: #fff; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/selectors.nested.styl b/node_modules/jade/support/stylus/test/cases/selectors.nested.styl new file mode 100644 index 0000000..dbe2170 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/selectors.nested.styl @@ -0,0 +1,33 @@ + +form + .foo + color black + .bar + padding 5px + color red + +body + .foo + .bar + display none + +body + .foo + .bar + .baz + .sdf + display none + +.foo +.bar + .baz + .raz + something 'else' + +.foo +.bar + .baz + .raz + background red + .ASDF + background white \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/selectors.pseudo.css b/node_modules/jade/support/stylus/test/cases/selectors.pseudo.css new file mode 100644 index 0000000..d5ef504 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/selectors.pseudo.css @@ -0,0 +1,27 @@ +ul td:nth-of-type(2), +ul td:nth-of-type(3) { + background: #000; +} +table td:nth-child(2), +table td:nth-child(3), +table td:nth-child(4), +table td:nth-child(5), +table td::first-letter { + background: #000; +} +table td:nth-child(2) li:first-child, +table td:nth-child(3) li:first-child, +table td:nth-child(4) li:first-child, +table td:nth-child(5) li:first-child, +table td::first-letter li:first-child, +table td:nth-child(2) li:last-child, +table td:nth-child(3) li:last-child, +table td:nth-child(4) li:last-child, +table td:nth-child(5) li:last-child, +table td::first-letter li:last-child { + background: #fff; +} +table :nth-child(2), +table :nth-child(3) { + background: #000; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/selectors.pseudo.styl b/node_modules/jade/support/stylus/test/cases/selectors.pseudo.styl new file mode 100644 index 0000000..e235a18 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/selectors.pseudo.styl @@ -0,0 +1,24 @@ + +mixin() + td:nth-of-type(2) + td:nth-of-type(3) + background black + +ul + mixin() + +table + td:nth-child(2) + td:nth-child(3) + td:nth-child(4) + td:nth-child(5) + td::first-letter + background black + li:first-child + li:last-child + background white + +table + :nth-child(2) + :nth-child(3) + background black \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/selectors.styl b/node_modules/jade/support/stylus/test/cases/selectors.styl new file mode 100644 index 0000000..f3a5b32 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/selectors.styl @@ -0,0 +1,41 @@ + +foo bar baz + foo bar + +foo > bar + foo bar + +input[type=text] + foo bar + +input[type="text"] + foo bar + +* + foo bar + +* .foo-bar + foo bar + +body > #container * + foo bar + +#foo > #bar + .baz + foo bar +#foo>#bar + foo bar + +p + p ~ p + foo bar + +ul :odd + foo bar + +ul > li:last-child + foo bar + +ul > li:nth-child(2n) + foo bar + +*, p + p, ul > li + foo bar \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/self-assignment.css b/node_modules/jade/support/stylus/test/cases/self-assignment.css new file mode 100644 index 0000000..deaf803 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/self-assignment.css @@ -0,0 +1,3 @@ +body { + background: #fff; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/self-assignment.styl b/node_modules/jade/support/stylus/test/cases/self-assignment.styl new file mode 100644 index 0000000..86ed143 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/self-assignment.styl @@ -0,0 +1,4 @@ +color = white +color = color is defined ? color : black +body + background color \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/vargs.call.css b/node_modules/jade/support/stylus/test/cases/vargs.call.css new file mode 100644 index 0000000..e9f521e --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/vargs.call.css @@ -0,0 +1,24 @@ +body { + padding: 5px; + padding: 5px 10px; +} +body { + padding: 5px ; + padding: 5px 10px; +} +body { + padding: 5px; + padding: 5px 10px; + padding: 5px 10px 0 2px; +} +body { + test-y: 1px; + test-y: 1px; + padding: 2px 3px; +} +body { + test-y: 1px; + test-x: ; + test-y: 1px; + test-x: 2px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/vargs.call.styl b/node_modules/jade/support/stylus/test/cases/vargs.call.styl new file mode 100644 index 0000000..bd62e64 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/vargs.call.styl @@ -0,0 +1,40 @@ + +padding(n) + padding n + +body + padding(5px) + padding(5px 10px) + +padding(y, x = null) + padding y x + +body + padding(5px) + padding(5px, 10px) + +padding(args...) + padding args + +body + padding(5px) + padding(5px, 10px) + padding(5px, 10px, 0 2px) + +padding(y, rest...) + test-y y + if rest + padding rest + +body + padding(1px) + padding(1px, 2px, 3px) + +padding(args...) + if args + test-y args[0] + test-x args[1] + +body + padding(1px) + padding(1px, 2px) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/vargs.css b/node_modules/jade/support/stylus/test/cases/vargs.css new file mode 100644 index 0000000..7db9f11 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/vargs.css @@ -0,0 +1,30 @@ +body { + padding: 5px; + padding: 5px; +} +body { + padding: 5px ; + padding: 5px 10px; +} +body { + padding: 5px; + padding: 5px 10px; + padding: 5px 10px 0 2px; +} +body { + test-y: 1px; + test-y: 1px; + padding: 2px 3px; +} +body { + test-y: 1px; + test-x: ; + test-y: 1px; + test-x: 2px; +} +body { + pad: 1; + pad: 2; + pad: 3 4 5; + len: 3; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/vargs.styl b/node_modules/jade/support/stylus/test/cases/vargs.styl new file mode 100644 index 0000000..297b2b8 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/vargs.styl @@ -0,0 +1,49 @@ + +padding(n) + padding n + +body + padding 5px + padding 5px 10px + +padding(y, x = null) + padding y x + +body + padding 5px + padding 5px 10px + +padding(args...) + padding args + +body + padding 5px + padding 5px 10px + padding 5px 10px 0 2px + +padding(y, rest...) + test-y y + if rest + padding rest + +body + padding 1px + padding 1px 2px 3px + +padding(args...) + if args + test-y args[0] + test-x args[1] + +body + padding 1px + padding 1px 2px + +padding(args...) + pad args[0] + pad args[1] + pad args[2] + len length(args) + +body + padding 1 2 (3 4 5) \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/variable.css b/node_modules/jade/support/stylus/test/cases/variable.css new file mode 100644 index 0000000..1ff59e5 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/variable.css @@ -0,0 +1,3 @@ +body { + font: 12px; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/variable.styl b/node_modules/jade/support/stylus/test/cases/variable.styl new file mode 100644 index 0000000..7b7c990 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/variable.styl @@ -0,0 +1,4 @@ +size = 12px + +body + font size \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/variables.css b/node_modules/jade/support/stylus/test/cases/variables.css new file mode 100644 index 0000000..45f21d7 --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/variables.css @@ -0,0 +1,12 @@ +body { + color: 204; +} +body { + font: 14px "Lucida Grande", Arial, sans-serif; + padding: 5px; + margin: 5px; +} +a { + font: 11px Impact, "Lucida Grande", Arial, sans-serif, serif; + border: 1px solid #fff; +} \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/cases/variables.styl b/node_modules/jade/support/stylus/test/cases/variables.styl new file mode 100644 index 0000000..faf4ced --- /dev/null +++ b/node_modules/jade/support/stylus/test/cases/variables.styl @@ -0,0 +1,17 @@ + +size = 14px +font-family = 'Lucida Grande', Arial, sans-serif +$type = solid +blue = #00c + +body + color blue(blue) + +body + font size font-family + padding pad = 5px + margin pad + +a + font 11px Impact, font-family, serif + border 1px $type #fff \ No newline at end of file diff --git a/node_modules/jade/support/stylus/test/images/gif b/node_modules/jade/support/stylus/test/images/gif new file mode 100644 index 0000000000000000000000000000000000000000..b3989fc3c149e41c80cbaa03d33ee82c97397976 GIT binary patch literal 59920 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

$4XOE=egZ3471rYlE*#RH*ieLNk^^kd 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 literal 0 HcmV?d00001 diff --git a/node_modules/jade/support/stylus/test/images/squirrel.jpeg b/node_modules/jade/support/stylus/test/images/squirrel.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..030ce1af21e95fdbc78bbf7ce23ccaad80347c9b GIT binary patch literal 21805 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 literal 0 HcmV?d00001 diff --git a/node_modules/jade/support/stylus/test/images/tux.png b/node_modules/jade/support/stylus/test/images/tux.png new file mode 100644 index 0000000000000000000000000000000000000000..df25ec4e45762ec5ffb4d62c1c4ea9a9db3cd225 GIT binary patch literal 41236 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ΝS%2?pd-%iml2 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�Uw`($_+hi3~iInAhSe;JEHXCeMoCQsGlK00Jf(R$B zO@~{nI+U?UJxM?E)4nq$wxjw6WrVhZAZzo-S8{zQX<$nQA3gEJCce~Y1@dj6~uH*2;1 zD2TGY-AB$J+EIr==jK}qPae98I`!c_jp-zli}**|eWnUl%=3v&)aIKFQ!XrX=^fg9 z8-|MNhsH6EEnpjVZTSC*+x!*F^yCK*$Bl-CS>X0J_3)GC z)ZukuzT9(^$q4)_;-*j;$GZ|$h7?pfnLJ&O{C=wjg(9)3$1VYklh%>b@H8#K8jd*0 z5TtDA2}2y$HyYnu^lFcE`K2kIq^S9n-3DICXoT4}MutN2yc4IgpCk68EzGtA(4!Sy z3LncMje_3D7EmWleVo&t%^G^dexN6{*yLR|ckp;hRB%vLVy%%|?12;tY`8Vp0tMyBIzXS&>B!Ds6g_V8xT5WLxg_8n0QOiAvQ-&SL6Z zgVUb)H}E4%mxB2R7!w7DV*LpX-)Co5zjZT))xpuzGnXC$>OHyYdc99bqE)l~)piOB zx_j6DyNp&zlYqJQ@r-ha@Zw7U)TRDFm5T-LMVXGK2HR_Wo$uI}q)3+LGh-2yPH7(# z6VWO(b1O&=ROTU>wKXHvD28(z1MdQVg7U!pq!iVqdzF(KRlH9BF%5K%gW!de6i$rh z^P0PdDi<9&&@H)G0N*|)PZ+MW=6-)52ZM&Ob&tB7l8K z>Y|TEMtJSg7Eu9p`{u6H0rpCImJI;UG%q47nLWR8dJrV#I`! zB`RkYBKpEkl`O>ESh!GOJ?c93%!z0=@DWgdLOjA&DoS^`&=Y&Y=|In<4!J?)`B_#l z_sk9r71W94%%Rkd=1;&nx5?yv5wGvEmfP9Wp1fgeNgSA_U3S%X&)j35gy8@KPzn zu>3TVATq$;gAX+i=pnHjI_u6*lno-&B|B6xa8fPY(Lt?q2zyI&T24GUe=LU5u;w=lD2_MgOL|OLOzBStP1yJy>+4ZC&rchj84erbHT^ zIVEXT83S~gbICW;J$UO{-fLHDV4d%vA8 z{^c(`ih7WT%y$yxzJ&&BMI|LE;~7qf`!0Yx-nsU@R8Uap3HH1qn0q7$5XK2v_~aM) zdF(w)gg6HE7l|;u?61?2s_iX@lbrS5!PpxrQUQonL<>URsVj!5lHIGV&5Eq2zm3oj zHw0)Bv5dBhdNO*1a$zbCrH7>SrP%C47L6!P90FHsvB8+dKjH6|xOevUKum2IUQCao z241Zxg$f@ZXD|<{XyMEGmRlS*Bu5Xc@1iNn{QzNL0U&>Ic3ven3%u!8yX?GOwFZ>h zyV!V+MC(_^L}XQJl$_Dx$pF~DC=5yTvWDr=BjVToCQi05-)r;TO4RE(s!bl~zFv=p z&lrY~@kAdzH@BCzBHd*$BpNS=KyOzXq3C*`B_ zIBDuS{wv!S*I;*{H%OwIeoGbvTqpuMQd!-K zrYBJ{=?9-hasa56(iBntju-g zXtAGjexJ6*Evm1msd&;!%}Nycp+ObslD`#U3yb=xT_*DjfUh9CZB{=0^a^4cV(KM{2|2E(PzkK_g9O5#_5K^x$7Jv+_3+z>-sRRB-TGdfz15xi_ z3kIl_z#tk9p-xoABVp+bKMD`)JUDciyGsVUcaAsgbX%)N<3Z3t>?r8SKRl@*{d!Q# z9#mNRlcl0M8=3qiF*&&pFpBNy)H2|+$+(hFib0!@;_#;O;^6AL9Aq0-RAeVMf}c-YAT5Bh!xIa2j4iQXm{5-ItFV6ne_ zC@r?{7wO&WlMz2$a%I`Gs~1-$3_MI7qS$(`CKE@K7v~7LLjanaR6L+%xZmB8(h!pV z^b{a$v%~hkDjdaaJ+z5NnOBKGK4NwOhKnioxEXBEi7C8vo;qiFwFL)s$`mIPRtYxw zED8pk|H7`;BQF}T&}cbm{NQutD(JQpa`J1e=8C&~jSMd|b#JiAUw4vW#E%`FJE{sw z@wJCF6g6ZO-$qmWuC!L=nZ^S&V6qE|)l;y%=j0?Te}Qw-_a)fr;%wLS5E?nhdUMB> zL-oPwEDG=uUIM6a!-0)}#rFctwWllX`f4?zSS2ZXYXH%6(z&WGUhUTg)rip*BSkL1 z`;X>*(Za2rDPQ!k8NA{%QwHN7lopqB&+ix8)Z1^gjr0h6LgWxi+XW;DKMj<2cyOJ|0GC-l8VsiSaT;sF;O77>HOc~g;E`;ky8yc@TjeXWS-w( zGGo)U3>VHGys0dpG&$FYKI2%hd$Nv-+rKHE6BwDJ_*FiO^S$$G){oRf*s+g zi-PFtn)juES(AoaJR5Bf+pfZ6ZoYD;#cv-b7{>XK8ZcpOglw zOdcBv;Yb}E5SNd-pl=4WJZ8NpR)*sC`%!44J>_Yuh9_4R0(sl!dcSj7$HOdluv*y| zRJP_PP2GwqAlxUVuO%nr<&F#wTTBB&oNYM*W!^)v%1yUBKDM0Ng1U|hEfXrw&(b~o zqR(Qf^$&5klg5`t`){CFhBSd=%Lt|7EIr{yh!;{q^3=~@>aGugumQ`E;Y;dWWG*jn zeRDTc%(#^uNs1$lf%VvRni!}C%>@DM4Z<##%iuC|NmyU_ak&@~N{?>8$l1=S(hWt` zrSHz}?ynqD5zlfNViyj@4{tAqX#v)x{P$|%0|?-ZkE4=M`||L=V}E}ijs%hr3wvTq8BvFoXhf3Pj4COH476Gt zg%&PJUnJs~5v@Yv3Ng-BOVS6bih>vySXcb2)-q|Inmg(!`1qL4=GVN>?GxH^WjI+` zQ&Rrr(-lASFFM=-C{nlmDH_rUEDe4Ap+C&prO&s3e3?#((f#p?K#y-?p*r$Q==X0@ zh@1VG)rI1;$&|jb*$H zrG*6U;PG5q%E2D97dv<@^^Wz0&dALeV)+;P@v}>spzuzk5s`kR>!Ix# zbz?6!M`J?(q;UJSZqa&zbVo3qIJrq4-*?W%O_%=~%Jned z5F&SGXlg1e2>is6xJg%S;Tb3GtLZhKBrNJYf+SMwY^4T!>wddiC8z&1!jA_Dqudd} z%c-x$GB520}NF+~!*3(I79mcdSHX?{81xKxsIWwS$1C zYZ7oi2tlFZRJ48z;N=O3h&ENCuqpYXtF5Nid!KHm?(bVM>a%3YuE;$;shP57D;17) zCi>X1q86pu6dM)Zx!2nvG-m=?Tg&Cmu0Q&+5I~66P=$Q2SG9z1?C&SAz2pUPE46b} zzTHN8FNrmac5w!Se#&g>c|zc`X-!j@|E=S-AD3ghC>uG zJy}v}8jik-3MOEzNR^HPrqiSWN32dDJ2n7t49wLeo;`z%_ep52WT;)&pav zI@Y>3P0JtS@n!d32nmi{)K%RvL1MMGap~_ghkM;}B5aY1;niA&65^j(o@1dZ{nQ&9 zQ1r>(5y%rQ`1H2oo}zNzC+?y#SZQbYBwom8_jdr$+=v$hi~+6t#jzBPXDoPoYw)`h zd8|pW1G?V>19Sq;OEPt4op;WKO|Lb^6{2k@At$7=o~Qc2U@3QmqGgp_q5B!bN`PQ} zn71ZDQ}<4}Wbs^+YLEX1d1ynn%pW%q6fHzgZyD;KB2Xk<&#IC=7pS%jkt)>ZHU9Q- zAP;5t*y8Q3-qcDIfo66N%us}9J>R|Jy|9U@Va=>D0puT}DxG*)Jq5(QBOe%S#@YSU z7^mQ_p{qLrXk)$eYXP)-ib2-*BZTV(W ztKSI_g;0DjeZ+DRwf4cVvN_bs0#gGoUJD%YXIhCc#kYAqs4`e8X0@lxi9W)q6B26g zLCE2GantutPrjURcqO03?%FxTIv^Q#i3nl9kdlYb1X28Pu|_VA(w0ZXQwFQ#t#(+wOl47&tq{RgCAb(lfUwRt-ag`s(D?Z z(#>5edLn7m02{h?JM{szq&!*CYwb5wB{O7W+?qHQ=o>dn4$+L;UOR4~KewE!5W{Sl zAaub{MEp=ha~Xa0FjN`c=epPdbJXj0$r^9gq}6^5rZM#%t9ZC|cy{zf-_rQxY&kJa zb8~fIE?(fn6)p{;n<7on-b5ZSU8H+NEom>`UoBG5>GIp1YN0$e&*ypeIVCQ7l%PKH zzQgu8F{XTk8$S(H469}SsbHx${t|~9KA#3atbEaNGjv*02h7!l5U_vI2lT3)*!>Nv z(7RwNX|{m^oV2PHrDcoe-`<|$?cFE;6l_PTtFy*DG~O1dWJt9LBoAn=p>8LKN4s`j zr;jgsSTq=9ia(pp0gtt2qP$uEwB z+W!L!$P*#`9Ukdd#ZqxL2w0gK7gmG*zRbdbxGiPhsYRYzQhDfFoSU}rM&5zVjWx-u zg1_{deQTlj1}=A+HB>pO*?wn&=Pxae-=achdO8CSDqmU|rAlgB)CZQs_EUj|JBe5z zOmrwLJk2dLC}57DDN7ylwk0*~Hhnd{?la%6^!ZqFGLC*5Hgi!eUv@FV2r3tu4}OcV zn3e%B5DVO!jg_PrI>*~50YWnq=~@xpfG|B07q)eNoGe1pAs7(#wjH_YdqT%Jsb4Z8uBrf-#UjcEVivK`lxHEVv3>gCBwq8H*CMs)uCW zEWDGXsU8s$r21e>H_OAR-l7;Qh3%j@tX-4Wmkjy*{tfTqIfgNIc{qrz7$xNfy$lvs zVgHHgA^HfNJG`f3%z40`Z}Ff1Pu!rF#*D2H8XWbb(W}9Hds}`1fl<5)uj3^oTHLIQ zcEC7J>c9Cn?RqVZwe{&@O!$6^`ysWj@}rvNHwQXMIZb->H?Wc!l0TMZ+&j(ZEpfg- zGSodO*)j(<_d2X{)Kb~C}pLAI)E|zF=oZaU_ftEA{ zt09pYb>@xXRRTEVvLTO^a)Q;@E)qc)96CBW#i0vAr_EnQC#OobLJz6$6#2QJY3>%H zX;XTuIwTz`su%bUssO~z`=B{1rXW=#uVuU>Zaw5Dae2B;A)E5POW@uPgo+5&fH2(P>bhHNpq zn780jo?X4^r>+Uh-Gjx(VkklWpLjJq%#5ByNvEqj%lK*rEYt~2gzlbgt|Hgz4+}&q zc0yl^D#Qo@`G6rmWYgqdC+dC*vEM-GXW0x%$f^+60)|4KjjtN_PXf9xLCw^8d$yAJlcCT5DQh8 z(&E{UKXM^`jJA=XR`Yl`IIPPQ^W|YA7Lof3Xt_fAT(m2#FbYTia}Cl;)h;9T z%}YQbxL5^OYE=X|F_zAyRlik4TC1 zTB$6n?~+e}{azo83hgrDyO39f>=F^8Lco3q2IO%*J?$DtX&U!_# zW`Ebmm3pH%R5$)9)0ANwRY(LoJGh8D6Lnx(+w_`A zUI4F4E*2xo@;zx)8h!Yw0t4>fNRo;KXPWR~yq^d;BndXByYoY=`J8D6?}#Ol30m~4 zgqED?TWA)Zb2d34;^bvL1+GHNtcZzxV+KcZ^Vx`s$2=LbxjXFbJ3k>;UW%GN0aXYu z)Rf0=!sQ!1q82*X6LGWfoJ*%011%Ual_(x6CGI~~&?Yw)%j8G>=QzE78NZ@)lu0xj zYA6W`$<LF#SNzg5q3k(ASMrP2KY$h;vzI#wy$H@a6oF0JYreKW- z&68>13noHrH(}QoyESI0HD@wL-VHBwo59cd+mkqk)8OswU5Rc*iLHu46z_`V24r(O2&=~j4-Xl!A!|Oe)}tBaHe^?)LNu^L4h}L9zKTFq$ z?PG>NLd;GLrll#dWMxVMd%K6=!UVILeNw@h7O0i7z^~y}fLDkQaQp~-ZJN`>zwR}i zKAymN!g#s2!aQHPc!Le@G9OzZ;_)S#&4rHkm5oi2P)xCBb z{Hi{^Nv)RM0nC+k4n956@zTld_lkbxjnGfYc(< zHKcI7BxUGgTyGxrMalC7BQ^!=tD`0b;v2X(zh#rNyAg}IMXf|7DMO}yQ6q(Pa4vpZ zOBwElHMTR}Q@dfuITvUyu}&UXwQxemg+#Yks}2@tiHhv$dR6ut!OXN6G9LFmD7CCJ z$Zh=-d7^_}&r)xGuP3urucL>2F`^6WSQTVU^j=rAyFgv^c0sp(TTt|8{ zCp}2tCL^BgjHa9jBLy``(fT)&U`il|R`q&!{SpSZj}*b}FvSKX?C>h_`{Yo21;|C$ zEll-mxF()!a>7w{SEtXb$GJC3M4Cz!fdR*BxsYpTi<{3$>)rs3MX{xeq;*6TA4f*a zd=6KJy$qT%0^6uSYo`Q%Kc{pxZESLq^z10E`$wws_5JUWV4R)ku_(4sy{q-GvHp7Ol zP1jj|S%B3ccXH)Vlf@2SUch5t_WgVMX8&UTwl&pbX2ra167-8I708=J<0}V5;j$%8 za24IUj#rT4KmZf3I=b;SV~iJv=qZ;Y3ELF1){Hl7v2<(5Kf}*f@5A8*){+JXa1QUZ zE@qpuy5X<9T(w=d+j6G94;!8!Eu&;BD0Fw`tch}hGcexUn~1Giyjc4>oNmE2Ox%4Z z>rUi%o)>;{wsIPj@p$rR;-|Ypfruyg6^9vD##(8xtS!Tk-={FbR9F~#5e-T+{xP`wT?4#c+ybr%%(OI}r; z%yZ(WgU)Rjz)h%PvxeBXyA={V56E;64GGeUvT>@X5)-wIgO<7q>&RUt7QdiI)FTF~ z_%Pp$@rE_%rVwH+Xe4Dm()Z;Ddqab6fPih?`Xbj;6lqE!onvw8w-3g=PD(%NW1FP! zVyUPIrL9tuY_oVLgu;PbX#tQ2&5Pw|D;L6#3RfU6c>KF3^Ds=5!Pd~+XVN!{sQy`( z6!I!R^W~?-Rl+uQ6jV3$i*lRrjZ)y!wEegqwJMw>Sks`b<4_wG}?Zn|4%~N1{{F6 zRaJjo1Z6*m?|=Az)~49~cFK6fu2X?fIh!gqm_MWBuWn(5*O<-?-uV7uVHp$>CG;sr zeg-57$_V3shP%v#j+fJNJyESoP(AIzCx4Fg4fUs<+hKXsKBFh6oqOL_} z(MZ*NXLd4|zp1VWvyYMMp>L{Wc^QX=H&sWy>Ct3ODA;DNO z*ak6vzp^Nw9G6*=(TMTDYd2U{8KzCJ^eqtz@qkPqULK#GP85=hN=K3n&CUgx1SKMb z7-e=vA@Ztx7wW1bY{&au1XD=wabN4wPB$mD4qI|G5r?$gwsZw2T*%OY= z#A%E#*`j#|hhr)CYsv`&m0yIetN2-5E$++5M{c;hngK~??G_L*FtDh5#pTPWOMF_t2>-Hc9WwQ>=%fE;OdmU&W!k$m7c*ZgGgSY@E~T{B zm*h@)%S+kdK3Gk;cR&r6_o+v=Fx4K`H|O3Oar(}n+uqOJmyCJ|+32s<&tHe4q$fCu zDs5BA+&9k8D77uOC{~$n8=Gf9!~47lClI!=VHwhaPDhYk89<1vniK3^8tuJ%{ue7M zG^J={x#QKK;jD+W2M=@f0D>VJYLiS6vauH8N_i&;@|fePPnQk78K2or^hoSkX3~P` zj$ZntR2%&6PeQ0Li;Fv}P!Ci(`jpG5B-Tj6_e+I(m(U>1 zOV464L#-NvTH-Aj#eH7~+5ftx){A9)yq!x!j9F@S3qvF{QbrggkGPVlATVg{D-2+yQD7 zz;dswrA@uG9<2djxzfuc-}pTD{O^CGU^s|r@;h$7oj2ZigZW~8y;TF<2eQw`7A7{O z6YrkwS>##b(0{yCB#;aq(92gNRte;`w6A4FCA@3|G}}p{@Xv`Qzq=rM0!q#Rm#N8K zxU)U9T+EPIyeHjIpEx$FY#v@(;){Xvwr=EC>8~*$z<{yXefB*YpC*4RS z0x*vPDamM{k7L49X>$i&n?DmjMecD(#$6nHwLa6`MEPd1BC8!n>+B@`I!_X`g2^qa?mt5^im_S zh&$8apV!kz90O&V^3{33It;3thCnN1FC$;iX%K6Lco+EAi2eXbGo}q|S=irM*Zx4E z^?UHt!^H7frMlA6aq5>0(A8cEz-22G?!D^4{A3cEY7Z=>yl~~KoP%mo;zj75hDpzSXg{G8(><4vXR`Olm)I)DiS$fA_KD1ut{qKJtzyJLo z^3+s!c<#C9`0QstYcUi!zvU~xKZc^D%u-OwKvQjqz(x{DjREAY2jU=BT($42CWC#z zU%vgH_h~Z-M5GTzgPSD;RIeCDlC_0Xiqi7O z>7KV1#!t*D$tms>%bHGc>~K8*8|wYk?mQ{B%+Sj!D2hUEaM-hF5Bfe@Mz9w+j1CoUx>~64_mvWVLDv<*q`ydsam2m4D2I%gnOgGf|_~u$}-SS)R zx#u1pdgvi+;UErrdf_RCzU2*BJVB5=?&IJUi>u7hDRh)ZynE|2G#24zzDDhPZ4gPNvcyNRIq zpA(1kzX?hhe9MJMERsY15{UH_efIB>10Z=ojn7K16%}JtRE{z@5CY&9T_FFtcaYD2 z{`0I@u|n*{WR1hIW5>jj+#mhuN1Qr!iiOICjPxN(8iA51<_3BwpAB^DcP1x*xuy?? z{*$G&?y4a&;LCLPsDvn6y+{UD3FJB;kXgP07DEED|6H;k#sxDfTDFRU2im zT$Z?$a)_UrwPc%Cbu;uv5KWWtDzYeLed)P&?z-zPYHMq`{PN408YgY&jd4-#d*Ou_ zP*s(Mi+O-B5Qrkn8YYxrMgp<1jXQJP_Fa<59*6!`lQ;w#^hj{6E{`2ppqPgT1!CVT zUoh?@kj#5%5bF~C5!?;nsRg8I1!0{CvPc^mK%S=7jo z<@{uOFUR|$TzTb{V%e#_xgTk8Hais3`07``%HZH2#esQ%FgR8DN^+%B`COaf_Gd&S zkJAImf`R`pj@{La_4_fyK?$zb<iCeS`Dt25KyyXs1O5z#gTZ_6vWyfaSA+3 zK&i;rQe3Nh_63vvR7xQ+IBU@^TYie3?g~;V8CimlTvEgTdbSNs)A;nKKh0y0J;ryw z^BvAT_gqd#dV70${PD-xx^=7QZD^WCvEg<};uOLeS75n=M%vYEl%s5xxMa7}1F=BU zB)Z29N{O zqy)1p>^I@XyK^_8E>g%aXzHxenWCgZ_c0-g(@3 zUL|HYk|B;Hb3`)ASF3@;7_7atjq2sYP6CENFe#x zm{ChX>=dBQS|Y6{YiMn)Nxy}U{`e?|dnTBPn{K*^v(G-83opEoi!Z(ypU+3JaP;WW zv@pcn#=yV;i+$dzC zUz~N;St6lSR#q;EGdK3`-OF2Vy(NbGo_XdOdU|>|U06S90)5I9AeYz}BFxdxOJ3mg zO&_CuCG@qH()m_+%Cw=uganTR4_@~5ecLf%Um)+rAiQ)0*`LL|$UElXe2)YMQ?QX>A_Oqbv9Pk$FBrHP3Nv74>_nZCrvgwbeJ^ey!7 z3=Iv@*ViZJGxU@pKKuLoIZYA6gN+ql(u4xzm~i<3DP6+KW*Kj8f8ON>$yh~rnxLj+ zdQX;#GS%3if4a2MBEk10_`iDE=qC>-dig30oQpw4!zcw{5vQ31#JWKCfjbP67a*&p zzt%Gyc9P1Zdy)jQ8&Zi`3$wm{fcB1RQYl$He$#nX{GaDLutPK&W&i&D;+l6H#P%hU z#LQ=)yF~gZNb)c@^GhK)xY$#OC{1-8sifyvg*dCjEDe$p{1SLbf){jgXyg$ExEhet zMlY`$E4pR1=6ee;*{D&7c7Q7YN(IOYsB_v5-dX}+@ouYB;{g(u=_|9rT30(jM`slP z@7z$%4_@hEAdkvb+nR!uF!Pp zY#jJE3BIaJV~}}50j|IxSTTXylL9Soig;J5;a&nio^})goQ*Lihl)`C|{ZT1{OQ;+881f_p^Lf2`;+yp=lD`$0}&sUqd{q zFb%H&-vxdl4tknr6ks(5q3}eJ4g?lqqdhqasR+m+kxD?aaZK$r_f#AEZb=Gg$yv+M z>q$@*9;Uai9DwW3uH@0}y+ji##e{?T5UEgLVroIi9?(?degVo>re?kjs71e|H<@sW zGF8XnDx*wgA_Dx>SV^^;0-^v-82AEl(B>@>IL~P+q=q3mW*qS3ouT}cO|r;-kkKq6 zmk>x6A{EW_v_MMzF5bPVoTqjUP*gaG<7+De3Tc9Y=~iHQvsi(Z|1y`5h&pCp99rQL zM@LJT)&n)7Np6M~;6V^g@j(g?3a}glZ%M*Q5`~bCmNM$MZg2&~XLb@WB^3KZi;|qR zK!YVwF)uJQ90cIXwPl7t9Ex@SD@oFXK+New0c23sdSZT7YECL5s7aQOk3jb*)AZZof%-wiToYE~kt z4iBdV!Wm0S#B$KlXo}*&VQGbjG=6U!m#kvKW?8R>^?T54iLj!4lr%0` z;(`@HUOF^P@!(KVqF|6-ePvDqk{2{JC#$Oj(xmT9b>HGy$!EI1kiSoicsaOz8RMf~ zCh(Pit7X5|3B=rl&t4=R zcT$u*#v*Y<^f78$0-euXROe2HdrjI3^k+K zo&-q-WRMV`X0bXef07d=EJaC)4Hf~`*7}Q8AWjcNNlu>>R1NFYkX4$n{~n~=m!0gx z$UupZM?C5#gFy*y*TwN1MT(ShBH=l}b3i?2@c5F1D#wLT^iMIhF3Xye8Wx0nB#>l_ zWHG-j3P$CK)2vdT_SG-?g#DyTx1ZBD)e`jipy9ZE+i7F zoS?K~oXWZp(R?q&W{OTfMFTChaDE$NEfGDyG#a!?@aLP21DzJPK&+**%8<#$8eA&DnOK8MQ4N_yDAPZK z<>ScmVibz=Yudhh9f_m@z&Bs)V?Pf_$pIHR{I*`5dEePxHu`bZ!1xX$n5+@JW(0-(vNxTT$s>`Dn;PexS zwNT1{OMuP5+ch{}0v|IY_#ULWt6y_iA80uo4JUK)(0kW;Ph-fi%|jvb>?k zECO#BloA^v$dh!U9e|o&S(xvMe#e0~mowZSn4HJI3VcDAM+yT+Al5?h0p|m62R3VP zi3DX>AW2XXil&7kl8VQZbkaqUJ=fh=$&uCu0OCoFcYo)A_?#mrf!)9^pap2l5XCTy zlMt{<$i#fDBF}u|#uZ%96a=8Yx}WByU1mYJ%RmVhGI5x{YbwOM@+>LyGh-uu4*qEw zu?cskIff;~b|lYWfg=!Wp}345%I0)R0qU`al30SUQ0uEi?%@>1O-h^(2f2;=}*d!%tr8#e%)S7GNvTN47ZlfK8L6at7dM4&3*S z20n0BB>)wrV{B|bVHSbx25%T(;q*aLBaj-;zc?h&G>PMf>gYTfW)hD9f2qqO0^kT_ z{)AGOQS#ahoGDo}92Iwp@=75S{WF5kA9scs3oMtR(E$67G?C`+pB&|2_XN|B0KNcx zJ?H%h2L)I^Nh)UpAuPD{f+{|Fc^v>AcY+Hxy*0H2eAOUHc}^kO3=#GNsl2C;L|oy} zu11Cj17wf_{tl#XZ2tOQ4ZsmdVTB?C*8uMU-T|z`0)I)|kcoa(L~tpoc}@w=b1iL4 z=;^NjpldkJO%ESNV@guM6~HUZ7Y;7q0^nNXItwrv;BCtSeCwtr(p<3dkmyC4MBpw1 zm)nLEawr;2g~UMKOID-9eh%$kMl9+kgFfJ9J$1Zv?<>5ScyrYhe-YNi84Q~GaVUa@2@K3;(SV%Z{fh*GKasPAeOhN_z2KW~iG!DPKXWet< ze&s!YNFRC%nOX!&3CQlkZXKc}Ar;BX`&Ct<<-k&UyUR$UK|+H2ba8we6OKR@gHRfP zs|}f4EkT{tKx28u7**B7LMVzw@5D(UW;%Pr9P6kj&4+*3!pZ&^8N`6QfS=<~3@QIU z;OoXIlcEnYWy+9bPy&TbAE^l-nd|q9lI+3V%NZFe$&|;41lQ{Fcm)Tf)8G$+1e}>s z?%E9aXXu?6G8v&VJc3(EIU6ookVq=*IJi2UKG<<`jC&tHK?Xy>^}z2b794?G0lbXC z`5WKD>rPB95!nMScY&7iszM++-wbiw!-3r^#AgP_LCE7EMT{d5`&06pGlX&$AWbKe zvhoO3;Ss`BBe>nk(=e4-)6%+xo`H(=V|@J4qa5s-z@Xh|)b6F2a0F5c3<5I1$|YSi zRQFF`!*KaPlIA~ssIi>)KB5yIcJEjzmg{D)9r%DQj~*5ojzH|M?z#cE5x4}9nTE>B zQEF<32v?2>xh(#nL2E`LCG2TgNt$2p8{#X!ZpUCh@NS@uV#JZiv%vcR0{$rHtUUrS zeJRW3ndd2V71Vf6-ye^;*|Vcb?B|xjFF>3eIF5rO5R2Z)^@dC~11`+q^(LsR8=$Us zFmI`(@N%(6(}+B@;v<6}8I$E2S>Oo7kx5O4Os)WwshaOqRl_vY_ltAD7hiKc zyT}6w0oMXCiWx^BUZ4XA1EPebm$EEs84}1cAmvvgS_;r|_D)rk*t>Hj zqa%JY_!;nFT^=enaRlQ0LAn$8N1zcighJ!gRu55EJ5Vgce|8Y5V|UBS^w1!Ox+g^M zL)CZ^xD`mS7;q%=9pD}Sx02+7jcoV_!dbg_TWiplc$wbAoP zkV71SI5N2mxW`B*3X>@D$7o#IOI78t=#vzG+AtGKxY>PpC2{=|K-CcP&?T}JxC=zi5$myIwjQc-;uWvhLAS1>l}CyfSgNN|}hk0^P<5r`v_rNAeEyMbyZ z;rGR9Tyl!)un|<6H=wfEa3r!9*pzOjpS|X&NFl{8 zkwj8qpPoD-W4=sz{FgE3G0HsP2*eSI0(?q?zn7qjN%*{R8tVF~tr^56sYRJMG6$;; z9A7TZI#2VTdk6X2Z#uRB9|JTNBaT2m20RR4TGCsb5)oyqJ-b#iKJF!hmx1@qek*nd z8Cy8$F*m7S{~|#x@aG!rCWC0q!?Ba~Y~QhtmSam89V-Ei^p$3&dl}ex&L$HvFS}cs zGvpx-i_-q}rLNBdA6?Y)aM+Sr#yZ(mD}G-WD}w_;-h6#craaK#x4^ZIJe&lw5GLQ> z4}1Z58v=7GX>91FCOm|MmfuujA0dtX$Cjrj&C^@8t6%pi86u(bxJmzjl1|1g8^@M7{|869y%|7@JldFA9l_j+W5U zvP7hgNqiIdp9^`ll_L;GBrA*_!CwG%OhajKoT`dp{WC()A1zqoP&G-+c(nD@kV?s9 z(moh}bZLd>&eL{nypygU1#ZQ_tt8phd_pwW7otQ|Ri?GAn)dc;CNTzlR2Ro%6cLU< zoQC`Lz{kWc!7~V4aixS%N&^wf^v__4=|HTUqG=LCV*v(+OX=4yJ$*2Vm~r;OBb@Fy zzlWa(uFOo*ORD?DnIW>QE(nPv5(*uiRdjV%n*I?4>;gWd%cF%N#u11!>3$t>18^na zW(H(Q!|#pZ_r*l%!0#2Gq86>oCTm$t#5}~}9`QL6DG}mOH3>7MfFA?12l!wOh zE)i9e>FY10r?-OPkpN~;fqw?RwAfc!IRbHH;sVYBE;FvT1J%qQCx9n`U+CiaBQxXR zNMt4OAn=Z9{$V4^u%W;Np^|a2XPhi)cBLVfl@AREgfIq&LsONh&>$tj&kb=L<}}3- zh$EGYfF@u)u+I2g3%IdQ7w{JFTi_X88VAT82S+5Efxpt=dI>ztKqxSd-y1hdvT;iM zQABd~m`)WGVu&XdF*P2Gc^DiCGB^|xL#;Cq1HKJ>O&3Q$nK(ECae!_5yom&717$#^ zafOY~T0jHhKmv#xR}|fL zE{-vZ7Dpfs4i1h?{tUPn{nFs=5|ooeG>A#C4R{%Ndhs4L>j=cb!NC#AYTz0pnXECc q)qsoH5d&T~gz-DzwZcx1JN!Sy^@52rc?8@50000 line + var condition = node.text[0] + , block = node.block; + node = new nodes.Code('if (' + condition + ')'); + node.block = block; + this.visit(node); + break; + case 'else': + var block = node.block; + node = new nodes.Code('else'); + node.block = block; + node.instrumentLineNumber = false; + this.visit(node); + break; + default: + Compiler.prototype.visitTag.call(this, node); + } +}; + +module.exports = { + 'test :cdata filter': function(assert){ + assert.equal('', render(':cdata\n foo')); + assert.equal('', render(':cdata\n foo\n bar')); + assert.equal('

something else

', render(':cdata\n foo\n bar\np something else')); + }, + + 'test :markdown filter': function(assert){ + assert.equal( + '

foo

\n\n
  • bar
  • baz
', + render(':markdown\n #foo\n - bar\n - baz\n')) + }, + + 'test :stylus filter': function(assert){ + assert.equal( + '', + render(':stylus\n body\n color #c00')); + }, + + 'test :stylus filter with options': function(assert){ + assert.equal( + '', + render(':stylus(compress=true)\n body\n color #c00')); + }, + + 'test :less filter': function(assert){ + assert.equal( + '', + render(':less\n .class { width: 10px * 2 }\n')); + }, + + 'test :coffeescript filter': function(assert){ + var coffee, js; + coffee = [ + ':coffeescript', + ' square = (x) ->', + ' x * x' + ].join('\n'); + js = [ + '' + ].join('\n'); + + assert.equal(js, render(coffee)); + + coffee = [ + ':coffeescript', + ' $ ->', + ' $("#flash").fadeIn ->', + ' console.log("first line")', + ' console.log("second line")' + ].join('\n'); + js = [ + '' + ].join('\n'); + + assert.equal(js, render(coffee)); + }, + + 'test parse tree': function(assert){ + var str = [ + 'conditionals:', + ' if false', + ' | oh noes', + ' else', + ' if null == false', + ' p doh', + ' else', + ' p amazing!' + ].join('\n'); + + var html = [ + '

amazing!

' + ].join(''); + + assert.equal(html, render(str)); + }, + + 'test filter attrs': function(assert){ + jade.filters.testing = function(str, attrs){ + return str + ' ' + attrs.stuff; + }; + + var str = [ + ':testing(stuff)', + ' foo bar', + ].join('\n'); + + assert.equal('foo bar true', render(str)); + } +}; \ No newline at end of file diff --git a/node_modules/jade/test/fixtures/invalid.jade b/node_modules/jade/test/fixtures/invalid.jade new file mode 100644 index 0000000..d498bbb --- /dev/null +++ b/node_modules/jade/test/fixtures/invalid.jade @@ -0,0 +1,3 @@ +ul + li= foo + li bar \ No newline at end of file diff --git a/node_modules/jade/test/fixtures/layout.jade b/node_modules/jade/test/fixtures/layout.jade new file mode 100644 index 0000000..a81624a --- /dev/null +++ b/node_modules/jade/test/fixtures/layout.jade @@ -0,0 +1,3 @@ +html + body + h1 Jade \ No newline at end of file diff --git a/node_modules/jade/test/jade.test.js b/node_modules/jade/test/jade.test.js new file mode 100644 index 0000000..bfb375e --- /dev/null +++ b/node_modules/jade/test/jade.test.js @@ -0,0 +1,879 @@ + +/** + * Module dependencies. + */ + +var jade = require('../') + , ENOENT; + +// COMPAT: + +try { + ENOENT = require('constants').ENOENT; +} catch (err) { + ENOENT = process.ENOENT; +} + +// Shortcut + +var render = jade.render; + +module.exports = { + 'test .version': function(assert){ + assert.ok(/^\d+\.\d+\.\d+$/.test(jade.version), "Invalid version format"); + }, + + 'test exports': function(assert){ + assert.equal('object', typeof jade.selfClosing, 'exports.selfClosing missing'); + assert.equal('object', typeof jade.doctypes, 'exports.doctypes missing'); + assert.equal('object', typeof jade.filters, 'exports.filters missing'); + assert.equal('object', typeof jade.utils, 'exports.utils missing'); + assert.equal('function', typeof jade.Compiler, 'exports.Compiler missing'); + }, + + 'test doctypes': function(assert){ + assert.equal('', render('!!! xml')); + assert.equal('', render('doctype html')); + assert.equal('', render('doctype HTML')); + assert.equal('', render('!!! 5')); + assert.equal('', render('!!!', { doctype:'html' })); + assert.equal('', render('!!! html', { doctype:'xml' })); + assert.equal('', render('html')); + assert.equal('', render('html', { doctype:'html' })); + }, + + 'test Buffers': function(assert){ + assert.equal('

foo

', render(new Buffer('p foo'))); + }, + + 'test line endings': function(assert){ + var str = [ + 'p', + 'div', + 'img' + ].join('\r\n'); + + var html = [ + '

', + '
', + '' + ].join(''); + + assert.equal(html, render(str)); + + var str = [ + 'p', + 'div', + 'img' + ].join('\r'); + + var html = [ + '

', + '
', + '' + ].join(''); + + assert.equal(html, render(str)); + + var str = [ + 'p', + 'div', + 'img' + ].join('\r\n'); + + var html = [ + '

', + '
', + '' + ].join(''); + + assert.equal(html, render(str, { doctype:'html' })); + }, + + 'test single quotes': function(assert){ + assert.equal("

'foo'

", render("p 'foo'")); + assert.equal("

'foo'\n

", render("p\n | 'foo'")); + assert.equal('
', render("- var path = 'foo';\na(href='/' + path)")); + }, + + 'test block-expansion': function(assert){ + assert.equal("
  • foo
  • bar
  • baz
  • ", render("li: a foo\nli: a bar\nli: a baz")); + assert.equal("
  • foo
  • bar
  • baz
  • ", render("li.first: a foo\nli: a bar\nli: a baz")); + }, + + 'test tags': function(assert){ + var str = [ + 'p', + 'div', + 'img' + ].join('\n'); + + var html = [ + '

    ', + '
    ', + '' + ].join(''); + + assert.equal(html, render(str), 'Test basic tags'); + assert.equal('', render('fb:foo-bar'), 'Test hyphens'); + assert.equal('
    ', render('div.something'), 'Test classes'); + assert.equal('
    ', render('div#something'), 'Test ids'); + assert.equal('
    ', render('.something'), 'Test stand-alone classes'); + assert.equal('
    ', render('#something'), 'Test stand-alone ids'); + assert.equal('
    ', render('#foo.bar')); + assert.equal('
    ', render('.bar#foo')); + assert.equal('
    ', render('div#foo(class="bar")')); + assert.equal('
    ', render('div(class="bar")#foo')); + assert.equal('
    ', render('div(id="bar").foo')); + assert.equal('
    ', render('div.foo.bar.baz')); + assert.equal('
    ', render('div(class="foo").bar.baz')); + assert.equal('
    ', render('div.foo(class="bar").baz')); + assert.equal('
    ', render('div.foo.bar(class="baz")')); + assert.equal('
    ', render('div.a-b2')); + assert.equal('
    ', render('div.a_b2')); + assert.equal('', render('fb:user')); + assert.equal('', render('fb:user:role')); + assert.equal('', render('colgroup\n col.test')); + }, + + 'test nested tags': function(assert){ + var str = [ + 'ul', + ' li a', + ' li b', + ' li', + ' ul', + ' li c', + ' li d', + ' li e', + ].join('\n'); + + var html = [ + '
      ', + '
    • a
    • ', + '
    • b
    • ', + '
      • c
      • d
    • ', + '
    • e
    • ', + '
    ' + ].join(''); + + assert.equal(html, render(str)); + + var str = [ + 'a(href="#")', + ' | foo ', + ' | bar ', + ' | baz' + ].join('\n'); + + assert.equal('foo \nbar \nbaz\n', render(str)); + + var str = [ + 'ul', + ' li one', + ' ul', + ' | two', + ' li three' + ].join('\n'); + + var html = [ + '
      ', + '
    • one
    • ', + '
        two\n', + '
      • three
      • ', + '
      ', + '
    ' + ].join(''); + + assert.equal(html, render(str)); + }, + + 'test variable length newlines': function(assert){ + var str = [ + 'ul', + ' li a', + ' ', + ' li b', + ' ', + ' ', + ' li', + ' ul', + ' li c', + '', + ' li d', + ' li e', + ].join('\n'); + + var html = [ + '
      ', + '
    • a
    • ', + '
    • b
    • ', + '
      • c
      • d
    • ', + '
    • e
    • ', + '
    ' + ].join(''); + + assert.equal(html, render(str)); + }, + + 'test tab conversion': function(assert){ + var str = [ + 'ul', + '\tli a', + '\t', + '\tli b', + '\t\t', + '\t\t\t\t\t\t', + '\tli', + '\t\tul', + '\t\t\tli c', + '', + '\t\t\tli d', + '\tli e', + ].join('\n'); + + var html = [ + '
      ', + '
    • a
    • ', + '
    • b
    • ', + '
      • c
      • d
    • ', + '
    • e
    • ', + '
    ' + ].join(''); + + assert.equal(html, render(str)); + }, + + 'test newlines': function(assert){ + var str = [ + 'ul', + ' li a', + ' ', + ' ', + '', + ' ', + ' li b', + ' li', + ' ', + ' ', + ' ', + ' ul', + ' ', + ' li c', + ' li d', + ' li e', + ].join('\n'); + + var html = [ + '
      ', + '
    • a
    • ', + '
    • b
    • ', + '
      • c
      • d
    • ', + '
    • e
    • ', + '
    ' + ].join(''); + + assert.equal(html, render(str)); + + var str = [ + 'html', + ' ', + ' head', + ' != "test"', + ' ', + ' ', + ' ', + ' body' + ].join('\n'); + + var html = [ + '', + '', + 'test', + '', + '', + '' + ].join(''); + + assert.equal(html, render(str)); + assert.equal('something', render('foo\n= "something"\nbar')); + assert.equal('somethingelse', render('foo\n= "something"\nbar\n= "else"')); + }, + + 'test cache': function(assert){ + var err; + try { + render('foo', { cache: true }); + } catch (e) { + err = e; + } + assert.equal('filename is required when using the cache option', err.message); + + assert.equal('

    ', render('p', { cache: true, filename: 'foo.jade' })); + assert.equal('

    ', render('p', { cache: true, filename: 'foo.jade' })); + assert.ok(typeof jade.cache['foo.jade'] === 'function', 'Test cache'); + }, + + 'test text': function(assert){ + assert.equal('foo\nbar\nbaz\n', render('| foo\n| bar\n| baz')); + assert.equal('foo \nbar \nbaz\n', render('| foo \n| bar \n| baz')); + assert.equal('(hey)\n', render('| (hey)')); + assert.equal('some random text\n', render('| some random text')); + assert.equal(' foo\n', render('| foo')); + assert.equal(' foo \n', render('| foo ')); + assert.equal(' foo \n bar \n', render('| foo \n| bar ')); + }, + + 'test pipe-less text': function(assert){ + assert.equal('
    foo\n\nbar\n
    ', render('pre\n code\n foo\n\n bar')); + assert.equal('

    foo\n\nbar\n

    ', render('p.\n foo\n\n bar')); + assert.equal('

    foo\n\n\n\nbar\n

    ', render('p.\n foo\n\n\n\n bar')); + assert.equal('

    foo\n bar\nfoo\n

    ', render('p.\n foo\n bar\n foo')); + assert.equal('', render('script\n s.parentNode.insertBefore(g,s)\n')); + assert.equal('', render('script\n s.parentNode.insertBefore(g,s)')); + }, + + 'test tag text': function(assert){ + assert.equal('

    some random text

    ', render('p some random text')); + assert.equal('

    click\nGoogle.\n

    ', render('p\n | click\n a Google\n | .')); + assert.equal('

    (parens)

    ', render('p (parens)')); + assert.equal('

    (parens)

    ', render('p(foo="bar") (parens)')); + assert.equal('', render('option(value="") -- (optional) foo --')); + }, + + 'test tag text block': function(assert){ + assert.equal('

    foo \nbar \nbaz\n

    ', render('p\n | foo \n | bar \n | baz')); + assert.equal('', render('label\n | Password:\n input')); + assert.equal('', render('label Password:\n input')); + }, + + 'test tag text interpolation': function(assert){ + assert.equal('yo, jade is cool\n', render('| yo, #{name} is cool\n', { locals: { name: 'jade' }})); + assert.equal('

    yo, jade is cool

    ', render('p yo, #{name} is cool', { locals: { name: 'jade' }})); + assert.equal('yo, jade is cool\n', render('| yo, #{name || "jade"} is cool', { locals: { name: null }})); + assert.equal('yo, \'jade\' is cool\n', render('| yo, #{name || "\'jade\'"} is cool', { locals: { name: null }})); + assert.equal('foo <script> bar\n', render('| foo #{code} bar', { locals: { code: ' + + + + +

    b ? 1 : 0; + }; + callback(null, _map(results.sort(fn), function (x) { + return x.value; + })); + } + }); + }; + + async.auto = function (tasks, callback) { + callback = callback || function () {}; + var keys = _keys(tasks); + if (!keys.length) { + return callback(null); + } + + var completed = []; + + var listeners = []; + var addListener = function (fn) { + listeners.unshift(fn); + }; + var removeListener = function (fn) { + for (var i = 0; i < listeners.length; i += 1) { + if (listeners[i] === fn) { + listeners.splice(i, 1); + return; + } + } + }; + var taskComplete = function () { + _forEach(listeners, function (fn) { + fn(); + }); + }; + + addListener(function () { + if (completed.length === keys.length) { + callback(null); + } + }); + + _forEach(keys, function (k) { + var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; + var taskCallback = function (err) { + if (err) { + callback(err); + // stop subsequent errors hitting callback multiple times + callback = function () {}; + } + else { + completed.push(k); + taskComplete(); + } + }; + var requires = task.slice(0, Math.abs(task.length - 1)) || []; + var ready = function () { + return _reduce(requires, function (a, x) { + return (a && _indexOf(completed, x) !== -1); + }, true); + }; + if (ready()) { + task[task.length - 1](taskCallback); + } + else { + var listener = function () { + if (ready()) { + removeListener(listener); + task[task.length - 1](taskCallback); + } + }; + addListener(listener); + } + }); + }; + + async.waterfall = function (tasks, callback) { + if (!tasks.length) { + return callback(); + } + callback = callback || function () {}; + var wrapIterator = function (iterator) { + return function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } + else { + args.push(callback); + } + async.nextTick(function () { + iterator.apply(null, args); + }); + } + }; + }; + wrapIterator(async.iterator(tasks))(); + }; + + async.parallel = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.map(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args || null); + }); + } + }, callback); + } + else { + var results = {}; + async.forEach(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.series = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.mapSeries(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args || null); + }); + } + }, callback); + } + else { + var results = {}; + async.forEachSeries(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.iterator = function (tasks) { + var makeCallback = function (index) { + var fn = function () { + if (tasks.length) { + tasks[index].apply(null, arguments); + } + return fn.next(); + }; + fn.next = function () { + return (index < tasks.length - 1) ? makeCallback(index + 1): null; + }; + return fn; + }; + return makeCallback(0); + }; + + async.apply = function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + return function () { + return fn.apply( + null, args.concat(Array.prototype.slice.call(arguments)) + ); + }; + }; + + var _concat = function (eachfn, arr, fn, callback) { + var r = []; + eachfn(arr, function (x, cb) { + fn(x, function (err, y) { + r = r.concat(y || []); + cb(err); + }); + }, function (err) { + callback(err, r); + }); + }; + async.concat = doParallel(_concat); + async.concatSeries = doSeries(_concat); + + async.whilst = function (test, iterator, callback) { + if (test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.whilst(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.until = function (test, iterator, callback) { + if (!test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.until(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.queue = function (worker, concurrency) { + var workers = 0; + var tasks = []; + var q = { + concurrency: concurrency, + push: function (data, callback) { + tasks.push({data: data, callback: callback}); + async.nextTick(q.process); + }, + process: function () { + if (workers < q.concurrency && tasks.length) { + var task = tasks.splice(0, 1)[0]; + workers += 1; + worker(task.data, function () { + workers -= 1; + if (task.callback) { + task.callback.apply(task, arguments); + } + q.process(); + }); + } + }, + length: function () { + return tasks.length; + } + }; + return q; + }; + + var _console_fn = function (name) { + return function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + fn.apply(null, args.concat([function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (typeof console !== 'undefined') { + if (err) { + if (console.error) { + console.error(err); + } + } + else if (console[name]) { + _forEach(args, function (x) { + console[name](x); + }); + } + } + }])); + }; + }; + async.log = _console_fn('log'); + async.dir = _console_fn('dir'); + /*async.info = _console_fn('info'); + async.warn = _console_fn('warn'); + async.error = _console_fn('error');*/ + + async.memoize = function (fn, hasher) { + var memo = {}; + hasher = hasher || function (x) { + return x; + }; + return function () { + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + var key = hasher.apply(null, args); + if (key in memo) { + callback.apply(null, memo[key]); + } + else { + fn.apply(null, args.concat([function () { + memo[key] = arguments; + callback.apply(null, arguments); + }])); + } + }; + }; + +}()); diff --git a/node_modules/mongodb/deps/nodeunit/deps/ejs.js b/node_modules/mongodb/deps/nodeunit/deps/ejs.js new file mode 100644 index 0000000..f6abf29 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/deps/ejs.js @@ -0,0 +1,125 @@ + +/*! + * EJS + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var sys = require('sys'); + +/** + * Library version. + */ + +exports.version = '0.0.3'; + +/** + * Intermediate js cache. + * + * @type Object + */ + +var cache = {}; + +/** + * Clear intermediate js cache. + * + * @api public + */ + +exports.clearCache = function(){ + cache = {}; +}; + +/** + * Escape the given string of `html`. + * + * @param {String} html + * @return {String} + * @api private + */ + +function escape(html){ + return String(html) + .replace(/&(?!\w+;)/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +} + +/** + * Parse the given `str` of ejs, returning the function body. + * + * @param {String} str + * @return {String} + * @api public + */ + +var parse = exports.parse = function(str){ + return 'var buf = [];\n' + + "with (locals) {\nbuf.push('" + + String(str) + .replace(/[\r\t]/g, " ") + .replace(/\n/g, "\\n") + .split("<%").join("\t") + .replace(/((^|%>)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "', escape($1) ,'") + .replace(/\t-(.*?)%>/g, "', $1 ,'") + .split("\t").join("');") + .split("%>").join("buf.push('") + .split("\r").join("\\'") + + "');\n}\nreturn buf.join('');"; +}; + +/** + * Compile the given `str` of ejs into a `Function`. + * + * @param {String} str + * @param {Object} options + * @return {Function} + * @api public + */ + +var compile = exports.compile = function(str, options){ + if (options.debug) sys.puts(parse(str)); + return new Function('locals, escape', parse(str)); +}; + +/** + * Render the given `str` of ejs. + * + * Options: + * + * - `locals` Local variables object + * - `cache` Compiled functions are cached, requires `filename` + * - `filename` Used by `cache` to key caches + * - `context|scope` Function execution context + * - `debug` Output generated function body + * + * @param {String} str + * @param {Object} options + * @return {String} + * @api public + */ + +exports.render = function(str, options){ + var fn, + options = options || {}; + if (options.cache) { + if (options.filename) { + fn = cache[options.filename] = compile(str, options); + } else { + throw new Error('"cache" option requires "filename".'); + } + } else { + fn = compile(str, options); + } + return fn.call( + options.context || options.scope, + options.locals || {}, + escape); +}; \ No newline at end of file diff --git a/node_modules/mongodb/deps/nodeunit/deps/json2.js b/node_modules/mongodb/deps/nodeunit/deps/json2.js new file mode 100644 index 0000000..22b44d9 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/deps/json2.js @@ -0,0 +1,483 @@ +/* + http://www.JSON.org/json2.js + 2010-11-17 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. +*/ + +/*jslint evil: true, strict: false, regexp: false */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ + + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +if (!this.JSON) { + this.JSON = {}; +} + +(function () { + "use strict"; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) ? + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? + '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/ +.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') +.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') +.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}()); diff --git a/node_modules/mongodb/deps/nodeunit/doc/nodeunit.md b/node_modules/mongodb/deps/nodeunit/doc/nodeunit.md new file mode 100644 index 0000000..efde75c --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/doc/nodeunit.md @@ -0,0 +1,60 @@ +nodeunit(1) -- simple node.js unit testing tool +=============================================== + +## SYNOPSIS + + nodeunit [options] [ ...] + +## DESCRIPTION + +Nodeunit is a simple unit testing tool based on the node.js assert module. + +* Simple to use +* Just export the tests from a module +* Helps you avoid common pitfalls when testing asynchronous code +* Easy to add test cases with setUp and tearDown functions if you wish +* Allows the use of mocks and stubs + +## OPTIONS + + __--config FILE__: + Load config options from a JSON file, allows the customisation + of color schemes for the default test reporter etc. + See bin/nodeunit.json for current available options. + + __--reporter FILE__: + You can set the test reporter to a custom module or on of the modules + in nodeunit/lib/reporters, when omitted, the default test runner is used. + + __--list-reporters__: + List available build-in reporters. + + __-h__, __--help__: + Display the help and exit. + + __-v__, __--version__: + Output version information and exit. + + ____: + You can run nodeunit on specific files or on all *\*.js* files inside + a directory. + +## AUTHORS + +Written by Caolan McMahon and other nodeunit contributors. +Contributors list: . + +## REPORTING BUGS + +Report nodeunit bugs to . + +## COPYRIGHT + +Copyright © 2010 Caolan McMahon. +Nodeunit has been released under the MIT license: +. + +## SEE ALSO + +node(1) + diff --git a/node_modules/mongodb/deps/nodeunit/examples/browser/nodeunit.js b/node_modules/mongodb/deps/nodeunit/examples/browser/nodeunit.js new file mode 100644 index 0000000..8c12b0f --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/examples/browser/nodeunit.js @@ -0,0 +1,1757 @@ +/*! + * Nodeunit + * https://github.com/caolan/nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + * + * json2.js + * http://www.JSON.org/json2.js + * Public Domain. + * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + */ +nodeunit = (function(){ +/* + http://www.JSON.org/json2.js + 2010-11-17 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. +*/ + +/*jslint evil: true, strict: false, regexp: false */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ + + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +if (!this.JSON) { + this.JSON = {}; +} + +(function () { + "use strict"; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) ? + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? + '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/ +.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') +.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') +.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}()); +var assert = {}; +var types = {}; +var core = {}; +var nodeunit = {}; +var reporter = {}; +(function(){ + + var async = {}; + + // global on the server, window in the browser + var root = this; + var previous_async = root.async; + + if(typeof module !== 'undefined' && module.exports) module.exports = async; + else root.async = async; + + async.noConflict = function(){ + root.async = previous_async; + return async; + }; + + //// cross-browser compatiblity functions //// + + var _forEach = function(arr, iterator){ + if(arr.forEach) return arr.forEach(iterator); + for(var i=0; i b ? 1 : 0; + }), function(x){return x.value;})); + }) + }; + + async.auto = function(tasks, callback){ + callback = callback || function(){}; + var keys = _keys(tasks); + if(!keys.length) return callback(null); + + var completed = []; + + var listeners = []; + var addListener = function(fn){ + listeners.unshift(fn); + }; + var removeListener = function(fn){ + for(var i=0; i +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the 'Software'), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +var pSlice = Array.prototype.slice; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = exports; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({message: message, actual: actual, expected: expected}) + +assert.AssertionError = function AssertionError (options) { + this.name = "AssertionError"; + this.message = options.message; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + var stackStartFunction = options.stackStartFunction || fail; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } +}; +// code from util.inherits in node +assert.AssertionError.super_ = Error; + + +// EDITED FOR BROWSER COMPATIBILITY: replaced Object.create call +// TODO: test what effect this may have +var ctor = function () { this.constructor = assert.AssertionError; }; +ctor.prototype = Error.prototype; +assert.AssertionError.prototype = new ctor(); + + +assert.AssertionError.prototype.toString = function() { + if (this.message) { + return [this.name+":", this.message].join(' '); + } else { + return [ this.name+":" + , JSON.stringify(this.expected ) + , this.operator + , JSON.stringify(this.actual) + ].join(" "); + } +}; + +// assert.AssertionError instanceof Error + +assert.AssertionError.__proto__ = Error.prototype; + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +assert.ok = function ok(value, message) { + if (!!!value) fail(value, true, message, "==", assert.ok); +}; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, "==", assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, "!=", assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, "deepEqual", assert.deepEqual); + } +}; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + + return true; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (actual instanceof Date && expected instanceof Date) { + return actual.getTime() === expected.getTime(); + + // 7.3. Other pairs that do not both pass typeof value == "object", + // equivalence is determined by ==. + } else if (typeof actual != 'object' && typeof expected != 'object') { + return actual == expected; + + // 7.4. For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical "prototype" property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isUndefinedOrNull (value) { + return value === null || value === undefined; +} + +function isArguments (object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv (a, b) { + if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) + return false; + // an identical "prototype" property. + if (a.prototype !== b.prototype) return false; + //~~~I've managed to break Object.keys through screwy arguments passing. + // Converting to array solves the problem. + if (isArguments(a)) { + if (!isArguments(b)) { + return false; + } + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + try{ + var ka = _keys(a), + kb = _keys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + // having the same number of owned properties (keys incorporates hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key] )) + return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, "===", assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as determined by !==. +// assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, "!==", assert.notStrictEqual); + } +}; + +function _throws (shouldThrow, block, err, message) { + var exception = null, + threw = false, + typematters = true; + + message = message || ""; + + //handle optional arguments + if (arguments.length == 3) { + if (typeof(err) == "string") { + message = err; + typematters = false; + } + } else if (arguments.length == 2) { + typematters = false; + } + + try { + block(); + } catch (e) { + threw = true; + exception = e; + } + + if (shouldThrow && !threw) { + fail( "Missing expected exception" + + (err && err.name ? " ("+err.name+")." : '.') + + (message ? " " + message : "") + ); + } + if (!shouldThrow && threw && typematters && exception instanceof err) { + fail( "Got unwanted exception" + + (err && err.name ? " ("+err.name+")." : '.') + + (message ? " " + message : "") + ); + } + if ((shouldThrow && threw && typematters && !(exception instanceof err)) || + (!shouldThrow && threw)) { + throw exception; + } +}; + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function (err) { if (err) {throw err;}}; +})(assert); +(function(exports){ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + * + * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +/** + * Module dependencies + */ + + + +/** + * Creates assertion objects representing the result of an assert call. + * Accepts an object or AssertionError as its argument. + * + * @param {object} obj + * @api public + */ + +exports.assertion = function (obj) { + return { + method: obj.method || '', + message: obj.message || (obj.error && obj.error.message) || '', + error: obj.error, + passed: function () { + return !this.error; + }, + failed: function () { + return Boolean(this.error); + } + }; +}; + +/** + * Creates an assertion list object representing a group of assertions. + * Accepts an array of assertion objects. + * + * @param {Array} arr + * @param {Number} duration + * @api public + */ + +exports.assertionList = function (arr, duration) { + var that = arr || []; + that.failures = function () { + var failures = 0; + for (var i=0; i'; +}; + + +/** + * Run all tests within each module, reporting the results + * + * @param {Array} files + * @api public + */ + +exports.run = function (modules, options) { + var start = new Date().getTime(); + exports.addStyles(); + + var html = ''; + nodeunit.runModules(modules, { + moduleStart: function (name) { + html += '

    ' + name + '

    '; + html += '
      '; + }, + testDone: function (name, assertions) { + if (!assertions.failures()) { + html += '
    1. ' + name + '
    2. '; + } + else { + html += '
    3. ' + name; + for (var i=0; i'; + } + html += '
      ';
      +                        html += a.error.stack || a.error;
      +                        html += '
      '; + } + }; + html += '
    4. '; + } + }, + moduleDone: function () { + html += '
    '; + }, + done: function (assertions) { + var end = new Date().getTime(); + var duration = end - start; + if (assertions.failures()) { + html += '

    FAILURES: ' + assertions.failures() + + '/' + assertions.length + ' assertions failed (' + + assertions.duration + 'ms)

    '; + } + else { + html += '

    OK: ' + assertions.length + + ' assertions (' + assertions.duration + 'ms)

    '; + } + document.body.innerHTML += html; + } + }); +}; +})(reporter); +nodeunit = core; +nodeunit.assert = assert; +nodeunit.reporter = reporter; +nodeunit.run = reporter.run; +return nodeunit; })(); diff --git a/node_modules/mongodb/deps/nodeunit/examples/browser/suite1.js b/node_modules/mongodb/deps/nodeunit/examples/browser/suite1.js new file mode 100644 index 0000000..0d5fc90 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/examples/browser/suite1.js @@ -0,0 +1,12 @@ +this.suite1 = { + 'test one': function (test) { + test.ok(true, 'everythings ok'); + setTimeout(function () { + test.done(); + }, 10); + }, + 'apples and oranges': function (test) { + test.equal('apples', 'oranges', 'comparing apples and oranges'); + test.done(); + } +}; diff --git a/node_modules/mongodb/deps/nodeunit/examples/browser/suite2.js b/node_modules/mongodb/deps/nodeunit/examples/browser/suite2.js new file mode 100644 index 0000000..c7288e8 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/examples/browser/suite2.js @@ -0,0 +1,13 @@ +this.suite2 = { + 'another test': function (test) { + setTimeout(function () { + // lots of assertions + test.ok(true, 'everythings ok'); + test.ok(true, 'everythings ok'); + test.ok(true, 'everythings ok'); + test.ok(true, 'everythings ok'); + test.ok(true, 'everythings ok'); + test.done(); + }, 10); + } +}; diff --git a/node_modules/mongodb/deps/nodeunit/examples/browser/test.html b/node_modules/mongodb/deps/nodeunit/examples/browser/test.html new file mode 100644 index 0000000..e9f8180 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/examples/browser/test.html @@ -0,0 +1,16 @@ + + + Example tests + + + + + + + + diff --git a/node_modules/mongodb/deps/nodeunit/img/example_fail.png b/node_modules/mongodb/deps/nodeunit/img/example_fail.png new file mode 100644 index 0000000000000000000000000000000000000000..78ff4258cd574420da27fcf38b4711d02db58a92 GIT binary patch literal 38642 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 literal 0 HcmV?d00001 diff --git a/node_modules/mongodb/deps/nodeunit/img/example_pass.png b/node_modules/mongodb/deps/nodeunit/img/example_pass.png new file mode 100644 index 0000000000000000000000000000000000000000..069d71698cd7cf33e3269ad0f17066774eb4bb7b GIT binary patch literal 14133 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 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the 'Software'), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +var pSlice = Array.prototype.slice; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = exports; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({message: message, actual: actual, expected: expected}) + +assert.AssertionError = function AssertionError (options) { + this.name = "AssertionError"; + this.message = options.message; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + var stackStartFunction = options.stackStartFunction || fail; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } +}; +// code from util.inherits in node +assert.AssertionError.super_ = Error; + + +// EDITED FOR BROWSER COMPATIBILITY: replaced Object.create call +// TODO: test what effect this may have +var ctor = function () { this.constructor = assert.AssertionError; }; +ctor.prototype = Error.prototype; +assert.AssertionError.prototype = new ctor(); + + +assert.AssertionError.prototype.toString = function() { + if (this.message) { + return [this.name+":", this.message].join(' '); + } else { + return [ this.name+":" + , JSON.stringify(this.expected ) + , this.operator + , JSON.stringify(this.actual) + ].join(" "); + } +}; + +// assert.AssertionError instanceof Error + +assert.AssertionError.__proto__ = Error.prototype; + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +assert.ok = function ok(value, message) { + if (!!!value) fail(value, true, message, "==", assert.ok); +}; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, "==", assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, "!=", assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, "deepEqual", assert.deepEqual); + } +}; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (actual instanceof Date && expected instanceof Date) { + return actual.getTime() === expected.getTime(); + + // 7.3. Other pairs that do not both pass typeof value == "object", + // equivalence is determined by ==. + } else if (typeof actual != 'object' && typeof expected != 'object') { + return actual == expected; + + // 7.4. For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical "prototype" property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isUndefinedOrNull (value) { + return value === null || value === undefined; +} + +function isArguments (object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv (a, b) { + if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) + return false; + // an identical "prototype" property. + if (a.prototype !== b.prototype) return false; + //~~~I've managed to break Object.keys through screwy arguments passing. + // Converting to array solves the problem. + if (isArguments(a)) { + if (!isArguments(b)) { + return false; + } + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + try{ + var ka = _keys(a), + kb = _keys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + // having the same number of owned properties (keys incorporates hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key] )) + return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, "===", assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as determined by !==. +// assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, "!==", assert.notStrictEqual); + } +}; + +function _throws (shouldThrow, block, err, message) { + var exception = null, + threw = false, + typematters = true; + + message = message || ""; + + //handle optional arguments + if (arguments.length == 3) { + if (typeof(err) == "string") { + message = err; + typematters = false; + } + } else if (arguments.length == 2) { + typematters = false; + } + + try { + block(); + } catch (e) { + threw = true; + exception = e; + } + + if (shouldThrow && !threw) { + fail( "Missing expected exception" + + (err && err.name ? " ("+err.name+")." : '.') + + (message ? " " + message : "") + ); + } + if (!shouldThrow && threw && typematters && exception instanceof err) { + fail( "Got unwanted exception" + + (err && err.name ? " ("+err.name+")." : '.') + + (message ? " " + message : "") + ); + } + if ((shouldThrow && threw && typematters && !(exception instanceof err)) || + (!shouldThrow && threw)) { + throw exception; + } +}; + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function (err) { if (err) {throw err;}}; diff --git a/node_modules/mongodb/deps/nodeunit/lib/core.js b/node_modules/mongodb/deps/nodeunit/lib/core.js new file mode 100644 index 0000000..981d7c6 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/lib/core.js @@ -0,0 +1,236 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + * + * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +/** + * Module dependencies + */ + +var async = require('../deps/async'), //@REMOVE_LINE_FOR_BROWSER + types = require('./types'); //@REMOVE_LINE_FOR_BROWSER + + +/** + * Added for browser compatibility + */ + +var _keys = function(obj){ + if(Object.keys) return Object.keys(obj); + var keys = []; + for(var k in obj){ + if(obj.hasOwnProperty(k)) keys.push(k); + } + return keys; +}; + + +/** + * Runs a test function (fn) from a loaded module. After the test function + * calls test.done(), the callback is executed with an assertionList as its + * second argument. + * + * @param {String} name + * @param {Function} fn + * @param {Object} opt + * @param {Function} callback + * @api public + */ + +exports.runTest = function (name, fn, opt, callback) { + var options = types.options(opt); + + options.testStart(name); + var start = new Date().getTime(); + var test = types.test(name, start, options, callback); + + try { + fn(test); + } + catch (e) { + test.done(e); + } +}; + +/** + * Takes an object containing test functions or other test suites as properties + * and runs each in series. After all tests have completed, the callback is + * called with a list of all assertions as the second argument. + * + * If a name is passed to this function it is prepended to all test and suite + * names that run within it. + * + * @param {String} name + * @param {Object} suite + * @param {Object} opt + * @param {Function} callback + * @api public + */ + +exports.runSuite = function (name, suite, opt, callback) { + var keys = _keys(suite); + + async.concatSeries(keys, function (k, cb) { + var prop = suite[k], _name; + + _name = name ? [].concat(name, k) : [k]; + + _name.toString = function () { + // fallback for old one + return this.join(' - '); + }; + + if (typeof prop === 'function') { + exports.runTest(_name, suite[k], opt, cb); + } + else { + exports.runSuite(_name, suite[k], opt, cb); + } + }, callback); +}; + +/** + * Run each exported test function or test suite from a loaded module. + * + * @param {String} name + * @param {Object} mod + * @param {Object} opt + * @param {Function} callback + * @api public + */ + +exports.runModule = function (name, mod, opt, callback) { + var options = types.options(opt); + + options.moduleStart(name); + var start = new Date().getTime(); + + exports.runSuite(null, mod, opt, function (err, a_list) { + var end = new Date().getTime(); + var assertion_list = types.assertionList(a_list, end - start); + options.moduleDone(name, assertion_list); + callback(null, a_list); + }); +}; + +/** + * Treats an object literal as a list of modules keyed by name. Runs each + * module and finished with calling 'done'. You can think of this as a browser + * safe alternative to runFiles in the nodeunit module. + * + * @param {Object} modules + * @param {Object} opt + * @api public + */ + +// TODO: add proper unit tests for this function +exports.runModules = function (modules, opt) { + var all_assertions = []; + var options = types.options(opt); + var start = new Date().getTime(); + + async.concatSeries(_keys(modules), function (k, cb) { + exports.runModule(k, modules[k], options, cb); + }, + function (err, all_assertions) { + var end = new Date().getTime(); + options.done(types.assertionList(all_assertions, end - start)); + }); +}; + + +/** + * Wraps a test function with setUp and tearDown functions. + * Used by testCase. + * + * @param {Function} setUp + * @param {Function} tearDown + * @param {Function} fn + * @api private + */ + +var wrapTest = function (setUp, tearDown, fn) { + return function (test) { + var context = {}; + if (tearDown) { + var done = test.done; + test.done = function (err) { + try { + tearDown.call(context, function (err2) { + if (err && err2) { + test._assertion_list.push( + types.assertion({error: err}) + ); + return done(err2); + } + done(err || err2); + }); + } + catch (e) { + done(e); + } + }; + } + if (setUp) { + setUp.call(context, function (err) { + if (err) { + return test.done(err); + } + fn.call(context, test); + }); + } + else { + fn.call(context, test); + } + } +}; + + +/** + * Wraps a group of tests with setUp and tearDown functions. + * Used by testCase. + * + * @param {Function} setUp + * @param {Function} tearDown + * @param {Object} group + * @api private + */ + +var wrapGroup = function (setUp, tearDown, group) { + var tests = {}; + var keys = _keys(group); + for (var i=0; i(' + + '' + assertions.failures() + ', ' + + '' + assertions.passes() + ', ' + + assertions.length + + ')'; + test.className = assertions.failures() ? 'fail': 'pass'; + test.appendChild(strong); + + var aList = document.createElement('ol'); + aList.style.display = 'none'; + test.onclick = function () { + var d = aList.style.display; + aList.style.display = (d == 'none') ? 'block': 'none'; + }; + for (var i=0; i' + (a.error.stack || a.error) + '

    '; + li.className = 'fail'; + } + else { + li.innerHTML = a.message || a.method || 'no message'; + li.className = 'pass'; + } + aList.appendChild(li); + } + test.appendChild(aList); + tests.appendChild(test); + }, + done: function (assertions) { + var end = new Date().getTime(); + var duration = end - start; + + var failures = assertions.failures(); + banner.className = failures ? 'fail': 'pass'; + + result.innerHTML = 'Tests completed in ' + duration + + ' milliseconds.
    ' + + assertions.passes() + ' assertions of ' + + '' + assertions.length + ' passed, ' + + assertions.failures() + ' failed.'; + } + }); +}; diff --git a/node_modules/mongodb/deps/nodeunit/lib/reporters/default.js b/node_modules/mongodb/deps/nodeunit/lib/reporters/default.js new file mode 100644 index 0000000..cc5a89e --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/lib/reporters/default.js @@ -0,0 +1,137 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var nodeunit = require('../nodeunit'), + utils = require('../utils'), + fs = require('fs'), + sys = require('sys'), + track = require('../track'), + path = require('path'); + AssertionError = require('../assert').AssertionError; + +/** + * Reporter info string + */ + +exports.info = "Default tests reporter"; + + +/** + * Run all tests within each module, reporting the results to the command-line. + * + * @param {Array} files + * @api public + */ + +exports.run = function (files, options, callback) { + + if (!options) { + // load default options + var content = fs.readFileSync( + __dirname + '/../../bin/nodeunit.json', 'utf8' + ); + options = JSON.parse(content); + } + + var error = function (str) { + return options.error_prefix + str + options.error_suffix; + }; + var ok = function (str) { + return options.ok_prefix + str + options.ok_suffix; + }; + var bold = function (str) { + return options.bold_prefix + str + options.bold_suffix; + }; + var assertion_message = function (str) { + return options.assertion_prefix + str + options.assertion_suffix; + }; + + var start = new Date().getTime(); + var paths = files.map(function (p) { + return path.join(process.cwd(), p); + }); + var tracker = track.createTracker(function (tracker) { + if (tracker.unfinished()) { + sys.puts(''); + sys.puts(error(bold( + 'FAILURES: Undone tests (or their setups/teardowns): ' + ))); + var names = tracker.names(); + for (var i = 0; i < names.length; i += 1) { + sys.puts('- ' + names[i]); + } + sys.puts(''); + sys.puts('To fix this, make sure all tests call test.done()'); + process.reallyExit(tracker.unfinished()); + } + }); + + nodeunit.runFiles(paths, { + moduleStart: function (name) { + sys.puts('\n' + bold(name)); + }, + testDone: function (name, assertions) { + tracker.remove(name); + + if (!assertions.failures()) { + sys.puts('✔ ' + name); + } + else { + sys.puts(error('✖ ' + name) + '\n'); + assertions.forEach(function (a) { + if (a.failed()) { + a = utils.betterErrors(a); + if (a.error instanceof AssertionError && a.message) { + sys.puts( + 'Assertion Message: ' + + assertion_message(a.message) + ); + } + sys.puts(a.error.stack + '\n'); + } + }); + } + }, + done: function (assertions) { + var end = new Date().getTime(); + var duration = end - start; + if (assertions.failures()) { + sys.puts( + '\n' + bold(error('FAILURES: ')) + assertions.failures() + + '/' + assertions.length + ' assertions failed (' + + assertions.duration + 'ms)' + ); + } + else { + sys.puts( + '\n' + bold(ok('OK: ')) + assertions.length + + ' assertions (' + assertions.duration + 'ms)' + ); + } + // alexgorbatchev 2010-11-10 :: should be able to flush stdout + // here, but doesn't seem to work, instead delay the exit to give + // enough to time flush. + // process.stdout.flush() + // process.stdout.end() + var timer = setTimeout(function () { + clearTimeout(timer); + + if(callback != null) { + return callback(); + } else { + process.reallyExit(assertions.failures()); + } + }, 10); + }, + testStart: function(name) { + tracker.put(name); + } + }); +}; diff --git a/node_modules/mongodb/deps/nodeunit/lib/reporters/html.js b/node_modules/mongodb/deps/nodeunit/lib/reporters/html.js new file mode 100644 index 0000000..a693c2d --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/lib/reporters/html.js @@ -0,0 +1,112 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var nodeunit = require('../nodeunit'), + utils = require('../utils'), + fs = require('fs'), + sys = require('sys'), + path = require('path'), + AssertionError = require('assert').AssertionError; + +/** + * Reporter info string + */ + +exports.info = "Report tests result as HTML"; + +/** + * Run all tests within each module, reporting the results to the command-line. + * + * @param {Array} files + * @api public + */ + +exports.run = function (files, options) { + + var start = new Date().getTime(); + var paths = files.map(function (p) { + return path.join(process.cwd(), p); + }); + + sys.puts(''); + sys.puts(''); + sys.puts(''); + sys.puts(''); + sys.puts(''); + sys.puts(''); + nodeunit.runFiles(paths, { + moduleStart: function (name) { + sys.puts('

    ' + name + '

    '); + sys.puts('
      '); + }, + testDone: function (name, assertions) { + if (!assertions.failures()) { + sys.puts('
    1. ' + name + '
    2. '); + } + else { + sys.puts('
    3. ' + name); + assertions.forEach(function (a) { + if (a.failed()) { + a = utils.betterErrors(a); + if (a.error instanceof AssertionError && a.message) { + sys.puts('
      ' + + 'Assertion Message: ' + a.message + + '
      '); + } + sys.puts('
      ');
      +                        sys.puts(a.error.stack);
      +                        sys.puts('
      '); + } + }); + sys.puts('
    4. '); + } + }, + moduleDone: function () { + sys.puts('
    '); + }, + done: function (assertions) { + var end = new Date().getTime(); + var duration = end - start; + if (assertions.failures()) { + sys.puts( + '

    FAILURES: ' + assertions.failures() + + '/' + assertions.length + ' assertions failed (' + + assertions.duration + 'ms)

    ' + ); + } + else { + sys.puts( + '

    OK: ' + assertions.length + + ' assertions (' + assertions.duration + 'ms)

    ' + ); + } + sys.puts(''); + // should be able to flush stdout here, but doesn't seem to work, + // instead delay the exit to give enough to time flush. + setTimeout(function () { + process.reallyExit(assertions.failures()); + }, 10); + } + }); + +}; diff --git a/node_modules/mongodb/deps/nodeunit/lib/reporters/index.js b/node_modules/mongodb/deps/nodeunit/lib/reporters/index.js new file mode 100644 index 0000000..bbaf800 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/lib/reporters/index.js @@ -0,0 +1,9 @@ +module.exports = { + 'junit': require('./junit'), + 'default': require('./default'), + 'skip_passed': require('./skip_passed'), + 'minimal': require('./minimal'), + 'html': require('./html') + // browser test reporter is not listed because it cannot be used + // with the command line tool, only inside a browser. +}; diff --git a/node_modules/mongodb/deps/nodeunit/lib/reporters/junit.js b/node_modules/mongodb/deps/nodeunit/lib/reporters/junit.js new file mode 100644 index 0000000..2519b29 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/lib/reporters/junit.js @@ -0,0 +1,194 @@ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + */ + +/** + * Module dependencies + */ + +var nodeunit = require('../nodeunit'), + utils = require('../utils'), + fs = require('fs'), + sys = require('sys'), + path = require('path'), + async = require('../../deps/async'), + AssertionError = require('assert').AssertionError, + child_process = require('child_process'), + ejs = require('../../deps/ejs'); + + +/** + * Reporter info string + */ + +exports.info = "jUnit XML test reports"; + + +/** + * Ensures a directory exists using mkdir -p. + * + * @param {String} path + * @param {Function} callback + * @api private + */ + +var ensureDir = function (path, callback) { + var mkdir = child_process.spawn('mkdir', ['-p', path]); + mkdir.on('error', function (err) { + callback(err); + callback = function(){}; + }); + mkdir.on('exit', function (code) { + if (code === 0) callback(); + else callback(new Error('mkdir exited with code: ' + code)); + }); +}; + + +/** + * Returns absolute version of a path. Relative paths are interpreted + * relative to process.cwd() or the cwd parameter. Paths that are already + * absolute are returned unaltered. + * + * @param {String} p + * @param {String} cwd + * @return {String} + * @api public + */ + +var abspath = function (p, /*optional*/cwd) { + if (p[0] === '/') return p; + cwd = cwd || process.cwd(); + return path.normalize(path.join(cwd, p)); +}; + + +/** + * Run all tests within each module, reporting the results to the command-line, + * then writes out junit-compatible xml documents. + * + * @param {Array} files + * @api public + */ + +exports.run = function (files, opts, callback) { + if (!opts.output) { + console.error( + 'Error: No output directory defined.\n' + + '\tEither add an "output" property to your nodeunit.json config ' + + 'file, or\n\tuse the --output command line option.' + ); + return; + } + opts.output = abspath(opts.output); + var error = function (str) { + return opts.error_prefix + str + opts.error_suffix; + }; + var ok = function (str) { + return opts.ok_prefix + str + opts.ok_suffix; + }; + var bold = function (str) { + return opts.bold_prefix + str + opts.bold_suffix; + }; + + var start = new Date().getTime(); + var paths = files.map(function (p) { + return path.join(process.cwd(), p); + }); + + var modules = {} + var curModule; + + nodeunit.runFiles(paths, { + moduleStart: function (name) { + curModule = { + errorCount: 0, + failureCount: 0, + tests: 0, + testcases: [], + name: name + }; + modules[name] = curModule; + }, + testDone: function (name, assertions) { + var testcase = {name: name}; + for (var i=0; i [ \.\.\.] +. +.fi +. +.SH "DESCRIPTION" +Nodeunit is a simple unit testing tool based on the node\.js assert module\. +. +.IP "\(bu" 4 +Simple to use +. +.IP "\(bu" 4 +Just export the tests from a module +. +.IP "\(bu" 4 +Helps you avoid common pitfalls when testing asynchronous code +. +.IP "\(bu" 4 +Easy to add test cases with setUp and tearDown functions if you wish +. +.IP "\(bu" 4 +Allows the use of mocks and stubs +. +.IP "" 0 +. +.SH "OPTIONS" + \fB\-\-config FILE\fR: +. +.br + Load config options from a JSON file, allows the customisation + of color schemes for the default test reporter etc\. + See bin/nodeunit\.json for current available options\. +. +.P + \fB\-\-reporter FILE\fR: +. +.br + You can set the test reporter to a custom module or on of the modules + in nodeunit/lib/reporters, when omitted, the default test runner is used\. +. +.P + \fB\-\-list\-reporters\fR: +. +.br + List available build\-in reporters\. +. +.P + \fB\-h\fR, \fB\-\-help\fR: +. +.br + Display the help and exit\. +. +.P + \fB\-v\fR, \fB\-\-version\fR: +. +.br + Output version information and exit\. +. +.P + \fB\fR: + You can run nodeunit on specific files or on all \fI*\.js\fR files inside +. +.br + a directory\. +. +.SH "AUTHORS" +Written by Caolan McMahon and other nodeunit contributors\. +. +.br +Contributors list: \fIhttp://github\.com/caolan/nodeunit/contributors\fR\|\. +. +.SH "REPORTING BUGS" +Report nodeunit bugs to \fIhttp://github\.com/caolan/nodeunit/issues\fR\|\. +. +.SH "COPYRIGHT" +Copyright © 2010 Caolan McMahon\. +. +.br +Nodeunit has been released under the MIT license: +. +.br +\fIhttp://github\.com/caolan/nodeunit/raw/master/LICENSE\fR\|\. +. +.SH "SEE ALSO" +node(1) diff --git a/node_modules/mongodb/deps/nodeunit/nodelint.cfg b/node_modules/mongodb/deps/nodeunit/nodelint.cfg new file mode 100644 index 0000000..457a967 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/nodelint.cfg @@ -0,0 +1,4 @@ +var options = { + indent: 4, + onevar: false +}; diff --git a/node_modules/mongodb/deps/nodeunit/package.json b/node_modules/mongodb/deps/nodeunit/package.json new file mode 100644 index 0000000..da62137 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/package.json @@ -0,0 +1,53 @@ +{ "name": "nodeunit" +, "description": "Easy unit testing for node.js and the browser." +, "maintainers": + [ { "name": "Caolan McMahon" + , "web": "https://github.com/caolan" + } + ] +, "contributors" : + [ { "name": "Alex Gorbatchev" + , "web": "https://github.com/alexgorbatchev" + } + , { "name": "Alex Wolfe" + , "web": "https://github.com/alexkwolfe" + } + , { "name": "Carl Fürstenberg" + , "web": "https://github.com/azatoth" + } + , { "name": "Gerad Suyderhoud" + , "web": "https://github.com/gerad" + } + , { "name": "Kadir Pekel" + , "web": "https://github.com/coffeemate" + } + , { "name": "Oleg Efimov" + , "web": "https://github.com/Sannis" + } + , { "name": "Orlando Vazquez" + , "web": "https://github.com/orlandov" + } + , { "name": "Ryan Dahl" + , "web": "https://github.com/ry" + } + , { "name": "Sam Stephenson" + , "web": "https://github.com/sstephenson" + } + , { "name": "Thomas Mayfield" + , "web": "https://github.com/thegreatape" + } + ] +, "version": "0.5.1" +, "repository" : + { "type" : "git" + , "url" : "http://github.com/caolan/nodeunit.git" + } +, "bugs" : { "web" : "http://github.com/caolan/nodeunit/issues" } +, "licenses" : + [ { "type" : "MIT" + , "url" : "http://github.com/caolan/nodeunit/raw/master/LICENSE" + } + ] +, "directories" : { "lib": "./lib", "doc" : "./doc", "man" : "./man1" } +, "bin" : { "nodeunit" : "./bin/nodeunit" } +} diff --git a/node_modules/mongodb/deps/nodeunit/share/junit.xml.ejs b/node_modules/mongodb/deps/nodeunit/share/junit.xml.ejs new file mode 100644 index 0000000..c1db5bb --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/share/junit.xml.ejs @@ -0,0 +1,19 @@ + +<% for (var i=0; i < suites.length; i++) { %> + <% var suite=suites[i]; %> + + <% for (var j=0; j < suite.testcases.length; j++) { %> + <% var testcase=suites[i].testcases[j]; %> + + <% if (testcase.failure) { %> + + <% if (testcase.failure.backtrace) { %><%= testcase.failure.backtrace %><% } %> + + <% } %> + + <% } %> + +<% } %> diff --git a/node_modules/mongodb/deps/nodeunit/share/license.js b/node_modules/mongodb/deps/nodeunit/share/license.js new file mode 100644 index 0000000..f0f326f --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/share/license.js @@ -0,0 +1,11 @@ +/*! + * Nodeunit + * https://github.com/caolan/nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + * + * json2.js + * http://www.JSON.org/json2.js + * Public Domain. + * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + */ diff --git a/node_modules/mongodb/deps/nodeunit/share/nodeunit.css b/node_modules/mongodb/deps/nodeunit/share/nodeunit.css new file mode 100644 index 0000000..274434a --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/share/nodeunit.css @@ -0,0 +1,70 @@ +/*! + * Styles taken from qunit.css + */ + +h1#nodeunit-header, h1.nodeunit-header { + padding: 15px; + font-size: large; + background-color: #06b; + color: white; + font-family: 'trebuchet ms', verdana, arial; + margin: 0; +} + +h1#nodeunit-header a { + color: white; +} + +h2#nodeunit-banner { + height: 2em; + border-bottom: 1px solid white; + background-color: #eee; + margin: 0; + font-family: 'trebuchet ms', verdana, arial; +} +h2#nodeunit-banner.pass { + background-color: green; +} +h2#nodeunit-banner.fail { + background-color: red; +} + +h2#nodeunit-userAgent, h2.nodeunit-userAgent { + padding: 10px; + background-color: #eee; + color: black; + margin: 0; + font-size: small; + font-weight: normal; + font-family: 'trebuchet ms', verdana, arial; + font-size: 10pt; +} + +div#nodeunit-testrunner-toolbar { + background: #eee; + border-top: 1px solid black; + padding: 10px; + font-family: 'trebuchet ms', verdana, arial; + margin: 0; + font-size: 10pt; +} + +ol#nodeunit-tests { + font-family: 'trebuchet ms', verdana, arial; + font-size: 10pt; +} +ol#nodeunit-tests li strong { + cursor:pointer; +} +ol#nodeunit-tests .pass { + color: green; +} +ol#nodeunit-tests .fail { + color: red; +} + +p#nodeunit-testresult { + margin-left: 1em; + font-size: 10pt; + font-family: 'trebuchet ms', verdana, arial; +} diff --git a/node_modules/mongodb/deps/nodeunit/test/fixtures/coffee/mock_coffee_module.coffee b/node_modules/mongodb/deps/nodeunit/test/fixtures/coffee/mock_coffee_module.coffee new file mode 100644 index 0000000..a1c069b --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/fixtures/coffee/mock_coffee_module.coffee @@ -0,0 +1,4 @@ +j = 0 +j += i for i in [0..5] + +exports.name = "mock_coffee_#{j}" diff --git a/node_modules/mongodb/deps/nodeunit/test/fixtures/dir/mock_module3.js b/node_modules/mongodb/deps/nodeunit/test/fixtures/dir/mock_module3.js new file mode 100644 index 0000000..3021776 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/fixtures/dir/mock_module3.js @@ -0,0 +1 @@ +exports.name = 'mock_module3'; diff --git a/node_modules/mongodb/deps/nodeunit/test/fixtures/dir/mock_module4.js b/node_modules/mongodb/deps/nodeunit/test/fixtures/dir/mock_module4.js new file mode 100644 index 0000000..876f9ca --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/fixtures/dir/mock_module4.js @@ -0,0 +1 @@ +exports.name = 'mock_module4'; diff --git a/node_modules/mongodb/deps/nodeunit/test/fixtures/mock_module1.js b/node_modules/mongodb/deps/nodeunit/test/fixtures/mock_module1.js new file mode 100644 index 0000000..4c093ad --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/fixtures/mock_module1.js @@ -0,0 +1 @@ +exports.name = 'mock_module1'; diff --git a/node_modules/mongodb/deps/nodeunit/test/fixtures/mock_module2.js b/node_modules/mongodb/deps/nodeunit/test/fixtures/mock_module2.js new file mode 100644 index 0000000..a63d012 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/fixtures/mock_module2.js @@ -0,0 +1 @@ +exports.name = 'mock_module2'; diff --git a/node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode1.js b/node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode1.js new file mode 100644 index 0000000..2ef7115 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode1.js @@ -0,0 +1,3 @@ +function hello_world(arg) { + return "_" + arg + "_"; +} diff --git a/node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode2.js b/node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode2.js new file mode 100644 index 0000000..55a764e --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode2.js @@ -0,0 +1,3 @@ +function get_a_variable() { + return typeof a_variable; +} diff --git a/node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode3.js b/node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode3.js new file mode 100644 index 0000000..1fd1e78 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/fixtures/raw_jscode3.js @@ -0,0 +1 @@ +var t=t?t+1:1; diff --git a/node_modules/mongodb/deps/nodeunit/test/test-base.js b/node_modules/mongodb/deps/nodeunit/test/test-base.js new file mode 100644 index 0000000..64b8c8b --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/test-base.js @@ -0,0 +1,219 @@ +/* + * This module is not a plain nodeunit test suite, but instead uses the + * assert module to ensure a basic level of functionality is present, + * allowing the rest of the tests to be written using nodeunit itself. + * + * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +var assert = require('assert'), // @REMOVE_LINE_FOR_BROWSER + async = require('../deps/async'), // @REMOVE_LINE_FOR_BROWSER + nodeunit = require('../lib/nodeunit'); // @REMOVE_LINE_FOR_BROWSER + + +// NOT A TEST - util function to make testing faster. +// retries the assertion until it passes or the timeout is reached, +// at which point it throws the assertion error +var waitFor = function (fn, timeout, callback, start) { + start = start || new Date().getTime(); + callback = callback || function () {}; + try { + fn(); + callback(); + } + catch (e) { + if (e instanceof assert.AssertionError) { + var now = new Date().getTime(); + if (now - start >= timeout) { + throw e; + } + else { + async.nextTick(function () { + waitFor(fn, timeout, callback, start); + }); + } + } + else { + throw e; + } + } +}; + + +// TESTS: + +// Are exported tests actually run? - store completed tests in this variable +// for checking later +var tests_called = {}; + +// most basic test that should run, the tests_called object is tested +// at the end of this module to ensure the tests were actually run by nodeunit +exports.testCalled = function (test) { + tests_called.testCalled = true; + test.done(); +}; + +// generates test functions for nodeunit assertions +var makeTest = function (method, args_pass, args_fail) { + return function (test) { + var test1_called = false; + var test2_called = false; + + // test pass + nodeunit.runTest( + 'testname', + function (test) { + test[method].apply(test, args_pass); + test.done(); + }, + {testDone: function (name, assertions) { + assert.equal(assertions.length, 1); + assert.equal(assertions.failures(), 0); + }}, + function () { + test1_called = true; + } + ); + + // test failure + nodeunit.runTest( + 'testname', + function (test) { + test[method].apply(test, args_fail); + test.done(); + }, + {testDone: function (name, assertions) { + assert.equal(assertions.length, 1); + assert.equal(assertions.failures(), 1); + }}, + function () { + test2_called = true; + } + ); + + // ensure tests were run + waitFor(function () { + assert.ok(test1_called); + assert.ok(test2_called); + tests_called[method] = true; + }, 500, test.done); + }; +}; + +// ensure basic assertions are working: +exports.testOk = makeTest('ok', [true], [false]); +exports.testEquals = makeTest('equals', [1, 1], [1, 2]); +exports.testSame = makeTest('same', + [{test: 'test'}, {test: 'test'}], + [{test: 'test'}, {monkey: 'penguin'}] +); + +// from the assert module: +exports.testEqual = makeTest('equal', [1, 1], [1, 2]); +exports.testNotEqual = makeTest('notEqual', [1, 2], [1, 1]); +exports.testDeepEqual = makeTest('deepEqual', + [{one: 1}, {one: 1}], [{one: 1}, {two: 2}] +); +exports.testNotDeepEqual = makeTest('notDeepEqual', + [{one: 1}, {two: 2}], [{one: 1}, {one: 1}] +); +exports.testStrictEqual = makeTest('strictEqual', [1, 1], [1, true]); +exports.testNotStrictEqual = makeTest('notStrictEqual', [true, 1], [1, 1]); +exports.testThrows = makeTest('throws', + [function () { + throw new Error('test'); + }], + [function () { + return; + }] +); +exports.testDoesNotThrows = makeTest('doesNotThrow', + [function () { + return; + }], + [function () { + throw new Error('test'); + }] +); +exports.testIfError = makeTest('ifError', [false], [new Error('test')]); + + +exports.testExpect = function (test) { + var test1_called = false, + test2_called = false, + test3_called = false; + + // correct number of tests run + nodeunit.runTest( + 'testname', + function (test) { + test.expect(2); + test.ok(true); + test.ok(true); + test.done(); + }, + {testDone: function (name, assertions) { + test.equals(assertions.length, 2); + test.equals(assertions.failures(), 0); + }}, + function () { + test1_called = true; + } + ); + + // no tests run + nodeunit.runTest( + 'testname', + function (test) { + test.expect(2); + test.done(); + }, + {testDone: function (name, assertions) { + test.equals(assertions.length, 1); + test.equals(assertions.failures(), 1); + }}, + function () { + test2_called = true; + } + ); + + // incorrect number of tests run + nodeunit.runTest( + 'testname', + function (test) { + test.expect(2); + test.ok(true); + test.ok(true); + test.ok(true); + test.done(); + }, + {testDone: function (name, assertions) { + test.equals(assertions.length, 4); + test.equals(assertions.failures(), 1); + }}, + function () { + test3_called = true; + } + ); + + // ensure callbacks fired + waitFor(function () { + assert.ok(test1_called); + assert.ok(test2_called); + assert.ok(test3_called); + tests_called.expect = true; + }, 500, test.done); +}; + + +// tests are async, so wait for them to be called +waitFor(function () { + assert.ok(tests_called.testCalled); + assert.ok(tests_called.ok); + assert.ok(tests_called.equals); + assert.ok(tests_called.same); + assert.ok(tests_called.expect); +}, 10000); diff --git a/node_modules/mongodb/deps/nodeunit/test/test-failing-callbacks.js b/node_modules/mongodb/deps/nodeunit/test/test-failing-callbacks.js new file mode 100644 index 0000000..08f7eb5 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/test-failing-callbacks.js @@ -0,0 +1,114 @@ +var nodeunit = require('../lib/nodeunit'); + + +exports.testFailingLog = function (test) { + test.expect(3); + + // this is meant to bubble to the top, and will be ignored for the purposes + // of testing: + var ignored_error = new Error('ignore this callback error'); + var err_handler = function (err) { + if (err && err.message !== ignored_error.message) { + throw err; + } + }; + process.addListener('uncaughtException', err_handler); + + // A failing callback should not affect the test outcome + var testfn = function (test) { + test.ok(true, 'test.ok'); + test.done(); + }; + nodeunit.runTest('testname', testfn, { + log: function (assertion) { + test.ok(true, 'log called'); + throw ignored_error; + }, + testDone: function (name, assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 1, 'total'); + process.removeListener('uncaughtException', err_handler); + } + }, test.done); +}; + +exports.testFailingTestDone = function (test) { + test.expect(2); + + var ignored_error = new Error('ignore this callback error'); + var err_handler = function (err) { + if (err && err.message !== ignored_error.message) { + throw err; + } + }; + process.addListener('uncaughtException', err_handler); + + // A failing callback should not affect the test outcome + var testfn = function (test) { + test.done(); + }; + nodeunit.runTest('testname', testfn, { + log: function (assertion) { + test.ok(false, 'log should not be called'); + }, + testDone: function (name, assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 0, 'total'); + process.nextTick(function () { + process.removeListener('uncaughtException', err_handler); + test.done(); + }); + throw ignored_error; + } + }, function () {}); +}; + +exports.testAssertionObj = function (test) { + test.expect(4); + var testfn = function (test) { + test.ok(true, 'ok true'); + test.done(); + }; + nodeunit.runTest('testname', testfn, { + log: function (assertion) { + test.ok(assertion.passed() === true, 'assertion.passed'); + test.ok(assertion.failed() === false, 'assertion.failed'); + }, + testDone: function (name, assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 1, 'total'); + } + }, test.done); +}; + +exports.testLogOptional = function (test) { + test.expect(2); + var testfn = function (test) { + test.ok(true, 'ok true'); + test.done(); + }; + nodeunit.runTest('testname', testfn, { + testDone: function (name, assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 1, 'total'); + } + }, test.done); +}; + +exports.testExpectWithFailure = function (test) { + test.expect(3); + var testfn = function (test) { + test.expect(1); + test.ok(false, 'test.ok'); + test.done(); + }; + nodeunit.runTest('testname', testfn, { + log: function (assertion) { + test.equals(assertion.method, 'ok', 'assertion.method'); + }, + testDone: function (name, assertions) { + test.equals(assertions.failures(), 1, 'failures'); + test.equals(assertions.length, 1, 'total'); + } + }, test.done); +}; diff --git a/node_modules/mongodb/deps/nodeunit/test/test-httputil.js b/node_modules/mongodb/deps/nodeunit/test/test-httputil.js new file mode 100644 index 0000000..e5ee25c --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/test-httputil.js @@ -0,0 +1,55 @@ +var nodeunit = require('../lib/nodeunit'); +var httputil = require('../lib/utils').httputil; + +exports.testHttpUtilBasics = function (test) { + + test.expect(6); + + httputil(function (req, resp) { + test.equal(req.method, 'PUT'); + test.equal(req.url, '/newpair'); + test.equal(req.headers.foo, 'bar'); + + resp.writeHead(500, {'content-type': 'text/plain'}); + resp.end('failed'); + }, function (server, client) { + client.fetch('PUT', '/newpair', {'foo': 'bar'}, function (resp) { + test.equal(resp.statusCode, 500); + test.equal(resp.headers['content-type'], 'text/plain'); + test.equal(resp.body, 'failed'); + + server.close(); + test.done(); + }); + }); +}; + +exports.testHttpUtilJsonHandling = function (test) { + + test.expect(9); + + httputil(function (req, resp) { + test.equal(req.method, 'GET'); + test.equal(req.url, '/'); + test.equal(req.headers.foo, 'bar'); + + var testdata = {foo1: 'bar', foo2: 'baz'}; + + resp.writeHead(200, {'content-type': 'application/json'}); + resp.end(JSON.stringify(testdata)); + + }, function (server, client) { + client.fetch('GET', '/', {'foo': 'bar'}, function (resp) { + test.equal(resp.statusCode, 200); + test.equal(resp.headers['content-type'], 'application/json'); + + test.ok(resp.bodyAsObject); + test.equal(typeof resp.bodyAsObject, 'object'); + test.equal(resp.bodyAsObject.foo1, 'bar'); + test.equal(resp.bodyAsObject.foo2, 'baz'); + + server.close(); + test.done(); + }); + }); +}; diff --git a/node_modules/mongodb/deps/nodeunit/test/test-runfiles.js b/node_modules/mongodb/deps/nodeunit/test/test-runfiles.js new file mode 100644 index 0000000..b9ef754 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/test-runfiles.js @@ -0,0 +1,214 @@ +var assert = require('assert'), + sys = require('sys'), + fs = require('fs'), + path = require('path'), + nodeunit = require('../lib/nodeunit'); + + +var setup = function (fn) { + return function (test) { + process.chdir(__dirname); + require.paths.push(__dirname); + var env = { + mock_module1: require('./fixtures/mock_module1'), + mock_module2: require('./fixtures/mock_module2'), + mock_module3: require('./fixtures/dir/mock_module3'), + mock_module4: require('./fixtures/dir/mock_module4') + }; + fn.call(env, test); + }; +}; + + +exports.testRunFiles = setup(function (test) { + test.expect(24); + var runModule_copy = nodeunit.runModule; + + var runModule_calls = []; + var modules = []; + + var opts = { + moduleStart: function () { + return 'moduleStart'; + }, + testDone: function () { + return 'testDone'; + }, + testStart: function () { + return 'testStart'; + }, + log: function () { + return 'log'; + }, + done: function (assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 4, 'length'); + test.ok(typeof assertions.duration === "number"); + + var called_with = function (name) { + return runModule_calls.some(function (m) { + return m.name === name; + }); + }; + test.ok(called_with('mock_module1'), 'mock_module1 ran'); + test.ok(called_with('mock_module2'), 'mock_module2 ran'); + test.ok(called_with('mock_module3'), 'mock_module3 ran'); + test.ok(called_with('mock_module4'), 'mock_module4 ran'); + test.equals(runModule_calls.length, 4); + + nodeunit.runModule = runModule_copy; + test.done(); + } + }; + + nodeunit.runModule = function (name, mod, options, callback) { + test.equals(options.testDone, opts.testDone); + test.equals(options.testStart, opts.testStart); + test.equals(options.log, opts.log); + test.ok(typeof name === "string"); + runModule_calls.push(mod); + var m = [{failed: function () { + return false; + }}]; + modules.push(m); + callback(null, m); + }; + + nodeunit.runFiles( + ['fixtures/mock_module1.js', 'fixtures/mock_module2.js', 'fixtures/dir'], + opts + ); +}); + +exports.testRunFilesEmpty = function (test) { + test.expect(3); + nodeunit.runFiles([], { + moduleStart: function () { + test.ok(false, 'should not be called'); + }, + testDone: function () { + test.ok(false, 'should not be called'); + }, + testStart: function () { + test.ok(false, 'should not be called'); + }, + log: function () { + test.ok(false, 'should not be called'); + }, + done: function (assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 0, 'length'); + test.ok(typeof assertions.duration === "number"); + test.done(); + } + }); +}; + + +exports.testEmptyDir = function (test) { + var dir2 = __dirname + '/fixtures/dir2'; + + // git doesn't like empty directories, so we have to create one + path.exists(dir2, function (exists) { + if (!exists) { + fs.mkdirSync(dir2, 0777); + } + + // runFiles on empty directory: + nodeunit.runFiles([dir2], { + moduleStart: function () { + test.ok(false, 'should not be called'); + }, + testDone: function () { + test.ok(false, 'should not be called'); + }, + testStart: function () { + test.ok(false, 'should not be called'); + }, + log: function () { + test.ok(false, 'should not be called'); + }, + done: function (assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 0, 'length'); + test.ok(typeof assertions.duration === "number"); + test.done(); + } + }); + }); +}; + + +var CoffeeScript; +try { + CoffeeScript = require('coffee-script'); +} catch (e) { +} + +if (CoffeeScript) { + exports.testCoffeeScript = function (test) { + process.chdir(__dirname); + require.paths.push(__dirname); + var env = { + mock_coffee_module: require('./fixtures/coffee/mock_coffee_module') + }; + + test.expect(9); + var runModule_copy = nodeunit.runModule; + + var runModule_calls = []; + var modules = []; + + var opts = { + moduleStart: function () { + return 'moduleStart'; + }, + testDone: function () { + return 'testDone'; + }, + testStart: function () { + return 'testStart'; + }, + log: function () { + return 'log'; + }, + done: function (assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 1, 'length'); + test.ok(typeof assertions.duration === "number"); + + var called_with = function (name) { + return runModule_calls.some(function (m) { + return m.name === name; + }); + }; + test.ok( + called_with('mock_coffee_15'), + 'mock_coffee_module ran' + ); + test.equals(runModule_calls.length, 1); + + nodeunit.runModule = runModule_copy; + test.done(); + } + }; + + nodeunit.runModule = function (name, mod, options, callback) { + test.equals(options.testDone, opts.testDone); + test.equals(options.testStart, opts.testStart); + test.equals(options.log, opts.log); + test.ok(typeof name === "string"); + runModule_calls.push(mod); + var m = [{failed: function () { + return false; + }}]; + modules.push(m); + callback(null, m); + }; + + nodeunit.runFiles( + ['fixtures/coffee/mock_coffee_module.coffee'], + opts + ); + }; +} diff --git a/node_modules/mongodb/deps/nodeunit/test/test-runmodule.js b/node_modules/mongodb/deps/nodeunit/test/test-runmodule.js new file mode 100644 index 0000000..218e8db --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/test-runmodule.js @@ -0,0 +1,125 @@ +/* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +var nodeunit = require('../lib/nodeunit'); // @REMOVE_LINE_FOR_BROWSER + + +exports.testRunModule = function (test) { + test.expect(11); + var call_order = []; + var testmodule = { + test1: function (test) { + call_order.push('test1'); + test.ok(true, 'ok true'); + test.done(); + }, + test2: function (test) { + call_order.push('test2'); + test.ok(false, 'ok false'); + test.ok(false, 'ok false'); + test.done(); + }, + test3: function (test) { + call_order.push('test3'); + test.done(); + } + }; + nodeunit.runModule('testmodule', testmodule, { + log: function (assertion) { + call_order.push('log'); + }, + testStart: function (name) { + call_order.push('testStart'); + test.ok( + name.toString() === 'test1' || + name.toString() === 'test2' || + name.toString() === 'test3', + 'testStart called with test name ' + ); + }, + testDone: function (name, assertions) { + call_order.push('testDone'); + test.ok( + name.toString() === 'test1' || + name.toString() === 'test2' || + name.toString() === 'test3', + 'testDone called with test name' + ); + }, + moduleDone: function (name, assertions) { + call_order.push('moduleDone'); + test.equals(assertions.length, 3); + test.equals(assertions.failures(), 2); + test.equals(name, 'testmodule'); + test.ok(typeof assertions.duration === "number"); + test.same(call_order, [ + 'testStart', 'test1', 'log', 'testDone', + 'testStart', 'test2', 'log', 'log', 'testDone', + 'testStart', 'test3', 'testDone', + 'moduleDone' + ]); + } + }, test.done); +}; + +exports.testRunModuleEmpty = function (test) { + nodeunit.runModule('module with no exports', {}, { + log: function (assertion) { + test.ok(false, 'log should not be called'); + }, + testStart: function (name) { + test.ok(false, 'testStart should not be called'); + }, + testDone: function (name, assertions) { + test.ok(false, 'testDone should not be called'); + }, + moduleDone: function (name, assertions) { + test.equals(assertions.length, 0); + test.equals(assertions.failures(), 0); + test.equals(name, 'module with no exports'); + test.ok(typeof assertions.duration === "number"); + } + }, test.done); +}; + +exports.testNestedTests = function (test) { + var call_order = []; + var m = { + test1: function (test) { + test.done(); + }, + suite: { + t1: function (test) { + test.done(); + }, + t2: function (test) { + test.done(); + }, + another_suite: { + t3: function (test) { + test.done(); + } + } + } + }; + nodeunit.runModule('modulename', m, { + testStart: function (name) { + call_order.push(['testStart'].concat(name)); + }, + testDone: function (name, assertions) { + call_order.push(['testDone'].concat(name)); + } + }, function () { + test.same(call_order, [ + ['testStart', 'test1'], ['testDone', 'test1'], + ['testStart', 'suite', 't1'], ['testDone', 'suite', 't1'], + ['testStart', 'suite', 't2'], ['testDone', 'suite', 't2'], + ['testStart', 'suite', 'another_suite', 't3'], + ['testDone', 'suite', 'another_suite', 't3'] + ]); + test.done(); + }); +}; diff --git a/node_modules/mongodb/deps/nodeunit/test/test-runtest.js b/node_modules/mongodb/deps/nodeunit/test/test-runtest.js new file mode 100644 index 0000000..8fc3d52 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/test-runtest.js @@ -0,0 +1,46 @@ +/* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +var nodeunit = require('../lib/nodeunit'); // @REMOVE_LINE_FOR_BROWSER + + +exports.testArgs = function (test) { + test.ok(test.expect instanceof Function, 'test.expect'); + test.ok(test.done instanceof Function, 'test.done'); + test.ok(test.ok instanceof Function, 'test.ok'); + test.ok(test.same instanceof Function, 'test.same'); + test.ok(test.equals instanceof Function, 'test.equals'); + test.done(); +}; + +exports.testDoneCallback = function (test) { + test.expect(4); + nodeunit.runTest('testname', exports.testArgs, { + testDone: function (name, assertions) { + test.equals(assertions.failures(), 0, 'failures'); + test.equals(assertions.length, 5, 'length'); + test.ok(typeof assertions.duration === "number"); + test.equals(name, 'testname'); + } + }, test.done); +}; + +exports.testThrowError = function (test) { + test.expect(3); + var err = new Error('test'); + var testfn = function (test) { + throw err; + }; + nodeunit.runTest('testname', testfn, { + log: function (assertion) { + test.same(assertion.error, err, 'assertion.error'); + }, + testDone: function (name, assertions) { + test.equals(assertions.failures(), 1); + test.equals(assertions.length, 1); + } + }, test.done); +}; diff --git a/node_modules/mongodb/deps/nodeunit/test/test-sandbox.js b/node_modules/mongodb/deps/nodeunit/test/test-sandbox.js new file mode 100644 index 0000000..1b249d7 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/test-sandbox.js @@ -0,0 +1,31 @@ +var nodeunit = require('../lib/nodeunit'); +var sandbox = require('../lib/utils').sandbox; +var testCase = nodeunit.testCase; + +exports.testSimpleSandbox = function (test) { + var raw_jscode1 = sandbox(__dirname + '/fixtures/raw_jscode1.js'); + test.equal(raw_jscode1.hello_world('foo'), '_foo_', 'evaluation ok'); + test.done(); +}; + +exports.testSandboxContext = function (test) { + var a_variable = 42; // should not be visible in the sandbox + var raw_jscode2 = sandbox(__dirname + '/fixtures/raw_jscode2.js'); + a_variable = 42; // again for the win + test.equal( + raw_jscode2.get_a_variable(), + 'undefined', + 'the variable should not be defined' + ); + test.done(); +}; + +exports.testSandboxMultiple = function (test) { + var raw_jscode3 = sandbox([ + __dirname + '/fixtures/raw_jscode3.js', + __dirname + '/fixtures/raw_jscode3.js', + __dirname + '/fixtures/raw_jscode3.js' + ]); + test.equal(raw_jscode3.t, 3, 'two files loaded'); + test.done(); +}; diff --git a/node_modules/mongodb/deps/nodeunit/test/test-testcase.js b/node_modules/mongodb/deps/nodeunit/test/test-testcase.js new file mode 100644 index 0000000..a3ea331 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/test-testcase.js @@ -0,0 +1,234 @@ +/* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +var nodeunit = require('../lib/nodeunit'); // @REMOVE_LINE_FOR_BROWSER +var testCase = nodeunit.testCase; + +exports.testTestCase = function (test) { + test.expect(7); + var call_order = []; + var s = testCase({ + setUp: function (callback) { + call_order.push('setUp'); + test.equals(this.one, undefined); + this.one = 1; + callback(); + }, + tearDown: function (callback) { + call_order.push('tearDown'); + test.ok(true, 'tearDown called'); + callback(); + }, + test1: function (t) { + call_order.push('test1'); + test.equals(this.one, 1); + this.one = 2; + t.done(); + }, + test2: function (t) { + call_order.push('test2'); + test.equals(this.one, 1); + t.done(); + } + }); + nodeunit.runSuite(null, s, {}, function () { + test.same(call_order, [ + 'setUp', 'test1', 'tearDown', + 'setUp', 'test2', 'tearDown' + ]); + test.done(); + }); +}; + +exports.tearDownAfterError = function (test) { + test.expect(1); + var s = testCase({ + tearDown: function (callback) { + test.ok(true, 'tearDown called'); + callback(); + }, + test: function (t) { + throw new Error('some error'); + } + }); + nodeunit.runSuite(null, s, {}, function () { + test.done(); + }); +}; + +exports.catchSetUpError = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = testCase({ + setUp: function (callback) { + throw test_error; + }, + test: function (t) { + test.ok(false, 'test function should not be called'); + t.done(); + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.setUpErrorCallback = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = testCase({ + setUp: function (callback) { + callback(test_error); + }, + test: function (t) { + test.ok(false, 'test function should not be called'); + t.done(); + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.catchTearDownError = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = testCase({ + tearDown: function (callback) { + throw test_error; + }, + test: function (t) { + t.done(); + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.tearDownErrorCallback = function (test) { + test.expect(2); + var test_error = new Error('test error'); + var s = testCase({ + tearDown: function (callback) { + callback(test_error); + }, + test: function (t) { + t.done(); + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 1); + test.equal(assertions[0].error, test_error); + test.done(); + }); +}; + +exports.testErrorAndtearDownError = function (test) { + test.expect(3); + var error1 = new Error('test error one'); + var error2 = new Error('test error two'); + var s = testCase({ + tearDown: function (callback) { + callback(error2); + }, + test: function (t) { + t.done(error1); + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.equal(assertions.length, 2); + test.equal(assertions[0].error, error1); + test.equal(assertions[1].error, error2); + test.done(); + }); +}; + +exports.testCaseGroups = function (test) { + var call_order = []; + var s = testCase({ + setUp: function (callback) { + call_order.push('setUp'); + callback(); + }, + tearDown: function (callback) { + call_order.push('tearDown'); + callback(); + }, + test1: function (test) { + call_order.push('test1'); + test.done(); + }, + group1: { + test2: function (test) { + call_order.push('group1.test2'); + test.done(); + } + } + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.same(call_order, [ + 'setUp', + 'test1', + 'tearDown', + 'setUp', + 'group1.test2', + 'tearDown' + ]); + test.done(); + }); +}; + +exports.nestedTestCases = function (test) { + var call_order = []; + var s = testCase({ + setUp: function (callback) { + call_order.push('setUp'); + callback(); + }, + tearDown: function (callback) { + call_order.push('tearDown'); + callback(); + }, + test1: function (test) { + call_order.push('test1'); + test.done(); + }, + group1: testCase({ + setUp: function (callback) { + call_order.push('group1.setUp'); + callback(); + }, + tearDown: function (callback) { + call_order.push('group1.tearDown'); + callback(); + }, + test2: function (test) { + call_order.push('group1.test2'); + test.done(); + } + }) + }); + nodeunit.runSuite(null, s, {}, function (err, assertions) { + test.same(call_order, [ + 'setUp', + 'test1', + 'tearDown', + 'setUp', + 'group1.setUp', + 'group1.test2', + 'group1.tearDown', + 'tearDown' + ]); + test.done(); + }); +}; diff --git a/node_modules/mongodb/deps/nodeunit/test/test.html b/node_modules/mongodb/deps/nodeunit/test/test.html new file mode 100644 index 0000000..31bda30 --- /dev/null +++ b/node_modules/mongodb/deps/nodeunit/test/test.html @@ -0,0 +1,26 @@ + + + Nodeunit Test Suite + + + + + + + + + +

    Nodeunit Test Suite

    + + + diff --git a/node_modules/mongodb/deps/step/README.markdown b/node_modules/mongodb/deps/step/README.markdown new file mode 100644 index 0000000..abf1f2b --- /dev/null +++ b/node_modules/mongodb/deps/step/README.markdown @@ -0,0 +1,71 @@ +# Step + +A simple control-flow library for node.JS that makes parallel execution, serial execution, and error handling painless. + +## How to install + +Simply copy or link the lib/step.js file into your `$HOME/.node_libraries` folder. + +## How to use + +The step library exports a single function I call `Step`. It accepts any number of functions as arguments and runs them in serial order using the passed in `this` context as the callback to the next step. + + Step( + function readSelf() { + fs.readFile(__filename, this); + }, + function capitalize(err, text) { + if (err) throw err; + return text.toUpperCase(); + }, + function showIt(err, newText) { + if (err) throw err; + console.log(newText); + } + ); + +Notice that we pass in `this` as the callback to `fs.readFile`. When the file read completes, step will send the result as the arguments to the next function in the chain. Then in the `capitalize` function we're doing synchronous work so we can simple return the new value and Step will route it as if we called the callback. + +The first parameter is reserved for errors since this is the node standard. Also any exceptions thrown are caught and passed as the first argument to the next function. As long as you don't nest callback functions inline your main functions this prevents there from ever being any uncaught exceptions. This is very important for long running node.JS servers since a single uncaught exception can bring the whole server down. + +Also there is support for parallel actions: + + Step( + // Loads two files in parallel + function loadStuff() { + fs.readFile(__filename, this.parallel()); + fs.readFile("/etc/passwd", this.parallel()); + }, + // Show the result when done + function showStuff(err, code, users) { + if (err) throw err; + sys.puts(code); + sys.puts(users); + } + ) + +Here we pass `this.parallel()` instead of `this` as the callback. It internally keeps track of the number of callbacks issued and preserves their order then giving the result to the next step after all have finished. If there is an error in any of the parallel actions, it will be passed as the first argument to the next step. + +Also you can use group with a dynamic number of common tasks. + + Step( + function readDir() { + fs.readdir(__dirname, this); + }, + function readFiles(err, results) { + if (err) throw err; + // Create a new group + var group = this.group(); + results.forEach(function (filename) { + if (/\.js$/.test(filename)) { + fs.readFile(__dirname + "/" + filename, 'utf8', group()); + } + }); + }, + function showAll(err , files) { + if (err) throw err; + sys.p(files); + } + ); + +*Note* that we both call `this.group()` and `group()`. The first reserves a slot in the parameters of the next step, then calling `group()` generates the individual callbacks and increments the internal counter. diff --git a/node_modules/mongodb/deps/step/lib/step.js b/node_modules/mongodb/deps/step/lib/step.js new file mode 100755 index 0000000..546c14d --- /dev/null +++ b/node_modules/mongodb/deps/step/lib/step.js @@ -0,0 +1,154 @@ +/* +Copyright (c) 2011 Tim Caswell + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +// Inspired by http://github.com/willconant/flow-js, but reimplemented and +// modified to fit my taste and the node.JS error handling system. +function Step() { + var steps = Array.prototype.slice.call(arguments), + pending, counter, results, lock; + + // Define the main callback that's given as `this` to the steps. + function next() { + + // Check if there are no steps left + if (steps.length === 0) { + // Throw uncaught errors + if (arguments[0]) { + throw arguments[0]; + } + return; + } + + // Get the next step to execute + var fn = steps.shift(); + counter = pending = 0; + results = []; + + // Run the step in a try..catch block so exceptions don't get out of hand. + try { + lock = true; + var result = fn.apply(next, arguments); + } catch (e) { + // Pass any exceptions on through the next callback + next(e); + } + + + // If a syncronous return is used, pass it to the callback + if (result !== undefined) { + next(undefined, result); + } + lock = false; + } + + // Add a special callback generator `this.parallel()` that groups stuff. + next.parallel = function () { + var index = 1 + counter++; + pending++; + + function check() { + if (pending === 0) { + // When they're all done, call the callback + next.apply(null, results); + } + } + process.nextTick(check); // Ensures that check is called at least once + + return function () { + pending--; + // Compress the error from any result to the first argument + if (arguments[0]) { + results[0] = arguments[0]; + } + // Send the other results as arguments + results[index] = arguments[1]; + if (!lock) { check(); } + }; + }; + + // Generates a callback generator for grouped results + next.group = function () { + var localCallback = next.parallel(); + var counter = 0; + var pending = 0; + var result = []; + var error = undefined; + + function check() { + if (pending === 0) { + // When group is done, call the callback + localCallback(error, result); + } + } + process.nextTick(check); // Ensures that check is called at least once + + // Generates a callback for the group + return function () { + var index = counter++; + pending++; + return function () { + pending--; + // Compress the error from any result to the first argument + if (arguments[0]) { + error = arguments[0]; + } + // Send the other results as arguments + result[index] = arguments[1]; + if (!lock) { check(); } + }; + }; + }; + + // Start the engine an pass nothing to the first step. + next(); +} + +// Tack on leading and tailing steps for input and output and return +// the whole thing as a function. Basically turns step calls into function +// factories. +Step.fn = function StepFn() { + var steps = Array.prototype.slice.call(arguments); + return function () { + var args = Array.prototype.slice.call(arguments); + + // Insert a first step that primes the data stream + var toRun = [function () { + this.apply(null, args); + }].concat(steps); + + // If the last arg is a function add it as a last step + if (typeof args[args.length-1] === 'function') { + toRun.push(args.pop()); + } + + + Step.apply(null, toRun); + } +} + + +// Hook into commonJS module systems +if (typeof module !== 'undefined' && "exports" in module) { + module.exports = Step; +} diff --git a/node_modules/mongodb/deps/step/package.json b/node_modules/mongodb/deps/step/package.json new file mode 100644 index 0000000..062ace0 --- /dev/null +++ b/node_modules/mongodb/deps/step/package.json @@ -0,0 +1,11 @@ +{ "name": "step", + "version": "0.0.4", + "description": "A simple control-flow library for node.JS that makes parallel execution, serial execution, and error handling painless.", + "engine": [ "node >=0.2.0" ], + "author": "Tim Caswell ", + "repository": + { "type" : "git", + "url" : "http://github.com/creationix/step.git" + }, + "main": "lib/step" +} diff --git a/node_modules/mongodb/deps/step/test/callbackTest.js b/node_modules/mongodb/deps/step/test/callbackTest.js new file mode 100644 index 0000000..2fc2351 --- /dev/null +++ b/node_modules/mongodb/deps/step/test/callbackTest.js @@ -0,0 +1,26 @@ +require('./helper'); + +var selfText = fs.readFileSync(__filename, 'utf8'); + +// This example tests passing async results and sync results to the next layer + +expect('one'); +expect('two'); +expect('three'); +Step( + function readSelf() { + fulfill("one"); + fs.readFile(__filename, 'utf8', this); + }, + function capitalize(err, text) { + fulfill("two"); + if (err) throw err; + assert.equal(selfText, text, "Text Loaded"); + return text.toUpperCase(); + }, + function showIt(err, newText) { + fulfill("three"); + if (err) throw err; + assert.equal(selfText.toUpperCase(), newText, "Text Uppercased"); + } +); diff --git a/node_modules/mongodb/deps/step/test/errorTest.js b/node_modules/mongodb/deps/step/test/errorTest.js new file mode 100644 index 0000000..30af683 --- /dev/null +++ b/node_modules/mongodb/deps/step/test/errorTest.js @@ -0,0 +1,27 @@ +require('./helper'); + +var exception = new Error('Catch me!'); + +expect('one'); +expect('timeout'); +expect('two'); +expect('three'); +Step( + function () { + fulfill('one'); + var callback = this; + setTimeout(function () { + fulfill('timeout'); + callback(exception); + }, 0); + }, + function (err) { + fulfill('two'); + assert.equal(exception, err, "error should passed through"); + throw exception; + }, + function (err) { + fulfill('three'); + assert.equal(exception, err, "error should be caught"); + } +); diff --git a/node_modules/mongodb/deps/step/test/fnTest.js b/node_modules/mongodb/deps/step/test/fnTest.js new file mode 100644 index 0000000..1964a35 --- /dev/null +++ b/node_modules/mongodb/deps/step/test/fnTest.js @@ -0,0 +1,21 @@ +require('./helper'); + + +var myfn = Step.fn( + function (name) { + fs.readFile(name, 'utf8', this); + }, + function capitalize(err, text) { + if (err) throw err; + return text.toUpperCase(); + } +); + +var selfText = fs.readFileSync(__filename, 'utf8'); + +expect('result'); +myfn(__filename, function (err, result) { + fulfill('result'); + if (err) throw err; + assert.equal(selfText.toUpperCase(), result, "It should work"); +}); diff --git a/node_modules/mongodb/deps/step/test/groupTest.js b/node_modules/mongodb/deps/step/test/groupTest.js new file mode 100644 index 0000000..c1124ab --- /dev/null +++ b/node_modules/mongodb/deps/step/test/groupTest.js @@ -0,0 +1,102 @@ +require('./helper'); + +var dirListing = fs.readdirSync(__dirname), + dirResults = dirListing.map(function (filename) { + return fs.readFileSync(__dirname + "/" + filename, 'utf8'); + }); + +expect('one'); +expect('two'); +expect('three'); +Step( + function readDir() { + fulfill('one'); + fs.readdir(__dirname, this); + }, + function readFiles(err, results) { + fulfill('two'); + if (err) throw err; + // Create a new group + assert.deepEqual(dirListing, results); + var group = this.group(); + results.forEach(function (filename) { + if (/\.js$/.test(filename)) { + fs.readFile(__dirname + "/" + filename, 'utf8', group()); + } + }); + }, + function showAll(err , files) { + fulfill('three'); + if (err) throw err; + assert.deepEqual(dirResults, files); + } +); + +expect('four'); +expect('five'); +// When the group is empty, it should fire with an empty array +Step( + function start() { + var group = this.group(); + fulfill('four'); + }, + function readFiles(err, results) { + if (err) throw err; + fulfill('five'); + assert.deepEqual(results, []); + } +); + +// Test lock functionality with N sized groups +expect("test3: 1"); +expect("test3: 1,2,3"); +expect("test3: 2"); +Step( + function() { + return 1; + }, + function makeGroup(err, num) { + if(err) throw err; + fulfill("test3: " + num); + var group = this.group(); + + setTimeout((function(callback) { return function() { callback(null, 1); } })(group()), 100); + group()(null, 2); + setTimeout((function(callback) { return function() { callback(null, 3); } })(group()), 0); + }, + function groupResults(err, results) { + if(err) throw err; + fulfill("test3: " + results); + return 2 + }, + function terminate(err, num) { + if(err) throw err; + fulfill("test3: " + num); + } +); + +// Test lock functionality with zero sized groups +expect("test4: 1"); +expect("test4: empty array"); +expect("test4: group of zero terminated"); +expect("test4: 2"); +Step( + function() { + return 1; + }, + function makeGroup(err, num) { + if(err) throw err; + fulfill("test4: " + num); + this.group(); + }, + function groupResults(err, results) { + if(err) throw err; + if(results.length === 0) { fulfill("test4: empty array"); } + fulfill('test4: group of zero terminated'); + return 2 + }, + function terminate(err, num) { + if(err) throw err; + fulfill("test4: " + num); + } +); \ No newline at end of file diff --git a/node_modules/mongodb/deps/step/test/helper.js b/node_modules/mongodb/deps/step/test/helper.js new file mode 100644 index 0000000..bd4ca8e --- /dev/null +++ b/node_modules/mongodb/deps/step/test/helper.js @@ -0,0 +1,17 @@ +global.assert = require('assert'); +global.fs = require('fs'); +global.Step = require('../lib/step'); + +// A mini expectations module to ensure expected callback fire at all. +var expectations = {}; +global.expect = function expect(message) { + expectations[message] = new Error("Missing expectation: " + message); +} +global.fulfill = function fulfill(message) { + delete expectations[message]; +} +process.addListener('exit', function () { + Object.keys(expectations).forEach(function (message) { + throw expectations[message]; + }); +}); diff --git a/node_modules/mongodb/deps/step/test/parallelTest.js b/node_modules/mongodb/deps/step/test/parallelTest.js new file mode 100644 index 0000000..baba74e --- /dev/null +++ b/node_modules/mongodb/deps/step/test/parallelTest.js @@ -0,0 +1,49 @@ +require('./helper'); + +var selfText = fs.readFileSync(__filename, 'utf8'), + etcText = fs.readFileSync('/etc/passwd', 'utf8'); + +expect('one'); +expect('two'); +Step( + // Loads two files in parallel + function loadStuff() { + fulfill('one'); + fs.readFile(__filename, this.parallel()); + fs.readFile("/etc/passwd", this.parallel()); + }, + // Show the result when done + function showStuff(err, code, users) { + fulfill('two'); + if (err) throw err; + assert.equal(selfText, code, "Code should come first"); + assert.equal(etcText, users, "Users should come second"); + } +); + +// Test lock functionality with N parallel calls +expect("test2: 1"); +expect("test2: 1,2,3"); +expect("test2: 2"); +Step( + function() { + return 1; + }, + function makeParallelCalls(err, num) { + if(err) throw err; + fulfill("test2: " + num); + + setTimeout((function(callback) { return function() { callback(null, 1); } })(this.parallel()), 100); + this.parallel()(null, 2); + setTimeout((function(callback) { return function() { callback(null, 3); } })(this.parallel()), 0); + }, + function parallelResults(err, one, two, three) { + if(err) throw err; + fulfill("test2: " + [one, two, three]); + return 2 + }, + function terminate(err, num) { + if(err) throw err; + fulfill("test2: " + num); + } +) \ No newline at end of file diff --git a/node_modules/mongodb/docs/README.md b/node_modules/mongodb/docs/README.md new file mode 100644 index 0000000..6bae039 --- /dev/null +++ b/node_modules/mongodb/docs/README.md @@ -0,0 +1,14 @@ +node-mongodb-native +=================== + +Select a topic of interest for detailed description: + + * [Database](https://github.com/christkv/node-mongodb-native/tree/master/docs/database.md) + * [Collections](https://github.com/christkv/node-mongodb-native/tree/master/docs/collections.md) + * [Querying documents](https://github.com/christkv/node-mongodb-native/tree/master/docs/queries.md) + * [Inserting/updating documents](https://github.com/christkv/node-mongodb-native/tree/master/docs/insert.md) + * [GridStore](https://github.com/christkv/node-mongodb-native/tree/master/docs/gridfs.md) + * [Indexes](https://github.com/christkv/node-mongodb-native/tree/master/docs/indexes.md) + * [Replicasets](https://github.com/christkv/node-mongodb-native/tree/master/docs/replicaset.md) + +This documentation is incomplete, the best source for documentation on all possible methods is [the source for node-mongodb-native](https://github.com/christkv/node-mongodb-native) and [the MongoDB manual](http://www.mongodb.org/display/DOCS/Manual). \ No newline at end of file diff --git a/node_modules/mongodb/docs/collections.md b/node_modules/mongodb/docs/collections.md new file mode 100644 index 0000000..2fb4bd5 --- /dev/null +++ b/node_modules/mongodb/docs/collections.md @@ -0,0 +1,112 @@ +Collections +=========== + +See also: + + * [Database](database.md) + * [Queries](queries.md) + +## Collection objects + +Collection obejct is a pointer to a specific collection in the [database](database.md). If you want to [insert](insert.md) new records or +[query](queries.md) existing ones then you need to have a valid collection object. + +**NB** Collection names can't start or end with a period nor contain a dollar sign! (`.tes$t` is not allowed) + +## Creating collections + +Collections can be created with `createCollection` + + db.createCollection(name, callback) + +where `name` is the name of the collection and `callback` is a callback function. `db` is the database object. + +The first parameter for +the callback is the error object (null if no error) and the second one is the pointer to the newly created +collection. If strict mode is on and the table exists, the operation yields in error. With strict mode off (default) +the function simple returns the pointer to the existing collection and does not truncate it. + + db.createCollection("test", function(err, collection){ + collection.insert({"test":"value"}); + }); + +### Collection properties + + * `collectionName` is the name of the collection (not including the database name as a prefix) + * `db` is the pointer to the corresponding databse object + +Example of usage: + + console.log("Collection name: "+collection.collectionName) + +## List existing collections + +### List names + +Collections can be listed with `collectionNames` + + db.collectionNames(callback); + +`callback` gets two parameters - an error object (if error occured) and an array of collection names as strings. + +Collection names also include database name, so a collection named `posts` in a database `blog` will be listed as `blog.posts`. + +Additionally there's system collections which should not be altered without knowing exactly what you are doing, these sollections +can be identified with `system` prefix. For example `posts.system.indexes`. + +Example: + + + var mongodb = require("mongodb"), + mongoserver = new mongodb.Server("localhost"), + db_connector = new mongodb.Db("blog", mongoserver); + + db_connector.open(function(err, db){ + db.collectionNames(function(err, collections){ + console.log(collections); // ["blog.posts", "blog.system.indexes"] + }); + }); + +## List collections + +Collection objects can be listed with database method `collections` + + db.collections(callback) + +Where `callback` gets two parameters - an error object (if an error occured) and an array of collection objects. + +## Selecting collections + +Existing collections can be opened with `collection` + + db.collection("name", callback); + +If strict mode is off, then a new collection is created if not already present. + +## Renaming collections + +A collection can be renamed with collection method `rename` + + collection.rename(new_name, callback); + +## Removing records from collections + +Records can be erased from a collection with `remove` + + collection.remove([[query[, options]], callback]); + +Where + + * `query` is the query that records to be removed need to match. If not set all records will be removed + * `options` indicate advanced options. For example use `{safe: true}` when using callbacks + * `callback` callback function that gets two parameters - an error object (if an error occured) and the count of removed records + +## Removing collections + +A collection can be dropped with `drop` + + collection.drop(callback); + +or with `dropCollection` + + db.dropCollection(collection_name, callback) \ No newline at end of file diff --git a/node_modules/mongodb/docs/database.md b/node_modules/mongodb/docs/database.md new file mode 100644 index 0000000..c628912 --- /dev/null +++ b/node_modules/mongodb/docs/database.md @@ -0,0 +1,101 @@ +Database +======== + +The first thing to do in order to make queries to the database is to open one. This can be done with the `Db` constructor. + + var mongodb = require("mongodb"), + mongoserver = new mongodb.Server(host, port, server_options), + db_connector = new mongodb.Db(name, mongoserver, db_options); + + db_connector.open(callback); + + * `host` is a server hostname or IP + * `port` is a MongoDB port, use `mongodb.Connection.DEFAULT_PORT` for default (27017) + * `server_options` see *Server options* + * `name` is the databse name that needs to be opened, database will be created automatically if it doesn't yet exist + * `db_options` see *DB options* + +## Server options +Several options can be passed to the `Server` constructor with `options` parameter. + + * `auto_reconnect` - to reconnect automatically, default is false + * `poolSize` - specify the number of connections in the pool, default is 1 + +## DB options + +Several options can be passed to the `Db` constructor with `options` parameter. + + * `native_parser` - if true, use native BSON parser + * `strict` - sets *strict mode*, if true then existing collections can't be "recreated" etc. + * `pk` - custom primary key factory to generate `_id` values (see Custom primary keys). + * `forceServerObjectId` - generation of objectid is delegated to the mongodb server instead of the driver. default is false + +## Opening a database + +Database can be opened with Db method `open`. + + db_connector.open(callback); + +`callback` is a callback function which gets 2 parameters - an error object (or null, if no errors occured) and a database object. + +Resulting database object can be used for creating and selecting [collections](collections.md). + + db_connector.open(function(err, db){ + db.collection(...); + }); + +### Database properties + + * `databaseName` is the name of the database + * `serverConfig` includes information about the server (`serverConfig.host', `serverConfig.port` etc.) + * `bson_serializer` points to the correct BSON serializer (native or non native, depending on the initial setup) for this connection + * `bson_deserializer` points to the correct BSON deserializer + * `state` indicates if the database is connected or not + * `strict` indicates if *strict mode* is on (true) or off (false, default) + * `version` indicates the version of the MongoDB database + +### Database events + + * `close` to indicate that the connection to the database was closed + +For example + + db.on("close", function(error){ + console.log("Connection to the database was closed!"); + }); + +NB! If `auto_reconnect` was set to true when creating the server, then the connection will be automatically reopened on next database operation. Nevertheless the `close` event will be fired. + +## Deleting a database + +To delete a database you need a pointer to it first. Deletion can be done with method `dropDatabase`. + + db_connector.open(function(err, db){ + db.dropDatabase() + }); + +## Custom primary keys + +Every record in the database has an unique primary key called `_id`. Default primary keys are 12 byte hashes but a custom key generator can be used for something else. If you set `_id` "by hand" when +inserting records then you can use whatever you want, primary key factory generates `_id` values only for records without ones. + +Example 1: No need to generate primary key, as its already defined: + + collection.insert({name:"Daniel", _id:"12345"}); + +Example 2: No primary key, so it needs to be generated before save: + + collectionn.insert({name:"Daniel"}); + +Custom primary key factory is actually an object with method `createPK` which returns a primary key. +The context (value for `this`) for `createPK` is left untouched. + + var CustomPKFactory = { + counter:0, + createPk: function() { + return ++this.counter; + } + } + + db_connector = new mongodb.Db(name, mongoserver, {pk: CustomPKFactory}); + diff --git a/node_modules/mongodb/docs/gridfs.md b/node_modules/mongodb/docs/gridfs.md new file mode 100644 index 0000000..9393c27 --- /dev/null +++ b/node_modules/mongodb/docs/gridfs.md @@ -0,0 +1,111 @@ +GridStore +====== + +GridFS is a scalable MongoDB *filesystem* for storing and retrieving large files. The default limit for a MongoDB record is +4 MB, so to store data that is larger than this limit, GridFS can be used. GridFS shards the data into smaller chunks automatically. +See [MongoDB documentation](http://www.mongodb.org/display/DOCS/GridFS+Specification) for details. + +GridStore is a single file inside GridFS that can be managed by the script. + +## Open GridStore + +Opening a GridStore (a single file in GridFS) is a bit similar to opening a database. At first you need to create a GridStore object and then `open` it. + + var gs = new mongodb.GridStore(db, filename, mode[, options]) + +Where + + * `db` is the database object + * `filename` is the name of the file in GridFS that needs to be accessed/created + * `mode` indicates if this is a read (value `"r"`), write (`"w"`) or append (`"w+"`) operation + * `options` can be used to specify some metadata for the file, for example `content_type`, `metadata` and `chunk_size` + +Example: + + var gs = new mongodb.GridStore(db, "test.png", "w", { + "content_type": "image/png", + "metadata":{ + "author": "Daniel" + }, + "chunk_size": 1024*4 + }); + +When GridStore object is created, it needs to be opened + + gs.open(callback); + +`callback` gets two parameters - and error object (if error occured) and the GridStore object. + +Opened GridStore object has a set of useful properties + + * `gs.length` - length of the file in bytes + * `gs.contentType` - the content type for the file + * `gs.uploadDate` - when the file was uploaded + * `gs.metadata` - metadata that was saved with the file + * `gs.chunkSize` - chunk size + +Example + + gs.open(function(err, gs){ + console.log("this file was uploaded at "+gs.uploadDate); + }); + +## Writing to GridStore + +Writing can be done with `write` + + gs.write(data, callback) + +where `data` is a `Buffer` or a string, callback gets two parameters - an error object (if error occured) and result value which indicates if the write was successful or not. + +While the GridStore is not closed, every write is appended to the opened GridStore. + +## Reading from GridStore + +Reading from GridStore can be done with `read` + + gs.read([size[, offset]], callback) + +where + + * `size` is the length of the data to be read + * `offset` is the position to start reading + * `callback` is a callback function with two parameters - error object (if an error occured) and data (binary string) + +## Delete a GridStore + +GridStore files can be unlinked with `unlink` + + mongodb.GridStore.unlink(db, name, callback) + +Where + + * `db` is the databse object + * `name` is either the name of a GridStore object or an array of GridStore object names + * `callback` is the callback function + +## Closing the GridStore + +GridStore needs to be closed after usage. This can be done with `close` + + gs.close(callback) + +## Check the existance of a GridStore file + +Checking if a file exists in GridFS can be done with `exist` + + mongodb.GridStore.exist(db, filename, callback) + +Where + + * `db` is the database object + * `filename` is the name of the file to be checked + * `callback` is a callback function with two parameters - an error object (if an error occured) and a boolean value indicating if the file exists or not + +## Seeking in a GridStore + +Seeking can be done with `seek` + + gs.seek(position); + +This function moves the internal pointer to the specified position. \ No newline at end of file diff --git a/node_modules/mongodb/docs/indexes.md b/node_modules/mongodb/docs/indexes.md new file mode 100644 index 0000000..ebe20e5 --- /dev/null +++ b/node_modules/mongodb/docs/indexes.md @@ -0,0 +1,75 @@ +Indexes +======= + +Indexes are needed to make queries faster. For example if you need to find records by a field named *username* and +the field has a related index set, then the query will be a lot faster compared to if the index was not present. + +See [MongoDB documentation](http://www.mongodb.org/display/DOCS/Indexes) for details. + +## Create indexes with createIndex() + +`createIndex` adds a new index to a collection. For checking if the index was already set, use `ensureIndex` instead. + + collection.createIndex(index[, options], callback) + +or + + db.createIndex(collectionname, index[, options], callback) + +where + + * `index` is the field or fields to be indexed. See *index field* + * `options` are options, for example `{sparse: true}` to include only records that have indexed field set or `{unique: true}` for unique indexes. If the `options` is a boolean value, then it indicates if it's an unique index or not. + * `callback` gets two parameters - an error object (if an error occured) and the name for the newly created index + +## Ensure indexes with ensureIndex() + +Same as `createIndex` with the difference that the index is checked for existence before adding to avoid duplicate indexes. + +## Index field + +Index field can be a simple string like `"username"` to index certain field (in this case, a field named as *username*). + + collection.ensureIndex("username",callback) + +It is possible to index fields inside nested objects, for example `"user.firstname"` to index field named *firstname* inside a document named *user*. + + collection.ensureIndex("user.firstname",callback) + +It is also possible to create mixed indexes to include several fields at once. + + collection.ensureIndex({firstname:1, lastname:1}, callback) + +or with tuples + + collection.ensureIndex([["firstname", 1], ["lastname", 1]], callback) + +The number value indicates direction - if it's 1, then it is an ascending value, +if it's -1 then it's descending. For example if you have documents with a field *date* and you want to sort these records in descending order then you might want to add corresponding index + + collection.ensureIndex({date:-1}, callback) + +## Remove indexes with dropIndex() + +All indexes can be dropped at once with `dropIndexes` + + collection.dropIndexes(callback) + +`callback` gets two parameters - an error object (if an error occured) and a boolean value true if operation succeeded. + +## Get index information with indexInformation() + +`indexInformation` can be used to fetch some useful information about collection indexes. + + collection.indexInformation(callback) + +Where `callback` gets two parameters - an error object (if an error occured) and an index information object. + +The keys in the index object are the index names and the values are tuples of included fields. + +For example if a collection has two indexes - as a default an ascending index for the `_id` field and an additonal descending index for `"username"` field, then the index information object would look like the following + + { + "_id":[["_id", 1]], + "username_-1":[["username", -1]] + } \ No newline at end of file diff --git a/node_modules/mongodb/docs/insert.md b/node_modules/mongodb/docs/insert.md new file mode 100644 index 0000000..a05bf65 --- /dev/null +++ b/node_modules/mongodb/docs/insert.md @@ -0,0 +1,125 @@ +Inserting and updating +====================== + +See also: + + * [Database](database.md) + * [Collections](collections.md) + +## Insert + +Records can be inserted to a collection with `insert` + + collection.insert(docs[, options, callback]) + +Where + + * `docs` is a single document object or an array of documents + * `options` is an object of parameters, if you use a callback, set `safe` to true - this way the callback is executed *after* the record is saved to the database, if `safe` is false (default) callback is fired immediately and thus doesn't make much sense. + * `callback` - callback function to run after the record is inserted. Set `safe` to true in `options` when using callback. First parameter for callback + is the error object (if an error occured) and the second is an array of records inserted. + +For example + + var document = {name:"David", title:"About MongoDB"}; + collection.insert(document, {safe: true}, function(err, records){ + console.log("Record added as "+records[0]._id); + }); + +If trying to insert a record with an existing `_id` value, then the operation yields in error. + + collection.insert({_id:1}, {safe:true}, function(err, doc){ + // no error, inserted new document, with _id=1 + collection.insert({_id:1}, {safe:true}, function(err, doc){ + // error occured since _id=1 already existed + }); + }); + +## Save + +Shorthand for insert/update is `save` - if `_id` value set, the record is updated if it exists or inserted if it does not; if the `_id` value is not set, then the record is inserted as a new one. + + collection.save({_id:"abc", user:"David"},{safe:true}, callback) + +`callback` gets two parameters - an error object (if an error occured) and the record if it was inserted or `1` if the record was updated. + +## Update + +Updates can be done with `update` + + collection.update(criteria, update[, options[, callback]]); + +Where + + * `criteria` is a query object to find records that need to be updated (see [Queries](queries.md)) + * `update` is the replacement object + * `options` is an options object (see below) + * `callback` is the callback to be run after the records are updated. Has two parameters, the first is an error object (if error occured), the second is the count of records that were modified. + +### Update options + +There are several option values that can be used with an update + + * `safe` - run callback only after the update is done, defaults to false + * `multi` - update all records that match the query object, default is false (only the first one found is updated) + * `upsert` - if true and no records match the query, insert `update` as a new record + +### Replacement object + +If the replacement object is a document, the matching documents will be replaced (except the `_id` values if no `_id` is set). + + collection.update({_id:"123"}, {author:"Jessica", title:"Mongo facts"}); + +The example above will replace the document contents of id=123 with the replacement object. + +To update only selected fields, `$set` operator needs to be used. Following replacement object +replaces author value but leaves everything else intact. + + collection.update({_id:"123"}, {$set: {author:"Jessica"}}); + +See [MongoDB documentation](http://www.mongodb.org/display/DOCS/Updating) for all possible operators. + +## Find and Modify + +To update and retrieve the contents for one single record you can use `findAndModify`. + + collection.findAndModify(criteria, sort, update[, options, callback]) + +Where + + * `criteria` is the query object to find the record + * `sort` indicates the order of the matches if there's more than one matching record. The first record on the result set will be used. See [Queries->find->options->sort](queries.md) for the format. + * `update` is the replacement object + * `options` define the behavior of the function + * `callback` is the function to run after the update is done. Has two parameters - error object (if error occured) and the record that was updated. + +### Options + +Options object can be used for the following options: + + * `remove` - if set to true (default is false), removes the record from the collection. Callback function still gets the object but it doesn't exist in the collection any more. + * `new` - if set to true, callback function returns the modified record. Default is false (original record is returned) + * `upsert` - if set to true and no record matched to the query, replacement object is inserted as a new record + +### Example + + var mongodb = require('mongodb'), + server = new mongodb.Server("127.0.0.1", 27017, {}); + + new mongodb.Db('test', server, {}).open(function (error, client) { + if (error) throw error; + var collection = new mongodb.Collection(client, 'test_collection'); + collection.findAndModify( + {hello: 'world'}, // query + [['_id','asc']], // sort order + {$set: {hi: 'there'}}, // replacement, replaces only the field "hi" + {}, // options + function(err, object) { + if (err){ + console.warn(err.message); + }else{ + console.dir(object); // undefined if no matching object exists. + } + }); + }); + \ No newline at end of file diff --git a/node_modules/mongodb/docs/queries.md b/node_modules/mongodb/docs/queries.md new file mode 100644 index 0000000..707571b --- /dev/null +++ b/node_modules/mongodb/docs/queries.md @@ -0,0 +1,278 @@ +Queries +======= + +See also: + + * [Database](database.md) + * [Collections](collections.md) + +## Making queries with find() + +[Collections](collections.md) can be queried with `find`. + + collection.find(query[[[, fields], options], callback]); + +Where + + * `query` - is a query object, defining the conditions the documents need to apply + * `fields` - indicates which fields should be included in the response (default is all) + * `options` - defines extra logic (sorting options, paging etc.) + +The result for the query is actually a cursor object. This can be used directly or converted to an array. + + var cursor = collection.find({}); + cursor.each(...); + +To indicate which fields must or must no be returned `fields` value can be used. For example the following `fields` value + + { + "name": true, + "title": true + } + +retrieves fields `name` and `title` (and as a default also `_id`) but not any others. + +## Find first occurence with findOne() + +`findOne` is a convinence method finding and returning the first match of a query while regular `find` returns a cursor object instead. +Use it when you expect only one record, for example when querying with `_id` or another unique property. + + collection.findOne([query], callback) + +Where + + * `query` is a query object or an `_id` value + * `callback` has two parameters - an error object (if an error occured) and the document object. + +Example: + + collection.findOne({_id: doc_id}, function(err, document) { + console.log(document.name); + }); + +## _id values + +Default `_id` values are 12 byte binary hashes. You can alter the format with custom Primary Key factories (see *Custom Primarky Keys* in [Database](database.md)). + +In order to treat these binary _id values as strings it would be wise to convert binary values to hex strings. This can be done with `toHexString` property. + + var idHex = document._id.toHexString(); + +Hex strings can be reverted back to binary (for example to perform queries) with `db.bson_serializer.ObjectID.createFromHexString` + + {_id: db.bson_serializer.ObjectID.createFromHexString(idHex)} + +When inserting new records it is possible to use custom `_id` values as well which do not need to be binary hashes, for example strings. + + collection.insert({_id: "abc", ...}); + collection.findOne({_id: "abc"},...); + +This way it is not necessary to convert `_id` values to hex strings and back. + +## Query object + +The simplest query object is an empty one `{}` which matches every record in the database. + +To make a simple query where one field must match to a defined value, one can do it as simply as + + {fieldname: "fieldvalue"} + +This query matches all the records that a) have fields called *fieldname* and b) its value is *"fieldvalue"*. + +For example if we have a collection of blog posts where the structure of the +records is `{title, author, contents}` and we want +to retrieve all the posts for a specific author then we can do it like this: + + posts = pointer_to_collection; + posts.find({author:"Daniel"}).toArray(function(err, results){ + console.log(results); // output all records + }); + +If the queried field is inside an object then that can be queried also. For example if we have a record with the following structure: + + { + user: { + name: "Daniel" + } + } + +Then we can query the "name" field like this: `{"user.name":"Daniel"}` + +### AND + +If more than one fieldname is specified, then it's an AND query + + { + key1: "value1", + name2: "value2" + } + +Whis query matches all records where *key1* is *"value1"* and *key2* is *"value2"* + +### OR + +OR queries are a bit trickier but doable with the `$or` operator. Query operator takes an array which includes +a set of query objects and at least one of these must match a document before it is retrieved + + { + $or:[ + {author:"Daniel"}, + {author:"Jessica"} + ] + } + +This query match all the documents where author is Daniel or Jessica. + +To mix AND and OR queries, you just need to use $or as one of regular query fields. + + { + title:"MongoDB", + $or:[ + {author:"Daniel"}, + {author:"Jessica"} + ] + } + +### Conditionals + +Conditional operators `<`, `<=`, `>`, `>=` and `!=` can't be used directly, as the query object format doesn't support it but the same +can be achieved with their aliases `$lt`, `$lte`, `$gt`, `$gte` and `$ne`. When a field value needs to match a conditional, the value +must be wrapped into a separate object. + + {"fieldname":{$gte:100}} + +This query defines that *fieldname* must be greater than or equal to `100`. + +Conditionals can also be mixed to create ranges. + + {"fieldname": {$lte:10, $gte:100}} + +### Regular expressions in queries + +Queried field values can also be matched with regular expressions + + {author:/^Daniel/} + +### Special query operators + +In addition to OR and conditional there's some more operators: + + * `$in` - specifies an array of possible matches, `{"name":{$in:[1,2,3]}}` + * `$nin` - specifies an array of unwanted matches + * `$all` - array value must match to the condition `{"name":{$all:[1,2,3]}}` + * `$exists` - checks for existence of a field `{"name":{$exists:true}}` + * `$mod` - check for a modulo `{"name":{$mod:{3,2}}` is the same as `"name" % 3 == 2` + * `$size` - checks the size of an array value `{"name": {$size:2}}` matches arrays *name* with 2 elements + + +## Queries inside objects and arrays + +If you have a document with nested objects/arrays then the keys inside these nested objects can still be used for queries. + +For example with the following document + + { + "_id": idvalue, + "author":{ + "firstname":"Daniel", + "lastname": "Defoe" + }, + "books":[ + { + "title":"Robinson Crusoe" + "year": 1714 + } + ] + } + +not only the `_id` field can be used as a query field - also the `firstname` and even `title` can be used. This can be done when +using nested field names as strings, concated with periods. + + collection.find({"author.firstname":"Daniel}) + +Works even inside arrays + + collection.find({"books.year":1714}) + +## Query options + +Query options define the behavior of the query. + + var options = { + "limit": 20, + "skip": 10, + "sort": title + } + + collection.find({}, options).toArray(...); + +### Paging + +Paging can be achieved with option parameters `limit` and `skip` + + { + "limit": 20, + "skip" 10 + } + +retrieves 10 elements starting from 20 + +### Sorting + +Sorting can be acieved with option parameter `sort` which takes an array of sort preferences + + { + "sort": [['field1','asc'], ['field2','desc']] + } + +With single ascending field the array can be replaced with the name of the field. + + { + "sort": "name" + } + +### Explain + +Option parameter `explain` turns the query into an explain query. + +## Cursors + +Cursor objects are the results for queries and can be used to fetch individual fields from the database. + +### nextObject + +`cursor.nextObject(function(err, doc){})` retrieves the next record from database. If doc is null, then there weren't any more records. + +### each + +`cursor.each(function(err, doc){})` retrieves all matching records one by one. + +### toArray + +`cursor.toArray(function(err, docs){})` converts the cursor object into an array of all the matching records. Probably the +most convenient way to retrieve results but be careful with large datasets as every record is loaded into memory. + + collection.find().toArray(function(err, docs){ + console.log("retrieved records:"); + console.log(docs); + }); + +### rewind + +`cursor.rewind()` resets the internal pointer in the cursor to the beginning. + +## Counting matches + +Counting total number of found matches can be done against cursors with method `count`. + + cursor.count(callback) + +Where + + * `callback` is the callback function with two parameters - an error object (if an error occured) and the number on matches as an integer. + +Example + + cursor.count(function(err, count){ + console.log("Total matches: "+count); + }); diff --git a/node_modules/mongodb/docs/replicaset.md b/node_modules/mongodb/docs/replicaset.md new file mode 100644 index 0000000..64d5423 --- /dev/null +++ b/node_modules/mongodb/docs/replicaset.md @@ -0,0 +1,40 @@ +Replicasets +=========== + +## Introduction + +Replica sets is the asynchronous master/slave replication added to Mongodb that takes care off all the failover and recovery for the member nodes. According to the mongodb documentation a replicaset is + + * Two or more nodes that are copies of each other + * Automatic assignment of a primary(master) node if none is available + * Drivers that automatically detect the new master and send writes to it + +More information at [Replicasets](http://www.mongodb.org/display/DOCS/Replica+Sets) + +## Driver usage + +To create a new replicaset follow the instructions on the mongodb site to setup the config and the replicaset instances. Then using the driver. + + var replSet = new ReplSetServers( [ + new Server( 127.0.0.1, 30000, { auto_reconnect: true } ), + new Server( 127.0.0.1, 30001, { auto_reconnect: true } ), + new Server( 127.0.0.1, 30002, { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + // Do you app stuff :) + }) + +The ReplSetSrvers object has the following parameters + + var replSet = new ReplSetSrvers(servers, options) + +Where + + * `servers` is an array of `Server` objects + * `options` can contain the following options + * `rs_name` is the name of the replicaset you configured when you started the server, you can have multiple replicasets running on your servers. + * `read_secondary` set's the driver to read from secondary servers (slaves) instead of only from the primary(master) server. diff --git a/node_modules/mongodb/examples/admin.js b/node_modules/mongodb/examples/admin.js new file mode 100644 index 0000000..5bcfcdb --- /dev/null +++ b/node_modules/mongodb/examples/admin.js @@ -0,0 +1,62 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +debug = require('util').debug, +inspect = require('util').inspect, +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + // BSON = require('../lib/mongodb').BSONPure; + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +sys.puts("Connecting to " + host + ":" + port); +var db = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db.open(function(err, db) { + db.dropDatabase(function(err, result){ + db.dropCollection('test', function(err, result) { + db.createCollection('test', function(err, collection) { + + // Erase all records in collection + collection.remove({}, function(err, r) { + db.admin(function(err, admin) { + + // Profiling level set/get + admin.profilingLevel(function(err, profilingLevel) { + sys.puts("Profiling level: " + profilingLevel); + }); + + // Start profiling everything + admin.setProfilingLevel('all', function(err, level) { + sys.puts("Profiling level: " + level); + + // Read records, creating a profiling event + collection.find(function(err, cursor) { + cursor.toArray(function(err, items) { + // Stop profiling + admin.setProfilingLevel('off', function(err, level) { + // Print all profiling info + admin.profilingInfo(function(err, info) { + sys.puts(sys.inspect(info)); + + // Validate returns a hash if all is well or return an error hash if there is a + // problem. + admin.validateCollection(collection.collectionName, function(err, result) { + sys.puts(result.result); + db.close(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/node_modules/mongodb/examples/blog.js b/node_modules/mongodb/examples/blog.js new file mode 100644 index 0000000..f9340fa --- /dev/null +++ b/node_modules/mongodb/examples/blog.js @@ -0,0 +1,109 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + // BSON = require('../lib/mongodb').BSONPure; + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +var LINE_SIZE = 120; + +sys.puts("Connecting to " + host + ":" + port); +var db = new Db('node-mongo-blog', new Server(host, port, {}), {native_parser:true}); +db.open(function(err, db) { + db.dropDatabase(function(err, result) { + sys.puts("==================================================================================="); + sys.puts(">> Adding Authors"); + db.collection('authors', function(err, collection) { + collection.createIndex(["meta", ['_id', 1], ['name', 1], ['age', 1]], function(err, indexName) { + sys.puts("==================================================================================="); + var authors = {}; + + // Insert authors + collection.insert([{'name':'William Shakespeare', 'email':'william@shakespeare.com', 'age':587}, + {'name':'Jorge Luis Borges', 'email':'jorge@borges.com', 'age':123}], function(err, docs) { + docs.forEach(function(doc) { + sys.puts(sys.inspect(doc)); + authors[doc.name] = doc; + }); + }); + + sys.puts("==================================================================================="); + sys.puts(">> Authors ordered by age ascending"); + sys.puts("==================================================================================="); + collection.find({}, {'sort':[['age', 1]]}, function(err, cursor) { + cursor.each(function(err, author) { + if(author != null) { + sys.puts("[" + author.name + "]:[" + author.email + "]:[" + author.age + "]"); + } else { + sys.puts("==================================================================================="); + sys.puts(">> Adding users"); + sys.puts("==================================================================================="); + db.collection('users', function(err, userCollection) { + var users = {}; + + userCollection.insert([{'login':'jdoe', 'name':'John Doe', 'email':'john@doe.com'}, + {'login':'lsmith', 'name':'Lucy Smith', 'email':'lucy@smith.com'}], function(err, docs) { + docs.forEach(function(doc) { + sys.puts(sys.inspect(doc)); + users[doc.login] = doc; + }); + }); + + sys.puts("==================================================================================="); + sys.puts(">> Users ordered by login ascending"); + sys.puts("==================================================================================="); + userCollection.find({}, {'sort':[['login', 1]]}, function(err, cursor) { + cursor.each(function(err, user) { + if(user != null) { + sys.puts("[" + user.login + "]:[" + user.name + "]:[" + user.email + "]"); + } else { + sys.puts("==================================================================================="); + sys.puts(">> Adding articles"); + sys.puts("==================================================================================="); + db.collection('articles', function(err, articlesCollection) { + articlesCollection.insert([ + { 'title':'Caminando por Buenos Aires', + 'body':'Las callecitas de Buenos Aires tienen ese no se que...', + 'author_id':authors['Jorge Luis Borges']._id}, + { 'title':'I must have seen thy face before', + 'body':'Thine eyes call me in a new way', + 'author_id':authors['William Shakespeare']._id, + 'comments':[{'user_id':users['jdoe']._id, 'body':"great article!"}] + } + ], function(err, docs) { + docs.forEach(function(doc) { + sys.puts(sys.inspect(doc)); + }); + }) + + sys.puts("==================================================================================="); + sys.puts(">> Articles ordered by title ascending"); + sys.puts("==================================================================================="); + articlesCollection.find({}, {'sort':[['title', 1]]}, function(err, cursor) { + cursor.each(function(err, article) { + if(article != null) { + sys.puts("[" + article.title + "]:[" + article.body + "]:[" + article.author_id.toHexString() + "]"); + sys.puts(">> Closing connection"); + db.close(); + } + }); + }); + }); + } + }); + }); + }); + } + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/node_modules/mongodb/examples/capped.js b/node_modules/mongodb/examples/capped.js new file mode 100644 index 0000000..07bf75f --- /dev/null +++ b/node_modules/mongodb/examples/capped.js @@ -0,0 +1,34 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + // BSON = require('../lib/mongodb').BSONPure; + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +sys.puts("Connecting to " + host + ":" + port); +var db = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db.open(function(err, db) { + db.dropCollection('test', function(err, result) { + // A capped collection has a max size and optionally a max number of records. + // Old records get pushed out by new ones once the size or max num records is + // reached. + db.createCollection('test', {'capped':true, 'size':1024, 'max':12}, function(err, collection) { + for(var i = 0; i < 100; i++) { collection.insert({'a':i}); } + + // We will only see the last 12 records + collection.find(function(err, cursor) { + cursor.toArray(function(err, items) { + sys.puts("The number of records: " + items.length); + db.close(); + }) + }) + }); + }); +}); \ No newline at end of file diff --git a/node_modules/mongodb/examples/cursor.js b/node_modules/mongodb/examples/cursor.js new file mode 100644 index 0000000..6ee3462 --- /dev/null +++ b/node_modules/mongodb/examples/cursor.js @@ -0,0 +1,76 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + // BSON = require('../lib/mongodb').BSONPure; + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +sys.puts("Connecting to " + host + ":" + port); +var db = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db.open(function(err, db) { + db.collection('test', function(err, collection) { + // Erase all records from collection, if any + collection.remove(function(err, collection) { + + // Insert 3 records + for(var i = 0; i < 3; i++) { + collection.insert({'a':i}); + } + + // Cursors don't run their queries until you actually attempt to retrieve data + // from them. + + // Find returns a Cursor, which is Enumerable. You can iterate: + collection.find(function(err, cursor) { + cursor.each(function(err, item) { + if(item != null) sys.puts(sys.inspect(item)); + }); + }); + + // You can turn it into an array + collection.find(function(err, cursor) { + cursor.toArray(function(err, items) { + sys.puts("count: " + items.length); + }); + }); + + // You can iterate after turning it into an array (the cursor will iterate over + // the copy of the array that it saves internally.) + collection.find(function(err, cursor) { + cursor.toArray(function(err, items) { + cursor.each(function(err, item) { + if(item != null) sys.puts(sys.inspect(item)); + }); + }); + }); + + // You can get the next object + collection.find(function(err, cursor) { + cursor.nextObject(function(err, item) { + if(item != null) sys.puts(sys.inspect(item)); + }); + }); + + // next_object returns null if there are no more objects that match + collection.find(function(err, cursor) { + cursor.nextObject(function(err, item) { + cursor.nextObject(function(err, item) { + cursor.nextObject(function(err, item) { + cursor.nextObject(function(err, item) { + sys.puts("nextObject returned: " + sys.inspect(item)); + db.close(); + }); + }); + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/node_modules/mongodb/examples/gridfs.js b/node_modules/mongodb/examples/gridfs.js new file mode 100644 index 0000000..a2f0084 --- /dev/null +++ b/node_modules/mongodb/examples/gridfs.js @@ -0,0 +1,156 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + GridStore = require('../lib/mongodb').GridStore, + // BSON = require('../lib/mongodb').BSONPure; + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +sys.puts(">> Connecting to " + host + ":" + port); +var db1 = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db1.open(function(err, db) { + // Write a new file + var gridStore = new GridStore(db, "foobar", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello world!", function(err, gridStore) { + gridStore.close(function(err, result) { + // Read the file and dump the contents + dump(db, 'foobar'); + + // Append more data + gridStore = new GridStore(db, 'foobar', "w+"); + gridStore.open(function(err, gridStore) { + gridStore.write('\n', function(err, gridStore) { + gridStore.puts('line two', function(err, gridStore) { + gridStore.close(function(err, result) { + dump(db, 'foobar'); + + // Overwrite + gridStore = new GridStore(db, 'foobar', "w"); + gridStore.open(function(err, gridStore) { + gridStore.write('hello, sailor!', function(err, gridStore) { + gridStore.close(function(err, result) { + dump(db, 'foobar', function() { + db.close(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); +}); + +var db2 = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db2.open(function(err, db) { + // File existence tests + var gridStore = new GridStore(db, "foobar2", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write( 'hello sailor', function(err, gridStore) { + gridStore.close(function(err, result) { + GridStore.exist(db, 'foobar2', function(err, result) { + sys.puts("File 'foobar2' exists: " + result); + }); + + GridStore.exist(db, 'does-not-exist', function(err, result) { + sys.puts("File 'does-not-exist' exists: " + result); + }); + + // Read with offset(uses seek) + GridStore.read(db, 'foobar2', 6, 7, function(err, data) { + sys.puts(data); + }); + + // Rewind/seek/tell + var gridStore2 = new GridStore(db, 'foobar2', 'w'); + gridStore2.open(function(err, gridStore) { + gridStore.write('hello, world!', function(err, gridStore){}); + gridStore.rewind(function(){}); + gridStore.write('xyzzz', function(err, gridStore){}); + gridStore.tell(function(tell) { + sys.puts("tell: " + tell); // Should be 5 + }); + gridStore.seek(4, function(err, gridStore){}); + gridStore.write('y', function(){}); + gridStore.close(function() { + dump(db, 'foobar2'); + + // Unlink file (delete) + GridStore.unlink(db, 'foobar2', function(err, gridStore) { + GridStore.exist(db, 'foobar2', function(err, result) { + sys.puts("File 'foobar2' exists: " + result); + db.close(); + }); + }); + }); + }); + }); + }); + }); +}); + +var db3 = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db3.open(function(err, db) { + // Metadata + var gridStore = new GridStore(db, "foobar3", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write('hello, world!', function(err, gridStore){}); + gridStore.close(function(err, gridStore) { + gridStore = new GridStore(db, 'foobar3', "r"); + gridStore.open(function(err, gridStore) { + sys.puts("contentType: " + gridStore.contentType); + sys.puts("uploadDate: " + gridStore.uploadDate); + sys.puts("chunkSize: " + gridStore.chunkSize); + sys.puts("metadata: " + gridStore.metadata); + }); + + // Add some metadata + gridStore = new GridStore(db, 'foobar3', "w+"); + gridStore.open(function(err, gridStore) { + gridStore.contentType = 'text/xml'; + gridStore.metadata = {'a':1}; + gridStore.close(function(err, gridStore) { + // Print the metadata + gridStore = new GridStore(db, 'foobar3', "r"); + gridStore.open(function(err, gridStore) { + sys.puts("contentType: " + gridStore.contentType); + sys.puts("uploadDate: " + gridStore.uploadDate); + sys.puts("chunkSize: " + gridStore.chunkSize); + sys.puts("metadata: " + gridStore.metadata); + db.close(); + }); + }); + }); + }); + }); + + // You can also set meta data when initially writing to a file + // setting root means that the file and its chunks are stored in a different root + // collection: instead of gridfs.files and gridfs.chunks, here we use + // my_files.files and my_files.chunks + var gridStore = new GridStore(db, "foobar3", "w", {'content_type':'text/plain', + 'metadata':{'a':1}, 'chunk_size': 1024*4, 'root':'my_files'}); + gridStore.open(function(err, gridStore) { + gridStore.write('hello, world!', function(err, gridStore){}); + gridStore.close(function() { + }); + }); +}); + +function dump(db, filename, callback) { + GridStore.read(db, filename, function(err, data) { + sys.puts(data); + if(callback != null) callback(); + }); +} \ No newline at end of file diff --git a/node_modules/mongodb/examples/index_test.js b/node_modules/mongodb/examples/index_test.js new file mode 100644 index 0000000..d762c80 --- /dev/null +++ b/node_modules/mongodb/examples/index_test.js @@ -0,0 +1,66 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + // BSON = require('../lib/mongodb').BSONPure; + BSON = require('../lib/mongodb').BSONNative; + +var mongo = require('../lib/mongodb'), + Integer = require('../lib/mongodb/goog/math/integer').Integer; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +sys.puts(">> Connecting to " + host + ":" + port); +var db = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db.open(function(err, db) { + sys.puts(">> Dropping collection test"); + db.dropCollection('test', function(err, result) { + sys.puts("dropped: " + sys.inspect(result)); + }); + + sys.puts(">> Creating collection test"); + db.collection('test', function(err, collection) { + sys.puts("created: " + sys.inspect(collection)); + + var objectCount = 100; + var objects = []; + var messages = ["hola", "hello", "aloha", "ciao"]; + sys.puts(">> Generate test data"); + for(var i = 0; i < objectCount; i++) { + objects.push({'number':i, 'rndm':((5*Math.random()) + 1), 'msg':messages[Integer.fromNumber((4*Math.random())).toInt()]}) + } + sys.puts("generated"); + + sys.puts(">> Inserting data (" + objects.length + ")"); + collection.insert(objects); + sys.puts("inserted"); + + sys.puts(">> Creating index") + collection.createIndex([['all'], ['_id', 1], ['number', 1], ['rndm', 1], ['msg', 1]], function(err, indexName) { + sys.puts("created index: " + indexName); + + sys.puts(">> Gathering index information"); + + collection.indexInformation(function(err, doc) { + sys.puts("indexInformation: " + sys.inspect(doc)); + + sys.puts(">> Dropping index"); + collection.dropIndex('all_1__id_1_number_1_rndm_1_msg_1', function(err, result) { + sys.puts("dropped: " + sys.inspect(result)); + + sys.puts(">> Gathering index information"); + collection.indexInformation(function(err, doc) { + sys.puts("indexInformation: " + sys.inspect(doc)); + sys.puts(">> Closing connection"); + db.close(); + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/node_modules/mongodb/examples/info.js b/node_modules/mongodb/examples/info.js new file mode 100644 index 0000000..3ced907 --- /dev/null +++ b/node_modules/mongodb/examples/info.js @@ -0,0 +1,55 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + // BSON = require('../lib/mongodb').BSONPure; + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +sys.puts("Connecting to " + host + ":" + port); +var db = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db.open(function(err, db) { + db.collection('test', function(err, collection) { + + // Remove all existing documents in collection + collection.remove(function(err, collection) { + + // Insert 3 records + for(var i = 0; i < 3; i++) { + collection.insert({'a':i}); + } + + // Show collection names in the database + db.collectionNames(function(err, names) { + names.forEach(function(name) { + sys.puts(sys.inspect(name)); + }); + }); + + // More information about each collection + db.collectionsInfo(function(err, cursor) { + cursor.toArray(function(err, items) { + items.forEach(function(item) { + sys.puts(sys.inspect(item)); + }); + }); + }) + + // Index information + db.createIndex('test', 'a', function(err, indexName) { + db.indexInformation('test', function(err, doc) { + sys.puts(sys.inspect(doc)); + collection.drop(function(err, result) { + db.close(); + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/node_modules/mongodb/examples/oplog.js b/node_modules/mongodb/examples/oplog.js new file mode 100644 index 0000000..a27e503 --- /dev/null +++ b/node_modules/mongodb/examples/oplog.js @@ -0,0 +1,119 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + Cursor = require('../lib/mongodb').Cursor; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +Slave = function() { + this.running = false; + this.callbacks = []; + //no native_parser right now (because timestamps) + //no strict mode (because system db signed with $ db.js line 189) + //connect without dbName for querying not only "local" db + sys.puts("Connecting to " + host + ":" + port); + this.db = new Db('', new Server(host, port, {}), {}); +} + +//start watching +Slave.prototype.start = function() { + var self = this; + if (this.running) return; + + this.db.open(function(err, db) { + if (err) { + sys.puts('> MongoSlave error' + err); + process.exit(1); + } + + db.collection('local.oplog.$main', function(err, collection) { + if (! collection) { + sys.puts('> MongoSlave - local.oplog.$main not found'); + self.stop(); + return false; + } + + process.on('SIGINT', function () { + self.stop(); //tailable cursor should be stopped manually + }); + + //get last row for init TS + collection.find({}, {'limit': 1, 'sort': [['$natural', -1]]}, function(err, cursor) { + cursor.toArray(function(err, items) { + if (items.length) { + sys.puts('> MongoSlave started'); + self.running = true; + self._runSlave(collection, items[0]['ts']); + } else if (err) { + sys.puts(err); + self.stop(); + } + }); + }); + }); + }); +} + +//stop watching +Slave.prototype.stop = function() { + if (!this.running) return; + sys.puts('> MongoSlave stopped'); + this.running = false; + this.db.close(); +} + +Slave.prototype._runSlave = function(collection, time) { + + var self = this; + + //watch oplog INFINITE (until Slave.stop()) + collection.find({'ts': {'$gt': time}}, {'tailable': 1, 'sort': [['$natural', 1]]}, function(err, cursor) { + cursor.each(function(err, item) { + if (cursor.state == Cursor.CLOSED) { //broken cursor + self.running && self._runSlave(collection, time); + return; + } + time = item['ts']; + + switch(item['op']) { + case 'i': //inserted + self._emitObj(item['o']); + break; + case 'u': //updated + self.db.collection(item['ns'], function(err, collection) { + collection.findOne(item['o2']['_id'], {}, function(err, item) { + item && self._emitObj(item); + }); + }); + break; + case 'd': //deleted + //nothing to do + break; + } + }); + }); +} + +Slave.prototype._emitObj = function (obj) { + for(var i in this.callbacks) this.callbacks[i].call(this, obj); +} + +Slave.prototype.onObject = function(callback) { + this.callbacks.push(callback); +} + + +//just for example +var watcher = new Slave(); + +watcher.onObject(function(obj) { + sys.puts(sys.inspect(obj)); +}); + +watcher.start(); \ No newline at end of file diff --git a/node_modules/mongodb/examples/queries.js b/node_modules/mongodb/examples/queries.js new file mode 100644 index 0000000..934cff9 --- /dev/null +++ b/node_modules/mongodb/examples/queries.js @@ -0,0 +1,132 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + // BSON = require('../lib/mongodb').BSONPure; + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + + + +sys.puts("Connecting to " + host + ":" + port); + +var db = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db.open(function(err, db) { + db.dropDatabase(function() { + // Fetch the collection test + db.collection('test', function(err, collection) { + // Remove all records in collection if any + collection.remove(function(err, collection) { + // Insert three records + collection.insert([{'a':1}, {'a':2}, {'b':3}], function(docs) { + // Count the number of records + collection.count(function(err, count) { + sys.puts("There are " + count + " records."); + }); + + // Find all records. find() returns a cursor + collection.find(function(err, cursor) { + // Print each row, each document has an _id field added on insert + // to override the basic behaviour implement a primary key factory + // that provides a 12 byte value + sys.puts("Printing docs from Cursor Each") + cursor.each(function(err, doc) { + if(doc != null) sys.puts("Doc from Each " + sys.inspect(doc)); + }) + }); + // Cursor has an to array method that reads in all the records to memory + collection.find(function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Printing docs from Array") + docs.forEach(function(doc) { + sys.puts("Doc from Array " + sys.inspect(doc)); + }); + }); + }); + + // Different methods to access records (no printing of the results) + + // Locate specific document by key + collection.find({'a':1}, function(err, cursor) { + cursor.nextObject(function(err, doc) { + sys.puts("Returned #1 documents"); + }); + }); + + // Find records sort by 'a', skip 1, limit 2 records + // Sort can be a single name, array, associate array or ordered hash + collection.find({}, {'skip':1, 'limit':1, 'sort':'a'}, function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Returned #" + docs.length + " documents"); + }) + }); + + // Find all records with 'a' > 1, you can also use $lt, $gte or $lte + collection.find({'a':{'$gt':1}}, function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Returned #" + docs.length + " documents"); + }); + }); + + collection.find({'a':{'$gt':1, '$lte':3}}, function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Returned #" + docs.length + " documents"); + }); + }); + + // Find all records with 'a' in a set of values + collection.find({'a':{'$in':[1,2]}}, function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Returned #" + docs.length + " documents"); + }); + }); + + // Find by regexp + collection.find({'a':/[1|2]/}, function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Returned #" + docs.length + " documents"); + }); + }); + + // Print Query explanation + collection.find({'a':/[1|2]/}, function(err, cursor) { + cursor.explain(function(err, doc) { + sys.puts("-------------------------- Explanation"); + sys.puts(sys.inspect(doc)); + }) + }); + + // Use a hint with a query, hint's can also be store in the collection + // and will be applied to each query done through the collection. + // Hint's can also be specified by query which will override the + // hint's associated with the collection + collection.createIndex('a', function(err, indexName) { + collection.hint = 'a'; + + // You will see a different explanation now that the hint was set + collection.find({'a':/[1|2]/}, function(err, cursor) { + cursor.explain(function(err, doc) { + sys.puts("-------------------------- Explanation"); + sys.puts(sys.inspect(doc)); + }) + }); + + collection.find({'a':/[1|2]/}, {'hint':'a'}, function(err, cursor) { + cursor.explain(function(err, doc) { + sys.puts("-------------------------- Explanation"); + sys.puts(sys.inspect(doc)); + db.close(); + }) + }); + }); + }); + }); + }); + }); +}); diff --git a/node_modules/mongodb/examples/replSetServersQueries.js b/node_modules/mongodb/examples/replSetServersQueries.js new file mode 100644 index 0000000..eee5cba --- /dev/null +++ b/node_modules/mongodb/examples/replSetServersQueries.js @@ -0,0 +1,144 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + ReplSetServers = require('../lib/mongodb').ReplSetServers, + // BSON = require('../lib/mongodb').BSONPure; + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + + +var port1 = 27018; +var port2 = 27019; +var server = new Server(host, port, {}); +var server1 = new Server(host, port1, {}); +var server2 = new Server(host, port2, {}); +var servers = new Array(); +servers[0] = server2; +servers[1] = server1; +servers[2] = server; + +var replStat = new ReplSetServers(servers); +sys.puts("Connecting to " + host + ":" + port); +sys.puts("Connecting to " + host1 + ":" + port1); +sys.puts("Connecting to " + host2 + ":" + port2); +var db = new Db('node-mongo-examples', replStat, {native_parser:true}); +db.open(function(err, db) { + db.dropDatabase(function() { + // Fetch the collection test + db.collection('test', function(err, collection) { + // Remove all records in collection if any + collection.remove(function(err, collection) { + // Insert three records + collection.insert([{'a':1}, {'a':2}, {'b':3}], function(docs) { + // Count the number of records + collection.count(function(err, count) { + sys.puts("There are " + count + " records."); + }); + + // Find all records. find() returns a cursor + collection.find(function(err, cursor) { + // Print each row, each document has an _id field added on insert + // to override the basic behaviour implement a primary key factory + // that provides a 12 byte value + sys.puts("Printing docs from Cursor Each") + cursor.each(function(err, doc) { + if(doc != null) sys.puts("Doc from Each " + sys.inspect(doc)); + }) + }); + // Cursor has an to array method that reads in all the records to memory + collection.find(function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Printing docs from Array") + docs.forEach(function(doc) { + sys.puts("Doc from Array " + sys.inspect(doc)); + }); + }); + }); + + // Different methods to access records (no printing of the results) + + // Locate specific document by key + collection.find({'a':1}, function(err, cursor) { + cursor.nextObject(function(err, doc) { + sys.puts("Returned #1 documents"); + }); + }); + + // Find records sort by 'a', skip 1, limit 2 records + // Sort can be a single name, array, associate array or ordered hash + collection.find({}, {'skip':1, 'limit':1, 'sort':'a'}, function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Returned #" + docs.length + " documents"); + }) + }); + + // Find all records with 'a' > 1, you can also use $lt, $gte or $lte + collection.find({'a':{'$gt':1}}, function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Returned #" + docs.length + " documents"); + }); + }); + + collection.find({'a':{'$gt':1, '$lte':3}}, function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Returned #" + docs.length + " documents"); + }); + }); + + // Find all records with 'a' in a set of values + collection.find({'a':{'$in':[1,2]}}, function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Returned #" + docs.length + " documents"); + }); + }); + + // Find by regexp + collection.find({'a':/[1|2]/}, function(err, cursor) { + cursor.toArray(function(err, docs) { + sys.puts("Returned #" + docs.length + " documents"); + }); + }); + + // Print Query explanation + collection.find({'a':/[1|2]/}, function(err, cursor) { + cursor.explain(function(err, doc) { + sys.puts("-------------------------- Explanation"); + sys.puts(sys.inspect(doc)); + }) + }); + + // Use a hint with a query, hint's can also be store in the collection + // and will be applied to each query done through the collection. + // Hint's can also be specified by query which will override the + // hint's associated with the collection + collection.createIndex('a', function(err, indexName) { + collection.hint = 'a'; + + // You will see a different explanation now that the hint was set + collection.find({'a':/[1|2]/}, function(err, cursor) { + cursor.explain(function(err, doc) { + sys.puts("-------------------------- Explanation"); + sys.puts(sys.inspect(doc)); + }) + }); + + collection.find({'a':/[1|2]/}, {'hint':'a'}, function(err, cursor) { + cursor.explain(function(err, doc) { + sys.puts("-------------------------- Explanation"); + sys.puts(sys.inspect(doc)); + db.close(); + }) + }); + }); + }); + }); + }); + }); +}); diff --git a/node_modules/mongodb/examples/replSetServersSimple.js b/node_modules/mongodb/examples/replSetServersSimple.js new file mode 100644 index 0000000..2c75905 --- /dev/null +++ b/node_modules/mongodb/examples/replSetServersSimple.js @@ -0,0 +1,75 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Admin = require('../lib/mongodb').Admin, + DbCommand = require('../lib/mongodb/commands/db_command').DbCommand, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + // BSON = require('../lib/mongodb').BSONPure; + ReplSetServers = require('../lib/mongodb').ReplSetServers, + CheckMaster = require('../lib/mongodb').CheckMaster, + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +var port1 = 27018; +var port2 = 27019; + + +sys.puts("Connecting to " + host + ":" + port); +sys.puts("Connecting to " + host + ":" + port1); +sys.puts("Connecting to " + host + ":" + port2); + +var server = new Server(host, port, {}); +var server1 = new Server(host, port1, {}); +var server2 = new Server(host, port2, {}); +var servers = new Array(); +servers[0] = server2; +servers[1] = server1; +servers[2] = server; + +var replStat = new ReplSetServers(servers); + + + var db = new Db('mongo-example', replStat, {native_parser:true}); + +db.open(function(err, db) { + + db.dropDatabase(function(err, result) { + db.collection('test', function(err, collection) { + collection.remove(function(err, collection) { + // Insert 3 records + for(var i = 0; i < 3; i++) { + collection.insert({'a':i}); + } + + collection.count(function(err, count) { + sys.puts("There are " + count + " records in the test collection. Here they are:"); + + collection.find(function(err, cursor) { + cursor.each(function(err, item) { + if(item != null) { + sys.puts(sys.inspect(item)); + sys.puts("created at " + new Date(item._id.generationTime) + "\n") + } + // Null signifies end of iterator + if(item == null) { + // Destory the collection + collection.drop(function(err, collection) { + db.close(); + }); + } + }); + }); + }); + }); + }); + }); +}); + + + diff --git a/node_modules/mongodb/examples/simple.js b/node_modules/mongodb/examples/simple.js new file mode 100644 index 0000000..3a4cb3f --- /dev/null +++ b/node_modules/mongodb/examples/simple.js @@ -0,0 +1,50 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"), +debug = require('util').debug, +inspect = require('util').inspect, +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +sys.puts("Connecting to " + host + ":" + port); +var db = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db.open(function(err, db) { + db.dropDatabase(function(err, result) { + db.collection('test', function(err, collection) { + // Erase all records from the collection, if any + collection.remove({}, function(err, result) { + // Insert 3 records + for(var i = 0; i < 3; i++) { + collection.insert({'a':i}); + } + + collection.count(function(err, count) { + sys.puts("There are " + count + " records in the test collection. Here they are:"); + + collection.find(function(err, cursor) { + cursor.each(function(err, item) { + if(item != null) { + sys.puts(sys.inspect(item)); + sys.puts("created at " + new Date(item._id.generationTime) + "\n") + } + // Null signifies end of iterator + if(item == null) { + // Destory the collection + collection.drop(function(err, collection) { + db.close(); + }); + } + }); + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/node_modules/mongodb/examples/strict.js b/node_modules/mongodb/examples/strict.js new file mode 100644 index 0000000..0830d96 --- /dev/null +++ b/node_modules/mongodb/examples/strict.js @@ -0,0 +1,43 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + // BSON = require('../lib/mongodb').BSONPure; + BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +sys.puts("Connecting to " + host + ":" + port); +var db = new Db('node-mongo-examples', new Server(host, port, {}), {native_parser:true}); +db.open(function(err, db) { + db.dropCollection('does-not-exist', function(err, result) { + db.createCollection('test', function(err, collection) { + db.strict = true; + + // Can't reference collections that does not exist in strict mode + db.collection('does-not-exist', function(err, collection) { + if(err instanceof Error) { + sys.puts("expected error: " + err.message); + } + + // Can't create collections that does not exist in strict mode + db.createCollection('test', function(err, collection) { + if(err instanceof Error) { + sys.puts("expected error: " + err.message); + } + + // Remove the strict mode + db.strict = false; + db.dropCollection('test', function(err, collection) { + db.close(); + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/node_modules/mongodb/examples/types.js b/node_modules/mongodb/examples/types.js new file mode 100644 index 0000000..1de100b --- /dev/null +++ b/node_modules/mongodb/examples/types.js @@ -0,0 +1,50 @@ +GLOBAL.DEBUG = true; + +// require.paths.unshift("../external-libs/bson"); + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + Connection = require('../lib/mongodb').Connection, + Server = require('../lib/mongodb').Server, + BSON = require('../lib/mongodb').BSONPure; + // BSON = require('../lib/mongodb').BSONNative; + +var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; +var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT; + +sys.puts("Connecting to " + host + ":" + port); +var db = new Db('node-mongo-examples', new Server(host, port, {}), {}); +db.open(function(err, db) { + db.collection('test', function(err, collection) { + // Remove all existing documents in collection + collection.remove(function(err, collection) { + // Insert record with all the available types of values + collection.insert({ + 'array':[1,2,3], + 'string':'hello', + 'hash':{'a':1, 'b':2}, + 'date':new Date(), // Stores only milisecond resolution + 'oid':new BSON.ObjectID(), + 'binary':new BSON.Binary("123"), + 'int':42, + 'float':33.3333, + 'regexp':/foobar/i, + 'regexp2':/foobar2/, + 'boolean':true, + 'where':new BSON.Code('this.x == 3'), + 'dbref':new BSON.DBRef(collection.collectionName, new BSON.ObjectID()), + 'null':null + }, function(err, doc) { + // Locate the first document + collection.findOne(function(err, document) { + sys.puts(sys.inspect(document)); + collection.remove(function(err, collection) { + db.close(); + }); + }) + }); + }); + }); +}); \ No newline at end of file diff --git a/node_modules/mongodb/examples/url.js b/node_modules/mongodb/examples/url.js new file mode 100644 index 0000000..c9d9545 --- /dev/null +++ b/node_modules/mongodb/examples/url.js @@ -0,0 +1,17 @@ +GLOBAL.DEBUG = true; + +sys = require("sys"); +test = require("assert"); + +var Db = require('../lib/mongodb').Db, + connect = require('../lib/mongodb').connect; + +sys.puts('Connecting to ' + Db.DEFAULT_URL); +connect(Db.DEFAULT_URL, function(err, db) { + db.dropDatabase(function(err, result) { + db.collection('test', function(err, collection) { + collection.insert({'a':1}); + db.close(); + }); + }); +}); diff --git a/node_modules/mongodb/external-libs/bson/Makefile b/node_modules/mongodb/external-libs/bson/Makefile new file mode 100644 index 0000000..96fbe37 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/Makefile @@ -0,0 +1,19 @@ + +NODE = node +name = all +JOBS = 1 + +all: + rm -rf build .lock-wscript bson.node + node-waf configure build + @$(NODE) --expose-gc test_bson.js + @$(NODE) --expose-gc test_full_bson.js + +test: + @$(NODE) --expose-gc test_bson.js + @$(NODE) --expose-gc test_full_bson.js + +clean: + rm -rf build .lock-wscript bson.node + +.PHONY: all \ No newline at end of file diff --git a/node_modules/mongodb/external-libs/bson/binary.cc b/node_modules/mongodb/external-libs/bson/binary.cc new file mode 100644 index 0000000..508b2b6 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/binary.cc @@ -0,0 +1,327 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "binary.h" + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +const uint32_t BSON_BINARY_SUBTYPE_DEFAULT = 0; +const uint32_t BSON_BINARY_SUBTYPE_FUNCTION = 1; +const uint32_t BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; +const uint32_t BSON_BINARY_SUBTYPE_UUID = 3; +const uint32_t BSON_BINARY_SUBTYPE_MD5 = 4; +const uint32_t BSON_BINARY_SUBTYPE_USER_DEFINED = 128; + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); + }; + +Persistent Binary::constructor_template; + +Binary::Binary(uint32_t sub_type, uint32_t number_of_bytes, uint32_t index, char *data) : ObjectWrap() { + this->sub_type = sub_type; + this->number_of_bytes = number_of_bytes; + this->index = index; + this->data = data; +} + +Binary::~Binary() { + free(this->data); +} + +Handle Binary::New(const Arguments &args) { + HandleScope scope; + Binary *binary; + + if(args.Length() > 2) { + return VException("Argument must be either none, a string or a sub_type and string"); + } + + if(args.Length() == 0) { + char *oid_string_bytes = (char *)malloc(256); + *(oid_string_bytes) = '\0'; + binary = new Binary(BSON_BINARY_SUBTYPE_DEFAULT, 256, 0, oid_string_bytes); + } else if(args.Length() == 1 && args[0]->IsString()) { + Local str = args[0]->ToString(); + // Contains the bytes for the data + char *oid_string_bytes = (char *)malloc(str->Length() + 1); + *(oid_string_bytes + str->Length()) = '\0'; + // Decode the data from the string + node::DecodeWrite(oid_string_bytes, str->Length(), str, node::BINARY); + // Create a binary object + binary = new Binary(BSON_BINARY_SUBTYPE_DEFAULT, str->Length(), str->Length(), oid_string_bytes); + } else if(args.Length() == 2 && args[1]->IsNumber() && args[0]->IsString()) { + Local str = args[0]->ToString(); + Local intr = args[1]->ToInteger(); + // Contains the bytes for the data + char *oid_string_bytes = (char *)malloc(str->Length() + 1); + *(oid_string_bytes + str->Length()) = '\0'; + // Decode the data from the string + node::DecodeWrite(oid_string_bytes, str->Length(), str, node::BINARY); + // Decode the subtype + uint32_t sub_type = intr->Uint32Value(); + binary = new Binary(sub_type, str->Length(), str->Length(), oid_string_bytes); + } else { + return VException("Argument must be either none, a string or a string and a sub_type"); + } + + // Wrap it + binary->Wrap(args.This()); + // Return the object + return args.This(); +} + +static Persistent subtype_symbol; + +void Binary::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("Binary")); + + // Propertry symbols + subtype_symbol = NODE_PSYMBOL("sub_type"); + + // Instance methods + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toString", ToString); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "inspect", Inspect); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "value", Data); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "length", Length); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "put", Put); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "write", Write); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "read", Read); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "readInto", ReadInto); + + // Getters for correct serialization of the object + constructor_template->InstanceTemplate()->SetAccessor(subtype_symbol, SubtypeGetter, SubtypeSetter); + + target->Set(String::NewSymbol("Binary"), constructor_template->GetFunction()); +} + +Handle Binary::SubtypeGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack object reference + Binary *binary_obj = ObjectWrap::Unwrap(info.Holder()); + + // Extract value doing a cast of the pointer to Long and accessing low_bits + Local sub_type_int = Integer::New(binary_obj->sub_type); + return scope.Close(sub_type_int); +} + +void Binary::SubtypeSetter(Local property, Local value, const AccessorInfo& info) { + if(value->IsNumber()) { + // Unpack the long object + Binary *b = ObjectWrap::Unwrap(info.Holder()); + // Set the low bits + b->sub_type = value->IntegerValue(); + } +} + +Handle Binary::Read(const Arguments &args) { + HandleScope scope; + + // Ensure we have the right parameters + if(args.Length() != 2 && !args[0]->IsUint32() && !args[1]->IsUint32()) return VException("Function takes two arguments of type Integer, position and offset"); + // Let's unpack the parameters + uint32_t position = args[0]->Uint32Value(); + uint32_t length = args[1]->Uint32Value(); + // Let's unpack the binary object + Binary *binary = ObjectWrap::Unwrap(args.This()); + + // Ensure that it's a valid range + if(binary->number_of_bytes >= position && binary->number_of_bytes >= (position + length)) { + // Decode the data + Local encoded_data = Encode((binary->data + position), length, BINARY)->ToString(); + // Return the data to the client + return scope.Close(encoded_data); + } else { + return VException("position and length is outside the size of the binary"); + } +} + +Handle Binary::ReadInto(const Arguments &args) { + HandleScope scope; + + if (args.Length() == 0 || !Buffer::HasInstance(args[0])) { + return VException("Function takes at least one argument of type Buffer"); + } + + size_t offset = args[1]->IsUint32() ? args[1]->Uint32Value() : 0; + Binary *binary = ObjectWrap::Unwrap(args.This()); + if (binary->index - offset < 0) { + return VException("offset argument out of bounds"); + } + + Local obj = args[0]->ToObject(); + size_t blength = Buffer::Length(obj); + char *data = Buffer::Data(obj); + size_t towrite = MIN(blength, binary->index - offset); + + if (towrite > 0) { + memmove(data, binary->data + offset, towrite); + } + + return scope.Close(Integer::New(towrite)); +} + +Handle Binary::Write(const Arguments &args) { + HandleScope scope; + + // Ensure we have the right parameters + if(args.Length() == 1 && (!args[0]->IsString() || Buffer::HasInstance(args[0]))) return VException("Function takes one argument of type String or Buffer"); + if(args.Length() == 2 && (!args[0]->IsString() || Buffer::HasInstance(args[0])) && !args[1]->IsUint32()) return VException("Function takes one argument of type String or Buffer"); + + // Reference variables + char *data; + uint32_t length; + uint32_t offset = 0; + Local obj = args[0]->ToObject(); + + // Unpack the offset value + if(args.Length() == 2) { + offset = args[1]->ToUint32()->Value(); + } + + // If we have a buffer let's retrieve the data + if(Buffer::HasInstance(obj)) { + #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3 + Buffer *buffer = ObjectWrap::Unwrap(obj); + data = buffer->data(); + length = buffer->length(); + #else + data = Buffer::Data(obj); + length = Buffer::Length(obj); + #endif + } else { + Local str = args[0]->ToString(); + length = DecodeBytes(str, BINARY); + data = (char *)malloc(length * sizeof(char)); + uint32_t written = DecodeWrite(data, length, str, BINARY); + assert(length == written); + } + + // Ensure we got enough allocated space for the content + Binary *binary = ObjectWrap::Unwrap(args.This()); + // Check if we have enough space or we need to allocate more space + if((binary->index + length) > binary->number_of_bytes) { + // Realocate memory (and add double the current space to allow for more writing) + binary->data = (char *)realloc(binary->data, ((binary->number_of_bytes * 2) + length)); + binary->number_of_bytes = (binary->number_of_bytes * 2) + length; + } + + // If no offset specified use internal index + if(offset == 0) offset = binary->index; + + // Write the element out + memcpy((binary->data + offset), data, length); + // Update the index pointer + binary->index = offset + length; + // free the memory if we have allocated + if(!Buffer::HasInstance(args[0])) { + free(data); + } + // Close and return + return scope.Close(Null()); +} + +Handle Binary::Put(const Arguments &args) { + HandleScope scope; + + // Ensure we have the right parameters + if(args.Length() != 1 && !args[0]->IsString()) return VException("Function takes one argument of type String containing one character"); + + // Unpack the character (string) + Local str = args[0]->ToString(); + // Let's unpack the string to char + ssize_t len = DecodeBytes(str, BINARY); + if(len != 1) return VException("Function takes one argument of type String containing one character"); + + // Let's define the buffer that contains the regexp string + // char *data = new char[len + 1]; + char *data = (char *)malloc(len * sizeof(char) + 1); + // Write the data to the buffer from the string object + ssize_t written = DecodeWrite(data, len, str, BINARY); + + // Unpack the binary object + Binary *binary = ObjectWrap::Unwrap(args.This()); + // Check if we need to adjust the size of the binary to fit more space + if((binary->index + len) > binary->number_of_bytes) { + // Realocate memory (and double the allocated space 256-512-1024-2048-4096) to try to lower + // the number of times we reallocate memory + binary->data = (char *)realloc(binary->data, binary->number_of_bytes * 2); + binary->number_of_bytes = binary->number_of_bytes * 2; + } + + // Write the element out + *(binary->data + binary->index) = *(data); + // Update the index pointer + binary->index = binary->index + 1; + // Free up the data + // delete data; + free(data); + // Return a null + return scope.Close(Null()); +} + +Handle Binary::Length(const Arguments &args) { + HandleScope scope; + + // Unpack the Binary object + Binary *binary = ObjectWrap::Unwrap(args.This()); + return scope.Close(Integer::New(binary->index)); +} + +Handle Binary::Data(const Arguments &args) { + HandleScope scope; + + // Unpack the Binary object + Binary *binary = ObjectWrap::Unwrap(args.This()); + // Return the raw data + Local bin_value = Encode(binary->data, binary->index, BINARY); + return scope.Close(bin_value); +} + +Handle Binary::Inspect(const Arguments &args) { + HandleScope scope; + + // Unpack the Binary object + Binary *binary = ObjectWrap::Unwrap(args.This()); + // Return the raw data + Local bin_value = Encode(binary->data, binary->number_of_bytes, BINARY); + return scope.Close(bin_value); +} + +Handle Binary::ToString(const Arguments &args) { + HandleScope scope; + + // Unpack the Binary object + Binary *binary = ObjectWrap::Unwrap(args.This()); + // Return the raw data + Local bin_value = Encode(binary->data, binary->number_of_bytes, BINARY); + return scope.Close(bin_value); +} + + + + + + + + + diff --git a/node_modules/mongodb/external-libs/bson/binary.h b/node_modules/mongodb/external-libs/bson/binary.h new file mode 100644 index 0000000..d6bcedc --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/binary.h @@ -0,0 +1,57 @@ +#ifndef BINARY_H_ +#define BINARY_H_ + +#include +#include +#include + +using namespace v8; +using namespace node; + +class Binary : public ObjectWrap { + public: + char *data; + uint32_t number_of_bytes; + uint32_t sub_type; + uint32_t index; + + Binary(uint32_t sub_type, uint32_t number_of_bytes, uint32_t index, char *data); + ~Binary(); + + // Has instance check + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + } + + // Functions available from V8 + static void Initialize(Handle target); + static Handle ToString(const Arguments &args); + static Handle Inspect(const Arguments &args); + static Handle Data(const Arguments &args); + static Handle Length(const Arguments &args); + static Handle Put(const Arguments &args); + static Handle Write(const Arguments &args); + static Handle Read(const Arguments &args); + + /** + * Writes this binary data into node Buffer passed as first js arg. + * Optional second js arg: internal data offset of this binary (Integer) + * Up to Min(Buffer.length, Binary.length - offset) bytes will be writen into buffer. + * Return number of bytes actually written into buffer. + */ + static Handle ReadInto(const Arguments &args); + + // Constructor used for creating new Long objects from C++ + static Persistent constructor_template; + + // Getter and Setter for object values + static Handle SubtypeGetter(Local property, const AccessorInfo& info); + static void SubtypeSetter(Local property, Local value, const AccessorInfo& info); + + private: + static Handle New(const Arguments &args); +}; + +#endif // BINARY_H_ \ No newline at end of file diff --git a/node_modules/mongodb/external-libs/bson/bson.cc b/node_modules/mongodb/external-libs/bson/bson.cc new file mode 100644 index 0000000..e791594 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/bson.cc @@ -0,0 +1,1697 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bson.h" +#include "long.h" +#include "timestamp.h" +#include "objectid.h" +#include "binary.h" +#include "code.h" +#include "dbref.h" + +using namespace v8; +using namespace node; + +// BSON DATA TYPES +const uint32_t BSON_DATA_NUMBER = 1; +const uint32_t BSON_DATA_STRING = 2; +const uint32_t BSON_DATA_OBJECT = 3; +const uint32_t BSON_DATA_ARRAY = 4; +const uint32_t BSON_DATA_BINARY = 5; +const uint32_t BSON_DATA_OID = 7; +const uint32_t BSON_DATA_BOOLEAN = 8; +const uint32_t BSON_DATA_DATE = 9; +const uint32_t BSON_DATA_NULL = 10; +const uint32_t BSON_DATA_REGEXP = 11; +const uint32_t BSON_DATA_CODE_W_SCOPE = 15; +const uint32_t BSON_DATA_INT = 16; +const uint32_t BSON_DATA_TIMESTAMP = 17; +const uint32_t BSON_DATA_LONG = 18; + +const int32_t BSON_INT32_MAX = (int32_t)2147483647L; +const int32_t BSON_INT32_MIN = (int32_t)(-1) * 2147483648L; + +// BSON BINARY DATA SUBTYPES +const uint32_t BSON_BINARY_SUBTYPE_FUNCTION = 1; +const uint32_t BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; +const uint32_t BSON_BINARY_SUBTYPE_UUID = 3; +const uint32_t BSON_BINARY_SUBTYPE_MD5 = 4; +const uint32_t BSON_BINARY_SUBTYPE_USER_DEFINED = 128; + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); + }; + +Persistent BSON::constructor_template; + +void BSON::Initialize(v8::Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("BSON")); + + // Class methods + NODE_SET_METHOD(constructor_template->GetFunction(), "serialize", BSONSerialize); + NODE_SET_METHOD(constructor_template->GetFunction(), "serializeWithBufferAndIndex", SerializeWithBufferAndIndex); + NODE_SET_METHOD(constructor_template->GetFunction(), "deserialize", BSONDeserialize); + NODE_SET_METHOD(constructor_template->GetFunction(), "encodeLong", EncodeLong); + NODE_SET_METHOD(constructor_template->GetFunction(), "toLong", ToLong); + NODE_SET_METHOD(constructor_template->GetFunction(), "toInt", ToInt); + NODE_SET_METHOD(constructor_template->GetFunction(), "calculateObjectSize", CalculateObjectSize); + + target->Set(String::NewSymbol("BSON"), constructor_template->GetFunction()); +} + +// Create a new instance of BSON and assing it the existing context +Handle BSON::New(const Arguments &args) { + HandleScope scope; + + BSON *bson = new BSON(); + bson->Wrap(args.This()); + return args.This(); +} + +Handle BSON::SerializeWithBufferAndIndex(const Arguments &args) { + HandleScope scope; + + //BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, checkKeys, buffer, index) { + // Ensure we have the correct values + if(args.Length() != 4) return VException("Four parameters required [object, boolean, Buffer, int]"); + if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32()) return VException("Four parameters required [object, boolean, Buffer, int]"); + + // Define pointer to data + char *data; + uint32_t length; + // Unpack the object + Local obj = args[2]->ToObject(); + + // Unpack the buffer object and get pointers to structures + #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3 + Buffer *buffer = ObjectWrap::Unwrap(obj); + data = buffer->data(); + length = buffer->length(); + #else + data = Buffer::Data(obj); + length = Buffer::Length(obj); + #endif + + // Calculate the total size of the document in binary form to ensure we only allocate memory once + uint32_t object_size = BSON::calculate_object_size(args[0]); + // Unpack the index variable + Local indexObject = args[3]->ToUint32(); + uint32_t index = indexObject->Value(); + + // Allocate the memory needed for the serializtion + char *serialized_object = (char *)malloc(object_size * sizeof(char)); + + // printf("=================================== length :: %u\n", length); + // printf("=================================== index :: %u\n", index); + // printf("=================================== size :: %u\n", object_size); + + // Catch any errors + try { + // Check if we have a boolean value + bool check_key = false; + if(args.Length() == 4 && args[1]->IsBoolean()) { + check_key = args[1]->BooleanValue(); + } + + // Serialize the object + BSON::serialize(serialized_object, 0, Null(), args[0], check_key); + } catch(char *err_msg) { + // Free up serialized object space + free(serialized_object); + V8::AdjustAmountOfExternalAllocatedMemory(-object_size); + // Throw exception with the string + Handle error = VException(err_msg); + // free error message + free(err_msg); + // Return error + return error; + } + + // // Write the object size + // BSON::write_int32(serialized_object, object_size); + + // memcopy to data + // memcpy((data + index), &serialized_object, object_size - 1); + + for(int i = 0; i < object_size; i++) { + *(data + index + i) = *(serialized_object + i); + } + + + // printf("=============================================== 2\n"); + + + // printf("=============================================== 3\n"); + // Unwrap object + // Buffer *outputBuffer = ObjectWrap::Unwrap(obj); + + // printf("=============================================== 4\n"); + + // printf("=================================== size :: %u\n", object_size); + + // Buffer *buffer = Buffer::New(0); + // return scope.Close(outputBuffer->handle_); + return scope.Close(Uint32::New(index + object_size - 1)); +} + +Handle BSON::BSONSerialize(const Arguments &args) { + HandleScope scope; + + // printf("= BSONSerialize ===================================== USING Native BSON Parser\n"); + if(args.Length() == 1 && !args[0]->IsObject()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]"); + if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]"); + if(args.Length() == 3 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]"); + if(args.Length() > 3) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]"); + + // Calculate the total size of the document in binary form to ensure we only allocate memory once + uint32_t object_size = BSON::calculate_object_size(args[0]); + // Allocate the memory needed for the serializtion + char *serialized_object = (char *)malloc(object_size * sizeof(char)); + // Catch any errors + try { + // Check if we have a boolean value + bool check_key = false; + if(args.Length() == 3 && args[1]->IsBoolean()) { + check_key = args[1]->BooleanValue(); + } + + // Serialize the object + BSON::serialize(serialized_object, 0, Null(), args[0], check_key); + } catch(char *err_msg) { + // Free up serialized object space + free(serialized_object); + V8::AdjustAmountOfExternalAllocatedMemory(-object_size); + // Throw exception with the string + Handle error = VException(err_msg); + // free error message + free(err_msg); + // Return error + return error; + } + + // Write the object size + BSON::write_int32((serialized_object), object_size); + + // If we have 3 arguments + if(args.Length() == 3) { + // Local asBuffer = args[2]->ToBoolean(); + Buffer *buffer = Buffer::New(serialized_object, object_size); + return scope.Close(buffer->handle_); + } else { + // Encode the string (string - null termiating character) + Local bin_value = Encode(serialized_object, object_size, BINARY)->ToString(); + // Return the serialized content + return bin_value; + } +} + +Handle BSON::CalculateObjectSize(const Arguments &args) { + HandleScope scope; + // Ensure we have a valid object + if(args.Length() == 1 && !args[0]->IsObject()) return VException("One argument required - [object]"); + if(args.Length() > 1) return VException("One argument required - [object]"); + // Calculate size of the object + uint32_t object_size = BSON::calculate_object_size(args[0]); + // Return the object size + return scope.Close(Uint32::New(object_size)); +} + + +Handle BSON::ToLong(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 2 && !args[0]->IsString() && !args[1]->IsString()) return VException("Two arguments of type String required"); + // Create a new Long value and return it + Local argv[] = {args[0], args[1]}; + Handle long_obj = Long::constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(long_obj); +} + +Handle BSON::ToInt(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 1 && !args[0]->IsNumber() && !args[1]->IsString()) return VException("One argument of type Number required"); + // Return int value + return scope.Close(args[0]->ToInt32()); +} + +Handle BSON::EncodeLong(const Arguments &args) { + HandleScope scope; + + // Encode the value + if(args.Length() != 1 && !Long::HasInstance(args[0])) return VException("One argument required of type Long"); + // Unpack the object and encode + Local obj = args[0]->ToObject(); + Long *long_obj = Long::Unwrap(obj); + // Allocate space + char *long_str = (char *)malloc(8 * sizeof(char)); + // Write the content to the char array + BSON::write_int32((long_str), long_obj->low_bits); + BSON::write_int32((long_str + 4), long_obj->high_bits); + // Encode the data + Local long_final_str = Encode(long_str, 8, BINARY)->ToString(); + // Free up memory + free(long_str); + // Return the encoded string + return scope.Close(long_final_str); +} + +void BSON::write_int32(char *data, uint32_t value) { + // Write the int to the char* + memcpy(data, &value, 4); +} + +void BSON::write_double(char *data, double value) { + // Write the double to the char* + memcpy(data, &value, 8); +} + +void BSON::write_int64(char *data, int64_t value) { + // Write the int to the char* + memcpy(data, &value, 8); +} + +char *BSON::check_key(Local key) { + // Allocate space for they key string + char *key_str = (char *)malloc(key->Length() * sizeof(char) + 1); + // Error string + char *error_str = (char *)malloc(256 * sizeof(char)); + // Decode the key + ssize_t len = DecodeBytes(key, BINARY); + ssize_t written = DecodeWrite(key_str, len, key, BINARY); + *(key_str + key->Length()) = '\0'; + // Check if we have a valid key + if(key->Length() > 0 && *(key_str) == '$') { + // Create the string + sprintf(error_str, "key %s must not start with '$'", key_str); + // Free up memory + free(key_str); + // Throw exception with string + throw error_str; + } else if(key->Length() > 0 && strchr(key_str, '.') != NULL) { + // Create the string + sprintf(error_str, "key %s must not contain '.'", key_str); + // Free up memory + free(key_str); + // Throw exception with string + throw error_str; + } + // Free allocated space + free(key_str); + free(error_str); + // Return No check key error + return NULL; +} + +uint32_t BSON::serialize(char *serialized_object, uint32_t index, Handle name, Handle value, bool check_key) { + // printf("============================================= serialized::::\n"); + HandleScope scope; + + // If we have a name check that key is valid + if(!name->IsNull() && check_key) { + if(BSON::check_key(name->ToString()) != NULL) return -1; + } + + // If we have an object let's serialize it + if(Long::HasInstance(value)) { + // printf("============================================= -- serialized::::long\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_LONG; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // Unpack the object and encode + Local obj = value->ToObject(); + Long *long_obj = Long::Unwrap(obj); + // Write the content to the char array + BSON::write_int32((serialized_object + index), long_obj->low_bits); + BSON::write_int32((serialized_object + index + 4), long_obj->high_bits); + // Adjust the index + index = index + 8; + } else if(Timestamp::HasInstance(value)) { + // printf("============================================= -- serialized::::long\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_TIMESTAMP; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // Unpack the object and encode + Local obj = value->ToObject(); + Timestamp *timestamp_obj = Timestamp::Unwrap(obj); + // Write the content to the char array + BSON::write_int32((serialized_object + index), timestamp_obj->low_bits); + BSON::write_int32((serialized_object + index + 4), timestamp_obj->high_bits); + // Adjust the index + index = index + 8; + } else if(ObjectID::HasInstance(value) || (value->IsObject() && value->ToObject()->HasRealNamedProperty(String::New("toHexString")))) { + // printf("============================================= -- serialized::::object_id\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_OID; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // Unpack the object and encode + Local obj = value->ToObject(); + ObjectID *object_id_obj = ObjectID::Unwrap(obj); + // Fetch the converted oid + char *binary_oid = object_id_obj->convert_hex_oid_to_bin(); + // Write the oid to the char array + memcpy((serialized_object + index), binary_oid, 12); + // Free memory + free(binary_oid); + // Adjust the index + index = index + 12; + } else if(Binary::HasInstance(value)) { + // printf("============================================= -- serialized::::binary\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_BINARY; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // Unpack the object and encode + Local obj = value->ToObject(); + Binary *binary_obj = Binary::Unwrap(obj); + // // Let's write the total size of the binary + // BSON::write_int32((serialized_object + index), (binary_obj->index + 4)); + // // Adjust index + // index = index + 4; + // Let's write the content to the char* array + BSON::write_int32((serialized_object + index), binary_obj->index); + // Adjust index + index = index + 4; + // Write subtype + *(serialized_object + index) = (char)binary_obj->sub_type; + // Adjust index + index = index + 1; + // Write binary content + memcpy((serialized_object + index), binary_obj->data, binary_obj->index); + // Adjust index + index = index + binary_obj->index; + } else if(DBRef::HasInstance(value)) { + // printf("============================================= -- serialized::::dbref\n"); + // Unpack the dbref + Local dbref = value->ToObject(); + // Create an object containing the right namespace variables + Local obj = Object::New(); + // unpack dbref to get to the bin + DBRef *db_ref_obj = DBRef::Unwrap(dbref); + // Unpack the reference value + Persistent oid_value = db_ref_obj->oid; + // Encode the oid to bin + obj->Set(String::New("$ref"), dbref->Get(String::New("namespace"))); + obj->Set(String::New("$id"), oid_value); + // obj->Set(String::New("$db"), dbref->Get(String::New("db"))); + if(db_ref_obj->db != NULL) obj->Set(String::New("$db"), dbref->Get(String::New("db"))); + // Encode the variable + index = BSON::serialize(serialized_object, index, name, obj, false); + } else if(Code::HasInstance(value)) { + // printf("============================================= -- serialized::::code\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_CODE_W_SCOPE; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // Unpack the object and encode + Local obj = value->ToObject(); + Code *code_obj = Code::Unwrap(obj); + // Keep pointer to start + uint32_t first_pointer = index; + // Adjust the index + index = index + 4; + // Write the size of the code string + BSON::write_int32((serialized_object + index), strlen(code_obj->code) + 1); + // Adjust the index + index = index + 4; + // Write the code string + memcpy((serialized_object + index), code_obj->code, strlen(code_obj->code)); + *(serialized_object + index + strlen(code_obj->code)) = '\0'; + // Adjust index + index = index + strlen(code_obj->code) + 1; + // Encode the scope + uint32_t scope_object_size = BSON::calculate_object_size(code_obj->scope_object); + // Serialize the scope object + BSON::serialize((serialized_object + index), 0, Null(), code_obj->scope_object, check_key); + // Adjust the index + index = index + scope_object_size; + // Encode the total size of the object + BSON::write_int32((serialized_object + first_pointer), (index - first_pointer)); + } else if(value->IsString()) { + // printf("============================================= -- serialized::::string\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_STRING; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // Write the actual string into the char array + Local str = value->ToString(); + // Let's fetch the int value + uint32_t utf8_length = str->Utf8Length(); + + // If the Utf8 length is different from the string length then we + // have a UTF8 encoded string, otherwise write it as ascii + if(utf8_length != str->Length()) { + // Write the integer to the char * + BSON::write_int32((serialized_object + index), utf8_length + 1); + // Adjust the index + index = index + 4; + // Write string to char in utf8 format + str->WriteUtf8((serialized_object + index), utf8_length); + // Add the null termination + *(serialized_object + index + utf8_length) = '\0'; + // Adjust the index + index = index + utf8_length + 1; + } else { + // Write the integer to the char * + BSON::write_int32((serialized_object + index), str->Length() + 1); + // Adjust the index + index = index + 4; + // Write string to char in utf8 format + written = DecodeWrite((serialized_object + index), str->Length(), str, BINARY); + // Add the null termination + *(serialized_object + index + str->Length()) = '\0'; + // Adjust the index + index = index + str->Length() + 1; + } + } else if(value->IsInt32()) { + // printf("============================================= -- serialized::::int32\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_INT; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // Write the integer to the char * + int32_t int_value = value->Int32Value(); + BSON::write_int32((serialized_object + index), int_value); + // Adjust the index + index = index + 4; + } else if(value->IsNull() || value->IsUndefined()) { + // printf("============================================= -- serialized::::null\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_NULL; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + } else if(value->IsNumber()) { + // printf("============================================= -- serialized::::number\n"); + uint32_t first_pointer = index; + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_INT; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + Local number = value->ToNumber(); + // Get the values + double d_number = number->NumberValue(); + int64_t l_number = number->IntegerValue(); + // printf("===================================================== l_number:%lli\n", l_number); + // Check if we have a double value and not a int64 + double d_result = d_number - l_number; + // If we have a value after subtracting the integer value we have a float + if(d_result > 0 || d_result < 0) { + // printf("============================================= -- serialized::::double\n"); + // Write the double to the char array + BSON::write_double((serialized_object + index), d_number); + // Adjust type to be double + *(serialized_object + first_pointer) = BSON_DATA_NUMBER; + // Adjust index for double + index = index + 8; + } else if(l_number <= BSON_INT32_MAX && l_number >= BSON_INT32_MIN) { + // printf("============================================= -- serialized::::int32\n"); + if(l_number == BSON_INT32_MAX) { + BSON::write_int32((serialized_object + index), BSON_INT32_MAX); + } else { + BSON::write_int32((serialized_object + index), BSON_INT32_MIN); + } + // Adjust the size of the index + index = index + 4; + } else { + // Fetch the double value + BSON::write_int64((serialized_object + index), l_number); + // Adjust type to be double + *(serialized_object + first_pointer) = BSON_DATA_LONG; + // Adjust the size of the index + index = index + 8; + } + } else if(value->IsBoolean()) { + // printf("============================================= -- serialized::::boolean\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_BOOLEAN; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // Save the boolean value + *(serialized_object + index) = value->BooleanValue() ? '\1' : '\0'; + // Adjust the index + index = index + 1; + } else if(value->IsDate()) { + // printf("============================================= -- serialized::::date\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_DATE; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // Fetch the Integer value + int64_t integer_value = value->IntegerValue(); + BSON::write_int64((serialized_object + index), integer_value); + // Adjust the index + index = index + 8; + // } else if(value->IsObject() && value->ToObject()->ObjectProtoToString()->Equals(String::New("[object RegExp]"))) { + } else if(value->IsRegExp()) { + // printf("============================================= -- serialized::::regexp\n"); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_REGEXP; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // Fetch the string for the regexp + Handle regExp = Handle::Cast(value); + len = DecodeBytes(regExp->GetSource(), UTF8); + written = DecodeWrite((serialized_object + index), len, regExp->GetSource(), UTF8); + int flags = regExp->GetFlags(); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + + // ignorecase + if((flags & (1 << 1)) != 0) { + *(serialized_object + index) = 'i'; + index = index + 1; + } + + //multiline + if((flags & (1 << 2)) != 0) { + *(serialized_object + index) = 'm'; + index = index + 1; + } + + // Add null termiation for the string + *(serialized_object + index) = '\0'; + // Adjust the index + index = index + 1; + } else if(value->IsArray()) { + // printf("============================================= -- serialized::::array\n"); + // Cast to array + Local array = Local::Cast(value->ToObject()); + // Turn length into string to calculate the size of all the strings needed + char *length_str = (char *)malloc(256 * sizeof(char)); + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_ARRAY; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + // Object size + uint32_t object_size = BSON::calculate_object_size(value); + // printf("C++ =================================== array_size: %d\n", object_size); + // Write the size of the object + BSON::write_int32((serialized_object + index), object_size); + // Adjust the index + index = index + 4; + // Write out all the elements + for(uint32_t i = 0; i < array->Length(); i++) { + // Add "index" string size for each element + sprintf(length_str, "%d", i); + // Encode the values + index = BSON::serialize(serialized_object, index, String::New(length_str), array->Get(Integer::New(i)), check_key); + // Write trailing '\0' for object + *(serialized_object + index) = '\0'; + } + // Write trailing '\0' for object + // *(serialized_object + index + 1) = '\0'; + // Pad the last item + *(serialized_object + index) = '\0'; + index = index + 1; + // Free up memory + free(length_str); + } else if(value->IsFunction()) { + } else if(value->IsObject()) { + // printf("============================================= -- serialized::::object\n"); + if(!name->IsNull()) { + // Save the string at the offset provided + *(serialized_object + index) = BSON_DATA_OBJECT; + // Adjust writing position for the first byte + index = index + 1; + // Convert name to char* + ssize_t len = DecodeBytes(name, UTF8); + ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8); + // Add null termiation for the string + *(serialized_object + index + len) = '\0'; + // Adjust the index + index = index + len + 1; + } + + // Unwrap the object + Local object = value->ToObject(); + Local property_names = object->GetPropertyNames(); + + // Calculate size of the total object + uint32_t object_size = BSON::calculate_object_size(value); + // Write the size + BSON::write_int32((serialized_object + index), object_size); + // Adjust size + index = index + 4; + + // printf("======================================== number_of_properties: %d\n", property_names->Length()); + + // Process all the properties on the object + for(uint32_t i = 0; i < property_names->Length(); i++) { + // Fetch the property name + Local property_name = property_names->Get(i)->ToString(); + + // Convert name to char* + ssize_t len = DecodeBytes(property_name, UTF8); + // char *data = new char[len]; + char *data = (char *)malloc(len + 1); + *(data + len) = '\0'; + ssize_t written = DecodeWrite(data, len, property_name, UTF8); + // Fetch the object for the property + Local property = object->Get(property_name); + // Write the next serialized object + index = BSON::serialize(serialized_object, index, property_name, property, check_key); + // Free up memory of data + free(data); + } + // Pad the last item + *(serialized_object + index) = '\0'; + index = index + 1; + + // Null out reminding fields if we have a toplevel object and nested levels + if(name->IsNull()) { + for(uint32_t i = 0; i < (object_size - index); i++) { + *(serialized_object + index + i) = '\0'; + } + } + } + + return index; +} + +uint32_t BSON::calculate_object_size(Handle value) { + uint32_t object_size = 0; + // printf("================================ ----------- calculate_object_size\n"); + + // If we have an object let's unwrap it and calculate the sub sections + if(Long::HasInstance(value)) { + // printf("================================ calculate_object_size:long\n"); + object_size = object_size + 8; + } else if(ObjectID::HasInstance(value)) { + // printf("================================ calculate_object_size:objectid\n"); + object_size = object_size + 12; + } else if(Binary::HasInstance(value)) { + // printf("================================ calculate_object_size:binary\n"); + // Unpack the object and encode + Local obj = value->ToObject(); + Binary *binary_obj = Binary::Unwrap(obj); + // Adjust the object_size, binary content lengt + total size int32 + binary size int32 + subtype + object_size += binary_obj->index + 4 + 1; + } else if(Code::HasInstance(value)) { + // printf("================================ calculate_object_size:code\n"); + // Unpack the object and encode + Local obj = value->ToObject(); + Code *code_obj = Code::Unwrap(obj); + // Let's calculate the size the code object adds adds + object_size += strlen(code_obj->code) + 4 + BSON::calculate_object_size(code_obj->scope_object) + 4 + 1; + } else if(DBRef::HasInstance(value)) { + // Unpack the dbref + Local dbref = value->ToObject(); + // Create an object containing the right namespace variables + Local obj = Object::New(); + // unpack dbref to get to the bin + DBRef *db_ref_obj = DBRef::Unwrap(dbref); + // Encode the oid to bin + obj->Set(String::New("$ref"), dbref->Get(String::New("namespace"))); + obj->Set(String::New("$id"), db_ref_obj->oid); + // obj->Set(String::New("$db"), dbref->Get(String::New("db"))); + if(db_ref_obj->db != NULL) obj->Set(String::New("$db"), dbref->Get(String::New("db"))); + // printf("================================ calculate_object_size:dbref:[%d]\n", BSON::calculate_object_size(obj)); + // Calculate size + object_size += BSON::calculate_object_size(obj); + } else if(value->IsString()) { + // printf("================================ calculate_object_size:string\n"); + Local str = value->ToString(); + uint32_t utf8_length = str->Utf8Length(); + + if(utf8_length != str->Length()) { + // Let's calculate the size the string adds, length + type(1 byte) + size(4 bytes) + object_size += str->Utf8Length() + 1 + 4; + } else { + object_size += str->Length() + 1 + 4; + } + } else if(value->IsInt32()) { + // printf("================================ calculate_object_size:int32\n"); + object_size += 4; + } else if(value->IsNull()) { + // printf("================================ calculate_object_size:null\n"); + } else if(value->IsNumber()) { + // Check if we have a float value or a long value + Local number = value->ToNumber(); + double d_number = number->NumberValue(); + int64_t l_number = number->IntegerValue(); + // Check if we have a double value and not a int64 + double d_result = d_number - l_number; + // If we have a value after subtracting the integer value we have a float + if(d_result > 0 || d_result < 0) { + object_size = object_size + 8; + } else if(l_number <= BSON_INT32_MAX && l_number >= BSON_INT32_MIN) { + object_size = object_size + 4; + } else { + object_size = object_size + 8; + } + } else if(value->IsBoolean()) { + // printf("================================ calculate_object_size:boolean\n"); + object_size = object_size + 1; + } else if(value->IsDate()) { + // printf("================================ calculate_object_size:date\n"); + object_size = object_size + 8; + // } else if(value->IsObject() && value->ToObject()->ObjectProtoToString()->Equals(String::New("[object RegExp]"))) { + } else if(value->IsRegExp()) { + // Fetch the string for the regexp + Handle regExp = Handle::Cast(value); + ssize_t len = DecodeBytes(regExp->GetSource(), UTF8); + int flags = regExp->GetFlags(); + + // ignorecase + if((flags & (1 << 1)) != 0) len++; + //multiline + if((flags & (1 << 2)) != 0) len++; + // Calculate the space needed for the regexp: size of string - 2 for the /'ses +2 for null termiations + object_size = object_size + len + 2; + } else if(value->IsArray()) { + // printf("================================ calculate_object_size:array\n"); + // Cast to array + Local array = Local::Cast(value->ToObject()); + // Turn length into string to calculate the size of all the strings needed + char *length_str = (char *)malloc(256 * sizeof(char)); + // Calculate the size of each element + for(uint32_t i = 0; i < array->Length(); i++) { + // Add "index" string size for each element + sprintf(length_str, "%d", i); + // Add the size of the string length + uint32_t label_length = strlen(length_str) + 1; + // Add the type definition size for each item + object_size = object_size + label_length + 1; + // Add size of the object + uint32_t object_length = BSON::calculate_object_size(array->Get(Integer::New(i))); + object_size = object_size + object_length; + } + // Add the object size + object_size = object_size + 4 + 1; + // Free up memory + free(length_str); + } else if(value->IsFunction()) { + } else if(value->IsObject()) { + // printf("================================ calculate_object_size:object\n"); + // Unwrap the object + Local object = value->ToObject(); + Local property_names = object->GetPropertyNames(); + + // Process all the properties on the object + for(uint32_t index = 0; index < property_names->Length(); index++) { + // printf("================================ calculate_object_size:string\n"); + + // Fetch the property name + Local property_name = property_names->Get(index)->ToString(); + + // Convert name to char* + ssize_t len = DecodeBytes(property_name, UTF8); + + // Local str = property_names->Get(index)->ToString(); + // uint32_t utf8_length = str->Utf8Length(); + + // if(utf8_length != str->Length()) { + // // Let's calculate the size the string adds, length + type(1 byte) + size(4 bytes) + // object_size += str->Utf8Length() + 1 + 4; + // } else { + // object_size += str->Length() + 1 + 4; + // } + + + // Fetch the property name + // Local property_name = property_names->Get(index)->ToString(); + + // Fetch the object for the property + Local property = object->Get(property_name); + // Get size of property (property + property name length + 1 for terminating 0) + // object_size += BSON::calculate_object_size(property) + property_name->Length() + 1 + 1; + object_size += BSON::calculate_object_size(property) + len + 1 + 1; + } + + object_size = object_size + 4 + 1; + } + + return object_size; +} + +Handle BSON::BSONDeserialize(const Arguments &args) { + HandleScope scope; + // printf("= BSONDeserialize ===================================== USING Native BSON Parser\n"); + // Ensure that we have an parameter + if(Buffer::HasInstance(args[0]) && args.Length() > 1) return VException("One argument required - buffer1."); + if(args[0]->IsString() && args.Length() > 1) return VException("One argument required - string1."); + // Throw an exception if the argument is not of type Buffer + if(!Buffer::HasInstance(args[0]) && !args[0]->IsString()) return VException("Argument must be a Buffer or String."); + + // Define pointer to data + char *data; + uint32_t length; + Local obj = args[0]->ToObject(); + + // If we passed in a buffer, let's unpack it, otherwise let's unpack the string + if(Buffer::HasInstance(obj)) { + + #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3 + Buffer *buffer = ObjectWrap::Unwrap(obj); + data = buffer->data(); + uint32_t length = buffer->length(); + #else + data = Buffer::Data(obj); + uint32_t length = Buffer::Length(obj); + #endif + + return BSON::deserialize(data, NULL); + } else { + // Let's fetch the encoding + // enum encoding enc = ParseEncoding(args[1]); + // The length of the data for this encoding + ssize_t len = DecodeBytes(args[0], BINARY); + // Let's define the buffer size + // data = new char[len]; + data = (char *)malloc(len); + // Write the data to the buffer from the string object + ssize_t written = DecodeWrite(data, len, args[0], BINARY); + // Assert that we wrote the same number of bytes as we have length + assert(written == len); + // Get result + Handle result = BSON::deserialize(data, NULL); + // Free memory + free(data); + // Deserialize the content + return result; + } +} + +// Deserialize the stream +Handle BSON::deserialize(char *data, bool is_array_item) { + // printf("----------------------------------------------------------------- deserialize\n"); + HandleScope scope; + // Holds references to the objects that are going to be returned + Local return_data = Object::New(); + Local return_array = Array::New(); + // The current index in the char data + uint32_t index = 0; + // Decode the size of the BSON data structure + uint32_t size = BSON::deserialize_int32(data, index); + // Adjust the index to point to next piece + index = index + 4; + + // for(int n = 0; n < size; n++) { + // printf("C:: ============ %02x\n",(unsigned char)data[n]); + // } + // + // for(int n = 0; s_value[n] != '\0'; n++) { + // printf("C:: ============ %02x\n",(unsigned char)s_value[n]); + // } + + // While we have data left let's decode + while(index < size) { + // Read the first to bytes to indicate the type of object we are decoding + uint16_t type = BSON::deserialize_int8(data, index); + // Handles the internal size of the object + uint32_t insert_index = 0; + // Adjust index to skip type byte + index = index + 1; + + if(type == BSON_DATA_STRING) { + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Read the length of the string (next 4 bytes) + uint32_t string_size = BSON::deserialize_int32(data, index); + // Adjust index to point to start of string + index = index + 4; + // Decode the string and add zero terminating value at the end of the string + char *value = (char *)malloc((string_size * sizeof(char))); + strncpy(value, (data + index), string_size); + // Encode the string (string - null termiating character) + Local utf8_encoded_str = Encode(value, string_size - 1, UTF8)->ToString(); + // Add the value to the data + if(is_array_item) { + return_array->Set(Number::New(insert_index), utf8_encoded_str); + } else { + return_data->Set(String::New(string_name), utf8_encoded_str); + } + + // Adjust index + index = index + string_size; + // Free up the memory + free(value); + free(string_name); + } else if(type == BSON_DATA_INT) { + // printf("===================================== decoding int\n"); + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // printf("================== label: %s\n", string_name); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Decode the integer value + uint32_t value = 0; + memcpy(&value, (data + index), 4); + + // Adjust the index for the size of the value + index = index + 4; + // Add the element to the object + if(is_array_item) { + // printf("=================== wow\n"); + return_array->Set(Integer::New(insert_index), Integer::New(value)); + } else { + return_data->Set(String::New(string_name), Integer::New(value)); + } + // Free up the memory + free(string_name); + } else if(type == BSON_DATA_TIMESTAMP) { + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Decode the integer value + int64_t value = 0; + memcpy(&value, (data + index), 8); + // Adjust the index for the size of the value + index = index + 8; + + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), BSON::decodeTimestamp(value)); + } else { + return_data->Set(String::New(string_name), BSON::decodeTimestamp(value)); + } + // Free up the memory + free(string_name); + } else if(type == BSON_DATA_LONG) { + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Decode the integer value + int64_t value = 0; + memcpy(&value, (data + index), 8); + // Adjust the index for the size of the value + index = index + 8; + + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), BSON::decodeLong(value)); + } else { + return_data->Set(String::New(string_name), BSON::decodeLong(value)); + } + // Free up the memory + free(string_name); + } else if(type == BSON_DATA_NUMBER) { + // printf("===================================== decoding float/double\n"); + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Decode the integer value + double value = 0; + memcpy(&value, (data + index), 8); + // Adjust the index for the size of the value + index = index + 8; + + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), Number::New(value)); + } else { + return_data->Set(String::New(string_name), Number::New(value)); + } + // Free up the memory + free(string_name); + } else if(type == BSON_DATA_NULL) { + // printf("===================================== decoding float/double\n"); + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), Null()); + } else { + return_data->Set(String::New(string_name), Null()); + } + // Free up the memory + free(string_name); + } else if(type == BSON_DATA_BOOLEAN) { + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Decode the boolean value + char bool_value = *(data + index); + // Adjust the index for the size of the value + index = index + 1; + + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), bool_value == 1 ? Boolean::New(true) : Boolean::New(false)); + } else { + return_data->Set(String::New(string_name), bool_value == 1 ? Boolean::New(true) : Boolean::New(false)); + } + // Free up the memory + free(string_name); + } else if(type == BSON_DATA_DATE) { + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Decode the value 64 bit integer + int64_t value = 0; + memcpy(&value, (data + index), 8); + // Adjust the index for the size of the value + index = index + 8; + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), Date::New((double)value)); + } else { + return_data->Set(String::New(string_name), Date::New((double)value)); + } + // Free up the memory + free(string_name); + } else if(type == BSON_DATA_REGEXP) { + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Length variable + int32_t length_regexp = 0; + int32_t start_index = index; + char chr; + + // Locate end of the regexp expression \0 + while((chr = *(data + index + length_regexp)) != '\0') { + length_regexp = length_regexp + 1; + } + + // Contains the reg exp + char *reg_exp = (char *)malloc(length_regexp * sizeof(char) + 2); + // Copy the regexp from the data to the char * + memcpy(reg_exp, (data + index), (length_regexp + 1)); + // Adjust the index to skip the first part of the regular expression + index = index + length_regexp + 1; + + // Reset the length + int32_t options_length = 0; + // Locate the end of the options for the regexp terminated with a '\0' + while((chr = *(data + index + options_length)) != '\0') { + options_length = options_length + 1; + } + + // Contains the reg exp + char *options = (char *)malloc(options_length * sizeof(char) + 1); + // Copy the options from the data to the char * + memcpy(options, (data + index), (options_length + 1)); + // Adjust the index to skip the option part of the regular expression + index = index + options_length + 1; + // ARRRRGH Google does not expose regular expressions through the v8 api + // Have to use Script to instantiate the object (slower) + + // Generate the string for execution in the string context + int flag = 0; + + for(int i = 0; i < options_length; i++) { + // Multiline + if(*(options + i) == 'm') { + flag = flag | 4; + } else if(*(options + i) == 'i') { + flag = flag | 2; + } + } + + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), RegExp::New(String::New(reg_exp), (v8::RegExp::Flags)flag)); + } else { + return_data->Set(String::New(string_name), RegExp::New(String::New(reg_exp), (v8::RegExp::Flags)flag)); + } + + // Free memory + free(reg_exp); + free(options); + free(string_name); + } else if(type == BSON_DATA_OID) { + // printf("=================================================== unpacking oid\n"); + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Allocate storage for a 24 character hex oid + char *oid_string = (char *)malloc(12 * 2 * sizeof(char) + 1); + char *pbuffer = oid_string; + // Terminate the string + *(pbuffer + 24) = '\0'; + // Unpack the oid in hex form + for(int32_t i = 0; i < 12; i++) { + sprintf(pbuffer, "%02x", (unsigned char)*(data + index + i)); + pbuffer += 2; + } + + // Adjust the index + index = index + 12; + + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), BSON::decodeOid(oid_string)); + } else { + return_data->Set(String::New(string_name), BSON::decodeOid(oid_string)); + } + // Free memory + free(oid_string); + free(string_name); + } else if(type == BSON_DATA_BINARY) { + // printf("=================================================== unpacking binary\n"); + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Read the binary data size + uint32_t number_of_bytes = BSON::deserialize_int32(data, index); + // Adjust the index + index = index + 4; + // Decode the subtype, ensure it's positive + uint32_t sub_type = (int)*(data + index) & 0xff; + // Adjust the index + index = index + 1; + // Copy the binary data into a buffer + char *buffer = (char *)malloc(number_of_bytes * sizeof(char) + 1); + memcpy(buffer, (data + index), number_of_bytes); + *(buffer + number_of_bytes) = '\0'; + // Adjust the index + index = index + number_of_bytes; + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), BSON::decodeBinary(sub_type, number_of_bytes, buffer)); + } else { + return_data->Set(String::New(string_name), BSON::decodeBinary(sub_type, number_of_bytes, buffer)); + } + // Free memory + free(buffer); + free(string_name); + } else if(type == BSON_DATA_CODE_W_SCOPE) { + // printf("=================================================== unpacking code\n"); + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Total number of bytes after array index + uint32_t total_code_size = BSON::deserialize_int32(data, index); + // Adjust the index + index = index + 4; + // Read the string size + uint32_t string_size = BSON::deserialize_int32(data, index); + // Adjust the index + index = index + 4; + // Read the string + char *code = (char *)malloc(string_size * sizeof(char) + 1); + // Copy string + terminating 0 + memcpy(code, (data + index), string_size); + // Adjust the index + index = index + string_size; + // Get the scope object (bson object) + uint32_t bson_object_size = total_code_size - string_size - 8; + // Allocate bson object buffer and copy out the content + char *bson_buffer = (char *)malloc(bson_object_size * sizeof(char)); + memcpy(bson_buffer, (data + index), bson_object_size); + // Adjust the index + index = index + bson_object_size; + // Parse the bson object + Handle scope_object = BSON::deserialize(bson_buffer, false); + // Define the try catch block + TryCatch try_catch; + // Decode the code object + Handle obj = BSON::decodeCode(code, scope_object); + // If an error was thrown push it up the chain + if(try_catch.HasCaught()) { + // Clean up memory allocation + free(bson_buffer); + // Rethrow exception + return try_catch.ReThrow(); + } + + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), obj); + } else { + return_data->Set(String::New(string_name), obj); + } + // Clean up memory allocation + free(bson_buffer); + free(string_name); + } else if(type == BSON_DATA_OBJECT) { + // printf("=================================================== unpacking object\n"); + // If this is the top level object we need to skip the undecoding + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Get the object size + uint32_t bson_object_size = BSON::deserialize_int32(data, index); + // Define the try catch block + TryCatch try_catch; + // Decode the code object + Handle obj = BSON::deserialize(data + index, false); + // Adjust the index + index = index + bson_object_size; + // If an error was thrown push it up the chain + if(try_catch.HasCaught()) { + // Rethrow exception + return try_catch.ReThrow(); + } + + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), obj); + } else { + return_data->Set(String::New(string_name), obj); + } + + // Clean up memory allocation + free(string_name); + } else if(type == BSON_DATA_ARRAY) { + // printf("=================================================== unpacking array\n"); + // Read the null terminated index String + char *string_name = BSON::extract_string(data, index); + if(string_name == NULL) return VException("Invalid C String found."); + // Let's create a new string + index = index + strlen(string_name) + 1; + // Handle array value if applicable + uint32_t insert_index = 0; + if(is_array_item) { + insert_index = atoi(string_name); + } + + // Get the size + uint32_t array_size = BSON::deserialize_int32(data, index); + // Define the try catch block + TryCatch try_catch; + + // Decode the code object + Handle obj = BSON::deserialize(data + index, true); + // If an error was thrown push it up the chain + if(try_catch.HasCaught()) { + // Rethrow exception + return try_catch.ReThrow(); + } + // Adjust the index for the next value + index = index + array_size; + // Add the element to the object + if(is_array_item) { + return_array->Set(Number::New(insert_index), obj); + } else { + return_data->Set(String::New(string_name), obj); + } + // Clean up memory allocation + free(string_name); + } + } + + // Check if we have a db reference + if(!is_array_item && return_data->Has(String::New("$ref")) && return_data->Has(String::New("$id"))) { + Handle dbref_value; + dbref_value = BSON::decodeDBref(return_data->Get(String::New("$ref")), return_data->Get(String::New("$id")), return_data->Get(String::New("$db"))); + return scope.Close(dbref_value); + } + + // Return the data object to javascript + if(is_array_item) { + return scope.Close(return_array); + } else { + return scope.Close(return_data); + } +} + +const char* BSON::ToCString(const v8::String::Utf8Value& value) { + return *value ? *value : ""; +} + +Handle BSON::decodeDBref(Local ref, Local oid, Local db) { + HandleScope scope; + Local argv[] = {ref, oid, db}; + Handle dbref_obj = DBRef::constructor_template->GetFunction()->NewInstance(3, argv); + return scope.Close(dbref_obj); +} + +Handle BSON::decodeCode(char *code, Handle scope_object) { + HandleScope scope; + + Local argv[] = {String::New(code), scope_object->ToObject()}; + Handle code_obj = Code::constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(code_obj); +} + +Handle BSON::decodeBinary(uint32_t sub_type, uint32_t number_of_bytes, char *data) { + HandleScope scope; + + Local str = Encode(data, number_of_bytes, BINARY)->ToString(); + Local argv[] = {str, Integer::New(sub_type)}; + Handle binary_obj = Binary::constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(binary_obj); +} + +Handle BSON::decodeOid(char *oid) { + HandleScope scope; + + Local argv[] = {String::New(oid)}; + Handle oid_obj = ObjectID::constructor_template->GetFunction()->NewInstance(1, argv); + return scope.Close(oid_obj); +} + +Handle BSON::decodeLong(int64_t value) { + HandleScope scope; + + // If precise return number + if(value < 0x20000000000000 && value >= -0x20000000000000) { + return scope.Close(Number::New(value)); + } + // Otherwise return long value + Local argv[] = {Number::New(value)}; + Handle long_obj = Long::constructor_template->GetFunction()->NewInstance(1, argv); + return scope.Close(long_obj); +} + +Handle BSON::decodeTimestamp(int64_t value) { + HandleScope scope; + + Local argv[] = {Number::New(value)}; + Handle timestamp_obj = Timestamp::constructor_template->GetFunction()->NewInstance(1, argv); + return scope.Close(timestamp_obj); +} + +// Search for 0 terminated C string and return the string +char* BSON::extract_string(char *data, uint32_t offset) { + char *prt = strchr((data + offset), '\0'); + if(prt == NULL) return NULL; + // Figure out the length of the string + uint32_t length = (prt - data) - offset; + // Allocate memory for the new string + char *string_name = (char *)malloc((length * sizeof(char)) + 1); + // Copy the variable into the string_name + strncpy(string_name, (data + offset), length); + // Ensure the string is null terminated + *(string_name + length) = '\0'; + // Return the unpacked string + return string_name; +} + +// Decode a signed byte +int BSON::deserialize_sint8(char *data, uint32_t offset) { + return (signed char)(*(data + offset)); +} + +int BSON::deserialize_sint16(char *data, uint32_t offset) { + return BSON::deserialize_sint8(data, offset) + (BSON::deserialize_sint8(data, offset + 1) << 8); +} + +long BSON::deserialize_sint32(char *data, uint32_t offset) { + return (long)BSON::deserialize_sint8(data, offset) + (BSON::deserialize_sint8(data, offset + 1) << 8) + + (BSON::deserialize_sint8(data, offset + 2) << 16) + (BSON::deserialize_sint8(data, offset + 3) << 24); +} + +// Convert raw binary string to utf8 encoded string +char *BSON::decode_utf8(char *string, uint32_t length) { + // Internal variables + uint32_t i = 0; + uint32_t utf8_i = 0; + // unsigned char unicode = 0; + uint16_t unicode = 0; + unsigned char c = 0; + unsigned char c1 = 0; + unsigned char c2 = 0; + unsigned char c3 = 0; + // Allocate enough space for the utf8 encoded string + char *utf8_string = (char*)malloc(length * sizeof(char)); + // Process the utf8 raw string + while(i < length) { + // Fetch character + c = (unsigned char)string[i]; + + if(c < 128) { + // // It's a basic ascii character just copy the string + *(utf8_string + utf8_i) = *(string + i); + // Upadate indexs + i = i + 1; + utf8_i = utf8_i + 1; + } else if((c > 191) && (c < 224)) { + // Let's create an integer containing the 16 bit value for unicode + c2 = (unsigned char)string[i + 1]; + // Pack to unicode value + unicode = (uint16_t)(((c & 31) << 6) | (c2 & 63)); + // Write the int 16 to the string and upate index + memcpy((utf8_string + utf8_i), &unicode, 2); + // Upadate index + i = i + 2; + utf8_i = utf8_i + 2; + } else { + // // Let's create the integers containing the 16 bit value for unicode + c2 = (unsigned char)string[i + 1]; + c3 = (unsigned char)string[i + 2]; + // Pack to unicode value + unicode = (uint16_t)(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + // Write the int 16 to the string and upate index + memcpy((utf8_string + utf8_i), &unicode, 2); + // Upadate indexs + i = i + 3; + utf8_i = utf8_i + 2; + } + } + // Add null termiating character + *(utf8_string + utf8_i + 1) = '\0'; + // Return pointer of converted string + return utf8_string; +} + +// Decode a byte +uint16_t BSON::deserialize_int8(char *data, uint32_t offset) { + uint16_t value = 0; + value |= *(data + offset + 0); + return value; +} + +// Requires a 4 byte char array +uint32_t BSON::deserialize_int32(char* data, uint32_t offset) { + uint32_t value = 0; + memcpy(&value, (data + offset), 4); + return value; +} + +// Exporting function +extern "C" void init(Handle target) { + HandleScope scope; + BSON::Initialize(target); + Long::Initialize(target); + ObjectID::Initialize(target); + Binary::Initialize(target); + Code::Initialize(target); + DBRef::Initialize(target); + Timestamp::Initialize(target); +} + +// NODE_MODULE(bson, BSON::Initialize); +// NODE_MODULE(l, Long::Initialize); diff --git a/node_modules/mongodb/external-libs/bson/bson.h b/node_modules/mongodb/external-libs/bson/bson.h new file mode 100644 index 0000000..70f975c --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/bson.h @@ -0,0 +1,61 @@ +#ifndef BSON_H_ +#define BSON_H_ + +#include +#include +#include + +using namespace v8; +using namespace node; + +class BSON : public EventEmitter { + public: + BSON() : EventEmitter() {} + ~BSON() {} + + static void Initialize(Handle target); + static Handle BSONSerialize(const Arguments &args); + static Handle BSONDeserialize(const Arguments &args); + + // Encode functions + static Handle EncodeLong(const Arguments &args); + static Handle ToLong(const Arguments &args); + static Handle ToInt(const Arguments &args); + + // Calculate size of function + static Handle CalculateObjectSize(const Arguments &args); + static Handle SerializeWithBufferAndIndex(const Arguments &args); + + // Constructor used for creating new BSON objects from C++ + static Persistent constructor_template; + + private: + static Handle New(const Arguments &args); + static Handle deserialize(char *data, bool is_array_item); + static uint32_t serialize(char *serialized_object, uint32_t index, Handle name, Handle value, bool check_key); + + static char* extract_string(char *data, uint32_t offset); + static const char* ToCString(const v8::String::Utf8Value& value); + static uint32_t calculate_object_size(Handle object); + + static void write_int32(char *data, uint32_t value); + static void write_int64(char *data, int64_t value); + static void write_double(char *data, double value); + static int deserialize_sint8(char *data, uint32_t offset); + static int deserialize_sint16(char *data, uint32_t offset); + static long deserialize_sint32(char *data, uint32_t offset); + static uint16_t deserialize_int8(char *data, uint32_t offset); + static uint32_t deserialize_int32(char* data, uint32_t offset); + static char *check_key(Local key); + static char *decode_utf8(char * string, uint32_t length); + + // Decode function + static Handle decodeLong(int64_t value); + static Handle decodeTimestamp(int64_t value); + static Handle decodeOid(char *oid); + static Handle decodeBinary(uint32_t sub_type, uint32_t number_of_bytes, char *data); + static Handle decodeCode(char *code, Handle scope); + static Handle decodeDBref(Local ref, Local oid, Local db); +}; + +#endif // BSON_H_ diff --git a/node_modules/mongodb/external-libs/bson/code.cc b/node_modules/mongodb/external-libs/bson/code.cc new file mode 100644 index 0000000..022e0ce --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/code.cc @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "code.h" + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); + }; + +Persistent Code::constructor_template; + +Code::Code(char *code, Persistent scope_object) : ObjectWrap() { + this->code = code; + this->scope_object = scope_object; +} + +Code::~Code() { + if(this->code != NULL) free(this->code); +} + +Handle Code::New(const Arguments &args) { + HandleScope scope; + + char *code; + Persistent scope_object; + Local str; + + if(args.Length() != 1 && args.Length() != 2) { + return VException("There must be either 1 or 2 arguments passed in where the first argument is a string and the second a object for the scope"); + } + + if(args.Length() == 1 && (!args[0]->IsString() && !args[0]->IsFunction())) { + return VException("There must be either 1 or 2 arguments passed in where the first argument is a string and the second a object for the scope"); + } + + if(args.Length() == 2 && (!args[0]->IsString() && !args[0]->IsFunction()) && !args[1]->IsObject()) { + return VException("There must be either 1 or 2 arguments passed in where the first argument is a string and the second a object for the scope"); + } + + if(args[0]->IsFunction()) { + str = args[0]->ToObject()->ToString(); + } else { + // Decode the string + str = args[0]->ToString(); + } + + // Set up the string + code = (char *)malloc(str->Length() * sizeof(char) + 1); + *(code + str->Length()) = '\0'; + // Copy over + node::DecodeWrite(code, str->Length(), str, node::BINARY); + // Decode the scope and wrap it in a persistent object to ensure + // v8 does not gc the object + if(args.Length() == 2) { + scope_object = Persistent::New(args[1]->ToObject()); + } else { + scope_object = Persistent::New(Object::New()); + } + + // Create code object + Code *code_obj = new Code(code, scope_object); + // Wrap it + code_obj->Wrap(args.This()); + // Return the object + return args.This(); +} + +static Persistent code_symbol; +static Persistent scope_symbol; + +void Code::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("Code")); + + // Propertry symbols + code_symbol = NODE_PSYMBOL("code"); + scope_symbol = NODE_PSYMBOL("scope"); + + // Getters for correct serialization of the object + constructor_template->InstanceTemplate()->SetAccessor(code_symbol, CodeGetter, CodeSetter); + constructor_template->InstanceTemplate()->SetAccessor(scope_symbol, ScopeGetter, ScopeSetter); + + // Instance methods + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toString", ToString); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "inspect", Inspect); + + target->Set(String::NewSymbol("Code"), constructor_template->GetFunction()); +} + +Handle Code::CodeGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack the long object + Code *code_obj = ObjectWrap::Unwrap(info.Holder()); + // Extract value doing a cast of the pointer to Long and accessing code + char *code = code_obj->code; + // Return the string + return scope.Close(String::New(code)); +} + +void Code::CodeSetter(Local property, Local value, const AccessorInfo& info) { + if(value->IsString()) { + // Unpack the long object + Code *code_obj = ObjectWrap::Unwrap(info.Holder()); + // Convert the value to a string + Local str = value->ToString(); + // Set up the string + char *code = (char *)malloc(str->Length() * sizeof(char) + 1); + *(code + str->Length()) = '\0'; + // Copy over + node::DecodeWrite(code, str->Length(), str, node::BINARY); + // Free existing pointer if any + if(code_obj->code != NULL) free(code_obj->code); + // Return the code + code_obj->code = code; + } +} + +Handle Code::ScopeGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack the long object + Code *code_obj = ObjectWrap::Unwrap(info.Holder()); + // Extracting value doing a cast of the pointer to Value + return scope.Close(code_obj->scope_object); +} + +void Code::ScopeSetter(Local property, Local value, const AccessorInfo& info) { + if(value->IsObject()) { + // Unpack the long object + Code *code_obj = ObjectWrap::Unwrap(info.Holder()); + // Fetch the local + Local value_obj = value->ToObject(); + // Set the low bits + code_obj->scope_object = Persistent::New(value_obj); + } +} + +Handle Code::Inspect(const Arguments &args) { + HandleScope scope; + + // Unpack the Binary object + Code *code = ObjectWrap::Unwrap(args.This()); + // Return a new Object + Local inspect_object = Object::New(); + inspect_object->Set(String::New("code"), String::New(code->code)); + inspect_object->Set(String::New("scope"), code->scope_object); + // Return the object + return scope.Close(inspect_object->ToString()); +} + +Handle Code::ToString(const Arguments &args) { + HandleScope scope; + + // Unpack the Binary object + // Binary *binary = ObjectWrap::Unwrap(args.This()); + // Return the raw data + // return String::New(binary->data); + return String::New("Code::ToString"); +} + + + + + + + + + diff --git a/node_modules/mongodb/external-libs/bson/code.h b/node_modules/mongodb/external-libs/bson/code.h new file mode 100644 index 0000000..50e929c --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/code.h @@ -0,0 +1,44 @@ +#ifndef CODE_H_ +#define CODE_H_ + +#include +#include +#include + +using namespace v8; +using namespace node; + +class Code : public ObjectWrap { + public: + char *code; + Persistent scope_object; + + Code(char *code, Persistent scope_object); + ~Code(); + + // Has instance check + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + } + + // Functions available from V8 + static void Initialize(Handle target); + static Handle ToString(const Arguments &args); + static Handle Inspect(const Arguments &args); + + // Constructor used for creating new Long objects from C++ + static Persistent constructor_template; + + // Setters and Getters for internal properties + static Handle CodeGetter(Local property, const AccessorInfo& info); + static void CodeSetter(Local property, Local value, const AccessorInfo& info); + static Handle ScopeGetter(Local property, const AccessorInfo& info); + static void ScopeSetter(Local property, Local value, const AccessorInfo& info); + + private: + static Handle New(const Arguments &args); +}; + +#endif // CODE_H_ \ No newline at end of file diff --git a/node_modules/mongodb/external-libs/bson/dbref.cc b/node_modules/mongodb/external-libs/bson/dbref.cc new file mode 100644 index 0000000..1b1f3e4 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/dbref.cc @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dbref.h" +#include "objectid.h" + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); + }; + +Persistent DBRef::constructor_template; + +DBRef::DBRef(char *ref, Persistent oid, char *db) : ObjectWrap() { + this->ref = ref; + this->oid = oid; + this->db = db; +} + +DBRef::~DBRef() { + if(this->ref != NULL) free(this->ref); + if(this->db != NULL) free(this->db); +} + +Handle DBRef::New(const Arguments &args) { + HandleScope scope; + + // Ensure we have the parameters needed + if(args.Length() != 2 && args.Length() != 3) return VException("Two or Three arguments needed [String, String|ObjectID, String|Null]"); + + // Initialize the objectid + char *db_data = NULL; + + // Unpack the values and create the associated objects + Local ref = args[0]->ToString(); + + // Persist the oid key object + Persistent oid_value = Persistent::New(args[1]); + + // Decode the db object + if(args.Length() == 3 && args[2]->IsString()) { + // Decode the db string + Local db = args[2]->ToString(); + // Unpack the db variable as char * + db_data = (char *)malloc(db->Length() + 1); + node::DecodeWrite(db_data, db->Length(), db, node::BINARY); + *(db_data + db->Length()) = '\0'; + } + + // Unpack the variables as char* + char *ref_data = (char *)malloc(ref->Length() + 1); + node::DecodeWrite(ref_data, ref->Length(), ref, node::BINARY); + *(ref_data + ref->Length()) = '\0'; + + // Create a db ref object + DBRef *dbref = new DBRef(ref_data, oid_value, db_data); + // Return the reference object + dbref->Wrap(args.This()); + // Return the object + return args.This(); +} + +static Persistent namespace_symbol; +static Persistent oid_symbol; +static Persistent db_symbol; + +static Persistent namespace_json_symbol; +static Persistent oid_json_symbol; +static Persistent db_json_symbol; +// static Persistent id_symbol; + +void DBRef::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("DBRef")); + + // Propertry symbols + namespace_symbol = NODE_PSYMBOL("namespace"); + oid_symbol = NODE_PSYMBOL("oid"); + db_symbol = NODE_PSYMBOL("db"); + + namespace_json_symbol = NODE_PSYMBOL("$ref"); + oid_json_symbol = NODE_PSYMBOL("$id"); + db_json_symbol = NODE_PSYMBOL("$db"); + // id_symbol = NODE_PSYMBOL("id"); + + // Getters for correct serialization of the object + constructor_template->InstanceTemplate()->SetAccessor(namespace_symbol, NamespaceGetter, NamespaceSetter); + constructor_template->InstanceTemplate()->SetAccessor(oid_symbol, OidGetter, OidSetter); + constructor_template->InstanceTemplate()->SetAccessor(db_symbol, DbGetter, DbSetter); + // constructor_template->InstanceTemplate()->SetAccessor(id_symbol, IdGetter, IdSetter); + + // Instance methods + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toString", ToString); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "inspect", Inspect); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toJSON", ToJSON); + + target->Set(String::NewSymbol("DBRef"), constructor_template->GetFunction()); +} + +// Namespace setter/getter +Handle DBRef::NamespaceGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack the long object + DBRef *dbref_obj = ObjectWrap::Unwrap(info.Holder()); + // Char value + char *value = dbref_obj->ref; + // Return the value + return scope.Close(String::New(value)); +} + +void DBRef::NamespaceSetter(Local property, Local value, const AccessorInfo& info) { + HandleScope scope; +} + +// oid setter/getter +Handle DBRef::OidGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack the long object + DBRef *dbref_obj = ObjectWrap::Unwrap(info.Holder()); + // Return the oid + return scope.Close(dbref_obj->oid); +} + +void DBRef::OidSetter(Local property, Local value, const AccessorInfo& info) { + HandleScope scope; +} + +// db setter/getter +Handle DBRef::DbGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack the long object + DBRef *dbref_obj = ObjectWrap::Unwrap(info.Holder()); + + // Char value + if(dbref_obj->db == NULL) { + return scope.Close(Null()); + } + + char *value = dbref_obj->db; + // Return the value + return scope.Close(String::New(value)); +} + +void DBRef::DbSetter(Local property, Local value, const AccessorInfo& info) { + HandleScope scope; +} + +Handle DBRef::Inspect(const Arguments &args) { + HandleScope scope; + return ToJSON(args); +} + +Handle DBRef::ToString(const Arguments &args) { + HandleScope scope; + return ToJSON(args); +} + +Handle DBRef::ToJSON(const Arguments &args) { + HandleScope scope; + + DBRef *dbref_obj = ObjectWrap::Unwrap (args.This()); + Local ret = Object::New(); + if (dbref_obj->ref) { + ret->Set(namespace_json_symbol, String::New(dbref_obj->ref)); + } + ret->Set(oid_json_symbol, dbref_obj->oid); + if (dbref_obj->db) { + ret->Set(db_json_symbol, String::New(dbref_obj->db)); + } + return scope.Close(ret); +} + + + + + + + diff --git a/node_modules/mongodb/external-libs/bson/dbref.h b/node_modules/mongodb/external-libs/bson/dbref.h new file mode 100644 index 0000000..7bacadb --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/dbref.h @@ -0,0 +1,49 @@ +#ifndef DBREF_H_ +#define DBREF_H_ + +#include +#include +#include +#include "objectid.h" + +using namespace v8; +using namespace node; + +class DBRef : public ObjectWrap { + public: + char *ref; + Persistent oid; + char *db; + + DBRef(char *ref, Persistent oid, char *db); + ~DBRef(); + + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + } + + // Functions available from V8 + static void Initialize(Handle target); + static Handle ToString(const Arguments &args); + static Handle Inspect(const Arguments &args); + static Handle ToJSON(const Arguments &args); + + // Properties + static Handle NamespaceGetter(Local property, const AccessorInfo& info); + static void NamespaceSetter(Local property, Local value, const AccessorInfo& info); + static Handle OidGetter(Local property, const AccessorInfo& info); + static void OidSetter(Local property, Local value, const AccessorInfo& info); + static Handle IdGetter(Local property, const AccessorInfo& info); + static void IdSetter(Local property, Local value, const AccessorInfo& info); + static Handle DbGetter(Local property, const AccessorInfo& info); + static void DbSetter(Local property, Local value, const AccessorInfo& info); + + // Constructor used for creating new Long objects from C++ + static Persistent constructor_template; + private: + static Handle New(const Arguments &args); +}; + +#endif // DBREF_H_ \ No newline at end of file diff --git a/node_modules/mongodb/external-libs/bson/index.js b/node_modules/mongodb/external-libs/bson/index.js new file mode 100644 index 0000000..61ba959 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/index.js @@ -0,0 +1,16 @@ +var bson = require('./bson'); +exports.BSON = bson.BSON; +exports.Long = bson.Long; +exports.ObjectID = bson.ObjectID; +exports.DBRef = bson.DBRef; +exports.Code = bson.Code; +exports.Timestamp = bson.Timestamp; +exports.Binary = bson.Binary; + +// Just add constants tot he Native BSON parser +exports.BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0; +exports.BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1; +exports.BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; +exports.BSON.BSON_BINARY_SUBTYPE_UUID = 3; +exports.BSON.BSON_BINARY_SUBTYPE_MD5 = 4; +exports.BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128; diff --git a/node_modules/mongodb/external-libs/bson/local.cc b/node_modules/mongodb/external-libs/bson/local.cc new file mode 100644 index 0000000..fbefdf4 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/local.cc @@ -0,0 +1,14 @@ +#if defined(__sun) +namespace std +{ + int isnan (int x) { return x != x; } + int isnan (float x) { return x != x; } + int isnan (double x) { return x != x; } + int isnan (long double x) { return x != x; } + + int isinf(int x) { return !isnan (x) && isnan (x - x); } + int isinf(float x) { return !isnan (x) && isnan (x - x); } + int isinf(double x) { return !isnan (x) && isnan (x - x); } + int isinf(long double x) { return !isnan (x) && isnan (x - x); } +} +#endif \ No newline at end of file diff --git a/node_modules/mongodb/external-libs/bson/local.h b/node_modules/mongodb/external-libs/bson/local.h new file mode 100644 index 0000000..54f14ae --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/local.h @@ -0,0 +1,14 @@ +#if defined(__sun) +namespace std +{ + int isnan (int x); + int isnan (float x); + int isnan (double x); + int isnan (long double x); + + int isinf(int x); + int isinf(float x); + int isinf(double x); + int isinf(long double x); +} +#endif \ No newline at end of file diff --git a/node_modules/mongodb/external-libs/bson/long.cc b/node_modules/mongodb/external-libs/bson/long.cc new file mode 100644 index 0000000..75c6cf3 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/long.cc @@ -0,0 +1,596 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "local.h" +#include "long.h" + +// BSON MAX VALUES +const int32_t BSON_INT32_MAX = (int32_t)2147483648L; +const int32_t BSON_INT32_MIN = (int32_t)(-1) * 2147483648L; +const int64_t BSON_INT32_ = pow(2, 32); + +const double LN2 = 0.6931471805599453; + +// Max Values +const int64_t BSON_INT64_MAX = (int64_t)9223372036854775807LL; +const int64_t BSON_INT64_MIN = (int64_t)(-1)*(9223372036854775807LL); + +// Constant objects used in calculations +Long* LONG_MIN_VALUE = Long::fromBits(0, 0x80000000 | 0); +Long* LONG_MAX_VALUE = Long::fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); +Long* LONG_ZERO = Long::fromInt(0); +Long* LONG_ONE = Long::fromInt(1); +Long* LONG_NEG_ONE = Long::fromInt(-1); + + +const int32_t LONG_BUFFER_SIZE = 64; + +#define max(a,b) ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; }) + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); + }; + +Persistent Long::constructor_template; + +static Persistent low_bits_symbol; +static Persistent high_bits_symbol; + +Long::Long(int32_t low_bits, int32_t high_bits) : ObjectWrap() { + this->low_bits = low_bits; + this->high_bits = high_bits; +} + +Long::~Long() {} + +Handle Long::New(const Arguments &args) { + HandleScope scope; + + // Ensure that we have an parameter + if(args.Length() == 1 && args[0]->IsNumber()) { + // Unpack the value + double value = args[0]->NumberValue(); + // Create an instance of long + Long *l = Long::fromNumber(value); + // Wrap it in the object wrap + l->Wrap(args.This()); + // Return the context + return args.This(); + } else if(args.Length() == 2 && args[0]->IsNumber() && args[1]->IsNumber()) { + // Unpack the value + int32_t low_bits = args[0]->Int32Value(); + int32_t high_bits = args[1]->Int32Value(); + // Create an instance of long + Long *l = new Long(low_bits, high_bits); + // Wrap it in the object wrap + l->Wrap(args.This()); + // Return the context + return args.This(); + } else if(args.Length() == 2 && args[0]->IsString() && args[1]->IsString()) { + // Parse the strings into int32_t values + int32_t low_bits = 0; + int32_t high_bits = 0; + + // Let's write the strings to the bits + DecodeWrite((char*)&low_bits, 4, args[0]->ToString(), BINARY); + DecodeWrite((char*)&high_bits, 4, args[1]->ToString(), BINARY); + + // Create an instance of long + Long *l = new Long(low_bits, high_bits); + // Wrap it in the object wrap + l->Wrap(args.This()); + // Return the context + return args.This(); + } else { + return VException("Argument passed in must be either a 64 bit number or two 32 bit numbers."); + } +} + +void Long::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("Long")); + + // Propertry symbols + low_bits_symbol = NODE_PSYMBOL("low_"); + high_bits_symbol = NODE_PSYMBOL("high_"); + + // Instance methods + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toString", ToString); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "isZero", IsZero); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "getLowBits", GetLowBits); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "getHighBits", GetHighBits); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "inspect", Inspect); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "greaterThan", GreatherThan); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toInt", ToInt); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toNumber", ToNumber); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toJSON", ToJSON); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "equals", Equals); + + // Getters for correct serialization of the object + constructor_template->InstanceTemplate()->SetAccessor(low_bits_symbol, LowGetter, LowSetter); + constructor_template->InstanceTemplate()->SetAccessor(high_bits_symbol, HighGetter, HighSetter); + + // Class methods + NODE_SET_METHOD(constructor_template->GetFunction(), "fromNumber", FromNumber); + NODE_SET_METHOD(constructor_template->GetFunction(), "fromInt", FromInt); + + // Add class to scope + target->Set(String::NewSymbol("Long"), constructor_template->GetFunction()); +} + +Handle Long::ToInt(const Arguments &args) { + HandleScope scope; + + // Let's unpack the Long instance that contains the number in low_bits and high_bits form + Long *l = ObjectWrap::Unwrap(args.This()); + // Get lower bits + uint32_t low_bits = l->low_bits; + // Return the value + return Int32::New(low_bits); +} + +Handle Long::ToNumber(const Arguments &args) { + HandleScope scope; + // Let's unpack the Long instance that contains the number in low_bits and high_bits form + Long *l = ObjectWrap::Unwrap(args.This()); + return Number::New(l->toNumber()); +} + + +Handle Long::LowGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack the long object + Long *l = ObjectWrap::Unwrap(info.Holder()); + // Return the low bits + return Integer::New(l->low_bits); +} + +void Long::LowSetter(Local property, Local value, const AccessorInfo& info) { + if(value->IsNumber()) { + // Unpack the long object + Long *l = ObjectWrap::Unwrap(info.Holder()); + // Set the low bits + l->low_bits = value->Int32Value(); + } +} + +Handle Long::HighGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack the long object + Long *l = ObjectWrap::Unwrap(info.Holder()); + // Return the low bits + return Integer::New(l->high_bits); +} + +void Long::HighSetter(Local property, Local value, const AccessorInfo& info) { + if(value->IsNumber()) { + // Unpack the long object + Long *l = ObjectWrap::Unwrap(info.Holder()); + // Set the low bits + l->high_bits = value->Int32Value(); + } +} + +Handle Long::Inspect(const Arguments &args) { + return ToString(args); +} + +Handle Long::GetLowBits(const Arguments &args) { + HandleScope scope; + + // Let's unpack the Long instance that contains the number in low_bits and high_bits form + Long *l = ObjectWrap::Unwrap(args.This()); + // Let's fetch the low bits + int32_t low_bits = l->low_bits; + // Package the result in a V8 Integer object and return + return Integer::New(low_bits); +} + +Handle Long::GetHighBits(const Arguments &args) { + HandleScope scope; + + // Let's unpack the Long instance that contains the number in low_bits and high_bits form + Long *l = ObjectWrap::Unwrap(args.This()); + // Let's fetch the low bits + int32_t high_bits = l->high_bits; + // Package the result in a V8 Integer object and return + return Integer::New(high_bits); +} + +bool Long::isZero() { + int32_t low_bits = this->low_bits; + int32_t high_bits = this->high_bits; + return low_bits == 0 && high_bits == 0; +} + +bool Long::isNegative() { + int32_t low_bits = this->low_bits; + int32_t high_bits = this->high_bits; + return high_bits < 0; +} + +bool Long::equals(Long *l) { + int32_t low_bits = this->low_bits; + int32_t high_bits = this->high_bits; + return (high_bits == l->high_bits) && (low_bits == l->low_bits); +} + +Handle Long::IsZero(const Arguments &args) { + HandleScope scope; + + // Let's unpack the Long instance that contains the number in low_bits and high_bits form + Long *l = ObjectWrap::Unwrap(args.This()); + return Boolean::New(l->isZero()); +} + +int32_t Long::toInt() { + return this->low_bits; +} + +char *Long::toString(int32_t opt_radix, char *buffer) { + if (opt_radix == 10) { + if (isNegative()) { + sprintf(buffer,"%lld",toNumber()); + } + else { + sprintf(buffer,"%llu",toNumber()); + } + } + else if (opt_radix == 16) { + sprintf(buffer,"%llx",toNumber()); + } + else { + throw "Unsupported radix"; + } + + return buffer; +} + +Handle Long::ToString(const Arguments &args) { + HandleScope scope; + + Long *l = ObjectWrap::Unwrap(args.This()); + + char buffer[LONG_BUFFER_SIZE]; + l->toString(10,buffer); + + return String::New(buffer); +} + +Handle Long::ToJSON(const Arguments &args) { + return ToString(args); +} + +Long *Long::shiftRight(int32_t number_bits) { + number_bits &= 63; + if(number_bits == 0) { + return this; + } else { + int32_t high_bits = this->high_bits; + if(number_bits < 32) { + int32_t low_bits = this->low_bits; + return Long::fromBits((low_bits >> number_bits) | (high_bits << (32 - number_bits)), high_bits >> number_bits); + } else { + return Long::fromBits(high_bits >> (number_bits - 32), high_bits >= 0 ? 0 : -1); + } + } +} + +Long *Long::shiftLeft(int32_t number_bits) { + number_bits &= 63; + if(number_bits == 0) { + return this; + } else { + int32_t low_bits = this->low_bits; + if(number_bits < 32) { + int32_t high_bits = this->high_bits; + return Long::fromBits(low_bits << number_bits, (high_bits << number_bits) | (low_bits >> (32 - number_bits))); + } else { + return Long::fromBits(0, low_bits << (number_bits - 32)); + } + } +} + +Long *Long::div(Long *other) { + // If we are about to do a divide by zero throw an exception + if(other->isZero()) { + throw "division by zero"; + } else if(this->isZero()) { + return new Long(0, 0); + } + + if(this->equals(LONG_MIN_VALUE)) { + if(other->equals(LONG_ONE) || other->equals(LONG_NEG_ONE)) { + return Long::fromBits(0, 0x80000000 | 0); + } else if(other->equals(LONG_MIN_VALUE)) { + return Long::fromNumber(1); + } else { + Long *half_this = this->shiftRight(1); + Long *div_obj = half_this->div(other); + Long *approx = div_obj->shiftLeft(1); + // Free memory + delete div_obj; + delete half_this; + // Check if we are done + if(approx->equals(LONG_ZERO)) { + return other->isNegative() ? Long::fromNumber(0) : Long::fromNumber(-1); + } else { + Long *mul = other->multiply(approx); + Long *rem = this->subtract(mul); + Long *rem_div = rem->div(other); + Long *result = approx->add(rem_div); + // Free memory + delete mul; + delete rem; + delete rem_div; + // Return result + return result; + } + } + } else if(other->equals(LONG_MIN_VALUE)) { + return new Long(0, 0); + } + + // If the value is negative + if(this->isNegative()) { + if(other->isNegative()) { + Long *neg = this->negate(); + Long *other_neg = other->negate(); + Long *result = neg->div(other_neg); + // Free memory + delete neg; + delete other_neg; + // Return result + return result; + } else { + Long *neg = this->negate(); + Long *neg_result = neg->div(other); + Long *result = neg_result->negate(); + // Free memory + delete neg; + delete neg_result; + // Return result + return result; + } + } else if(other->isNegative()) { + Long *other_neg = other->negate(); + Long *div_result = this->div(other_neg); + Long *result = div_result->negate(); + // Free memory + delete other_neg; + delete div_result; + // Return the result + return result; + } + + int64_t this_number = this->toNumber(); + int64_t other_number = other->toNumber(); + int64_t result = this_number / other_number; + // Split into the 32 bit valu + int32_t low32, high32; + high32 = (uint64_t)result >> 32; + low32 = (int32_t)result; + return Long::fromBits(low32, high32); +} + +Long *Long::multiply(Long *other) { + if(this->isZero() || other->isZero()) { + return new Long(0, 0); + } + + int64_t this_number = this->toNumber(); + int64_t other_number = other->toNumber(); + int64_t result = this_number * other_number; + + // Split into the 32 bit valu + int32_t low32, high32; + high32 = (uint64_t)result >> 32; + low32 = (int32_t)result; + return Long::fromBits(low32, high32); +} + +bool Long::isOdd() { + return (this->low_bits & 1) == 1; +} + +// /** @return {number} The closest floating-point representation to this value. */ +// exports.Long.prototype.toNumber = function() { +// return this.high_ * exports.Long.TWO_PWR_32_DBL_ + +// this.getLowBitsUnsigned(); +// }; + +int64_t Long::toNumber() { + return (int64_t)(this->high_bits * BSON_INT32_ + this->getLowBitsUnsigned()); +} + +int64_t Long::getLowBitsUnsigned() { + return (this->low_bits >= 0) ? this->low_bits : BSON_INT32_ + this->low_bits; +} + +int64_t Long::compare(Long *other) { + if(this->equals(other)) { + return 0; + } + + bool this_neg = this->isNegative(); + bool other_neg = other->isNegative(); + if(this_neg && !other_neg) { + return -1; + } + if(!this_neg && other_neg) { + return 1; + } + + Long *return_value = this->subtract(other); + // At this point, the signs are the same, so subtraction will not overflow + if(return_value->isNegative()) { + delete return_value; + return -1; + } else { + delete return_value; + return 1; + } +} + +Long *Long::negate() { + if(this->equals(LONG_MIN_VALUE)) { + return LONG_MIN_VALUE; + } else { + Long *not_obj = this->not_(); + Long *add = not_obj->add(LONG_ONE); + delete not_obj; + return add; + } +} + +Long *Long::not_() { + return new Long(~this->low_bits, ~this->high_bits); +} + +Long *Long::add(Long *other) { + int64_t this_number = this->toNumber(); + int64_t other_number = other->toNumber(); + int64_t result = this_number + other_number; + // Split into the 32 bit valu + int32_t low32, high32; + high32 = (uint64_t)result >> 32; + low32 = (int32_t)result; + return Long::fromBits(low32, high32); +} + +Long *Long::subtract(Long *other) { + int64_t this_number = this->toNumber(); + int64_t other_number = other->toNumber(); + int64_t result = this_number - other_number; + // Split into the 32 bit valu + int32_t low32, high32; + high32 = (uint64_t)result >> 32; + low32 = (int32_t)result; + return Long::fromBits(low32, high32); +} + +Handle Long::GreatherThan(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 1 && !Long::HasInstance(args[0])) return VException("One argument of type Long required"); + + // Let's unpack the Long instance that contains the number in low_bits and high_bits form + Long *current_long_obj = ObjectWrap::Unwrap(args.This()); + // Unpack Long + Local obj = args[0]->ToObject(); + Long *long_obj = Long::Unwrap(obj); + // Compare the longs + bool comparision_result = current_long_obj->greaterThan(long_obj); + return scope.Close(Boolean::New(comparision_result)); +} + +Handle Long::Equals(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 1 && !Long::HasInstance(args[0])) return VException("One argument of type Long required"); + + // Let's unpack the Long instance that contains the number in low_bits and high_bits form + Long *current_long_obj = ObjectWrap::Unwrap(args.This()); + // Unpack Long + Local obj = args[0]->ToObject(); + Long *long_obj = Long::Unwrap(obj); + // Compare the longs + bool comparision_result = (current_long_obj->compare(long_obj) == 0); + return scope.Close(Boolean::New(comparision_result)); +} + +bool Long::greaterThan(Long *other) { + return this->compare(other) > 0; +} + +bool Long::greaterThanOrEqual(Long *other) { + return this->compare(other) >= 0; +} + +Handle Long::FromInt(const Arguments &args) { + HandleScope scope; + + // Validate the arguments + if(args.Length() != 1 && !args[0]->IsNumber()) return VException("One argument of type number required"); + // Unwrap Number variable + Local number = args[0]->ToNumber(); + // Instantiate Long object and return + Local argv[] = {number}; + Local long_obj = constructor_template->GetFunction()->NewInstance(1, argv); + return scope.Close(long_obj); +} + +Long *Long::fromInt(int64_t value) { + return new Long((value | 0), (value < 0 ? -1 : 0)); +} + +Long *Long::fromBits(int32_t low_bits, int32_t high_bits) { + return new Long(low_bits, high_bits); +} + +Long *Long::fromNumber(double value) { + // Ensure we have a valid ranged number + if(std::isinf(value) || std::isnan(value)) { + return Long::fromBits(0, 0); + } else if(value <= BSON_INT64_MIN) { + return Long::fromBits(0, 0x80000000 | 0); + } else if(value >= BSON_INT64_MAX) { + return Long::fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); + } else if(value < 0) { + return Long::fromNumber(-value)->negate(); + } else { + int64_t int_value = (int64_t)value; + return Long::fromBits((int_value % BSON_INT32_) | 0, (int_value / BSON_INT32_) | 0); + } +} + +Handle Long::FromNumber(const Arguments &args) { + HandleScope scope; + + // Ensure that we have an parameter + if(args.Length() != 1) return VException("One argument required - number."); + if(!args[0]->IsNumber()) return VException("Arguments passed in must be numbers."); + // Unpack the variable as a 64 bit integer + int64_t value = args[0]->IntegerValue(); + double double_value = args[0]->NumberValue(); + // Ensure we have a valid ranged number + if(std::isinf(double_value) || std::isnan(double_value)) { + Local argv[] = {Integer::New(0), Integer::New(0)}; + Local long_obj = constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(long_obj); + } else if(double_value <= BSON_INT64_MIN) { + Local argv[] = {Integer::New(0), Integer::New(0x80000000 | 0)}; + Local long_obj = constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(long_obj); + } else if(double_value >= BSON_INT64_MAX) { + Local argv[] = {Integer::New(0xFFFFFFFF | 0), Integer::New(0x7FFFFFFF | 0)}; + Local long_obj = constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(long_obj); + } else if(double_value < 0) { + Local argv[] = {Number::New(double_value)}; + Local long_obj = constructor_template->GetFunction()->NewInstance(1, argv); + return scope.Close(long_obj); + } else { + Local argv[] = {Integer::New((value % BSON_INT32_) | 0), Integer::New((value / BSON_INT32_) | 0)}; + Local long_obj = constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(long_obj); + } +} diff --git a/node_modules/mongodb/external-libs/bson/long.h b/node_modules/mongodb/external-libs/bson/long.h new file mode 100644 index 0000000..0650ce3 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/long.h @@ -0,0 +1,76 @@ +#ifndef LONG_H_ +#define LONG_H_ + +#include +#include +#include + +using namespace v8; +using namespace node; + +class Long : public ObjectWrap { + public: + int32_t low_bits; + int32_t high_bits; + + Long(int32_t low_bits, int32_t high_bits); + ~Long(); + + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + } + + bool isZero(); + bool isNegative(); + bool equals(Long *other); + Long *div(Long *other); + Long *subtract(Long *other); + Long *negate(); + Long *multiply(Long *other); + Long *add(Long *other); + Long *not_(); + bool isOdd(); + bool greaterThanOrEqual(Long *other); + bool greaterThan(Long *other); + int64_t toNumber(); + int32_t toInt(); + int64_t compare(Long *other); + int64_t getLowBitsUnsigned(); + char *toString(int32_t radix, char *buffer); + Long *shiftRight(int32_t number_bits); + Long *shiftLeft(int32_t number_bits); + + static Long *fromInt(int64_t value); + static Long *fromBits(int32_t low_bits, int32_t high_bits); + static Long *fromNumber(double value); + + // Getter and Setter for object values + static Handle LowGetter(Local property, const AccessorInfo& info); + static void LowSetter(Local property, Local value, const AccessorInfo& info); + static Handle HighGetter(Local property, const AccessorInfo& info); + static void HighSetter(Local property, Local value, const AccessorInfo& info); + // Functions available from V8 + static void Initialize(Handle target); + static Handle FromNumber(const Arguments &args); + static Handle ToString(const Arguments &args); + static Handle Inspect(const Arguments &args); + static Handle IsZero(const Arguments &args); + static Handle GetLowBits(const Arguments &args); + static Handle GetHighBits(const Arguments &args); + static Handle GreatherThan(const Arguments &args); + static Handle FromInt(const Arguments &args); + static Handle ToInt(const Arguments &args); + static Handle ToNumber(const Arguments &args); + static Handle ToJSON(const Arguments &args); + static Handle Equals(const Arguments &args); + + // Constructor used for creating new Long objects from C++ + static Persistent constructor_template; + + protected: + static Handle New(const Arguments &args); +}; + +#endif // LONG_H_ \ No newline at end of file diff --git a/node_modules/mongodb/external-libs/bson/objectid.cc b/node_modules/mongodb/external-libs/bson/objectid.cc new file mode 100644 index 0000000..ec92607 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/objectid.cc @@ -0,0 +1,295 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "objectid.h" + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); + }; + +Persistent ObjectID::constructor_template; + +ObjectID::ObjectID(char *o) : ObjectWrap() { + memcpy(this->oid, o, OBJECTID_SIZE); +} + +ObjectID::~ObjectID() { +} + +char *ObjectID::uint32_to_char(uint32_t value, char *buf) { + *(buf) = (char)(value & 0xff); + *(buf + 1) = (char)((value >> 8) & 0xff); + *(buf + 2) = (char)((value >> 16) & 0xff); + *(buf + 3) = (char)((value >> 24) & 0xff); + *(buf + 4) = '\0'; + return buf; +} + +// Generates a new oid +char *ObjectID::oid_id_generator(char *oid_string) { + // Blatant copy of the code from mongodb-c driver + static int incr = 0; + int fuzz = 0; + // Fetch a new counter () + int i = incr++; /*TODO make atomic*/ + int t = time(NULL); + + /* TODO rand sucks. find something better */ + if (!fuzz){ + srand(t); + fuzz = rand(); + } + + // Build a 12 byte char string based on the address of the current object, the rand number and the current time + char oid_string_c[12 * sizeof(char) + 1]; + + *(oid_string_c + 12) = '\0'; + + ObjectID::uint32_to_char(t,oid_string_c); + ObjectID::uint32_to_char(fuzz,oid_string_c + 4); + ObjectID::uint32_to_char(i,oid_string_c + 8); + + // Allocate storage for a 24 character hex oid + char *pbuffer = oid_string; + // Terminate the string + *(pbuffer + 24) = '\0'; + // Unpack the oid in hex form + for(int32_t i = 0; i < 12; i++) { + sprintf(pbuffer, "%02x", (unsigned char)*(oid_string_c + i)); + pbuffer += 2; + } + + return oid_string; +} + +Handle ObjectID::New(const Arguments &args) { + HandleScope scope; + + // If no arguments are passed in we generate a new ID automagically + if(args.Length() == 0) { + // Instantiate a ObjectID object + char oid_string[OBJECTID_SIZE]; + ObjectID::oid_id_generator(oid_string); + ObjectID *oid = new ObjectID(oid_string); + + // Wrap it + oid->Wrap(args.This()); + // Return the object + return args.This(); + } else { + // Ensure we have correct parameters passed in + if(args.Length() != 1 && (!args[0]->IsString() || !args[0]->IsNull())) { + return VException("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters in hex format"); + } + + // Contains the final oid string + char oid_string_c[OBJECTID_SIZE]; + + + // If we have a null generate a new oid + if(args[0]->IsNull()) { + ObjectID::oid_id_generator(oid_string_c); + } else { + *(oid_string_c + 24) = '\0'; + + // Convert the argument to a String + Local oid_string = args[0]->ToString(); + if(oid_string->Length() != 12 && oid_string->Length() != 24) { + return VException("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters in hex format"); + } + + if(oid_string->Length() == 12) { + // Contains the bytes for the string + char oid_string_bytes[13]; + // Decode the 12 bytes of the oid + node::DecodeWrite(oid_string_bytes, 13, oid_string, node::BINARY); + // Unpack the String object to char* + char *pbuffer = oid_string_c; + // Unpack the oid in hex form + for(int32_t i = 0; i < 12; i++) { + sprintf(pbuffer, "%02x", (unsigned char)*(oid_string_bytes + i)); + pbuffer += 2; + } + } else { + // Decode the content + node::DecodeWrite(oid_string_c, 25, oid_string, node::BINARY); + } + } + + // Instantiate a ObjectID object + ObjectID *oid = new ObjectID(oid_string_c); + + // Wrap it + oid->Wrap(args.This()); + // Return the object + return args.This(); + } +} + +static Persistent id_symbol; + +void ObjectID::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("ObjectID")); + + // Propertry symbols + id_symbol = NODE_PSYMBOL("id"); + + // Getters for correct serialization of the object + constructor_template->InstanceTemplate()->SetAccessor(id_symbol, IdGetter, IdSetter); + + // Instance methods + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toString", ToString); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "inspect", Inspect); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toHexString", ToHexString); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "equals", Equals); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toJSON", ToJSON); + + // Class methods + NODE_SET_METHOD(constructor_template->GetFunction(), "createPk", CreatePk); + NODE_SET_METHOD(constructor_template->GetFunction(), "createFromHexString", CreateFromHexString); + + target->Set(String::NewSymbol("ObjectID"), constructor_template->GetFunction()); +} + +Handle ObjectID::Equals(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 1 && !args[0]->IsObject()) return scope.Close(Boolean::New(false)); + // Retrieve the object + Local object_id_obj = args[0]->ToObject(); + // Ensure it's a valid type object (of type Object ID) + if(!ObjectID::HasInstance(object_id_obj)) return scope.Close(Boolean::New(false)); + // Ok we got an object ID, let's unwrap the value to compare the actual id's + ObjectID *object_id = ObjectWrap::Unwrap(object_id_obj); + // Let's unpack the current object + ObjectID *current_object_id = ObjectWrap::Unwrap(args.This()); + // Now let's compare the id values between out current object and the existing one + bool result = current_object_id->equals(object_id); + // Return the result of the comparision + return scope.Close(Boolean::New(result)); +} + +Handle ObjectID::CreatePk(const Arguments &args) { + HandleScope scope; + + char oid_string[OBJECTID_SIZE]; + ObjectID::oid_id_generator(oid_string); + // Return the value + Local argv[] = {String::New(oid_string)}; + Handle object_id_obj = ObjectID::constructor_template->GetFunction()->NewInstance(1, argv); + + // Return the close object + return scope.Close(object_id_obj); +} + +Handle ObjectID::IdGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack the long object + ObjectID *objectid_obj = ObjectWrap::Unwrap(info.Holder()); + // Convert the hex oid to bin + char *binary_oid = objectid_obj->convert_hex_oid_to_bin(); + // Create string and return it + Local final_str = Encode(binary_oid, 12, BINARY)->ToString(); + // Free the memory for binary_oid + free(binary_oid); + // Close the scope + return scope.Close(final_str); +} + +bool ObjectID::equals(ObjectID *object_id) { + char *current_id = this->oid; + char *compare_id = object_id->oid; + + for(uint32_t i = 0; i < 24; i++) { + if(*(current_id + i) != *(compare_id + i)) + { + return false; + } + } + + return true; +} + +char *ObjectID::convert_hex_oid_to_bin() { + // Turn the oid into the binary equivalent + char *binary_oid = (char *)malloc(12 * sizeof(char) + 1); + *(binary_oid + 12) = '\0'; + char n_val; + char *nval_str = (char *)malloc(3); + *(nval_str + 2) = '\0'; + uint32_t x1; + + // Let's convert the hex value to binary + for(uint32_t i = 0; i < 12; i++) { + nval_str[0] = *(this->oid + (i*2)); + nval_str[1] = *(this->oid + (i*2) + 1); + sscanf(nval_str, "%x", &x1); + *(binary_oid + i) = (char)(x1); + } + + // release the memory for the n_val_str + free(nval_str); + // Return the pointer to the converted string + return binary_oid; +} + +void ObjectID::IdSetter(Local property, Local value, const AccessorInfo& info) { +} + + +Handle ObjectID::CreateFromHexString(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 1 && args[0]->IsString()) return VException("One argument required of type string"); + + Local argv[] = {args[0]}; + Handle oid_obj = ObjectID::constructor_template->GetFunction()->NewInstance(1, argv); + return scope.Close(oid_obj); +} + +Handle ObjectID::ToHexString(const Arguments &args) { + return ToString(args); +} + +Handle ObjectID::Inspect(const Arguments &args) { + return ToString(args); +} + +Handle ObjectID::ToString(const Arguments &args) { + HandleScope scope; + + // Unpack the ObjectID instance + ObjectID *oid = ObjectWrap::Unwrap(args.This()); + // Return the id + return String::New(oid->oid); +} + +Handle ObjectID::ToJSON(const Arguments &args) { + return ToString(args); +} + + + + + + + + diff --git a/node_modules/mongodb/external-libs/bson/objectid.h b/node_modules/mongodb/external-libs/bson/objectid.h new file mode 100644 index 0000000..714a5e1 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/objectid.h @@ -0,0 +1,54 @@ +#ifndef OBJECTID_H_ +#define OBJECTID_H_ + +#include +#include +#include + +using namespace v8; +using namespace node; + +class ObjectID : public ObjectWrap { + public: + + static const int32_t OBJECTID_SIZE = 24+1; + + char oid[OBJECTID_SIZE]; + + ObjectID(char *oid); + ~ObjectID(); + + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + } + + // Functions available from V8 + static void Initialize(Handle target); + static Handle ToString(const Arguments &args); + static Handle Inspect(const Arguments &args); + static Handle ToHexString(const Arguments &args); + static Handle ToJSON(const Arguments &args); + static Handle CreatePk(const Arguments &args); + static Handle CreateFromHexString(const Arguments &args); + static Handle Equals(const Arguments &args); + + // Properties + static Handle IdGetter(Local property, const AccessorInfo& info); + static void IdSetter(Local property, Local value, const AccessorInfo& info); + + // Constructor used for creating new Long objects from C++ + static Persistent constructor_template; + // Instance methods + char *convert_hex_oid_to_bin(); + bool equals(ObjectID *object_id); + private: + static Handle New(const Arguments &args); + + // Generates oid's (Based on BSON C lib) + static char *oid_id_generator(char* buffer); + static char *uint32_to_char(uint32_t value, char* buffer); +}; + +#endif // OBJECTID_H_ \ No newline at end of file diff --git a/node_modules/mongodb/external-libs/bson/test_bson.js b/node_modules/mongodb/external-libs/bson/test_bson.js new file mode 100644 index 0000000..0081398 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/test_bson.js @@ -0,0 +1,328 @@ +require.paths.unshift("../../lib"); + +var sys = require('util'), + debug = require('util').debug, + inspect = require('util').inspect, + Buffer = require('buffer').Buffer, + BSON = require('./bson').BSON, + Buffer = require('buffer').Buffer, + BSONJS = require('mongodb/bson/bson').BSON, + BinaryParser = require('mongodb/bson/binary_parser').BinaryParser, + Long = require('mongodb/goog/math/long').Long, + ObjectID = require('mongodb/bson/bson').ObjectID, + Binary = require('mongodb/bson/bson').Binary, + Code = require('mongodb/bson/bson').Code, + DBRef = require('mongodb/bson/bson').DBRef, + assert = require('assert'); + +var Long2 = require('./bson').Long, + ObjectID2 = require('./bson').ObjectID, + Binary2 = require('./bson').Binary, + Code2 = require('./bson').Code, + DBRef2 = require('./bson').DBRef; + +sys.puts("=== EXECUTING TEST_BSON ==="); + +// Should fail due to illegal key +assert.throws(function() { new ObjectID('foo'); }) +assert.throws(function() { new ObjectID2('foo'); }) + +// Long data type tests +var l2_string = Long2.fromNumber(100); +var l_string = Long.fromNumber(100); +assert.equal(l_string.toNumber(), l2_string.toNumber()); + +var l2_string = Long2.fromNumber(9223372036854775807).toString(); +var l_string = Long.fromNumber(9223372036854775807).toString(); +assert.equal(l_string, l2_string); + +l2_string = Long2.fromNumber(9223372036800).toString(); +l_string = Long.fromNumber(9223372036800).toString(); +assert.equal(l_string, l2_string); + +l2_string = Long2.fromNumber(2355).toString(); +l_string = Long.fromNumber(2355).toString(); +assert.equal(l_string, l2_string); + +l_string = Long.fromNumber(-9223372036854775807).toString(); +l2_string = Long2.fromNumber(-9223372036854775807).toString(); +assert.equal(l_string, l2_string); + +l2_string = Long2.fromNumber(-2355).toString(); +l_string = Long.fromNumber(-2355).toString(); +assert.equal(l_string, l2_string); + +l2_string = Long2.fromNumber(-1).toString(); +l_string = Long.fromNumber(-1).toString(); +assert.equal(l_string, l2_string); + +l2_string = Long2.fromNumber(1).toString(); +l_string = Long.fromNumber(1).toString(); +assert.equal(l_string, l2_string); + +var a = Long2.fromNumber(10); +assert.equal(10, a); + +var a = Long2.fromNumber(9223372036854775807); +assert.equal(9223372036854775807, a); + +// Simple serialization and deserialization test for a Single String value +var doc = {doc:'Serialize'}; +var simple_string_serialized = BSON.serialize(doc, true, false); + +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +// Nested doc +var doc = {a:{b:{c:1}}}; +var simple_string_serialized = BSON.serialize(doc, false, true); + +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +// Simple integer serialization/deserialization test, including testing boundary conditions +var doc = {doc:-1}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +var doc = {doc:2147483648}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +var doc = {doc:-2147483648}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +// Simple serialization and deserialization test for a Long value +var doc = {doc:Long2.fromNumber(9223372036854775807)}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize({doc:Long.fromNumber(9223372036854775807)}, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +var doc = {doc:Long2.fromNumber(-9223372036854775807)}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize({doc:Long.fromNumber(-9223372036854775807)}, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +// Simple serialization and deserialization for a Float value +var doc = {doc:2222.3333}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +var doc = {doc:-2222.3333}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +// Simple serialization and deserialization for a null value +var doc = {doc:null}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +// Simple serialization and deserialization for a boolean value +var doc = {doc:true}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +// Simple serialization and deserialization for a date value +var date = new Date(); +var doc = {doc:date}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')), BSON.deserialize(simple_string_serialized)); + +// Simple serialization and deserialization for a boolean value +var doc = {doc:/abcd/mi}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.equal(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString(), BSON.deserialize(simple_string_serialized).doc.toString()); + +var doc = {doc:/abcd/}; +var simple_string_serialized = BSON.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc, false, true)); +assert.equal(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString(), BSON.deserialize(simple_string_serialized).doc.toString()); + +// Simple serialization and deserialization for a objectId value +var doc = {doc:new ObjectID2()}; +var simple_string_serialized = BSON.serialize(doc, false, true); +var doc2 = {doc:ObjectID.createFromHexString(doc.doc.toHexString())}; + +assert.deepEqual(simple_string_serialized, BSONJS.serialize(doc2, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString(), BSON.deserialize(simple_string_serialized).doc.toString()); + +// Simple serialization and deserialization for a Binary value +var binary = new Binary2(); +var string = 'binstring' +for(var index = 0; index < string.length; index++) { binary.put(string.charAt(index)); } + +var binary2 = new Binary(); +var string = 'binstring' +for(var index = 0; index < string.length; index++) { binary2.put(string.charAt(index)); } + +var simple_string_serialized = BSON.serialize({doc:binary}, false, true); +assert.deepEqual(simple_string_serialized, BSONJS.serialize({doc:binary2}, false, true)); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.value(), BSON.deserialize(simple_string_serialized).doc.value()); + +// Simple serialization and deserialization for a Code value +var code = new Code2('this.a > i', {'i': 1}); +var code2 = new Code('this.a > i', {'i': 1}); +var simple_string_serialized_2 = BSONJS.serialize({doc:code2}, false, true); +var simple_string_serialized = BSON.serialize({doc:code}, false, true); + +assert.deepEqual(simple_string_serialized, simple_string_serialized_2); +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')).doc.scope, BSON.deserialize(simple_string_serialized).doc.scope); + +// Simple serialization and deserialization for an Object +var simple_string_serialized = BSON.serialize({doc:{a:1, b:{c:2}}}, false, true); +var simple_string_serialized_2 = BSONJS.serialize({doc:{a:1, b:{c:2}}}, false, true); +assert.deepEqual(simple_string_serialized, simple_string_serialized_2) +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')).doc, BSON.deserialize(simple_string_serialized).doc); + +// Simple serialization and deserialization for an Array +var simple_string_serialized = BSON.serialize({doc:[9, 9, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1]}, false, true); +var simple_string_serialized_2 = BSONJS.serialize({doc:[9, 9, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1]}, false, true); + +assert.deepEqual(simple_string_serialized, simple_string_serialized_2) +assert.deepEqual(BSONJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')).doc, BSON.deserialize(simple_string_serialized).doc); + +// Simple serialization and deserialization for a DBRef +var oid = new ObjectID2() +var oid2 = new ObjectID.createFromHexString(oid.toHexString()) +var simple_string_serialized = BSONJS.serialize({doc:new DBRef('namespace', oid2, 'integration_tests_')}, false, true); +var simple_string_serialized_2 = BSON.serialize({doc:new DBRef2('namespace', oid, 'integration_tests_')}, false, true); + +assert.deepEqual(simple_string_serialized, simple_string_serialized_2) +// Ensure we have the same values for the dbref +var object_js = BSONJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')); +var object_c = BSON.deserialize(simple_string_serialized); + +assert.equal(object_js.doc.namespace, object_c.doc.namespace); +assert.equal(object_js.doc.oid.toHexString(), object_c.doc.oid.toHexString()); +assert.equal(object_js.doc.db, object_c.doc.db); + +// Serialized document +var bytes = [47,0,0,0,2,110,97,109,101,0,6,0,0,0,80,97,116,116,121,0,16,97,103,101,0,34,0,0,0,7,95,105,100,0,76,100,12,23,11,30,39,8,89,0,0,1,0]; +var serialized_data = ''; +// Convert to chars +for(var i = 0; i < bytes.length; i++) { + serialized_data = serialized_data + BinaryParser.fromByte(bytes[i]); +} +var object = BSON.deserialize(new Buffer(serialized_data, 'binary')); +assert.equal('Patty', object.name) +assert.equal(34, object.age) +assert.equal('4c640c170b1e270859000001', object._id.toHexString()) + +// Serialize utf8 +var doc = { "name" : "本荘由利地域に洪水警報", "name1" : "öüóőúéáűíÖÜÓŐÚÉÁŰÍ", "name2" : "abcdedede"}; +var simple_string_serialized = BSON.serialize(doc, false, true); +var simple_string_serialized2 = BSONJS.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, simple_string_serialized2) + +var object = BSON.deserialize(simple_string_serialized); +assert.equal(doc.name, object.name) +assert.equal(doc.name1, object.name1) +assert.equal(doc.name2, object.name2) + +// Serialize object with array +var doc = {b:[1, 2, 3]}; +var simple_string_serialized = BSON.serialize(doc, false, true); +var simple_string_serialized_2 = BSONJS.serialize(doc, false, true); +assert.deepEqual(simple_string_serialized, simple_string_serialized_2) + +var object = BSON.deserialize(simple_string_serialized); +assert.deepEqual(doc, object) + +// Test equality of an object ID +var object_id = new ObjectID2(); +var object_id_2 = new ObjectID2(); +assert.ok(object_id.equals(object_id)); +assert.ok(!(object_id.equals(object_id_2))) + +// Test same serialization for Object ID +var object_id = new ObjectID(); +var object_id2 = ObjectID2.createFromHexString(object_id.toString()) +var simple_string_serialized = BSONJS.serialize({doc:object_id}, false, true); +var simple_string_serialized_2 = BSON.serialize({doc:object_id2}, false, true); + +assert.equal(simple_string_serialized_2.length, simple_string_serialized.length); +assert.deepEqual(simple_string_serialized, simple_string_serialized_2) +var object = BSONJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')); +var object2 = BSON.deserialize(simple_string_serialized); +assert.deepEqual(object, object2); + +// JS Object +var c1 = { _id: new ObjectID, comments: [], title: 'number 1' }; +var c2 = { _id: new ObjectID, comments: [], title: 'number 2' }; +var doc = { + numbers: [] + , owners: [] + , comments: [c1, c2] + , _id: new ObjectID +}; + +var simple_string_serialized = BSONJS.serialize(doc, false, true); + +// C++ Object +var c1 = { _id: ObjectID2.createFromHexString(c1._id.toHexString()), comments: [], title: 'number 1' }; +var c2 = { _id: ObjectID2.createFromHexString(c2._id.toHexString()), comments: [], title: 'number 2' }; +var doc = { + numbers: [] + , owners: [] + , comments: [c1, c2] + , _id: ObjectID2.createFromHexString(doc._id.toHexString()) +}; + +var simple_string_serialized_2 = BSON.serialize(doc, false, true); + +for(var i = 0; i < simple_string_serialized_2.length; i++) { + // debug(i + "[" + simple_string_serialized_2[i] + "] = [" + simple_string_serialized[i] + "]") + assert.equal(simple_string_serialized_2[i], simple_string_serialized[i]); +} + +// Deserialize the string +var doc1 = BSONJS.deserialize(new Buffer(simple_string_serialized_2)); +var doc2 = BSON.deserialize(new Buffer(simple_string_serialized_2)); +assert.deepEqual(doc2, doc1) + +var doc = { + _id: 'testid', + key1: { code: 'test1', time: {start:1309323402727,end:1309323402727}, x:10, y:5 }, + key2: { code: 'test1', time: {start:1309323402727,end:1309323402727}, x:10, y:5 } +}; + +var simple_string_serialized = BSONJS.serialize(doc, false, true); +var simple_string_serialized_2 = BSON.serialize(doc, false, true); + +for(var i = 0; i < simple_string_serialized_2.length; i++) { + // debug(i + "[" + simple_string_serialized_2[i] + "] = [" + simple_string_serialized[i] + "]") + assert.equal(simple_string_serialized_2[i], simple_string_serialized[i]); +} + +// Deserialize the string +var doc1 = BSONJS.deserialize(new Buffer(simple_string_serialized_2)); +var doc2 = BSON.deserialize(new Buffer(simple_string_serialized_2)); +assert.deepEqual(doc2, doc1) + +// Force garbage collect +global.gc(); + + + + + + + + + + + + + + + diff --git a/node_modules/mongodb/external-libs/bson/test_full_bson.js b/node_modules/mongodb/external-libs/bson/test_full_bson.js new file mode 100644 index 0000000..2fd270d --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/test_full_bson.js @@ -0,0 +1,209 @@ +require.paths.unshift("../../lib"); + +var sys = require('util'), + fs = require('fs'), + Buffer = require('buffer').Buffer, + BSON = require('./bson').BSON, + Buffer = require('buffer').Buffer, + assert = require('assert'), + Long = require('./bson').Long, + ObjectID = require('./bson').ObjectID, + Binary = require('./bson').Binary, + Code = require('./bson').Code, + BinaryParser = require('mongodb/bson/binary_parser').BinaryParser, + BSONJS = require('mongodb/bson/bson').BSON, + Binary2 = require('mongodb/bson/bson').Binary; + +sys.puts("=== EXECUTING TEST_FULL_BSON ==="); + +// Should Correctly Deserialize object +var bytes = [95,0,0,0,2,110,115,0,42,0,0,0,105,110,116,101,103,114,97,116,105,111,110,95,116,101,115,116,115,95,46,116,101,115,116,95,105,110,100,101,120,95,105,110,102,111,114,109,97,116,105,111,110,0,8,117,110,105,113,117,101,0,0,3,107,101,121,0,12,0,0,0,16,97,0,1,0,0,0,0,2,110,97,109,101,0,4,0,0,0,97,95,49,0,0]; +var serialized_data = ''; +// Convert to chars +for(var i = 0; i < bytes.length; i++) { + serialized_data = serialized_data + BinaryParser.fromByte(bytes[i]); +} +var object = BSON.deserialize(serialized_data); +assert.equal("a_1", object.name); +assert.equal(false, object.unique); +assert.equal(1, object.key.a); + +// Should Correctly Deserialize object with all types +var bytes = [26,1,0,0,7,95,105,100,0,161,190,98,75,118,169,3,0,0,3,0,0,4,97,114,114,97,121,0,26,0,0,0,16,48,0,1,0,0,0,16,49,0,2,0,0,0,16,50,0,3,0,0,0,0,2,115,116,114,105,110,103,0,6,0,0,0,104,101,108,108,111,0,3,104,97,115,104,0,19,0,0,0,16,97,0,1,0,0,0,16,98,0,2,0,0,0,0,9,100,97,116,101,0,161,190,98,75,0,0,0,0,7,111,105,100,0,161,190,98,75,90,217,18,0,0,1,0,0,5,98,105,110,97,114,121,0,7,0,0,0,2,3,0,0,0,49,50,51,16,105,110,116,0,42,0,0,0,1,102,108,111,97,116,0,223,224,11,147,169,170,64,64,11,114,101,103,101,120,112,0,102,111,111,98,97,114,0,105,0,8,98,111,111,108,101,97,110,0,1,15,119,104,101,114,101,0,25,0,0,0,12,0,0,0,116,104,105,115,46,120,32,61,61,32,51,0,5,0,0,0,0,3,100,98,114,101,102,0,37,0,0,0,2,36,114,101,102,0,5,0,0,0,116,101,115,116,0,7,36,105,100,0,161,190,98,75,2,180,1,0,0,2,0,0,0,10,110,117,108,108,0,0]; +var serialized_data = ''; +// Convert to chars +for(var i = 0; i < bytes.length; i++) { + serialized_data = serialized_data + BinaryParser.fromByte(bytes[i]); +} + +var object = BSONJS.deserialize(new Buffer(serialized_data, 'binary')); +assert.equal("hello", object.string); +assert.deepEqual([1, 2, 3], object.array); +assert.equal(1, object.hash.a); +assert.equal(2, object.hash.b); +assert.ok(object.date != null); +assert.ok(object.oid != null); +assert.ok(object.binary != null); +assert.equal(42, object.int); +assert.equal(33.3333, object.float); +assert.ok(object.regexp != null); +assert.equal(true, object.boolean); +assert.ok(object.where != null); +assert.ok(object.dbref != null); +assert.ok(object['null'] == null); + +// Should Serialize and Deserialze String +var test_string = {hello: 'world'} +var serialized_data = BSON.serialize(test_string) +assert.deepEqual(test_string, BSON.deserialize(serialized_data)); + +// Should Correctly Serialize and Deserialize Integer +var test_number = {doc: 5} +var serialized_data = BSON.serialize(test_number) +assert.deepEqual(test_number, BSON.deserialize(serialized_data)); + +// Should Correctly Serialize and Deserialize null value +var test_null = {doc:null} +var serialized_data = BSON.serialize(test_null) +var object = BSON.deserialize(serialized_data); +assert.deepEqual(test_null, object); + +// Should Correctly Serialize and Deserialize undefined value +var test_undefined = {doc:undefined} +var serialized_data = BSON.serialize(test_undefined) +var object = BSONJS.deserialize(new Buffer(serialized_data, 'binary')); +assert.equal(null, object.doc) + +// Should Correctly Serialize and Deserialize Number +var test_number = {doc: 5.5} +var serialized_data = BSON.serialize(test_number) +assert.deepEqual(test_number, BSON.deserialize(serialized_data)); + +// Should Correctly Serialize and Deserialize Integer +var test_int = {doc: 42} +var serialized_data = BSON.serialize(test_int) +assert.deepEqual(test_int, BSON.deserialize(serialized_data)); + +test_int = {doc: -5600} +serialized_data = BSON.serialize(test_int) +assert.deepEqual(test_int, BSON.deserialize(serialized_data)); + +test_int = {doc: 2147483647} +serialized_data = BSON.serialize(test_int) +assert.deepEqual(test_int, BSON.deserialize(serialized_data)); + +test_int = {doc: -2147483648} +serialized_data = BSON.serialize(test_int) +assert.deepEqual(test_int, BSON.deserialize(serialized_data)); + +// Should Correctly Serialize and Deserialize Object +var doc = {doc: {age: 42, name: 'Spongebob', shoe_size: 9.5}} +var serialized_data = BSON.serialize(doc) +assert.deepEqual(doc, BSON.deserialize(serialized_data)); + +// Should Correctly Serialize and Deserialize Array +var doc = {doc: [1, 2, 'a', 'b']} +var serialized_data = BSON.serialize(doc) +assert.deepEqual(doc, BSON.deserialize(serialized_data)); + +// Should Correctly Serialize and Deserialize Array with added on functions +var doc = {doc: [1, 2, 'a', 'b']} +var serialized_data = BSON.serialize(doc) +assert.deepEqual(doc, BSON.deserialize(serialized_data)); + +// Should Correctly Serialize and Deserialize A Boolean +var doc = {doc: true} +var serialized_data = BSON.serialize(doc) +assert.deepEqual(doc, BSON.deserialize(serialized_data)); + +// Should Correctly Serialize and Deserialize a Date +var date = new Date() +//(2009, 11, 12, 12, 00, 30) +date.setUTCDate(12) +date.setUTCFullYear(2009) +date.setUTCMonth(11 - 1) +date.setUTCHours(12) +date.setUTCMinutes(0) +date.setUTCSeconds(30) +var doc = {doc: date} +var serialized_data = BSON.serialize(doc) +assert.deepEqual(doc, BSON.deserialize(serialized_data)); + +// // Should Correctly Serialize and Deserialize Oid +var doc = {doc: new ObjectID()} +var serialized_data = BSON.serialize(doc) +assert.deepEqual(doc.doc.toHexString(), BSON.deserialize(serialized_data).doc.toHexString()) + +// Should Correctly encode Empty Hash +var test_code = {} +var serialized_data = BSON.serialize(test_code) +assert.deepEqual(test_code, BSON.deserialize(serialized_data)); + +// Should Correctly Serialize and Deserialize Ordered Hash +var doc = {doc: {b:1, a:2, c:3, d:4}} +var serialized_data = BSON.serialize(doc) +var decoded_hash = BSON.deserialize(serialized_data).doc +var keys = [] +for(name in decoded_hash) keys.push(name) +assert.deepEqual(['b', 'a', 'c', 'd'], keys) + +// Should Correctly Serialize and Deserialize Regular Expression +// Serialize the regular expression +var doc = {doc: /foobar/mi} +var serialized_data = BSON.serialize(doc) +var doc2 = BSON.deserialize(serialized_data); +assert.equal(doc.doc.toString(), doc2.doc.toString()) + +// Should Correctly Serialize and Deserialize a Binary object +var bin = new Binary() +var string = 'binstring' +for(var index = 0; index < string.length; index++) { + bin.put(string.charAt(index)) +} +var doc = {doc: bin} +var serialized_data = BSON.serialize(doc) +var deserialized_data = BSON.deserialize(serialized_data); +assert.equal(doc.doc.value(), deserialized_data.doc.value()) + +// Should Correctly Serialize and Deserialize a big Binary object +var data = fs.readFileSync("../../test/gridstore/test_gs_weird_bug.png", 'binary'); +var bin = new Binary() +bin.write(data) +var doc = {doc: bin} +var serialized_data = BSON.serialize(doc) +var deserialized_data = BSON.deserialize(serialized_data); +assert.equal(doc.doc.value(), deserialized_data.doc.value()) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/node_modules/mongodb/external-libs/bson/timestamp.cc b/node_modules/mongodb/external-libs/bson/timestamp.cc new file mode 100644 index 0000000..9ae1164 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/timestamp.cc @@ -0,0 +1,592 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "local.h" +#include "timestamp.h" + +// BSON MAX VALUES +const int32_t BSON_INT32_MAX = (int32_t)2147483648L; +const int32_t BSON_INT32_MIN = (int32_t)(-1) * 2147483648L; +const int64_t BSON_INT32_ = pow(2, 32); + +const double LN2 = 0.6931471805599453; + +// Max Values +const int64_t BSON_INT64_MAX = (int64_t)9223372036854775807LL; +const int64_t BSON_INT64_MIN = (int64_t)(-1)*(9223372036854775807LL); + +const int32_t TIMESTAMP_BUFFER_SIZE = 64; + +// Constant objects used in calculations +Timestamp* TIMESTAMP_MIN_VALUE = Timestamp::fromBits(0, 0x80000000 | 0); +Timestamp* TIMESTAMP_MAX_VALUE = Timestamp::fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); +Timestamp* TIMESTAMP_ZERO = Timestamp::fromInt(0); +Timestamp* TIMESTAMP_ONE = Timestamp::fromInt(1); +Timestamp* TIMESTAMP_NEG_ONE = Timestamp::fromInt(-1); + +#define max(a,b) ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; }) + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); + }; + +Persistent Timestamp::constructor_template; + +Timestamp::Timestamp(int32_t low_bits, int32_t high_bits) : ObjectWrap() { + this->low_bits = low_bits; + this->high_bits = high_bits; +} + +Timestamp::~Timestamp() {} + +Handle Timestamp::New(const Arguments &args) { + HandleScope scope; + + // Ensure that we have an parameter + if(args.Length() == 1 && args[0]->IsNumber()) { + // Unpack the value + double value = args[0]->NumberValue(); + // Create an instance of long + Timestamp *l = Timestamp::fromNumber(value); + // Wrap it in the object wrap + l->Wrap(args.This()); + // Return the context + return args.This(); + } else if(args.Length() == 2 && args[0]->IsNumber() && args[1]->IsNumber()) { + // Unpack the value + int32_t low_bits = args[0]->Int32Value(); + int32_t high_bits = args[1]->Int32Value(); + // Create an instance of long + Timestamp *l = new Timestamp(low_bits, high_bits); + // Wrap it in the object wrap + l->Wrap(args.This()); + // Return the context + return args.This(); + } else if(args.Length() == 2 && args[0]->IsString() && args[1]->IsString()) { + // Parse the strings into int32_t values + int32_t low_bits = 0; + int32_t high_bits = 0; + + // Let's write the strings to the bits + DecodeWrite((char*)&low_bits, 4, args[0]->ToString(), BINARY); + DecodeWrite((char*)&high_bits, 4, args[1]->ToString(), BINARY); + + // Create an instance of long + Timestamp *l = new Timestamp(low_bits, high_bits); + // Wrap it in the object wrap + l->Wrap(args.This()); + // Return the context + return args.This(); + } else { + return VException("Argument passed in must be either a 64 bit number or two 32 bit numbers."); + } +} + +void Timestamp::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("Timestamp")); + + // Propertry symbols + low_bits_symbol = NODE_PSYMBOL("low_"); + high_bits_symbol = NODE_PSYMBOL("high_"); + + // Instance methods + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toString", ToString); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "isZero", IsZero); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "getLowBits", GetLowBits); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "getHighBits", GetHighBits); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "inspect", Inspect); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "greaterThan", GreatherThan); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toInt", ToInt); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toNumber", ToNumber); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toJSON", ToJSON); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "equals", Equals); + + // Getters for correct serialization of the object + constructor_template->InstanceTemplate()->SetAccessor(low_bits_symbol, LowGetter, LowSetter); + constructor_template->InstanceTemplate()->SetAccessor(high_bits_symbol, HighGetter, HighSetter); + + // Class methods + NODE_SET_METHOD(constructor_template->GetFunction(), "fromNumber", FromNumber); + NODE_SET_METHOD(constructor_template->GetFunction(), "fromInt", FromInt); + + // Add class to scope + target->Set(String::NewSymbol("Timestamp"), constructor_template->GetFunction()); +} + +Handle Timestamp::ToInt(const Arguments &args) { + HandleScope scope; + + // Let's unpack the Timestamp instance that contains the number in low_bits and high_bits form + Timestamp *l = ObjectWrap::Unwrap(args.This()); + // Get lower bits + uint32_t low_bits = l->low_bits; + // Return the value + return Int32::New(low_bits); +} + +Handle Timestamp::ToNumber(const Arguments &args) { + HandleScope scope; + // Let's unpack the Timestamp instance that contains the number in low_bits and high_bits form + Timestamp *l = ObjectWrap::Unwrap(args.This()); + return Number::New(l->toNumber()); +} + + +Handle Timestamp::LowGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack the long object + Timestamp *l = ObjectWrap::Unwrap(info.Holder()); + // Return the low bits + return Integer::New(l->low_bits); +} + +void Timestamp::LowSetter(Local property, Local value, const AccessorInfo& info) { + if(value->IsNumber()) { + // Unpack the long object + Timestamp *l = ObjectWrap::Unwrap(info.Holder()); + // Set the low bits + l->low_bits = value->Int32Value(); + } +} + +Handle Timestamp::HighGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + + // Unpack the long object + Timestamp *l = ObjectWrap::Unwrap(info.Holder()); + // Return the low bits + return Integer::New(l->high_bits); +} + +void Timestamp::HighSetter(Local property, Local value, const AccessorInfo& info) { + if(value->IsNumber()) { + // Unpack the long object + Timestamp *l = ObjectWrap::Unwrap(info.Holder()); + // Set the low bits + l->high_bits = value->Int32Value(); + } +} + +Handle Timestamp::Inspect(const Arguments &args) { + return ToString(args); +} + +Handle Timestamp::GetLowBits(const Arguments &args) { + HandleScope scope; + + // Let's unpack the Timestamp instance that contains the number in low_bits and high_bits form + Timestamp *l = ObjectWrap::Unwrap(args.This()); + // Let's fetch the low bits + int32_t low_bits = l->low_bits; + // Package the result in a V8 Integer object and return + return Integer::New(low_bits); +} + +Handle Timestamp::GetHighBits(const Arguments &args) { + HandleScope scope; + + // Let's unpack the Timestamp instance that contains the number in low_bits and high_bits form + Timestamp *l = ObjectWrap::Unwrap(args.This()); + // Let's fetch the low bits + int32_t high_bits = l->high_bits; + // Package the result in a V8 Integer object and return + return Integer::New(high_bits); +} + +bool Timestamp::isZero() { + int32_t low_bits = this->low_bits; + int32_t high_bits = this->high_bits; + return low_bits == 0 && high_bits == 0; +} + +bool Timestamp::isNegative() { + int32_t low_bits = this->low_bits; + int32_t high_bits = this->high_bits; + return high_bits < 0; +} + +bool Timestamp::equals(Timestamp *l) { + int32_t low_bits = this->low_bits; + int32_t high_bits = this->high_bits; + return (high_bits == l->high_bits) && (low_bits == l->low_bits); +} + +Handle Timestamp::IsZero(const Arguments &args) { + HandleScope scope; + + // Let's unpack the Timestamp instance that contains the number in low_bits and high_bits form + Timestamp *l = ObjectWrap::Unwrap(args.This()); + return Boolean::New(l->isZero()); +} + +int32_t Timestamp::toInt() { + return this->low_bits; +} + +char *Timestamp::toString(int32_t opt_radix, char *buffer) { + if (opt_radix == 10) { + if (isNegative()) { + sprintf(buffer,"%lld",toNumber()); + } + else { + sprintf(buffer,"%llu",toNumber()); + } + } + else if (opt_radix == 16) { + sprintf(buffer,"%llx",toNumber()); + } + else { + throw "Unsupported radix"; + } + + return buffer; +} + +Handle Timestamp::ToString(const Arguments &args) { + HandleScope scope; + + Timestamp *ts = ObjectWrap::Unwrap(args.This()); + + char buffer[TIMESTAMP_BUFFER_SIZE]; + ts->toString(10,buffer); + + return String::New(buffer); +} + +Handle Timestamp::ToJSON(const Arguments &args) { + return ToString(args); +} + +Timestamp *Timestamp::shiftRight(int32_t number_bits) { + number_bits &= 63; + if(number_bits == 0) { + return this; + } else { + int32_t high_bits = this->high_bits; + if(number_bits < 32) { + int32_t low_bits = this->low_bits; + return Timestamp::fromBits((low_bits >> number_bits) | (high_bits << (32 - number_bits)), high_bits >> number_bits); + } else { + return Timestamp::fromBits(high_bits >> (number_bits - 32), high_bits >= 0 ? 0 : -1); + } + } +} + +Timestamp *Timestamp::shiftLeft(int32_t number_bits) { + number_bits &= 63; + if(number_bits == 0) { + return this; + } else { + int32_t low_bits = this->low_bits; + if(number_bits < 32) { + int32_t high_bits = this->high_bits; + return Timestamp::fromBits(low_bits << number_bits, (high_bits << number_bits) | (low_bits >> (32 - number_bits))); + } else { + return Timestamp::fromBits(0, low_bits << (number_bits - 32)); + } + } +} + +Timestamp *Timestamp::div(Timestamp *other) { + // If we are about to do a divide by zero throw an exception + if(other->isZero()) { + throw "division by zero"; + } else if(this->isZero()) { + return new Timestamp(0, 0); + } + + if(this->equals(TIMESTAMP_MIN_VALUE)) { + if(other->equals(TIMESTAMP_ONE) || other->equals(TIMESTAMP_NEG_ONE)) { + return Timestamp::fromBits(0, 0x80000000 | 0); + } else if(other->equals(TIMESTAMP_MIN_VALUE)) { + return Timestamp::fromNumber(1); + } else { + Timestamp *half_this = this->shiftRight(1); + Timestamp *div_obj = half_this->div(other); + Timestamp *approx = div_obj->shiftLeft(1); + // Free memory + delete div_obj; + delete half_this; + // Check if we are done + if(approx->equals(TIMESTAMP_ZERO)) { + return other->isNegative() ? Timestamp::fromNumber(0) : Timestamp::fromNumber(-1); + } else { + Timestamp *mul = other->multiply(approx); + Timestamp *rem = this->subtract(mul); + Timestamp *rem_div = rem->div(other); + Timestamp *result = approx->add(rem_div); + // Free memory + delete mul; + delete rem; + delete rem_div; + // Return result + return result; + } + } + } else if(other->equals(TIMESTAMP_MIN_VALUE)) { + return new Timestamp(0, 0); + } + + // If the value is negative + if(this->isNegative()) { + if(other->isNegative()) { + Timestamp *neg = this->negate(); + Timestamp *other_neg = other->negate(); + Timestamp *result = neg->div(other_neg); + // Free memory + delete neg; + delete other_neg; + // Return result + return result; + } else { + Timestamp *neg = this->negate(); + Timestamp *neg_result = neg->div(other); + Timestamp *result = neg_result->negate(); + // Free memory + delete neg; + delete neg_result; + // Return result + return result; + } + } else if(other->isNegative()) { + Timestamp *other_neg = other->negate(); + Timestamp *div_result = this->div(other_neg); + Timestamp *result = div_result->negate(); + // Free memory + delete other_neg; + delete div_result; + // Return the result + return result; + } + + int64_t this_number = this->toNumber(); + int64_t other_number = other->toNumber(); + int64_t result = this_number / other_number; + // Split into the 32 bit valu + int32_t low32, high32; + high32 = (uint64_t)result >> 32; + low32 = (int32_t)result; + return Timestamp::fromBits(low32, high32); +} + +Timestamp *Timestamp::multiply(Timestamp *other) { + if(this->isZero() || other->isZero()) { + return new Timestamp(0, 0); + } + + int64_t this_number = this->toNumber(); + int64_t other_number = other->toNumber(); + int64_t result = this_number * other_number; + + // Split into the 32 bit valu + int32_t low32, high32; + high32 = (uint64_t)result >> 32; + low32 = (int32_t)result; + return Timestamp::fromBits(low32, high32); +} + +bool Timestamp::isOdd() { + return (this->low_bits & 1) == 1; +} + +// /** @return {number} The closest floating-point representation to this value. */ +// exports.Timestamp.prototype.toNumber = function() { +// return this.high_ * exports.Timestamp.TWO_PWR_32_DBL_ + +// this.getLowBitsUnsigned(); +// }; + +int64_t Timestamp::toNumber() { + return (int64_t)(this->high_bits * BSON_INT32_ + this->getLowBitsUnsigned()); +} + +int64_t Timestamp::getLowBitsUnsigned() { + return (this->low_bits >= 0) ? this->low_bits : BSON_INT32_ + this->low_bits; +} + +int64_t Timestamp::compare(Timestamp *other) { + if(this->equals(other)) { + return 0; + } + + bool this_neg = this->isNegative(); + bool other_neg = other->isNegative(); + if(this_neg && !other_neg) { + return -1; + } + if(!this_neg && other_neg) { + return 1; + } + + Timestamp *return_value = this->subtract(other); + // At this point, the signs are the same, so subtraction will not overflow + if(return_value->isNegative()) { + delete return_value; + return -1; + } else { + delete return_value; + return 1; + } +} + +Timestamp *Timestamp::negate() { + if(this->equals(TIMESTAMP_MIN_VALUE)) { + return TIMESTAMP_MIN_VALUE; + } else { + Timestamp *not_obj = this->not_(); + Timestamp *add = not_obj->add(TIMESTAMP_ONE); + delete not_obj; + return add; + } +} + +Timestamp *Timestamp::not_() { + return new Timestamp(~this->low_bits, ~this->high_bits); +} + +Timestamp *Timestamp::add(Timestamp *other) { + int64_t this_number = this->toNumber(); + int64_t other_number = other->toNumber(); + int64_t result = this_number + other_number; + // Split into the 32 bit valu + int32_t low32, high32; + high32 = (uint64_t)result >> 32; + low32 = (int32_t)result; + return Timestamp::fromBits(low32, high32); +} + +Timestamp *Timestamp::subtract(Timestamp *other) { + int64_t this_number = this->toNumber(); + int64_t other_number = other->toNumber(); + int64_t result = this_number - other_number; + // Split into the 32 bit valu + int32_t low32, high32; + high32 = (uint64_t)result >> 32; + low32 = (int32_t)result; + return Timestamp::fromBits(low32, high32); +} + +Handle Timestamp::GreatherThan(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 1 && !Timestamp::HasInstance(args[0])) return VException("One argument of type Timestamp required"); + + // Let's unpack the Timestamp instance that contains the number in low_bits and high_bits form + Timestamp *current_long_obj = ObjectWrap::Unwrap(args.This()); + // Unpack Timestamp + Local obj = args[0]->ToObject(); + Timestamp *long_obj = Timestamp::Unwrap(obj); + // Compare the longs + bool comparision_result = current_long_obj->greaterThan(long_obj); + return scope.Close(Boolean::New(comparision_result)); +} + +Handle Timestamp::Equals(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 1 && !Timestamp::HasInstance(args[0])) return VException("One argument of type Timestamp required"); + + // Let's unpack the Timestamp instance that contains the number in low_bits and high_bits form + Timestamp *current_long_obj = ObjectWrap::Unwrap(args.This()); + // Unpack Timestamp + Local obj = args[0]->ToObject(); + Timestamp *long_obj = Timestamp::Unwrap(obj); + // Compare the longs + bool comparision_result = (current_long_obj->compare(long_obj) == 0); + return scope.Close(Boolean::New(comparision_result)); +} + +bool Timestamp::greaterThan(Timestamp *other) { + return this->compare(other) > 0; +} + +bool Timestamp::greaterThanOrEqual(Timestamp *other) { + return this->compare(other) >= 0; +} + +Handle Timestamp::FromInt(const Arguments &args) { + HandleScope scope; + + // Validate the arguments + if(args.Length() != 1 && !args[0]->IsNumber()) return VException("One argument of type number required"); + // Unwrap Number variable + Local number = args[0]->ToNumber(); + // Instantiate Timestamp object and return + Local argv[] = {number}; + Local long_obj = constructor_template->GetFunction()->NewInstance(1, argv); + return scope.Close(long_obj); +} + +Timestamp *Timestamp::fromInt(int64_t value) { + return new Timestamp((value | 0), (value < 0 ? -1 : 0)); +} + +Timestamp *Timestamp::fromBits(int32_t low_bits, int32_t high_bits) { + return new Timestamp(low_bits, high_bits); +} + +Timestamp *Timestamp::fromNumber(double value) { + // Ensure we have a valid ranged number + if(std::isinf(value) || std::isnan(value)) { + return Timestamp::fromBits(0, 0); + } else if(value <= BSON_INT64_MIN) { + return Timestamp::fromBits(0, 0x80000000 | 0); + } else if(value >= BSON_INT64_MAX) { + return Timestamp::fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); + } else if(value < 0) { + return Timestamp::fromNumber(-value)->negate(); + } else { + int64_t int_value = (int64_t)value; + return Timestamp::fromBits((int_value % BSON_INT32_) | 0, (int_value / BSON_INT32_) | 0); + } +} + +Handle Timestamp::FromNumber(const Arguments &args) { + HandleScope scope; + + // Ensure that we have an parameter + if(args.Length() != 1) return VException("One argument required - number."); + if(!args[0]->IsNumber()) return VException("Arguments passed in must be numbers."); + // Unpack the variable as a 64 bit integer + int64_t value = args[0]->IntegerValue(); + double double_value = args[0]->NumberValue(); + // Ensure we have a valid ranged number + if(std::isinf(double_value) || std::isnan(double_value)) { + Local argv[] = {Integer::New(0), Integer::New(0)}; + Local long_obj = constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(long_obj); + } else if(double_value <= BSON_INT64_MIN) { + Local argv[] = {Integer::New(0), Integer::New(0x80000000 | 0)}; + Local long_obj = constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(long_obj); + } else if(double_value >= BSON_INT64_MAX) { + Local argv[] = {Integer::New(0xFFFFFFFF | 0), Integer::New(0x7FFFFFFF | 0)}; + Local long_obj = constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(long_obj); + } else if(double_value < 0) { + Local argv[] = {Number::New(double_value)}; + Local long_obj = constructor_template->GetFunction()->NewInstance(1, argv); + return scope.Close(long_obj); + } else { + Local argv[] = {Integer::New((value % BSON_INT32_) | 0), Integer::New((value / BSON_INT32_) | 0)}; + Local long_obj = constructor_template->GetFunction()->NewInstance(2, argv); + return scope.Close(long_obj); + } +} diff --git a/node_modules/mongodb/external-libs/bson/timestamp.h b/node_modules/mongodb/external-libs/bson/timestamp.h new file mode 100644 index 0000000..8ac3442 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/timestamp.h @@ -0,0 +1,79 @@ +#ifndef TIMESTAMP_H_ +#define TIMESTAMP_H_ + +#include +#include +#include + +using namespace v8; +using namespace node; + +static Persistent low_bits_symbol; +static Persistent high_bits_symbol; + +class Timestamp : public ObjectWrap { + public: + int32_t low_bits; + int32_t high_bits; + + Timestamp(int32_t low_bits, int32_t high_bits); + ~Timestamp(); + + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + } + + bool isZero(); + bool isNegative(); + bool equals(Timestamp *other); + Timestamp *div(Timestamp *other); + Timestamp *subtract(Timestamp *other); + Timestamp *negate(); + Timestamp *multiply(Timestamp *other); + Timestamp *add(Timestamp *other); + Timestamp *not_(); + bool isOdd(); + bool greaterThanOrEqual(Timestamp *other); + bool greaterThan(Timestamp *other); + int64_t toNumber(); + int32_t toInt(); + int64_t compare(Timestamp *other); + int64_t getLowBitsUnsigned(); + char *toString(int32_t radix, char *buffer); + Timestamp *shiftRight(int32_t number_bits); + Timestamp *shiftLeft(int32_t number_bits); + + static Timestamp *fromInt(int64_t value); + static Timestamp *fromBits(int32_t low_bits, int32_t high_bits); + static Timestamp *fromNumber(double value); + + // Getter and Setter for object values + static Handle LowGetter(Local property, const AccessorInfo& info); + static void LowSetter(Local property, Local value, const AccessorInfo& info); + static Handle HighGetter(Local property, const AccessorInfo& info); + static void HighSetter(Local property, Local value, const AccessorInfo& info); + // Functions available from V8 + static void Initialize(Handle target); + static Handle FromNumber(const Arguments &args); + static Handle ToString(const Arguments &args); + static Handle Inspect(const Arguments &args); + static Handle IsZero(const Arguments &args); + static Handle GetLowBits(const Arguments &args); + static Handle GetHighBits(const Arguments &args); + static Handle GreatherThan(const Arguments &args); + static Handle FromInt(const Arguments &args); + static Handle ToInt(const Arguments &args); + static Handle ToNumber(const Arguments &args); + static Handle ToJSON(const Arguments &args); + static Handle Equals(const Arguments &args); + + // Constructor used for creating new Timestamp objects from C++ + static Persistent constructor_template; + + protected: + static Handle New(const Arguments &args); +}; + +#endif // TIMESTAMP_H_ diff --git a/node_modules/mongodb/external-libs/bson/wscript b/node_modules/mongodb/external-libs/bson/wscript new file mode 100644 index 0000000..76f4452 --- /dev/null +++ b/node_modules/mongodb/external-libs/bson/wscript @@ -0,0 +1,38 @@ +import Options +from os import unlink, symlink, popen +from os.path import exists + +srcdir = "." +blddir = "build" +VERSION = "0.1.0" + +def set_options(opt): + opt.tool_options("compiler_cxx") + opt.add_option( '--debug' + , action='store_true' + , default=False + , help='Build debug variant [Default: False]' + , dest='debug' + ) + +def configure(conf): + conf.check_tool("compiler_cxx") + conf.check_tool("node_addon") + # conf.env.append_value('CXXFLAGS', ['-DDEBUG', '-g', '-O0', '-Wall', '-Wextra']) + + # conf.check(lib='node', libpath=['/usr/lib', '/usr/local/lib'], uselib_store='NODE') + +def build(bld): + obj = bld.new_task_gen("cxx", "shlib", "node_addon") + obj.target = "bson" + obj.source = ["bson.cc", "long.cc", "objectid.cc", "binary.cc", "code.cc", "dbref.cc", "timestamp.cc", "local.cc"] + # obj.uselib = "NODE" + +def shutdown(): + # HACK to get compress.node out of build directory. + # better way to do this? + if Options.commands['clean']: + if exists('bson.node'): unlink('bson.node') + else: + if exists('build/default/bson.node') and not exists('bson.node'): + symlink('build/default/bson.node', 'bson.node') diff --git a/node_modules/mongodb/index.js b/node_modules/mongodb/index.js new file mode 100755 index 0000000..4f59e9d --- /dev/null +++ b/node_modules/mongodb/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/mongodb'); diff --git a/node_modules/mongodb/install.sh b/node_modules/mongodb/install.sh new file mode 100755 index 0000000..f218630 --- /dev/null +++ b/node_modules/mongodb/install.sh @@ -0,0 +1,20 @@ +#!/bin/bash +echo "================================================================================" +echo "= =" +echo "= To install with C++ bson parser do =" +echo "= the parser only works for node 0.4.X or lower =" +echo "= =" +echo "================================================================================" +echo "Not building native library for cygwin" +if [ x`which gmake` != "x" ]; then + echo "Using GNU make"; + + if [ $npm_package_config_native = "true" ]; then + gmake total + fi +else + + if [ $npm_package_config_native = "true" ]; then + make total + fi +fi diff --git a/node_modules/mongodb/lib/mongodb/admin.js b/node_modules/mongodb/lib/mongodb/admin.js new file mode 100644 index 0000000..d8e20cb --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/admin.js @@ -0,0 +1,146 @@ +var Collection = require('./collection').Collection, + Cursor = require('./cursor').Cursor, + DbCommand = require('./commands/db_command').DbCommand, + debug = require('util').debug, + inspect = require('util').inspect; + +var Admin = exports.Admin = function(db) { + this.db = db; +}; + +Admin.prototype.serverInfo = function(callback) { + var self = this; + var command = {buildinfo:1}; + this.command(command, function(err, doc) { + if(err != null) return callback(err, null); + return callback(null, doc.documents[0]); + }); +} + +Admin.prototype.profilingLevel = function(callback) { + var self = this; + var command = {profile:-1}; + + this.command(command, function(err, doc) { + doc = doc.documents[0]; + + if(err == null && (doc.ok == 1 || doc.was.constructor == Numeric)) { + var was = doc.was; + if(was == 0) { + callback(null, "off"); + } else if(was == 1) { + callback(null, "slow_only"); + } else if(was == 2) { + callback(null, "all"); + } else { + callback(new Error("Error: illegal profiling level value " + was), null); + } + } else { + err != null ? callback(err, null) : callback(new Error("Error with profile command"), null); + } + }); +}; + +Admin.prototype.authenticate = function(username, password, callback) { + var self = this; + var databaseName = this.db.databaseName; + this.db.databaseName = 'admin'; + this.db.authenticate(username, password, function(err, result) { + self.db.databaseName = databaseName; + return callback(err, result); + }) +} + +Admin.prototype.logout = function(options, callback) { + var self = this; + var databaseName = this.db.databaseName; + this.db.databaseName = 'admin'; + this.db.logout(options, function(err, result) { + return callback(err, result); + }) + + self.db.databaseName = databaseName; +} + +Admin.prototype.addUser = function(username, password, callback) { + var self = this; + var databaseName = this.db.databaseName; + this.db.databaseName = 'admin'; + this.db.addUser(username, password, function(err, result) { + self.db.databaseName = databaseName; + return callback(err, result); + }) +} + +Admin.prototype.setProfilingLevel = function(level, callback) { + var self = this; + var command = {}; + var profile = 0; + + if(level == "off") { + profile = 0; + } else if(level == "slow_only") { + profile = 1; + } else if(level == "all") { + profile = 2; + } else { + return callback(new Error("Error: illegal profiling level value " + level)); + } + command['profile'] = profile; + + this.command(command, function(err, doc) { + doc = doc.documents[0]; + + if(err == null && (doc.ok == 1 || doc.was.constructor == Numeric)) { + return callback(null, level); + } else { + return err != null ? callback(err, null) : callback(new Error("Error with profile command"), null); + } + }); +}; + +Admin.prototype.profilingInfo = function(callback) { + var self = this; + var databaseName = this.db.databaseName; + this.db.databaseName = 'admin'; + + try { + new Cursor(this.db, new Collection(this.db, DbCommand.SYSTEM_PROFILE_COLLECTION), {}).toArray(function(err, items) { + return callback(err, items); + }); + } catch (err) { + return callback(err, null); + } + + self.db.databaseName = databaseName; +}; + +Admin.prototype.command = function(command, callback) { + var self = this; + + // Execute a command + this.db.executeDbAdminCommand(command, function(err, result) { + // Ensure change before event loop executes + return callback(err, result); + }); +} + +Admin.prototype.validateCollection = function(collectionName, callback) { + var self = this; + var command = {validate: collectionName}; + + this.db.executeDbCommand(command, function(err, doc) { + if(err != null) return callback(err, null); + doc = doc.documents[0]; + + if(doc.ok == 0) { + return callback(new Error("Error with validate command"), null); + } else if(doc.result.constructor != String) { + return callback(new Error("Error with validation data"), null); + } else if(doc.result.match(/exception|corrupt/) != null) { + return callback(new Error("Error: invalid collection " + collectionName), null); + } else { + return callback(null, doc); + } + }); +}; diff --git a/node_modules/mongodb/lib/mongodb/bson/binary.js b/node_modules/mongodb/lib/mongodb/bson/binary.js new file mode 100644 index 0000000..8b22451 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/bson/binary.js @@ -0,0 +1,123 @@ + +/** + * Module dependencies. + */ + +var Buffer = require('buffer').Buffer; // TODO just use global Buffer +var bson = require('./bson'), + debug = require('util').debug, + inspect = require('util').inspect; + +/** + * Binary constructor. + * + * @param {Buffer} buffer (optional) + */ + +function Binary(buffer, subType) { + if(buffer instanceof Number) { + this.sub_type = buffer; + } else { + this.sub_type = subType == null ? bson.BSON.BSON_BINARY_SUBTYPE_DEFAULT : subType; + } + + if(buffer != null && !(buffer instanceof Number)) { + this.buffer = typeof buffer == 'string' ? new Buffer(buffer) : buffer; + this.position = buffer.length; + } else { + this.buffer = new Buffer(Binary.BUFFER_SIZE); + this.position = 0; + } +}; + +/** + * Updates this binary with `byte_value`. + * + * @param {TODO} byte_value + */ + +Binary.prototype.put = function put (byte_value) { + if (this.buffer.length > this.position) { + this.buffer[this.position++] = byte_value.charCodeAt(0); + } else { + // Create additional overflow buffer + var buffer = new Buffer(Binary.BUFFER_SIZE + this.buffer.length); + // Combine the two buffers together + this.buffer.copy(buffer, 0, 0, this.buffer.length); + this.buffer = buffer; + this.buffer[this.position++] = byte_value.charCodeAt(0); + } +}; + +/** + * Writes. + * + * @param {String} string + * @param {Number} offset + */ + +Binary.prototype.write = function write (string, offset) { + offset = offset ? offset : this.position; + + // If the buffer is to small let's extend the buffer + if (this.buffer.length < offset + string.length) { + var buffer = new Buffer(this.buffer.length + string.length); + this.buffer.copy(buffer, 0, 0, this.buffer.length); + // Assign the new buffer + this.buffer = buffer; + } + + if (string instanceof Buffer) { + string.copy(this.buffer, offset, 0, string.length); + } else { + this.buffer.write(string, 'binary', offset); + } + + this.position = offset + string.length; +}; + +/** + * Reads `length` bytes starting at `position`. + * + * @param {Number} position + * @param {Number} length + * @return {String} + */ + +Binary.prototype.read = function read (position, length) { + length = length && length > 0 + ? length + : this.position; + + return this.buffer.toString('binary', position, position + length); +}; + +/** + * Returns the value of this binary as a string. + * + * @return {String} + */ + +Binary.prototype.value = function value(asRaw) { + asRaw = asRaw == null ? false : asRaw; + return asRaw ? this.buffer.slice(0, this.position) : this.buffer.toString('binary', 0, this.position); +}; + +/** + * Length. + * + * @return {Number} + */ + +Binary.prototype.length = function length () { + return this.position; +}; + +Binary.BUFFER_SIZE = 256; + +/** + * Expose. + */ + +exports.Binary = Binary; + diff --git a/node_modules/mongodb/lib/mongodb/bson/binary_parser.js b/node_modules/mongodb/lib/mongodb/bson/binary_parser.js new file mode 100644 index 0000000..a6108cb --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/bson/binary_parser.js @@ -0,0 +1,392 @@ + +/** + * Module dependencies. + */ + +var sys = require('util'); + +/** + * Binary Parser. + * Jonas Raoni Soares Silva + * http://jsfromhell.com/classes/binary-parser [v1.0] + */ + +var chr = String.fromCharCode; + +var maxBits = []; +for (var i = 0; i < 64; i++) { + maxBits[i] = Math.pow(2, i); +} + +function BinaryParser (bigEndian, allowExceptions) { + this.bigEndian = bigEndian; + this.allowExceptions = allowExceptions; +}; + +BinaryParser.warn = function warn (msg) { + if (this.allowExceptions) { + throw new Error(msg); + } + + return 1; +}; + +BinaryParser.decodeFloat = function decodeFloat (data, precisionBits, exponentBits) { + var b = new this.Buffer(this.bigEndian, data); + + b.checkBuffer(precisionBits + exponentBits + 1); + + var bias = maxBits[exponentBits - 1] - 1 + , signal = b.readBits(precisionBits + exponentBits, 1) + , exponent = b.readBits(precisionBits, exponentBits) + , significand = 0 + , divisor = 2 + , curByte = b.buffer.length + (-precisionBits >> 3) - 1; + + do { + for (var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 ); + } while (precisionBits -= startBit); + + return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 ); +}; + +BinaryParser.decodeInt = function decodeInt (data, bits, signed, forceBigEndian) { + var b = new this.Buffer(this.bigEndian || forceBigEndian, data) + , x = b.readBits(0, bits) + , max = maxBits[bits]; //max = Math.pow( 2, bits ); + + return signed && x >= max / 2 + ? x - max + : x; +}; + +BinaryParser.encodeFloat = function encodeFloat (data, precisionBits, exponentBits) { + var bias = maxBits[exponentBits - 1] - 1 + , minExp = -bias + 1 + , maxExp = bias + , minUnnormExp = minExp - precisionBits + , n = parseFloat(data) + , status = isNaN(n) || n == -Infinity || n == +Infinity ? n : 0 + , exp = 0 + , len = 2 * bias + 1 + precisionBits + 3 + , bin = new Array(len) + , signal = (n = status !== 0 ? 0 : n) < 0 + , intPart = Math.floor(n = Math.abs(n)) + , floatPart = n - intPart + , lastBit + , rounded + , result + , i + , j; + + for (i = len; i; bin[--i] = 0); + + for (i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor(intPart / 2)); + + for (i = bias + 1; floatPart > 0 && i; (bin[++i] = ((floatPart *= 2) >= 1) - 0 ) && --floatPart); + + for (i = -1; ++i < len && !bin[i];); + + if (bin[(lastBit = precisionBits - 1 + (i = (exp = bias + 1 - i) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - (exp = minExp - 1))) + 1]) { + if (!(rounded = bin[lastBit])) { + for (j = lastBit + 2; !rounded && j < len; rounded = bin[j++]); + } + + for (j = lastBit + 1; rounded && --j >= 0; (bin[j] = !bin[j] - 0) && (rounded = 0)); + } + + for (i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i];); + + if ((exp = bias + 1 - i) >= minExp && exp <= maxExp) { + ++i; + } else if (exp < minExp) { + exp != bias + 1 - len && exp < minUnnormExp && this.warn("encodeFloat::float underflow"); + i = bias + 1 - (exp = minExp - 1); + } + + if (intPart || status !== 0) { + this.warn(intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status); + exp = maxExp + 1; + i = bias + 2; + + if (status == -Infinity) { + signal = 1; + } else if (isNaN(status)) { + bin[i] = 1; + } + } + + for (n = Math.abs(exp + bias), j = exponentBits + 1, result = ""; --j; result = (n % 2) + result, n = n >>= 1); + + for (n = 0, j = 0, i = (result = (signal ? "1" : "0") + result + bin.slice(i, i + precisionBits).join("")).length, r = []; i; j = (j + 1) % 8) { + n += (1 << j) * result.charAt(--i); + if (j == 7) { + r[r.length] = String.fromCharCode(n); + n = 0; + } + } + + r[r.length] = n + ? String.fromCharCode(n) + : ""; + + return (this.bigEndian ? r.reverse() : r).join(""); +}; + +BinaryParser.encodeInt = function encodeInt (data, bits, signed, forceBigEndian) { + var max = maxBits[bits]; + + if (data >= max || data < -(max / 2)) { + this.warn("encodeInt::overflow"); + data = 0; + } + + if (data < 0) { + data += max; + } + + for (var r = []; data; r[r.length] = String.fromCharCode(data % 256), data = Math.floor(data / 256)); + + for (bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0"); + + return ((this.bigEndian || forceBigEndian) ? r.reverse() : r).join(""); +}; + +BinaryParser.toSmall = function( data ){ return this.decodeInt( data, 8, true ); }; +BinaryParser.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); }; +BinaryParser.toByte = function( data ){ return this.decodeInt( data, 8, false ); }; +BinaryParser.fromByte = function( data ){ return this.encodeInt( data, 8, false ); }; +BinaryParser.toShort = function( data ){ return this.decodeInt( data, 16, true ); }; +BinaryParser.fromShort = function( data ){ return this.encodeInt( data, 16, true ); }; +BinaryParser.toWord = function( data ){ return this.decodeInt( data, 16, false ); }; +BinaryParser.fromWord = function( data ){ return this.encodeInt( data, 16, false ); }; +BinaryParser.toInt = function( data ){ return this.decodeInt( data, 32, true ); }; +BinaryParser.fromInt = function( data ){ return this.encodeInt( data, 32, true ); }; +BinaryParser.toLong = function( data ){ return this.decodeInt( data, 64, true ); }; +BinaryParser.fromLong = function( data ){ return this.encodeInt( data, 64, true ); }; +BinaryParser.toDWord = function( data ){ return this.decodeInt( data, 32, false ); }; +BinaryParser.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); }; +BinaryParser.toQWord = function( data ){ return this.decodeInt( data, 64, true ); }; +BinaryParser.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); }; +BinaryParser.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); }; +BinaryParser.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); }; +BinaryParser.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); }; +BinaryParser.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); }; + +// Factor out the encode so it can be shared by add_header and push_int32 +BinaryParser.encode_int32 = function encode_int32 (number) { + var a, b, c, d, unsigned; + unsigned = (number < 0) ? (number + 0x100000000) : number; + a = Math.floor(unsigned / 0xffffff); + unsigned &= 0xffffff; + b = Math.floor(unsigned / 0xffff); + unsigned &= 0xffff; + c = Math.floor(unsigned / 0xff); + unsigned &= 0xff; + d = Math.floor(unsigned); + return chr(a) + chr(b) + chr(c) + chr(d); +}; + +BinaryParser.encode_int64 = function encode_int64 (number) { + var a, b, c, d, e, f, g, h, unsigned; + unsigned = (number < 0) ? (number + 0x10000000000000000) : number; + a = Math.floor(unsigned / 0xffffffffffffff); + unsigned &= 0xffffffffffffff; + b = Math.floor(unsigned / 0xffffffffffff); + unsigned &= 0xffffffffffff; + c = Math.floor(unsigned / 0xffffffffff); + unsigned &= 0xffffffffff; + d = Math.floor(unsigned / 0xffffffff); + unsigned &= 0xffffffff; + e = Math.floor(unsigned / 0xffffff); + unsigned &= 0xffffff; + f = Math.floor(unsigned / 0xffff); + unsigned &= 0xffff; + g = Math.floor(unsigned / 0xff); + unsigned &= 0xff; + h = Math.floor(unsigned); + return chr(a) + chr(b) + chr(c) + chr(d) + chr(e) + chr(f) + chr(g) + chr(h); +}; + +/** + * UTF8 methods + */ + +// Take a raw binary string and return a utf8 string +BinaryParser.decode_utf8 = function decode_utf8 (binaryStr) { + var len = binaryStr.length + , decoded = '' + , i = 0 + , c = 0 + , c1 = 0 + , c2 = 0 + , c3; + + while (i < len) { + c = binaryStr.charCodeAt(i); + if (c < 128) { + decoded += String.fromCharCode(c); + i++; + } else if ((c > 191) && (c < 224)) { + c2 = binaryStr.charCodeAt(i+1); + decoded += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); + i += 2; + } else { + c2 = binaryStr.charCodeAt(i+1); + c3 = binaryStr.charCodeAt(i+2); + decoded += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + } + + return decoded; +}; + +// Encode a cstring +BinaryParser.encode_cstring = function encode_cstring (s) { + return unescape(encodeURIComponent(s)) + BinaryParser.fromByte(0); +}; + +// Take a utf8 string and return a binary string +BinaryParser.encode_utf8 = function encode_utf8 (s) { + var a = "" + , c; + + for (var n = 0, len = s.length; n < len; n++) { + c = s.charCodeAt(n); + + if (c < 128) { + a += String.fromCharCode(c); + } else if ((c > 127) && (c < 2048)) { + a += String.fromCharCode((c>>6) | 192) ; + a += String.fromCharCode((c&63) | 128); + } else { + a += String.fromCharCode((c>>12) | 224); + a += String.fromCharCode(((c>>6) & 63) | 128); + a += String.fromCharCode((c&63) | 128); + } + } + + return a; +}; + +BinaryParser.hprint = function hprint (s) { + var number; + + for (var i = 0, len = s.length; i < len; i++) { + if (s.charCodeAt(i) < 32) { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + process.stdout.write(number + " ") + } else { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + process.stdout.write(number + " ") + } + } + + process.stdout.write("\n\n"); +}; + +BinaryParser.ilprint = function hprint (s) { + var number; + + for (var i = 0, len = s.length; i < len; i++) { + if (s.charCodeAt(i) < 32) { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(10) + : s.charCodeAt(i).toString(10); + + sys.debug(number+' : '); + } else { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(10) + : s.charCodeAt(i).toString(10); + sys.debug(number+' : '+ s.charAt(i)); + } + } +}; + +BinaryParser.hlprint = function hprint (s) { + var number; + + for (var i = 0, len = s.length; i < len; i++) { + if (s.charCodeAt(i) < 32) { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + sys.debug(number+' : '); + } else { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + sys.debug(number+' : '+ s.charAt(i)); + } + } +}; + +/** + * BinaryParser buffer constructor. + */ + +function BinaryParserBuffer (bigEndian, buffer) { + this.bigEndian = bigEndian || 0; + this.buffer = []; + this.setBuffer(buffer); +}; + +BinaryParserBuffer.prototype.setBuffer = function setBuffer (data) { + var l, i, b; + + if (data) { + i = l = data.length; + b = this.buffer = new Array(l); + for (; i; b[l - i] = data.charCodeAt(--i)); + this.bigEndian && b.reverse(); + } +}; + +BinaryParserBuffer.prototype.hasNeededBits = function hasNeededBits (neededBits) { + return this.buffer.length >= -(-neededBits >> 3); +}; + +BinaryParserBuffer.prototype.checkBuffer = function checkBuffer (neededBits) { + if (!this.hasNeededBits(neededBits)) { + throw new Error("checkBuffer::missing bytes"); + } +}; + +BinaryParserBuffer.prototype.readBits = function readBits (start, length) { + //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni) + + function shl (a, b) { + for (; b--; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1); + return a; + } + + if (start < 0 || length <= 0) { + return 0; + } + + this.checkBuffer(start + length); + + var offsetLeft + , offsetRight = start % 8 + , curByte = this.buffer.length - ( start >> 3 ) - 1 + , lastByte = this.buffer.length + ( -( start + length ) >> 3 ) + , diff = curByte - lastByte + , sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1)) + (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[lastByte++] & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight : 0); + + for(; diff; sum += shl(this.buffer[lastByte++], (diff-- << 3) - offsetRight)); + + return sum; +}; + +/** + * Expose. + */ + +exports.BinaryParser = BinaryParser; +BinaryParser.Buffer = BinaryParserBuffer; diff --git a/node_modules/mongodb/lib/mongodb/bson/binary_utils.js b/node_modules/mongodb/lib/mongodb/bson/binary_utils.js new file mode 100644 index 0000000..c52accd --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/bson/binary_utils.js @@ -0,0 +1,29 @@ +exports.encodeInt = function(value) { + var buffer = new Buffer(4); + buffer[3] = (value >> 24) & 0xff; + buffer[2] = (value >> 16) & 0xff; + buffer[1] = (value >> 8) & 0xff; + buffer[0] = value & 0xff; + return buffer; +} + +exports.encodeIntInPlace = function(value, buffer, index) { + buffer[index + 3] = (value >> 24) & 0xff; + buffer[index + 2] = (value >> 16) & 0xff; + buffer[index + 1] = (value >> 8) & 0xff; + buffer[index] = value & 0xff; +} + +exports.encodeCString = function(string) { + var buf = new Buffer(string, 'utf8'); + return [buf, new Buffer([0])]; +} + +exports.decodeUInt32 = function(array, index) { + return array[index] | array[index + 1] << 8 | array[index + 2] << 16 | array[index + 3] << 24; +} + +// Decode the int +exports.decodeUInt8 = function(array, index) { + return array[index]; +} diff --git a/node_modules/mongodb/lib/mongodb/bson/bson.js b/node_modules/mongodb/lib/mongodb/bson/bson.js new file mode 100644 index 0000000..b6fe1d1 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/bson/bson.js @@ -0,0 +1,1714 @@ +/** + * Module dependencies. + */ +var BinaryParser = require('./binary_parser').BinaryParser + , Long = require('../goog/math/long').Long + , Timestamp = require('./timestamp').Timestamp + , ObjectID = require('./objectid').ObjectID + , Binary = require('./binary').Binary + , debug = require('util').debug + , inspect = require('util').inspect + , inherits = require('util').inherits + , ieee754 = require('./float_parser'); + +/** + * BSON constructor. + */ + +function BSON () {}; + +// BSON MAX VALUES +BSON.BSON_INT32_MAX = 0x80000000; +BSON.BSON_INT32_MIN = -0x80000000; + +// JS MAX PRECISE VALUES +BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. +BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. + +// BSON DATA TYPES +BSON.BSON_DATA_NUMBER = 1; +BSON.BSON_DATA_STRING = 2; +BSON.BSON_DATA_OBJECT = 3; +BSON.BSON_DATA_ARRAY = 4; +BSON.BSON_DATA_BINARY = 5; +BSON.BSON_DATA_OID = 7; +BSON.BSON_DATA_BOOLEAN = 8; +BSON.BSON_DATA_DATE = 9; +BSON.BSON_DATA_NULL = 10; +BSON.BSON_DATA_REGEXP = 11; +BSON.BSON_DATA_CODE = 13; +BSON.BSON_DATA_SYMBOL = 14; +BSON.BSON_DATA_CODE_W_SCOPE = 15; +BSON.BSON_DATA_INT = 16; +BSON.BSON_DATA_TIMESTAMP = 17; +BSON.BSON_DATA_LONG = 18; + +// BSON BINARY DATA SUBTYPES +BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0; +BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1; +BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; +BSON.BSON_BINARY_SUBTYPE_UUID = 3; +BSON.BSON_BINARY_SUBTYPE_MD5 = 4; +BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128; + +/** + * Serialize `data` as BSON. + * + * @param {TODO} data + * @param {Bool|null} checkKeys - TODO + * @return {TODO} + */ + +// Does not do recursion, uses a stack to handle depth +// Experiment for performance +BSON.calculateObjectSize = function(object) { + var totalLength = (4 + 1); + var done = false; + var stack = []; + var currentObject = object; + var keys = null; + // Controls the flow + var finished = false; + + while(!done) { + // Only get keys if we have a new object + keys = keys == null ? Object.keys(currentObject) : keys; + + // Let's process all the elements + while(keys.length > 0) { + var name = keys.shift(); + var value = currentObject[name]; + + if(value == null) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (1); + } else if(typeof value == 'string') { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (Buffer.byteLength(value, 'utf8') + 4 + 1 + 1); + } else if(Array.isArray(value)) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (4 + 1) + 1; + stack.push({keys:keys, object:currentObject}); + currentObject = value; + keys = Object.keys(value) + } else if(typeof value == 'number' || toString.call(value) === '[object Number]') { + if(value >= BSON.BSON_INT32_MAX || value < BSON.BSON_INT32_MIN || + value !== parseInt(value, 10)) { + // Long and Number take same number of bytes. + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (8 + 1); + } else { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (4 + 1); + } + } else if(typeof value == 'boolean' || toString.call(value) === '[object Boolean]') { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (1 + 1); + } else if(value instanceof Date) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (8 + 1); + } else if(value instanceof ObjectID || (value.id && value.toHexString)) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (12 + 1); + } else if(value instanceof Binary) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (value.position + 1 + 4 + 1); + } else if(value instanceof Long) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (8 + 1); + } else if(value instanceof Timestamp) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (8 + 1); + } else if(value instanceof RegExp || toString.call(value) === '[object RegExp]') { + // Keep list of valid options + var options_array = []; + var str = value.toString(); + var clean_regexp = str.match(/\/.*\//, ''); + clean_regexp = clean_regexp[0].substring(1, clean_regexp[0].length - 1); + var options = str.substr(clean_regexp.length + 2); + + // Extract all options that are legal and sort them alphabetically + for(var index = 0, len = options.length; index < len; ++index) { + var chr = options.charAt(index); + if('i' == chr || 'm' == chr || 'x' == chr) { + options_array.push(chr); + } + } + + // Calculate the total length + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (Buffer.byteLength(clean_regexp) + 1 + options_array.length + 1 + 1); + } else if(value instanceof DBRef) { + var ordered_values = { + '$ref': value.namespace + , '$id' : value.oid + }; + + if(null != value.db) { + ordered_values['$db'] = value.db; + } + + // Calculate the object + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (4 + 1 + 1); + stack.push({keys:keys, object:currentObject}); + currentObject = ordered_values; + keys = Object.keys(ordered_values) + } else if(value instanceof Code && Object.keys(value.scope).length == 0) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (Buffer.byteLength(value.code.toString(), 'utf8') + 4 + 1 + 1); + } else if(value instanceof Code) { + // Calculate the length of the code string + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + 4 + (Buffer.byteLength(value.code.toString(), 'utf8') + 1) + 4; + totalLength += (4 + 1 + 1); + // Push the current object + stack.push({keys:keys, object:currentObject}); + currentObject = value.scope; + keys = Object.keys(value.scope) + } else if(value instanceof Symbol) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (Buffer.byteLength(value.value, 'utf8') + 4 + 1 + 1); + } else if(typeof value == 'object') { + // Calculate the object + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (4 + 1 + 1); + // Otherwise handle keys + stack.push({keys:keys, object:currentObject}); + currentObject = value; + keys = Object.keys(value) + } + + // Finished up the object + if(keys.length == 0) { + finished = true; + } + } + + // If the stack is empty let's finish up, otherwise pop the previous object and + // continue + if(stack.length == 0) { + done = true; + } else if(finished || keys.length == 0){ + var currentObjectStored = stack.pop(); + currentObject = currentObjectStored.object; + keys = currentObjectStored.keys; + finished = keys.length == 0; + } + } + + return totalLength; +} + +// In place serialization with index to starting point of serialization +BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, checkKeys, buffer, startIndex) { + if(object instanceof Object) { + // Encode the object using single allocated buffer and no recursion + var index = startIndex == null ? 0 : startIndex; + var done = false; + var stack = []; + var currentObject = object; + var keys = null; + var size = 0; + var objectIndex = 0; + var totalNumberOfObjects = 0; + // Special index for Code objects + var codeStartIndex = 0; + // Signals if we are finished up + var finished = false; + + // Current parsing object state + var currentObjectStored = {object: object, index: index, endIndex: 0, keys: Object.keys(object)}; + // Adjust the index + index = index + 4; + + // While meeting + while(!done) { + // While current object has keys + while(currentObjectStored.keys.length > 0) { + var name = currentObjectStored.keys.shift(); + var value = currentObjectStored.object[name]; + + // If we got a key check for valid type + if(name != null && checkKeys == true && (name != '$db' && name != '$ref' && name != '$id')) { + BSON.checkKey(name); + } + + if(value == null) { + // Write the type + buffer[index++] = BSON.BSON_DATA_NULL; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + } else if(typeof value == 'string') { + // Write the type + buffer[index++] = BSON.BSON_DATA_STRING; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Calculate size + size = Buffer.byteLength(value) + 1; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Ajust the index + index = index + 4; + // Write the string + buffer.write(value, index, 'utf8'); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + } else if((typeof value == 'number' || toString.call(value) === '[object Number]') && + value === parseInt(value, 10) && + value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { + // Write the type + var int64 = value >= BSON.BSON_INT32_MAX || value < BSON.BSON_INT32_MIN; + buffer[index++] = int64 ? BSON.BSON_DATA_LONG : BSON.BSON_DATA_INT; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + if(int64) { + // Write the number + var long = Long.fromNumber(value); + var lowBits = long.getLowBits(); + var highBits = long.getHighBits(); + + buffer[index + 3] = (lowBits >> 24) & 0xff; + buffer[index + 2] = (lowBits >> 16) & 0xff; + buffer[index + 1] = (lowBits >> 8) & 0xff; + buffer[index] = lowBits & 0xff; + + index += 4; + + buffer[index + 3] = (highBits >> 24) & 0xff; + buffer[index + 2] = (highBits >> 16) & 0xff; + buffer[index + 1] = (highBits >> 8) & 0xff; + buffer[index] = highBits & 0xff; + + index += 4; + } else { + // Write the int value to the buffer + buffer[index + 3] = (value >> 24) & 0xff; + buffer[index + 2] = (value >> 16) & 0xff; + buffer[index + 1] = (value >> 8) & 0xff; + buffer[index] = value & 0xff; + index = index + 4; + } + } else if(typeof value == 'number' || toString.call(value) === '[object Number]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_NUMBER; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Write float + ieee754.writeIEEE754(buffer, value, index, 'little', 52, 8); + // Ajust index + index = index + 8; + } else if(typeof value == 'boolean' || toString.call(value) === '[object Boolean]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_BOOLEAN; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + buffer[index++] = value ? 1 : 0; + } else if(value instanceof Date || toString.call(value) === '[object Date]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_DATE; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Write the date + var dateInMilis = Long.fromNumber(value.getTime()); + var lowBits = dateInMilis.getLowBits(); + var highBits = dateInMilis.getHighBits(); + + buffer[index + 3] = (lowBits >> 24) & 0xff; + buffer[index + 2] = (lowBits >> 16) & 0xff; + buffer[index + 1] = (lowBits >> 8) & 0xff; + buffer[index] = lowBits & 0xff; + index = index + 4; + + buffer[index + 3] = (highBits >> 24) & 0xff; + buffer[index + 2] = (highBits >> 16) & 0xff; + buffer[index + 1] = (highBits >> 8) & 0xff; + buffer[index] = highBits & 0xff; + index = index + 4; + } else if(value instanceof RegExp || toString.call(value) === '[object RegExp]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_REGEXP; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Keep list of valid options + var options_array = []; + var str = value.toString(); + var clean_regexp = str.match(/\/.*\//, ''); + clean_regexp = clean_regexp[0].substring(1, clean_regexp[0].length - 1); + // Get options from the regular expression + var options = str.substr(clean_regexp.length + 2); + + // Write the regexp to the buffer + buffer.write(clean_regexp, index, 'utf8'); + // Update the index + index = index + Buffer.byteLength(clean_regexp) + 1; + // Write ending cstring zero + buffer[index - 1] = 0; + + // Extract all options that are legal and sort them alphabetically + for(var i = 0, len = options.length; i < len; ++i) { + var chr = options[i]; + if('i' == chr || 'm' == chr || 'x' == chr) { + buffer[index++] = chr.charCodeAt(0) + } + } + + // Write ending cstring zero + buffer[index++] = 0; + } else if(value instanceof Long) { + // Write the type + buffer[index++] = BSON.BSON_DATA_LONG; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Write the date + var lowBits = value.getLowBits(); + var highBits = value.getHighBits(); + + buffer[index + 3] = (lowBits >> 24) & 0xff; + buffer[index + 2] = (lowBits >> 16) & 0xff; + buffer[index + 1] = (lowBits >> 8) & 0xff; + buffer[index] = lowBits & 0xff; + index = index + 4; + + buffer[index + 3] = (highBits >> 24) & 0xff; + buffer[index + 2] = (highBits >> 16) & 0xff; + buffer[index + 1] = (highBits >> 8) & 0xff; + buffer[index] = highBits & 0xff; + index = index + 4; + } else if(value instanceof Timestamp) { + // Write the type + buffer[index++] = BSON.BSON_DATA_TIMESTAMP; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Write the date + var lowBits = value.getLowBits(); + var highBits = value.getHighBits(); + + buffer[index + 3] = (lowBits >> 24) & 0xff; + buffer[index + 2] = (lowBits >> 16) & 0xff; + buffer[index + 1] = (lowBits >> 8) & 0xff; + buffer[index] = lowBits & 0xff; + index = index + 4; + + buffer[index + 3] = (highBits >> 24) & 0xff; + buffer[index + 2] = (highBits >> 16) & 0xff; + buffer[index + 1] = (highBits >> 8) & 0xff; + buffer[index] = highBits & 0xff; + index = index + 4; + } else if(value instanceof Binary) { + // Write the type + buffer[index++] = BSON.BSON_DATA_BINARY; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Extract the buffer + var data = value.value(true); + // Calculate size + size = data.length; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Update the index + index = index + 4; + // Write the subtype to the buffer + buffer[index++] = value.sub_type; + // Write the data to the object + data.copy(buffer, index, 0, data.length); + // Ajust index + index = index + data.length; + } else if(value instanceof ObjectID) { + // Write the type + buffer[index++] = BSON.BSON_DATA_OID; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Write objectid + buffer.write(value.id, index, 'binary'); + // Ajust index + index = index + 12; + } else if(value instanceof DBRef) { + // Write the type + buffer[index++] = BSON.BSON_DATA_OBJECT; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + var ordered_values = { + '$ref': value.namespace + , '$id' : value.oid + }; + + if(null != value.db) { + ordered_values['$db'] = value.db; + } + + // Push object on stack + stack.push(currentObjectStored); + // Set the new object + currentObjectStored = {object: ordered_values, index: index, endIndex: 0, keys: Object.keys(ordered_values)}; + // Adjust index + index = index + 4; + } else if(value instanceof Code && Object.keys(value.scope).length == 0) { + // Write the type + buffer[index++] = BSON.BSON_DATA_CODE; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Calculate size + size = Buffer.byteLength(value.code.toString()) + 1; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Ajust the index + index = index + 4; + // Write the string + buffer.write(value.code.toString(), index, 'utf8'); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + } else if(value instanceof Code) { + // Calculate the scope size + var scopeSize = BSON.calculateObjectSize(value.scope); + // Write the type + buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Convert value to string + var codeString = value.code.toString(); + var codeStringLength = Buffer.byteLength(codeString); + // Calculate size + size = 4 + codeStringLength + 1 + 4 + scopeSize; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Update index + index = index + 4; + + // Calculate codestring length + size = codeStringLength + 1; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Update index + index = index + 4; + + // Write the string + buffer.write(codeString, index, 'utf8'); + // Update index + index = index + codeStringLength; + // Add final 0 for cstring + buffer[index++] = 0; + + // Push the scope object + stack.push(currentObjectStored); + // Set the new object + currentObjectStored = {object: value.scope, index: index, endIndex: 0, keys: Object.keys(value.scope)}; + // Adjust index + index = index + 4; + } else if(value instanceof Symbol) { + // Write the type + buffer[index++] = BSON.BSON_DATA_SYMBOL; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Calculate size + size = Buffer.byteLength(value.value) + 1; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Ajust the index + index = index + 4; + // Write the string + buffer.write(value, index, 'utf8'); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + } else if(typeof value == 'object') { + // Write the type of either Array or object + buffer[index++] = Array.isArray(value) ? BSON.BSON_DATA_ARRAY : BSON.BSON_DATA_OBJECT; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Push object on stack + stack.push(currentObjectStored); + // Set the new object + currentObjectStored = {object: value, index: index, endIndex: 0, keys: Object.keys(value)}; + // Adjust index + index = index + 4; + } + + if(currentObjectStored.keys.length == 0) { + // Save end index + currentObjectStored.endIndex = index; + + // If we have a stack pop and finish up processing + if(stack.length > 0) { + // Write the current object size out + // Pack the size of the total buffer length + size = currentObjectStored.endIndex - currentObjectStored.index + 1; + // Write the size of the string to buffer + buffer[currentObjectStored.index + 3] = (size >> 24) & 0xff; + buffer[currentObjectStored.index + 2] = (size >> 16) & 0xff; + buffer[currentObjectStored.index + 1] = (size >> 8) & 0xff; + buffer[currentObjectStored.index] = size & 0xff; + // Adjust and set null last parameter + buffer[index++] = 0; + + // Pop off the stored object + currentObjectStored = stack.pop(); + } + } + } + + if(stack.length > 0) { + // Write the current object size out + // Pack the size of the total buffer length + size = stack.length >= 1 ? (index - currentObjectStored.index + 1) : + currentObjectStored.endIndex - currentObjectStored.index + 16; + // Write the size of the string to buffer + buffer[currentObjectStored.index + 3] = (size >> 24) & 0xff; + buffer[currentObjectStored.index + 2] = (size >> 16) & 0xff; + buffer[currentObjectStored.index + 1] = (size >> 8) & 0xff; + buffer[currentObjectStored.index] = size & 0xff; + // Adjust and set null last parameter + buffer[index++] = 0; + // Pop off the stored object + currentObjectStored = stack.pop(); + } else { + // Pack the size of the total buffer length + size = buffer.length; + // Write the size of the string to buffer + buffer[3] = (size >> 24) & 0xff; + buffer[2] = (size >> 16) & 0xff; + buffer[1] = (size >> 8) & 0xff; + buffer[0] = size & 0xff; + // Set last buffer field to 0 + buffer[buffer.length - 1] = 0; + // return buffer; + done = true; + break; + } + } + + // If we passed in an index + return index; + } else { + throw new Error("Not a valid object"); + } +} + +BSON.serialize = function serialize(object, checkKeys, asBuffer) { + if(object instanceof Object) { + // + // Calculate size of the object + // + var totalLength = (4 + 1); + var done = false; + var stack = []; + var currentObject = object; + var keys = null; + // Controls the flow + var finished = false; + + while(!done) { + // Only get keys if we have a new object + keys = keys == null ? Object.keys(currentObject) : keys; + + // Let's process all the elements + while(keys.length > 0) { + var name = keys.shift(); + var value = currentObject[name]; + + if(value == null) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (1); + } else if(typeof value == 'string') { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (Buffer.byteLength(value, 'utf8') + 4 + 1 + 1); + } else if(Array.isArray(value)) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (4 + 1) + 1; + stack.push({keys:keys, object:currentObject}); + currentObject = value; + keys = Object.keys(value) + } else if((typeof value == 'number' || toString.call(value) === '[object Number]') && + value === parseInt(value, 10) && + value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { + if(value >= BSON.BSON_INT32_MAX || value < BSON.BSON_INT32_MIN) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (8 + 1); + } else { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (4 + 1); + } + } else if(typeof value == 'number' || toString.call(value) === '[object Number]') { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (8 + 1); + } else if(typeof value == 'boolean' || toString.call(value) === '[object Boolean]') { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (1 + 1); + } else if(value instanceof Date) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (8 + 1); + } else if(value instanceof ObjectID || (value.id && value.toHexString)) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (12 + 1); + } else if(value instanceof Binary) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (value.position + 1 + 4 + 1); + } else if(value instanceof Long) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (8 + 1); + } else if(value instanceof Timestamp) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (8 + 1); + } else if(value instanceof RegExp || toString.call(value) === '[object RegExp]') { + // Keep list of valid options + var options_array = []; + var str = value.toString(); + var clean_regexp = str.match(/\/.*\//, ''); + clean_regexp = clean_regexp[0].substring(1, clean_regexp[0].length - 1); + var options = str.substr(clean_regexp.length + 2); + + // Extract all options that are legal and sort them alphabetically + for(var index = 0, len = options.length; index < len; ++index) { + var chr = options.charAt(index); + if('i' == chr || 'm' == chr || 'x' == chr) { + options_array.push(chr); + } + } + + // Calculate the total length + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (Buffer.byteLength(clean_regexp) + 1 + options_array.length + 1 + 1); + } else if(value instanceof DBRef) { + var ordered_values = { + '$ref': value.namespace + , '$id' : value.oid + }; + + if(null != value.db) { + ordered_values['$db'] = value.db; + } + + // Calculate the object + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (4 + 1 + 1); + stack.push({keys:keys, object:currentObject}); + currentObject = ordered_values; + keys = Object.keys(ordered_values) + } else if(value instanceof Code && Object.keys(value.scope).length == 0) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (Buffer.byteLength(value.code, 'utf8') + 4 + 1 + 1); + } else if(value instanceof Code) { + // Calculate the length of the code string + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + 4 + (Buffer.byteLength(value.code, 'utf8') + 1) + 4; + totalLength += (4 + 1 + 1); + // Push the current object + stack.push({keys:keys, object:currentObject}); + currentObject = value.scope; + keys = Object.keys(value.scope) + } else if(value instanceof Symbol) { + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (Buffer.byteLength(value.value, 'utf8') + 4 + 1 + 1); + } else if(typeof value == 'object') { + // Calculate the object + totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (4 + 1 + 1); + // Otherwise handle keys + stack.push({keys:keys, object:currentObject}); + currentObject = value; + keys = Object.keys(value) + } + + // Finished up the object + if(keys.length == 0) { + finished = true; + } + } + + // If the stack is empty let's finish up, otherwise pop the previous object and + // continue + if(stack.length == 0) { + done = true; + } else if(finished || keys.length == 0){ + var currentObjectStored = stack.pop(); + currentObject = currentObjectStored.object; + keys = currentObjectStored.keys; + finished = keys.length == 0; + } + } + + // Create a single buffer object + var buffer = new Buffer(totalLength); + + // + // Serialize object + // + var index = 0; + var done = false; + var stack = []; + var currentObject = object; + var keys = null; + var size = 0; + var objectIndex = 0; + var totalNumberOfObjects = 0; + // Special index for Code objects + var codeStartIndex = 0; + // Signals if we are finished up + var finished = false; + + // Current parsing object state + var currentObjectStored = {object: object, index: index, endIndex: 0, keys: Object.keys(object)}; + // Adjust the index + index = index + 4; + + // While meeting + while(!done) { + // While current object has keys + while(currentObjectStored.keys.length > 0) { + var name = currentObjectStored.keys.shift(); + var value = currentObjectStored.object[name]; + + // If we got a key check for valid type + if(name != null && checkKeys == true && (name != '$db' && name != '$ref' && name != '$id')) { + BSON.checkKey(name); + } + + if(value == null) { + // Write the type + buffer[index++] = BSON.BSON_DATA_NULL; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + } else if(typeof value == 'string') { + // Write the type + buffer[index++] = BSON.BSON_DATA_STRING; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Calculate size + size = Buffer.byteLength(value) + 1; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Ajust the index + index = index + 4; + // Write the string + buffer.write(value, index, 'utf8'); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + } else if((typeof value == 'number' || toString.call(value) === '[object Number]') && + value === parseInt(value, 10) && + value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { + // Write the type + var int64 = value >= BSON.BSON_INT32_MAX || value < BSON.BSON_INT32_MIN; + buffer[index++] = int64 ? BSON.BSON_DATA_LONG : BSON.BSON_DATA_INT; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + if(int64) { + // Write the number + var long = Long.fromNumber(value); + var lowBits = long.getLowBits(); + var highBits = long.getHighBits(); + + buffer[index + 3] = (lowBits >> 24) & 0xff; + buffer[index + 2] = (lowBits >> 16) & 0xff; + buffer[index + 1] = (lowBits >> 8) & 0xff; + buffer[index] = lowBits & 0xff; + index = index + 4; + + buffer[index + 3] = (highBits >> 24) & 0xff; + buffer[index + 2] = (highBits >> 16) & 0xff; + buffer[index + 1] = (highBits >> 8) & 0xff; + buffer[index] = highBits & 0xff; + index = index + 4; + } else { + // Write the int value to the buffer + buffer[index + 3] = (value >> 24) & 0xff; + buffer[index + 2] = (value >> 16) & 0xff; + buffer[index + 1] = (value >> 8) & 0xff; + buffer[index] = value & 0xff; + index = index + 4; + } + } else if(typeof value == 'number' || toString.call(value) === '[object Number]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_NUMBER; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Write float + ieee754.writeIEEE754(buffer, value, index, 'little', 52, 8); + // Ajust index + index = index + 8; + } else if(typeof value == 'boolean' || toString.call(value) === '[object Boolean]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_BOOLEAN; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + buffer[index++] = value ? 1 : 0; + } else if(value instanceof Date || toString.call(value) === '[object Date]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_DATE; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Write the date + var dateInMilis = Long.fromNumber(value.getTime()); + var lowBits = dateInMilis.getLowBits(); + var highBits = dateInMilis.getHighBits(); + + buffer[index + 3] = (lowBits >> 24) & 0xff; + buffer[index + 2] = (lowBits >> 16) & 0xff; + buffer[index + 1] = (lowBits >> 8) & 0xff; + buffer[index] = lowBits & 0xff; + index = index + 4; + + buffer[index + 3] = (highBits >> 24) & 0xff; + buffer[index + 2] = (highBits >> 16) & 0xff; + buffer[index + 1] = (highBits >> 8) & 0xff; + buffer[index] = highBits & 0xff; + index = index + 4; + } else if(value instanceof RegExp || toString.call(value) === '[object RegExp]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_REGEXP; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Keep list of valid options + var options_array = []; + var str = value.toString(); + var clean_regexp = str.match(/\/.*\//, ''); + clean_regexp = clean_regexp[0].substring(1, clean_regexp[0].length - 1); + // Get options from the regular expression + var options = str.substr(clean_regexp.length + 2); + + // Write the regexp to the buffer + buffer.write(clean_regexp, index, 'utf8'); + // Update the index + index = index + Buffer.byteLength(clean_regexp) + 1; + // Write ending cstring zero + buffer[index - 1] = 0; + + // Extract all options that are legal and sort them alphabetically + for(var i = 0, len = options.length; i < len; ++i) { + var chr = options[i]; + if('i' == chr || 'm' == chr || 'x' == chr) { + buffer[index++] = chr.charCodeAt(0) + } + } + + // Write ending cstring zero + buffer[index++] = 0; + } else if(value instanceof Long) { + // Write the type + buffer[index++] = BSON.BSON_DATA_LONG; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Write the date + var lowBits = value.getLowBits(); + var highBits = value.getHighBits(); + + buffer[index + 3] = (lowBits >> 24) & 0xff; + buffer[index + 2] = (lowBits >> 16) & 0xff; + buffer[index + 1] = (lowBits >> 8) & 0xff; + buffer[index] = lowBits & 0xff; + index = index + 4; + + buffer[index + 3] = (highBits >> 24) & 0xff; + buffer[index + 2] = (highBits >> 16) & 0xff; + buffer[index + 1] = (highBits >> 8) & 0xff; + buffer[index] = highBits & 0xff; + index = index + 4; + } else if(value instanceof Timestamp) { + // Write the type + buffer[index++] = BSON.BSON_DATA_TIMESTAMP; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Write the date + var lowBits = value.getLowBits(); + var highBits = value.getHighBits(); + + buffer[index + 3] = (lowBits >> 24) & 0xff; + buffer[index + 2] = (lowBits >> 16) & 0xff; + buffer[index + 1] = (lowBits >> 8) & 0xff; + buffer[index] = lowBits & 0xff; + index = index + 4; + + buffer[index + 3] = (highBits >> 24) & 0xff; + buffer[index + 2] = (highBits >> 16) & 0xff; + buffer[index + 1] = (highBits >> 8) & 0xff; + buffer[index] = highBits & 0xff; + index = index + 4; + // Ajust index + index = index + 8; + } else if(value instanceof Binary) { + // Write the type + buffer[index++] = BSON.BSON_DATA_BINARY; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Extract the buffer + var data = value.value(true); + // Calculate size + size = data.length; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Update the index + index = index + 4; + // Write the subtype to the buffer + buffer[index++] = value.sub_type; + // Write the data to the object + data.copy(buffer, index, 0, data.length); + // Ajust index + index = index + data.length; + } else if(value instanceof ObjectID) { + // Write the type + buffer[index++] = BSON.BSON_DATA_OID; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Write objectid + buffer.write(value.id, index, 'binary'); + // Ajust index + index = index + 12; + } else if(value instanceof DBRef) { + // Write the type + buffer[index++] = BSON.BSON_DATA_OBJECT; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + var ordered_values = { + '$ref': value.namespace + , '$id' : value.oid + }; + + if(null != value.db) { + ordered_values['$db'] = value.db; + } + + // Push object on stack + stack.push(currentObjectStored); + // Set the new object + currentObjectStored = {object: ordered_values, index: index, endIndex: 0, keys: Object.keys(ordered_values)}; + // Adjust index + index = index + 4; + } else if(value instanceof Code && Object.keys(value.scope).length == 0) { + // Write the type + buffer[index++] = BSON.BSON_DATA_CODE; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Calculate size + size = Buffer.byteLength(value.code) + 1; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Ajust the index + index = index + 4; + // Write the string + buffer.write(value.code, index, 'utf8'); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + } else if(value instanceof Code) { + // Calculate the scope size + var scopeSize = BSON.calculateObjectSize(value.scope); + // Write the type + buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Convert value to string + var codeString = value.code.toString(); + var codeStringLength = Buffer.byteLength(codeString); + // Calculate size + size = 4 + codeStringLength + 1 + 4 + scopeSize; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Update index + index = index + 4; + + // Calculate codestring length + size = codeStringLength + 1; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Update index + index = index + 4; + + // Write the string + buffer.write(codeString, index, 'utf8'); + // Update index + index = index + codeStringLength; + // Add final 0 for cstring + buffer[index++] = 0; + + // Push the scope object + stack.push(currentObjectStored); + // Set the new object + currentObjectStored = {object: value.scope, index: index, endIndex: 0, keys: Object.keys(value.scope)}; + // Adjust index + index = index + 4; + } else if(value instanceof Symbol) { + // Write the type + buffer[index++] = BSON.BSON_DATA_SYMBOL; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Calculate size + size = Buffer.byteLength(value.value) + 1; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Ajust the index + index = index + 4; + // Write the string + buffer.write(value.value, index, 'utf8'); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + } else if(typeof value == 'object') { + // Write the type of either Array or object + buffer[index++] = Array.isArray(value) ? BSON.BSON_DATA_ARRAY : BSON.BSON_DATA_OBJECT; + // Write the name + if(name != null) { + index = index + buffer.write(name, index, 'utf8') + 1; + buffer[index - 1] = 0; + } + + // Push object on stack + stack.push(currentObjectStored); + // Set the new object + currentObjectStored = {object: value, index: index, endIndex: 0, keys: Object.keys(value)}; + // Adjust index + index = index + 4; + } + + if(currentObjectStored.keys.length == 0) { + // Save end index + currentObjectStored.endIndex = index; + + // If we have a stack pop and finish up processing + if(stack.length > 0) { + // Write the current object size out + // Pack the size of the total buffer length + size = currentObjectStored.endIndex - currentObjectStored.index + 1; + // Write the size of the string to buffer + buffer[currentObjectStored.index + 3] = (size >> 24) & 0xff; + buffer[currentObjectStored.index + 2] = (size >> 16) & 0xff; + buffer[currentObjectStored.index + 1] = (size >> 8) & 0xff; + buffer[currentObjectStored.index] = size & 0xff; + // Adjust and set null last parameter + buffer[index++] = 0; + + // Pop off the stored object + currentObjectStored = stack.pop(); + } + } + } + + if(stack.length > 0) { + // Write the current object size out + // Pack the size of the total buffer length + size = stack.length >= 1 ? (index - currentObjectStored.index + 1) : + currentObjectStored.endIndex - currentObjectStored.index + 16; + // Write the size of the string to buffer + buffer[currentObjectStored.index + 3] = (size >> 24) & 0xff; + buffer[currentObjectStored.index + 2] = (size >> 16) & 0xff; + buffer[currentObjectStored.index + 1] = (size >> 8) & 0xff; + buffer[currentObjectStored.index] = size & 0xff; + // Adjust and set null last parameter + buffer[index++] = 0; + // Pop off the stored object + currentObjectStored = stack.pop(); + } else { + // Pack the size of the total buffer length + size = buffer.length; + // Write the size of the string to buffer + buffer[3] = (size >> 24) & 0xff; + buffer[2] = (size >> 16) & 0xff; + buffer[1] = (size >> 8) & 0xff; + buffer[0] = size & 0xff; + // Set last buffer field to 0 + buffer[buffer.length - 1] = 0; + // return buffer; + done = true; + break; + } + } + + // Return serialized object + return buffer; + } else { + throw new Error("Not a valid object"); + } +}; + +/** + * Deserialize `data` as BSON. + * + * @param {TODO} data + * @param {Bool} is_array_item + * @param {TODO} returnData + * @param {TODO} returnArray + * @return {TODO} + */ + +BSON.deserialize = function(data) { + if(!(data instanceof Buffer)) throw new Error("data stream not a buffer object"); + // Finial object returned to user + var object = {}; + var currentObject = object; + // Index for parse position + var index = 0; + // Stack for keeping parser objects + var stack = []; + // Size Of data + var bufferLength = data.length; + // Local variables + var value = null; + var string_name = null; + var string_end_index = 0; + var string_size = 0; + // Variables keeping track of sub object parsing + var object_end_index = 0; + var object_name= null; + + // Decode + var size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Ajust index + index = index + 4; + // Data length + var dataLength = data.length; + + while(index < dataLength) { + // Read the first byte indicating the type of object + var type = data[index]; + + // Adjust for the type of element + index = index + 1; + + // Check if we have finished an object + if(object_end_index !== 0 && index > object_end_index) { + // Save the current Object for storing + var value = currentObject; + + // Pop the previous object so we can add the attribute + var currentObjectInstance = stack.pop(); + + // Let's set the parent object as the current Object + if(currentObjectInstance != null) { + currentObject = currentObjectInstance.object; + object_end_index = currentObjectInstance.index; + + if(value['$id'] != null && value['$ref'] != null) { + value = new DBRef(value['$ref'], value['$id'], value['$db']); + } + + currentObject[currentObjectInstance.name] = value; + } + } + + if(type === BSON.BSON_DATA_STRING) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Decode the length of the string (next 4 bytes) + string_size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Adjust the index to point at start of string + index = index + 4; + // Read the string + value = data.toString('utf8', index, index + string_size - 1); + // Adjust the index with the size of the string + index = index + string_size; + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_REGEXP) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Read characters until end of regular expression + var reg_exp_array = []; + var chr = 1; + var start_index = index; + + while(data[index] !== 0) { + index = index + 1; + } + + // RegExp Expression + reg_exp = data.toString('utf8', start_index, index); + index = index + 1; + + // Read the options for the regular expression + var options_array = []; + + while(data[index] !== 0) { + options_array.push(String.fromCharCode(data[index])); + index = index + 1; + } + + // Regular expression + var value = new RegExp(reg_exp, options_array.join('')); + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_DATE) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Read low bits + var low_bits = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Adjust index + index = index + 4; + // Read high bits + var high_bits = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Adjust index + index = index + 4; + + // Create to integers + var value_in_seconds = new Long(low_bits, high_bits).toNumber(); + // Calculate date with miliseconds + var value = new Date(); + value.setTime(value_in_seconds); + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_BINARY) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Read the size of the binary + var number_of_bytes = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + index = index + 4; + + // Decode the subtype + var sub_type = data[index]; + index = index + 1; + + // Read the next bytes into our Binary object + var bin_data = data.slice(index, index + number_of_bytes); + // Binary object + var value = new Binary(bin_data); + value.sub_type = sub_type; + // Adjust index with number of bytes + index = index + number_of_bytes; + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_NUMBER) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Read the number value + var value = ieee754.readIEEE754(data, index, 'little', 52, 8); + // Adjust the index with the size + index = index + 8; + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_OID) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Read the oid (12 bytes) + var oid = data.toString('binary', index, index + 12); + // Calculate date with miliseconds + var value = new ObjectID(oid); + // Adjust the index + index = index + 12; + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_CODE_W_SCOPE) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Unpack the integer sizes + var total_code_size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + index = index + 4; + var string_size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + index = index + 4; + // Read the string + terminating null + var code_string = data.toString('utf8', index, index + string_size - 1); + index = index + string_size; + // Get the bson object + var bson_object_size = total_code_size - string_size - 8; + var bson_object_string = data.slice(index, index + bson_object_size); + index = index + bson_object_size; + // Parse the bson object + var scope_object = BSON.deserialize(bson_object_string, false); + // Create code object + var value = new Code(code_string, scope_object); + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_LONG || type === BSON.BSON_DATA_TIMESTAMP) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Read the number value + var low_bits = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Adjust index + index = index + 4; + // Read high bits + var high_bits = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Adjust index + index = index + 4; + var value; + if (type === BSON.BSON_DATA_LONG) { + value = new Long(low_bits, high_bits); + // Tricky: if this value is in [-2^53, 2^53], then it's perfectly + // representable as a Number. + if ((high_bits < 0x200000 || (high_bits === 0x200000 && low_bits === 0)) && + high_bits >= -0x200000) { + value = value.toNumber(); + } + } else { + value = new Timestamp(low_bits, high_bits); + } + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_INT) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Decode the length of the string (next 4 bytes) + var value = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Adjust the index with the size + index = index + 4; + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_NULL) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + // Set null value + value = null; + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_BOOLEAN) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Read the length of the string (next 4 bytes) + var boolean_value = data[index]; + var value = boolean_value == 1 ? true : false; + // Adjust the index + index = index + 1; + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } else if(type === BSON.BSON_DATA_OBJECT || type === BSON.BSON_DATA_ARRAY) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + object_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Decode the length of the object (next 4 bytes) + var object_size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Stack object + var stackObject = {name: object_name, object: currentObject, index: object_end_index}; + // Let's push the current object to the stack and work on this one + stack.push(stackObject); + // Set current pointer to empty object + currentObject = type === BSON.BSON_DATA_ARRAY ? [] : {}; + // Set the end index for the new object so we know then to stop + object_end_index = index + object_size; + // Ajdust index + index = index + 4; + } else if(type === BSON.BSON_DATA_SYMBOL) { + // Read the null terminated string (indexof until first 0) + string_end_index = index; + while(data[string_end_index++] !== 0); + string_end_index = string_end_index - 1; + + // Fetch the string name + string_name = data.toString('utf8', index, string_end_index); + // Ajust index to point to the end of the string + index = string_end_index + 1; + + // Decode the length of the string (next 4 bytes) + string_size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Adjust the index to point at start of string + index = index + 4; + // Read the string + value = new Symbol(data.toString('utf8', index, index + string_size - 1)); + // Adjust the index with the size of the string + index = index + string_size; + + // Set object property + currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value; + } + } + + // Return the object + return object; +} + +/** + * Check if key name is valid. + * + * @param {TODO} key + */ +BSON.checkKey = function checkKey (key) { + if (!key.length) return; + + // Check if we have a legal key for the object + if ('$' == key[0]) { + throw Error("key " + key + " must not start with '$'"); + } else if (!!~key.indexOf('.')) { + throw Error("key " + key + " must not contain '.'"); + } +}; + +/** + * Code constructor. + * + * @param {TODO} code + * @param {TODO} scope + */ + +function Code(code, scope) { + this.code = code; + this.scope = scope == null ? {} : scope; +}; + +/** + * Symbol constructor. + * + * @param {TODO} value + */ +function Symbol(value) { + this.value = value; +} + +Symbol.prototype.toString = function() { + return this.value; +} + +/** + * DBRef constructor. + * + * @param {TODO} namespace + * @param {TODO} oid + * @param {TODO} db + */ + +function DBRef (namespace, oid, db) { + this.namespace = namespace; + this.oid = oid; + this.db = db; +}; + +DBRef.prototype.toJSON = function() { + return JSON.stringify({ + '$ref':this.namespace, + '$id':this.oid, + '$db':this.db == null ? '' : this.db + }); +} + +/** + * Expose. + */ + +exports.Code = Code; +exports.Symbol = Symbol; +exports.BSON = BSON; +exports.DBRef = DBRef; +exports.Binary = Binary; +exports.ObjectID = ObjectID; +exports.Long = Long; +exports.Timestamp = Timestamp; diff --git a/node_modules/mongodb/lib/mongodb/bson/float_parser.js b/node_modules/mongodb/lib/mongodb/bson/float_parser.js new file mode 100644 index 0000000..5d2af61 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/bson/float_parser.js @@ -0,0 +1,118 @@ +// Copyright (c) 2008, Fair Oaks Labs, Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 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. +// +// +// Modifications to writeIEEE754 to support negative zeroes made by Brian White + +exports.readIEEE754 = function(buffer, offset, endian, mLen, nBytes) { + var e, m, + bBE = (endian === 'big'), + eLen = nBytes * 8 - mLen - 1, + eMax = (1 << eLen) - 1, + eBias = eMax >> 1, + nBits = -7, + i = bBE ? 0 : (nBytes - 1), + d = bBE ? 1 : -1, + s = buffer[offset + i]; + + i += d; + + e = s & ((1 << (-nBits)) - 1); + s >>= (-nBits); + nBits += eLen; + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); + + m = e & ((1 << (-nBits)) - 1); + e >>= (-nBits); + nBits += mLen; + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); + + if (e === 0) { + e = 1 - eBias; + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity); + } else { + m = m + Math.pow(2, mLen); + e = e - eBias; + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen); +}; + +exports.writeIEEE754 = function(buffer, value, offset, endian, mLen, nBytes) { + var e, m, c, + bBE = (endian === 'big'), + eLen = nBytes * 8 - mLen - 1, + eMax = (1 << eLen) - 1, + eBias = eMax >> 1, + rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), + i = bBE ? (nBytes-1) : 0, + d = bBE ? -1 : 1, + s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; + + value = Math.abs(value); + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0; + e = eMax; + } else { + e = Math.floor(Math.log(value) / Math.LN2); + if (value * (c = Math.pow(2, -e)) < 1) { + e--; + c *= 2; + } + if (e+eBias >= 1) { + value += rt / c; + } else { + value += rt * Math.pow(2, 1 - eBias); + } + if (value * c >= 2) { + e++; + c /= 2; + } + + if (e + eBias >= eMax) { + m = 0; + e = eMax; + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen); + e = e + eBias; + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); + e = 0; + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); + + e = (e << mLen) | m; + eLen += mLen; + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); + + buffer[offset + i - d] |= s * 128; +}; diff --git a/node_modules/mongodb/lib/mongodb/bson/objectid.js b/node_modules/mongodb/lib/mongodb/bson/objectid.js new file mode 100644 index 0000000..21dbaf4 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/bson/objectid.js @@ -0,0 +1,175 @@ +/** + * Module dependencies. + */ + +var BinaryParser = require('./binary_parser').BinaryParser, + inspect = require('util').inspect, + debug = require('util').debug; + +/** + * Machine id. + * + * Create a random 3-byte value (i.e. unique for this + * process). Other drivers use a md5 of the machine id here, but + * that would mean an asyc call to gethostname, so we don't bother. + */ + +var MACHINE_ID = parseInt(Math.random() * 0xFFFFFF, 10); + +/** + * Constructor. + * + * @param {String} id (optional) + */ + +function ObjectID (id) { + // Throw an error if it's not a valid setup + if(id != null && (id.length != 12 && id.length != 24)) throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters in hex format"); + // Generate id based on the input + if (null == id) { + this.id = this.generate(); + } else if (/^[0-9a-fA-F]{24}$/.test(id)) { + return ObjectID.createFromHexString(id); + } else { + this.id = id; + } +}; + +/** + * Updates the ObjectID index. + * + * @return {Number} + */ + +ObjectID.prototype.get_inc = function() { + return ObjectID.index = (ObjectID.index + 1) % 0xFFFFFF; +}; + +/** + * Generates an ObjectId. + * + * @return {String} + */ + +ObjectID.prototype.generate = function() { + var unixTime = parseInt(Date.now()/1000, 10); + var time4Bytes = BinaryParser.encodeInt(unixTime, 32, true, true); + var machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false); + var pid2Bytes = BinaryParser.fromShort(process.pid); + var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true); + return time4Bytes + machine3Bytes + pid2Bytes + index3Bytes; +}; + +/** + * Converts this ObjectId to a hex string. + * + * @return {String} + */ + +ObjectID.prototype.toHexString = function() { + var hexString = '' + , number + , value; + + for (var index = 0, len = this.id.length; index < len; index++) { + value = BinaryParser.toByte(this.id.substr(index, 1)); + number = value <= 15 + ? '0' + value.toString(16) + : value.toString(16); + hexString = hexString + number; + } + + return hexString; +}; + +/** + * Converts this id to a string. + * + * @return {String} + */ + +ObjectID.prototype.toString = function() { + return this.toHexString(); +}; + +/** + * Converts to a string representation of this Id. + */ + +ObjectID.prototype.inspect = ObjectID.prototype.toString; + +/** + * Converts to its JSON representation. + */ + +ObjectID.prototype.toJSON = ObjectID.prototype.toString; + +/** + * Compares the equality of this ObjectID with `otherID`. + * + * @return {Bool} + */ + +ObjectID.prototype.equals = function equals (otherID) { + var id = (otherID instanceof ObjectID || otherID.toHexString) + ? otherID.id + : ObjectID.createFromHexString(otherID).id; + + return this.id === id; +} + +/** + * Returns the generation time in seconds that this + * ID was generated. + * + * @return {Number} + */ + +ObjectID.prototype.__defineGetter__("generationTime", function() { + return BinaryParser.decodeInt(this.id.substring(0,4), 32, true, true) * 1000; +}); + +/** + * Statics. + */ + +ObjectID.index = 0; + +ObjectID.createPk = function createPk () { + return new ObjectID(); +}; + +/** + * Creates an ObjectID from a hex string representation + * of an ObjectID. + * + * @param {String} hexString + * @return {ObjectID} + */ + +ObjectID.createFromHexString = function createFromHexString (hexString) { + var len = hexString.length; + + if (len > 12*2) { + throw new Error('Id cannot be longer than 12 bytes'); + } + + var result = '' + , string + , number; + + for (var index = 0; index < len; index += 2) { + string = hexString.substr(index, 2); + number = parseInt(string, 16); + result += BinaryParser.fromByte(number); + } + + return new ObjectID(result); +}; + +/** + * Expose. + */ + +exports.ObjectID = ObjectID; + diff --git a/node_modules/mongodb/lib/mongodb/bson/timestamp.js b/node_modules/mongodb/lib/mongodb/bson/timestamp.js new file mode 100644 index 0000000..ae775be --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/bson/timestamp.js @@ -0,0 +1,791 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2009 Google Inc. All Rights Reserved + +/** + * @fileoverview Defines a exports.Timestamp class for representing a 64-bit two's-complement + * integer value, which faithfully simulates the behavior of a Java "Timestamp". This + * implementation is derived from exports.TimestampLib in GWT. + * + */ + +/** + * Constructs a 64-bit two's-complement integer, given its low and high 32-bit + * values as *signed* integers. See the from* functions below for more + * convenient ways of constructing exports.Timestamps. + * + * The internal representation of a Timestamp is the two given signed, 32-bit values. + * We use 32-bit pieces because these are the size of integers on which + * Javascript performs bit-operations. For operations like addition and + * multiplication, we split each number into 16-bit pieces, which can easily be + * multiplied within Javascript's floating-point representation without overflow + * or change in sign. + * + * In the algorithms below, we frequently reduce the negative case to the + * positive case by negating the input(s) and then post-processing the result. + * Note that we must ALWAYS check specially whether those values are MIN_VALUE + * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as + * a positive number, it overflows back into a negative). Not handling this + * case would often result in infinite recursion. + * + * @param {number} low The low (signed) 32 bits of the Timestamp. + * @param {number} high The high (signed) 32 bits of the Timestamp. + * @constructor + */ +exports.Timestamp = function(low, high) { + /** + * @type {number} + * @private + */ + this.low_ = low | 0; // force into 32 signed bits. + + /** + * @type {number} + * @private + */ + this.high_ = high | 0; // force into 32 signed bits. +}; + + +// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the +// from* methods on which they depend. + + +/** + * A cache of the exports.Timestamp representations of small integer values. + * @type {Object} + * @private + */ +exports.Timestamp.INT_CACHE_ = {}; + + +/** + * Returns a exports.Timestamp representing the given (32-bit) integer value. + * @param {number} value The 32-bit integer in question. + * @return {exports.Timestamp} The corresponding exports.Timestamp value. + */ +exports.Timestamp.fromInt = function(value) { + if (-128 <= value && value < 128) { + var cachedObj = exports.Timestamp.INT_CACHE_[value]; + if (cachedObj) { + return cachedObj; + } + } + + var obj = new exports.Timestamp(value | 0, value < 0 ? -1 : 0); + if (-128 <= value && value < 128) { + exports.Timestamp.INT_CACHE_[value] = obj; + } + return obj; +}; + + +/** + * Returns a exports.Timestamp representing the given value, provided that it is a finite + * number. Otherwise, zero is returned. + * @param {number} value The number in question. + * @return {exports.Timestamp} The corresponding exports.Timestamp value. + */ +exports.Timestamp.fromNumber = function(value) { + if (isNaN(value) || !isFinite(value)) { + return exports.Timestamp.ZERO; + } else if (value <= -exports.Timestamp.TWO_PWR_63_DBL_) { + return exports.Timestamp.MIN_VALUE; + } else if (value + 1 >= exports.Timestamp.TWO_PWR_63_DBL_) { + return exports.Timestamp.MAX_VALUE; + } else if (value < 0) { + return exports.Timestamp.fromNumber(-value).negate(); + } else { + return new exports.Timestamp( + (value % exports.Timestamp.TWO_PWR_32_DBL_) | 0, + (value / exports.Timestamp.TWO_PWR_32_DBL_) | 0); + } +}; + + +/** + * Returns a exports.Timestamp representing the 64-bit integer that comes by concatenating + * the given high and low bits. Each is assumed to use 32 bits. + * @param {number} lowBits The low 32-bits. + * @param {number} highBits The high 32-bits. + * @return {exports.Timestamp} The corresponding exports.Timestamp value. + */ +exports.Timestamp.fromBits = function(lowBits, highBits) { + return new exports.Timestamp(lowBits, highBits); +}; + + +/** + * Returns a exports.Timestamp representation of the given string, written using the given + * radix. + * @param {string} str The textual representation of the exports.Timestamp. + * @param {number} opt_radix The radix in which the text is written. + * @return {exports.Timestamp} The corresponding exports.Timestamp value. + */ +exports.Timestamp.fromString = function(str, opt_radix) { + if (str.length == 0) { + throw Error('number format error: empty string'); + } + + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (str.charAt(0) == '-') { + return exports.Timestamp.fromString(str.substring(1), radix).negate(); + } else if (str.indexOf('-') >= 0) { + throw Error('number format error: interior "-" character: ' + str); + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = exports.Timestamp.fromNumber(Math.pow(radix, 8)); + + var result = exports.Timestamp.ZERO; + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i); + var value = parseInt(str.substring(i, i + size), radix); + if (size < 8) { + var power = exports.Timestamp.fromNumber(Math.pow(radix, size)); + result = result.multiply(power).add(exports.Timestamp.fromNumber(value)); + } else { + result = result.multiply(radixToPower); + result = result.add(exports.Timestamp.fromNumber(value)); + } + } + return result; +}; + + +// NOTE: the compiler should inline these constant values below and then remove +// these variables, so there should be no runtime penalty for these. + + +/** + * Number used repeated below in calculations. This must appear before the + * first call to any from* function below. + * @type {number} + * @private + */ +exports.Timestamp.TWO_PWR_16_DBL_ = 1 << 16; + +/** + * @type {number} + * @private + */ +exports.Timestamp.TWO_PWR_24_DBL_ = 1 << 24; + +/** + * @type {number} + * @private + */ +exports.Timestamp.TWO_PWR_32_DBL_ = + exports.Timestamp.TWO_PWR_16_DBL_ * exports.Timestamp.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @private + */ +exports.Timestamp.TWO_PWR_31_DBL_ = + exports.Timestamp.TWO_PWR_32_DBL_ / 2; + +/** + * @type {number} + * @private + */ +exports.Timestamp.TWO_PWR_48_DBL_ = + exports.Timestamp.TWO_PWR_32_DBL_ * exports.Timestamp.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @private + */ +exports.Timestamp.TWO_PWR_64_DBL_ = + exports.Timestamp.TWO_PWR_32_DBL_ * exports.Timestamp.TWO_PWR_32_DBL_; + +/** + * @type {number} + * @private + */ +exports.Timestamp.TWO_PWR_63_DBL_ = + exports.Timestamp.TWO_PWR_64_DBL_ / 2; + + +/** @type {exports.Timestamp} */ +exports.Timestamp.ZERO = exports.Timestamp.fromInt(0); + +/** @type {exports.Timestamp} */ +exports.Timestamp.ONE = exports.Timestamp.fromInt(1); + +/** @type {exports.Timestamp} */ +exports.Timestamp.NEG_ONE = exports.Timestamp.fromInt(-1); + +/** @type {exports.Timestamp} */ +exports.Timestamp.MAX_VALUE = + exports.Timestamp.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); + +/** @type {exports.Timestamp} */ +exports.Timestamp.MIN_VALUE = exports.Timestamp.fromBits(0, 0x80000000 | 0); + + +/** + * @type {exports.Timestamp} + * @private + */ +exports.Timestamp.TWO_PWR_24_ = exports.Timestamp.fromInt(1 << 24); + + +/** @return {number} The value, assuming it is a 32-bit integer. */ +exports.Timestamp.prototype.toInt = function() { + return this.low_; +}; + + +/** @return {number} The closest floating-point representation to this value. */ +exports.Timestamp.prototype.toNumber = function() { + return this.high_ * exports.Timestamp.TWO_PWR_32_DBL_ + + this.getLowBitsUnsigned(); +}; + +/** convert code to JSON **/ +exports.Timestamp.prototype.toJSON = function() { + return this.toString(); +} + +/** + * @param {number} opt_radix The radix in which the text should be written. + * @return {string} The textual representation of this value. + */ +exports.Timestamp.prototype.toString = function(opt_radix) { + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (this.isZero()) { + return '0'; + } + + if (this.isNegative()) { + if (this.equals(exports.Timestamp.MIN_VALUE)) { + // We need to change the exports.Timestamp value before it can be negated, so we remove + // the bottom-most digit in this base and then recurse to do the rest. + var radixTimestamp = exports.Timestamp.fromNumber(radix); + var div = this.div(radixTimestamp); + var rem = div.multiply(radixTimestamp).subtract(this); + return div.toString(radix) + rem.toInt().toString(radix); + } else { + return '-' + this.negate().toString(radix); + } + } + + // Do several (6) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = exports.Timestamp.fromNumber(Math.pow(radix, 6)); + + var rem = this; + var result = ''; + while (true) { + var remDiv = rem.div(radixToPower); + var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); + var digits = intval.toString(radix); + + rem = remDiv; + if (rem.isZero()) { + return digits + result; + } else { + while (digits.length < 6) { + digits = '0' + digits; + } + result = '' + digits + result; + } + } +}; + + +/** @return {number} The high 32-bits as a signed value. */ +exports.Timestamp.prototype.getHighBits = function() { + return this.high_; +}; + + +/** @return {number} The low 32-bits as a signed value. */ +exports.Timestamp.prototype.getLowBits = function() { + return this.low_; +}; + + +/** @return {number} The low 32-bits as an unsigned value. */ +exports.Timestamp.prototype.getLowBitsUnsigned = function() { + return (this.low_ >= 0) ? + this.low_ : exports.Timestamp.TWO_PWR_32_DBL_ + this.low_; +}; + + +/** + * @return {number} Returns the number of bits needed to represent the absolute + * value of this exports.Timestamp. + */ +exports.Timestamp.prototype.getNumBitsAbs = function() { + if (this.isNegative()) { + if (this.equals(exports.Timestamp.MIN_VALUE)) { + return 64; + } else { + return this.negate().getNumBitsAbs(); + } + } else { + var val = this.high_ != 0 ? this.high_ : this.low_; + for (var bit = 31; bit > 0; bit--) { + if ((val & (1 << bit)) != 0) { + break; + } + } + return this.high_ != 0 ? bit + 33 : bit + 1; + } +}; + + +/** @return {boolean} Whether this value is zero. */ +exports.Timestamp.prototype.isZero = function() { + return this.high_ == 0 && this.low_ == 0; +}; + + +/** @return {boolean} Whether this value is negative. */ +exports.Timestamp.prototype.isNegative = function() { + return this.high_ < 0; +}; + + +/** @return {boolean} Whether this value is odd. */ +exports.Timestamp.prototype.isOdd = function() { + return (this.low_ & 1) == 1; +}; + + +/** + * @param {exports.Timestamp} other exports.Timestamp to compare against. + * @return {boolean} Whether this exports.Timestamp equals the other. + */ +exports.Timestamp.prototype.equals = function(other) { + return (this.high_ == other.high_) && (this.low_ == other.low_); +}; + + +/** + * @param {exports.Timestamp} other exports.Timestamp to compare against. + * @return {boolean} Whether this exports.Timestamp does not equal the other. + */ +exports.Timestamp.prototype.notEquals = function(other) { + return (this.high_ != other.high_) || (this.low_ != other.low_); +}; + + +/** + * @param {exports.Timestamp} other exports.Timestamp to compare against. + * @return {boolean} Whether this exports.Timestamp is less than the other. + */ +exports.Timestamp.prototype.lessThan = function(other) { + return this.compare(other) < 0; +}; + + +/** + * @param {exports.Timestamp} other exports.Timestamp to compare against. + * @return {boolean} Whether this exports.Timestamp is less than or equal to the other. + */ +exports.Timestamp.prototype.lessThanOrEqual = function(other) { + return this.compare(other) <= 0; +}; + + +/** + * @param {exports.Timestamp} other exports.Timestamp to compare against. + * @return {boolean} Whether this exports.Timestamp is greater than the other. + */ +exports.Timestamp.prototype.greaterThan = function(other) { + return this.compare(other) > 0; +}; + + +/** + * @param {exports.Timestamp} other exports.Timestamp to compare against. + * @return {boolean} Whether this exports.Timestamp is greater than or equal to the other. + */ +exports.Timestamp.prototype.greaterThanOrEqual = function(other) { + return this.compare(other) >= 0; +}; + + +/** + * Compares this exports.Timestamp with the given one. + * @param {exports.Timestamp} other exports.Timestamp to compare against. + * @return {number} 0 if they are the same, 1 if the this is greater, and -1 + * if the given one is greater. + */ +exports.Timestamp.prototype.compare = function(other) { + if (this.equals(other)) { + return 0; + } + + var thisNeg = this.isNegative(); + var otherNeg = other.isNegative(); + if (thisNeg && !otherNeg) { + return -1; + } + if (!thisNeg && otherNeg) { + return 1; + } + + // at this point, the signs are the same, so subtraction will not overflow + if (this.subtract(other).isNegative()) { + return -1; + } else { + return 1; + } +}; + + +/** @return {exports.Timestamp} The negation of this value. */ +exports.Timestamp.prototype.negate = function() { + if (this.equals(exports.Timestamp.MIN_VALUE)) { + return exports.Timestamp.MIN_VALUE; + } else { + return this.not().add(exports.Timestamp.ONE); + } +}; + + +/** + * Returns the sum of this and the given exports.Timestamp. + * @param {exports.Timestamp} other exports.Timestamp to add to this one. + * @return {exports.Timestamp} The sum of this and the given exports.Timestamp. + */ +exports.Timestamp.prototype.add = function(other) { + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 + b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 + b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 + b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 + b48; + c48 &= 0xFFFF; + return exports.Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + + +/** + * Returns the difference of this and the given exports.Timestamp. + * @param {exports.Timestamp} other exports.Timestamp to subtract from this. + * @return {exports.Timestamp} The difference of this and the given exports.Timestamp. + */ +exports.Timestamp.prototype.subtract = function(other) { + return this.add(other.negate()); +}; + + +/** + * Returns the product of this and the given Timestamp. + * @param {exports.Timestamp} other exports.Timestamp to multiply with this. + * @return {exports.Timestamp} The product of this and the other. + */ +exports.Timestamp.prototype.multiply = function(other) { + if (this.isZero()) { + return exports.Timestamp.ZERO; + } else if (other.isZero()) { + return exports.Timestamp.ZERO; + } + + if (this.equals(exports.Timestamp.MIN_VALUE)) { + return other.isOdd() ? exports.Timestamp.MIN_VALUE : exports.Timestamp.ZERO; + } else if (other.equals(exports.Timestamp.MIN_VALUE)) { + return this.isOdd() ? exports.Timestamp.MIN_VALUE : exports.Timestamp.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().multiply(other.negate()); + } else { + return this.negate().multiply(other).negate(); + } + } else if (other.isNegative()) { + return this.multiply(other.negate()).negate(); + } + + // If both Timestamps are small, use float multiplication + if (this.lessThan(exports.Timestamp.TWO_PWR_24_) && + other.lessThan(exports.Timestamp.TWO_PWR_24_)) { + return exports.Timestamp.fromNumber(this.toNumber() * other.toNumber()); + } + + // Divide each Timestamp into 4 chunks of 16 bits, and then add up 4x4 products. + // We can skip products that would overflow. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 * b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 * b00; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c16 += a00 * b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 * b00; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a16 * b16; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a00 * b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; + c48 &= 0xFFFF; + return exports.Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + + +/** + * Returns this exports.Timestamp divided by the given one. + * @param {exports.Timestamp} other exports.Timestamp by which to divide. + * @return {exports.Timestamp} This exports.Timestamp divided by the given one. + */ +exports.Timestamp.prototype.div = function(other) { + if (other.isZero()) { + throw Error('division by zero'); + } else if (this.isZero()) { + return exports.Timestamp.ZERO; + } + + if (this.equals(exports.Timestamp.MIN_VALUE)) { + if (other.equals(exports.Timestamp.ONE) || + other.equals(exports.Timestamp.NEG_ONE)) { + return exports.Timestamp.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE + } else if (other.equals(exports.Timestamp.MIN_VALUE)) { + return exports.Timestamp.ONE; + } else { + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. + var halfThis = this.shiftRight(1); + var approx = halfThis.div(other).shiftLeft(1); + if (approx.equals(exports.Timestamp.ZERO)) { + return other.isNegative() ? exports.Timestamp.ONE : exports.Timestamp.NEG_ONE; + } else { + var rem = this.subtract(other.multiply(approx)); + var result = approx.add(rem.div(other)); + return result; + } + } + } else if (other.equals(exports.Timestamp.MIN_VALUE)) { + return exports.Timestamp.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().div(other.negate()); + } else { + return this.negate().div(other).negate(); + } + } else if (other.isNegative()) { + return this.div(other.negate()).negate(); + } + + // Repeat the following until the remainder is less than other: find a + // floating-point that approximates remainder / other *from below*, add this + // into the result, and subtract it from the remainder. It is critical that + // the approximate value is less than or equal to the real value so that the + // remainder never becomes negative. + var res = exports.Timestamp.ZERO; + var rem = this; + while (rem.greaterThanOrEqual(other)) { + // Approximate the result of division. This may be a little greater or + // smaller than the actual value. + var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); + + // We will tweak the approximate result by changing it in the 48-th digit or + // the smallest non-fractional digit, whichever is larger. + var log2 = Math.ceil(Math.log(approx) / Math.LN2); + var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); + + // Decrease the approximation until it is smaller than the remainder. Note + // that if it is too large, the product overflows and is negative. + var approxRes = exports.Timestamp.fromNumber(approx); + var approxRem = approxRes.multiply(other); + while (approxRem.isNegative() || approxRem.greaterThan(rem)) { + approx -= delta; + approxRes = exports.Timestamp.fromNumber(approx); + approxRem = approxRes.multiply(other); + } + + // We know the answer can't be zero... and actually, zero would cause + // infinite recursion since we would make no progress. + if (approxRes.isZero()) { + approxRes = exports.Timestamp.ONE; + } + + res = res.add(approxRes); + rem = rem.subtract(approxRem); + } + return res; +}; + + +/** + * Returns this exports.Timestamp modulo the given one. + * @param {exports.Timestamp} other exports.Timestamp by which to mod. + * @return {exports.Timestamp} This exports.Timestamp modulo the given one. + */ +exports.Timestamp.prototype.modulo = function(other) { + return this.subtract(this.div(other).multiply(other)); +}; + + +/** @return {exports.Timestamp} The bitwise-NOT of this value. */ +exports.Timestamp.prototype.not = function() { + return exports.Timestamp.fromBits(~this.low_, ~this.high_); +}; + + +/** + * Returns the bitwise-AND of this exports.Timestamp and the given one. + * @param {exports.Timestamp} other The exports.Timestamp with which to AND. + * @return {exports.Timestamp} The bitwise-AND of this and the other. + */ +exports.Timestamp.prototype.and = function(other) { + return exports.Timestamp.fromBits(this.low_ & other.low_, + this.high_ & other.high_); +}; + + +/** + * Returns the bitwise-OR of this exports.Timestamp and the given one. + * @param {exports.Timestamp} other The exports.Timestamp with which to OR. + * @return {exports.Timestamp} The bitwise-OR of this and the other. + */ +exports.Timestamp.prototype.or = function(other) { + return exports.Timestamp.fromBits(this.low_ | other.low_, + this.high_ | other.high_); +}; + + +/** + * Returns the bitwise-XOR of this exports.Timestamp and the given one. + * @param {exports.Timestamp} other The exports.Timestamp with which to XOR. + * @return {exports.Timestamp} The bitwise-XOR of this and the other. + */ +exports.Timestamp.prototype.xor = function(other) { + return exports.Timestamp.fromBits(this.low_ ^ other.low_, + this.high_ ^ other.high_); +}; + + +/** + * Returns this exports.Timestamp with bits shifted to the left by the given amount. + * @param {number} numBits The number of bits by which to shift. + * @return {exports.Timestamp} This shifted to the left by the given amount. + */ +exports.Timestamp.prototype.shiftLeft = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var low = this.low_; + if (numBits < 32) { + var high = this.high_; + return exports.Timestamp.fromBits( + low << numBits, + (high << numBits) | (low >>> (32 - numBits))); + } else { + return exports.Timestamp.fromBits(0, low << (numBits - 32)); + } + } +}; + + +/** + * Returns this exports.Timestamp with bits shifted to the right by the given amount. + * @param {number} numBits The number of bits by which to shift. + * @return {exports.Timestamp} This shifted to the right by the given amount. + */ +exports.Timestamp.prototype.shiftRight = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return exports.Timestamp.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >> numBits); + } else { + return exports.Timestamp.fromBits( + high >> (numBits - 32), + high >= 0 ? 0 : -1); + } + } +}; + + +/** + * Returns this exports.Timestamp with bits shifted to the right by the given amount, with + * the new top bits matching the current sign bit. + * @param {number} numBits The number of bits by which to shift. + * @return {exports.Timestamp} This shifted to the right by the given amount, with + * zeros placed into the new leading bits. + */ +exports.Timestamp.prototype.shiftRightUnsigned = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return exports.Timestamp.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >>> numBits); + } else if (numBits == 32) { + return exports.Timestamp.fromBits(high, 0); + } else { + return exports.Timestamp.fromBits(high >>> (numBits - 32), 0); + } + } +}; \ No newline at end of file diff --git a/node_modules/mongodb/lib/mongodb/collection.js b/node_modules/mongodb/lib/mongodb/collection.js new file mode 100644 index 0000000..0404c41 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/collection.js @@ -0,0 +1,1027 @@ +/** + * Module dependencies. + */ +var InsertCommand = require('./commands/insert_command').InsertCommand + , QueryCommand = require('./commands/query_command').QueryCommand + , DeleteCommand = require('./commands/delete_command').DeleteCommand + , UpdateCommand = require('./commands/update_command').UpdateCommand + , DbCommand = require('./commands/db_command').DbCommand + , BinaryParser = require('./bson/binary_parser').BinaryParser + , Cursor = require('./cursor').Cursor + , debug = require('util').debug + , inspect = require('util').inspect; + +/** + * Sort functions, Normalize and prepare sort parameters + */ + +function formatSortValue (sortDirection) { + var value = ("" + sortDirection).toLowerCase(); + + switch (value) { + case 'ascending': + case 'asc': + case '1': + return 1; + case 'descending': + case 'desc': + case '-1': + return -1; + default: + throw new Error("Illegal sort clause, must be of the form " + + "[['field1', '(ascending|descending)'], " + + "['field2', '(ascending|descending)']]"); + } +}; + +function formattedOrderClause (sortValue) { + var orderBy = {}; + + if (Array.isArray(sortValue)) { + sortValue.forEach(function (sortElement) { + if (sortElement.constructor == String) { + orderBy[sortElement] = 1; + } else { + orderBy[sortElement[0]] = formatSortValue(sortElement[1]); + } + }); + } else if (sortValue.constructor == String) { + orderBy[sortValue] = 1; + } else { + throw new Error("Illegal sort clause, must be of the form " + + "[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]"); + } + + return orderBy; +}; + +/** + * toString helper. + */ + +var toString = Object.prototype.toString; + +/** + * Collection constructor. + * + * @param {Database} db + * @param {String} collectionName + * @param {Function} pkFactory + */ + +function Collection (db, collectionName, pkFactory, options) { + this.checkCollectionName(collectionName); + + this.db = db; + this.collectionName = collectionName; + this.internalHint; + this.opts = options != null && ('object' === typeof options) ? options : {}; + this.slaveOk = options == null || options.slaveOk == null ? db.slaveOk : options.slaveOk; + + this.pkFactory = pkFactory == null + ? db.bson_serializer.ObjectID + : pkFactory; + + Object.defineProperty(this, "hint", { + enumerable: true + , get: function () { + return this.internalHint; + } + , set: function (v) { + this.internalHint = this.normalizeHintField(v); + } + }); +}; + +/** + * Inserts `docs` into the db. + * + * @param {Array|Object} docs + * @param {Object} options (optional) + * @param {Function} callback (optional) + * @return {Collection} + */ + +Collection.prototype.insert = function insert (docs, options, callback) { + if ('function' === typeof options) callback = options, options = {}; + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + + this.insertAll(Array.isArray(docs) ? docs : [docs], options, callback); + + return this; +}; + +/** + * Checks if `collectionName` is valid. + * + * @param {String} collectionName + */ + +Collection.prototype.checkCollectionName = function checkCollectionName (collectionName) { + if ('string' !== typeof collectionName) { + throw Error("collection name must be a String"); + } + + if (!collectionName || collectionName.indexOf('..') != -1) { + throw Error("collection names cannot be empty"); + } + + if (collectionName.indexOf('$') != -1 && + collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null) { + throw Error("collection names must not contain '$'"); + } + + if (collectionName.match(/^\.|\.$/) != null) { + throw Error("collection names must not start or end with '.'"); + } +}; + +/** + * Removes documents specified by `selector` from the db. + * @param {Object} selector (optional) + * @param {Object} options (optional) + * @param {Function} callback (optional) + */ + +Collection.prototype.remove = function remove (selector, options, callback) { + if ('function' === typeof selector) { + callback = selector; + selector = options = {}; + } else if ('function' === typeof options) { + callback = options; + options = {}; + } + + // Ensure options + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + + var deleteCommand = new DeleteCommand( + this.db + , this.db.databaseName + "." + this.collectionName + , selector); + + var errorOptions = options.safe != null ? options.safe : null; + errorOptions = errorOptions == null && this.opts.safe != null ? this.opts.safe : errorOptions; + errorOptions = errorOptions == null && this.db.strict != null ? this.db.strict : errorOptions; + + // Execute the command, do not add a callback as it's async + if (options && options.safe || this.opts.safe != null || this.db.strict) { + // Insert options + var commandOptions = {read:false}; + // If we have safe set set async to false + if(errorOptions == null) commandOptions['async'] = true; + // Set safe option + commandOptions['safe'] = true; + // If we have an error option + if(typeof errorOptions == 'object') { + var keys = Object.keys(errorOptions); + for(var i = 0; i < keys.length; i++) { + commandOptions[keys[i]] = errorOptions[keys[i]]; + } + } + + // Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection) + this.db.executeCommand(deleteCommand, commandOptions, function (err, error) { + error = error && error.documents; + if(!callback) return; + + if (err) { + callback(err); + } else if (error[0].err) { + callback(new Error(error[0].err)); + } else { + callback(null, error[0].n); + } + }); + } else { + var result = this.db.executeCommand(deleteCommand); + // If no callback just return + if (!callback) return; + // If error return error + if (result instanceof Error) { + return callback(result); + } + // Otherwise just return + return callback(); + } +}; + +/** + * Renames the collection. + * + * @param {String} newName + * @param {Function} callback + */ + +Collection.prototype.rename = function rename (newName, callback) { + var self = this; + + this.checkCollectionName(newName); + this.db.renameCollection(this.collectionName, newName, function (err, result) { + if (err) { + callback(err); + } else if (result.documents[0].ok == 0) { + callback(new Error(result.documents[0].errmsg)); + } else { + self.db.collection(newName, callback); + } + }); +}; + +/** + * Insert many docs into the db. + * + * @param {Array} docs + * @param {Object} options (optional) + * @param {Function} callback (optional) + */ + +Collection.prototype.insertAll = function insertAll (docs, options, callback) { + if('function' === typeof options) callback = options, options = {}; + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + + var insertCommand = new InsertCommand( + this.db + , this.db.databaseName + "." + this.collectionName); + + // Add the documents and decorate them with id's if they have none + for (var index = 0, len = docs.length; index < len; ++index) { + var doc = docs[index]; + + // Add id to each document if it's not already defined + if (!doc['_id'] && this.db.forceServerObjectId != true) { + doc['_id'] = this.pkFactory.createPk(); + } + + insertCommand.add(doc); + } + + // Collect errorOptions + var errorOptions = options.safe != null ? options.safe : null; + errorOptions = errorOptions == null && this.opts.safe != null ? this.opts.safe : errorOptions; + errorOptions = errorOptions == null && this.db.strict != null ? this.db.strict : errorOptions; + + // If safe is defined check for error message + // if(options != null && (options.safe == true || this.db.strict == true || this.opts.safe == true)) { + if(errorOptions) { + // Insert options + var commandOptions = {read:false}; + // If we have safe set set async to false + if(errorOptions == null) commandOptions['async'] = true; + // Set safe option + commandOptions['safe'] = true; + // If we have an error option + if(typeof errorOptions == 'object') { + var keys = Object.keys(errorOptions); + for(var i = 0; i < keys.length; i++) { + commandOptions[keys[i]] = errorOptions[keys[i]]; + } + } + + // Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection) + this.db.executeCommand(insertCommand, commandOptions, function (err, error) { + error = error && error.documents; + if(!callback) return; + + if (err) { + callback(err); + } else if (error[0].err) { + callback(new Error(error[0].err)); + } else { + callback(null, docs); + } + }); + } else { + var result = this.db.executeCommand(insertCommand); + // If no callback just return + if(!callback) return; + // If error return error + if(result instanceof Error) { + return callback(result); + } + // Otherwise just return + return callback(null, docs); + } +}; + +/** + * Save a document. + * + * @param {Object} doc + * @param {Object} options (optional) + * @param {Function} callback (optional) + */ + +Collection.prototype.save = function save (doc, options, callback) { + if('function' === typeof options) callback = options, options = null; + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + + var errorOptions = options.safe != null ? options.safe : false; + errorOptions = errorOptions == null && this.opts.safe != null ? this.opts.safe : errorOptions; + + var id = doc['_id']; + + if (id) { + this.update({ _id: id }, doc, { upsert: true, safe: errorOptions }, callback); + } else { + this.insert(doc, { safe: errorOptions }, callback && function (err, docs) { + if (err) return callback(err, null); + + if (Array.isArray(docs)) { + callback(err, docs[0]); + } else { + callback(err, docs); + } + }); + } +}; + +/** + * Updates documents. + * + * By default updates only the first found doc. To update all matching + * docs in the db, set options.multi to true. + * + * @param {Object} selector + * @param {Object} document - the fields/vals to be updated, or in the case of + * an upsert operation, inserted. + * @param {Object} options (optional) + * upsert - {bool} perform an upsert operation + * multi - {bool} update all documents matching the selector + * safe - {bool} check if the update failed (requires extra call to db) + * @param {Function} callback (optional) + */ + +Collection.prototype.update = function update (selector, document, options, callback) { + if('function' === typeof options) callback = options, options = null; + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + + var updateCommand = new UpdateCommand( + this.db + , this.db.databaseName + "." + this.collectionName + , selector + , document + , options); + + // Unpack the error options if any + var errorOptions = (options && options.safe != null) ? options.safe : null; + errorOptions = errorOptions == null && this.opts.safe != null ? this.opts.safe : errorOptions; + errorOptions = errorOptions == null && this.db.strict != null ? this.db.strict : errorOptions; + + // If we are executing in strict mode or safe both the update and the safe command must happen on the same line + if(errorOptions) { + // Insert options + var commandOptions = {read:false}; + // If we have safe set set async to false + if(errorOptions == null) commandOptions['async'] = true; + // Set safe option + commandOptions['safe'] = true; + // If we have an error option + if(typeof errorOptions == 'object') { + var keys = Object.keys(errorOptions); + for(var i = 0; i < keys.length; i++) { + commandOptions[keys[i]] = errorOptions[keys[i]]; + } + } + + // Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection) + this.db.executeCommand(updateCommand, commandOptions, function (err, error) { + error = error && error.documents; + if(!callback) return; + + if (err) { + callback(err); + } else if (error[0].err) { + callback(new Error(error[0].err)); + } else { + callback(null, error[0].n); + } + }); + } else { + var result = this.db.executeCommand(updateCommand); + // If no callback just return + if (!callback) return; + // If error return error + if (result instanceof Error) { + return callback(result); + } + // Otherwise just return + return callback(); + } +}; + +/** + * Fetch a distinct collection + * @param {String} key + * @param {Object} query (optional) + * @param {Function} callback (optional) + */ + +Collection.prototype.distinct = function distinct (key, query, callback) { + if ('function' === typeof query) callback = query, query = {}; + + var mapCommandHash = { + distinct: this.collectionName + , query: query + , key: key + }; + + var cmd = DbCommand.createDbCommand(this.db, mapCommandHash); + + this.db.executeCommand(cmd, {read:true}, function (err, result) { + if (err) { + return callback(err); + } + + if (result.documents[0].ok != 1) { + return callback(new Error(result.documents[0].errmsg)); + } + + callback(null, result.documents[0].values); + }); +}; + +/** + * Count number of matching documents in the db. + * + * @param {Object} query + * @param {Function} callback + */ + +Collection.prototype.count = function count (query, callback) { + if ('function' === typeof query) callback = query, query = {}; + + var final_query = { + count: this.collectionName + , query: query + , fields: null + }; + + var queryCommand = new QueryCommand( + this.db + , this.db.databaseName + ".$cmd" + , QueryCommand.OPTS_NO_CURSOR_TIMEOUT + , 0 + , -1 + , final_query + , null + ); + + this.db.executeCommand(queryCommand, {read:true}, function (err, result) { + if (err) { + callback(err); + } else if (result.documents[0].ok != 1) { + callback(new Error(result.documents[0].errmsg)); + } else { + callback(null, result.documents[0].n); + } + }); +}; + +/** + * Drop this collection. + * + * @param {Function} callback + */ + +Collection.prototype.drop = function drop (callback) { + this.db.dropCollection(this.collectionName, callback); +}; + +/** + * Find and update a document. + * + * @param {Object} query + * @param {Array} sort - if multiple docs match, choose the first one + * in the specified sort order as the object to manipulate + * @param {Object} doc - the fields/vals to be updated + * @param {Object} options - + * remove: {Bool} set to true to remove the object before returning + * upsert: {Bool} perform an upsert operation + * new: {Bool} set to true if you want to return the modified object + * rather than the original. Ignored for remove. + * @param {Function} callback + */ + +Collection.prototype.findAndModify = function findAndModify (query, sort, doc, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + sort = args.length ? args.shift() : []; + doc = args.length ? args.shift() : null; + options = args.length ? args.shift() : {}; + + var queryObject = { + 'findandmodify': this.collectionName + , 'query': query + , 'sort': formattedOrderClause(sort) + }; + + queryObject.new = options.new ? 1 : 0; + queryObject.remove = options.remove ? 1 : 0; + queryObject.upsert = options.upsert ? 1 : 0; + + if (options.fields) { + queryObject.fields = options.fields; + } + + if (doc && !options.remove) { + queryObject.update = doc; + } + + this.db.executeDbCommand(queryObject, function (err, result) { + if (err) { + callback(err); + } else if (result.documents[0].ok != 1) { + callback(new Error(result.documents[0].errmsg)); + } else { + callback(err, result.documents[0].value) + } + }); +} + +/** + * Various argument possibilities + * TODO : combine/reduce # of possibilities + * 1 callback? + * 2 selector, callback?, + * 2 callback?, options // really?! + * 3 selector, fields, callback? + * 3 selector, options, callback? + * 4,selector, fields, options, callback? + * 5 selector, fields, skip, limit, callback? + * 6 selector, fields, skip, limit, timeout, callback? + * + * Available options: + * limit, sort, fields, skip, hint, explain, snapshot, timeout, tailable, batchSize + */ + +Collection.prototype.find = function find () { + var options + , args = Array.prototype.slice.call(arguments, 0) + , has_callback = typeof args[args.length - 1] === 'function' + , has_weird_callback = typeof args[0] === 'function' + , callback = has_callback ? args.pop() : (has_weird_callback ? args.shift() : null) + , len = args.length + , selector = len >= 1 ? args[0] : {} + , fields = len >= 2 ? args[1] : undefined; + + if (len === 1 && has_weird_callback) { + // backwards compat for callback?, options case + selector = {}; + options = args[0]; + } + + if (len === 2) { + // backwards compat for options object + var test = ['limit','sort','fields','skip','hint','explain','snapshot','timeout','tailable', 'batchSize'] + , is_option = false; + + for (var idx = 0, l = test.length; idx < l; ++idx) { + if (test[idx] in fields) { + is_option = true; + break; + } + } + + if (is_option) { + options = fields; + fields = undefined; + } else { + options = {}; + } + } + + if (3 === len) { + options = args[2]; + } + + if (options && options.fields) { + fields = {}; + if (Array.isArray(options.fields)) { + if (!options.fields.length) { + fields['_id'] = 1; + } else { + for (var i = 0, l = options.fields.length; i < l; i++) { + fields[options.fields[i]] = 1; + } + } + } else { + fields = options.fields; + } + } + + if (!options) options = {}; + + options.skip = len > 3 ? args[2] : options.skip ? options.skip : 0; + options.limit = len > 3 ? args[3] : options.limit ? options.limit : 0; + options.hint = options.hint != null ? this.normalizeHintField(options.hint) : this.internalHint; + options.timeout = len == 5 ? args[4] : options.timeout ? options.timeout : undefined; + // If we have overridden slaveOk otherwise use the default db setting + options.slaveOk = options.slaveOk != null ? options.slaveOk : this.db.slaveOk; + + var o = options; + + // callback for backward compatibility + if (callback) { + // TODO refactor Cursor args + callback(null, new Cursor(this.db, this, selector, fields, o.skip, o.limit, o.sort, o.hint, o.explain, o.snapshot, o.timeout, o.tailable, o.batchSize, o.slaveOk)); + } else { + return new Cursor(this.db, this, selector, fields, o.skip, o.limit, o.sort, o.hint, o.explain, o.snapshot, o.timeout, o.tailable, o.batchSize, o.slaveOk); + } +}; + +/** + * Normalizes a `hint` argument. + * + * @param {String|Object|Array} hint + * @return {Object} + */ + +Collection.prototype.normalizeHintField = function normalizeHintField (hint) { + var finalHint = null; + + if (null != hint) { + switch (hint.constructor) { + case String: + finalHint = {}; + finalHint[hint] = 1; + break; + case Object: + finalHint = {}; + for (var name in hint) { + finalHint[name] = hint[name]; + } + break; + case Array: + finalHint = {}; + hint.forEach(function(param) { + finalHint[param] = 1; + }); + break; + } + } + + return finalHint; +}; + +/** + * Finds one document. + * + * @param {Object} queryObject + * @param {Object} options + * @param {Function} callback + */ + +Collection.prototype.findOne = function findOne (queryObject, options, callback) { + if ('function' === typeof queryObject) { + callback = queryObject; + queryObject = {}; + options = {}; + } else if ('function' === typeof options) { + callback = options; + options = {}; + } + + var fields; + + if (options.fields && Array.isArray(options.fields)) { + fields = {}; + if (0 === options.fields.length) { + fields['_id'] = 1; + } else { + for (var i = 0, len = options.fields.length; i < len; ++i) { + fields[options.fields[i]] = 1; + } + } + } else { + fields = options.fields; + } + + if (queryObject instanceof this.db.bson_serializer.ObjectID || + '[object ObjectID]' === toString.call(queryObject)) { + queryObject = { '_id': queryObject }; + } + + var query = { 'query': queryObject }; + + // If we have a timeout set + var timeout = null != options.timeout + ? options.timeout + : QueryCommand.OPTS_NONE; + + // Make sure we can do slaveOk commands + if (options.slaveOk || this.slaveOk || this.db.slaveOk) { + timeout |= QueryCommand.OPTS_SLAVE; + } + + var collectionName = (this.db.databaseName ? this.db.databaseName + '.' : '') + + this.collectionName; + + var queryCommand = new QueryCommand( + this.db + , collectionName + , timeout + , 0 + , 1 + , query + , fields); + + this.db.executeCommand(queryCommand, {read:true}, function (err, result) { + if (!err && result.documents[0] && result.documents[0]['$err']) { + return callback(result.documents[0]['$err']); + } + + callback(err, result && result.documents && result.documents[0]); + }); +}; + +/** + * Creates an index on this collection. + * + * @param {Object} fieldOrSpec + * @param {Object} options + * @param {Function} callback + */ + +Collection.prototype.createIndex = function createIndex (fieldOrSpec, options, callback) { + this.db.createIndex(this.collectionName, fieldOrSpec, options, callback); +}; + +/** + * Ensures the index exists on this collection. + * + * @param {Object} fieldOrSpec + * @param {Object} options + * @param {Function} callback + */ + +Collection.prototype.ensureIndex = function ensureIndex (fieldOrSpec, options, callback) { + this.db.ensureIndex(this.collectionName, fieldOrSpec, options, callback); +}; + +/** + * Retrieves this collections index info. + * + * @param {Object} options - + * full: {Bool} set to true to remove raw index information + * @param {Function} callback + */ +Collection.prototype.indexInformation = function indexInformation (options, callback) { + // Unpack calls + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + options = args.length ? args.shift() : {}; + // Call the index information + this.db.indexInformation(this.collectionName, options, callback); +}; + +/** + * Drops an index from this collection. + * + * @param {String} name + * @param {Function} callback + */ + +Collection.prototype.dropIndex = function dropIndex (name, callback) { + this.db.dropIndex(this.collectionName, name, callback); +}; + +/** + * Drops all indexes from this collection. + * + * @param {Function} callback + */ + +Collection.prototype.dropIndexes = function dropIndexes (callback) { + this.db.dropIndex(this.collectionName, '*', function (err, result) { + if (err) { + callback(err); + } else if (1 == result.documents[0].ok) { + callback(null, true); + } else { + callback(new Error("map-reduce failed: " + result.documents[0].errmsg), false); + } + }); +}; + +/** + * Map reduce. + * + * @param {Function|String} map + * @param {Function|String} reduce + * @param {Objects} options + * @param {Function} callback + */ + +Collection.prototype.mapReduce = function mapReduce (map, reduce, options, callback) { + if ('function' === typeof options) callback = options, options = {}; + + // Set default to be inline if we are dealing with a v 1.7.6 > server + var version = 'string' === typeof this.db.version + ? parseInt(this.db.version.replace(/\./g, '')) + : 0; + + if (version > 0 && version > 176) { + if (null == options.out) options.out = 'inline'; + } + + if ('function' === typeof map) { + map = map.toString(); + } + + if ('function' === typeof reduce) { + reduce = reduce.toString(); + } + + if ('function' === typeof options.finalize) { + options.finalize = options.finalize.toString(); + } + + var mapCommandHash = { + mapreduce: this.collectionName + , map: map + , reduce: reduce + }; + + // Add any other options passed in + for (var name in options) { + mapCommandHash[name] = options[name]; + } + + var self = this; + var cmd = DbCommand.createDbCommand(this.db, mapCommandHash); + + this.db.executeCommand(cmd, {read:true}, function (err, result) { + if (err) { + return callback(err); + } + + if (1 != result.documents[0].ok) { + return callback(result.documents[0]); + } + + // invoked with inline? + if (result.documents[0].results) { + return callback(null, result.documents[0].results); + } + + // Create a collection object that wraps the result collection + self.db.collection(result.documents[0].result, function (err, collection) { + if (!options.include_statistics) { + return callback(err, collection); + } + + var stats = { + processtime: result.documents[0].timeMillis + , counts: result.documents[0].counts + }; + + callback(err, collection, stats); + }); + }); +}; + +/** + * Group function helper + */ + +var groupFunction = function () { + var c = db[ns].find(condition); + var map = new Map(); + var reduce_function = reduce; + + while (c.hasNext()) { + var obj = c.next(); + var key = {}; + + for (var i = 0, len = keys.length; i < len; ++i) { + var k = keys[i]; + key[k] = obj[k]; + } + + var aggObj = map.get(key); + + if (aggObj == null) { + var newObj = Object.extend({}, key); + aggObj = Object.extend(newObj, initial); + map.put(key, aggObj); + } + + reduce_function(obj, aggObj); + } + + return { "result": map.values() }; +}.toString(); + +/** + * Group. + * + * @param {Object|Array|Function|Code} keys + * @param {TODO} condition + * @param {TODO} initial + * @param {Function|Code} reduce + * @param {Boolean} command + * @param {Function} callback + */ + +Collection.prototype.group = function group (keys, condition, initial, reduce, command, callback) { + var args = Array.prototype.slice.call(arguments, 3); + callback = args.pop(); + reduce = args.length ? args.shift() : null; + command = args.length ? args.shift() : null; + + var Code = this.db.bson_serializer.Code + + if (!Array.isArray(keys) && keys instanceof Object && typeof(keys) !== 'function') { + keys = Object.keys(keys); + } + + if(reduce instanceof Function) { + reduce = reduce.toString(); + } + + if(command) { + var reduceFunction = reduce instanceof Code + ? reduce + : new Code(reduce); + + var selector = { + group: { + 'ns': this.collectionName + , '$reduce': reduceFunction + , 'cond': condition + , 'initial': initial + } + }; + + if ('function' === typeof keys) { + selector.group.$keyf = keys instanceof Code + ? keys + : new Code(keys); + } else { + var hash = {}; + keys.forEach(function (key) { + hash[key] = 1; + }); + selector.group.key = hash; + } + + var cmd = DbCommand.createDbCommand(this.db, selector); + + this.db.executeCommand(cmd, {read:true}, function (err, result) { + if (err) return callback(err); + + var document = result.documents[0]; + if (null == document.retval) { + return callback(new Error("group command failed: " + document.errmsg)); + } + + callback(null, document.retval); + }); + + } else { + // Create execution scope + var scope = reduce != null && reduce instanceof Code + ? reduce.scope + : {}; + + scope.ns = this.collectionName; + scope.keys = keys; + scope.condition = condition; + scope.initial = initial; + + // Pass in the function text to execute within mongodb. + var groupfn = groupFunction.replace(/ reduce;/, reduce.toString() + ';'); + + this.db.eval(new Code(groupfn, scope), function (err, results) { + if (err) return callback(err, null); + callback(null, results.result || results); + }); + } +}; + +/** + * Options. + * + * @param {Function} callback + */ + +Collection.prototype.options = function options (callback) { + this.db.collectionsInfo(this.collectionName, function (err, cursor) { + if (err) return callback(err); + cursor.nextObject(function (err, document) { + callback(err, document && document.options || null); + }); + }); +}; + +/** + * Expose. + */ + +exports.Collection = Collection; diff --git a/node_modules/mongodb/lib/mongodb/commands/base_command.js b/node_modules/mongodb/lib/mongodb/commands/base_command.js new file mode 100644 index 0000000..be65299 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/commands/base_command.js @@ -0,0 +1,26 @@ +var BinaryParser = require('../bson/binary_parser').BinaryParser, + debug = require('util').debug, + inspect = require('util').inspect; + +/** + Base object used for common functionality +**/ +var BaseCommand = exports.BaseCommand = function() { +}; + +var id = 1; +BaseCommand.prototype.getRequestId = function() { + if (!this.requestId) this.requestId = id++; + return this.requestId; +}; + +// OpCodes +BaseCommand.OP_REPLY = 1; +BaseCommand.OP_MSG = 1000; +BaseCommand.OP_UPDATE = 2001; +BaseCommand.OP_INSERT = 2002; +BaseCommand.OP_GET_BY_OID = 2003; +BaseCommand.OP_QUERY = 2004; +BaseCommand.OP_GET_MORE = 2005; +BaseCommand.OP_DELETE = 2006; +BaseCommand.OP_KILL_CURSORS = 2007; \ No newline at end of file diff --git a/node_modules/mongodb/lib/mongodb/commands/db_command.js b/node_modules/mongodb/lib/mongodb/commands/db_command.js new file mode 100644 index 0000000..47f04d6 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/commands/db_command.js @@ -0,0 +1,188 @@ +var QueryCommand = require('./query_command').QueryCommand, + InsertCommand = require('./insert_command').InsertCommand, + inherits = require('util').inherits, + debug = require('util').debug, + crypto = require('crypto'), + inspect = require('util').inspect; + +/** + Db Command +**/ +var DbCommand = exports.DbCommand = function(db, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector) { + QueryCommand.call(db, this); + + this.collectionName = collectionName; + this.queryOptions = queryOptions; + this.numberToSkip = numberToSkip; + this.numberToReturn = numberToReturn; + this.query = query; + this.returnFieldSelector = returnFieldSelector; + this.db = db; +}; + +inherits(DbCommand, QueryCommand); + +// Constants +DbCommand.SYSTEM_NAMESPACE_COLLECTION = "system.namespaces"; +DbCommand.SYSTEM_INDEX_COLLECTION = "system.indexes"; +DbCommand.SYSTEM_PROFILE_COLLECTION = "system.profile"; +DbCommand.SYSTEM_USER_COLLECTION = "system.users"; +DbCommand.SYSTEM_COMMAND_COLLECTION = "$cmd"; + +// Provide constructors for different db commands +DbCommand.createIsMasterCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null); +}; + +DbCommand.createCollectionInfoCommand = function(db, selector) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_NAMESPACE_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, 0, selector, null); +}; + +DbCommand.createGetNonceCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getnonce':1}, null); +}; + +DbCommand.createAuthenticationCommand = function(db, username, password, nonce) { + // Use node md5 generator + var md5 = crypto.createHash('md5'); + // Generate keys used for authentication + md5.update(username + ":mongo:" + password); + var hash_password = md5.digest('hex'); + // Final key + md5 = crypto.createHash('md5'); + md5.update(nonce + username + hash_password); + var key = md5.digest('hex'); + // Creat selector + var selector = {'authenticate':1, 'user':username, 'nonce':nonce, 'key':key}; + // Create db command + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NONE, 0, -1, selector, null); +}; + +DbCommand.createLogoutCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'logout':1}, null); +}; + +DbCommand.createCreateCollectionCommand = function(db, collectionName, options) { + var selector = {'create':collectionName}; + // Modify the options to ensure correct behaviour + for(var name in options) { + if(options[name] != null && options[name].constructor != Function) selector[name] = options[name]; + } + // Execute the command + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, selector, null); +}; + +DbCommand.createDropCollectionCommand = function(db, collectionName) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'drop':collectionName}, null); +}; + +DbCommand.createRenameCollectionCommand = function(db, fromCollectionName, toCollectionName) { + var renameCollection = db.databaseName + "." + fromCollectionName; + var toCollection = db.databaseName + "." + toCollectionName; + return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'renameCollection':renameCollection, 'to':toCollection}, null); +}; + +DbCommand.createGetLastErrorCommand = function(options, db) { + var args = Array.prototype.slice.call(arguments, 0); + db = args.pop(); + options = args.length ? args.shift() : {}; + // Final command + var command = {'getlasterror':1}; + // If we have an options Object let's merge in the fields (fsync/wtimeout/w) + if('object' === typeof options) { + for(var name in options) { + command[name] = options[name] + } + } + + // Execute command + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command, null); +}; + +DbCommand.createGetLastStatusCommand = DbCommand.createGetLastErrorCommand; + +DbCommand.createGetPreviousErrorsCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getpreverror':1}, null); +}; + +DbCommand.createResetErrorHistoryCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reseterror':1}, null); +}; + +DbCommand.createCreateIndexCommand = function(db, collectionName, fieldOrSpec, options) { + var finalUnique = options == null && !(options instanceof Object) ? false : options; + var fieldHash = {}; + var indexes = []; + var keys; + var sparse; + var background; + + // If the options is a hash + if(options instanceof Object) { + finalUnique = options['unique'] != null ? options['unique'] : false; + sparse = options['sparse'] != null ? options['sparse'] : false; + background = options['background'] != null ? options['background'] : false; + } + + // Get all the fields accordingly + if (fieldOrSpec.constructor === String) { // 'type' + indexes.push(fieldOrSpec + '_' + 1); + fieldHash[fieldOrSpec] = 1; + } else if (fieldOrSpec.constructor === Array) { // [{location:'2d'}, ...] + fieldOrSpec.forEach(function(f) { + if (f.constructor === String) { // [{location:'2d'}, 'type'] + indexes.push(f + '_' + 1); + fieldHash[f] = 1; + } else if (f.constructor === Array) { // [['location', '2d'],['type', 1]] + indexes.push(f[0] + '_' + (f[1] || 1)); + fieldHash[f[0]] = f[1] || 1; + } else if (f.constructor === Object) { // [{location:'2d'}, {type:1}] + keys = Object.keys(f); + keys.forEach(function(k) { + indexes.push(k + '_' + f[k]); + fieldHash[k] = f[k]; + }); + } else { + // undefined + } + }); + } else if (fieldOrSpec.constructor === Object) { // {location:'2d', type:1} + keys = Object.keys(fieldOrSpec); + keys.forEach(function(key) { + indexes.push(key + '_' + fieldOrSpec[key]); + fieldHash[key] = fieldOrSpec[key]; + }); + } else { + // undefined + } + + // Generate the index name + var indexName = indexes.join("_"); + // Build the selector + var selector = {'ns':(db.databaseName + "." + collectionName), 'key':fieldHash, 'name':indexName}; + selector['unique'] = finalUnique; + selector['sparse'] = sparse; + selector['background'] = background; + // Create the insert command for the index and return the document + return new InsertCommand(db, db.databaseName + "." + DbCommand.SYSTEM_INDEX_COLLECTION, false).add(selector); +}; + +DbCommand.logoutCommand = function(db, command_hash) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null); +} + +DbCommand.createDropIndexCommand = function(db, collectionName, indexName) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'deleteIndexes':collectionName, 'index':indexName}, null); +}; + +DbCommand.createDropDatabaseCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'dropDatabase':1}, null); +}; + +DbCommand.createDbCommand = function(db, command_hash) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null); +}; + +DbCommand.createAdminDbCommand = function(db, command_hash) { + return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null); +}; diff --git a/node_modules/mongodb/lib/mongodb/commands/delete_command.js b/node_modules/mongodb/lib/mongodb/commands/delete_command.js new file mode 100644 index 0000000..e995279 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/commands/delete_command.js @@ -0,0 +1,91 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits, + debug = require('util').debug, + inspect = require('util').inspect; + +/** + Insert Document Command +**/ +var DeleteCommand = exports.DeleteCommand = function(db, collectionName, selector) { + BaseCommand.call(this); + + this.collectionName = collectionName; + this.selector = selector; + this.db = db; +}; + +inherits(DeleteCommand, BaseCommand); + +DeleteCommand.OP_DELETE = 2006; + +/* +struct { + MsgHeader header; // standard message header + int32 ZERO; // 0 - reserved for future use + cstring fullCollectionName; // "dbname.collectionname" + int32 ZERO; // 0 - reserved for future use + mongo.BSON selector; // query object. See below for details. +} +*/ +DeleteCommand.prototype.toBinary = function() { + // Calculate total length of the document + var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson_serializer.BSON.calculateObjectSize(this.selector) + (4 * 4); + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (DeleteCommand.OP_DELETE >> 24) & 0xff; + _command[_index + 2] = (DeleteCommand.OP_DELETE >> 16) & 0xff; + _command[_index + 1] = (DeleteCommand.OP_DELETE >> 8) & 0xff; + _command[_index] = DeleteCommand.OP_DELETE & 0xff; + // Adjust index + _index = _index + 4; + + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + + // Write the collection name to the command + _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1; + _command[_index - 1] = 0; + + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + + // Serialize the selector + var documentLength = this.db.bson_serializer.BSON.serializeWithBufferAndIndex(this.selector, this.checkKeys, _command, _index) - _index + 1; + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + return _command; +}; \ No newline at end of file diff --git a/node_modules/mongodb/lib/mongodb/commands/get_more_command.js b/node_modules/mongodb/lib/mongodb/commands/get_more_command.js new file mode 100644 index 0000000..7151883 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/commands/get_more_command.js @@ -0,0 +1,96 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits, + debug = require('util').debug, + inspect = require('util').inspect, + binaryutils = require('../bson/binary_utils'); + +/** + Get More Document Command +**/ +var GetMoreCommand = exports.GetMoreCommand = function(db, collectionName, numberToReturn, cursorId) { + BaseCommand.call(this); + + this.collectionName = collectionName; + this.numberToReturn = numberToReturn; + this.cursorId = cursorId; + this.db = db; +}; + +inherits(GetMoreCommand, BaseCommand); + +GetMoreCommand.OP_GET_MORE = 2005; + +GetMoreCommand.prototype.toBinary = function() { + // debug("======================================================= GETMORE") + // debug("================ " + this.db.bson_serializer.BSON.calculateObjectSize(this.query)) + // Calculate total length of the document + var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 8 + (4 * 4); + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (GetMoreCommand.OP_GET_MORE >> 24) & 0xff; + _command[_index + 2] = (GetMoreCommand.OP_GET_MORE >> 16) & 0xff; + _command[_index + 1] = (GetMoreCommand.OP_GET_MORE >> 8) & 0xff; + _command[_index] = GetMoreCommand.OP_GET_MORE & 0xff; + // Adjust index + _index = _index + 4; + + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + + // Write the collection name to the command + _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1; + _command[_index - 1] = 0; + + // Number of documents to return + _command[_index + 3] = (this.numberToReturn >> 24) & 0xff; + _command[_index + 2] = (this.numberToReturn >> 16) & 0xff; + _command[_index + 1] = (this.numberToReturn >> 8) & 0xff; + _command[_index] = this.numberToReturn & 0xff; + // Adjust index + _index = _index + 4; + + // Encode the cursor id + var low_bits = this.cursorId.getLowBits(); + // Encode low bits + _command[_index + 3] = (low_bits >> 24) & 0xff; + _command[_index + 2] = (low_bits >> 16) & 0xff; + _command[_index + 1] = (low_bits >> 8) & 0xff; + _command[_index] = low_bits & 0xff; + // Adjust index + _index = _index + 4; + + var high_bits = this.cursorId.getHighBits(); + // Encode high bits + _command[_index + 3] = (high_bits >> 24) & 0xff; + _command[_index + 2] = (high_bits >> 16) & 0xff; + _command[_index + 1] = (high_bits >> 8) & 0xff; + _command[_index] = high_bits & 0xff; + // Adjust index + _index = _index + 4; + + return _command; +}; \ No newline at end of file diff --git a/node_modules/mongodb/lib/mongodb/commands/insert_command.js b/node_modules/mongodb/lib/mongodb/commands/insert_command.js new file mode 100644 index 0000000..a27a309 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/commands/insert_command.js @@ -0,0 +1,99 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits, + debug = require('util').debug, + inspect = require('util').inspect; + +/** + Insert Document Command +**/ +var InsertCommand = exports.InsertCommand = function(db, collectionName, checkKeys) { + BaseCommand.call(this); + + this.collectionName = collectionName; + this.documents = []; + this.checkKeys = checkKeys == null ? true : checkKeys; + this.db = db; +}; + +inherits(InsertCommand, BaseCommand); + +// OpCodes +InsertCommand.OP_INSERT = 2002; + +InsertCommand.prototype.add = function(document) { + this.documents.push(document); + return this; +}; + +/* +struct { + MsgHeader header; // standard message header + int32 ZERO; // 0 - reserved for future use + cstring fullCollectionName; // "dbname.collectionname" + BSON[] documents; // one or more documents to insert into the collection +} +*/ +InsertCommand.prototype.toBinary = function() { + // Calculate total length of the document + var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + (4 * 4); + // var docLength = 0 + for(var i = 0; i < this.documents.length; i++) { + // Calculate size of document + totalLengthOfCommand += this.db.bson_serializer.BSON.calculateObjectSize(this.documents[i]); + } + + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (InsertCommand.OP_INSERT >> 24) & 0xff; + _command[_index + 2] = (InsertCommand.OP_INSERT >> 16) & 0xff; + _command[_index + 1] = (InsertCommand.OP_INSERT >> 8) & 0xff; + _command[_index] = InsertCommand.OP_INSERT & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the collection name to the command + _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1; + _command[_index - 1] = 0; + + // Write all the bson documents to the buffer at the index offset + for(var i = 0; i < this.documents.length; i++) { + // Serialize the document straight to the buffer + var documentLength = this.db.bson_serializer.BSON.serializeWithBufferAndIndex(this.documents[i], this.checkKeys, _command, _index) - _index + 1; + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + } + + return _command; +}; diff --git a/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js b/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js new file mode 100644 index 0000000..9778848 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js @@ -0,0 +1,100 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits, + binaryutils = require('../bson/binary_utils'), + debug = require('util').debug, + inspect = require('util').inspect; + +/** + Insert Document Command +**/ +var KillCursorCommand = exports.KillCursorCommand = function(db, cursorIds) { + BaseCommand.call(this); + + this.cursorIds = cursorIds; + this.db = db; +}; + +inherits(KillCursorCommand, BaseCommand); + +KillCursorCommand.OP_KILL_CURSORS = 2007; + +/* +struct { + MsgHeader header; // standard message header + int32 ZERO; // 0 - reserved for future use + int32 numberOfCursorIDs; // number of cursorIDs in message + int64[] cursorIDs; // array of cursorIDs to close +} +*/ +KillCursorCommand.prototype.toBinary = function() { + // Calculate total length of the document + var totalLengthOfCommand = 4 + 4 + (4 * 4) + (this.cursorIds.length * 8); + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (KillCursorCommand.OP_KILL_CURSORS >> 24) & 0xff; + _command[_index + 2] = (KillCursorCommand.OP_KILL_CURSORS >> 16) & 0xff; + _command[_index + 1] = (KillCursorCommand.OP_KILL_CURSORS >> 8) & 0xff; + _command[_index] = KillCursorCommand.OP_KILL_CURSORS & 0xff; + // Adjust index + _index = _index + 4; + + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + + // Number of cursors to kill + var numberOfCursors = this.cursorIds.length; + _command[_index + 3] = (numberOfCursors >> 24) & 0xff; + _command[_index + 2] = (numberOfCursors >> 16) & 0xff; + _command[_index + 1] = (numberOfCursors >> 8) & 0xff; + _command[_index] = numberOfCursors & 0xff; + // Adjust index + _index = _index + 4; + + // Encode all the cursors + for(var i = 0; i < this.cursorIds.length; i++) { + // Encode the cursor id + var low_bits = this.cursorIds[i].getLowBits(); + // Encode low bits + _command[_index + 3] = (low_bits >> 24) & 0xff; + _command[_index + 2] = (low_bits >> 16) & 0xff; + _command[_index + 1] = (low_bits >> 8) & 0xff; + _command[_index] = low_bits & 0xff; + // Adjust index + _index = _index + 4; + + var high_bits = this.cursorIds[i].getHighBits(); + // Encode high bits + _command[_index + 3] = (high_bits >> 24) & 0xff; + _command[_index + 2] = (high_bits >> 16) & 0xff; + _command[_index + 1] = (high_bits >> 8) & 0xff; + _command[_index] = high_bits & 0xff; + // Adjust index + _index = _index + 4; + } + + return _command; +}; \ No newline at end of file diff --git a/node_modules/mongodb/lib/mongodb/commands/query_command.js b/node_modules/mongodb/lib/mongodb/commands/query_command.js new file mode 100644 index 0000000..a258659 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/commands/query_command.js @@ -0,0 +1,151 @@ +var BaseCommand = require('./base_command').BaseCommand, + BinaryParser = require('../bson/binary_parser').BinaryParser, + inherits = require('util').inherits, + debug = require('util').debug, + inspect = require('util').inspect; + +/** + Insert Document Command +**/ +var QueryCommand = exports.QueryCommand = function(db, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector) { + BaseCommand.call(this); + + this.collectionName = collectionName; + this.queryOptions = queryOptions; + this.numberToSkip = numberToSkip; + this.numberToReturn = numberToReturn; + this.query = query; + this.returnFieldSelector = returnFieldSelector; + this.db = db; +}; + +inherits(QueryCommand, BaseCommand); + +QueryCommand.OP_QUERY = 2004; + +/* +struct { + MsgHeader header; // standard message header + int32 opts; // query options. See below for details. + cstring fullCollectionName; // "dbname.collectionname" + int32 numberToSkip; // number of documents to skip when returning results + int32 numberToReturn; // number of documents to return in the first OP_REPLY + BSON query ; // query object. See below for details. + [ BSON returnFieldSelector; ] // OPTIONAL : selector indicating the fields to return. See below for details. +} +*/ +QueryCommand.prototype.toBinary = function() { + // debug("======================================================= QUERY") + // debug("================ " + this.db.bson_serializer.BSON.calculateObjectSize(this.query)) + + // Calculate total length of the document + var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.db.bson_serializer.BSON.calculateObjectSize(this.query) + (4 * 4); + // Calculate extra fields size + if(this.returnFieldSelector != null) { + if(Object.keys(this.returnFieldSelector).length > 0) { + totalLengthOfCommand += this.db.bson_serializer.BSON.calculateObjectSize(this.returnFieldSelector); + } + } + + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (QueryCommand.OP_QUERY >> 24) & 0xff; + _command[_index + 2] = (QueryCommand.OP_QUERY >> 16) & 0xff; + _command[_index + 1] = (QueryCommand.OP_QUERY >> 8) & 0xff; + _command[_index] = QueryCommand.OP_QUERY & 0xff; + // Adjust index + _index = _index + 4; + + // Write the query options + _command[_index + 3] = (this.queryOptions >> 24) & 0xff; + _command[_index + 2] = (this.queryOptions >> 16) & 0xff; + _command[_index + 1] = (this.queryOptions >> 8) & 0xff; + _command[_index] = this.queryOptions & 0xff; + // Adjust index + _index = _index + 4; + + // Write the collection name to the command + _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1; + _command[_index - 1] = 0; + + // Write the number of documents to skip + _command[_index + 3] = (this.numberToSkip >> 24) & 0xff; + _command[_index + 2] = (this.numberToSkip >> 16) & 0xff; + _command[_index + 1] = (this.numberToSkip >> 8) & 0xff; + _command[_index] = this.numberToSkip & 0xff; + // Adjust index + _index = _index + 4; + + // Write the number of documents to return + _command[_index + 3] = (this.numberToReturn >> 24) & 0xff; + _command[_index + 2] = (this.numberToReturn >> 16) & 0xff; + _command[_index + 1] = (this.numberToReturn >> 8) & 0xff; + _command[_index] = this.numberToReturn & 0xff; + // Adjust index + _index = _index + 4; + + // Serialize the query document straight to the buffer + var documentLength = this.db.bson_serializer.BSON.serializeWithBufferAndIndex(this.query, this.checkKeys, _command, _index) - _index + 1; + // debug(inspect("===================== documentLength :: " + documentLength)) + + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + + // Push field selector if available + if(this.returnFieldSelector != null) { + if(Object.keys(this.returnFieldSelector).length > 0) { + var documentLength = this.db.bson_serializer.BSON.serializeWithBufferAndIndex(this.returnFieldSelector, this.checkKeys, _command, _index) - _index + 1; + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + } + } + + // debug("------------------------------------------------------------------------") + // debug(inspect(_command)) + + return _command; +}; + +// Constants +QueryCommand.OPTS_NONE = 0; +QueryCommand.OPTS_TAILABLE_CURSOR = 2; +QueryCommand.OPTS_SLAVE = 4; +QueryCommand.OPTS_OPLOG_REPLY = 8; +QueryCommand.OPTS_NO_CURSOR_TIMEOUT = 16; +QueryCommand.OPTS_AWAIT_DATA = 32; +QueryCommand.OPTS_EXHAUST = 64; \ No newline at end of file diff --git a/node_modules/mongodb/lib/mongodb/commands/update_command.js b/node_modules/mongodb/lib/mongodb/commands/update_command.js new file mode 100644 index 0000000..f9b97ea --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/commands/update_command.js @@ -0,0 +1,123 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits, + debug = require('util').debug, + inspect = require('util').inspect; + +/** + Update Document Command +**/ +var UpdateCommand = exports.UpdateCommand = function(db, collectionName, spec, document, options) { + BaseCommand.call(this); + + this.collectionName = collectionName; + this.spec = spec; + this.document = document; + this.db = db; + + // Generate correct flags + var db_upsert = 0; + var db_multi_update = 0; + db_upsert = options != null && options['upsert'] != null ? (options['upsert'] == true ? 1 : 0) : db_upsert; + db_multi_update = options != null && options['multi'] != null ? (options['multi'] == true ? 1 : 0) : db_multi_update; + + // Flags + this.flags = parseInt(db_multi_update.toString() + db_upsert.toString(), 2); +}; + +inherits(UpdateCommand, BaseCommand); + +UpdateCommand.OP_UPDATE = 2001; + +/* +struct { + MsgHeader header; // standard message header + int32 ZERO; // 0 - reserved for future use + cstring fullCollectionName; // "dbname.collectionname" + int32 flags; // bit vector. see below + BSON spec; // the query to select the document + BSON document; // the document data to update with or insert +} +*/ +UpdateCommand.prototype.toBinary = function() { + // Calculate total length of the document + var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson_serializer.BSON.calculateObjectSize(this.spec) + + this.db.bson_serializer.BSON.calculateObjectSize(this.document) + (4 * 4); + + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (UpdateCommand.OP_UPDATE >> 24) & 0xff; + _command[_index + 2] = (UpdateCommand.OP_UPDATE >> 16) & 0xff; + _command[_index + 1] = (UpdateCommand.OP_UPDATE >> 8) & 0xff; + _command[_index] = UpdateCommand.OP_UPDATE & 0xff; + // Adjust index + _index = _index + 4; + + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + + // Write the collection name to the command + _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1; + _command[_index - 1] = 0; + + // Write the update flags + _command[_index + 3] = (this.flags >> 24) & 0xff; + _command[_index + 2] = (this.flags >> 16) & 0xff; + _command[_index + 1] = (this.flags >> 8) & 0xff; + _command[_index] = this.flags & 0xff; + // Adjust index + _index = _index + 4; + + // Serialize the spec document + var documentLength = this.db.bson_serializer.BSON.serializeWithBufferAndIndex(this.spec, this.checkKeys, _command, _index) - _index + 1; + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + + // Serialize the document + var documentLength = this.db.bson_serializer.BSON.serializeWithBufferAndIndex(this.document, this.checkKeys, _command, _index) - _index + 1; + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + + return _command; +}; + +// Constants +UpdateCommand.DB_UPSERT = 0; +UpdateCommand.DB_MULTI_UPDATE = 1; \ No newline at end of file diff --git a/node_modules/mongodb/lib/mongodb/connection.js b/node_modules/mongodb/lib/mongodb/connection.js new file mode 100644 index 0000000..cf77953 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/connection.js @@ -0,0 +1,319 @@ +var net = require('net'), + debug = require('util').debug, + inspect = require('util').inspect, + EventEmitter = require("events").EventEmitter, + BinaryParser = require('./bson/binary_parser').BinaryParser, + inherits = require('util').inherits, + Server = require('./connections/server').Server, + binaryutils = require("./bson/binary_utils"); + +var Connection = exports.Connection = function(host, port, autoReconnect, options) { + this.options = options == null ? {} : options; + this.host = host; + this.port = port; + this.autoReconnect = autoReconnect; + this.drained = true; + // Fetch the poolsize + this.poolSize = this.options["poolSize"] == null ? 1 : this.options["poolSize"]; + // Reconnect buffer for messages + this.messages = []; + + // Status messages + this.sizeOfMessage = 0; + this.bytesRead = 0; + this.buffer = ''; + this.stubBuffer = ''; + this.connected = false; + this.closedConnectionCount = 0; + + // Connection pool variables + this.pool = []; + this.poolByReference = {}; + this.poolIndex = 0; +}; + +inherits(Connection, EventEmitter); + +var getConnection = function(self) { + return self.pool[self.poolIndex++ % self.pool.length]; +} + +// Setup the connection pool +var setupConnectionPool = function(self, poolSize, reconnect) { + // Pool off connections and status variables + var connectionPool = []; + var connectedTo = 0; + var errors = 0; + var connectionError = null; + + // Receive listener + var receiveListener = function(result, fd) { + fd = fd == null ? this.fd : fd; + + // Fetch the pool reference + var conObj = self.poolByReference[fd]; + + // Check if we have an unfinished message + if(conObj != null && conObj.bytesRead > 0 && conObj.sizeOfMessage > 0) { + // Calculate remaing bytes to fetch + var remainingBytes = conObj.sizeOfMessage - conObj.bytesRead; + // Check if we have multiple packet messages and save the pieces otherwise emit the message + if(remainingBytes > result.length) { + // Let's copy all the results into a new buffer + var buffer = new Buffer(conObj.buffer.length + result.length); + conObj.buffer.copy(buffer, 0, 0, conObj.buffer.length); + result.copy(buffer, conObj.buffer.length, 0, result.length); + // Save the reference to the new buffer + conObj.buffer = buffer; + // Adjust the number of read bytes + conObj.bytesRead = conObj.bytesRead + result.length; + } else { + // Cut off the remaining message + var buffer = new Buffer(conObj.buffer.length + remainingBytes); + conObj.buffer.copy(buffer, 0, 0, conObj.buffer.length); + result.copy(buffer, conObj.buffer.length, 0, remainingBytes); + // Emit the message + self.emit("data", buffer); + // Reset the variables + conObj.buffer = new Buffer(0); conObj.bytesRead = 0; conObj.sizeOfMessage = 0; + // If message is longer than the current one, keep parsing + if(remainingBytes < result.length) { + receiveListener(result.slice(remainingBytes, result.length), fd); + } + } + } else if(conObj != null){ + if(conObj.stubBuffer.length > 0) { + // Add missing stub files + var buffer = new Buffer(conObj.stubBuffer.length + result.length); + conObj.stubBuffer.copy(buffer, 0, 0, conObj.stubBuffer.length); + result.copy(buffer, conObj.stubBuffer.length, 0, result.length); + // New result contains the former missing bytes as well as the incoming payload + result = buffer; + conObj.stubBuffer = new Buffer(0); + } + + if(result.length > 4) { + // var sizeOfMessage = BinaryParser.toInt(result.toString('binary', 0, 4)); + var sizeOfMessage = binaryutils.decodeUInt32(result, 0); + // We got a partial message, store the result and wait for more + if(sizeOfMessage > result.length) { + // Create a new buffer with the correct size + var buffer = new Buffer(conObj.buffer.length + result.length); + conObj.buffer.copy(buffer, 0, 0, self.buffer.length); + result.copy(buffer, conObj.buffer.length, 0, result.length); + conObj.buffer = buffer; + // Adjust variables + conObj.bytesRead = result.length; conObj.sizeOfMessage = sizeOfMessage; + } else if(sizeOfMessage == result.length) { + self.emit("data", result); + } else if(sizeOfMessage < result.length) { + self.emit("data", result.slice(0, sizeOfMessage)); + receiveListener(result.slice(sizeOfMessage, result.length), fd); + } + } else { + conObj.stubBuffer = result; + } + } + }; + + // Fill the pool + for(var i = 0; i < poolSize; i++) { + // Create the associated connection + var connection = net.createConnection(self.port, self.host); + // Add connnect listener + connection.addListener("connect", function() { + // // this.setEncoding("binary"); + this.setTimeout(0); + this.setNoDelay(); + // Update number of connected to server + connectedTo = connectedTo + 1; + }); + + connection.addListener("error", function(err) { + // Update number of errors + errors = errors + 1; + connectionError = err; + }); + + connection.addListener("timeout", function(err) { + // Update number of errors + errors = errors + 1; + connectionError = err; + }); + + // Add a close listener + connection.addListener("close", function() { + // Only emit close once all connections in the pool have closed. + // Note that connections which emit an error also emit a close. + if (++self.closedConnectionCount === self.pool.length) + self.emit("close"); + }); + + // Add connection to the pool array + connectionPool.push({"connection": connection, + "sizeOfMessage": 0, + "bytesRead": 0, + "buffer": new Buffer(0), + "stubBuffer": ''}); + + // Add the listener to the connection + connection.addListener("data", receiveListener); + } + + // Function that wait for connection to finish up + var waitForConnections = function() { + // Emit a connect message once all connections are up + if(connectedTo == connectionPool.length) { + if(reconnect == null || !reconnect) { + self.connected = true; + self.poolByReference = {}; + + // Save the connections by the fd reference + self.pool.forEach(function(con) { + self.poolByReference[con.connection.fd] = con; + }); + + self.emit("connect"); + } else { + self.connected = false; + self.emit("reconnect"); + } + } else if(errors + connectedTo == connectionPool.length) { + if(reconnect == null || !reconnect) { + self.connected = false; + self.emit("error", connectionError); + } else { + self.connected = false; + self.emit("reconnect"); + } + } else { + process.nextTick(waitForConnections); + } + } + + // Wait until we are done connected to all pool entries before emitting connect signal + process.nextTick(waitForConnections); + + // Return the pool + return connectionPool; +} + +// Functions to open the connection +Connection.prototype.open = function() { + // Create the pool with connections + this.pool = setupConnectionPool(this, this.poolSize); +} + +Connection.prototype.close = function(callback) { + this.connected = false; + // Close all entries in the pool + if (!callback) { + // This seems to block until completion. + for(var i = 0; i < this.pool.length; i++) { + this.pool[i].connection.end(); + } + } else { + this.once("close", callback); + this.pool.forEach(function(poolMember, i) { + var connection = poolMember.connection; + // Force an async flush. + connection.write('', function() { + // Hopefully this doesn't block. + connection.end(); + }); + }); + } +}; + +Connection.prototype.send = function(command, rawConnection) { + var self = this; + // If we are executing the commnand on the entire pool + var connection = null; + // If we are forcing the use of a connection + if(rawConnection != null) { + connection = rawConnection; + } else { + connection = getConnection(self).connection; + } + + // Check if the connection is closed + try { + if (connection.readyState != "open") { + throw 'notConnected'; + } + + // Send the command, if it's an array of commands execute them all on the same connection + if(Array.isArray(command)) { + for(var i = 0; i < command.length; i++) { + connection.write(command[i].toBinary()); + } + } else { + connection.write(command.toBinary()); + } + } catch(err) { + // Check if the connection is closed + if(connection.readyState != "open" && self.autoReconnect) { + // Add the message to the queue of messages to send + self.messages.push(command); + // Initiate reconnect if no current running + if(self.currently_reconnecting == null || self.currently_reconnecting == false) { + self.currently_reconnecting = true; + + // Create the pool with connections + self.pool = setupConnectionPool(self, self.poolSize, true); + self.poolByReference = {}; + // Save the connections by the fd reference + self.pool.forEach(function(con) { + self.poolByReference[con.connection.fd] = con; + }) + + // Wait for a reconnect and send all the messages + self.on("resend", function() { + self.currently_reconnecting = false; + // Fire the message again + while(self.messages.length > 0) { + // Fetch a connection and resend messages + connection = getConnection(self).connection; + // Fetch the a message + var command = self.messages.shift(); + // Fire + if(Array.isArray(command)) { + for(var i = 0; i < command.length; i++) { + connection.write(command[i].toBinary()); + } + } else { + connection.write(command.toBinary()); + } + } + }) + } + } else { + // Set connected to false + self.connected = false; + // Throw error + throw err; + } + } +}; + +/** +* Wrtie command without an attempt of reconnect +* @param command +*/ +Connection.prototype.sendwithoutReconnect = function(command) { + var self = this; + var connection = this.connection; + + // Check if the connection is closed + if (connection.readyState != "open") { + throw new Error( 'Connection closed!' ); + } + + // If connection.write() throws there is + // no need to reconnect since called by latest master + // and already went through send() function + connection.write(command.toBinary(), "binary"); +}; + +// Some basic defaults +Connection.DEFAULT_PORT = 27017; diff --git a/node_modules/mongodb/lib/mongodb/connections/repl_set_servers.js b/node_modules/mongodb/lib/mongodb/connections/repl_set_servers.js new file mode 100644 index 0000000..eb826b3 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/connections/repl_set_servers.js @@ -0,0 +1,356 @@ +var Connection = require('../connection').Connection, + DbCommand = require('../commands/db_command').DbCommand, + MongoReply = require('../responses/mongo_reply').MongoReply, + EventEmitter = require("events").EventEmitter, + inherits = require('util').inherits, + debug = require('util').debug, + inspect = require('util').inspect, + Server = require('./server').Server; + +/** +* ReplSetServers constructor provides master-slave functionality +* +* @param serverArr{Array of type Server} +* @return constructor of ServerCluster +* +*/ +var ReplSetServers = exports.ReplSetServers = function(servers, options) { + EventEmitter.call(this); + // Contains the master server entry + this.master = null; + this.target = null; + this.options = options == null ? {} : options; + this.reconnectWait = options["reconnectWait"] != null ? options["reconnectWait"] : 1000; + this.retries = options["retries"] != null ? options["retries"] : 30; + // Set up internal state variables + this.replicaSet = options["rs_name"]; + // Keep references to node types for caching purposes + this.secondaries = []; + this.arbiters = []; + // Are we allowing reads from secondaries ? + this.readSecondary = options["read_secondary"]; + this.slaveOk = this.readSecondary; + this.otherErrors = []; + this.closedConnectionCount = 0; + + if(!Array.isArray(servers) || servers.length == 0) { + throw Error("The parameter must be an array of servers and contain at least one server"); + } else if(Array.isArray(servers) || servers.length > 0) { + var count = 0; + servers.forEach(function(server) { + if(server instanceof Server) count = count + 1; + // Ensure no server has reconnect on + server.options.auto_reconnect = false; + }); + + if(count < servers.length) { + throw Error("All server entries must be of type Server"); + } else { + this.servers = servers; + } + } + + // Auto Reconnect property + Object.defineProperty(this, "autoReconnect", { + enumerable: true + , get: function () { + if(this.target != null) return this.target.autoReconnect; + if(this.primary != null) return this.primary.autoReconnect; + } + }); + + // Auto Reconnect property + Object.defineProperty(this, "host", { + enumerable: true + , get: function () { + if (this.primary != null) return this.primary.host; + } + }); + + Object.defineProperty(this, "port", { + enumerable: true + , get: function () { + if (this.primary != null) return this.primary.port; + } + }); + + Object.defineProperty(this, "read", { + enumerable: true + , get: function () { + return this.secondaries.length > 0 ? this.secondaries[0] : null; + } + }); + + // Master connection property + Object.defineProperty(this, "primary", { + enumerable: true + , get: function () { + // Allow overriding to a specific connection + if(this.target != null && this.target instanceof Server) { + return this.target.primary; + } else { + var finalServer = null; + this.servers.forEach(function(server) { + if(server.master == true && (server.isConnected())) finalServer = server; + }); + return finalServer != null ? finalServer.primary : finalServer; + } + } + }); +}; + +inherits(ReplSetServers, EventEmitter); + +ReplSetServers.prototype.setTarget = function(target) { + this.target = target; +}; + +ReplSetServers.prototype.isConnected = function() { + return this.primary != null && this.primary.isConnected(); +} + +ReplSetServers.prototype.isPrimary = function(config) { + return this.readSecondary && this.secondaries.length > 0 ? false : true; +} + +ReplSetServers.prototype.isReadPrimary = ReplSetServers.prototype.isPrimary; + +ReplSetServers.prototype.connect = function(parent, callback) { + var replSetSelf = this; + var serverConnections = this.servers; + var numberOfConnectedServers = 0; + var numberOfErrorServers = 0; + this.addresses = {}; + this.target = null; + // Ensure parent can do a slave query if it's set + parent.slaveOk = this.slaveOk ? this.slaveOk : parent.slaveOk; + + var initServer = function(server) { + replSetSelf.addresses[server.host + ':' + server.port] = 1; + server.connection = new Connection(server.host, server.port, server.autoReconnect); + + // Add the connect + server.connection.on("connect", function() { + // Create a callback function for a given connection + var connectCallback = function(err, reply) { + if(replSetSelf.otherErrors.length > 0) return; + // Update number of connected servers, ensure we update before any possible errors + numberOfConnectedServers = numberOfConnectedServers + 1; + + if(err != null) return callback(err, null); + + server.master = reply.documents[0].ismaster == 1 ? true : false; + server.connected = true; + + if(reply.documents[0].hosts != undefined) { + // Get all possible server references from the node + var node = reply.documents[0]; + var hosts = node.hosts; + var arbiters = node.arbiters != null ? node.arbiters : []; + var passives = node.passives != null ? node.passives : []; + var replicas = hosts.concat(arbiters).concat(passives); + + // Add server to list of connected servers + if(replSetSelf.addresses[server.host + ":" + server.port] == null) { + // Add server to addresses, ensure we don't have duplicate entries + replSetSelf.addresses[server.host + ":" + server.port] = 1; + // Add to server connections + serverConnections.push( server ); + // Adjust the number of connections opened + numberOfConnectedServers = numberOfConnectedServers + 1; + } + + // Check if the node is a secondary one + if(node["secondary"]) { + // If the reference does not exist + if(replSetSelf.secondaries.indexOf(server) == -1) { + replSetSelf.secondaries.push(server); + } + } else if(node["arbiterOnly"]) { + if(replSetSelf.arbiters.indexOf(server) == -1) { + replSetSelf.arbiters.push(server); + } + } else if(node["ismaster"]) { + // Set target/primary server + replSetSelf.target = server; + + if(replSetSelf.replicaSet == null) { + replSetSelf.replicaSet = node["setName"]; + } else if(replSetSelf.replicaSet != node["setName"]) { + // Add other error to the list of errors + var errorMessage = new Error("configured mongodb replicaset does not match provided replicaset [" + node["setName"] + "] != [" + replSetSelf.replicaSet + "]"); + replSetSelf.otherErrors.push(errorMessage); + // Close all servers and return an error + for(var i = 0; i < serverConnections.length; i++) { + serverConnections[i].close(); + } + + // Return the error message + return callback(errorMessage); + } + } + + // Add servers to list of connections, discover servers in the replicaset + // that the driver has not explicitly added + for(var i in replicas) { + var replica = replicas[i]; + // Make sure we don't have duplicate entries + if(replSetSelf.addresses[replica] == 1) { + continue; + } + + // Add replica address to our internal address array + replSetSelf.addresses[replica] = 1; + var ipAndPort = replica.split(":"); + var newServer = new Server(ipAndPort[0], parseInt( ipAndPort[1]), { auto_reconnect: true}); + + // Add to connection list + serverConnections.push(newServer); + initServer(newServer); + } + } + + // emit a message saying we got a master and are ready to go and change state to reflect it + if(numberOfConnectedServers >= serverConnections.length && (parent.state == 'notConnected')) { + parent.isInitializing = false; + // If we have no master connection + if(replSetSelf.otherErrors.length > 0) { + return callback(replSetSelf.otherErrors.shift(), null); + } else if(replSetSelf.primary == null && !replSetSelf.readSecondary && replSetSelf.secondaries.length > 0) { + return callback(new Error('No master available'), null); + } + + parent.state = 'connected'; + return callback(null, parent); + } + + //we have the master we are ok, wait for others (if any) to connect too + if(server.master) { + parent.state = 'connected'; + replSetSelf.target = server; + } + + // We had some errored out servers, does not matter as long as we have a master server + // we can write to. + if((numberOfConnectedServers + numberOfErrorServers) >= serverConnections.length) { + parent.isInitializing = false; + // If we have no master connection + if(replSetSelf.otherErrors.length > 0) { + return callback(replSetSelf.otherErrors.shift(), null); + } else if(replSetSelf.primary == null && !replSetSelf.readSecondary && replSetSelf.secondaries.length > 0) { + return callback(new Error('No master available'), null); + } + + if (parent.state == 'connected') { + return callback( null, parent ); + } else { + return callback(new Error('No master available'), null); + } + } + }; + + // Create db command and Add the callback to the list of callbacks by the request id (mapping outgoing messages to correct callbacks) + var db_command = DbCommand.createIsMasterCommand(parent); + parent.on(db_command.getRequestId().toString(), connectCallback); + parent.notReplied[db_command.getRequestId().toString()] = this; + + // Let's send a request to identify the state of the server + this.send(db_command); + + server.connection.on("data", function(message) { + // Parse the data as a reply object + var reply = new MongoReply(parent, message); + // Emit error if there is one + reply.responseHasError ? parent.emit(reply.responseTo.toString(), reply.documents[0], reply) : parent.emit(reply.responseTo.toString(), null, reply); + // Remove the listener + if(parent.notReplied [reply.responseTo.toString()]) { + delete parent.notReplied[reply.responseTo.toString()]; + parent.removeListener(reply.responseTo.toString(), parent.listeners(reply.responseTo.toString())[0]); + } + }); + }); + + server.connection.on("error", function(err) { + if(parent.isInitializing) { + //we only have one error, if the rest are ok there is no problem + numberOfErrorServers++; + if((numberOfErrorServers + numberOfConnectedServers) == serverConnections.length) { + parent.isInitializing = false; + + if(parent.state == 'connected') { + return callback( null, parent); + } else { + return callback(new Error('No master available'), null); + } + } + } else { + for(var i in parent.notReplied) { + if(parent.notReplied[i] == this) { + delete parent.notReplied[i]; + parent.emit(i, null, { documents: [{'$err':'Connection closed'}] }); + parent.removeListener( i, parent.listeners( i )[0]); + } + } + } + }); + + // Emit timeout and close events so the client using db can figure do proper error handling (emit contains the connection that triggered the event) + server.connection.on("timeout", function() { parent.emit("timeout", replSetSelf); }); + server.connection.on("close", function() { + if (++replSetSelf.closedConnectionCount === replSetSelf.servers.length) { + parent.emit("close", replSetSelf); + // Call any callback registered in the close() method. + if (replSetSelf.closeCallback) + replSetSelf.closeCallback(); + } + }); + // Open the connection + server.connection.open(); + }; + + // Initialize connections + serverConnections.forEach(initServer); +} + +ReplSetServers.prototype.checkoutWriter = function() { + return this.primary.connection; +} + +ReplSetServers.prototype.checkoutReader = function() { + // If we have specified to read from a secondary server grab a random one and read + // from it, otherwise just pass the primary connection + if(this.readSecondary && this.secondaries.length > 0) { + var server = this.secondaries[Math.floor(Math.random() * this.secondaries.length)]; + return server.connection; + } else { + return this.checkoutWriter(); + } +} + +ReplSetServers.prototype.allRawConnections = function() { + var connections = this.checkoutWriter().pool.slice(0); + // Add all the pool connections + if(this.readSecondary && this.secondaries.length > 0) { + for(var i = 0; i < this.secondaries.length; i++) { + connections.concat(this.secondaries[i].connection.pool); + } + } + // Return the server connections + return connections; +} + +ReplSetServers.prototype.disconnect = function(callback) { + this.close(callback); +} + +ReplSetServers.prototype.close = function(callback) { + var self = this; + // Close all server connections in parallel. + this.closeCallback = callback; // Will be called by "close" event listener. + this.servers.forEach(function(server) { + server.close(); + }); + // Clear up + this.secondaries = []; + this.arbiters = []; +} diff --git a/node_modules/mongodb/lib/mongodb/connections/server.js b/node_modules/mongodb/lib/mongodb/connections/server.js new file mode 100644 index 0000000..225bf32 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/connections/server.js @@ -0,0 +1,136 @@ +var Connection = require('../connection').Connection, + DbCommand = require('../commands/db_command').DbCommand, + MongoReply = require('../responses/mongo_reply').MongoReply, + EventEmitter = require("events").EventEmitter, + inherits = require('util').inherits, + debug = require('util').debug, + inspect = require('util').inspect; + +var Server = exports.Server = function(host, port, options) { + EventEmitter.call(this); + var self = this; + this.host = host; + this.port = port; + this.options = options == null ? {} : options; + this.internalConnection; + this.internalMaster = false; + this.connected = false; + this.poolSize = this.options.poolSize == null ? 1 : this.options.poolSize; + this.slaveOk = this.options["slave_ok"]; + this.auths = []; + // Setters and getters + this.__defineGetter__("autoReconnect", function() { return self.options['auto_reconnect'] == null ? false : this.options['auto_reconnect']; }); + this.__defineGetter__("connection", function() { return self.internalConnection; }); + this.__defineSetter__("connection", function(connection) { self.internalConnection = connection; }); + this.__defineGetter__("master", function() { return self.internalMaster; }); + this.__defineSetter__("master", function(value) { self.internalMaster = value; }); + this.__defineGetter__("primary", function() { return self; }); + + // Add handler of resend message + this.on('resend', function(err) { + self.connection.emit("resend"); + }); +}; + +inherits(Server, EventEmitter); + +Server.prototype.close = function(callback) { + this.connected = false; + this.internalMaster = false; + // Close the internal connection + this.internalConnection.close(callback); +}; + +Server.prototype.send = function(command) { + this.internalConnection.send(command); +} + +Server.prototype.isConnected = function() { + return this.connected; +} + +Server.prototype.connect = function(parent, callback) { + // Ensure parent can do a slave query if it's set + parent.slaveOk = this.slaveOk ? this.slaveOk : parent.slaveOk; + // Let's connect + var server = this; + server.connection = new Connection(this.host, this.port, this.autoReconnect, {poolSize:this.poolSize}); + server.connection.on("connect", function() { + // Create a callback function for a given connection + var connectCallback = function(err, reply) { + if(err != null) return callback(err, null); + server.master = reply.documents[0].ismaster == 1 ? true : false; + // Set server as connected + server.connected = true; + + // emit a message saying we got a master and are ready to go and change state to reflect it + if(parent.state == 'notConnected') { + parent.state = 'connected'; + // + // Call the server version function via admin to adapt to changes from 1.7.6 > + var admindb = parent.admin() + admindb.serverInfo(function(err, doc) { + if(err != null) return callback(err, null); + // Store the db version + parent.version = doc.version; + callback(null, parent); + }); + } else { + callback("connection already opened"); + } + }; + + // Create db command and Add the callback to the list of callbacks by the request id (mapping outgoing messages to correct callbacks) + var db_command = DbCommand.createIsMasterCommand(parent); + // Add listeners + parent.on(db_command.getRequestId().toString(), connectCallback); + parent.notReplied[db_command.getRequestId().toString()] = this; + + // Let's send a request to identify the state of the server + this.send(db_command); + }); + + server.connection.on("data", function(message) { + // Parse the data as a reply object + var reply = new MongoReply(parent, message); + // Emit message + parent.emit(reply.responseTo.toString(), null, reply); + // Remove the listener + if(parent.notReplied[reply.responseTo.toString()]) { + delete parent.notReplied[reply.responseTo.toString()]; + parent.removeListener(reply.responseTo.toString(), parent.listeners(reply.responseTo.toString())[0]); + } + }); + + server.connection.on("reconnect", function(err) { + server.emit('reconnect'); + }); + + server.connection.on("error", function(err) { + if(parent.listeners("error") != null && parent.listeners("error").length > 0) parent.emit("error", err); + parent.state = "notConnected" + server.connected = false; + return callback(err, null); + }); + + // Emit timeout and close events so the client using db can figure do proper error handling (emit contains the connection that triggered the event) + server.connection.on("timeout", function() { parent.emit("timeout", this); }); + server.connection.on("close", function() { + server.connected = false; + parent.emit("close", this); + }); + // Open the connection + server.connection.open(); +} + +Server.prototype.allRawConnections = function() { + return this.checkoutWriter().pool.slice(0); +} + +Server.prototype.checkoutWriter = function() { + return this.connection; +} + +Server.prototype.checkoutReader = function() { + return this.connection; +} \ No newline at end of file diff --git a/node_modules/mongodb/lib/mongodb/cursor.js b/node_modules/mongodb/lib/mongodb/cursor.js new file mode 100644 index 0000000..febf6ec --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/cursor.js @@ -0,0 +1,679 @@ +var QueryCommand = require('./commands/query_command').QueryCommand, + GetMoreCommand = require('./commands/get_more_command').GetMoreCommand, + KillCursorCommand = require('./commands/kill_cursor_command').KillCursorCommand, + Long = require('./goog/math/long').Long, + debug = require('util').debug, + inspect = require('util').inspect; + +/** + * Constructor for a cursor object that handles all the operations on query result + * using find. This cursor object is unidirectional and cannot traverse backwards. + * As an alternative, {@link Cursor#toArray} can be used to obtain all the results. + * Clients should not be creating a cursor directly, but use {@link Collection#find} + * to acquire a cursor. + * + * @constructor + * + * @param db {Db} The database object to work with + * @param collection {Colleciton} The collection to query + * @param selector + * @param fields + * @param skip {number} + * @param limit {number} The number of results to return. -1 has a special meaning and + * is used by {@link Db#eval}. A value of 1 will also be treated as if it were -1. + * @param sort {string|Array >} Please refer to {@link Cursor#sort} + * @param hint + * @param explain + * @param snapshot + * @param timeout + * @param tailable {?boolean} + * @param batchSize {?number} The number of the subset of results to request the database + * to return for every request. This should initially be greater than 1 otherwise + * the database will automatically close the cursor. The batch size can be set to 1 + * with {@link Cursor#batchSize} after performing the initial query to the database. + * + * @see Cursor#toArray + * @see Cursor#skip + * @see Cursor#sort + * @see Cursor#limit + * @see Cursor#batchSize + * @see Collection#find + * @see Db#eval + */ +var Cursor = exports.Cursor = function(db, collection, selector, fields, skip, limit, sort, hint, explain, snapshot, timeout, tailable, batchSize, slaveOk) { + this.db = db; + this.collection = collection; + this.selector = selector; + this.fields = fields; + this.skipValue = skip == null ? 0 : skip; + this.limitValue = limit == null ? 0 : limit; + this.sortValue = sort; + this.hint = hint; + this.explainValue = explain; + this.snapshot = snapshot; + this.timeout = timeout == null ? true : timeout; + this.tailable = tailable; + this.batchSizeValue = batchSize == null ? 0 : batchSize; + this.slaveOk = slaveOk == null ? collection.slaveOk : slaveOk; + + this.totalNumberOfRecords = 0; + this.items = []; + this.cursorId = this.db.bson_serializer.Long.fromInt(0); + + // State variables for the cursor + this.state = Cursor.INIT; + // Keep track of the current query run + this.queryRun = false; + this.getMoreTimer = false; + this.collectionName = (this.db.databaseName ? this.db.databaseName + "." : '') + this.collection.collectionName; +}; + +/** + * Resets this cursor to its initial state. All settings like the query string, + * tailable, batchSizeValue, skipValue and limits are preserved. + */ +Cursor.prototype.rewind = function() { + var self = this; + + if (self.state != Cursor.INIT) { + if (self.state != Cursor.CLOSED) { + self.close(function() {}); + } + + self.numberOfReturned = 0; + self.totalNumberOfRecords = 0; + self.items = []; + self.cursorId = self.db.bson_serializer.Long.fromInt(0); + self.state = Cursor.INIT; + self.queryRun = false; + } +}; + + +/** + * Returns an array of documents. The caller is responsible for making sure that there + * is enough memory to store the results. Note that the array only contain partial + * results when this cursor had been previouly accessed. In that case, + * {@link Cursor#rewind} can be used to reset the cursor. + * + * @param callback {function(Error, Array)} This will be called after executing + * this method successfully. The first paramter will contain the Error object if an + * error occured, or null otherwise. The second paramter will contain an array of + * BSON deserialized objects as a result of the query. + * + * Error cases include: + *
      + *
    1. Attempting to call this method with a tailable cursor.
    2. + *
    + * + * @see Cursor#rewind + * @see Cursor#each + */ +Cursor.prototype.toArray = function(callback) { + var self = this; + + if(!callback) { + throw new Error('callback is mandatory'); + } + + if(this.tailable) { + callback(new Error("Tailable cursor cannot be converted to array"), null); + } else if(this.state != Cursor.CLOSED) { + var items = []; + + this.each(function(err, item) { + if(err != null) return callback(err, null); + + if (item != null) { + items.push(item); + } else { + callback(err, items); + items = null; + } + }); + } else { + callback(new Error("Cursor is closed"), null); + } +}; + +/** + * Iterates over all the documents for this cursor. As with {@link Cursor#toArray}, + * not all of the elements will be iterated if this cursor had been previouly accessed. + * In that case, {@link Cursor#rewind} can be used to reset the cursor. However, unlike + * {@link Cursor#toArray}, the cursor will only hold a maximum of batch size elements + * at any given time if batch size is specified. Otherwise, the caller is responsible + * for making sure that the entire result can fit the memory. + * + * @param callback {function(Error, Object)} This will be called for while iterating + * every document of the query result. The first paramter will contain the Error + * object if an error occured, or null otherwise. While the second paramter will + * contain the document. + * + * @see Cursor#rewind + * @see Cursor#toArray + * @see Cursor#batchSize + */ +Cursor.prototype.each = function(callback) { + var self = this; + + if (!callback) { + throw new Error('callback is mandatory'); + } + + if(this.state != Cursor.CLOSED) { + //FIX: stack overflow (on deep callback) (cred: https://github.com/limp/node-mongodb-native/commit/27da7e4b2af02035847f262b29837a94bbbf6ce2) + process.nextTick(function(){ + // Fetch the next object until there is no more objects + self.nextObject(function(err, item) { + if(err != null) return callback(err, null); + + if(item != null) { + callback(null, item); + self.each(callback); + } else { + // Close the cursor if done + self.state = Cursor.CLOSED; + callback(err, null); + } + + item = null; + }); + }); + } else { + callback(new Error("Cursor is closed"), null); + } +}; + +/** + * Determines how many result the query for this cursor will return + * + * @param callback {function(?Error, ?number)} This will be after executing this method. + * The first paramter will contain the Error object if an error occured, or null + * otherwise. While the second paramter will contain the number of results or null + * if an error occured. + */ +Cursor.prototype.count = function(callback) { + this.collection.count(this.selector, callback); +}; + +/** + * Sets the sort parameter of this cursor to the given value. + * + * This method has the following method signatures: + * (keyOrList, callback) + * (keyOrList, direction, callback) + * + * @param keyOrList {string|Array >} This can be a string or an array. + * If passed as a string, the string will be the field to sort. If passed an array, + * each element will represent a field to be sorted and should be an array that contains + * the format [string, direction]. Example of a valid array passed: + * + *
    
    + *     [
    + *       ["id", "asc"], //direction using the abbreviated string format
    + *       ["name", -1], //direction using the number format
    + *       ["age", "descending"], //direction using the string format
    + *     ]
    + *     
    + * + * @param direction {string|number} This determines how the results are sorted. "asc", + * "ascending" or 1 for asceding order while "desc", "desceding or -1 for descending + * order. Note that the strings are case insensitive. + * @param callback {?function(?Error, ?Cursor)} This will be called after executing + * this method. The first parameter will contain an error object when the + * cursor is already closed while the second parameter will contain a reference + * to this object upon successful execution. + * + * @return {Cursor} an instance of this object. + * + * @see Cursor#formatSortValue + */ +Cursor.prototype.sort = function(keyOrList, direction, callback) { + callback = callback || function(){}; + if(typeof direction === "function") { callback = direction; direction = null; } + + if(this.tailable) { + callback(new Error("Tailable cursor doesn't support sorting"), null); + } else if(this.queryRun == true || this.state == Cursor.CLOSED) { + callback(new Error("Cursor is closed"), null); + } else { + var order = keyOrList; + + if(direction != null) { + order = [[keyOrList, direction]]; + } + + this.sortValue = order; + callback(null, this); + } + return this; +}; + +/** + * Sets the limit parameter of this cursor to the given value. + * + * @param limit {Number} The new limit. + * @param callback {?function(?Error, ?Cursor)} This will be called after executing + * this method. The first parameter will contain an error object when the + * limit given is not a valid number or when the cursor is already closed while + * the second parameter will contain a reference to this object upon successful + * execution. + * + * @return {Cursor} an instance of this object. + */ +Cursor.prototype.limit = function(limit, callback) { + callback = callback || function(){}; + + if(this.tailable) { + callback(new Error("Tailable cursor doesn't support limit"), null); + } else if(this.queryRun == true || this.state == Cursor.CLOSED) { + callback(new Error("Cursor is closed"), null); + } else { + if(limit != null && limit.constructor != Number) { + callback(new Error("limit requires an integer"), null); + } else { + this.limitValue = limit; + callback(null, this); + } + } + + return this; +}; + +/** + * Sets the skip parameter of this cursor to the given value. + * + * @param skip {Number} The new skip value. + * @param callback {?function(?Error, ?Cursor)} This will be called after executing + * this method. The first parameter will contain an error object when the + * skip value given is not a valid number or when the cursor is already closed while + * the second parameter will contain a reference to this object upon successful + * execution. + * + * @return {Cursor} an instance of this object. + */ +Cursor.prototype.skip = function(skip, callback) { + callback = callback || function(){}; + + if(this.tailable) { + callback(new Error("Tailable cursor doesn't support skip"), null); + } else if(this.queryRun == true || this.state == Cursor.CLOSED) { + callback(new Error("Cursor is closed"), null); + } else { + if(skip != null && skip.constructor != Number) { + callback(new Error("skip requires an integer"), null); + } else { + this.skipValue = skip; + callback(null, this); + } + } + + return this; +}; + +/** + * Sets the batch size parameter of this cursor to the given value. + * + * @param batchSize {Number} The new batch size. + * @param callback {?function(?Error, ?Cursor)} This will be called after executing + * this method. The first parameter will contain an error object when the + * batchSize given is not a valid number or when the cursor is already closed while + * the second parameter will contain a reference to this object upon successful + * execution. + * + * @return {Cursor} an instance of this object. + */ +Cursor.prototype.batchSize = function(batchSize, callback) { + callback = callback || function(){}; + + if(this.state == Cursor.CLOSED) { + callback(new Error("Cursor is closed"), null); + } else if(batchSize != null && batchSize.constructor != Number) { + callback(new Error("batchSize requires an integer"), null); + } else { + this.batchSizeValue = batchSize; + callback(null, this); + } + + return this; +}; + +/** + * @return {number} The number of records to request per batch. + */ +Cursor.prototype.limitRequest = function() { + var requestedLimit = this.limitValue; + + if (this.limitValue > 0) { + if (this.batchSizeValue > 0) { + requestedLimit = this.limitValue < this.batchSizeValue ? + this.limitValue : this.batchSizeValue; + } + } else { + requestedLimit = this.batchSizeValue; + } + + return requestedLimit; +}; + + +/** + * Generates a QueryCommand object using the parameters of this cursor. + * + * @return {QueryCommand} The command object + */ +Cursor.prototype.generateQueryCommand = function() { + // Unpack the options + var queryOptions = QueryCommand.OPTS_NONE; + if (!this.timeout) { + queryOptions |= QueryCommand.OPTS_NO_CURSOR_TIMEOUT; + } + if (this.tailable != null) { + queryOptions |= QueryCommand.OPTS_TAILABLE_CURSOR; + this.skipValue = this.limitValue = 0; + } + if (this.slaveOk) { + queryOptions |= QueryCommand.OPTS_SLAVE; + } + + // limitValue of -1 is a special case used by Db#eval + var numberToReturn = this.limitValue == -1 ? -1 : this.limitRequest(); + + // Check if we need a special selector + if(this.sortValue != null || this.explainValue != null || this.hint != null || this.snapshot != null) { + // Build special selector + var specialSelector = {'query':this.selector}; + if(this.sortValue != null) specialSelector['orderby'] = this.formattedOrderClause(); + if(this.hint != null && this.hint.constructor == Object) specialSelector['$hint'] = this.hint; + if(this.explainValue != null) specialSelector['$explain'] = true; + if(this.snapshot != null) specialSelector['$snapshot'] = true; + + return new QueryCommand(this.db, this.collectionName, queryOptions, this.skipValue, numberToReturn, specialSelector, this.fields); + } else { + return new QueryCommand(this.db, this.collectionName, queryOptions, this.skipValue, numberToReturn, this.selector, this.fields); + } +}; + +/** + * @return {Object} Returns an object containing the sort value of this cursor with + * the proper formatting that can be used internally in this cursor. + */ +Cursor.prototype.formattedOrderClause = function() { + var orderBy = {}; + var self = this; + + if(Array.isArray(this.sortValue)) { + this.sortValue.forEach(function(sortElement) { + if(sortElement.constructor == String) { + orderBy[sortElement] = 1; + } else { + orderBy[sortElement[0]] = self.formatSortValue(sortElement[1]); + } + }); + } else if(Object.prototype.toString.call(this.sortValue) === '[object Object]') { + return orderBy = this.sortValue; + } else if(this.sortValue.constructor == String) { + orderBy[this.sortValue] = 1 + } else { + throw new Error("Illegal sort clause, must be of the form " + + "[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]"); + } + return orderBy; +}; + +/** + * Converts the value of the sort direction into its equivalent numerical value. + * + * @param sortDirection {String|number} Range of acceptable values: + * 'ascending', 'descending', 'asc', 'desc', 1, -1 + * + * @return {number} The equivalent numerical value + * @throws Error if the given sortDirection is invalid + */ +Cursor.prototype.formatSortValue = function(sortDirection) { + var value = ("" + sortDirection).toLowerCase(); + if(value == 'ascending' || value == 'asc' || value == 1) return 1; + if(value == 'descending' || value == 'desc' || value == -1 ) return -1; + throw new Error("Illegal sort clause, must be of the form " + + "[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]"); +}; + +/** + * Gets the next document from the database. + * + * @param callback {function(?Error, ?Object)} This will be called after executing + * this method. The first parameter will contain an error object on error while + * the second parameter will contain a document from the returned result or null + * if there are no more results. + * + * @see Cursor#limit + * @see Cursor#batchSize + */ +Cursor.prototype.nextObject = function(callback) { + var self = this; + + if(self.state == Cursor.INIT) { + var cmd; + try { + cmd = self.generateQueryCommand(); + } catch (err) { + return callback(err, null); + } + + var commandHandler = function(err, result) { + if(err != null && result == null) return callback(err, null); + + if(!err && result.documents[0] && result.documents[0]['$err']) { + return self.close(function() {callback(result.documents[0]['$err'], null);}); + } + + self.queryRun = true; + self.state = Cursor.OPEN; // Adjust the state of the cursor + self.cursorId = result.cursorId; + self.totalNumberOfRecords = result.numberReturned; + + // Add the new documents to the list of items + self.items = self.items.concat(result.documents); + self.nextObject(callback); + result = null; + }; + + self.db.executeCommand(cmd, {read:true}, commandHandler); + commandHandler = null; + } else if(self.items.length) { + callback(null, self.items.shift()); + } else if(self.cursorId.greaterThan(self.db.bson_serializer.Long.fromInt(0))) { + self.getMore(callback); + } else { + // Force cursor to stay open + return self.close(function() {callback(null, null);}); + } +} + +/** + * Gets more results from the database if any. + * + * @param callback {function(?Error, ?Object)} This will be called after executing + * this method. The first parameter will contain an error object on error while + * the second parameter will contain a document from the returned result or null + * if there are no more results. + */ +Cursor.prototype.getMore = function(callback) { + var self = this; + var limit = 0; + + if (!self.tailable && self.limitValue > 0) { + limit = self.limitValue - self.totalNumberOfRecords; + if (limit < 1) { + self.close(function() {callback(null, null);}); + return; + } + } + try { + var getMoreCommand = new GetMoreCommand(self.db, self.collectionName, self.limitRequest(), self.cursorId); + // Execute the command + self.db.executeCommand(getMoreCommand, {read:true}, function(err, result) { + try { + if(err != null) callback(err, null); + + self.cursorId = result.cursorId; + self.totalNumberOfRecords += result.numberReturned; + // Determine if there's more documents to fetch + if(result.numberReturned > 0) { + if (self.limitValue > 0) { + var excessResult = self.totalNumberOfRecords - self.limitValue; + + if (excessResult > 0) { + result.documents.splice(-1*excessResult, excessResult); + } + } + + self.items = self.items.concat(result.documents); + callback(null, self.items.shift()); + } else if(self.tailable) { + self.getMoreTimer = setTimeout(function() {self.getMore(callback);}, 500); + } else { + self.close(function() {callback(null, null);}); + } + + result = null; + } catch(err) { + callback(err, null); + } + }); + + getMoreCommand = null; + } catch(err) { + var handleClose = function() { + callback(err, null); + }; + + self.close(handleClose); + handleClose = null; + } +} + +/** + * Gets a detailed information about how the query is performed on this cursor and how + * long it took the database to process it. + * + * @param callback {function(null, Object)} This will be called after executing this + * method. The first parameter will always be null while the second parameter + * will be an object containing the details. + * + * @see http://www.mongodb.org/display/DOCS/Optimization#Optimization-Explain + */ +Cursor.prototype.explain = function(callback) { + var limit = (-1)*Math.abs(this.limitValue); + // Create a new cursor and fetch the plan + var cursor = new Cursor(this.db, this.collection, this.selector, this.fields, this.skipValue, limit, + this.sortValue, this.hint, true, this.snapshot, this.timeout, this.tailable, this.batchSizeValue); + cursor.nextObject(function(err, item) { + if(err != null) return callback(err, null); + // close the cursor + cursor.close(function(err, result) { + if(err != null) return callback(err, null); + callback(null, item); + }); + }); +}; + +Cursor.prototype.streamRecords = function(options) { + var args = Array.prototype.slice.call(arguments, 0); + options = args.length ? args.shift() : {}; + + var + self = this, + stream = new process.EventEmitter(), + recordLimitValue = this.limitValue || 0, + emittedRecordCount = 0, + queryCommand = this.generateQueryCommand(); + + // see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol + queryCommand.numberToReturn = options.fetchSize ? options.fetchSize : 500; + + execute(queryCommand); + + function execute(command) { + self.db.executeCommand(command, {read:true}, function(err,result) { + if(err != null) return callback(err, null); + + if (!self.queryRun && result) { + self.queryRun = true; + self.cursorId = result.cursorId; + self.state = Cursor.OPEN; + self.getMoreCommand = new GetMoreCommand(self.db, self.collectionName, queryCommand.numberToReturn, result.cursorId); + } + + if (result.documents && result.documents.length) { + try { + result.documents.forEach(function(doc){ + if (recordLimitValue && emittedRecordCount>=recordLimitValue) { + throw("done"); + } + emittedRecordCount++; + stream.emit('data', doc); + }); + } catch(err) { + if (err != "done") { throw err; } + else { + stream.emit('end', recordLimitValue); + self.close(function(){}); + return(null); + } + } + // rinse & repeat + execute(self.getMoreCommand); + } else { + self.close(function(){ + stream.emit('end', recordLimitValue); + }); + } + }); + } + + return stream; +}; + +/** + * Close this cursor. + * + * @param callback {?function(null, ?Object)} This will be called after executing + * this method. The first parameter will always contain null while the second + * parameter will contain a reference to this cursor. + */ +Cursor.prototype.close = function(callback) { + var self = this + this.getMoreTimer && clearTimeout(this.getMoreTimer); + // Close the cursor if not needed + if(this.cursorId instanceof self.db.bson_serializer.Long && this.cursorId.greaterThan(self.db.bson_serializer.Long.fromInt(0))) { + try { + var command = new KillCursorCommand(this.db, [this.cursorId]); + this.db.executeCommand(command, {read:true}, null); + } catch(err) {} + } + + this.cursorId = self.db.bson_serializer.Long.fromInt(0); + this.state = Cursor.CLOSED; + + if(callback) { + process.nextTick(function(){ + callback(null, self); + self.items = null; + }); + } + + return this; +}; + +/** + * @return true if this cursor is closed + */ +Cursor.prototype.isClosed = function() { + return this.state == Cursor.CLOSED ? true : false; +}; + +// Static variables +Cursor.INIT = 0; +Cursor.OPEN = 1; +Cursor.CLOSED = 2; diff --git a/node_modules/mongodb/lib/mongodb/db.js b/node_modules/mongodb/lib/mongodb/db.js new file mode 100644 index 0000000..ce7fc04 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/db.js @@ -0,0 +1,796 @@ +var QueryCommand = require('./commands/query_command').QueryCommand, + DbCommand = require('./commands/db_command').DbCommand, + BinaryParser = require('./bson/binary_parser').BinaryParser, + MongoReply = require('./responses/mongo_reply').MongoReply, + Admin = require('./admin').Admin, + Connection = require('./connection').Connection, + Collection = require('./collection').Collection, + Server = require('./connections/server').Server, + ReplSetServers = require('./connections/repl_set_servers').ReplSetServers, + Cursor = require('./cursor').Cursor, + EventEmitter = require('events').EventEmitter, + inherits = require('util').inherits, + crypto = require('crypto'), + debug = require('util').debug, + inspect = require('util').inspect; + +var Db = exports.Db = function(databaseName, serverConfig, options) { + EventEmitter.call(this); + this.databaseName = databaseName; + this.serverConfig = serverConfig; + this.options = options == null ? {} : options; + + // Contains all the connections for the db + try { + this.native_parser = this.options.native_parser; + var serializer = this.options.native_parser ? require('../../external-libs/bson') : require('./bson/bson'); + this.bson_serializer = serializer; + this.bson_deserializer = serializer; + } catch (err) { + // If we tried to instantiate the native driver + throw "Native bson parser not compiled, please compile or avoid using native_parser=true"; + } + + // State of the db connection + this.state = 'notConnected'; + this.pkFactory = this.options.pk == null ? this.bson_serializer.ObjectID : this.options.pk; + this.forceServerObjectId = this.options.forceServerObjectId != null ? this.options.forceServerObjectId : false; + // Added strict + this.strict = this.options.strict == null ? false : this.options.strict; + this.notReplied ={}; + this.isInitializing = true; + this.auths = []; + // Allow slaveOk + this.slaveOk = this.options["slave_ok"] == null ? false : this.options["slave_ok"]; + + var self = this; + // Add a listener for the reconnect event + this.serverConfig.on("reconnect", function() { + // Number of current auths + var authLength = self.auths.length; + var numberOfReadyAuth = 0; + + if(authLength > 0) { + // If we have any auths fire off the auth message to all the connections + for(var i = 0; i < authLength; i++) { + + // Execute auth commands + self.authenticate(self.auths[i].username, self.auths[i].password, function(err, result) { + numberOfReadyAuth = numberOfReadyAuth + 1; + + if(numberOfReadyAuth == self.auths.length) { + self.serverConfig.emit("resend"); + } + }); + } + } else { + self.serverConfig.emit("resend"); + } + }); +}; + +inherits(Db, EventEmitter); + +Db.prototype.open = function(callback) { + var self = this; + // Set up connections + if(self.serverConfig instanceof Server || self.serverConfig instanceof ReplSetServers) { + self.serverConfig.connect(self, function(err, result) { + if(err != null) return callback(err, null); + // Callback + return callback(null, self); + }); + + } else { + return callback(Error("Server parameter must be of type Server or ReplSetServers"), null); + } +}; + +Db.prototype.close = function(callback) { + // Remove all listeners + this.removeAllListeners("reconnect"); + // Clear out state of the connection + this.state = "notConnected" + // Close connection + this.serverConfig.close(callback); +}; + +Db.prototype.admin = function(callback) { + if(callback == null) return new Admin(this); + callback(null, new Admin(this)); +}; + +/** + Get the list of all collections for a mongo master server +**/ +Db.prototype.collectionsInfo = function(collection_name, callback) { + if(callback == null) { callback = collection_name; collection_name = null; } + // Create selector + var selector = {}; + // If we are limiting the access to a specific collection name + if(collection_name != null) selector.name = this.databaseName + "." + collection_name; + + // Return Cursor + // callback for backward compatibility + if (callback) { + callback(null, new Cursor(this, new Collection(this, DbCommand.SYSTEM_NAMESPACE_COLLECTION), selector)); + } else { + return new Cursor(this, new Collection(this, DbCommand.SYSTEM_NAMESPACE_COLLECTION), selector); + } +}; + +/** + Get the list of all collection names for the specified db +**/ +Db.prototype.collectionNames = function(collection_name, callback) { + if(callback == null) { callback = collection_name; collection_name = null; } + var self = this; + // Let's make our own callback to reuse the existing collections info method + self.collectionsInfo(collection_name, function(err, cursor) { + if(err != null) return callback(err, null); + + cursor.toArray(function(err, documents) { + if(err != null) return callback(err, null); + + // List of result documents that have been filtered + var filtered_documents = []; + // Remove any collections that are not part of the db or a system db signed with $ + documents.forEach(function(document) { + if(!(document.name.indexOf(self.databaseName) == -1 || document.name.indexOf('$') != -1)) + filtered_documents.push(document); + }); + // Return filtered items + callback(null, filtered_documents); + }); + }); +}; + +/** + Fetch a specific collection (containing the actual collection information) +**/ +Db.prototype.collection = function(collectionName, options, callback) { + var self = this; + if(typeof options === "function") { callback = options; options = {}; } + // Execute safe + if(options && options.safe || this.strict) { + self.collectionNames(collectionName, function(err, collections) { + if(err != null) return callback(err, null); + + if(collections.length == 0) { + return callback(new Error("Collection " + collectionName + " does not exist. Currently in strict mode."), null); + } else { + try { + var collection = new Collection(self, collectionName, self.pkFactory, options); + } catch(err) { + return callback(err, null); + } + return callback(null, collection); + } + }); + } else { + try { + var collection = new Collection(self, collectionName, self.pkFactory, options); + } catch(err) { + return callback(err, null); + } + return callback(null, collection); + } +}; + +/** + Fetch all collections for the given db +**/ +Db.prototype.collections = function(callback) { + var self = this; + // Let's get the collection names + self.collectionNames(function(err, documents) { + if(err != null) return callback(err, null); + var collections = []; + documents.forEach(function(document) { + collections.push(new Collection(self, document.name.replace(self.databaseName + ".", ''), self.pkFactory)); + }); + // Return the collection objects + callback(null, collections); + }); +}; + +/** + Evaluate javascript on the server +**/ +Db.prototype.eval = function(code, parameters, callback) { + if(typeof parameters === "function") { callback = parameters; parameters = null; } + var finalCode = code; + var finalParameters = []; + // If not a code object translate to one + if(!(finalCode instanceof this.bson_serializer.Code)) { + finalCode = new this.bson_serializer.Code(finalCode); + } + + // Ensure the parameters are correct + if(parameters != null && parameters.constructor != Array) { + finalParameters = [parameters]; + } else if(parameters != null && parameters.constructor == Array) { + finalParameters = parameters; + } + // Create execution selector + var selector = {'$eval':finalCode, 'args':finalParameters}; + // Iterate through all the fields of the index + new Cursor(this, new Collection(this, DbCommand.SYSTEM_COMMAND_COLLECTION), selector, {}, 0, -1).nextObject(function(err, result) { + if(err != null) return callback(err, null); + + if(result.ok == 1) { + callback(null, result.retval); + } else { + callback(new Error("eval failed: " + result.errmsg), null); return; + } + }); +}; + +Db.prototype.dereference = function(dbRef, callback) { + this.collection(dbRef.namespace, function(err, collection) { + if(err != null) return callback(err, null); + + collection.findOne({'_id':dbRef.oid}, function(err, result) { + callback(err, result); + }); + }); +}; + +/** + Logout user from server + Fire off on all connections and remove all auth info +**/ +Db.prototype.logout = function(options, callback) { + var self = this; + // If the first object is a function + if(typeof options === "function") { callback = options; options = {}} + + // Let's generate the logout command object + var logoutCommand = DbCommand.logoutCommand(self, {logout:1, socket:options['socket']}); + + // For all the connections let's execute the command + var rawConnections = self.serverConfig.allRawConnections(); + var numberOfExpectedReturns = rawConnections.length; + + for(var index = 0; index < numberOfExpectedReturns; index++) { + // Execute the logout on all raw connections + self.executeCommand(logoutCommand, {writer: rawConnections[index].connection}, function(err, result) { + // Ajust the number of expected results + numberOfExpectedReturns = numberOfExpectedReturns - 1; + + // If we are done let's evaluate + if(numberOfExpectedReturns <= 0) { + // Reset auth + self.auths = []; + + // Handle any errors + if(err == null && result.documents[0].ok == 1) { + callback(null, true); + } else { + err != null ? callback(err, false) : callback(new Error(result.documents[0].errmsg), false); + } + } + }); + } +} + +/** + Authenticate against server +**/ +Db.prototype.authenticate = function(username, password, callback) { + var self = this; + // Add the auth details to the connection for reconnects or update existing if any + var found = false; + for(var i = 0; i < self.auths.length; i++) { + // If we have found an existing auth, update the password + if(self.auths[i].username == username) { + found = true; + self.auths[i].password = password; + } + } + // Push the new auth if we have no previous record + if(!found) self.auths.push({'username':username, 'password':password}); + // Figure out the number of times we need to trigger + var rawConnections = self.serverConfig.allRawConnections(); + var numberOfExpectedReturns = rawConnections.length; + // Execute the commands + for(var i = 0; i < numberOfExpectedReturns; i++) { + // Execute command + var createNonceCallback = function(index) { + return function(err, reply) { + if(err == null) { + // Nonce used to make authentication request with md5 hash + var nonce = reply.documents[0].nonce; + // Execute command + self.executeCommand(DbCommand.createAuthenticationCommand(self, username, password, nonce), {writer: rawConnections[index].connection}, function(err, result) { + // Ajust the number of expected results + numberOfExpectedReturns = numberOfExpectedReturns - 1; + // If we are done let's evaluate + if(numberOfExpectedReturns <= 0) { + if(err == null && result.documents[0].ok == 1) { + callback(null, true); + } else { + err != null ? callback(err, false) : callback(new Error(result.documents[0].errmsg), false); + } + } + }); + } else { + callback(err, null); + } + } + } + + this.executeCommand(DbCommand.createGetNonceCommand(self), {writer: rawConnections[i].connection}, createNonceCallback(i)); + } +}; + +/** + Add a user +**/ +Db.prototype.addUser = function(username, password, callback) { + // Use node md5 generator + var md5 = crypto.createHash('md5'); + // Generate keys used for authentication + md5.update(username + ":mongo:" + password); + var userPassword = md5.digest('hex'); + // Fetch a user collection + this.collection(DbCommand.SYSTEM_USER_COLLECTION, function(err, collection) { + // Insert the user into the system users collections + collection.insert({user: username, pwd: userPassword}, {safe:true}, function(err, documents) { + callback(err, documents); + }); + }); +}; + +/** + Remove a user +**/ +Db.prototype.removeUser = function(username, callback) { + // Fetch a user collection + this.collection(DbCommand.SYSTEM_USER_COLLECTION, function(err, collection) { + collection.findOne({user: username}, function(err, user) { + if(user != null) { + collection.remove({user: username}, function(err, result) { + callback(err, true); + }); + } else { + callback(err, false); + } + }); + }); +}; + +/** + Create Collection +**/ +Db.prototype.createCollection = function(collectionName, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() : null; + var self = this; + // Check if we have the name + this.collectionNames(collectionName, function(err, collections) { + if(err != null) return callback(err, null); + + var found = false; + collections.forEach(function(collection) { + if(collection.name == self.databaseName + "." + collectionName) found = true; + }); + + // If the collection exists either throw an exception (if db in strict mode) or return the existing collection + if(found && self.strict) { + return callback(new Error("Collection " + collectionName + " already exists. Currently in strict mode."), null); + } else if(found){ + try { + var collection = new Collection(self, collectionName, self.pkFactory); + } catch(err) { + return callback(err, null); + } + return callback(null, collection); + } + + // Create a new collection and return it + self.executeCommand(DbCommand.createCreateCollectionCommand(self, collectionName, options), {read:false, safe:true}, function(err, result) { + if(err == null && result.documents[0].ok == 1) { + try { + var collection = new Collection(self, collectionName, self.pkFactory); + } catch(err) { + return callback(err, null); + } + return callback(null, collection); + } else { + err != null ? callback(err, null) : callback(new Error("Error creating collection: " + collectionName), null); + } + }); + }); +}; + +Db.prototype.command = function(selector, callback) { + var cursor = new Cursor(this, new Collection(this, DbCommand.SYSTEM_COMMAND_COLLECTION), selector, {}, 0, -1, null, null, null, null, QueryCommand.OPTS_NO_CURSOR_TIMEOUT); + cursor.nextObject(callback); +}; + +/** + Drop Collection +**/ +Db.prototype.dropCollection = function(collectionName, callback) { + this.executeCommand(DbCommand.createDropCollectionCommand(this, collectionName), function(err, result) { + if(err == null && result.documents[0].ok == 1) { + if(callback != null) return callback(null, true); + } else { + if(callback != null) err != null ? callback(err, null) : callback(new Error(result.documents[0].errmsg), null); + } + }); +}; + +/** + Rename Collection +**/ +Db.prototype.renameCollection = function(fromCollection, toCollection, callback) { + this.executeCommand(DbCommand.createRenameCollectionCommand(this, fromCollection, toCollection), function(err, doc) { callback(err, doc); }); +}; + +/** + Return last error message for the given connection +**/ +Db.prototype.lastError = function(options, callback) { + if ('function' === typeof options) callback = options, options = {}; + + this.executeCommand(DbCommand.createGetLastErrorCommand(options, this), function(err, error) { + callback(err, error && error.documents); + }); +}; + +Db.prototype.error = function(options, callback) { + this.lastError(options, callback); +}; + +/** + Return the status for the last operation on the given connection +**/ +Db.prototype.lastStatus = function(callback) { + this.executeCommand(DbCommand.createGetLastStatusCommand(this), callback); +}; + +/** + Return all errors up to the last time db reset_error_history was called +**/ +Db.prototype.previousErrors = function(callback) { + this.executeCommand(DbCommand.createGetPreviousErrorsCommand(this), function(err, error) { + callback(err, error.documents); + }); +}; + +/** + Runs a command on the database +**/ +Db.prototype.executeDbCommand = function(command_hash, callback) { + this.executeCommand(DbCommand.createDbCommand(this, command_hash), callback); +}; + +/** + Runs a command on the database as admin +**/ +Db.prototype.executeDbAdminCommand = function(command_hash, callback) { + this.executeCommand(DbCommand.createAdminDbCommand(this, command_hash), callback); +}; + +/** + Resets the error history of the mongo instance +**/ +Db.prototype.resetErrorHistory = function(callback) { + this.executeCommand(DbCommand.createResetErrorHistoryCommand(this), callback); +}; + +/** + Create an index on a collection +**/ +Db.prototype.createIndex = function(collectionName, fieldOrSpec, options, callback) { + if(callback == null) { callback = options; options = null; } + var command = DbCommand.createCreateIndexCommand(this, collectionName, fieldOrSpec, options); + this.executeCommand(command, {read:false, safe:true}, function(err, result) { + if(err != null) return callback(err, null); + + result = result && result.documents; + if (result[0].err) { + callback(new Error(result[0].err)); + } else { + callback(null, command.documents[0].name); + } + }); +}; + +/** + Ensure index, create an index if it does not exist +**/ +Db.prototype.ensureIndex = function(collectionName, fieldOrSpec, options, callback) { + if(callback == null) { callback = options; options = null; } + var command = DbCommand.createCreateIndexCommand(this, collectionName, fieldOrSpec, options); + var index_name = command.documents[0].name; + var self = this; + // Check if the index allready exists + this.indexInformation(collectionName, function(err, collectionInfo) { + if(!collectionInfo[index_name]) { + self.executeCommand(command, {read:false, safe:true}, function(err, result) { + if(err != null) return callback(err, null); + + result = result && result.documents; + if (result[0].err) { + callback(new Error(result[0].err)); + } else { + callback(null, command.documents[0].name); + } + }); + } else { + return callback(null, index_name); + } + }); +}; + +/** + Fetch the cursor information +**/ +Db.prototype.cursorInfo = function(callback) { + this.executeCommand(DbCommand.createDbCommand(this, {'cursorInfo':1}), function(err, result) { + callback(err, result.documents[0]); + }); +}; + +/** + Drop Index on a collection +**/ +Db.prototype.dropIndex = function(collectionName, indexName, callback) { + this.executeCommand(DbCommand.createDropIndexCommand(this, collectionName, indexName), callback); +}; + +/** + Index Information +**/ +Db.prototype.indexInformation = function(collectionName, options, callback) { + // Unpack calls + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + collectionName = args.length ? args.shift() : null; + options = args.length ? args.shift() : {}; + + // If we specified full information + var full = options['full'] == null ? false : options['full']; + // Build selector for the indexes + var selector = collectionName != null ? {ns: (this.databaseName + "." + collectionName)} : {}; + // Iterate through all the fields of the index + new Cursor(this, new Collection(this, DbCommand.SYSTEM_INDEX_COLLECTION), selector).toArray(function(err, indexes) { + if(err != null) return callback(err, null); + // Contains all the information + var info = {}; + + // if full defined just return all the indexes directly + if(full) return callback(null, indexes); + + // Process all the indexes + for(var i = 0; i < indexes.length; i++) { + var index = indexes[i]; + // Let's unpack the object + info[index.name] = []; + for(var name in index.key) { + info[index.name].push([name, index.key[name]]); + } + } + + // Return all the indexes + callback(null, info); + }); +}; + +/** + Database Drop Command +**/ +Db.prototype.dropDatabase = function(callback) { + this.executeCommand(DbCommand.createDropDatabaseCommand(this), function(err, result) { + callback(err, result); + }); +}; + +/** + Execute db command +**/ +Db.prototype.executeCommand = function(db_command, options, callback) { + var self = this; + + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() : {}; + + // Options unpacking + var read = options['read'] != null ? options['read'] : false; + var safe = options['safe'] != null ? options['safe'] : false; + // Let's us pass in a writer to force the use of a connection (used for admin where we need to peform 2 calls against the same connection) + var rawConnection = options['writer'] != null ? options['writer'] : null; + + var errorCommand = null; + if(safe == true) { + errorCommand = DbCommand.createGetLastErrorCommand(safe, this); + } + + // If we have a callback execute + if(callback instanceof Function) { + var listenToCommand = errorCommand != null ? errorCommand : db_command; + // Add the callback to the list of callbacks by the request id (mapping outgoing messages to correct callbacks) + this.on(listenToCommand.getRequestId().toString(), callback); + if(self.serverConfig.primary != null) { + this.notReplied[listenToCommand.getRequestId().toString()] = self.serverConfig.primary; + } + } + + try{ + // Attempt forcing a reconnect if we have a replicaset server + if(self.serverConfig instanceof ReplSetServers && !self.serverConfig.isConnected()) { + // Initialize + self.isInitializing = true; + // Number of retries + var retries = self.serverConfig.retries; + // Attempts a reconnect + var reconnectAttempt = function() { + // Try reconnect + self.serverConfig.connect(self, function(err, result) { + // Initialize + self.isInitializing = true; + // Set retries + retries = retries - 1; + // If we fail retry the connec + if(err != null && retries > 0) { + // Wait an try again + setTimeout(reconnectAttempt, self.serverConfig.reconnectWait); + } else { + // Ensure we catch any errors happening and report them (especially important for replicaset servers) + try { + if(err != null && callback instanceof Function) return callback(err, null); + // for the other instances fire the message + var writer = read ? self.serverConfig.checkoutReader() : self.serverConfig.checkoutWriter(); + // If we got safe set + if(errorCommand != null) { + writer.send([db_command, errorCommand], rawConnection); + } else { + writer.send(db_command, rawConnection) + } + } catch (err) { + // Set server config to disconnected if it's a replicaset + if(self.serverConfig instanceof ReplSetServers && err == "notConnected") { + // Just clear up all connections as we need to perform a complete reconnect for the call + self.serverConfig.disconnect(); + } + + // Signal an error + if(!(err instanceof Error)) err = new Error(err); + if(callback instanceof Function) { + if(errorCommand != null) delete self.notReplied[errorCommand.getRequestId().toString()]; + return callback(err, null); + } + } + } + }); + } + + // Force a reconnect after self.serverConfig.reconnectWait seconds + setTimeout(reconnectAttempt, self.serverConfig.reconnectWait); + } else { + // for the other instances fire the message + var writer = read ? self.serverConfig.checkoutReader() : self.serverConfig.checkoutWriter(); + // If we got safe set + if(errorCommand != null) { + writer.send([db_command, errorCommand], rawConnection); + } else { + writer.send(db_command, rawConnection) + } + } + } catch(err){ + // Set server config to disconnected if it's a replicaset + if(self.serverConfig instanceof ReplSetServers && err == "notConnected") { + // Just clear up all connections as we need to perform a complete reconnect for the call + self.serverConfig.disconnect(); + } + + // Signal an error + if(!(err instanceof Error)) err = new Error(err); + if(callback instanceof Function) { + if(errorCommand != null) delete self.notReplied[errorCommand.getRequestId().toString()]; + return callback(err, null); + } + + // Return error object + return err; + } +}; + +/** + * Connect to URL + * + * The mongodb URL scheme is documented at: + * http://www.mongodb.org/display/DOCS/Connections +**/ +Db.DEFAULT_URL = 'mongodb://localhost:27017/default'; + +exports.connect = function(url, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() : null; + options = options || {}; + var serverOptions = options.server || {}; + var replSetServersOptions = options.replSetServers || {}; + var dbOptions = options.db || {}; + + var urlRE = new RegExp('^mongo(?:db)?://(?:|([^@/]*)@)([^@/]*)(?:|/([^?]*)(?:|\\?([^?]*)))$'); + var match = (url || Db.DEFAULT_URL).match(urlRE); + if (!match) + throw Error("URL must be in the format mongodb://user:pass@host:port/dbname"); + + var authPart = match[1] || ''; + var auth = authPart.split(':', 2); + var hostPart = match[2]; + var dbname = match[3] || 'default'; + var urlOptions = (match[4] || '').split(/[&;]/); + + // Ugh, we have to figure out which options go to which constructor manually. + urlOptions.forEach(function(opt) { + if (!opt) return; + var splitOpt = opt.split('='), name = splitOpt[0], value = splitOpt[1]; + + // Server options: + if (name == 'slaveOk' || name == 'slave_ok') + serverOptions.slave_ok = (value == 'true'); + if (name == 'poolSize') + serverOptions.poolSize = Number(value); + if (name == 'autoReconnect' || name == 'auto_reconnect') + serverOptions.auto_reconnect = (value == 'true'); + + // ReplSetServers options: + if (name == 'replicaSet' || name == 'rs_name') + replSetServersOptions.rs_name = value; + if (name == 'reconnectWait') + replSetServersOptions.reconnectWait = Number(value); + if (name == 'retries') + replSetServersOptions.retries = Number(value); + if (name == 'readSecondary' || name == 'read_secondary') + replSetServersOptions.read_secondary = (value == 'true'); + + // DB options: + if (name == 'safe') + dbOptions.safe = (value == 'true'); + // Not supported by Db: safe, w, wtimeoutMS, fsync, journal, connectTimeoutMS, socketTimeoutMS + if (name == 'nativeParser' || name == 'native_parser') + dbOptions.native_parser = (value == 'true'); + if (name == 'strict') + dbOptions.strict = (value == 'true'); + }); + + var servers = hostPart.split(',').map(function(h) { + var hostPort = h.split(':', 2); + return new Server(hostPort[0] || 'localhost', hostPort[1] || 27017, + serverOptions); + }); + + var server; + if (servers.length == 1) { + server = servers[0]; + } else { + server = new ReplSetServers(servers, replSetServersOptions); + } + + var db = new Db(dbname, server, dbOptions); + if (options.noOpen) + return db; + + db.open(function(err, db){ + if(!err && authPart){ + db.authenticate(auth[0], auth[1], function(err, success){ + if(success){ + callback(null, db); + } + else { + callback(err ? err : new Error('Could not authenticate user ' + auth[0]), null); + } + }); + } else { + callback(err, db); + } + }); +} diff --git a/node_modules/mongodb/lib/mongodb/goog/math/long.js b/node_modules/mongodb/lib/mongodb/goog/math/long.js new file mode 100644 index 0000000..faa8e29 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/goog/math/long.js @@ -0,0 +1,791 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2009 Google Inc. All Rights Reserved + +/** + * @fileoverview Defines a exports.Long class for representing a 64-bit two's-complement + * integer value, which faithfully simulates the behavior of a Java "long". This + * implementation is derived from exports.LongLib in GWT. + * + */ + +/** + * Constructs a 64-bit two's-complement integer, given its low and high 32-bit + * values as *signed* integers. See the from* functions below for more + * convenient ways of constructing exports.Longs. + * + * The internal representation of a long is the two given signed, 32-bit values. + * We use 32-bit pieces because these are the size of integers on which + * Javascript performs bit-operations. For operations like addition and + * multiplication, we split each number into 16-bit pieces, which can easily be + * multiplied within Javascript's floating-point representation without overflow + * or change in sign. + * + * In the algorithms below, we frequently reduce the negative case to the + * positive case by negating the input(s) and then post-processing the result. + * Note that we must ALWAYS check specially whether those values are MIN_VALUE + * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as + * a positive number, it overflows back into a negative). Not handling this + * case would often result in infinite recursion. + * + * @param {number} low The low (signed) 32 bits of the long. + * @param {number} high The high (signed) 32 bits of the long. + * @constructor + */ +exports.Long = function(low, high) { + /** + * @type {number} + * @private + */ + this.low_ = low | 0; // force into 32 signed bits. + + /** + * @type {number} + * @private + */ + this.high_ = high | 0; // force into 32 signed bits. +}; + + +// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the +// from* methods on which they depend. + + +/** + * A cache of the exports.Long representations of small integer values. + * @type {Object} + * @private + */ +exports.Long.INT_CACHE_ = {}; + + +/** + * Returns a exports.Long representing the given (32-bit) integer value. + * @param {number} value The 32-bit integer in question. + * @return {exports.Long} The corresponding exports.Long value. + */ +exports.Long.fromInt = function(value) { + if (-128 <= value && value < 128) { + var cachedObj = exports.Long.INT_CACHE_[value]; + if (cachedObj) { + return cachedObj; + } + } + + var obj = new exports.Long(value | 0, value < 0 ? -1 : 0); + if (-128 <= value && value < 128) { + exports.Long.INT_CACHE_[value] = obj; + } + return obj; +}; + + +/** + * Returns a exports.Long representing the given value, provided that it is a finite + * number. Otherwise, zero is returned. + * @param {number} value The number in question. + * @return {exports.Long} The corresponding exports.Long value. + */ +exports.Long.fromNumber = function(value) { + if (isNaN(value) || !isFinite(value)) { + return exports.Long.ZERO; + } else if (value <= -exports.Long.TWO_PWR_63_DBL_) { + return exports.Long.MIN_VALUE; + } else if (value + 1 >= exports.Long.TWO_PWR_63_DBL_) { + return exports.Long.MAX_VALUE; + } else if (value < 0) { + return exports.Long.fromNumber(-value).negate(); + } else { + return new exports.Long( + (value % exports.Long.TWO_PWR_32_DBL_) | 0, + (value / exports.Long.TWO_PWR_32_DBL_) | 0); + } +}; + + +/** + * Returns a exports.Long representing the 64-bit integer that comes by concatenating + * the given high and low bits. Each is assumed to use 32 bits. + * @param {number} lowBits The low 32-bits. + * @param {number} highBits The high 32-bits. + * @return {exports.Long} The corresponding exports.Long value. + */ +exports.Long.fromBits = function(lowBits, highBits) { + return new exports.Long(lowBits, highBits); +}; + + +/** + * Returns a exports.Long representation of the given string, written using the given + * radix. + * @param {string} str The textual representation of the exports.Long. + * @param {number} opt_radix The radix in which the text is written. + * @return {exports.Long} The corresponding exports.Long value. + */ +exports.Long.fromString = function(str, opt_radix) { + if (str.length == 0) { + throw Error('number format error: empty string'); + } + + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (str.charAt(0) == '-') { + return exports.Long.fromString(str.substring(1), radix).negate(); + } else if (str.indexOf('-') >= 0) { + throw Error('number format error: interior "-" character: ' + str); + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = exports.Long.fromNumber(Math.pow(radix, 8)); + + var result = exports.Long.ZERO; + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i); + var value = parseInt(str.substring(i, i + size), radix); + if (size < 8) { + var power = exports.Long.fromNumber(Math.pow(radix, size)); + result = result.multiply(power).add(exports.Long.fromNumber(value)); + } else { + result = result.multiply(radixToPower); + result = result.add(exports.Long.fromNumber(value)); + } + } + return result; +}; + + +// NOTE: the compiler should inline these constant values below and then remove +// these variables, so there should be no runtime penalty for these. + + +/** + * Number used repeated below in calculations. This must appear before the + * first call to any from* function below. + * @type {number} + * @private + */ +exports.Long.TWO_PWR_16_DBL_ = 1 << 16; + +/** + * @type {number} + * @private + */ +exports.Long.TWO_PWR_24_DBL_ = 1 << 24; + +/** + * @type {number} + * @private + */ +exports.Long.TWO_PWR_32_DBL_ = + exports.Long.TWO_PWR_16_DBL_ * exports.Long.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @private + */ +exports.Long.TWO_PWR_31_DBL_ = + exports.Long.TWO_PWR_32_DBL_ / 2; + +/** + * @type {number} + * @private + */ +exports.Long.TWO_PWR_48_DBL_ = + exports.Long.TWO_PWR_32_DBL_ * exports.Long.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @private + */ +exports.Long.TWO_PWR_64_DBL_ = + exports.Long.TWO_PWR_32_DBL_ * exports.Long.TWO_PWR_32_DBL_; + +/** + * @type {number} + * @private + */ +exports.Long.TWO_PWR_63_DBL_ = + exports.Long.TWO_PWR_64_DBL_ / 2; + + +/** @type {exports.Long} */ +exports.Long.ZERO = exports.Long.fromInt(0); + +/** @type {exports.Long} */ +exports.Long.ONE = exports.Long.fromInt(1); + +/** @type {exports.Long} */ +exports.Long.NEG_ONE = exports.Long.fromInt(-1); + +/** @type {exports.Long} */ +exports.Long.MAX_VALUE = + exports.Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); + +/** @type {exports.Long} */ +exports.Long.MIN_VALUE = exports.Long.fromBits(0, 0x80000000 | 0); + + +/** + * @type {exports.Long} + * @private + */ +exports.Long.TWO_PWR_24_ = exports.Long.fromInt(1 << 24); + + +/** @return {number} The value, assuming it is a 32-bit integer. */ +exports.Long.prototype.toInt = function() { + return this.low_; +}; + + +/** @return {number} The closest floating-point representation to this value. */ +exports.Long.prototype.toNumber = function() { + return this.high_ * exports.Long.TWO_PWR_32_DBL_ + + this.getLowBitsUnsigned(); +}; + +/** convert code to JSON **/ +exports.Long.prototype.toJSON = function() { + return this.toString(); +} + +/** + * @param {number} opt_radix The radix in which the text should be written. + * @return {string} The textual representation of this value. + */ +exports.Long.prototype.toString = function(opt_radix) { + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (this.isZero()) { + return '0'; + } + + if (this.isNegative()) { + if (this.equals(exports.Long.MIN_VALUE)) { + // We need to change the exports.Long value before it can be negated, so we remove + // the bottom-most digit in this base and then recurse to do the rest. + var radixLong = exports.Long.fromNumber(radix); + var div = this.div(radixLong); + var rem = div.multiply(radixLong).subtract(this); + return div.toString(radix) + rem.toInt().toString(radix); + } else { + return '-' + this.negate().toString(radix); + } + } + + // Do several (6) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = exports.Long.fromNumber(Math.pow(radix, 6)); + + var rem = this; + var result = ''; + while (true) { + var remDiv = rem.div(radixToPower); + var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); + var digits = intval.toString(radix); + + rem = remDiv; + if (rem.isZero()) { + return digits + result; + } else { + while (digits.length < 6) { + digits = '0' + digits; + } + result = '' + digits + result; + } + } +}; + + +/** @return {number} The high 32-bits as a signed value. */ +exports.Long.prototype.getHighBits = function() { + return this.high_; +}; + + +/** @return {number} The low 32-bits as a signed value. */ +exports.Long.prototype.getLowBits = function() { + return this.low_; +}; + + +/** @return {number} The low 32-bits as an unsigned value. */ +exports.Long.prototype.getLowBitsUnsigned = function() { + return (this.low_ >= 0) ? + this.low_ : exports.Long.TWO_PWR_32_DBL_ + this.low_; +}; + + +/** + * @return {number} Returns the number of bits needed to represent the absolute + * value of this exports.Long. + */ +exports.Long.prototype.getNumBitsAbs = function() { + if (this.isNegative()) { + if (this.equals(exports.Long.MIN_VALUE)) { + return 64; + } else { + return this.negate().getNumBitsAbs(); + } + } else { + var val = this.high_ != 0 ? this.high_ : this.low_; + for (var bit = 31; bit > 0; bit--) { + if ((val & (1 << bit)) != 0) { + break; + } + } + return this.high_ != 0 ? bit + 33 : bit + 1; + } +}; + + +/** @return {boolean} Whether this value is zero. */ +exports.Long.prototype.isZero = function() { + return this.high_ == 0 && this.low_ == 0; +}; + + +/** @return {boolean} Whether this value is negative. */ +exports.Long.prototype.isNegative = function() { + return this.high_ < 0; +}; + + +/** @return {boolean} Whether this value is odd. */ +exports.Long.prototype.isOdd = function() { + return (this.low_ & 1) == 1; +}; + + +/** + * @param {exports.Long} other exports.Long to compare against. + * @return {boolean} Whether this exports.Long equals the other. + */ +exports.Long.prototype.equals = function(other) { + return (this.high_ == other.high_) && (this.low_ == other.low_); +}; + + +/** + * @param {exports.Long} other exports.Long to compare against. + * @return {boolean} Whether this exports.Long does not equal the other. + */ +exports.Long.prototype.notEquals = function(other) { + return (this.high_ != other.high_) || (this.low_ != other.low_); +}; + + +/** + * @param {exports.Long} other exports.Long to compare against. + * @return {boolean} Whether this exports.Long is less than the other. + */ +exports.Long.prototype.lessThan = function(other) { + return this.compare(other) < 0; +}; + + +/** + * @param {exports.Long} other exports.Long to compare against. + * @return {boolean} Whether this exports.Long is less than or equal to the other. + */ +exports.Long.prototype.lessThanOrEqual = function(other) { + return this.compare(other) <= 0; +}; + + +/** + * @param {exports.Long} other exports.Long to compare against. + * @return {boolean} Whether this exports.Long is greater than the other. + */ +exports.Long.prototype.greaterThan = function(other) { + return this.compare(other) > 0; +}; + + +/** + * @param {exports.Long} other exports.Long to compare against. + * @return {boolean} Whether this exports.Long is greater than or equal to the other. + */ +exports.Long.prototype.greaterThanOrEqual = function(other) { + return this.compare(other) >= 0; +}; + + +/** + * Compares this exports.Long with the given one. + * @param {exports.Long} other exports.Long to compare against. + * @return {number} 0 if they are the same, 1 if the this is greater, and -1 + * if the given one is greater. + */ +exports.Long.prototype.compare = function(other) { + if (this.equals(other)) { + return 0; + } + + var thisNeg = this.isNegative(); + var otherNeg = other.isNegative(); + if (thisNeg && !otherNeg) { + return -1; + } + if (!thisNeg && otherNeg) { + return 1; + } + + // at this point, the signs are the same, so subtraction will not overflow + if (this.subtract(other).isNegative()) { + return -1; + } else { + return 1; + } +}; + + +/** @return {exports.Long} The negation of this value. */ +exports.Long.prototype.negate = function() { + if (this.equals(exports.Long.MIN_VALUE)) { + return exports.Long.MIN_VALUE; + } else { + return this.not().add(exports.Long.ONE); + } +}; + + +/** + * Returns the sum of this and the given exports.Long. + * @param {exports.Long} other exports.Long to add to this one. + * @return {exports.Long} The sum of this and the given exports.Long. + */ +exports.Long.prototype.add = function(other) { + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 + b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 + b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 + b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 + b48; + c48 &= 0xFFFF; + return exports.Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + + +/** + * Returns the difference of this and the given exports.Long. + * @param {exports.Long} other exports.Long to subtract from this. + * @return {exports.Long} The difference of this and the given exports.Long. + */ +exports.Long.prototype.subtract = function(other) { + return this.add(other.negate()); +}; + + +/** + * Returns the product of this and the given long. + * @param {exports.Long} other exports.Long to multiply with this. + * @return {exports.Long} The product of this and the other. + */ +exports.Long.prototype.multiply = function(other) { + if (this.isZero()) { + return exports.Long.ZERO; + } else if (other.isZero()) { + return exports.Long.ZERO; + } + + if (this.equals(exports.Long.MIN_VALUE)) { + return other.isOdd() ? exports.Long.MIN_VALUE : exports.Long.ZERO; + } else if (other.equals(exports.Long.MIN_VALUE)) { + return this.isOdd() ? exports.Long.MIN_VALUE : exports.Long.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().multiply(other.negate()); + } else { + return this.negate().multiply(other).negate(); + } + } else if (other.isNegative()) { + return this.multiply(other.negate()).negate(); + } + + // If both longs are small, use float multiplication + if (this.lessThan(exports.Long.TWO_PWR_24_) && + other.lessThan(exports.Long.TWO_PWR_24_)) { + return exports.Long.fromNumber(this.toNumber() * other.toNumber()); + } + + // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. + // We can skip products that would overflow. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 * b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 * b00; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c16 += a00 * b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 * b00; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a16 * b16; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a00 * b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; + c48 &= 0xFFFF; + return exports.Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + + +/** + * Returns this exports.Long divided by the given one. + * @param {exports.Long} other exports.Long by which to divide. + * @return {exports.Long} This exports.Long divided by the given one. + */ +exports.Long.prototype.div = function(other) { + if (other.isZero()) { + throw Error('division by zero'); + } else if (this.isZero()) { + return exports.Long.ZERO; + } + + if (this.equals(exports.Long.MIN_VALUE)) { + if (other.equals(exports.Long.ONE) || + other.equals(exports.Long.NEG_ONE)) { + return exports.Long.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE + } else if (other.equals(exports.Long.MIN_VALUE)) { + return exports.Long.ONE; + } else { + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. + var halfThis = this.shiftRight(1); + var approx = halfThis.div(other).shiftLeft(1); + if (approx.equals(exports.Long.ZERO)) { + return other.isNegative() ? exports.Long.ONE : exports.Long.NEG_ONE; + } else { + var rem = this.subtract(other.multiply(approx)); + var result = approx.add(rem.div(other)); + return result; + } + } + } else if (other.equals(exports.Long.MIN_VALUE)) { + return exports.Long.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().div(other.negate()); + } else { + return this.negate().div(other).negate(); + } + } else if (other.isNegative()) { + return this.div(other.negate()).negate(); + } + + // Repeat the following until the remainder is less than other: find a + // floating-point that approximates remainder / other *from below*, add this + // into the result, and subtract it from the remainder. It is critical that + // the approximate value is less than or equal to the real value so that the + // remainder never becomes negative. + var res = exports.Long.ZERO; + var rem = this; + while (rem.greaterThanOrEqual(other)) { + // Approximate the result of division. This may be a little greater or + // smaller than the actual value. + var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); + + // We will tweak the approximate result by changing it in the 48-th digit or + // the smallest non-fractional digit, whichever is larger. + var log2 = Math.ceil(Math.log(approx) / Math.LN2); + var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); + + // Decrease the approximation until it is smaller than the remainder. Note + // that if it is too large, the product overflows and is negative. + var approxRes = exports.Long.fromNumber(approx); + var approxRem = approxRes.multiply(other); + while (approxRem.isNegative() || approxRem.greaterThan(rem)) { + approx -= delta; + approxRes = exports.Long.fromNumber(approx); + approxRem = approxRes.multiply(other); + } + + // We know the answer can't be zero... and actually, zero would cause + // infinite recursion since we would make no progress. + if (approxRes.isZero()) { + approxRes = exports.Long.ONE; + } + + res = res.add(approxRes); + rem = rem.subtract(approxRem); + } + return res; +}; + + +/** + * Returns this exports.Long modulo the given one. + * @param {exports.Long} other exports.Long by which to mod. + * @return {exports.Long} This exports.Long modulo the given one. + */ +exports.Long.prototype.modulo = function(other) { + return this.subtract(this.div(other).multiply(other)); +}; + + +/** @return {exports.Long} The bitwise-NOT of this value. */ +exports.Long.prototype.not = function() { + return exports.Long.fromBits(~this.low_, ~this.high_); +}; + + +/** + * Returns the bitwise-AND of this exports.Long and the given one. + * @param {exports.Long} other The exports.Long with which to AND. + * @return {exports.Long} The bitwise-AND of this and the other. + */ +exports.Long.prototype.and = function(other) { + return exports.Long.fromBits(this.low_ & other.low_, + this.high_ & other.high_); +}; + + +/** + * Returns the bitwise-OR of this exports.Long and the given one. + * @param {exports.Long} other The exports.Long with which to OR. + * @return {exports.Long} The bitwise-OR of this and the other. + */ +exports.Long.prototype.or = function(other) { + return exports.Long.fromBits(this.low_ | other.low_, + this.high_ | other.high_); +}; + + +/** + * Returns the bitwise-XOR of this exports.Long and the given one. + * @param {exports.Long} other The exports.Long with which to XOR. + * @return {exports.Long} The bitwise-XOR of this and the other. + */ +exports.Long.prototype.xor = function(other) { + return exports.Long.fromBits(this.low_ ^ other.low_, + this.high_ ^ other.high_); +}; + + +/** + * Returns this exports.Long with bits shifted to the left by the given amount. + * @param {number} numBits The number of bits by which to shift. + * @return {exports.Long} This shifted to the left by the given amount. + */ +exports.Long.prototype.shiftLeft = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var low = this.low_; + if (numBits < 32) { + var high = this.high_; + return exports.Long.fromBits( + low << numBits, + (high << numBits) | (low >>> (32 - numBits))); + } else { + return exports.Long.fromBits(0, low << (numBits - 32)); + } + } +}; + + +/** + * Returns this exports.Long with bits shifted to the right by the given amount. + * @param {number} numBits The number of bits by which to shift. + * @return {exports.Long} This shifted to the right by the given amount. + */ +exports.Long.prototype.shiftRight = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return exports.Long.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >> numBits); + } else { + return exports.Long.fromBits( + high >> (numBits - 32), + high >= 0 ? 0 : -1); + } + } +}; + + +/** + * Returns this exports.Long with bits shifted to the right by the given amount, with + * the new top bits matching the current sign bit. + * @param {number} numBits The number of bits by which to shift. + * @return {exports.Long} This shifted to the right by the given amount, with + * zeros placed into the new leading bits. + */ +exports.Long.prototype.shiftRightUnsigned = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return exports.Long.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >>> numBits); + } else if (numBits == 32) { + return exports.Long.fromBits(high, 0); + } else { + return exports.Long.fromBits(high >>> (numBits - 32), 0); + } + } +}; \ No newline at end of file diff --git a/node_modules/mongodb/lib/mongodb/gridfs/chunk.js b/node_modules/mongodb/lib/mongodb/gridfs/chunk.js new file mode 100644 index 0000000..9050b2e --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/gridfs/chunk.js @@ -0,0 +1,202 @@ +var BinaryParser = require('../bson/binary_parser').BinaryParser, + sys = require('util'), + debug = require('util').debug, + inspect = require('util').inspect; + +/** + * Class for representing a signle chunk in GridFS. + * + * @class + * + * @param file {GridStore} The {@link GridStore} object holding this chunk. + * @param mongoObject {object} The mongo object representation of this chunk. + * + * @throws Error when the type of data field for {@link mongoObject} is not + * supported. Currently supported types for data field are instances of + * {@link String}, {@link Array}, {@link Binary} and {@link Binary} + * from the bson module + * + * @see Chunk#buildMongoObject + */ +var Chunk = exports.Chunk = function(file, mongoObject) { + this.file = file; + var mongoObjectFinal = mongoObject == null ? {} : mongoObject; + + this.objectId = mongoObjectFinal._id == null ? new file.db.bson_serializer.ObjectID() : mongoObjectFinal._id; + this.chunkNumber = mongoObjectFinal.n == null ? 0 : mongoObjectFinal.n; + this.data = new file.db.bson_serializer.Binary(); + + if(mongoObjectFinal.data == null) { + } else if(mongoObjectFinal.data.constructor == String) { + var buffer = new Buffer(mongoObjectFinal.data.length); + buffer.write(mongoObjectFinal.data, 'binary', 0); + this.data = new file.db.bson_serializer.Binary(buffer); + } else if(mongoObjectFinal.data.constructor == Array) { + var buffer = new Buffer(mongoObjectFinal.data.length); + buffer.write(mongoObjectFinal.data.join(''), 'binary', 0); + this.data = new file.db.bson_serializer.Binary(buffer); + } else if(mongoObjectFinal.data instanceof file.db.bson_serializer.Binary || Object.prototype.toString.call(mongoObjectFinal.data) == "[object Binary]") { + this.data = mongoObjectFinal.data; + } else if(mongoObjectFinal.data instanceof Buffer) { + } else { + throw Error("Illegal chunk format"); + } + // Update position + this.internalPosition = 0; + /** + * The position of the read/write head + * @name position + * @lends Chunk# + * @field + */ + this.__defineGetter__("position", function() { return this.internalPosition; }); + this.__defineSetter__("position", function(value) { this.internalPosition = value; }); +}; + +/** + * Writes a data to this object and advance the read/write head. + * + * @param data {string} the data to write + * @param callback {function(*, GridStore)} This will be called after executing + * this method. The first parameter will contain null and the second one + * will contain a reference to this object. + */ +Chunk.prototype.write = function(data, callback) { + this.data.write(data, this.internalPosition); + this.internalPosition = this.data.length(); + callback(null, this); +}; + +/** + * Reads data and advances the read/write head. + * + * @param length {number} The length of data to read. + * + * @return {string} The data read if the given length will not exceed the end of + * the chunk. Returns an empty String otherwise. + */ +Chunk.prototype.read = function(length) { + // Default to full read if no index defined + length = length == null || length == 0 ? this.length() : length; + + if(this.length() - this.internalPosition + 1 >= length) { + var data = this.data.read(this.internalPosition, length); + this.internalPosition = this.internalPosition + length; + return data; + } else { + return ''; + } +}; + +Chunk.prototype.readSlice = function(length) { + if ((this.length() - this.internalPosition + 1) >= length) { + var data = null; + if (this.data.buffer != null) { //Pure BSON + data = this.data.buffer.slice(this.internalPosition, this.internalPosition + length); + } else { //Native BSON + data = new Buffer(length); + //length = data.write(this.data.read(this.internalPosition, length), 'binary', 0); + length = this.data.readInto(data, this.internalPosition); + } + this.internalPosition = this.internalPosition + length; + return data; + } else { + return null; + } +}; + +/** + * Checks if the read/write head is at the end. + * + * @return {boolean} Whether the read/write head has reached the end of this + * chunk. + */ +Chunk.prototype.eof = function() { + return this.internalPosition == this.length() ? true : false; +}; + +/** + * Reads one character from the data of this chunk and advances the read/write + * head. + * + * @return {string} a single character data read if the the read/write head is + * not at the end of the chunk. Returns an empty String otherwise. + */ +Chunk.prototype.getc = function() { + return this.read(1); +}; + +/** + * Clears the contents of the data in this chunk and resets the read/write head + * to the initial position. + */ +Chunk.prototype.rewind = function() { + this.internalPosition = 0; + this.data = new this.file.db.bson_serializer.Binary(); +}; + +/** + * Saves this chunk to the database. Also overwrites existing entries having the + * same id as this chunk. + * + * @param callback {function(*, GridStore)} This will be called after executing + * this method. The first parameter will contain null and the second one + * will contain a reference to this object. + */ +Chunk.prototype.save = function(callback) { + var self = this; + + self.file.chunkCollection(function(err, collection) { + collection.remove({'_id':self.objectId}, {safe:true}, function(err, result) { + if(self.data.length() > 0) { + self.buildMongoObject(function(mongoObject) { + + collection.insert(mongoObject, {safe:true}, function(err, collection) { + callback(null, self); + }); + }); + } else { + callback(null, self); + } + }); + }); +}; + +/** + * Creates a mongoDB object representation of this chunk. + * + * @param callback {function(Object)} This will be called after executing this + * method. The object will be passed to the first parameter and will have + * the structure: + * + *
    
    + *        {
    + *          '_id' : , // {number} id for this chunk
    + *          'files_id' : , // {number} foreign key to the file collection
    + *          'n' : , // {number} chunk number
    + *          'data' : , // {bson#Binary} the chunk data itself
    + *        }
    + *        
    + * + * @see MongoDB GridFS Chunk Object Structure + */ +Chunk.prototype.buildMongoObject = function(callback) { + var mongoObject = {'_id': this.objectId, + 'files_id': this.file.fileId, + 'n': this.chunkNumber, + 'data': this.data}; + callback(mongoObject); +}; + +/** + * @return {number} the length of the data + */ +Chunk.prototype.length = function() { + return this.data.length(); +}; + +/** + * The default chunk size + * @constant + */ +Chunk.DEFAULT_CHUNK_SIZE = 1024 * 256; diff --git a/node_modules/mongodb/lib/mongodb/gridfs/grid.js b/node_modules/mongodb/lib/mongodb/gridfs/grid.js new file mode 100644 index 0000000..a4dd089 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/gridfs/grid.js @@ -0,0 +1,96 @@ +var GridStore = require('./gridstore').GridStore, + debug = require('util').debug, + inspect = require('util').inspect; + +/** + * Simple Grid interface + * + */ +var Grid = exports.Grid = function(db, fsName) { + this.db = db; + this.fsName = fsName == null ? GridStore.DEFAULT_ROOT_COLLECTION : fsName; +} + +/** + * Puts binary data to the grid + * + * @param data Buffer with Binary Data + * @param options {object=} opt_argument The options for the files. + * @callback {function(?Error, GridStore)} This will be called after this method + * is executed. The first parameter will contain an Error object if an error + * occured or null otherwise. The second parameter will contain a reference + * to this object. + * + */ +Grid.prototype.put = function(data, options, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() : {}; + // If root is not defined add our default one + options['root'] = options['root'] == null ? this.fsName : options['root']; + + // Return if we don't have a buffer object as data + if(!(data instanceof Buffer)) return callback(new Error("Data object must be a buffer object"), null); + // Get filename if we are using it + var filename = options['filename']; + // Create gridstore + var gridStore = new GridStore(this.db, filename, "w", options); + gridStore.open(function(err, gridStore) { + if(err) return callback(err, null); + + gridStore.writeBuffer(data, function(err, result) { + if(err) return callback(err, null); + + gridStore.close(function(err, result) { + if(err) return callback(err, null); + callback(null, result); + }) + }) + }) +} + +/** + * Get binary data to the grid + * + * @param id ObjectID for file + * @callback {function(?Error, GridStore)} This will be called after this method + * is executed. The first parameter will contain an Error object if an error + * occured or null otherwise. The second parameter will contain a reference + * to this object. + * + */ +Grid.prototype.get = function(id, callback) { + // Validate that we have a valid ObjectId + if(!(id instanceof this.db.bson_serializer.ObjectID)) return callback(new Error("Not a valid ObjectID", null)); + // Create gridstore + var gridStore = new GridStore(this.db, id, "r", {root:this.fsName}); + gridStore.open(function(err, gridStore) { + if(err) return callback(err, null); + + // Return the data + gridStore.readBuffer(function(err, data) { + return callback(err, data) + }); + }) +} + +/** + * Delete file from grid + * + * @param id ObjectID for file + * @callback {function(?Error, GridStore)} This will be called after this method + * is executed. The first parameter will contain an Error object if an error + * occured or null otherwise. The second parameter will contain a reference + * to this object. + * + */ +Grid.prototype.delete = function(id, callback) { + // Validate that we have a valid ObjectId + if(!(id instanceof this.db.bson_serializer.ObjectID)) return callback(new Error("Not a valid ObjectID", null)); + // Create gridstore + GridStore.unlink(this.db, id, {root:this.fsName}, function(err, result) { + if(err) return callback(err, false); + return callback(null, true); + }); +} diff --git a/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js b/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js new file mode 100644 index 0000000..df2d378 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js @@ -0,0 +1,1240 @@ +/** + * @fileOverview GridFS is a tool for MongoDB to store files to the database. + * Because of the restrictions of the object size the database can hold, a + * facility to split a file into several chunks is needed. The {@link GridStore} + * class offers a simplified api to interact with files while managing the + * chunks of split files behind the scenes. More information about GridFS can be + * found here. + */ + +var BinaryParser = require('../bson/binary_parser').BinaryParser, + Chunk = require('./chunk').Chunk, + DbCommand = require('../commands/db_command').DbCommand, + Buffer = require('buffer').Buffer, + fs = require('fs'), + util = require('util'), + debug = require('util').debug, + inspect = require('util').inspect, + Stream = require('stream').Stream; + +var REFERENCE_BY_FILENAME = 0, + REFERENCE_BY_ID = 1; + +/** + * A class representation of a file stored in GridFS. + * + * @class + * + * @param db {Db} A database instance to interact with. + * @param filename {string} The name for the file. + * @param mode {?string} Set the mode for this file. Available modes: + *
      + *
    • "r" - read only. This is the default mode.
    • + *
    • "w" - write in truncate mode. Existing data will be overwriten
    • + *
    • "w+" - write in edit mode.
    • + *
    + + * @param options {?object} Optional properties to specify. Recognized keys: + * + *
    
    + *     {
    + *       'root' : , // {string} root collection to use. Defaults to GridStore#DEFAULT_ROOT_COLLECTION
    + *       'chunk_type' : , // {string} mime type of the file. Defaults to GridStore#DEFAULT_CONTENT_TYPE
    + *       'chunk_size' : , // {number} size for the chunk. Defaults to Chunk#DEFAULT_CHUNK_SIZE.
    + *       'metadata' : , // {object} arbitrary data the user wants to store
    + *     }
    + *     
    + * + * @see MongoDB GridFS Specification + */ +var GridStore = exports.GridStore = function(db, fileIdObject, mode, options) { + this.db = db; + + // set grid referencetype + this.referenceBy = typeof fileIdObject == 'string' ? 0 : 1; + this.filename = fileIdObject; + this.fileId = fileIdObject; + + // Set up the rest + this.mode = mode == null ? "r" : mode; + this.options = options == null ? {} : options; + this.root = this.options['root'] == null ? exports.GridStore.DEFAULT_ROOT_COLLECTION : this.options['root']; + this.position = 0; + // Set default chunk size + this.internalChunkSize = Chunk.DEFAULT_CHUNK_SIZE; + + /** + * The chunk size used by this file. + * + * @name chunkSize + * @lends GridStore + * @field + */ + this.__defineGetter__("chunkSize", function() { + return this.internalChunkSize; }); + this.__defineSetter__("chunkSize", function(value) { + if(!(this.mode[0] == "w" && this.position == 0 && this.uploadDate == null)) { + this.internalChunkSize = this.internalChunkSize; + } else { + this.internalChunkSize = value; + } + }); + + /** + * The md5 checksum for this file. + * + * @name md5 + * @lends GridStore + * @field + */ + this.__defineGetter__("md5", function() { return this.internalMd5; }); + this.__defineSetter__("md5", function(value) {}); +}; + +/** + * Opens the file from the database and initialize this object. Also creates a + * new one if file does not exist. + * + * @param callback {function(?Error, ?GridStore)} This will be called after + * executing this method. The first parameter will contain an {@link Error} + * object and the second parameter will be null if an error occured. + * Otherwise, the first parameter will be null and the second will contain + * the reference to this object. + */ +GridStore.prototype.open = function(callback) { + var self = this; + + if((self.mode == "w" || self.mode == "w+") && self.db.serverConfig.primary != null) { + // Get files collection + self.collection(function(err, collection) { + // Ensure index on files Collection + collection.ensureIndex([['filename', 1], ['uploadDate', -1]], function(err, index) { + + // Get chunk collection + self.chunkCollection(function(err, chunkCollection) { + // Ensure index on chunk collection + chunkCollection.ensureIndex([['files_id', 1], ['n', 1]], function(err, index) { + self._open(callback); + }); + }); + }); + }); + } else { + self._open(callback); + } +} + +GridStore.prototype._open = function(callback) { + var self = this; + + self.collection(function(err, collection) { + if(err!==null) { + callback(new Error("at collection: "+err), null); + return; + } + + // Create the query + var query = self.referenceBy == REFERENCE_BY_ID ? {_id:self.fileId} : {filename:self.filename}; + query = self.fileId == null && this.filename == null ? null : query; + + // Fetch the chunks + self.chunkCollection(function(err, chunkCollection) { + if(query != null) { + collection.find(query, function(err, cursor) { + // Fetch the file + cursor.nextObject(function(err, doc) { + // Chek if the collection for the files exists otherwise prepare the new one + if(doc != null) { + self.fileId = doc._id; + self.contentType = doc.contentType; + self.internalChunkSize = doc.chunkSize; + self.uploadDate = doc.uploadDate; + self.aliases = doc.aliases; + self.length = doc.length; + self.metadata = doc.metadata; + self.internalMd5 = doc.md5; + } else { + self.fileId = self.fileId instanceof self.db.bson_serializer.ObjectID ? self.fileId : new self.db.bson_serializer.ObjectID(); + self.contentType = exports.GridStore.DEFAULT_CONTENT_TYPE; + self.internalChunkSize = self.internalChunkSize == null ? Chunk.DEFAULT_CHUNK_SIZE : self.internalChunkSize; + self.length = 0; + } + + // Process the mode of the object + if(self.mode == "r") { + self.nthChunk(0, function(err, chunk) { + self.currentChunk = chunk; + self.position = 0; + callback(null, self); + }); + } else if(self.mode == "w") { + self.chunkCollection(function(err, collection2) { + // Delete any existing chunks + self.deleteChunks(function(err, result) { + self.currentChunk = new Chunk(self, {'n':0}); + self.contentType = self.options['content_type'] == null ? self.contentType : self.options['content_type']; + self.internalChunkSize = self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size']; + self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata']; + self.position = 0; + callback(null, self); + }); + }); + } else if(self.mode == "w+") { + self.chunkCollection(function(err, collection) { + self.nthChunk(self.lastChunkNumber(), function(err, chunk) { + // Set the current chunk + self.currentChunk = chunk == null ? new Chunk(self, {'n':0}) : chunk; + self.currentChunk.position = self.currentChunk.data.length(); + self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata']; + self.position = self.length; + callback(null, self); + }); + }); + } else { + callback(new Error("Illegal mode " + self.mode), null); + } + }); + }); + } else { + // Write only mode + self.fileId = new self.db.bson_serializer.ObjectID(); + self.contentType = exports.GridStore.DEFAULT_CONTENT_TYPE; + self.internalChunkSize = self.internalChunkSize == null ? Chunk.DEFAULT_CHUNK_SIZE : self.internalChunkSize; + self.length = 0; + + // No file exists set up write mode + if(self.mode == "w") { + self.chunkCollection(function(err, collection2) { + // Delete any existing chunks + self.deleteChunks(function(err, result) { + self.currentChunk = new Chunk(self, {'n':0}); + self.contentType = self.options['content_type'] == null ? self.contentType : self.options['content_type']; + self.internalChunkSize = self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size']; + self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata']; + self.position = 0; + callback(null, self); + }); + }); + } else if(self.mode == "w+") { + self.chunkCollection(function(err, collection) { + self.nthChunk(self.lastChunkNumber(), function(err, chunk) { + // Set the current chunk + self.currentChunk = chunk == null ? new Chunk(self, {'n':0}) : chunk; + self.currentChunk.position = self.currentChunk.data.length(); + self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata']; + self.position = self.length; + callback(null, self); + }); + }); + } else { + callback(new Error("Illegal mode " + self.mode), null); + } + } + }); + }); +}; + +/** + * Stores a file from the file system to the GridFS database. + * + * @param file {string|fd} The file to store. + * @param callback {function(*, GridStore)} This will be called after this + * method is executed. The first parameter will be null and the the + * second will contain the reference to this object. + * + * @see GridStore#write + */ +GridStore.prototype.writeFile = function (file, callback) { + var self = this; + if (typeof file === 'string') { + fs.open(file, 'r', 0666, function (err, fd) { + // TODO Handle err + self.writeFile(fd, callback); + }); + return; + } + + self.open(function (err, self) { + fs.fstat(file, function (err, stats) { + var offset = 0; + var index = 0; + var numberOfChunksLeft = Math.min(stats.size / self.chunkSize); + + // Write a chunk + var writeChunk = function() { + fs.read(file, self.chunkSize, offset, 'binary', function(err, data, bytesRead) { + offset = offset + bytesRead; + // Create a new chunk for the data + var chunk = new Chunk(self, {n:index++}); + chunk.write(data, function(err, chunk) { + chunk.save(function(err, result) { + // Point to current chunk + self.currentChunk = chunk; + + if(offset >= stats.size) { + fs.close(file); + self.close(function(err, result) { + return callback(null, result); + }) + } else { + return process.nextTick(writeChunk); + } + }); + }); + }); + } + + // Process the first write + process.nextTick(writeChunk); + }); + }); + +}; + +/** + * Writes some data. This method will work properly only if initialized with mode + * "w" or "w+". + * + * @param string {string} The data to write. + * @param close {boolean=false} opt_argument Closes this file after writing if + * true. + * @param callback {function(*, GridStore)} This will be called after executing + * this method. The first parameter will contain null and the second one + * will contain a reference to this object. + * + * @see GridStore#writeFile + */ +GridStore.prototype.write = function(string, close, callback) { + if(typeof close === "function") { callback = close; close = null; } + var self = this; + var finalClose = close == null ? false : close; + // Check if we are trying to write a buffer and use the right method + if(string instanceof Buffer) return this.writeBuffer(string, close, callback); + // Otherwise let's write the data + if(self.mode[0] != "w") { + callback(new Error((self.referenceBy == REFERENCE_BY_ID ? self.toHexString() : self.filename) + " not opened for writing"), null); + } else { + if((self.currentChunk.position + string.length) > self.chunkSize) { + var previousChunkNumber = self.currentChunk.chunkNumber; + var leftOverDataSize = self.chunkSize - self.currentChunk.position; + var previousChunkData = string.substr(0, leftOverDataSize); + var leftOverData = string.substr(leftOverDataSize, (string.length - leftOverDataSize)); + // Let's finish the current chunk and then call write again for the remaining data + self.currentChunk.write(previousChunkData, function(err, chunk) { + chunk.save(function(err, result) { + self.currentChunk = new Chunk(self, {'n': (previousChunkNumber + 1)}); + self.position = self.position + leftOverDataSize; + // Write the remaining data + self.write(leftOverData, function(err, gridStore) { + if(finalClose) { + self.close(function(err, result) { + callback(null, gridStore); + }); + } else { + callback(null, gridStore); + } + }); + }); + }); + } else { + self.currentChunk.write(string, function(err, chunk) { + self.position = self.position + string.length; + if(finalClose) { + self.close(function(err, result) { + callback(null, self); + }); + } else { + callback(null, self); + } + }); + } + } +}; + +GridStore.prototype.writeBuffer = function(buffer, close, callback) { + if(typeof close === "function") { callback = close; close = null; } + var self = this; + var finalClose = (close == null) ? false : close; + + if(self.mode[0] != "w") { + callback(new Error((self.referenceBy == REFERENCE_BY_ID ? self.toHexString() : self.filename) + " not opened for writing"), null); + } + else { + if((self.currentChunk.position + buffer.length) > self.chunkSize) { + // Data exceeds current chunk remaining free size; fill up current chunk and write the rest + // to a new chunk (recursively) + var previousChunkNumber = self.currentChunk.chunkNumber; + var leftOverDataSize = self.chunkSize - self.currentChunk.position; + var firstChunkData = buffer.slice(0, leftOverDataSize); + + var leftOverData = buffer.slice(leftOverDataSize); + + // Let's finish the current chunk and then call write again for the remaining data + self.currentChunk.write(firstChunkData, function(err, chunk) { + chunk.save(function(err, result) { + self.currentChunk = new Chunk(self, {'n': (previousChunkNumber + 1)}); + self.position = self.position + leftOverDataSize; + + // Write the remaining data + self.writeBuffer(leftOverData, function(err, gridStore) { + if(finalClose) { + self.close(function(err, result) { + callback(null, gridStore); + }); + } + else { + callback(null, gridStore); + } + }); + }); + }); + } + else { + // Write buffer to chunk all at once + self.currentChunk.write(buffer, function(err, chunk) { + self.position = self.position + buffer.length; + if(finalClose) { + self.close(function(err, result) { + callback(null, self); + }); + } + else { + callback(null, self); + } + }); + } + } +}; + +/** + * Creates a mongoDB object representation of this object. + * + * @param callback {function(object)} This will be called after executing this + * method. The object will be passed to the first parameter and will have + * the structure: + * + *
    
    + *        {
    + *          '_id' : , // {number} id for this file
    + *          'filename' : , // {string} name for this file
    + *          'contentType' : , // {string} mime type for this file
    + *          'length' : , // {number} size of this file?
    + *          'chunksize' : , // {number} chunk size used by this file
    + *          'uploadDate' : , // {Date}
    + *          'aliases' : , // {array of string}
    + *          'metadata' : , // {string}
    + *        }
    + *        
    + * + * @see MongoDB GridFS File Object Structure + */ +GridStore.prototype.buildMongoObject = function(callback) { + var length = this.currentChunk != null ? (this.currentChunk.chunkNumber * this.chunkSize + this.currentChunk.position) : 0; + var mongoObject = { + '_id': this.fileId, + 'filename': this.filename, + 'contentType': this.contentType, + 'length': length < 0 ? 0 : length, + 'chunkSize': this.chunkSize, + 'uploadDate': this.uploadDate, + 'aliases': this.aliases, + 'metadata': this.metadata + }; + + var md5Command = {filemd5:this.fileId, root:this.root}; + this.db.command(md5Command, function(err, results) { + mongoObject.md5 = results.md5; + callback(mongoObject); + }); +}; + +/** + * Saves this file to the database. This will overwrite the old entry if it + * already exists. This will work properly only if mode was initialized to + * "w" or "w+". + * + * @param callback {function(?Error, GridStore)} This will be called after + * executing this method. Passes an {@link Error} object to the first + * parameter and null to the second if an error occured. Otherwise, passes + * null to the first and a reference to this object to the second. + */ +GridStore.prototype.close = function(callback) { + var self = this; + + if(self.mode[0] == "w") { + if(self.currentChunk != null && self.currentChunk.position > 0) { + self.currentChunk.save(function(err, chuck) { + self.collection(function(err, files) { + // Build the mongo object + if(self.uploadDate != null) { + files.remove({'_id':self.fileId}, {safe:true}, function(err, collection) { + self.buildMongoObject(function(mongoObject) { + files.save(mongoObject, {safe:true}, function(err, doc) { + callback(err, mongoObject); + }); + }); + }); + } else { + self.uploadDate = new Date(); + self.buildMongoObject(function(mongoObject) { + files.save(mongoObject, {safe:true}, function(err, doc) { + callback(err, mongoObject); + }); + }); + } + }); + }); + } else { + self.collection(function(err, files) { + self.uploadDate = new Date(); + self.buildMongoObject(function(mongoObject) { + files.save(mongoObject, {safe:true}, function(err, doc) { + callback(err, mongoObject); + }); + }); + }); + } + } else if(self.mode[0] == "r") { + callback(null, null); + } else { + callback(new Error("Illegal mode " + self.mode), null); + } +}; + +/** + * Gets the nth chunk of this file. + * + * @param chunkNumber {number} The nth chunk to retrieve. + * @param callback {function(*, Chunk|object)} This will be called after + * executing this method. null will be passed to the first parameter while + * a new {@link Chunk} instance will be passed to the second parameter if + * the chunk was found or an empty object {} if not. + * + * @see GridStore#lastChunkNumber + */ +GridStore.prototype.nthChunk = function(chunkNumber, callback) { + var self = this; + + self.chunkCollection(function(err, collection) { + collection.find({'files_id':self.fileId, 'n':chunkNumber}, function(err, cursor) { + cursor.nextObject(function(err, chunk) { + var finalChunk = chunk == null ? {} : chunk; + callback(null, new Chunk(self, finalChunk)); + }); + }); + }); +}; + +/** + * @return {number} The last chunk number of this file. + * + * @see GridStore#nthChunk + */ +GridStore.prototype.lastChunkNumber = function() { + return Math.floor(this.length/this.chunkSize); +}; + +/** + * Retrieve this file's chunks collection. + * + * @param callback {function(?Error, ?Collection)} This will be called after + * executing this method. An exception object will be passed to the first + * parameter when an error occured or null otherwise. A new + * {@link Collection} object will be passed to the second parameter if no + * error occured. + * + * @see Db#collection + * @see GridStore#collection + */ +GridStore.prototype.chunkCollection = function(callback) { + this.db.collection((this.root + ".chunks"), callback); +}; + +/** + * Deletes all the chunks of this file in the database. + * + * @param callback {function(*, boolean)} This will be called after this method + * executes. Passes null to the first and true to the second argument. + * + * @see GridStore#rewind + */ +GridStore.prototype.deleteChunks = function(callback) { + var self = this; + + if(self.fileId != null) { + self.chunkCollection(function(err, collection) { + if(err!==null) { + callback(err, false); + } + collection.remove({'files_id':self.fileId}, {safe:true}, function(err, result) { + callback(null, true); + }); + }); + } else { + callback(null, true); + } +}; + +GridStore.prototype.unlink = function(callback) { + var self = this; + this.deleteChunks(function(err) { + if(err!==null) { + callback("at deleteChunks: "+err); + return; + } + + self.collection(function(err, collection) { + if(err!==null) { + callback("at collection: "+err); + return; + } + + collection.remove({'_id':self.fileId}, {safe:true}, function(err, collection) { + callback(err, self); + }); + }); + }); +}; + +/** + * Retrieves the file collection associated with this object. + * + * @param callback {function(?Error, ?Collection)} This will be called after + * executing this method. An exception object will be passed to the first + * parameter when an error occured or null otherwise. A new + * {@link Collection} object will be passed to the second parameter if no + * error occured. + * + * @see Db#collection + * @see GridStore#chunkCollection + */ +GridStore.prototype.collection = function(callback) { + this.db.collection(this.root + ".files", function(err, collection) { + callback(err, collection); + }); +}; + +/** + * Reads the data of this file. + * + * @param separator {string=null} opt_argument The character to be recognized as + * the newline separator. + * @param callback {function(*, Array)} This will be called after this + * method is executed. The first parameter will be null and the second + * parameter will contain an array of strings representing the entire data, + * each element representing a line including the separator character. + * + * @see GridStore#read + * @see GridStore#eof + */ +GridStore.prototype.readlines = function(separator, callback) { + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + separator = args.length ? args.shift() : null; + + this.read(function(err, data) { + var items = data.split(separator); + items = items.length > 0 ? items.splice(0, items.length - 1) : []; + for(var i = 0; i < items.length; i++) { + items[i] = items[i] + separator; + } + callback(null, items); + }); +}; + +/** + * Deletes all the chunks of this file in the database if mode was set to "w" or + * "w+" and resets the read/write head to the initial position. + * + * @param callback {function(*, GridStore)} This will be called after executing + * this method. The first parameter will contain null and the second one + * will contain a reference to this object. + * + * @see GridStore#deleteChunks + */ +GridStore.prototype.rewind = function(callback) { + var self = this; + + if(this.currentChunk.chunkNumber != 0) { + if(this.mode[0] == "w") { + self.deleteChunks(function(err, gridStore) { + self.currentChunk = new Chunk(self, {'n': 0}); + self.position = 0; + callback(null, self); + }); + } else { + self.currentChunk(0, function(err, chunk) { + self.currentChunk = chunk; + self.currentChunk.rewind(); + self.position = 0; + callback(null, self); + }); + } + } else { + self.currentChunk.rewind(); + self.position = 0; + callback(null, self); + } +}; + +/** + * Retrieves the contents of this file and advances the read/write head. + * + * There are 3 signatures for this method: + * + * (callback) + * (length, callback) + * (length, buffer, callback) + * + * @param length {number=} opt_argument The number of characters to read. Reads + * all the characters from the read/write head to the EOF if not specified. + * @param buffer {string=''} opt_argument A string to hold temporary data. This + * is used for storing the string data read so far when recursively calling + * this method. + * @param callback {function(*, string)} This will be called after this method + * is executed. null will be passed to the first parameter and a string + * containing the contents of the buffer concatenated with the contents read + * from this file will be passed to the second. + * + * @see GridStore#readlines + * @see GridStore#eof + */ +GridStore.prototype.read = function(length, buffer, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + length = args.length ? args.shift() : null; + buffer = args.length ? args.shift() : null; + + // The data is a c-terminated string and thus the length - 1 + var finalBuffer = buffer == null ? '' : buffer; + var finalLength = length == null ? self.length - self.position : length; + + // debug("===================================================================== read") + // debug(inspect(self.length)) + // debug(inspect(self.position)) + // debug(finalLength) + + if((self.currentChunk.length() - self.currentChunk.position + 1 + finalBuffer.length) >= finalLength) { + // debug("---------------------------- finalLength :: " + finalLength) + finalBuffer = finalBuffer + self.currentChunk.read(finalLength - finalBuffer.length); + + // debug("---------------------------- finalLength :: " + finalBuffer.length) + + self.position = finalBuffer.length; + callback(null, finalBuffer); + } else { + finalBuffer = finalBuffer + self.currentChunk.read(self.currentChunk.length()); + // Load the next chunk and read some more + self.nthChunk(self.currentChunk.chunkNumber + 1, function(err, chunk) { + self.currentChunk = chunk; + self.read(length, finalBuffer, callback); + }); + } +}; + +GridStore.prototype.readBuffer = function(length, buffer, callback) { + var self = this; + + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + length = args.length ? args.shift() : null; + buffer = args.length ? args.shift() : null; + + // The data is a c-terminated string and thus the length - 1 + var finalLength = length == null ? self.length - self.position : length; + var finalBuffer = buffer == null ? new Buffer(finalLength) : buffer; + // Add a index to buffer to keep track of writing position or apply current index + finalBuffer._index = buffer != null && buffer._index != null ? buffer._index : 0; + + if((self.currentChunk.length() - self.currentChunk.position + 1 + finalBuffer._index) >= finalLength) { + var slice = self.currentChunk.readSlice(finalLength - finalBuffer._index); + // Copy content to final buffer + slice.copy(finalBuffer, finalBuffer._index); + // Update internal position + self.position = finalBuffer.length; + // Check if we don't have a file at all + if(finalLength == 0 && finalBuffer.length == 0) return callback(new Error("File does not exist"), null); + // Else return data + callback(null, finalBuffer); + } else { + var slice = self.currentChunk.readSlice(self.currentChunk.length()); + // Copy content to final buffer + slice.copy(finalBuffer, finalBuffer._index); + // Update index position + finalBuffer._index += slice.length; + + // Load next chunk and read more + self.nthChunk(self.currentChunk.chunkNumber + 1, function(err, chunk) { + self.currentChunk = chunk; + self.readBuffer(length, finalBuffer, callback); + }); + } +} + +/** + * Retrieves the position of the read/write head of this file. + * + * @param callback {function(*, number)} This gets called after this method + * terminates. null is passed to the first parameter and the position is + * passed to the second. + * + * @see GridStore#seek + */ +GridStore.prototype.tell = function(callback) { + callback(null, this.position); +}; + +/** + * Moves the read/write head to a new location. + * + * There are 3 signatures for this method: + * + * (callback) + * (position, callback) + * (position, seekLocation, callback) + * + * @param position + * @param seekLocation {number} Seek mode. Use one of the ff constants - + * {@link GridStore#IO_SEEK_SET}, {@link GridStore#IO_SEEK_CUR} or + * {@link GridStore#IO_SEEK_END}. Defaults to {@link GridStore#IO_SEEK_SET} + * when not specified. + * @param callback {function(*, GridStore)} This will be called after executing + * this method. The first parameter will contain null and the second one + * will contain a reference to this object. + * + * @see GridStore#IO_SEEK_SET + * @see GridStore#IO_SEEK_CUR + * @see GridStore#IO_SEEK_END + */ +GridStore.prototype.seek = function(position, seekLocation, callback) { + var self = this; + + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + seekLocation = args.length ? args.shift() : null; + + var seekLocationFinal = seekLocation == null ? exports.GridStore.IO_SEEK_SET : seekLocation; + var finalPosition = position; + var targetPosition = 0; + if(seekLocationFinal == exports.GridStore.IO_SEEK_CUR) { + targetPosition = self.position + finalPosition; + } else if(seekLocationFinal == exports.GridStore.IO_SEEK_END) { + targetPosition = self.length + finalPosition; + } else { + targetPosition = finalPosition; + } + + var newChunkNumber = Math.floor(targetPosition/self.chunkSize); + if(newChunkNumber != self.currentChunk.chunkNumber) { + if(self.mode[0] == 'w') { + self.currentChunk.save(function(err, chunk) { + self.nthChunk(newChunkNumber, function(err, chunk) { + self.currentChunk = chunk; + self.position = targetPosition; + self.currentChunk.position = (self.position % self.chunkSize); + callback(null, self); + }); + }); + } + } else { + self.position = targetPosition; + self.currentChunk.position = (self.position % self.chunkSize); + callback(null, self); + } +}; + +/** + * @return {boolean} True if the read/write head is at the end of this file. + */ +GridStore.prototype.eof = function() { + return this.position == this.length ? true : false; +}; + +/** + * Retrieves a single character from this file. + * + * @param callback {function(*, ?string)} This gets called after this method is + * executed. Passes null to the first parameter and the character read to + * the second or null to the second if the read/write head is at the end of + * the file. + */ +GridStore.prototype.getc = function(callback) { + var self = this; + + if(self.eof()) { + callback(null, null); + } else if(self.currentChunk.eof()) { + self.nthChunk(self.currentChunk.chunkNumber + 1, function(err, chunk) { + self.currentChunk = chunk; + self.position = self.position + 1; + callback(null, self.currentChunk.getc()); + }); + } else { + self.position = self.position + 1; + callback(null, self.currentChunk.getc()); + } +}; + +/** + * Writes a string to the file with a newline character appended at the end if + * the given string does not have one. + * + * @param string {string} The string to write. + * @param callback {function(*, GridStore)} This will be called after executing + * this method. The first parameter will contain null and the second one + * will contain a reference to this object. + * + * @see GridStore#write + * @see GridStore#writeFile + */ +GridStore.prototype.puts = function(string, callback) { + var finalString = string.match(/\n$/) == null ? string + "\n" : string; + this.write(finalString, callback); +}; + +/** + * The collection to be used for holding the files and chunks collection. + * @constant + */ +GridStore.DEFAULT_ROOT_COLLECTION = 'fs'; +/** + * Default file mime type + * @constant + */ +GridStore.DEFAULT_CONTENT_TYPE = 'binary/octet-stream'; +/** + * Seek mode where the given length is absolute. + * @constant + */ +GridStore.IO_SEEK_SET = 0; +/** + * Seek mode where the given length is an offset to the current read/write head. + * @constant + */ +GridStore.IO_SEEK_CUR = 1; +/** + * Seek mode where the given length is an offset to the end of the file. + * @constant + */ +GridStore.IO_SEEK_END = 2; + +/** + * Checks if a file exists in the database. + * + * @param db {Db} The database to query. + * @param name {string} The name of the file to look for. + * @param rootCollection {string=} opt_argument The root collection that holds the files + * and chunks collection. Defaults to {@link GridStore.DEFAULT_ROOT_COLLECTION} + * @param callback {function(*, boolean)} This will be called after this method + * executes. Passes null to the first and passes true to the second if the + * file exists and false otherwise. + */ +GridStore.exist = function(db, fileIdObject, rootCollection, callback) { + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + rootCollection = args.length ? args.shift() : null; + + // Fetch collection + var rootCollectionFinal = rootCollection != null ? rootCollection : GridStore.DEFAULT_ROOT_COLLECTION; + db.collection(rootCollectionFinal + ".files", function(err, collection) { + // Build query + var query = typeof fileIdObject == 'string' ? {'filename':fileIdObject} : {'_id':fileIdObject}; + // Attempt to locate file + collection.find(query, function(err, cursor) { + cursor.nextObject(function(err, item) { + callback(null, item == null ? false : true); + }); + }); + }); +}; + +/** + * Gets the list of files stored in the GridFS. + * + * @param db {Db} The database to query. + * @param rootCollection {string=} opt_argument The root collection that holds the files + * and chunks collection. Defaults to {@link GridStore.DEFAULT_ROOT_COLLECTION} + * @param callback {function(*, array)} This will be called after this method + * executes. Passes null to the first and passes an array of strings containing + * the names of the files. + */ +GridStore.list = function(db, rootCollection, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + rootCollection = args.length ? args.shift() : null; + options = args.length ? args.shift() : {}; + + // Ensure we have correct values + if(rootCollection != null && typeof rootCollection == 'object') { + options = rootCollection; + rootCollection = null; + } + + // Check if we are returning by id not filename + var byId = options['id'] != null ? options['id'] : false; + // Fetch item + var rootCollectionFinal = rootCollection != null ? rootCollection : GridStore.DEFAULT_ROOT_COLLECTION; + var items = []; + db.collection((rootCollectionFinal + ".files"), function(err, collection) { + collection.find(function(err, cursor) { + cursor.each(function(err, item) { + if(item != null) { + items.push(byId ? item._id : item.filename); + } else { + callback(null, items); + } + }); + }); + }); +}; + +/** + * Reads the contents of a file. + * + * This method has the following signatures + * + * (db, name, callback) + * (db, name, length, callback) + * (db, name, length, offset, callback) + * (db, name, length, offset, options, callback) + * + * @param db {Db} The database to query. + * @param name {string} The name of the file + * @param length {number=} opt_argument The size of data to read. + * @param offset {number=} opt_argument The offset from the head of the file of + * which to start reading from. + * @param options {object=} opt_argument The options for the file. + * @param callback {function(?Error|string, ?string)} This will be called after + * this method executes. A string with an error message will be passed to + * the first parameter when the length and offset combination exceeds the + * length of the file while an Error object will be passed if other forms + * of error occured, otherwise, a string is passed. The second parameter + * will contain the data read if successful or null if an error occured. + * + * @see GridStore#read + * @see GridStore#readlines + * @see GridStore for how to pass the options + */ +GridStore.read = function(db, name, length, offset, options, callback) { + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + length = args.length ? args.shift() : null; + offset = args.length ? args.shift() : null; + options = args.length ? args.shift() : null; + + new GridStore(db, name, "r", options).open(function(err, gridStore) { + // Make sure we are not reading out of bounds + if(offset && offset >= gridStore.length) return callback("offset larger than size of file", null); + if(length && length > gridStore.length) return callback("length is larger than the size of the file", null); + if(offset && length && (offset + length) > gridStore.length) return callback("offset and length is larger than the size of the file", null); + + if(offset != null) { + gridStore.seek(offset, function(err, gridStore) { + gridStore.read(length, function(err, data) { + callback(err, data); + }); + }); + } else { + gridStore.read(length, function(err, data) { + callback(err, data); + }); + } + }); +}; + +/** + * Reads the data of this file. + * + * @param db {Db} The database to query. + * @param name {string} The name of the file. + * @param separator {string=null} opt_argument The character to be recognized as + * the newline separator. + * @param options {object=} opt_argument + * @param callback {function(*, Array)} This will be called after this + * method is executed. The first parameter will be null and the second + * parameter will contain an array of strings representing the entire data, + * each element representing a line including the separator character. + * + * @see GridStore#read + * @see GridStore#readlines + * @see GridStore for how to pass the options + */ +GridStore.readlines = function(db, name, separator, options, callback) { + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + separator = args.length ? args.shift() : null; + options = args.length ? args.shift() : null; + + var finalSeperator = separator == null ? "\n" : separator; + new GridStore(db, name, "r", options).open(function(err, gridStore) { + gridStore.readlines(finalSeperator, function(err, lines) { + callback(err, lines); + }); + }); +}; + +/** + * Deletes the chunks and metadata information of a file from GridFS. + * + * @param db {Db} The database to interact with. + * @param names {string|Array} The names of the files to delete. + * @param options {object=} opt_argument The options for the files. + * @callback {function(?Error, GridStore)} This will be called after this method + * is executed. The first parameter will contain an Error object if an error + * occured or null otherwise. The second parameter will contain a reference + * to this object. + * + * @see GridStore#deleteChunks + * @see GridStore#rewind + * @see GridStore for how to pass the options + */ +GridStore.unlink = function(db, names, options, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + options = args.length ? args.shift() : null; + + if(names.constructor == Array) { + var tc = 0; + for(var i = 0; i < names.length; i++) { + ++tc; + self.unlink(db, names[i], function(result) { + if(--tc == 0) { + callback(null, self); + } + }); + } + } else { + new GridStore(db, names, "w", options).open(function(err, gridStore) { + gridStore.deleteChunks(function(err, result) { + gridStore.collection(function(err, collection) { + collection.remove({'_id':gridStore.fileId}, {safe:true}, function(err, collection) { + callback(err, self); + }); + }); + }); + }); + } +}; + +var ReadStream = function(autoclose, gstore) { + if (!(this instanceof ReadStream)) return new ReadStream(autoclose, gstore); + Stream.call(this); + + this.autoclose = !!autoclose; + this.gstore = gstore; + + this.finalLength = gstore.length - gstore.position; + this.completedLength = 0; + + this.paused = false; + this.readable = true; + this.pendingChunk = null; + + var self = this; + process.nextTick(function() { + self._execute(); + }); +}; + +util.inherits(ReadStream, Stream); + +ReadStream.prototype._execute = function() { + if(this.paused === true || this.readable === false) { + return; + } + + var gstore = this.gstore; + var self = this; + + var last = false; + var toRead = 0; + + if ((gstore.currentChunk.length() - gstore.currentChunk.position + 1 + self.completedLength) >= self.finalLength) { + toRead = self.finalLength - self.completedLength; + last = true; + } else { + toRead = gstore.currentChunk.length(); + } + + var data = gstore.currentChunk.readSlice(toRead); + if (data != null) { + self.completedLength += data.length; + self.pendingChunk = null; + self.emit("data", data); + } + + if (last === true) { + self.readable = false; + self.emit("end"); + if (self.autoclose === true) { + if (gstore.mode[0] == "w") { + gstore.close(function(err, doc) { + if (err) { + self.emit("error", err); + return; + } + self.emit("close", doc); + }); + } else { + self.emit("close"); + } + } + } else { + gstore.nthChunk(gstore.currentChunk.chunkNumber + 1, function(err, chunk) { + if (err) { + self.readable = false; + self.emit("error", err); + return; + } + self.pendingChunk = chunk; + if (self.paused === true) { + return; + } + gstore.currentChunk = self.pendingChunk; + self._execute(); + }); + } +}; + +/** + * Returns read stream based on this GridStore file + * Supported events: + *
      + *
    • data
    • + *
    • end
    • + *
    • close
    • + *
    • error
    • + *
    + * + * @param autoclose {Boolean?false} If true current GridStore will be closed when EOF + * and 'close' event will be fired + */ +GridStore.prototype.stream = function(autoclose) { + return new ReadStream(autoclose, this); +}; + +/** + * Pauses this stream, then no farther events will be fired + */ +ReadStream.prototype.pause = function() { + this.paused = true; +}; + +/** + * Resumes this strea, + */ +ReadStream.prototype.resume = function() { + this.paused = false; + var self = this; + if (self.pendingChunk) { + self.currentChunk = self.pendingChunk; + process.nextTick(function() { + self._execute(); + }); + } +}; + + + diff --git a/node_modules/mongodb/lib/mongodb/index.js b/node_modules/mongodb/lib/mongodb/index.js new file mode 100644 index 0000000..fb3ec9f --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/index.js @@ -0,0 +1,102 @@ + +try { + exports.BSONPure = require('./bson/bson'); + exports.BSONNative = require('../../external-libs/bson/bson'); +} catch(err) { + // do nothing +} + +[ 'bson/binary_parser' + , 'commands/base_command' + , 'commands/db_command' + , 'commands/delete_command' + , 'commands/get_more_command' + , 'commands/insert_command' + , 'commands/kill_cursor_command' + , 'commands/query_command' + , 'commands/update_command' + , 'responses/mongo_reply' + , 'admin' + , 'collection' + , 'connections/server' + , 'connections/repl_set_servers' + , 'connection' + , 'cursor' + , 'db' + , 'goog/math/long' + , 'gridfs/grid' + , 'gridfs/chunk' + , 'gridfs/gridstore'].forEach(function (path) { + var module = require('./' + path); + for (var i in module) { + exports[i] = module[i]; + } +}); + +// Exports all the classes for the NATIVE JS BSON Parser +exports.native = function() { + var classes = {}; + // Map all the classes + [ 'bson/binary_parser' + , '../../external-libs/bson/bson' + , 'commands/base_command' + , 'commands/db_command' + , 'commands/delete_command' + , 'commands/get_more_command' + , 'commands/insert_command' + , 'commands/kill_cursor_command' + , 'commands/query_command' + , 'commands/update_command' + , 'responses/mongo_reply' + , 'admin' + , 'collection' + , 'connections/server' + , 'connections/repl_set_servers' + , 'connection' + , 'cursor' + , 'db' + , 'gridfs/grid' + , 'gridfs/chunk' + , 'gridfs/gridstore'].forEach(function (path) { + var module = require('./' + path); + for (var i in module) { + classes[i] = module[i]; + } + }); + // Return classes list + return classes; +} + +// Exports all the classes for the PURE JS BSON Parser +exports.pure = function() { + var classes = {}; + // Map all the classes + [ 'bson/binary_parser' + , './bson/bson' + , 'commands/base_command' + , 'commands/db_command' + , 'commands/delete_command' + , 'commands/get_more_command' + , 'commands/insert_command' + , 'commands/kill_cursor_command' + , 'commands/query_command' + , 'commands/update_command' + , 'responses/mongo_reply' + , 'admin' + , 'collection' + , 'connections/server' + , 'connections/repl_set_servers' + , 'connection' + , 'cursor' + , 'db' + , 'gridfs/grid' + , 'gridfs/chunk' + , 'gridfs/gridstore'].forEach(function (path) { + var module = require('./' + path); + for (var i in module) { + classes[i] = module[i]; + } + }); + // Return classes list + return classes; +} diff --git a/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js b/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js new file mode 100644 index 0000000..1d738d2 --- /dev/null +++ b/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js @@ -0,0 +1,58 @@ +var Long = require('../goog/math/long').Long, + debug = require('util').debug, + inspect = require('util').inspect, + binaryutils = require('../bson/binary_utils'); + +/** + Reply message from mongo db +**/ +var MongoReply = exports.MongoReply = function(db, binary_reply) { + this.documents = []; + var index = 0; + // Unpack the standard header first + var messageLength = binaryutils.decodeUInt32(binary_reply, index); + index = index + 4; + // Fetch the request id for this reply + this.requestId = binaryutils.decodeUInt32(binary_reply, index); + index = index + 4; + // Fetch the id of the request that triggered the response + this.responseTo = binaryutils.decodeUInt32(binary_reply, index); + // Skip op-code field + index = index + 4 + 4; + // Unpack the reply message + this.responseFlag = binaryutils.decodeUInt32(binary_reply, index); + index = index + 4; + // Unpack the cursor id (a 64 bit long integer) + var low_bits = binaryutils.decodeUInt32(binary_reply, index); + var high_bits = binaryutils.decodeUInt32(binary_reply, index + 4); + + this.cursorId = new db.bson_deserializer.Long(low_bits, high_bits); + index = index + 8; + // Unpack the starting from + this.startingFrom = binaryutils.decodeUInt32(binary_reply, index); + index = index + 4; + // Unpack the number of objects returned + this.numberReturned = binaryutils.decodeUInt32(binary_reply, index); + index = index + 4; + + // Let's unpack all the bson document, deserialize them and store them + for(var object_index = 0; object_index < this.numberReturned; object_index++) { + // Read the size of the bson object + var bsonObjectSize = binaryutils.decodeUInt32(binary_reply, index); + // Deserialize the object and add to the documents array + this.documents.push(db.bson_deserializer.BSON.deserialize(binary_reply.slice(index, index + bsonObjectSize))); + // Adjust binary index to point to next block of binary bson data + index = index + bsonObjectSize; + } +}; + +MongoReply.prototype.is_error = function(){ + if(this.documents.length == 1) { + return this.documents[0].ok == 1 ? false : true; + } + return false; +}; + +MongoReply.prototype.error_message = function() { + return this.documents.length == 1 && this.documents[0].ok == 1 ? '' : this.documents[0].errmsg; +}; \ No newline at end of file diff --git a/node_modules/mongodb/package.json b/node_modules/mongodb/package.json new file mode 100755 index 0000000..16d2add --- /dev/null +++ b/node_modules/mongodb/package.json @@ -0,0 +1,67 @@ +{ "name" : "mongodb" +, "description" : "A node.js driver for MongoDB" +, "version" : "0.9.6-8" +, "author" : "Christian Amor Kvalheim " +, "contributors" : [ "Aaron Heckmann", + "Christoph Pojer", + "Pau Ramon Revilla", + "Nathan White", + "Emmerman", + "Seth LaForge", + "Boris Filipov", + "Stefan Schärmeli", + "Tedde Lundgren", + "renctan", + "Sergey Ukustov", + "Ciaran Jessup", + "kuno", + "srimonti", + "Erik Abele", + "Pratik Daga", + "Slobodan Utvic", + "Kristina Chodorow", + "Yonathan Randolph", + "Brian Noguchi", + "Sam Epstein", + "James Harrison Fisher", + "Vladimir Dronnikov", + "Ben Hockey", + "Henrik Johansson", + "Simon Weare", + "Alex Gorbatchev", + "Shimon Doodkin", + "Kyle Mueller", + "Eran Hammer-Lahav", + "Marcin Ciszak", + "François de Metz", + "Vinay Pulim", + "nstielau", + "Adam Wiggins", + "entrinzikyl", + "Jeremy Selier", + "Ian Millington", + "Public Keating", + "andrewjstone", + "Christopher Stott", + "Corey Jewett", + "brettkiefer", + "Rob Holland", + "Senmiao Liu", + "heroic", + "gitfy"] + +, "repository" : { "type" : "git" + , "url" : "http://github.com/christkv/node-mongodb-native.git" } +, "bugs" : { "mail" : "node-mongodb-native@googlegroups.com" + , "web" : "http://github.com/christkv/node-mongodb-native/issues" } +, "os" : [ "linux" + , "darwin" + , "freebsd" ] +, "config": { "native" : false } +, "main": "./lib/mongodb/index" +, "directories" : { "lib" : "./lib/mongodb" } +, "engines" : { "node" : ">=0.4.0" } +, "scripts": { "install" : "bash ./install.sh" } +, "licenses" : [ { "type" : "Apache License, Version 2.0" + , "url" : "http://www.apache.org/licenses/LICENSE-2.0" } ] +} diff --git a/node_modules/mongodb/test/admin_test.js b/node_modules/mongodb/test/admin_test.js new file mode 100644 index 0000000..1cc4052 --- /dev/null +++ b/node_modules/mongodb/test/admin_test.js @@ -0,0 +1,323 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 1}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldCorrectlyCallValidateCollection : function(test) { + var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + fs_client.bson_deserializer = client.bson_deserializer; + fs_client.bson_serializer = client.bson_serializer; + fs_client.pkFactory = client.pkFactory; + + fs_client.open(function(err, fs_client) { + fs_client.dropDatabase(function(err, done) { + fs_client.collection('test', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(err, doc) { + fs_client.admin(function(err, adminDb) { + adminDb.authenticate('admin', 'admin', function(err, replies) { + adminDb.validateCollection('test', function(err, doc) { + test.ok(doc.result != null); + test.ok(doc.result.match(/firstExtent/) != null); + + fs_client.close(); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlySetDefaultProfilingLevel : function(test) { + var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + fs_client.bson_deserializer = client.bson_deserializer; + fs_client.bson_serializer = client.bson_serializer; + fs_client.pkFactory = client.pkFactory; + + fs_client.open(function(err, fs_client) { + fs_client.dropDatabase(function(err, done) { + fs_client.collection('test', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(err, doc) { + fs_client.admin(function(err, adminDb) { + adminDb.authenticate('admin', 'admin', function(err, replies) { + adminDb.profilingLevel(function(err, level) { + test.equal("off", level); + + fs_client.close(); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyChangeProfilingLevel : function(test) { + var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + fs_client.bson_deserializer = client.bson_deserializer; + fs_client.bson_serializer = client.bson_serializer; + fs_client.pkFactory = client.pkFactory; + + fs_client.open(function(err, fs_client) { + fs_client.dropDatabase(function(err, done) { + fs_client.collection('test', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(err, doc) { + fs_client.admin(function(err, adminDb) { + adminDb.authenticate('admin', 'admin', function(err, replies) { + adminDb.setProfilingLevel('slow_only', function(err, level) { + adminDb.profilingLevel(function(err, level) { + test.equal('slow_only', level); + + adminDb.setProfilingLevel('off', function(err, level) { + adminDb.profilingLevel(function(err, level) { + test.equal('off', level); + + adminDb.setProfilingLevel('all', function(err, level) { + adminDb.profilingLevel(function(err, level) { + test.equal('all', level); + + adminDb.setProfilingLevel('medium', function(err, level) { + test.ok(err instanceof Error); + test.equal("Error: illegal profiling level value medium", err.message); + + fs_client.close(); + test.done(); + }); + }) + }); + }) + }); + }) + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlySetAndExtractProfilingInfo : function(test) { + var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + fs_client.bson_deserializer = client.bson_deserializer; + fs_client.bson_serializer = client.bson_serializer; + fs_client.pkFactory = client.pkFactory; + + fs_client.open(function(err, fs_client) { + fs_client.dropDatabase(function(err, done) { + fs_client.collection('test', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(doc) { + fs_client.admin(function(err, adminDb) { + adminDb.authenticate('admin', 'admin', function(err, replies) { + adminDb.setProfilingLevel('all', function(err, level) { + collection.find(function(err, cursor) { + cursor.toArray(function(err, items) { + adminDb.setProfilingLevel('off', function(err, level) { + adminDb.profilingInfo(function(err, infos) { + test.ok(infos.constructor == Array); + test.ok(infos.length >= 1); + test.ok(infos[0].ts.constructor == Date); + test.ok(infos[0].info.constructor == String); + test.ok(infos[0].millis.constructor == Number); + + fs_client.close(); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; + +// test_kill_cursors : function() { +// var test_kill_cursors_client = new Db('integration_tests4_', new Server("127.0.0.1", 27017, {auto_reconnect: true}), {}); +// test_kill_cursors_client.bson_deserializer = client.bson_deserializer; +// test_kill_cursors_client.bson_serializer = client.bson_serializer; +// test_kill_cursors_client.pkFactory = client.pkFactory; +// +// test_kill_cursors_client.open(function(err, test_kill_cursors_client) { +// var number_of_tests_done = 0; +// +// test_kill_cursors_client.dropCollection('test_kill_cursors', function(err, collection) { +// test_kill_cursors_client.createCollection('test_kill_cursors', function(err, collection) { +// test_kill_cursors_client.cursorInfo(function(err, cursorInfo) { +// var clientCursors = cursorInfo.clientCursors_size; +// var byLocation = cursorInfo.byLocation_size; +// +// for(var i = 0; i < 1000; i++) { +// collection.save({'i': i}, function(err, doc) {}); +// } +// +// test_kill_cursors_client.cursorInfo(function(err, cursorInfo) { +// test.equal(clientCursors, cursorInfo.clientCursors_size); +// test.equal(byLocation, cursorInfo.byLocation_size); +// +// for(var i = 0; i < 10; i++) { +// collection.findOne(function(err, item) {}); +// } +// +// test_kill_cursors_client.cursorInfo(function(err, cursorInfo) { +// test.equal(clientCursors, cursorInfo.clientCursors_size); +// test.equal(byLocation, cursorInfo.byLocation_size); +// +// for(var i = 0; i < 10; i++) { +// collection.find(function(err, cursor) { +// cursor.nextObject(function(err, item) { +// cursor.close(function(err, cursor) {}); +// +// if(i == 10) { +// test_kill_cursors_client.cursorInfo(function(err, cursorInfo) { +// test.equal(clientCursors, cursorInfo.clientCursors_size); +// test.equal(byLocation, cursorInfo.byLocation_size); +// +// collection.find(function(err, cursor) { +// cursor.nextObject(function(err, item) { +// test_kill_cursors_client.cursorInfo(function(err, cursorInfo) { +// test.equal(clientCursors, cursorInfo.clientCursors_size); +// test.equal(byLocation, cursorInfo.byLocation_size); +// +// cursor.close(function(err, cursor) { +// test_kill_cursors_client.cursorInfo(function(err, cursorInfo) { +// test.equal(clientCursors, cursorInfo.clientCursors_size); +// test.equal(byLocation, cursorInfo.byLocation_size); +// +// collection.find({}, {'limit':10}, function(err, cursor) { +// cursor.nextObject(function(err, item) { +// test_kill_cursors_client.cursorInfo(function(err, cursorInfo) { +// test_kill_cursors_client.cursorInfo(function(err, cursorInfo) { +// sys.puts("===================================== err: " + err) +// sys.puts("===================================== cursorInfo: " + sys.inspect(cursorInfo)) +// +// +// test.equal(clientCursors, cursorInfo.clientCursors_size); +// test.equal(byLocation, cursorInfo.byLocation_size); +// number_of_tests_done = 1; +// }); +// }); +// }); +// }); +// }); +// }); +// }); +// }); +// }); +// }); +// } +// }); +// }); +// } +// }); +// }); +// }); +// }); +// }); +// +// var intervalId = setInterval(function() { +// if(number_of_tests_done == 1) { +// clearInterval(intervalId); +// finished_test({test_kill_cursors:'ok'}); +// test_kill_cursors_client.close(); +// } +// }, 100); +// }); +// }, + +// test_force_binary_error : function() { +// client.createCollection('test_force_binary_error', function(err, collection) { +// // Try to fetch an object using a totally invalid and wrong hex string... what we're interested in here +// // is the error handling of the findOne Method +// var result= ""; +// var hexString = "5e9bd59248305adf18ebc15703a1"; +// for(var index=0 ; index < hexString.length; index+=2) { +// var string= hexString.substr(index, 2); +// var number= parseInt(string, 16); +// result+= BinaryParser.fromByte(number); +// } +// +// // Generate a illegal ID +// var id = client.bson_serializer.ObjectID.createFromHexString('5e9bd59248305adf18ebc157'); +// id.id = result; +// +// // Execute with error +// collection.findOne({"_id": id}, function(err, result) { +// // test.equal(undefined, result) +// test.ok(err != null) +// finished_test({test_force_binary_error:'ok'}); +// }); +// }); +// }, + +// test_long_term_insert : function() { +// var numberOfTimes = 21000; +// +// client.createCollection('test_safe_insert', function(err, collection) { +// var timer = setInterval(function() { +// collection.insert({'test': 1}, {safe:true}, function(err, result) { +// numberOfTimes = numberOfTimes - 1; +// +// if(numberOfTimes <= 0) { +// clearInterval(timer); +// collection.count(function(err, count) { +// test.equal(21000, count); +// finished_test({test_long_term_insert:'ok'}) +// }); +// } +// }); +// }, 1); +// }); +// }, diff --git a/node_modules/mongodb/test/authentication_test.js b/node_modules/mongodb/test/authentication_test.js new file mode 100644 index 0000000..d91aeca --- /dev/null +++ b/node_modules/mongodb/test/authentication_test.js @@ -0,0 +1,144 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + // Test the authentication method for the user + shouldCorrectlyAuthenticate : function(test) { + var user_name = 'spongebob'; + var password = 'squarepants'; + + client.authenticate('admin', 'admin', function(err, replies) { + test.ok(err instanceof Error); + test.ok(!replies); + + // Add a user + client.addUser(user_name, password, function(err, result) { + client.authenticate(user_name, password, function(err, replies) { + test.ok(!(err instanceof Error)); + test.ok(replies); + test.done(); + }); + }); + }); + }, + + shouldCorrectlyReAuthorizeReconnectedConnections : function(test) { + var user_name = 'spongebob2'; + var password = 'password'; + + var p_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize:3}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + p_client.bson_deserializer = client.bson_deserializer; + p_client.bson_serializer = client.bson_serializer; + p_client.pkFactory = client.pkFactory; + + p_client.open(function(err, automatic_connect_client) { + p_client.authenticate('admin', 'admin', function(err, replies) { + test.ok(err instanceof Error); + // Add a user + p_client.addUser(user_name, password, function(err, result) { + // Execute authentication + p_client.authenticate(user_name, password, function(err, replies) { + test.ok(err == null); + test.ok(replies); + + // Kill a connection to force a reconnect + p_client.serverConfig.connection.pool[0].connection.end(); + + p_client.createCollection('shouldCorrectlyReAuthorizeReconnectedConnections', function(err, collection) { + collection.insert({a:1}, {safe:true}, function(err, r) { + collection.insert({a:2}, {safe:true}, function(err, r) { + collection.insert({a:3}, {safe:true}, function(err, r) { + + collection.count(function(err, count) { + test.equal(3, count); + p_client.close(); + test.done(); + }) + }) + }) + }) + }); + }); + }); + }); + }); + }, + + shouldCorrectlyAddAndRemoveUser : function(test) { + var user_name = 'spongebob2'; + var password = 'password'; + + var p_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + p_client.bson_deserializer = client.bson_deserializer; + p_client.bson_serializer = client.bson_serializer; + p_client.pkFactory = client.pkFactory; + + p_client.open(function(err, automatic_connect_client) { + p_client.authenticate('admin', 'admin', function(err, replies) { + test.ok(err instanceof Error); + + // Add a user + p_client.addUser(user_name, password, function(err, result) { + p_client.authenticate(user_name, password, function(err, replies) { + test.ok(replies); + + // Remove the user and try to authenticate again + p_client.removeUser(user_name, function(err, result) { + p_client.authenticate(user_name, password, function(err, replies) { + test.ok(err instanceof Error); + + test.done(); + p_client.close(); + }); + }); + }); + }); + }); + }); + } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/auxilliary/authentication_test.js b/node_modules/mongodb/test/auxilliary/authentication_test.js new file mode 100644 index 0000000..a218980 --- /dev/null +++ b/node_modules/mongodb/test/auxilliary/authentication_test.js @@ -0,0 +1,195 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../../lib/mongodb').native() : require('../../lib/mongodb').pure(); + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server, + ServerManager = require('../../test/tools/server_manager').ServerManager, + Step = require("../../deps/step/lib/step"); + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 1}), {native_parser: (process.env['TEST_NATIVE'] != null)}); +var serverManager = null; + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + callback(); + }, + + tearDown: function(callback) { + serverManager.stop(9, function(err, result) { + callback(); + }); + }, + + shouldCorrectlyAuthenticate : function(test) { + var db1 = new Db('mongo-ruby-test-auth1', new Server("127.0.0.1", 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + var db2 = new Db('mongo-ruby-test-auth2', new Server("127.0.0.1", 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + var admin = new Db('admin', new Server("127.0.0.1", 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + + Step( + function bootTheServerWithNoAuth() { + serverManager = new ServerManager({auth:false, purgedirectories:true}) + serverManager.start(true, this); + }, + + function openDbs() { + db1.open(this.parallel()); + db2.open(this.parallel()); + admin.open(this.parallel()); + }, + + function addAdminUserToDatabase(err, db1, db2, admin) { + test.equal(null, err); + admin.addUser('admin', 'admin', this); + }, + + function restartServerInAuthMode(err, result) { + test.equal(null, err); + test.equal('7c67ef13bbd4cae106d959320af3f704', result.shift().pwd); + + db1.close(); + db2.close(); + admin.close(); + + serverManager = new ServerManager({auth:true, purgedirectories:false}) + serverManager.start(true, this); + }, + + function openDbs() { + db1.open(this.parallel()); + db2.open(this.parallel()); + admin.open(this.parallel()); + }, + + function authenticateAdminUser(err) { + test.equal(null, err); + + admin.authenticate('admin', 'admin', this.parallel()); + db1.admin().authenticate('admin', 'admin', this.parallel()); + db2.admin().authenticate('admin', 'admin', this.parallel()); + }, + + function addDbUsersForAuthentication(err, result1, result2, result3) { + test.equal(null, err); + test.ok(result1); + test.ok(result2); + test.ok(result3); + + db1.addUser('user1', 'secret', this.parallel()); + db2.addUser('user2', 'secret', this.parallel()); + }, + + function closeAdminConnection(err, result1, result2) { + test.ok(err == null); + test.ok(result1 != null); + test.ok(result2 != null); + + admin.logout(this.parallel()); + db1.admin().logout(this.parallel()); + db2.admin().logout(this.parallel()); + }, + + function failAuthenticationWithDbs(err, result) { + var self = this; + + db1.collection('stuff', function(err, collection) { + collection.insert({a:2}, {safe:true}, self.parallel()); + }); + + db2.collection('stuff', function(err, collection) { + collection.insert({a:2}, {safe:true}, self.parallel()); + }); + }, + + function authenticateAgainstDbs(err, result) { + test.ok(err != null); + + db1.authenticate('user1', 'secret', this.parallel()); + db2.authenticate('user2', 'secret', this.parallel()); + }, + + function correctlyInsertRowToDbs(err, result1, result2) { + var self = this; + test.ok(err == null); + test.ok(result1); + test.ok(result2); + + db1.collection('stuff', function(err, collection) { + collection.insert({a:2}, {safe:true}, self.parallel()); + }); + + db2.collection('stuff', function(err, collection) { + collection.insert({a:2}, {safe:true}, self.parallel()); + }); + }, + + function validateCorrectInsertsAndBounceServer(err, result1, result2) { + test.ok(err == null); + test.ok(result1 != null); + test.ok(result2 != null); + + serverManager = new ServerManager({auth:true, purgedirectories:false}) + serverManager.start(true, this); + }, + + function reconnectAndVerifyThatAuthIsAutomaticallyApplied() { + var self = this; + db1.collection('stuff', function(err, collection) { + collection.find().toArray(function(err, items) { + test.ok(err == null); + test.equal(1, items.length); + + db1.collection('stuff', function(err, collection) { + collection.insert({a:2}, {safe:true}, self.parallel()); + }); + + db2.collection('stuff', function(err, collection) { + collection.insert({a:2}, {safe:true}, self.parallel()); + }); + }) + }); + }, + + function logoutDb1(err, result1, result2) { + test.ok(err == null); + test.ok(result1 != null); + test.ok(result2 != null); + + db1.logout(this); + }, + + function insertShouldFail(err, result) { + var self = this; + db1.collection('stuff', function(err, collection) { + collection.insert({a:2}, {safe:true}, self.parallel()); + }); + }, + + function logoutDb2(err, result) { + test.ok(err != null); + + db2.logout(this); + }, + + function insertShouldFail(err, result) { + var self = this; + db2.collection('stuff', function(err, collection) { + collection.insert({a:2}, {safe:true}, function(err, result) { + test.ok(err != null); + test.done(); + }); + }); + } + ) + }, +}) + +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/auxilliary/replicaset_auth_test.js b/node_modules/mongodb/test/auxilliary/replicaset_auth_test.js new file mode 100644 index 0000000..8c3ca57 --- /dev/null +++ b/node_modules/mongodb/test/auxilliary/replicaset_auth_test.js @@ -0,0 +1,147 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../../lib/mongodb').native() : require('../../lib/mongodb').pure(); + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server, + ReplSetServers = mongodb.ReplSetServers, + ReplicaSetManager = require('../../test/tools/replica_set_manager').ReplicaSetManager, + Step = require("../../deps/step/lib/step"); + +var MONGODB = 'integration_tests'; +// var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 1}), {native_parser: (process.env['TEST_NATIVE'] != null)}); +var serverManager = null; + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + RS = new ReplicaSetManager({retries:120, auth:true}); + RS.startSet(true, function(err, result) { + if(err != null) throw err; + // Finish setup + callback(); + }); + }, + + tearDown: function(callback) { + RS.killAll(function() { + callback(); + }) + }, + + shouldCorrectlyAuthenticate : function(test) { + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + // Connect to the replicaset + var slaveDb = null; + var db = new Db('foo', replSet, {native_parser: (process.env['TEST_NATIVE'] != null)}); + db.open(function(err, p_db) { + Step( + function addUser() { + db.admin().addUser("me", "secret", this); + }, + + function ensureFailingInsert(err, result) { + var self = this; + test.equal(null, err); + test.ok(result != null); + + db.collection("stuff", function(err, collection) { + collection.insert({a:2}, {safe: {w: 3}}, self); + }); + }, + + function authenticate(err, result) { + test.ok(err != null); + + db.admin().authenticate("me", "secret", this); + }, + + function insertShouldSuccedNow(err, result) { + var self = this; + test.equal(null, err); + test.ok(result); + + db.collection("stuff", function(err, collection) { + collection.insert({a:2}, {safe: {w: 3}}, self); + }); + }, + + function queryShouldExecuteCorrectly(err, result) { + var self = this; + test.equal(null, err); + + db.collection("stuff", function(err, collection) { + collection.findOne(self); + }); + }, + + function logout(err, item) { + test.ok(err == null); + test.equal(2, item.a); + + db.admin().logout(this); + }, + + function findShouldFailDueToLoggedOut(err, result) { + var self = this; + test.equal(null, err); + + db.collection("stuff", function(err, collection) { + collection.findOne(self); + }); + }, + + function sameShouldApplyToRandomSecondaryServer(err, result) { + var self = this; + test.ok(err != null); + + slaveDb = new Db('foo', new Server(db.serverConfig.secondaries[0].host + , db.serverConfig.secondaries[0].port, {auto_reconnect: true, poolSize: 1}), {native_parser: (process.env['TEST_NATIVE'] != null), slave_ok:true}); + slaveDb.open(function(err, slaveDb) { + slaveDb.collection('stuff', function(err, collection) { + collection.findOne(self) + }) + }); + }, + + function shouldCorrectlyAuthenticateAgainstSecondary(err, result) { + test.ok(err != null) + + slaveDb.admin().authenticate('me', 'secret', this); + }, + + function shouldCorrectlyInsertItem(err, result) { + var self = this; + test.equal(null, err); + test.ok(result); + + slaveDb.collection('stuff', function(err, collection) { + collection.findOne(self) + }) + }, + + function finishUp(err, item) { + test.ok(err == null); + test.equal(2, item.a); + + test.done(); + } + ) + }); + } +}) + +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/bson/bson_test.js b/node_modules/mongodb/test/bson/bson_test.js new file mode 100644 index 0000000..1c7e190 --- /dev/null +++ b/node_modules/mongodb/test/bson/bson_test.js @@ -0,0 +1,631 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../../lib/mongodb').native() : require('../../lib/mongodb').pure(); + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + fs = require('fs'), + BSON = mongodb.BSON, + Code = mongodb.Code, + Binary = mongodb.Binary, + Timestamp = mongodb.Timestamp, + Long = mongodb.Long, + ObjectID = mongodb.ObjectID, + Symbol = mongodb.Symbol, + DBRef = mongodb.DBRef, + BinaryParser = mongodb.BinaryParser; + +var BSONSE = mongodb, + BSONDE = mongodb; + +// BSONDE = require('../../lib/mongodb').native(); + +// for tests +BSONDE.BSON_BINARY_SUBTYPE_DEFAULT = 0; +BSONDE.BSON_BINARY_SUBTYPE_FUNCTION = 1; +BSONDE.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; +BSONDE.BSON_BINARY_SUBTYPE_UUID = 3; +BSONDE.BSON_BINARY_SUBTYPE_MD5 = 4; +BSONDE.BSON_BINARY_SUBTYPE_USER_DEFINED = 128; + +BSONSE.BSON_BINARY_SUBTYPE_DEFAULT = 0; +BSONSE.BSON_BINARY_SUBTYPE_FUNCTION = 1; +BSONSE.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; +BSONSE.BSON_BINARY_SUBTYPE_UUID = 3; +BSONSE.BSON_BINARY_SUBTYPE_MD5 = 4; +BSONSE.BSON_BINARY_SUBTYPE_USER_DEFINED = 128; + +var tests = testCase({ + setUp: function(callback) { + callback(); + }, + + tearDown: function(callback) { + callback(); + }, + + 'Should Correctly Deserialize object' : function(test) { + var bytes = [95,0,0,0,2,110,115,0,42,0,0,0,105,110,116,101,103,114,97,116,105,111,110,95,116,101,115,116,115,95,46,116,101,115,116,95,105,110,100,101,120,95,105,110,102,111,114,109,97,116,105,111,110,0,8,117,110,105,113,117,101,0,0,3,107,101,121,0,12,0,0,0,16,97,0,1,0,0,0,0,2,110,97,109,101,0,4,0,0,0,97,95,49,0,0]; + var serialized_data = ''; + // Convert to chars + for(var i = 0; i < bytes.length; i++) { + serialized_data = serialized_data + BinaryParser.fromByte(bytes[i]); + } + var object = BSONDE.BSON.deserialize(new Buffer(serialized_data, 'binary')); + test.equal("a_1", object.name); + test.equal(false, object.unique); + test.equal(1, object.key.a); + test.done(); + }, + + 'Should Correctly Deserialize object with all types' : function(test) { + var bytes = [26,1,0,0,7,95,105,100,0,161,190,98,75,118,169,3,0,0,3,0,0,4,97,114,114,97,121,0,26,0,0,0,16,48,0,1,0,0,0,16,49,0,2,0,0,0,16,50,0,3,0,0,0,0,2,115,116,114,105,110,103,0,6,0,0,0,104,101,108,108,111,0,3,104,97,115,104,0,19,0,0,0,16,97,0,1,0,0,0,16,98,0,2,0,0,0,0,9,100,97,116,101,0,161,190,98,75,0,0,0,0,7,111,105,100,0,161,190,98,75,90,217,18,0,0,1,0,0,5,98,105,110,97,114,121,0,7,0,0,0,2,3,0,0,0,49,50,51,16,105,110,116,0,42,0,0,0,1,102,108,111,97,116,0,223,224,11,147,169,170,64,64,11,114,101,103,101,120,112,0,102,111,111,98,97,114,0,105,0,8,98,111,111,108,101,97,110,0,1,15,119,104,101,114,101,0,25,0,0,0,12,0,0,0,116,104,105,115,46,120,32,61,61,32,51,0,5,0,0,0,0,3,100,98,114,101,102,0,37,0,0,0,2,36,114,101,102,0,5,0,0,0,116,101,115,116,0,7,36,105,100,0,161,190,98,75,2,180,1,0,0,2,0,0,0,10,110,117,108,108,0,0]; + var serialized_data = ''; + // Convert to chars + for(var i = 0; i < bytes.length; i++) { + serialized_data = serialized_data + BinaryParser.fromByte(bytes[i]); + } + + var object = BSONDE.BSON.deserialize(new Buffer(serialized_data, 'binary'));//, false, true); + // Perform tests + test.equal("hello", object.string); + test.deepEqual([1,2,3], object.array); + test.equal(1, object.hash.a); + test.equal(2, object.hash.b); + test.ok(object.date != null); + test.ok(object.oid != null); + test.ok(object.binary != null); + test.equal(42, object.int); + test.equal(33.3333, object.float); + test.ok(object.regexp != null); + test.equal(true, object.boolean); + test.ok(object.where != null); + test.ok(object.dbref != null); + test.ok(object[null] == null); + test.done(); + }, + + 'Should Serialize and Deserialize String' : function(test) { + var test_string = {hello: 'world'}; + var serialized_data = BSONSE.BSON.serialize(test_string, false, true); + test.deepEqual(test_string, BSONDE.BSON.deserialize(serialized_data)); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Integer' : function(test) { + var test_number = {doc: 5}; + var serialized_data = BSONSE.BSON.serialize(test_number, false, true); + test.deepEqual(test_number, BSONDE.BSON.deserialize(serialized_data)); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize null value' : function(test) { + var test_null = {doc:null}; + var serialized_data = BSONSE.BSON.serialize(test_null, false, true); + var object = BSONDE.BSON.deserialize(serialized_data); + test.equal(null, object.doc); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Number' : function(test) { + var test_number = {doc: 5.5}; + var serialized_data = BSONSE.BSON.serialize(test_number, false, true); + test.deepEqual(test_number, BSONDE.BSON.deserialize(serialized_data)); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Integer' : function(test) { + var test_int = {doc: 42}; + var serialized_data = BSONSE.BSON.serialize(test_int, false, true); + test.deepEqual(test_int.doc, BSONDE.BSON.deserialize(serialized_data).doc); + + test_int = {doc: -5600}; + serialized_data = BSONSE.BSON.serialize(test_int, false, true); + test.deepEqual(test_int.doc, BSONDE.BSON.deserialize(serialized_data).doc); + + test_int = {doc: 2147483647}; + serialized_data = BSONSE.BSON.serialize(test_int, false, true); + test.deepEqual(test_int.doc, BSONDE.BSON.deserialize(serialized_data).doc); + + test_int = {doc: -2147483648}; + serialized_data = BSONSE.BSON.serialize(test_int, false, true); + test.deepEqual(test_int.doc, BSONDE.BSON.deserialize(serialized_data).doc); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Object' : function(test) { + var doc = {doc: {age: 42, name: 'Spongebob', shoe_size: 9.5}}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + + test.deepEqual(doc.doc.age, BSONDE.BSON.deserialize(serialized_data).doc.age); + test.deepEqual(doc.doc.name, BSONDE.BSON.deserialize(serialized_data).doc.name); + test.deepEqual(doc.doc.shoe_size, BSONDE.BSON.deserialize(serialized_data).doc.shoe_size); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Array' : function(test) { + var doc = {doc: [1, 2, 'a', 'b']}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized = BSONDE.BSON.deserialize(serialized_data); + + test.equal(doc.doc[0], deserialized.doc[0]) + test.equal(doc.doc[1], deserialized.doc[1]) + test.equal(doc.doc[2], deserialized.doc[2]) + test.equal(doc.doc[3], deserialized.doc[3]) + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Array with added on functions' : function(test) { + Array.prototype.toXml = function() {}; + var doc = {doc: [1, 2, 'a', 'b']}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized = BSONDE.BSON.deserialize(serialized_data); + + test.equal(doc.doc[0], deserialized.doc[0]) + test.equal(doc.doc[1], deserialized.doc[1]) + test.equal(doc.doc[2], deserialized.doc[2]) + test.equal(doc.doc[3], deserialized.doc[3]) + test.done(); + }, + + 'Should correctly deserialize a nested object' : function(test) { + var doc = {doc: {doc:1}}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + + test.deepEqual(doc.doc.doc, BSONDE.BSON.deserialize(serialized_data).doc.doc); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize A Boolean' : function(test) { + var doc = {doc: true}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + + test.equal(doc.doc, BSONDE.BSON.deserialize(serialized_data).doc); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize a Date' : function(test) { + var date = new Date(); + //(2009, 11, 12, 12, 00, 30) + date.setUTCDate(12); + date.setUTCFullYear(2009); + date.setUTCMonth(11 - 1); + date.setUTCHours(12); + date.setUTCMinutes(0); + date.setUTCSeconds(30); + var doc = {doc: date}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + + test.equal(doc.date, BSONDE.BSON.deserialize(serialized_data).doc.date); + test.done(); + }, + + 'Should Correctly Serialize nested doc' : function(test) { + var doc = { + string: "Strings are great", + decimal: 3.14159265, + bool: true, + integer: 5, + + subObject: { + moreText: "Bacon ipsum dolor.", + longKeylongKeylongKeylongKeylongKeylongKey: "Pork belly." + }, + + subArray: [1,2,3,4,5,6,7,8,9,10], + anotherString: "another string" + } + + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Oid' : function(test) { + var doc = {doc: new BSONSE.ObjectID()}; + var doc2 = {doc: BSONDE.ObjectID.createFromHexString(doc.doc.toHexString())}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + + test.deepEqual(doc, BSONDE.BSON.deserialize(serialized_data)); + test.done(); + }, + + 'Should Correctly encode Empty Hash' : function(test) { + var doc = {}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + + test.deepEqual(doc, BSONDE.BSON.deserialize(serialized_data)); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Ordered Hash' : function(test) { + var doc = {doc: {b:1, a:2, c:3, d:4}}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var decoded_hash = BSONDE.BSON.deserialize(serialized_data).doc; + var keys = []; + + for(name in decoded_hash) keys.push(name); + test.deepEqual(['b', 'a', 'c', 'd'], keys); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Regular Expression' : function(test) { + // Serialize the regular expression + var doc = {doc: /foobar/mi}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var doc2 = BSONDE.BSON.deserialize(serialized_data); + + test.deepEqual(doc.doc.toString(), doc2.doc.toString()); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize a Binary object' : function(test) { + var bin = new Binary(); + var string = 'binstring'; + for(var index = 0; index < string.length; index++) { + bin.put(string.charAt(index)); + } + var doc = {doc: bin}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.doc.value(), deserialized_data.doc.value()); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize a big Binary object' : function(test) { + var data = fs.readFileSync("test/gridstore/test_gs_weird_bug.png", 'binary'); + var bin = new Binary(); + bin.write(data); + var doc = {doc: bin}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.doc.value(), deserialized_data.doc.value()); + test.done(); + }, + + "Should Correctly Serialize and Deserialize DBRef" : function(test) { + var oid = new ObjectID(); + var doc = {dbref: new DBRef('namespace', oid, null)}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + + var doc2 = BSONDE.BSON.deserialize(serialized_data); + test.equal("namespace", doc2.dbref.namespace); + test.deepEqual(doc2.dbref.oid.toHexString(), oid.toHexString()); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize partial DBRef' : function(test) { + var id = new ObjectID(); + var doc = {'name':'something', 'user':{'$ref':'username', '$id': id}}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var doc2 = BSONDE.BSON.deserialize(serialized_data); + test.equal('something', doc2.name); + test.equal('username', doc2.user.namespace); + test.equal(id.toString(), doc2.user.oid.toString()); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize simple Int' : function(test) { + var doc = {doc:2147483648}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var doc2 = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.doc, doc2.doc) + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Long Integer' : function(test) { + var doc = {doc: Long.fromNumber(9223372036854775807)}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.doc, deserialized_data.doc); + + doc = {doc: Long.fromNumber(-9223372036854775)}; + serialized_data = BSONSE.BSON.serialize(doc, false, true); + deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.doc, deserialized_data.doc); + + doc = {doc: Long.fromNumber(-9223372036854775809)}; + serialized_data = BSONSE.BSON.serialize(doc, false, true); + deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.doc, deserialized_data.doc); + test.done(); + }, + + 'Should Deserialize Large Integers as Number not Long' : function(test) { + function roundTrip(val) { + var doc = {doc: val}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.doc, deserialized_data.doc); + }; + + roundTrip(Math.pow(2,52)); + roundTrip(Math.pow(2,53) - 1); + roundTrip(Math.pow(2,53)); + roundTrip(-Math.pow(2,52)); + roundTrip(-Math.pow(2,53) + 1); + roundTrip(-Math.pow(2,53)); + roundTrip(Math.pow(2,65)); // Too big for Long. + roundTrip(-Math.pow(2,65)); + roundTrip(1234567890123456800); // Bigger than 2^53, stays a double. + roundTrip(-1234567890123456800); + test.done(); + }, + + 'Should Deserialize Larger Integers as Long not Number' : function(test) { + function roundTrip(val) { + var doc = {doc: val}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.doc, deserialized_data.doc); + }; + + roundTrip(Long.fromNumber(Math.pow(2,53)).add(Long.ONE)); + roundTrip(Long.fromNumber(-Math.pow(2,53)).subtract(Long.ONE)); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Long Integer and Timestamp as different types' : function(test) { + var long = Long.fromNumber(9223372036854775807); + var timestamp = Timestamp.fromNumber(9223372036854775807); + test.ok(long instanceof Long); + test.ok(!(long instanceof Timestamp)); + test.ok(timestamp instanceof Timestamp); + test.ok(!(timestamp instanceof Long)); + + var test_int = {doc: long, doc2: timestamp}; + var serialized_data = BSONSE.BSON.serialize(test_int, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + + test.deepEqual(test_int.doc, deserialized_data.doc); + test.done(); + }, + + 'Should Always put the id as the first item in a hash' : function(test) { + var hash = {doc: {not_id:1, '_id':2}}; + var serialized_data = BSONSE.BSON.serialize(hash, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + var keys = []; + + for(name in deserialized_data.doc) { + keys.push(name); + } + + test.deepEqual(['not_id', '_id'], keys); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize a User defined Binary object' : function(test) { + var bin = new Binary(); + bin.sub_type = BSON.BSON_BINARY_SUBTYPE_USER_DEFINED; + var string = 'binstring'; + for(var index = 0; index < string.length; index++) { + bin.put(string.charAt(index)); + } + + var doc = {doc: bin}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + + test.deepEqual(deserialized_data.doc.sub_type, BSON.BSON_BINARY_SUBTYPE_USER_DEFINED); + test.deepEqual(doc.doc.value(), deserialized_data.doc.value()); + test.done(); + }, + + 'Should Correclty Serialize and Deserialize a Code object' : function(test) { + var doc = {'doc': {'doc2': new BSONSE.Code('this.a > i', {i:1})}}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + + test.deepEqual(doc.doc.doc2.code, deserialized_data.doc.doc2.code); + test.deepEqual(doc.doc.doc2.scope.i, deserialized_data.doc.doc2.scope.i); + test.done(); + }, + + 'Should Correctly serialize and deserialize and embedded array' : function(test) { + var doc = {'a':0, + 'b':['tmp1', 'tmp2', 'tmp3', 'tmp4', 'tmp5', 'tmp6', 'tmp7', 'tmp8', 'tmp9', 'tmp10', 'tmp11', 'tmp12', 'tmp13', 'tmp14', 'tmp15', 'tmp16'] + }; + + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.a, deserialized_data.a); + test.deepEqual(doc.b, deserialized_data.b); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize UTF8' : function(test) { + // Serialize utf8 + var doc = { "name" : "本荘由利地域に洪水警報", "name1" : "öüóőúéáűíÖÜÓŐÚÉÁŰÍ", "name2" : "abcdedede"}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc, deserialized_data); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize query object' : function(test) { + var doc = { count: 'remove_with_no_callback_bug_test', query: {}, fields: null}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc, deserialized_data); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize empty query object' : function(test) { + var doc = {}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc, deserialized_data); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize array based doc' : function(test) { + var doc = { b: [ 1, 2, 3 ], _id: new BSONSE.ObjectID() }; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.b, deserialized_data.b) + test.deepEqual(doc, deserialized_data); + test.done(); + }, + + 'Should Correctly Serialize and Deserialize Symbol' : function(test) { + var doc = { b: [ new Symbol('test') ], _id: new BSONSE.ObjectID() }; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc.b, deserialized_data.b) + test.deepEqual(doc, deserialized_data); + test.done(); + }, + + 'Should handle Deeply nested document' : function(test) { + var doc = {a:{b:{c:{d:2}}}}; + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var deserialized_data = BSONDE.BSON.deserialize(serialized_data); + test.deepEqual(doc, deserialized_data); + test.done(); + }, + + 'Should handle complicated all typed object' : function(test) { + // First doc + var date = new Date(); + var oid = new BSONSE.ObjectID(); + var string = 'binstring' + var bin = new BSONSE.Binary() + for(var index = 0; index < string.length; index++) { + bin.put(string.charAt(index)) + } + + var doc = { + 'string': 'hello', + 'array': [1,2,3], + 'hash': {'a':1, 'b':2}, + 'date': date, + 'oid': oid, + 'binary': bin, + 'int': 42, + 'float': 33.3333, + 'regexp': /regexp/, + 'boolean': true, + 'long': date.getTime(), + 'where': new BSONSE.Code('this.a > i', {i:1}), + 'dbref': new BSONSE.DBRef('namespace', oid, 'integration_tests_') + } + + // Second doc + var oid = new BSONDE.ObjectID.createFromHexString(oid.toHexString()); + var string = 'binstring' + var bin = new BSONDE.Binary() + for(var index = 0; index < string.length; index++) { + bin.put(string.charAt(index)) + } + + var doc2 = { + 'string': 'hello', + 'array': [1,2,3], + 'hash': {'a':1, 'b':2}, + 'date': date, + 'oid': oid, + 'binary': bin, + 'int': 42, + 'float': 33.3333, + 'regexp': /regexp/, + 'boolean': true, + 'long': date.getTime(), + 'where': new BSONDE.Code('this.a > i', {i:1}), + 'dbref': new BSONDE.DBRef('namespace', oid, 'integration_tests_') + } + + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var serialized_data2 = BSONDE.BSON.serialize(doc2, false, true); + + for(var i = 0; i < serialized_data2.length; i++) { + require('assert').equal(serialized_data2[i], serialized_data[i]) + } + + test.done(); + }, + + 'Should Correctly Serialize Complex Nested Object' : function(test) { + var doc = { email: 'email@email.com', + encrypted_password: 'password', + friends: [ '4db96b973d01205364000006', + '4dc77b24c5ba38be14000002' ], + location: [ 72.4930088, 23.0431957 ], + name: 'Amit Kumar', + password_salt: 'salty', + profile_fields: [], + username: 'amit', + _id: new BSONSE.ObjectID() } + + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + + var doc2 = doc; + doc2._id = BSONDE.ObjectID.createFromHexString(doc2._id.toHexString()); + var serialized_data2 = BSONDE.BSON.serialize(doc2, false, true); + + for(var i = 0; i < serialized_data2.length; i++) { + // debug("[" + i + "] :: " + serialized_data.toString('ascii', i, i+1) + " :: [" + serialized_data[i] + "]" + " = [" + serialized_data2[i] + "] :: " + serialized_data2.toString('ascii', i, i+1) + // + ((serialized_data2[i] != serialized_data[i]) ? " = false" : "")) + require('assert').equal(serialized_data2[i], serialized_data[i]) + } + + test.done(); + }, + + 'Should correctly massive doc' : function(test) { + var oid1 = new BSONSE.ObjectID(); + var oid2 = new BSONSE.ObjectID(); + + // JS doc + var doc = { dbref2: new BSONSE.DBRef('namespace', oid1, 'integration_tests_'), + _id: oid2 }; + + var doc2 = { dbref2: new BSONDE.DBRef('namespace', BSONDE.ObjectID.createFromHexString(oid1.toHexString()), 'integration_tests_'), + _id: new BSONDE.ObjectID.createFromHexString(oid2.toHexString()) }; + + // var doc = { + // 'dbref': new BSONSE.DBRef('namespace', oid, 'integration_tests_') + // } + // + // var doc2 = { + // 'dbref': new BSONDE.DBRef('namespace', BSONDE.ObjectID.createFromHexString(oid.toHexString()), 'integration_tests_') + // } + + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var serialized_data2 = BSONDE.BSON.serialize(doc2, false, true); + + // for(var i = 0; i < serialized_data2.length; i++) { + // debug("[" + i + "] :: " + serialized_data.toString('ascii', i, i+1) + " :: [" + serialized_data[i] + "]" + " = [" + serialized_data2[i] + "] :: " + serialized_data2.toString('ascii', i, i+1) + // + ((serialized_data2[i] != serialized_data[i]) ? " = false" : "")) + // // require('assert').equal(serialized_data2[i], serialized_data[i]) + // } + + test.done(); + }, + + 'Should Correctly Serialize/Deserialize regexp object' : function(test) { + var doc = {'b':/foobaré/}; + + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var serialized_data2 = BSONDE.BSON.serialize(doc, false, true); + + for(var i = 0; i < serialized_data2.length; i++) { + // debug("[" + i + "] :: " + serialized_data.toString('ascii', i, i+1) + " :: [" + serialized_data[i] + "]" + " = [" + serialized_data2[i] + "] :: " + serialized_data2.toString('ascii', i, i+1) + // + ((serialized_data2[i] != serialized_data[i]) ? " = false" : "")) + require('assert').equal(serialized_data2[i], serialized_data[i]) + } + + test.done(); + }, + + 'Should Correctly Serialize/Deserialize complicated object' : function(test) { + var doc = {a:{b:{c:[new BSONSE.ObjectID(), new BSONSE.ObjectID()]}}, d:{f:1332.3323}}; + + var serialized_data = BSONSE.BSON.serialize(doc, false, true); + var doc2 = BSONSE.BSON.deserialize(serialized_data); + + test.deepEqual(doc, doc2) + test.done(); + } +}); + +// Assign out tests +module.exports = tests; diff --git a/node_modules/mongodb/test/bson/commands_test.js b/node_modules/mongodb/test/bson/commands_test.js new file mode 100644 index 0000000..c318ffc --- /dev/null +++ b/node_modules/mongodb/test/bson/commands_test.js @@ -0,0 +1,121 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../../lib/mongodb').native() : require('../../lib/mongodb').pure(); + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + fs = require('fs'), + BSON = mongodb.BSON, + Code = mongodb.Code, + Binary = mongodb.Binary, + Long = mongodb.Long, + ObjectID = mongodb.ObjectID, + DBRef = mongodb.DBRef, + BaseCommand = mongodb.BaseCommand, + InsertCommand = mongodb.InsertCommand, + UpdateCommand = mongodb.UpdateCommand, + DeleteCommand = mongodb.DeleteCommand, + GetMoreCommand = mongodb.GetMoreCommand, + KillCursorCommand = mongodb.KillCursorCommand, + QueryCommand = mongodb.QueryCommand, + MongoReply = mongodb.MongoReply, + BinaryParser = mongodb.BinaryParser; + +var tests = testCase({ + setUp: function(callback) { + callback(); + }, + + tearDown: function(callback) { + callback(); + }, + + 'Should Correctly Generate an Insert Command' : function(test) { + var full_collection_name = "db.users"; + var insert_command = new InsertCommand({bson_serializer: {BSON:BSON}}, full_collection_name); + insert_command.add({name: 'peter pan'}); + insert_command.add({name: 'monkey king'}); + // assert the length of the binary + test.equal(81, insert_command.toBinary().length); + test.done(); + }, + + 'Should Correctly Generate an Update Command' : function(test) { + var full_collection_name = "db.users"; + var flags = UpdateCommand.DB_UPSERT; + var selector = {name: 'peter pan'}; + var document = {name: 'peter pan junior'}; + // Create the command + var update_command = new UpdateCommand({bson_serializer: {BSON:BSON}}, full_collection_name, selector, document, flags); + // assert the length of the binary + test.equal(90, update_command.toBinary().length); + test.done(); + }, + + 'Should Correctly Generate a Delete Command' : function(test) { + var full_collection_name = "db.users"; + var selector = {name: 'peter pan'}; + // Create the command + var delete_command = new DeleteCommand({bson_serializer: {BSON:BSON}}, full_collection_name, selector); + // assert the length of the binary + test.equal(58, delete_command.toBinary().length); + test.done(); + }, + + 'Should Correctly Generate a Get More Command' : function(test) { + var full_collection_name = "db.users"; + var numberToReturn = 100; + var cursorId = Long.fromNumber(10000222); + // Create the command + var get_more_command = new GetMoreCommand({bson_serializer: {BSON:BSON}}, full_collection_name, numberToReturn, cursorId); + // assert the length of the binary + test.equal(41, get_more_command.toBinary().length); + test.done(); + }, + + 'Should Correctly Generate a Kill Cursors Command' : function(test) { + Array.prototype.toXml = function() {} + var cursorIds = [Long.fromNumber(1), Long.fromNumber(10000222)]; + // Create the command + var kill_cursor_command = new KillCursorCommand({bson_serializer: {BSON:BSON}}, cursorIds); + // assert the length of the binary + test.equal(40, kill_cursor_command.toBinary().length); + test.done(); + }, + + 'Should Correctly Generate a Query Command' : function(test) { + var full_collection_name = "db.users"; + var options = QueryCommand.OPTS_SLAVE; + var numberToSkip = 100; + var numberToReturn = 200; + var query = {name:'peter pan'}; + var query_command = new QueryCommand({bson_serializer: {BSON:BSON}}, full_collection_name, options, numberToSkip, numberToReturn, query, null); + // assert the length of the binary + test.equal(62, query_command.toBinary().length); + // Generate command with return field filter + query_command = new QueryCommand({bson_serializer: {BSON:BSON}}, full_collection_name, options, numberToSkip, numberToReturn, query, { a : 1, b : 1, c : 1}); + test.equal(88, query_command.toBinary().length); + test.done(); + }, + + // 'Should Correctly Generate and parse a Reply Object' : function(test) { + // var reply_message = BinaryParser.fromInt(0) + BSON.encodeLong(Long.fromNumber(1222)) + BinaryParser.fromInt(100) + BinaryParser.fromInt(2); + // reply_message = reply_message + BSON.serialize({name:'peter pan'}) + BSON.serialize({name:'captain hook'}); + // var message = BinaryParser.fromInt(reply_message.length + 4*4) + BinaryParser.fromInt(2) + BinaryParser.fromInt(1) + BinaryParser.fromInt(BaseCommand.OP_QUERY) + reply_message; + // // Parse the message into a proper reply object + // var mongo_reply = new MongoReply({bson_deserializer: {BSON:BSON}, + // bson_serializer: {BSON:BSON}}, message); + // test.equal(2, mongo_reply.requestId); + // test.equal(1, mongo_reply.responseTo); + // test.equal(0, mongo_reply.responseFlag); + // test.equal(Long.fromNumber(1222).toString(), mongo_reply.cursorId.toString()); + // test.equal(100, mongo_reply.startingFrom); + // test.equal(2, mongo_reply.numberReturned); + // test.equal(2, mongo_reply.documents.length); + // test.deepEqual({name:'peter pan'}, mongo_reply.documents[0]); + // test.deepEqual({name:'captain hook'}, mongo_reply.documents[1]); + // test.done(); + // }, +}); + +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/collection_test.js b/node_modules/mongodb/test/collection_test.js new file mode 100644 index 0000000..6432796 --- /dev/null +++ b/node_modules/mongodb/test/collection_test.js @@ -0,0 +1,634 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Step = require("../deps/step/lib/step"), + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + // Test the creation of a collection on the mongo db + shouldCorrectExecuteBasicCollectionMethods : function(test) { + client.createCollection('test_collection_methods', function(err, collection) { + // Verify that all the result are correct coming back (should contain the value ok) + test.equal('test_collection_methods', collection.collectionName); + // Let's check that the collection was created correctly + client.collectionNames(function(err, documents) { + var found = false; + documents.forEach(function(document) { + if(document.name == "integration_tests_.test_collection_methods") found = true; + }); + test.ok(true, found); + // Rename the collection and check that it's gone + client.renameCollection("test_collection_methods", "test_collection_methods2", function(err, reply) { + test.equal(1, reply.documents[0].ok); + // Drop the collection and check that it's gone + client.dropCollection("test_collection_methods2", function(err, result) { + test.equal(true, result); + test.done(); + }) + }); + }); + }) + }, + + // Test the access to collections + shouldAccessToCollections : function(test) { + // Create two collections + client.createCollection('test.spiderman', function(r) { + client.createCollection('test.mario', function(r) { + // Insert test documents (creates collections) + client.collection('test.spiderman', function(err, spiderman_collection) { + spiderman_collection.insert({foo:5}, {safe:true}, function(err, r) { + + client.collection('test.mario', function(err, mario_collection) { + mario_collection.insert({bar:0}, {safe:true}, function(err, r) { + // Assert collections + client.collections(function(err, collections) { + var found_spiderman = false; + var found_mario = false; + var found_does_not_exist = false; + + collections.forEach(function(collection) { + if(collection.collectionName == "test.spiderman") found_spiderman = true; + if(collection.collectionName == "test.mario") found_mario = true; + if(collection.collectionName == "does_not_exist") found_does_not_exist = true; + }); + + test.ok(found_spiderman); + test.ok(found_mario); + test.ok(!found_does_not_exist); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }, + + // Test dropping of collections + shouldCorrectlyDropCollection : function(test) { + client.createCollection('test_drop_collection2', function(err, r) { + client.dropCollection('test_drop_collection', function(err, r) { + test.ok(err instanceof Error); + test.equal("ns not found", err.message); + var found = false; + // Ensure we don't have the collection in the set of names + client.collectionNames(function(err, replies) { + replies.forEach(function(err, document) { + if(document.name == "test_drop_collection") { + found = true; + return; + } + }); + // If we have an instance of the index throw and error + if(found) throw new Error("should not fail"); + // Let's close the db + test.done(); + }); + }); + }); + }, + + // Test dropping using the collection drop command + shouldCorrectlyDropCollectionWithDropFunction : function(test) { + client.createCollection('test_other_drop', function(err, r) { + client.collection('test_other_drop', function(err, collection) { + collection.drop(function(err, reply) { + // Ensure we don't have the collection in the set of names + client.collectionNames(function(err, replies) { + var found = false; + replies.forEach(function(document) { + if(document.name == "test_other_drop") { + found = true; + return; + } + }); + // If we have an instance of the index throw and error + if(found) throw new Error("should not fail"); + // Let's close the db + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyRetriveCollectionNames : function(test) { + client.createCollection('test_collection_names', function(err, r) { + client.collectionNames(function(err, documents) { + var found = false; + var found2 = false; + documents.forEach(function(document) { + if(document.name == MONGODB + '.test_collection_names') found = true; + }); + test.ok(found); + // Insert a document in an non-existing collection should create the collection + client.collection('test_collection_names2', function(err, collection) { + collection.insert({a:1}, {safe:true}, function(err, r) { + client.collectionNames(function(err, documents) { + documents.forEach(function(document) { + if(document.name == MONGODB + '.test_collection_names2') found = true; + if(document.name == MONGODB + '.test_collection_names') found2 = true; + }); + + test.ok(found); + test.ok(found2); + // Let's close the db + test.done(); + }); + }) + }); + }); + }); + }, + + shouldCorrectlyRetrieveCollectionInfo : function(test) { + client.createCollection('test_collections_info', function(err, r) { + client.collectionsInfo(function(err, cursor) { + test.ok((cursor instanceof Cursor)); + // Fetch all the collection info + cursor.toArray(function(err, documents) { + test.ok(documents.length > 1); + + var found = false; + documents.forEach(function(document) { + if(document.name == MONGODB + '.test_collections_info') found = true; + }); + test.ok(found); + // Let's close the db + test.done(); + }); + }); + }); + }, + + shouldCorrectlyRetriveCollectionOptions : function(test) { + client.createCollection('test_collection_options', {'capped':true, 'size':1024}, function(err, collection) { + test.ok(collection instanceof Collection); + test.equal('test_collection_options', collection.collectionName); + // Let's fetch the collection options + collection.options(function(err, options) { + test.equal(true, options.capped); + test.equal(1024, options.size); + test.equal("test_collection_options", options.create); + // Let's close the db + test.done(); + }); + }); + }, + + shouldEnsureStrictAccessCollection : function(test) { + var error_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {strict:true, native_parser: (process.env['TEST_NATIVE'] != null)}); + error_client.bson_deserializer = client.bson_deserializer; + error_client.bson_serializer = client.bson_serializer; + error_client.pkFactory = client.pkFactory; + + test.equal(true, error_client.strict); + error_client.open(function(err, error_client) { + error_client.collection('does-not-exist', function(err, collection) { + test.ok(err instanceof Error); + test.equal("Collection does-not-exist does not exist. Currently in strict mode.", err.message); + }); + + error_client.createCollection('test_strict_access_collection', function(err, collection) { + error_client.collection('test_strict_access_collection', function(err, collection) { + test.ok(collection instanceof Collection); + // Let's close the db + error_client.close(); + test.done(); + }); + }); + }); + }, + + shouldPerformStrictCreateCollection : function(test) { + var error_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {strict:true, native_parser: (process.env['TEST_NATIVE'] != null)}); + error_client.bson_deserializer = client.bson_deserializer; + error_client.bson_serializer = client.bson_serializer; + error_client.pkFactory = client.pkFactory; + test.equal(true, error_client.strict); + + error_client.open(function(err, error_client) { + error_client.createCollection('test_strict_create_collection', function(err, collection) { + test.ok(collection instanceof Collection); + + // Creating an existing collection should fail + error_client.createCollection('test_strict_create_collection', function(err, collection) { + test.ok(err instanceof Error); + test.equal("Collection test_strict_create_collection already exists. Currently in strict mode.", err.message); + + // Switch out of strict mode and try to re-create collection + error_client.strict = false; + error_client.createCollection('test_strict_create_collection', function(err, collection) { + test.ok(collection instanceof Collection); + + // Let's close the db + error_client.close(); + test.done(); + }); + }); + }); + }); + }, + + shouldFailToInsertDueToIllegalKeys : function(test) { + client.createCollection('test_invalid_key_names', function(err, collection) { + // Legal inserts + collection.insert([{'hello':'world'}, {'hello':{'hello':'world'}}], {safe:true}, function(err, r) { + // Illegal insert for key + collection.insert({'$hello':'world'}, {safe:true}, function(err, doc) { + test.ok(err instanceof Error); + test.equal("key $hello must not start with '$'", err.message); + }); + + collection.insert({'hello':{'$hello':'world'}}, {safe:true}, function(err, doc) { + test.ok(err instanceof Error); + test.equal("key $hello must not start with '$'", err.message); + }); + + collection.insert({'he$llo':'world'}, {safe:true}, function(err, docs) { + test.ok(docs[0].constructor == Object); + }) + + collection.insert({'hello':{'hell$o':'world'}}, {safe:true}, function(err, docs) { + test.ok(err == null); + }) + + collection.insert({'.hello':'world'}, {safe:true}, function(err, doc) { + test.ok(err instanceof Error); + test.equal("key .hello must not contain '.'", err.message); + }); + + collection.insert({'hello':{'.hello':'world'}}, {safe:true}, function(err, doc) { + test.ok(err instanceof Error); + test.equal("key .hello must not contain '.'", err.message); + }); + + collection.insert({'hello.':'world'}, {safe:true}, function(err, doc) { + test.ok(err instanceof Error); + test.equal("key hello. must not contain '.'", err.message); + }); + + collection.insert({'hello':{'hello.':'world'}}, {safe:true}, function(err, doc) { + test.ok(err instanceof Error); + test.equal("key hello. must not contain '.'", err.message); + // Let's close the db + test.done(); + }); + }); + }); + }, + + shouldFailDueToIllegalCollectionNames : function(test) { + client.collection(5, function(err, collection) { + test.equal("collection name must be a String", err.message); + }); + + client.collection("", function(err, collection) { + test.equal("collection names cannot be empty", err.message); + }); + + client.collection("te$t", function(err, collection) { + test.equal("collection names must not contain '$'", err.message); + }); + + client.collection(".test", function(err, collection) { + test.equal("collection names must not start or end with '.'", err.message); + }); + + client.collection("test.", function(err, collection) { + test.equal("collection names must not start or end with '.'", err.message); + }); + + client.collection("test..t", function(err, collection) { + test.equal("collection names cannot be empty", err.message); + test.done(); + }); + }, + + // Test the count result on a collection that does not exist + shouldCorrectlyCountOnNonExistingCollection : function(test) { + client.collection('test_multiple_insert_2', function(err, collection) { + collection.count(function(err, count) { + test.equal(0, count); + // Let's close the db + test.done(); + }); + }); + }, + + shouldCorrectlyExecuteSave : function(test) { + client.createCollection('test_save', function(err, collection) { + var doc = {'hello':'world'}; + collection.save(doc, {safe:true}, function(err, docs) { + test.ok(docs._id instanceof client.bson_serializer.ObjectID || Object.prototype.toString.call(docs._id) === '[object ObjectID]'); + + collection.count(function(err, count) { + test.equal(1, count); + doc = docs; + + collection.save(doc, {safe:true}, function(err, doc2) { + + collection.count(function(err, count) { + test.equal(1, count); + + collection.findOne(function(err, doc3) { + test.equal('world', doc3.hello); + + doc3.hello = 'mike'; + + collection.save(doc3, {safe:true}, function(err, doc4) { + collection.count(function(err, count) { + test.equal(1, count); + + collection.findOne(function(err, doc5) { + test.equal('mike', doc5.hello); + + // Save another document + collection.save({hello:'world'}, {safe:true}, function(err, doc) { + collection.count(function(err, count) { + test.equal(2, count); + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlySaveDocumentWithLongValue : function(test) { + client.createCollection('test_save_long', function(err, collection) { + collection.insert({'x':client.bson_serializer.Long.fromNumber(9223372036854775807)}, {safe:true}, function(err, r) { + collection.findOne(function(err, doc) { + test.ok(client.bson_serializer.Long.fromNumber(9223372036854775807).equals(doc.x)); + // Let's close the db + test.done(); + }); + }); + }); + }, + + shouldSaveObjectThatHasIdButDoesNotExistInCollection : function(test) { + client.createCollection('test_save_with_object_that_has_id_but_does_not_actually_exist_in_collection', function(err, collection) { + var a = {'_id':'1', 'hello':'world'}; + collection.save(a, {safe:true}, function(err, docs) { + collection.count(function(err, count) { + test.equal(1, count); + + collection.findOne(function(err, doc) { + test.equal('world', doc.hello); + + doc.hello = 'mike'; + collection.save(doc, {safe:true}, function(err, doc) { + collection.count(function(err, count) { + test.equal(1, count); + }); + + collection.findOne(function(err, doc) { + test.equal('mike', doc.hello); + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyPerformUpsert : function(test) { + client.createCollection('test_should_correctly_do_upsert', function(err, collection) { + var id = new client.bson_serializer.ObjectID(null) + var doc = {_id:id, a:1}; + + Step( + function test1() { + var self = this; + + collection.update({"_id":id}, doc, {upsert:true, safe:true}, function(err, result) { + test.equal(null, err); + test.equal(1, result); + + collection.findOne({"_id":id}, self); + }); + }, + + function test2(err, doc) { + var self = this; + test.equal(1, doc.a); + + id = new client.bson_serializer.ObjectID(null) + doc = {_id:id, a:2}; + + collection.update({"_id":id}, doc, {safe:true, upsert:true}, function(err, result) { + test.equal(null, err); + test.equal(1, result); + + collection.findOne({"_id":id}, self); + }); + }, + + function test3(err, doc2) { + var self = this; + test.equal(2, doc2.a); + + collection.update({"_id":id}, doc2, {safe:true, upsert:true}, function(err, result) { + test.equal(null, err); + test.equal(1, result); + + collection.findOne({"_id":id}, function(err, doc) { + test.equal(2, doc.a); + test.done(); + }); + }); + } + ); + }); + }, + + shouldCorrectlyUpdateWithNoDocs : function(test) { + client.createCollection('test_should_correctly_do_update_with_no_docs', function(err, collection) { + var id = new client.bson_serializer.ObjectID(null) + var doc = {_id:id, a:1}; + collection.update({"_id":id}, doc, {safe:true}, function(err, numberofupdateddocs) { + test.equal(null, err); + test.equal(0, numberofupdateddocs); + + test.done(); + }); + }); + }, + + shouldCorrectlyExecuteInsertUpdateDeleteSafeMode : function(test) { + client.createCollection('test_should_execute_insert_update_delete_safe_mode', function(err, collection) { + test.ok(collection instanceof Collection); + test.equal('test_should_execute_insert_update_delete_safe_mode', collection.collectionName); + + collection.insert({i:1}, {safe:true}, function(err, ids) { + test.equal(1, ids.length); + test.ok(ids[0]._id.toHexString().length == 24); + + // Update the record + collection.update({i:1}, {"$set":{i:2}}, {safe:true}, function(err, result) { + test.equal(null, err); + test.equal(1, result); + + // Remove safely + collection.remove({}, {safe:true}, function(err, result) { + test.equal(null, err); + + test.done(); + }); + }); + }); + }); + }, + + shouldPerformMultipleSaves : function(test) { + client.createCollection("multiple_save_test", function(err, collection) { + var doc = { + name: 'amit', + text: 'some text' + }; + + //insert new user + collection.save(doc, {safe:true}, function(err, r) { + collection.find({}, {name: 1}).limit(1).toArray(function(err, users){ + user = users[0] + + if(err) { + throw new Error(err) + } else if(user) { + user.pants = 'worn' + + collection.save(user, {safe:true}, function(err, result){ + test.equal(null, err); + test.equal(1, result); + + test.done(); + }) + } + }); + }) + }); + }, + + shouldCorrectlySaveDocumentWithNestedArray : function(test) { + var db = new Db(MONGODB, new Server('localhost', 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + db.bson_deserializer = client.bson_deserializer; + db.bson_serializer = client.bson_serializer; + db.pkFactory = client.pkFactory; + + db.open(function(err, db) { + db.createCollection("save_error_on_save_test", function(err, collection) { + // Create unique index for username + collection.createIndex([['username', 1]], true, function(err, result) { + var doc = { + email: 'email@email.com', + encrypted_password: 'password', + friends: + [ '4db96b973d01205364000006', + '4db94a1948a683a176000001', + '4dc77b24c5ba38be14000002' ], + location: [ 72.4930088, 23.0431957 ], + name: 'Amit Kumar', + password_salt: 'salty', + profile_fields: [], + username: 'amit' }; + //insert new user + collection.save(doc, {safe:true}, function(err, doc) { + + collection.find({}).limit(1).toArray(function(err, users) { + test.equal(null, err); + user = users[0] + user.friends.splice(1,1) + + collection.save(user, function(err, doc) { + test.equal(null, err); + + // Update again + collection.update({_id:new client.bson_serializer.ObjectID(user._id.toString())}, {friends:user.friends}, {upsert:true, safe:true}, function(err, result) { + test.equal(null, err); + test.equal(1, result); + + db.close(); + test.done(); + }); + }); + }); + }); + }) + }); + }); + }, + + shouldPeformCollectionRemoveWithNoCallback : function(test) { + client.collection("remove_with_no_callback_bug_test", function(err, collection) { + collection.save({a:1}, {safe:true}, function(){ + collection.save({b:1}, {safe:true}, function(){ + collection.save({c:1}, {safe:true}, function(){ + collection.remove({a:1}, {safe:true}, function() { + // Let's perform a count + collection.count(function(err, count) { + test.equal(null, err); + test.equal(2, count); + test.done(); + }); + }) + }); + }); + }); + }); + }, +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/connect_test.js b/node_modules/mongodb/test/connect_test.js new file mode 100644 index 0000000..eed528c --- /dev/null +++ b/node_modules/mongodb/test/connect_test.js @@ -0,0 +1,92 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + connect = mongodb.connect, + Script = require('vm'), + Collection = mongodb.Collection, + Server = mongodb.Server, + Step = require("../deps/step/lib/step"); + +var MONGODB = 'integration_tests'; +var clientUrl = 'mongo://localhost:27017/' + MONGODB; + +function connectionTester(test, testName) { + return function(err, db) { + test.equal(err, null); + db.collection(testName, function(err, collection) { + test.equal(err, null); + var doc = {foo:123}; + collection.insert({foo:123}, {safe:true}, function(err, docs) { + test.equal(err, null); + db.dropDatabase(function(err, done) { + test.equal(err, null); + test.ok(done); + test.done(); + }); + }); + }); + }; +}; + +exports.testConnectNoOptions = function(test) { + connect(clientUrl, connectionTester(test, 'testConnectNoOptions')); +}; + +exports.testConnectDbOptions = function(test) { + connect(clientUrl, + { db: {native_parser: (process.env['TEST_NATIVE'] != null)} }, + connectionTester(test, 'testConnectDbOptions')); +}; + +exports.testConnectServerOptions = function(test) { + connect(clientUrl, + { server: {auto_reconnect: true, poolSize: 4} }, + connectionTester(test, 'testConnectServerOptions')); +}; + +exports.testConnectAllOptions = function(test) { + connect(clientUrl, + { server: {auto_reconnect: true, poolSize: 4}, + db: {native_parser: (process.env['TEST_NATIVE'] != null)} }, + connectionTester(test, 'testConnectAllOptions')); +}; + +exports.testConnectGoodAuth = function(test) { + var user = 'testConnectGoodAuth', password = 'password'; + // First add a user. + connect(clientUrl, function(err, db) { + test.equal(err, null); + db.addUser(user, password, function(err, result) { + test.equal(err, null); + db.close(); + restOfTest(); + }); + }); + function restOfTest() { + var url = 'mongo://' + user + ':' + password + '@localhost:27017/' + MONGODB; + connect(url, connectionTester(test, 'testConnectGoodAuth')); + } +}; + +exports.testConnectBadAuth = function(test) { + var url = 'mongo://slithy:toves@localhost:27017/' + MONGODB; + connect(url, function(err, db) { + test.ok(err); + test.equal(db, null); + test.done(); + }); +}; + +exports.testConnectBadUrl = function(test) { + test.throws(function() { + connect('mango://localhost:27017/' + MONGODB, function(err, db) { + test.ok(false, 'Bad URL!'); + }); + }); + test.done(); +}; diff --git a/node_modules/mongodb/test/connection_test.js b/node_modules/mongodb/test/connection_test.js new file mode 100644 index 0000000..6cc6297 --- /dev/null +++ b/node_modules/mongodb/test/connection_test.js @@ -0,0 +1,84 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + connect = mongodb.connect, + Script = require('vm'), + Collection = mongodb.Collection, + Server = mongodb.Server, + ServerManager = require('../test/tools/server_manager').ServerManager, + Step = require("../deps/step/lib/step"); + +// Test db +var MONGODB = 'integration_tests'; + +function connectionTester(test, testName, callback) { + return function(err, db) { + test.equal(err, null); + db.collection(testName, function(err, collection) { + test.equal(err, null); + var doc = {foo:123}; + collection.insert({foo:123}, {safe:true}, function(err, docs) { + test.equal(err, null); + db.dropDatabase(function(err, done) { + test.equal(err, null); + test.ok(done); + callback(); + }); + }); + }); + }; +}; + +var console = require('console'); +exports.testCloseNoCallback = function(test) { + var db = new Db(MONGODB, + new Server("127.0.0.1", 27017, + {auto_reconnect: true, poolSize: 4}), + {native_parser: (process.env['TEST_NATIVE'] != null)}); + db.open(connectionTester(test, 'testCloseNoCallback', function() { + var dbCloseCount = 0, connectionCloseCount = 0, poolCloseCount = 0; + db.on('close', function() { ++dbCloseCount; }); + var connection = db.serverConfig.connection; + connection.on('close', function() { ++connectionCloseCount; }); + connection.pool.forEach(function(poolMember) { + poolMember.connection.on('close', function() { ++poolCloseCount; }); + }); + db.close(); + setTimeout(function() { + test.equal(dbCloseCount, 1); + test.equal(connectionCloseCount, 1); + test.equal(poolCloseCount, 4); + test.done(); + }, 250); + })); +}; + +exports.testCloseWithCallback = function(test) { + var db = new Db(MONGODB, + new Server("127.0.0.1", 27017, + {auto_reconnect: true, poolSize: 4}), + {native_parser: (process.env['TEST_NATIVE'] != null)}); + db.open(connectionTester(test, 'testCloseWithCallback', function() { + var dbCloseCount = 0, connectionCloseCount = 0, poolCloseCount = 0; + db.on('close', function() { ++dbCloseCount; }); + var connection = db.serverConfig.connection; + connection.on('close', function() { ++connectionCloseCount; }); + connection.pool.forEach(function(poolMember) { + poolMember.connection.on('close', function() { ++poolCloseCount; }); + }); + db.close(function() { + // Let all events fire. + process.nextTick(function() { + test.equal(dbCloseCount, 1); + test.equal(connectionCloseCount, 1); + test.equal(poolCloseCount, 4); + test.done(); + }); + }); + })); +}; \ No newline at end of file diff --git a/node_modules/mongodb/test/cursor_test.js b/node_modules/mongodb/test/cursor_test.js new file mode 100644 index 0000000..fdbe9ec --- /dev/null +++ b/node_modules/mongodb/test/cursor_test.js @@ -0,0 +1,954 @@ +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = require('../lib/mongodb').Db, + Cursor = require('../lib/mongodb').Cursor, + Step = require("../deps/step/lib/step"), + Collection = require('../lib/mongodb').Collection, + Server = require('../lib/mongodb').Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldCorrectlyExecuteToArray : function(test) { + // Create a non-unique index and test inserts + client.createCollection('test_array', function(err, collection) { + collection.insert({'b':[1, 2, 3]}, {safe:true}, function(err, ids) { + collection.find().toArray(function(err, documents) { + test.deepEqual([1, 2, 3], documents[0].b); + // Let's close the db + test.done(); + }); + }); + }); + }, + + shouldCorrectlyExecuteToArrayAndFailOnFurtherCursorAccess : function(test) { + client.createCollection('test_to_a', function(err, collection) { + test.ok(collection instanceof Collection); + collection.insert({'a':1}, {safe:true}, function(err, ids) { + collection.find({}, function(err, cursor) { + cursor.toArray(function(err, items) { + // Should fail if called again (cursor should be closed) + cursor.toArray(function(err, items) { + test.ok(err instanceof Error); + test.equal("Cursor is closed", err.message); + + // Should fail if called again (cursor should be closed) + cursor.each(function(err, item) { + test.ok(err instanceof Error); + test.equal("Cursor is closed", err.message); + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyFailToArrayDueToFinishedEachOperation : function(test) { + client.createCollection('test_to_a_after_each', function(err, collection) { + test.ok(collection instanceof Collection); + collection.insert({'a':1}, {safe:true}, function(err, ids) { + collection.find(function(err, cursor) { + cursor.each(function(err, item) { + if(item == null) { + cursor.toArray(function(err, items) { + test.ok(err instanceof Error); + test.equal("Cursor is closed", err.message); + + // Let's close the db + test.done(); + }); + }; + }); + }); + }); + }); + }, + + shouldCorrectlyExecuteCursorExplain : function(test) { + client.createCollection('test_explain', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(err, r) { + collection.find({'a':1}, function(err, cursor) { + cursor.explain(function(err, explaination) { + test.ok(explaination.cursor != null); + test.ok(explaination.n.constructor == Number); + test.ok(explaination.millis.constructor == Number); + test.ok(explaination.nscanned.constructor == Number); + + // Let's close the db + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyExecuteCursorCount : function(test) { + client.createCollection('test_count', function(err, collection) { + collection.find(function(err, cursor) { + cursor.count(function(err, count) { + test.equal(0, count); + + Step( + function insert() { + var group = this.group(); + + for(var i = 0; i < 10; i++) { + collection.insert({'x':i}, {safe:true}, group()); + } + }, + + function finished() { + collection.find().count(function(err, count) { + test.equal(10, count); + test.ok(count.constructor == Number); + }); + + collection.find({}, {'limit':5}).count(function(err, count) { + test.equal(10, count); + }); + + collection.find({}, {'skip':5}).count(function(err, count) { + test.equal(10, count); + }); + + collection.find(function(err, cursor) { + cursor.count(function(err, count) { + test.equal(10, count); + + cursor.each(function(err, item) { + if(item == null) { + cursor.count(function(err, count2) { + test.equal(10, count2); + test.equal(count, count2); + // Let's close the db + test.done(); + }); + } + }); + }); + }); + + client.collection('acollectionthatdoesn', function(err, collection) { + collection.count(function(err, count) { + test.equal(0, count); + }); + }) + } + ) + }); + }); + }); + }, + + shouldCorrectlyExecuteSortOnCursor : function(test) { + client.createCollection('test_sort', function(err, collection) { + Step( + function insert() { + var group = this.group(); + + for(var i = 0; i < 5; i++) { + collection.insert({'a':i}, {safe:true}, group()); + } + }, + + function finished() { + collection.find(function(err, cursor) { + cursor.sort(['a', 1], function(err, cursor) { + test.ok(cursor instanceof Cursor); + test.deepEqual(['a', 1], cursor.sortValue); + }); + }); + + collection.find(function(err, cursor) { + cursor.sort('a', 1, function(err, cursor) { + cursor.nextObject(function(err, doc) { + test.equal(0, doc.a); + }); + }); + }); + + collection.find(function(err, cursor) { + cursor.sort('a', -1, function(err, cursor) { + cursor.nextObject(function(err, doc) { + test.equal(4, doc.a); + }); + }); + }); + + collection.find(function(err, cursor) { + cursor.sort('a', "asc", function(err, cursor) { + cursor.nextObject(function(err, doc) { + test.equal(0, doc.a); + }); + }); + }); + + collection.find(function(err, cursor) { + cursor.sort([['a', -1], ['b', 1]], function(err, cursor) { + test.ok(cursor instanceof Cursor); + test.deepEqual([['a', -1], ['b', 1]], cursor.sortValue); + }); + }); + + collection.find(function(err, cursor) { + cursor.sort('a', 1, function(err, cursor) { + cursor.sort('a', -1, function(err, cursor) { + cursor.nextObject(function(err, doc) { + test.equal(4, doc.a); + }); + }) + }); + }); + + collection.find(function(err, cursor) { + cursor.sort('a', -1, function(err, cursor) { + cursor.sort('a', 1, function(err, cursor) { + cursor.nextObject(function(err, doc) { + test.equal(0, doc.a); + }); + }) + }); + }); + + collection.find(function(err, cursor) { + cursor.nextObject(function(err, doc) { + cursor.sort(['a'], function(err, cursor) { + test.ok(err instanceof Error); + test.equal("Cursor is closed", err.message); + }); + }); + }); + + collection.find(function(err, cursor) { + cursor.sort('a', 25, function(err, cursor) { + cursor.nextObject(function(err, doc) { + test.ok(err instanceof Error); + test.equal("Illegal sort clause, must be of the form [['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]", err.message); + }); + }); + }); + + collection.find(function(err, cursor) { + cursor.sort(25, function(err, cursor) { + cursor.nextObject(function(err, doc) { + test.ok(err instanceof Error); + test.equal("Illegal sort clause, must be of the form [['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]", err.message); + // Let's close the db + test.done(); + }); + }); + }); + } + ); + }); + }, + + shouldCorrectlyThrowErrorOnToArrayWhenMissingCallback : function(test) { + client.createCollection('test_to_array', function(err, collection) { + Step( + function insert() { + var group = this.group(); + + for(var i = 0; i < 2; i++) { + collection.save({'x':1}, {safe:true}, group()); + } + }, + + function finished() { + collection.find(function(err, cursor) { + test.throws(function () { + cursor.toArray(); + }); + test.done(); + }); + } + ) + }); + }, + + shouldThrowErrorOnEachWhenMissingCallback : function(test) { + client.createCollection('test_each', function(err, collection) { + Step( + function insert() { + var group = this.group(); + + for(var i = 0; i < 2; i++) { + collection.save({'x':1}, {safe:true}, group()); + } + }, + + function finished() { + collection.find(function(err, cursor) { + test.throws(function () { + cursor.each(); + }); + test.done(); + }); + } + ) + }); + }, + + shouldCorrectlyHandleLimitOnCursor : function(test) { + client.createCollection('test_cursor_limit', function(err, collection) { + Step( + function insert() { + var group = this.group(); + + for(var i = 0; i < 10; i++) { + collection.save({'x':1}, {safe:true}, group()); + } + }, + + function finished() { + collection.find().count(function(err, count) { + test.equal(10, count); + }); + + collection.find(function(err, cursor) { + cursor.limit(5, function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(5, items.length); + // Let's close the db + test.done(); + }); + }); + }); + } + ); + }); + }, + + shouldCorrectlyReturnErrorsOnIllegalLimitValues : function(test) { + client.createCollection('test_limit_exceptions', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(err, docs) {}); + collection.find(function(err, cursor) { + cursor.limit('not-an-integer', function(err, cursor) { + test.ok(err instanceof Error); + test.equal("limit requires an integer", err.message); + }); + }); + + collection.find(function(err, cursor) { + cursor.nextObject(function(err, doc) { + cursor.limit(1, function(err, cursor) { + test.ok(err instanceof Error); + test.equal("Cursor is closed", err.message); + }); + }); + }); + + collection.find(function(err, cursor) { + cursor.close(function(err, cursor) { + cursor.limit(1, function(err, cursor) { + test.ok(err instanceof Error); + test.equal("Cursor is closed", err.message); + + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlySkipRecordsOnCursor : function(test) { + client.createCollection('test_skip', function(err, collection) { + Step( + function insert() { + var group = this.group(); + + for(var i = 0; i < 10; i++) { + collection.insert({'x':i}, {safe:true}, group()); + } + }, + + function finished() { + collection.find(function(err, cursor) { + cursor.count(function(err, count) { + test.equal(10, count); + }); + }); + + collection.find(function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(10, items.length); + + collection.find(function(err, cursor) { + cursor.skip(2, function(err, cursor) { + cursor.toArray(function(err, items2) { + test.equal(8, items2.length); + + // Check that we have the same elements + var numberEqual = 0; + var sliced = items.slice(2, 10); + + for(var i = 0; i < sliced.length; i++) { + if(sliced[i].x == items2[i].x) numberEqual = numberEqual + 1; + } + test.equal(8, numberEqual); + + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + } + ) + }); + }, + + shouldCorrectlyReturnErrorsOnIllegalSkipValues : function(test) { + client.createCollection('test_skip_exceptions', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(err, docs) {}); + collection.find(function(err, cursor) { + cursor.skip('not-an-integer', function(err, cursor) { + test.ok(err instanceof Error); + test.equal("skip requires an integer", err.message); + }); + }); + + collection.find(function(err, cursor) { + cursor.nextObject(function(err, doc) { + cursor.skip(1, function(err, cursor) { + test.ok(err instanceof Error); + test.equal("Cursor is closed", err.message); + }); + }); + }); + + collection.find(function(err, cursor) { + cursor.close(function(err, cursor) { + cursor.skip(1, function(err, cursor) { + test.ok(err instanceof Error); + test.equal("Cursor is closed", err.message); + + test.done(); + }); + }); + }); + }); + }, + + shouldReturnErrorsOnIllegalBatchSizes : function(test) { + client.createCollection('test_batchSize_exceptions', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(err, docs) {}); + collection.find(function(err, cursor) { + cursor.batchSize('not-an-integer', function(err, cursor) { + test.ok(err instanceof Error); + test.equal("batchSize requires an integer", err.message); + }); + }); + + collection.find(function(err, cursor) { + cursor.nextObject(function(err, doc) { + cursor.nextObject(function(err, doc) { + cursor.batchSize(1, function(err, cursor) { + test.ok(err instanceof Error); + test.equal("Cursor is closed", err.message); + }); + }); + }); + }); + + collection.find(function(err, cursor) { + cursor.close(function(err, cursor) { + cursor.batchSize(1, function(err, cursor) { + test.ok(err instanceof Error); + test.equal("Cursor is closed", err.message); + + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyHandleChangesInBatchSizes : function(test) { + client.createCollection('test_not_multiple_batch_size', function(err, collection) { + var records = 6; + var batchSize = 2; + var docs = []; + for(var i = 0; i < records; i++) { + docs.push({'a':i}); + } + + collection.insert(docs, {safe:true}, function() { + collection.find({}, {batchSize : batchSize}, function(err, cursor) { + //1st + cursor.nextObject(function(err, items) { + //cursor.items should contain 1 since nextObject already popped one + test.equal(1, cursor.items.length); + test.ok(items != null); + + //2nd + cursor.nextObject(function(err, items) { + test.equal(0, cursor.items.length); + test.ok(items != null); + + //test batch size modification on the fly + batchSize = 3; + cursor.batchSize(batchSize); + + //3rd + cursor.nextObject(function(err, items) { + test.equal(2, cursor.items.length); + test.ok(items != null); + + //4th + cursor.nextObject(function(err, items) { + test.equal(1, cursor.items.length); + test.ok(items != null); + + //5th + cursor.nextObject(function(err, items) { + test.equal(0, cursor.items.length); + test.ok(items != null); + + //6th + cursor.nextObject(function(err, items) { + test.equal(0, cursor.items.length); + test.ok(items != null); + + //No more + cursor.nextObject(function(err, items) { + test.ok(items == null); + test.ok(cursor.isClosed()); + + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyHandleBatchSize : function(test) { + client.createCollection('test_multiple_batch_size', function(err, collection) { + //test with the last batch that is a multiple of batchSize + var records = 4; + var batchSize = 2; + var docs = []; + for(var i = 0; i < records; i++) { + docs.push({'a':i}); + } + + collection.insert(docs, {safe:true}, function() { + collection.find({}, {batchSize : batchSize}, function(err, cursor) { + //1st + cursor.nextObject(function(err, items) { + test.equal(1, cursor.items.length); + test.ok(items != null); + + //2nd + cursor.nextObject(function(err, items) { + test.equal(0, cursor.items.length); + test.ok(items != null); + + //3rd + cursor.nextObject(function(err, items) { + test.equal(1, cursor.items.length); + test.ok(items != null); + + //4th + cursor.nextObject(function(err, items) { + test.equal(0, cursor.items.length); + test.ok(items != null); + + //No more + cursor.nextObject(function(err, items) { + test.ok(items == null); + test.ok(cursor.isClosed()); + + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldHandleWhenLimitBiggerThanBatchSize : function(test) { + client.createCollection('test_limit_greater_than_batch_size', function(err, collection) { + var limit = 4; + var records = 10; + var batchSize = 3; + var docs = []; + for(var i = 0; i < records; i++) { + docs.push({'a':i}); + } + + collection.insert(docs, {safe:true}, function() { + collection.find({}, {batchSize : batchSize, limit : limit}, function(err, cursor) { + //1st + cursor.nextObject(function(err, items) { + test.equal(2, cursor.items.length); + + //2nd + cursor.nextObject(function(err, items) { + test.equal(1, cursor.items.length); + + //3rd + cursor.nextObject(function(err, items) { + test.equal(0, cursor.items.length); + + //4th + cursor.nextObject(function(err, items) { + test.equal(0, cursor.items.length); + + //No more + cursor.nextObject(function(err, items) { + test.ok(items == null); + test.ok(cursor.isClosed()); + + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldHandleLimitLessThanBatchSize : function(test) { + client.createCollection('test_limit_less_than_batch_size', function(err, collection) { + var limit = 2; + var records = 10; + var batchSize = 4; + var docs = []; + for(var i = 0; i < records; i++) { + docs.push({'a':i}); + } + + collection.insert(docs, {safe:true}, function() { + collection.find({}, {batchSize : batchSize, limit : limit}, function(err, cursor) { + //1st + cursor.nextObject(function(err, items) { + test.equal(1, cursor.items.length); + + //2nd + cursor.nextObject(function(err, items) { + test.equal(0, cursor.items.length); + + //No more + cursor.nextObject(function(err, items) { + test.ok(items == null); + test.ok(cursor.isClosed()); + + test.done(); + }); + }); + }); + }); + }); + }); + }, + + shouldHandleSkipLimitChaining : function(test) { + client.createCollection('test_limit_skip_chaining', function(err, collection) { + Step( + function insert() { + var group = this.group(); + + for(var i = 0; i < 10; i++) { + collection.insert({'x':1}, {safe:true}, group()); + } + }, + + function finished() { + collection.find(function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(10, items.length); + + collection.find(function(err, cursor) { + cursor.limit(5, function(err, cursor) { + cursor.skip(3, function(err, cursor) { + cursor.toArray(function(err, items2) { + test.equal(5, items2.length); + + // Check that we have the same elements + var numberEqual = 0; + var sliced = items.slice(3, 8); + + for(var i = 0; i < sliced.length; i++) { + if(sliced[i].x == items2[i].x) numberEqual = numberEqual + 1; + } + test.equal(5, numberEqual); + + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + }); + } + ) + }); + }, + + shouldCorrectlyHandleLimitSkipChainingInline : function(test) { + client.createCollection('test_limit_skip_chaining_inline', function(err, collection) { + Step( + function insert() { + var group = this.group(); + + for(var i = 0; i < 10; i++) { + collection.insert({'x':1}, {safe:true}, group()); + } + }, + + function finished() { + collection.find(function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(10, items.length); + + collection.find(function(err, cursor) { + cursor.limit(5).skip(3).toArray(function(err, items2) { + test.equal(5, items2.length); + + // Check that we have the same elements + var numberEqual = 0; + var sliced = items.slice(3, 8); + + for(var i = 0; i < sliced.length; i++) { + if(sliced[i].x == items2[i].x) numberEqual = numberEqual + 1; + } + test.equal(5, numberEqual); + + // Let's close the db + test.done(); + }); + }); + }); + }); + } + ) + }); + }, + + shouldCloseCursorNoQuerySent : function(test) { + client.createCollection('test_close_no_query_sent', function(err, collection) { + collection.find(function(err, cursor) { + cursor.close(function(err, cursor) { + test.equal(true, cursor.isClosed()); + // Let's close the db + test.done(); + }); + }); + }); + }, + + shouldCorrectlyRefillViaGetMoreCommand : function(test) { + client.createCollection('test_refill_via_get_more', function(err, collection) { + Step( + function insert() { + var group = this.group(); + + for(var i = 0; i < 1000; i++) { + collection.save({'a': i}, {safe:true}, group()); + } + }, + + function finished() { + collection.count(function(err, count) { + test.equal(1000, count); + }); + + var total = 0; + collection.find(function(err, cursor) { + cursor.each(function(err, item) { + if(item != null) { + total = total + item.a; + } else { + test.equal(499500, total); + + collection.count(function(err, count) { + test.equal(1000, count); + }); + + collection.count(function(err, count) { + test.equal(1000, count); + + var total2 = 0; + collection.find(function(err, cursor) { + cursor.each(function(err, item) { + if(item != null) { + total2 = total2 + item.a; + } else { + test.equal(499500, total2); + collection.count(function(err, count) { + test.equal(1000, count); + test.equal(total, total2); + // Let's close the db + test.done(); + }); + } + }); + }); + }); + } + }); + }); + } + ) + }); + }, + + shouldCorrectlyRefillViaGetMoreAlternativeCollection : function(test) { + client.createCollection('test_refill_via_get_more_alt_coll', function(err, collection) { + + Step( + function insert() { + var group = this.group(); + + for(var i = 0; i < 1000; i++) { + collection.save({'a': i}, {safe:true}, group()); + } + }, + + function finished() { + collection.count(function(err, count) { + test.equal(1000, count); + }); + + var total = 0; + collection.find(function(err, cursor) { + cursor.each(function(err, item) { + if(item != null) { + total = total + item.a; + } else { + test.equal(499500, total); + + collection.count(function(err, count) { + test.equal(1000, count); + }); + + collection.count(function(err, count) { + test.equal(1000, count); + + var total2 = 0; + collection.find(function(err, cursor) { + cursor.each(function(err, item) { + if(item != null) { + total2 = total2 + item.a; + } else { + test.equal(499500, total2); + collection.count(function(err, count) { + test.equal(1000, count); + test.equal(total, total2); + // Let's close the db + test.done(); + }); + } + }); + }); + }); + } + }); + }); + } + ) + }); + }, + + shouldCloseCursorAfterQueryHasBeenSent : function(test) { + client.createCollection('test_close_after_query_sent', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(err, r) { + collection.find({'a':1}, function(err, cursor) { + cursor.nextObject(function(err, item) { + cursor.close(function(err, cursor) { + test.equal(true, cursor.isClosed()); + // Let's close the db + test.done(); + }) + }); + }); + }); + }); + }, + + shouldCorrectlyExecuteCursorCountWithFields : function(test) { + client.createCollection('test_count_with_fields', function(err, collection) { + collection.save({'x':1, 'a':2}, {safe:true}, function(err, doc) { + collection.find({}, {'fields':['a']}).toArray(function(err, items) { + test.equal(1, items.length); + test.equal(2, items[0].a); + test.equal(null, items[0].x); + }); + + collection.findOne({}, {'fields':['a']}, function(err, item) { + test.equal(2, item.a); + test.equal(null, item.x); + test.done(); + }); + }); + }); + }, + + shouldCorrectlyCountWithFieldsUsingExclude : function(test) { + client.createCollection('test_count_with_fields_using_exclude', function(err, collection) { + collection.save({'x':1, 'a':2}, {safe:true}, function(err, doc) { + collection.find({}, {'fields':{'x':0}}).toArray(function(err, items) { + test.equal(1, items.length); + test.equal(2, items[0].a); + test.equal(null, items[0].x); + test.done(); + }); + }); + }); + } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; diff --git a/node_modules/mongodb/test/custom_pk_test.js b/node_modules/mongodb/test/custom_pk_test.js new file mode 100644 index 0000000..aaa437e --- /dev/null +++ b/node_modules/mongodb/test/custom_pk_test.js @@ -0,0 +1,79 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4, native_parser: (process.env['TEST_NATIVE'] != null) ? true : false})); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldCreateRecordsWithCustomPKFactory : function(test) { + // Custom factory (need to provide a 12 byte array); + CustomPKFactory = function() {} + CustomPKFactory.prototype = new Object(); + CustomPKFactory.createPk = function() { + return new client.bson_serializer.ObjectID("aaaaaaaaaaaa"); + } + + var p_client = new Db(MONGODB, new Server("127.0.0.1", 27017), {'pk':CustomPKFactory, native_parser: (process.env['TEST_NATIVE'] != null)}); + p_client.bson_deserializer = client.bson_deserializer; + p_client.bson_serializer = client.bson_serializer; + + p_client.open(function(err, p_client) { + p_client.dropDatabase(function(err, done) { + p_client.createCollection('test_custom_key', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(err, doc) { + collection.find({'_id':new client.bson_serializer.ObjectID("aaaaaaaaaaaa")}, function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(1, items.length); + + p_client.close(); + test.done(); + }); + }); + }); + }); + }); + }); + }, +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/db_test.js b/node_modules/mongodb/test/db_test.js new file mode 100644 index 0000000..6db61ee --- /dev/null +++ b/node_modules/mongodb/test/db_test.js @@ -0,0 +1,305 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + // Test the auto connect functionality of the db + shouldCorrectlyPerformAutomaticConnect : function(test) { + var automatic_connect_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + automatic_connect_client.bson_deserializer = client.bson_deserializer; + automatic_connect_client.bson_serializer = client.bson_serializer; + automatic_connect_client.pkFactory = client.pkFactory; + + automatic_connect_client.open(function(err, automatic_connect_client) { + + // Listener for closing event + var closeListener = function(has_error) { + + // Remove the listener for the close to avoid loop + automatic_connect_client.removeListener("close", closeListener); + // Let's insert a document + automatic_connect_client.collection('test_object_id_generation.data2', function(err, collection) { + + // Insert another test document and collect using ObjectId + collection.insert({"name":"Patty", "age":34}, {safe:true}, function(err, ids) { + test.equal(1, ids.length); + test.ok(ids[0]._id.toHexString().length == 24); + + collection.findOne({"name":"Patty"}, function(err, document) { + test.equal(ids[0]._id.toHexString(), document._id.toHexString()); + // Let's close the db + automatic_connect_client.close(); + test.done(); + }); + }); + }); + }; + + // Add listener to close event + automatic_connect_client.on("close", closeListener); + automatic_connect_client.close(); + }); + }, + + // // Test that error conditions are handled correctly + // shouldCorrectlyHandleConnectionErrors : function(test) { + // // Test error handling for single server connection + // var serverConfig = new Server("127.0.0.1", 21017, {auto_reconnect: true}); + // var error_client = new Db(MONGODB, serverConfig, {native_parser: (process.env['TEST_NATIVE'] != null) ? true : false}); + // + // error_client.on("error", function(err) {}); + // error_client.on("close", function(connection) { + // test.ok(typeof connection == typeof serverConfig); + // test.equal("127.0.0.1", connection.host); + // test.equal(21017, connection.port); + // test.equal(true, connection.autoReconnect); + // test.done(); + // }); + // error_client.open(function(err, error_client) {}); + // }, + // + // shouldCorrectlyExecuteEvalFunctions : function(test) { + // client.eval('function (x) {return x;}', [3], function(err, result) { + // test.equal(3, result); + // }); + // + // client.eval('function (x) {db.test_eval.save({y:x});}', [5], function(err, result) { + // // Locate the entry + // client.collection('test_eval', function(err, collection) { + // collection.findOne(function(err, item) { + // test.equal(5, item.y); + // }); + // }); + // }); + // + // client.eval('function (x, y) {return x + y;}', [2, 3], function(err, result) { + // test.equal(5, result); + // }); + // + // client.eval('function () {return 5;}', function(err, result) { + // test.equal(5, result); + // }); + // + // client.eval('2 + 3;', function(err, result) { + // test.equal(5, result); + // }); + // + // client.eval(new client.bson_serializer.Code("2 + 3;"), function(err, result) { + // test.equal(5, result); + // }); + // + // client.eval(new client.bson_serializer.Code("return i;", {'i':2}), function(err, result) { + // test.equal(2, result); + // }); + // + // client.eval(new client.bson_serializer.Code("i + 3;", {'i':2}), function(err, result) { + // test.equal(5, result); + // }); + // + // client.eval("5 ++ 5;", function(err, result) { + // test.ok(err instanceof Error); + // test.ok(err.message != null); + // // Let's close the db + // test.done(); + // }); + // }, + // + // shouldCorrectlyDereferenceDbRef : function(test) { + // client.createCollection('test_deref', function(err, collection) { + // collection.insert({'a':1}, {safe:true}, function(err, ids) { + // collection.remove({}, {safe:true}, function(err, result) { + // collection.count(function(err, count) { + // test.equal(0, count); + // + // // Execute deref a db reference + // client.dereference(new client.bson_serializer.DBRef("test_deref", new client.bson_serializer.ObjectID()), function(err, result) { + // collection.insert({'x':'hello'}, {safe:true}, function(err, ids) { + // collection.findOne(function(err, document) { + // test.equal('hello', document.x); + // + // client.dereference(new client.bson_serializer.DBRef("test_deref", document._id), function(err, result) { + // test.equal('hello', document.x); + // + // client.dereference(new client.bson_serializer.DBRef("test_deref", 4), function(err, result) { + // var obj = {'_id':4}; + // + // collection.insert(obj, {safe:true}, function(err, ids) { + // client.dereference(new client.bson_serializer.DBRef("test_deref", 4), function(err, document) { + // + // test.equal(obj['_id'], document._id); + // collection.remove({}, {safe:true}, function(err, result) { + // collection.insert({'x':'hello'}, {safe:true}, function(err, ids) { + // client.dereference(new client.bson_serializer.DBRef("test_deref", null), function(err, result) { + // test.equal(null, result); + // // Let's close the db + // test.done(); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }) + // }) + // }) + // }); + // }, + // + // shouldCorrectlyRenameCollection : function(test) { + // client.createCollection('test_rename_collection', function(err, collection) { + // client.createCollection('test_rename_collection2', function(err, collection) { + // client.collection('test_rename_collection', function(err, collection1) { + // client.collection('test_rename_collection2', function(err, collection2) { + // // Assert rename + // collection1.rename(5, function(err, collection) { + // test.ok(err instanceof Error); + // test.equal("collection name must be a String", err.message); + // }); + // + // collection1.rename("", function(err, collection) { + // test.ok(err instanceof Error); + // test.equal("collection names cannot be empty", err.message); + // }); + // + // collection1.rename("te$t", function(err, collection) { + // test.ok(err instanceof Error); + // test.equal("collection names must not contain '$'", err.message); + // }); + // + // collection1.rename(".test", function(err, collection) { + // test.ok(err instanceof Error); + // test.equal("collection names must not start or end with '.'", err.message); + // }); + // + // collection1.rename("test.", function(err, collection) { + // test.ok(err instanceof Error); + // test.equal("collection names must not start or end with '.'", err.message); + // }); + // + // collection1.rename("tes..t", function(err, collection) { + // test.equal("collection names cannot be empty", err.message); + // }); + // + // collection1.count(function(err, count) { + // test.equal(0, count); + // + // collection1.insert([{'x':1}, {'x':2}], {safe:true}, function(err, docs) { + // collection1.count(function(err, count) { + // test.equal(2, count); + // + // collection1.rename('test_rename_collection2', function(err, collection) { + // test.ok(err instanceof Error); + // test.ok(err.message.length > 0); + // + // collection1.rename('test_rename_collection3', function(err, collection) { + // test.equal("test_rename_collection3", collection.collectionName); + // + // // Check count + // collection.count(function(err, count) { + // test.equal(2, count); + // // Let's close the db + // test.done(); + // }); + // }); + // }); + // }); + // }) + // }) + // + // collection2.count(function(err, count) { + // test.equal(0, count); + // }) + // }); + // }); + // }); + // }); + // }, + // + // shouldCorrectlyHandleFailedConnection : function(test) { + // var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27117, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + // fs_client.bson_deserializer = client.bson_deserializer; + // fs_client.bson_serializer = client.bson_serializer; + // fs_client.pkFactory = client.pkFactory; + // fs_client.open(function(err, fs_client) { + // test.ok(err != null) + // test.done(); + // }) + // }, + // + // shouldCorrectlyResaveDBRef : function(test) { + // client.dropCollection('test_resave_dbref', function() { + // client.createCollection('test_resave_dbref', function(err, collection) { + // test.ifError(err); + // collection.insert({'name': 'parent'}, {safe : true}, function(err, objs) { + // test.ok(objs && objs.length == 1 && objs[0]._id != null); + // var parent = objs[0]; + // var child = {'name' : 'child', 'parent' : new client.bson_serializer.DBRef("test_resave_dbref", parent._id)}; + // collection.insert(child, {safe : true}, function(err, objs) { + // test.ifError(err); + // collection.findOne({'name' : 'child'}, function(err, child) { //Child deserialized + // test.ifError(err); + // test.ok(child != null); + // collection.save(child, {save : true}, function(err) { + // test.ifError(err); //Child node with dbref resaved! + // collection.findOne({'parent' : new client.bson_serializer.DBRef("test_resave_dbref", parent._id)}, + // function(err, child) { + // test.ifError(err); + // test.ok(child != null);//!!!! Main test point! + // test.done(); + // }) + // }); + // }); + // }); + // }); + // }); + // }); + // } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/error_test.js b/node_modules/mongodb/test/error_test.js new file mode 100644 index 0000000..6017950 --- /dev/null +++ b/node_modules/mongodb/test/error_test.js @@ -0,0 +1,267 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + // Test the error reporting functionality + shouldCorrectlyRetrieveErrorMessagesFromServer : function(test) { + // Just run with one connection in the pool + var error_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false, poolSize:1}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + error_client.bson_deserializer = client.bson_deserializer; + error_client.bson_serializer = client.bson_serializer; + error_client.pkFactory = client.pkFactory; + + // Open the db + error_client.open(function(err, error_client) { + error_client.resetErrorHistory(function() { + error_client.error(function(err, documents) { + test.equal(true, documents[0].ok); + test.equal(0, documents[0].n); + + // Force error on server + error_client.executeDbCommand({forceerror: 1}, function(err, r) { + test.equal(0, r.documents[0].ok); + test.ok(r.documents[0].errmsg.length > 0); + // Check for previous errors + error_client.previousErrors(function(err, documents) { + test.equal(true, documents[0].ok); + test.equal(1, documents[0].nPrev); + test.equal("forced error", documents[0].err); + + // Check for the last error + error_client.error(function(err, documents) { + test.equal("forced error", documents[0].err); + // Force another error + error_client.collection('test_error_collection', function(err, collection) { + collection.findOne({name:"Fred"}, function(err, document) { + // Check that we have two previous errors + error_client.previousErrors(function(err, documents) { + test.equal(true, documents[0].ok); + test.equal(2, documents[0].nPrev); + test.equal("forced error", documents[0].err); + + error_client.resetErrorHistory(function() { + error_client.previousErrors(function(err, documents) { + test.equal(true, documents[0].ok); + test.equal(-1, documents[0].nPrev); + + error_client.error(function(err, documents) { + test.equal(true, documents[0].ok); + test.equal(0, documents[0].n); + + // Let's close the db + error_client.close(); + + error_client.error(function(err, documents) { + test.ok(err instanceof Error); + test.ok('notConnected' === err.message); + test.done(); + }); + }); + }) + }); + }); + }); + }); + }) + }); + }); + }); + }); + }); + }, + + // Test the last status functionality of the driver + shouldCorrectlyExecuteLastStatus : function(test) { + // Just run with one connection in the pool + var error_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false, poolSize:1,}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + error_client.bson_deserializer = client.bson_deserializer; + error_client.bson_serializer = client.bson_serializer; + error_client.pkFactory = client.pkFactory; + + // Open the db + error_client.open(function(err, client) { + client.createCollection('test_last_status', function(err, collection) { + test.ok(collection instanceof Collection); + test.equal('test_last_status', collection.collectionName); + + // Get the collection + client.collection('test_last_status', function(err, collection) { + // Remove all the elements of the collection + collection.remove(function(err, result) { + // Check update of a document + collection.insert({i:1}, function(err, ids) { + test.equal(1, ids.length); + test.ok(ids[0]._id.toHexString().length == 24); + + // Update the record + collection.update({i:1}, {"$set":{i:2}}, function(err, result) { + // Check for the last message from the server + client.lastStatus(function(err, status) { + test.equal(true, status.documents[0].ok); + test.equal(true, status.documents[0].updatedExisting); + // Check for failed update of document + collection.update({i:1}, {"$set":{i:500}}, function(err, result) { + client.lastStatus(function(err, status) { + test.equal(true, status.documents[0].ok); + test.equal(false, status.documents[0].updatedExisting); + + // Check safe update of a document + collection.insert({x:1}, function(err, ids) { + collection.update({x:1}, {"$set":{x:2}}, {'safe':true}, function(err, document) { + }); + + collection.update({x:1}, {"$set":{x:2}}, {'safe':true}); + + collection.update({y:1}, {"$set":{y:2}}, {'safe':true}, function(err, result) { + test.equal(0, result); + + // Let's close the db + error_client.close(); + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldFailInsertDueToUniqueIndex : function(test) { + client.createCollection('test_failing_insert_due_to_unique_index', function(err, r) { + client.collection('test_failing_insert_due_to_unique_index', function(err, collection) { + collection.ensureIndex([['a', 1 ]], true, function(err, indexName) { + collection.insert({a:2}, {safe: true}, function(err, r) { + test.ok(err == null); + collection.insert({a:2}, {safe: true}, function(err, r) { + test.ok(err != null); + test.done(); + }) + }) + }) + }) + }) + }, + + // Test the error reporting functionality + shouldFailInsertDueToUniqueIndexStrict : function(test) { + var error_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + error_client.bson_deserializer = client.bson_deserializer; + error_client.bson_serializer = client.bson_serializer; + error_client.pkFactory = client.pkFactory; + + error_client.open(function(err, error_client) { + error_client.dropCollection('test_failing_insert_due_to_unique_index_strict', function(err, r) { + error_client.createCollection('test_failing_insert_due_to_unique_index_strict', function(err, r) { + error_client.collection('test_failing_insert_due_to_unique_index_strict', function(err, collection) { + collection.ensureIndex([['a', 1 ]], true, function(err, indexName) { + collection.insert({a:2}, {safe:true}, function(err, r) { + test.ok(err == null); + collection.insert({a:2}, {safe:true}, function(err, r) { + test.ok(err != null); + error_client.close(); + test.done(); + }) + }) + }) + }) + }) + }); + }); + }, + + 'safe mode should pass the disconnected error to the callback': function (test) { + var error_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + error_client.bson_deserializer = client.bson_deserializer; + error_client.bson_serializer = client.bson_serializer; + error_client.pkFactory = client.pkFactory; + + var name = 'test_safe_mode_when_disconnected'; + error_client.open(function(err, error_client) { + test.ok(err == null); + error_client.resetErrorHistory(function() { + error_client.dropCollection(name, function() { + error_client.createCollection(name, function(err, collection) { + test.ok(err == null); + collection.insert({ inserted: true }, { safe: true }, function (err) { + test.ok(err == null); + error_client.close(); + + collection.insert({ works: true }, { safe: true }, function (err) { + test.ok(err instanceof Error); + test.ok('notConnected' === err.message); + + collection.update({ inserted: true }, { inserted: true, x: 1 }, { safe: true }, function (err) { + test.ok(err instanceof Error); + test.ok('notConnected' === err.message); + + collection.remove({ inserted: true }, { safe: true }, function (err) { + test.ok(err instanceof Error); + test.ok('notConnected' === err.message); + + collection.findOne({ works: true }, function (err) { + test.ok(err instanceof Error); + test.ok('notConnected' === err.message); + test.done(); + }); + }); + }); + }); + + }); + }); + }); + }); + }); + } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; diff --git a/node_modules/mongodb/test/exception_handling_test.js b/node_modules/mongodb/test/exception_handling_test.js new file mode 100644 index 0000000..ea137d3 --- /dev/null +++ b/node_modules/mongodb/test/exception_handling_test.js @@ -0,0 +1,80 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldCorrectlyHandleThrownError : function(test) { + client.createCollection('shouldCorrectlyHandleThrownError', function(err, r) { + try { + client.collection('shouldCorrectlyHandleThrownError', function(err, collection) { + debug(someUndefinedVariable); + }); + } catch (err) { + test.ok(err != null); + test.done(); + } + }); + }, + + shouldCorrectlyHandleThrownErrorInRename : function(test) { + // Handle exception + var exceptionCatcher = function(err) { + test.done(); + } + + // Register handler + process.once("uncaughtException", exceptionCatcher); + // Execute code + client.createCollection('shouldCorrectlyHandleThrownErrorInRename', function(err, r) { + client.collection('shouldCorrectlyHandleThrownError', function(err, collection) { + collection.rename("shouldCorrectlyHandleThrownErrorInRename2", function(err, result) { + debug(someUndefinedVariable); + }) + }); + }); + }, +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/find_test.js b/node_modules/mongodb/test/find_test.js new file mode 100644 index 0000000..80c239f --- /dev/null +++ b/node_modules/mongodb/test/find_test.js @@ -0,0 +1,762 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Step = require('../deps/step/lib/step'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + // Test a simple find + shouldCorrectlyPerformSimpleFind : function(test) { + client.createCollection('test_find_simple', function(err, r) { + var collection = client.collection('test_find_simple', function(err, collection) { + var doc1 = null; + var doc2 = null; + + // Insert some test documents + collection.insert([{a:2}, {b:3}], {safe:true}, function(err, docs) { + doc1 = docs[0]; + doc2 = docs[1] + + // Ensure correct insertion testing via the cursor and the count function + collection.find(function(err, cursor) { + cursor.toArray(function(err, documents) { + test.equal(2, documents.length); + }) + }); + collection.count(function(err, count) { + test.equal(2, count); + }); + // Fetch values by selection + collection.find({'a': doc1.a}, function(err, cursor) { + cursor.toArray(function(err, documents) { + test.equal(1, documents.length); + test.equal(doc1.a, documents[0].a); + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + }, + + // Test a simple find chained + shouldCorrectlyPeformSimpleChainedFind : function(test) { + client.createCollection('test_find_simple_chained', function(err, r) { + var collection = client.collection('test_find_simple_chained', function(err, collection) { + var doc1 = null; + var doc2 = null; + + // Insert some test documents + collection.insert([{a:2}, {b:3}], {safe:true}, function(err, docs) { + doc1 = docs[0]; + doc2 = docs[1] + + // Ensure correct insertion testing via the cursor and the count function + collection.find().toArray(function(err, documents) { + test.equal(2, documents.length); + }); + collection.count(function(err, count) { + test.equal(2, count); + }); + // Fetch values by selection + collection.find({'a': doc1.a}).toArray(function(err, documents) { + test.equal(1, documents.length); + test.equal(doc1.a, documents[0].a); + // Let's close the db + test.done(); + }); + }); + }); + }); + }, + + // Test advanced find + shouldCorrectlyPeformAdvancedFinds : function(test) { + client.createCollection('test_find_advanced', function(err, r) { + var collection = client.collection('test_find_advanced', function(err, collection) { + var doc1 = null, doc2 = null, doc3 = null; + + // Insert some test documents + collection.insert([{a:1}, {a:2}, {b:3}], {safe:true}, function(err, docs) { + var doc1 = docs[0], doc2 = docs[1], doc3 = docs[2]; + + // Locate by less than + collection.find({'a':{'$lt':10}}).toArray(function(err, documents) { + test.equal(2, documents.length); + // Check that the correct documents are returned + var results = []; + // Check that we have all the results we want + documents.forEach(function(doc) { + if(doc.a == 1 || doc.a == 2) results.push(1); + }); + test.equal(2, results.length); + }); + + // Locate by greater than + collection.find({'a':{'$gt':1}}).toArray(function(err, documents) { + test.equal(1, documents.length); + test.equal(2, documents[0].a); + }); + + // Locate by less than or equal to + collection.find({'a':{'$lte':1}}).toArray(function(err, documents) { + test.equal(1, documents.length); + test.equal(1, documents[0].a); + }); + + // Locate by greater than or equal to + collection.find({'a':{'$gte':1}}).toArray(function(err, documents) { + test.equal(2, documents.length); + // Check that the correct documents are returned + var results = []; + // Check that we have all the results we want + documents.forEach(function(doc) { + if(doc.a == 1 || doc.a == 2) results.push(1); + }); + test.equal(2, results.length); + }); + + // Locate by between + collection.find({'a':{'$gt':1, '$lt':3}}).toArray(function(err, documents) { + test.equal(1, documents.length); + test.equal(2, documents[0].a); + }); + + // Locate in clause + collection.find({'a':{'$in':[1,2]}}).toArray(function(err, documents) { + test.equal(2, documents.length); + // Check that the correct documents are returned + var results = []; + // Check that we have all the results we want + documents.forEach(function(doc) { + if(doc.a == 1 || doc.a == 2) results.push(1); + }); + test.equal(2, results.length); + }); + + // Locate in _id clause + collection.find({'_id':{'$in':[doc1['_id'], doc2['_id']]}}).toArray(function(err, documents) { + test.equal(2, documents.length); + // Check that the correct documents are returned + var results = []; + // Check that we have all the results we want + documents.forEach(function(doc) { + if(doc.a == 1 || doc.a == 2) results.push(1); + }); + test.equal(2, results.length); + // Let's close the db + test.done(); + }); + }); + }); + }); + }, + + // Test sorting of results + shouldCorrectlyPerformFindWithSort : function(test) { + client.createCollection('test_find_sorting', function(err, r) { + client.collection('test_find_sorting', function(err, collection) { + var doc1 = null, doc2 = null, doc3 = null, doc4 = null; + // Insert some test documents + collection.insert([{a:1, b:2}, + {a:2, b:1}, + {a:3, b:2}, + {a:4, b:1} + ], {safe:true}, function(err, docs) { + doc1 = docs[0]; + doc2 = docs[1]; + doc3 = docs[2]; + doc4 = docs[3] + + // Test sorting (ascending) + collection.find({'a': {'$lt':10}}, {'sort': [['a', 1]]}).toArray(function(err, documents) { + test.equal(4, documents.length); + test.equal(1, documents[0].a); + test.equal(2, documents[1].a); + test.equal(3, documents[2].a); + test.equal(4, documents[3].a); + + // Test sorting (descending) + collection.find({'a': {'$lt':10}}, {'sort': [['a', -1]]}).toArray(function(err, documents) { + test.equal(4, documents.length); + test.equal(4, documents[0].a); + test.equal(3, documents[1].a); + test.equal(2, documents[2].a); + test.equal(1, documents[3].a); + + // Test sorting (descending), sort is hash + collection.find({'a': {'$lt':10}}, {sort: {a: -1}}).toArray(function(err, documents) { + test.equal(4, documents.length); + test.equal(4, documents[0].a); + test.equal(3, documents[1].a); + test.equal(2, documents[2].a); + test.equal(1, documents[3].a); + + // Sorting using array of names, assumes ascending order + collection.find({'a': {'$lt':10}}, {'sort': ['a']}).toArray(function(err, documents) { + test.equal(4, documents.length); + test.equal(1, documents[0].a); + test.equal(2, documents[1].a); + test.equal(3, documents[2].a); + test.equal(4, documents[3].a); + + // Sorting using single name, assumes ascending order + collection.find({'a': {'$lt':10}}, {'sort': 'a'}).toArray(function(err, documents) { + test.equal(4, documents.length); + test.equal(1, documents[0].a); + test.equal(2, documents[1].a); + test.equal(3, documents[2].a); + test.equal(4, documents[3].a); + + // Sorting using single name, assumes ascending order, sort is hash + collection.find({'a': {'$lt':10}}, {sort: {'a':1}}).toArray(function(err, documents) { + test.equal(4, documents.length); + test.equal(1, documents[0].a); + test.equal(2, documents[1].a); + test.equal(3, documents[2].a); + test.equal(4, documents[3].a); + + collection.find({'a': {'$lt':10}}, {'sort': ['b', 'a']}).toArray(function(err, documents) { + test.equal(4, documents.length); + test.equal(2, documents[0].a); + test.equal(4, documents[1].a); + test.equal(1, documents[2].a); + test.equal(3, documents[3].a); + + // Sorting using empty array, no order guarantee should not blow up + collection.find({'a': {'$lt':10}}, {'sort': []}).toArray(function(err, documents) { + test.equal(4, documents.length); + + /* NONACTUAL */ + // Sorting using ordered hash + collection.find({'a': {'$lt':10}}, {'sort': {a:-1}}).toArray(function(err, documents) { + // Fail test if not an error + test.equal(4, documents.length); + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + // Test the limit function of the db + shouldCorrectlyPerformFindWithLimit : function(test) { + client.createCollection('test_find_limits', function(err, r) { + client.collection('test_find_limits', function(err, collection) { + var doc1 = null, doc2 = null, doc3 = null, doc4 = null; + + // Insert some test documents + collection.insert([{a:1}, + {b:2}, + {c:3}, + {d:4} + ], {safe:true}, function(err, docs) { + doc1 = docs[0]; + doc2 = docs[1]; + doc3 = docs[2]; + doc4 = docs[3] + + // Test limits + collection.find({}, {'limit': 1}).toArray(function(err, documents) { + test.equal(1, documents.length); + }); + + collection.find({}, {'limit': 2}).toArray(function(err, documents) { + test.equal(2, documents.length); + }); + + collection.find({}, {'limit': 3}).toArray(function(err, documents) { + test.equal(3, documents.length); + }); + + collection.find({}, {'limit': 4}).toArray(function(err, documents) { + test.equal(4, documents.length); + }); + + collection.find({}, {}).toArray(function(err, documents) { + test.equal(4, documents.length); + }); + + collection.find({}, {'limit':99}).toArray(function(err, documents) { + test.equal(4, documents.length); + // Let's close the db + test.done(); + }); + }); + }); + }); + }, + + // Test find by non-quoted values (issue #128) + shouldCorrectlyFindWithNonQuotedValues : function(test) { + client.createCollection('test_find_non_quoted_values', function(err, r) { + client.collection('test_find_non_quoted_values', function(err, collection) { + // insert test document + collection.insert([{ a: 19, b: 'teststring', c: 59920303 }, + { a: "19", b: 'teststring', c: 3984929 }], {safe:true} , function(err, r) { + + collection.find({ a: 19 }).toArray(function(err, documents) { + test.equal(1, documents.length); + test.done(); + }); + }); + }); + }); + }, + + // Test for querying embedded document using dot-notation (issue #126) + shouldCorrectlyFindEmbeddedDocument : function(test) { + client.createCollection('test_find_embedded_document', function(err, r) { + client.collection('test_find_embedded_document', function(err, collection) { + // insert test document + collection.insert([{ a: { id: 10, value: 'foo' }, b: 'bar', c: { id: 20, value: 'foobar' }}, + { a: { id: 11, value: 'foo' }, b: 'bar2', c: { id: 20, value: 'foobar' }}], {safe:true}, function(err, r) { + + // test using integer value + collection.find({ 'a.id': 10 }).toArray(function(err, documents) { + test.equal(1, documents.length); + test.equal('bar', documents[0].b); + }); + + // test using string value + collection.find({ 'a.value': 'foo' }).toArray(function(err, documents) { + // should yield 2 documents + test.equal(2, documents.length); + test.equal('bar', documents[0].b); + test.equal('bar2', documents[1].b); + test.done(); + }); + }); + }); + }); + }, + + // Find no records + shouldCorrectlyFindNoRecords : function(test) { + client.createCollection('test_find_one_no_records', function(err, r) { + client.collection('test_find_one_no_records', function(err, collection) { + collection.find({'a':1}, {}).toArray(function(err, documents) { + test.equal(0, documents.length); + // Let's close the db + test.done(); + }); + }); + }); + }, + + shouldCorrectlyPerformFindByWhere : function(test) { + client.createCollection('test_where', function(err, collection) { + test.ok(collection instanceof Collection); + collection.insert([{'a':1}, {'a':2}, {'a':3}], {safe:true}, function(err, ids) { + collection.count(function(err, count) { + test.equal(3, count); + + // Let's test usage of the $where statement + collection.find({'$where':new client.bson_serializer.Code('this.a > 2')}).count(function(err, count) { + test.equal(1, count); + }); + + collection.find({'$where':new client.bson_serializer.Code('this.a > i', {i:1})}).count(function(err, count) { + test.equal(2, count); + + // Let's close the db + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyPerformFindsWithHintTurnedOn : function(test) { + client.createCollection('test_hint', function(err, collection) { + collection.insert({'a':1}, {safe:true}, function(err, ids) { + client.createIndex(collection.collectionName, "a", function(err, indexName) { + collection.find({'a':1}, {'hint':'a'}).toArray(function(err, items) { + test.equal(1, items.length); + }); + + collection.find({'a':1}, {'hint':['a']}).toArray(function(err, items) { + test.equal(1, items.length); + }); + + collection.find({'a':1}, {'hint':{'a':1}}).toArray(function(err, items) { + test.equal(1, items.length); + }); + + // Modify hints + collection.hint = 'a'; + test.equal(1, collection.hint['a']); + collection.find({'a':1}).toArray(function(err, items) { + test.equal(1, items.length); + }); + + collection.hint = ['a']; + test.equal(1, collection.hint['a']); + collection.find({'a':1}).toArray(function(err, items) { + test.equal(1, items.length); + }); + + collection.hint = {'a':1}; + test.equal(1, collection.hint['a']); + collection.find({'a':1}).toArray(function(err, items) { + test.equal(1, items.length); + }); + + collection.hint = null; + test.ok(collection.hint == null); + collection.find({'a':1}).toArray(function(err, items) { + test.equal(1, items.length); + // Let's close the db + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyPerformFindByObjectID : function(test) { + client.createCollection('test_find_by_oid', function(err, collection) { + collection.save({'hello':'mike'}, {safe:true}, function(err, docs) { + test.ok(docs._id instanceof client.bson_serializer.ObjectID || Object.prototype.toString.call(docs._id) === '[object ObjectID]'); + + collection.findOne({'_id':docs._id}, function(err, doc) { + test.equal('mike', doc.hello); + + var id = doc._id.toString(); + collection.findOne({'_id':new client.bson_serializer.ObjectID(id)}, function(err, doc) { + test.equal('mike', doc.hello); + // Let's close the db + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyReturnDocumentWithOriginalStructure: function(test) { + client.createCollection('test_find_by_oid_with_subdocs', function(err, collection) { + var c1 = { _id: new client.bson_serializer.ObjectID, comments: [], title: 'number 1' }; + var c2 = { _id: new client.bson_serializer.ObjectID, comments: [], title: 'number 2' }; + var doc = { + numbers: [] + , owners: [] + , comments: [c1, c2] + , _id: new client.bson_serializer.ObjectID + }; + + collection.insert(doc, {safe:true}, function(err, docs) { + collection.findOne({'_id':doc._id}, {safe:true,fields: undefined}, function(err, doc) { + if (err) console.error('error', err); + test.equal(2, doc.comments.length); + test.equal('number 1', doc.comments[0].title); + test.equal('number 2', doc.comments[1].title); + + test.done(); + }); + }); + }); + }, + + shouldCorrectlyRetrieveSingleRecord : function(test) { + var p_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + p_client.bson_deserializer = client.bson_deserializer; + p_client.bson_serializer = client.bson_serializer; + p_client.pkFactory = client.pkFactory; + + p_client.open(function(err, p_client) { + client.createCollection('test_should_correctly_retrieve_one_record', function(err, collection) { + collection.insert({'a':0}, {safe:true}, function(err, r) { + p_client.collection('test_should_correctly_retrieve_one_record', function(err, usercollection) { + usercollection.findOne({'a': 0}, function(err, result) { + p_client.close(); + + test.done(); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyHandleError : function(test) { + client.createCollection('test_find_one_error_handling', function(err, collection) { + // Try to fetch an object using a totally invalid and wrong hex string... what we're interested in here + // is the error handling of the findOne Method + try { + collection.findOne({"_id":client.bson_serializer.ObjectID.createFromHexString('5e9bd59248305adf18ebc15703a1')}, function(err, result) {}); + } catch (err) { + test.done(); + } + }); + }, + + // Test field select with options + shouldCorrectlyPerformFindWithOptions : function(test) { + client.createCollection('test_field_select_with_options', function(err, r) { + var collection = client.collection('test_field_select_with_options', function(err, collection) { + var docCount = 25, docs = []; + + // Insert some test documents + while(docCount--) docs.push({a:docCount, b:docCount}); + collection.insert(docs, {safe:true}, function(err,retDocs) { + docs = retDocs; + + collection.find({},{ 'a' : 1},{ limit : 3, sort : [['a',-1]] }).toArray(function(err,documents){ + test.equal(3,documents.length); + documents.forEach(function(doc,idx){ + test.equal(undefined,doc.b); // making sure field select works + test.equal((24-idx),doc.a); // checking limit sort object with field select + }); + }); + + collection.find({},{},10,3).toArray(function(err,documents){ + test.equal(3,documents.length); + documents.forEach(function(doc,idx){ + test.equal(doc.a,doc.b); // making sure empty field select returns properly + test.equal((14-idx),doc.a); // checking skip and limit in args + }); + + test.done(); + }); + }); + }); + }); + }, + + // Test findAndModify a document + shouldCorrectlyFindAndModifyDocument : function(test) { + client.createCollection('test_find_and_modify_a_document', function(err, collection) { + // Test return new document on change + collection.insert({'a':1, 'b':2}, {safe:true}, function(err, doc) { + // Let's modify the document in place + collection.findAndModify({'a':1}, [['a', 1]], {'$set':{'b':3}}, {'new': true}, function(err, updated_doc) { + test.equal(1, updated_doc.a); + test.equal(3, updated_doc.b); + }) + }); + + // Test return old document on change + collection.insert({'a':2, 'b':2}, {safe:true}, function(err, doc) { + // Let's modify the document in place + collection.findAndModify({'a':2}, [['a', 1]], {'$set':{'b':3}}, {safe:true}, function(err, updated_doc) { + test.equal(2, updated_doc.a); + test.equal(2, updated_doc.b); + }) + }); + + // Test remove object on change + collection.insert({'a':3, 'b':2}, {safe:true}, function(err, doc) { + // Let's modify the document in place + collection.findAndModify({'a':3}, [], {'$set':{'b':3}}, {'new': true, remove: true}, function(err, updated_doc) { + test.equal(3, updated_doc.a); + test.equal(2, updated_doc.b); + }) + }); + + // Let's upsert! + collection.findAndModify({'a':4}, [], {'$set':{'b':3}}, {'new': true, upsert: true}, function(err, updated_doc) { + test.equal(4, updated_doc.a); + test.equal(3, updated_doc.b); + }); + + // Test selecting a subset of fields + collection.insert({a: 100, b: 101}, {safe:true}, function (err, ids) { + collection.findAndModify({'a': 100}, [], {'$set': {'b': 5}}, {'new': true, fields: {b: 1}}, function (err, updated_doc) { + test.equal(2, Object.keys(updated_doc).length); + test.equal(ids[0]['_id'].toHexString(), updated_doc._id.toHexString()); + test.equal(5, updated_doc.b); + test.equal("undefined", typeof updated_doc.a); + + test.done(); + }); + }); + }); + }, + + shouldCorrectlyExecuteFindOneWithAnInSearchTag : function(test) { + client.createCollection('shouldCorrectlyExecuteFindOneWithAnInSearchTag', function(err, collection) { + // Test return new document on change + collection.insert({'tags':[]}, {safe:true}, function(err, docs) { + // Fetch the id + var id = docs[0]._id + + Step( + function findFirst() { + var self = this; + + collection.findOne({_id:id}, function(err, doc) { + test.equal(null, err) + test.ok(doc != null); + + // Perform atomic push operation + collection.update({_id:id}, {'$push':{comments:{title:'1'}}}, {safe:true}, self); + }) + }, + + function findSecond(err, result) { + var self = this; + test.equal(1, result); + test.equal(null, err); + + collection.findOne({_id:id}, function(err, doc) { + test.equal(null, err) + test.ok(doc != null); + test.deepEqual(1, doc.comments.length); + + // Perform atomic push operation + collection.update({_id:id}, {'$push':{comments:{title:'2'}}}, {safe:true}, self); + }) + }, + + function findThird(err, result) { + var self = this; + test.equal(1, result); + test.equal(null, err); + + collection.findOne({_id:id}, function(err, doc) { + test.equal(null, err) + test.ok(doc != null); + test.deepEqual(2, doc.comments.length); + + // Perform atomic push operation + collection.update({_id:id}, {'$push':{comments:{title:'3'}}}, {safe:true}, self); + }) + }, + + function findFourth(err, result) { + var self = this; + test.equal(1, result); + test.equal(null, err); + + collection.findOne({_id:id}, function(err, doc) { + test.equal(null, err) + test.ok(doc != null); + test.deepEqual(3, doc.comments.length); + // Perform atomic push operation + collection.update({_id:id}, {'$pushAll':{comments:[{title:'4'}, {title:'5'}]}}, {safe:true}, self); + }) + }, + + function findFourth(err, result) { + var self = this; + test.equal(1, result); + test.equal(null, err); + + collection.findOne({_id:id}, function(err, doc) { + test.equal(null, err) + test.ok(doc != null); + test.deepEqual(5, doc.comments.length); + test.done(); + }) + } + ) + }) + }); + }, + + 'ShouldCorrectlyLocatePostAndIncValues': function(test) { + client.createCollection('shouldCorrectlyExecuteFindOneWithAnInSearchTag', function(err, collection) { + // Test return new document on change + collection.insert({title:'Tobi', + author:'Brian', + newTitle:'Woot', meta:{visitors:0}}, {safe:true}, function(err, docs) { + // Fetch the id + var id = docs[0]._id + + collection.update({_id:id}, {$inc:{ 'meta.visitors': 1 }}, {safe:true}, function(err, result) { + test.equal(1, result); + test.equal(null, err); + + collection.findOne({_id:id}, function(err, item) { + test.equal(1, item.meta.visitors); + test.done() + }) + }); + }); + }); + }, + + // Test findAndModify a document + 'Should Correctly Handle FindAndModify Duplicate Key Error' : function(test) { + client.createCollection('FindAndModifyDuplicateKey Error', function(err, collection) { + collection.ensureIndex(['name', 1], {unique:true}, function(err, index) { + // Test return new document on change + collection.insert([{name:'test1'}, {name:'test2'}], {safe:true}, function(err, doc) { + // Let's modify the document in place + collection.findAndModify({name: 'test1'}, [], {$set: {name: 'test2'}}, {}, function(err, updated_doc) { + test.equal(null, updated_doc); + test.ok(err != null); + test.done(); + }); + }); + }); + }); + }, + + 'Should correctly handle chained skip and limit on find with toArray' : function(test) { + client.createCollection('skipAndLimitOnFindWithToArray', function(err, collection) { + collection.insert([{a:1}, {b:2}, {c:3}], {safe:true}, function(err, result) { + + collection.find().skip(1).limit(1).toArray(function(err, items) { + test.equal(null, err); + test.equal(1, items.length); + test.equal(2, items[0].b) + test.done(); + }) + }); + }); + } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/gridstore/grid_store_file_test.js b/node_modules/mongodb/test/gridstore/grid_store_file_test.js new file mode 100644 index 0000000..9511c9a --- /dev/null +++ b/node_modules/mongodb/test/gridstore/grid_store_file_test.js @@ -0,0 +1,710 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../../lib/mongodb').native() : require('../../lib/mongodb').pure(); + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + GridStore = mongodb.GridStore, + Chunk = mongodb.Chunk, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldCorrectlyWriteASmallPayload : function(test) { + var gridStore = new GridStore(client, "test_gs_small_write", "w"); + gridStore.open(function(err, gridStore) { + + gridStore.write("hello world!", function(err, gridStore) { + + gridStore.close(function(err, result) { + + client.collection('fs.files', function(err, collection) { + + collection.find({'filename':'test_gs_small_write'}, function(err, cursor) { + + cursor.toArray(function(err, items) { + test.equal(1, items.length); + var item = items[0]; + test.ok(item._id instanceof client.bson_serializer.ObjectID || Object.prototype.toString.call(item._id) === '[object ObjectID]'); + + client.collection('fs.chunks', function(err, collection) { + var id = client.bson_serializer.ObjectID.createFromHexString(item._id.toHexString()); + + collection.find({'files_id':id}, function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(1, items.length); + test.done(); + }) + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyWriteSmallFileUsingABuffer : function(test) { + var gridStore = new GridStore(client, "test_gs_small_write_with_buffer", "w"); + gridStore.open(function(err, gridStore) { + var data = new Buffer("hello world", "utf8"); + + gridStore.writeBuffer(data, function(err, gridStore) { + gridStore.close(function(err, result) { + client.collection('fs.files', function(err, collection) { + collection.find({'filename':'test_gs_small_write_with_buffer'}, function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(1, items.length); + var item = items[0]; + test.ok(item._id instanceof client.bson_serializer.ObjectID || Object.prototype.toString.call(item._id) === '[object ObjectID]'); + + client.collection('fs.chunks', function(err, collection) { + collection.find({'files_id':item._id}, function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(1, items.length); + test.done(); + }) + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldSaveSmallFileToGridStore : function(test) { + var gridStore = new GridStore(client, "test_gs_small_file", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello world!", function(err, gridStore) { + gridStore.close(function(err, result) { + client.collection('fs.files', function(err, collection) { + + collection.find({'filename':'test_gs_small_file'}, function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(1, items.length); + + // Read test of the file + GridStore.read(client, 'test_gs_small_file', function(err, data) { + test.equal('hello world!', data); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyOverwriteFile : function(test) { + var gridStore = new GridStore(client, "test_gs_overwrite", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello world!", function(err, gridStore) { + gridStore.close(function(err, result) { + var gridStore2 = new GridStore(client, "test_gs_overwrite", "w"); + gridStore2.open(function(err, gridStore) { + gridStore2.write("overwrite", function(err, gridStore) { + gridStore2.close(function(err, result) { + + // Assert that we have overwriten the data + GridStore.read(client, 'test_gs_overwrite', function(err, data) { + test.equal('overwrite', data); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlySeekWithBuffer : function(test) { + var gridStore = new GridStore(client, "test_gs_seek_with_buffer", "w"); + gridStore.open(function(err, gridStore) { + var data = new Buffer("hello, world!", "utf8"); + gridStore.writeBuffer(data, function(err, gridStore) { + gridStore.close(function(result) { + var gridStore2 = new GridStore(client, "test_gs_seek_with_buffer", "r"); + gridStore2.open(function(err, gridStore) { + gridStore.seek(0, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('h', chr); + }); + }); + }); + + var gridStore3 = new GridStore(client, "test_gs_seek_with_buffer", "r"); + gridStore3.open(function(err, gridStore) { + gridStore.seek(7, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('w', chr); + }); + }); + }); + + var gridStore4 = new GridStore(client, "test_gs_seek_with_buffer", "r"); + gridStore4.open(function(err, gridStore) { + gridStore.seek(4, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('o', chr); + }); + }); + }); + + var gridStore5 = new GridStore(client, "test_gs_seek_with_buffer", "r"); + gridStore5.open(function(err, gridStore) { + gridStore.seek(-1, GridStore.IO_SEEK_END, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('!', chr); + }); + }); + }); + + var gridStore6 = new GridStore(client, "test_gs_seek_with_buffer", "r"); + gridStore6.open(function(err, gridStore) { + gridStore.seek(-6, GridStore.IO_SEEK_END, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('w', chr); + }); + }); + }); + + var gridStore7 = new GridStore(client, "test_gs_seek_with_buffer", "r"); + gridStore7.open(function(err, gridStore) { + gridStore.seek(7, GridStore.IO_SEEK_CUR, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('w', chr); + + gridStore.seek(-1, GridStore.IO_SEEK_CUR, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('w', chr); + + gridStore.seek(-4, GridStore.IO_SEEK_CUR, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('o', chr); + + gridStore.seek(3, GridStore.IO_SEEK_CUR, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('o', chr); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlySeekWithString : function(test) { + var gridStore = new GridStore(client, "test_gs_seek", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello, world!", function(err, gridStore) { + gridStore.close(function(result) { + var gridStore2 = new GridStore(client, "test_gs_seek", "r"); + gridStore2.open(function(err, gridStore) { + gridStore.seek(0, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('h', chr); + }); + }); + }); + + var gridStore3 = new GridStore(client, "test_gs_seek", "r"); + gridStore3.open(function(err, gridStore) { + gridStore.seek(7, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('w', chr); + }); + }); + }); + + var gridStore4 = new GridStore(client, "test_gs_seek", "r"); + gridStore4.open(function(err, gridStore) { + gridStore.seek(4, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('o', chr); + }); + }); + }); + + var gridStore5 = new GridStore(client, "test_gs_seek", "r"); + gridStore5.open(function(err, gridStore) { + gridStore.seek(-1, GridStore.IO_SEEK_END, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('!', chr); + }); + }); + }); + + var gridStore6 = new GridStore(client, "test_gs_seek", "r"); + gridStore6.open(function(err, gridStore) { + gridStore.seek(-6, GridStore.IO_SEEK_END, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('w', chr); + }); + }); + }); + + var gridStore7 = new GridStore(client, "test_gs_seek", "r"); + gridStore7.open(function(err, gridStore) { + gridStore.seek(7, GridStore.IO_SEEK_CUR, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('w', chr); + + gridStore.seek(-1, GridStore.IO_SEEK_CUR, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('w', chr); + + gridStore.seek(-4, GridStore.IO_SEEK_CUR, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('o', chr); + + gridStore.seek(3, GridStore.IO_SEEK_CUR, function(err, gridStore) { + gridStore.getc(function(err, chr) { + test.equal('o', chr); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyAppendToFile : function(test) { + var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + fs_client.bson_deserializer = client.bson_deserializer; + fs_client.bson_serializer = client.bson_serializer; + fs_client.pkFactory = client.pkFactory; + + fs_client.open(function(err, fs_client) { + fs_client.dropDatabase(function(err, done) { + var gridStore = new GridStore(fs_client, "test_gs_append", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello, world!", function(err, gridStore) { + gridStore.close(function(err, result) { + + var gridStore2 = new GridStore(fs_client, "test_gs_append", "w+"); + gridStore2.open(function(err, gridStore) { + gridStore.write(" how are you?", function(err, gridStore) { + gridStore.close(function(err, result) { + + fs_client.collection('fs.chunks', function(err, collection) { + collection.count(function(err, count) { + test.equal(1, count); + + GridStore.read(fs_client, 'test_gs_append', function(err, data) { + test.equal("hello, world! how are you?", data); + + fs_client.close(); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyRewingAndTruncateOnWrite : function(test) { + var gridStore = new GridStore(client, "test_gs_rewind_and_truncate_on_write", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello, world!", function(err, gridStore) { + gridStore.close(function(err, result) { + + var gridStore2 = new GridStore(client, "test_gs_rewind_and_truncate_on_write", "w"); + gridStore2.open(function(err, gridStore) { + gridStore.write('some text is inserted here', function(err, gridStore) { + gridStore.rewind(function(err, gridStore) { + gridStore.write('abc', function(err, gridStore) { + gridStore.close(function(err, result) { + + GridStore.read(client, 'test_gs_rewind_and_truncate_on_write', function(err, data) { + test.equal("abc", data); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyExecuteGridstoreTell : function(test) { + var gridStore = new GridStore(client, "test_gs_tell", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello, world!", function(err, gridStore) { + gridStore.close(function(err, result) { + var gridStore2 = new GridStore(client, "test_gs_tell", "r"); + gridStore2.open(function(err, gridStore) { + gridStore.read(5, function(err, data) { + test.equal("hello", data); + + gridStore.tell(function(err, position) { + test.equal(5, position); + test.done(); + }) + }); + }); + }); + }); + }); + }, + + shouldCorrectlySaveEmptyFile : function(test) { + var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + fs_client.bson_deserializer = client.bson_deserializer; + fs_client.bson_serializer = client.bson_serializer; + fs_client.pkFactory = client.pkFactory; + + fs_client.open(function(err, fs_client) { + fs_client.dropDatabase(function(err, done) { + var gridStore = new GridStore(fs_client, "test_gs_save_empty_file", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("", function(err, gridStore) { + gridStore.close(function(err, result) { + fs_client.collection('fs.files', function(err, collection) { + collection.count(function(err, count) { + test.equal(1, count); + }); + }); + + fs_client.collection('fs.chunks', function(err, collection) { + collection.count(function(err, count) { + test.equal(0, count); + + fs_client.close(); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyDetectEOF : function(test) { + var gridStore = new GridStore(client, 'test_gs_empty_file_eof', "w"); + gridStore.open(function(err, gridStore) { + gridStore.close(function(err, gridStore) { + var gridStore2 = new GridStore(client, 'test_gs_empty_file_eof', "r"); + gridStore2.open(function(err, gridStore) { + test.equal(true, gridStore.eof()); + test.done(); + }) + }); + }); + }, + + shouldEnsureThatChunkSizeCannotBeChangedDuringRead : function(test) { + var gridStore = new GridStore(client, "test_gs_cannot_change_chunk_size_on_read", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello, world!", function(err, gridStore) { + gridStore.close(function(err, result) { + + var gridStore2 = new GridStore(client, "test_gs_cannot_change_chunk_size_on_read", "r"); + gridStore2.open(function(err, gridStore) { + gridStore.chunkSize = 42; + test.equal(Chunk.DEFAULT_CHUNK_SIZE, gridStore.chunkSize); + test.done(); + }); + }); + }); + }); + }, + + shouldEnsureChunkSizeCannotChangeAfterDataHasBeenWritten : function(test) { + var gridStore = new GridStore(client, "test_gs_cannot_change_chunk_size_after_data_written", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello, world!", function(err, gridStore) { + gridStore.chunkSize = 42; + test.equal(Chunk.DEFAULT_CHUNK_SIZE, gridStore.chunkSize); + test.done(); + }); + }); + }, + + // checks if 8 bit values will be preserved in gridstore + shouldCorrectlyStore8bitValues : function(test) { + var gridStore = new GridStore(client, "test_gs_check_high_bits", "w"); + var data = new Buffer(255); + for(var i=0; i<255; i++){ + data[i] = i; + } + + gridStore.open(function(err, gridStore) { + gridStore.write(data, function(err, gridStore) { + gridStore.close(function(err, result) { + // Assert that we have overwriten the data + GridStore.read(client, 'test_gs_check_high_bits', function(err, fileData) { + // change testvalue into a string like "0,1,2,...,255" + test.equal(Array.prototype.join.call(data), + Array.prototype.join.call(new Buffer(fileData, "binary"))); + test.done(); + }); + }); + }); + }); + }, + + shouldAllowChangingChunkSize : function(test) { + var gridStore = new GridStore(client, "test_change_chunk_size", "w"); + gridStore.open(function(err, gridStore) { + gridStore.chunkSize = 42 + + gridStore.write('foo', function(err, gridStore) { + gridStore.close(function(err, result) { + var gridStore2 = new GridStore(client, "test_change_chunk_size", "r"); + gridStore2.open(function(err, gridStore) { + test.equal(42, gridStore.chunkSize); + test.done(); + }); + }); + }); + }); + }, + + shouldAllowChangingChunkSizeAtCreationOfGridStore : function(test) { + var gridStore = new GridStore(client, "test_change_chunk_size", "w", {'chunk_size':42}); + gridStore.open(function(err, gridStore) { + gridStore.write('foo', function(err, gridStore) { + gridStore.close(function(err, result) { + var gridStore2 = new GridStore(client, "test_change_chunk_size", "r"); + gridStore2.open(function(err, gridStore) { + test.equal(42, gridStore.chunkSize); + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyCalculateMD5 : function(test) { + var gridStore = new GridStore(client, "new-file", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write('hello world\n', function(err, gridStore) { + gridStore.close(function(err, result) { + var gridStore2 = new GridStore(client, "new-file", "r"); + gridStore2.open(function(err, gridStore) { + test.equal("6f5902ac237024bdd0c176cb93063dc4", gridStore.md5); + gridStore.md5 = "can't do this"; + test.equal("6f5902ac237024bdd0c176cb93063dc4", gridStore.md5); + + var gridStore2 = new GridStore(client, "new-file", "w"); + gridStore2.open(function(err, gridStore) { + gridStore.close(function(err, result) { + var gridStore3 = new GridStore(client, "new-file", "r"); + gridStore3.open(function(err, gridStore) { + test.equal("d41d8cd98f00b204e9800998ecf8427e", gridStore.md5); + test.done(); + }); + }) + }) + }); + }); + }); + }); + }, + + shouldCorrectlyUpdateUploadDate : function(test) { + var now = new Date(); + var originalFileUploadDate = null; + + var gridStore = new GridStore(client, "test_gs_upload_date", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write('hello world\n', function(err, gridStore) { + gridStore.close(function(err, result) { + + var gridStore2 = new GridStore(client, "test_gs_upload_date", "r"); + gridStore2.open(function(err, gridStore) { + test.ok(gridStore.uploadDate != null); + originalFileUploadDate = gridStore.uploadDate; + + gridStore2.close(function(err, result) { + var gridStore3 = new GridStore(client, "test_gs_upload_date", "w"); + gridStore3.open(function(err, gridStore) { + gridStore3.write('new data', function(err, gridStore) { + gridStore3.close(function(err, result) { + var fileUploadDate = null; + + var gridStore4 = new GridStore(client, "test_gs_upload_date", "r"); + gridStore4.open(function(err, gridStore) { + test.equal(originalFileUploadDate.getTime(), gridStore.uploadDate.getTime()); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlySaveContentType : function(test) { + var ct = null; + + var gridStore = new GridStore(client, "test_gs_content_type", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write('hello world\n', function(err, gridStore) { + gridStore.close(function(err, result) { + + var gridStore2 = new GridStore(client, "test_gs_content_type", "r"); + gridStore2.open(function(err, gridStore) { + ct = gridStore.contentType; + test.equal(GridStore.DEFAULT_CONTENT_TYPE, ct); + + var gridStore3 = new GridStore(client, "test_gs_content_type", "w+"); + gridStore3.open(function(err, gridStore) { + gridStore.contentType = "text/html"; + gridStore.close(function(err, result) { + var gridStore4 = new GridStore(client, "test_gs_content_type", "r"); + gridStore4.open(function(err, gridStore) { + test.equal("text/html", gridStore.contentType); + test.done(); + }); + }) + }); + }); + }); + }); + }); + }, + + shouldCorrectlySaveContentTypeWhenPassedInAtGridStoreCreation : function(test) { + var gridStore = new GridStore(client, "test_gs_content_type_option", "w", {'content_type':'image/jpg'}); + gridStore.open(function(err, gridStore) { + gridStore.write('hello world\n', function(err, gridStore) { + gridStore.close(function(result) { + + var gridStore2 = new GridStore(client, "test_gs_content_type_option", "r"); + gridStore2.open(function(err, gridStore) { + test.equal('image/jpg', gridStore.contentType); + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyReportIllegalMode : function(test) { + var gridStore = new GridStore(client, "test_gs_unknown_mode", "x"); + gridStore.open(function(err, gridStore) { + test.ok(err instanceof Error); + test.equal("Illegal mode x", err.message); + test.done(); + }); + }, + + shouldCorrectlySaveAndRetrieveFileMetadata : function(test) { + var gridStore = new GridStore(client, "test_gs_metadata", "w", {'content_type':'image/jpg'}); + gridStore.open(function(err, gridStore) { + gridStore.write('hello world\n', function(err, gridStore) { + gridStore.close(function(err, result) { + + var gridStore2 = new GridStore(client, "test_gs_metadata", "r"); + gridStore2.open(function(err, gridStore) { + test.equal(null, gridStore.metadata); + + var gridStore3 = new GridStore(client, "test_gs_metadata", "w+"); + gridStore3.open(function(err, gridStore) { + gridStore.metadata = {'a':1}; + gridStore.close(function(err, result) { + + var gridStore4 = new GridStore(client, "test_gs_metadata", "r"); + gridStore4.open(function(err, gridStore) { + test.equal(1, gridStore.metadata.a); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldNotThrowErrorOnClose : function(test) { + var gridStore = new GridStore(client, "test_gs_metadata", "w", {'content_type':'image/jpg'}); + gridStore.open(function(err, gridStore) { + gridStore.write('hello world\n', function(err, gridStore) { + gridStore.close(function(err, result) { + + var gridStore2 = new GridStore(client, "test_gs_metadata", "r"); + gridStore2.open(function(err, gridStore) { + gridStore.close(function(err, fo) { + test.ok(err == null); + test.ok(fo == null); + test.done(); + }) + }); + }); + }); + }); + } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/gridstore/grid_store_stream_test.js b/node_modules/mongodb/test/gridstore/grid_store_stream_test.js new file mode 100644 index 0000000..5f1b3c0 --- /dev/null +++ b/node_modules/mongodb/test/gridstore/grid_store_stream_test.js @@ -0,0 +1,82 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../../lib/mongodb').native() : require('../../lib/mongodb').pure(); + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../../deps/nodeunit'), + fs = require('fs'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + GridStore = mongodb.GridStore, + Chunk = mongodb.Chunk, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldCorrectlyReadFileUsingStream : function(test) { + var gridStoreR = new GridStore(client, "test_gs_read_stream", "r"); + var gridStoreW = new GridStore(client, "test_gs_read_stream", "w"); + var data = fs.readFileSync("./test/gridstore/test_gs_weird_bug.png", 'binary'); + + var readLen = 0; + var gotEnd = 0; + + gridStoreW.open(function(err, gs) { + gs.write(data, function(err, gs) { + gs.close(function(err, result) { + gridStoreR.open(function(err, gs) { + var stream = gs.stream(true); + stream.on("data", function(chunk) { + readLen += chunk.length; + }); + stream.on("end", function() { + ++gotEnd; + }); + stream.on("close", function() { + test.equal(data.length, readLen); + test.equal(1, gotEnd); + test.done(); + }); + }); + }); + }); + }); + }, +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/gridstore/grid_store_test.js b/node_modules/mongodb/test/gridstore/grid_store_test.js new file mode 100644 index 0000000..1fbb099 --- /dev/null +++ b/node_modules/mongodb/test/gridstore/grid_store_test.js @@ -0,0 +1,660 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../../lib/mongodb').native() : require('../../lib/mongodb').pure(); + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../../deps/nodeunit'), + fs = require('fs'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + GridStore = mongodb.GridStore, + Chunk = mongodb.Chunk, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +// var MONGODB = 'ruby-test-db'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + // // Gridstore tests + // shouldCorrectlyExecuteGridStoreExistsByObjectId : function(test) { + // var gridStore = new GridStore(client, null, "w"); + // gridStore.open(function(err, gridStore) { + // gridStore.write("hello world!", function(err, gridStore) { + // gridStore.close(function(err, result) { + // GridStore.exist(client, result._id, function(err, result) { + // test.equal(true, result); + // }) + // + // GridStore.exist(client, new client.bson_serializer.ObjectID(), function(err, result) { + // test.equal(false, result); + // }); + // + // GridStore.exist(client, new client.bson_serializer.ObjectID(), 'another_root', function(err, result) { + // test.equal(false, result); + // test.done(); + // }); + // }); + // }); + // }); + // }, + // + // shouldCorrectlySafeFileAndReadFileByObjectId : function(test) { + // var gridStore = new GridStore(client, null, "w"); + // gridStore.open(function(err, gridStore) { + // gridStore.write("hello world!", function(err, gridStore) { + // gridStore.close(function(err, result) { + // + // // Let's read the file using object Id + // GridStore.read(client, result._id, function(err, data) { + // test.equal('hello world!', data); + // test.done(); + // }); + // }); + // }); + // }); + // }, + // + // shouldCorrectlyExecuteGridStoreExists : function(test) { + // var gridStore = new GridStore(client, "foobar", "w"); + // gridStore.open(function(err, gridStore) { + // gridStore.write("hello world!", function(err, gridStore) { + // gridStore.close(function(err, result) { + // GridStore.exist(client, 'foobar', function(err, result) { + // test.equal(true, result); + // }); + // + // GridStore.exist(client, 'does_not_exist', function(err, result) { + // test.equal(false, result); + // }); + // + // GridStore.exist(client, 'foobar', 'another_root', function(err, result) { + // test.equal(false, result); + // test.done(); + // }); + // }); + // }); + // }); + // }, + // + // shouldCorrectlyExecuteGridStoreList : function(test) { + // var gridStore = new GridStore(client, "foobar2", "w"); + // gridStore.open(function(err, gridStore) { + // gridStore.write("hello world!", function(err, gridStore) { + // gridStore.close(function(err, result) { + // GridStore.list(client, function(err, items) { + // var found = false; + // items.forEach(function(filename) { + // if(filename == 'foobar2') found = true; + // }); + // + // test.ok(items.length >= 1); + // test.ok(found); + // }); + // + // GridStore.list(client, {id:true}, function(err, items) { + // var found = false; + // items.forEach(function(id) { + // test.ok(typeof id == 'object'); + // }); + // + // test.ok(items.length >= 1); + // }); + // + // GridStore.list(client, 'fs', function(err, items) { + // var found = false; + // items.forEach(function(filename) { + // if(filename == 'foobar2') found = true; + // }); + // + // test.ok(items.length >= 1); + // test.ok(found); + // }); + // + // GridStore.list(client, 'my_fs', function(err, items) { + // var found = false; + // items.forEach(function(filename) { + // if(filename == 'foobar2') found = true; + // }); + // + // test.ok(items.length >= 0); + // test.ok(!found); + // + // var gridStore2 = new GridStore(client, "foobar3", "w"); + // gridStore2.open(function(err, gridStore) { + // gridStore2.write('my file', function(err, gridStore) { + // gridStore.close(function(err, result) { + // GridStore.list(client, function(err, items) { + // var found = false; + // var found2 = false; + // items.forEach(function(filename) { + // if(filename == 'foobar2') found = true; + // if(filename == 'foobar3') found2 = true; + // }); + // + // test.ok(items.length >= 2); + // test.ok(found); + // test.ok(found2); + // + // test.done(); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }, + // + // shouldCorrectlyPeformGridStoreReadLength : function(test) { + // var gridStore = new GridStore(client, "test_gs_read_length", "w"); + // gridStore.open(function(err, gridStore) { + // gridStore.write("hello world!", function(err, gridStore) { + // gridStore.close(function(err, result) { + // // Assert that we have overwriten the data + // GridStore.read(client, 'test_gs_read_length', 5, function(err, data) { + // test.equal('hello', data); + // test.done(); + // }); + // }); + // }); + // }); + // }, + + shouldCorrectlyReadFromFileWithOffset : function(test) { + var gridStore = new GridStore(client, "test_gs_read_with_offset", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello, world!", function(err, gridStore) { + gridStore.close(function(err, result) { + // Assert that we have overwriten the data + GridStore.read(client, 'test_gs_read_with_offset', 5, 7, function(err, data) { + test.equal('world', data); + }); + + GridStore.read(client, 'test_gs_read_with_offset', null, 7, function(err, data) { + test.equal('world!', data); + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyHandleMultipleChunkGridStore : function(test) { + var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + fs_client.bson_deserializer = client.bson_deserializer; + fs_client.bson_serializer = client.bson_serializer; + fs_client.pkFactory = client.pkFactory; + + fs_client.open(function(err, fs_client) { + fs_client.dropDatabase(function(err, done) { + var gridStore = new GridStore(fs_client, "test_gs_multi_chunk", "w"); + gridStore.open(function(err, gridStore) { + gridStore.chunkSize = 512; + var file1 = ''; var file2 = ''; var file3 = ''; + for(var i = 0; i < gridStore.chunkSize; i++) { file1 = file1 + 'x'; } + for(var i = 0; i < gridStore.chunkSize; i++) { file2 = file2 + 'y'; } + for(var i = 0; i < gridStore.chunkSize; i++) { file3 = file3 + 'z'; } + + gridStore.write(file1, function(err, gridStore) { + gridStore.write(file2, function(err, gridStore) { + gridStore.write(file3, function(err, gridStore) { + gridStore.close(function(err, result) { + fs_client.collection('fs.chunks', function(err, collection) { + collection.count(function(err, count) { + test.equal(3, count); + + GridStore.read(fs_client, 'test_gs_multi_chunk', function(err, data) { + test.equal(512*3, data.length); + fs_client.close(); + + test.done(); + }); + }) + }); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyReadlinesAndPutLines : function(test) { + var gridStore = new GridStore(client, "test_gs_puts_and_readlines", "w"); + gridStore.open(function(err, gridStore) { + gridStore.puts("line one", function(err, gridStore) { + gridStore.puts("line two\n", function(err, gridStore) { + gridStore.puts("line three", function(err, gridStore) { + gridStore.close(function(err, result) { + GridStore.readlines(client, 'test_gs_puts_and_readlines', function(err, lines) { + test.deepEqual(["line one\n", "line two\n", "line three\n"], lines); + test.done(); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyHandleUnlinkingWeirdName : function(test) { + var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + fs_client.bson_deserializer = client.bson_deserializer; + fs_client.bson_serializer = client.bson_serializer; + fs_client.pkFactory = client.pkFactory; + + fs_client.open(function(err, fs_client) { + fs_client.dropDatabase(function(err, done) { + var gridStore = new GridStore(fs_client, "9476700.937375426_1271170118964-clipped.png", "w", {'root':'articles'}); + gridStore.open(function(err, gridStore) { + gridStore.write("hello, world!", function(err, gridStore) { + gridStore.close(function(err, result) { + fs_client.collection('articles.files', function(err, collection) { + collection.count(function(err, count) { + test.equal(1, count); + }) + }); + + fs_client.collection('articles.chunks', function(err, collection) { + collection.count(function(err, count) { + test.equal(1, count); + + // Unlink the file + GridStore.unlink(fs_client, '9476700.937375426_1271170118964-clipped.png', {'root':'articles'}, function(err, gridStore) { + fs_client.collection('articles.files', function(err, collection) { + collection.count(function(err, count) { + test.equal(0, count); + }) + }); + + fs_client.collection('articles.chunks', function(err, collection) { + collection.count(function(err, count) { + test.equal(0, count); + + fs_client.close(); + test.done(); + }) + }); + }); + }) + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyUnlink : function(test) { + var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + fs_client.bson_deserializer = client.bson_deserializer; + fs_client.bson_serializer = client.bson_serializer; + fs_client.pkFactory = client.pkFactory; + + fs_client.open(function(err, fs_client) { + fs_client.dropDatabase(function(err, done) { + var gridStore = new GridStore(fs_client, "test_gs_unlink", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello, world!", function(err, gridStore) { + gridStore.close(function(err, result) { + fs_client.collection('fs.files', function(err, collection) { + collection.count(function(err, count) { + test.equal(1, count); + }) + }); + + fs_client.collection('fs.chunks', function(err, collection) { + collection.count(function(err, count) { + test.equal(1, count); + + // Unlink the file + GridStore.unlink(fs_client, 'test_gs_unlink', function(err, gridStore) { + fs_client.collection('fs.files', function(err, collection) { + collection.count(function(err, count) { + test.equal(0, count); + }) + }); + + fs_client.collection('fs.chunks', function(err, collection) { + collection.count(function(err, count) { + test.equal(0, count); + + fs_client.close(); + test.done(); + }) + }); + }); + }) + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyUnlinkAnArrayOfFiles : function(test) { + var fs_client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: false}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + fs_client.bson_deserializer = client.bson_deserializer; + fs_client.bson_serializer = client.bson_serializer; + fs_client.pkFactory = client.pkFactory; + + fs_client.open(function(err, fs_client) { + fs_client.dropDatabase(function(err, done) { + var gridStore = new GridStore(fs_client, "test_gs_unlink_as_array", "w"); + gridStore.open(function(err, gridStore) { + gridStore.write("hello, world!", function(err, gridStore) { + gridStore.close(function(err, result) { + fs_client.collection('fs.files', function(err, collection) { + collection.count(function(err, count) { + test.equal(1, count); + }) + }); + + fs_client.collection('fs.chunks', function(err, collection) { + collection.count(function(err, count) { + test.equal(1, count); + + // Unlink the file + GridStore.unlink(fs_client, ['test_gs_unlink_as_array'], function(err, gridStore) { + fs_client.collection('fs.files', function(err, collection) { + collection.count(function(err, count) { + test.equal(0, count); + }) + }); + + fs_client.collection('fs.chunks', function(err, collection) { + collection.count(function(err, count) { + test.equal(0, count); + fs_client.close(); + + test.done(); + }) + }); + }); + }) + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyWriteFileToGridStore: function(test) { + var gridStore = new GridStore(client, 'test_gs_writing_file', 'w'); + var fileSize = fs.statSync('./test/gridstore/test_gs_weird_bug.png').size; + var data = fs.readFileSync('./test/gridstore/test_gs_weird_bug.png', 'binary'); + + gridStore.open(function(err, gridStore) { + gridStore.writeFile('./test/gridstore/test_gs_weird_bug.png', function(err, doc) { + GridStore.read(client, 'test_gs_writing_file', function(err, fileData) { + test.equal(data, fileData) + test.equal(fileSize, fileData.length); + + // Ensure we have a md5 + var gridStore2 = new GridStore(client, 'test_gs_writing_file', 'r'); + gridStore2.open(function(err, gridStore2) { + test.ok(gridStore2.md5 != null) + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyWriteFileToGridStoreUsingObjectId: function(test) { + var gridStore = new GridStore(client, null, 'w'); + var fileSize = fs.statSync('./test/gridstore/test_gs_weird_bug.png').size; + var data = fs.readFileSync('./test/gridstore/test_gs_weird_bug.png', 'binary'); + + gridStore.open(function(err, gridStore) { + gridStore.writeFile('./test/gridstore/test_gs_weird_bug.png', function(err, doc) { + + GridStore.read(client, doc._id, function(err, fileData) { + test.equal(data, fileData) + test.equal(fileSize, fileData.length); + + // Ensure we have a md5 + var gridStore2 = new GridStore(client, doc._id, 'r'); + gridStore2.open(function(err, gridStore2) { + test.ok(gridStore2.md5 != null) + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyPerformWorkingFiledRead : function(test) { + var gridStore = new GridStore(client, "test_gs_working_field_read", "w"); + var data = fs.readFileSync("./test/gridstore/test_gs_working_field_read.pdf", 'binary'); + + gridStore.open(function(err, gridStore) { + gridStore.write(data, function(err, gridStore) { + gridStore.close(function(err, result) { + // Assert that we have overwriten the data + GridStore.read(client, 'test_gs_working_field_read', function(err, fileData) { + test.equal(data.length, fileData.length); + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyReadAndWriteFile : function(test) { + var gridStore = new GridStore(client, "test_gs_weird_bug", "w"); + var data = fs.readFileSync("./test/gridstore/test_gs_weird_bug.png", 'binary'); + + gridStore.open(function(err, gridStore) { + gridStore.write(data, function(err, gridStore) { + gridStore.close(function(err, result) { + // Assert that we have overwriten the data + GridStore.read(client, 'test_gs_weird_bug', function(err, fileData) { + test.equal(data.length, fileData.length); + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyReadAndWriteFileByObjectId : function(test) { + var gridStore = new GridStore(client, null, "w"); + var data = fs.readFileSync("./test/gridstore/test_gs_weird_bug.png", 'binary'); + + gridStore.open(function(err, gridStore) { + gridStore.write(data, function(err, gridStore) { + gridStore.close(function(err, result) { + + // Assert that we have overwriten the data + GridStore.read(client, result._id, function(err, fileData) { + test.equal(data.length, fileData.length); + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyWriteAndReadJpgImage : function(test) { + var data = fs.readFileSync('./test/gridstore/iya_logo_final_bw.jpg').toString('binary'); + + var gs = new GridStore(client, "test", "w"); + gs.open(function(err, gs) { + gs.write(data, function(err, gs) { + gs.close(function(err, gs) { + + // Open and read + var gs2 = new GridStore(client, "test", "r"); + gs2.open(function(err, gs) { + gs2.seek(0, function() { + gs2.read(0, function(err, data2) { + test.equal(data, data2); + test.done(); + }); + }); + }); + }); + }) + }) + }, + + shouldCorrectlyReadAndWriteBuffersMultipleChunks : function(test) { + var gridStore = new GridStore(client, null, 'w'); + // Force multiple chunks to be stored + gridStore.chunkSize = 5000; + var fileSize = fs.statSync('./test/gridstore/test_gs_weird_bug.png').size; + var data = fs.readFileSync('./test/gridstore/test_gs_weird_bug.png'); + + gridStore.open(function(err, gridStore) { + + // Write the file using writeBuffer + gridStore.writeBuffer(data, function(err, doc) { + gridStore.close(function(err, doc) { + + // Read the file using readBuffer + new GridStore(client, doc._id, 'r').open(function(err, gridStore) { + gridStore.readBuffer(function(err, data2) { + test.equal(data.toString('base64'), data2.toString('base64')); + test.done(); + }) + }); + }); + }) + }); + }, + + shouldCorrectlyReadAndWriteBuffersSingleChunks : function(test) { + var gridStore = new GridStore(client, null, 'w'); + // Force multiple chunks to be stored + var fileSize = fs.statSync('./test/gridstore/test_gs_weird_bug.png').size; + var data = fs.readFileSync('./test/gridstore/test_gs_weird_bug.png'); + + gridStore.open(function(err, gridStore) { + + // Write the file using writeBuffer + gridStore.writeBuffer(data, function(err, doc) { + gridStore.close(function(err, doc) { + + // Read the file using readBuffer + new GridStore(client, doc._id, 'r').open(function(err, gridStore) { + gridStore.readBuffer(function(err, data2) { + test.equal(data.toString('base64'), data2.toString('base64')); + test.done(); + }) + }); + }); + }) + }); + }, + + shouldCorrectlyReadAndWriteBuffersUsingNormalWriteWithMultipleChunks : function(test) { + var gridStore = new GridStore(client, null, 'w'); + // Force multiple chunks to be stored + gridStore.chunkSize = 5000; + var fileSize = fs.statSync('./test/gridstore/test_gs_weird_bug.png').size; + var data = fs.readFileSync('./test/gridstore/test_gs_weird_bug.png'); + + gridStore.open(function(err, gridStore) { + + // Write the buffer using the .write method that should use writeBuffer correctly + gridStore.write(data, function(err, doc) { + gridStore.close(function(err, doc) { + + // Read the file using readBuffer + new GridStore(client, doc._id, 'r').open(function(err, gridStore) { + gridStore.readBuffer(function(err, data2) { + test.equal(data.toString('base64'), data2.toString('base64')); + test.done(); + }) + }); + }); + }) + }); + }, + + shouldCorrectlyReadAndWriteBuffersSingleChunksAndVerifyExistance : function(test) { + var gridStore = new GridStore(client, null, 'w'); + // Force multiple chunks to be stored + var fileSize = fs.statSync('./test/gridstore/test_gs_weird_bug.png').size; + var data = fs.readFileSync('./test/gridstore/test_gs_weird_bug.png'); + + gridStore.open(function(err, gridStore) { + + // Write the file using writeBuffer + gridStore.writeBuffer(data, function(err, doc) { + gridStore.close(function(err, doc) { + + // Read the file using readBuffer + GridStore.exist(client, doc._id, function(err, result) { + test.equal(null, err); + test.equal(true, result); + + client.close(); + test.done(); + }); + }); + }) + }); + }, + + shouldCorrectlySaveDataByObjectID : function(test) { + var id = new client.bson_serializer.ObjectID(); + var gridStore = new GridStore(client, id, 'w'); + + gridStore.open(function(err, gridStore) { + gridStore.write('bar', function(err, gridStore) { + gridStore.close(function(err, result) { + + GridStore.exist(client, id, function(err, result) { + test.equal(null, err); + test.equal(true, result); + + client.close(); + test.done(); + }); + }); + }); + }); + } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/gridstore/grid_test.js b/node_modules/mongodb/test/gridstore/grid_test.js new file mode 100644 index 0000000..8741f41 --- /dev/null +++ b/node_modules/mongodb/test/gridstore/grid_test.js @@ -0,0 +1,102 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../../lib/mongodb').native() : require('../../lib/mongodb').pure(); + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + GridStore = mongodb.GridStore, + Grid = mongodb.Grid, + Chunk = mongodb.Chunk, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldPutAndGetFileCorrectlyToGridUsingObjectId : function(test) { + var grid = new Grid(client, 'fs'); + var originalData = new Buffer('Hello world'); + // Write data to grid + grid.put(originalData, {}, function(err, result) { + // Fetch the content + grid.get(result._id, function(err, data) { + test.deepEqual(originalData.toString('base64'), data.toString('base64')); + + // Should fail due to illegal objectID + grid.get('not an id', function(err, result) { + test.ok(err != null); + + test.done(); + }) + }) + }) + }, + + shouldFailToPutFileDueToDataObjectNotBeingBuffer : function(test) { + var grid = new Grid(client, 'fs'); + var originalData = 'Hello world'; + // Write data to grid + grid.put(originalData, {}, function(err, result) { + test.ok(err != null); + test.done(); + }) + }, + + shouldCorrectlyWriteFileAndThenDeleteIt : function(test) { + var grid = new Grid(client, 'fs'); + var originalData = new Buffer('Hello world'); + // Write data to grid + grid.put(originalData, {}, function(err, result) { + + // Delete file + grid.delete(result._id, function(err, result2) { + test.equal(null, err); + test.equal(true, result2); + + // Fetch the content + grid.get(result._id, function(err, data) { + test.ok(err != null); + test.equal(null, data); + test.done(); + }) + }); + }) + } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/gridstore/iya_logo_final_bw.jpg b/node_modules/mongodb/test/gridstore/iya_logo_final_bw.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f07b9e3a4c88c5bea3393e65c2d30b8bada9c71 GIT binary patch literal 74008 zcmeFZ2UL^Y)-D=F1q&i#08v2&MFNN@O+ca|O?pW}j|NbRh*1!!QBlz#ARt9RqS6x} zf;6SX7LhI;K|uovO+XS5UI@uu_z_rBwfbI&+;j2o93d6ST=HOn)fIoDj_ z_wv8NwwyLJF@&vJ4THIZe=z|53 zhuwm$U9)ln_iF{$g8%E+tzElr{RSbS^+G}$gg0yiw++IZHf>t@FCro;Dk35wE-o&y z{U5hg>(;H?uzrJ>u&|i8=w?yzf4uO2_W}PkOjJmqVAZU^DpA;K(NzMXtN8C%Jp&UI zT(xoo4}Ra)tQAk)7}F}sZ3#hg2L z^-fYw`G;=SFHIxN`M}8J+={xMk$Ej+d(UfkQ}QZ5_Kq$n95r$93cB|w|7HE>F$kf3 z+R;0hm`Z-t&^Nva7QPzHaxKunx-~)q0={59q5^AHX1vxK%y=FCM%>}2#Xq;bY5OjF z5^jULJaa@&P5-8NyzRbcZY6I8ue7T(PDM!AB>?G2Zr`tAASLhakJ4mkzIb;)p<{@1 z>tR;uf1k1;`oAXqFX#Mkrp)hyZ4&rBO;H#U#&$1h9Is#cuw?XdhK>$y=fh|_rnM+F zUWCEu`E=AkDQ)`0QVU|*5j#H=HUbYUR9Tv-!wG4&Z1aYx}?J^uTSoH12)QH0xZnMh(-y*jI03Zt;V!UnH?z(W1@U zWPME}f*A!8P1?Kouq5@brj4(j-1l}wHGckj*C{=`z%ZJghd4Gy%)SQHTI|V(aiaOK zN5LbBlc9rWQoY)!N;H#`?ynS8o>|`wThPT*`98=@Nx|C3Z|M4A+R90*VbJEB9Q^1x8tM;Po zk}6S6wYf8wW5E;=8d~HPlMBv`L+<9o4iQvK*K*{O;@_0kWjLL=SY&qi%B|~zLWcce z6?E4t1zwn7acZ7t^7pmB9$isR{1p9Co+6Mk7-eO5dB;wa0I~AHlj6~}7KmTREP40} z&Jhzfy)}(0+d#)Zey1%p#HDr-GK)J^EPHpvOuQ<{>FR zI{Ta-WzBhPYW(@oB`*@F67#Xvu!p9q`#Qss-Fu_#=Wmt?UvU59xXr13E<14B&4py&??hb$F8^b|6)4+_`-!8H z{6n|-?B=x1$@xx&%$Li zoKNF!XWmG(r_6YFKF{f;bP`6bfd?T69gUXvlNPgyRlM6WoQUPQEJC{%A4ayP(EjNS zSv>H3`UP$?n~+>4b7aDLjFLTeX&E>A=Bj(b^*!P6S-J&Ji_%nG#+)>2PUWRB3wIj^ z97CV=^_2Is&~q1?Q5Rk-cn9$d`yX8}6Az~L7;0QC9#d!jayRCd=10jT5o@b(ElPcL z+b|!d7Nlq;g-tDudc1$`hG+cu@b%j+I3C@WGK}?iBWBr?kw$F+ghS)#MZMc@df8+b z%^e{+c885S$33-IeR&)iikg*A=EFud(^Ss(a~TI_rx4Y6+&DV_2~nYGi>@j3O+|@nIRX znIc4q-?Td)X3wieS%LsE@3#;5lod4eaRA-U&CMRuK1RQju>R)yqWIya2A7N?8xO~> zs!b@QAJjD6bbbA@;FC!{4E_~hN+@b>{&95=fk|x)!?vKU-W|-$9W$~fu8)v3yLpIf zuc(O6=UqUtC6+h)v5c1OXJsIXKt2pLgO-32`LLtHEIzDR=AcSaK=TpP(h{dU>Zxu; z?Z%cZuQ${yQpH-siZSg3&YeL>N!@bE?+YK+sa}qNc5u@8u>Cz5gvko>9D@SHKlgfGhZi zF7aVD1NY{?61vP#99qg;RqSCX0?mPcv3?Uk889d49_r~Zs=WMz@-gAPSQ*}q0_40b z2t3A+535ItESLGw7(T>WIc_7kjvY~1x;T!U+qyszqoeDW`@z=`(1>LX&LGd&{0bko z>L_x2BRt%lHt);JU$&>rwHhWJP!m3A^4QIi?4%;Ud&8@}dHFLq7##~jOp9ZV5!e?)QJg_81Ix3}!7h0WhG)@TZ-94{@#Y~J-l1{qjN%0pP-4r@pt{-Q zhh={IzSKKCUNRW;$ANFPwiWAEnR!IO4X{n2I1*(g|;p8EQ=P>Iq zowtq#(v4bic+5jae$PX06`nPy=2>fBMlCFGeRuw2c!TjbV?OMMSVEX2Wmc9m-&D?r zB@+@-6U$Q!O6RZ61cew!Up*jiX*>hee06+el#W#)wCsT)HHCJqiw?4cwr@r(?%-V( z;50TNA3DZFcs%n;(!S~4Juha~^TEpM_2?6ooW>qfD2hRw)z%B+!}9%3ElttJa{x8i zC8GxnuHsqPJa*0&Zmc^77H>HsqXRji*cnfsdZD`=tJn4UL|ws;KT8ruv6wy;c;a)y zM;bR>&x8*ve@3XUpksZ3gii82gCg0KMk(|Q=0~NGS2dltA2x=^8{a&#CLVRlZ#&a& z*9@kaFsn6~ik-Xoi8dxZ!fQ~q8$1OJ<`d_>gf-!A=*t|}-pkSzol-sy3-bu~pa&$J zU@JUKg>_7%fj~kg9r$!Z{mu)ox#q1<=la5nl^L706FrA_%2@?|#ba0o@5LM~)e9Sb zR+h(oe~e5r?xl!4xsO_01)!BP{8)tD%6=X+f-#6ibrtMz?4o}4{@IJz{_M7h6=loj z*8y%nR52|);B4s>ZUaa9=}~r9ALOP#Y>-`3im&%?>-p}LlZYLX%{va8pCD$X3UY@l zM#OIi?RuYaMw|ZX`Qgvr59mr4bz(g85!|jBOkX&PBlwUu0%(L%R{Y|}9lH!%>(CwU zd$P)^?ytUfOs^f~9$n`xU4^5z_-Q~_CmQt5cZX7gzfAdu)L-axw9@`CC~$-4XkD9* z`qj$)PUV^IvgP&n$jk}*5uZ;ti9iiNS&&f+?<~6}CL-&Lqvw44=Qp~nZ^je54mjPv z;lq}sZ2ym*-o%G#AhiK%HjmEUEvq?PXDOv)@pFfm!oiEH*D=Rm_|MW6h}A13oXUqu z(>OgmbvoL7`3Gr2rU#IX6^35Qhk4Z6Q)W9j=lL)>%SW`IyZoTTsu%kq~=a}A=b;<2U{N$eT4;J6WYV*WmAAdApKyGF<6Ad^VYZhsN( z+8*B17$D6K+5kmnp;?4$j>n7{afb;!6QmXh_-Zn95}Og+w&7aYX}U{&sL>#?Dt_TU zs`_`nFpA_dGjpdNF6zj64g=Gb0=&^albeke5ui&p?!0P7N;GE*4|PDl+&m z_DLVo!uonX%*vj^0U@KxZ_aX@j?Jc}*_!%7>x-QGKejoacy>bR@KeOcv9ZG?ag_)I zL&Pm^7NxzL>hMe1_b$Mn3O?}jyvoj4rRc$n*L^!d#3B`wN#m8R*&Wm9%* zizW|EW6FujV9lz}p15*;kKV(Ko#l+77XrkmG-Vna2Wj&9`}~#->WH-+z$V`T3^n)T z!+aZ&kft62n&#nE_%Qih)a8gkA`0@k9jdVFK=0UMsu-@HELO6 z_Jr_)jumB4vymerp_z-=*3`((XhB^qopd8*ML8$t6gh*LM#@!$EkM0WkTeeAoezWZGmUZEm9; zVgU=s@80nEI#3dc6D#Gxx&f&$uLXGcc$rtvHzkDb*SdH<{u+dNGW$gX!5!fo8`jQE z3HW-llMl=6a_y_*NU#;n+9&1L`xZhTYBYPlG1ECL_9R#UK>&5E7efUXsQpXFWUfJmId?Z^+R zu&t;lqjl|)%h-6lQOI-1K61;C=E@U}00xr(2?lCUbARj(zX&n12z9uj1soOmH%}-R zI;OgkLZkj=W{W2MsAz0*-n*3}f7*8;PfkZdH1v{3}82*H**mt)(gg z@I8_W))wzKp&;{ILJb-@lPa^2%Aj^*HC!NEU1QI@>*dAVg>!PYdAtYF9_8O$PA=YU zcoTWJw7&?L{Y)&Ek<1A~^1lBhbZtTn4#_}t6&9PY{O%iI9g>tCoat0xe^N!EaV%4U zN<|{g!aVz{QO+{@!#2`{@L)@jkqyQtQF^0Zla|OSfXu;Uh&ck3J#o*z~2-)CPc@2 z5n9dyP3KgA?`D#?X(V{)JkV1zAC?f)!}}aKn6HX?LTK?N)bNY|+0ahrp6-W-#uSV; z%oLk!xf9)kE68~gdkJ9hxku_1BeBDd1$6Vel+vpemFhB8ooCms*V}o}jmf5CQ#i?Os3FSj`O9}7cCzmHg!r1S#yZ2{15k+kIIN~r&c z$Mj-TQU{rv6RzY^Szc`hoy8yh2Rk&{zG&ubSj>2IZSXEticuiLbpzj?%^k1=CKxI+ zrw;Hp=uHzc4+}Qeh2Z>4+1#LjzqUtSCW#93^c7>zG!4GO7-ak&fY&Q)~O)1 zwfYqX9z+@joKZ%O59_x^4)-&tpJ+|kMw$Z8-3y(HNqe93p?%op&1j2nD_J!2Yb5q| zOfRL0Hj1Lj5#r~049jIa`UH~()rr*Ctea9c>^SLink6o>DK+|iMI1%=&Ft6vMq{?b z;%TVi7=a^Vz&`d~8uk1Xo8C#laMqP=DtmQvyQP5StyN=n`%acVjrs7*Q>1k8I%MsV4R?!r?Auw}#Zljp;} z=!q;oCDv+lCu`VAPod<3uaM+t871Q+n$7YKsdv7p^7|%l;C3Pd>xuw>Ob1-%e;rg} zJ`Sc2LK@W^5VEUi3mJ&lGZ-ATL!=SQec&j_TRj0N1_(LcUW3!9Snjz<-u_C;Y$oqA z5-=!II)No6vKSQ!5BK_833PESFy07lQ^?TGcE)K!qPX&>oY8KsB#wF?siC~DnA^(9 zE`1w+up+d75*2?g&a%B=Gvb{pW}BB_&h;0x*F^0k-|I^=m@z6Vb}5oe7oM&FfV5?tpv_J0;Dxbm`n~^On?Uqa#=k~gTsV{clm_( zg~gbUy_6roMntq0lWNbh;Y}oXRnd!_r#uq{;kU7K&W3|OVh|k5me_{=2*40lXE=5Y zDfo=|G=@wVT9*_K%~a_SYQOFyBq0`cc$eLp%6W!dQu6T*p^7v|QBQHvJx@)o5>qqY zu2JB9#8F#yQL`fd6T+en0%^@~D|E9K0OoTBH36u!i0&E?Yk&P)K7Vhb$v2-wRoQ;R0Ju$O;0Cf&~e>ech>hxGQzoNFIFzSs#E zO7H#wpfyYL9&{VhRiV0}`7lxFLgN)l8Ik-eo~GB2r33nLXf{eVe_Z=&>N$Jix%c8Z zfpGgKwo+*C20Il*I%<-ZD#M9(9AU;jWN|#YYkbH~PG9u>_SMu>#~l)*!I+PFtyE>g z5kK#v9NWhyEGtcG^cYS$m927>b^{->;|_2v(+|#J_d!K7a}NGX z>YZwnr^BX>?Tf?3D_{%KUL~Gec-8qhkJ3mOIpptjOp~M6XkB(ZenQ&}BXNDh<<#}= z5s&6o$s(EX5X?Ul7gH`Ur~0aq*rf~3giXJTH-D7-DSTKRl?%8>G#-^e2$5f`n`4ky zs>ZlNvC zzCk0r{y@TvF6stwaBPlD5)Im2`j6D2^S`AQAgo}L=3+H@7$~7J16v^x{Nd>u>prJs zg(Mjn~5Qf5EH z1r#XX8@Xs%0*FT?rLp?Wlkr+iH?_K^=(uv3uLkxcd#(Qi*%{&EqYh3u?VTva72*Z{ zG+m4HH7AWcp?9KlzvwRKqRgx-Y9jazms0oeYz^Uci@9(QP(zQya$*)+)64E~dg5$! zqH)*SkGUBI+B;s^@YCdJ;Ik{=R+kjRpX}}-QvMQ--#1R<#Yil$GCX=+tjYer4g$a{*UCWI~BE+ibk(R$uT!I@t7UtSRis7vE8=7-Lr6=l#IQl($W!$V!8j_3Flvv~ zA&fi5@)CZ~#*0AF=ATUONtqv1hizUKF|F+`vs9^DmzH~C-`C-{zuFq~HzZ$Wlq7i{ z7+r@*;u#Qzzp*Ws%fxu*wTQ(u-W44_Y~Mg6h){q}jf;n(erBu`8P7xOcXuN9>1M3Y z^F1sb?&F~=qrU|8|udUY7@o2)X4?(*6%!< zb-P-B!!Cht2iRFpSs<4Dcz7Dy)SCOeq*M0| zD=9j(wcyl)9a`zeNlAHM7StlXd+i!^ihXN!A59F4{4(+@2($F}6e zoxPNkf8fR=W}Ib!m&?tJZvw>HB%mCC?DcLS%?Ta?Y0eBLmgh-mITr2<#d0K?wSUDv z+4mta-`m#tbBmv{tcqBBWK@G>m@FJ8Gpi)?m^P;j$g;^V>>LIjxV%wt#BbTunh$Fa zOI}9N?Q5Z3po={P8q$`PDkDRx6}h8YGo9I zSk!OEauNf1o@~SH;e6fPwFQnb8U7u?6-_^`Kd}hiw9)nP(J(Cviwn{fP((gJ7}={r zPzWu%!mJ`3q*Jn+XH##yjGruQcqAL6xAT;Z|Llb0Jl)lLMC1@HEwrl;dS;40zyC#u zGRKj!c=Lz?b<3~{;@T%%{z~C_mXM4bK~T9h!%iZyxrw_giFIaDR<)W1_rDps&1nU% z*<6;Zk_!(Vxd>9er1dc7=qs&VimxLqb5bZ1$i-ccZFyNyeoJ?0%L%`M@pBh)+_)T& z@FaElv|HC_=7p;0;1RaRxz`0N!<+i^VKbKUBIeeG5)?!ZsRpkXY6YiD*>i<4Y zl(ZcwDi?C&``CR3seLSQ1-Z+6hKuf(A{q?q;9;i2AUH?+n3WRWwFV#PPTegwTb?oD zcj;STyo7Xu=Btv>Vhq6aPfVU;uruw{L~S9mYF7Ex!sSJ}Dtaxbu9hU0yvSXs#5 zi=%~jl~lO5Y0P!PPvXr-LgF6jI(X;{%7j!7E&r>J_SfN8cPPOuCrZ^FrfhNlmEKj) z1PE>Yo-HNv-l%axD+*-Ovi^qt@Qc3j@Tb=4TX_W0he8MGG!(z~NO zLLe&Bo=e3uEBznF{Mx~X6&hXbS(Ae5i4@ot7Bp9ccuhdiRQGd>IR4=mA}q|&#*^nu z#p6$(5$xGGb47>`J0EMIMGk|Sq1G$VJH4o5Em6|<{oN}K?5BiV^XC$_%XMol%*-w? zGN=dW&c}C0e3~TIW_?1A99D0Z(eF@8qaohped%?i`zSAAbyqWzq2l?J&z5I;6vL<7Bt%mhZy!=Qs7pD0AN9@Eh@%53HosCy z9V(M(&2%no?>mxmE8UK|^}AE7Yc<$Ioo*3pY-NUJWS z1SvM9k`l`*7reFIKWvv=Eq-cZXFj$!Q78anY@apm<-d17OCiDCiie|k`i{jyhp65NBHv0R=M;evxdG82nVR4 zs7K+LaI4;+G=p01YtB?b=u5~i`)G_$m%xNXeEw77z|&W%Lyb{e2RGdGF|d79y$qPq zP)_|E2-?r4F~$0IvoV=@jlxY4xd&GbXA`<*3=uH|uuIX1ZI0dwHeB=trV2 zYuI{ZUZ%;Gao?C>=nFrh& zmP|uzQ>^B=byHtYl6dc!<<5e*{D;!cpFr`_0>KVNA=$2pUPVw{W9t4V+Y8i>*|ax| zSrb)>K}nh$-aTamGxA3OfG5t9_VL_hbG&+aZ7GBks}h-3lIP-IM?=%AI1c_%ds(B2>M3WCAY( zk%&2M;dVR}@4TmD;r#H2e6mweuHp3oOQvsNgzir&)+8y*j=Lw~IrI1%A7>P&u4zk1 zM6rx6YKmvit>)IU10VPgHnlbn7I_O`uSz?xGcs5bmC=E7=N@c3lNIW8__mE+n>UV} zR2vLj>|*zRsjDxbvw_Ts?Uo`PQsGaPI43uM`FwQW$vLFYFdn@NdIz0BDy#R)bx>)h zK^T{Eso3N)TML`xo%?ncZhN)Pw*IQe?oa-7S07?dtxLj*NS6*K=aht|tBc8v&dDDs z``*3Nx8AY!iMrPp9M!G327D>DQ>9R8FS{-c?NrYwkItAnxF_e*^;C`M$R-uA zFR8(E4l0^%(55AGTLTE^cOI@kmd%j7TY2BOR0W~&db%7jqoU^$?&{*L5ewmS$AhmX zm2>^}cFQ?<_{6xgPZrI(ZrcUgPcqpg_T8YVK^u&aj9 zNhP`x8tfQQs4B)73O+?|(;`Q2Mr1%oPM7uQerGm|FFO=~j*pgxQCYa#HcplwJyM?@ zvq1T(JCg+H|X&Vc^)iyYm+!p3z(Ctg# zQ&pk1a6O+fVO{SXd~^Mpoxsnr%w^4HLW-*+d*FG|qHBI=d5@P^%9jtQ*thQj#)x_0 zxKUtSoasm0s%*ugv}|wN&wWbwUEW)(OC;>-U1Aheu%p;@r#TO$rqgtX^6ImK1R9Fh zmqq0vX{m-glZ5UG>s#dB)5%+%^AvrGaELatOF4V-F_pQiYal)MI_+g=wo?UmM4|b* zpPwyUKO7hC039Cs_%r+h&-SZ}DO3NF(p;f9m;JIM7q>0+R6<<>;z84(m%XZ>hwC0< z&AWP1qMmiTZkiw~a76m)m9xx7*3grn;CDXDMwQ-kcHVY2B$4+HC*UaOaF9>7=#-M| z2=z<1J9w=<61ES&&hRekz6J@~F}$57sOciAbCC&1rgymYI7TWqf${J}!I) zo?#$fi<7Bz;XF-FQm~))u)Bw#WeM?mQfggM1)1$Y1Cd=xOMx0UShb7_wwnvPF zJQizKZ9SO0F7XQCZJ+I?j4YKcGFz99_QNfZW`q`H&>KJnn7L>g#iKBamQ?}d0di?W zO9NGogDQ(uVznVNQ$)w<=5zLy4dp+!=HAtt&BkLoTraaDxkJ;;_tK6P9F0hp;#VW* zwr^c#sbRgdb$PHer{ebrCYrwK7y zvuJDFAsBONpM!(B{%Y+lfs&Ll5seQ>JtSh1c1THfE6*L;tKPxw@!HVs)VQm``SyA?BPyp(n8>h3;Gs;=4Ap3< z_7ytPTI<4rXGP0&`8|ypv-@P?qjNXc@Rw)rvKHkKz}|TFWCh3-v_jtqrwUC5?Acs! zS7X&wd&wt}?TP(kbO#Bh5zknrg*2x`v!-K_D}LMvHuH=UkdsxpgwE5r0#IF61jPr- zbR=v4An(a{y2E+q19=|4m2-EM?S#VxJv@U71J#<3gLpa?FzOZ+PpR^ItY{;SqT?N3 z#rjn7gsXn)I;Ebt#H@|RLk9)(k7q|~OP#^ zLC)Vir%Q)>J*V4Oh!Lyq(QW;dvvunM7wtdY%6ldT52kUMh#n5r8Off=1y+r~QQ;np z?CQ1QAh|t1;vUTuX^3qUX>`#|@tszip-v!3B857)14b-pHA#kpZ$d$DNVTfnP{ZQf z{KM+HEGW(VL0wSRS0n#hzV+6%YI=%$FB?h=!h?Ib%>5DPb9kP+T;HsAgp$q6yGEZ~ zZ}{@`DpZkE5Y~eDIVDL!aLX+rp;~iLs{94&1J>4z0t)Z)K1HaF1@;S6#0TdD*CE(c zOJGLA*QQ5QAi8Nt)zE~uo_-Iyq5bOD?sl8IvQ+l1N))u4?ivJ1J>-64oA6;}zuR%F zNa^|5W|FSVlFL`n6*hy(aZdg2acaWkv!&iIe^C)4Ekzk3*WY^&%^!vX{&5$>vFjDY-8<6Kf)Q zmq`vjw5GwIU9_oL0>bOptBWM>G$Wb(txdxsQioOQ4G}*JP>&!Zj*K(=;%!#!L9d^E zU%gy?OBa)}g&9>pSGlZ-yA-f-_tss#(*3vszf&DM9J>8$wyzh-cXj%_ZkJK_K6}9Z zg^4vZ-sN0J=18NAoIP*kIQ!}&-}7$ga_4>I+LZ2hj$utZEHmNPHY4Uh^^BzE5`^XW zH0EpX z-eGU()>zKH*A*<+XWO<~CR1MvT(;B#UBi6XE#0rSe3&+i+QYLyNEpvRJ z+*TDo(Y1NPnlU@R83Dcfcl|;&BpyD}zSE!9a%@9)!&PEG+B8ksP^LFY)K9KK@>)S0 zMF8xNZilD^T$am@_GS5;FP|HI=WcDK*WcVTd?)d94B`WF)SISZ_`TE{ zpw}@1s~R;b6_^2N5kFpKNG`i28%Gq@z6SI2t2yXpkwAvB?!hLaZfg9CK zcHS1Dy&wE34-Z`$W01Sc#l|Hx7Q@Kf5Blvh^^~=?X*YYbP2`al1)$vsVkD9qlIaBDn@E<7Xv;7f;GZ#7QHkbxBu2@l0+jDXsQ2^4E)% zJwLJp=bj=|IO4{K`B11}xAz0>o!*()ld;Va7L}GN%jd_7y}#MW6x{T@@rHWH5Yen# z0opmrm}hrhl|KKns_Z_jJoSmw=tAu0f;U+L%NR*YXU0S$i4&)1z(MB+J?Znrrs~56TWRDrzX>%y z$VrrP|0R+9Omu-I<-*?-Gj$%uhiF&uRZXsm@4f$w3{^vp^sPBPW)RrU?_ zDIS@-C&^7ZLVSiiHm4Qf*CKM%rT_UgjFkqtv2uU6T!ptN&+a_@9FlW?@p1OA8Wytg zn9Eou#4*YEsOaxhDSI{gHo>REOJQmq0+jx==9u`WyfZYKs?yJD z^Ny`=Z(jE$RyTC;E;n*;-To;>(T5e*e%H`T!GCi+3Xg0fQV1=E_G7P@x$y)|HF~P( zNYpytlPz8u0e4ty4TrX0zNYe_k?u(oJ`UHSjDURrGK~vL1+CbH9=L<%dnr zgX8!~Az7Rd-JXS56#E$N%RUc|e=O66=UM1yuXgbg_9WDYdnIK&+($9qe{S~y_|VKD z^yv+EP~`l89xkJT)#r?FpPX%Wvvjjp*U=e8OX#=ds|b$$z@wd*tp_0_4^Q{tL_QAi zkvSB8&S+yDNa7T|N`mWsl!$hXI-lTbYDx_-_)vXJL#=POy05-#7j>=~?S{`E$82>O zFe7+7*uSv4y5rO4cktlYVM~&~2x9!zU{WZ{AvAHsR4jYEqtLSJ%N=``+M1cwMmER$ zo>t-VTL2f-Dub?bN_nSWcIfsqKU*s9vT6Ax)c8KURXy(Jom|&VpbKWeh+9<5jq7A^ zKXSiyT~I#g9}rZERQ%jhp;@7Md&AQ`o_bPTU2nyiBQQ-Ar}fd?QmZ-?i{U6QYz!)J zH4Qm@aQqHhZuc*PXR%3$U&uzEDr4G+G#{qvyT6jCL%DaMMrc=;d$8mL-Glu4O$X9;iravRm@yFKLx zOzf##I%*7TTE{2!yYepiV8j!Q@B&Wux0Cj7z7^%Z?zYJe9CeTA5{`O>Th56EBzqV* zv^?R+K?_n=>4%9%X`D{f#-x3fM|BWa&g~}Mx!>^q0v@$v5c(j~RF;+$v3R6O$~mpy z`zj_*?qcLqMFksVZxWP_N(egtF$2wws<--#vI#-W{h z;q3JG=P?K7D1t#dZ=+BzPnyV|S%;XXHY4kIoo}I~NKL2uQx6ASRz}(+$=}pTW0&06 zRgITE;dVw(?$``^k05ubt2}M@OAd)8kyQG4?~w*(;lbMC%T@uRnRn}C`>7up`SPrJ z*1AZRmcOMOB)wj_`Ucau$uW?;p+4Z~wvfnmkuQfDFFT~Pmu|=+B&Y~iuqqNpD&zLt zIc6ed;=TuEB={xaxT>8dtHS^fkwz501te_`h{}yI{^;SMQoQDZA!1gg!JN?G>c-yx z5>grQJ)s6%GcFGbbV$8Gq`t8s~wYd0X{Mmhid3#=%scW8`@7xybaO}~EEzlK?e53WUQ)A!qAxnz6>Zf)WR8n>(@bDPUy^F^V zD5*`PoebY~QgI<{9hSATvfdI@3=Vd*K3vHMqAg|uqL4=brM%kg;pKNG%*h;~xnwpy zWF^VYR9}62qb;%4Ey>}0lF7)`q@c%HNf`BWfx3_G&B*n@&8lA(eTA@1QkIXD!0}3h zVa?)IONJ7gFvH^;NEwJl8fU3V+UgTcrOYHWEod94Ii>a`mS^V+xf{Bd-RYCR^k%(c zbE3CM;04so0AfBCq>)ihgeJ;R;1%Jl%cGjbN)?-n8Lef`9!Lyz)8cQOQD+) z#E`Ulw^@%@8ODS`o6|o?Kjq?x`9iO^t&V`Z{suwxvM#FZ?tv%Uqy^wEV~oPZYvk%9 zE=~%jKKGvJckPKAvgK?5GbEy-c73imrxOp#1E4xki7Qf#D27XtTPbzCB`mnyvUh5m zzz#pcYgorhJiYM|BWihmXHgVrZpqq& z+T`{nW4JS8c!@zdjiX5I2I88hqZ}Et^wAypP1|yxc@Qi}<2^BmTeCNbt4@4VMP;j^ zH130M(A|t6AM~?PIdO2rSUXrz@mB8QlMeXF;4}W)ARJ{w9I=d8xZznAZ2g28IBoHM z-L^AAKefn%7Rce13C|Ak43_R7s^FJk{xD1-&`u#9&OFgrSBn?`TEOy-5k{z7A7Vk; z(r08hk_xx|=Y!r(uyoWlvlZ#*iNRgP;C7-6@=e{9>uNBJfPxs5_u;+dZz+Ea%2`#^ zKn7wk2mBboHA;8}V%icO2*^$ceMRu#Dc1}{TP)n^9o***qBQ6Cs3R7rGANs_k>94Q zj7PC>dt11z0x|y~-L3&FvIFh}mibTT&nf@1Kkcu5#ojdx%3B3u7<0g*s{u=qa^vY_=fw^3wJAEfsyo3AQSuuieQaM;cKUl*gvFsf@ za1*LXlH$CgAN2ie-GUcyDtgPS!5dR-0_4~eZKjI%_a1#nh9V`gUAN02V*1;E5peD!fD;fc2^v7zz zg8nhinxXy}Ko$9=*T|2|R+eJp2{dAc8XZiKw&BAhf+)7nJ(o{KG%l9DwkeI9OdXKr zY&8?2ySludSra{~$f4VPR$ci6lLWZEfhzjXE$e?}c<9$fh#Ffs%8rgo{H-iBc!UCv z%upy`eBc7Di?aL6kAN%vV>pY!SB3=q!a+o@*~)6a{HeSD*=l=sqKfo-$?cW@rMy4< zX2o@WuiHHHx5~_N5Lxxa+LcCtV{H-MdcHj_-g|HMSllNqlx1LKe%>S2`f{#5=#xn; zo7^5LmOGBQ`kIiivk5G4qZw*9(7VH5%ePT9`+XGrU!*cct1DOZTL4Uzj3YOskW0V? zP%%*ZpUVEj2?1*S!)}4;7HuRJ4Vf>ldZ|S=4PlvXM613Q?u@`$wShvB{oJCe-E*jX zoF-gwB6K}2e7V@pgPP`>e!IHDld^=*aGUC76vX$1gnYc!T~bg?>a*?Wjp-#<{+8cw z^9LpZ|U;TMDA>}+&;ZZ03=6|WXY{ybZZc?jGD zd`N^5F%JO1%EuiJM|zlM%l4Uh}q7XyG7`GzW5lqHNW$_i05%6=w&SR0&{6Pnbp^SF@Z4rgqqTh^8s-i=l1;zB(4*B6tLx!H83>QQWCkz5{M&3aHZv)4m0$2S5 zGm5^cqCq72PAvQ%L`kDRFHcRyI_V&A0u(1NJ&Y~ju0q%)b&Y7=*7$YI;3!Jf(~hXQO;Ko+xutMl>Dn@85H7V{=r+duB>k%HtNqd+r!?Y*++2z)Rprr?ijX z+*cv-$x?0WqNfRJL2^&7Y!@Dr>^;c2n_>2n;<-4LpQ}3hVo}prFGjV3tAXH%906oW z#dUPgu%)i2g4EQyf)NY1*`!1~CK8HlEC~u98E^LvcFplN%FlAi9>!(tJD!7h05q(W zLXO&xcm_~0&J5-BS3rGb@aM_QqCb=x@LQ>vziW5}C;&YCmtNP>F}GI6Z|&mpk&me6 zcT(OS`QVc<`gGUvy#-*4WW@fj#+eG@3qK|3an`ljujb>;Kl{H_*o4TEI`L@y*wTu& zKmc0_Sydgs{)EimVGC#y!~k?6-BE#9_}kw9xc{5suY@wPpQO$fkybdmw6@c~XRB95 zg@%prJI7`@d7kJUL}Te-i%hfdZfaL(SJ+DFR!Sx?*r9RE>vYUPD?M+ndk zQsQQ)6A5r@fLPmAQQ#s_X7*19BNzSk6Efo|!-tC?7!H4 z_Z-k(qFe^Y2#V3$|IXp4exJa(d!yn~yov1XuoK^!XAUj3ARb-P`g@!QMq3HOofgF) ztQb|TiYBg5tUrj>%Ke|?x5-}kEiw?QSBPUG-4*QmX!RG>J%cFD#H(2nQo22IV#PlD zw-VlOpTR_aX_yZbb2Y6_KCC-sc{MJI^q!G-?sugBFDv>(Qb26z1wtm_cli$OzYK7D zrGA(9f3f%G(NO>I|FGUIv}&6ul}b?~NzrDRkS(&mOo$0>5)zVart(f2BxEUT*=I13 zeVevX5we%HM%F@h!tHKRW7_viQh{m!}1eeQGaKkjqX@uHY{UeCwldR)u%dfp>H z#c(&0s$sSr)v=vix#nBK8z^RPz1`z^p?gKZ-GVJj53VzezDp6sw@c&e9j68y=$ZpE zCaP<+^tD9z)%z+gufk@6&%DEvcU*$!ZbOva(QWvZyAx0K#B9&C*m2^HyM=k2CEu}- z1f~Hen@QX8AN@rYAGIXAdRy%bw!3&{ z6IS#jx`e!?MYrD_5UU`?3s60Qt|)AtM>56^fz&g7_>c~WP~GK{8vPyhZjbWc3i`OU zfTFK&7%NPP;_)Dl6n&Dh@s;G%W7d=v1ynB_WWRb-Akv^7AVT>94K<7r22v}705e+P zF(nUi?^K~)`|W0PiSlWz03@ux<6KTbqMOe^-FSD? z0V3)7I5Rzv@9aiRtlJ_7fypDN?f{XAijZ4QD6^ufpX)L4cNq9PN2rU(@F9r>?sAG7 zB@ZG)d&}E`t_QVE5sESHm6DQ}v&h2-6>0)vsoVa@bWgXC@mooKhuGl}htFE*dN#g& zh5M8tW1{hb$rGczDB-uZD89uo8DW@7qU6f^0A_`c!fhdjCbIhw(|23K7C>e|@VmrYVRANEq+PW|oo*3X7x7;^Y0!;-*7|GoM_P9e$GwuO0viIcc0 z_?I0^oCLhd-BA(%VM2=deQEj<|v zEVZ}#do3o#-gvVdW(*vmR!?tQ7UW+rg>tKL1(O2&0Q(aJaT+ZCXQz2xkD~n%Jp5T^ zQzwL92U%4K4s=e0<3WNcWYk^fd8>>#p{s0)$KYY>!o&G9h;*Zih&OVS~Ic4>Bpt*TXyu8<6 z>Ro!1vJ69Ot`*SDE=f+y=BZ+^3Lb+xC|G-*A<)ea4@S;o+V6WI=whpVr3yPiZ4YplTPIjpp`5R4|vdeF~gY z6Wt^@`eM!oW5ex1rsPctZOC4lasI}xEn5#^;RIahY1WuU&eJwwnvLjiH}eX45Y}l~FQ#VMIsfOE(9P%-(&0K8NkU{7^ zKz!T2XFt!L|EUwnQP`F!n%H{sTowG_1^Aa>x5;Hy)JVcpvr<+vd%^RB1n zO>Mh|%`I|2GD}T0tPexUa(vE6yHQ^&x#OivN{;Sw!N+q?#sd)17x$k=qDiek`2c3d z)k#>}e?&xF9j_~Eud4j)tSd=6lUAx_SC}!$(#XS(S1lh~KAKk^n-Z$#6Et;MZRKat zAJKQ&GWcgKqbeoB*s18}EDx2lc~0wVg&(gC(Aak5f&2~YbiFFvqqvCcha=1^GcLCz zbtmKqt@c-ol+0wfpJH5}gt=OBokxl01fiLT2S!mY58Fg=DS^2fUF4Du)}Vug?cTw~ z5BU@S(s&&ABaX??N5d#_Y;q-c_ki|>heUYb`5ga!sLx3|z@+Rgp!j5>4*+9Pfbj|h ziI}2s`_G?dVl$~^DwaukS3t?mM8ypHK!Jy3Y`H6KXA5Dppq|`fxuwErYM=LuS&269 zPt@w+@$c;iobA1rtM2ZvOc2C~T@c-iEdQfuQqfc(!)pmQug2Y4yfl=(wiv$(@>bnQ zMJbq^4edW=m+HuK1jBI6h`HKp-Y#OVf((^>$fc?kosT@OXYIUxtY}|M>e1z!!=P&= zIOyzK7m1g7a6ZU~3rIAP1KWUy$^T?<3edC}q;g&rP(PEl4ZjhZ8Hyb|5z--ZRYQjtGnq3O>+{XArFjt{eJ; zMAQvgaADa-;`;NS48)Y=@rw@~K|_Hx94MerV0Hb;R0@+)!F}Mat~I*4F+EWi(~jHI z;!VHevR_~IGM+FRWmtM<5-mH-Mhj~r+gk&xo*Ok8aI~O3gN8Xf6eN;!ZI9OK+TdF& z1b!&DSyQ32@ON(Se>pbOf(1i3_dck?@FT5iMJXYGySiw>vzk00V5PgHUx3DsACxg`U}4NP7uty z6A0%~cLG~arvTlDu-j6zndk$$55JRBVIRVS&pzxB4&KsO{j@bDonFH8B^W2<9M@x` zz640jnCHId9ScN@cvK)6X4qA-c*^6T(XO_j$W+GZ@P7m+e|G15>MC!k;YKZ!B~N_ctoi6eE(?ZUR*mTdRZ-Kk zu6E0mJ><(e7tw#b=xp1JME?9wdJUEbU8H}k6D$>P!IB|u!Xt7uC*%-s$NY!LAtd7w zIjUls(XhjKqZ7KZ+DH(7pmd)4FFJ=e-^itN)Wx3QJ|J9wYrcjvAk_nH6O z?eoxm-G_^nN;Y{V!G6yQa3=IErF#UX>Ag_~S@?!C3ouLKhXneRhyIgxG{a*qakmY+ zd3ehKB96BlXc)&89FP8B=n>Dg@m2&L_|G89JaoZ|@E#n4hH$+pKN&Mi-9TQs_>6K;tUupLLJl2sOa?Z^u zcIRdl5Y6rfm$#V3-HR8SlAc<{-%T!EcoW?)IowRzX=Y1nYywR%F;LTn0hi8jmzkZuvte@PN`u zHj}c7>(-vacaEVC)HA<>JELe&0I1F;$2V(}s2H_FJ zR{_n{>u@oI78iJO9sGP0mtW^8mA4@Ct{wPwehv2W{5+3rc?-g+0iI1Ff!yV~rQIlo zjA6*;ywe9Cg*ttn0^s>53hx1Y6nHOqpn&({C9DI8XWg&3hgRh01*b^1y3Tap8y-Y#w2s_LQX+= z)7KTwuNb>j8}<*#7>i`0i}a-ZH@~=v!g1v19AQd=;5>}{07gJ82IzJ{efPiCh4;YC z=W}-mtQh(L>ypZ&VdE$KuQ6Uhy>qMGNmVm>(f;L~O*4$t!M-*@gX1h?S}i#%;D0>m zN28E-l{9j8j6SOyO6*SS^RiF;MwG|{DjDa~XJ_G)VI|-Lw#LD&^FZNcAkfhG6fDCZ z52FC035IvcpKxXi~o{_i9mT>10y%L#ifdg!NweZ%sE`tv8(lPS~WxcX>gl@ zo92>Np(oNwU#aA05?nSmaAoKZ!G40^ljMxn z*@3X+t(Xq-g*5hHlU_pVrJ@$8#UBos>U4IiwAImnoSFMXWyt(X*icB{+W!)ib&t~- zovW%hRZG>Z^*(PbFDdZ(;o_YO-#-Krkf`p^Xe#li5Q9MHJIa}rbGCVJ{OG!ae*W&@ zo;I(1#_2MU0g*&=Ryqq;6>j!0Kt1N@OmcE*U`gU%onuw0kp08X%HQ0E#`TEr7oU$o zv1lcem#sjv!NAu4fFM`m@D_I-f+#2bAt?Eij{Dw9%*N)^V~_pVyNfJU`o^zuwj5fz zcUp3EIgjdXp4AUqHE(h;-{>l6cv6>GwM<@prI$K3hIrAEh-grSOFo}>a?bR3QTXvU zb(>%Km*xDLY*2Ip%}JxiCG^+f9vQ`)_hqsCdeayc2+5|YLaq#BVQZ8Sw=`oe#}&Xi zY48v#zvWdhxJ_Y75uiSS>p9WqKT-nx#J?UOj)w{zH-O~2Q7FH-$Mq&Z-pBT9K5GIk z7E53LG+la!&a}aJ<^Nk#8Ep|X^cFR*mpdnGx4dAV-Qeb1L0@F>ZI+it%L029*V>C2 z2Q}mr{-y0+7n^v%Fm3O}=ga2AY{+GjV{Tz`gk9ewHf>FhEA{WnFVH{X{Oax3Fv(9- zTke0ND3gmbKT*FszJtDxUwrqx5{u5aMNe4p2d0+Q;wIt}l`f2l2X>!Q7&!KU^YFya+v_(ch4ov?(44zIxiKu|-B@ET^>L|v`u_Sv z(RAH%6~$@3gb{|3x9C{0YO$-oX;$2+3$4uobJlCd;_(aT?m>_8d2cI9OVUu3Gp0Q; z&ic~nW9-0VqBdj-c&$J1Lv=6jAtSl{P+Z!l0f9?R5&PQ~!j!0QE7>x}vv7*)vZZHJ zipk2&hP!gkxg^R^>^T($Q~^+kTbzvLfw{U+&riL<>79#%C_`YbifSY#aXHo~?jm088 zO<5@E^>zjnlt0iaD{;6!sdH^sP4-8%6FZ*Gu3b~&;4yQ}Fz{;@oXVG=KP#;p&U9&4 z=g*@*4~{R)e_#;&@uLsNlbL!2c?`pDN>~T0HynFdjn^r}88!;#H+FAx#*N(L!PU`k z8)o}MGU_#+2%`}nqwrcSf8BhEOBpYx)o_o>>OGn1j_^*S`nK9MDLlU+?cy1J>;2Yr38pV1`h16r zW0Sl!EkPlo*IT~YE2`+8F^o4`XBbW4e*EI|#g@>9MYvZDod1JYa7gi7 z<$GS3dUVXe&!v6g`+S8XQ5i?)RGH<3Gx)wJj5Rnfa8amJ-@$cWDAw#Zrr!s3hTh6goMW1DXH{o=DcMCc-yEz(!Hqj>zujEu?1znGW$g9QD!!!)9~d21-X zo|c)R`P0Pe01PGhfP9BumY>kY>sZm%Bc;ghe4<=wS^xAGpI&}|7v3c6e*CKJSBJMs z=39}=PAytv@R6DMJ*%Hw_J-|0Mw(7}|31ayeT~V-BcJt*MifhNP7-W^FW$`5z?zH24U-b{HxKwDR=Ttn)&4x7hm~e zd{5a5oUO2%iO3pqSx&w5*T(TmDU&wC<)7AmT|cq8DT(wcCJQn76NB+Wcr{;a{A-Lp z(CB9P#WKbRAzktsm=sRqqD=bD%buqvS0JkabIM$kG(Z7J#`uK6Ba7{X;aygnR!!I_ z&y3(pIgb5%_#e7lSI&E+VDe>J?1a$-g-Kg|T<}!+?`%L{0m{ax_XJ$JaC81>uDVeM zt#@14to#|*(mKo_#7+gz;3Eu3Wxc_;FJ}S})qlf~+stsfY(lo?VE?&ae9q4H*QtYh z9Ysj*v&dy+NNfcjhG3nwe5`kr&X!Dzlk0onG&+Yai({u^e58#o?Kt5Wh zQk~aoX2@PReQUbQ%lC`#tUjD{%QAk# zjaO00RFsJt-C!A@RUGRF7Kf4#_}ewhh$FZrQ5uHm@ttp9R$8juUz1-JcFp!M^pE^5 zaq~jYVfvW=;n=unxl)A~nrznYtx}H1NK0YVc2_;aByz-f2`#~PX6TVy!oV}B>KN~J z%FYYj)PE{QZfStr;+MD&dOHSi5oPBKJ`Nw%zSK#tm)49g$g@#%TxBS#_Kmbw{Z$(@DJuAC2*=jm=h2J0c3Z99Radv042@~ zpsZ88RdK*b{Iq&X0?P%#R z3ufwwD^J59WhS?$gsO9c`WL&NU6{jWjD9Gx{kq|~ZAF)QiR09n@pj=~d}ZAW{k{3~ zu+!p`6~m`W3hQ$PwzkYvo7^7gP}a~AQ!v#83xA~VQt0KZ9IJ}5(0Z-Wv?qB0!7aNd z>|q!;{dO1bQz-nhbK4$x1fVrFwAcfNVU{?es5plxv^1fV}7Wrzf)4_6@Wq9WXLBA{;201f;h0RC^DUDdG_uI>2o`=Q-Yx@Ydk zogL9s5NSFu`V(B@Nf1NZxCT4PWm^=25aXTL!OaIi<_Pj?1_F^({I!gX!1nr0Ql%x& z*L@LF>3oeLUL8ANqS{y^Ha`4sjcWl+`M#K*M!f8r0q-!2M#c-F3IB(Nt>S*?K2^@e&4Gl~NP77kh~2Ki!V>7y5` zab1qvKUuVC)!^$%Z4PNhBO9#@Ua9`#+i1h=JjP6);~@>|o=}hj-2kr2FviZLUV)xc zMg1s{n5ip} zK1g4=_*8iO2%ic4S(~f>tgXUB6&u=LL3)qDc9fSwo=?Jm_xbI?H_xA!TeRinB3FL& zSL*)&BIdeAo^DCK&eJiz*t@{hTpLntdGNFR4L@UH%J$#bd%E75(kElA0;mG&1}uRY zAD%&0`;(sv*mlkYWJP%N_G!h9Q79wQ+zVFn3TOM0jAEA%RbJNB1F>lsC1`Euq)VKYT5T| zl1}d!C_A6RxU}g(Yr~a`PNkkdE!ei?GP5yU6#I4W@=luFRL!*ty(bPz0^9j>oPzEU zz4e^QiCjNGQy&%TiB0J~xHT$utU;mFOh7BW>C4oeAkdBvuK!GiIijZ;We2al+M;)| zK%2UeVH2jHfmk(~dis=MDL|NQ)~Rk_u>b_{1#F3m9UkO>Ktb=A>&+)cm`aCOam{2Z zfajk;^HU~2UCmWJDqJC?wvB5o;6)TtV92%p++-Wiq)_&tVWCy$9)0F+x9j+}+6j?L zZJ8lOJyW_s7M>yeZ_oCLlADv>u!Z`Df zG@+#=9E%nE)-xvBJzkWN?lmDQr9Gp(8(aSQ?(#b`8$w7R5CzrtKGWX(Q?piY-QEWk zz5$tcL!K#ZBg5qj3t9NyNYZ|G%*Bj@yBp(w@u@ah5k3_MEX&1(8)ymj>VBdgbm1}- zWTU%D(VdZTU!)dT)yI(D6g|6?^W~DaaI@_`0XTV@qql*z85y~fU8#_*rx3VzG%LjP z+^(4RK-0*W_Y#@V;>asfW|>%g!^wBLOB=6Ev(51gU!M9If59^L>8d&j$E|lU-bO1K zrGq(#!$aT(2^-V+FpmRAD8b{K5t|jrDy|X&XZPE7@N6~j{J`1KP-k}~D6s6}1eBQo zTs&XrgHoTtvft1549HK#gekk0VDAMw8J}E%nu?3L|9l1^gFm^<9W0jKpeVJja+6BT zkmEk-EhIPuEX+QCgxam}PltxSuPbrw^qG_iYg(i9zRHQ3eSP_^v?kf_T2xMnK<8VG zPQZ=%$P7wDPkQrxdp6oZC}*WpaqpB|8ohG2+1NWu zXQZ6$9I8B8cEr4o@b@pihpVvfa65nT$>?=YMJ3qvFJn35yDm~`mlz~hCq3cFVUE@n zWXgS6#YTa1XE&OjQs%#^yhWKCJ=0D%{E$^VFm}4}!iE{wzfUE9Ed#(%V%9)sI7n*L4_F0b3rz5s8!r&3h_G{znhCq1&%?>j|rFr z_z+?Up2<*jt>?Nm;7f7<_p?1!vo8J1FSTIh*qJ7@h}_$RE>Q@Pcf zKk+lQ7fxSyR(AD>N~-m)JO=Yp!e5KTCom&)olTX9KE$y(%hND=g}xV=ptHMDdMKBh zWQYX2sr8NN`hm-sMx~7GWiyLnvsIL8$RsKpqdvFuql2CfGBV8mCed@--QPgzK;3=pAtOAk1=#2KZ!<}4Gkqwi*T6^MGw$iBaWNR%&6~j zChy^}s?&E{n;TiipEYr5IpZwf> zxYBXIt)-fOjR(bFUY?q2pMK?>p+v}@uur>LQ5VBvWLPHtPB@nz>Q?U8f*yo8cLM9SXHHW z#aWXg(FiM{M^P&`ZvXd9#hapLXQL>y+6VWuS7F1LJdo+QR0$b1?Py4@&v?vK+)*_l zr5rKWXeW|*rT1IiK5WFFEj?SstvFJ0P5nmpGerS0j6T%s%EH)>*?u9a_C3RjEf4*iqE3EH5nZ>HDpwKf-)^Jm zk?)JGruT{^bhB)(bq<%RybDUI_{9fa&6l@*k@u1>cj#?Q4Bj6s@Z+7k;2Ue23%hT$ z?sAdIBbI;iE;UBULPX$LV(JPb(Fv{b);Tzh7mdVm4DI0bo@SNG`P!)E8-fa0k5P+(hI)HHn7oa@E&VK>@);5Nrp5kSCd`WPRg>{KpjdoG6AnU@8d%yTV z0}&l|KfMK=48QZ(llgE*M|Ty~o!_!~BI;^?uc(nu;28&(PpT)r;d4Ts!wqKv2vk8H zxroptS$9oF+xu{4b<*P558_(J&rtGbGq_WsaT+yTr z+X?^NnsNpDLt+2jMHO`c+M5HP5pcvC9MvGjlO49BDM|Ja`{#$(t=W9I?>1T6MXTY8 z@Q>Fvkgaol1`~^0%8ED8y5DA*)eg}v+}^$Z#wgyp^M^8naDr$?s#faTsujNFqGhn$ z@Bs~tJD>MlywX)-kT=xD>g-#H@mz89acCjL`1eWGYIk7tpgGC%>11V4O%sE#e*TqT z$Ii5lHV%5dXIUki65?Y&XC&3{>vH%mlH>A=?`9W-H_}lGg|6MW{g!=hh$EFQ>F$?8 zT{tWf^mt+_6C09H;*kA@u`AH0yek#r2N=0MGgY~X=^k3yay{o^ud~3+tDw&@N*npv z!bd3Q0K7_Q0PzI2L>cz3!!*UmI`tyMEME+#KS@I z(*$9PxB`ONioFMTPAvx%*JDnU%NU>eL*1|u+;Qx0MC#1J(G-JxlP+bCNLCJ~%_FuZ-&=m(~D-W;K^#@4(imESE3 zfRYE+w2dfzZzo9(y&b!};W+8tE1-{Q>K~;7*Y*WPbmWK2SsaP^F+8WXb-B~pxapA1 z$U0WzH)sznTHSmlp__7vQvFqfvFk~P+LX*();NFjiFz|H4hySIyYi04_cI=KTOW$3~+IZ7tQNL>&sN0aU!|KaRs=xqV~F{ zTR_1oAnUeb$vWuY{y~@%Jn{u&q4MSdO1adYAXcTld0|*KOit80*`_JfoD2j`7w9ZJrvoWjQ)VF-Hn{?xK$L>?O&yc2kppS={EMN!M zZc;rVe0ipts3c8_pmzPV>xL=OzR{pC3&^KX$#mR&zMHN>>Rr_8$4G++=177QJDG~nz+T!ePvxq>##7XC3c6=!4ALEomu#N zQnh@?)y9cIg_z_V->(`a2iD{Mj->W&JiZOuQq(r;e(`C56!i&q#ptckyN@p9=c~v@ z4Yb>4d=e8SW2fJ=dcjyL%TrCdw|cy#jiofLV{8hhd)6zkM5E{hsr)W9%77&VDMCP_JiV#r?y zSsRI(Yi%Tz3D?eK*o;T?c;#W+p4O&IrN8(Ya@;|bqZ@!Q3()wD8gg`(3wiy4Q(}wA za+nL(Ws!w%LUoXtJ1mWFH(*wdm(NqyML(gBuO|WxnkR=HaPBfR;@%sAP|NtJp@Zxk zBi<5xTtdxYIeb~THN!?Rj`2}8D~u}?KapXw%-w81MAKsDOVNCO;vd^x_+eQN;moO|iT8 zwkZTBDqHk6eyneich`gewe1h>K?CnQDowSf_O;paVv$I{5$p!#Uwo?>1Ou&3%-PP! z4nw`etm}419ugnsW>i1!otsH;q5bXulilZOO$*twabrU8$zvh+1D{K-^h0lqod^n< zFv@V()@ayRs54o)zLz6)ck0x1hLdqOpop1zy`TIf4x(m^E!5*MNhJhCOsZl11GR*45H^pzp zRAbqlV?()|9q3J&WoJUB3=2ZU;0DpXci`{84aiv~TwE1^pOSGGWD{6{OETPr(h}TF z@rDK8urwDf^V2o6`=PjCMW(BYbvid=PQVHiB0J+OEg&%m2mLZ%uHIGJ*x4_Cb}@g7 z*HdS`(C5;%H6?f*7X|_jhD&v8 zxqj%Rb!uWiXh<+XJw{EV75;!BFmOxW(@@Nbx6RzIX_X9T2<~$~_`$4qpOj6?8SOQ{ z`20_>+RgIE*tRU+!xy<=bH`qg>Wo4iHaHXM3asr$NeVH!`TIGExYTk!- z$1K8gQ!H%F{w5~Hv|TugFQBO#eSSD32)Eb|r&Wig zM77%Ml2}%`GcQ;(e)N&GpD1L2luR@t1d@U0o7P8CcF7nUZbrIDW1(ifeKnP?b+rXm znS_`2x;?ukog|okO3`q6E_V&<={rj9a&T-${gr*z6S5ZjIS-q#O6wLE|CJRtT_wGq zg@;@Fwr9>Mou-Jx45@|&>kK9>hTgkhRwk8$Zyo3hi#pLL)hqQC^TN&zs=h7^!U8S> z(T|gQSK~$v^5^m#Nyay*eL5&Skv*%hKF%NlAoMvx*`SIthN`9$Sc*o*_3olEI(ux) ze31I_*3)~w)Hz2&f%YZ2#OAjkFz&4gnb~^jV{-p%gIqZPN+r4MQ`7~kAtz%oW~!}> zu_XLl?#_?m$}iaaGw2@ppLV`A1-3a55x5SnN7;3ZnbsWCGQrV2(>5YOeb*dMr%Vzhc~(6q`Y z%F-vX?bByY{G^Y*OA>5*VNI!xM%Ld=21&u=54z7@@IgPp`S}Cbln0=44c68bIh^(tkUUik;65G|a40CuUS2H;~GSoDIE?y)$t>tWaA_v-87`({sHT zJQy$W2p0qiM<}q3@A+Tjzn6?<&%*WTd}FvC!N`ff9j=dBmTXALe`2pGmQrO{KwSl- z@;t7BBu4KMjLo4*9|%oxp6ST!n!FOfJrOe!dg*PkHLdQF$&uh4_ZB&+KM@O5!ysyy z<3IU;a`!-H<`ZSR2;o}!BZeBged)^w#Sm6B%R!| zFV0ml%BO2lAc$%|W-6NC9EYJ_$CN}v&74Ve>ETvR>_*VnQ&*5Tx5%led%A+G8swT8 zz&LN_XlB}lG}4BM6w3kUO{zAIQVp>|PR_f!-!zAAs&W>q*^a9c6T;nN z7^C|%69(b3A8n0eU9BZ(XvfLzj1aQ&Wp>>7pbsOaVlT$c?nOqC_Vm2NZW|8%C7u(m z?Y`i9h4^mL8geR=^5F2&ucYo^k)g9r`1XBmH?3xmuYpn(N)o0(;?dkdn(M#h2#txcU9Es|vhy0gh(fq)H{o64ZR|Mh zcLh-gLepoardDIg@K0@yP}cQcX;2zdX76kgRm6PXDSiw^;{xa;d4^oGQkAr{hn_{v+RZ5N|IhI6TBva zZ@(pWXYFodjrEt;?zFf~A@3I5CWD8>b_<~|?t_H~#!|*YC%<-8o5KT5Th50(>`NIu zK8W#^-cBy-xyNcf-tMj@;ythmo7{_0DTMSfko#uTf_6U?*e4t&zV02&O`L^Z}E$9M&m%jK6_R zO>(~`kyupvwID`=pz^^O|Ec0T6thFYQZPZZ`MtCIY_$g={Nw(dusLtt^Y8*bzg7>U zGGBiojQTMM33;{3_KQsNYSRyW+`(9+xjStWA0_?{@H7Ij1XVj+_{sf$v~pRx}Qe}TFK5l~OpBK2-r2O(uhnVx0zU`hl>-Qok( z5j-A2^%F?#(Fh`b1yPQ|=)-#a;91cbH7P9;E&|H!Y-c%F%H;j1zZ`*85Sm(p9}dNM zF+d!79|jrP-Hl7@$8(&D?uQQOT*+a+cCue?f)^bLQGN>)JEZ~5-O{Xga|i31b1baz zUrU~Qnu@TCZI230o5C=3X2#*qju5>&e!?jpcnOEho7PR0r(i6$GxRe-xdYzbVpIzu zfx$B$d_fsp05A~AmD@b4HP_`;17}ko3`3G1TC^Y=8I7#Ii@}3I*8esh>g)h|D6+(O zdTwDG@G?^~raHWfA(z1C?|2uv?li2jmpTlqa7?!8dxA_R(X3aMe zG-idJA3HyO##Qfte(R{{dJnIQQ#P$l9`8pX!vHspp|EP?!pf8YH%*c$u*-LnsxS2C zI*Qwonyv?wkS$Q*~BjK2Nx#w=1k)xApRMBwkY>iI+-f_i!mFo5Ncf#ZTGCxlLR=&q* zs9moNONE=tprQUKfAXC3`|uWW20@1&c<<-^uR5n-#4=oVl#5>eZ3P!bdS@ljrPgUX ziip_I*;df0zqiGAT#nL2nwwz0ls5^lUtv}F0;RdGL zjI2)KqU+>lWGxSIKv;WVWmU;VQ~EyI&x#v{q5^XR)>`Q3jjG(KfiBqIvZPc!>gB^l z8MRW*BqyncH_!u9eFpN>OUcjS22Sx)y){SrI|vKzgdT2^)56a+UtGFGm9XKnP#aw2 zO1<$l-&fM}Mw8?X18d)%>y1w=KzJSx5Y`6>%fqJA$P_A*LYbz-d!ZfH;U137^u1EK zeApQin!S|QT9=R|Y}m`MK2dcqrF$(nLY-JQI@39zq%s=wX#M`aJOK@Q;{z!BW*?ZQ zyqcy&DPa?VFu|%iT&TrYp-@W`dNlFQtFU_xZy9}S>mysKM#1ZWOCkC=H!e&adu*Fr z_}DzkSK3KFr~c@GrHW}#oi2>`Eb|BGUmNvaJQXW#^Sx59?xE zY#Og@}CJpMMsb(Zg_=A@zaYKV`v%?)t&kjr*2iC@#{g`~_%jUJ&6ZdqLDPSSJ; zdzObARdX`d2Jmt1i1H>1y!)v3N8k0&)z%z=#q$xnl`j8*dB63-fM(m1ZWyFJmdyw~ip;!(cu{hqQ@yIpi)3W!Ox7ddo5i*$Mal!Bz4-42u`n)l)c`iwp8{K>`ljPB0w`LUX<0GLt@>8ELEr^`6(zDE(m`c z?+3I8p`gUZbB$|8o6iPY;ds43Jnx4zFjMawp%nd-O#g;wz$I7@l*&W!Lx4~*NHJbP z#w6I^t`|?#9I%Zg1X4GIU3L&RsBbQoV~eRl{NQJuJ~bNkeq}H1h}kFIzx$eGA+eDk zfA`Y&u7d_dL@^8B9vr5R;WO3;y~(%mEZ-#8mY_~d%`pgYDl&o~Fq=;aTXG2dcVl{} zNuBE!tikEwL5UozK?QqJwmq4?&r&Eqc(8kY_=Zb~{Li;DLCz&}kgQ{Ik6pGLSr%2L zTfNLvp-&L{RrF#whf+>Hwg!?#KeU+?9WK=-0uG-uDf>VefM0-l@**Ed$-nsaU#Ndd zG$~rK^z6+or5EOYyzPB|`xjpp!%~f02Bwd8AJu3`zc^O@1hdbvF~jAKRZ;6gtzDuc zVRzSXG?idZbxfAAJXaP0j_~gZ(H@R{!?*!ms^-KZGE4EpJ;pD-ueDkDIG!Use~Glp zCo#2eul-$i@EK(NZv=9URy}Vtlv%GIq4;bDKgc^ovUIwY*Wb*uSqjRS07O*4fEnin z46y9Hi07FN1>%~!&dP1EuYuhU_nx}K3aWbClxu0w-u~|F5jVJJ%&kQ4dV9_I^} z=R3SJ_T~y?^6fWJ68ypJlof{!?lj9O9ezwD)@6wn`6bl+JXJYE+`9i!{h3mP4VCbaXUT)h<{jIucH(Zxgw%sEm-nNHzY z^P`NMORQaFQsU(ZNzOp7%29o|#CPt_6r9c*?2{V&k@4ht&b_lad4X2>cNSyB0v02n zMv=@EEwwi?Leaue1XEHR&9xdD2YP^TG@ylRt4^xaAO zZG@s-!W3#A_O1=er~k1g@U1?VV&O|vJ6^+=k;GIWw@ErX`ac8<@Z@S8F6U-~&lH1( z2d=a~AqfRNz-9(H>lYu+?xOOjNpYH((<7;^BF>$SaZ`Krg5k&u`FQ-o*O28R1S_3@ zJgi+O(_Vd_*`a&e_Dcr&+I8mm5UE0~j>IF>@4K8WX5e>CQ;N#|;Rz`qJVh~<=tn2U z@ezX{3c-i5yLURfGl>;0n^gAvoK%lf{r3$T_c=Wh&@l{I%_G#Oay3!8LHmnLwqRcm z)Y2WzM#?*Jx`%)wn%N^J{wNkv<#V2EQ>{3RA;egwa6u>hY?bf5C)xB+y};=^no!`_7%V{}OP`Ew~DEd_)4{oxnQ(?TCU;cjNQW zfXD5_8z=0-+BWX_`6h+6V~Nk3hAD<=6j%W$c8I5XuQM#&SoCCK=&0N*Wi&$X#&BqP zaJ~>Eb+0oBd+Q@!9n0&4SxZ0q@b!7Oao_F>SoqeE#-c-Z_yvEU~mzQ7xisR>-s0bw>CvM7MnqC?nw>I_RQP-P3# zqDa{O7VF$qPrSCgC7W+|oQBgFEVyqimOvj*`#B+T3kO+verTvUDLAB%{PuNY=|Ya!QilFDQZ+IV zHx!3$2@*6MGMa&6BjgHtv0fiZMWa2DWt)=<92@W$)qHk0E+*(xt;^qA*B3gnqM(}1 z?w06TFnjEJ0DY|788DiKpsH1s6=q=4E*hKr`GGGeR9<4 z6!X+wdAGVAA6>r&aTdE$aWW>KVd5?_cDITU@z}UUBO+t`>*5bR15CTfO{TFbPt;Cp z7Guc^bdazhR)ye)o4f7DeU-#plxLC|cpAG~sArofCOn`+Vqi?LQ3;z)AA4BlDe8E# zwv*%DCe5yfY&PdwLRHsn)j}=OgjqMK%NerQoNF}8UwqeDmM`fIg^x&Pd027~=NhGJ zuCx0{4cn&F>KEVIznQ7;=)HT!dw%hGC{SI>#N`WGIlDG7Q~T(>5^QLU>g+R1v{W$b z(3@^|GIk-1g@{H#e~0I)G)F>Do;svlPCDU(iEc!zOGM9tj}evil~Q2=&bhB@)~T4- zn(}=vVoNqyr-zOP;v`EFh0GdDYE#-+PmQtBr6-tt(_*d+b@DGlXsIJQFjOS905&f7a6ypSklkBvp= zZm6}L^vM@CQ&D=fISBq`Cg~7qzk?m8r-RSaoUwx7cM?YJY-)6!bGEqDY1WYGy2Q6E zqUqeebzw)H_^r%f?yR=*j+~u%8y&=PF~?vElG^`jF#E55v;TTDA*T&2VBojQJT5;e zijl?nVk6D%S_Wg3(x?RU`jjMRY*4`=Y)mWh9BZ;JHX@RCdR1LPBm3+HBcq|M&T#D=zU&azDE=>6qi@BU~l zAD;dw-9=8!$3;E%a@}BdZftAS!F1Ij%ZnH-2l}Csm%G%GGLljim*T_dU;RXVvBB+- znGtdoq-w8?`<%ZNT2cSz;~b%=Ij3G0`a8F~oAFZ7+ZLP|^8_I@OqgD~6;hLNY9EGwk^c0Il%P(y9Pw0Y>7IySb2bCFflaogO_q2YQg zCT+$DOjb;&nvJ=`2^E>nElIySbhVR)(H*4AdKEe;UyU#c@E8lwq5tK%)Z=eSoUu>XKZ-e9y9~TTjN4YK^s)>Gy@% zt9`bA=je9c$A+Ha*qA1%#RNQu1r>PPc62j}hgZ$XsrjqT(l{r2Iz2;YvW)K!f7sML zq1Kdeb-*M38U(9<UU=ip zkGPSwGR8yA)n(^%<7Y-~tT_5`3{Eg{0C@t^!AM-T!aBo&WhK zBft2%nmO>2$_ps(e@~+P|6j)ccUL1VmKtwow%Nm_r8FSV>GEV+s%?hU9>w&iy=f}M zb;D$;ZHLL&23q3f$DD{{J@xva%k8qeUX&-GfAZ!Ay?YNE z;1I1V96uBr^XDXHXb<^wC@@9qLx;iG;ZSMo`jW;Zy+neZK%s9(uipi~tm9qx>`jAzJ8@0L|XON|`2U@G7O8RVKg)SupOyE_JTdXxYh)_ab3oTMk-a_ca^ALEcrOsP2 zqW{X)e5t)!QaSs!8^h%CW6Ol6mk*n%)9iMIr<~vJJ5*<-abIm9eX*0VTR5BAgFAA0 zWs*BVCkkmW6ff|!bJ+DpQ{}mrn%aW1GA7_u{$-6c9Ap)Yto(R*9LUWe{?gV8gA` z$0|BQp|^7DwP&01?sT&Vn)Y1{ncsXXJ~M2ML%O?GNw!~>F_w;^OS0#_oi-f)FtdKr z!|U(89s%}Ss-9fvQ@pWB^QGdg9R<{t45Ju)MVZaV@j*#^<9M;Zl(e~DO=8E%gt~$N zzDD&$lV>lv!T7!77)Aaw$iZgWm3EbQYV!A{1N~EjE8HX<<&Fwpur#2*(o9%^?A^J* z=%aO7Z=_dJkK-Q2XyW-g2iY_^0j1n?`PlW9g1Xu&UT*weh#132QTuq4i|45Wvqsq= zO*N+ZhaVf)83n%K8`<|z;_@^U3Be1CCiKn3fqCpj)bs4x4JYR0wKXg52KSkh$FP#h zUF0W2gZpx3i~X1PS+-2p;cxeJ=p$X>hp>Gw#<6Ovut6Wa@-taaN3{i|ZO1Mje(++- zSxrE+_%`f}&oGjt!9f?>9KkNmgmLacYNOqM7sXN!lmwfZkL;@y{`T$KwkwCflb_>Q z2BOh~iCvcoE`$jqjHXu&%e6OdSF3pki*~%IPRb!^zj@WQ)spYl)7LPfh})tOGBd3m zu9&P!?mI?$EIm&3ca*-IX;YuOXT89Mv%}t)zMCz{~I~k^TBXE0h`@K3-wh$_} zo+)W`c`0cgMZJ1Q@pPXlQQXMDfSioSh2Wy{9^{OmR-trPg?@-#nUn!2h{np!~7cD!{IIbsM;c^$_Z%`5_9Ht?&x}lXiu7bc`@PowEz?|z0<~WAF zqle)lx1QUO=56mt?fW^fVQuR9g6D-cE8iH~Q%2+$K=Xagn9=(UvHHzY!zJ`R#iO`K z+vX&@?S5X~)TC;1tH##;)6cVRNlO`~ip`woOW*{}EeL}q{(^AoW$M78d;MmXZLM$g z#5S+f+SD-hbU%h+SfZai-`)3|eeXD9obyit!>l#eTyY%QtedJ` z{9?TjKV7xoI)%?M_|A)?%|UwRf|DfZmIg5`nDp3fWX=@V{izb?7@e&J1Wk;3daiY^+ix!Y z8sPxDUo8(XY;6^nda`NqRUY>~omz>c!kLk`p&huh zN4m!K5gXbGkeha(gpCcc0u@EX1e@Uh#|A3au`Yv(Q{&vdxKg}Al=%rH?`|vZUa2fl zIRT~-igj@QrpaRV4{fFrVS1uH>=t_2F1b>5=9s!qn&h6dQpUk%+k$+b;_F`SPf5{T zbr+8xH&IDC^)MpO52>f{=Mmg0aE->A1245RTYb@=vR#S}M5>238TIz%OBxK0KpyvP zyv+82X8Qzqc|xxEdKrm@-RN3&0wHa{AAkZ1msub{y4MSG&Q=#(VM$SilsnLgssX{( z7cqW_-~b0J)9wXH)4tmZTM1a$_~*&|J2WUwx|S7DjL4rgt@AaIHG=Ad$Ca0r+rD|J z68~b)rHhI%V^|vJI`)7j>MpZ?fM0KSDwu2oq$9>0T#i9$ax%i zdl-QnFgyGv4gQ4z$aqjDA&ZLd-7UUZUzW76B$cJVP%Nr$chTWy)2#00LYOS7gyZzV zofSqkl<7zlhD4ej6pmp9-rD};bRXpMC*LE!y58kGdKa$y6vK*WN5P31$QXv7xw1)W zgKB&b0_IO*$5!up2iDgI>C7_k_3-Qq+*B#x=Xl2UGM(BYUi7RQ0CeDmB79wv&w|~v zntCdZ21B!eBMsq3ef{+WRN0t_Kta2F%eI;8Cn65PA{ewlKUxINfH9sb;YS>!IPT?` z$_GgXM7cHs_)*Skz`aH$FHl|F%`h}PU0$@`@Tq^0kgH}rHET*WS18P8KnuMM-+Cq%z1G6xGuqalO7~hF=pDj;Rw!ksm$w770+jSprRv7 zDVJmLb#4$}#55sxg`~t<8gk8`% z#rq>kDjaoJj)`P2Ug3(=F{&~bB%%yn2W~?`Jcbs8)XcpSgeMiw+x&SjY@?AtM zu!MuA3B;|&2eR~qissi!s-g>%;!mWXLWsaFzopp0H@wV!Ni%L=4wj&c3|x6!y(rfo z|0$*lese9)0Wn7$V07J{7;paD4^RJFdq-YF&Xd#8%gt=i_Ioef$Px2IHW&kG!vJ;{ z*xHpLz*a68w$!q@DWi_TG8w2g)2y=`^FH;^e50OD%YFJ)Qhiq*!?JM7u2J|*#Ujmh z@LHsLRQ0T?2oK&UVQ%$TjFmr&JX!Kpu9OgUocLK5RgQJQO-Ha3esiHf(v}BMxi%{* z#2HeXOk3v#jA$z%Zunu8OV;QWujx6#P^f9|xB6E~Gujv}Sh>(H7*hkm{L~>(nTE+8 zo#EISy8RHVOj=k8v&h~Hi#sEveIxIoXb$Y7Itah#HJ^g81mZn_CofH;LX!uQ#c3YN z3JL6b2DV@=;h9pOkHp?HwJGbeRp)ICGE#iKXYhr+{_}7JxCDEXN<7H-sX1ZzP}GJs;}Jl_+XnfFJryI>m{t+7;H^8Iy+|vAz`cPD-qR9Abk^2f_7Yx$Fx-#}~(vUHHwl@H7j+Qp1sOc2U<# z1e6ieuDVuBQ$w5|$INslD7YJJTm-L$R^`q0I^M$;8(E2SU7i$Eo)-7rjJXy&x2<(r zdL+@scQtimS8kTB3uf=TXIlY^ml)@@MeKI)frC>#xvmyNm64m}Sdd8rukGnu_}f`gETEw}ycepKT+q-P&p;J8{j?-1LNNtC*Gs=rWN zOH5v>T*hnvG1r$jnx5pZgW+g1ySsQ6>%@?#=C_Yf2@0fys-(xZ_k_G z1zQ2g>M!E5*n2}wulbDRO>Z7IGqWlIq>*iZb}0S9wyhIX!sat8+%;qfrm<6?FgW@bQFeW%%ZOwY$y?NG0~&1?nnGti}MjPsTM&8Jclb-pG#{T>M>u#%ui^ zko4mf?nYL}ZQg8OnmH{N1o;&VBR8kpGL&Qd$1+(pBg{zc=CIaP->PICL z7Wq7T)-452pKx}tSeWzGFqTdVhp?0>zgE^HgQwa65Yt#Fq?2n~Oax{dt1$-{zf{}MAP7616- z;pqhXJ!>ijkElYhIUAh`VtlDU0AbDxC4UgYZ^ zvZw?%LMrDjb61q#n+Xf&BUb3ow~`Hw&JK^?&k8h)+AXH$a~uGg{`3a_Q;&;uncc#S zkD`t6h*-NAs>HNnttz{Hptjq&z4o37_jYJj9s;&%pk7d!5x7G|rTHg35LazXlqnw} z?z+0`h)`;3)~fL9{9L05Pjl{*rJqEMc0?RomTNv%5?%Z=d4)3b@?NMpb;d zpgXVg%7}!^X{YDNLj@EAjrs&4h}*KYiE z5jjcupcvY?5|g+<(}%tgGwU|m1xw`E&#h^?GU-YF&Do*5(ul6|c2=Q-&(l+bGozn5 z156KrbA@x?0&6{M>cVlWivP{kqRd;IaqRl*cxw#<2rS_+QEsdJta8Q-f*WZep0Em+ z;%QT}^=c!kVQhUK^^rt^WyN|fmnqCZx3_4@Q>-UvY>@lu1O*$`V21!bxwrsoUKc&7 zGSt_&^YJI>=AJkd5R?-^?HrzUKf}9>8bf1qWor#J9>j2uP)$A31={kdW>~&Fv|J^+<B)Q1@|(A5 zs|9J5$0!!}A_`qK(fx%!?IPcce2kR5Ys#u^TbfVg z7vfB3-J|%UFXi8Vo5x7c*@bVTm@aiJsbX-Q`$igXm7vo5BKqQP z)w~^grg{WK(?DRqE+yDGoE}DVQ%HwjFv_yFV&ywsDrv}YZ6FjK-Hr)8ysvMcDa46? z{0=*X`6$*uDjP#GVG0w77?l3j3E0fThm4Q&Z9*?x>~cLThloP;y}!9mnRigjmo8vx zj4oZKbzGdkJ8(Af{K}^|*B~i_s1XR}anVlSbzs2>s_z(0&mQ$aRzxO?WNSHM_|`Bx z)#`P;Rj0d{A;nM%z)AqG%}XWPduUu2Icajw{6i)HOwL*z4XmI8oQ(t+j$X zHx#Vei|P*VQK>p>{vw{<8nHXb)6A)gE_ITFWVtamFC7h?YN#Gy_p3LF>U-GuKAbtR zBSG)YaBlT+Vy7%B1C!ff1y6=cvs1EcC8s*<%#;OOQnPOn^rPzaw#CF@K2Geh(~!W| z&^xTIPQ<7_dUYMK@o=!s%T2CCYZXV-zh{3P8i!$Ms7#X7ZyLN(?e$29t-#wsWO5$& zXWq4Q>aO?U7qE?}XFrmC@l|@^%}UmOotra1@k%h}C{nJgq8`y|)gDaFGw8N zB9n~!muHc-xfn8|m60QnvecU7!Tw7Bnh`zR*;bSNwzRZ29y!@FV$Iv5KB~{vFusxp zt25UZOV&-ka4}*!TMRe+=uR=u)EX$sVs36e>~;sU)e9AH$KwPq)1b z4RtuNgMkPDyYO%SsrG+pu4nf5oU;Afy86Qi`#&%PLj4as{{H)Aba^{mdQaf;{D%Og zjoz{Rxwovz{Qlfn_8{(XdSmNwQJahm8NN2eslFTDcjD6zf0J#r%EB zP6|lD=zw4_0%u)mAN2HHYq06h4UXfbI6Rm`2)t;bn6$P^jH#lpT(3xP@mTNgL+sz` z*{Me~N$uU$ zGgn51Gr>KiU_4rfb5j%-lv{np>?-pMj4KD4jE?b*)}}Y%_sfC=d(&OLmL(6~-A~jJ z4Mf{v=?dCrwuoRts5tpu(j}Qy=h2^)L3=lm!t;%gn^hCc6oIHzPB_D6uPe`|RU%#P z$kNQmV*o04j?oE_In+VIn0f^(lG?PAC!_bm=&?heLQm)0)%|Z2kfh;rmlkzkOgQkX zZxV!_e&6tjVe*!d_L(TeNo#77%!=(%j%b#=>GiWa@?+n4h@%~j1*Lb2bI_O=lYal1 zEX^`Ncck@`4Q zJqPndr)Q7*t*xVZuZ3=3y(E$-6Oeic(EH)-oh|ifMoJs~Dmh^;*>PAf0&0f*CjLa= zaBH=tgPQ8#`v^c59YrqUqJX@?MhGo6*LEN)!H8j09;{UT^4a9tRrs;{d^=zy-RO{j zAR}kugkooVWYba;+O*ZqxLc%8aSlB;rj-rj(-nl&G$h3EFGC)vJ;lFO2FKXYK!9)K zbgh;f`t4xPiSwMdA(7wlWg17B>kJ1bu9q=EJNxudf{*vr>(~T~MJdC|_qvZWtoXz; zZW89~NoU#X;QzRv!r+Xfl`)Fc2FBx4KJlYyQe^L?H%$LR+ zWhFuO{7QmlReRp=(o^=VoNEGL^5Cb%Q-4nR6WOpzVy*;N%V7NX*u_0^d7$oJ{msRu zNe8`g(X?QcCz~hSxg}PU+A2D%bxg8FYN#83F0UB&s~6(yF}*&$Sj(y^s;|gQ;gPY3 zQ*C(L+N2}sdCb6B_>RzSZNc>S1sg=u0rF|!9RDryT4^tsDz?A5Ks$FsdKH!Tm0lek zw!O*12h}VuvVDwC{PA5ntI*u z!5=!+SgfjXS-aLdSc(dBl5$^AEII*lY)U$@=4!exJIkYRrXgWaTH)O7jn5w2PS#tW zfKi^H!+OQ~0%A7Lpqg(!gQQvW`8%a4(vc9kn*hD`?%(BCL!yYCmCdSho`r z&<$jCkgqWW1|8k&ZOiv%&S3_j%f0vo-VB~~**3gczWP92m{ zSP=NwF(Y2G*VEnofC<-N6t|A{4l^)92K?U>bxW_E8}0(q0ITxjmnCiHF?>7<^;Y|Q zWuIo7Ln>ZRzwy1lU}OVqf;~M!Rb}mN&up`jst#*Ozx^=!+|+f^iU#i3w@;MJa7&`l zxovBnsHfnZM}tJH1BNxZLQAv5X|i5+i!;{3+jph7-_LmSu3lpKqWMlsslN5CQh4lS z;Ze>5?oKN}WSfx+iMv}k&nCT2C@+g{*^>d}i(+hKBXrM5);Rz%1=Lyz>eb&Y;y<4W z4Fh2Bn|Bqm<5(UvM7xH2z_}%JOOd!rQR7}n7({%Fr3@z=!IzL&6mq-Zm?2ZSZNsTb zmQKHufO={%U)5E1QJZA&{xc4g|BY}>|2WQ0cK4unlf%kN>kQn`<;gyojK_v?XlE*o z03z~9R z>k~(Q1lM=$II%?*S&Do3n`@TPk8hX(O9VQ@&7#!KO&6Dm)!hKL|A(HP=$t&BK`pZX z)FyDP-6P+{D|@WG!1;=f+m*>eO+KLyIj~I+&V%8BUQ2d%w|Z0ea&2Xw``IdowRp85 z3q1njBW`Gt6rr9#^&_jYz*(CebzYP7NT|$UXMjp5Rg%E$xX`|0PXb&h`f2se-P7yT zwU}uhv0h`)jrDSL>PptgN!uP2j}+Y+Iei*Z(^m$%7~eWSr!}i3r-H=rMR6mz0yM|d zl&OSJat0!f9?8@E42xm;87KOb{7lhizB?gdWaZr<#jW66AcS^-t+H?^m;+T;gMernEvW-P}O0I2S=*Q}q~jAmXbEky2uI4~&U~0+cxpQebezm?V{v>54cighAM@2!(p$8Y&qt0~{)Ar*|~V~TCC zJ&ig6n=lYMcde~4P3o%q6!(WpFD*{HEEeb3GxSB1%jAWc#UWSzyqGs|9cMXiwle}7 zSgSeyT}DSyv<>k*w^g_Pox^9uv%K=eBbgBm-4qMJ&Kaam3tweZ;^(eCzmmaX8G}-Wc}lD(@bc!COW1UC;meYBAW=gDWIf(^B)om1e9< zEL47`E4yfg7JNf)ySq%+<7hIJr4^z>K_AA1T;i^$fVElQT~1zj$a>|*<6n2G?crlphb*<0CC5ropDuBoQ$3XUj{@jF_3iS;#0}~P zeXI{2HNJ8-BY%|Q=o;wTs`ecH`A@n_Kci>}Z^boF$Z#y2i;q;C2|=8G=-`-JP}iXw zUix$Qmm++_MFu(1Lp_(KA=);uW6MLY7SB+GmW$rBD~N}Lc?-=m(-Sl4D1p!gkh+|UM_#joQPUYF&nV!cL-i=$c|gBCZ2j2&iC@F*pohZ z%P03Z|1=t+DYBg;aYFD0qlnsG?sInO+V%};QS#z`)yUOYdy-20MR%&RwCLkIS9F7s z=e}(cxpZJTNd0^+!buPehln#WtWRimQgY+gTQKI!Bl;ts;W_}gdwPx;!oE`pJ~}6h zinS-+=72#!Kb!~&03D2r=9kz}45|@)G#-p|u6x;&f><(49x~*Sf{;bPFL0j{I0^Me z7J(+H0XHg3bhf{(+E9Ew%vtKgPLBM~^6-j%Px=V1smK*Ho2H!VJr@AgVpsQ0>(s8s zn2~|2Yf#;ha`PYKyL2ABe=Ow}j-->BAsbhHLulC@nWsoU0z@Vs*Jq{cecR31HUZIx z)6ZAD^NH-xu=<)>E}&Qe0%LmEW`aVJ~}v85=&s8Y^lR zl+%mf@Dk0)l#nVotR=KZLl)K5pfgZTU^PcJ&rO`iM4KU$U0y`l8oSJ%>ASgQzP0;# z?CJMQ?Y=-e>eOJlhH0znKn8WomD{~wCZ?idRQ$EKhS|FLF-MILKnb%4H$}<;#7ajp zJKYAk_J~a*vEMY9f|*j`#Oi?|A|2W!bXt+zAtOF)kntvXl{98NwY5*Y8vV=L204dg zCR>e`v52k0wmh6jhg`!vxreLwa%8vbmVWpJ#CZO85=@2mBMDlA3Plh4@ixFGaJ}Th zQ1CNk%&&i(JaXPcK0K|UB*frl%}e|F#IT%*)!LZ#a(#S*Jv$T}iJhYq7po^`%=i1<^S2ZH;tO@k=Bb3G0y4&r0Xt6ye=Gofcx&@&31|y_ z4tuu||K^Qe*b&Y~%6HZ~;PGLfPe@oX?3A0UK__@Gx2&7j2Dk7yC4GFL*}@|VBt{3o z7g>!F;?!fP@RopM8|E|>dUfbSkyeD(fo=I5cEThp2iA;J#H~h`lQ(a(a2#=Wd;^4H zSw;1r@nx_a=^F5MKAWtH@GUg5%oI^*si&KlelmzVmvzaW1SVN@5U6FqMCc;R8o{P9 zFxDjpvk(RPyC$cMUhTq924cT>p1@@o z(~h>4zF1ynvR^7~vOK=$&~L7qm{;gS+z@}${F$m`rEI^7W%)muL4ni-xt^ z*_8Gl(H5p7qUNcZROrBEERc@K8OHj6j97znPs|sUT6n6oE;;HACiv^&U1}z3O|6nR z_zhW9BGw!Hjf^(69Y*g!Cmc2Mdoz;pj@<3&VP#SDe%h%jp|GT25n0eTDhpCYtGVhw zP_KY9AXjt)Y*l&C>8w0JUWItz-y&E|6YMnXeV_uoHnF;M7mN}9f6F5GqTwu3Q-d+P zp<5BrCM4;)Ar^7R15#3sUrXS**A_X`b{P+QO9ivwsR;(ii0H@Rv%1jr?Il29paf|F z*90G(5Q(#cpWS2Q9kT*?l}r8z4jput`X(5t@kqMzp<~BySM^kcJ${xE-F8BOTPD9iM|?3^3JfQppNo5<1*YWwB+GGG(oEZ|UJ>RsOp`hm5kdrA+7FL=9oEjytPjta6 z{{gyHDubK6VW028rYduc+aGamfd{e?bPf5OgW}wBMaSEDzGZ5MoR^x?49>ru^NiMU zSwoL~ao>Y0UxA5_5qNlpSi6~VEF&$1t{h!Gu75D~!K@Tl{<~g_2bOutt5U?}Lv<49 z5`2St5BxvJz>j1)f3_Z3&A+y-H&uC=wDG0G3R{Q-Rc?p<=NVS+Ezx~qHIS0~S)jW*X6tuwjS6i2=Dl7LDCy9~sSrs)e=FKfEG9xpdQqbDCj#Di8l?j53|A-e< zLPm1LWb8$ra@EsJV{-GJS6iYGOfH>}N^V3ajo%s&iRtStqNzG1Y87l*b(937U7)Fi zc_8?YOD1nLTcNi~|K#IGD=FxGf09@@Jnq4q(c--aVxVx^wDwp?5k(LCd z#UiUOv`e$9_r_HUz;nHbVTEFFG(EV~-9YOf8zNUQdFO^~Y>kdT4%$6`MbMpdLlcC6 z+JCj43&?Ch2Ixfp0uD*a>!p9CymJ5ka?%;*djPpkrtWhgL`}RB??}J-lv9#-ZeZzV z___2e4^1TWP*H-3TblKIRfs3x%miHgyrFWGN0{uHP(xmQwP>t5lC&WR#KktEJaFG6 zakM(*E0zrB0ij7?J*k{5J&bW>>Lggcd)X|L#Yg0AKAm-I>n!#1v`jC)4#9cQ+l>A` z(dNw*Dz{NsQnU_>hn;(~HY8~pnIZ#DQ#ns_einiyPQrR<6I*ht1hUm&qy^6)K_lgU`^wwco{%bqA`tdl7#`DFv$xe^c5%_`N=S4ucpbGNHHu4&B zornE>FvUm6qh%QEj0%0L#a^xWUA^@Vok10oO#-0HcFRuA3>RmdNSx-;Z~+E`9pg@2 z3))iNV^)lwFtf zln(4Oj?Q1#$e%z~QOGNX_Ers^BIw!s`o?UN6y1s~fq`BNh^DFU8HK|LnpAF5kNhfB z*5XZ)%g-&>CST)<<&|(x>(4IrN;y!cW6W!@AEK_^=ShnD z02RfTqFHS+vXlaj!;td@xEO7g&Cl$cy$KZ;Yy-T;*MCQqY4V}V{jlJpNpJnRoj3!tl76*@wDD$h@E)_-;e~pyN`L& z@D3Gm4$!6>qFpNd5*wYT(3g2}19xH;DQHa&_A49 zcRAm$~I;wq4@7 z8fW&99Pp$ky=Zz9HFz%<5-`XD-KN4gkU))ygPd_$4Q$3g(rYVF_9PF-s1Y2yXXtD| zhc$t-TA=K-277SqDnVCw^TC$G|18aahG3Z60-VZTbr!vyyCpB{1MXoCD`Cz3^wvBm zOho#h{K2k*pnscHBjJXY#@fuxi@xCL8T{FJiSOLgX9KE-o;75evZKI}0{Vj_yyeaK ziwmO^&;5mOn`$B6>Tw~}0I0i2Xtxky|7rPny=4}K+Z&;cDkH7;Ju567;fAm;r#;~n zz(vcV!oe4vVbMBUp^5yeyD~2Xx3-(lxOs>QoU4Bt_8x$xDEN**_M2TW@GLv7bBx_o z;mI=O3o8;AWz?$*FI4wm+h<$2_=8V3N*j?ab&>hw_$!wRq<`B#=UNXW^hLA<65=oO zsdVu^`YPc0=(uY#oxJSk&Jh(Z@gV zpqxLxG@DXBQzlk&!TZ)?;Wi2y`*jp^hw~tX5&qT2P$(g3{+A%0tH;7MDu4eu+t6p8 z=wx2ao_XS=j4JDBJ3OJLJXtw;Wk&KI_mQ2H{nj?;e*82vmOH=Mc>fR#NN3SoHO-kk zsTI!U2uYVR*W}pGJO(=pUY|{+di}f_SbLEh63|Z#;Aw?2!w7LzH4XKiLKBH37pb|= z&Vvbcde3@Bg|<{?ALTMH{@mBVGq~EW+cr$grU}_0P^SI&Zr9d$_NE5cnLR{8_eE~Q z*AxH$M5%&T?TU5Xqt;DbqnGC-<#h~dR1dcRXU3 z3>_}RdCak}#ad!0pKBH(UX|8Gyx{G06WUon4dO#E$$;@s&5%d@1~0ORXr!CkTW^Z!<$} zG~^y$SGSDylZG)SSZ$HYIva!pvW)lIUbpN|8^#;Q*KUZt{&ep-F6uC7{N9#DwH#bS zwEl08X(%E`7klRiJa%I(lO~1Iem5YqD5V`2(m(xDcApwEDKdW(LE*{;^rJ#FQ=(%X zp4jlPpFQSz)H<7umy)s#JnsHR>*S4SC9!k)xeq+ePyan~*O!_-SWSlLRv8IbJCi|g z%hh(dMe3rI$q5H70pq7OHoL8EhL%&}$6E(6k|sLBg`Qqghb76C zVMdMq$dy4VI3~tR-dJAA#NM3gaa$`n7pfR$j;#Ntw6*fUr5g-!$YWjF5`8_HteBspZkUNN7w6T@d{5Jf>+83pS;^#~@~&s-K2-yx6%fI} zIQt4yr>>Ubyl;ziy~({*n!Or?3GO0l=-^=|EJmC+U> zv!&W1R&6bd&(4Vk2PHU|#8E7;u--!ksL!Aw^MpMPF7OG+@a5PcIT+Q>%Qd~ZZ)+;v zxxJ&kyn4%>`|~9;$gi+L$m3n$RI?hOSxXT8TD`vbSvpid|D}FS2&e(ouQQ2EW-BhG z0aez6`;<^~uPoOldn|3P^XTU+(%z`pL)x~+ z{7M+)S7yANt3$l}&!&*~YzmmK&eredJeX*1u|XA zV3*^|(&pb>T$+!GRI(=49#h5?x7bpo5vM$1+biRvc#H>zQ8y6LOe>b z3u7s=!dzI^bR-kGNKne&{uOa&)$NhRL@Z^GYeU~jK=7kYq%V-=>ellxA3IuXRre1S zy|LCGyX~X&v+!!XQB}65`ChO`@8IH~NvZ_uos@;T=Gzfow_DsR+*OpfdAV-J%>I^K6;fPSxgvE;5ORt9y6lqr*|nVFOIK&*92 zD(kcK)-Mh9WA^!z z=PtkzU%4Te0ay!MrmmAGn!WIvRXq81=~VY(P+xq>1=On@j&I_JpkWQLHn=+ICQ0Iy zeYPYl-}caZGJ6ZHn!mq`61(FR+uU?)I2O>65cv8{2B2yPz+2q+n=sahS)+4&{L1!g zpREm|5-qzVTLQGI@4-H%&Ee}(I@9mgFb7k8NJ?WwosFViqhkj~!>^y)djPrgQ4vY8 z=!Wcg4ER|76W~6%vso#O2fd62p?$OCYr~yJ<*KnUI$bfj<=Tm-PUdmaC)AP5HSh+^ zK*3>^#7Bt3dU+^}&oEu@r|g}_76GFPM$**H{(w9Ub>ucy89l|L4X5dfyH5&T$nlR@R)Q;=z5Qh|)oRsoz{js#FSi!BB>W`QWReb(-+X z)3sZ5-r^jckAce+3u!WopH)T8#`wsbo6z53Pttf|IL-A4ZtilNClPQNe=O_$Y$-a~ zoi3;IjhO!v=Bxv&`hPB3uE6fNx>g!7(2ZIoux^nmAUE`$x$`%dZLB9^?W#Qq2wBki z;1_)qEYJ41D}466vAWq5$dmkO?#Rky;S*fPNvw11w2#ydWk!HKjg0G`!DrPF*prd; zv+3b$8v(&N1rml5eFt2=i65RM!I;o!_84{V4m;;AQu#9@Uc+ij5eLq-a@nd)K8neK ze-!kpBIS>XI(U)V9hxzA*pJ04V|h1^BV*SF2XFK zD0sO$vUMPIH$Y6!wN1p3lQ`FPQ*0SUZ1bqa_4p>~h4;&H)=3cEjXsLS@lz`-Fi!i| z)&1EXyj=N1k0%RrThR%2e#|EasRXH6)z|~h()K~|6C7RrFEYRGB4=tIu_qtVg&4ur zrM=}{IH$$c6CrJvO2HOZ0Y*A1?5^*vE9rr)EX@)xG%oW zZx-k@F!>2#1>Wn%WL~YRsh0SnaanQ2L-gl))f;O+#Uk$_mqTdl>?vp>I}q}POvRjG z^27m^pqKEOwWx^ZxWgtEeLmiTkFG0&Iyca^@!G%k%MB}R8jd(&?c!@&SXC1@{Y=o> z&_~WtETS8!LkH@qED(lOqH-)g?W$nC{&c<1V(-z`u8VxH*0*C02PZZ9m>k`@i(EaM zl08$Sm}-TMaoid7Tr^y%vZPS<+}c&H14#bAxl_iYJ1#i)Gij@JDDxPZy+w5GXl2u{ zaZgRaIY}e5BUqm&r02R3M2_vTF2%P8LJaJ2x;DyI=SD|L78<{S0tt8l9dq*)CQ<9n z=dKJEX7^UOiLWfWi=VVb*sICC9kVprGismz&ye>gsM&#|TM=A)F9~a}y*tsrRjh_T zW;*lz<)?nW=@*F4L_xJlJ}JOyNv|d@kk0~`xl9wEeP>IuVguo4Q2Y-Wwfq2T+MMX% zSpIi>>7SV%coL*DY*25fV%ha<3f?Vr9;L(Ner9Ubd&54K9NvxBRau_C`1k^lN5W+a2H-5SRcmk zs?z<y*glY)YCTtZyjkUtjg^T^z*Q76Q%|M=_e$#Y!` zSX{F}ajMeJ@}nox>UyOTS~YLoxAa))+s{pA+ul7d7|B~_Jpu98V1==6(I#3CqF2yK zMduGt8Zz=fpvr5Ivknh-9>?}59)E1=j|}>+7yN(9{;q{M3SVYuR2lqGtO&#>J*azKTj3L}1XWyA3#_J?Zr^rHEfC)z0=^`L z9a_csp2FmBu6!fK>mos#c~!(aU@7oy@(k2T+(Fk4|0UDjnMn2jd!jFEOEMaF94YT@ zn>%^o%YL=mbXdWz=@JEQ2sQ-Q0mtfm#ag)>nX8#T4^OW+_p~OqJ1EvzV%0e^a&x(H zSS=t5U*8MCG|~`sR1{odYGrk^*R!z3EAVQ`cI&F$nR0!SdbngA;eG&LVTEzLlsg_p z*I*p9ddpL+IE#i;XXaOy)vw7$#vOuv<^g#yT`MNBzYvL=u>W`n9$~#qvHZh*yck2@ zJaNPSQ|62>r3m-!oopaM3;dp-OW0PtufB$U(i(~Ue;T47BdJK zB95>F!8$&g?!3^>mqy>O%&1s-E;25^<$!R4w*&sC8^_8MNJ|HZ9_SkVBt)qTRjg|f z!&?l=sb0u)ymcLn&M795iWt;oW=;@>+9~@rdoj*8^>#$1zgr*wPXYS3ZO#=Z#&`S^>aRA+XQTGSQSKaeXv5; zFPlqFBu^wQaxyU^b}|FxEa~0fgcFG(fLlyIO;%YskNnQGZC`O%&?*pn^y1U|B>uk5 zRC`heP8vtQ;GJgT?A_UBtKn@qeVX5@gnlN&$fZe_YgF;Zm<;>98p$^K!~w)_mJPcQBfxfuoby zZur8K&9Cr3Vw9$T(-i<)PX~T^Tl>IT*s;qZn}I21o9gqEfT{A_u=#6aGHr$gA&QcHs#fJhSZc%W;9uZp>=;vVHTW>=>hcSJub>!q^zcR_9> zTEryrA4v%44sbKdm=0~^IIBrlRrMmxC^gcIJD-lo{=^O5-B)9I%1*HaB1%v*s91Jy zCabq~7?)Ijf>V;?D!ccVLs|Zh@f1JD4chfLs|BxLpIo2|Z zK5s@mFTCR|QCNnbF=u)1H^cJ@GxhXq`gruN7CrLbDb)K{55iJY68WLA; zCv?<&zI*q^6UT~YbyhTOjYq#6OxIGr>QT_?kJi^~vKPK&=i9Vm@@$)&YHF(;#7gx> z;+@oD@ELy-G8E+>Hp)Lc_wPNOtaR?jtZQLmIqdz4C?sGGT+|3_L77m5i1Gib;-NhA zb0a>XNLw|i^sdFr^g47EqFhskMnUTUK}9%S1}8D4UB&M1{x;eFvav1n_#8TTe0no* zGY39vPm1*XlgwC#P;;Y5a9Q?THpaNC+;gmX7CoBBne33kyJ-4jAz(`a2j{3P7gcOv z_E+Z`qZ+H38vniSE*{6- zy6|rd{M^j1#!% zU>~hB8D5wZq&KfMG)eSC9o0e~KyK)RrCwsWK&gYTqy!cZr{5loQxv+@^sB38;JD`X zj0|X-HN@`_>=!rZ!4>AmxlYyg&X~G)-rX!2!`M&vmlbzqcpb@9JF@mVBIt;(?61iA zZd9krf9>`;j^`4yhsmIu2ex8wy>qDx%`-Ui`FYikncMIQ-S0=l*Yn^5f&&HQ%Qt$i zT8iFWu0HTG=XGH9sh6)ONviB0?6PupH$$5i_JQBJVi)srjVrg%@cB3K^U;w{w<7!w zAX#DRM~6G5irU-{wjJu~+>e*j7lb(8nk?L-Qt($H;eS32Zi7pz=W|rp?-}$sP~D=( zGwO5MrJpQ8^E%oYn0V&D5z{OAk|BBtazvYp>pBhm!M#^0N72i~8dEDnyHatp<48&|tMa==nuHX=nz6 zVRCnA(j8@>1Gk?PmQa;p-wp?ZjJKfX0ksH;O(VodtC3->kH<1Q%AD6S1T1tTM!7|((;x|V}O0+ zS_l#|GEzN_=EtLovDRZ6C*!(S-OS!yEi#bbr+#N#`9KI@u}8`|^9j3jDZ-^)LuXw! zipt{?w#S`zG^q<=8DLK@;mPNG7Wmd%eQCMW1^vepGs-4kZFu;DS{?|u8v~bGL-1~s zs^RoQ{x54D#rq&MZ7GKB4;&nF%MK2-^yf|c>1()g0M5Z=k`xH1OW|a*nEa`k42|dg z-F0O;bx8PunpmQ_cw<-ibKwKl5dV>X-5RlG-q)T)#?g=AWdE=BzB8!Fwe1!wHbjvC ziWsE`Mv5p+T12D>Vn7I?M?nybfCz}8#fC_bE>)UQQrbIzRke#^wsr@Zub4L??HO;gWMj=4Ir{eoTWt)~&-uTu zt4u)!U+{YfC~Ike6N6!mb4Ek~;4;2XaoNq=8xudee$s{4$n;C;?hH7yYb9l70TVbv z)&c~@Nc;d(r`cPq*8kN*D|UGIzV#^A>uL_hGc&m%tS|qnefYqaqT`+&#eGU!}!C#S!4RZBQ55p_0cd@M$4TAL4nS-7L zgtB>{JI3eWCWRJU`4?CkuuKMBvl)pw&AwCF&^+$i;@Y+BcDqZpZ-4cw7Oze1d8@D& zJ)%$n@Q?l3VS$5LPi6rWEW`~RMeq^->707+XG8Z2Il;Affx@coDaqj@rGJwwP<&h( znY#smj~#W0A3$3D8u&3JvT6cYyn7v@n_61db3Ux*29Y{Bjm`R0s1dsV=^UT zEiXZlJ`p7&;&LQ22bLH}li5^y)jvoU1H5dY74{tl&4nt_+6WhVl5ek^JQ{zG`|EK8 zi$${mouyLO_%(W1>mYAS;>@B}lzCZy+S}hGK^vPq7dT17W|)yC=AmY+g2Dsns)r?B z$r?(SQ`yXkC29SD+PmHvZuodn)favR^_J&ZUsGOK{AgC5k8%;sOOWpzHb0>f?DGMi zy=)#41`L&!w0{Q3>89p1e+Sy@-x8gxnr&nEo=aWpAFtOEY}|IG+|`#cBWAO+ z-BnCw+OEBMbLX?yF4C}hHWwLVM+_OE0pr29H#;eu>MsyFbU|ZE@rUBr@MQ#%sZj1b zo+3TPwyn(SDSmNc{`%I=v>nY0ppDYAB{$~l7*_Ty?QXR+beCFwsT%8bMPd9^QcEb| z3vkZ*1&rwfHJe~nKiil!&~dimO1+g-+7R)>eoxeel;_h&5bMW*QVE!pVDV-+cuX(b zmZ*-gv804LxOH0$Mr=(VZ>b#yKT{Cq2U~5?A6SANkL;{*;-k zz{+NX{0uoEUy|i#+;qgsG~@Qb;LSVaV7=+B*I5sd!$iu(U%pcTrV9L*;!w~cww2^8 zpAtfjlYA{HYW$&*XWc=Bx!xrK0hf{%^cN&E#vfzt#dvLPE63$EURmbaQ@O?iC$*@X zgv)|v2IlYkvv>Xv=d_SIu`{374C-fvh0IAxMOR0j1s0IL=%pdV&sD3kN?cegbo4mM zDdW@m^qPnmfZKr4!nVIdLIH3uDq?gh#xeyP3+fQFufKgg_d7@2a~hVUM5;kfoXh|O zzT@&}mqMG5!Yp=S$l4PGYnFz!CA9HQ>esZgZ+NaY_kS~;pLv<}9JBuX9%<$<`g=Qz z?o#2ZI-iQiA1QFMu(Q@pdfZnS0eF-F{wy?eW1{o%uMAQ>%yvUsJBu*AJAb1J$PWmT zI5}T>7`el{%yi+Z=rtiC1)$T3Eg!Vz!xvGf5WUWDlYQmipDZhwf}|Evzd<$yvl5|~ z+_GS)Les!w>6n3rYnE}D>_?JS!Vl9^;EHWWe5XQ9t@vWs#&zvpg;D8JFI*<~kv;6H z6z}sOEqeWpQGhR&TarJv=GQ}cd5b1}iylhfE_5OMjVDm=#lBWnc*R$g;nZIR|2(De zW=IP)o-BKmB?w5-vK}xdGMv?#dYb91d8zz~7;t3q6ShNYf~_Y;&_%>fUb)Wzfhj>w z?EJF(CBBKC!W+9BabWhabPZdaNGSxqhJ?0jR;tv5-tf{-r5|R|$WQGmhtbSGyePqI z+JH%m!kTv1ysG|=_Q$U7KlKdP4{;_{eI3`mQOc;JW;=ecDvKOZ**OG@=yu!l zPB#arl!EINT>}9q$GEK$2+I}z&S8ZPp0=1Pp{uL_MQrU+lkPEe$h?fGlfAu$*0vYk z65oig{(jj%IZE769aXBCj%?%F6usNhG1J=i+i%%MF3&@$XOp%g*2QSpGr(a9x6=vo zOPhR|qd+2MRQcK#2YjM_9Ryn%_ehK4Y&VfhV9RD(^(PAjQjX1F)aL*<7vv5%FrEbM z6V#}7X(}b@h~w3pG0x7m$?tbN)^M+${zz*0w-}h=USu;y3UCTe$3T2{ zx*!9roPnokHh|Z`!6SCoFhGh(Vg0mfDuKoCA)9|phjZH(!!b7D|a0$f#$;s~5TL}1r zS;%nj7dMBaD3>bkjxBs^cC3HB9NG(XS7cz`*I*wPY1qgiHvkNr$5*yk$SZ{)(N!fz zUkWZyQGq<$G#Ppy^a$_M#p%=E=tJ<1=e>DSCvcJI??WWgP>~9aW4qp5_0P85p;isuV0_ zvHVHrVg2nXgClIEyEzM#E~!*zFf}>~;%_>Q54N~pLr0z2LBD5Z zG&>WSDG(=AgA@@7yS;ZBOo?gO6hJ^fayJY>q48VJ7sYmWu}GT=Y%_CR9fbA6UP(lx zcq)-5Sm-rp5W#;qND_|w#&bzvQETs@&w5Nk-72YT0RyP$)x&+%GpuPZiy-;tFIoL( zKXHC3BklP$Y@67;xYO&M6fgpo8oCeUe3xy=2gW?pO{Y9D);;${#@tL5p$FIH;llXL zcY!i_lPevY=6c(}oP#PJ-ov|k-wm_zt{yLIl%SMvin_u|0^T4OBIxcQ>Isl$Sm^Kb zEPB!>f->Hwj=Ja2rJ}CiT5n_6_O|3$*KLx?+NX7%rv8gH3 z1p0_}0zO0DD^gpsrM}!jUMV+TZtD+Qau2-8aa-wlVC2`$i5@E4b%Wdhpag!K(M;b= zf+9ZDy*$>Ga);1c9zK$D{MUO@Oedo516bu=$N17>h`M)QPf5TuyZGt|X-PMrF5YJo zjAx+v;E|Tcw&VuGSDagV{0}UGjR=4)B_1axAd_xn4OAC~Ql~UQumOCZ-ZIh`SE$AO zSxUm){dWV;1KIm%S`Ao${`E z(!5-;%{AtAk4WKWOFr1 ztj|5?H>K4ppIwQRJP;tM%vdU<02WK$N~N%pQeeK&e@QG};EElL0@9iT=DZ(qU52Z_ zbEFM`<(mS`1d26oxP?hF6RD1VfLsjSj#vl>ipUz+joR(o%r<8j0<2?%+y+=t*v4scGfGZB z*C||5trX$u5s+ArVw@XK@2hAF3cgDqkv{S9c`nd~R5{KyGp@ z$qc8!uy*R&Ih$6N{Gq8bC#Ki*i6OWDX%S$zo(|9~@rmx_tO@ZXi;~Rr8un&^KCpl# z|KChx7M-0_>?uJ(LA=Yn%V8Z?oJ)vg;n~S-AiM$XK`+6_!DLz?pX7b0o^Cat@r@pu zz(v}EKRUIQLCib4f+qRofZ`eN-o&@~ADL zwLVU@m2f;g*XmYhV`17Bqrqw1!I5w(HD&-OLp#QMBgJuQl)aGP`7S`| z=948B&Y+=V^m{Ef4t=(2#>Q3F>#q;n=3M?Y?Bz#!Tm##$)35J8QQNH-Lg_TO%z>Uh zx6N)YU7VE`RoNQUPZbk~`D>`SdlBdku2p?7KY%(Zp^hqZCfd$b1dvje4NqJeGA2%6q(-Ydi5uRCYO;8z>lw$FXNzzW>Xex3 zz>L6)qvt?{2```&b?414ajB1}kOZ@Pakw}$)jQh2;jG4X2hFfz`B6HQa(Jv44U)2zK2#B4Loyy z(ErNv;}Q+4j8nH{a>t6}u%{eX`c0-BuPhJg`j1R)THA|w{+Hm6frqQiG~2e!(qPNQ z>K+%f4!eSf7eU*u3%`t56K8<-NU-%#_lGHX+!_D-od}`gX0MB$J27OQ<|c_v3naxi zU>zBcYgXoeE{Aj8(tLNnQ$IR2!}NP-#*%}bsh3M$%S9zp)5dTEsRUxBWL4qX-B{() zB>C(FAXJGL5bh2X{IhFHQDxke76*Owfz;j%tQ^ zgVb8g8Y$z)Ca}HY4(0UD?}Iyzff!#`M%wn@xnvj2Vvd*JY7QcBh)H^%rFc=DRQ=ZS+UBeAofR8yd4L(%K#eh_Rn=!d>HdVboa}v`u#DZMz2i$3l!2hEl19Q>;ZP$|)&E-1Vyjwv z42vvg_-*+LJnwQK+d`U??`UXtBBnkDv9OPWck`o~zoYaN_n32EA5y|MN*-q*JS4&l z@Dl;-At3t*06ZWVmv0bD=YKJ~<7J>#H($!4=P@`LX8UJ;`~&yN*`tk5yYCru;TfUm zDzzTwPqCy;TGs6N#)BaIc3;+{v{ey%g;7`TZLsZalBc|{nvyvcbk|@UTLN(dF@#!h z&c!OXu-vYqYA+|<<}8uk2f{yk`3Pba#dcR7=wj7;kj^Py6VUrX^HgN@5h)J;WJM+U{RYmip!LZ=W(dle76qvcB?BypXM$PS9i$k}ZfF2QF=`gMIf^(y1EmGx(3nyc%s*vN~AJJ2u<$=XFgeUE^^6;aA^z4>;? zfz=t{BHb!h%%Ev%^51s(=nM`O&F(9_q&XG6lxL*n%A>Ir$GcxbH|^OrEi~`0)LR@v z1twvw6n92_L~&McRZmV$rkT`vxy(YnQUCqgC3rY1dMgmOpq?R2NU>;S?={T$7=5 z&%Q0Wg9_1Fb#KBW*S30+oESsqilw{b4|A{b3y}Ij29=o@O73@^fG2(tPJaDzsbq!U zNEEz|K$?xyueC>BU_-zA&7r%Dx|sBcs$R*fSw&W21Tdj#B);KpOF}K`04F#ZTy2Oj zeH(Jz>evGUKMfmu)Ns>RBIN~m>$2S!j`%aT$F-u!jw9Exd~eG%)?O)*=JL=Br7U_| zqUm&_MVX+g*Yah*?i%4R;8WRf@7Gpl2E7J~GNrC8b{H#~@#Z9LF1@VE6`J=vnFCg@ zL}1>_2v#1eryFC+YGKBt20nMkVbad9FSyI$R;3X&ZX11>QGx?0XEL_nrnmf3-HYt^ zIM`q!c@K$k{ph*?>9cA9$kFx?DYY(UEh9$VuJjzQ(0RDt$RoB?Dez!!aKpU%NNBq? zaN8&sk3dH)CwD?Z{sED^V8$P($f8qY-X|Y1><+%WedIGY)fXL#gEJHQtFoIxjuRiS zJPY4b5i-z@THXilttxti?ao?Zbuhc{SWK-g##CHS4eatLSW-HOnkmOarRT{S}PvlgbwRU>LHh0T}^Xx=RT{^Zo7CEILnrJJOe zcoeob{$YrUK}BWG!V^BX)n{l3@#^WeQoBmHd*4r@(0}Oaw7yliyv)1FS792B6PtVG zgLvoUw3z|!zz0Ma6M*;IS;4IPom9!Zkv`AvU?XNvEup&nhnxAykguiW*}Hh2fz3Q9s|~aRkKt*UbPFvJ&u7qv=98W^B_! zbe<`XL5`l!Cfx4A6iC1r<{v#m-U^Oxaqp8@NE3)P)LG*Uiwkyt&OKXBcn^lyK-=XJ z+bzq&nx6^op!VqA^raBl_10QRLqbFCCG?s;kpg0IBCR82W&G8X*TI;MrF+)xk1?`U zT)%VdZ6s25{Tk#=6RJ@AO*3l%GVli4q7D86f;U?nwBgQjGL7k!VVQ+z6IO4I z{;}uO9RT>>U!dbxnhnQ89rQQSdG zV_f2_2pt+W5p;e3QT072H3#gEL*S?1U`2&BDy!OfGR5Bf&cQ$Ro$>aG(Sn(I17hEn zWrydk$EG-ISUu=P2gK?CuzF|Tx#DDB$&eYReGT2wtdWN&4pPLg6}@vDO$!Z^nC>9N zPRV}A~ypsQF=wjBO(v)!ZxdzmmNCW{Ow>%@i;#|{k=>4#i+}dzFYZ&1_)zmL_ zyr%)!Lt33mups0XfN{2%sTTxWT(7LMpHdhimmZ^PY_vKa6qCU)*1|E$uL{p4j>;^Qrg#$&=V2J64wTp@a@nWOso6-`_?ha}$XuTomAu7E|hDoMVPiQvTt|$dJN*7Ea>Sv0Ph(*sSOiXMDg^AjENk)b6c24 zMo+a;;K{p?fH?;I7N5HaRs(B=A)0)S)!ggxaYXi;^0Pp6r@*cgr4_a`ezvTB8#2|F zEc?p=o(3lZD_qsL)=n3j!Ir(%%y8OMlSkGm_XNIP=f(U6V17wNia3ZaEzHOvTmpZD z^Y!g&(#Lz`VaDwF@*{}|zuu#*>~@&%D`IsR+wFyg0Y5XgnN4yFG`38V4GTu?mb3d7 z!D~zIlteE8BsV2`Or(kJ5wJ59iP5gUtzbi-KBVdb5uh;eJO7FY{iI5S_N%cwfNfzO zm%za>1tz0eDUs?L$XH~o#pOr0A9&)QPaS#(XMA$k2H!MUzYe*qMCy>1K3ZHFGey@T z_HPBUwym)JoX2f_IbbwwG&P=bC#s$8+gH^~qmT)Av>qy&6g~Dflwk!MqQK(NzMl^T z^N%vJ*mNxO*%2euNw%>Q#ud(`*>Y)(Hn3m&q+$&Rv;)T7>4qt^v3_^$h8w|SM8(o9 z89%1Rr_@~pPu+utG$xR8L(o90cYDJ8$M_{&RvG#@B~gBKk6pjg!)(Yl=ierK|2p17 zaApuZE{D!7-a2Lpkw}o8&#C&6D1&IqW>r7_<7d7o0W``DQ%hh*4?jQf%{wn8zJFV} zvxt%X5nG}xmNb}v_`FY9N8w%jjnC_OXvW`z3vw#Z3M5E~Guz`wn0JeA5#Fm~d_={h`pv!dEz;vcHp0Dl0`n!(AFg+eJ>tm^Wvyv(n3_!-VFk0oQBP(BN*R`&Zd zwQ%}1B2}4#gX2%JE3z9nFxOdiC}H+BovfQ@ye&B6-#hi)stXcoxY^%?d$ann4)v%H zL`Pnl%^C3VT#z2&3@i0`XSy+ckUOa@{O)#-t7?|E_3LXKCv8GGZQU>vhYR#wC1Y0h zS1InR)B;c+Mn{tt{e14A?n_RX`JdHuBwnP^dzj7{pXZyOs@1lLJ-W z7-us~cfsUtSnlAY1<>IBs3u4^S+R}@>755^<>F-y~MImbiTxZ-;5Yq|Y2 z{HE>2<|c{<<}yC~7|BtjVLrR+QP%(JQ`c&@F=SE%#N=08>%{BiE}zLI7YKpA(^4rPSX!8k)&#FM(+6|INSI z!D<0F!Jp|hZu5XUu4Go{Qe{!{oC=Icn{e71DN-hSk!P>mvlW_+COE*?DHoWT`H&wy zU$HeoHoxa_N_DC2c`Hjw=ljL=c>Xy#H9!UhfH7+{4bN=8d&H5!8gW*KPS$pHKQSt* zk$^ks4%n(EKL-Y`mHO7_dwm2aMaqlHLtd7Z#%tD#x+oPEmS}7}w9gG>_!mfKkj1O$ z*1A#%t3NB>7{RJM6HxY~GQw3PyfEuw`5slkfTEHnE81h{lIv}{T#8Axa*jYK^GJIC zxs!{wIbL$?Yb(#t{8=BdQ++3HWb~r|x6?6Z*-e$fP8-o(`4!3I6eL5(3ca#DB<-7xb?2;{0Z->iE<~LySAND8qA+(a z>dNJ@Ip8LV>z|7rPdc)K?URmd*XtSqN{FIzyGUP0TJ9Puii6N|8mWLhEzjL5bJiM) zoKaQSrJkSuv4Gq&^C9y7GJTBc&Z_@y4|+q&6d+8jWg7M+mKidfSm1vZa#JmRZ56hV z8MrHB=;dLu)D>dvZdRLuxgT4mpJuZ{tlGjPv)xK{SoJZkr|~Xk#n`i_^5&ZSbG*-` zF1>$v1+`iL&ZESUCW-`;FrJd48l+M~57|7|Bqk~~^)jJjz4soZ?H>u0#cHZA{Cs40 zB1E=^joy_r!3G5_Z}CM>vB3v`C734W;)kk3CJEBSv4iq{=7)w(1y;G8;%V_!BE$Iv zNOQwY?M)#4m^jW}OFLHH{rX`N%B*b5G{1E9_5o4c4~a@{cVl8TkPngv0o4d<=8rGo zhA=i3kJha(@ET1i2jY9xwt$p7C_&!43%VM(bcM;^itShEB^2JZ!%+{4&f8M|CGj7?o zY-Hy)g6+ATHjnprVBY!PVu0c_BwHb#-gou7TiC9$oA;=J=N+vp67LqKT068sLb#5ng4CR>TAvN2+q~%ME;;C@v$;y- zne$oaE_W`7>QZZ>~;hCYUjrD!*q) z3|r12kb4F=cYd0HOF?k3i^$YY=S#|}RdC|27g^Q~M`yTyGC2SUa=`gY4eT%kFBOzr zlp8*7ezC3olBjo-(npkg?T2dhCa$Q@z-`j&uViG>e7;ZKRqE!l_i})jSZMyWqY1rJ z(z#%S05;D)J)hAAi0=dcON2H}$cu>>;)0vsD|S^uJoe#tIc5Duu$m-0RDJ0>13u2R zfGHcvKTXQPY>E!p6=A52sGsu<8GG?*PhYZGr?kCF{PBXf5n-JTfH&7wMIKK&R-14+ zD9dS1S^ibtsr`#}Bx2@jZemxB^Bw?qiYhFez}rVW6h;tZ9OO7Qecqsxt0O1GUsgPv zZluOw?9-piDQCsM6w^6Sq~+k9un2q~2|%ENGxN_}Xz3FitpC(y_PCEvC7uuG^E56a zq9HJ{;?3vN5r%GSInR#?t5}~4dBAB;bRXQ?;@{2) zz+SY?w$?NNJ9(JG9?37%qNpFuxa>~H7xd6wU<~Y?!WzvQt0Rf%D?WF29&^9adj;jF z9`Nu2Y85#4+JTtc3Z1+P+D*?2m-lm1bDq3_HuGu}%<8m0sHTjg5VT3iRr5`!VW{M- z{Lz3o!t3HJP@ggjLu2z36-rU~29x0m11d2g@s6x4wye&_i3 z$q8tYKQ1 z=k?>$Z>Dx7JOb=b5E`OqH#!~Tw_pag4bJKS`5RL@!M}dFKZV6hU}_`gA)8@fEUR*p z@ZAWAgoBhn?&I%9=$-|q`<>439CEg=|DXAg9GQ6JX&~$%xV4kjK|k4Qi3&xR>Ej{; zwr1}lu@IT5vH~QYKbx`mNt>&Ess%Y(d3Z0QGGMuPSD&OKTdhJezF|CQ26A?%&1DcZ z8ky=zhwoB6JC62_8uCu@?U9^ARcdRVpIEmMAbng+ftm?TQW}`)qA80Dk9{wCIc$h! zS$u4fHDM8ep54X$*o9kmANy_k*q3Z`6u>hBAgoFjNzih7-KhRTVIklmM%SlNL&3I~ zBBAZZ%|4?>=dm#9`m8(KFh)IzD2Wv_;j}I6;%A^1X;pUwWpLHE90f8x-*gmBmES2= zhWSntl?I;taeXCs^-UO;X%(o|;D@QDPmpHkB6g z${!Br>5LdX37lL0T-n&DC(7B>`u4C9Al z=Qz*lOR%lbi{i0ho_NML`W`Xa{)4BK@W`X6{xz=;nDTtv$dnmbQ!gj*Mv%~nI}Zk0 zLT)+P@bh7a!;d9p(WO963>g{o^q^|(%40SyKYCP=C8vixj1IsNnDNP)#oCAV2Ifw6 zaTng$Z+-!_*3yY&MbT{F6IiH;+A=IxFP0o3dc?FVW1HT$5}(4XIyx!{Rdq8EcF&~C zz+Em@5vXAtki}<42RF=k7oFiTOF2ON!(#Z4ZuFmskAL7wposXZb^j&J{i~1tKlHEv z^CkWw#{c~!$gxwDyp$ooOg8o~`o@|J%W`7{w{o4IEd|JwG;4P7?;HRzeLn)CB8aZR zgs*NG0-*fUsNc&-)DFVPFi0B1lhg%QmNa615xZK-=7)Lx&*%LA{Csjt*JOGKgU^=; LjUXod{^@@K2r?wl literal 0 HcmV?d00001 diff --git a/node_modules/mongodb/test/gridstore/test_gs_weird_bug.png b/node_modules/mongodb/test/gridstore/test_gs_weird_bug.png new file mode 100644 index 0000000000000000000000000000000000000000..1554dc3238dc94f4c8375b17b4b8d34a337d9c1b GIT binary patch literal 52184 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 literal 0 HcmV?d00001 diff --git a/node_modules/mongodb/test/gridstore/test_gs_working_field_read.pdf b/node_modules/mongodb/test/gridstore/test_gs_working_field_read.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4b1247a542ca908c91f6b7baa038004a449e696a GIT binary patch literal 130253 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 count1); + test.ok(collectionInfo2['_id_'] != null); + test.equal('_id', collectionInfo2['_id_'][0][0]); + test.ok(collectionInfo2['a_1'] != null); + test.deepEqual([["a", 1]], collectionInfo2['a_1']); + test.ok((collectionInfo[indexName] != null)); + test.deepEqual([["a", 1]], collectionInfo[indexName]); + + // Let's close the db + test.done(); + }); + }); + }); + }) + }); + }, + + shouldCorrectlyHandleMultipleColumnIndexes : function(test) { + client.createCollection('test_multiple_index_cols', function(err, collection) { + collection.insert({a:1}, function(err, ids) { + // Create an index on the collection + client.createIndex(collection.collectionName, [['a', -1], ['b', 1], ['c', -1]], function(err, indexName) { + test.equal("a_-1_b_1_c_-1", indexName); + // Let's fetch the index information + client.indexInformation(collection.collectionName, function(err, collectionInfo) { + var count1 = 0; + // Get count of indexes + for(var i in collectionInfo) { count1 += 1;} + + // Test + test.equal(2, count1); + test.ok(collectionInfo[indexName] != null); + test.deepEqual([['a', -1], ['b', 1], ['c', -1]], collectionInfo[indexName]); + + // Let's close the db + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyHandleUniqueIndex : function(test) { + // Create a non-unique index and test inserts + client.createCollection('test_unique_index', function(err, collection) { + client.createIndex(collection.collectionName, 'hello', function(err, indexName) { + // Insert some docs + collection.insert([{'hello':'world'}, {'hello':'mike'}, {'hello':'world'}], {safe:true}, function(err, errors) { + // Assert that we have no erros + client.error(function(err, errors) { + test.equal(1, errors.length); + test.equal(null, errors[0].err); + + // Create a unique index and test that insert fails + client.createCollection('test_unique_index2', function(err, collection) { + client.createIndex(collection.collectionName, 'hello', {unique:true}, function(err, indexName) { + // Insert some docs + collection.insert([{'hello':'world'}, {'hello':'mike'}, {'hello':'world'}], {safe:true}, function(err, ids) { + test.ok(err != null); + test.done(); + }); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyCreateSubfieldIndex : function(test) { + // Create a non-unique index and test inserts + client.createCollection('test_index_on_subfield', function(err, collection) { + collection.insert([{'hello': {'a':4, 'b':5}}, {'hello': {'a':7, 'b':2}}, {'hello': {'a':4, 'b':10}}], {safe:true}, function(err, ids) { + // Assert that we have no erros + client.error(function(err, errors) { + test.equal(1, errors.length); + test.ok(errors[0].err == null); + + // Create a unique subfield index and test that insert fails + client.createCollection('test_index_on_subfield2', function(err, collection) { + client.createIndex(collection.collectionName, 'hello.a', true, function(err, indexName) { + collection.insert([{'hello': {'a':4, 'b':5}}, {'hello': {'a':7, 'b':2}}, {'hello': {'a':4, 'b':10}}], {safe:true}, function(err, ids) { + // Assert that we have erros + test.ok(err != null); + test.done(); + }); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyDropIndexes : function(test) { + client.createCollection('test_drop_indexes', function(err, collection) { + collection.insert({a:1}, {safe:true}, function(err, ids) { + // Create an index on the collection + client.createIndex(collection.collectionName, 'a', function(err, indexName) { + test.equal("a_1", indexName); + // Drop all the indexes + collection.dropIndexes(function(err, result) { + test.equal(true, result); + + collection.indexInformation(function(err, result) { + test.ok(result['a_1'] == null); + test.done(); + }) + }) + }); + }) + }); + }, + + shouldCorrectlyHandleDistinctIndexes : function(test) { + client.createCollection('test_distinct_queries', function(err, collection) { + collection.insert([{'a':0, 'b':{'c':'a'}}, + {'a':1, 'b':{'c':'b'}}, + {'a':1, 'b':{'c':'c'}}, + {'a':2, 'b':{'c':'a'}}, {'a':3}, {'a':3}], {safe:true}, function(err, ids) { + collection.distinct('a', function(err, docs) { + test.deepEqual([0, 1, 2, 3], docs.sort()); + }); + + collection.distinct('b.c', function(err, docs) { + test.deepEqual(['a', 'b', 'c'], docs.sort()); + test.done(); + }); + }) + }); + }, + + shouldCorrectlyExecuteEnsureIndex : function(test) { + client.createCollection('test_ensure_index', function(err, collection) { + // Create an index on the collection + client.ensureIndex(collection.collectionName, 'a', function(err, indexName) { + test.equal("a_1", indexName); + // Let's fetch the index information + client.indexInformation(collection.collectionName, function(err, collectionInfo) { + test.ok(collectionInfo['_id_'] != null); + test.equal('_id', collectionInfo['_id_'][0][0]); + test.ok(collectionInfo['a_1'] != null); + test.deepEqual([["a", 1]], collectionInfo['a_1']); + + client.ensureIndex(collection.collectionName, 'a', function(err, indexName) { + test.equal("a_1", indexName); + // Let's fetch the index information + client.indexInformation(collection.collectionName, function(err, collectionInfo) { + test.ok(collectionInfo['_id_'] != null); + test.equal('_id', collectionInfo['_id_'][0][0]); + test.ok(collectionInfo['a_1'] != null); + test.deepEqual([["a", 1]], collectionInfo['a_1']); + // Let's close the db + test.done(); + }); + }); + }); + }); + }) + }, + + shouldCorrectlyCreateAndUseSparseIndex : function(test) { + client.createCollection('create_and_use_sparse_index_test', function(err, r) { + client.collection('create_and_use_sparse_index_test', function(err, collection) { + + collection.ensureIndex({title:1}, {sparse:true}, function(err, indexName) { + collection.insert([{name:"Jim"}, {name:"Sarah", title:"Princess"}], {safe:true}, function(err, result) { + collection.find({title:{$ne:null}}).sort({title:1}).toArray(function(err, items) { + test.equal(1, items.length); + test.equal("Sarah", items[0].name); + + // Fetch the info for the indexes + collection.indexInformation({full:true}, function(err, indexInfo) { + test.equal(null, err); + test.equal(2, indexInfo.length); + test.done(); + }) + }) + }); + }) + }) + }) + }, +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/insert_test.js b/node_modules/mongodb/test/insert_test.js new file mode 100644 index 0000000..a02aeee --- /dev/null +++ b/node_modules/mongodb/test/insert_test.js @@ -0,0 +1,646 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Script = require('vm'), + Collection = mongodb.Collection, + Server = mongodb.Server, + Step = require("../deps/step/lib/step"), + ServerManager = require('./tools/server_manager').ServerManager; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + // Close the client + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldForceMongoDbServerToAssignId : function(test) { + /// Set up server with custom pk factory + var db = new Db(MONGODB, new Server('localhost', 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null), 'forceServerObjectId':true}); + db.bson_deserializer = client.bson_deserializer; + db.bson_serializer = client.bson_serializer; + + db.open(function(err, client) { + client.createCollection('test_insert2', function(err, r) { + client.collection('test_insert2', function(err, collection) { + + Step( + function inserts() { + var group = this.group(); + + for(var i = 1; i < 1000; i++) { + collection.insert({c:i}, {safe:true}, group()); + } + }, + + function done(err, result) { + collection.insert({a:2}, {safe:true}, function(err, r) { + collection.insert({a:3}, {safe:true}, function(err, r) { + collection.count(function(err, count) { + test.equal(1001, count); + // Locate all the entries using find + collection.find(function(err, cursor) { + cursor.toArray(function(err, results) { + test.equal(1001, results.length); + test.ok(results[0] != null); + + client.close(); + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + } + ) + }); + }); + }); + }, + + shouldCorrectlyPerformSingleInsert : function(test) { + client.createCollection('shouldCorrectlyPerformSingleInsert', function(err, collection) { + collection.insert({a:1}, {safe:true}, function(err, result) { + collection.findOne(function(err, item) { + test.equal(1, item.a); + test.done(); + }) + }) + }) + }, + + shouldCorrectlyPerformBasicInsert : function(test) { + client.createCollection('test_insert', function(err, r) { + client.collection('test_insert', function(err, collection) { + + Step( + function inserts() { + var group = this.group(); + + for(var i = 1; i < 1000; i++) { + collection.insert({c:i}, {safe:true}, group()); + } + }, + + function done(err, result) { + collection.insert({a:2}, {safe:true}, function(err, r) { + collection.insert({a:3}, {safe:true}, function(err, r) { + collection.count(function(err, count) { + test.equal(1001, count); + // Locate all the entries using find + collection.find(function(err, cursor) { + cursor.toArray(function(err, results) { + test.equal(1001, results.length); + test.ok(results[0] != null); + + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + } + ) + }); + }); + }, + + // Test multiple document insert + shouldCorrectlyHandleMultipleDocumentInsert : function(test) { + client.createCollection('test_multiple_insert', function(err, r) { + var collection = client.collection('test_multiple_insert', function(err, collection) { + var docs = [{a:1}, {a:2}]; + + collection.insert(docs, {safe:true}, function(err, ids) { + ids.forEach(function(doc) { + test.ok(((doc['_id']) instanceof client.bson_serializer.ObjectID || Object.prototype.toString.call(doc['_id']) === '[object ObjectID]')); + }); + + // Let's ensure we have both documents + collection.find(function(err, cursor) { + cursor.toArray(function(err, docs) { + test.equal(2, docs.length); + var results = []; + // Check that we have all the results we want + docs.forEach(function(doc) { + if(doc.a == 1 || doc.a == 2) results.push(1); + }); + test.equal(2, results.length); + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + }, + + shouldCorrectlyExecuteSaveInsertUpdate: function(test) { + client.createCollection('shouldCorrectlyExecuteSaveInsertUpdate', function(err, collection) { + collection.save({ email : 'save' }, {safe:true}, function() { + collection.insert({ email : 'insert' }, {safe:true}, function() { + collection.update( + { email : 'update' }, + { email : 'update' }, + { upsert: true, safe:true}, + + function() { + collection.find(function(e, c) { + c.toArray(function(e, a) { + test.equal(3, a.length) + test.done(); + }); + }); + } + ); + }); + }); + }); + }, + + shouldCorrectlyInsertAndRetrieveLargeIntegratedArrayDocument : function(test) { + client.createCollection('test_should_deserialize_large_integrated_array', function(err, collection) { + var doc = {'a':0, + 'b':['tmp1', 'tmp2', 'tmp3', 'tmp4', 'tmp5', 'tmp6', 'tmp7', 'tmp8', 'tmp9', 'tmp10', 'tmp11', 'tmp12', 'tmp13', 'tmp14', 'tmp15', 'tmp16'] + }; + // Insert the collection + collection.insert(doc, {safe:true}, function(err, r) { + // Fetch and check the collection + collection.findOne({'a': 0}, function(err, result) { + test.deepEqual(doc.a, result.a); + test.deepEqual(doc.b, result.b); + test.done(); + }); + }); + }); + }, + + shouldCorrectlyInsertAndRetrieveDocumentWithAllTypes : function(test) { + client.createCollection('test_all_serialization_types', function(err, collection) { + var date = new Date(); + var oid = new client.bson_serializer.ObjectID(); + var string = 'binstring' + var bin = new client.bson_serializer.Binary() + for(var index = 0; index < string.length; index++) { + bin.put(string.charAt(index)) + } + + var motherOfAllDocuments = { + 'string': 'hello', + 'array': [1,2,3], + 'hash': {'a':1, 'b':2}, + 'date': date, + 'oid': oid, + 'binary': bin, + 'int': 42, + 'float': 33.3333, + 'regexp': /regexp/, + 'boolean': true, + 'long': date.getTime(), + 'where': new client.bson_serializer.Code('this.a > i', {i:1}), + 'dbref': new client.bson_serializer.DBRef('namespace', oid, 'integration_tests_') + } + + collection.insert(motherOfAllDocuments, {safe:true}, function(err, docs) { + + collection.findOne(function(err, doc) { + // Assert correct deserialization of the values + test.equal(motherOfAllDocuments.string, doc.string); + test.deepEqual(motherOfAllDocuments.array, doc.array); + test.equal(motherOfAllDocuments.hash.a, doc.hash.a); + test.equal(motherOfAllDocuments.hash.b, doc.hash.b); + test.equal(date.getTime(), doc.long); + test.equal(date.toString(), doc.date.toString()); + test.equal(date.getTime(), doc.date.getTime()); + test.equal(motherOfAllDocuments.oid.toHexString(), doc.oid.toHexString()); + test.equal(motherOfAllDocuments.binary.value(), doc.binary.value()); + + test.equal(motherOfAllDocuments.int, doc.int); + test.equal(motherOfAllDocuments.long, doc.long); + test.equal(motherOfAllDocuments.float, doc.float); + test.equal(motherOfAllDocuments.regexp.toString(), doc.regexp.toString()); + test.equal(motherOfAllDocuments.boolean, doc.boolean); + test.equal(motherOfAllDocuments.where.code, doc.where.code); + test.equal(motherOfAllDocuments.where.scope['i'], doc.where.scope.i); + + test.equal(motherOfAllDocuments.dbref.namespace, doc.dbref.namespace); + test.equal(motherOfAllDocuments.dbref.oid.toHexString(), doc.dbref.oid.toHexString()); + test.equal(motherOfAllDocuments.dbref.db, doc.dbref.db); + test.done(); + }) + }); + }); + }, + + shouldCorrectlyInsertAndUpdateDocumentWithNewScriptContext: function(test) { + var db = new Db(MONGODB, new Server('localhost', 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + db.bson_deserializer = client.bson_deserializer; + db.bson_serializer = client.bson_serializer; + db.pkFactory = client.pkFactory; + + db.open(function(err, db) { + //convience curried handler for functions of type 'a -> (err, result) + function getResult(callback){ + return function(error, result) { + test.ok(error == null); + return callback(result); + } + }; + + db.collection('users', getResult(function(user_collection){ + user_collection.remove({}, {safe:true}, function(err, result) { + //first, create a user object + var newUser = { name : 'Test Account', settings : {} }; + user_collection.insert([newUser], {safe:true}, getResult(function(users){ + var user = users[0]; + + var scriptCode = "settings.block = []; settings.block.push('test');"; + var context = { settings : { thisOneWorks : "somestring" } }; + + Script.runInNewContext(scriptCode, context, "testScript"); + + //now create update command and issue it + var updateCommand = { $set : context }; + + user_collection.update({_id : user._id}, updateCommand, {safe:true}, + getResult(function(updateCommand) { + // Fetch the object and check that the changes are persisted + user_collection.findOne({_id : user._id}, function(err, doc) { + test.ok(err == null); + test.equal("Test Account", doc.name); + test.equal("somestring", doc.settings.thisOneWorks); + test.equal("test", doc.settings.block[0]); + + // Let's close the db + db.close(); + test.done(); + }); + }) + ); + })); + }); + })); + }); + }, + + shouldCorrectlySerializeDocumentWithAllTypesInNewContext : function(test) { + client.createCollection('test_all_serialization_types_new_context', function(err, collection) { + var date = new Date(); + var scriptCode = + "var string = 'binstring'\n" + + "var bin = new mongo.Binary()\n" + + "for(var index = 0; index < string.length; index++) {\n" + + " bin.put(string.charAt(index))\n" + + "}\n" + + "motherOfAllDocuments['string'] = 'hello';" + + "motherOfAllDocuments['array'] = [1,2,3];" + + "motherOfAllDocuments['hash'] = {'a':1, 'b':2};" + + "motherOfAllDocuments['date'] = date;" + + "motherOfAllDocuments['oid'] = new mongo.ObjectID();" + + "motherOfAllDocuments['binary'] = bin;" + + "motherOfAllDocuments['int'] = 42;" + + "motherOfAllDocuments['float'] = 33.3333;" + + "motherOfAllDocuments['regexp'] = /regexp/;" + + "motherOfAllDocuments['boolean'] = true;" + + "motherOfAllDocuments['long'] = motherOfAllDocuments['date'].getTime();" + + "motherOfAllDocuments['where'] = new mongo.Code('this.a > i', {i:1});" + + "motherOfAllDocuments['dbref'] = new mongo.DBRef('namespace', motherOfAllDocuments['oid'], 'integration_tests_');"; + + var context = { motherOfAllDocuments : {}, mongo:client.bson_serializer, date:date}; + // Execute function in context + Script.runInNewContext(scriptCode, context, "testScript"); + // sys.puts(sys.inspect(context.motherOfAllDocuments)) + var motherOfAllDocuments = context.motherOfAllDocuments; + + collection.insert(context.motherOfAllDocuments, {safe:true}, function(err, docs) { + collection.findOne(function(err, doc) { + // Assert correct deserialization of the values + test.equal(motherOfAllDocuments.string, doc.string); + test.deepEqual(motherOfAllDocuments.array, doc.array); + test.equal(motherOfAllDocuments.hash.a, doc.hash.a); + test.equal(motherOfAllDocuments.hash.b, doc.hash.b); + test.equal(date.getTime(), doc.long); + test.equal(date.toString(), doc.date.toString()); + test.equal(date.getTime(), doc.date.getTime()); + test.equal(motherOfAllDocuments.oid.toHexString(), doc.oid.toHexString()); + test.equal(motherOfAllDocuments.binary.value(), doc.binary.value()); + + test.equal(motherOfAllDocuments.int, doc.int); + test.equal(motherOfAllDocuments.long, doc.long); + test.equal(motherOfAllDocuments.float, doc.float); + test.equal(motherOfAllDocuments.regexp.toString(), doc.regexp.toString()); + test.equal(motherOfAllDocuments.boolean, doc.boolean); + test.equal(motherOfAllDocuments.where.code, doc.where.code); + test.equal(motherOfAllDocuments.where.scope['i'], doc.where.scope.i); + test.equal(motherOfAllDocuments.dbref.namespace, doc.dbref.namespace); + test.equal(motherOfAllDocuments.dbref.oid.toHexString(), doc.dbref.oid.toHexString()); + test.equal(motherOfAllDocuments.dbref.db, doc.dbref.db); + + test.done(); + }) + }); + }); + }, + + shouldCorrectlyDoToJsonForLongValue : function(test) { + client.createCollection('test_to_json_for_long', function(err, collection) { + test.ok(collection instanceof Collection); + + collection.insertAll([{value: client.bson_serializer.Long.fromNumber(32222432)}], {safe:true}, function(err, ids) { + collection.findOne({}, function(err, item) { + test.equal(32222432, item.value); + test.done(); + }); + }); + }); + }, + + shouldCorrectlyInsertAndUpdateWithNoCallback : function(test) { + var db = new Db(MONGODB, new Server('localhost', 27017, {auto_reconnect: true, poolSize: 1}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + db.bson_deserializer = client.bson_deserializer; + db.bson_serializer = client.bson_serializer; + db.pkFactory = client.pkFactory; + + db.open(function(err, client) { + client.createCollection('test_insert_and_update_no_callback', function(err, collection) { + // Insert the update + collection.insert({i:1}, {safe:true}) + // Update the record + collection.update({i:1}, {"$set":{i:2}}, {safe:true}) + + // Make sure we leave enough time for mongodb to record the data + setTimeout(function() { + // Locate document + collection.findOne({}, function(err, item) { + test.equal(2, item.i) + + client.close(); + test.done(); + }); + }, 100) + }) + }); + }, + + shouldInsertAndQueryTimestamp : function(test) { + client.createCollection('test_insert_and_query_timestamp', function(err, collection) { + // Insert the update + collection.insert({i:client.bson_serializer.Timestamp.fromNumber(100), j:client.bson_serializer.Long.fromNumber(200)}, {safe:true}, function(err, r) { + // Locate document + collection.findOne({}, function(err, item) { + test.ok(item.i instanceof client.bson_serializer.Timestamp); + test.equal(100, item.i); + test.ok(typeof item.j == "number"); + test.equal(200, item.j); + + test.done(); + }); + }) + }) + }, + + shouldCorrectlyInsertAndQueryUndefined : function(test) { + client.createCollection('test_insert_and_query_undefined', function(err, collection) { + // Insert the update + collection.insert({i:undefined}, {safe:true}, function(err, r) { + // Locate document + collection.findOne({}, function(err, item) { + test.equal(null, item.i) + + test.done(); + }); + }) + }) + }, + + shouldCorrectlySerializeDBRefToJSON : function(test) { + var dbref = new client.bson_serializer.DBRef("foo", + client.bson_serializer.ObjectID.createFromHexString("fc24a04d4560531f00000000"), + null); + JSON.stringify(dbref); + test.done(); + }, + + shouldCorrectlyPerformSafeInsert : function(test) { + var fixtures = [{ + name: "empty", array: [], bool: false, dict: {}, float: 0.0, string: "" + }, { + name: "not empty", array: [1], bool: true, dict: {x: "y"}, float: 1.0, string: "something" + }, { + name: "simple nested", array: [1, [2, [3]]], bool: true, dict: {x: "y", array: [1,2,3,4], dict: {x: "y", array: [1,2,3,4]}}, float: 1.5, string: "something simply nested" + }]; + + + client.createCollection('test_safe_insert', function(err, collection) { + Step( + function inserts() { + var group = this.group(); + + for(var i = 0; i < fixtures.length; i++) { + collection.insert(fixtures[i], {safe:true}, group()); + } + }, + + function done() { + collection.count(function(err, count) { + test.equal(3, count); + + collection.find().toArray(function(err, docs) { + test.equal(3, docs.length) + }); + }); + + + collection.find({}, {}, function(err, cursor) { + var counter = 0; + + cursor.each(function(err, doc) { + if(doc == null) { + test.equal(3, counter); + test.done(); + } else { + counter = counter + 1; + } + }); + }); + } + ) + }) + }, + + shouldThrowErrorIfSerializingFunction : function(test) { + client.createCollection('test_should_throw_error_if_serializing_function', function(err, collection) { + // Insert the update + collection.insert({i:1, z:function() { return 1} }, {safe:true}, function(err, result) { + collection.findOne({_id:result[0]._id}, function(err, object) { + test.equal(null, object.z); + test.equal(1, object.i); + + test.done(); + }) + }) + }) + }, + + shouldCorrectlyInsertDocumentWithUUID : function(test) { + client.collection("insert_doc_with_uuid", function(err, collection) { + collection.insert({_id : "12345678123456781234567812345678", field: '1'}, {safe:true}, function(err, result) { + test.equal(null, err); + + collection.find({_id : "12345678123456781234567812345678"}).toArray(function(err, items) { + test.equal(null, err); + test.equal(items[0]._id, "12345678123456781234567812345678") + test.equal(items[0].field, '1') + + // Generate a binary id + var binaryUUID = new client.bson_serializer.Binary('00000078123456781234567812345678', client.bson_serializer.BSON.BSON_BINARY_SUBTYPE_UUID); + + collection.insert({_id : binaryUUID, field: '2'}, {safe:true}, function(err, result) { + collection.find({_id : binaryUUID}).toArray(function(err, items) { + test.equal(null, err); + test.equal(items[0].field, '2') + test.done(); + }); + }); + }) + }); + }); + }, + + shouldCorrectlyCallCallbackWithDbDriverInStrictMode : function(test) { + var db = new Db(MONGODB, new Server('localhost', 27017, {auto_reconnect: true, poolSize: 1}), {strict:true, native_parser: (process.env['TEST_NATIVE'] != null)}); + db.bson_deserializer = client.bson_deserializer; + db.bson_serializer = client.bson_serializer; + db.pkFactory = client.pkFactory; + + db.open(function(err, client) { + client.createCollection('test_insert_and_update_no_callback_strict', function(err, collection) { + collection.insert({_id : "12345678123456781234567812345678", field: '1'}, {safe:true}, function(err, result) { + test.equal(null, err); + + collection.update({ '_id': "12345678123456781234567812345678" }, { '$set': { 'field': 0 }}, function(err, numberOfUpdates) { + test.equal(null, err); + test.equal(1, numberOfUpdates); + + db.close(); + test.done(); + }); + }); + }); + }); + }, + + shouldCorrectlyInsertDBRefWithDbNotDefined : function(test) { + client.createCollection('shouldCorrectlyInsertDBRefWithDbNotDefined', function(err, collection) { + var doc = {_id: new client.bson_serializer.ObjectID()}; + var doc2 = {_id: new client.bson_serializer.ObjectID()}; + var doc3 = {_id: new client.bson_serializer.ObjectID()}; + collection.insert(doc, {safe:true}, function(err, result) { + // Create object with dbref + doc2.ref = new client.bson_serializer.DBRef('shouldCorrectlyInsertDBRefWithDbNotDefined', doc._id); + doc3.ref = new client.bson_serializer.DBRef('shouldCorrectlyInsertDBRefWithDbNotDefined', doc._id, MONGODB); + + collection.insert([doc2, doc3], {safe:true}, function(err, result) { + // Get all items + collection.find().toArray(function(err, items) { + test.equal("shouldCorrectlyInsertDBRefWithDbNotDefined", items[1].ref.namespace); + test.equal(doc._id.toString(), items[1].ref.oid.toString()); + test.equal(null, items[1].ref.db); + + test.equal("shouldCorrectlyInsertDBRefWithDbNotDefined", items[2].ref.namespace); + test.equal(doc._id.toString(), items[2].ref.oid.toString()); + test.equal(MONGODB, items[2].ref.db); + + test.done(); + }) + }); + }); + }); + }, + + shouldCorrectlyInsertUpdateRemoveWithNoOptions : function(test) { + var db = new Db(MONGODB, new Server('localhost', 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + db.bson_deserializer = client.bson_deserializer; + db.bson_serializer = client.bson_serializer; + db.pkFactory = client.pkFactory; + + db.open(function(err, db) { + db.collection('shouldCorrectlyInsertUpdateRemoveWithNoOptions', function(err, collection) { + collection.insert({a:1});//, function(err, result) { + collection.update({a:1}, {a:2});//, function(err, result) { + collection.remove({a:2});//, function(err, result) { + + collection.count(function(err, count) { + test.equal(0, count); + + db.close(); + test.done(); + }) + }); + }); + }, + + shouldCorrectlyExecuteMultipleFetches : function(test) { + var db = new Db(MONGODB, new Server('localhost', 27017, {auto_reconnect: true}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + db.bson_deserializer = client.bson_deserializer; + db.bson_serializer = client.bson_serializer; + db.pkFactory = client.pkFactory; + + // Search parameter + var to = 'ralph' + // Execute query + db.open(function(err, db) { + db.collection('shouldCorrectlyExecuteMultipleFetches', function(err, collection) { + collection.insert({addresses:{localPart:'ralph'}}, {safe:true}, function(err, result) { + // Let's find our user + collection.findOne({"addresses.localPart" : to}, function( err, doc ) { + test.equal(null, err); + test.equal(to, doc.addresses.localPart); + + db.close(); + test.done(); + }); + }); + }); + }); + } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/map_reduce_test.js b/node_modules/mongodb/test/map_reduce_test.js new file mode 100644 index 0000000..a611427 --- /dev/null +++ b/node_modules/mongodb/test/map_reduce_test.js @@ -0,0 +1,299 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldCorrectlyExecuteGroupFunction : function(test) { + client.createCollection('test_group', function(err, collection) { + collection.group([], {}, {"count":0}, "function (obj, prev) { prev.count++; }", function(err, results) { + test.deepEqual([], results); + }); + + collection.group([], {}, {"count":0}, "function (obj, prev) { prev.count++; }", true, function(err, results) { + test.deepEqual([], results); + + // Trigger some inserts + collection.insert([{'a':2}, {'b':5}, {'a':1}], {safe:true}, function(err, ids) { + collection.group([], {}, {"count":0}, "function (obj, prev) { prev.count++; }", function(err, results) { + test.equal(3, results[0].count); + + collection.group([], {}, {"count":0}, "function (obj, prev) { prev.count++; }", true, function(err, results) { + test.equal(3, results[0].count); + + collection.group([], {'a':{'$gt':1}}, {"count":0}, "function (obj, prev) { prev.count++; }", function(err, results) { + test.equal(1, results[0].count); + + collection.group([], {'a':{'$gt':1}}, {"count":0}, "function (obj, prev) { prev.count++; }", true, function(err, results) { + test.equal(1, results[0].count); + + // Insert some more test data + collection.insert([{'a':2}, {'b':3}], {safe:true}, function(err, ids) { + collection.group(['a'], {}, {"count":0}, "function (obj, prev) { prev.count++; }", function(err, results) { + test.equal(2, results[0].a); + test.equal(2, results[0].count); + test.equal(null, results[1].a); + test.equal(2, results[1].count); + test.equal(1, results[2].a); + test.equal(1, results[2].count); + + collection.group({'a':true}, {}, {"count":0}, function (obj, prev) { prev.count++; }, true, function(err, results) { + test.equal(2, results[0].a); + test.equal(2, results[0].count); + test.equal(null, results[1].a); + test.equal(2, results[1].count); + test.equal(1, results[2].a); + test.equal(1, results[2].count); + + collection.group([], {}, {}, "5 ++ 5", function(err, results) { + test.ok(err instanceof Error); + test.ok(err.message != null); + + var keyf = function(doc) { return {a: doc.a}; }; + collection.group(keyf, {a: {$gt: 0}}, {"count": 0, "value": 0}, function(obj, prev) { prev.count++; prev.value += obj.a; }, true, function(err, results) { + results.sort(function(a, b) { return b.count - a.count; }); + test.equal(2, results[0].count); + test.equal(2, results[0].a); + test.equal(4, results[0].value); + test.equal(1, results[1].count); + test.equal(1, results[1].a); + test.equal(1, results[1].value); + + collection.group([], {}, {}, "5 ++ 5", true, function(err, results) { + test.ok(err instanceof Error); + test.ok(err.message != null); + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + // Mapreduce tests functions + shouldPerformSimpleMapReduceFunctions : function(test) { + client.createCollection('test_map_reduce_functions', function(err, collection) { + collection.insert([{'user_id':1}, {'user_id':2}], {safe:true}, function(err, r) { + // String functions + var map = function() { emit(this.user_id, 1); }; + var reduce = function(k,vals) { return 1; }; + + collection.mapReduce(map, reduce, function(err, collection) { + collection.findOne({'_id':1}, function(err, result) { + test.equal(1, result.value); + }); + + collection.findOne({'_id':2}, function(err, result) { + test.equal(1, result.value); + test.done(); + }); + }); + }); + }); + }, + + //map/reduce inline option test + shouldPerformMapReduceFunctionInline : function(test) { + // Parse version of server if available + var version = client.version != null ? parseInt(client.version.replace(/\./g, '')) : 0; + if(version >= 176) { + client.createCollection('test_map_reduce_functions_inline', function(err, collection) { + collection.insert([{'user_id':1}, {'user_id':2}], {safe:true}, function(err, r) { + // String functions + var map = function() { emit(this.user_id, 1); }; + var reduce = function(k,vals) { return 1; }; + + collection.mapReduce(map, reduce, {out : {inline: 1}}, function(err, results) { + test.equal(2, results.length); + test.done(); + }); + }); + }); + } else { + test.done(); + } + }, + + // Mapreduce different test + shouldPerformMapReduceInContext : function(test) { + client.createCollection('test_map_reduce_functions_scope', function(err, collection) { + collection.insert([{'user_id':1, 'timestamp':new Date()}, {'user_id':2, 'timestamp':new Date()}], {safe:true}, function(err, r) { + var map = function(){ + emit(test(this.timestamp.getYear()), 1); + } + + var reduce = function(k, v){ + count = 0; + for(i = 0; i < v.length; i++) { + count += v[i]; + } + return count; + } + + var t = function(val){ return val+1; } + + collection.mapReduce(map, reduce, {scope:{test:new client.bson_serializer.Code(t.toString())}}, function(err, collection) { + collection.find(function(err, cursor) { + cursor.toArray(function(err, results) { + test.equal(2, results[0].value) + test.done(); + }) + }) + }); + }); + }); + }, + + // Mapreduce tests + shouldPerformMapReduceWithStringFunctions : function(test) { + client.createCollection('test_map_reduce', function(err, collection) { + collection.insert([{'user_id':1}, {'user_id':2}], {safe:true}, function(err, r) { + // String functions + var map = "function() { emit(this.user_id, 1); }"; + var reduce = "function(k,vals) { return 1; }"; + + collection.mapReduce(map, reduce, function(err, collection) { + collection.findOne({'_id':1}, function(err, result) { + test.equal(1, result.value); + }); + + collection.findOne({'_id':2}, function(err, result) { + test.equal(1, result.value); + test.done(); + }); + }); + }); + }); + }, + + shouldPerformMapReduceWithParametersBeingFunctions : function(test) { + client.createCollection('test_map_reduce_with_functions_as_arguments', function(err, collection) { + collection.insert([{'user_id':1}, {'user_id':2}], {safe:true}, function(err, r) { + // String functions + var map = function() { emit(this.user_id, 1); }; + var reduce = function(k,vals) { return 1; }; + + collection.mapReduce(map, reduce, function(err, collection) { + collection.findOne({'_id':1}, function(err, result) { + test.equal(1, result.value); + }); + collection.findOne({'_id':2}, function(err, result) { + test.equal(1, result.value); + test.done(); + }); + }); + }); + }); + }, + + shouldPerformMapReduceWithCodeObjects : function(test) { + client.createCollection('test_map_reduce_with_code_objects', function(err, collection) { + collection.insert([{'user_id':1}, {'user_id':2}], {safe:true}, function(err, r) { + // String functions + var map = new client.bson_serializer.Code("function() { emit(this.user_id, 1); }"); + var reduce = new client.bson_serializer.Code("function(k,vals) { return 1; }"); + + collection.mapReduce(map, reduce, function(err, collection) { + collection.findOne({'_id':1}, function(err, result) { + test.equal(1, result.value); + }); + collection.findOne({'_id':2}, function(err, result) { + test.equal(1, result.value); + test.done(); + }); + }); + }); + }); + }, + + shouldPerformMapReduceWithOptions : function(test) { + client.createCollection('test_map_reduce_with_options', function(err, collection) { + collection.insert([{'user_id':1}, {'user_id':2}, {'user_id':3}], {safe:true}, function(err, r) { + // String functions + var map = new client.bson_serializer.Code("function() { emit(this.user_id, 1); }"); + var reduce = new client.bson_serializer.Code("function(k,vals) { return 1; }"); + + collection.mapReduce(map, reduce, {'query': {'user_id':{'$gt':1}}}, function(err, collection) { + collection.count(function(err, count) { + test.equal(2, count); + + collection.findOne({'_id':2}, function(err, result) { + test.equal(1, result.value); + }); + collection.findOne({'_id':3}, function(err, result) { + test.equal(1, result.value); + test.done(); + }); + }); + }); + }); + }); + }, + + shouldHandleMapReduceErrors : function(test) { + client.createCollection('test_map_reduce_error', function(err, collection) { + collection.insert([{'user_id':1}, {'user_id':2}, {'user_id':3}], {safe:true}, function(err, r) { + // String functions + var map = new client.bson_serializer.Code("function() { throw 'error'; }"); + var reduce = new client.bson_serializer.Code("function(k,vals) { throw 'error'; }"); + + collection.mapReduce(map, reduce, {'query': {'user_id':{'$gt':1}}}, function(err, r) { + test.ok(err != null); + test.done(); + }); + }); + }); + }, +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/objectid_test.js b/node_modules/mongodb/test/objectid_test.js new file mode 100644 index 0000000..5d665a9 --- /dev/null +++ b/node_modules/mongodb/test/objectid_test.js @@ -0,0 +1,134 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + // Test the generation of the object ids + shouldCorrectlyGenerateObjectID : function(test) { + var number_of_tests_done = 0; + + client.collection('test_object_id_generation.data', function(err, collection) { + // Insert test documents (creates collections and test fetch by query) + collection.insert({name:"Fred", age:42}, {safe:true}, function(err, ids) { + test.equal(1, ids.length); + test.ok(ids[0]['_id'].toHexString().length == 24); + // Locate the first document inserted + collection.findOne({name:"Fred"}, function(err, document) { + test.equal(ids[0]['_id'].toHexString(), document._id.toHexString()); + number_of_tests_done++; + }); + }); + + // Insert another test document and collect using ObjectId + collection.insert({name:"Pat", age:21}, {safe:true}, function(err, ids) { + test.equal(1, ids.length); + test.ok(ids[0]['_id'].toHexString().length == 24); + // Locate the first document inserted + collection.findOne(ids[0]['_id'], function(err, document) { + test.equal(ids[0]['_id'].toHexString(), document._id.toHexString()); + number_of_tests_done++; + }); + }); + + // Manually created id + var objectId = new client.bson_serializer.ObjectID(null); + // Insert a manually created document with generated oid + collection.insert({"_id":objectId, name:"Donald", age:95}, {safe:true}, function(err, ids) { + test.equal(1, ids.length); + test.ok(ids[0]['_id'].toHexString().length == 24); + test.equal(objectId.toHexString(), ids[0]['_id'].toHexString()); + // Locate the first document inserted + collection.findOne(ids[0]['_id'], function(err, document) { + test.equal(ids[0]['_id'].toHexString(), document._id.toHexString()); + test.equal(objectId.toHexString(), document._id.toHexString()); + number_of_tests_done++; + }); + }); + }); + + var intervalId = setInterval(function() { + if(number_of_tests_done == 3) { + clearInterval(intervalId); + test.done(); + } + }, 100); + }, + + shouldCorrectlyTransformObjectIDToAndFromHexString : function(test) { + var objectId = new client.bson_serializer.ObjectID(null); + var originalHex= objectId.toHexString(); + + var newObjectId= new client.bson_serializer.ObjectID.createFromHexString(originalHex) + newHex= newObjectId.toHexString(); + test.equal(originalHex, newHex); + test.done(); + }, + + // Use some other id than the standard for inserts + shouldCorrectlyCreateOIDNotUsingObjectID : function(test) { + client.createCollection('test_non_oid_id', function(err, collection) { + var date = new Date(); + date.setUTCDate(12); + date.setUTCFullYear(2009); + date.setUTCMonth(11 - 1); + date.setUTCHours(12); + date.setUTCMinutes(0); + date.setUTCSeconds(30); + + collection.insert({'_id':date}, {safe:true}, function(err, ids) { + collection.find({'_id':date}, function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(("" + date), ("" + items[0]._id)); + + // Let's close the db + test.done(); + }); + }); + }); + }); + }, +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/regexp_test.js b/node_modules/mongodb/test/regexp_test.js new file mode 100644 index 0000000..2725d53 --- /dev/null +++ b/node_modules/mongodb/test/regexp_test.js @@ -0,0 +1,105 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + // shouldCorrectlyInsertSimpleRegExpDocument : function(test) { + // var regexp = /foobar/i; + // + // client.createCollection('test_regex', function(err, collection) { + // collection.insert({'b':regexp}, {safe:true}, function(err, ids) { + // collection.find({}, {'fields': ['b']}, function(err, cursor) { + // cursor.toArray(function(err, items) { + // test.equal(("" + regexp), ("" + items[0].b)); + // // Let's close the db + // test.done(); + // }); + // }); + // }); + // }); + // }, + + shouldCorrectlyInsertSimpleUTF8Regexp : function(test) { + var regexp = /foobaré/; + + client.createCollection('test_utf8_regex', function(err, collection) { + collection.insert({'b':regexp}, {safe:true}, function(err, ids) { + collection.find({}, {'fields': ['b']}, function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(("" + regexp), ("" + items[0].b)); + // Let's close the db + test.done(); + }); + }); + }); + }); + }, + + // shouldCorrectlyFindDocumentsByRegExp : function(test) { + // // Serialized regexes contain extra trailing chars. Sometimes these trailing chars contain / which makes + // // the original regex invalid, and leads to segmentation fault. + // client.createCollection('test_regex_serialization', function(err, collection) { + // collection.insert({keywords: ["test", "segmentation", "fault", "regex", "serialization", "native"]}, {safe:true}, function(err, r) { + // + // var count = 20, + // run = function(i) { + // // search by regex + // collection.findOne({keywords: {$all: [/ser/, /test/, /seg/, /fault/, /nat/]}}, function(err, item) { + // test.equal(6, item.keywords.length); + // if (i === 0) { + // test.done() + // } + // }); + // }; + // // loop a few times to catch the / in trailing chars case + // while (count--) { + // run(count); + // } + // }); + // }); + // } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/remove_test.js b/node_modules/mongodb/test/remove_test.js new file mode 100644 index 0000000..8666247 --- /dev/null +++ b/node_modules/mongodb/test/remove_test.js @@ -0,0 +1,74 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + // Test clearing out of the collection + shouldCorrectlyClearOutCollection : function(test) { + client.createCollection('test_clear', function(err, r) { + client.collection('test_clear', function(err, collection) { + collection.insert({i:1}, {safe:true}, function(err, ids) { + collection.insert({i:2}, {safe:true}, function(err, ids) { + collection.count(function(err, count) { + test.equal(2, count); + // Clear the collection + collection.remove({}, {safe:true}, function(err, result) { + test.equal(2, result); + + collection.count(function(err, count) { + test.equal(0, count); + // Let's close the db + test.done(); + }); + }); + }); + }); + }); + }); + }); + } +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/replicaset/connect_test.js b/node_modules/mongodb/test/replicaset/connect_test.js new file mode 100644 index 0000000..ace4676 --- /dev/null +++ b/node_modules/mongodb/test/replicaset/connect_test.js @@ -0,0 +1,323 @@ +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + ReplicaSetManager = require('../tools/replica_set_manager').ReplicaSetManager, + Db = require('../../lib/mongodb').Db, + ReplSetServers = require('../../lib/mongodb').ReplSetServers, + Server = require('../../lib/mongodb').Server; + +// Keep instance of ReplicaSetManager +var serversUp = false; +var retries = 120; + +var ensureConnection = function(test, numberOfTries, callback) { + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + if(numberOfTries <= 0) return callback(new Error("could not connect correctly"), null); + + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + if(err != null) { + db.close(); + // Wait for a sec and retry + setTimeout(function() { + numberOfTries = numberOfTries - 1; + ensureConnection(test, numberOfTries, callback); + }, 1000); + } else { + return callback(null, p_db); + } + }) +} + +module.exports = testCase({ + setUp: function(callback) { + // Create instance of replicaset manager but only for the first call + if(!serversUp) { + serversUp = true; + RS = new ReplicaSetManager(); + RS.startSet(true, function(err, result) { + callback(); + }); + } else { + RS.restartKilledNodes(function(err, result) { + callback(); + }) + } + }, + + tearDown: function(callback) { + RS.restartKilledNodes(function(err, result) { + callback(); + }) + }, + + shouldCorrectlyConnectWithDefaultReplicaset : function(test) { + // Replica configuration + var replSet = new ReplSetServers([ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {} + ); + + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + test.equal(null, err); + test.done(); + }) + }, + + shouldEmitCloseNoCallback : function(test) { + // Replica configuration + var replSet = new ReplSetServers([ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], {} + ); + + new Db('integration_test_', replSet).open(function(err, db) { + test.equal(null, err); + var dbCloseCount = 0, serverCloseCount = 0; + db.on('close', function() { ++dbCloseCount; }); + db.serverConfig.servers.forEach(function(server) { + server.connection.on('close', function() { ++serverCloseCount; }); + }); + db.close(); + setTimeout(function() { + test.equal(dbCloseCount, 1); + test.equal(serverCloseCount, db.serverConfig.servers.length); + test.done(); + }, 250); + }) + }, + + shouldEmitCloseWithCallback : function(test) { + // Replica configuration + var replSet = new ReplSetServers([ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], {} + ); + + new Db('integration_test_', replSet).open(function(err, db) { + test.equal(null, err); + var dbCloseCount = 0, serverCloseCount = 0; + db.on('close', function() { ++dbCloseCount; }); + var connection = db.serverConfig.connection; + db.serverConfig.servers.forEach(function(server) { + server.connection.on('close', function() { ++serverCloseCount; }); + }); + db.close(function() { + // Let all events fire. + process.nextTick(function() { + test.equal(dbCloseCount, 1); + test.equal(serverCloseCount, db.serverConfig.servers.length); + test.done(); + }); + }); + }) + }, + + shouldCorrectlyPassErrorWhenWrongReplicaSet : function(test) { + // Replica configuration + var replSet = new ReplSetServers([ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name + "-wrong"} + ); + + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + test.notEqual(null, err); + test.done(); + }) + }, + + shouldConnectWithPrimarySteppedDown : function(test) { + // debug("=========================================== shouldConnectWithPrimarySteppedDown") + // Step down primary server + RS.stepDownPrimary(function(err, result) { + // Wait for new primary to pop up + ensureConnection(test, retries, function(err, p_db) { + if(err != null) debug("shouldConnectWithPrimarySteppedDown :: " + inspect(err)); + test.ok(err == null); + test.equal(true, p_db.serverConfig.isConnected()); + + p_db.close(); + test.done(); + }); + }); + }, + + shouldConnectWithThirdNodeKilled : function(test) { + // debug("=========================================== shouldConnectWithThirdNodeKilled") + RS.getNodeFromPort(RS.ports[2], function(err, node) { + if(err != null) debug("shouldConnectWithThirdNodeKilled :: " + inspect(err)); + + RS.kill(node, function(err, result) { + if(err != null) debug("shouldConnectWithThirdNodeKilled :: " + inspect(err)); + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + // Wait for new primary to pop up + ensureConnection(test, retries, function(err, p_db) { + if(err != null) debug("shouldConnectWithThirdNodeKilled :: " + inspect(err)); + test.ok(err == null); + test.equal(true, p_db.serverConfig.isConnected()); + + p_db.close(); + test.done(); + }); + }); + }); + }, + + shouldConnectWithSecondaryNodeKilled : function(test) { + // debug("=========================================== shouldConnectWithSecondaryNodeKilled") + RS.killSecondary(function(node) { + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + if(err != null) debug("shouldConnectWithSecondaryNodeKilled :: " + inspect(err)); + test.ok(err == null); + test.equal(true, p_db.serverConfig.isConnected()); + + // Close and cleanup + db.close(); + test.done(); + }) + }); + }, + + shouldConnectWithPrimaryNodeKilled : function(test) { + // debug("=========================================== shouldConnectWithPrimaryNodeKilled") + RS.killPrimary(function(node) { + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + var db = new Db('integration_test_', replSet); + ensureConnection(test, retries, function(err, p_db) { + if(err != null) debug("shouldConnectWithPrimaryNodeKilled :: " + inspect(err)); + test.ok(err == null); + test.equal(true, p_db.serverConfig.isConnected()); + + p_db.close(); + test.done(); + }); + // }) + }); + }, + + shouldCorrectlyBeAbleToUsePortAccessors : function(test) { + // debug("=========================================== shouldCorrectlyBeAbleToUsePortAccessors") + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + if(err != null) debug("shouldCorrectlyBeAbleToUsePortAccessors :: " + inspect(err)); + test.equal(replSet.host, p_db.serverConfig.primary.host); + test.equal(replSet.port, p_db.serverConfig.primary.port); + + db.close(); + test.done(); + }) + }, + + shouldCorrectlyConnect: function(test) { + // debug("=========================================== shouldCorrectlyConnect") + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + var db = new Db('integration_test_', replSet ); + db.open(function(err, p_db) { + if(err != null) debug("shouldCorrectlyConnect :: " + inspect(err)); + test.equal(true, p_db.serverConfig.isConnected()); + + // Test primary + RS.primary(function(err, primary) { + if(err != null) debug("shouldCorrectlyConnect :: " + inspect(err)); + + test.notEqual(null, primary); + test.equal(primary, p_db.serverConfig.primary.host + ":" + p_db.serverConfig.primary.port); + + // Perform tests + RS.secondaries(function(err, items) { + if(err != null) debug("shouldCorrectlyConnect :: " + inspect(err)); + + // Test if we have the right secondaries + test.deepEqual(items.sort(), p_db.serverConfig.secondaries.map(function(item) { + return item.host + ":" + item.port; + }).sort()); + + // Test if we have the right arbiters + RS.arbiters(function(err, items) { + if(err != null) debug("shouldCorrectlyConnect :: " + inspect(err)); + + test.deepEqual(items.sort(), p_db.serverConfig.arbiters.map(function(item) { + return item.host + ":" + item.port; + }).sort()); + + // Force new instance + var db2 = new Db('integration_test_', replSet ); + db2.open(function(err, p_db2) { + if(err != null) debug("shouldCorrectlyConnect :: " + inspect(err)); + + test.equal(true, p_db2.serverConfig.isConnected()); + + // Close top instance + db.close(); + db2.close(); + test.done(); + }); + }); + }); + }) + }); + }, +}) diff --git a/node_modules/mongodb/test/replicaset/count_test.js b/node_modules/mongodb/test/replicaset/count_test.js new file mode 100644 index 0000000..c5d9163 --- /dev/null +++ b/node_modules/mongodb/test/replicaset/count_test.js @@ -0,0 +1,174 @@ +var noReplicasetStart = process.env['NO_REPLICASET_START'] != null ? true : false; + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + ReplicaSetManager = require('../tools/replica_set_manager').ReplicaSetManager, + Db = require('../../lib/mongodb').Db, + ReplSetServers = require('../../lib/mongodb').ReplSetServers, + Server = require('../../lib/mongodb').Server; + +// Keep instance of ReplicaSetManager +var serversUp = false; +var retries = 120; + +var ensureConnection = function(test, numberOfTries, callback) { + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + if(numberOfTries <= 0) return callback(new Error("could not connect correctly"), null); + + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + if(err != null) { + db.close(); + // Wait for a sec and retry + setTimeout(function() { + numberOfTries = numberOfTries - 1; + ensureConnection(test, numberOfTries, callback); + }, 1000); + } else { + return callback(null, p_db); + } + }) +} + +module.exports = testCase({ + setUp: function(callback) { + // Create instance of replicaset manager but only for the first call + if(!serversUp && !noReplicasetStart) { + serversUp = true; + RS = new ReplicaSetManager(); + RS.startSet(true, function(err, result) { + if(err != null) throw err; + // Finish setup + callback(); + }); + } else { + RS.restartKilledNodes(function(err, result) { + if(err != null) throw err; + callback(); + }) + } + }, + + tearDown: function(callback) { + RS.restartKilledNodes(function(err, result) { + if(err != null) throw err; + callback(); + }) + }, + + shouldRetrieveCorrectCountAfterInsertionReconnect : function(test) { + // debug("=========================================== shouldRetrieveCorrectCountAfterInsertionReconnect") + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + // Insert some data + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + // debug("====================================================== 1") + if(err != null) debug("shouldRetrieveCorrectCountAfterInsertionReconnect :: " + inspect(err)); + // Drop collection on replicaset + p_db.dropCollection('testsets', function(err, r) { + // debug("====================================================== 2") + if(err != null) debug("shouldRetrieveCorrectCountAfterInsertionReconnect :: " + inspect(err)); + + // Recreate collection on replicaset + p_db.createCollection('testsets', function(err, collection) { + // debug("====================================================== 3") + if(err != null) debug("shouldRetrieveCorrectCountAfterInsertionReconnect :: " + inspect(err)); + + // Insert a dummy document + collection.insert({a:20}, {safe: {w:2, wtimeout: 10000}}, function(err, r) { + // debug("====================================================== 4") + if(err != null) debug("shouldRetrieveCorrectCountAfterInsertionReconnect :: " + inspect(err)); + + // Execute a count + collection.count(function(err, c) { + // debug("====================================================== 5") + if(err != null) debug("shouldRetrieveCorrectCountAfterInsertionReconnect :: " + inspect(err)); + + test.equal(1, c); + // Close starting connection + p_db.close(); + + // Ensure replication happened in time + setTimeout(function() { + // Kill the primary + RS.killPrimary(function(node) { + // debug("====================================================== 6") + + // Ensure valid connection + // Do inserts + ensureConnection(test, retries, function(err, p_db) { + // debug("====================================================== 7") + if(err != null) debug("shouldRetrieveCorrectCountAfterInsertionReconnect :: " + inspect(err)); + + test.ok(err == null); + test.equal(true, p_db.serverConfig.isConnected()); + + p_db.collection('testsets', function(err, collection) { + // debug("====================================================== 8") + if(err != null) debug("shouldRetrieveCorrectCountAfterInsertionReconnect :: " + inspect(err)); + + collection.insert({a:30}, {safe:true}, function(err, r) { + // debug("====================================================== 9") + if(err != null) debug("shouldRetrieveCorrectCountAfterInsertionReconnect :: " + inspect(err)); + + collection.insert({a:40}, {safe:true}, function(err, r) { + // debug("====================================================== 10") + if(err != null) debug("shouldRetrieveCorrectCountAfterInsertionReconnect :: " + inspect(err)); + + // Execute count + collection.count(function(err, c) { + // debug("====================================================== 11") + if(err != null) debug("shouldRetrieveCorrectCountAfterInsertionReconnect :: " + inspect(err)); + + test.equal(3, c); + + p_db.close(); + test.done(); + }); + }); + }); + }); + }); + }); + }, 2000); + }) + }) + }); + }); + }) + } +}) + + + + + + + + + + + + + + + + + diff --git a/node_modules/mongodb/test/replicaset/insert_test.js b/node_modules/mongodb/test/replicaset/insert_test.js new file mode 100644 index 0000000..b29963b --- /dev/null +++ b/node_modules/mongodb/test/replicaset/insert_test.js @@ -0,0 +1,335 @@ +var noReplicasetStart = process.env['NO_REPLICASET_START'] != null ? true : false; + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + ReplicaSetManager = require('../tools/replica_set_manager').ReplicaSetManager, + Db = require('../../lib/mongodb').Db, + ReplSetServers = require('../../lib/mongodb').ReplSetServers, + Server = require('../../lib/mongodb').Server, + Step = require("../../deps/step/lib/step"); + +// Keep instance of ReplicaSetManager +var serversUp = false; +var retries = 120; +// var RS = null; + +var ensureConnection = function(test, numberOfTries, callback) { + // debug("=========================================== ensureConnection::" + numberOfTries) + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + if(numberOfTries <= 0) return callback(new Error("could not connect correctly"), null); + + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + if(err != null) { + db.close(); + // Wait for a sec and retry + setTimeout(function() { + numberOfTries = numberOfTries - 1; + ensureConnection(test, numberOfTries, callback); + }, 1000); + } else { + return callback(null, p_db); + } + }) +} + +module.exports = testCase({ + setUp: function(callback) { + // Create instance of replicaset manager but only for the first call + if(!serversUp && !noReplicasetStart) { + serversUp = true; + // RS = new ReplicaSetManager({retries:120, arbiter_count:0, passive_count:1}); + RS = new ReplicaSetManager({retries:120}); + RS.startSet(true, function(err, result) { + if(err != null) throw err; + // Finish setup + callback(); + }); + } else { + RS.restartKilledNodes(function(err, result) { + if(err != null) throw err; + callback(); + }) + } + }, + + tearDown: function(callback) { + RS.restartKilledNodes(function(err, result) { + if(err != null) throw err; + callback(); + }) + }, + + shouldCorrectlyInsertAfterPrimaryComesBackUp : function(test) { + // debug("=========================================== shouldWorkCorrectlyWithInserts") + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + // Insert some data + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + // Check if we got an error + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + // Drop collection on replicaset + p_db.dropCollection('testsets', function(err, r) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + // Recreate collection on replicaset + p_db.createCollection('testsets', function(err, collection) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + // Insert a dummy document + collection.insert({a:20}, {safe: {w:2, wtimeout: 10000}}, function(err, r) { + // Kill the primary and attemp to insert + // Ensure replication happened in time + setTimeout(function() { + // Kill the primary + RS.killPrimary(function(node) { + // Attempt insert (should fail) + collection.insert({a:30}, {safe: {w:2, wtimeout: 10000}}, function(err, r) { + if(err != null) { + collection.insert({a:30}, {safe: true}, function(err, r) { + // Peform a count + collection.count(function(err, count) { + test.equal(2, count); + test.done(); + }); + }); + } + }); + }); + }, 2000); + }); + }); + }); + }); + }, + + shouldCorrectlyQueryAfterPrimaryComesBackUp : function(test) { + // debug("=========================================== shouldWorkCorrectlyWithInserts") + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + // Insert some data + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + // Check if we got an error + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + // Drop collection on replicaset + p_db.dropCollection('testsets', function(err, r) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + // Recreate collection on replicaset + p_db.createCollection('testsets', function(err, collection) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + // Insert a dummy document + collection.insert({a:20}, {safe: {w:2, wtimeout: 10000}}, function(err, r) { + // Kill the primary and attemp to insert + // Ensure replication happened in time + setTimeout(function() { + // Kill the primary + RS.killPrimary(function(node) { + // Ok let's execute same query a couple of times + collection.find({}).toArray(function(err, items) { + test.ok(err != null); + + // debug(" 1 =============================== err :: " + inspect(err)) + // debug(inspect(items)) + + collection.find({}).toArray(function(err, items) { + // debug(" 2 =============================== err :: " + inspect(err)) + // debug(inspect(items)) + + test.ok(err == null); + test.equal(1, items.length); + + collection.find({}).toArray(function(err, items) { + // debug(" 2 =============================== err :: " + inspect(err)) + // debug(inspect(items)) + + test.ok(err == null); + test.equal(1, items.length); + + test.done(); + }); + }); + }); + }); + }, 2000); + }); + }); + }); + }); + }, + + shouldWorkCorrectlyWithInserts : function(test) { + // debug("=========================================== shouldWorkCorrectlyWithInserts") + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name} + ); + + // Insert some data + var db = new Db('integration_test_', replSet); + db.open(function(err, p_db) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + // Drop collection on replicaset + p_db.dropCollection('testsets', function(err, r) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + // Recreate collection on replicaset + p_db.createCollection('testsets', function(err, collection) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + // Insert a dummy document + collection.insert({a:20}, {safe: {w:2, wtimeout: 10000}}, function(err, r) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + // Execute a count + collection.count(function(err, c) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + test.equal(1, c); + // Close starting connection + p_db.close(); + + // Ensure replication happened in time + setTimeout(function() { + // Kill the primary + RS.killPrimary(function(node) { + + // Ensure valid connection + // Do inserts + ensureConnection(test, retries, function(err, p_db) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + test.ok(err == null); + test.equal(true, p_db.serverConfig.isConnected()); + + p_db.collection('testsets', function(err, collection) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + // Execute a set of inserts + Step( + function inserts() { + var group = this.group(); + collection.save({a:30}, {safe:true}, group()); + collection.save({a:40}, {safe:true}, group()); + collection.save({a:50}, {safe:true}, group()); + collection.save({a:60}, {safe:true}, group()); + collection.save({a:70}, {safe:true}, group()); + }, + + function finishUp(err, values) { + // Restart the old master and wait for the sync to happen + RS.restartKilledNodes(function(err, result) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + if(err != null) throw err; + // Contains the results + var results = []; + + // Just wait for the results + setTimeout(function() { + + // Ensure the connection + ensureConnection(test, retries, function(err, p_db) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + // Get the collection + p_db.collection('testsets', function(err, collection) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + collection.find().each(function(err, item) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + if(item == null) { + // Ensure we have the correct values + test.equal(6, results.length); + [20, 30, 40, 50, 60, 70].forEach(function(a) { + test.equal(1, results.filter(function(element) { + return element.a == a; + }).length); + }); + + // Run second check + collection.save({a:80}, {safe:true}, function(err, r) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + collection.find().toArray(function(err, items) { + if(err != null) debug("shouldWorkCorrectlyWithInserts :: " + inspect(err)); + + // Ensure we have the correct values + test.equal(7, items.length); + + [20, 30, 40, 50, 60, 70, 80].forEach(function(a) { + test.equal(1, items.filter(function(element) { + return element.a == a; + }).length); + }); + + p_db.close(); + test.done(); + }); + }); + } else { + results.push(item); + } + }); + }); + }); + }, 1000); + }) + } + ); + }); + }); + }); + }, 2000); + }) + }) + }); + }); + }) + } +}) + + + + + + + + + + + + + + + + + diff --git a/node_modules/mongodb/test/replicaset/query_secondaries_test.js b/node_modules/mongodb/test/replicaset/query_secondaries_test.js new file mode 100644 index 0000000..fea93bd --- /dev/null +++ b/node_modules/mongodb/test/replicaset/query_secondaries_test.js @@ -0,0 +1,248 @@ +var noReplicasetStart = process.env['NO_REPLICASET_START'] != null ? true : false; + +var testCase = require('../../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + ReplicaSetManager = require('../tools/replica_set_manager').ReplicaSetManager, + Db = require('../../lib/mongodb').Db, + ReplSetServers = require('../../lib/mongodb').ReplSetServers, + Server = require('../../lib/mongodb').Server, + Step = require("../../deps/step/lib/step"); + +// Keep instance of ReplicaSetManager +var serversUp = false; +var retries = 120; +// var RS = null; + +var ensureConnection = function(test, numberOfTries, callback) { + // Replica configuration + var replSet = new ReplSetServers( [ + // new Server( RS.host, RS.ports[1], { auto_reconnect: true } ), + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + // new Server( RS.host, RS.ports[2], { auto_reconnect: true } ) + ], + {rs_name:RS.name, read_secondary:true} + ); + + if(numberOfTries <= 0) return callback(new Error("could not connect correctly"), null); + + var db = new Db('ruby-test-db', replSet); + db.open(function(err, p_db) { + if(err != null) { + db.close(); + // Wait for a sec and retry + setTimeout(function() { + numberOfTries = numberOfTries - 1; + ensureConnection(test, numberOfTries, callback); + }, 1000); + } else { + return callback(null, p_db); + } + }) +} + +module.exports = testCase({ + setUp: function(callback) { + // Create instance of replicaset manager but only for the first call + if(!serversUp && !noReplicasetStart) { + serversUp = true; + RS = new ReplicaSetManager(); + RS.startSet(true, function(err, result) { + if(err != null) throw err; + // Finish setup + callback(); + }); + } else { + RS.restartKilledNodes(function(err, result) { + if(err != null) throw err; + callback(); + }) + } + }, + + tearDown: function(callback) { + RS.restartKilledNodes(function(err, result) { + if(err != null) throw err; + callback(); + }) + }, + + // shouldReadPrimary : function(test) { + // // debug("=========================================== shouldReadPrimary") + // // Replica configuration + // var replSet = new ReplSetServers( [ + // new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + // ], + // {rs_name:RS.name, read_secondary:true} + // ); + // + // // Insert some data + // var db = new Db('integration_test_', replSet); + // db.open(function(err, p_db) { + // if(err != null) debug("shouldReadPrimary :: " + inspect(err)); + // // Drop collection on replicaset + // p_db.dropCollection('testsets', function(err, r) { + // if(err != null) debug("shouldReadPrimary :: " + inspect(err)); + // + // test.equal(false, p_db.serverConfig.isReadPrimary()); + // test.equal(false, p_db.serverConfig.isPrimary()); + // test.done(); + // }); + // }) + // }, + // + // shouldCorrectlyTestConnection : function(test) { + // // debug("=========================================== shouldCorrectlyTestConnection") + // // Replica configuration + // var replSet = new ReplSetServers( [ + // new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + // ], + // {rs_name:RS.name, read_secondary:true} + // ); + // + // // Insert some data + // var db = new Db('integration_test_', replSet); + // db.open(function(err, p_db) { + // if(err != null) debug("shouldReadPrimary :: " + inspect(err)); + // + // // Drop collection on replicaset + // p_db.dropCollection('testsets', function(err, r) { + // if(err != null) debug("shouldReadPrimary :: " + inspect(err)); + // + // test.ok(p_db.serverConfig.primary != null); + // test.ok(p_db.serverConfig.read != null); + // test.ok(p_db.serverConfig.primary.port != p_db.serverConfig.read.port); + // test.done(); + // }); + // }) + // }, + + shouldCorrectlyQuerySecondaries : function(test) { + // debug("=========================================== shouldCorrectlyQuerySecondaries") + var self = this; + // Replica configuration + var replSet = new ReplSetServers( [ + new Server( RS.host, RS.ports[0], { auto_reconnect: true } ), + ], + {rs_name:RS.name, read_secondary:true} + ); + + // Insert some data + var db = new Db('ruby-test-db', replSet); + db.open(function(err, p_db) { + if(err != null) debug("shouldReadPrimary :: " + inspect(err)); + + p_db.createCollection("test-sets", {safe:{w:3, wtimeout:10000}}, function(err, collection) { + if(err != null) debug("shouldReadPrimary :: " + inspect(err)); + + Step( + function inserts() { + var group = this.group(); + collection.save({a:20}, group()); + collection.save({a:30}, group()); + collection.save({a:40}, group()); + }, + + function done(err, values) { + if(err != null) debug("shouldReadPrimary :: " + inspect(err)); + var results = []; + + retryEnsure(60, function(done) { + results = []; + + collection.find().each(function(err, item) { + if(item == null) { + var correct = 0; + // Check all the values + var r = [20, 30, 40]; + for(var i = 0; i < r.length; i++) { + correct += results.filter(function(element) { + return element.a == r[i]; + }).length; + } + return correct == 3 ? done(true) : done(false); + } else { + results.push(item); + } + }); + }, function(err, result) { + if(err != null) debug("shouldReadPrimary :: " + inspect(err)); + test.ifError(err); + + // Ensure replication happened in time + setTimeout(function() { + // Kill the primary + RS.killPrimary(function(node) { + + // + // Retry again to read the docs with primary dead + retryEnsure(60, function(done) { + results = []; + + collection.find().each(function(err, item) { + if(err != null) debug("shouldReadPrimary :: " + inspect(err)); + + if(item == null) { + var correct = 0; + // Check all the values + var r = [20, 30, 40]; + for(var i = 0; i < r.length; i++) { + correct += results.filter(function(element) { + return element.a == r[i]; + }).length; + } + return correct == 3 ? done(true) : done(false); + } else { + results.push(item); + } + }); + }, function(err, result) { + test.ifError(err); + + test.done(); + p_db.close(); + }) + }); + }, 2000); + }) + } + ); + }); + }) + } +}) + +var retryEnsure = function(numberOfRetries, execute, callback) { + execute(function(done) { + if(done) { + return callback(null, null); + } else { + numberOfRetries = numberOfRetries - 1; + + if(numberOfRetries <= 0) { + return callback(new Error("Failed to execute command"), null); + } else { + setTimeout(function() { + retryEnsure(numberOfRetries, execute, callback); + }, 1000); + } + } + }); +} + + + + + + + + + + + + + + + + + diff --git a/node_modules/mongodb/test/streaming_test.js b/node_modules/mongodb/test/streaming_test.js new file mode 100644 index 0000000..c308644 --- /dev/null +++ b/node_modules/mongodb/test/streaming_test.js @@ -0,0 +1,121 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldStreamRecordsCallsDataTheRightNumberOfTimes : function(test) { + client.createCollection('test_stream_records', function(err, collection) { + test.ok(collection instanceof Collection); + collection.insert([{'a':1}, {'b' : 2}, {'c' : 3}, {'d' : 4}, {'e' : 5}], {safe:true}, function(err, ids) { + var stream = collection.find({}, {'limit' : 3}).streamRecords(); + var callsToEnd = 0; + stream.on('end', function() { + test.done(); + }); + + var callsToData = 0; + stream.on('data',function(data){ + callsToData += 1; + test.ok(callsToData <= 3); + }); + }); + }); + }, + + shouldStreamRecordsCallsEndTheRightNumberOfTimes : function(test) { + client.createCollection('test_stream_records', function(err, collection) { + test.ok(collection instanceof Collection); + collection.insert([{'a':1}, {'b' : 2}, {'c' : 3}, {'d' : 4}, {'e' : 5}], {safe:true}, function(err, ids) { + collection.find({}, {'limit' : 3}, function(err, cursor) { + var stream = cursor.streamRecords(function(er,item) {}); + var callsToEnd = 0; + stream.on('end', function() { + callsToEnd += 1; + test.equal(1, callsToEnd); + setTimeout(function() { + // Let's close the db + if (callsToEnd == 1) { + test.done(); + } + }.bind(this), 1000); + }); + + stream.on('data',function(data){ /* nothing here */ }); + }); + }); + }); + }, + + shouldStreamDocumentsWithLimitForFetching : function(test) { + var docs = [] + + for(var i = 0; i < 3000; i++) { + docs.push({'a':i}) + } + + client.createCollection('test_streaming_function_with_limit_for_fetching', function(err, collection) { + test.ok(collection instanceof Collection); + + collection.insertAll(docs, {safe:true}, function(err, ids) { + collection.find({}, function(err, cursor) { + // Execute find on all the documents + var stream = cursor.streamRecords({fetchSize:1000}); + var callsToEnd = 0; + stream.on('end', function() { + test.done(); + }); + + var callsToData = 0; + stream.on('data',function(data){ + callsToData += 1; + test.ok(callsToData <= 3000); + }); + }); + }); + }); + }, +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/test/tools/keyfile.txt b/node_modules/mongodb/test/tools/keyfile.txt new file mode 100644 index 0000000..f15d680 --- /dev/null +++ b/node_modules/mongodb/test/tools/keyfile.txt @@ -0,0 +1 @@ +THIS IS A SECRET KEYFILE FOR REPLICA SETS BWAHAHAHAH diff --git a/node_modules/mongodb/test/tools/replica_set_manager.js b/node_modules/mongodb/test/tools/replica_set_manager.js new file mode 100644 index 0000000..52f5f9f --- /dev/null +++ b/node_modules/mongodb/test/tools/replica_set_manager.js @@ -0,0 +1,522 @@ +var debug = require('util').debug, + inspect = require('util').inspect, + path = require('path'), + fs = require('fs'), + exec = require('child_process').exec, + spawn = require('child_process').spawn, + Connection = require('../../lib/mongodb').Connection, + Db = require('../../lib/mongodb').Db, + Server = require('../../lib/mongodb').Server, + Step = require("../../deps/step/lib/step"); + +var ReplicaSetManager = exports.ReplicaSetManager = function(options) { + options = options == null ? {} : options; + + this.startPort = options["start_port"] || 30000; + this.ports = []; + this.name = options["name"] != null ? options["name"] : "replica-set-foo"; + this.host = options["host"] != null ? options["host"] : "localhost"; + this.retries = options["retries"] != null ? options["retries"] : 60; + this.config = {"_id": this.name, "members": []}; + this.durable = options["durable"] != null ? options["durable"] : false; + this.auth = options['auth'] != null ? options['auth'] : false; + this.path = path.resolve("data"); + + this.arbiterCount = options["arbiter_count"] != null ? options["arbiter_count"] : 2; + this.secondaryCount = options["secondary_count"] != null ? options["secondary_count"] : 1; + this.passiveCount = options["passive_count"] != null ? options["passive_count"] : 1; + this.primaryCount = 1; + this.keyPath = [process.cwd(), "test", "tools", "keyfile.txt"].join("/"); + fs.chmodSync(this.keyPath, 0600); + + this.count = this.primaryCount + this.passiveCount + this.arbiterCount + this.secondaryCount; + if(this.count > 7) { + throw new Error("Cannot create a replica set with #{node_count} nodes. 7 is the max."); + } + + this.mongods = {}; + var self = this; + + // Add a handler for errors that bubble up all the way + // process.on('uncaughtException', function (err) { + // debug("============================================================= uncaught Exception") + // debug(inspect(err)) + // // Kill all mongod servers and cleanup before exiting + // self.killAll(function() { + // // Force exit + // process.exit(); + // }) + // }); +} + +ReplicaSetManager.prototype.secondaries = function(callback) { + return this.allHostPairsWithState(2, callback); +} + +ReplicaSetManager.prototype.arbiters = function(callback) { + return this.allHostPairsWithState(7, callback); +} + +ReplicaSetManager.prototype.primary = function(callback) { + return this.allHostPairsWithState(1, function(err, items) { + if(items.length == 0) { + return callback(null, null); + } else { + return callback(null, items[0]); + } + }); +} + +ReplicaSetManager.prototype.allHostPairsWithState = function(state, callback) { + this.ensureUp(function(err, status) { + if(err != null) return callback(err, null); + + var members = status["members"]; + // Get the correct state memebers + var nodes = members.filter(function(value) { + return value["state"] == state; + }); + + // Filter out address of the server + var servers = nodes.map(function(item) { + return item["name"]; + }); + + // Map nodes + return callback(null, servers); + }) +} + +ReplicaSetManager.prototype.startSet = function(killall, callback) { + var self = this; + // Unpack callback and variables + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + killall = args.length ? args.shift() : true; + + debug("** Starting a replica set with " + this.count + " nodes"); + + // Kill all existing mongod instances + exec(killall ? 'killall mongod' : '', function(err, stdout, stderr) { + var n = 0; + + Step( + function startPrimaries() { + var group = this.group(); + // Start primary instances + for(n = 0; n < (self.primaryCount + self.secondaryCount); n++) { + self.initNode(n, {}, group()); + } + + // Start passive instances + for(var i = 0; i < self.passiveCount; i++) { + self.initNode(n, {priority:0}, group()) + n = n + 1; + } + + // Start arbiter instances + for(var i = 0; i < self.arbiterCount; i++) { + self.initNode(n, {arbiterOnly:true}, group()); + n = n + 1; + } + }, + + function finishUp(err, values) { + self.numberOfInitiateRetries = 0; + // Initiate + self.initiate(function(err, result) { + if(err != null) return callback(err, null); + self.ensureUpRetries = 0; + + // Ensure all the members are up + // process.stdout.write("** Ensuring members are up..."); + debug("** Ensuring members are up..."); + // Let's ensure everything is up + self.ensureUp(function(err, result) { + if(err != null) return callback(err, null); + // Return a correct result + callback(null, result); + }) + }); + } + ); + }) +} + +ReplicaSetManager.prototype.initiate = function(callback) { + var self = this; + // Get master connection + self.getConnection(function(err, connection) { + if(err != null) return callback(err, null); + // debug("=================================================== replicaset config") + // debug(inspect(self.config)) + + // Set replica configuration + connection.admin().command({replSetInitiate:self.config}, function(err, result) { + // If we have an error let's + if(err != null) { + // Retry a number of times + if(self.numberOfInitiateRetries < self.retries) { + setTimeout(function() { + self.numberOfInitiateRetries = self.numberOfInitiateRetries + 1; + self.initiate(callback); + }, 1000); + } + } else { + self.numberOfInitiateRetries = 0; + callback(null, null); + } + }); + }); +} + +// Get absolute path +var getPath = function(self, name) { + return path.join(self.path, name); +} + +ReplicaSetManager.prototype.initNode = function(n, fields, callback) { + var self = this; + this.mongods[n] = this.mongods[n] == null ? {} : this.mongods[n]; + var port = this.startPort + n; + this.ports.push(port); + this.mongods[n]["port"] = port; + this.mongods[n]["db_path"] = getPath(this, "rs-" + port); + this.mongods[n]["log_path"] = getPath(this, "log-" + port); + this.up = false; + + // Add extra fields provided + for(var name in fields) { + this.mongods[n][name] = fields[name]; + } + + // debug("================================================== initNode") + // debug(inspect(this.mongods[n])); + + // Perform cleanup of directories + exec("rm -rf " + self.mongods[n]["db_path"], function(err, stdout, stderr) { + // debug("======================================== err1::" + err) + + if(err != null) return callback(err, null); + + // Create directory + exec("mkdir -p " + self.mongods[n]["db_path"], function(err, stdout, stderr) { + // debug("======================================== err2::" + err) + + if(err != null) return callback(err, null); + + // debug("= ======================================= start1::" + self.mongods[n]["start"]) + + self.mongods[n]["start"] = self.startCmd(n); + self.start(n, function() { + // Add instance to list of members + var member = {"_id": n, "host": self.host + ":" + self.mongods[n]["port"]}; + if(self.mongods[n]['arbiterOnly']) { + member['arbiterOnly'] = true; + } + self.config["members"].push(member); + // Return + return callback(); + }); + }); + }); +} + +ReplicaSetManager.prototype.killAll = function(callback) { + exec('killall mongod', function(err, stdout, stderr) { + return callback(); + }); +} + +ReplicaSetManager.prototype.kill = function(node, signal, callback) { + var self = this; + // Unpack callback and variables + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + signal = args.length ? args.shift() : 2; + + debug("** Killing node with pid " + this.mongods[node]["pid"] + " at port " + this.mongods[node]['port']); + var command = "kill -" + signal + " " + this.mongods[node]["pid"]; + // Kill process + exec(command, + function (error, stdout, stderr) { + console.log('stdout: ' + stdout); + console.log('stderr: ' + stderr); + if (error !== null) { + console.log('exec error: ' + error); + } + + self.mongods[node]["up"] = false; + // Wait for 5 seconds to give the server time to die a proper death + setTimeout(callback, 20000); + }); +} + +ReplicaSetManager.prototype.killPrimary = function(signal, callback) { + var self = this; + // Unpack callback and variables + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + signal = args.length ? args.shift() : 2; + + this.getNodeWithState(1, function(err, node) { + if(err != null) return callback(err, null); + + // Kill process and return node reference + self.kill(node, signal, function() { + // Wait for a while before passing back + callback(null, node); + }) + }); +} + +ReplicaSetManager.prototype.killSecondary = function(callback) { + var self = this; + + this.getNodeWithState(2, function(err, node) { + if(err != null) return callback(err, null); + // Kill process and return node reference + self.kill(node, function() { + callback(null, node); + }) + }); +} + +ReplicaSetManager.prototype.stepDownPrimary = function(callback) { + var self = this; + + this.getNodeWithState(1, function(err, primary) { + self.getConnection(primary, function(err, connection) { + if(err) return callback(err, null); + + // Closes the connection so never gets a response + connection.admin().command({"replSetStepDown": 90}); + // Call back + return callback(null, null); + }); + }); +} + +ReplicaSetManager.prototype.getNodeFromPort = function(port, callback) { + var self = this; + var nodes = Object.keys(this.mongods).filter(function(key, index, array) { + return self.mongods[key]["port"] == port; + }); + // Return first node + callback(null, nodes.length > 0 ? nodes.shift() : null); +} + +ReplicaSetManager.prototype.getNodeWithState = function(state, callback) { + var self = this; + self.ensureUpRetries = 0; + self.ensureUp(function(err, status) { + if(err != null) return callback(err, null); + + var node = status["members"].filter(function(element, index, array) { + return element["state"] == state; + }).shift(); + + if(node != null) { + var hostPort = node["name"].split(":"); + var port = hostPort[1] != null ? parseInt(hostPort[1]) : 27017; + var key = Object.keys(self.mongods).filter(function(element, index, array) { + return self.mongods[element]["port"] == port; + }).shift(); + return callback(null, key); + } else { + return callback(null, false); + } + }); +} + +ReplicaSetManager.prototype.ensureUp = function(callback) { + var self = this; + + // Write out the ensureUp + // process.stdout.write("."); + if(!self.up) process.stdout.write("."); + // Retry check for server up sleeping inbetween + self.retriedConnects = 0; + // Attemp to retrieve a connection + self.getConnection(function(err, connection) { + // If we have an error or no connection object retry + if(err != null || connection == null) { + setTimeout(function() { + self.ensureUpRetries++; + self.ensureUp(callback); + }, 1000) + // Return + return; + } + + // Check repl set get status + connection.admin().command({"replSetGetStatus": 1}, function(err, object) { + /// Get documents + var documents = object.documents; + // Get status object + var status = documents[0]; + + // If no members set + if(status["members"] == null || err != null) { + // Ensure we perform enough retries + if(self.ensureUpRetries < self.retries) { + setTimeout(function() { + self.ensureUpRetries++; + self.ensureUp(callback); + }, 1000) + } else { + return callback(new Error("Operation Failure"), null); + } + } else { + // Establish all health member + var healthyMembers = status.members.filter(function(element) { + return element["health"] == 1 && [1, 2, 7].indexOf(element["state"]) != -1 + }); + + var stateCheck = status["members"].filter(function(element, indexOf, array) { + return element["state"] == 1; + }); + + if(healthyMembers.length == status.members.length && stateCheck.length > 0) { + // process.stdout.write("all members up! \n\n"); + if(!self.up) process.stdout.write("all members up!\n\n") + self.up = true; + return callback(null, status); + } else { + // Ensure we perform enough retries + if(self.ensureUpRetries < self.retries) { + setTimeout(function() { + self.ensureUpRetries++; + self.ensureUp(callback); + }, 1000) + } else { + return callback(new Error("Operation Failure"), null); + } + } + } + }); + }); +} + +// Restart +ReplicaSetManager.prototype.restartKilledNodes = function(callback) { + var self = this; + + var nodes = Object.keys(self.mongods).filter(function(key) { + return self.mongods[key]["up"] == false; + }); + + Step( + // Start all nodes + function start() { + var group = this.group(); + // Start all nodes + for(var i = 0; i < nodes.length; i++) { + self.start(nodes[i], group()); + } + }, + + function finished() { + self.ensureUp(callback); + } + ) + // + // nodes.forEach(function(node) { + // self.start(node, function() {}); + // }); + // + // self.ensureUp(callback); +} + +ReplicaSetManager.prototype.getConnection = function(node, callback) { + var self = this; + // Unpack callback and variables + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + node = args.length ? args.shift() : null; + + if(node == null) { + var keys = Object.keys(this.mongods); + for(var i = 0; i < keys.length; i++) { + var key = keys[i]; + // Locate first db that's runing and is not an arbiter + if(this.mongods[keys[i]]["arbiterOnly"] == null && this.mongods[key]["up"]) { + node = keys[i]; + break; + } + } + } + + // Fire up the connection to check if we are running + // var db = new Db('node-mongo-blog', new Server(host, port, {}), {native_parser:true}); + var connection = new Db("", new Server(this.host, this.mongods[node]["port"], {})); + connection.open(function(err, connection) { + // We need to retry if we have not finished up the number of retries + if(err != null && self.retriedConnects < self.retries) { + // Sleep for a second then retry + setTimeout(function() { + // Update retries + self.retriedConnects++; + // Perform anothe reconnect + self.getConnection(node, callback); + }, 1000) + } else if(err != null && self.retriedConnects >= self.retries){ + callback(new Error("Failed to reconnect"), null); + } else { + callback(null, connection); + } + }) +} + +// Fire up the mongodb instance +var start = ReplicaSetManager.prototype.start = function(node, callback) { + var self = this; + // Start up mongod process + // debug("======================================================================================= starting process") + // debug(self.mongods[node]["start"]) + + var mongodb = exec(self.mongods[node]["start"], + function (error, stdout, stderr) { + console.log('stdout: ' + stdout); + console.log('stderr: ' + stderr); + if (error !== null) { + console.log('exec error: ' + error); + } + }); + + // Wait for a half a second then save the pids + setTimeout(function() { + // Mark server as running + self.mongods[node]["up"] = true; + self.mongods[node]["pid"]= fs.readFileSync(path.join(self.mongods[node]["db_path"], "mongod.lock"), 'ascii').trim(); + // Callback + callback(); + }, 5000); +} + +ReplicaSetManager.prototype.restart = start; + +ReplicaSetManager.prototype.startCmd = function(n) { + // Create boot command + this.mongods[n]["start"] = "mongod --noprealloc --smallfiles --replSet " + this.name + " --logpath '" + this.mongods[n]['log_path'] + "' " + + " --dbpath " + this.mongods[n]['db_path'] + " --port " + this.mongods[n]['port'] + " --fork"; + this.mongods[n]["start"] = this.durable ? this.mongods[n]["start"] + " --dur" : this.mongods[n]["start"]; + + if(this.auth) { + this.mongods[n]["start"] = this.auth ? this.mongods[n]["start"] + " --keyFile " + this.keyPath : this.mongods[n]["start"]; + } + return this.mongods[n]["start"]; +} + + + + + + + + + + + + + diff --git a/node_modules/mongodb/test/tools/server_manager.js b/node_modules/mongodb/test/tools/server_manager.js new file mode 100644 index 0000000..b5277c4 --- /dev/null +++ b/node_modules/mongodb/test/tools/server_manager.js @@ -0,0 +1,126 @@ +var debug = require('util').debug, + inspect = require('util').inspect, + path = require('path'), + fs = require('fs'), + exec = require('child_process').exec, + spawn = require('child_process').spawn, + Connection = require('../../lib/mongodb').Connection, + Db = require('../../lib/mongodb').Db, + Server = require('../../lib/mongodb').Server; + +var ServerManager = exports.ServerManager = function(options) { + options = options == null ? {} : options; + // Basic unpack values + this.path = path.resolve("data"); + this.port = options["start_port"] != null ? options["start_port"] : 27017; + this.db_path = getPath(this, "data-" + this.port); + this.log_path = getPath(this, "log-" + this.port); + this.durable = options["durable"] != null ? options["durable"] : false; + this.auth = options['auth'] != null ? options['auth'] : false; + this.purgedirectories = options['purgedirectories'] != null ? options['purgedirectories'] : true; + + // Server status values + this.up = false; + this.pid = null; +} + +// Start up the server instance +ServerManager.prototype.start = function(killall, callback) { + var self = this; + // Unpack callback and variables + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + killall = args.length ? args.shift() : true; + // Create start command + var startCmd = generateStartCmd({log_path: self.log_path, + db_path: self.db_path, port: self.port, durable: self.durable, auth:self.auth}); + + exec(killall ? 'killall mongod' : '', function(err, stdout, stderr) { + if(self.purgedirectories) { + // Remove directory + exec("rm -rf " + self.db_path, function(err, stdout, stderr) { + if(err != null) return callback(err, null); + // Create directory + exec("mkdir -p " + self.db_path, function(err, stdout, stderr) { + if(err != null) return callback(err, null); + // Start up mongod process + var mongodb = exec(startCmd, + function (error, stdout, stderr) { + // console.log('stdout: ' + stdout); + // console.log('stderr: ' + stderr); + if (error !== null) { + console.log('exec error: ' + error); + } + }); + + // Wait for a half a second then save the pids + setTimeout(function() { + // Mark server as running + self.up = true; + self.pid = fs.readFileSync(path.join(self.db_path, "mongod.lock"), 'ascii').trim(); + // Callback + callback(); + }, 500); + }); + }); + } else { + // Ensure we remove the lock file as we are not purging the directory + fs.unlinkSync(path.join(self.db_path, "mongod.lock")); + + // Start up mongod process + var mongodb = exec(startCmd, + function (error, stdout, stderr) { + if (error !== null) { + console.log('exec error: ' + error); + } + }); + + // Wait for a half a second then save the pids + setTimeout(function() { + // Mark server as running + self.up = true; + self.pid = fs.readFileSync(path.join(self.db_path, "mongod.lock"), 'ascii').trim(); + // Callback + callback(); + }, 500); + } + }); +} + +ServerManager.prototype.stop = function(signal, callback) { + var self = this; + // Unpack callback and variables + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + signal = args.length ? args.shift() : 2; + // Stop the server + var command = "kill -" + signal + " " + self.pid; + // Kill process + exec(command, + function (error, stdout, stderr) { + // console.log('stdout: ' + stdout); + // console.log('stderr: ' + stderr); + if (error !== null) { + console.log('exec error: ' + error); + } + + self.up = false; + // Wait for a second + setTimeout(callback, 1000); + }); +} + +// Get absolute path +var getPath = function(self, name) { + return path.join(self.path, name); +} + +// Generate start command +var generateStartCmd = function(options) { + // Create boot command + var startCmd = "mongod --logpath '" + options['log_path'] + "' " + + " --dbpath " + options['db_path'] + " --port " + options['port'] + " --fork"; + startCmd = options['durable'] ? startCmd + " --dur" : startCmd; + startCmd = options['auth'] ? startCmd + " --auth" : startCmd; + return startCmd; +} diff --git a/node_modules/mongodb/test/unicode_test.js b/node_modules/mongodb/test/unicode_test.js new file mode 100644 index 0000000..8597518 --- /dev/null +++ b/node_modules/mongodb/test/unicode_test.js @@ -0,0 +1,160 @@ +var mongodb = process.env['TEST_NATIVE'] != null ? require('../lib/mongodb').native() : require('../lib/mongodb').pure(); + +var testCase = require('../deps/nodeunit').testCase, + debug = require('util').debug + inspect = require('util').inspect, + nodeunit = require('../deps/nodeunit'), + Db = mongodb.Db, + Cursor = mongodb.Cursor, + Collection = mongodb.Collection, + Server = mongodb.Server; + +var MONGODB = 'integration_tests'; +var client = new Db(MONGODB, new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize: 4}), {native_parser: (process.env['TEST_NATIVE'] != null)}); + +// Define the tests, we want them to run as a nested test so we only clean up the +// db connection once +var tests = testCase({ + setUp: function(callback) { + client.open(function(err, db_p) { + if(numberOfTestsRun == Object.keys(tests).length) { + // If first test drop the db + client.dropDatabase(function(err, done) { + callback(); + }); + } else { + return callback(); + } + }); + }, + + tearDown: function(callback) { + numberOfTestsRun = numberOfTestsRun - 1; + // Drop the database and close it + if(numberOfTestsRun <= 0) { + // client.dropDatabase(function(err, done) { + client.close(); + callback(); + // }); + } else { + client.close(); + callback(); + } + }, + + shouldCorrectlySaveUnicodeContainingDocument : function(test) { + var doc = {statuses_count: 1687 + , created_at: 'Mon Oct 22 14:55:08 +0000 2007' + , description: 'NodeJS hacker, Cofounder of Debuggable, CakePHP core alumnus' + , favourites_count: 6 + , profile_sidebar_fill_color: 'EADEAA' + , screen_name: 'felixge' + , status: + { created_at: 'Fri Mar 12 08:59:44 +0000 2010' + , in_reply_to_screen_name: null + , truncated: false + , in_reply_to_user_id: null + , source: 'Tweetie' + , favorited: false + , in_reply_to_status_id: null + , id: 10364119169 + , text: '#berlin #snow = #fail : (' + } + , contributors_enabled: false + , following: null + , geo_enabled: false + , time_zone: 'Eastern Time (US & Canada)' + , profile_sidebar_border_color: 'D9B17E' + , url: 'http://debuggable.com' + , verified: false + , location: 'Berlin' + , profile_text_color: '333333' + , notifications: null + , profile_background_image_url: 'http://s.twimg.com/a/1268354287/images/themes/theme8/bg.gif' + , protected: false + , profile_link_color: '9D582E' + , followers_count: 840 + , name: 'Felix Geisend\u00f6rfer' + , profile_background_tile: false + , id: 9599342 + , lang: 'en' + , utc_offset: -18000 + , friends_count: 450 + , profile_background_color: '8B542B' + , profile_image_url: 'http://a3.twimg.com/profile_images/107142257/passbild-square_normal.jpg' + }; + + client.createCollection('test_should_correctly_save_unicode_containing_document', function(err, collection) { + doc['_id'] = 'felixge'; + + collection.save(doc, {safe:true}, function(err, doc) { + collection.findOne(function(err, doc) { + test.equal('felixge', doc._id); + test.done(); + }); + }); + }); + }, + + // Test unicode characters + shouldCorrectlyInsertUnicodeCharacters : function(test) { + client.createCollection('unicode_test_collection', function(err, collection) { + var test_strings = ["ouooueauiOUOOUEAUI", "öüóőúéáűíÖÜÓŐÚÉÁŰÍ", "本荘由利地域に洪水警報"]; + collection.insert({id: 0, text: test_strings[0]}, {safe:true}, function(err, ids) { + collection.insert({id: 1, text: test_strings[1]}, {safe:true}, function(err, ids) { + collection.insert({id: 2, text: test_strings[2]}, {safe:true}, function(err, ids) { + collection.find(function(err, cursor) { + cursor.each(function(err, item) { + if(item !== null) { + test.equal(test_strings[item.id], item.text); + } else { + test.done(); + } + }); + }); + }); + }); + }); + }); + }, + + shouldCreateObjectWithChineseObjectName : function(test) { + var object = {'客家话' : 'Hello'}; + + client.createCollection('create_object_with_chinese_object_name', function(err, r) { + client.collection('create_object_with_chinese_object_name', function(err, collection) { + + collection.insert(object, {safe:true}, function(err, result) { + collection.findOne(function(err, item) { + test.equal(object['客家话'], item['客家话']) + + collection.find().toArray(function(err, items) { + test.equal(object['客家话'], items[0]['客家话']) + test.done(); + }) + }) + }); + }) + }) + }, + + shouldCorrectlyHandleUT8KeyNames : function(test) { + client.createCollection('test_utf8_key_name', function(err, collection) { + collection.insert({'šđžčćŠĐŽČĆ':1}, {safe:true}, function(err, ids) { + // finished_test({test_utf8_key_name:'ok'}); + collection.find({}, {'fields': ['šđžčćŠĐŽČĆ']}, function(err, cursor) { + cursor.toArray(function(err, items) { + test.equal(1, items[0]['šđžčćŠĐŽČĆ']); + // Let's close the db + test.done(); + }); + }); + }); + }); + }, +}) + +// Stupid freaking workaround due to there being no way to run setup once for each suite +var numberOfTestsRun = Object.keys(tests).length; +// Assign out tests +module.exports = tests; \ No newline at end of file diff --git a/node_modules/mongodb/tools/test_all.js b/node_modules/mongodb/tools/test_all.js new file mode 100644 index 0000000..8106c37 --- /dev/null +++ b/node_modules/mongodb/tools/test_all.js @@ -0,0 +1,122 @@ +var nodeunit = require('../deps/nodeunit'), + debug = require('util').debug, + inspect = require('util').inspect, + fs = require('fs'), + exec = require('child_process').exec, + Step = require('../deps/step/lib/step'), + ServerManager = require('../test/tools/server_manager').ServerManager, + ReplicaSetManager = require('../test/tools/replica_set_manager').ReplicaSetManager; + +// Manage the test server +var serverManager = new ServerManager(); +var replicaSetManager = new ReplicaSetManager(); +// test directories +var files = []; +var directories = [{dir: __dirname + "/../test", path: "/test/"}, + {dir: __dirname + "/../test/gridstore", path: "/test/gridstore/"}]; + +// Generate a list of tests +directories.forEach(function(dirEntry) { + // Add the files + files = files.concat(fs.readdirSync(dirEntry.dir).filter(function(item) { + return /_test\.js$/i.test(item); + }).map(function(file) { + return dirEntry.path + file; + })); +}); + +// Replicasetfiles +var replicasetFiles = fs.readdirSync(__dirname + "/../test/replicaset").filter(function(item) { + return /_test\.js$/i.test(item); +}).map(function(file) { + return "/test/replicaset/" + file; +}); + +var specifedParameter = function(arguments, param) { + for(var i = 0; i < arguments.length; i++) { + if(arguments[i] == param) return true; + } + return false; +} + +// Different options +var junit = specifedParameter(process.argv, '--junit', false); +var noReplicaSet = specifedParameter(process.argv, '--noreplicaset', false); + +// Basic default test runner +var runner = nodeunit.reporters.default; +var options = { error_prefix: '\u001b[31m', + error_suffix: '\u001b[39m', + ok_prefix: '\u001b[32m', + ok_suffix: '\u001b[39m', + bold_prefix: '\u001b[1m', + bold_suffix: '\u001b[22m', + assertion_prefix: '\u001b[35m', + assertion_suffix: '\u001b[39m' }; + +// cleanup output directory +exec('rm -rf ./output', function(err, stdout, stderr) { + // if we have a junit reporter + if(junit) { + // Remove directory + fs.mkdirSync("./output", 0777); + // Set up the runner for junit + runner = nodeunit.reporters.junit; + // Set up options + options.output = './output'; + } + + // Run all tests including replicaset ones + if(!noReplicaSet) { + // Boot up the test server and run the tests + Step( + // Start the single server + function startSingleServer() { + serverManager.start(true, {purgedirectories:true}, this); + }, + // Run all the integration tests using the pure js bson parser + function runPureJS() { + options.suffix = 'pure'; + runner.run(files, options, this); + }, + // Run all integration tests using the native bson parser + function runNativeJS() { + process.env['TEST_NATIVE'] = 'TRUE'; + options.suffix = 'native'; + runner.run(files, options, this); + }, + // Execute all the replicaset tests + function executeReplicaSetTests() { + runner.run(replicasetFiles, options, this); + }, + function done() { + // Kill all mongod server + replicaSetManager.killAll(function() { + // Force exit + process.exit(); + }) + } + ); + } else { + // Execute without replicaset tests + Step( + function startSingleServer() { + serverManager.start(true, {purgedirectories:true}, this); + }, + function runPureJS() { + options.suffix = 'pure'; + runner.run(files, options, this); + }, + function runNativeJS() { + process.env['TEST_NATIVE'] = 'TRUE'; + options.suffix = 'native'; + runner.run(files, options, this); + }, + function done() { + replicaSetManager.killAll(function() { + process.exit(); + }) + } + ); + } +}); diff --git a/node_modules/mongoose/History.md b/node_modules/mongoose/History.md new file mode 100644 index 0000000..a88d7e2 --- /dev/null +++ b/node_modules/mongoose/History.md @@ -0,0 +1,410 @@ + +1.7.4 / 2011-07-25 +=================== + + * fixed; sparse now a valid seperate schema option + * fixed; now catching cast errors in queries + * fixed; calling new Schema with object created in vm.runInNewContext now works (#384) [Sija] + * fixed; String enum was disallowing null + * fixed; Find by nested document _id now works (#389) + +1.7.3 / 2011-07-16 +=================== + + * fixed; MongooseArray#indexOf now works with ObjectIds + * fixed; validation scope now set properly (#418) + * fixed; added missing colors dependency (#398) + +1.7.2 / 2011-07-13 +=================== + + * changed; node-mongodb-native driver to v0.9.6.7 + +1.7.1 / 2011-07-12 +=================== + + * changed; roll back node-mongodb-native driver to v0.9.6.4 + +1.7.0 / 2011-07-12 +=================== + + * fixed; collection name misspelling [mathrawka] + * fixed; 2nd param is required for ReplSetServers [kevinmarvin] + * fixed; MongooseArray behaves properly with Object.keys + * changed; node-mongodb-native driver to v0.9.6.6 + * fixed/changed; Mongodb segfault when passed invalid ObjectId (#407) + - This means invalid data passed to the ObjectId constructor will now error + +1.6.0 / 2011-07-07 +=================== + + * changed; .save() errors are now emitted on the instances db instead of the instance 9782463fc + * fixed; errors occurring when creating indexes now properly emit on db + * added; $maxDistance support to MongooseArrays + * fixed; RegExps now work with $all + * changed; node-mongodb-native driver to v0.9.6.4 + * fixed; model names are now accessible via .modelName + * added; Query#slaveOk support + +1.5.0 / 2011-06-27 +=================== + + * changed; saving without a callback no longer ignores the error (@bnoguchi) + * changed; hook-js version bump to 0.1.9 + * changed; node-mongodb-native version bumped to 0.9.6.1 - When .remove() doesn't + return an error, null is no longer passed. + * fixed; two memory leaks (@justmoon) + * added; sparse index support + * added; more ObjectId conditionals (gt, lt, gte, lte) (@phillyqueso) + * added; options are now passed in model#remote (@JerryLuke) + +1.4.0 / 2011-06-10 +=================== + + * bumped hooks-js dependency (fixes issue passing null as first arg to next()) + * fixed; document#inspect now works properly with nested docs + * fixed; 'set' now works as a schema attribute (GH-365) + * fixed; _id is now set properly within pre-init hooks (GH-289) + * added; Query#distinct / Model#distinct support (GH-155) + * fixed; embedded docs now can use instance methods (GH-249) + * fixed; can now overwrite strings conflicting with schema type + +1.3.7 / 2011-06-03 +=================== + + * added MongooseArray#splice support + * fixed; 'path' is now a valid Schema pathname + * improved hooks (utilizing https://github.com/bnoguchi/hooks-js) + * fixed; MongooseArray#$shift now works (never did) + * fixed; Document.modified no longer throws + * fixed; modifying subdoc property sets modified paths for subdoc and parent doc + * fixed; marking subdoc path as modified properly persists the value to the db + * fixed; RexExps can again be saved ( #357 ) + +1.3.6 / 2011-05-18 +=================== + + * fixed; corrected casting for queries against array types + * added; Document#set now accepts Document instances + +1.3.5 / 2011-05-17 +=================== + + * fixed; $ne queries work properly with single vals + * added; #inspect() methods to improve console.log output + +1.3.4 / 2011-05-17 +=================== + + * fixed; find by Date works as expected (#336) + * added; geospatial 2d index support + * added; support for $near (#309) + * updated; node-mongodb-native driver + * fixed; updating numbers work (#342) + * added; better error msg when try to remove an embedded doc without an _id (#307) + * added; support for 'on-the-fly' schemas (#227) + * changed; virtual id getters can now be skipped + * fixed; .index() called on subdoc schema now works as expected + * fixed; db.setProfile() now buffers until the db is open (#340) + +1.3.3 / 2011-04-27 +=================== + + * fixed; corrected query casting on nested mixed types + +1.3.2 / 2011-04-27 +=================== + + * fixed; query hints now retain key order + +1.3.1 / 2011-04-27 +=================== + + * fixed; setting a property on an embedded array no longer overwrites entire array (GH-310) + * fixed; setting nested properties works when sibling prop is named "type" + * fixed; isModified is now much finer grained when .set() is used (GH-323) + * fixed; mongoose.model() and connection.model() now return the Model (GH-308, GH-305) + * fixed; can now use $gt, $lt, $gte, $lte with String schema types (GH-317) + * fixed; .lowercase() -> .toLowerCase() in pluralize() + * fixed; updating an embedded document by index works (GH-334) + * changed; .save() now passes the instance to the callback (GH-294, GH-264) + * added; can now query system.profile and system.indexes collections + * added; db.model('system.profile') is now included as a default Schema + * added; db.setProfiling(level, ms, callback) + * added; Query#hint() support + * added; more tests + * updated node-mongodb-native to 0.9.3 + +1.3.0 / 2011-04-19 +=================== + + * changed; save() callbacks now fire only once on failed validation + * changed; Errors returned from save() callbacks now instances of ValidationError + * fixed; MongooseArray#indexOf now works properly + +1.2.0 / 2011-04-11 +=================== + + * changed; MongooseNumber now casts empty string to null + +1.1.25 / 2011-04-08 +=================== + + * fixed; post init now fires at proper time + +1.1.24 / 2011-04-03 +=================== + + * fixed; pushing an array onto an Array works on existing docs + +1.1.23 / 2011-04-01 +=================== + + * Added Model#model + +1.1.22 / 2011-03-31 +=================== + + * Fixed; $in queries on mixed types now work + +1.1.21 / 2011-03-31 +=================== + + * Fixed; setting object root to null/undefined works + +1.1.20 / 2011-03-31 +=================== + + * Fixed; setting multiple props on null field works + +1.1.19 / 2011-03-31 +=================== + + * Fixed; no longer using $set on paths to an unexisting fields + +1.1.18 / 2011-03-30 +=================== + + * Fixed; non-mixed type object setters work after initd from null + +1.1.17 / 2011-03-30 +=================== + + * Fixed; nested object property access works when root initd with null value + +1.1.16 / 2011-03-28 +=================== + + * Fixed; empty arrays are now saved + +1.1.15 / 2011-03-28 +=================== + + * Fixed; `null` and `undefined` are set atomically. + +1.1.14 / 2011-03-28 +=================== + + * Changed; more forgiving date casting, accepting '' as null. + +1.1.13 / 2011-03-26 +=================== + + * Fixed setting values as `undefined`. + +1.1.12 / 2011-03-26 +=================== + + * Fixed; nested objects now convert to JSON properly + * Fixed; setting nested objects directly now works + * Update node-mongodb-native + +1.1.11 / 2011-03-25 +=================== + + * Fixed for use of `type` as a key. + +1.1.10 / 2011-03-23 +=================== + + * Changed; Make sure to only ensure indexes while connected + +1.1.9 / 2011-03-2 +================== + + * Fixed; Mixed can now default to empty arrays + * Fixed; keys by the name 'type' are now valid + * Fixed; null values retrieved from the database are hydrated as null values. + * Fixed repeated atomic operations when saving a same document twice. + +1.1.8 / 2011-03-23 +================== + + * Fixed 'id' overriding. [bnoguchi] + +1.1.7 / 2011-03-22 +================== + + * Fixed RegExp query casting when querying against an Array of Strings [bnoguchi] + * Fixed getters/setters for nested virtualsl. [bnoguchi] + +1.1.6 / 2011-03-22 +================== + + * Only doValidate when path exists in Schema [aheckmann] + * Allow function defaults for Array types [aheckmann] + * Fix validation hang [aheckmann] + * Fix setting of isRequired of SchemaType [aheckmann] + * Fix SchemaType#required(false) filter [aheckmann] + * More backwards compatibility [aheckmann] + * More tests [aheckmann] + +1.1.5 / 2011-03-14 +================== + + * Added support for `uri, db, fn` and `uri, fn` signatures for replica sets. + * Improved/extended replica set tests. + +1.1.4 / 2011-03-09 +================== + + * Fixed; running an empty Query doesn't throw. [aheckmann] + * Changed; Promise#addBack returns promise. [aheckmann] + * Added streaming cursor support. [aheckmann] + * Changed; Query#update defaults to use$SetOnSave now. [brian] + * Added more docs. + +1.1.3 / 2011-03-04 +================== + + * Added Promise#resolve [aheckmann] + * Fixed backward compatibility with nulls [aheckmann] + * Changed; Query#{run,exec} return promises [aheckmann] + +1.1.2 / 2011-03-03 +================== + + * Restored Query#exec and added notion of default operation [brian] + * Fixed ValidatorError messages [brian] + +1.1.1 / 2011-03-01 +================== + + * Added SchemaType String `lowercase`, `uppercase`, `trim`. + * Public exports (`Model`, `Document`) and tests. + * Added ObjectId casting support for `Document`s. + +1.1.0 / 2011-02-25 +================== + + * Added support for replica sets. + +1.0.16 / 2011-02-18 +=================== + + * Added $nin as another whitelisted $conditional for SchemaArray [brian] + * Changed #with to #where [brian] + * Added ability to use $in conditional with Array types [brian] + +1.0.15 / 2011-02-18 +=================== + + * Added `id` virtual getter for documents to easily access the hexString of + the `_id`. + +1.0.14 / 2011-02-17 +=================== + + * Fix for arrays within subdocuments [brian] + +1.0.13 / 2011-02-16 +=================== + + * Fixed embedded documents saving. + +1.0.12 / 2011-02-14 +=================== + + * Minor refactorings [brian] + +1.0.11 / 2011-02-14 +=================== + + * Query refactor and $ne, $slice, $or, $size, $elemMatch, $nin, $exists support [brian] + * Named scopes sugar [brian] + +1.0.10 / 2011-02-11 +=================== + + * Updated node-mongodb-native driver [thanks John Allen] + +1.0.9 / 2011-02-09 +================== + + * Fixed single member arrays as defaults [brian] + +1.0.8 / 2011-02-09 +================== + + * Fixed for collection-level buffering of commands [gitfy] + * Fixed `Document#toJSON` [dalejefferson] + * Fixed `Connection` authentication [robrighter] + * Fixed clash of accessors in getters/setters [eirikurn] + * Improved `Model#save` promise handling + +1.0.7 / 2011-02-05 +================== + + * Fixed memory leak warnings for test suite on 0.3 + * Fixed querying documents that have an array that contain at least one + specified member. [brian] + * Fixed default value for Array types (fixes GH-210). [brian] + * Fixed example code. + +1.0.6 / 2011-02-03 +================== + + * Fixed `post` middleware + * Fixed; it's now possible to instantiate a model even when one of the paths maps + to an undefined value [brian] + +1.0.5 / 2011-02-02 +================== + + * Fixed; combo $push and $pushAll auto-converts into a $pushAll [brian] + * Fixed; combo $pull and $pullAll auto-converts to a single $pullAll [brian] + * Fixed; $pullAll now removes said members from array before save (so it acts just + like pushAll) [brian] + * Fixed; multiple $pulls and $pushes become a single $pullAll and $pushAll. + Moreover, $pull now modifies the array before save to reflect the immediate + change [brian] + * Added tests for nested shortcut getters [brian] + * Added tests that show that Schemas with nested Arrays don't apply defaults + [brian] + +1.0.4 / 2011-02-02 +================== + + * Added MongooseNumber#toString + * Added MongooseNumber unit tests + +1.0.3 / 2011-02-02 +================== + + * Make sure safe mode works with Model#save + * Changed Schema options: safe mode is now the default + * Updated node-mongodb-native to HEAD + +1.0.2 / 2011-02-02 +================== + + * Added a Model.create shortcut for creating documents. [brian] + * Fixed; we can now instantiate models with hashes that map to at least one + null value. [brian] + * Fixed Schema with more than 2 nested levels. [brian] + +1.0.1 / 2011-02-02 +================== + + * Improved `MongooseNumber`, works almost like the native except for `typeof` + not being `'number'`. diff --git a/node_modules/mongoose/Makefile b/node_modules/mongoose/Makefile new file mode 100644 index 0000000..47ab06c --- /dev/null +++ b/node_modules/mongoose/Makefile @@ -0,0 +1,28 @@ + +TESTS = $(shell find test/ -name '*.test.js') + +test: + @NODE_ENV=test ./support/expresso/bin/expresso \ + -I lib \ + -I support \ + -I support/should.js/lib \ + -I support/cli-table/lib \ + $(TESTFLAGS) \ + $(TESTS) + +test-cov: + @TESTFLAGS=--cov $(MAKE) test + +docs: docs/api.html + +docs/api.html: lib/mongoose/*.js + dox \ + --private \ + --title Mongooose \ + --desc "Expressive MongoDB for Node.JS" \ + $(shell find lib/mongoose/* -type f) > $@ + +docclean: + rm -f docs/*.{1,html} + +.PHONY: test test-cov docs docclean diff --git a/node_modules/mongoose/README.md b/node_modules/mongoose/README.md new file mode 100644 index 0000000..62d3c30 --- /dev/null +++ b/node_modules/mongoose/README.md @@ -0,0 +1,382 @@ +Mongoose 1.0 +============ + +## What's Mongoose? + +Mongoose is a MongoDB object modeling tool designed to work in an asynchronous +environment. + +Defining a model is as easy as: + +```javascript +var Comments = new Schema({ + title : String + , body : String + , date : Date +}); + +var BlogPost = new Schema({ + author : ObjectId + , title : String + , body : String + , date : Date + , comments : [Comments] + , meta : { + votes : Number + , favs : Number + } +}); + +mongoose.model('BlogPost', BlogPost); +``` + +## Installation + +The recommended way is through the excellent NPM: + +```bash +$ npm install mongoose +``` + +Otherwise, you can check it in your repository and then expose it: + +```bash +$ git clone git@github.com:LearnBoost/mongoose.git support/mongoose/ +``` +```javascript +// in your code +require.paths.unshift('support/mongoose/lib') +``` + +Then you can `require` it: + +```javascript +require('mongoose') +``` + +## Connecting to MongoDB + +First, we need to define a connection. If your app uses only one database, you +should use `mongose.connect`. If you need to create additional connections, use +`mongoose.createConnection`. + +Both `connect` and `createConnection` take a `mongodb://` URI, or the parameters +`host, database, port`. + +```javascript +var mongoose = require('mongoose'); + +mongoose.connect('mongodb://localhost/my_database'); +``` + +Once connected, the `open` event is fired on the `Connection` instance. If +you're using `mongoose.connect`, the `Connection` is `mongoose.connection`. +Otherwise, `mongoose.createConnection` return value is a `Connection`. + +**Important!** Mongoose buffers all the commands until it's connected to the +database. This means that you don't have to wait until it connects to MongoDB +in order to define models, run queries, etc. + +## Defining a Model + +Models are defined through the `Schema` interface. + +```javascript +var Schema = mongoose.Schema + , ObjectId = Schema.ObjectId; + +var BlogPost = new Schema({ + author : ObjectId + , title : String + , body : String + , date : Date +}); +``` + +Aside from defining the structure of your documents and the types of data you're +storing, a Schema handles the definition of: + +* Validators (async and sync) +* Defaults +* Getters +* Setters +* Indexes +* Middleware +* Methods definition +* Statics definition +* Plugins + +The following example shows some of these features: + +```javascript +var Comment = new Schema({ + name : { type: String, default: 'hahaha' } + , age : { type: Number, min: 18, index: true } + , bio : { type: String, match: /[a-z]/ } + , date : { type: Date, default: Date.now } +}); + +// a setter +Comment.path('name').set(function (v) { + return v.capitalize(); +}); + +// middleware +Comment.pre('save', function (next) { + notify(this.get('email')); + next(); +}); +``` + +Take a look at the example in `examples/schema.js` for an end-to-end example of +(almost) all the functionality available. + +## Accessing a Model + +Once we define a model through `mongoose.model('ModelName', mySchema)`, we can +access it through the same function + +```javascript +var myModel = mongoose.model('ModelName'); +``` + +We can then instantiate it, and save it: + +```javascript +var instance = new myModel(); +instance.my.key = 'hello'; +instance.save(function (err) { + // +}); +``` + +Or we can find documents from the same collection + +```javascript +myModel.find({}, function (err, docs) { + // docs.forEach +}); +``` + +You can also `findOne`, `findById`, `update`, etc. For more details check out +the API docs. + +## Embedded Documents + +In the first example snippet, we defined a key in the Schema that looks like: + +``` +comments: [Comments] +``` + +Where `Comments` is a `Schema` we created. This means that creating embedded +documents is as simple as: + +```javascript +// retrieve my model +var BlogPost = mongoose.model('BlogPost'); + +// create a blog post +var post = new BlogPost(); + +// create a comment +post.comments.push({ title: 'My comment' }); + +post.save(function (err) { + if (!err) console.log('Success!'); +}); +``` + +The same goes for removing them: + +```javascript +BlogPost.findById(myId, function (err, post) { + if (!err) { + post.comments[0].remove(); + post.save(function (err) { + // do something + }); + } +}); +``` + +Embedded documents enjoy all the same features as your models. Defaults, +validators, middleware. Whenever an error occurs, it's bubbled to the `save()` +error callback, so error handling is a snap! + +Mongoose interacts with your embedded documents in arrays _atomically_, out of +the box. + +## Middleware + +Middleware is one of the most exciting features about Mongoose 1.0. Middleware +takes away all the pain of nested callbacks. + +Middleware are defined at the Schema level and are applied when the methods +`init` (when a document is initialized with data from MongoDB), `save` (when +a document or embedded document is saved). + +There's two types of middleware: + +- Serial + Serial middleware are defined like: + +```javascript +.pre(method, function (next, methodArg1, methodArg2, ...) { + // ... +}) +``` + + They're executed one after the other, when each middleware calls `next`. + + You can also intercept the `method`'s incoming arguments via your middleware -- + notice `methodArg1`, `methodArg2`, etc in the `pre` definition above. See + section "Intercepting and mutating method arguments" below. + + +- Parallel + Parallel middleware offer more fine-grained flow control, and are defined + like: + +```javascript +.pre(method, true, function (next, done, methodArg1, methodArg2) { + // ... +}) +``` + + Parallel middleware can `next()` immediately, but the final argument will be + called when all the parallel middleware have called `done()`. + +### Error handling + +If any middleware calls `next` or `done` with an `Error` instance, the flow is +interrupted, and the error is passed to the function passed as an argument. + +For example: + +```javascript +schema.pre('save', function (next) { + // something goes wrong + next(new Error('something went wrong')); +}); + +// later... + +myModel.save(function (err) { + // err can come from a middleware +}); +``` + +### Intercepting and mutating method arguments + +You can intercept method arguments via middleware. + +For example, this would allow you to broadcast changes about your Documents +every time someone `set`s a path in your Document to a new value: + +```javascript +schema.pre('set', function (next, path, val, typel) { + // `this` is the current Document + this.emit('set', path, val); + + // Pass control to the next pre + next(); +}); +``` + +Moreover, you can mutate the incoming `method` arguments so that subsequent +middleware see different values for those arguments. To do so, just pass the +new values to `next`: + +```javascript +.pre(method, function firstPre (next, methodArg1, methodArg2) { + // Mutate methodArg1 + next("altered-" + methodArg1.toString(), methodArg2); +}) // pre declaration is chainable +.pre(method, function secondPre (next, methodArg1, methodArg2) { + console.log(methodArg1); + // => 'altered-originalValOfMethodArg1' + + console.log(methodArg2); + // => 'originalValOfMethodArg2' + + // Passing no arguments to `next` automatically passes along the current argument values + // i.e., the following `next()` is equivalent to `next(methodArg1, methodArg2)` + // and also equivalent to, with the example method arg + // values, `next('altered-originalValOfMethodArg1', 'originalValOfMethodArg2')` + next(); +}) +``` + +## API docs + +You can find the [Dox](http://github.com/visionmedia/dox) generated API docs at +[http://mongoosejs.com](http://mongoosejs.com). + +## Getting support + +Please subscribe to the Google Groups [mailing +list](http://groups.google.com/group/mongoose-orm/boxsubscribe). + +## Mongoose Plugins + +The following plugins are currently available for use with mongoose: + +- [mongoose-types](https://github.com/bnoguchi/mongoose-types) - Adds + several additional types (e.g., Email) that you can use in your + Schema declarations +- [mongoose-auth](https://github.com/bnoguchi/mongoose-auth) - A drop in + solution for your auth needs. Currently supports Password, Facebook, + Twitter, Github, and more. +- [mongoose-dbref](https://github.com/goulash1971/mongoose-dbref) - Adds DBRef support +- [mongoose-joins](https://github.com/goulash1971/mongoose-joins) - Adds simple join support + +## Contributing to Mongoose + +### Cloning the repository + +Make a fork of `mongoose`, then clone it in your computer. The `master` branch +contains the current stable release, and the `develop` branch the next upcoming +major release. + +If `master` is at `1.0`, `develop` will contain the upcoming `1.1` (or `2.0` if +the `1` branch is nearing its completion). + +### Guidelines + +- Please write inline documentation for new methods or class members. +- Please write tests and make sure your tests pass. +- Before starting to write code, look for existing tickets or create one for + your specifc issue (unless you're addressing something that's clearly broken). + That way you avoid working on something that might not be of interest or that + has been addressed already in a different branch. + +## Credits + +- Guillermo Rauch - guillermo@learnboost.com - [Guille](http://github.com/guille) +- Nathan White - [nw](http://github.com/nw/) +- Brian Noguchi - [bnoguchi](https://github.com/bnoguchi) +- Aaron Heckmann - [aheckmann](https://github.com/aheckmann) + +## License + +Copyright (c) 2010 LearnBoost <dev@learnboost.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/mongoose/docs/defaults.md b/node_modules/mongoose/docs/defaults.md new file mode 100644 index 0000000..7324577 --- /dev/null +++ b/node_modules/mongoose/docs/defaults.md @@ -0,0 +1,29 @@ + +Defaults +======== + +Each `SchemaType` that you define (you can read more about them in the model +definition chapter) can have a default value. + +Default values are applied when the document skeleton is constructed. This +means that if you create a new document (`new MyModel`) or if you find an +existing document (`MyModel.findById` for example), both will have defaults +provided that a certain key is missing. + +## Definition + +You can define a default with a function: + + new Schema({ + date: { type: Date, default: Date.now } + }) + +or a value: + + new Schema({ + date: { type: Date, default: '12/10/1990' } + }) + +Notice that defaults are automatically casted. In both cases, the defaults will +become actual `Date` objects, but we're passing a timestamp first, and a string +date second. diff --git a/node_modules/mongoose/docs/embedded-documents.md b/node_modules/mongoose/docs/embedded-documents.md new file mode 100644 index 0000000..10b6aae --- /dev/null +++ b/node_modules/mongoose/docs/embedded-documents.md @@ -0,0 +1,79 @@ + +Embedded Documents +================== + +Embedded documents are documents with schemas of their own that are part of +other documents (as items within an array). + +Embedded documents enjoy all the same features as your models. Defaults, +validators, middleware. Whenever an error occurs, it's bubbled to the `save()` +error callback, so error handling is a snap! + +Mongoose interacts with your embedded documents in arrays _atomically_, out of +the box. + +## Definition and initialization + +When you define a Schema like this: + + var Comments = new Schema({ + title : String + , body : String + , date : Date + }); + + var BlogPost = new Schema({ + author : ObjectId + , title : String + , body : String + , date : Date + , comments : [Comments] + , meta : { + votes : Number + , favs : Number + } + }); + + mongoose.model('BlogPost', BlogPost); + +The `comments` key of your `BlogPost` documents will then be an instance of +`DocumentArray`. This is a special subclassed `Array` that can deal with +casting, and has special methods to work with embedded documents. + +## Adding an embedded document to an array + + // retrieve my model + var BlogPost = mongoose.model('BlogPost'); + + // create a blog post + var post = new BlogPost(); + + // create a comment + post.comments.push({ title: 'My comment' }); + + post.save(function (err) { + if (!err) console.log('Success!'); + }); + +## Removing an embedded document + + BlogPost.findById(myId, function (err, post) { + if (!err) { + post.comments[0].remove(); + post.save(function (err) { + // do something + }); + } + }); + +## Finding an embedded document by id + +`DocumentArray`s have an special method `id` that filters your embedded +documents by their `_id` property (each embedded document gets one): + +Consider the following snippet: + + post.comments.id(my_id).remove(); + post.save(function (err) { + // embedded comment with id `my_id` removed! + }); diff --git a/node_modules/mongoose/docs/finding-documents.md b/node_modules/mongoose/docs/finding-documents.md new file mode 100644 index 0000000..2e00657 --- /dev/null +++ b/node_modules/mongoose/docs/finding-documents.md @@ -0,0 +1,63 @@ + +Finding documents +================= + +Documents can be retrieved through `find`, `findOne` and `findById`. These +methods are executed on your `Model`s. + +## Model#find + + Model.find(query, fields, options, callback) + + // fields and options can be ommitted + +### Simple query: + + Model.find({ 'some.value': 5 }, function(err, docs){ + // docs is an array + }); + +### Retrieveing only certain fields + + Model.find({}, ['first', 'last'], function (err, docs){ + // docs is an array of partially-`init`d documents + }) + +## Model#findOne + +Same as `Model#find`, but only receives a single document as second parameter: + + Model.findOne({ age: 5}, function (err, doc){ + // doc is a Document + }); + +## Model#findById + +Same as `findById`, but receives a value to search a document by their `_id` +key. This value is subject to casting, so it can be a hex string or a proper +ObjectId. + +## count + + Model.count(query, callback) + +## Query + +Each of these methods returns a Query. If you don't pass a callback to these +methods, the Query can be continued to be modified (such as adding options, +fields, etc), before it's `exec`d. + + var query = Model.find({}); + + query.where('field', 5); + query.limit(5); + query.skip(100); + + // query.executed == false + + query.exec (function (err, docs) { + // called when the `query.complete` or `query.error` are called + // internally + }); + + // query.executed == true diff --git a/node_modules/mongoose/docs/getters-setters.md b/node_modules/mongoose/docs/getters-setters.md new file mode 100644 index 0000000..7cf7b94 --- /dev/null +++ b/node_modules/mongoose/docs/getters-setters.md @@ -0,0 +1,52 @@ +Getters and Setters +==================== + +Getters and setters help you change how you get and set the attributes defined by the keys and values in the underlying raw document. + +## Setters + +Setters allow you to transform the mongoose document's data before it gets to the raw mongodb document and is set as a value on an actual key. + +Suppose you are implementing user registration for a website. User provide an email and password, which gets saved to mongodb. The email is a string that you will want to normalize to lower case, in order to avoid one email having more than one account -- e.g., otherwise, avenue@q.com can be registered for 2 accounts via avenue@q.com and AvEnUe@Q.CoM. + +You can set up email lower case normalization easily via a Mongoose setter. Note in the following snippet that setters (and also getters) are defined in the `Schema`: + + function toLower (v) { + return v.toLowerCase(); + } + + var UserSchema = new Schema({ + email: { type: String, set: toLower } + }); + + var User = mongoose.model('User', UserSchema); + var user = new User({email: 'AVENUE@Q.COM'}); + + console.log(user.email); // 'avenue@q.com' + + +As you can see above, setters allow you to transform the data before it gets to the raw mongodb document and is set as a value on an actual key. + +## Getters + +Getters allow you to transform the representation of the data as it travels from the raw mongodb document to the value that you see. + +Suppose you are storing credit card numbers and you want to hide everything except the last 4 digits to the mongoose user. You can do so by defining a getter in the following way (again, notice that getters are defined in the `Schema`): + + function obfuscate (cc) { + return '****-****-****-' + cc.slice(cc.length-4, cc.length); + } + + var AccountSchema = new Schema({ + creditCardNumber: { type: String, get: obfuscate } + }); + + var Account = mongoose.model('Account', AccountSchema); + + Account.findById( someId, function (err, found) { + console.log(found.creditCardNumber); // '****-****-****-1234' + }); + +## Summary + +Setters are intended to modify the underlying raw data. Getters are intended to transform (but not modify at the raw data level) the underlying raw data into something that the user expects to see. They are both defined in the `Schema` definition. diff --git a/node_modules/mongoose/docs/indexes.md b/node_modules/mongoose/docs/indexes.md new file mode 100644 index 0000000..76e0ed7 --- /dev/null +++ b/node_modules/mongoose/docs/indexes.md @@ -0,0 +1,31 @@ + +Indexes +======= + +Indexes are defined through `ensureIndex` every time a model is compiled for a +certain connection / database. This means that indexes will only be ensured +once during the lifetime of your app. + +## Definition + +Regular indexes: + + var User = new Schema({ + name: { type: String, index: true } + }) + +Unique indexes: + + var User = new Schema({ + name: { type: String, unique: true } + }) + + // or + + var User = new Schema({ + name: { type: String, index: { unique: true } } + }) + +Compound indexes are defined on the `Schema` + + User.index({ first: 1, last: -1 }) diff --git a/node_modules/mongoose/docs/methods-statics.md b/node_modules/mongoose/docs/methods-statics.md new file mode 100644 index 0000000..999972e --- /dev/null +++ b/node_modules/mongoose/docs/methods-statics.md @@ -0,0 +1,44 @@ +Methods +======= + +Methods can be defined by calling the 'method' method of the schema you wish +to attach it to and passing a JSON object containing the method. + +## Adding a method to a model + + AccountSchema.method({ + changeEmail: function(edit_email,callback){ + this.email = edit_email; + this.save(callback); + } + }); + +You can now call this by doing something like + + // Assuming you've obtained an account document model instance from mongo called a + a.changeEmail('example@somedomain.com',function(){ + console.log('changed account email'); + }); + +Statics +======= + +Similar to methods, statics can be defined by calling the 'static' method of the schema you wish +to attach it to and passing a JSON object containing the method. Here because it is a static +you no longer have access to 'this'. + +## Adding a static function to the model + + AccountSchema.static({ + hashPassword: function(unhashed_password){ + var salt = '_should_make_this_salt_dynamic'; + var hash = hashlib.sha1(unhashed_password+salt); + return hash; + } + }); + +You can now call this by doing something like + + // Account is the overall mongoose model not an instance + var hashed_pw = Account.hashPassword('mypassword'); + diff --git a/node_modules/mongoose/docs/middleware.md b/node_modules/mongoose/docs/middleware.md new file mode 100644 index 0000000..68eec6f --- /dev/null +++ b/node_modules/mongoose/docs/middleware.md @@ -0,0 +1,64 @@ + +Middleware +========== + +Middleware are defined at the Schema level and are applied when the methods +`init` (when a document is initialized with data from MongoDB), `save`, and +`remove` are called on a document instance. + +There's two types of middleware, determined by the signature of the function +you define (ie: the parameters your function accepts): + +- Serial + Serial middleware are defined like: + + schema.pre(methodName, function (next) { + // ... + }) + + They're executed one after the other, when each middleware calls `next`. + +- Parallel + Parallel middleware offer more fine-grained flow control, and are defined + like + + schema.pre(methodName, function (next, done) { + // ... + }) + + Parallel middleware can `next()` immediately, but the final argument will be + called when all the parallel middleware have called `done()`. + +## Use cases + +Middleware are useful for: + +- Complex validation +- Removing dependent documents when a certain document is removed (eg: +removing a user removes all his blogposts) +- Asynchronous defaults +- Asynchronous tasks that a certain action triggers. For example: + - Triggering custom events + - Creating notifications + - Emails + +and many other things. They're specially useful for atomizing model logic +and avoiding nested blocks of async code. + +## Error handling + +If any middleware calls `next` or `done` with an `Error` instance, the flow is +interrupted, and the error is passed to the function passed as an argument. + +For example: + + schema.pre('save', function (next) { + // something goes wrong + next(new Error('something went wrong')); + }); + + // later... + + myModel.save(function (err) { + // err can come from a middleware + }); diff --git a/node_modules/mongoose/docs/model-definition.md b/node_modules/mongoose/docs/model-definition.md new file mode 100644 index 0000000..4457ce0 --- /dev/null +++ b/node_modules/mongoose/docs/model-definition.md @@ -0,0 +1,136 @@ + +Defining a model +================ + +Models are defined by passing a `Schema` instance to `mongoose.model`. + + mongoose.model('MyModel', mySchema); + // mySchema is + +You can easily access the `Schema` constructor from the `mongoose` singleton: + + var mongoose = require('mongoose') + , Schema = mongoose.Schema; + + var mySchema = new Schema({ + // my props + }); + +Models are then accessed from `mongoose` if you want to use a single +connection: + + // connect the `mongoose` instance + mongoose.connect('mongodb://host/db'); + + var BlogPost = mongoose.model('BlogPost'); + +Or from a `Connection` instance if you want to use multiple +databases/connections: + + var db = mongoose.createConnection('mongodb://host/db') + , BlogPost = db.model('BlogPost'); + +**Important**: the actual interaction with the data happens with the `Model` +that you obtain through `mongoose.model` or `db.model`. That's the object that +you can instantiate or that you can call `.find()`, `.findOne()`, etc upon. +Don't confuse schemas and actual models! + +## Defining your keys + +The `Schema` constructor receives an object representation of your schemas as +its first parameter. If you want to add more keys later, `Schema#add` provides +the same functionality. + +Unlike older versions of mongoose, defining the data types is now a main part +of defining your models. Your schema is constructed by passing all the +JavaScript natives that you know (Schema, Number, Date) as well as others +exclusive to MongoDb (for example `Schema.ObjectId`). + + var ObjectId = Schema.ObjectId; + + var PostSchema = new Schema({ + owner : ObjectId + , title : String + , date : Date + }); + +### Defining documents within documents + +To define an array of documents that follows a certain schema, make the value +an array with the schema constructor inside. + +For example, let's assume we want to have a collection of comments within a +blogpost, and we want the to be subject to casting, validation, and other +functionality provided by models: + + var Comment = new Schema({ + body : String + , date : Date + }); + + var Post = new Schema({ + title : String + , comments : [Comment] + }); + +This will allow you to interact very easily with subdocuments later on. For +more information, refer to the chapter on embedded documents that's part of +this documentation. + +### Defining custom options for keys + +Each key that you define is internally mapped to a `SchemaType`. Bear in mind, a +Schema is not something that you interact directly with, but it's a way to +describe to Mongoose what your want your data to look like, and how you want +it to behave. + +`SchemaType`s take care of validation, casting, defaults, and other general +options. Some functionality is exclusive to certain types of `SchemaType`s, for +example only numbers support `min` and `max` values. + +In order to customize some of these options directly from the definition of +your model, set your key to an object with the format `{ type: {Type}, … }`. + + var Person = new Schema({ + title : { type: String, required: true } + , age : { type: Number, min: 5, max: 20 } + , meta : { + likes : [String] + , birth : { type: Date, default: Date.now } + } + }); + +Those options are functions that are called on each SchemaType. +If you want to define options later on, you could access a certain key through +the `path` function: + + Person.path('age').max(400); + + Person.path('meta.birth').set(function (v) { + // this is a setter + }); + + Person.path('title').validate(function (v) { + return v.length > 50; + }); + +Some of the options are versatile. `default` takes a `Function` or a value. +`validate` takes a `Function` or a `RegExp`. More information on these can be +found in other chapters. + +## Beyond keys: Middleware + +Middleware are special user-defined functions that are called transparently +when certain native methods are called on `Document` instances (`init`, `save` +and `remove`). + +Let's say that you want to email a certain user when his document changes. +You'd then define a hook on the User schema like this: + + User.pre('save', function (next) { + email(this.email, 'Your record has changed'); + next(); + }); + +More information about the specifics of middleware can be found in the +appropriate chapter. diff --git a/node_modules/mongoose/docs/validation.md b/node_modules/mongoose/docs/validation.md new file mode 100644 index 0000000..496d5c2 --- /dev/null +++ b/node_modules/mongoose/docs/validation.md @@ -0,0 +1,90 @@ + +Validation in models +==================== + +Before we get into the specifics of validation syntax, please keep the +following rules in mind: + +- Validation is defined in the `Schema` + +- Validation occurs when a document attempts to be saved, after defaults have +been applied. + +- Mongoose doesn't care about complex error message construction. Errors have +type identifiers. For example, `"min"` is the identifier for the error +triggered when a number doesn't meet the minimum value. The path and value +that triggered the error can be accessed in the `ValidationError` object. + +- Validation is an internal piece of middleware + +- Validation is asynchronously recursive: when you call `Model#save`, embedded + documents validation is executed. If an error happens, your `Model#save` + callback receives it. + +## Simple validation + +Simple validation is declared by passing a function to `validate` and an error +type to your `SchemaType` (please read the chapter on model definition to learn +more about schemas). + + function validator (v) { + return v.length > 5; + }; + + new Schema({ + name: { type: String, validate: [validator, 'my error type'] } + }) + +If you find this syntax too clumsy, you can also define the type + + var schema = new Schema({ + name: String + }) + +and then your validator + + schema.path('name').validate(function (v) { + return v.length > 5; + }, 'my error type'); + +## Regular expressions + +If you want to test a certain value against a regular expression: + + var schema = new Schema({ + name: { type: String, validate: /[a-z]/ } + }); + +## Asynchronous validation + +If you define a validator function with two parameters, like: + + schema.path('name').validate(function (v, fn) { + // my logic + }, 'my error type'); + +Then the function `fn` has to be called with `true` or `false`, depending on +whether the validator passed. This allows for calling other models and querying +data asynchronously from your validator. + +## Built in validators + +- For Strings: + - `enum`: takes a list of allowed values. Example: + + var Post = new Schema({ + type: { type: String, enum: ['page', 'post', 'link'] } + }) + +- For Numbers: + - `min`: minimum value + + var Person = new Schema({ + age: { type: Number, min: 5 } + }) + + - `max`: maxmimum value + + var Person = new Schema({ + age: { type: Number, max: 100 } + }) diff --git a/node_modules/mongoose/docs/virtuals.md b/node_modules/mongoose/docs/virtuals.md new file mode 100644 index 0000000..97a3c01 --- /dev/null +++ b/node_modules/mongoose/docs/virtuals.md @@ -0,0 +1,79 @@ +Virtual attributes +==================== + +Mongoose supports virtual attributes. Virtual attributes are attributes +that are convenient to have around but that do not get persisted to mongodb. + +An example is helpful. + +## Example +Take the following schema: + + var PersonSchema = new Schema({ + name: { + first: String + , last: String + } + }); + + var Person = mongoose.model('Person', PersonSchema); + + var theSituation = new Person({name: { first: 'Michael', last: 'Sorrentino' }}); + +Suppose you want to write `theSituation`'s full name. You could do so via: + console.log( theSituation.name.first + ' ' + theSituation.name.last ); + +It is more convenient to define a virtual attribute, `name.full`, so you can instead write: + + console.log( theSituation.name.full ); + +To do so, you can declare a virtual attribute on the Schema, `Person`: + + PersonSchema.virtual('name.full') + .get( function () { + return this.name.first + ' ' + this.name.last; + }); + +So when you get `name.full`, via + + theSituation.name.full; + +the implementation ends up invoking the getter function + + function () { + return this.name.first + ' ' + this.name.last; + } + +and returning it. + +It would also be nice to be able to set `this.name.first` and `this.name.last` by setting `this.name.full`. For example, it would be nice if we wanted to change theSituation's `name.first` and `name.last` to 'The' and 'Situation' respectively just by invoking: + + theSituation.set('name.full', 'The Situation'); + +Mongoose allows you to do this, too, via virtual attribute setters. You can define a virtual attribute setter thusly: + + PersonSchema.virtual('name.full') + .get( function () { + return this.name.first + ' ' + this.name.last; + }) + .set( function (setFullNameTo) { + var split = setFullNameTo.split(' ') + , firstName = split[0], lastName = split[1]; + this.set('name.first', firstName); + this.set('name.last', lastName); + }); + +Then, when you invoke: + + theSituation.set('name.full', 'The Situation'); + +and you save the document, then `name.first` and `name.last` will be changed in monbodb, but the mongodb document will not have persisted a `name.full` key or value to the database: + + theSituation.save( function (err) { + Person.findById(theSituation._id, function (err, found) { + console.log(found.name.first); // 'The' + console.log(found.name.last); // 'Situation' + }); + }); + +If you want attributes that you can get and set but that are not themselves persisted to mongodb, virtual attributes is the Mongoose feature for you. diff --git a/node_modules/mongoose/examples/schema.js b/node_modules/mongoose/examples/schema.js new file mode 100644 index 0000000..3ea6f16 --- /dev/null +++ b/node_modules/mongoose/examples/schema.js @@ -0,0 +1,74 @@ + +/** + * Module dependencies. + */ + +var mongoose = require('mongoose') + , Schema = mongoose.Schema; + +/** + * Schema definition + */ + +var BlogPost = new Schema({ + title : String + , slug : String + , date : Date + , comments : [Comments] +}); + +// recursive embedded-document schema + +var Comments = new Schema(); + +Comments.add({ + title : { type: String, index: true } + , date : Date + , body : String + , comments : [Comments] +}); + +/** + * Accessing a specific schema type by key + */ + +BlogPost.path('date') + .default(function(){ + return new Date() + }) + .set(function(v){ + return v == 'now' ? new Date() : v; + }); + +/** + * Pre hook. + */ + +BlogPost.pre('save', function(next, done){ + emailAuthor(done); // some async function + next(); +}); + +/** + * Plugins + */ + +function slugGenerator (options){ + options = options || {}; + var key = options.key || 'title'; + + return function slugGenerator(schema){ + schema.path(key).set(function(v){ + this.slug = v.toLowerCase().replace(/[^a-z0-9]/g, '').replace(/-+/g, ''); + return v; + }); + }; +}; + +BlogPost.plugin(slugGenerator()); + +/** + * Define model. + */ + +mongoose.model('BlogPost', BlogPost); diff --git a/node_modules/mongoose/index.js b/node_modules/mongoose/index.js new file mode 100644 index 0000000..e10d5ab --- /dev/null +++ b/node_modules/mongoose/index.js @@ -0,0 +1,7 @@ + +/** + * Export lib/mongoose + * + */ + +module.exports = require('./lib/mongoose/'); diff --git a/node_modules/mongoose/lib/mongoose/collection.js b/node_modules/mongoose/lib/mongoose/collection.js new file mode 100644 index 0000000..c4d5e79 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/collection.js @@ -0,0 +1,167 @@ + +/** + * Collection constructor + * + * @param {String} collection name + * @param {Collection} connection object + * @api public + */ + +function Collection (name, conn) { + this.name = name; + this.conn = conn; + this.buffer = true; + this.queue = []; + if (this.conn.readyState == 1) this.onOpen(); +}; + +/** + * The collection name + * + * @api public + */ + +Collection.prototype.name; + +/** + * The Connection instance + * + * @api public + */ + +Collection.prototype.conn; + +/** + * Called when the database connects + * + * @api private + */ + +Collection.prototype.onOpen = function () { + var self = this; + this.buffer = false; + self.doQueue(); +}; + +/** + * Called when the database disconnects + * + * @api private + */ + +Collection.prototype.onClose = function () { + this.buffer = true; +}; + +/** + * Adds a callback to the queue + * + * @param {String} method name + * @param {Array} arguments + * @api private + */ + +Collection.prototype.addQueue = function (name, args) { + this.queue.push([name, args]); + return this; +}; + +/** + * Executes the current queue + * + * @api private + */ + +Collection.prototype.doQueue = function () { + for (var i = 0, l = this.queue.length; i < l; i++){ + this[this.queue[i][0]].apply(this, this.queue[i][1]); + } + this.queue = []; + return this; +}; + +/** + * Ensure index function + * + * @api private + */ + +Collection.prototype.ensureIndex = function(){ + throw new Error('Collection#ensureIndex unimplemented by driver'); +}; + +/** + * FindAndModify command + * + * @api private + */ + +Collection.prototype.findAndModify = function(){ + throw new Error('Collection#findAndModify unimplemented by driver'); +}; + +/** + * FindOne command + * + * @api private + */ + +Collection.prototype.findOne = function(){ + throw new Error('Collection#findOne unimplemented by driver'); +}; + +/** + * Find command + * + * @api private + */ + +Collection.prototype.find = function(){ + throw new Error('Collection#find unimplemented by driver'); +}; + +/** + * Insert command + * + * @api private + */ + +Collection.prototype.insert = function(){ + throw new Error('Collection#insert unimplemented by driver'); +}; + +/** + * Update command + * + * @api private + */ + +Collection.prototype.save = function(){ + throw new Error('Collection#save unimplemented by driver'); +}; + +/** + * Insert command + * + * @api private + */ + +Collection.prototype.update = function(){ + throw new Error('Collection#update unimplemented by driver'); +}; + +/** + * getIndexes command + * + * @api private + */ + +Collection.prototype.getIndexes = function(){ + throw new Error('Collection#getIndexes unimplemented by driver'); +}; + +/** + * Module exports. + */ + +module.exports = Collection; diff --git a/node_modules/mongoose/lib/mongoose/compat.js b/node_modules/mongoose/lib/mongoose/compat.js new file mode 100644 index 0000000..645fe40 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/compat.js @@ -0,0 +1,19 @@ + +/** + * Module dependencies. + */ + +var mongoose = require('./') + , Mongoose = mongoose.Mongoose; + +/** + * Support for old way of defining models. + * - mongoose.model('Name', { definition }); + */ + +var oldModel = Mongoose.prototype.model; + +Mongoose.prototype.model = function(){ + oldModel.apply(this, arguments); +}; + diff --git a/node_modules/mongoose/lib/mongoose/connection.js b/node_modules/mongoose/lib/mongoose/connection.js new file mode 100644 index 0000000..12494bf --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/connection.js @@ -0,0 +1,409 @@ + +/** + * Module dependencies. + */ + +var url = require('url') + , utils = require('./utils') + , EventEmitter = utils.EventEmitter + , driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native' + , Model = require('./model') + , Schema = require('./schema') + , Collection = require(driver + '/collection'); + +/** + * Connection constructor. For practical reasons, a Connection equals a Db + * + * @param {Mongoose} mongoose base + * @api public + */ + +function Connection (base) { + this.base = base; + this.collections = {}; + this.models = {}; +}; + +/** + * Inherit from EventEmitter. + * + */ + +Connection.prototype.__proto__ = EventEmitter.prototype; + +/** + * Connection ready state: + * 0 = Disconnected + * 1 = Connected + * 2 = Connecting + * 3 = Disconnecting + * + * @api public + */ + +Connection.prototype.readyState = 0; + +/** + * A hash of the collections associated with this connection + * + * @param text + */ + +Connection.prototype.collections; + +/** + * The mongodb.Db instance, set when the connection is opened + * + * @api public + */ + +Connection.prototype.db; + +/** + * Establishes the connection + * + * @param {String} mongodb://uri + * @return {Connection} self + * @api public + */ + +Connection.prototype.open = function (host, database, port, callback) { + var self = this + , uri; + + // if we've been supplied an uri + if (typeof database != 'string'){ + uri = url.parse(host); + host = uri.hostname; + port = uri.port || 27017; + callback = database; + database = uri.pathname.replace(/\//g, ''); + } else { + callback = callback || port; + port = typeof port == 'number' ? port : 27017; + } + + // make sure we can open + if (this.readyState != 0){ + if ('function' == typeof callback) + callback(new Error('Trying to open unclosed connection')); + return this; + } + + // handle authentication + if (uri && uri.auth){ + var auth = uri.auth.split(':'); + this.user = auth[0]; + this.pass = auth[1]; + } else + this.user = this.pass = undefined; + + if (!host) { + if ('function' == typeof callback) + callback(new Error('Please provide a valid hostname.')); + return this; + } + + if (!database) { + if ('function' == typeof callback) + callback(new Error('Please provide a database to connect to.')); + return this; + } + + this.name = database; + this.host = host; + this.port = port; + + // signal connecting + this.readyState = 2; + this.emit('opening'); + + // open connection + this.doOpen(function (err) { + if (err) { + if (typeof callback == 'function') + callback(err); + } else { + self.onOpen(); + + if (typeof callback == 'function') + callback(null); + } + }); + + return this; +}; + +/** + * Connects to a replica set. + * + * Supply a comma-separted list of mongodb:// URIs. You only need to specify + * the database name and/or auth to one of them. + * + * @param {String} comma-separated mongodb:// URIs + * @param {Function} optional callback + */ + +Connection.prototype.openSet = function (uris, database, callback) { + var uris = uris.split(',') + , self = this; + + if (uris.length < 2) { + if (callback) callback(new Error('Please provide comma-separated URIs')); + return this; + } + + // signal connecting + this.readyState = 2; + this.emit('opening'); + + this.host = []; + this.port = []; + + if ('function' == typeof database) + callback = database; + else + this.name = database; + + uris.forEach(function (uri) { + var uri = url.parse(uri); + + self.host.push(uri.hostname); + self.port.push(uri.port || 27017); + + if (!self.name && uri.pathname.replace(/\//g, '')) + self.name = uri.pathname.replace(/\//g, ''); + + if (!self.user && uri.auth) { + var auth = uri.auth.split(':'); + self.user = auth[0]; + self.pass = auth[1]; + } + }); + + if (!this.name) { + if (callback) + callback(new Error('No database name provided for replica set')); + return; + } + + // open connection + this.doOpenSet(function (err) { + if (err) { + if (typeof callback == 'function') + callback(err); + } else { + self.onOpen(); + + if (typeof callback == 'function') + callback(null); + } + }); +}; + +/** + * Called when the connection is opened + * + * @api private + */ + +Connection.prototype.onOpen = function () { + var self = this; + + function open () { + self.readyState = 1; + + // avoid having the collection subscribe to our event emitter + // to prevent 0.3 warning + for (var i in self.collections) + self.collections[i].onOpen(); + + self.emit('open'); + }; + + // re-authenticate + if (self.user && self.pass) + self.db.authenticate(self.user, self.pass, open); + else + open(); +}; + +/** + * Closes the connection + * + * @param {Function} optional callback + * @return {Connection} self + * @api public + */ + +Connection.prototype.close = function (callback) { + var self = this + , callback = callback || function(){}; + + switch (this.readyState){ + case 0: // disconnected + callback(null); + break; + + case 1: // connected + this.readyState = 3; + this.doClose(function(err){ + if (err){ + callback(err); + } else { + self.onClose(); + callback(null); + } + }); + break; + + case 2: // connecting + this.once('open', function(){ + self.close(callback); + }); + break; + + case 3: // disconnecting + this.once('close', function () { + callback(null); + }); + break; + } + + return this; +}; + +/** + * Called when the connection closes + * + * @api private + */ + +Connection.prototype.onClose = function () { + this.readyState = 0; + + // avoid having the collection subscribe to our event emitter + // to prevent 0.3 warning + for (var i in this.collections) + this.collections[i].onClose(); + + this.emit('close'); +}; + +/** + * Retrieves a collection, creating it if not cached. + * + * @param {String} collection name + * @return {Collection} collection instance + * @api public + */ + +Connection.prototype.collection = function (name) { + if (!(name in this.collections)) + this.collections[name] = new Collection(name, this); + return this.collections[name]; +}; + +/** + * Defines a model or retrieves it + * + * @param {String} model name + * @param {Schema} schema object + * @param {String} collection name (optional, induced from model name) + * @api public + */ + +Connection.prototype.model = function (name, schema, collection) { + if (!(schema instanceof Schema)) { + collection = schema; + schema = null; + } + + collection || (collection = utils.toCollectionName(name)); + + // look up models for the collection + if (!this.models[collection]) + this.models[collection] = {}; + + if (!this.models[collection][name]) { + var model = this.base.model(name, schema, collection, true) + , Model; + + if (model.prototype.connection != this){ + Model = function Model (){ + model.apply(this, arguments); + }; + + Model.__proto__ = model; + Model.prototype.__proto__ = model.prototype; + Model.prototype.db = this; + Model.prototype.collection = this.collection(collection); + Model.init(); + } + + this.models[collection][name] = Model || model; + } + + return this.models[collection][name]; +}; + +/** + * Set profiling level. + * + * @param {Int|String} level - Either off (0), slow (1), or all (2) + * @param {Int} [ms] If profiling `level` is set to 1, this determines + * the threshold in milliseconds above which queries + * will be logged. Defaults to 100. (optional) + * @param {Function} callback + * @api public + */ + +Connection.prototype.setProfiling = function (level, ms, callback) { + if (1 !== this.readyState) { + return this.on('open', this.setProfiling.bind(this, level, ms, callback)); + } + + if (!callback) callback = ms, ms = 100; + + var cmd = {}; + + switch (level) { + case 0: + case 'off': + cmd.profile = 0; + break; + case 1: + case 'slow': + cmd.profile = 1; + if ('number' !== typeof ms) { + ms = parseInt(ms, 10); + if (isNaN(ms)) ms = 100; + } + cmd.slowms = ms; + break; + case 2: + case 'all': + cmd.profile = 2; + break; + default: + return callback(new Error('Invalid profiling level: '+ level)); + } + + this.db.executeDbCommand(cmd, function (err, resp) { + if (err) return callback(err); + + var doc = resp.documents[0]; + + err = 1 === doc.ok + ? null + : new Error('Could not set profiling level to: '+ level) + + callback(err, doc); + }); +}; + +/** + * Module exports. + */ + +module.exports = Connection; diff --git a/node_modules/mongoose/lib/mongoose/document.js b/node_modules/mongoose/lib/mongoose/document.js new file mode 100644 index 0000000..6d9c7a2 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/document.js @@ -0,0 +1,775 @@ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , MongooseError = require('./error') + , MixedSchema = require('./schema/mixed') + , Schema = require('./schema') + , utils = require('./utils') + , clone = utils.clone + , inspect = require('util').inspect + , ActiveRoster = utils.StateMachine.ctor('require', 'modify', 'init') + , deepEqual = utils.deepEqual + , hooks = require('hooks'); + +/** + * Document constructor. + * + * @param {Object} values to set + * @api private + */ + +function Document (obj) { + this.doc = this.buildDoc(); + this.activePaths = new ActiveRoster(); + var self = this; + this.schema.requiredPaths.forEach( function (path) { + self.activePaths.require(path); + }); + this.saveError = null; + this.isNew = true; + if (obj) this.set(obj); + this.registerHooks(); + this.doQueue(); + this.errors = undefined; +}; + +/** + * Inherit from EventEmitter. + */ + +Document.prototype.__proto__ = EventEmitter.prototype; + +/** + * Base Mongoose instance for the model. Set by the Mongoose instance upon + * pre-compilation. + * + * @api public + */ + +Document.prototype.base; + +/** + * Document schema as a nested structure. + * + * @api public + */ + +Document.prototype.schema; + +/** + * Whether the document is new. + * + * @api public + */ + +Document.prototype.isNew; + +/** + * Builds the default doc structure + * + * @api private + */ + +Document.prototype.buildDoc = function () { + var doc = {} + , self = this; + + this.schema.eachPath( function (i, type) { + var path = i.split('.') + , len = path.length; + + path.reduce( function (ref, piece, i) { + var _default; + if (i === len-1) { + _default = type.getDefault(self); + if ('undefined' !== typeof _default) + ref[piece] = _default; + } else + return ref[piece] || (ref[piece] = {}); + }, doc); + }); + + return doc; +}; + +/** + * Inits (hydrates) the document. + * + * @param {Object} document returned by mongo + * @api private + */ + +Document.prototype.init = function (doc, fn) { + var self = this; + this.isNew = false; + + function init (obj, doc, prefix) { + prefix = prefix || ''; + + var keys = Object.keys(obj) + , len = keys.length + , i; + + while (len--) { + i = keys[len]; + var path = prefix + i + , schema = self.schema.path(path); + + if (!schema && obj[i] && obj[i].constructor == Object){ // assume nested object + doc[i] = {}; + init(obj[i], doc[i], path + '.'); + } else { + if (obj[i] === null) { + doc[i] = null; + } else if (obj[i] !== undefined) { + if (schema) { + self.try(function(){ + doc[i] = schema.applySetters(schema.cast(obj[i], self), self); + }); + } else { + doc[i] = obj[i]; + } + } + // mark as hydrated + self.activePaths.init(path); + } + } + }; + + init(doc, self.doc); + + this.emit('init'); + + if (fn) + fn(null); + + return this; +}; + +// Set up middleware support +for (var k in hooks) { + Document.prototype[k] = Document[k] = hooks[k]; +} + +/** + * Sets a path, or many paths + * + * Examples: + * // path, value + * doc.set(path, value) + * + * // object + * doc.set({ + * path : value + * , path2 : { + * path : value + * } + * } + * + * @param {String|Object} key path, or object + * @param {Object} value, or undefined or a prefix if first parameter is an object + * @param @optional {Schema|String|...} specify a type if this is an on-the-fly attribute + * @api public + */ + +Document.prototype.set = function (path, val, type) { + var adhocs; + if (type) { + adhocs = this._adhocPaths || (this._adhocPaths = {}); + adhocs[path] = Schema.interpretAsType(path, type); + } + + if ('string' !== typeof path) { + + if (null === path || undefined === path) + return this.set(val, path); + + var prefix = val + ? val + '.' + : ''; + + if (path instanceof Document) { + path = path.doc; + } + + var keys = Object.keys(path); + var i = keys.length; + var key; + + while (i--) { + key = keys[i]; + if (!(this._path(prefix + key) instanceof MixedSchema) + && undefined !== path[key] + && null !== path[key] + && Object == path[key].constructor) { + this.set(path[key], prefix + key); + } else if (undefined !== path[key]) { + this.set(prefix + key, path[key]); + } + } + + return this; + } + + var schema = this._path(path) + , parts = path.split('.') + , obj = this.doc + , self = this; + + if (this.schema.pathType(path) === 'virtual') { + schema = this.schema.virtualpath(path); + schema.applySetters(val, this); + return this; + } + + // When using the $set operator the path to the field must already exist. + // Else mongodb throws: "LEFT_SUBFIELD only supports Object" + var pathToMark + , subpaths + , subpath; + + if (parts.length <= 1) { + pathToMark = path; + } else { + subpaths = parts.map(function (part, i) { + return parts.slice(0, i).concat(part).join('.'); + }); + + for (var i = 0, l = subpaths.length; i < l; i++) { + subpath = subpaths[i]; + if (this.isDirectModified(subpath) // earlier prefixes that are already + // marked as dirty have precedence + || this.get(subpath) === null) { + pathToMark = subpath; + break; + } + } + + if (!pathToMark) pathToMark = path; + } + + var markedModified = this.isDirectModified(pathToMark); + + if ((!schema || null === val || undefined === val) || + this.try(function(){ + val = schema.applySetters(schema.cast(val, self), self); + })) { + + var priorVal = this.get(path); + + if (!markedModified && !deepEqual(val, priorVal)) { + this.activePaths.modify(pathToMark); + } + + for (var i = 0, l = parts.length; i < l; i++) { + var next = i + 1 + , last = next === l; + + if (last) { + obj[parts[i]] = val; + } else { + // TODO - does this handle obj[parts[i]] === 0 ? + if (obj[parts[i]] && obj[parts[i]].constructor === Object) { + obj = obj[parts[i]]; + } else { + obj = obj[parts[i]] = {}; + } + } + } + } + + return this; +}; + +/** + * Gets a raw value from a path (no getters) + * + * @param {String} path + * @api private + */ + +Document.prototype.getValue = function (path) { + var parts = path.split('.') + , obj = this.doc + , part; + + for (var i = 0, l = parts.length; i < l-1; i++) { + part = parts[i]; + path = convertIfInt(path); + obj = obj.getValue + ? obj.getValue(part) // If we have an embedded array document member + : obj[part]; + if (!obj) return obj; + } + part = parts[l-1]; + path = convertIfInt(path); + return obj.getValue + ? obj.getValue(part) // If we have an embedded array document member + : obj[part]; +}; + +function convertIfInt (string) { + if (/^\d+$/.test(string)) { + return parseInt(string, 10); + } + return string; +} + +/** + * Sets a raw value for a path (no casting, setters, transformations) + * + * @param {String} path + * @param {Object} value + * @api private + */ + +Document.prototype.setValue = function (path, val) { + var parts = path.split('.') + , obj = this.doc; + + for (var i = 0, l = parts.length; i < l-1; i++) obj = obj[parts[i]]; + obj[parts[l-1]] = val; + + return this; +}; + +/** + * Triggers casting on a specific path + * + * @param {String} path + * @api public + */ + +Document.prototype.doCast = function (path) { + var schema = this.schema.path(path); + if (schema) + this.setValue(path, this.getValue(path)); +}; + +/** + * Gets a path + * + * @param {String} key path + * @param @optional {Schema|String|...} specify a type if this is an on-the-fly attribute + * @api public + */ + +Document.prototype.get = function (path, type) { + var adhocs; + if (type) { + adhocs = this._adhocPaths || (this._adhocPaths = {}); + adhocs[path] = Schema.interpretAsType(path, type); + } + + var schema = this._path(path) || this.schema.virtualpath(path) + , pieces = path.split('.') + , obj = this.doc; + + for (var i = 0, l = pieces.length; i < l; i++) { + obj = null === obj ? null : obj[pieces[i]]; + } + + if (schema) { + obj = schema.applyGetters(obj, this); + } + // TODO Cache obj + + return obj; +}; + +/** + * Finds the path in the ad hoc type schema list or + * in the schema's list of type schemas + * @param {String} path + * @param {Object} obj + * @api private + */ + +Document.prototype._path = function (path, obj) { + var adhocs = this._adhocPaths + , adhocType = adhocs && adhocs[path]; + if (adhocType) { + return adhocType; + } else { + return this.schema.path(path); + } +}; + +/** + * Commits a path, marking as modified if needed. Useful for mixed keys + * + * @api public + */ + +Document.prototype.markModified = +Document.prototype.commit = function (path) { + this.activePaths.modify(path); +}; + +/** + * Captures an exception that will be bubbled to `save` + * + * @param {Function} function to execute + * @param {Object} scope + */ + +Document.prototype.try = function (fn, scope) { + var res; + try { + fn.call(scope); + res = true; + } catch(e){ + this.error(e); + res = false; + }; + return res; +}; + +/** + * Checks if a path or any full path containing path as part of + * its path chain has been directly modified. + * + * e.g., if we set `documents.0.title` to 'newTitle' + * then we have directly modified `documents.0.title` + * but not directly modified `documents` or `documents.0`. + * Nonetheless, we still say `documents` and `documents.0` + * are modified. They just are not considered direct modified. + * The distinction is important because we need to distinguish + * between what has been directly modified and what hasn't so + * that we can determine the MINIMUM set of dirty data + * that we want to send to MongoDB on a Document save. + * + * @param {String} path + */ + +Document.prototype.isModified = function (path) { + var directModifiedPaths = Object.keys(this.activePaths.states.modify); + + var allPossibleChains = directModifiedPaths.reduce(function (list, path) { + var parts = path.split('.'); + return list.concat(parts.reduce(function (chains, part, i) { + return chains.concat(parts.slice(0, i).concat(part).join('.')); + }, [])); + }, []); + + return !!~allPossibleChains.indexOf(path); +}; + +/** + * Checks if a path has been directly set and modified. False if + * the path is only part of a larger path that was directly set. + * + * e.g., if we set `documents.0.title` to 'newTitle' + * then we have directly modified `documents.0.title` + * but not directly modified `documents` or `documents.0`. + * Nonetheless, we still say `documents` and `documents.0` + * are modified. They just are not considered direct modified. + * The distinction is important because we need to distinguish + * between what has been directly modified and what hasn't so + * that we can determine the MINIMUM set of dirty data + * that we want to send to MongoDB on a Document save. + * + * @param {String} path + */ + +Document.prototype.isDirectModified = function (path) { + return (path in this.activePaths.states.modify); +}; + +/** + * Checks if a certain path was initialized + * + * @param {String} path + */ + +Document.prototype.isInit = function (path) { + return (path in this.activePaths.states.init); +}; + +/** + * Validation middleware + * + * @param {Function} next + * @api private + */ + +Document.prototype.validate = function (next) { + var total = 0 + , self = this + , validating = {} + , validationError = null; + + if (!this.activePaths.some('require', 'init', 'modify')) + return next(); + + function validatePath (path) { + if (validating[path]) return; + total++; + process.nextTick(function(){ + var p = self.schema.path(path); + if (!p) return --total || next(); + + p.doValidate(self.getValue(path), function (err) { + if (err) { + validationError = validationError || new ValidationError(self); + validationError.errors[err.path] = err.message; + } + --total || + (validationError ? next(validationError) : next()); + }, self); + }); + validating[path] = true; + } + + this.activePaths.forEach('require', 'init', 'modify', function (path) { + validatePath(path); + }); + + return this; +}; + +/** + * Returns if the document has been modified + * + * @return {Boolean} + * @api public + */ + +Document.prototype.__defineGetter__('modified', function () { + return this.activePaths.some('modify'); +}); + +/** + * We override the schema setter to compile accessors + * + * @api private + */ + +function compile (tree, proto, prefix) { + var keys = Object.keys(tree) + , i = keys.length + , limb + , key; + + while (i--) { + key = keys[i]; + limb = tree[key]; + + define(key + , ((limb.constructor == Object + && Object.keys(limb).length) + && (!limb.type || limb.type.type) + ? limb + : null) + , proto + , prefix); + } +}; + +/** + * Defines the accessor named prop on the incoming prototype. + */ + +function define (prop, subprops, prototype, prefix) { + var prefix = prefix || '' + , path = (prefix ? prefix + '.' : '') + prop; + + if (subprops) { + + Object.defineProperty(prototype, prop, { + enumerable: true + , get: function ( ) { + if (!this.__getters) + this.__getters = {}; + + if (!this.__getters[path]) { + var nested = Object.create(this); + nested.toObject = function () { + return this.get(path); + }; + compile(subprops, nested, path); + this.__getters[path] = nested; + } + + return this.__getters[path]; + } + , set: function (v) { + return this.set(v, path); + } + }); + + } else { + + Object.defineProperty(prototype, prop, { + enumerable: true + , get: function ( ) { return this.get(path); } + , set: function (v) { return this.set(path, v); } + }); + } +}; + +Document.prototype.__defineSetter__('schema', function (schema) { + compile(schema.tree, this); + this._schema = schema; +}); + +/** + * We override the schema getter to return the internal reference + * + * @api private + */ + +Document.prototype.__defineGetter__('schema', function () { + return this._schema; +}); + +/** + * Register default hooks + * + * @api private + */ + +Document.prototype.registerHooks = function () { + var self = this; + + if (!this.save) return; + + this.pre('save', function checkForExistingErrors (next) { + if (self.saveError){ + next(self.saveError); + self.saveError = null; + } else { + next(); + } + }, function (err) { + this.db.emit('error', err); + }).pre('save', function validation (next) { + return self.validate.call(self, next); + }); +}; + +/** + * Registers an error + * TODO: handle multiple + * + * @param {Error} error + * @api private + */ + +Document.prototype.error = function (err) { + this.saveError = err; + return this; +}; + +/** + * Executes methods queued from the Schema definition + * + * @api private + */ + +Document.prototype.doQueue = function () { + if (this.schema && this.schema.callQueue) + for (var i = 0, l = this.schema.callQueue.length; i < l; i++) { + this[this.schema.callQueue[i][0]].apply(this, this.schema.callQueue[i][1]); + } + return this; +}; + +/** + * Gets the document + * + * @todo Should we apply getters? + * @return {Object} plain object + * @api public + */ + +Document.prototype.toObject = function (ref) { + if (ref) return this.doc; + return clone(this.doc, true); +}; + +/** + * Returns a JSON string for the document + * + * @return {String} JSON representation + * @api public + */ + +Document.prototype.toJSON = function () { + return this.toObject(); +}; + +/** + * Helper for console.log + * + * @api public + */ + +Document.prototype.inspect = function () { + return inspect(this.toObject(true)); +}; + +/** + * Returns true if the Document stores the same data as doc. + * @param {Document} doc to compare to + * @return {Boolean} + * @api public + */ + +Document.prototype.equals = function (doc) { + return this.get('_id') === doc.get('_id'); +}; + +/** + * Module exports. + */ + +module.exports = Document; + +/** + * Document Validation Error + */ + +function ValidationError (instance) { + MongooseError.call(this, "Validation failed"); + Error.captureStackTrace(this, arguments.callee); + this.name = 'ValidationError'; + this.errors = instance.errors = {}; +}; + +ValidationError.prototype.toString = function () { + return this.name + ': ' + Object.keys(this.errors).map(function (key) { + return this.errors[key]; + }, this).join(', '); +}; + +/** + * Inherits from MongooseError. + */ + +ValidationError.prototype.__proto__ = MongooseError.prototype; + +Document.ValidationError = ValidationError; + +/** + * Document Error + * + * @param text + */ + +function DocumentError () { + MongooseError.call(this, msg); + Error.captureStackTrace(this, arguments.callee); + this.name = 'DocumentError'; +}; + +/** + * Inherits from MongooseError. + */ + +DocumentError.prototype.__proto__ = MongooseError.prototype; + +exports.Error = DocumentError; diff --git a/node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/collection.js b/node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/collection.js new file mode 100644 index 0000000..ba1831a --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/collection.js @@ -0,0 +1,104 @@ + +/** + * Module dependencies. + */ + +var Collection = require('../../collection') + , MongoCollection = require('mongodb').Collection; + +/** + * Native collection + * + * @api private + */ + +function NativeCollection () { + Collection.apply(this, arguments); +}; + +/** + * Inherit from Collection. + */ + +NativeCollection.prototype.__proto__ = Collection.prototype; + +/** + * Called when the connection opens + * + * @api private + */ + +NativeCollection.prototype.onOpen = function () { + var self = this; + this.conn.db.collection(this.name, function(err, collection){ + if (!err){ + self.collection = collection; + Collection.prototype.onOpen.call(self); + } + }); +}; + +/** + * Called when the connection closes + * + * @api private + */ + +NativeCollection.prototype.onClose = function () { + Collection.prototype.onClose.call(this); +}; + +/** + * Copy the collection methods and make them subject to queues + */ + +for (var i in MongoCollection.prototype) + (function(i){ + NativeCollection.prototype[i] = function () { + // BENCHMARKME: is it worth caching the prototype methods? probably + if (!this.buffer){ + var collection = this.collection + , args = arguments + , self = this; + + process.nextTick(function(){ + collection[i].apply(collection, args); + }); + } else + this.addQueue(i, arguments); + }; + })(i); + +/** + * Implement getIndexes + * + * @param {Function} callback + * @api private + */ + +NativeCollection.prototype.getIndexes = NativeCollection.prototype.indexInformation; + +/** + * Override signature of ensureIndex. -native one is not standard. + * + * @param {Object} spec + * @param {Object} options + * @param {Function} callback + * @api public + */ + +var oldEnsureIndex = MongoCollection.prototype.ensureIndex; + +function noop () {}; + +MongoCollection.prototype.ensureIndex = function(fields, options, fn){ + if (!this.buffer) { + return oldEnsureIndex.apply(this, arguments); + } +}; + +/** + * Module exports. + */ + +module.exports = NativeCollection; diff --git a/node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/connection.js b/node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/connection.js new file mode 100644 index 0000000..ae25b8d --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/connection.js @@ -0,0 +1,84 @@ +/** + * Module dependencies. + */ + +var Connection = require('../../connection') + , mongo = require('mongodb') + , Server = mongo.Server + , ReplSetServers = mongo.ReplSetServers; + +/** + * Connection for mongodb-native driver + * + * @api private + */ + +function NativeConnection() { + Connection.apply(this, arguments); +}; + +/** + * Inherits from Connection. + */ + +NativeConnection.prototype.__proto__ = Connection.prototype; + +/** + * Opens the connection + * + * @param {Function} callback + * @api private + */ + +NativeConnection.prototype.doOpen = function (fn) { + if (!this.db) + this.db = new mongo.Db(this.name, new mongo.Server(this.host, this.port)); + + this.db.open(fn); + + return this; +}; + +/** + * Opens a set connection + * + * @param {Function} callback + * @api private + */ + +NativeConnection.prototype.doOpenSet = function (fn) { + if (!this.db) { + var servers = [] + , ports = this.port; + + this.host.forEach(function (host, i) { + servers.push(new mongo.Server(host, ports[i], {})); + }); + + this.db = new mongo.Db(this.name, new ReplSetServers(servers, {})); + } + + this.db.open(fn); + + return this; +}; + + +/** + * Closes the connection + * + * @param {Function} callback + * @api private + */ + +NativeConnection.prototype.doClose = function (fn) { + this.db.close(); + if (fn) fn(); + return this; +} + +/** + * Module exports. + */ + +module.exports = NativeConnection; diff --git a/node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/objectid.js b/node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/objectid.js new file mode 100644 index 0000000..ee6d598 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/drivers/node-mongodb-native/objectid.js @@ -0,0 +1,43 @@ + +/** + * Module dependencies. + */ + +var ObjectId = require('mongodb').BSONPure.ObjectID; + +/** + * Constructor export + * + * @api private + */ + +var ObjectIdToString = ObjectId.toString.bind(ObjectId); + +module.exports = exports = ObjectId; +/** + * Creates an ObjectID for this driver + * + * @param {Object} hex string or ObjectId + * @api private + */ + +exports.fromString = function(str){ + // patch native driver bug in V0.9.6.4 + if (!('string' === typeof str && 24 === str.length)) { + throw new Error("Invalid ObjectId"); + } + + return ObjectId.createFromHexString(str); +}; + +/** + * Gets an ObjectId and converts it to string. + * + * @param {ObjectId} -native objectid + * @api private + */ + +exports.toString = function(oid){ + if (!arguments.length) return ObjectIdToString(); + return oid.toHexString(); +}; diff --git a/node_modules/mongoose/lib/mongoose/error.js b/node_modules/mongoose/lib/mongoose/error.js new file mode 100644 index 0000000..bd4ee61 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/error.js @@ -0,0 +1,25 @@ + +/** + * Mongoose error + * + * @api private + */ + +function MongooseError (msg) { + Error.call(this); + Error.captureStackTrace(this, arguments.callee); + this.message = msg; + this.name = 'MongooseError'; +}; + +/** + * Inherits from Error. + */ + +MongooseError.prototype.__proto__ = Error.prototype; + +/** + * Module exports. + */ + +module.exports = MongooseError; diff --git a/node_modules/mongoose/lib/mongoose/index.js b/node_modules/mongoose/lib/mongoose/index.js new file mode 100644 index 0000000..aa9665b --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/index.js @@ -0,0 +1,382 @@ + +/** + * Module dependencies. + */ + +var Schema = require('./schema') + , SchemaType = require('./schematype') + , VirtualType = require('./virtualtype') + , SchemaTypes = Schema.Types + , SchemaDefaults = require('./schemadefault') + , Types = require('./types') + , Query = require('./query') + , Promise = require('./promise') + , Model = require('./model') + , Document = require('./document') + , utils = require('./utils'); + +/** + * Mongoose constructor. Most apps will only use one instance. + * + * @api public + */ + +function Mongoose () { + this.connections = []; + this.plugins = []; + this.models = {}; + this.modelSchemas = {}; + this.options = {}; + this.createConnection(); // default connection +}; + +/** + * Sets/gets mongoose options + * + * Examples: + * mongoose.set('test') // returns the 'test' value + * mongoose.set('test', value) // sets the 'test' value + * + * @param {String} key + * @param {String} value + * @api public + */ + +Mongoose.prototype.set = +Mongoose.prototype.get = function (key, value) { + if (arguments.length == 1) + return this.options[key]; + this.options[key] = value; + return this; +}; + +/** + * Creates a Connection instance. + * + * Examples: + * + * // with mongodb:// URI + * db = mongoose.createConnection('mongodb://localhost:port/database'); + * + * // with [host, database_name[, port] signature + * db = mongoose.createConnection('localhost', 'database', port) + * + * // initialize now, connect later + * db = mongoose.createConnection(); + * db.open('localhost', 'database', port); + * + * @param {String} mongodb:// URI + * @return {Connection} the created Connection object + * @api public + */ + +Mongoose.prototype.createConnection = function () { + var conn = new Connection(this); + this.connections.push(conn); + if (arguments.length) + conn.open.apply(conn, arguments); + return conn; +}; + +/** + * Creates a replica set connection + * + * @see {Mongoose#createConnection} + * @api public + */ + +Mongoose.prototype.createSetConnection = function () { + var conn = new Connection(this); + this.connections.push(conn); + if (arguments.length) + conn.openSet.apply(conn, arguments); + return conn; +}; + +/** + * Connects the default mongoose connection + * + * @see {Mongoose#createConnection} + * @api public + */ + +Mongoose.prototype.connect = function (){ + this.connection.open.apply(this.connection, arguments); + return this; +}; + +/** + * Connects the default mongoose connection to a replica set + * + * @see {Mongoose#createConnection} + * @api public + */ + +Mongoose.prototype.connectSet = function (){ + this.connection.openSet.apply(this.connection, arguments); + return this; +}; + +/** + * Disconnects from all connections. + * + * @param {Function} optional callback + * @api public + */ + +Mongoose.prototype.disconnect = function (fn) { + var count = this.connections.length; + this.connections.forEach(function(conn){ + conn.close(function(err){ + if (err) return fn(err); + if (fn) + --count || fn(); + }); + }); + return this; +}; + +/** + * Defines a model or retrieves it + * + * @param {String} model name + * @param {Schema} schema object + * @param {String} collection name (optional, induced from model name) + * @param {Boolean} whether to skip initialization (defaults to false) + * @api public + */ + +Mongoose.prototype.model = function (name, schema, collection, skipInit) { + // normalize collection + if (!(schema instanceof Schema)) { + collection = schema; + schema = false; + } + + if ('boolean' === typeof collection) { + skipInit = collection; + collection = null; + } + + collection = collection || utils.toCollectionName(name); + + // look up models for the collection + if (!this.modelSchemas[name]) { + if (name in SchemaDefaults) { + schema = SchemaDefaults[name]; + } + + if (schema) { + this.modelSchemas[name] = schema; + for (var i = 0, l = this.plugins.length; i < l; i++) { + schema.plugin(this.plugins[i][0], this.plugins[i][1]); + } + } else { + throw new Error('Schema hasn\'t been registered for model "' + name + '".\n' + + 'Use mongoose.model(name, schema)'); + } + } + + var conn = this.connection + , model; + + if (!this.models[collection]) this.models[collection] = {}; + + if (!this.models[collection][name]) { + model = Model.compile(name + , this.modelSchemas[name] + , collection + , conn + , this); + + if (!skipInit) model.init(); + + this.models[collection][name] = model; + } + + return this.models[collection][name]; +}; + +/** + * Declares a plugin executed on Schemas. Equivalent to calling `.plugin(fn)` + * on each Schema you create. + * + * @param {Function} plugin callback + * @api public + */ + +Mongoose.prototype.plugin = function (fn, opts) { + this.plugins.push([fn, opts]); + return this; +}; + +/** + * Default connection + * + * @api public + */ + +Mongoose.prototype.__defineGetter__('connection', function(){ + return this.connections[0]; +}); + +/** + * Compat flag. + * + * @api public + */ + +var compat = false; + +exports.__defineGetter__('compat', function(){ + return compat; +}); + +exports.__defineSetter__('compat', function(v){ + compat = v; + if (v) require('./compat'); +}); + +/** + * Driver depentend APIs + */ + +var driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native'; + +/** + * Connection + * + * @api public + */ + +var Connection = require(driver + '/connection'); + +/** + * Collection + * + * @api public + */ + +var Collection = require(driver + '/collection'); + +/** + * Export default singleton. + * + * @api public + */ + +module.exports = exports = new Mongoose(); + +/** + * Collection + * + * @api public + */ + +exports.Collection = Collection; + +/** + * Connection + * + * @api public + */ + +exports.Connection = Connection; + +/** + * Exports Mongoose version + * + * @param version + */ + +exports.version = '1.7.4'; + +/** + * Export Mongoose constructor + * + * @api public + */ + +exports.Mongoose = Mongoose; + +/** + * Export Schema constructor + * + * @api public + */ + +exports.Schema = Schema; + +/** + * Export SchemaType constructor. + * + * @api public + */ + +exports.SchemaType = SchemaType; + +/** + * Export VirtualType constructor. + * + * @api public + */ + +exports.VirtualType = VirtualType; + +/** + * Export Schema types + * + * @api public + */ + +exports.SchemaTypes = SchemaTypes; + +/** + * Export types + * + * @api public + */ + +exports.Types = Types; + +/** + * Export Query + * + * @api public + */ + +exports.Query = Query; + +/** + * Export Promise + * + * @api public + */ + +exports.Promise = Promise; + +/** + * Export Model constructor + * + * @api public + */ + +exports.Model = Model; + +/** + * Export Document constructor + * + * @api public + */ + +exports.Document = Document; + +/** + * Export MongooseError + * + * @api public + */ + +exports.Error = require('./error'); + +exports.mongo = require('mongodb'); diff --git a/node_modules/mongoose/lib/mongoose/model.js b/node_modules/mongoose/lib/mongoose/model.js new file mode 100644 index 0000000..65b59e4 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/model.js @@ -0,0 +1,724 @@ + +/** + * Module dependencies. + */ + +var Document = require('./document') + , MongooseArray = require('./types/array') + , DocumentArray = require('./types/documentarray') + , MongooseError = require('./error') + , Query = require('./query') + , utils = require('./utils') + , EventEmitter = utils.EventEmitter + , merge = utils.merge + , Promise = require('./promise'); + +/** + * Model constructor + * + * @param {Object} values to set + * @api public + */ + +function Model (doc) { + Document.call(this, doc); +}; + +/** + * Inherits from Document. + */ + +Model.prototype.__proto__ = Document.prototype; + +/** + * Connection the model uses. Set by the Connection or if absent set to the + * default mongoose connection; + * + * @api public + */ + +Model.prototype.db; + +/** + * Collection the model uses. Set by Mongoose instance + * + * @api public + */ + +Model.prototype.collection; + +/** + * Model name. + * + * @api public + */ + +Model.prototype.name; + +/** + * Saves the document. + * + * @see Model#registerHooks + * @param {Function} callback + * @api public + */ + +function makeSaveHandler(promise, self) { + return function (err) { + if (err) return promise.error(err); + promise.complete(self); + self.emit('save', self); + promise = null; + self = null; + }; +}; + +/** + * Saves this document. + * + * @param {Function} fn + * @api public + */ + +Model.prototype.save = function (fn) { + var promise = new Promise(fn) + , options = {} + , self = this + , complete = makeSaveHandler(promise, self); + + if (this.options.safe) { + options.safe = true; + } + + if (this.isNew) { + // send entire doc + this.collection.insert(this.toObject(), options, complete); + this.isNew = false; + + this._dirty().forEach( function (dirt) { + var type = dirt.value; + if (type && type._path && type.doAtomics) { + type._atomics = {}; + } + }); + + } else { + var delta = this._delta(); + + if (Object.keys(delta).length) { + this.collection.update({ _id: this.doc._id }, delta, options, complete); + } else { + complete(null); + } + } + + // Clear 'modify'('dirty') cache + this.activePaths.clear('modify'); + this.schema.requiredPaths.forEach( function (path) { + self.activePaths.require(path); + }); +}; + +/** + * Returns the dirty paths / vals + * + * @api private + */ + +Model.prototype._dirty = function () { + var self = this; + + return this.activePaths.map('modify', function (path) { + return { path: path + , value: self.getValue(path) + , schema: self._path(path) }; + }); +} + +/** + * Produces a special query document of the modified properties. + * @api private + */ + +Model.prototype._delta = function () { + // send delta + var self = this + , delta + , useSet = this.options['use$SetOnSave']; + + return this._dirty().reduce(function (delta, data) { + var type = data.value + , schema = data.schema + , atomics, val, obj; + + if (type === null || type === undefined) { + if (!('$set' in delta)) + delta['$set'] = {}; + + delta['$set'][data.path] = type; + } else if (type._path && type.doAtomics) { + // a MongooseArray or MongooseNumber + atomics = type._atomics; + + var ops = Object.keys(atomics) + , i = ops.length + , op; + + while (i--) { + op = ops[i] + if (op === '$pushAll' || op === '$pullAll') { + if (atomics[op].length === 1) { + val = atomics[op][0]; + delete atomics[op]; + op = op.replace('All', ''); + atomics[op] = val; + } + } + val = atomics[op]; + obj = delta[op] = delta[op] || {}; + if (op === '$pull' || op === '$push') { + if (val.constructor !== Object) { + if (Array.isArray(val)) val = [val]; + // TODO Should we place pull and push casting into the pull and push methods? + val = schema.cast(val)[0]; + } + } + obj[data.path] = val.toObject + ? val.toObject() // If the value is an array + : Array.isArray(val) + ? val.map( function (mem) { + return mem.toObject + ? mem.toObject() + : mem.valueOf + ? mem.valueOf() + : mem; + }) + : val.valueOf + ? val.valueOf() // Numbers + : val; + } + type._atomics = {}; + } else { + // normalize MongooseArray or MongooseNumber + if (type instanceof MongooseArray) { + type = type.toObject(); + } else if (type._path) + type = type.valueOf(); + + if (useSet) { + if (!('$set' in delta)) + delta['$set'] = {}; + + delta['$set'][data.path] = type; + } else + delta[data.path] = type; + } + + return delta; + }, {}); +} + +/** + * Remove the document + * + * @param {Function} callback + * @api public + */ + +Model.prototype.remove = function (fn) { + if (this.removing || this.removed) + return this; + + if (!this.removing) { + var promise = this.removing = new Promise(fn) + , self = this; + + this.collection.remove({ _id: this.doc._id }, function (err) { + if (err) return promise.error(err); + promise.complete(); + self.emit('remove'); + }); + } + + return this; +}; + +/** + * Register hooks override + * + * @api private + */ + +Model.prototype.registerHooks = function () { + // make sure to pass along all the errors from subdocuments + this.pre('save', function (next) { + // we keep the error semaphore to make sure we don't + // call `save` unnecessarily (we only need 1 error) + var subdocs = 0 + , error = false + , self = this; + + var arrays = this.activePaths + .map('init', 'modify', function (i) { + return self.getValue(i); + }) + .filter(function (val) { + return (val && val instanceof DocumentArray && val.length); + }); + + if (!arrays.length) + return next(); + + arrays.forEach(function (array) { + subdocs += array.length; + array.forEach(function (value) { + if (!error) + value.save(function (err) { + if (!error) { + if (err) { + error = true; + next(err); + } else + --subdocs || next(); + } + }); + }); + }); + }, function (err) { + this.db.emit('error', err); + }); + + Document.prototype.registerHooks.call(this); +}; + +/** + * Shortcut to access another model. + * + * @param {String} model name + */ + +Model.prototype.model = function (name) { + return this.db.model(name); +}; + +/** + * Access the options defined in the schema + * + * @api private + */ + +Model.prototype.__defineGetter__('options', function () { + return this.schema ? this.schema.options : {}; +}); + +/** + * Give the constructor the ability to emit events. + */ + +for (var i in EventEmitter.prototype) + Model[i] = EventEmitter.prototype[i]; + +/** + * Called when the model compiles + * + * @api private + */ + +Model.init = function () { + // build indexes + var self = this + , indexes = this.schema.indexes + , count = indexes.length; + + indexes.forEach(function (index) { + self.collection.ensureIndex(index[0], index[1], function (err) { + if (err) return self.db.emit('error', err); + --count || self.emit('index'); + }); + }); +}; + +/** + * Document schema + * + * @api public + */ + +Model.schema; + +/** + * Database instance the model uses. + * + * @api public + */ + +Model.db; + +/** + * Collection the model uses. + * + * @api public + */ + +Model.collection; + +/** + * Define properties that access the prototype. + */ + +['db', 'collection', 'schema', 'options'].forEach(function(prop){ + Model.__defineGetter__(prop, function(){ + return this.prototype[prop]; + }); +}); + +/** + * Module exports. + */ + +module.exports = exports = Model; + +Model.remove = function (conditions, callback) { + if ('function' === typeof conditions) { + callback = conditions; + conditions = {}; + } + var query = new Query(conditions).bind(this, 'remove'); + if ('undefined' === typeof callback) + return query; + var cQuery; + if (cQuery = this._cumulativeQuery) { + merge(query._conditions, cQuery._conditions); + if (query.options && cQuery.options) + merge(query.options, cQuery.options); + delete this._cumulativeQuery; + } + if (!query.model) query.bind(this, 'remove'); + return query.remove(callback); +}; + +/** + * Finds documents + * + * Examples: + * // retrieve only certain keys + * MyModel.find({ name: /john/i }, ['name', 'friends'], function () { }) + * + * // pass options + * MyModel.find({ name: /john/i }, [], { skip: 10 } ) + * + * @param {Object} conditions + * @param {Object/Function} (optional) fields to hydrate or callback + * @param {Function} callback + * @api public + */ + +Model.find = function (conditions, fields, options, callback) { + if ('function' == typeof conditions) { + callback = conditions; + conditions = {}; + fields = null; + options = null; + } else if ('function' == typeof fields) { + callback = fields; + fields = null; + options = null; + } else if ('function' == typeof options) { + callback = options; + options = null; + } + + var query = new Query(conditions, options).select(fields).bind(this, 'find'); + + if ('undefined' === typeof callback) + return query; + + var cQuery; + if (cQuery = this._cumulativeQuery) { + merge(query._conditions, cQuery._conditions); + if (query._fields && cQuery._fields) + merge(query._fields, cQuery._fields); + if (query.options && cQuery.options) + merge(query.options, cQuery.options); + delete this._cumulativeQuery; + } + if (!query.model) + query.bind(this, 'find'); + return query.find(callback); +}; + +/** + * Finds by id + * + * @param {ObjectId/Object} objectid, or a value that can be casted to it + * @api public + */ + +Model.findById = function (id, fields, options, callback) { + return this.findOne({ _id: id }, fields, options, callback); +}; + +/** + * Finds one document + * + * @param {Object} conditions + * @param {Object/Function} (optional) fields to hydrate or callback + * @param {Function} callback + * @api public + */ + +Model.findOne = function (conditions, fields, options, callback) { + if ('function' == typeof options) { + // TODO Handle all 3 of the following scenarios + // Hint: Only some of these scenarios are possible if cQuery is present + // Scenario: findOne(conditions, fields, callback); + // Scenario: findOne(fields, options, callback); + // Scenario: findOne(conditions, options, callback); + callback = options; + options = null; + } else if ('function' == typeof fields) { + // TODO Handle all 2 of the following scenarios + // Scenario: findOne(conditions, callback) + // Scenario: findOne(fields, callback) + // Scenario: findOne(options, callback); + callback = fields; + fields = null; + options = null; + } else if ('function' == typeof conditions) { + callback = conditions; + conditions = {}; + fields = null; + options = null; + } + + var query = new Query(conditions, options).select(fields).bind(this, 'findOne'); + if ('undefined' == typeof callback) + return query; + var cQuery; + if (cQuery = this._cumulativeQuery) { + merge(query._conditions, cQuery._conditions); + if (query._fields && cQuery._fields) + merge(query._fields, cQuery._fields); + if (query.options && cQuery.options) + merge(query.options, cQuery.options); + delete this._cumulativeQuery; + } + if (!query.model) query.bind(this, 'findOne'); + return query.findOne(callback); +}; + +/** + * Counts documents + * + * @param {Object} conditions + * @param {Function} optional callback + * @api public + */ + +Model.count = function (conditions, callback) { + var query = new Query(conditions).bind(this, 'count'); + if ('undefined' == typeof callback) + return query; + var cQuery; + if (cQuery = this._cumulativeQuery) { + merge(query._conditions, cQuery._conditions); + if (query.options && cQuery.options) + merge(query.options, cQuery.options); + delete this._cumulativeQuery; + } + if (!query.model) query.bind(this, 'count'); + return query.count(callback); +}; + +Model.distinct = function (field, conditions, callback) { + var query = new Query(conditions).bind(this, 'distinct'); + if ('undefined' == typeof callback) { + query._distinctArg = field; + return query; + } + var cQuery; + if (cQuery = this._cumulativeQuery) { + merge(query._conditions, cQuery._conditions); + if (query.options && cQuery.options) + merge(query.options, cQuery.options); + delete this._cumulativeQuery; + } + if (!query.model) query.bind(this, 'distinct'); + return query.distinct(field, callback); +}; + +/** + * `where` enables a very nice sugary api for doing your queries. + * For example, instead of writing: + * User.find({age: {$gte: 21, $lte: 65}}, callback); + * we can instead write more readably: + * User.where('age').gte(21).lte(65); + * Moreover, you can also chain a bunch of these together like: + * User + * .where('age').gte(21).lte(65) + * .where('name', /^b/i) // All names that begin where b or B + * .where('friends').slice(10); + * @param {String} path + * @param {Object} val (optional) + * @return {Query} + * @api public + */ + +Model.where = function (path, val) { + var q = new Query().bind(this, 'find'); + return q.where.apply(q, arguments); +}; + +/** + * Sometimes you need to query for things in mongodb using a JavaScript + * expression. You can do so via find({$where: javascript}), or you can + * use the mongoose shortcut method $where via a Query chain or from + * your mongoose Model. + * + * @param {String|Function} js is a javascript string or anonymous function + * @return {Query} + * @api public + */ + +Model.$where = function () { + var q = new Query().bind(this, 'find'); + return q.$where.apply(q, arguments); +}; + +/** + * Shortcut for creating a new Document that is automatically saved + * to the db if valid. + * + * @param {Object} doc + * @param {Function} callback + * @api public + */ + +Model.create = function (doc, fn) { + var args = [].slice.call(arguments) + , lastArg = args[args.length-1] + , count, docs = []; + if (typeof lastArg === 'function') { + fn = args.pop(); + } + count = args.length; + var self = this; + args.forEach( function (arg, i) { + var doc = new self(arg); + docs[i] = doc; + doc.save(function (err) { + if (err) return fn(err); + --count || fn.apply(null, [null].concat(docs)); + }); + }); +}; + +/** + * Updates documents. + * + * Examples: + * + * MyModel.update({ age: { $gt: 18 } }, { oldEnough: true }, fn); + * MyModel.update({ name: 'Tobi' }, { ferret: true }, { multi: true }, fn); + * + * Valid options: + * - safe (boolean) safe mode (defaults to value set in schema (false)) + * - upsert (boolean) whether to create the doc if it doesn't match (false) + * - multi (boolean) whether multiple documents should be update (false) + * + * @param {Object} conditions + * @param {Object] doc + * @param {Object/Function} optional options or callback + * @param {Function} callback + * @return {Query} + * @api public + */ + +Model.update = function (conditions, doc, options, callback) { + if ('function' === typeof doc) { + // Scenario: update(doc, callback); + callback = doc; + doc = conditions; + conditions = {}; + options = null; + } else if ('function' === typeof options) { + callback = options; + if (!Object.keys(doc).length || this._objectHasPathKeys(doc)) { + // Scenario: update(conditions, doc, callback) + options = null; + } else { + // Scenario: update(doc, options, callback) + options = doc; + doc = conditions; + conditions = {}; + } + } + var query = new Query(conditions, options).bind(this, 'update', doc); + if ('undefined' == typeof callback) + return query; + var cQuery; + if (cQuery = this._cumulativeQuery) { + merge(query._conditions, cQuery._conditions); + if (query.options && cQuery.options) + merge(query.options, cQuery.options); + delete this._cumulativeQuery; + } + if (!query.model) query.bind(this, 'update'); + return query.update(doc, callback); +}; + +/** + * True if the first level of keys contains at least one + * key that is equal to a path name. + * + * @param {Object} object + * @return {Boolean} + * @api private + */ + +Model._objectHasPathKeys = function (object) { + var objectKeys = Object.keys(object) + , anyPaths = Object.keys(this.schema.paths).some( function (path) { + return ~objectKeys.indexOf(path); + }); + return anyPaths; +}; + +/** + * Compiler utility. + * + * @param {String} model name + * @param {Schema} schema object + * @param {String} collection name + * @param {Connection} connection to use + * @param {Mongoose} mongoose instance + * @api private + */ + +Model.compile = function (name, schema, collectionName, connection, base) { + // generate new class + function model () { + Model.apply(this, arguments); + }; + + model.modelName = name; + model.__proto__ = Model; + model.prototype.__proto__ = Model.prototype; + model.prototype.base = base; + model.prototype.schema = schema; + model.prototype.db = connection; + model.prototype.collection = connection.collection(collectionName); + + // apply methods + for (var i in schema.methods) + model.prototype[i] = schema.methods[i]; + + // apply statics + for (var i in schema.statics) + model[i] = schema.statics[i]; + + // apply named scopes + if(schema.namedScopes) schema.namedScopes.compile(model); + + return model; +}; diff --git a/node_modules/mongoose/lib/mongoose/namedscope.js b/node_modules/mongoose/lib/mongoose/namedscope.js new file mode 100644 index 0000000..4829d35 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/namedscope.js @@ -0,0 +1,66 @@ +var Query = require('./query'); +function NamedScope () {} + +NamedScope.prototype.query; + +NamedScope.prototype.where = function () { + var q = this.query || (this.query = new Query()); + q.where.apply(q, arguments); + return q; +}; + +/** + * @param {NamedScope} target + * @param {Object} getters + */ +NamedScope.prototype.decorate = function (target, getters) { + var name = this.name + , block = this.block + , query = this.query; + if (block) { + if (block.length === 0) { + Object.defineProperty(target, name, { + get: getters.block0(block) + }); + } else { + target[name] = getters.blockN(block); + } + } else { + Object.defineProperty(target, name, { + get: getters.basic(query) + }); + } +}; + +NamedScope.prototype.compile = function (model) { + var allScopes = this.scopesByName + , scope; + for (var k in allScopes) { + scope = allScopes[k]; + scope.decorate(model, { + block0: function (block) { + return function () { + var cquery = this._cumulativeQuery || (this._cumulativeQuery = new Query().bind(this)); + block.call(cquery); + return this; + }; + }, + blockN: function (block) { + return function () { + var cquery = this._cumulativeQuery || (this._cumulativeQuery = new Query().bind(this)); + block.apply(cquery, arguments); + return this; + }; + }, + basic: function (query) { + return function () { + var cquery = this._cumulativeQuery || (this._cumulativeQuery = new Query().bind(this)); + cquery.find(query); + return this; + }; + } + }); + } +}; + +module.exports = NamedScope; diff --git a/node_modules/mongoose/lib/mongoose/promise.js b/node_modules/mongoose/lib/mongoose/promise.js new file mode 100644 index 0000000..25fda29 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/promise.js @@ -0,0 +1,145 @@ + +/** + * Module dependencies. + */ + +var EventEmitter = require('./utils').EventEmitter; + +/** + * Promise constructor. + * + * @param {Function} a callback+errback that takes err, ... as signature + * @api public + */ + +function Promise (back) { + this.emitted = {}; + if ('function' == typeof back) + this.addBack(back); +}; + +/** + * Inherits from EventEmitter. + */ + +Promise.prototype.__proto__ = EventEmitter.prototype; + +/** + * Adds an event or fires the callback right away. + * + * @return promise + * @api public + */ + +Promise.prototype.on = function (event, callback) { + if (this.emitted[event]) + callback.apply(this, this.emitted[event]); + else + EventEmitter.prototype.on.call(this, event, callback); + + return this; +}; + +/** + * Keeps track of emitted events to run them on `on` + * + * @api private + */ + +Promise.prototype.emit = function (event) { + // ensures a promise can't be complete() or error() twice + if (event == 'err' || event == 'complete'){ + if (this.emitted.err || this.emitted.complete) + return this; + this.emitted[event] = Array.prototype.slice.call(arguments, 1); + } + + return EventEmitter.prototype.emit.apply(this, arguments); +}; + +/** + * Shortcut for emitting complete event + * + * @api public + */ + +Promise.prototype.complete = function () { + var args = Array.prototype.slice.call(arguments); + return this.emit.apply(this, ['complete'].concat(args)); +}; + +/** + * Shortcut for emitting err event + * + * @api public + */ + +Promise.prototype.error = function () { + var args = Array.prototype.slice.call(arguments); + return this.emit.apply(this, ['err'].concat(args)); +}; + +/** + * Shortcut for `.on('complete', fn)` + * + * @return promise + * @api public + */ + +Promise.prototype.addCallback = function (fn) { + return this.on('complete', fn); +}; + +/** + * Shortcut for `.on('err', fn)` + * + * @return promise + * @api public + */ + +Promise.prototype.addErrback = function (fn) { + return this.on('err', fn); +}; + +/** + * Adds a single function that's both callback and errback + * + * @return promise + * @api private + */ + +Promise.prototype.addBack = function (fn) { + var self = this; + + this.on('err', function(err){ + fn.call(this, err); + }); + + this.on('complete', function(){ + var args = Array.prototype.slice.call(arguments); + fn.apply(this, [null].concat(args)); + }); + + return this; +}; + +/** + * Sugar for handling cases where you may be + * resolving to either an error condition or a + * success condition. + * + * @param {Error} optional error or null + * @param {Object} value to complete the promise with + * @api public + */ + +Promise.prototype.resolve = function (err, val) { + if (err) return this.error(err); + return this.complete(val); +}; + +/** + * Module exports. + */ + +module.exports = Promise; diff --git a/node_modules/mongoose/lib/mongoose/query.js b/node_modules/mongoose/lib/mongoose/query.js new file mode 100644 index 0000000..8894082 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/query.js @@ -0,0 +1,945 @@ +var utils = require('./utils') + , merge = utils.merge + , Promise = require('./promise') + , inGroupsOf = utils.inGroupsOf; + +/** + * Query constructor + * + * @api private + */ + +function Query (criteria, options) { + options = this.options = options || {}; + this.safe = options.safe + this._conditions = {}; + if (criteria) this.find(criteria); +} + +/** + * Spawns a new query that's bound to a new model. + * @param {Function} param + * @return {Query} + * @api public + */ + +Query.prototype.bind = function (model, op, updateArg) { + var ret = Object.create(this); + ret.model = model; + ret.op = op; + if (op === 'update') this._updateArg = updateArg; + return ret; +}; + +/** + * Executes the query returning a promise. + * + * Examples: + * query.run(); + * query.run(callback); + * query.run('update'); + * query.run('find', callback); + * + * @param {String|Function} op (optional) + * @param {Function} callback (optional) + * @return {Promise} + * @api public + */ + +Query.prototype.run = +Query.prototype.exec = function (op, callback) { + var promise = new Promise(); + + switch (typeof op) { + case 'function': + callback = op; + op = null; + break; + case 'string': + this.op = op; + break; + } + + if (callback) promise.addBack(callback); + + if (!this.op) { + promise.complete(); + return promise; + } + + if ('update' == this.op) { + this.update(this._updateArg, promise.resolve.bind(promise)); + return promise; + } + + if ('distinct' == this.op) { + this.distinct(this._distinctArg, promise.resolve.bind(promise)); + return promise; + } + + this[this.op](promise.resolve.bind(promise)); + return promise; +}; + +Query.prototype.find = function (criteria, callback) { + this.op = 'find'; + if ('function' === typeof criteria) { + callback = criteria; + criteria = {}; + } else if (criteria instanceof Query) { + // TODO Merge options, too + merge(this._conditions, criteria._conditions); + } else { + merge(this._conditions, criteria); + } + if (!callback) return this; + return this.execFind(callback); +}; + +/** + * Casts obj, or if obj is not present, then this._conditions, + * based on the model's schema. + * + * @param {Function} model + * @param {Object} obj (optional) + * @api public + */ + +Query.prototype.cast = function (model, obj) { + obj || (obj= this._conditions); + + var schema = model.schema + , paths = Object.keys(obj) + , i = paths.length + , any$conditionals + , schematype + , nested + , path + , type + , val; + + while (i--) { + path = paths[i]; + val = obj[path]; + + if (path === '$or') { + var k = val.length + , orComponentQuery; + + while (k--) { + orComponentQuery = new Query(val[k]); + orComponentQuery.cast(model); + val[k] = orComponentQuery._conditions; + } + + } else if (path === '$where') { + type = typeof val; + + if ('string' !== type && 'function' !== type) { + throw new Error("Must have a string or function for $where"); + } + + if ('function' === type) { + obj[path] = val.toString(); + } + + continue; + + } else { + schematype = schema.path(path); + + if (!schematype) { + // Handle potential embedded array queries + var split = path.split('.') + , j = split.length + , pathFirstHalf + , pathLastHalf + , remainingConds + , castingQuery; + + // Find the part of the var path that is a path of the Schema + while (j--) { + pathFirstHalf = split.slice(0, j).join('.'); + schematype = schema.path(pathFirstHalf); + if (schematype) break; + } + + // If a substring of the input path resolves to an actual real path... + if (schematype) { + // Apply the casting; similar code for $elemMatch in schema/array.js + if (schematype.caster) { + remainingConds = {}; + pathLastHalf = split.slice(j).join('.'); + remainingConds[pathLastHalf] = val; + castingQuery = new Query(remainingConds); + castingQuery.cast(schematype.caster); + obj[path] = castingQuery._conditions[pathLastHalf]; + } else { + obj[path] = val; + } + } + + } else if (val === null || val === undefined) { + continue; + } else if (val.constructor == Object) { + + any$conditionals = Object.keys(val).some(function (k) { + return k.charAt(0) === '$'; + }); + + if (!any$conditionals) { + obj[path] = schematype.castForQuery(val); + } else { + + var ks = Object.keys(val) + , k = ks.length + , $cond; + + while (k--) { + $cond = ks[k]; + nested = val[$cond]; + + if ('$ne' === $cond && null === $cond) { + continue; + } + + if ('$exists' === $cond) { + if ('boolean' !== typeof nested) { + throw new Error("$exists parameter must be Boolean"); + } + continue; + } + + if ('$not' === $cond) { + this.cast(model, val[$cond]); + } else { + val[$cond] = schematype.castForQuery($cond, nested); + } + } + } + } else { + obj[path] = schematype.castForQuery(val); + } + } + } +}; + +Query.prototype._optionsForExec = function (model) { + var options = utils.clone(this.options); + if (! ('safe' in options)) options.safe = model.options.safe; + return options; +}; + +/** + * Sometimes you need to query for things in mongodb using a JavaScript + * expression. You can do so via find({$where: javascript}), or you can + * use the mongoose shortcut method $where via a Query chain or from + * your mongoose Model. + * + * @param {String|Function} js is a javascript string or anonymous function + * @return {Query} + * @api public + */ + +Query.prototype.$where = function (js) { + this._conditions['$where'] = js; + return this; +}; + +/** + * `where` enables a very nice sugary api for doing your queries. + * For example, instead of writing: + * User.find({age: {$gte: 21, $lte: 65}}, callback); + * we can instead write more readably: + * User.where('age').gte(21).lte(65); + * Moreover, you can also chain a bunch of these together like: + * User + * .where('age').gte(21).lte(65) + * .where('name', /^b/i) // All names that begin where b or B + * .where('friends').slice(10); + * @param {String} path + * @param {Object} val (optional) + * @return {Query} + * @api public + */ + +Query.prototype.where = function (path, val) { + var conds; + if (arguments.length === 2) { + this._conditions[path] = val; + } + this._currPath = path; + return this; +}; + +// $lt, $lte, $gt, $gte can be used on Numbers or Dates +'gt gte lt lte ne in nin all size maxDistance'.split(' ').forEach( function ($conditional) { + Query.prototype['$' + $conditional] = + Query.prototype[$conditional] = function (path, val) { + if (arguments.length === 1) { + val = path; + path = this._currPath + } + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds['$' + $conditional] = val; + return this; + }; +}); + +Query.prototype.notEqualTo = Query.prototype.ne; + +;['mod', 'near'].forEach( function ($conditional) { + Query.prototype['$' + $conditional] = + Query.prototype[$conditional] = function (path, val) { + if (arguments.length === 1) { + val = path; + path = this._currPath + } else if (arguments.length === 2 && !Array.isArray(val)) { + val = [].slice.call(arguments); + path = this._currPath; + } else if (arguments.length === 3) { + val = [].slice.call(arguments, 1); + } + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds['$' + $conditional] = val; + return this; + }; +}); + +Query.prototype['$exists'] = +Query.prototype.exists = function (path, val) { + if (arguments.length === 0) { + path = this._currPath + val = true; + } else if (arguments.length === 1) { + if ('boolean' === typeof path) { + val = path; + path = this._currPath; + } else { + val = true; + } + } + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds['$exists'] = val; + return this; +}; + +Query.prototype['$elemMatch'] = +Query.prototype.elemMatch = function (path, criteria) { + var block; + if (path.constructor === Object) { + criteria = path; + path = this._currPath; + } else if ('function' === typeof path) { + block = path; + path = this._currPath; + } else if (criteria.constructor === Object) { + } else if ('function' === typeof criteria) { + block = criteria; + } else { + throw new Error("Argument error"); + } + var conds = this._conditions[path] || (this._conditions[path] = {}); + if (block) { + criteria = new Query(); + block(criteria); + conds['$elemMatch'] = criteria._conditions; + } else { + conds['$elemMatch'] = criteria; + } + return this; +}; + +;['maxscan'].forEach( function (method) { + Query.prototype[method] = function (v) { + this.options[method] = v; + return this; + }; +}); + +// TODO +Query.prototype.explain = function () { + throw new Error("Unimplemented"); +}; + +// TODO Add being able to skip casting -- e.g., this would be nice for scenarios like +// if you're migrating to usernames from user id numbers: +// query.where('user_id').in([4444, 'brian']); + +// TODO "immortal" cursors - (only work on capped collections) +// TODO geoNear command + +// To be used idiomatically where Query#box and Query#center +;['wherein', '$wherein'].forEach(function (getter) { + Object.defineProperty(Query.prototype, getter, { + get: function () { + return this; + } + }); +}); + +Query.prototype['$box'] = +Query.prototype.box = function (path, val) { + if (arguments.length === 1) { + val = path; + path = this._currPath; + } + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds['$wherein'] = { '$box': [val.ll, val.ur] }; + return this; +}; + +Query.prototype['$center'] = +Query.prototype.center = function (path, val) { + if (arguments.length === 1) { + val = path; + path = this._currPath; + } + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds['$wherein'] = { '$center': [val.center, val.radius] }; + return this; +}; + +/** + * Chainable method for specifying which fields + * to include or exclude from the document that is + * returned from MongoDB. + * + * Examples: + * query.fields({a: 1, b: 1, c: 1, _id: 0}); + * query.fields('a b c'); + * + * @param {Object} + */ + +Query.prototype.select = +Query.prototype.fields = function () { + var arg0 = arguments[0]; + if (!arg0) return this; + if (arg0.constructor === Object || Array.isArray(arg0)) { + this._applyFields(arg0); + } else if (arguments.length === 1 && typeof arg0 === 'string') { + this._applyFields({only: arg0}); + } else { + this._applyFields({only: this._parseOnlyExcludeFields.apply(this, arguments)}); + } + return this; +}; + +/** + * Chainable method for adding the specified fields to the + * object of fields to only include. + * + * Examples: + * query.only('a b c'); + * query.only('a', 'b', 'c'); + * query.only(['a', 'b', 'c']); + * @param {String|Array} space separated list of fields OR + * an array of field names + * We can also take arguments as the "array" of field names + * @api public + */ + +Query.prototype.only = function (fields) { + fields = this._parseOnlyExcludeFields.apply(this, arguments); + this._applyFields({ only: fields }); + return this; +}; + +/** + * Chainable method for adding the specified fields to the + * object of fields to exclude. + * + * Examples: + * query.exclude('a b c'); + * query.exclude('a', 'b', 'c'); + * query.exclude(['a', 'b', 'c']); + * @param {String|Array} space separated list of fields OR + * an array of field names + * We can also take arguments as the "array" of field names + * @api public + */ + +Query.prototype.exclude = function (fields) { + fields = this._parseOnlyExcludeFields.apply(this, arguments); + this._applyFields({ exclude: fields }); + return this; +}; + +Query.prototype['$slice'] = +Query.prototype.slice = function (path, val) { + if (arguments.length === 1) { + val = path; + path = this._currPath + } else if (arguments.length === 2) { + if ('number' === typeof path) { + val = [path, val]; + path = this._currPath; + } + } else if (arguments.length === 3) { + val = [].slice.call(arguments, 1); + } + var myFields = this._fields || (this._fields = {}); + myFields[path] = { '$slice': val }; + return this; +}; + +/** + * Private method for interpreting the different ways + * you can pass in fields to both Query.prototype.only + * and Query.prototype.exclude. + * + * @param {String|Array|Object} fields + * @api private + */ + +Query.prototype._parseOnlyExcludeFields = function (fields) { + if (1 === arguments.length && 'string' === typeof fields) { + fields = fields.split(' '); + } else if (Array.isArray(fields)) { + // do nothing + } else { + fields = [].slice.call(arguments); + } + return fields; +}; + +/** + * Private method for interpreting and applying the different + * ways you can specify which fields you want to include + * or exclude. + * + * Example 1: Include fields 'a', 'b', and 'c' via an Array + * query.fields('a', 'b', 'c'); + * query.fields(['a', 'b', 'c']); + * + * Example 2: Include fields via 'only' shortcut + * query.only('a b c'); + * + * Example 3: Exclude fields via 'exclude' shortcut + * query.exclude('a b c'); + * + * Example 4: Include fields via MongoDB's native format + * query.fields({a: 1, b: 1, c: 1}) + * + * Example 5: Exclude fields via MongoDB's native format + * query.fields({a: 0, b: 0, c: 0}); + * + * @param {Object|Array} the formatted collection of fields to + * include and/or exclude + * @api private + */ + +Query.prototype._applyFields = function (fields) { + var $fields + , pathList; + + if (Array.isArray(fields)) { + $fields = fields.reduce(function ($fields, field) { + $fields[field] = 1; + return $fields; + }, {}); + } else if (pathList = fields.only || fields.exclude) { + $fields = + this._parseOnlyExcludeFields(pathList) + .reduce(function ($fields, field) { + $fields[field] = fields.only ? 1: 0; + return $fields; + }, {}); + } else if (fields.constructor === Object) { + $fields = fields; + } else { + throw new Error("fields is invalid"); + } + + var myFields = this._fields || (this._fields = {}); + for (var k in $fields) myFields[k] = $fields[k]; +}; + +/** + * Sets the sort + * + * Examples: + * query.sort('test', 1) + * query.sort('field', -1) + * query.sort('field', -1, 'test', 1) + * + * @api public + */ + +Query.prototype.sort = function () { + var sort = this.options.sort || (this.options.sort = []); + + inGroupsOf(2, arguments, function (field, value) { + sort.push([field, value]); + }); + + return this; +}; + +Query.prototype.asc = function () { + var sort = this.options.sort || (this.options.sort = []); + for (var i = 0, l = arguments.length; i < l; i++) { + sort.push([arguments[i], 1]); + } + return this; +}; + +Query.prototype.desc = function () { + var sort = this.options.sort || (this.options.sort = []); + for (var i = 0, l = arguments.length; i < l; i++) { + sort.push([arguments[i], -1]); + } + return this; +}; + +;['limit', 'skip', 'maxscan', 'snapshot'].forEach( function (method) { + Query.prototype[method] = function (v) { + this.options[method] = v; + return this; + }; +}); + +/** + * Query hints. + * + * Examples: + * new Query().hint({ indexA: 1, indexB: -1}) + * new Query().hint("indexA", 1, "indexB", -1) + * + * @param {Object|String} v + * @param {Int} [multi] + * @return {Query} + * @api public + */ + +Query.prototype.hint = function (v, multi) { + var hint = this.options.hint || (this.options.hint = {}) + , k + + if (multi) { + inGroupsOf(2, arguments, function (field, val) { + hint[field] = val; + }); + } else if (v.constructor === Object) { + // must keep object keys in order so don't use Object.keys() + for (k in v) { + hint[k] = v[k]; + } + } + + return this; +}; + +/** + * Sets slaveOk option + * + * new Query().slaveOk() <== true + * new Query().slaveOk(true) + * new Query().slaveOk(false) + * + * @param {Boolean} v (defaults to true) + */ + +Query.prototype.slaveOk = function (v) { + this.options.slaveOk = arguments.length ? !!v : true; + return this; +}; + +Query.prototype.execFind = function (callback) { + var model = this.model + , options = this._optionsForExec(model); + options.fields = this._fields; + + var promise = new Promise(callback); + + try { + this.cast(model); + } catch (err) { + return promise.error(err); + } + + var castQuery = this._conditions; + + model.collection.find(castQuery, options, function (err, cursor) { + if (err) return promise.error(err); + + cursor.toArray(function (err, docs) { + if (err) return promise.error(err); + + var arr = [] + , count = docs.length; + + if (!count) return promise.complete([]); + + for (var i = 0, l = docs.length; i < l; i++) { + arr[i] = new model(); + delete arr[i].doc._id; // Remove the _id, so that pre inits do not + // have an _id + arr[i].init(docs[i], function (err) { + if (err) return promise.error(err); + --count || promise.complete(arr); + }); + } + }); + }); + + return this; +}; + +/** + * Steaming cursors. + * + * The `callback` is called repeatedly for each document + * found in the collection as it's streamed. If an error + * occurs streaming stops. + * + * Example: + * query.each(function (err, user) { + * if (err) return res.end("aww, received an error. all done."); + * if (user) { + * res.write(user.name + '\n') + * } else { + * res.end("reached end of cursor. all done."); + * } + * }); + * + * A third parameter may also be used in the callback which + * allows you to iterate the cursor manually. + * + * Example: + * query.each(function (err, user, next) { + * if (err) return res.end("aww, received an error. all done."); + * if (user) { + * res.write(user.name + '\n') + * doSomethingAsync(next); + * } else { + * res.end("reached end of cursor. all done."); + * } + * }); + * + * @param {Function} callback + * @return {Query} + * @api public + */ + +Query.prototype.each = function (callback) { + var model = this.model + , options = this._optionsForExec(model) + , manual = 3 == callback.length + + options.fields = this._fields; + + try { + this.cast(model); + } catch (err) { + return callback(err); + } + + function complete (err, val) { + if (complete.ran) return; + complete.ran = true; + callback(err, val); + } + + model.collection.find(this._conditions, options, function (err, cursor) { + if (err) return complete(err); + + next(); + + function next () { + // nextTick is necessary to avoid stack overflows when + // dealing with large result sets. + process.nextTick(function () { + cursor.nextObject(onNextObject); + }); + } + + function onNextObject (err, doc) { + if (err) return complete(err); + + // when doc is null we hit the end of the cursor + if (!doc) return complete(null, null); + + var instance = new model; + + delete instance.doc._id; // Remove the _id, so that pre inits do not + // have an _id + instance.init(doc, function (err) { + if (err) return complete(err); + + if (manual) { + callback(null, instance, next); + } else { + callback(null, instance); + next(); + } + + }); + } + + }); + + return this; +} + +/** + * Casts the query, sends the findOne command to mongodb. + * Upon receiving the document, we initialize a mongoose + * document based on the returned document from mongodb, + * and then we invoke a callback on our mongoose document. + * + * @param {Function} callback function (err, found) + * @api public + */ + +Query.prototype.findOne = function (callback) { + this.op = 'findOne'; + var model = this.model; + var options = this._optionsForExec(model); + + options.fields = this._fields; + + var promise = new Promise(callback); + + try { + this.cast(model); + } catch (err) { + return promise.error(err); + } + + var castQuery = this._conditions; + + model.collection.findOne(castQuery, options, function (err, doc) { + if (err) return promise.error(err); + if (!doc) return promise.complete(null); + + var casted = new model(); + delete casted.doc._id; // Remove the _id, so that pre inits do not have + // an _id + casted.init(doc, function (err) { + if (err) return promise.error(err); + promise.complete(casted); + }); + }); + + return this; +}; + +/** + * Casts this._conditions and sends a count + * command to mongodb. Invokes a callback upon + * receiving results + * + * @param {Function} callback fn(err, cardinality) + * @api public + */ + +Query.prototype.count = function (callback) { + this.op = 'count'; + var model = this.model; + + try { + this.cast(model); + } catch (err) { + return callback(err); + } + + var castQuery = this._conditions; + model.collection.count(castQuery, callback); + return this; +}; + +/** + * Casts this._conditions and sends a distinct + * command to mongodb. Invokes a callback upon + * receiving results + * + * @param {Function} callback fn(err, cardinality) + * @api public + */ + +Query.prototype.distinct = function (field, callback) { + this.op = 'distinct'; + var model = this.model; + + try { + this.cast(model); + } catch (err) { + return callback(err); + } + + var castQuery = this._conditions; + model.collection.distinct(field, castQuery, callback); + return this; +}; + +/** + * Casts the query, sends the update command to mongodb. + * + * @param {Function} callback fn(err) + * @api public + */ + +Query.prototype.update = function (doc, callback) { + this.op = 'update'; + this._updateArg = doc; + + var model = this.model + , options = this._optionsForExec(model) + , useSet = model.options['use$SetOnSave']; + + try { + this.cast(model); + } catch (err) { + return callback(err); + } + + var castQuery = this._conditions; + + var castingQuery = {_conditions: doc}; + + try { + this.cast.call(castingQuery, model); + } catch (err) { + return callback(err); + } + + var castDoc = castingQuery._conditions; + + if (useSet) { + castDoc = {'$set': castDoc}; + } + + model.collection.update(castQuery, castDoc, options, callback); + return this; +}; + +/** + * Casts the query, sends the remove command to + * mongodb where the query contents, and then + * invokes a callback upon receiving the command + * result. + * + * @param {Function} callback + * @api public + */ + +Query.prototype.remove = function (callback) { + this.op = 'remove'; + + var model = this.model + , options = this._optionsForExec(model); + + try { + this.cast(model); + } catch (err) { + return callback(err); + } + + var castQuery = this._conditions; + model.collection.remove(castQuery, options, callback); + return this; +}; + +module.exports = Query; diff --git a/node_modules/mongoose/lib/mongoose/schema.js b/node_modules/mongoose/lib/mongoose/schema.js new file mode 100644 index 0000000..a39762a --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schema.js @@ -0,0 +1,520 @@ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , Types + , VirtualType = require('./virtualtype') + , utils = require('./utils') + , NamedScope = require('./namedscope') + , Query = require('./query'); + +/** + * Schema constructor. + * + * @param {Object} definition + * @api public + */ + +function Schema (obj, options) { + this.paths = {}; + this.virtuals = {}; + this.inherits = {}; + this.callQueue = []; + this._indexes = []; + this.methods = {}; + this.statics = {}; + this.tree = {}; + + // set options + this.options = utils.options({ + safe: true + , 'use$SetOnSave': true + }, options); + + // build paths + if (obj) + this.add(obj); + + if (!this.paths['_id']) + this.add({ _id: {type: ObjectId, auto: true} }); + + if (!this.paths['id'] && !this.options.noVirtualId) { + this.virtual('id').get(function () { + return this._id.toString(); + }); + } + + delete this.options.noVirtualId; +}; + +/** + * Inherit from EventEmitter. + */ + +Schema.prototype.__proto__ = EventEmitter.prototype; + +/** + * Schema by paths + * + * Example (embedded doc): + * { + * 'test' : SchemaType, + * , 'test.test' : SchemaType, + * , 'first_name' : SchemaType + * } + * + * @api private + */ + +Schema.prototype.paths; + +/** + * Schema as a tree + * + * Example: + * { + * '_id' : ObjectId + * , 'nested' : { + * 'key': String + * } + * } + * + * @api private + */ + +Schema.prototype.tree; + +/** + * Sets the keys + * + * @param {Object} keys + * @param {String} prefix + * @api public + */ + +Schema.prototype.add = function (obj, prefix) { + prefix = prefix || ''; + for (var i in obj) { + // make sure set of keys are in `tree` + if (!prefix && !this.tree[i]) + this.tree[i] = obj[i]; + + if (obj[i].constructor.name == 'Object' && (!obj[i].type || obj[i].type.type)) { + if (Object.keys(obj[i]).length) + this.add(obj[i], prefix + i + '.'); + else + this.path(prefix + i, obj[i]); // mixed type + } else + this.path(prefix + i, obj[i]); + } +}; + +/** + * Sets a path (if arity 2) + * Gets a path (if arity 1) + * + * @param {String} path + * @param {Object} constructor + * @api public + */ + +Schema.prototype.path = function (path, obj) { + if (obj == undefined) { + if (this.paths[path]) return this.paths[path]; + + // Sometimes path will come in as + // pathNameA.4.pathNameB where 4 means the index + // of an embedded document in an embedded array. + // In this case, we need to jump to the Array's + // schema and call path() from there to resolve to + // the correct path type (otherwise, it falsely + // resolves to undefined + var self = this + , subpaths = path.split(/\.\d+\./); + if (subpaths.length > 1) { + return subpaths.reduce( function (val, subpath) { + return val ? val.schema.path(subpath) + : self.path(subpath); + }, null); + } + return; // Otherwise, return `undefined` + } + + this.paths[path] = Schema.interpretAsType(path, obj); + return this; +}; + +/** + * Converts -- e.g., Number, [SomeSchema], + * { type: String, enum: ['m', 'f'] } -- into + * the appropriate Mongoose Type, which we use + * later for casting, validation, etc. + * @param {String} path + * @param {Object} constructor + */ + +Schema.interpretAsType = function (path, obj) { + if (obj.constructor.name != 'Object') + obj = { type: obj }; + + // Get the type making sure to allow keys named "type" + // and default to mixed if not specified. + // { type: { type: String, default: 'freshcut' } } + var type = obj.type && !obj.type.type + ? obj.type + : {}; + + if (type.constructor.name == 'Object') { + return new Types.Mixed(path, obj); + } + + if (Array.isArray(type) || type == Array) { + // if it was specified through { type } look for `cast` + var cast = type == Array + ? obj.cast + : type[0]; + + cast = cast || Types.Mixed; + + if (cast instanceof Schema) { + return new Types.DocumentArray(path, cast, obj); + } + return new Types.Array(path, cast, obj); + } + return new Types[type.name](path, obj); +}; + +/** + * Iterates through the schema's paths, passing the path string and type object + * to the callback. + * + * @param {Function} callback function - fn(pathstring, type) + * @return {Schema} this for chaining + * @api public + */ + +Schema.prototype.eachPath = function (fn) { + var keys = Object.keys(this.paths) + , len = keys.length; + + for (var i = 0; i < len; ++i) { + fn(keys[i], this.paths[keys[i]]); + } + + return this; +}; + +/** + * Returns an Array of path strings that are required. + * @api public + */ + +Object.defineProperty(Schema.prototype, 'requiredPaths', { + get: function () { + var paths = this.paths + , pathnames = Object.keys(paths) + , i = pathnames.length + , pathname, path + , requiredPaths = []; + while (i--) { + pathname = pathnames[i]; + path = paths[pathname]; + if (path.isRequired) requiredPaths.push(pathname); + } + return requiredPaths; + } +}); + +/** + * Given a path, returns whether it is a real, virtual, or + * ad-hoc/undefined path + * + * @param {String} path + * @return {String} + * @api public + */ +Schema.prototype.pathType = function (path) { + if (path in this.paths) return 'real'; + if (path in this.virtuals) return 'virtual'; + return 'adhocOrUndefined'; +}; + +/** + * Adds a method call to the queue + * + * @param {String} method name + * @param {Array} arguments + * @api private + */ + +Schema.prototype.queue = function(name, args){ + this.callQueue.push([name, args]); + return this; +}; + +/** + * Defines a pre for the document + * + * @param {String} method + * @param {Function} callback + * @api public + */ + +Schema.prototype.pre = function(){ + return this.queue('pre', arguments); +}; + +/** + * Defines a post for the document + * + * @param {String} method + * @param {Function} callback + * @api public + */ + +Schema.prototype.post = function(method, fn){ + return this.queue('on', arguments); +}; + +/** + * Registers a plugin for this schema + * + * @param {Function} plugin callback + * @api public + */ + +Schema.prototype.plugin = function (fn, opts) { + fn(this, opts); + return this; +}; + +/** + * Adds a method + * + * @param {String} method name + * @param {Function} handler + * @api public + */ + +Schema.prototype.method = function (name, fn) { + if ('string' != typeof name) + for (var i in name) + this.methods[i] = name[i]; + else + this.methods[name] = fn; + return this; +}; + +/** + * Defines a static method + * + * @param {String} name + * @param {Function} handler + * @api public + */ + +Schema.prototype.static = function(name, fn) { + if ('string' != typeof name) + for (var i in name) + this.statics[i] = name[i]; + else + this.statics[name] = fn; + return this; +}; + +/** + * Defines an index (most likely compound) + * Example: + * schema.index({ first: 1, last: -1 }) + * + * @param {Object} field + * @param {Object} optional options object + * @api public + */ + +Schema.prototype.index = function (fields, options) { + this._indexes.push([fields, options || {}]); + return this; +}; + +/** + * Sets/gets an option + * + * @param {String} key + * @param {Object} optional value + * @api public + */ + +Schema.prototype.set = function (key, value) { + if (arguments.length == 1) + return this.options[key]; + this.options[key] = value; + return this; +}; + +/** + * Compiles indexes from fields and schema-level indexes + * + * @api public + */ + +Schema.prototype.__defineGetter__('indexes', function () { + var indexes = [] + , seenSchemas = []; + + collectIndexes(this); + + return indexes; + + function collectIndexes (schema, prefix) { + if (~seenSchemas.indexOf(schema)) return; + seenSchemas.push(schema); + + var index; + var paths = schema.paths; + prefix = prefix || ''; + + for (var i in paths) { + if (paths[i]) { + if (paths[i] instanceof Types.DocumentArray) { + collectIndexes(paths[i].schema, i + '.'); + } else { + index = paths[i]._index; + + if (index !== false && index !== null){ + var field = {}; + field[prefix + i] = '2d' === index ? index : 1; + indexes.push([field, index.constructor == Object ? index : {} ]); + } + } + } + } + + if (prefix) { + fixSubIndexPaths(schema, prefix); + } else { + indexes = indexes.concat(schema._indexes); + } + } + + /** + * Checks for indexes added to subdocs using Schema.index(). + * These indexes need their paths prefixed properly. + * + * schema._indexes = [ [indexObj, options], [indexObj, options] ..] + */ + + function fixSubIndexPaths (schema, prefix) { + var subindexes = schema._indexes + , len = subindexes.length + , indexObj + , newindex + , klen + , keys + , key + , i = 0 + , j + + for (i = 0; i < len; ++i) { + indexObj = subindexes[i][0]; + keys = Object.keys(indexObj); + klen = keys.length; + newindex = {}; + + // use forward iteration, order matters + for (j = 0; j < klen; ++j) { + key = keys[j]; + newindex[prefix + key] = indexObj[key]; + } + + indexes.push([newindex, subindexes[i][1]]); + } + } + +}); + +/** + * Retrieves or creates the virtual type with the given name. + * + * @param {String} name + * @return {VirtualType} + */ + +Schema.prototype.virtual = function (name) { + var virtuals = this.virtuals || (this.virtuals = {}); + var parts = name.split('.'); + return virtuals[name] = parts.reduce( function (mem, part, i) { + mem[part] || (mem[part] = (i === parts.length-1) + ? new VirtualType() + : {}); + return mem[part]; + }, this.tree); +}; + +/** + * Fetches the virtual type with the given name. + * Should be distinct from virtual because virtual auto-defines a new VirtualType + * if the path doesn't exist. + * + * @param {String} name + * @return {VirtualType} + */ + +Schema.prototype.virtualpath = function (name) { + return this.virtuals[name]; +}; + +Schema.prototype.namedScope = function (name, fn) { + var namedScopes = this.namedScopes || (this.namedScopes = new NamedScope) + , newScope = Object.create(namedScopes) + , allScopes = namedScopes.scopesByName || (namedScopes.scopesByName = {}); + allScopes[name] = newScope; + newScope.name = name; + newScope.block = fn; + newScope.query = new Query(); + newScope.decorate(namedScopes, { + block0: function (block) { + return function () { + block.call(this.query); + return this; + }; + }, + blockN: function (block) { + return function () { + block.apply(this.query, arguments); + return this; + }; + }, + basic: function (query) { + return function () { + this.query.find(query); + return this; + }; + } + }); + return newScope; +}; + +/** + * ObjectId schema identifier. Not an actual ObjectId, only used for Schemas. + * + * @api public + */ + +function ObjectId () { + throw new Error('This is an abstract interface. Its only purpose is to mark ' + + 'fields as ObjectId in the schema creation.'); +} + +/** + * Module exports. + */ + +module.exports = exports = Schema; + +// require down here because of reference issues +exports.Types = Types = require('./schema/index'); + +exports.ObjectId = ObjectId; diff --git a/node_modules/mongoose/lib/mongoose/schema/array.js b/node_modules/mongoose/lib/mongoose/schema/array.js new file mode 100644 index 0000000..67f2e15 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schema/array.js @@ -0,0 +1,197 @@ +/** + * Module dependencies. + */ + +var SchemaType = require('../schematype') + , CastError = SchemaType.CastError + , ArrayNumberSchema = function () {} + , Types = { + Boolean: require('./boolean') + , Date: require('./date') + , Number: ArrayNumberSchema + , String: require('./string') + , ObjectId: require('./objectid') + } + , MongooseArray = require('../types').Array + , Query = require('../query'); + +/** + * Array SchemaType constructor + * + * @param {String} key + * @param {SchemaType} cast + * @api private + */ + +function SchemaArray (key, cast, options) { + SchemaType.call(this, key, options); + + if (cast) { + this.caster = cast.name in Types ? Types[cast.name] : cast; + } + + var self = this + , defaultArr + , fn; + + if (this.defaultValue) { + defaultArr = this.defaultValue; + fn = 'function' == typeof defaultArr; + } + + this.default(function(){ + var arr = fn ? defaultArr() : defaultArr || []; + return new MongooseArray(arr, self.path, this); + }); +}; + +/** + * Inherits from SchemaType. + */ + +SchemaArray.prototype.__proto__ = SchemaType.prototype; + +/** + * Check required + * + * @api private + */ + +SchemaArray.prototype.checkRequired = function (value) { + return !!(value && value.length); +}; + +/** + * Casts contents + * + * @param {Object} value + * @param {Document} document that triggers the casting + * @api private + */ + +SchemaArray.prototype.cast = function (value, doc) { + if (Array.isArray(value)) { + if (!(value instanceof MongooseArray)) { + value = new MongooseArray(value, this.path, doc); + } + + var caster = this.caster; + + if (caster) { + for (var i = 0, l = value.length; i < l; i++) { + try { + value[i] = caster.prototype.cast.call(null, value[i]); + } catch(e){ + // rethrow + throw new CastError(e.type, value); + } + } + } + + return value; + } else { + return this.cast([value], doc); + } + + throw new CastError('array', value); +}; + +SchemaArray.prototype.$conditionalHandlers = { + '$all': function handle$all (val) { + if (!Array.isArray(val)) { + val = [val]; + } + + if (!(val instanceof MongooseArray)) { + val = new MongooseArray(val, this.path); + } + + // use castForQuery where available + var proto = this.caster.prototype; + var method = proto.castForQuery || proto.cast; + + try { + return val.map(function (v) { + return method.call(proto, v); + }); + } catch (err) { + // rethrow + throw new CastError(err.type, val); + } + } + // TODO Move elemMatch to documentarray + , '$elemMatch': function (val) { + var query = new Query(val); + query.cast(this.caster) + return query._conditions; + } + , '$size': function (val) { + return ArrayNumberSchema.prototype.cast.call(this, val); + } + , '$ne': function (val) { + if (Array.isArray(val)) { + return this.cast(val); + } else { + var proto = this.caster.prototype; + var method = proto.castForQuery || proto.cast; + if (method) return method.call(proto, val); + return val.toObject ? val.toObject() : val; + } + } + , '$in': function (val) { + return this.cast(val); + } + , '$nin': function (val) { + return this.cast(val); + } + , '$near': function (val) { + return this.cast(val); + } + , '$maxDistance': function (val) { + return ArrayNumberSchema.prototype.cast.call(this, val); + } +}; + +SchemaArray.prototype.castForQuery = function ($conditional, val) { + var handler; + if (arguments.length === 2) { + handler = this.$conditionalHandlers[$conditional]; + if (!handler) + throw new Error("Can't use " + $conditional + " with Array."); + return handler.call(this, val); + } else { + val = $conditional; + if (Array.isArray(val)) { + return this.cast(val); + } else { + var proto = this.caster.prototype; + var method = proto.castForQuery || proto.cast; + if (method) return method.call(proto, val); + return val.toObject ? val.toObject() : val; + } + } +}; + +/** + * Number casting for arrays (equivalent, but without MongoseNumber) + * + * @see GH-176 + * @param {Object} value + * @api private + */ + +ArrayNumberSchema.prototype.cast = function (value) { + if (!isNaN(value)) { + if (value instanceof Number || typeof value == 'number' || + (value.toString && value.toString() == Number(value))) + return Number(value); + } + + throw new CastError('number', value); +}; + +/** + * Module exports. + */ + +module.exports = SchemaArray; diff --git a/node_modules/mongoose/lib/mongoose/schema/boolean.js b/node_modules/mongoose/lib/mongoose/schema/boolean.js new file mode 100644 index 0000000..2bba62f --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schema/boolean.js @@ -0,0 +1,58 @@ + +/** + * Module dependencies. + */ + +var SchemaType = require('../schematype'); + +/** + * Boolean SchemaType constructor. + * + * @param {String} path + * @param {Object} options + * @api private + */ + +function SchemaBoolean (path, options) { + SchemaType.call(this, path, options); +}; + +/** + * Inherits from SchemaType. + */ +SchemaBoolean.prototype.__proto__ = SchemaType.prototype; + +/** + * Required validator for date + * + * @api private + */ + +SchemaBoolean.prototype.checkRequired = function (value) { + return value === true || value === false; +}; + +/** + * Casts to boolean + * + * @param {Object} value to cast + * @api private + */ + +SchemaBoolean.prototype.cast = function (value) { + if (value === '0') return false; + return !!value; +}; + +SchemaBoolean.prototype.castForQuery = function ($conditional, val) { + if (arguments.length === 1) { + val = $conditional; + } + return this.cast(val); +}; + +/** + * Module exports. + */ + +module.exports = SchemaBoolean; diff --git a/node_modules/mongoose/lib/mongoose/schema/date.js b/node_modules/mongoose/lib/mongoose/schema/date.js new file mode 100644 index 0000000..b5c06d2 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schema/date.js @@ -0,0 +1,115 @@ + +/** + * Module requirements. + */ + +var SchemaType = require('../schematype') + , CastError = SchemaType.CastError; + +/** + * Date SchemaType constructor. + * + * @param {String} key + * @param {Object} options + * @api private + */ + +function SchemaDate (key, options) { + SchemaType.call(this, key, options); +}; + +/** + * Inherits from SchemaType. + */ + +SchemaDate.prototype.__proto__ = SchemaType.prototype; + +/** + * Required validator for date + * + * @api private + */ + +SchemaDate.prototype.checkRequired = function (value) { + return value instanceof Date; +}; + +/** + * Casts to date + * + * @param {Object} value to cast + * @api private + */ + +SchemaDate.prototype.cast = function (value) { + if (value === null || value === '') + return null; + + if (value instanceof Date) + return value; + + var date; + + // support for timestamps + if (value instanceof Number || 'number' == typeof value + || String(value) == Number(value)) + date = new Date(Number(value)); + + // support for date strings + else if (value.toString) + date = new Date(value.toString()); + + if (date.toString() != 'Invalid Date') + return date; + + throw new CastError('date', value); +}; + +/** + * Date Query casting. + * + * @api private + */ + +function handleSingle (val) { + return this.cast(val); +} + +function handleArray (val) { + var self = this; + return val.map( function (m) { + return self.cast(m); + }); +} + +SchemaDate.prototype.$conditionalHandlers = { + '$lt': handleSingle + , '$lte': handleSingle + , '$gt': handleSingle + , '$gte': handleSingle + , '$ne': handleSingle + , '$in': handleArray + , '$nin': handleArray +}; + +SchemaDate.prototype.castForQuery = function ($conditional, val) { + var handler; + + if (2 !== arguments.length) { + return this.cast($conditional); + } + + handler = this.$conditionalHandlers[$conditional]; + + if (!handler) { + throw new Error("Can't use " + $conditional + " with Date."); + } + + return handler.call(this, val); +}; + +/** + * Module exports. + */ + +module.exports = SchemaDate; diff --git a/node_modules/mongoose/lib/mongoose/schema/documentarray.js b/node_modules/mongoose/lib/mongoose/schema/documentarray.js new file mode 100644 index 0000000..908f0fa --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schema/documentarray.js @@ -0,0 +1,120 @@ + +/** + * Module dependencies. + */ + +var SchemaType = require('../schematype') + , ArrayType = require('./array') + , MongooseDocumentArray = require('../types/documentarray') + , Subdocument = require('../types/document') + , CastError = SchemaType.CastError + , Document = require('../document'); + +/** + * SubdocsArray SchemaType constructor + * + * @param {String} key + * @param {Schema} schema + * @param {Object} options + * @api private + */ + +function DocumentArray (key, schema, options) { + // compile an embedded document for this schema + // TODO Move this into parent model compilation for performance improvement? + function EmbeddedDocument () { + Subdocument.apply(this, arguments); + }; + + EmbeddedDocument.prototype.__proto__ = Subdocument.prototype; + EmbeddedDocument.prototype.schema = schema; + EmbeddedDocument.schema = schema; + + // apply methods + for (var i in schema.methods) { + EmbeddedDocument.prototype[i] = schema.methods[i]; + } + + // apply statics + for (var i in schema.statics) + EmbeddedDocument[i] = schema.statics[i]; + + ArrayType.call(this, key, EmbeddedDocument, options); + + var self = this; + + this.schema = schema; + this.default(function(){ + return new MongooseDocumentArray([], self.path, this); + }); +}; + +/** + * Inherits from ArrayType. + */ + +DocumentArray.prototype.__proto__ = ArrayType.prototype; + +/** + * Performs local validations first, then validations on each embedded doc + * + * @api private + */ + +DocumentArray.prototype.doValidate = function (array, fn, scope) { + var self = this; + SchemaType.prototype.doValidate.call(this, array, function(err){ + if (err) return fn(err); + + var count = array.length + , error = false; + + if (!count) return fn(); + + array.forEach(function(doc, index){ + doc.validate(function(err){ + if (err && !error){ + // rewrite they key + err.key = self.key + '.' + index + '.' + err.key; + fn(err); + error = true; + } else { + --count || fn(); + } + }); + }); + }, scope); +}; + +/** + * Casts contents + * + * @param {Object} value + * @param {Document} document that triggers the casting + * @api private + */ + +DocumentArray.prototype.cast = function (value, doc) { + if (Array.isArray(value)){ + if (!(value instanceof MongooseDocumentArray)) + value = new MongooseDocumentArray(value, this.path, doc); + + for (var i = 0, l = value.length; i < l; i++) + if (!(value[i] instanceof Subdocument)){ + var doc = new this.caster(null, value); + value[i] = doc.init(value[i].doc || value[i]); + } + + return value; + } else { + return this.cast([value], doc); + } + + throw new CastError('documentarray', value); +}; + +/** + * Module exports. + */ + +module.exports = DocumentArray; diff --git a/node_modules/mongoose/lib/mongoose/schema/index.js b/node_modules/mongoose/lib/mongoose/schema/index.js new file mode 100644 index 0000000..d7c1a1f --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schema/index.js @@ -0,0 +1,20 @@ + +/** + * Module exports. + */ + +exports.String = require('./string'); + +exports.Number = require('./number'); + +exports.Boolean = require('./boolean'); + +exports.DocumentArray = require('./documentarray'); + +exports.Array = require('./array'); + +exports.Date = require('./date'); + +exports.ObjectId = require('./objectid'); + +exports.Mixed = require('./mixed'); diff --git a/node_modules/mongoose/lib/mongoose/schema/mixed.js b/node_modules/mongoose/lib/mongoose/schema/mixed.js new file mode 100644 index 0000000..6f98be0 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schema/mixed.js @@ -0,0 +1,63 @@ + +/** + * Module dependencies. + */ + +var SchemaType = require('../schematype'); + +/** + * Mixed SchemaType constructor. + * + * @param {String} path + * @param {Object} options + * @api private + */ + +function Mixed (path, options) { + // make sure empty array defaults are handled + if (options && + options.default && + Array.isArray(options.default) && + 0 === options.default.length) { + options.default = Array; + } + + SchemaType.call(this, path, options); +}; + +/** + * Inherits from SchemaType. + */ +Mixed.prototype.__proto__ = SchemaType.prototype; + +/** + * Required validator for mixed type + * + * @api private + */ + +Mixed.prototype.checkRequired = function (val) { + return true; +}; + +/** + * Noop casting + * + * @param {Object} value to cast + * @api private + */ + +Mixed.prototype.cast = function (val) { + return val; +}; + +Mixed.prototype.castForQuery = function ($cond, val) { + if (arguments.length === 2) return val; + return $cond; +}; + +/** + * Module exports. + */ + +module.exports = Mixed; diff --git a/node_modules/mongoose/lib/mongoose/schema/number.js b/node_modules/mongoose/lib/mongoose/schema/number.js new file mode 100644 index 0000000..1f31b32 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schema/number.js @@ -0,0 +1,134 @@ + +/** + * Module requirements. + */ + +var SchemaType = require('../schematype') + , CastError = SchemaType.CastError + , MongooseNumber = require('../types/number'); + +/** + * Number SchemaType constructor. + * + * @param {String} key + * @param {Object} options + * @api private + */ + +function SchemaNumber (key, options) { + SchemaType.call(this, key, options); +}; + +/** + * Inherits from SchemaType. + */ + +SchemaNumber.prototype.__proto__ = SchemaType.prototype; + +/** + * Required validator for number + * + * @api private + */ + +SchemaNumber.prototype.checkRequired = function (value) { + return typeof value == 'number' || value instanceof Number; +}; + +/** + * Sets a maximum number validator + * + * @param {Number} minimum number + * @api public + */ + +SchemaNumber.prototype.min = function (value, message) { + if (this.minValidator) + this.validators = this.validators.filter(function(v){ + return v[1] != 'min'; + }); + if (value != null) + this.validators.push([function(v){ + return v >= value; + }, 'min']); + return this; +}; + +/** + * Sets a maximum number validator + * + * @param {Number} maximum number + * @api public + */ + +SchemaNumber.prototype.max = function (value, message) { + if (this.maxValidator) + this.validators = this.validators.filter(function(v){ + return v[1] != 'max'; + }); + if (value != null) + this.validators.push([this.maxValidator = function(v){ + return v <= value; + }, 'max']); + return this; +}; + +/** + * Casts to number + * + * @param {Object} value to cast + * @param {Document} document that triggers the casting + * @api private + */ + +SchemaNumber.prototype.cast = function (value, doc) { + if (!isNaN(value)){ + if (null === value) return value; + if ('' === value) return null; + if ('string' === typeof value) value = Number(value); + if (value instanceof Number || typeof value == 'number' || + (value.toString && value.toString() == Number(value))) + return new MongooseNumber(value, this.path, doc); + } + throw new CastError('number', value); +}; + +function handleSingle (val) { + return this.cast(val).valueOf(); +} + +function handleArray (val) { + var self = this; + return val.map( function (m) { + return self.cast(m).valueOf(); + }); +} + +SchemaNumber.prototype.$conditionalHandlers = { + '$lt': handleSingle + , '$lte': handleSingle + , '$gt': handleSingle + , '$gte': handleSingle + , '$ne': handleSingle + , '$in': handleArray + , '$nin': handleArray + , '$mod': handleArray +}; +SchemaNumber.prototype.castForQuery = function ($conditional, val) { + var handler; + if (arguments.length === 2) { + handler = this.$conditionalHandlers[$conditional]; + if (!handler) + throw new Error("Can't use " + $conditional + " with Number."); + return handler.call(this, val); + } else { + val = $conditional; + return this.cast(val); + } +}; + +/** + * Module exports. + */ + +module.exports = SchemaNumber; diff --git a/node_modules/mongoose/lib/mongoose/schema/objectid.js b/node_modules/mongoose/lib/mongoose/schema/objectid.js new file mode 100644 index 0000000..e4f99a0 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schema/objectid.js @@ -0,0 +1,110 @@ +/** + * Module dependencies. + */ + +var SchemaType = require('../schematype') + , CastError = SchemaType.CastError + , driver = global.MONGOOSE_DRIVER_PATH || './../drivers/node-mongodb-native' + , oid = require('../types/objectid'); + + +/** + * ObjectId SchemaType constructor. + * + * @param {String} key + * @param {Object} options + * @api private + */ + +function ObjectId (key, options) { + SchemaType.call(this, key, options); +}; + +/** + * Inherits from SchemaType. + */ + +ObjectId.prototype.__proto__ = SchemaType.prototype; + +/** + * Check required + * + * @api private + */ + +ObjectId.prototype.checkRequired = function (value) { + return !!value && value instanceof oid; +}; + +/** + * Casts to ObjectId + * + * @api private + */ + +ObjectId.prototype.cast = function (value) { + if (value === null) return value; + + if (value instanceof oid) + return value; + + if (value._id && value._id instanceof oid) + value = value._id; + + if (value.toString) + return oid.fromString(value.toString()); + + throw new CastError('object id', value); +}; + +function handleSingle (val) { + return this.cast(val); +} + +function handleArray (val) { + var self = this; + return val.map(function (m) { + return self.cast(m); + }); +} + +ObjectId.prototype.$conditionalHandlers = { + '$ne': handleSingle + , '$in': handleArray + , '$nin': handleArray + , '$gt': handleSingle + , '$lt': handleSingle + , '$gte': handleSingle + , '$lte': handleSingle +}; +ObjectId.prototype.castForQuery = function ($conditional, val) { + var handler; + if (arguments.length === 2) { + handler = this.$conditionalHandlers[$conditional]; + if (!handler) + throw new Error("Can't use " + $conditional + " with ObjectId."); + return handler.call(this, val); + } else { + val = $conditional; + return this.cast(val); + } +}; + +/** + * Adds an auto-generated ObjectId default if turnOn is true. + * @param {Boolean} turnOn auto generated ObjectId defaults + * @api private + */ +ObjectId.prototype.auto = function (turnOn) { + if (turnOn) { + this.default(function(){ + return new oid(); + }); + } +}; + +/** + * Module exports. + */ + +module.exports = ObjectId; diff --git a/node_modules/mongoose/lib/mongoose/schema/string.js b/node_modules/mongoose/lib/mongoose/schema/string.js new file mode 100644 index 0000000..6e44377 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schema/string.js @@ -0,0 +1,172 @@ + +/** + * Module dependencies. + */ + +var SchemaType = require('../schematype') + , CastError = SchemaType.CastError; + +/** + * String SchemaType constructor. + * + * @param {String} key + * @api private + */ + +function SchemaString (key, options) { + this.enumValues = []; + this.regExp = null; + SchemaType.call(this, key, options); +}; + +/** + * Inherits from SchemaType. + */ + +SchemaString.prototype.__proto__ = SchemaType.prototype; + +/** + * Adds enumeration values + * + * @param {multiple} enumeration values + * @api public + */ + +SchemaString.prototype.enum = function () { + var len = arguments.length; + if (!len || undefined === arguments[0] || false === arguments[0]) { + if (this.enumValidator){ + this.enumValidator = false; + this.validators = this.validators.filter(function(v){ + return v[1] != 'enum'; + }); + } + return; + } + + for (var i = 0; i < len; i++) { + if (undefined !== arguments[i]) { + this.enumValues.push(this.cast(arguments[i])); + } + } + + if (!this.enumValidator) { + var values = this.enumValues; + this.enumValidator = function(v){ + return ~values.indexOf(v); + }; + this.validators.push([this.enumValidator, 'enum']); + } +}; + +/** + * Adds a lowercase setter + * + * @api public + */ + +SchemaString.prototype.lowercase = function () { + return this.set(function (v) { + return v.toLowerCase(); + }); +}; + +/** + * Adds an uppercase setter + * + * @api public + */ + +SchemaString.prototype.uppercase = function () { + return this.set(function (v) { + return v.toUpperCase(); + }); +}; + +/** + * Adds a trim setter + * + * @api public + */ + +SchemaString.prototype.trim = function () { + return this.set(function (v) { + return v.trim(); + }); +}; + +/** + * Sets a regexp test + * + * @param {RegExp} regular expression to test against + * @param {String} optional validator message + * @api public + */ + +SchemaString.prototype.match = function(regExp){ + this.validators.push([function(v){ + return regExp.test(v); + }, 'regexp']); +}; + +/** + * Check required + * + * @api private + */ + +SchemaString.prototype.checkRequired = function (v) { + return (v instanceof String || typeof v == 'string') && v.length; +}; + +/** + * Casts to String + * + * @api private + */ + +SchemaString.prototype.cast = function (value) { + if (value === null) return value; + if (value.toString) return value.toString(); + throw new CastError('string', value); +}; + +function handleSingle (val) { + return this.castForQuery(val); +} + +function handleArray (val) { + var self = this; + return val.map( function (m) { + return self.castForQuery(m); + }); +} + +SchemaString.prototype.$conditionalHandlers = { + '$ne' : handleSingle + , '$in' : handleArray + , '$nin': handleArray + , '$gt' : handleSingle + , '$lt' : handleSingle + , '$gte': handleSingle + , '$lte': handleSingle +}; +SchemaString.prototype.castForQuery = function ($conditional, val) { + var handler; + if (arguments.length === 2) { + handler = this.$conditionalHandlers[$conditional]; + if (!handler) + throw new Error("Can't use " + $conditional + " with String."); + return handler.call(this, val); + } else { + val = $conditional; + if (val instanceof RegExp) return val; + return this.cast(val); + } +}; + +/** + * Module exports. + */ + +module.exports = SchemaString; diff --git a/node_modules/mongoose/lib/mongoose/schemadefault.js b/node_modules/mongoose/lib/mongoose/schemadefault.js new file mode 100644 index 0000000..296e826 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schemadefault.js @@ -0,0 +1,18 @@ + +/** + * Module dependencies. + */ + +var Schema = require('./schema') + +/** + * Default model for querying the system.profiles + * collection (it only exists when profiling is + * enabled. + */ + +exports['system.profile'] = new Schema({ + ts: Date + , info: String + , millis: Number +}); diff --git a/node_modules/mongoose/lib/mongoose/schematype.js b/node_modules/mongoose/lib/mongoose/schematype.js new file mode 100644 index 0000000..8398621 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/schematype.js @@ -0,0 +1,331 @@ + +/** + * Module dependencies. + */ + +var MongooseError = require('./error'); + +/** + * SchemaType constructor + * + * @param {String} path + * @api public + */ + +function SchemaType (path, options) { + this.path = path; + this.validators = []; + this.setters = []; + this.getters = []; + this.options = options; + this._index = null; + for (var i in options) + if (this[i] && 'function' == typeof this[i]){ + var opts = Array.isArray(options[i]) ? options[i] : [options[i]]; + this[i].apply(this, opts); + } +}; + +/** + * Base schema. Set by Schema when instantiated. + * + * @api private + */ + +SchemaType.prototype.base; + +/** + * Sets a default + * + * @param {Object} default value + * @api public + */ + +SchemaType.prototype.default = function (val) { + if (arguments.length === 1) { + this.defaultValue = (typeof val === 'function') + ? val + : this.cast(val); + return this; + } else if (arguments.length > 1) { + this.defaultValue = [].slice.call(arguments); + } + return this.defaultValue; +}; + +/** + * Sets index. It can be a boolean or a hash of options + * Example: + * Schema.path('my.path').index(true); + * Schema.path('my.path').index({ unique: true }); + * + * "Direction doesn't matter for single key indexes" + * http://www.mongodb.org/display/DOCS/Indexes#Indexes-CompoundKeysIndexes + * + * @param {Object} true/ + * @api public + */ + +SchemaType.prototype.index = function (index) { + this._index = index; + return this; +}; + +/** + * Adds an unique index + * + * @param {Boolean} + * @api private + */ + +SchemaType.prototype.unique = function (bool) { + if (!this._index || Object !== this._index.constructor) { + this._index = {}; + } + + this._index.unique = bool; + return this; +}; + +/** + * Adds an unique index + * + * @param {Boolean} + * @api private + */ + +SchemaType.prototype.sparse = function (bool) { + if (!this._index || Object !== this._index.constructor) { + this._index = {}; + } + + this._index.sparse = bool; + return this; +}; + +/** + * Adds a setter + * + * @param {Function} setter + * @api public + */ + +SchemaType.prototype.set = function (fn) { + this.setters.push(fn); + return this; +}; + +/** + * Adds a getter + * + * @param {Function} getter + * @api public + */ + +SchemaType.prototype.get = function (fn) { + this.getters.push(fn); + return this; +}; + +/** + * Adds a validator + * + * @param {Object} validator + * @param {String} optional error message + * @api public + */ + +SchemaType.prototype.validate = function(obj, error){ + this.validators.push([obj, error]); + return this; +}; + +/** + * Adds a required validator + * + * @param {Boolean} enable/disable the validator + * @api public + */ + +SchemaType.prototype.required = function(required){ + var self = this; + + function __checkRequired (v) { + return self.checkRequired(v); + } + + if (false === required){ + this.isRequired = false; + this.validators = this.validators.filter(function(v){ + return v[0].name !== '__checkRequired'; + }); + } else { + this.isRequired = true; + this.validators.push([__checkRequired, 'required']); + } + + return this; +}; + +/** + * Gets the default value + * + * @param {Object} scope for callback defaults + * @api private + */ + +SchemaType.prototype.getDefault = function (scope) { + var ret; + + if ('function' == typeof this.defaultValue) + ret = this.defaultValue.call(scope); + else + ret = this.defaultValue; + + if (ret !== null && ret !== undefined) + ret = this.cast(ret, scope); + + return ret; +}; + +/** + * Applies setters + * + * @param {Object} value + * @param {Object} scope + * @api private + */ + +SchemaType.prototype.applySetters = function (value, scope) { + var v = value + , setters = this.setters + , l = setters.length; + for (var k = l - 1; k >= 0; k--){ + v = setters[k].call(scope, v); + if (v === null || v === undefined) return v; + v = this.cast(v, scope); + } + if (!l) { + if (v === null || v === undefined) return v; + v = this.cast(v, scope); + } + return v; +}; + +/** + * Applies getters to a value + * + * @param {Object} value + * @param {Object} scope + * @api private + */ + +SchemaType.prototype.applyGetters = function (value, scope) { + var v = value + , getters = this.getters + , l = getters.length; + for (var k = l - 1; k >= 0; k--){ + v = this.getters[k].call(scope, v); + if (v === null || v === undefined) return v; + v = this.cast(v, scope); + } + if (!l) { + if (v === null || v === undefined) return v; + v = this.cast(v, scope); + } + return v; +}; + +/** + * Performs a validation + * + * @param {Function} callback + * @param {Object} scope + * @api private + */ + +SchemaType.prototype.doValidate = function (value, fn, scope) { + var err = false + , path = this.path + , count = this.validators.length; + + if (!count) return fn(null); + + function validate (val, msg) { + if (err) return; + if (val === undefined || val) { + --count || fn(null); + } else { + fn(new ValidatorError(path, msg)); + err = true; + } + } + + this.validators.forEach(function (v){ + var validator = v[0] + , message = v[1]; + if (validator instanceof RegExp) + validate(validator.test(value), message); + else if ('function' == typeof validator) + if (2 == validator.length) + validator.call(scope, value, function(val){ + validate(val, message); + }) + else + validate(validator.call(scope, value), message); + }); +}; + +/** + * Schema validator error + * + * @param {String} path + * @param {String} msg + * @api private + */ + +function ValidatorError (path, msg) { + msg = msg + ? '"' + msg + '" ' + : ''; + MongooseError.call(this, 'Validator ' + msg + 'failed for path ' + path); + Error.captureStackTrace(this, arguments.callee); + this.name = 'ValidatorError'; + this.path = path; +}; + +/** + * Inherits from MongooseError + */ + +ValidatorError.prototype.__proto__ = MongooseError.prototype; + +/** + * Cast error + * + * @api private + */ + +function CastError (type, value) { + MongooseError.call(this, 'Cast to ' + type + ' failed for value "' + value + '"'); + Error.captureStackTrace(this, arguments.callee); + this.name = 'CastError'; + this.type = type; + this.value = value; +}; + +/** + * Inherits from MongooseError. + */ + +CastError.prototype.__proto__ = MongooseError.prototype; + +/** + * Module exports. + */ + +module.exports = exports = SchemaType; + +exports.CastError = CastError; + +exports.ValidatorError = ValidatorError; diff --git a/node_modules/mongoose/lib/mongoose/types/array.js b/node_modules/mongoose/lib/mongoose/types/array.js new file mode 100644 index 0000000..9b134f9 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/types/array.js @@ -0,0 +1,340 @@ + +/** + * Module dependencies. + */ + +var EmbeddedDocument = require('./document'); +var ObjectId = require('./objectid'); + +/** + * Mongoose Array constructor. + * Values always have to be passed to the constructor to initialize, since + * otherwise MongooseArray#push will mark the array as modified to the parent. + * + * @param {Array} values + * @param {String} key path + * @param {Document} parent document + * @api private + * @see http://bit.ly/f6CnZU + */ + +function MongooseArray (values, path, doc) { + var arr = []; + arr.push.apply(arr, values); + arr.__proto__ = MongooseArray.prototype; + + // make sure these internal props don't show up in Object.keys() + Object.defineProperties(arr, { + _atomics: { value: {} } + , validators: { value: [] } + , _path: { value: path } + , _parent: { value: doc } + }); + + if (doc) { + Object.defineProperty(arr, '_schema', { + value: doc.schema.path(path) + }); + } + + return arr; +}; + +/** + * Inherit from Array. + */ + +MongooseArray.prototype = new Array(); + +/** + * Stores a queue of atomic operations to perform + * + * @api private + */ + +MongooseArray.prototype._atomics; + +/** + * Parent owner document + * + * @api private + */ + +MongooseArray.prototype._parent; + +/** + * Casts a member + * + * @api private + */ + +MongooseArray.prototype._cast = function (value) { + var cast = this._schema.caster.prototype.cast + , doc = this._parent; + + return cast.call(null, value, doc); +}; + +/** + * Marks this array as modified. + * It is called during a nonAtomicPush, an atomic opteration, + * or by an existing embedded document that is modified. + * + * If it bubbles up from an embedded document change, + * then it takes the following arguments (otherwise, takes + * 0 arguments) + * @param {EmbeddedDocument} embeddedDoc that invokes this method on the MongooseArray + * @param {String} embeddedPath is what changed inthe embeddedDoc + * + * @api public + */ + +MongooseArray.prototype._markModified = function (embeddedDoc, embeddedPath) { + var parent = this._parent + , dirtyPath; + + if (parent) { + dirtyPath = this._path; + if (arguments.length) { + // If an embedded doc bubbled up the change + dirtyPath = [this._path, this.indexOf(embeddedDoc), embeddedPath].join('.'); + } + parent.markModified(dirtyPath); + } + return this; +}; + +/** + * Register an atomic operation with the parent + * + * @param {Array} operation + * @api private + */ + +MongooseArray.prototype._registerAtomic = function (op, val) { + var atomics = this._atomics + if (op === '$pullAll' || op === '$pushAll') { + atomics[op] || (atomics[op] = []); + atomics[op] = atomics[op].concat(val); + } else { + atomics[op] = val; + } + this._markModified(); + return this; +}; + +/** + * Returns true if we have to perform atomics for this, and no normal + * operations + * + * @api public + */ + +MongooseArray.prototype.__defineGetter__('doAtomics', function () { + return Object.keys(this._atomics).length; +}); + +/** + * Pushes item/s to the array atomically. Overrides Array#push + * + * @param {Object} value + * @api public + */ + +var oldPush = MongooseArray.prototype.push; + +MongooseArray.prototype.$push = +MongooseArray.prototype.push = function () { + var values = Array.prototype.map.call(arguments, this._cast, this) + , ret = oldPush.apply(this, values); + + // $pushAll might be fibbed (could be $push). But it makes it easier to + // handle what could have been $push, $pushAll combos + this._registerAtomic('$pushAll', values); + + return ret; +}; + +/** + * Pushes item/s to the array non-atomically + * + * @param {Object} value + * @api public + */ + +MongooseArray.prototype.nonAtomicPush = function () { + var self = this + , values = Array.prototype.map.call(arguments, this._cast, this) + , ret = oldPush.apply(this, values); + + this._markModified(); + + return ret; +}; + +/** + * Pushes several items at once to the array atomically + * + * @param {Array} values + * @api public + */ + +MongooseArray.prototype.$pushAll = function (value) { + var length = this.length; + this.nonAtomicPush.apply(this, value); + // make sure we access the casted elements + this._registerAtomic('$pushAll', this.slice(length)); + return this; +}; + +/** + * Pops the array atomically + * + * @api public + */ + +MongooseArray.prototype.$pop = function () { + this._registerAtomic('$pop', 1); + return this.pop(); +}; + +/** + * Shifts the array + * + * @api public + */ + +MongooseArray.prototype.$shift = function () { + this._registerAtomic('$pop', -1); + return this.shift(); +}; + +/** + * Removes items from an array atomically + * + * Examples: + * doc.array.remove(ObjectId) + * doc.array.remove('tag 1', 'tag 2') + * + * @param {Object} value to remove + * @api public + */ + +MongooseArray.prototype.remove = function () { + var args = Array.prototype.map.call(arguments, this._cast, this); + if (args.length == 1) + this.$pull(args[0]); + else + this.$pullAll(args); + return args; +}; + +/** + * Pulls from the array + * + * @api public + */ + +MongooseArray.prototype.pull = +MongooseArray.prototype.$pull = function () { + var values = Array.prototype.map.call(arguments, this._cast, this) + , oldArr = this._parent.get(this._path) + , i = oldArr.length, mem; + while (i--) { + mem = oldArr[i]; + if (mem instanceof EmbeddedDocument) { + if (values.some( function (v) { return v.equals(mem); } )) { + oldArr.splice(i, 1); + } + } else if (~values.indexOf(mem)) oldArr.splice(i, 1); + } + if (values[0] instanceof EmbeddedDocument) { + this._registerAtomic('$pullAll', values.map( function (v) { return {_id: v._id}; } )); + } else { + this._registerAtomic('$pullAll', values); + } + return this; +}; + +/** + * Pulls many items from an array + * + * @api public + */ + +MongooseArray.prototype.$pullAll = function (values) { + if (values && values.length) { + var oldArr = this._parent.get(this._path) + , i = oldArr.length, mem; + while (i--) { + mem = oldArr[i]; + if (mem instanceof EmbeddedDocument) { + if (values.some( function (v) { return v.equals(mem); } )) { + oldArr.splice(i, 1); + } + } else if (~values.indexOf(mem)) oldArr.splice(i, 1); + } + this._registerAtomic('$pullAll', values); + } + return this; +}; + +/** + * Splices the array. + */ + +MongooseArray.prototype.splice = function () { + Array.prototype.splice.apply(this, arguments); + this._markModified(); + return this; +}; + +/** + * Returns an Array + * + * @return {Array} + * @api public + */ + +MongooseArray.prototype.toObject = function () { + return this.map( function (doc) { + return doc; + }); +}; + +/** + * Helper for console.log + * + * @api public + */ + +MongooseArray.prototype.inspect = function () { + return '[' + this.map(function (doc) { + return ' ' + doc; + }) + ' ]'; +}; + + + +/** + * Return the index of `obj` or `-1.` + * + * @param {Object} obj + * @return {Number} + * @api public + */ + +MongooseArray.prototype.indexOf = function(obj){ + if (obj instanceof ObjectId) obj = obj.toString(); + for (var i = 0, len = this.length; i < len; ++i) { + if (obj == this[i]) + return i; + } + return -1; +}; + +/** + * Module exports. + */ + +module.exports = MongooseArray; diff --git a/node_modules/mongoose/lib/mongoose/types/document.js b/node_modules/mongoose/lib/mongoose/types/document.js new file mode 100644 index 0000000..e56c484 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/types/document.js @@ -0,0 +1,113 @@ + +/** + * Module dependencies. + */ + +var Document = require('../document') + , inspect = require('util').inspect; + +/** + * EmbeddedDocument constructor. + * + * @param {Object} object from db + * @param {MongooseDocumentArray} parent array + * @api private + */ + +function EmbeddedDocument (obj, parentArr) { + this.parentArray = parentArr; + this.parent = parentArr.parent; + Document.call(this, obj); +}; + +/** + * Inherit from Document + * + */ + +EmbeddedDocument.prototype.__proto__ = Document.prototype; + +/** + * Override set to mark the parent as modified + * + * @api public + */ + +var oldSet = Document.prototype.set; + +EmbeddedDocument.prototype.set = function (path) { + this.markModified(path); + return oldSet.apply(this, arguments); +}; + +/** + * Marks parent array as modified + * + * @api private + */ + +EmbeddedDocument.prototype.commit = +EmbeddedDocument.prototype.markModified = function (path) { + this.activePaths.modify(path); + + if (this.isNew) { + // Mark the WHOLE parent array as modified + // if this is a new document (i.e., we are initializing + // a document), + this.parentArray._markModified(); + } else + this.parentArray._markModified(this, path); +}; + +/** + * Save the subdocument + * + * @api public + */ + +EmbeddedDocument.prototype.save = function(fn) { + if (fn) + fn(null); + this.emit('save', this); + return this; +}; + +/** + * Remove the subdocument + * + * @api public + */ + +EmbeddedDocument.prototype.remove = function (fn) { + var _id; + if (!this.willRemove){ + _id = this.doc._id; + if (!_id) { + throw new Error('For your own good, Mongoose does not know ' + + 'how to remove an EmbeddedDocument that has no _id'); + } + this.parentArray.$pull({ _id: _id }); + this.willRemove = true; + } + + if (fn) + fn(null); + + return this; +}; + +/** + * Helper for console.log + * + * @api public + */ + +EmbeddedDocument.prototype.inspect = function () { + return inspect(this.toObject()); +}; + +/** + * Module exxports. + */ + +module.exports = EmbeddedDocument; diff --git a/node_modules/mongoose/lib/mongoose/types/documentarray.js b/node_modules/mongoose/lib/mongoose/types/documentarray.js new file mode 100644 index 0000000..f56d537 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/types/documentarray.js @@ -0,0 +1,106 @@ + +/** + * Module dependencies. + */ + +var MongooseArray = require('./array') + , driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native' + , ObjectId = require(driver + '/objectid') + , ObjectIdSchema = require('../schema/objectid'); + +/** + * Array of embedded documents + * Values always have to be passed to the constructor to initialize, since + * otherwise MongooseArray#push will mark the array as modified to the parent. + * + * @param {Array} values + * @param {String} key path + * @param {Document} parent document + * @api private + * @see http://bit.ly/f6CnZU + */ + +function MongooseDocumentArray (values, path, doc) { + var arr = []; + arr.push.apply(arr, values); + arr.__proto__ = MongooseDocumentArray.prototype; + arr._atomics = []; + arr.validators = []; + arr._path = path; + arr._parent = doc; + if (doc) + arr._schema = doc.schema.path(path); + return arr; +}; + +/** + * Inherits from MongooseArray + */ + +MongooseDocumentArray.prototype.__proto__ = MongooseArray.prototype; + +/** + * Overrides cast + * + * @api private + */ + +MongooseDocumentArray.prototype._cast = function (value) { + var doc = new this._schema.caster(value, this); + return doc; +}; + +/** + * Filters items by id + * + * @param {Object} id + * @api public + */ + +MongooseDocumentArray.prototype.id = function(id) { + try { + var casted = ObjectIdSchema.prototype.cast.call(null, id); + } catch (e) { + // cast error + return null; + } + + for (var i = 0, l = this.length; i < l; i++) { + if (ObjectId.toString(casted) == ObjectId.toString(this[i].get('_id'))) + return this[i]; + } + + return null; +}; + +/** + * Returns an Array and converts any Document + * members toObject. + * + * @return {Array} + * @api public + */ + +MongooseDocumentArray.prototype.toObject = function () { + return this.map( function (doc) { + return doc.toObject(); + }); +}; + +/** + * Helper for console.log + * + * @api public + */ + +MongooseDocumentArray.prototype.inspect = function () { + return '[' + this.map(function (doc) { + return doc.inspect(); + }).join('\n') + ']'; +}; + +/** + * Module exports. + */ + +module.exports = MongooseDocumentArray; diff --git a/node_modules/mongoose/lib/mongoose/types/index.js b/node_modules/mongoose/lib/mongoose/types/index.js new file mode 100644 index 0000000..63cbf7f --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/types/index.js @@ -0,0 +1,10 @@ + +/** + * Module exports. + */ + +exports.Array = require('./array'); +exports.Document = require('./document'); +exports.DocumentArray = require('./documentarray'); +exports.Number = require('./number'); +exports.ObjectId = require('./objectid'); diff --git a/node_modules/mongoose/lib/mongoose/types/number.js b/node_modules/mongoose/lib/mongoose/types/number.js new file mode 100644 index 0000000..9827974 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/types/number.js @@ -0,0 +1,82 @@ + +/** + * Module dependencies. + */ + +/** + * MongooseNumber constructor. + * + * @param {Object} value to pass to Number + * @param {Document} parent document + * @api private + */ + +function MongooseNumber (value, path, doc) { + var number = new Number(value); + number.__proto__ = MongooseNumber.prototype; + number._atomics = {}; + number._path = path; + number._parent = doc; + return number; +}; + +/** + * Inherits from Number. + */ + +MongooseNumber.prototype = new Number(); + +/** + * Atomic increment + * + * @api public + */ + +MongooseNumber.prototype.increment = function(value){ + var schema = this._parent.schema.path(this._path) + , value = Number(value) || 1; + if (isNaN(value)) value = 1; + this._parent.setValue(this._path, schema.cast(this + value)); + this._parent.getValue(this._path)._atomics['$inc'] = value || 1; + this._parent.activePaths.modify(this._path); + return this; +}; + +/** + * Returns true if we have to perform atomics for this, and no normal + * operations + * + * @api public + */ + +MongooseNumber.prototype.__defineGetter__('doAtomics', function () { + return Object.keys(this._atomics).length; +}); + +/** + * Atomic decrement + * + * @api public + */ + +MongooseNumber.prototype.decrement = function(){ + this.increment(-1); +}; + +/** + * Re-declare toString (for `console.log`) + * + * @api public + */ + +MongooseNumber.prototype.inspect = +MongooseNumber.prototype.toString = function () { + return String(this.valueOf()); +}; + + +/** + * Module exports + */ + +module.exports = MongooseNumber; diff --git a/node_modules/mongoose/lib/mongoose/types/objectid.js b/node_modules/mongoose/lib/mongoose/types/objectid.js new file mode 100644 index 0000000..e811fdf --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/types/objectid.js @@ -0,0 +1,12 @@ + +/** + * Access driver. + */ + +var driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native'; + +/** + * Module exports. + */ + +module.exports = require(driver + '/objectid'); diff --git a/node_modules/mongoose/lib/mongoose/utils.js b/node_modules/mongoose/lib/mongoose/utils.js new file mode 100644 index 0000000..a504272 --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/utils.js @@ -0,0 +1,479 @@ +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , ObjectId = require('./types/objectid') + +/** + * Produces a collection name from a model name + * + * @param {String} model name + * @return {String} collection name + * @api private + */ + +exports.toCollectionName = function (name) { + if ('system.profile' === name) return name; + if ('system.indexes' === name) return name; + return pluralize(name.toLowerCase()); +}; + +/** + * Pluralization rules. + */ + +var rules = [ + [/(m)an$/gi, '$1en'], + [/(pe)rson$/gi, '$1ople'], + [/(child)$/gi, '$1ren'], + [/^(ox)$/gi, '$1en'], + [/(ax|test)is$/gi, '$1es'], + [/(octop|vir)us$/gi, '$1i'], + [/(alias|status)$/gi, '$1es'], + [/(bu)s$/gi, '$1ses'], + [/(buffal|tomat|potat)o$/gi, '$1oes'], + [/([ti])um$/gi, '$1a'], + [/sis$/gi, 'ses'], + [/(?:([^f])fe|([lr])f)$/gi, '$1$2ves'], + [/(hive)$/gi, '$1s'], + [/([^aeiouy]|qu)y$/gi, '$1ies'], + [/(x|ch|ss|sh)$/gi, '$1es'], + [/(matr|vert|ind)ix|ex$/gi, '$1ices'], + [/([m|l])ouse$/gi, '$1ice'], + [/(quiz)$/gi, '$1zes'], + [/s$/gi, 's'], + [/$/gi, 's'] +]; + +/** + * Uncountable words. + */ + +var uncountables = [ + 'advice', + 'energy', + 'excretion', + 'digestion', + 'cooperation', + 'health', + 'justice', + 'labour', + 'machinery', + 'equipment', + 'information', + 'pollution', + 'sewage', + 'paper', + 'money', + 'species', + 'series', + 'rain', + 'rice', + 'fish', + 'sheep', + 'moose', + 'deer', + 'news' +]; + +/** + * Pluralize function. + * + * @author TJ Holowaychuk (extracted from _ext.js_) + * @param {String} string to pluralize + * @api private + */ + +function pluralize (str) { + var rule, found; + if (!~uncountables.indexOf(str.toLowerCase())){ + found = rules.filter(function(rule){ + return str.match(rule[0]); + }); + if (found[0]) return str.replace(found[0][0], found[0][1]); + } + return str; +}; + +/** + * Add `once` to EventEmitter if absent + * + * @param {String} event name + * @param {Function} listener + * @api private + */ + +var Events = EventEmitter; + +if (!('once' in EventEmitter.prototype)){ + + Events = function () { + EventEmitter.apply(this, arguments); + }; + + /** + * Inherit from EventEmitter. + */ + + Events.prototype.__proto__ = EventEmitter.prototype; + + /** + * Add `once`. + */ + + Events.prototype.once = function (type, listener) { + var self = this; + self.on(type, function g(){ + self.removeListener(type, g); + listener.apply(this, arguments); + }); + }; + +} + +exports.EventEmitter = Events; + +// Modified from node/lib/assert.js +exports.deepEqual = function deepEqual (a, b) { + if (a === b) return true; + if (a instanceof Date && b instanceof Date) + return a.getTime() === b.getTime(); + if (typeof a !== 'object' && typeof b !== 'object') + return a == b; + if (a === null || b === null || a === undefined || b === undefined) + return false + if (a.prototype !== b.prototype) return false; + + try { + var ka = Object.keys(a), + kb = Object.keys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!deepEqual(a[key], b[key])) return false; + } + + // Handle MongooseNumber edge case + if (a.valueOf && b.valueOf && a.valueOf() !== b.valueOf()) { + return false; + } + + return true; +}; + +/** + * Object clone with Mongoose natives support. + * Creates a minimal data Object. + * It does not clone empty Arrays, empty Objects, + * and undefined values. + * This makes the data payload sent to MongoDB as minimal + * as possible. + * + * @param {Object} object to clone + * @param {Boolean} shouldMinimizeData + * @return {Object} cloned object + * @api private + */ + +var clone = exports.clone = function (obj, shouldMinimizeData) { + if (obj === undefined || obj === null) + return obj + + if (Array.isArray(obj)) + return cloneArray(obj, shouldMinimizeData); + + if (obj.toObject) + return obj.toObject(); + + if (obj.constructor == Object) + return cloneObject(obj, shouldMinimizeData); + + if (obj.constructor == Date || obj.constructor == Function) + return new obj.constructor(+obj); + + if (obj.constructor == RegExp) + return new RegExp(obj.source); + + if (obj instanceof ObjectId) + return ObjectId.fromString(ObjectId.toString(obj)); + + if (obj.valueOf) + return obj.valueOf(); +}; + +function cloneObject (obj, shouldMinimizeData) { + var ret = {} + , val + , hasKeys; + for (var k in obj) { + val = clone(obj[k], shouldMinimizeData); + if (!shouldMinimizeData || ('undefined' !== typeof val)) { + hasKeys || (hasKeys = true); + ret[k] = val; + } + } + return shouldMinimizeData + ? hasKeys && ret + : ret; +}; + +function cloneArray (arr, shouldMinimizeData) { + var ret = []; + for (var i = 0, l = arr.length; i < l; i++) + ret.push(clone(arr[i], shouldMinimizeData)); + return ret; +}; + +/** + * Copies and merges options with defaults. + * + * @param {Object} defaults + * @param {Object} options + * @return {Object} (merged) object + * @api private + */ + +exports.options = function (defaults, options) { + var keys = Object.keys(defaults) + , i = keys.length + , k ; + + options = options || {}; + + while (i--) { + k = keys[i]; + if (!(k in options)) { + options[k] = defaults[k]; + } + } + + return options; +}; + +/** + * Erases an item from an array + * + * @param {Array} array + * @param {Object} value + * @return undefined + * @api private + */ + +exports.erase = function (arr, item) { + for (var i = 0, l = arr.length; i < l; i++) + if (arr[i] === item) arr.splice(i, 1); +}; + +/** + * Generates a random string + * + * @api private + */ + +exports.random = function () { + return Math.random().toString().substr(3); +}; + + +/** + * A StateMachine represents a minimal `interface` for the + * constructors it builds via StateMachine.ctor(...). + * + * @api private + */ + +function StateMachine () { + this.paths = {}; + this.states = {}; +} + +/** + * StateMachine.ctor('state1', 'state2', ...) + * A factory method for subclassing StateMachine. + * The arguments are a list of states. For each state, + * the constructor's prototype gets state transition + * methods named after each state. These transition methods + * place their path argument into the given state. + * + * @param {String} state + * @param {String} [state] + * @return {Function} subclass constructor + * @api public + */ + +StateMachine.ctor = function () { + var states = [].slice.call(arguments); + var ctor = function () { + StateMachine.apply(this, arguments); + this.stateNames = states; + var i = states.length + , state; + while (i--) { + state = states[i]; + this.states[state] = {}; + } + }; + + ctor.prototype.__proto__ = StateMachine.prototype; + states.forEach( function (state) { + /** + * Changes the `path`'s state to `state`. + */ + ctor.prototype[state] = function (path) { + this._changeState(path, state); + } + }); + return ctor; +}; + +StateMachine.prototype = { + /** + * This function is wrapped by the state change functions: + * - `require(path)` + * - `modify(path)` + * - `init(path)` + * @api private + */ + + _changeState: function (path, nextState) { + var prevState = this.paths[path] + , prevBucket = this.states[prevState]; + delete this.paths[path]; + if (prevBucket) delete prevBucket[path]; + + this.paths[path] = nextState; + this.states[nextState][path] = true; + }, + + stateOf: function (path) { + return this.paths[path]; + }, + + clear: function (state) { + for (var path in this.states[state]) { + delete this.states[state][path]; + delete this.paths[path]; + } + }, + + /** + * Checks to see if at least one path is in the states passed in via `arguments` + * e.g., this.some('required', 'inited') + * @param {String} state that we want to check for. + * @api public + */ + + some: function () { + var self = this; + return Array.prototype.some.call(arguments.length ? arguments : this.stateNames, function (state) { + return Object.keys(self.states[state]).length; + }); + }, + + /** + * This function builds the functions that get assigned to `forEach` and `map`, + * since both of those methods share a lot of the same logic. + * + * @param {String} iterMethod is either 'forEach' or 'map' + * @return {Function} + * @api private + */ + + _iter: function (iterMethod) { + return function () { + var numArgs = arguments.length + , states = [].slice.call(arguments, 0, numArgs-1) + , callback = arguments[arguments.length-1]; + if (!states.length) states = this.stateNames; + var self = this; + var paths = states.reduce( function (paths, state) { + return paths.concat(Object.keys(self.states[state])); + + }, []); + return paths[iterMethod]( function (path) { + return callback(path); + }); + }; + }, + + /** + * Iterates over the paths that belong to one of the parameter states. + * + * The function profile can look like: + * this.forEach(state1, fn); // iterates over all paths in state1 + * this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2 + * this.forEach(fn); // iterates over all paths in all states + * + * @param {String} [state] + * @param {String} [state] + * @param {Function} callback + * @api public + */ + + forEach: function () { + this.forEach = this._iter('forEach'); + return this.forEach.apply(this, arguments); + }, + + /** + * Maps over the paths that belong to one of the parameter states. + * + * The function profile can look like: + * this.forEach(state1, fn); // iterates over all paths in state1 + * this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2 + * this.forEach(fn); // iterates over all paths in all states + * + * @param {String} [state] + * @param {String} [state] + * @param {Function} callback + * @return {Array} + * @api public + */ + + map: function () { + this.map = this._iter('map'); + return this.map.apply(this, arguments); + } +}; + +exports.StateMachine = StateMachine; + +exports.inGroupsOf = function inGroupsOf (card, arr, fn) { + var group = []; + for (var i = 0, l = arr.length; i < l; i++) { + if (i && i % card === 0) { + fn.apply(this, group); + group.length = 0; + } + group.push(arr[i]); + } + fn.apply(this, group); +}; + +exports.merge = function merge (objA, objB) { + for (var k in objB) { + if ('undefined' === typeof objA[k]) { + objA[k] = objB[k]; + } else { + merge(objA[k], objB[k]); + } + } +}; diff --git a/node_modules/mongoose/lib/mongoose/virtualtype.js b/node_modules/mongoose/lib/mongoose/virtualtype.js new file mode 100644 index 0000000..48b524e --- /dev/null +++ b/node_modules/mongoose/lib/mongoose/virtualtype.js @@ -0,0 +1,73 @@ +/** + * VirtualType constructor + * + * This is what mongoose uses to define virtual attributes via + * `Schema.prototype.virtual` + * + * @api public + */ + +function VirtualType () { + this.getters = []; + this.setters = []; +} + +/** + * Adds a getter + * + * @param {Function} fn + * @return {VirtualType} this + * @api public + */ + +VirtualType.prototype.get = function (fn) { + this.getters.push(fn); + return this; +}; + +/** + * Adds a setter + * + * @param {Function} fn + * @return {VirtualType} this + * @api public + */ + +VirtualType.prototype.set = function (fn) { + this.setters.push(fn); + return this; +}; + +/** + * Applies getters + * + * @param {Object} value + * @param {Object} scope + * @api public + */ + +VirtualType.prototype.applyGetters = function (value, scope) { + var v = value; + for (var l = this.getters.length - 1; l >= 0; l--){ + v = this.getters[l].call(scope, v); + } + return v; +}; + +/** + * Applies setters + * + * @param {Object} value + * @param {Object} scope + * @api public + */ + +VirtualType.prototype.applySetters = function (value, scope) { + var v = value; + for (var l = this.setters.length - 1; l >= 0; l--){ + this.setters[l].call(scope, v); + } + return v; +}; + +module.exports = VirtualType; diff --git a/node_modules/mongoose/package.json b/node_modules/mongoose/package.json new file mode 100644 index 0000000..4c9f89e --- /dev/null +++ b/node_modules/mongoose/package.json @@ -0,0 +1,23 @@ +{ + "name": "mongoose" + , "description": "Mongoose MongoDB ORM" + , "version": "1.7.4" + , "author": "Guillermo Rauch " + , "keywords": ["mongodb", "mongoose", "orm", "data", "datastore", "nosql"] + , "dependencies": { + "hooks": "0.1.9" + , "mongodb": "0.9.6-7" + , "colors": "0.5.0" + } + , "devDependencies": { + "should": "0.2.1" + } + , "directories": { "lib": "./lib/mongoose" } + , "scripts": { "test": "make test" } + , "main": "./index.js" + , "engines": { "node": ">= 0.2.0" } + , "repository": { + "type": "git" + , "url": "git://github.com/LearnBoost/mongoose.git" + } +} diff --git a/node_modules/mongoose/support/cli-table/History.md b/node_modules/mongoose/support/cli-table/History.md new file mode 100644 index 0000000..4f02434 --- /dev/null +++ b/node_modules/mongoose/support/cli-table/History.md @@ -0,0 +1,5 @@ + +0.0.1 / 2011-01-03 +================== + +Initial release diff --git a/node_modules/mongoose/support/cli-table/Makefile b/node_modules/mongoose/support/cli-table/Makefile new file mode 100644 index 0000000..479a783 --- /dev/null +++ b/node_modules/mongoose/support/cli-table/Makefile @@ -0,0 +1,14 @@ + +test: + @NODE_ENV=test ./support/expresso/bin/expresso \ + -I lib \ + -I support \ + -I support/should.js/lib \ + -I support/colors.js \ + $(TESTFLAGS) \ + test/*.test.js + +test-cov: + @TESTFLAGS=--cov $(MAKE) test + +.PHONY: test test-cov diff --git a/node_modules/mongoose/support/cli-table/README.md b/node_modules/mongoose/support/cli-table/README.md new file mode 100644 index 0000000..4248e7c --- /dev/null +++ b/node_modules/mongoose/support/cli-table/README.md @@ -0,0 +1,77 @@ + +CLI Table +========= + +This utility allows you to render unicode-aided tables on the command line from +your node.js scripts. + +![Screenshot](http://i.imgur.com/sYq4T.png) + +## Features + +- Customizable characters that constitute the table. +- Color/background styling in the header through + [colors.js](http://github.com/marak/colors.js) +- Column width customization +- Text truncation based on predefined widths +- Text alignment (left, right, center) +- Padding (left, right) +- Easy-to-use API + +## Installation + + npm install cli-table + +## How to use + + var Table = require('cli-table'); + + // instantiate + var table = new Table({ + head: ['TH 1 label', 'TH 2 label'] + , colWidths: [100, 200] + }); + + // table is an Array, so you can `push`, `unshift`, `splice` and friends + table.push( + ['First value', 'Second value'] + , ['First value', 'Second value'] + ); + + // render + console.log(table.toString()); + +## Running tests + +Clone the repository with all its submodules and run: + + $ make test + +## Credits + +- Guillermo Rauch <guillermo@learnboost.com> ([Guille](http://github.com/guille)) + +## License + +(The MIT License) + +Copyright (c) 2010 LearnBoost <dev@learnboost.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/mongoose/support/cli-table/examples/revs.js b/node_modules/mongoose/support/cli-table/examples/revs.js new file mode 100644 index 0000000..0f5fcc1 --- /dev/null +++ b/node_modules/mongoose/support/cli-table/examples/revs.js @@ -0,0 +1,25 @@ + +/** + * Module requirements. + */ + +// this line is only needed if you refuse to use npm +require.paths.unshift(__dirname + '/../support/colors'); + +var Table = require('../lib/cli-table'); + +/** + * Example. + */ + +var table = new Table({ + head: ['Rel', 'Change', 'By', 'When'] + , colWidths: [6, 21, 25, 17] +}); + +table.push( + ['v0.1', 'Testing something cool', 'rauchg@gmail.com', '7 minutes ago'] + , ['v0.1', 'Testing something cool', 'rauchg@gmail.com', '8 minutes ago'] +); + +console.log(table.toString()); diff --git a/node_modules/mongoose/support/cli-table/index.js b/node_modules/mongoose/support/cli-table/index.js new file mode 100644 index 0000000..1c01669 --- /dev/null +++ b/node_modules/mongoose/support/cli-table/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/cli-table'); diff --git a/node_modules/mongoose/support/cli-table/lib/cli-table/index.js b/node_modules/mongoose/support/cli-table/lib/cli-table/index.js new file mode 100644 index 0000000..6882a52 --- /dev/null +++ b/node_modules/mongoose/support/cli-table/lib/cli-table/index.js @@ -0,0 +1,205 @@ + +/** + * Module dependencies. + */ + +var utils = require('./utils') + , repeat = utils.repeat + , truncate = utils.truncate + , pad = utils.pad; + +require('colors'); + +/** + * Table constructor + * + * @param {Object} options + * @api public + */ + +function Table (options){ + this.options = utils.options({ + chars: { + 'top': '━' + , 'top-mid': '┳' + , 'top-left': '┏' + , 'top-right': '┓' + , 'bottom': '━' + , 'bottom-mid': '┻' + , 'bottom-left': '┗' + , 'bottom-right': '┛' + , 'left': '┃' + , 'left-mid': '┣' + , 'mid': '━' + , 'mid-mid': '╋' + , 'right': '┃' + , 'right-mid': '┫' + } + , truncate: '…' + , colWidths: [] + , colAligns: [] + , style: { + 'padding-left': 1 + , 'padding-right': 1 + , head: ['cyan'] + } + , head: [] + }, options); +}; + +/** + * Inherit from Array. + */ + +Table.prototype.__proto__ = Array.prototype; + +/** + * Width getter + * + * @return {Number} width + * @api public + */ + +Table.prototype.__defineGetter__('width', function (){ + var str = this.toString().split("\n"); + if (str.length) return str[0].length; + return 0; +}); + +/** + * Render to a string. + * + * @return {String} table representation + * @api public + */ + +Table.prototype.render +Table.prototype.toString = function (){ + var ret = '' + , options = this.options + , style = options.style + , head = options.head + , chars = options.chars + , truncater = options.truncate + , colWidths = options.colWidths || [] + , totalWidth = 0; + + if (!head.length && !this.length) return ''; + + if (!colWidths.length){ + this.concat([head]).forEach(function(cells){ + cells.forEach(function(cell, i){ + var width = typeof cell == 'object' && cell.width != undefined + ? cell.width + : ((typeof cell == 'object' ? String(cell.text) : String(cell)).length + (style['padding-left'] || 0) + (style['padding-right'] || 0)) + colWidths[i] = Math.max(colWidths[i] || 0, width || 0); + }); + }); + }; + + totalWidth = (colWidths.length == 1 ? colWidths[0] : colWidths.reduce( + function (a, b){ + return a + b + })) + colWidths.length + 1; + + // draws a line + function line (line, left, right, intersection){ + var width = 0 + , line = + left + + repeat(line, totalWidth - 2) + + right; + + colWidths.forEach(function (w, i){ + if (i == colWidths.length - 1) return; + width += w + 1; + line = line.substr(0, width) + intersection + line.substr(width + 1); + }); + + ret += line; + }; + + // draws the top line + function lineTop (){ + line(chars.top + , chars['top-left'] || chars.top + , chars['top-right'] || chars.top + , chars['top-mid']); + ret += "\n"; + }; + + // renders a string, by padding it or truncating it + function string (str, index){ + var str = String(typeof str == 'object' && str.text ? str.text : str) + , length = str.length + , width = colWidths[index] + - (style['padding-left'] || 0) + - (style['padding-right'] || 0) + , align = options.colAligns[index] || 'left'; + + return repeat(' ', style['padding-left'] || 0) + + (length == width ? str : + (length < width + ? pad(str, width, ' ', align == 'left' ? 'right' : + (align == 'middle' ? 'both' : 'left')) + : (truncater ? truncate(str, width, truncater) : str)) + ) + + repeat(' ', style['padding-right'] || 0); + }; + + if (head.length){ + lineTop(); + + ret += chars.left; + + head.forEach(function (th, index){ + var text = string(th, index); + if (style.head){ + style.head.forEach(function(style){ + text = text[style]; + }); + } + + ret += text; + ret += chars.right; + }); + + ret += "\n"; + } + + if (this.length) + this.forEach(function (cells, i){ + if (!head.length && i == 0) + lineTop(); + else { + line(chars.mid + , chars['left-mid'] + , chars['right-mid'] + , chars['mid-mid']); + + ret += "\n" + chars.left; + + cells.forEach(function(cell, i){ + ret += string(cell, i); + ret += chars.right; + }); + + ret += "\n"; + } + }); + + line(chars.bottom + , chars['bottom-left'] || chars.bottom + , chars['bottom-right'] || chars.bottom + , chars['bottom-mid']); + + return ret; +}; + +/** + * Module exports. + */ + +module.exports = Table; + +module.exports.version = '0.0.1'; diff --git a/node_modules/mongoose/support/cli-table/lib/cli-table/utils.js b/node_modules/mongoose/support/cli-table/lib/cli-table/utils.js new file mode 100644 index 0000000..9b0c137 --- /dev/null +++ b/node_modules/mongoose/support/cli-table/lib/cli-table/utils.js @@ -0,0 +1,81 @@ + +/** + * Repeats a string. + * + * @param {String} char(s) + * @param {Number} number of times + * @return {String} repeated string + */ + +exports.repeat = function (str, times){ + return Array(times + 1).join(str); +}; + +/** + * Pads a string + * + * @api public + */ + +exports.pad = function (str, len, pad, dir) { + if (len + 1 >= str.length) + switch (dir){ + case 'left': + str = Array(len + 1 - str.length).join(pad) + str; + break; + + case 'both': + var right = Math.ceil((padlen = len - str.length) / 2); + var left = padlen - right; + str = Array(left + 1).join(pad) + str + Array(right + 1).join(pad); + break; + + default: + str = str + Array(len + 1 - str.length).join(pad); + }; + + return str; +}; + +/** + * Truncates a string + * + * @api public + */ + +exports.truncate = function (str, length, chr){ + chr = chr || '…'; + return str.length >= length ? str.substr(0, length - chr.length) + chr : str; +}; + +/** + * Copies and merges options with defaults. + * + * @param {Object} defaults + * @param {Object} supplied options + * @return {Object} new (merged) object + */ + +function clone(a){ + var b; + if (Array.isArray(a)){ + b = []; + for (var i = 0, l = a.length; i < l; i++) + b.push(typeof a[i] == 'object' ? clone(a[i]) : a[i]); + return b; + } else if (typeof a == 'object'){ + b = {}; + for (var i in a) + b[i] = typeof a[i] == 'object' ? clone(a[i]) : a[i]; + return b; + } + return a; +}; + +exports.options = function (defaults, opts){ + var c = clone(opts); + for (var i in defaults) + if (!(i in opts)) + c[i] = defaults[i]; + return c; +}; diff --git a/node_modules/mongoose/support/cli-table/package.json b/node_modules/mongoose/support/cli-table/package.json new file mode 100644 index 0000000..33c4295 --- /dev/null +++ b/node_modules/mongoose/support/cli-table/package.json @@ -0,0 +1,11 @@ +{ "name": "cli-table" + , "description": "Pretty unicode tables for the CLI" + , "version": "0.0.1" + , "author": "Guillermo Rauch " + , "keywords": ["cli", "colors", "table"] + , "dependencies": { + "colors": "0.3.0" + } + , "main": "./index.js" + , "engines": { "node": ">= 0.2.0" } +} diff --git a/node_modules/mongoose/support/cli-table/test/common.js b/node_modules/mongoose/support/cli-table/test/common.js new file mode 100644 index 0000000..9b65e08 --- /dev/null +++ b/node_modules/mongoose/support/cli-table/test/common.js @@ -0,0 +1,6 @@ + +/** + * Module dependencies. + */ + +require('should'); diff --git a/node_modules/mongoose/support/cli-table/test/index.test.js b/node_modules/mongoose/support/cli-table/test/index.test.js new file mode 100644 index 0000000..2711e11 --- /dev/null +++ b/node_modules/mongoose/support/cli-table/test/index.test.js @@ -0,0 +1,52 @@ + +/** + * Module requirements. + */ + +require('./common'); + +var Table = require('cli-table'); + +/** + * Tests. + */ + +module.exports = { + + 'test complete table': function (){ + var table = new Table({ + head: ['Rel', 'Change', 'By', 'When'] + , style: { + 'padding-left': 1 + , 'padding-right': 1 + } + , colWidths: [6, 21, 25, 17] + }); + + table.push( + ['v0.1', 'Testing something cool', 'rauchg@gmail.com', '7 minutes ago'] + , ['v0.1', 'Testing something cool', 'rauchg@gmail.com', '8 minutes ago'] + ); + + var expected = [ + '┏━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓' + , '┃ Rel ┃ Change ┃ By ┃ When ┃' + , '┣━━━━━━╋━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫' + , '┃ v0.1 ┃ Testing something … ┃ rauchg@gmail.com ┃ 7 minutes ago ┃' + , '┣━━━━━━╋━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫' + , '┃ v0.1 ┃ Testing something … ┃ rauchg@gmail.com ┃ 8 minutes ago ┃' + , '┗━━━━━━┻━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┛' + ]; + + table.toString().should.eql(expected.join("\n")); + }, + + 'test width property': function (){ + var table = new Table({ + head: ['Cool'] + }); + + table.width.should.eql(8); + } + +}; diff --git a/node_modules/mongoose/support/expresso/History.md b/node_modules/mongoose/support/expresso/History.md new file mode 100644 index 0000000..cb16fa9 --- /dev/null +++ b/node_modules/mongoose/support/expresso/History.md @@ -0,0 +1,128 @@ + +0.7.2 / 2010-12-29 +================== + + * Fixed problem with `listen()` sometimes firing on the same tick [guillermo] + +0.7.1 / 2010-12-28 +================== + + * Fixed `assert.request()` client logic into an issue() function, fired upon the `listen()` callback if the server doesn't have an assigned fd. [guillermo] + * Removed `--watch` + +0.7.0 / 2010-11-19 +================== + + * Removed `assert` from test function signature + Just use `require('assert')` :) this will make integration + with libraries like [should](http://github.com/visionmedia/should) cleaner. + +0.6.4 / 2010-11-02 +================== + + * Added regexp support to `assert.response()` headers + * Removed `waitForExit` code, causing issues + +0.6.3 / 2010-11-02 +================== + + * Added `assert.response()` body RegExp support + * Fixed issue with _--serial_ not executing files sequentially. Closes #42 + * Fixed hang when modules use `setInterval` - monitor running tests & force the process to quit after all have completed + timeout [Steve Mason] + +0.6.2 / 2010-09-17 +================== + + * Added _node-jsocoverage_ to package.json (aka will respect npm's binroot) + * Added _-t, --timeout_ MS option, defaulting to 2000 ms + * Added _-s, --serial_ + * __PREFIX__ clobberable + * Fixed `assert.response()` for latest node + * Fixed cov reporting from exploding on empty files + +0.6.2 / 2010-08-03 +================== + + * Added `assert.type()` + * Renamed `assert.isNotUndefined()` to `assert.isDefined()` + * Fixed `assert.includes()` param ordering + +0.6.0 / 2010-07-31 +================== + + * Added _docs/api.html_ + * Added -w, --watch + * Added `Array` support to `assert.includes()` + * Added; outputting exceptions immediately. Closes #19 + * Fixed `assert.includes()` param ordering + * Fixed `assert.length()` param ordering + * Fixed jscoverage links + +0.5.0 / 2010-07-16 +================== + + * Added support for async exports + * Added timeout support to `assert.response()`. Closes #3 + * Added 4th arg callback support to `assert.response()` + * Added `assert.length()` + * Added `assert.match()` + * Added `assert.isUndefined()` + * Added `assert.isNull()` + * Added `assert.includes()` + * Added growlnotify support via -g, --growl + * Added -o, --only TESTS. Ex: --only "test foo()" --only "test foo(), test bar()" + * Removed profanity + +0.4.0 / 2010-07-09 +================== + + * Added reporting source coverage (respects --boring for color haters) + * Added callback to assert.response(). Closes #12 + * Fixed; putting exceptions to stderr. Closes #13 + +0.3.1 / 2010-06-28 +================== + + * Faster assert.response() + +0.3.0 / 2010-06-28 +================== + + * Added -p, --port NUM flags + * Added assert.response(). Closes #11 + +0.2.1 / 2010-06-25 +================== + + * Fixed issue with reporting object assertions + +0.2.0 / 2010-06-21 +================== + + * Added `make uninstall` + * Added better readdir() failure message + * Fixed `make install` for kiwi + +0.1.0 / 2010-06-15 +================== + + * Added better usage docs via --help + * Added better conditional color support + * Added pre exit assertion support + +0.0.3 / 2010-06-02 +================== + + * Added more room for filenames in test coverage + * Added boring output support via --boring (suppress colored output) + * Fixed async failure exit status + +0.0.2 / 2010-05-30 +================== + + * Fixed exit status for CI support + +0.0.1 / 2010-05-30 +================== + + * Initial release \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/Makefile b/node_modules/mongoose/support/expresso/Makefile new file mode 100644 index 0000000..8acfe56 --- /dev/null +++ b/node_modules/mongoose/support/expresso/Makefile @@ -0,0 +1,53 @@ + +PREFIX ?= /usr/local +BIN = bin/expresso +JSCOV = deps/jscoverage/node-jscoverage +DOCS = docs/index.md +HTMLDOCS = $(DOCS:.md=.html) + +test: $(BIN) + @./$(BIN) -I lib --growl $(TEST_FLAGS) test/*.test.js + +test-cov: + @./$(BIN) -I lib --cov $(TEST_FLAGS) test/*.test.js + +test-serial: + @./$(BIN) --serial -I lib $(TEST_FLAGS) test/serial/*.test.js + +install: install-jscov install-expresso + +uninstall: + rm -f $(PREFIX)/bin/expresso + rm -f $(PREFIX)/bin/node-jscoverage + +install-jscov: $(JSCOV) + install $(JSCOV) $(PREFIX)/bin + +install-expresso: + install $(BIN) $(PREFIX)/bin + +$(JSCOV): + cd deps/jscoverage && ./configure && make && mv jscoverage node-jscoverage + +clean: + @cd deps/jscoverage && git clean -fd + +docs: docs/api.html $(HTMLDOCS) + +%.html: %.md + @echo "... $< > $@" + @ronn -5 --pipe --fragment $< \ + | cat docs/layout/head.html - docs/layout/foot.html \ + > $@ + +docs/api.html: bin/expresso + dox \ + --title "Expresso" \ + --ribbon "http://github.com/visionmedia/expresso" \ + --desc "Insanely fast TDD framework for [node](http://nodejs.org) featuring code coverage reporting." \ + $< > $@ + +docclean: + rm -f docs/*.html + +.PHONY: test test-cov install uninstall install-expresso install-jscov clean docs docclean \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/Readme.md b/node_modules/mongoose/support/expresso/Readme.md new file mode 100644 index 0000000..05c972e --- /dev/null +++ b/node_modules/mongoose/support/expresso/Readme.md @@ -0,0 +1,61 @@ + +# Expresso + + TDD framework for [nodejs](http://nodejs.org). + +## Features + + - light-weight + - intuitive async support + - intuitive test runner executable + - test coverage support and reporting + - uses the _assert_ module + - `assert.eql()` alias of `assert.deepEqual()` + - `assert.response()` http response utility + - `assert.includes()` + - `assert.type()` + - `assert.isNull()` + - `assert.isUndefined()` + - `assert.isNotNull()` + - `assert.isDefined()` + - `assert.match()` + - `assert.length()` + +## Installation + +To install both expresso _and_ node-jscoverage run: + + $ make install + +To install expresso alone (no build required) run: + + $ make install-expresso + +Install via npm: + + $ npm install expresso + +## License + +(The MIT License) + +Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/mongoose/support/expresso/bin/expresso b/node_modules/mongoose/support/expresso/bin/expresso new file mode 100755 index 0000000..fd98fff --- /dev/null +++ b/node_modules/mongoose/support/expresso/bin/expresso @@ -0,0 +1,874 @@ +#!/usr/bin/env node + +/* + * Expresso + * Copyright(c) TJ Holowaychuk + * (MIT Licensed) + */ + +/** + * Module dependencies. + */ + +var assert = require('assert'), + childProcess = require('child_process'), + http = require('http'), + path = require('path'), + sys = require('sys'), + cwd = process.cwd(), + fs = require('fs'), + defer; + +/** + * Expresso version. + */ + +var version = '0.7.2'; + +/** + * Failure count. + */ + +var failures = 0; + + +/** + * Number of tests executed. + */ + +var testcount = 0; + +/** + * Whitelist of tests to run. + */ + +var only = []; + +/** + * Boring output. + */ + +var boring = false; + +/** + * Growl notifications. + */ + +var growl = false; + +/** + * Server port. + */ + +var port = 5555; + +/** + * Execute serially. + */ + +var serial = false; + +/** + * Default timeout. + */ + +var timeout = 2000; + +/** + * Quiet output. + */ + +var quiet = false; + +/** + * Usage documentation. + */ + +var usage = '' + + '[bold]{Usage}: expresso [options] ' + + '\n' + + '\n[bold]{Options}:' + + '\n -g, --growl Enable growl notifications' + + '\n -c, --coverage Generate and report test coverage' + + '\n -q, --quiet Suppress coverage report if 100%' + + '\n -t, --timeout MS Timeout in milliseconds, defaults to 2000' + + '\n -r, --require PATH Require the given module path' + + '\n -o, --only TESTS Execute only the comma sperated TESTS (can be set several times)' + + '\n -I, --include PATH Unshift the given path to require.paths' + + '\n -p, --port NUM Port number for test servers, starts at 5555' + + '\n -s, --serial Execute tests serially' + + '\n -b, --boring Suppress ansi-escape colors' + + '\n -v, --version Output version number' + + '\n -h, --help Display help information' + + '\n'; + +// Parse arguments + +var files = [], + args = process.argv.slice(2); + +while (args.length) { + var arg = args.shift(); + switch (arg) { + case '-h': + case '--help': + print(usage + '\n'); + process.exit(1); + break; + case '-v': + case '--version': + sys.puts(version); + process.exit(1); + break; + case '-i': + case '-I': + case '--include': + if (arg = args.shift()) { + require.paths.unshift(arg); + } else { + throw new Error('--include requires a path'); + } + break; + case '-o': + case '--only': + if (arg = args.shift()) { + only = only.concat(arg.split(/ *, */)); + } else { + throw new Error('--only requires comma-separated test names'); + } + break; + case '-p': + case '--port': + if (arg = args.shift()) { + port = parseInt(arg, 10); + } else { + throw new Error('--port requires a number'); + } + break; + case '-r': + case '--require': + if (arg = args.shift()) { + require(arg); + } else { + throw new Error('--require requires a path'); + } + break; + case '-t': + case '--timeout': + if (arg = args.shift()) { + timeout = parseInt(arg, 10); + } else { + throw new Error('--timeout requires an argument'); + } + break; + case '-c': + case '--cov': + case '--coverage': + defer = true; + childProcess.exec('rm -fr lib-cov && node-jscoverage lib lib-cov', function(err){ + if (err) throw err; + require.paths.unshift('lib-cov'); + run(files); + }) + break; + case '-q': + case '--quiet': + quiet = true; + break; + case '-b': + case '--boring': + boring = true; + break; + case '-g': + case '--growl': + growl = true; + break; + case '-s': + case '--serial': + serial = true; + break; + default: + if (/\.js$/.test(arg)) { + files.push(arg); + } + break; + } +} + +/** + * Colorized sys.error(). + * + * @param {String} str + */ + +function print(str){ + sys.error(colorize(str)); +} + +/** + * Colorize the given string using ansi-escape sequences. + * Disabled when --boring is set. + * + * @param {String} str + * @return {String} + */ + +function colorize(str){ + var colors = { bold: 1, red: 31, green: 32, yellow: 33 }; + return str.replace(/\[(\w+)\]\{([^]*?)\}/g, function(_, color, str){ + return boring + ? str + : '\x1B[' + colors[color] + 'm' + str + '\x1B[0m'; + }); +} + +// Alias deepEqual as eql for complex equality + +assert.eql = assert.deepEqual; + +/** + * Assert that `val` is null. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isNull = function(val, msg) { + assert.strictEqual(null, val, msg); +}; + +/** + * Assert that `val` is not null. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isNotNull = function(val, msg) { + assert.notStrictEqual(null, val, msg); +}; + +/** + * Assert that `val` is undefined. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isUndefined = function(val, msg) { + assert.strictEqual(undefined, val, msg); +}; + +/** + * Assert that `val` is not undefined. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isDefined = function(val, msg) { + assert.notStrictEqual(undefined, val, msg); +}; + +/** + * Assert that `obj` is `type`. + * + * @param {Mixed} obj + * @param {String} type + * @api public + */ + +assert.type = function(obj, type, msg){ + var real = typeof obj; + msg = msg || 'typeof ' + sys.inspect(obj) + ' is ' + real + ', expected ' + type; + assert.ok(type === real, msg); +}; + +/** + * Assert that `str` matches `regexp`. + * + * @param {String} str + * @param {RegExp} regexp + * @param {String} msg + */ + +assert.match = function(str, regexp, msg) { + msg = msg || sys.inspect(str) + ' does not match ' + sys.inspect(regexp); + assert.ok(regexp.test(str), msg); +}; + +/** + * Assert that `val` is within `obj`. + * + * Examples: + * + * assert.includes('foobar', 'bar'); + * assert.includes(['foo', 'bar'], 'foo'); + * + * @param {String|Array} obj + * @param {Mixed} val + * @param {String} msg + */ + +assert.includes = function(obj, val, msg) { + msg = msg || sys.inspect(obj) + ' does not include ' + sys.inspect(val); + assert.ok(obj.indexOf(val) >= 0, msg); +}; + +/** + * Assert length of `val` is `n`. + * + * @param {Mixed} val + * @param {Number} n + * @param {String} msg + */ + +assert.length = function(val, n, msg) { + msg = msg || sys.inspect(val) + ' has length of ' + val.length + ', expected ' + n; + assert.equal(n, val.length, msg); +}; + +/** + * Assert response from `server` with + * the given `req` object and `res` assertions object. + * + * @param {Server} server + * @param {Object} req + * @param {Object|Function} res + * @param {String} msg + */ + +assert.response = function(server, req, res, msg){ + // Check that the server is ready or defer + if (!server.fd) { + if (!('__deferred' in server)) { + server.__deferred = []; + } + server.__deferred.push(arguments); + if (!server.__started) { + server.listen(server.__port = port++, '127.0.0.1', function(){ + if (server.__deferred) { + process.nextTick(function(){ + server.__deferred.forEach(function(args){ + assert.response.apply(assert, args); + }); + }); + } + }); + server.__started = true; + } + return; + } + + // Callback as third or fourth arg + var callback = typeof res === 'function' + ? res + : typeof msg === 'function' + ? msg + : function(){}; + + // Default messate to test title + if (typeof msg === 'function') msg = null; + msg = msg || assert.testTitle; + msg += '. '; + + // Pending responses + server.__pending = server.__pending || 0; + server.__pending++; + + // Create client + if (!server.fd) { + server.listen(server.__port = port++, '127.0.0.1', issue); + } else { + issue(); + } + + function issue(){ + if (!server.client) + server.client = http.createClient(server.__port); + + // Issue request + var timer, + client = server.client, + method = req.method || 'GET', + status = res.status || res.statusCode, + data = req.data || req.body, + requestTimeout = req.timeout || 0; + + var request = client.request(method, req.url, req.headers); + + // Timeout + if (requestTimeout) { + timer = setTimeout(function(){ + --server.__pending || server.close(); + delete req.timeout; + assert.fail(msg + 'Request timed out after ' + requestTimeout + 'ms.'); + }, requestTimeout); + } + + if (data) request.write(data); + request.addListener('response', function(response){ + response.body = ''; + response.setEncoding('utf8'); + response.addListener('data', function(chunk){ response.body += chunk; }); + response.addListener('end', function(){ + --server.__pending || server.close(); + if (timer) clearTimeout(timer); + + // Assert response body + if (res.body !== undefined) { + var eql = res.body instanceof RegExp + ? res.body.test(response.body) + : res.body === response.body; + assert.ok( + eql, + msg + 'Invalid response body.\n' + + ' Expected: ' + sys.inspect(res.body) + '\n' + + ' Got: ' + sys.inspect(response.body) + ); + } + + // Assert response status + if (typeof status === 'number') { + assert.equal( + response.statusCode, + status, + msg + colorize('Invalid response status code.\n' + + ' Expected: [green]{' + status + '}\n' + + ' Got: [red]{' + response.statusCode + '}') + ); + } + + // Assert response headers + if (res.headers) { + var keys = Object.keys(res.headers); + for (var i = 0, len = keys.length; i < len; ++i) { + var name = keys[i], + actual = response.headers[name.toLowerCase()], + expected = res.headers[name], + eql = expected instanceof RegExp + ? expected.test(actual) + : expected == actual; + assert.ok( + eql, + msg + colorize('Invalid response header [bold]{' + name + '}.\n' + + ' Expected: [green]{' + expected + '}\n' + + ' Got: [red]{' + actual + '}') + ); + } + } + + // Callback + callback(response); + }); + }); + request.end(); + } +}; + +/** + * Pad the given string to the maximum width provided. + * + * @param {String} str + * @param {Number} width + * @return {String} + */ + +function lpad(str, width) { + str = String(str); + var n = width - str.length; + if (n < 1) return str; + while (n--) str = ' ' + str; + return str; +} + +/** + * Pad the given string to the maximum width provided. + * + * @param {String} str + * @param {Number} width + * @return {String} + */ + +function rpad(str, width) { + str = String(str); + var n = width - str.length; + if (n < 1) return str; + while (n--) str = str + ' '; + return str; +} + +/** + * Report test coverage. + * + * @param {Object} cov + */ + +function reportCoverage(cov) { + // Stats + print('\n [bold]{Test Coverage}\n'); + var sep = ' +------------------------------------------+----------+------+------+--------+', + lastSep = ' +----------+------+------+--------+'; + sys.puts(sep); + sys.puts(' | filename | coverage | LOC | SLOC | missed |'); + sys.puts(sep); + for (var name in cov) { + var file = cov[name]; + if (Array.isArray(file)) { + sys.print(' | ' + rpad(name, 40)); + sys.print(' | ' + lpad(file.coverage.toFixed(2), 8)); + sys.print(' | ' + lpad(file.LOC, 4)); + sys.print(' | ' + lpad(file.SLOC, 4)); + sys.print(' | ' + lpad(file.totalMisses, 6)); + sys.print(' |\n'); + } + } + sys.puts(sep); + sys.print(' ' + rpad('', 40)); + sys.print(' | ' + lpad(cov.coverage.toFixed(2), 8)); + sys.print(' | ' + lpad(cov.LOC, 4)); + sys.print(' | ' + lpad(cov.SLOC, 4)); + sys.print(' | ' + lpad(cov.totalMisses, 6)); + sys.print(' |\n'); + sys.puts(lastSep); + // Source + for (var name in cov) { + if (name.match(/\.js$/)) { + var file = cov[name]; + if ((file.coverage < 100) || !quiet) { + print('\n [bold]{' + name + '}:'); + print(file.source); + sys.print('\n'); + } + } + } +} + +/** + * Populate code coverage data. + * + * @param {Object} cov + */ + +function populateCoverage(cov) { + cov.LOC = + cov.SLOC = + cov.totalFiles = + cov.totalHits = + cov.totalMisses = + cov.coverage = 0; + for (var name in cov) { + var file = cov[name]; + if (Array.isArray(file)) { + // Stats + ++cov.totalFiles; + cov.totalHits += file.totalHits = coverage(file, true); + cov.totalMisses += file.totalMisses = coverage(file, false); + file.totalLines = file.totalHits + file.totalMisses; + cov.SLOC += file.SLOC = file.totalLines; + if (!file.source) file.source = []; + cov.LOC += file.LOC = file.source.length; + file.coverage = (file.totalHits / file.totalLines) * 100; + // Source + var width = file.source.length.toString().length; + file.source = file.source.map(function(line, i){ + ++i; + var hits = file[i] === 0 ? 0 : (file[i] || ' '); + if (!boring) { + if (hits === 0) { + hits = '\x1b[31m' + hits + '\x1b[0m'; + line = '\x1b[41m' + line + '\x1b[0m'; + } else { + hits = '\x1b[32m' + hits + '\x1b[0m'; + } + } + return '\n ' + lpad(i, width) + ' | ' + hits + ' | ' + line; + }).join(''); + } + } + cov.coverage = (cov.totalHits / cov.SLOC) * 100; +} + +/** + * Total coverage for the given file data. + * + * @param {Array} data + * @return {Type} + */ + +function coverage(data, val) { + var n = 0; + for (var i = 0, len = data.length; i < len; ++i) { + if (data[i] !== undefined && data[i] == val) ++n; + } + return n; +} + +/** + * Test if all files have 100% coverage + * + * @param {Object} cov + * @return {Boolean} + */ + +function hasFullCoverage(cov) { + for (var name in cov) { + var file = cov[name]; + if (file instanceof Array) { + if (file.coverage !== 100) { + return false; + } + } + } + return true; +} + +/** + * Run the given test `files`, or try _test/*_. + * + * @param {Array} files + */ + +function run(files) { + cursor(false); + if (!files.length) { + try { + files = fs.readdirSync('test').map(function(file){ + return 'test/' + file; + }); + } catch (err) { + print('\n failed to load tests in [bold]{./test}\n'); + ++failures; + process.exit(1); + } + } + runFiles(files); +} + +/** + * Show the cursor when `show` is true, otherwise hide it. + * + * @param {Boolean} show + */ + +function cursor(show) { + if (show) { + sys.print('\x1b[?25h'); + } else { + sys.print('\x1b[?25l'); + } +} + +/** + * Run the given test `files`. + * + * @param {Array} files + */ + +function runFiles(files) { + if (serial) { + (function next(){ + if (files.length) { + runFile(files.shift(), next); + } + })(); + } else { + files.forEach(runFile); + } +} + +/** + * Run tests for the given `file`, callback `fn()` when finished. + * + * @param {String} file + * @param {Function} fn + */ + +function runFile(file, fn) { + if (file.match(/\.js$/)) { + var title = path.basename(file), + file = path.join(cwd, file), + mod = require(file.replace(/\.js$/, '')); + (function check(){ + var len = Object.keys(mod).length; + if (len) { + runSuite(title, mod, fn); + } else { + setTimeout(check, 20); + } + })(); + } +} + +/** + * Report `err` for the given `test` and `suite`. + * + * @param {String} suite + * @param {String} test + * @param {Error} err + */ + +function error(suite, test, err) { + ++failures; + var name = err.name, + stack = err.stack.replace(err.name, ''), + label = test === 'uncaught' + ? test + : suite + ' ' + test; + print('\n [bold]{' + label + '}: [red]{' + name + '}' + stack + '\n'); +} + +/** + * Run the given tests, callback `fn()` when finished. + * + * @param {String} title + * @param {Object} tests + * @param {Function} fn + */ + +var dots = 0; +function runSuite(title, tests, fn) { + // Keys + var keys = only.length + ? only.slice(0) + : Object.keys(tests); + + // Setup + var setup = tests.setup || function(fn){ fn(); }; + + // Iterate tests + (function next(){ + if (keys.length) { + var key, + test = tests[key = keys.shift()]; + // Non-tests + if (key === 'setup') return next(); + + // Run test + if (test) { + try { + ++testcount; + assert.testTitle = key; + if (serial) { + sys.print('.'); + if (++dots % 25 === 0) sys.print('\n'); + setup(function(){ + if (test.length < 1) { + test(); + next(); + } else { + var id = setTimeout(function(){ + throw new Error("'" + key + "' timed out"); + }, timeout); + test(function(){ + clearTimeout(id); + next(); + }); + } + }); + } else { + test(function(fn){ + addBeforeExit(function(){ + try { + fn(); + } catch (err) { + error(title, key, err); + } + }); + }); + } + } catch (err) { + error(title, key, err); + } + } + if (!serial) next(); + } else if (serial) { + fn(); + } + })(); +} + +/** + * Adds before exit handlers with only one event handler + * + * @param {Function} callback + * @api private + */ + +var beforeExitHandlers = []; + +function addBeforeExit (fn) { + if (!beforeExitHandlers.length) + process.on('beforeExit', function () { + for (var i = 0, l = beforeExitHandlers.length; i < l; i++) + beforeExitHandlers[i](); + }); + beforeExitHandlers.push(fn); +}; + +/** + * Report exceptions. + */ + +function report() { + cursor(true); + process.emit('beforeExit'); + if (failures) { + print('\n [bold]{Failures}: [red]{' + failures + '}\n\n'); + notify('Failures: ' + failures); + } else { + if (serial) print(''); + print('\n [green]{100%} ' + testcount + ' tests\n'); + notify('100% ok'); + } + if (typeof _$jscoverage === 'object') { + populateCoverage(_$jscoverage); + if (!hasFullCoverage(_$jscoverage) || !quiet) { + reportCoverage(_$jscoverage); + } + } +} + +/** + * Growl notify the given `msg`. + * + * @param {String} msg + */ + +function notify(msg) { + if (growl) { + childProcess.exec('growlnotify -name Expresso -m "' + msg + '"'); + } +} + +// Report uncaught exceptions + +process.addListener('uncaughtException', function(err){ + error('uncaught', 'uncaught', err); +}); + +// Show cursor + +['INT', 'TERM', 'QUIT'].forEach(function(sig){ + process.addListener('SIG' + sig, function(){ + cursor(true); + process.exit(1); + }); +}); + +// Report test coverage when available +// and emit "beforeExit" event to perform +// final assertions + +var orig = process.emit; +process.emit = function(event){ + if (event === 'exit') { + report(); + process.reallyExit(failures); + } + orig.apply(this, arguments); +}; + +// Run test files + +if (!defer) run(files); diff --git a/node_modules/mongoose/support/expresso/docs/api.html b/node_modules/mongoose/support/expresso/docs/api.html new file mode 100644 index 0000000..7b8fb2b --- /dev/null +++ b/node_modules/mongoose/support/expresso/docs/api.html @@ -0,0 +1,1080 @@ +Fork me on GitHub + + Expresso + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Expresso

    Insanely fast TDD framework for node featuring code coverage reporting.

    expresso

    bin/expresso
    +

    !/usr/bin/env node

    +
    +
    
    + * Expresso
    + * Copyright(c) TJ Holowaychuk &lt;tj@vision-media.ca&gt;
    + * (MIT Licensed)
    + 
    +
    +

    Module dependencies. +

    +
    +
    var assert = require('assert'),
    +    childProcess = require('child_process'),
    +    http = require('http'),
    +    path = require('path'),
    +    sys = require('sys'),
    +    cwd = process.cwd(),
    +    fs = require('fs'),
    +    defer;
    +
    +

    Expresso version. +

    +
    +
    var version = '0.6.4';
    +
    +

    Failure count. +

    +
    +
    var failures = 0;
    +
    +

    Number of tests executed. +

    +
    +
    var testcount = 0;
    +
    +

    Whitelist of tests to run. +

    +
    +
    var only = [];
    +
    +

    Boring output. +

    +
    +
    var boring = false;
    +
    +

    Growl notifications. +

    +
    +
    var growl = false;
    +
    +

    Server port. +

    +
    +
    var port = 5555;
    +
    +

    Watch mode. +

    +
    +
    var watch = false;
    +
    +

    Execute serially. +

    +
    +
    var serial = false;
    +
    +

    Default timeout. +

    +
    +
    var timeout = 2000;
    +
    +

    Usage documentation. +

    +
    +
    var usage = ''
    +    + '[bold]{Usage}: expresso [options] <file ...>'
    +    + '\n'
    +    + '\n[bold]{Options}:'
    +    + '\n  -w, --watch          Watch for modifications and re-execute tests'
    +    + '\n  -g, --growl          Enable growl notifications'
    +    + '\n  -c, --coverage       Generate and report test coverage'
    +    + '\n  -t, --timeout MS     Timeout in milliseconds, defaults to 2000'
    +    + '\n  -r, --require PATH   Require the given module path'
    +    + '\n  -o, --only TESTS     Execute only the comma sperated TESTS (can be set several times)'
    +    + '\n  -I, --include PATH   Unshift the given path to require.paths'
    +    + '\n  -p, --port NUM       Port number for test servers, starts at 5555'
    +    + '\n  -s, --serial         Execute tests serially'
    +    + '\n  -b, --boring         Suppress ansi-escape colors'
    +    + '\n  -v, --version        Output version number'
    +    + '\n  -h, --help           Display help information'
    +    + '\n';
    +
    +// Parse arguments
    +
    +var files = [],
    +    args = process.argv.slice(2);
    +
    +while (args.length) {
    +    var arg = args.shift();
    +    switch (arg) {
    +        case '-h':
    +        case '--help':
    +            print(usage + '\n');
    +            process.exit(1);
    +            break;
    +        case '-v':
    +        case '--version':
    +            sys.puts(version);
    +            process.exit(1);
    +            break;
    +        case '-i':
    +        case '-I':
    +        case '--include':
    +            if (arg = args.shift()) {
    +                require.paths.unshift(arg);
    +            } else {
    +                throw new Error('--include requires a path');
    +            }
    +            break;
    +        case '-o':
    +        case '--only':
    +            if (arg = args.shift()) {
    +                only = only.concat(arg.split(/ *, */));
    +            } else {
    +                throw new Error('--only requires comma-separated test names');
    +            }
    +            break;
    +        case '-p':
    +        case '--port':
    +            if (arg = args.shift()) {
    +                port = parseInt(arg, 10);
    +            } else {
    +                throw new Error('--port requires a number');
    +            }
    +            break;
    +        case '-r':
    +        case '--require':
    +            if (arg = args.shift()) {
    +                require(arg);
    +            } else {
    +                throw new Error('--require requires a path');
    +            }
    +            break;
    +        case '-t':
    +        case '--timeout':
    +          if (arg = args.shift()) {
    +            timeout = parseInt(arg, 10);
    +          } else {
    +            throw new Error('--timeout requires an argument');
    +          }
    +          break;
    +        case '-c':
    +        case '--cov':
    +        case '--coverage':
    +            defer = true;
    +            childProcess.exec('rm -fr lib-cov && node-jscoverage lib lib-cov', function(err){
    +                if (err) throw err;
    +                require.paths.unshift('lib-cov');
    +                run(files);
    +            })
    +            break;
    +        case '-b':
    +        case '--boring':
    +        	boring = true;
    +        	break;
    +        case '-w':
    +        case '--watch':
    +            watch = true;
    +            break;
    +        case '-g':
    +        case '--growl':
    +            growl = true;
    +            break;
    +        case '-s':
    +        case '--serial':
    +            serial = true;
    +            break;
    +        default:
    +            if (/\.js$/.test(arg)) {
    +                files.push(arg);
    +            }
    +            break;
    +    }
    +}
    +
    +

    Colorized sys.error().

    + +

    + +
    • param: String str

    +
    +
    function print(str){
    +    sys.error(colorize(str));
    +}
    +
    +

    Colorize the given string using ansi-escape sequences. +Disabled when --boring is set.

    + +

    + +
    • param: String str

    • return: String

    +
    +
    function colorize(str){
    +    var colors = { bold: 1, red: 31, green: 32, yellow: 33 };
    +    return str.replace(/\[(\w+)\]\{([^]*?)\}/g, function(_, color, str){
    +        return boring
    +            ? str
    +            : '\x1B[' + colors[color] + 'm' + str + '\x1B[0m';
    +    });
    +}
    +
    +// Alias deepEqual as eql for complex equality
    +
    +assert.eql = assert.deepEqual;
    +
    +

    Assert that val is null.

    + +

    + +
    • param: Mixed val

    • param: String msg

    +
    +
    assert.isNull = function(val, msg) {
    +    assert.strictEqual(null, val, msg);
    +};
    +
    +

    Assert that val is not null.

    + +

    + +
    • param: Mixed val

    • param: String msg

    +
    +
    assert.isNotNull = function(val, msg) {
    +    assert.notStrictEqual(null, val, msg);
    +};
    +
    +

    Assert that val is undefined.

    + +

    + +
    • param: Mixed val

    • param: String msg

    +
    +
    assert.isUndefined = function(val, msg) {
    +    assert.strictEqual(undefined, val, msg);
    +};
    +
    +

    Assert that val is not undefined.

    + +

    + +
    • param: Mixed val

    • param: String msg

    +
    +
    assert.isDefined = function(val, msg) {
    +    assert.notStrictEqual(undefined, val, msg);
    +};
    +
    +

    Assert that obj is type.

    + +

    + +
    • param: Mixed obj

    • param: String type

    • api: public

    +
    +
    assert.type = function(obj, type, msg){
    +    var real = typeof obj;
    +    msg = msg || 'typeof ' + sys.inspect(obj) + ' is ' + real + ', expected ' + type;
    +    assert.ok(type === real, msg);
    +};
    +
    +

    Assert that str matches regexp.

    + +

    + +
    • param: String str

    • param: RegExp regexp

    • param: String msg

    +
    +
    assert.match = function(str, regexp, msg) {
    +    msg = msg || sys.inspect(str) + ' does not match ' + sys.inspect(regexp);
    +    assert.ok(regexp.test(str), msg);
    +};
    +
    +

    Assert that val is within obj.

    + +

    Examples

    + +

    assert.includes('foobar', 'bar'); + assert.includes(['foo', 'bar'], 'foo');

    + +

    + +
    • param: String | Array obj

    • param: Mixed val

    • param: String msg

    +
    +
    assert.includes = function(obj, val, msg) {
    +    msg = msg || sys.inspect(obj) + ' does not include ' + sys.inspect(val);
    +    assert.ok(obj.indexOf(val) &gt;= 0, msg);
    +};
    +
    +

    Assert length of val is n.

    + +

    + +
    • param: Mixed val

    • param: Number n

    • param: String msg

    +
    +
    assert.length = function(val, n, msg) {
    +    msg = msg || sys.inspect(val) + ' has length of ' + val.length + ', expected ' + n;
    +    assert.equal(n, val.length, msg);
    +};
    +
    +

    Assert response from server with +the given req object and res assertions object.

    + +

    + +
    • param: Server server

    • param: Object req

    • param: Object | Function res

    • param: String msg

    +
    +
    assert.response = function(server, req, res, msg){
    +    // Callback as third or fourth arg
    +    var callback = typeof res === 'function'
    +        ? res
    +        : typeof msg === 'function'
    +            ? msg
    +            : function(){};
    +
    +    // Default messate to test title
    +    if (typeof msg === 'function') msg = null;
    +    msg = msg || assert.testTitle;
    +    msg += '. ';
    +
    +    // Pending responses
    +    server.__pending = server.__pending || 0;
    +    server.__pending++;
    +
    +    // Create client
    +    if (!server.fd) {
    +        server.listen(server.__port = port++, '127.0.0.1');
    +        server.client = http.createClient(server.__port);
    +    }
    +
    +    // Issue request
    +    var timer,
    +        client = server.client,
    +        method = req.method || 'GET',
    +        status = res.status || res.statusCode,
    +        data = req.data || req.body,
    +        requestTimeout = req.timeout || 0;
    +
    +    var request = client.request(method, req.url, req.headers);
    +
    +    // Timeout
    +    if (requestTimeout) {
    +        timer = setTimeout(function(){
    +            --server.__pending || server.close();
    +            delete req.timeout;
    +            assert.fail(msg + 'Request timed out after ' + requestTimeout + 'ms.');
    +        }, requestTimeout);
    +    }
    +
    +    if (data) request.write(data);
    +    request.addListener('response', function(response){
    +        response.body = '';
    +        response.setEncoding('utf8');
    +        response.addListener('data', function(chunk){ response.body += chunk; });
    +        response.addListener('end', function(){
    +            --server.__pending || server.close();
    +            if (timer) clearTimeout(timer);
    +
    +            // Assert response body
    +            if (res.body !== undefined) {
    +                var eql = res.body instanceof RegExp
    +                  ? res.body.test(response.body)
    +                  : res.body === response.body;
    +                assert.ok(
    +                    eql,
    +                    msg + 'Invalid response body.\n'
    +                        + '    Expected: ' + sys.inspect(res.body) + '\n'
    +                        + '    Got: ' + sys.inspect(response.body)
    +                );
    +            }
    +
    +            // Assert response status
    +            if (typeof status === 'number') {
    +                assert.equal(
    +                    response.statusCode,
    +                    status,
    +                    msg + colorize('Invalid response status code.\n'
    +                        + '    Expected: [green]{' + status + '}\n'
    +                        + '    Got: [red]{' + response.statusCode + '}')
    +                );
    +            }
    +
    +            // Assert response headers
    +            if (res.headers) {
    +                var keys = Object.keys(res.headers);
    +                for (var i = 0, len = keys.length; i &lt; len; ++i) {
    +                    var name = keys[i],
    +                        actual = response.headers[name.toLowerCase()],
    +                        expected = res.headers[name],
    +                        eql = expected instanceof RegExp
    +                          ? expected.test(actual)
    +                          : expected == actual;
    +                    assert.ok(
    +                        eql,
    +                        msg + colorize('Invalid response header [bold]{' + name + '}.\n'
    +                            + '    Expected: [green]{' + expected + '}\n'
    +                            + '    Got: [red]{' + actual + '}')
    +                    );
    +                }
    +            }
    +
    +            // Callback
    +            callback(response);
    +        });
    +    });
    +    request.end();
    +};
    +
    +

    Pad the given string to the maximum width provided.

    + +

    + +
    • param: String str

    • param: Number width

    • return: String

    +
    +
    function lpad(str, width) {
    +    str = String(str);
    +    var n = width - str.length;
    +    if (n &lt; 1) return str;
    +    while (n--) str = ' ' + str;
    +    return str;
    +}
    +
    +

    Pad the given string to the maximum width provided.

    + +

    + +
    • param: String str

    • param: Number width

    • return: String

    +
    +
    function rpad(str, width) {
    +    str = String(str);
    +    var n = width - str.length;
    +    if (n &lt; 1) return str;
    +    while (n--) str = str + ' ';
    +    return str;
    +}
    +
    +

    Report test coverage.

    + +

    + +
    • param: Object cov

    +
    +
    function reportCoverage(cov) {
    +    populateCoverage(cov);
    +    // Stats
    +    print('\n   [bold]{Test Coverage}\n');
    +    var sep = '   +------------------------------------------+----------+------+------+--------+',
    +        lastSep = '                                              +----------+------+------+--------+';
    +    sys.puts(sep);
    +    sys.puts('   | filename                                 | coverage | LOC  | SLOC | missed |');
    +    sys.puts(sep);
    +    for (var name in cov) {
    +        var file = cov[name];
    +        if (Array.isArray(file)) {
    +            sys.print('   | ' + rpad(name, 40));
    +            sys.print(' | ' + lpad(file.coverage.toFixed(2), 8));
    +            sys.print(' | ' + lpad(file.LOC, 4));
    +            sys.print(' | ' + lpad(file.SLOC, 4));
    +            sys.print(' | ' + lpad(file.totalMisses, 6));
    +            sys.print(' |\n');
    +        }
    +    }
    +    sys.puts(sep);
    +    sys.print('     ' + rpad('', 40));
    +    sys.print(' | ' + lpad(cov.coverage.toFixed(2), 8));
    +    sys.print(' | ' + lpad(cov.LOC, 4));
    +    sys.print(' | ' + lpad(cov.SLOC, 4));
    +    sys.print(' | ' + lpad(cov.totalMisses, 6));
    +    sys.print(' |\n');
    +    sys.puts(lastSep);
    +    // Source
    +    for (var name in cov) {
    +        if (name.match(/\.js$/)) {
    +            var file = cov[name];
    +            print('\n   [bold]{' + name + '}:');
    +            print(file.source);
    +            sys.print('\n');
    +        }
    +    }
    +}
    +
    +

    Populate code coverage data.

    + +

    + +
    • param: Object cov

    +
    +
    function populateCoverage(cov) {
    +    cov.LOC = 
    +    cov.SLOC =
    +    cov.totalFiles =
    +    cov.totalHits =
    +    cov.totalMisses = 
    +    cov.coverage = 0;
    +    for (var name in cov) {
    +        var file = cov[name];
    +        if (Array.isArray(file)) {
    +            // Stats
    +            ++cov.totalFiles;
    +            cov.totalHits += file.totalHits = coverage(file, true);
    +            cov.totalMisses += file.totalMisses = coverage(file, false);
    +            file.totalLines = file.totalHits + file.totalMisses;
    +            cov.SLOC += file.SLOC = file.totalLines;
    +            if (!file.source) file.source = [];
    +            cov.LOC += file.LOC = file.source.length;
    +            file.coverage = (file.totalHits / file.totalLines) * 100;
    +            // Source
    +            var width = file.source.length.toString().length;
    +            file.source = file.source.map(function(line, i){
    +                ++i;
    +                var hits = file[i] === 0 ? 0 : (file[i] || ' ');
    +                if (!boring) {
    +                    if (hits === 0) {
    +                        hits = '\x1b[31m' + hits + '\x1b[0m';
    +                        line = '\x1b[41m' + line + '\x1b[0m';
    +                    } else {
    +                        hits = '\x1b[32m' + hits + '\x1b[0m';
    +                    }
    +                }
    +                return '\n     ' + lpad(i, width) + ' | ' + hits + ' | ' + line;
    +            }).join('');
    +        }
    +    }
    +    cov.coverage = (cov.totalHits / cov.SLOC) * 100;
    +}
    +
    +

    Total coverage for the given file data.

    + +

    + +
    • param: Array data

    • return: Type

    +
    +
    function coverage(data, val) {
    +    var n = 0;
    +    for (var i = 0, len = data.length; i &lt; len; ++i) {
    +        if (data[i] !== undefined &amp;&amp; data[i] == val) ++n;
    +    }
    +    return n;  
    +}
    +
    +

    Run the given test files, or try test/*.

    + +

    + +
    • param: Array files

    +
    +
    function run(files) {
    +    if (!files.length) {
    +        try {
    +            files = fs.readdirSync('test').map(function(file){
    +                return 'test/' + file;
    +            });
    +        } catch (err) {
    +            print('\n  failed to load tests in [bold]{./test}\n');
    +            ++failures;
    +            process.exit(1);
    +        }
    +    }
    +    if (watch) watchFiles(files);
    +    runFiles(files);
    +}
    +
    +

    Show the cursor when show is true, otherwise hide it.

    + +

    + +
    • param: Boolean show

    +
    +
    function cursor(show) {
    +    if (show) {
    +        sys.print('\x1b[?25h');
    +    } else {
    +        sys.print('\x1b[?25l');
    +    }
    +}
    +
    +

    Run the given test files.

    + +

    + +
    • param: Array files

    +
    +
    function runFiles(files) {
    +    if (serial) {
    +        (function next(){
    +            if (files.length) {
    +                runFile(files.shift(), next);
    +            }
    +        })();
    +    } else {
    +      files.forEach(runFile);
    +    }
    +}
    +
    +

    Run tests for the given file, callback fn() when finished.

    + +

    + +
    • param: String file

    • param: Function fn

    +
    +
    function runFile(file, fn) {
    +    if (file.match(/\.js$/)) {
    +        var title = path.basename(file),
    +            file = path.join(cwd, file),
    +            mod = require(file.replace(/\.js$/, ''));
    +        (function check(){
    +           var len = Object.keys(mod).length;
    +           if (len) {
    +               runSuite(title, mod, fn);
    +           } else {
    +               setTimeout(check, 20);
    +           }
    +        })();
    +    }
    +}
    +
    +

    Clear the module cache for the given file.

    + +

    + +
    • param: String file

    +
    +
    function clearCache(file) {
    +    var keys = Object.keys(module.moduleCache);
    +    for (var i = 0, len = keys.length; i &lt; len; ++i) {
    +        var key = keys[i];
    +        if (key.indexOf(file) === key.length - file.length) {
    +            delete module.moduleCache[key];
    +        }
    +    }
    +}
    +
    +

    Watch the given files for changes.

    + +

    + +
    • param: Array files

    +
    +
    function watchFiles(files) {
    +    var p = 0,
    +        c = ['▫   ', '▫▫  ', '▫▫▫ ', ' ▫▫▫',
    +             '  ▫▫', '   ▫', '   ▫', '  ▫▫',
    +             '▫▫▫ ', '▫▫  ', '▫   '],
    +        l = c.length;
    +    cursor(false);
    +    setInterval(function(){
    +        sys.print(colorize('  [green]{' + c[p++ % l] + '} watching\r'));
    +    }, 100);
    +    files.forEach(function(file){
    +        fs.watchFile(file, { interval: 100 }, function(curr, prev){
    +            if (curr.mtime &gt; prev.mtime) {
    +                print('  [yellow]{◦} ' + file);
    +                clearCache(file);
    +                runFile(file);
    +            }
    +        });
    +    });
    +}
    +
    +

    Report err for the given test and suite.

    + +

    + +
    • param: String suite

    • param: String test

    • param: Error err

    +
    +
    function error(suite, test, err) {
    +    ++failures;
    +    var name = err.name,
    +        stack = err.stack.replace(err.name, ''),
    +        label = test === 'uncaught'
    +            ? test
    +            : suite + ' ' + test;
    +    print('\n   [bold]{' + label + '}: [red]{' + name + '}' + stack + '\n');
    +    if (watch) notify(label + ' failed');
    +}
    +
    +

    Run the given tests, callback fn() when finished.

    + +

    + +
    • param: String title

    • param: Object tests

    • param: Function fn

    +
    +
    var dots = 0;
    +function runSuite(title, tests, fn) {
    +    // Keys
    +    var keys = only.length
    +        ? only.slice(0)
    +        : Object.keys(tests);
    +
    +    // Setup
    +    var setup = tests.setup || function(fn){ fn(); };
    +
    +    // Iterate tests
    +    (function next(){
    +        if (keys.length) {
    +            var key,
    +                test = tests[key = keys.shift()];
    +            // Non-tests
    +            if (key === 'setup') return next();
    +
    +            // Run test
    +            if (test) {
    +                try {
    +                    ++testcount;
    +                    assert.testTitle = key;
    +                    if (serial) {
    +                        if (!watch) {
    +                            sys.print('.');
    +                            if (++dots % 25 === 0) sys.print('\n');
    +                        }
    +                        setup(function(){
    +                            if (test.length &lt; 1) {
    +                                test();
    +                                next();
    +                            } else {
    +                                var id = setTimeout(function(){
    +                                    throw new Error(&quot;'" + key + "' timed out&quot;);
    +                                }, timeout);
    +                                test(function(){
    +                                    clearTimeout(id);
    +                                    next();
    +                                });
    +                            } 
    +                        });
    +                    } else {
    +                        test(function(fn){
    +                            process.addListener('beforeExit', function(){
    +                                try {
    +                                    fn();
    +                                } catch (err) {
    +                                    error(title, key, err);
    +                                }
    +                            });
    +                        });
    +                    }
    +                } catch (err) {
    +                    error(title, key, err);
    +                }
    +            }
    +            if (!serial) next();
    +        } else if (serial) {
    +          fn();
    +        }
    +    })();
    +}
    +
    +

    Report exceptions. +

    +
    +
    function report() {
    +    process.emit('beforeExit');
    +    if (failures) {
    +        print('\n   [bold]{Failures}: [red]{' + failures + '}\n\n');
    +        notify('Failures: ' + failures);
    +    } else {
    +        if (serial) print('');
    +        print('\n   [green]{100%} ' + testcount + ' tests\n');
    +        notify('100% ok');
    +    }
    +    if (typeof _$jscoverage === 'object') {
    +        reportCoverage(_$jscoverage);
    +    }
    +}
    +
    +

    Growl notify the given msg.

    + +

    + +
    • param: String msg

    +
    +
    function notify(msg) {
    +    if (growl) {
    +        childProcess.exec('growlnotify -name Expresso -m "' + msg + '"');
    +    }
    +}
    +
    +// Report uncaught exceptions
    +
    +process.addListener('uncaughtException', function(err){
    +    error('uncaught', 'uncaught', err);
    +});
    +
    +// Show cursor
    +
    +['INT', 'TERM', 'QUIT'].forEach(function(sig){
    +    process.addListener('SIG' + sig, function(){
    +        cursor(true);
    +        process.exit(1);
    +    });
    +});
    +
    +// Report test coverage when available
    +// and emit "beforeExit" event to perform
    +// final assertions
    +
    +var orig = process.emit;
    +process.emit = function(event){
    +    if (event === 'exit') {
    +        report();
    +        process.reallyExit(failures);
    +    }
    +    orig.apply(this, arguments);
    +};
    +
    +// Run test files
    +
    +if (!defer) run(files);
    +
    +
    \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/docs/index.html b/node_modules/mongoose/support/expresso/docs/index.html new file mode 100644 index 0000000..064313f --- /dev/null +++ b/node_modules/mongoose/support/expresso/docs/index.html @@ -0,0 +1,377 @@ + + + Expresso - TDD Framework For Node + + + + + Fork me on GitHub + +
    +

    Expresso

    +
    +

    NAME

    +

    + index +

    +

    Expresso is a JavaScript TDD framework written for nodejs. Expresso is extremely fast, and is packed with features such as additional assertion methods, code coverage reporting, CI support, and more.

    + +

    Features

    + +
      +
    • light-weight
    • +
    • intuitive async support
    • +
    • intuitive test runner executable
    • +
    • test coverage support and reporting via node-jscoverage
    • +
    • uses and extends the core assert module
    • +
    • assert.eql() alias of assert.deepEqual()
    • +
    • assert.response() http response utility
    • +
    • assert.includes()
    • +
    • assert.isNull()
    • +
    • assert.isUndefined()
    • +
    • assert.isNotNull()
    • +
    • assert.isDefined()
    • +
    • assert.match()
    • +
    • assert.length()
    • +
    + + +

    Installation

    + +

    To install both expresso and node-jscoverage run +the command below, which will first compile node-jscoverage:

    + +
    $ make install
    +
    + +

    To install expresso alone without coverage reporting run:

    + +
    $ make install-expresso
    +
    + +

    Install via npm:

    + +
    $ npm install expresso
    +
    + +

    Examples

    + +

    To define tests we simply export several functions:

    + +
    exports['test String#length'] = function(){
    +    assert.equal(6, 'foobar'.length);
    +};
    +
    + +

    Alternatively for large numbers of tests you may want to +export your own object containing the tests, however this +is essentially the as above:

    + +
    module.exports = {
    +    'test String#length': function(){
    +        assert.equal(6, 'foobar'.length);
    +    }
    +};
    +
    + +

    If you prefer not to use quoted keys:

    + +
    exports.testsStringLength = function(){
    +    assert.equal(6, 'foobar'.length);
    +};
    +
    + +

    The argument passed to each callback is beforeExit, +which is typically used to assert that callbacks have been +invoked.

    + +
    exports.testAsync = function(beforeExit){
    +    var n = 0;
    +    setTimeout(function(){
    +        ++n;
    +        assert.ok(true);
    +    }, 200);
    +    setTimeout(function(){
    +        ++n;
    +        assert.ok(true);
    +    }, 200);
    +    beforeExit(function(){
    +        assert.equal(2, n, 'Ensure both timeouts are called');
    +    });
    +};
    +
    + +

    Assert Utilities

    + +

    assert.isNull(val[, msg])

    + +

    Asserts that the given val is null.

    + +
    assert.isNull(null);
    +
    + +

    assert.isNotNull(val[, msg])

    + +

    Asserts that the given val is not null.

    + +
    assert.isNotNull(undefined);
    +assert.isNotNull(false);
    +
    + +

    assert.isUndefined(val[, msg])

    + +

    Asserts that the given val is undefined.

    + +
    assert.isUndefined(undefined);
    +
    + +

    assert.isDefined(val[, msg])

    + +

    Asserts that the given val is not undefined.

    + +
    assert.isDefined(null);
    +assert.isDefined(false);
    +
    + +

    assert.match(str, regexp[, msg])

    + +

    Asserts that the given str matches regexp.

    + +
    assert.match('foobar', /^foo(bar)?/);
    +assert.match('foo', /^foo(bar)?/);
    +
    + +

    assert.length(val, n[, msg])

    + +

    Assert that the given val has a length of n.

    + +
    assert.length([1,2,3], 3);
    +assert.length('foo', 3);
    +
    + +

    assert.type(obj, type[, msg])

    + +

    Assert that the given obj is typeof type.

    + +
    assert.type(3, 'number');
    +
    + +

    assert.eql(a, b[, msg])

    + +

    Assert that object b is equal to object a. This is an +alias for the core assert.deepEqual() method which does complex +comparisons, opposed to assert.equal() which uses ==.

    + +
    assert.eql('foo', 'foo');
    +assert.eql([1,2], [1,2]);
    +assert.eql({ foo: 'bar' }, { foo: 'bar' });
    +
    + +

    assert.includes(obj, val[, msg])

    + +

    Assert that obj is within val. This method supports Array_s +and Strings_s.

    + +
    assert.includes([1,2,3], 3);
    +assert.includes('foobar', 'foo');
    +assert.includes('foobar', 'bar');
    +
    + +

    assert.response(server, req, res|fn[, msg|fn])

    + +

    Performs assertions on the given server, which should not call +listen(), as this is handled internally by expresso and the server +is killed after all responses have completed. This method works with +any http.Server instance, so Connect and Express servers will work +as well.

    + +

    The req object may contain:

    + +
      +
    • url request url
    • +
    • timeout timeout in milliseconds
    • +
    • method HTTP method
    • +
    • data request body
    • +
    • headers headers object
    • +
    + + +

    The res object may be a callback function which +receives the response for assertions, or an object +which is then used to perform several assertions +on the response with the following properties:

    + +
      +
    • body assert response body (regexp or string)
    • +
    • status assert response status code
    • +
    • header assert that all given headers match (unspecified are ignored, use a regexp or string)
    • +
    + + +

    When providing res you may then also pass a callback function +as the fourth argument for additional assertions.

    + +

    Below are some examples:

    + +
    assert.response(server, {
    +    url: '/', timeout: 500
    +}, {
    +    body: 'foobar'
    +});
    +
    +assert.response(server, {
    +    url: '/',
    +    method: 'GET'
    +},{
    +    body: '{"name":"tj"}',
    +    status: 200,
    +    headers: {
    +        'Content-Type': 'application/json; charset=utf8',
    +        'X-Foo': 'bar'
    +    }
    +});
    +
    +assert.response(server, {
    +    url: '/foo',
    +    method: 'POST',
    +    data: 'bar baz'
    +},{
    +    body: '/foo bar baz',
    +    status: 200
    +}, 'Test POST');
    +
    +assert.response(server, {
    +    url: '/foo',
    +    method: 'POST',
    +    data: 'bar baz'
    +},{
    +    body: '/foo bar baz',
    +    status: 200
    +}, function(res){
    +    // All done, do some more tests if needed
    +});
    +
    +assert.response(server, {
    +    url: '/'
    +}, function(res){
    +    assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback');
    +});
    +
    + +

    expresso(1)

    + +

    To run a single test suite (file) run:

    + +
    $ expresso test/a.test.js
    +
    + +

    To run several suites we may simply append another:

    + +
    $ expresso test/a.test.js test/b.test.js
    +
    + +

    We can also pass a whitelist of tests to run within all suites:

    + +
    $ expresso --only "foo()" --only "bar()"
    +
    + +

    Or several with one call:

    + +
    $ expresso --only "foo(), bar()"
    +
    + +

    Globbing is of course possible as well:

    + +
    $ expresso test/*
    +
    + +

    When expresso is called without any files, test/* is the default, +so the following is equivalent to the command above:

    + +
    $ expresso
    +
    + +

    If you wish to unshift a path to require.paths before +running tests, you may use the -I or --include flag.

    + +
    $ expresso --include lib test/*
    +
    + +

    The previous example is typically what I would recommend, since expresso +supports test coverage via node-jscoverage (bundled with expresso), +so you will need to expose an instrumented version of you library.

    + +

    To instrument your library, simply run node-jscoverage, +passing the src and dest directories:

    + +
    $ node-jscoverage lib lib-cov
    +
    + +

    Now we can run our tests again, using the lib-cov directory that has been +instrumented with coverage statements:

    + +
    $ expresso -I lib-cov test/*
    +
    + +

    The output will look similar to below, depending on your test coverage of course :)

    + +

    node coverage

    + +

    To make this process easier expresso has the -c or --cov which essentially +does the same as the two commands above. The following two commands will +run the same tests, however one will auto-instrument, and unshift lib-cov, +and the other will run tests normally:

    + +
    $ expresso -I lib test/*
    +$ expresso -I lib --cov test/*
    +
    + +

    Currently coverage is bound to the lib directory, however in the +future --cov will most likely accept a path.

    + +

    Async Exports

    + +

    Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the exports.foo = function(){}; syntax is supported for this:

    + +
    setTimeout(function(){
    +    exports['test async exports'] = function(){
    +        assert.ok('wahoo');
    +    };
    +}, 100);
    +
    + +
    +
    + + \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/docs/index.md b/node_modules/mongoose/support/expresso/docs/index.md new file mode 100644 index 0000000..489f931 --- /dev/null +++ b/node_modules/mongoose/support/expresso/docs/index.md @@ -0,0 +1,290 @@ + +[Expresso](http://github.com/visionmedia/expresso) is a JavaScript [TDD](http://en.wikipedia.org/wiki/Test-driven_development) framework written for [nodejs](http://nodejs.org). Expresso is extremely fast, and is packed with features such as additional assertion methods, code coverage reporting, CI support, and more. + +## Features + + - light-weight + - intuitive async support + - intuitive test runner executable + - test coverage support and reporting via [node-jscoverage](http://github.com/visionmedia/node-jscoverage) + - uses and extends the core _assert_ module + - `assert.eql()` alias of `assert.deepEqual()` + - `assert.response()` http response utility + - `assert.includes()` + - `assert.isNull()` + - `assert.isUndefined()` + - `assert.isNotNull()` + - `assert.isDefined()` + - `assert.match()` + - `assert.length()` + +## Installation + +To install both expresso _and_ node-jscoverage run +the command below, which will first compile node-jscoverage: + + $ make install + +To install expresso alone without coverage reporting run: + + $ make install-expresso + +Install via npm: + + $ npm install expresso + +## Examples + +To define tests we simply export several functions: + + exports['test String#length'] = function(){ + assert.equal(6, 'foobar'.length); + }; + +Alternatively for large numbers of tests you may want to +export your own object containing the tests, however this +is essentially the as above: + + module.exports = { + 'test String#length': function(){ + assert.equal(6, 'foobar'.length); + } + }; + +If you prefer not to use quoted keys: + + exports.testsStringLength = function(){ + assert.equal(6, 'foobar'.length); + }; + +The argument passed to each callback is _beforeExit_, +which is typically used to assert that callbacks have been +invoked. + + exports.testAsync = function(beforeExit){ + var n = 0; + setTimeout(function(){ + ++n; + assert.ok(true); + }, 200); + setTimeout(function(){ + ++n; + assert.ok(true); + }, 200); + beforeExit(function(){ + assert.equal(2, n, 'Ensure both timeouts are called'); + }); + }; + +## Assert Utilities + +### assert.isNull(val[, msg]) + +Asserts that the given _val_ is _null_. + + assert.isNull(null); + +### assert.isNotNull(val[, msg]) + +Asserts that the given _val_ is not _null_. + + assert.isNotNull(undefined); + assert.isNotNull(false); + +### assert.isUndefined(val[, msg]) + +Asserts that the given _val_ is _undefined_. + + assert.isUndefined(undefined); + +### assert.isDefined(val[, msg]) + +Asserts that the given _val_ is not _undefined_. + + assert.isDefined(null); + assert.isDefined(false); + +### assert.match(str, regexp[, msg]) + +Asserts that the given _str_ matches _regexp_. + + assert.match('foobar', /^foo(bar)?/); + assert.match('foo', /^foo(bar)?/); + +### assert.length(val, n[, msg]) + +Assert that the given _val_ has a length of _n_. + + assert.length([1,2,3], 3); + assert.length('foo', 3); + +### assert.type(obj, type[, msg]) + +Assert that the given _obj_ is typeof _type_. + + assert.type(3, 'number'); + +### assert.eql(a, b[, msg]) + +Assert that object _b_ is equal to object _a_. This is an +alias for the core _assert.deepEqual()_ method which does complex +comparisons, opposed to _assert.equal()_ which uses _==_. + + assert.eql('foo', 'foo'); + assert.eql([1,2], [1,2]); + assert.eql({ foo: 'bar' }, { foo: 'bar' }); + +### assert.includes(obj, val[, msg]) + +Assert that _obj_ is within _val_. This method supports _Array_s +and _Strings_s. + + assert.includes([1,2,3], 3); + assert.includes('foobar', 'foo'); + assert.includes('foobar', 'bar'); + +### assert.response(server, req, res|fn[, msg|fn]) + +Performs assertions on the given _server_, which should _not_ call +listen(), as this is handled internally by expresso and the server +is killed after all responses have completed. This method works with +any _http.Server_ instance, so _Connect_ and _Express_ servers will work +as well. + +The _req_ object may contain: + + - _url_ request url + - _timeout_ timeout in milliseconds + - _method_ HTTP method + - _data_ request body + - _headers_ headers object + +The _res_ object may be a callback function which +receives the response for assertions, or an object +which is then used to perform several assertions +on the response with the following properties: + + - _body_ assert response body (regexp or string) + - _status_ assert response status code + - _header_ assert that all given headers match (unspecified are ignored, use a regexp or string) + +When providing _res_ you may then also pass a callback function +as the fourth argument for additional assertions. + +Below are some examples: + + assert.response(server, { + url: '/', timeout: 500 + }, { + body: 'foobar' + }); + + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8', + 'X-Foo': 'bar' + } + }); + + assert.response(server, { + url: '/foo', + method: 'POST', + data: 'bar baz' + },{ + body: '/foo bar baz', + status: 200 + }, 'Test POST'); + + assert.response(server, { + url: '/foo', + method: 'POST', + data: 'bar baz' + },{ + body: '/foo bar baz', + status: 200 + }, function(res){ + // All done, do some more tests if needed + }); + + assert.response(server, { + url: '/' + }, function(res){ + assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback'); + }); + + +## expresso(1) + +To run a single test suite (file) run: + + $ expresso test/a.test.js + +To run several suites we may simply append another: + + $ expresso test/a.test.js test/b.test.js + +We can also pass a whitelist of tests to run within all suites: + + $ expresso --only "foo()" --only "bar()" + +Or several with one call: + + $ expresso --only "foo(), bar()" + +Globbing is of course possible as well: + + $ expresso test/* + +When expresso is called without any files, _test/*_ is the default, +so the following is equivalent to the command above: + + $ expresso + +If you wish to unshift a path to `require.paths` before +running tests, you may use the `-I` or `--include` flag. + + $ expresso --include lib test/* + +The previous example is typically what I would recommend, since expresso +supports test coverage via [node-jscoverage](http://github.com/visionmedia/node-jscoverage) (bundled with expresso), +so you will need to expose an instrumented version of you library. + +To instrument your library, simply run [node-jscoverage](http://github.com/visionmedia/node-jscoverage), +passing the _src_ and _dest_ directories: + + $ node-jscoverage lib lib-cov + +Now we can run our tests again, using the _lib-cov_ directory that has been +instrumented with coverage statements: + + $ expresso -I lib-cov test/* + +The output will look similar to below, depending on your test coverage of course :) + +![node coverage](http://dl.dropbox.com/u/6396913/cov.png) + +To make this process easier expresso has the _-c_ or _--cov_ which essentially +does the same as the two commands above. The following two commands will +run the same tests, however one will auto-instrument, and unshift _lib-cov_, +and the other will run tests normally: + + $ expresso -I lib test/* + $ expresso -I lib --cov test/* + +Currently coverage is bound to the _lib_ directory, however in the +future `--cov` will most likely accept a path. + +## Async Exports + +Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the _exports.foo = function(){};_ syntax is supported for this: + + setTimeout(function(){ + exports['test async exports'] = function(){ + assert.ok('wahoo'); + }; + }, 100); diff --git a/node_modules/mongoose/support/expresso/docs/layout/foot.html b/node_modules/mongoose/support/expresso/docs/layout/foot.html new file mode 100644 index 0000000..44d85e9 --- /dev/null +++ b/node_modules/mongoose/support/expresso/docs/layout/foot.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/docs/layout/head.html b/node_modules/mongoose/support/expresso/docs/layout/head.html new file mode 100644 index 0000000..567f62e --- /dev/null +++ b/node_modules/mongoose/support/expresso/docs/layout/head.html @@ -0,0 +1,42 @@ + + + Expresso - TDD Framework For Node + + + + + Fork me on GitHub + +
    +

    Expresso

    diff --git a/node_modules/mongoose/support/expresso/lib/bar.js b/node_modules/mongoose/support/expresso/lib/bar.js new file mode 100644 index 0000000..e15aad4 --- /dev/null +++ b/node_modules/mongoose/support/expresso/lib/bar.js @@ -0,0 +1,4 @@ + +exports.bar = function(msg){ + return msg || 'bar'; +}; \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/lib/foo.js b/node_modules/mongoose/support/expresso/lib/foo.js new file mode 100644 index 0000000..15701a5 --- /dev/null +++ b/node_modules/mongoose/support/expresso/lib/foo.js @@ -0,0 +1,16 @@ + +exports.foo = function(msg){ + if (msg) { + return msg; + } else { + return generateFoo(); + } +}; + +function generateFoo() { + return 'foo'; +} + +function Foo(msg){ + this.msg = msg || 'foo'; +} diff --git a/node_modules/mongoose/support/expresso/package.json b/node_modules/mongoose/support/expresso/package.json new file mode 100644 index 0000000..569a54b --- /dev/null +++ b/node_modules/mongoose/support/expresso/package.json @@ -0,0 +1,12 @@ +{ "name": "expresso", + "version": "0.7.2", + "description": "TDD framework, light-weight, fast, CI-friendly", + "author": "TJ Holowaychuk ", + "bin": { + "expresso": "./bin/expresso", + "node-jscoverage": "./deps/jscoverage/node-jscoverage" + }, + "scripts": { + "preinstall": "make deps/jscoverage/node-jscoverage" + } +} \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/test/assert.test.js b/node_modules/mongoose/support/expresso/test/assert.test.js new file mode 100644 index 0000000..f822595 --- /dev/null +++ b/node_modules/mongoose/support/expresso/test/assert.test.js @@ -0,0 +1,91 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert'); + +module.exports = { + 'assert.eql()': function(){ + assert.equal(assert.deepEqual, assert.eql); + }, + + 'assert.type()': function(){ + assert.type('foobar', 'string'); + assert.type(2, 'number'); + assert.throws(function(){ + assert.type([1,2,3], 'string'); + }); + }, + + 'assert.includes()': function(){ + assert.includes('some random string', 'dom'); + assert.throws(function(){ + assert.include('some random string', 'foobar'); + }); + + assert.includes(['foo', 'bar'], 'bar'); + assert.includes(['foo', 'bar'], 'foo'); + assert.includes([1,2,3], 3); + assert.includes([1,2,3], 2); + assert.includes([1,2,3], 1); + assert.throws(function(){ + assert.includes(['foo', 'bar'], 'baz'); + }); + + assert.throws(function(){ + assert.includes({ wrong: 'type' }, 'foo'); + }); + }, + + 'assert.isNull()': function(){ + assert.isNull(null); + assert.throws(function(){ + assert.isNull(undefined); + }); + assert.throws(function(){ + assert.isNull(false); + }); + }, + + 'assert.isUndefined()': function(){ + assert.isUndefined(undefined); + assert.throws(function(){ + assert.isUndefined(null); + }); + assert.throws(function(){ + assert.isUndefined(false); + }); + }, + + 'assert.isNotNull()': function(){ + assert.isNotNull(false); + assert.isNotNull(undefined); + assert.throws(function(){ + assert.isNotNull(null); + }); + }, + + 'assert.isDefined()': function(){ + assert.isDefined(false); + assert.isDefined(null); + assert.throws(function(){ + assert.isDefined(undefined); + }); + }, + + 'assert.match()': function(){ + assert.match('foobar', /foo(bar)?/); + assert.throws(function(){ + assert.match('something', /rawr/); + }); + }, + + 'assert.length()': function(){ + assert.length('test', 4); + assert.length([1,2,3,4], 4); + assert.throws(function(){ + assert.length([1,2,3], 4); + }); + } +}; \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/test/async.test.js b/node_modules/mongoose/support/expresso/test/async.test.js new file mode 100644 index 0000000..d1d2036 --- /dev/null +++ b/node_modules/mongoose/support/expresso/test/async.test.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert'); + +setTimeout(function(){ + exports['test async exports'] = function(){ + assert.ok('wahoo'); + }; +}, 100); \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/test/bar.test.js b/node_modules/mongoose/support/expresso/test/bar.test.js new file mode 100644 index 0000000..cfc2e11 --- /dev/null +++ b/node_modules/mongoose/support/expresso/test/bar.test.js @@ -0,0 +1,13 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , bar = require('bar'); + +module.exports = { + 'bar()': function(){ + assert.equal('bar', bar.bar()); + } +}; \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/test/foo.test.js b/node_modules/mongoose/support/expresso/test/foo.test.js new file mode 100644 index 0000000..ee5cff3 --- /dev/null +++ b/node_modules/mongoose/support/expresso/test/foo.test.js @@ -0,0 +1,14 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , foo = require('foo'); + +module.exports = { + 'foo()': function(){ + assert.equal('foo', foo.foo()); + assert.equal('foo', foo.foo()); + } +}; \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/test/http.test.js b/node_modules/mongoose/support/expresso/test/http.test.js new file mode 100644 index 0000000..41648d2 --- /dev/null +++ b/node_modules/mongoose/support/expresso/test/http.test.js @@ -0,0 +1,109 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , http = require('http'); + +var server = http.createServer(function(req, res){ + if (req.method === 'GET') { + if (req.url === '/delay') { + setTimeout(function(){ + res.writeHead(200, {}); + res.end('delayed'); + }, 200); + } else { + var body = JSON.stringify({ name: 'tj' }); + res.writeHead(200, { + 'Content-Type': 'application/json; charset=utf8', + 'Content-Length': body.length + }); + res.end(body); + } + } else { + var body = ''; + req.setEncoding('utf8'); + req.addListener('data', function(chunk){ body += chunk }); + req.addListener('end', function(){ + res.writeHead(200, {}); + res.end(req.url + ' ' + body); + }); + } +}); + +var delayedServer = http.createServer(function(req, res){ + res.writeHead(200); + res.end('it worked'); +}); + +var oldListen = delayedServer.listen; +delayedServer.listen = function(){ + var args = arguments; + setTimeout(function(){ + oldListen.apply(delayedServer, args); + }, 100); +}; + +module.exports = { + 'test assert.response()': function(beforeExit){ + var called = 0; + + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8' + } + }); + + assert.response(server, { + url: '/foo', + method: 'POST', + data: 'bar baz' + },{ + body: '/foo bar baz', + status: 200 + }, function(res){ + ++called; + assert.ok(res); + }); + + assert.response(server, { + url: '/foo' + }, function(res){ + ++called; + assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback'); + }); + + assert.response(server, + { url: '/delay', timeout: 300 }, + { body: 'delayed' }); + + beforeExit(function(){ + assert.equal(2, called); + }); + }, + + 'test assert.response() regexp': function(){ + assert.response(server, + { url: '/foo', method: 'POST', data: 'foobar' }, + { body: /^\/foo foo(bar)?/ }); + }, + + 'test assert.response() regexp headers': function(){ + assert.response(server, + { url: '/' }, + { body: '{"name":"tj"}', headers: { 'Content-Type': /^application\/json/ } }); + }, + + // [!] if this test doesn't pass, an uncaught ECONNREFUSED will display + 'test assert.response() with deferred listen()': function(){ + assert.response(delayedServer, + { url: '/' }, + { body: 'it worked' }); + } +}; diff --git a/node_modules/mongoose/support/expresso/test/serial/async.test.js b/node_modules/mongoose/support/expresso/test/serial/async.test.js new file mode 100644 index 0000000..c596d5c --- /dev/null +++ b/node_modules/mongoose/support/expresso/test/serial/async.test.js @@ -0,0 +1,39 @@ + +var assert = require('assert') + , setup = 0 + , order = []; + +module.exports = { + setup: function(done){ + ++setup; + done(); + }, + + a: function(done){ + assert.equal(1, setup); + order.push('a'); + setTimeout(function(){ + done(); + }, 500); + }, + + b: function(done){ + assert.equal(2, setup); + order.push('b'); + setTimeout(function(){ + done(); + }, 200); + }, + + c: function(done){ + assert.equal(3, setup); + order.push('c'); + setTimeout(function(){ + done(); + }, 1000); + }, + + d: function(){ + assert.eql(order, ['a', 'b', 'c']); + } +}; \ No newline at end of file diff --git a/node_modules/mongoose/support/expresso/test/serial/http.test.js b/node_modules/mongoose/support/expresso/test/serial/http.test.js new file mode 100644 index 0000000..7783eb5 --- /dev/null +++ b/node_modules/mongoose/support/expresso/test/serial/http.test.js @@ -0,0 +1,48 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , http = require('http'); + +var server = http.createServer(function(req, res){ + if (req.method === 'GET') { + if (req.url === '/delay') { + setTimeout(function(){ + res.writeHead(200, {}); + res.end('delayed'); + }, 200); + } else { + var body = JSON.stringify({ name: 'tj' }); + res.writeHead(200, { + 'Content-Type': 'application/json; charset=utf8', + 'Content-Length': body.length + }); + res.end(body); + } + } else { + var body = ''; + req.setEncoding('utf8'); + req.addListener('data', function(chunk){ body += chunk }); + req.addListener('end', function(){ + res.writeHead(200, {}); + res.end(req.url + ' ' + body); + }); + } +}); + +module.exports = { + 'test assert.response()': function(done){ + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8' + } + }, done); + } +}; \ No newline at end of file diff --git a/node_modules/mongoose/support/should.js/History.md b/node_modules/mongoose/support/should.js/History.md new file mode 100644 index 0000000..cb95b57 --- /dev/null +++ b/node_modules/mongoose/support/should.js/History.md @@ -0,0 +1,22 @@ + +0.0.4 / 2010-11-24 +================== + + * Added `.ok` to assert truthfulness + * Added `.arguments` + * Fixed double required bug. [thanks dominictarr] + +0.0.3 / 2010-11-19 +================== + + * Added `true` / `false` assertions + +0.0.2 / 2010-11-19 +================== + + * Added chaining support + +0.0.1 / 2010-11-19 +================== + + * Initial release diff --git a/node_modules/mongoose/support/should.js/Makefile b/node_modules/mongoose/support/should.js/Makefile new file mode 100644 index 0000000..a2f2a41 --- /dev/null +++ b/node_modules/mongoose/support/should.js/Makefile @@ -0,0 +1,6 @@ + +test: + @./support/expresso/bin/expresso \ + -I lib + +.PHONY: test \ No newline at end of file diff --git a/node_modules/mongoose/support/should.js/Readme.md b/node_modules/mongoose/support/should.js/Readme.md new file mode 100644 index 0000000..7c5c0ac --- /dev/null +++ b/node_modules/mongoose/support/should.js/Readme.md @@ -0,0 +1,248 @@ + _should_ is an expressive, test framework agnostic, assertion library for [node](http://nodejs.org). + +_should_ literally extends node's _assert_ module, in fact, it is node's assert module, for example `should.equal(str, 'foo')` will work, just as `assert.equal(str, 'foo')` would, and `should.AssertionError` **is** `asset.AssertionError`, meaning any test framework supporting this constructor will function properly with _should_. + +## Example + + var user = { + name: 'tj' + , pets: ['tobi', 'loki', 'jane', 'bandit'] + }; + + user.should.have.property('name', 'tj'); + user.should.have.property('pets').with.lengthOf(4) + +## Installation + + $ npm install should + +## modifiers + + _should_'s assertion chaining provides an expressive way to build up an assertion, along with dummy getters such as _an_, _have_, and _be_, provided are what I am simply calling **modifiers**, which have a meaning effect on the assertion. An example of this is the _not_ getter, which negates the meaning, aka `user.should.not.have.property('name')`. In the previous example note the use of _have_, as we could omit it and still construct a valid assertion. + +Some modifiers such as _include_ only have an effect with specific assertion methods, for example when asserting a substring like so: `str.should.include.string('test')`, we could omit _include_, but it helps express the meaning, however _keys_ has a strict effect, unless the _include_ modifier is used. + +## chaining assertions + +Some assertions can be chained, for example if a property is volatile we can first assert property existence: + + user.should.have.property('pets').with.lengthOf(4) + +which is essentially equivalent to below, however the property may not exist: + + user.pets.should.have.lengthOf(4) + +our dummy getters such as _and_ also help express chaining: + + user.should.be.a('object').and.have.property('name', 'tj') + +## ok + +Assert truthfulness: + + true.should.be.ok + 'yay'.should.be.ok + (1).should.be.ok + +or negated: + + false.should.not.be.ok + ''.should.not.be.ok + (0).should.not.be.ok + +## true + +Assert === true: + + true.should.be.true + '1'.should.not.be.true + +## false + +Assert === false: + + false.should.be.false + (0).should.not.be.false + +## arguments + +Assert `Arguments`: + + var args = (function(){ return arguments; })(1,2,3); + args.should.be.arguments; + [].should.not.be.arguments; + +## empty + +Asserts that length is 0: + + [].should.be.empty + ''.should.be.empty + ({ length: 0 }).should.be.empty + +## eql + +equality: + + ({ foo: 'bar' }).should.eql({ foo: 'bar' }) + [1,2,3].should.eql([1,2,3]) + +## equal + +strict equality: + + should.strictEqual(undefined, value) + should.strictEqual(false, value) + (4).should.equal(4) + 'test'.should.equal('test') + [1,2,3].should.not.equal([1,2,3]) + +## within + +Assert inclusive numeric range: + + user.age.should.be.within(5, 50) + +## a + +Assert __typeof__: + + user.should.be.a('object') + 'test'.should.be.a('string') + +## instanceof + +Assert __instanceof__: + + user.should.be.an.instanceof(User) + [].should.be.an.instanceof(Array) + +## above + +Assert numeric value above the given value: + + user.age.should.be.above(5) + user.age.should.not.be.above(100) + +## below + +Assert numeric value below the given value: + + user.age.should.be.below(100) + user.age.should.not.be.below(5) + +## match + +Assert regexp match: + + username.should.match(/^\w+$/) + +## length + +Assert _length_ property exists and has a value of the given number: + + user.pets.should.have.length(5) + user.pets.should.have.a.lengthOf(5) + +Aliases: _lengthOf_ + +## string + +Substring assertion: + + 'foobar'.should.include.string('foo') + 'foobar'.should.include.string('bar') + 'foobar'.should.not.include.string('baz') + +## property + +Assert property exists and has optional value: + + user.should.have.property('name') + user.should.have.property('age', 15) + user.should.not.have.property('rawr') + user.should.not.have.property('age', 0) + +## ownProperty + +Assert own property (on the immediate object): + + ({ foo: 'bar' }).should.have.ownProperty('foo') + +## contain + +Assert array value: + + [1,2,3].should.contain(3) + [1,2,3].should.contain(2) + [1,2,3].should.not.contain(4) + +## keys + +Assert own object keys, which must match _exactly_, +and will fail if you omit a key or two: + + var obj = { foo: 'bar', baz: 'raz' }; + obj.should.have.keys('foo', 'bar'); + obj.should.have.keys(['foo', 'bar']); + +using the _include_ modifier, we can check inclusion of a key, +but not fail when we omit a few: + + obj.should.include.keys('foo') + obj.should.include.keys('bar') + obj.should.not.include.keys('baz') + +## respondTo + +Assert that the given property is a function: + + user.should.respondTo('email') + +## Express example + +For example you can use should with the [Expresso TDD Framework](http://github.com/visionmedia/expresso) by simply including it: + + var lib = require('mylib') + , should = require('should'); + + module.exports = { + 'test .version': function(){ + lib.version.should.match(/^\d+\.\d+\.\d+$/); + } + }; + +## Running tests + +To run the tests for _should_ simple update your git submodules and run: + + $ make test + +## OMG IT EXTENDS OBJECT???!?!@ + +Yes, yes it does, with a single getter _should_, and no it wont break your code, because it does this **properly** with a non-enumerable property. + +## License + +(The MIT License) + +Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/mongoose/support/should.js/examples/runner.js b/node_modules/mongoose/support/should.js/examples/runner.js new file mode 100644 index 0000000..9355955 --- /dev/null +++ b/node_modules/mongoose/support/should.js/examples/runner.js @@ -0,0 +1,53 @@ + +/** + * Module dependencies. + */ + +var should = require('../'); + +function test(name, fn){ + try { + fn(); + } catch (err) { + console.log(' \x1b[31m%s', name); + console.log(' %s\x1b[0m', err.stack); + return; + } + console.log(' √ \x1b[32m%s\x1b[0m', name); +} + +function Point(x, y) { + this.x = x; + this.y = y; + this.sub = function(other){ + return new Point( + this.x - other.x + , this.y - other.y); + } +} + +console.log(); + +test('new Point(x, y)', function(){ + var point = new Point(50, 100); + point.should.be.an.instanceof(Point); + point.should.have.property('x', 50); + point.should.have.property('y', 100); +}); + +test('Point#sub()', function(){ + var a = new Point(50, 100) + , b = new Point(20, 50); + a.sub(b).should.be.an.instanceof(Point); + a.sub(b).should.not.equal(a); + a.sub(b).should.not.equal(b); + a.sub(b).should.have.property('x', 30); + a.sub(b).should.have.property('y', 50); +}); + +test('Point#add()', function(){ + var point = new Point(50, 100); + point.should.respondTo('add'); +}); + +console.log(); \ No newline at end of file diff --git a/node_modules/mongoose/support/should.js/index.js b/node_modules/mongoose/support/should.js/index.js new file mode 100644 index 0000000..6dbdbde --- /dev/null +++ b/node_modules/mongoose/support/should.js/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/should'); \ No newline at end of file diff --git a/node_modules/mongoose/support/should.js/lib/eql.js b/node_modules/mongoose/support/should.js/lib/eql.js new file mode 100644 index 0000000..31135e9 --- /dev/null +++ b/node_modules/mongoose/support/should.js/lib/eql.js @@ -0,0 +1,91 @@ + +// Taken from node's assert module, because it sucks +// and exposes next to nothing useful. + +module.exports = _deepEqual; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + + return true; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (actual instanceof Date && expected instanceof Date) { + return actual.getTime() === expected.getTime(); + + // 7.3. Other pairs that do not both pass typeof value == "object", + // equivalence is determined by ==. + } else if (typeof actual != 'object' && typeof expected != 'object') { + return actual == expected; + + // 7.4. For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical "prototype" property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isUndefinedOrNull (value) { + return value === null || value === undefined; +} + +function isArguments (object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv (a, b) { + if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) + return false; + // an identical "prototype" property. + if (a.prototype !== b.prototype) return false; + //~~~I've managed to break Object.keys through screwy arguments passing. + // Converting to array solves the problem. + if (isArguments(a)) { + if (!isArguments(b)) { + return false; + } + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + try{ + var ka = Object.keys(a), + kb = Object.keys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + // having the same number of owned properties (keys incorporates hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key] )) + return false; + } + return true; +} diff --git a/node_modules/mongoose/support/should.js/lib/should.js b/node_modules/mongoose/support/should.js/lib/should.js new file mode 100644 index 0000000..f49475a --- /dev/null +++ b/node_modules/mongoose/support/should.js/lib/should.js @@ -0,0 +1,548 @@ + +/*! + * Should + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var util = require('sys') + , assert = require('assert') + , AssertionError = assert.AssertionError + , eql = require('./eql') + , i = util.inspect; + +/** + * Expose assert as should. + * + * This allows you to do things like below + * without require()ing the assert module. + * + * should.equal(foo.bar, undefined); + * + */ + +exports = module.exports = assert; + +/** + * Library version. + */ + +exports.version = '0.0.4'; + +/** + * Expose api via `Object#should`. + * + * @api public + */ + +Object.defineProperty(Object.prototype, 'should', { + set: function(){}, + get: function(){ + return new Assertion(this); + } +}); + +/** + * Initialize a new `Assertion` with the given _obj_. + * + * @param {Mixed} obj + * @api private + */ + +var Assertion = exports.Assertion = function Assertion(obj) { + this.obj = obj; +}; + +/** + * Prototype. + */ + +Assertion.prototype = { + + /** + * HACK: prevents double require() from failing. + */ + + exports: exports, + + /** + * Assert _expr_ with the given _msg_ and _negatedMsg_. + * + * @param {Boolean} expr + * @param {String} msg + * @param {String} negatedMsg + * @api private + */ + + assert: function(expr, msg, negatedMsg){ + var msg = this.negate ? negatedMsg : msg + , ok = this.negate ? !expr : expr; + if (!ok) { + throw new AssertionError({ + message: msg + , stackStartFunction: this.assert + }); + } + }, + + /** + * Dummy getter. + * + * @api public + */ + + get an() { + return this; + }, + + /** + * Dummy getter. + * + * @api public + */ + + get and() { + return this; + }, + + /** + * Dummy getter. + * + * @api public + */ + + get be() { + return this; + }, + + /** + * Dummy getter. + * + * @api public + */ + + get have() { + return this; + }, + + /** + * Dummy getter. + * + * @api public + */ + + get with() { + return this; + }, + + /** + * Inclusion modifier. + * + * @api public + */ + + get include() { + this.includes = true; + return this; + }, + + /** + * Negation modifier. + * + * @api public + */ + + get not() { + this.negate = true; + return this; + }, + + /** + * Get object inspection string. + * + * @return {String} + * @api private + */ + + get inspect() { + return i(this.obj); + }, + + /** + * Assert instanceof `Arguments`. + * + * @api public + */ + + get arguments() { + this.assert( + '[object Arguments]' == Object.prototype.toString.call(this.obj) + , 'expected ' + this.inspect + ' to be arguments' + , 'expected ' + this.inspect + ' to not be arguments'); + return this; + }, + + /** + * Assert that an object is empty aka length of 0. + * + * @api public + */ + + get empty() { + this.obj.should.have.property('length'); + this.assert( + 0 === this.obj.length + , 'expected ' + this.inspect + ' to be empty' + , 'expected ' + this.inspect + ' not to be empty'); + return this; + }, + + /** + * Assert ok. + * + * @api public + */ + + get ok() { + this.assert( + this.obj + , 'expected ' + this.inspect + ' to be truthy' + , 'expected ' + this.inspect + ' to be falsey'); + return this; + }, + + /** + * Assert true. + * + * @api public + */ + + get true() { + this.assert( + true === this.obj + , 'expected ' + this.inspect + ' to be true' + , 'expected ' + this.inspect + ' not to be true'); + return this; + }, + + /** + * Assert false. + * + * @api public + */ + + get false() { + this.assert( + false === this.obj + , 'expected ' + this.inspect + ' to be false' + , 'expected ' + this.inspect + ' not to be false'); + return this; + }, + + /** + * Assert equal. + * + * @param {Mixed} val + * @api public + */ + + eql: function(val){ + this.assert( + eql(val, this.obj) + , 'expected ' + this.inspect + ' to equal ' + i(val) + , 'expected ' + this.inspect + ' to not equal ' + i(val)); + return this; + }, + + /** + * Assert strict equal. + * + * @param {Mixed} val + * @api public + */ + + equal: function(val){ + this.assert( + val === this.obj + , 'expected ' + this.inspect + ' to equal ' + i(val) + , 'expected ' + this.inspect + ' to not equal ' + i(val)); + return this; + }, + + /** + * Assert within start to finish (inclusive). + * + * @param {Number} start + * @param {Number} finish + * @api public + */ + + within: function(start, finish){ + var range = start + '..' + finish; + this.assert( + this.obj >= start && this.obj <= finish + , 'expected ' + this.inspect + ' to be within ' + range + , 'expected ' + this.inspect + ' to not be within ' + range); + return this; + }, + + /** + * Assert typeof. + * + * @api public + */ + + a: function(type){ + this.assert( + type == typeof this.obj + , 'expected ' + this.inspect + ' to be a ' + type + , 'expected ' + this.inspect + ' not to be a ' + type); + return this; + }, + + /** + * Assert instanceof. + * + * @api public + */ + + instanceof: function(constructor){ + var name = constructor.name; + this.assert( + this.obj instanceof constructor + , 'expected ' + this.inspect + ' to be an instance of ' + name + , 'expected ' + this.inspect + ' not to be an instance of ' + name); + return this; + }, + + /** + * Assert numeric value above _n_. + * + * @param {Number} n + * @api public + */ + + above: function(n){ + this.assert( + this.obj > n + , 'expected ' + this.inspect + ' to be above ' + n + , 'expected ' + this.inspect + ' to be below ' + n); + return this; + }, + + /** + * Assert numeric value below _n_. + * + * @param {Number} n + * @api public + */ + + below: function(n){ + this.assert( + this.obj < n + , 'expected ' + this.inspect + ' to be below ' + n + , 'expected ' + this.inspect + ' to be above ' + n); + return this; + }, + + /** + * Assert string value matches _regexp_. + * + * @param {RegExp} regexp + * @api public + */ + + match: function(regexp){ + this.assert( + regexp.exec(this.obj) + , 'expected ' + this.inspect + ' to match ' + regexp + , 'expected ' + this.inspect + ' not to match ' + regexp); + return this; + }, + + /** + * Assert property "length" exists and has value of _n_. + * + * @param {Number} n + * @api public + */ + + length: function(n){ + this.obj.should.have.property('length'); + var len = this.obj.length; + this.assert( + n == len + , 'expected ' + this.inspect + ' to have a length of ' + n + ' but got ' + len + , 'expected ' + this.inspect + ' to not have a length of ' + len); + return this; + }, + + /** + * Assert substring. + * + * @param {String} str + * @api public + */ + + string: function(str){ + this.obj.should.be.a('string'); + this.assert( + ~this.obj.indexOf(str) + , 'expected ' + this.inspect + ' to include ' + i(str) + , 'expected ' + this.inspect + ' to not include ' + i(str)); + return this; + }, + + /** + * Assert property _name_ exists, with optional _val_. + * + * @param {String} name + * @param {Mixed} val + * @api public + */ + + property: function(name, val){ + if (this.negate && undefined !== val) { + if (undefined === this.obj[name]) { + throw new Error(this.inspect + ' has no property ' + i(name)); + } + } else { + this.assert( + undefined !== this.obj[name] + , 'expected ' + this.inspect + ' to have a property ' + i(name) + , 'expected ' + this.inspect + ' to not have a property ' + i(name)); + } + + if (undefined !== val) { + this.assert( + val === this.obj[name] + , 'expected ' + this.inspect + ' to have a property ' + i(name) + + ' of ' + i(val) + ', but got ' + i(this.obj[name]) + , 'expected ' + this.inspect + ' to not have a property ' + i(name) + ' of ' + i(val)); + } + + this.obj = this.obj[name]; + return this; + }, + + /** + * Assert own property _name_ exists. + * + * @param {String} name + * @api public + */ + + ownProperty: function(name){ + this.assert( + this.obj.hasOwnProperty(name) + , 'expected ' + this.inspect + ' to have own property ' + i(name) + , 'expected ' + this.inspect + ' to not have own property ' + i(name)); + return this; + }, + + /** + * Assert that the array contains _obj_. + * + * @param {Mixed} obj + * @api public + */ + + contain: function(obj){ + this.obj.should.be.an.instanceof(Array); + this.assert( + ~this.obj.indexOf(obj) + , 'expected ' + this.inspect + ' to contain ' + i(obj) + , 'expected ' + this.inspect + ' to not contain ' + i(obj)); + return this; + }, + + /** + * Assert exact keys or inclusion of keys by using + * the `.include` modifier. + * + * @param {Array|String ...} keys + * @api public + */ + + keys: function(keys){ + var str + , ok = true; + + keys = keys instanceof Array + ? keys + : Array.prototype.slice.call(arguments); + + if (!keys.length) throw new Error('keys required'); + + var actual = Object.keys(this.obj) + , len = keys.length; + + // Inclusion + ok = keys.every(function(key){ + return ~actual.indexOf(key); + }); + + // Strict + if (!this.negate && !this.includes) { + ok = ok && keys.length == actual.length; + } + + // Key string + if (len > 1) { + keys = keys.map(function(key){ + return i(key); + }); + var last = keys.pop(); + str = keys.join(', ') + ', and ' + last; + } else { + str = i(keys[0]); + } + + // Form + str = (len > 1 ? 'keys ' : 'key ') + str; + + // Have / include + str = (this.includes ? 'include ' : 'have ') + str; + + // Assertion + this.assert( + ok + , 'expected ' + this.inspect + ' to ' + str + , 'expected ' + this.inspect + ' to not ' + str); + + return this; + }, + + /** + * Assert that _method_ is a function. + * + * @param {String} method + * @api public + */ + + respondTo: function(method){ + this.assert( + 'function' == typeof this.obj[method] + , 'expected ' + this.inspect + ' to respond to ' + method + '()' + , 'expected ' + this.inspect + ' to not respond to ' + method + '()'); + return this; + } +}; + +/** + * Aliases. + */ + +(function alias(name, as){ + Assertion.prototype[as] = Assertion.prototype[name]; + return alias; +}) +('length', 'lengthOf') +('keys', 'key') +('ownProperty', 'haveOwnProperty') +('above', 'greaterThan') +('below', 'lessThan'); diff --git a/node_modules/mongoose/support/should.js/package.json b/node_modules/mongoose/support/should.js/package.json new file mode 100644 index 0000000..413e437 --- /dev/null +++ b/node_modules/mongoose/support/should.js/package.json @@ -0,0 +1,8 @@ +{ "name": "should" + , "description": "test framework agnostic BDD-style assertions" + , "version": "0.0.4" + , "author": "TJ Holowaychuk " + , "keywords": ["test", "bdd", "assert"] + , "main": "./lib/should.js" + , "engines": { "node": ">= 0.2.0" } +} \ No newline at end of file diff --git a/node_modules/mongoose/support/should.js/test/should.test.js b/node_modules/mongoose/support/should.js/test/should.test.js new file mode 100644 index 0000000..4f39f67 --- /dev/null +++ b/node_modules/mongoose/support/should.js/test/should.test.js @@ -0,0 +1,358 @@ + +/** + * Module dependencies. + */ + +var should = require('should'); + +function err(fn, msg) { + try { + fn(); + should.fail('expected an error'); + } catch (err) { + should.equal(msg, err.message); + } +} + +module.exports = { + 'test .version': function(){ + should.version.should.match(/^\d+\.\d+\.\d+$/); + }, + + 'test double require': function(){ + require('should').should.equal(should); + }, + + 'test assertion': function(){ + 'test'.should.be.a.string; + should.equal('foo', 'foo'); + }, + + 'test true': function(){ + true.should.be.true; + false.should.not.be.true; + (1).should.not.be.true; + + err(function(){ + 'test'.should.be.true; + }, "expected 'test' to be true") + }, + + 'test ok': function(){ + true.should.be.ok; + false.should.not.be.ok; + (1).should.be.ok; + (0).should.not.be.ok; + + err(function(){ + ''.should.be.ok; + }, "expected '' to be truthy"); + + err(function(){ + 'test'.should.not.be.ok; + }, "expected 'test' to be falsey"); + }, + + 'test false': function(){ + false.should.be.false; + true.should.not.be.false; + (0).should.not.be.false; + + err(function(){ + ''.should.be.false; + }, "expected '' to be false") + }, + + 'test arguments': function(){ + var args = (function(){ return arguments; })(1,2,3); + args.should.be.arguments; + [].should.not.be.arguments; + }, + + 'test .equal()': function(){ + var foo; + should.equal(undefined, foo); + }, + + 'test typeof': function(){ + 'test'.should.be.a('string'); + + err(function(){ + 'test'.should.not.be.a('string'); + }, "expected 'test' not to be a string"); + + (5).should.be.a('number'); + + err(function(){ + (5).should.not.be.a('number'); + }, "expected 5 not to be a number"); + }, + + 'test instanceof': function(){ + function Foo(){} + new Foo().should.be.an.instanceof(Foo); + + err(function(){ + (3).should.an.instanceof(Foo); + }, "expected 3 to be an instance of Foo"); + }, + + 'test within(start, finish)': function(){ + (5).should.be.within(5, 10); + (5).should.be.within(3,6); + (5).should.be.within(3,5); + (5).should.not.be.within(1,3); + + err(function(){ + (5).should.not.be.within(4,6); + }, "expected 5 to not be within 4..6"); + + err(function(){ + (10).should.be.within(50,100); + }, "expected 10 to be within 50..100"); + }, + + 'test above(n)': function(){ + (5).should.be.above(2); + (5).should.be.greaterThan(2); + (5).should.not.be.above(5); + (5).should.not.be.above(6); + + err(function(){ + (5).should.be.above(6); + }, "expected 5 to be above 6"); + + err(function(){ + (10).should.not.be.above(6); + }, "expected 10 to be below 6"); + }, + + 'test match(regexp)': function(){ + 'foobar'.should.match(/^foo/) + 'foobar'.should.not.match(/^bar/) + + err(function(){ + 'foobar'.should.match(/^bar/i) + }, "expected 'foobar' to match /^bar/i"); + + err(function(){ + 'foobar'.should.not.match(/^foo/i) + }, "expected 'foobar' not to match /^foo/i"); + }, + + 'test length(n)': function(){ + 'test'.should.have.length(4); + 'test'.should.not.have.length(3); + [1,2,3].should.have.length(3); + + err(function(){ + (4).should.have.length(3); + }, 'expected 4 to have a property \'length\''); + + err(function(){ + 'asd'.should.not.have.length(3); + }, "expected 'asd' to not have a length of 3"); + }, + + 'test eql(val)': function(){ + 'test'.should.eql('test'); + ({ foo: 'bar' }).should.eql({ foo: 'bar' }); + (1).should.eql(1); + '4'.should.eql(4); + + err(function(){ + (4).should.eql(3); + }, 'expected 4 to equal 3'); + }, + + 'test equal(val)': function(){ + 'test'.should.equal('test'); + (1).should.equal(1); + + err(function(){ + (4).should.equal(3); + }, 'expected 4 to equal 3'); + + err(function(){ + '4'.should.equal(4); + }, "expected '4' to equal 4"); + }, + + 'test empty': function(){ + ''.should.be.empty; + [].should.be.empty; + ({ length: 0 }).should.be.empty; + + err(function(){ + ({}).should.be.empty; + }, 'expected {} to have a property \'length\''); + + err(function(){ + 'asd'.should.be.empty; + }, "expected 'asd' to be empty"); + + err(function(){ + ''.should.not.be.empty; + }, "expected '' not to be empty"); + }, + + 'test property(name)': function(){ + 'test'.should.have.property('length'); + (4).should.not.have.property('length'); + + err(function(){ + 'asd'.should.have.property('foo'); + }, "expected 'asd' to have a property 'foo'"); + }, + + 'test property(name, val)': function(){ + 'test'.should.have.property('length', 4); + 'asd'.should.have.property('constructor', String); + + err(function(){ + 'asd'.should.have.property('length', 4); + }, "expected 'asd' to have a property 'length' of 4, but got 3"); + + err(function(){ + 'asd'.should.not.have.property('length', 3); + }, "expected 'asd' to not have a property 'length' of 3"); + + err(function(){ + 'asd'.should.not.have.property('foo', 3); + }, "'asd' has no property 'foo'"); + + err(function(){ + 'asd'.should.have.property('constructor', Number); + }, "expected 'asd' to have a property 'constructor' of [Function: Number], but got [Function: String]"); + }, + + 'test ownProperty(name)': function(){ + 'test'.should.have.ownProperty('length'); + 'test'.should.haveOwnProperty('length'); + ({ length: 12 }).should.have.ownProperty('length'); + + err(function(){ + ({ length: 12 }).should.not.have.ownProperty('length'); + }, "expected { length: 12 } to not have own property 'length'"); + }, + + 'test string()': function(){ + 'foobar'.should.include.string('bar'); + 'foobar'.should.include.string('foo'); + 'foobar'.should.not.include.string('baz'); + + err(function(){ + (3).should.include.string('baz'); + }, "expected 3 to be a string"); + + err(function(){ + 'foobar'.should.include.string('baz'); + }, "expected 'foobar' to include 'baz'"); + + err(function(){ + 'foobar'.should.not.include.string('bar'); + }, "expected 'foobar' to not include 'bar'"); + }, + + 'test contain()': function(){ + ['foo', 'bar'].should.contain('foo'); + ['foo', 'bar'].should.contain('foo'); + ['foo', 'bar'].should.contain('bar'); + [1,2].should.contain(1); + ['foo', 'bar'].should.not.contain('baz'); + ['foo', 'bar'].should.not.contain(1); + + err(function(){ + ['foo'].should.contain('bar'); + }, "expected [ 'foo' ] to contain 'bar'"); + + err(function(){ + ['bar', 'foo'].should.not.contain('foo'); + }, "expected [ 'bar', 'foo' ] to not contain 'foo'"); + }, + + 'test keys(array)': function(){ + ({ foo: 1 }).should.have.keys(['foo']); + ({ foo: 1, bar: 2 }).should.have.keys(['foo', 'bar']); + ({ foo: 1, bar: 2 }).should.have.keys('foo', 'bar'); + ({ foo: 1, bar: 2, baz: 3 }).should.include.keys('foo', 'bar'); + ({ foo: 1, bar: 2, baz: 3 }).should.include.keys('bar', 'foo'); + ({ foo: 1, bar: 2, baz: 3 }).should.include.keys('baz'); + + ({ foo: 1, bar: 2 }).should.include.keys('foo'); + ({ foo: 1, bar: 2 }).should.include.keys('bar', 'foo'); + ({ foo: 1, bar: 2 }).should.include.keys(['foo']); + ({ foo: 1, bar: 2 }).should.include.keys(['bar']); + ({ foo: 1, bar: 2 }).should.include.keys(['bar', 'foo']); + + ({ foo: 1, bar: 2 }).should.not.have.keys('baz'); + ({ foo: 1, bar: 2 }).should.not.have.keys('foo', 'baz'); + ({ foo: 1, bar: 2 }).should.not.include.keys('baz'); + ({ foo: 1, bar: 2 }).should.not.include.keys('foo', 'baz'); + ({ foo: 1, bar: 2 }).should.not.include.keys('baz', 'foo'); + + err(function(){ + ({ foo: 1 }).should.have.keys(); + }, "keys required"); + + err(function(){ + ({ foo: 1 }).should.have.keys([]); + }, "keys required"); + + err(function(){ + ({ foo: 1 }).should.not.have.keys([]); + }, "keys required"); + + err(function(){ + ({ foo: 1 }).should.include.keys([]); + }, "keys required"); + + err(function(){ + ({ foo: 1 }).should.have.keys(['bar']); + }, "expected { foo: 1 } to have key 'bar'"); + + err(function(){ + ({ foo: 1 }).should.have.keys(['bar', 'baz']); + }, "expected { foo: 1 } to have keys 'bar', and 'baz'"); + + err(function(){ + ({ foo: 1 }).should.have.keys(['foo', 'bar', 'baz']); + }, "expected { foo: 1 } to have keys 'foo', 'bar', and 'baz'"); + + err(function(){ + ({ foo: 1 }).should.not.have.keys(['foo']); + }, "expected { foo: 1 } to not have key 'foo'"); + + err(function(){ + ({ foo: 1 }).should.not.have.keys(['foo']); + }, "expected { foo: 1 } to not have key 'foo'"); + + err(function(){ + ({ foo: 1, bar: 2 }).should.not.have.keys(['foo', 'bar']); + }, "expected { foo: 1, bar: 2 } to not have keys 'foo', and 'bar'"); + + err(function(){ + ({ foo: 1 }).should.not.include.keys(['foo']); + }, "expected { foo: 1 } to not include key 'foo'"); + + err(function(){ + ({ foo: 1 }).should.include.keys('foo', 'bar'); + }, "expected { foo: 1 } to include keys 'foo', and 'bar'"); + }, + + 'test respondTo(method)': function(){ + 'test'.should.respondTo('toString'); + 'test'.should.not.respondTo('toBuffer'); + }, + + 'test chaining': function(){ + var user = { name: 'tj', pets: ['tobi', 'loki', 'jane', 'bandit'] }; + user.should.have.property('pets').with.lengthOf(4); + + err(function(){ + user.should.have.property('pets').with.lengthOf(5); + }, "expected [ 'tobi', 'loki', 'jane', 'bandit' ] to have a length of 5 but got 4"); + + user.should.be.a('object').and.have.property('name', 'tj'); + } +}; \ No newline at end of file diff --git a/node_modules/mongoose/test/collection.test.js b/node_modules/mongoose/test/collection.test.js new file mode 100644 index 0000000..25b15b6 --- /dev/null +++ b/node_modules/mongoose/test/collection.test.js @@ -0,0 +1,118 @@ + +var start = require('./common') + , mongoose = start.mongoose + , Collection = require('mongoose/collection'); + +module.exports = { + + 'test buffering of commands until connection is established': function(beforeExit){ + var db = mongoose.createConnection() + , collection = db.collection('test-buffering-collection') + , connected = false + , inserted = false; + + collection.insert({ }, function(){ + connected.should.be.true; + inserted = true; + db.close(); + }); + + process.nextTick(function(){ + var uri = 'mongodb://localhost/mongoose_test'; + db.open(process.env.MONGOOSE_TEST_URI || uri, function(err){ + connected = !err; + }); + }); + + beforeExit(function(){ + connected.should.be.true; + inserted.should.be.true; + }); + }, + + 'test methods that should throw (unimplemented)': function () { + var collection = new Collection('test', mongoose.connection) + , thrown = false; + + try { + collection.getIndexes(); + } catch (e) { + /unimplemented/.test(e.message).should.be.true; + thrown = true; + } + + thrown.should.be.true; + thrown = false; + + try { + collection.update(); + } catch (e) { + /unimplemented/.test(e.message).should.be.true; + thrown = true; + } + + thrown.should.be.true; + thrown = false; + + try { + collection.save(); + } catch (e) { + /unimplemented/.test(e.message).should.be.true; + thrown = true; + } + + thrown.should.be.true; + thrown = false; + + try { + collection.insert(); + } catch (e) { + /unimplemented/.test(e.message).should.be.true; + thrown = true; + } + + thrown.should.be.true; + thrown = false; + + try { + collection.find(); + } catch (e) { + /unimplemented/.test(e.message).should.be.true; + thrown = true; + } + + thrown.should.be.true; + thrown = false; + + try { + collection.findOne(); + } catch (e) { + /unimplemented/.test(e.message).should.be.true; + thrown = true; + } + + thrown.should.be.true; + thrown = false; + + try { + collection.findAndModify(); + } catch (e) { + /unimplemented/.test(e.message).should.be.true; + thrown = true; + } + + thrown.should.be.true; + thrown = false; + + try { + collection.ensureIndex(); + } catch (e) { + /unimplemented/.test(e.message).should.be.true; + thrown = true; + } + + thrown.should.be.true; + thrown = false; + } + +}; diff --git a/node_modules/mongoose/test/common.js b/node_modules/mongoose/test/common.js new file mode 100644 index 0000000..5c7b975 --- /dev/null +++ b/node_modules/mongoose/test/common.js @@ -0,0 +1,134 @@ + +/** + * Module dependencies. + */ + +var mongoose = require('../') + , should = require('should') + , Table = require('cli-table') + , Mongoose = mongoose.Mongoose + , Collection = mongoose.Collection + , Assertion = should.Assertion + , startTime = Date.now() + , queryCount = 0 + , opened = 0 + , closed = 0; + +/** + * Override all Collection related queries to keep count + */ + +[ 'ensureIndex' + , 'findAndModify' + , 'findOne' + , 'find' + , 'insert' + , 'save' + , 'update' +].forEach(function (method) { + + var oldMethod = Collection.prototype[method]; + + Collection.prototype[method] = function () { + queryCount++; + return oldMethod.apply(this, arguments); + }; + +}); + +/** + * Override Collection#onOpen to keep track of connections + */ + +var oldOnOpen = Collection.prototype.onOpen; + +Collection.prototype.onOpen = function(){ + opened++; + return oldOnOpen.apply(this, arguments); +}; + +/** + * Override Collection#onClose to keep track of disconnections + */ + +var oldOnClose = Collection.prototype.onClose; + +Collection.prototype.onClose = function(){ + closed++; + return oldOnClose.apply(this, arguments); +}; + +/** + * Assert that a connection is open or that mongoose connections are open. + * Examples: + * mongoose.should.be.connected; + * db.should.be.connected; + * + * @api public + */ + +Assertion.prototype.__defineGetter__('connected', function(){ + if (this.obj instanceof Mongoose) + this.obj.connections.forEach(function(connected){ + c.should.be.connected; + }); + else + this.obj.readyState.should.eql(1); +}); + +/** + * Assert that a connection is closed or that a mongoose connections are closed. + * Examples: + * mongoose.should.be.disconnected; + * db.should.be.disconnected; + * + * @api public + */ + +Assertion.prototype.__defineGetter__('disconnected', function(){ + if (this.obj instanceof Mongoose) + this.obj.connections.forEach(function(){ + c.should.be.disconnected; + }); + else + this.obj.readyState.should.eql(0); +}); + +/** + * Create a connection to the test database. + * You can set the environmental variable MONGOOSE_TEST_URI to override this. + * + * @api private + */ + +module.exports = function(){ + return mongoose.createConnection( + process.env.MONGOOSE_TEST_URI || 'mongodb://localhost/mongoose_test' + ); +}; + +/** + * Provide stats for tests + */ + +process.on('beforeExit', function(){ + var table = new Table({ + head: ['Stat', 'Time (ms)'] + , colWidths: [23, 15] + }); + + table.push( + ['Queries run', queryCount] + , ['Time ellapsed', Date.now() - startTime] + , ['Connections opened', opened] + , ['Connections closed', closed] + ); + + console.log(table.toString()); +}); + +/** + * Module exports. + */ + +module.exports.mongoose = mongoose; diff --git a/node_modules/mongoose/test/connection.test.js b/node_modules/mongoose/test/connection.test.js new file mode 100644 index 0000000..5beea3d --- /dev/null +++ b/node_modules/mongoose/test/connection.test.js @@ -0,0 +1,46 @@ + +/** + * Module dependencies. + */ + +var start = require('./common') + , should = require('should') + , mongoose = start.mongoose + , Schema = mongoose.Schema + +/** + * Test. + */ + +module.exports = { + + 'test closing a connection that\'s already closed': function (beforeExit) { + var db = mongoose.createConnection() + , called = false; + + db.readyState.should.eql(0); + db.close(function (err) { + should.strictEqual(err, null); + called = true; + }); + + beforeExit(function () { + called.should.be.true; + }); + }, + + 'connection.model allows passing a schema': function () { + var db = start(); + var MyModel = db.model('MyModelasdf', new Schema({ + name: String + })); + + MyModel.schema.should.be.an.instanceof(Schema); + MyModel.prototype.schema.should.be.an.instanceof(Schema); + + var m = new MyModel({name:'aaron'}); + m.name.should.eql('aaron'); + db.close(); + } + +}; diff --git a/node_modules/mongoose/test/crash.test.js b/node_modules/mongoose/test/crash.test.js new file mode 100644 index 0000000..67e6c86 --- /dev/null +++ b/node_modules/mongoose/test/crash.test.js @@ -0,0 +1,36 @@ + +// GH-407 + +var start = require('./common') + , mongoose = start.mongoose + , should = require('should') + +exports['test mongodb crash with invalid objectid string'] = function () { + var db = mongoose.createConnection("mongodb://localhost/test-crash"); + + var IndexedGuy = new mongoose.Schema({ + name: { type: String } + }); + + var Guy = db.model('Guy', IndexedGuy); + Guy.find({ + _id: { + $in: [ + '4e0de2a6ee47bff98000e145', + '4e137bd81a6a8e00000007ac', + '', + '4e0e2ca0795666368603d974'] + } + }, function (err) { + db.close(); + + // should is acting strange + try { + should.strictEqual(err.message, "Invalid ObjectId"); + } catch (er) { + console.error(err); + throw er; + } + }); + +} diff --git a/node_modules/mongoose/test/document.test.js b/node_modules/mongoose/test/document.test.js new file mode 100644 index 0000000..e83e74b --- /dev/null +++ b/node_modules/mongoose/test/document.test.js @@ -0,0 +1,472 @@ + +/** + * Module dependencies. + */ + +var start = require('./common') + , should = require('should') + , mongoose = start.mongoose + , Schema = mongoose.Schema + , ObjectId = Schema.ObjectId + , Document = require('mongoose/document') + , DocumentObjectId = mongoose.Types.ObjectId; + +/** + * Test Document constructor. + */ + +function TestDocument () { + Document.apply(this, arguments); +}; + +/** + * Inherits from Document. + */ + +TestDocument.prototype.__proto__ = Document.prototype; + +/** + * Set a dummy schema to simulate compilation. + */ + +TestDocument.prototype.schema = new Schema({ + test : String + , oids : [ObjectId] + , nested : { + age : Number + , cool : ObjectId + } +}); + +/** + * Method subject to hooks. Simply fires the callback once the hooks are + * executed. + */ + +TestDocument.prototype.hooksTest = function(fn){ + fn(null, arguments); +}; + +/** + * Test. + */ + +module.exports = { + 'test shortcut getters': function(){ + var doc = new TestDocument(); + doc.init({ + test : 'test' + , oids : [] + , nested : { + age : 5 + , cool : DocumentObjectId.fromString('4c6c2d6240ced95d0e00003c') + } + }); + + var doc2 = new TestDocument(); + doc2.init({ + test : 'toop' + , oids : [] + , nested : { + age : 2 + , cool : DocumentObjectId.fromString('4cf70857337498f95900001c') + } + }); + + doc.test.should.eql('test'); + doc.oids.should.be.an.instanceof(Array); + (doc.nested.age == 5).should.be.true; + DocumentObjectId.toString(doc.nested.cool).should.eql('4c6c2d6240ced95d0e00003c'); + + doc2.test.should.eql('toop'); + doc2.oids.should.be.an.instanceof(Array); + (doc2.nested.age == 2).should.be.true; + + // GH-366 + should.strictEqual(doc2.nested.nested, undefined); + should.strictEqual(doc2.nested.test, undefined); + + DocumentObjectId.toString(doc2.nested.cool).should.eql('4cf70857337498f95900001c'); + + doc.oids.should.not.equal(doc2.oids); + }, + + 'test shortcut setters': function () { + var doc = new TestDocument(); + + doc.init({ + test : 'Test' + , nested : { + age : 5 + } + }); + + doc.isModified('test').should.be.false; + doc.test = 'Woot'; + doc.test.should.eql('Woot'); + doc.isModified('test').should.be.true; + + doc.isModified('nested.age').should.be.false; + doc.nested.age = 2; + (doc.nested.age == 2).should.be.true; + doc.isModified('nested.age').should.be.true; + }, + + 'test accessor of id': function () { + var doc = new TestDocument(); + doc._id.should.be.an.instanceof(DocumentObjectId); + }, + + 'test shortcut of id hexString': function () { + var doc = new TestDocument() + , _id = doc._id.toString(); + doc.id.should.be.a('string'); + }, + + 'test toObject clone': function(){ + var doc = new TestDocument(); + doc.init({ + test : 'test' + , oids : [] + , nested : { + age : 5 + , cool : new DocumentObjectId + } + }); + + var copy = doc.toObject(); + + copy.test._marked = true; + copy.nested._marked = true; + copy.nested.age._marked = true; + copy.nested.cool._marked = true; + + should.strictEqual(doc.doc.test._marked, undefined); + should.strictEqual(doc.doc.nested._marked, undefined); + should.strictEqual(doc.doc.nested.age._marked, undefined); + should.strictEqual(doc.doc.nested.cool._marked, undefined); + }, + + 'test hooks system': function(beforeExit){ + var doc = new TestDocument() + , steps = 0 + , awaiting = 0 + , called = false; + + // serial + doc.pre('hooksTest', function(next){ + steps++; + setTimeout(function(){ + // make sure next step hasn't executed yet + steps.should.eql(1); + next(); + }, 50); + }); + + doc.pre('hooksTest', function(next){ + steps++; + next(); + }); + + // parallel + doc.pre('hooksTest', true, function(next, done){ + steps++; + setTimeout(function(){ + steps.should.eql(4); + }, 50); + setTimeout(function(){ + steps++; + done(); + }, 100); + next(); + }); + + doc.pre('hooksTest', true, function(next, done){ + steps++; + setTimeout(function(){ + steps.should.eql(4); + }, 50); + setTimeout(function(){ + steps++; + done(); + }, 100); + next(); + }); + + doc.hooksTest(function(err){ + should.strictEqual(err, null); + steps++; + called = true; + }); + + beforeExit(function(){ + steps.should.eql(7); + called.should.be.true; + }); + }, + + 'test that calling next twice doesnt break': function(beforeExit){ + var doc = new TestDocument() + , steps = 0 + , called = false; + + doc.pre('hooksTest', function(next){ + steps++; + next(); + next(); + }); + + doc.pre('hooksTest', function(next){ + steps++; + next(); + }); + + doc.hooksTest(function(err){ + should.strictEqual(err, null); + steps++; + called = true; + }); + + beforeExit(function(){ + steps.should.eql(3); + called.should.be.true; + }); + }, + + 'test that calling done twice doesnt break': function(beforeExit){ + var doc = new TestDocument() + , steps = 0 + , called = false; + + doc.pre('hooksTest', true, function(next, done){ + steps++; + next(); + done(); + done(); + }); + + doc.pre('hooksTest', true, function(next, done){ + steps++; + next(); + done(); + done(); + }); + + doc.hooksTest(function(err){ + should.strictEqual(err, null); + steps++; + called = true; + }); + + beforeExit(function(){ + steps.should.eql(3); + called.should.be.true; + }); + }, + + 'test that calling done twice on the same doesnt mean completion': + function(beforeExit){ + var doc = new TestDocument() + , steps = 0 + , called = false; + + doc.pre('hooksTest', true, function(next, done){ + steps++; + next(); + done(); + done(); + }); + + doc.pre('hooksTest', true, function(next, done){ + steps++; + next(); + }); + + doc.hooksTest(function(err){ + should.strictEqual(err, null); + called = true; + }); + + beforeExit(function(){ + steps.should.eql(2); + called.should.be.false; + }); + }, + + 'test hooks system errors from a serial hook': function(beforeExit){ + var doc = new TestDocument() + , steps = 0 + , called = false; + + doc.pre('hooksTest', function(next){ + steps++; + next(); + }); + + doc.pre('hooksTest', function(next){ + steps++; + next(new Error); + }); + + doc.pre('hooksTest', function(next){ + steps++; + }); + + doc.hooksTest(function(err){ + err.should.be.an.instanceof(Error); + steps++; + called = true; + }); + + beforeExit(function(){ + steps.should.eql(3); + called.should.be.true; + }); + }, + + 'test hooks system erros from last serial hook': function(beforeExit){ + var doc = new TestDocument() + , called = false; + + doc.pre('hooksTest', function(next){ + next(new Error()); + }); + + doc.hooksTest(function(err){ + err.should.be.an.instanceof(Error); + called = true; + }); + + beforeExit(function(){ + called.should.be.true; + }); + }, + + 'test mutating incoming args via middleware': function (beforeExit) { + var doc = new TestDocument(); + + doc.pre('set', function(next, path, val){ + next(path, 'altered-' + val); + }); + + doc.set('test', 'me'); + + beforeExit(function(){ + doc.test.should.equal('altered-me'); + }); + }, + + 'test hooks system errors from a parallel hook': function(beforeExit){ + var doc = new TestDocument() + , steps = 0 + , called = false; + + doc.pre('hooksTest', true, function(next, done){ + steps++; + next(); + done(); + }); + + doc.pre('hooksTest', true, function(next, done){ + steps++; + next(); + done(); + }); + + doc.pre('hooksTest', true, function(next, done){ + steps++; + next(); + done(new Error); + }); + + doc.hooksTest(function(err){ + err.should.be.an.instanceof(Error); + steps++; + called = true; + }); + + beforeExit(function(){ + steps.should.eql(4); + called.should.be.true; + }); + }, + + 'test that its not necessary to call the last next in the parallel chain': + function(beforeExit){ + var doc = new TestDocument() + , steps = 0 + , called = false; + + doc.pre('hooksTest', function(next, done){ + next(); + done(); + }); + + doc.pre('hooksTest', function(next, done){ + done(); + }); + + doc.hooksTest(function(){ + called = true; + }); + + beforeExit(function(){ + called.should.be.true; + }); + }, + + 'test passing two arguments to a method subject to hooks and return value': + function (beforeExit) { + var doc = new TestDocument() + , called = false; + + doc.pre('hooksTest', function (next) { + next(); + }); + + doc.hooksTest(function (err, args) { + args.should.have.length(2); + args[1].should.eql('test'); + called = true; + }, 'test') + + beforeExit(function () { + called.should.be.true; + }); + }, + + 'test jsonifying an object': function () { + var doc = new TestDocument({ test: 'woot' }) + , oidString = DocumentObjectId.toString(doc._id); + + // convert to json string + var json = JSON.stringify(doc); + + // parse again + var obj = JSON.parse(json); + + obj.test.should.eql('woot'); + obj._id.should.eql(oidString); + }, + + 'toObject should not set undefined values to null': function () { + var doc = new TestDocument() + , obj = doc.toObject(); + + delete obj._id; + obj.should.eql({ oids: [] }); + }, + + // GH-209 + 'MongooseErrors should be instances of Error': function () { + var MongooseError = require('../lib/mongoose/error') + , err = new MongooseError("Some message"); + err.should.be.an.instanceof(Error); + }, + 'ValidationErrors should be instances of Error': function () { + var ValidationError = Document.ValidationError + , err = new ValidationError(new TestDocument); + err.should.be.an.instanceof(Error); + } + +}; diff --git a/node_modules/mongoose/test/drivers/node-mongodb-native/collection.test.js b/node_modules/mongoose/test/drivers/node-mongodb-native/collection.test.js new file mode 100644 index 0000000..2ae5a4b --- /dev/null +++ b/node_modules/mongoose/test/drivers/node-mongodb-native/collection.test.js @@ -0,0 +1,64 @@ + +/** + * Module dependencies. + */ + +var start = require('../../common') + , mongoose = start.mongoose + , should = require('should') + , Schema = mongoose.Schema; + +/** + * Setup. + */ + +mongoose.model('NativeDriverTest', new Schema({ + title: String +})); + +/** + * Test. + */ + +module.exports = { + + 'test that trying to implement a sparse index works': function () { + var db = start() + , NativeTestCollection = db.model('NativeDriverTest'); + + NativeTestCollection.collection.ensureIndex({ title: 1 }, { sparse: true }, function (err) { + should.strictEqual(!!err, false); + NativeTestCollection.collection.getIndexes(function (err, indexes) { + db.close(); + should.strictEqual(!!err, false); + indexes.should.be.instanceof(Object); + indexes['title_1'].should.eql([['title', 1]]); + }); + }); + }, + + 'test that the -native traditional ensureIndex spec syntax for fields works': function () { + var db = start() + , NativeTestCollection = db.model('NativeDriverTest'); + + NativeTestCollection.collection.ensureIndex([['a', 1]], function () { + db.close(); + }); + }, + + 'unique index fails passes error': function () { + var db = start() + , schema = new Schema({ title: String }) + , NativeTestCollection = db.model('NativeDriverTestUnique', schema) + + NativeTestCollection.create({ title: 'x' }, {title:'x'}, function (err) { + should.strictEqual(!!err, false); + + NativeTestCollection.collection.ensureIndex({ title: 1 }, { unique: true }, function (err) { + ;/E11000 duplicate key error index/.test(err.message).should.equal(true); + + db.close(); + }); + }); + } +}; diff --git a/node_modules/mongoose/test/index.test.js b/node_modules/mongoose/test/index.test.js new file mode 100644 index 0000000..0cdba0d --- /dev/null +++ b/node_modules/mongoose/test/index.test.js @@ -0,0 +1,235 @@ + +var url = require('url') + , start = require('./common') + , should = require('should') + , mongoose = start.mongoose + , Mongoose = mongoose.Mongoose + , Schema = mongoose.Schema; + +module.exports = { + + 'test connecting to the demo database': function(beforeExit){ + var db = start() + , connected = false; + + db.on('open', function(){ + connected = true; + db.close(); + }); + + beforeExit(function(){ + connected.should.be.true; + }); + }, + + 'test default connection': function(beforeExit){ + var db = mongoose.connection + , uri = 'mongodb://localhost/mongoose_test' + , connected = false; + + mongoose.connect(process.env.MONGOOSE_TEST_URI || uri); + db.on('open', function(){ + connected = true; + db.close(); + }); + + beforeExit(function(){ + connected.should.be.true; + }); + }, + + 'test setting options': function(){ + var mongoose = new Mongoose(); + + mongoose.set('a', 'b'); + mongoose.set('long option', 'c'); + + mongoose.get('a').should.eql('b'); + mongoose.set('a').should.eql('b'); + mongoose.get('long option').should.eql('c'); + }, + + 'test declaring global plugins': function (beforeExit) { + var mong = new Mongoose() + , schema = new Schema() + , called = 0; + + mong.plugin(function (s) { + s.should.equal(schema); + called++; + }); + + schema.plugin(function (s) { + s.should.equal(schema); + called++; + }); + + mong.model('GlobalPlugins', schema); + + beforeExit(function () { + called.should.eql(2); + }); + }, + + 'test disconnection of all connections': function (beforeExit) { + var mong = new Mongoose() + , uri = 'mongodb://localhost/mongoose_test' + , connections = 0 + , disconnections = 0; + + mong.connect(process.env.MONGOOSE_TEST_URI || uri); + var db = mong.connection; + + db.on('open', function(){ + connections++; + }); + + db.on('close', function () { + disconnections++; + }); + + var db2 = mong.createConnection(process.env.MONGOOSE_TEST_URI || uri); + + db2.on('open', function () { + connections++; + }); + + db2.on('close', function () { + disconnections++; + }); + + mong.disconnect(); + + beforeExit(function () { + connections.should.eql(2); + disconnections.should.eql(2); + }); + }, + + 'test disconnection of all connections callback': function (beforeExit) { + var mong = new Mongoose() + , uri = 'mongodb://localhost/mongoose_test' + , called = false; + + mong.connect(process.env.MONGOOSE_TEST_URI || uri); + + mong.connection.on('open', function () { + mong.disconnect(function () { + called = true; + }); + }); + + beforeExit(function () { + called.should.be.true; + }); + }, + + 'try accessing a model that hasn\'t been defined': function () { + var mong = new Mongoose() + , thrown = false; + + try { + mong.model('Test'); + } catch (e) { + /hasn't been registered/.test(e.message).should.be.true; + thrown = true; + } + + thrown.should.be.true; + }, + + 'test connecting with a signature of host, database, function': function (){ + var mong = new Mongoose() + , uri = process.env.MONGOOSE_TEST_URI || 'mongodb://localhost/mongoose_test'; + + uri = url.parse(uri); + + mong.connect(uri.hostname, uri.pathname.substr(1), function (err) { + should.strictEqual(err, null); + mong.connection.close(); + }); + }, + + 'test connecting to a replica set': function () { + var uri = process.env.MONGOOSE_SET_TEST_URI; + + if (!uri) { + console.log('\033[31m', '\n', 'You\'re not testing for replica sets!' + , '\n', 'Please set the MONGOOSE_SET_TEST_URI env variable.', '\n' + , 'e.g: `mongodb://localhost:27017/db,mongodb://localhost…`', '\n' + , '\033[39m'); + return; + } + + var mong = new Mongoose(); + + mong.connectSet(uri, function (err) { + should.strictEqual(err, null); + + mong.model('Test', new mongoose.Schema({ + test: String + })); + + var Test = mong.model('Test') + , test = new Test(); + + test.test = 'aa'; + test.save(function (err) { + should.strictEqual(err, null); + + Test.findById(test._id, function (err, doc) { + should.strictEqual(err, null); + + doc.test.should.eql('aa'); + + mong.connection.close(); + }); + }); + }); + }, + + 'test initializing a new Connection to a replica set': function () { + var uri = process.env.MONGOOSE_SET_TEST_URI; + + if (!uri) return; + + var mong = new Mongoose(true); + + var conn = mong.createSetConnection(uri, function (err) { + should.strictEqual(err, null); + + mong.model('ReplSetTwo', new mongoose.Schema({ + test: String + })); + + var Test = conn.model('ReplSetTwo') + , test = new Test(); + + test.test = 'aa'; + test.save(function (err) { + should.strictEqual(err, null); + + Test.findById(test._id, function (err, doc) { + should.strictEqual(err, null); + + doc.test.should.eql('aa'); + + conn.close(); + }); + }); + }); + }, + + 'test public exports': function () { + mongoose.version.should.be.a('string'); + mongoose.Collection.should.be.a('function'); + mongoose.Connection.should.be.a('function'); + mongoose.Schema.should.be.a('function'); + mongoose.SchemaType.should.be.a('function'); + mongoose.Query.should.be.a('function'); + mongoose.Promise.should.be.a('function'); + mongoose.Model.should.be.a('function'); + mongoose.Document.should.be.a('function'); + } + +}; diff --git a/node_modules/mongoose/test/model.querying.test.js b/node_modules/mongoose/test/model.querying.test.js new file mode 100644 index 0000000..2adb9ba --- /dev/null +++ b/node_modules/mongoose/test/model.querying.test.js @@ -0,0 +1,1415 @@ + +/** + * Test dependencies. + */ + +var start = require('./common') + , should = require('should') + , mongoose = start.mongoose + , random = require('mongoose/utils').random + , Query = require('mongoose/query') + , Schema = mongoose.Schema + , SchemaType = mongoose.SchemaType + , CastError = SchemaType.CastError + , ObjectId = Schema.ObjectId + , DocumentObjectId = mongoose.Types.ObjectId; + +/** + * Setup. + */ + +var Comments = new Schema(); + +Comments.add({ + title : String + , date : Date + , body : String + , comments : [Comments] +}); + +var BlogPostB = new Schema({ + title : String + , author : String + , slug : String + , date : Date + , meta : { + date : Date + , visitors : Number + } + , published : Boolean + , mixed : {} + , numbers : [Number] + , tags : [String] + , owners : [ObjectId] + , comments : [Comments] +}); + +mongoose.model('BlogPostB', BlogPostB); +var collection = 'blogposts_' + random(); + +var ModSchema = new Schema({ + num: Number +}); +mongoose.model('Mod', ModSchema); + +var geoSchema = new Schema({ loc: { type: [Number], index: '2d'}}); + +module.exports = { + + 'test that find returns a Query': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + // query + BlogPostB.find({}).should.be.an.instanceof(Query); + + // query, fields + BlogPostB.find({}, {}).should.be.an.instanceof(Query); + + // query, fields (array) + BlogPostB.find({}, []).should.be.an.instanceof(Query); + + // query, fields, options + BlogPostB.find({}, {}, {}).should.be.an.instanceof(Query); + + // query, fields (array), options + BlogPostB.find({}, [], {}).should.be.an.instanceof(Query); + + db.close(); + }, + + 'test that findOne returns a Query': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + // query + BlogPostB.findOne({}).should.be.an.instanceof(Query); + + // query, fields + BlogPostB.findOne({}, {}).should.be.an.instanceof(Query); + + // query, fields (array) + BlogPostB.findOne({}, []).should.be.an.instanceof(Query); + + // query, fields, options + BlogPostB.findOne({}, {}, {}).should.be.an.instanceof(Query); + + // query, fields (array), options + BlogPostB.findOne({}, [], {}).should.be.an.instanceof(Query); + + db.close(); + }, + + 'test that an empty find does not hang': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + + function fn () { + db.close(); + }; + + BlogPostB.find({}, fn); + }, + + 'test that a query is executed when a callback is passed': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , count = 5 + , q = { _id: new DocumentObjectId }; // make sure the query is fast + + function fn () { + --count || db.close(); + }; + + // query + BlogPostB.find(q, fn).should.be.an.instanceof(Query); + + // query, fields + BlogPostB.find(q, {}, fn).should.be.an.instanceof(Query); + + // query, fields (array) + BlogPostB.find(q, [], fn).should.be.an.instanceof(Query); + + // query, fields, options + BlogPostB.find(q, {}, {}, fn).should.be.an.instanceof(Query); + + // query, fields (array), options + BlogPostB.find(q, [], {}, fn).should.be.an.instanceof(Query); + }, + + 'test that query is executed where a callback for findOne': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , count = 5 + , q = { _id: new DocumentObjectId }; // make sure the query is fast + + function fn () { + --count || db.close(); + }; + + // query + BlogPostB.findOne(q, fn).should.be.an.instanceof(Query); + + // query, fields + BlogPostB.findOne(q, {}, fn).should.be.an.instanceof(Query); + + // query, fields (array) + BlogPostB.findOne(q, [], fn).should.be.an.instanceof(Query); + + // query, fields, options + BlogPostB.findOne(q, {}, {}, fn).should.be.an.instanceof(Query); + + // query, fields (array), options + BlogPostB.findOne(q, [], {}, fn).should.be.an.instanceof(Query); + }, + + 'test that count returns a Query': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.count({}).should.be.an.instanceof(Query); + + db.close(); + }, + + 'test that count Query executes when you pass a callback': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + function fn () { + db.close(); + }; + + BlogPostB.count({}, fn).should.be.an.instanceof(Query); + }, + + 'test that distinct returns a Query': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.distinct('title', {}).should.be.an.instanceof(Query); + + db.close(); + }, + + 'test that distinct Query executes when you pass a callback': function () { + var db = start(); + var Address = new Schema({ zip: String }); + Address = db.model('Address', Address, 'addresses_' + random()); + + Address.create({ zip: '10010'}, { zip: '10010'}, { zip: '99701'}, function (err, a1, a2, a3) { + should.strictEqual(null, err); + var query = Address.distinct('zip', {}, function (err, results) { + should.strictEqual(null, err); + results.should.eql(['10010', '99701']); + db.close(); + }); + query.should.be.an.instanceof(Query); + }); + }, + + + 'test that update returns a Query': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.update({}, {}).should.be.an.instanceof(Query); + BlogPostB.update({}, {}, {}).should.be.an.instanceof(Query); + + db.close(); + }, + + 'test that update Query executes when you pass a callback': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , count = 2; + + function fn () { + --count || db.close(); + }; + + BlogPostB.update({title: random()}, {}, fn).should.be.an.instanceof(Query); + + BlogPostB.update({title: random()}, {}, {}, fn).should.be.an.instanceof(Query); + }, + + 'test finding a document': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , title = 'Wooooot ' + random(); + + var post = new BlogPostB(); + post.set('title', title); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.findOne({ title: title }, function (err, doc) { + should.strictEqual(err, null); + doc.get('title').should.eql(title); + doc.isNew.should.be.false; + + db.close(); + }); + }); + }, + + 'test finding a document byId': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , title = 'Edwald ' + random(); + + var post = new BlogPostB(); + post.set('title', title); + + post.save(function (err) { + should.strictEqual(err, null); + + var pending = 2; + + BlogPostB.findById(post.get('_id'), function (err, doc) { + should.strictEqual(err, null); + doc.should.be.an.instanceof(BlogPostB); + doc.get('title').should.eql(title); + --pending || db.close(); + }); + + BlogPostB.findById(post.get('_id').toHexString(), function (err, doc) { + should.strictEqual(err, null); + doc.should.be.an.instanceof(BlogPostB); + doc.get('title').should.eql(title); + --pending || db.close(); + }); + }); + }, + + 'test finding documents': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , title = 'Wooooot ' + random(); + + var post = new BlogPostB(); + post.set('title', title); + + post.save(function (err) { + should.strictEqual(err, null); + + var post = new BlogPostB(); + post.set('title', title); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.find({ title: title }, function (err, docs) { + should.strictEqual(err, null); + docs.should.have.length(2); + + docs[0].get('title').should.eql(title); + docs[0].isNew.should.be.false; + + docs[1].get('title').should.eql(title); + docs[1].isNew.should.be.false; + + db.close(); + }); + }); + }); + }, + + 'test finding documents where an array that contains one specific member': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + BlogPostB.create({numbers: [100, 101, 102]}, function (err, created) { + should.strictEqual(err, null); + BlogPostB.find({numbers: 100}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(1); + found[0]._id.should.eql(created._id); + db.close(); + }); + }); + }, + + 'test counting documents': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , title = 'Wooooot ' + random(); + + var post = new BlogPostB(); + post.set('title', title); + + post.save(function (err) { + should.strictEqual(err, null); + + var post = new BlogPostB(); + post.set('title', title); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.count({ title: title }, function (err, count) { + should.strictEqual(err, null); + + count.should.be.a('number'); + count.should.eql(2); + + db.close(); + }); + }); + }); + }, + + 'test query casting': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , title = 'Loki ' + random(); + + var post = new BlogPostB() + , id = DocumentObjectId.toString(post.get('_id')); + + post.set('title', title); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.findOne({ _id: id }, function (err, doc) { + should.strictEqual(err, null); + + doc.get('title').should.equal(title); + db.close(); + }); + }); + }, + + 'test a query that includes a casting error': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.find({ date: 'invalid date' }, function (err) { + err.should.be.an.instanceof(Error); + err.should.be.an.instanceof(CastError); + db.close(); + }); + }, + + 'test findOne queries that require casting for $modifiers': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , post = new BlogPostB({ + meta: { + visitors: -10 + } + }); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.findOne({ 'meta.visitors': { $gt: '-20', $lt: -1 } }, + function (err, found) { + found.get('meta.visitors') + .valueOf().should.equal(post.get('meta.visitors').valueOf()); + found.get('_id').should.eql(post.get('_id')); + db.close(); + }); + }); + }, + + 'test find queries that require casting for $modifiers': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , post = new BlogPostB({ + meta: { + visitors: -75 + } + }); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.find({ 'meta.visitors': { $gt: '-100', $lt: -50 } }, + function (err, found) { + should.strictEqual(err, null); + + found.should.have.length(1); + found[0].get('_id').should.eql(post.get('_id')); + found[0].get('meta.visitors').valueOf() + .should.equal(post.get('meta.visitors').valueOf()); + db.close(); + }); + }); + }, + + // GH-199 + 'test find queries where $in cast the values wherein the array': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + var post = new BlogPostB() + , id = DocumentObjectId.toString(post._id); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.findOne({ _id: { $in: [id] } }, function (err, doc) { + should.strictEqual(err, null); + + DocumentObjectId.toString(doc._id).should.eql(id); + db.close(); + }); + }); + }, + + // GH-232 + 'test find queries where $nin cast the values wherein the array': function () { + var db = start() + , NinSchema = new Schema({ + num: Number + }); + mongoose.model('Nin', NinSchema); + var Nin = db.model('Nin', 'nins_' + random()); + Nin.create({ num: 1 }, function (err, one) { + should.strictEqual(err, null); + Nin.create({ num: 2 }, function (err, two) { + should.strictEqual(err, null); + Nin.create({num: 3}, function (err, three) { + should.strictEqual(err, null); + Nin.find({ num: {$nin: [2]}}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + db.close(); + }); + }); + }); + }); + }, + + 'test find queries with $ne with single value against array': function () { + var db = start(); + var schema = new Schema({ + ids: [Schema.ObjectId] + , b: Schema.ObjectId + }); + + var NE = db.model('NE_Test', schema, 'nes__' + random()); + + var id1 = new DocumentObjectId; + var id2 = new DocumentObjectId; + var id3 = new DocumentObjectId; + var id4 = new DocumentObjectId; + + NE.create({ ids: [id1, id4], b: id3 }, function (err, ne1) { + should.strictEqual(err, null); + NE.create({ ids: [id2, id4], b: id3 },function (err, ne2) { + should.strictEqual(err, null); + + var query = NE.find({ 'b': id3.toString(), 'ids': { $ne: id1 }}); + query.run(function (err, nes1) { + should.strictEqual(err, null); + nes1.length.should.eql(1); + + NE.find({ b: { $ne: [1] }}, function (err, nes2) { + err.message.should.eql("Invalid ObjectId"); + + NE.find({ b: { $ne: 4 }}, function (err, nes3) { + err.message.should.eql("Invalid ObjectId"); + + NE.find({ b: id3, ids: { $ne: id4 }}, function (err, nes4) { + db.close(); + should.strictEqual(err, null); + nes4.length.should.eql(0); + }); + }); + }); + }); + + }); + }); + + }, + + 'test for findById where partial initialization': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , queries = 5; + + var post = new BlogPostB(); + + post.title = 'hahaha'; + post.slug = 'woot'; + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.findById(post.get('_id'), function (err, doc) { + should.strictEqual(err, null); + doc.isInit('title').should.be.true; + doc.isInit('slug').should.be.true; + doc.isInit('date').should.be.false; + --queries || db.close(); + }); + + BlogPostB.findById(post.get('_id'), ['title'], function (err, doc) { + should.strictEqual(err, null); + doc.isInit('title').should.be.true; + doc.isInit('slug').should.be.false; + doc.isInit('date').should.be.false; + --queries || db.close(); + }); + + BlogPostB.findById(post.get('_id'), { slug: 0 }, function (err, doc) { + should.strictEqual(err, null); + doc.isInit('title').should.be.true; + doc.isInit('slug').should.be.false; + doc.isInit('date').should.be.false; + --queries || db.close(); + }); + + BlogPostB.findById(post.get('_id'), ['title'], function (err, doc) { + should.strictEqual(err, null); + doc.isInit('title').should.be.true; + doc.isInit('slug').should.be.false; + doc.isInit('date').should.be.false; + --queries || db.close(); + }); + + BlogPostB.findById(post.get('_id'), ['slug'], function (err, doc) { + should.strictEqual(err, null); + doc.isInit('title').should.be.false; + doc.isInit('slug').should.be.true; + doc.isInit('date').should.be.false; + --queries || db.close(); + }); + }); + }, + + 'test findOne where subset of fields, excluding _id': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + BlogPostB.create({title: 'subset 1'}, function (err, created) { + should.strictEqual(err, null); + BlogPostB.findOne({title: 'subset 1'}, {title: 1, _id: 0}, function (err, found) { + should.strictEqual(err, null); + should.strictEqual(undefined, found._id); + found.title.should.equal('subset 1'); + db.close(); + }); + }); + }, + + 'test find where subset of fields, excluding _id': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + BlogPostB.create({title: 'subset 1'}, function (err, created) { + should.strictEqual(err, null); + BlogPostB.find({title: 'subset 1'}, {title: 1, _id: 0}, function (err, found) { + should.strictEqual(err, null); + should.strictEqual(undefined, found[0]._id); + found[0].title.should.equal('subset 1'); + db.close(); + }); + }); + }, + + 'exluded fields that are not objects or arrays in the schema should be undefined': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + BlogPostB.create({title: 'subset 1'}, function (err, created) { + should.strictEqual(err, null); + BlogPostB.findById(created.id, {title: 0}, function (err, found) { + should.strictEqual(err, null); + found._id.should.eql(created._id); + should.strictEqual(undefined, found.title); + db.close(); + }); + }); + }, + + 'test for find where partial initialization': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , queries = 5; + + var post = new BlogPostB(); + + post.title = 'hahaha'; + post.slug = 'woot'; + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.find({ _id: post.get('_id') }, function (err, docs) { + should.strictEqual(err, null); + docs[0].isInit('title').should.be.true; + docs[0].isInit('slug').should.be.true; + docs[0].isInit('date').should.be.false; + --queries || db.close(); + }); + + BlogPostB.find({ _id: post.get('_id') }, ['title'], function (err, docs) { + should.strictEqual(err, null); + docs[0].isInit('title').should.be.true; + docs[0].isInit('slug').should.be.false; + docs[0].isInit('date').should.be.false; + --queries || db.close(); + }); + + BlogPostB.find({ _id: post.get('_id') }, { slug: 0 }, function (err, docs) { + should.strictEqual(err, null); + docs[0].isInit('title').should.be.true; + docs[0].isInit('slug').should.be.false; + docs[0].isInit('date').should.be.false; + --queries || db.close(); + }); + + BlogPostB.find({ _id: post.get('_id') }, ['title'], function (err, docs) { + should.strictEqual(err, null); + docs[0].isInit('title').should.be.true; + docs[0].isInit('slug').should.be.false; + docs[0].isInit('date').should.be.false; + --queries || db.close(); + }); + + BlogPostB.find({ _id: post.get('_id') }, ['slug'], function (err, docs) { + should.strictEqual(err, null); + docs[0].isInit('title').should.be.false; + docs[0].isInit('slug').should.be.true; + docs[0].isInit('date').should.be.false; + --queries || db.close(); + }); + }); + }, + + // GH-204 + 'test query casting when finding by Date': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + var post = new BlogPostB(); + + post.meta.date = new Date(); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.findOne({ _id: post._id, 'meta.date': { $lte: Date.now() } }, + function (err, doc) { + should.strictEqual(err, null); + + DocumentObjectId.toString(doc._id).should.eql(DocumentObjectId.toString(post._id)); + db.close(); + }); + }); + }, + + // GH-220 + 'test querying if an array contains at least a certain single member': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + var post = new BlogPostB(); + + post.tags.push('cat'); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.findOne({tags: 'cat'}, function (err, doc) { + should.strictEqual(err, null); + + doc._id.should.eql(post._id); + db.close(); + }); + }); + }, + + 'test querying if an array contains one of multiple members $in a set': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + var post = new BlogPostB(); + + post.tags.push('football'); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.findOne({tags: {$in: ['football', 'baseball']}}, function (err, doc) { + should.strictEqual(err, null); + doc._id.should.eql(post._id); + + BlogPostB.findOne({ _id: post._id, tags: /otba/i }, function (err, doc) { + should.strictEqual(err, null); + doc._id.should.eql(post._id); + + db.close(); + }) + }); + }); + }, + + 'test querying if an array contains one of multiple members $in a set 2': function () { + var db = start() + , BlogPostA = db.model('BlogPostB', collection) + + var post = new BlogPostA({ tags: ['gooberOne'] }); + + post.save(function (err) { + should.strictEqual(err, null); + + var query = {tags: {$in:[ 'gooberOne' ]}}; + + BlogPostA.findOne(query, function (err, returned) { + done(); + should.strictEqual(err, null); + ;(!!~returned.tags.indexOf('gooberOne')).should.be.true; + returned._id.should.eql(post._id); + }); + }); + + post.collection.insert({ meta: { visitors: 9898, a: null } }, {}, function (err, b) { + should.strictEqual(err, null); + + BlogPostA.findOne({_id: b[0]._id}, function (err, found) { + done(); + should.strictEqual(err, null); + found.get('meta.visitors').valueOf().should.eql(9898); + }) + }); + + var pending = 2; + function done () { + if (--pending) return; + db.close(); + } + }, + + 'test querying via $which where a string': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({ title: 'Steve Jobs', author: 'Steve Jobs'}, function (err, created) { + should.strictEqual(err, null); + + BlogPostB.findOne({ $where: "this.title && this.title === this.author" }, function (err, found) { + should.strictEqual(err, null); + + found._id.should.eql(created._id); + db.close(); + }); + }); + }, + + 'test querying via $which where a function': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({ author: 'Atari', slug: 'Atari'}, function (err, created) { + should.strictEqual(err, null); + + BlogPostB.findOne({ $where: function () { + return (this.author && this.slug && this.author === this.slug); + } }, function (err, found) { + should.strictEqual(err, null); + + found._id.should.eql(created._id); + db.close(); + }); + }); + }, + + // TODO Won't pass until we fix materialization/raw data assymetry + 'test find where $exists': function () { + var db = start() + , ExistsSchema = new Schema({ + a: Number + , b: String + }); + mongoose.model('Exists', ExistsSchema); + var Exists = db.model('Exists', 'exists_' + random()); + Exists.create({ a: 1}, function (err, aExisting) { + should.strictEqual(err, null); + Exists.create({b: 'hi'}, function (err, bExisting) { + should.strictEqual(err, null); + Exists.find({b: {$exists: true}}, function (err, docs) { + should.strictEqual(err, null); + db.close(); + docs.should.have.length(1); + }); + }); + }); + }, + + 'test finding based on nested fields': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , post = new BlogPostB({ + meta: { + visitors: 5678 + } + }); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.findOne({ 'meta.visitors': 5678 }, function (err, found) { + should.strictEqual(err, null); + found.get('meta.visitors') + .valueOf().should.equal(post.get('meta.visitors').valueOf()); + found.get('_id').should.eql(post.get('_id')); + db.close(); + }); + }); + }, + + // GH-242 + 'test finding based on embedded document fields': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({comments: [{title: 'i should be queryable'}]}, function (err, created) { + should.strictEqual(err, null); + BlogPostB.findOne({'comments.title': 'i should be queryable'}, function (err, found) { + should.strictEqual(err, null); + found._id.should.eql(created._id); + db.close(); + }); + }); + }, + + // GH-389 + 'find nested doc using string id': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({comments: [{title: 'i should be queryable by _id'}, {title:'me too me too!'}]}, function (err, created) { + should.strictEqual(err, null); + var id = created.comments[1]._id.toString(); + BlogPostB.findOne({'comments._id': id}, function (err, found) { + db.close(); + should.strictEqual(err, null); + should.strictEqual(!! found, true, 'Find by nested doc id hex string fails'); + found._id.should.eql(created._id); + }); + }); + }, + + 'test finding where $elemMatch': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , dateAnchor = +new Date; + + BlogPostB.create({comments: [{title: 'elemMatch', date: dateAnchor + 5}]}, function (err, createdAfter) { + should.strictEqual(err, null); + BlogPostB.create({comments: [{title: 'elemMatch', date: dateAnchor - 5}]}, function (err, createdBefore) { + should.strictEqual(err, null); + BlogPostB.find({'comments': {'$elemMatch': {title: 'elemMatch', date: {$gt: dateAnchor}}}}, + function (err, found) { + should.strictEqual(err, null); + found.should.have.length(1); + found[0]._id.should.eql(createdAfter._id); + db.close(); + } + ); + }); + }); + }, + + 'test finding where $mod': function () { + var db = start() + , Mod = db.model('Mod', 'mods_' + random()); + Mod.create({num: 1}, function (err, one) { + should.strictEqual(err, null); + Mod.create({num: 2}, function (err, two) { + should.strictEqual(err, null); + Mod.find({num: {$mod: [2, 1]}}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(1); + found[0]._id.should.eql(one._id); + db.close(); + }); + }); + }); + }, + + 'test finding where $not': function () { + var db = start() + , Mod = db.model('Mod', 'mods_' + random()); + Mod.create({num: 1}, function (err, one) { + should.strictEqual(err, null); + Mod.create({num: 2}, function (err, two) { + should.strictEqual(err, null); + Mod.find({num: {$not: {$mod: [2, 1]}}}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(1); + found[0]._id.should.eql(two._id); + db.close(); + }); + }); + }); + }, + + 'test finding where $or': function () { + var db = start() + , Mod = db.model('Mod', 'mods_' + random()); + Mod.create({num: 1}, function (err, one) { + should.strictEqual(err, null); + Mod.create({num: 2}, function (err, two) { + should.strictEqual(err, null); + Mod.create({num: 3}, function (err, three) { + should.strictEqual(err, null); + Mod.find({$or: [{num: 1}, {num: 2}]}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + found[0]._id.should.eql(one._id); + found[1]._id.should.eql(two._id); + db.close(); + }); + }); + }); + }); + }, + + 'test finding where $ne': function () { + var db = start() + , Mod = db.model('Mod', 'mods_' + random()); + Mod.create({num: 1}, function (err, one) { + should.strictEqual(err, null); + Mod.create({num: 2}, function (err, two) { + should.strictEqual(err, null); + Mod.create({num: 3}, function (err, three) { + should.strictEqual(err, null); + Mod.find({num: {$ne: 1}}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + found[0]._id.should.eql(two._id); + found[1]._id.should.eql(three._id); + db.close(); + }); + }); + }); + }); + }, + + 'test finding null matches null and undefined': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection + random()); + + BlogPostB.create({title: 'A', author: null}, function (err, createdA) { + should.strictEqual(err, null); + BlogPostB.create({title: 'B'}, function (err, createdB) { + should.strictEqual(err, null); + BlogPostB.find({author: null}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + db.close(); + }); + }); + }); + }, + + 'test finding STRICT null matches': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection + random()); + + BlogPostB.create({title: 'A', author: null}, function (err, createdA) { + should.strictEqual(err, null); + BlogPostB.create({title: 'B'}, function (err, createdB) { + should.strictEqual(err, null); + BlogPostB.find({author: {$in: [null], $exists: true}}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(1); + found[0]._id.should.eql(createdA._id); + db.close(); + }); + }); + }); + }, + + 'test finding strings via regular expressions': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({title: 'Next to Normal'}, function (err, created) { + should.strictEqual(err, null); + BlogPostB.findOne({title: /^Next/}, function (err, found) { + should.strictEqual(err, null); + found._id.should.eql(created._id); + db.close(); + }); + }); + }, + + 'test finding a document whose arrays contain at least $all values': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({numbers: [-1,-2,-3,-4]}, function (err, whereoutZero) { + should.strictEqual(err, null); + BlogPostB.create({numbers: [0,-1,-2,-3,-4]}, function (err, whereZero) { + should.strictEqual(err, null); + BlogPostB.find({numbers: {$all: [-1, -2, -3, -4]}}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + BlogPostB.find({numbers: {$all: [0, -1]}}, function (err, found) { + db.close(); + should.strictEqual(err, null); + found.should.have.length(1); + }); + }); + }); + }); + }, + + 'test finding a document whose arrays contain at least $all string values': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + var post = new BlogPostB(); + + post.tags.push('onex'); + post.tags.push('twox'); + post.tags.push('threex'); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPostB.findById(post._id, function (err, post) { + should.strictEqual(err, null); + + BlogPostB.find({tags: { '$all': [/^onex/i]}}, function (err, docs) { + should.strictEqual(err, null); + docs.length.should.equal(1); + + BlogPostB.findOne({tags: { '$all': /^two/ }}, function (err, doc) { + db.close(); + should.strictEqual(err, null); + doc.id.should.eql(post.id); + }); + }); + }); + + }); + }, + + 'test finding documents where an array of a certain $size': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({numbers: [1,2,3,4,5,6,7,8,9,10]}, function (err, whereoutZero) { + should.strictEqual(err, null); + BlogPostB.create({numbers: [11,12,13,14,15,16,17,18,19,20]}, function (err, whereZero) { + should.strictEqual(err, null); + BlogPostB.create({numbers: [1,2,3,4,5,6,7,8,9,10,11]}, function (err, found) { + BlogPostB.find({numbers: {$size: 10}}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + BlogPostB.find({numbers: {$size: 11}}, function (err, found) { + should.strictEqual(err, null); + found.should.have.length(1); + db.close(); + }); + }); + }); + }); + }); + }, + + 'test finding documents where an array where the $slice operator': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({numbers: [500,600,700,800]}, function (err, created) { + should.strictEqual(err, null); + BlogPostB.findById(created._id, {numbers: {$slice: 2}}, function (err, found) { + should.strictEqual(err, null); + found._id.should.eql(created._id); + found.numbers.should.have.length(2); + found.numbers[0].should.equal(500); + found.numbers[1].should.equal(600); + BlogPostB.findById(created._id, {numbers: {$slice: -2}}, function (err, found) { + should.strictEqual(err, null); + found._id.should.eql(created._id); + found.numbers.should.have.length(2); + found.numbers[0].should.equal(700); + found.numbers[1].should.equal(800); + BlogPostB.findById(created._id, {numbers: {$slice: [1, 2]}}, function (err, found) { + should.strictEqual(err, null); + found._id.should.eql(created._id); + found.numbers.should.have.length(2); + found.numbers[0].should.equal(600); + found.numbers[1].should.equal(700); + db.close(); + }); + }); + }); + }); + }, + + 'test limits': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({title: 'first limit'}, function (err, first) { + should.strictEqual(err, null); + BlogPostB.create({title: 'second limit'}, function (err, second) { + should.strictEqual(err, null); + BlogPostB.create({title: 'third limit'}, function (err, third) { + should.strictEqual(err, null); + BlogPostB.find({title: /limit$/}).limit(2).find( function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + found[0]._id.should.eql(first._id); + found[1]._id.should.eql(second._id); + db.close(); + }); + }); + }); + }); + }, + + 'test skips': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({title: 'first skip'}, function (err, first) { + should.strictEqual(err, null); + BlogPostB.create({title: 'second skip'}, function (err, second) { + should.strictEqual(err, null); + BlogPostB.create({title: 'third skip'}, function (err, third) { + should.strictEqual(err, null); + BlogPostB.find({title: /skip$/}).skip(1).limit(2).find( function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + found[0]._id.should.eql(second._id); + found[1]._id.should.eql(third._id); + db.close(); + }); + }); + }); + }); + }, + + 'test sorts': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({meta: {visitors: 100}}, function (err, least) { + should.strictEqual(err, null); + BlogPostB.create({meta: {visitors: 300}}, function (err, largest) { + should.strictEqual(err, null); + BlogPostB.create({meta: {visitors: 200}}, function (err, middle) { + should.strictEqual(err, null); + BlogPostB + .where('meta.visitors').gt(99).lt(301) + .sort('meta.visitors', -1) + .find( function (err, found) { + should.strictEqual(err, null); + found.should.have.length(3); + found[0]._id.should.eql(largest._id); + found[1]._id.should.eql(middle._id); + found[2]._id.should.eql(least._id); + db.close(); + }); + }); + }); + }); + }, + + 'test backwards compatibility with previously existing null values in db': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , post = new BlogPostB(); + + post.collection.insert({ meta: { visitors: 9898, a: null } }, {}, function (err, b) { + should.strictEqual(err, null); + + BlogPostB.findOne({_id: b[0]._id}, function (err, found) { + should.strictEqual(err, null); + found.get('meta.visitors').valueOf().should.eql(9898); + db.close(); + }) + }) + }, + + 'test backwards compatibility with unused values in db': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection) + , post = new BlogPostB(); + + post.collection.insert({ meta: { visitors: 9898, color: 'blue'}}, {}, function (err, b) { + should.strictEqual(err, null); + + BlogPostB.findOne({_id: b[0]._id}, function (err, found) { + should.strictEqual(err, null); + found.get('meta.visitors').valueOf().should.eql(9898); + found.save(function (err) { + should.strictEqual(err, null); + db.close(); + }) + }) + }) + }, + + 'test streaming cursors with #each': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({title: "The Wrestler", tags: ["movie"]}, function (err, wrestler) { + should.strictEqual(err, null); + BlogPostB.create({title: "Black Swan", tags: ["movie"]}, function (err, blackswan) { + should.strictEqual(err, null); + BlogPostB.create({title: "Pi", tags: ["movie"]}, function (err, pi) { + should.strictEqual(err, null); + var found = {}; + BlogPostB + .find({tags: "movie"}) + .sort('title', -1) + .each(function (err, post) { + should.strictEqual(err, null); + if (post) found[post.title] = 1; + else { + found.should.have.property("The Wrestler", 1); + found.should.have.property("Black Swan", 1); + found.should.have.property("Pi", 1); + db.close(); + } + }); + }); + }); + }); + }, + + 'test streaming cursors with #each and manual iteration': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.create({title: "Bleu", tags: ["Krzysztof Kieślowski"]}, function (err, wrestler) { + should.strictEqual(err, null); + BlogPostB.create({title: "Blanc", tags: ["Krzysztof Kieślowski"]}, function (err, blackswan) { + should.strictEqual(err, null); + BlogPostB.create({title: "Rouge", tags: ["Krzysztof Kieślowski"]}, function (err, pi) { + should.strictEqual(err, null); + var found = {}; + BlogPostB + .find({tags: "Krzysztof Kieślowski"}) + .each(function (err, post, next) { + should.strictEqual(err, null); + if (post) { + found[post.title] = 1; + process.nextTick(next); + } else { + found.should.have.property("Bleu", 1); + found.should.have.property("Blanc", 1); + found.should.have.property("Rouge", 1); + db.close(); + } + }); + }); + }); + }); + }, + + '$gt, $lt, $lte, $gte work on strings': function () { + var db = start() + var D = db.model('D', new Schema({dt: String}), collection); + + D.create({ dt: '2011-03-30' }, done); + D.create({ dt: '2011-03-31' }, done); + D.create({ dt: '2011-04-01' }, done); + D.create({ dt: '2011-04-02' }, done); + + var pending = 3; + function done (err) { + if (err) db.close(); + should.strictEqual(err, null); + + if (--pending) return; + + pending = 2; + + D.find({ 'dt': { $gte: '2011-03-30', $lte: '2011-04-01' }}).sort('dt', 1).run(function (err, docs) { + if (--pending) db.close(); + should.strictEqual(err, null); + docs.length.should.eql(3); + docs[0].dt.should.eql('2011-03-30'); + docs[1].dt.should.eql('2011-03-31'); + docs[2].dt.should.eql('2011-04-01'); + docs.some(function (d) { return '2011-04-02' === d.dt }).should.be.false; + }); + + D.find({ 'dt': { $gt: '2011-03-30', $lt: '2011-04-02' }}).sort('dt', 1).run(function (err, docs) { + if (--pending) db.close(); + should.strictEqual(err, null); + docs.length.should.eql(2); + docs[0].dt.should.eql('2011-03-31'); + docs[1].dt.should.eql('2011-04-01'); + docs.some(function (d) { return '2011-03-30' === d.dt }).should.be.false; + docs.some(function (d) { return '2011-04-02' === d.dt }).should.be.false; + }); + } + }, + + 'nested mixed queries (x.y.z)': function () { + var db = start() + , BlogPostB = db.model('BlogPostB', collection); + + BlogPostB.find({ 'mixed.nested.stuff': 'skynet' }, function (err, docs) { + db.close(); + should.strictEqual(err, null); + }); + }, + + // GH-336 + 'finding by Date field works': function () { + var db = start() + , Test = db.model('TestDateQuery', new Schema({ date: Date }), 'datetest_' + random()) + , now = new Date; + + Test.create({ date: now }, { date: new Date(now-10000) }, function (err, a, b) { + should.strictEqual(err, null); + Test.find({ date: now }, function (err, docs) { + db.close(); + should.strictEqual(err, null); + docs.length.should.equal(1); + }); + }); + }, + + // GH-309 + 'using $near with Arrays works (geo-spatial)': function () { + var db = start() + , Test = db.model('Geo1', geoSchema, collection + 'geospatial'); + + Test.create({ loc: [ 10, 20 ]}, { loc: [ 40, 90 ]}, function (err) { + should.strictEqual(err, null); + setTimeout(function () { + Test.find({ loc: { $near: [30, 40] }}, function (err, docs) { + db.close(); + should.strictEqual(err, null); + docs.length.should.equal(2); + }); + }, 700); + }); + }, + + 'using $maxDistance with Array works (geo-spatial)': function () { + var db = start() + , Test = db.model('Geo2', geoSchema, "x"+random()); + + Test.create({ loc: [ 20, 80 ]}, { loc: [ 25, 30 ]}, function (err, docs) { + should.strictEqual(!!err, false); + setTimeout(function () { + Test.find({ loc: { $near: [25, 31], $maxDistance: 1 }}, function (err, docs) { + should.strictEqual(err, null); + docs.length.should.equal(1); + Test.find({ loc: { $near: [25, 32], $maxDistance: 1 }}, function (err, docs) { + db.close(); + should.strictEqual(err, null); + docs.length.should.equal(0); + }); + }); + }, 500); + }); + } + +}; diff --git a/node_modules/mongoose/test/model.test.js b/node_modules/mongoose/test/model.test.js new file mode 100644 index 0000000..cacbef4 --- /dev/null +++ b/node_modules/mongoose/test/model.test.js @@ -0,0 +1,3824 @@ + +/** + * Test dependencies. + */ + +var start = require('./common') + , should = require('should') + , mongoose = start.mongoose + , random = require('mongoose/utils').random + , Query = require('mongoose/query') + , Schema = mongoose.Schema + , SchemaType = mongoose.SchemaType + , CastError = SchemaType.CastError + , ValidatorError = SchemaType.ValidatorError + , ValidationError = mongoose.Document.ValidationError + , ObjectId = Schema.ObjectId + , DocumentObjectId = mongoose.Types.ObjectId + , DocumentArray = mongoose.Types.DocumentArray + , EmbeddedDocument = mongoose.Types.Document + , MongooseNumber = mongoose.Types.Number + , MongooseArray = mongoose.Types.Array + , MongooseError = mongoose.Error; + +/** + * Setup. + */ + +var Comments = new Schema(); + +Comments.add({ + title : String + , date : Date + , body : String + , comments : [Comments] +}); + +var BlogPost = new Schema({ + title : String + , author : String + , slug : String + , date : Date + , meta : { + date : Date + , visitors : Number + } + , published : Boolean + , mixed : {} + , numbers : [Number] + , owners : [ObjectId] + , comments : [Comments] +}); + +BlogPost.virtual('titleWithAuthor') + .get(function () { + return this.get('title') + ' by ' + this.get('author'); + }) + .set(function (val) { + var split = val.split(' by '); + this.set('title', split[0]); + this.set('author', split[1]); + }); + +BlogPost.method('cool', function(){ + return this; +}); + +BlogPost.static('woot', function(){ + return this; +}); + +mongoose.model('BlogPost', BlogPost); + +var collection = 'blogposts_' + random(); + +module.exports = { + + 'test a model isNew flag when instantiating': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + post.isNew.should.be.true; + db.close(); + }, + + 'modified getter should not throw': function () { + var db = start(); + var BlogPost = db.model('BlogPost', collection); + var post = new BlogPost; + db.close(); + + var threw = false; + try { + post.modified; + } catch (err) { + threw = true; + } + + threw.should.be.false; + }, + + 'test presence of model schema': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.schema.should.be.an.instanceof(Schema); + BlogPost.prototype.schema.should.be.an.instanceof(Schema); + db.close(); + }, + + 'test a model default structure when instantiated': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + post.isNew.should.be.true; + post.db.model('BlogPost').modelName.should.equal('BlogPost'); + post.constructor.modelName.should.equal('BlogPost'); + + post.get('_id').should.be.an.instanceof(DocumentObjectId); + + should.equal(undefined, post.get('title')); + should.equal(undefined, post.get('slug')); + should.equal(undefined, post.get('date')); + + post.get('meta').should.be.a('object'); + post.get('meta').should.eql({}); + should.equal(undefined, post.get('meta.date')); + should.equal(undefined, post.get('meta.visitors')); + + should.equal(undefined, post.get('published')); + + post.get('numbers').should.be.an.instanceof(MongooseArray); + post.get('owners').should.be.an.instanceof(MongooseArray); + post.get('comments').should.be.an.instanceof(DocumentArray); + db.close(); + }, + + 'mongoose.model returns the model at creation': function () { + var Named = mongoose.model('Named', new Schema({ name: String })); + var n1 = new Named(); + should.equal(n1.name, null); + var n2 = new Named({ name: 'Peter Bjorn' }); + should.equal(n2.name, 'Peter Bjorn'); + + var schema = new Schema({ number: Number }); + var Numbered = mongoose.model('Numbered', schema, collection); + var n3 = new Numbered({ number: 1234 }); + n3.number.valueOf().should.equal(1234); + }, + + 'test default Array type casts to Mixed': function () { + var db = start() + , DefaultArraySchema = new Schema({ + num1: Array + , num2: [] + }) + + mongoose.model('DefaultArraySchema', DefaultArraySchema); + var DefaultArray = db.model('DefaultArraySchema', collection); + var arr = new DefaultArray(); + + arr.get('num1').should.have.length(0); + arr.get('num2').should.have.length(0); + + var threw1 = false + , threw2 = false; + + try { + arr.num1.push({ x: 1 }) + arr.num1.push(9) + arr.num1.push("woah") + } catch (err) { + threw1 = true; + } + + threw1.should.equal(false); + + try { + arr.num2.push({ x: 1 }) + arr.num2.push(9) + arr.num2.push("woah") + } catch (err) { + threw2 = true; + } + + threw2.should.equal(false); + + db.close(); + + }, + + 'test a model default structure that has a nested Array when instantiated': function () { + var db = start() + , NestedSchema = new Schema({ + nested: { + array: [Number] + } + }); + mongoose.model('NestedNumbers', NestedSchema); + var NestedNumbers = db.model('NestedNumbers', collection); + + var nested = new NestedNumbers(); + nested.get('nested.array').should.be.an.instanceof(MongooseArray); + db.close(); + }, + + 'test a model that defaults an Array attribute to a default non-empty array': function () { + var db = start() + , DefaultArraySchema = new Schema({ + arr: {type: Array, cast: String, default: ['a', 'b', 'c']} + }); + mongoose.model('DefaultArray', DefaultArraySchema); + var DefaultArray = db.model('DefaultArray', collection); + var arr = new DefaultArray(); + arr.get('arr').should.have.length(3); + arr.get('arr')[0].should.equal('a'); + arr.get('arr')[1].should.equal('b'); + arr.get('arr')[2].should.equal('c'); + db.close(); + }, + + 'test a model that defaults an Array attribute to a default single member array': function () { + var db = start() + , DefaultOneCardArraySchema = new Schema({ + arr: {type: Array, cast: String, default: ['a']} + }); + mongoose.model('DefaultOneCardArray', DefaultOneCardArraySchema); + var DefaultOneCardArray = db.model('DefaultOneCardArray', collection); + var arr = new DefaultOneCardArray(); + arr.get('arr').should.have.length(1); + arr.get('arr')[0].should.equal('a'); + db.close(); + }, + + 'test a model that defaults an Array attributes to an empty array': function () { + var db = start() + , DefaultZeroCardArraySchema = new Schema({ + arr: {type: Array, cast: String, default: []} + }); + mongoose.model('DefaultZeroCardArray', DefaultZeroCardArraySchema); + var DefaultZeroCardArray = db.model('DefaultZeroCardArray', collection); + var arr = new DefaultZeroCardArray(); + arr.get('arr').should.have.length(0); + arr.arr.should.have.length(0); + db.close(); + }, + + 'test that arrays auto-default to the empty array': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + post.numbers.should.have.length(0); + db.close(); + }, + + 'test instantiating a model with a hash that maps to at least 1 null value': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost({ + title: null + }); + should.strictEqual(null, post.title); + db.close(); + }, + + 'saving a model with a null value should perpetuate that null value to the db': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost({ + title: null + }); + should.strictEqual(null, post.title); + post.save( function (err) { + should.strictEqual(err, null); + BlogPost.findById(post.id, function (err, found) { + db.close(); + should.strictEqual(err, null); + should.strictEqual(found.title, null); + }); + }); + }, + + 'test instantiating a model with a hash that maps to at least 1 undefined value': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost({ + title: undefined + }); + should.strictEqual(undefined, post.title); + post.save( function (err) { + should.strictEqual(null, err); + BlogPost.findById(post.id, function (err, found) { + db.close(); + should.strictEqual(err, null); + should.strictEqual(found.title, undefined); + }); + }); + }, + + 'test a model structure when saved': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection) + , pending = 2; + + function done () { + if (!--pending) db.close(); + } + + var post = new BlogPost(); + post.on('save', function (post) { + post.get('_id').should.be.an.instanceof(DocumentObjectId); + + should.equal(undefined, post.get('title')); + should.equal(undefined, post.get('slug')); + should.equal(undefined, post.get('date')); + should.equal(undefined, post.get('published')); + + post.get('meta').should.be.a('object'); + post.get('meta').should.eql({}); + should.equal(undefined, post.get('meta.date')); + should.equal(undefined, post.get('meta.visitors')); + + post.get('owners').should.be.an.instanceof(MongooseArray); + post.get('comments').should.be.an.instanceof(DocumentArray); + done(); + }); + + post.save(function(err, post){ + should.strictEqual(err, null); + post.get('_id').should.be.an.instanceof(DocumentObjectId); + + should.equal(undefined, post.get('title')); + should.equal(undefined, post.get('slug')); + should.equal(undefined, post.get('date')); + should.equal(undefined, post.get('published')); + + post.get('meta').should.be.a('object'); + post.get('meta').should.eql({}); + should.equal(undefined, post.get('meta.date')); + should.equal(undefined, post.get('meta.visitors')); + + post.get('owners').should.be.an.instanceof(MongooseArray); + post.get('comments').should.be.an.instanceof(DocumentArray); + done(); + }); + }, + + 'test a model structures when created': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create({ title: 'hi there'}, function (err, post) { + should.strictEqual(err, null); + post.get('_id').should.be.an.instanceof(DocumentObjectId); + + should.strictEqual(post.get('title'), 'hi there'); + should.equal(undefined, post.get('slug')); + should.equal(undefined, post.get('date')); + + post.get('meta').should.be.a('object'); + post.get('meta').should.eql({}); + should.equal(undefined, post.get('meta.date')); + should.equal(undefined, post.get('meta.visitors')); + + should.strictEqual(undefined, post.get('published')); + + post.get('owners').should.be.an.instanceof(MongooseArray); + post.get('comments').should.be.an.instanceof(DocumentArray); + db.close(); + }); + }, + + 'test a model structure when initd': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost() + post.init({ + title : 'Test' + , slug : 'test' + , date : new Date + , meta : { + date : new Date + , visitors : 5 + } + , published : true + , owners : [new DocumentObjectId, new DocumentObjectId] + , comments : [ + { title: 'Test', date: new Date, body: 'Test' } + , { title: 'Super', date: new Date, body: 'Cool' } + ] + }); + + post.get('title').should.eql('Test'); + post.get('slug').should.eql('test'); + post.get('date').should.be.an.instanceof(Date); + post.get('meta').should.be.a('object'); + post.get('meta').date.should.be.an.instanceof(Date); + post.get('meta').visitors.should.be.an.instanceof(MongooseNumber); + post.get('published').should.be.true; + + post.title.should.eql('Test'); + post.slug.should.eql('test'); + post.date.should.be.an.instanceof(Date); + post.meta.should.be.a('object'); + post.meta.date.should.be.an.instanceof(Date); + post.meta.visitors.should.be.an.instanceof(MongooseNumber); + post.published.should.be.true; + + post.get('owners').should.be.an.instanceof(MongooseArray); + post.get('owners')[0].should.be.an.instanceof(DocumentObjectId); + post.get('owners')[1].should.be.an.instanceof(DocumentObjectId); + + post.owners.should.be.an.instanceof(MongooseArray); + post.owners[0].should.be.an.instanceof(DocumentObjectId); + post.owners[1].should.be.an.instanceof(DocumentObjectId); + + post.get('comments').should.be.an.instanceof(DocumentArray); + post.get('comments')[0].should.be.an.instanceof(EmbeddedDocument); + post.get('comments')[1].should.be.an.instanceof(EmbeddedDocument); + + post.comments.should.be.an.instanceof(DocumentArray); + post.comments[0].should.be.an.instanceof(EmbeddedDocument); + post.comments[1].should.be.an.instanceof(EmbeddedDocument); + + db.close(); + }, + + 'test a model structure when partially initd': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost() + post.init({ + title : 'Test' + , slug : 'test' + , date : new Date + }); + + post.get('title').should.eql('Test'); + post.get('slug').should.eql('test'); + post.get('date').should.be.an.instanceof(Date); + post.get('meta').should.be.a('object'); + + post.get('meta').should.eql({}); + should.equal(undefined, post.get('meta.date')); + should.equal(undefined, post.get('meta.visitors')); + + should.equal(undefined, post.get('published')); + + post.get('owners').should.be.an.instanceof(MongooseArray); + post.get('comments').should.be.an.instanceof(DocumentArray); + db.close(); + }, + + 'test initializing with a nested hash': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost({ + meta: { + date : new Date + , visitors : 5 + } + }); + + post.get('meta.visitors').valueOf().should.equal(5); + db.close(); + }, + + 'test isNew on embedded documents after initing': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost() + post.init({ + title : 'Test' + , slug : 'test' + , comments : [ { title: 'Test', date: new Date, body: 'Test' } ] + }); + + post.get('comments')[0].isNew.should.be.false; + db.close(); + }, + + 'test isModified when modifying keys': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost() + post.init({ + title : 'Test' + , slug : 'test' + , date : new Date + }); + + post.isModified('title').should.be.false; + post.set('title', 'test'); + post.isModified('title').should.be.true; + + post.isModified('date').should.be.false; + post.set('date', new Date(post.date + 1)); + post.isModified('date').should.be.true; + + post.isModified('meta.date').should.be.false; + db.close(); + }, + + 'setting a key identically to its current value should not dirty the key': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost() + post.init({ + title : 'Test' + , slug : 'test' + , date : new Date + }); + + post.isModified('title').should.be.false; + post.set('title', 'Test'); + post.isModified('title').should.be.false; + db.close(); + }, + + 'test isModified and isDirectModified on a DocumentArray': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost() + post.init({ + title : 'Test' + , slug : 'test' + , comments : [ { title: 'Test', date: new Date, body: 'Test' } ] + }); + + post.isModified('comments.0.title').should.be.false; + post.get('comments')[0].set('title', 'Woot'); + post.isModified('comments').should.be.true; + post.isDirectModified('comments').should.be.false; + post.isModified('comments.0.title').should.be.true; + post.isDirectModified('comments.0.title').should.be.true; + + db.close(); + }, + + 'test isModified on a DocumentArray with accessors': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost() + post.init({ + title : 'Test' + , slug : 'test' + , comments : [ { title: 'Test', date: new Date, body: 'Test' } ] + }); + + post.isModified('comments.0.body').should.be.false; + post.get('comments')[0].body = 'Woot'; + post.isModified('comments').should.be.true; + post.isDirectModified('comments').should.be.false; + post.isModified('comments.0.body').should.be.true; + post.isDirectModified('comments.0.body').should.be.true; + + db.close(); + }, + + 'test isModified on a MongooseArray with atomics methods': function(){ + // COMPLETEME + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost() + + post.isModified('owners').should.be.false; + post.get('owners').$push(new DocumentObjectId); + post.isModified('owners').should.be.true; + + db.close(); + }, + + 'test isModified on a MongooseArray with native methods': function(){ + // COMPLETEME + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost() + + post.isModified('owners').should.be.false; + post.get('owners').push(new DocumentObjectId); + + db.close(); + }, + + // GH-342 + 'over-writing a number should persist to the db': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost({ + meta: { + date : new Date + , visitors : 10 + } + }); + + post.save( function (err) { + should.strictEqual(null, err); + post.set('meta.visitors', 20); + post.save( function (err) { + should.strictEqual(null, err); + BlogPost.findById(post.id, function (err, found) { + should.strictEqual(null, err); + found.get('meta.visitors').valueOf().should.equal(20); + db.close(); + }); + }); + }); + }, + + 'test defining a new method': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + post.cool().should.eql(post); + db.close(); + }, + + 'test defining a static': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.woot().should.eql(BlogPost); + db.close(); + }, + + 'test casting error': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection) + , threw = false; + + var post = new BlogPost(); + + try { + post.init({ + date: 'Test' + }); + } catch(e){ + threw = true; + } + + threw.should.be.false; + + try { + post.set('title', 'Test'); + } catch(e){ + threw = true; + } + + threw.should.be.false; + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(CastError); + db.close(); + }); + }, + + 'test nested casting error': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection) + , threw = false; + + var post = new BlogPost(); + + try { + post.init({ + meta: { + date: 'Test' + } + }); + } catch(e){ + threw = true; + } + + threw.should.be.false; + + try { + post.set('meta.date', 'Test'); + } catch(e){ + threw = true; + } + + threw.should.be.false; + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(CastError); + db.close(); + }); + }, + + 'test casting error in subdocuments': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection) + , threw = false; + + var post = new BlogPost() + post.init({ + title : 'Test' + , slug : 'test' + , comments : [ { title: 'Test', date: new Date, body: 'Test' } ] + }); + + post.get('comments')[0].set('date', 'invalid'); + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(CastError); + db.close(); + }); + }, + + 'test casting error when adding a subdocument': function(){ + var db = start() + , BlogPost = db.model('BlogPost', collection) + , threw = false; + + var post = new BlogPost() + + try { + post.get('comments').push({ + date: 'Bad date' + }); + } catch (e) { + threw = true; + } + + threw.should.be.false; + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(CastError); + db.close(); + }); + }, + + 'test validation': function(){ + function dovalidate (val) { + this.asyncScope.should.equal('correct'); + return true; + } + + function dovalidateAsync (val, callback) { + this.scope.should.equal('correct'); + process.nextTick(function () { + callback(true); + }); + } + + mongoose.model('TestValidation', new Schema({ + simple: { type: String, required: true } + , scope: { type: String, validate: [dovalidate, 'scope failed'], required: true } + , asyncScope: { type: String, validate: [dovalidateAsync, 'async scope failed'], required: true } + })); + + var db = start() + , TestValidation = db.model('TestValidation'); + + var post = new TestValidation(); + post.set('simple', ''); + post.set('scope', 'correct'); + post.set('asyncScope', 'correct'); + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + + post.set('simple', 'here'); + post.save(function(err){ + should.strictEqual(err, null); + db.close(); + }); + }); + }, + + 'test validation with custom message': function () { + function validate (val) { + return val === 'abc'; + } + mongoose.model('TestValidationMessage', new Schema({ + simple: { type: String, validate: [validate, 'must be abc'] } + })); + + var db = start() + , TestValidationMessage = db.model('TestValidationMessage'); + + var post = new TestValidationMessage(); + post.set('simple', ''); + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + err.errors.simple.should.equal('Validator "must be abc" failed for path simple'); + post.errors.simple.should.equal('Validator "must be abc" failed for path simple'); + + post.set('simple', 'abc'); + post.save(function(err){ + should.strictEqual(err, null); + db.close(); + }); + }); + }, + + // GH-272 + 'test validation with Model.schema.path introspection': function () { + var db = start(); + var IntrospectionValidationSchema = new Schema({ + name: String + }); + var IntrospectionValidation = db.model('IntrospectionValidation', IntrospectionValidationSchema, 'introspections_' + random()); + IntrospectionValidation.schema.path('name').validate(function (value) { + return value.length < 2; + }, 'Name cannot be greater than 1 character'); + var doc = new IntrospectionValidation({name: 'hi'}); + doc.save( function (err) { + err.errors.name.should.equal("Validator \"Name cannot be greater than 1 character\" failed for path name"); + err.name.should.equal("ValidationError"); + err.message.should.equal("Validation failed"); + db.close(); + }); + }, + + 'test required validation for undefined values': function () { + mongoose.model('TestUndefinedValidation', new Schema({ + simple: { type: String, required: true } + })); + + var db = start() + , TestUndefinedValidation = db.model('TestUndefinedValidation'); + + var post = new TestUndefinedValidation(); + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + + post.set('simple', 'here'); + post.save(function(err){ + should.strictEqual(err, null); + db.close(); + }); + }); + }, + + // GH-319 + 'save callback should only execute once regardless of number of failed validations': function () { + mongoose.model('CallbackFiresOnceValidation', new Schema({ + username: { type: String, validate: /^[a-z]{6}$/i } + , email: { type: String, validate: /^[a-z]{6}$/i } + , password: { type: String, validate: /^[a-z]{6}$/i } + })); + + var db = start() + , CallbackFiresOnceValidation = db.model('CallbackFiresOnceValidation'); + + var post = new CallbackFiresOnceValidation({ + username: "nope" + , email: "too" + , password: "short" + }); + + var timesCalled = 0; + + post.save(function (err) { + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + + (++timesCalled).should.eql(1); + + (Object.keys(err.errors).length).should.eql(3); + err.errors.password.should.eql('Validator failed for path password'); + err.errors.email.should.eql('Validator failed for path email'); + err.errors.username.should.eql('Validator failed for path username'); + + (Object.keys(post.errors).length).should.eql(3); + post.errors.password.should.eql('Validator failed for path password'); + post.errors.email.should.eql('Validator failed for path email'); + post.errors.username.should.eql('Validator failed for path username'); + + db.close(); + }); + }, + + 'test validation on a query result': function () { + mongoose.model('TestValidationOnResult', new Schema({ + resultv: { type: String, required: true } + })); + + var db = start() + , TestV = db.model('TestValidationOnResult'); + + var post = new TestV; + + post.validate(function (err) { + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + + post.resultv = 'yeah'; + post.save(function (err) { + should.strictEqual(err, null); + TestV.findOne({ _id: post.id }, function (err, found) { + should.strictEqual(err, null); + found.resultv.should.eql('yeah'); + found.save(function(err){ + should.strictEqual(err, null); + db.close(); + }) + }); + }); + }) + }, + + 'test required validation for previously existing null values': function () { + mongoose.model('TestPreviousNullValidation', new Schema({ + previous: { type: String, required: true } + , a: String + })); + + var db = start() + , TestP = db.model('TestPreviousNullValidation') + + TestP.collection.insert({ a: null, previous: null}, {}, function (err, f) { + should.strictEqual(err, null); + + TestP.findOne({_id: f[0]._id}, function (err, found) { + should.strictEqual(err, null); + found.isNew.should.be.false; + should.strictEqual(found.get('previous'), null); + + found.validate(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + + found.set('previous', 'yoyo'); + found.save(function (err) { + should.strictEqual(err, null); + db.close(); + }); + }) + }) + }); + }, + + 'test nested validation': function(){ + mongoose.model('TestNestedValidation', new Schema({ + nested: { + required: { type: String, required: true } + } + })); + + var db = start() + , TestNestedValidation = db.model('TestNestedValidation'); + + var post = new TestNestedValidation(); + post.set('nested.required', null); + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + + post.set('nested.required', 'here'); + post.save(function(err){ + should.strictEqual(err, null); + db.close(); + }); + }); + }, + + 'test validation in subdocuments': function(){ + var Subdocs = new Schema({ + required: { type: String, required: true } + }); + + mongoose.model('TestSubdocumentsValidation', new Schema({ + items: [Subdocs] + })); + + var db = start() + , TestSubdocumentsValidation = db.model('TestSubdocumentsValidation'); + + var post = new TestSubdocumentsValidation(); + + post.get('items').push({ required: '' }); + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + err.errors.required.should.eql('Validator "required" failed for path required'); + + post.get('items')[0].set('required', true); + post.save(function(err){ + should.strictEqual(err, null); + db.close(); + }); + }); + }, + + 'test async validation': function(){ + var executed = false; + + function validator(v, fn){ + setTimeout(function () { + executed = true; + fn(v !== 'test'); + }, 50); + }; + mongoose.model('TestAsyncValidation', new Schema({ + async: { type: String, validate: [validator, 'async validator'] } + })); + + var db = start() + , TestAsyncValidation = db.model('TestAsyncValidation'); + + var post = new TestAsyncValidation(); + post.set('async', 'test'); + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + err.errors.async.should.eql('Validator "async validator" failed for path async'); + executed.should.be.true; + executed = false; + + post.set('async', 'woot'); + post.save(function(err){ + executed.should.be.true; + should.strictEqual(err, null); + db.close(); + }); + }); + }, + + 'test nested async validation': function(){ + var executed = false; + + function validator(v, fn){ + setTimeout(function () { + executed = true; + fn(v !== 'test'); + }, 50); + }; + + mongoose.model('TestNestedAsyncValidation', new Schema({ + nested: { + async: { type: String, validate: [validator, 'async validator'] } + } + })); + + var db = start() + , TestNestedAsyncValidation = db.model('TestNestedAsyncValidation'); + + var post = new TestNestedAsyncValidation(); + post.set('nested.async', 'test'); + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + executed.should.be.true; + executed = false; + + post.validate(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + executed.should.be.true; + executed = false; + + post.set('nested.async', 'woot'); + post.validate(function(err){ + executed.should.be.true; + should.equal(err, null); + executed = false; + + post.save(function(err){ + executed.should.be.true; + should.strictEqual(err, null); + db.close(); + }); + }); + }) + + }); + }, + + 'test async validation in subdocuments': function(){ + var executed = false; + + function validator (v, fn) { + setTimeout(function(){ + executed = true; + fn(v !== ''); + }, 50); + }; + + var Subdocs = new Schema({ + required: { type: String, validate: [validator, 'async in subdocs'] } + }); + + mongoose.model('TestSubdocumentsAsyncValidation', new Schema({ + items: [Subdocs] + })); + + var db = start() + , Test = db.model('TestSubdocumentsAsyncValidation'); + + var post = new Test(); + + post.get('items').push({ required: '' }); + + post.save(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + executed.should.be.true; + executed = false; + + post.get('items')[0].set({ required: 'here' }); + post.save(function(err){ + executed.should.be.true; + should.strictEqual(err, null); + db.close(); + }); + }); + }, + + 'test validation without saving': function(){ + + mongoose.model('TestCallingValidation', new Schema({ + item: { type: String, required: true } + })); + + var db = start() + , TestCallingValidation = db.model('TestCallingValidation'); + + var post = new TestCallingValidation; + + post.schema.path('item').isRequired.should.be.true; + + should.strictEqual(post.isNew, true); + + post.validate(function(err){ + err.should.be.an.instanceof(MongooseError); + err.should.be.an.instanceof(ValidationError); + should.strictEqual(post.isNew, true); + + post.item = 'yo'; + post.validate(function(err){ + should.equal(err, null); + should.strictEqual(post.isNew, true); + db.close(); + }); + }); + + }, + + 'test setting required to false': function () { + function validator () { + return true; + } + + mongoose.model('TestRequiredFalse', new Schema({ + result: { type: String, validate: [validator, 'chump validator'], required: false } + })); + + var db = start() + , TestV = db.model('TestRequiredFalse'); + + var post = new TestV; + + post.schema.path('result').isRequired.should.be.false; + + db.close(); + }, + + 'test defaults application': function(){ + var now = Date.now(); + + mongoose.model('TestDefaults', new Schema({ + date: { type: Date, default: now } + })); + + var db = start() + , TestDefaults = db.model('TestDefaults'); + + var post = new TestDefaults(); + post.get('date').should.be.an.instanceof(Date); + (+post.get('date')).should.eql(now); + db.close(); + }, + + 'test "type" is allowed as a key': function(){ + mongoose.model('TestTypeDefaults', new Schema({ + type: { type: String, default: 'YES!' } + })); + + var db = start() + , TestDefaults = db.model('TestTypeDefaults'); + + var post = new TestDefaults(); + post.get('type').should.be.a('string'); + post.get('type').should.eql('YES!'); + + // GH-402 + var TestDefaults2 = db.model('TestTypeDefaults2', new Schema({ + x: { y: { type: { type: String }, owner: String } } + })); + + var post = new TestDefaults2; + post.x.y.type = "#402"; + post.x.y.owner= "me"; + post.save(function (err) { + db.close(); + should.strictEqual(null, err); + }); + + }, + + 'test nested defaults application': function(){ + var now = Date.now(); + + mongoose.model('TestNestedDefaults', new Schema({ + nested: { + date: { type: Date, default: now } + } + })); + + var db = start() + , TestDefaults = db.model('TestNestedDefaults'); + + var post = new TestDefaults(); + post.get('nested.date').should.be.an.instanceof(Date); + (+post.get('nested.date')).should.eql(now); + db.close(); + }, + + 'test defaults application in subdocuments': function(){ + var now = Date.now(); + + var Items = new Schema({ + date: { type: Date, default: now } + }); + + mongoose.model('TestSubdocumentsDefaults', new Schema({ + items: [Items] + })); + + var db = start() + , TestSubdocumentsDefaults = db.model('TestSubdocumentsDefaults'); + + var post = new TestSubdocumentsDefaults(); + post.get('items').push({}); + post.get('items')[0].get('date').should.be.an.instanceof(Date); + (+post.get('items')[0].get('date')).should.eql(now); + db.close(); + }, + + // TODO: adapt this text to handle a getIndexes callback that's not unique to + // the mongodb-native driver. + 'test that indexes are ensured when the model is compiled': function(){ + var Indexed = new Schema({ + name : { type: String, index: true } + , last : String + , email : String + }); + + Indexed.index({ last: 1, email: 1 }, { unique: true }); + + var db = start() + , IndexedModel = db.model('IndexedModel', Indexed, 'indexedmodel' + random()) + , assertions = 0; + + IndexedModel.on('index', function(){ + IndexedModel.collection.getIndexes(function(err, indexes){ + should.strictEqual(err, null); + + for (var i in indexes) + indexes[i].forEach(function(index){ + if (index[0] == 'name') + assertions++; + if (index[0] == 'last') + assertions++; + if (index[0] == 'email') + assertions++; + }); + + assertions.should.eql(3); + db.close(); + }); + }); + }, + + 'test indexes on embedded documents': function () { + var BlogPosts = new Schema({ + _id : { type: ObjectId, index: true } + , title : { type: String, index: true } + , desc : String + }); + + var User = new Schema({ + name : { type: String, index: true } + , blogposts : [BlogPosts] + }); + + var db = start() + , UserModel = db.model('DeepIndexedModel', User, 'deepindexedmodel' + random()) + , assertions = 0; + + UserModel.on('index', function () { + UserModel.collection.getIndexes(function (err, indexes) { + should.strictEqual(err, null); + + for (var i in indexes) + indexes[i].forEach(function(index){ + if (index[0] == 'name') + assertions++; + if (index[0] == 'blogposts._id') + assertions++; + if (index[0] == 'blogposts.title') + assertions++; + }); + + assertions.should.eql(3); + db.close(); + }); + }); + }, + + 'compound indexes on embedded documents should be created': function () { + var BlogPosts = new Schema({ + title : String + , desc : String + }); + + BlogPosts.index({ title: 1, desc: 1 }); + + var User = new Schema({ + name : { type: String, index: true } + , blogposts : [BlogPosts] + }); + + var db = start() + , UserModel = db.model('DeepCompoundIndexModel', User, 'deepcompoundindexmodel' + random()) + , found = 0; + + UserModel.on('index', function () { + UserModel.collection.getIndexes(function (err, indexes) { + should.strictEqual(err, null); + + for (var index in indexes) { + switch (index) { + case 'name_1': + case 'blogposts.title_1_blogposts.desc_1': + ++found; + break; + } + } + + db.close(); + found.should.eql(2); + }); + }); + }, + + 'test getters with same name on embedded documents not clashing': function() { + var Post = new Schema({ + title : String + , author : { name : String } + , subject : { name : String } + }); + + mongoose.model('PostWithClashGetters', Post); + + var db = start() + , PostModel = db.model('PostWithClashGetters', 'postwithclash' + random()); + + var post = new PostModel({ + title: 'Test' + , author: { name: 'A' } + , subject: { name: 'B' } + }); + + post.author.name.should.eql('A'); + post.subject.name.should.eql('B'); + post.author.name.should.eql('A'); + + db.close(); + }, + + 'test post save middleware': function () { + var schema = new Schema({ + title: String + }); + + var called = 0; + + schema.post('save', function (obj) { + obj.title.should.eql('Little Green Running Hood'); + called.should.equal(0); + called++; + }); + + schema.post('save', function (obj) { + obj.title.should.eql('Little Green Running Hood'); + called.should.equal(1); + called++; + }); + + schema.post('save', function (obj) { + obj.title.should.eql('Little Green Running Hood'); + called.should.equal(2); + db.close(); + }); + + var db = start() + , TestMiddleware = db.model('TestPostSaveMiddleware', schema); + + var test = new TestMiddleware({ title: 'Little Green Running Hood'}); + + test.save(function(err){ + should.strictEqual(err, null); + }); + }, + + 'test middleware': function () { + var schema = new Schema({ + title: String + }); + + var called = 0; + + schema.pre('init', function (next) { + called++; + next(); + }); + + schema.pre('save', function (next) { + called++; + next(new Error('Error 101')); + }); + + schema.pre('remove', function (next) { + called++; + next(); + }); + + mongoose.model('TestMiddleware', schema); + + var db = start() + , TestMiddleware = db.model('TestMiddleware'); + + var test = new TestMiddleware(); + + test.init({ + title: 'Test' + }); + + called.should.eql(1); + + test.save(function(err){ + err.should.be.an.instanceof(Error); + err.message.should.eql('Error 101'); + called.should.eql(2); + + test.remove(function(err){ + should.strictEqual(err, null); + called.should.eql(3); + db.close(); + }); + }); + }, + + 'test post init middleware': function () { + var schema = new Schema({ + title: String + }); + + var preinit = 0 + , postinit = 0 + + schema.pre('init', function (next) { + ++preinit; + next(); + }); + + schema.post('init', function () { + ++postinit; + }); + + mongoose.model('TestPostInitMiddleware', schema); + + var db = start() + , Test = db.model('TestPostInitMiddleware'); + + var test = new Test({ title: "banana" }); + + test.save(function(err){ + should.strictEqual(err, null); + + Test.findById(test._id, function (err, test) { + should.strictEqual(err, null); + preinit.should.eql(1); + postinit.should.eql(1); + test.remove(function(err){ + db.close(); + }); + }); + }); + }, + + 'test updating documents': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , title = 'Tobi ' + random() + , author = 'Brian ' + random() + , newTitle = 'Woot ' + random(); + + var post = new BlogPost(); + post.set('title', title); + post.author = author; + post.meta.visitors = 0; + + post.save(function (err) { + should.strictEqual(err, null); + BlogPost.findById(post._id, function (err, createdFound) { + should.strictEqual(err, null); + createdFound.title.should.equal(title); + createdFound.author.should.equal(author); + createdFound.meta.visitors.valueOf().should.eql(0); + + BlogPost.update({ title: title }, { title: newTitle }, function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post._id, function (err, updatedFound) { + should.strictEqual(err, null); + updatedFound.title.should.equal(newTitle); + updatedFound.author.should.equal(author); + updatedFound.meta.visitors.valueOf().should.equal(0); + + // Note: use BlogPost.collection.update for anything other than set operations + BlogPost.update({ _id: post._id }, { $inc: { 'meta.visitors': 1 } }, function (err) { + if (err) db.close(); + should.strictEqual(!!err, false, "Model.update doesn't work with $inc"); + + BlogPost.findById(post._id, function (err, updatedFound) { + db.close(); + should.strictEqual(err, null); + updatedFound.meta.visitors.valueOf().should.equal(1); + updatedFound.title.should.equal(newTitle); + updatedFound.author.should.equal(author); + }); + }); + }); + }); + }); + }); + }, + + 'test update doc casting': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + post.set('title', '1'); + + var id = post.get('_id'); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.update({ title: 1, _id: id }, { title: 2 }, function (err) { + should.strictEqual(err, null); + + BlogPost.findOne({ _id: post.get('_id') }, function (err, doc) { + should.strictEqual(err, null); + + doc.get('title').should.eql('2'); + db.close(); + }); + }); + }); + }, + + 'test $push casting': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , post = new BlogPost(); + + post.get('numbers').push('3'); + post.get('numbers')[0].should.equal(3); + db.close(); + }, + + 'test $pull casting': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , post = new BlogPost(); + + post.get('numbers').push(1, 2, 3, 4); + post.save( function (err) { + BlogPost.findById( post.get('_id'), function (err, found) { + found.get('numbers').length.should.equal(4); + found.get('numbers').$pull('3'); + found.save( function (err) { + BlogPost.findById( found.get('_id'), function (err, found2) { + found2.get('numbers').length.should.equal(3); + db.close(); + }); + }); + }); + }); + }, + + 'test updating numbers atomically': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , totalDocs = 4 + , saveQueue = []; + + var post = new BlogPost(); + post.set('meta.visitors', 5); + + post.save(function(err){ + if (err) throw err; + + BlogPost.findOne({ _id: post.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('meta.visitors').increment(); + doc.get('meta.visitors').valueOf().should.be.equal(6); + save(doc); + }); + + BlogPost.findOne({ _id: post.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('meta.visitors').increment(); + doc.get('meta.visitors').valueOf().should.be.equal(6); + save(doc); + }); + + BlogPost.findOne({ _id: post.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('meta.visitors').increment(); + doc.get('meta.visitors').valueOf().should.be.equal(6); + save(doc); + }); + + BlogPost.findOne({ _id: post.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('meta.visitors').increment(); + doc.get('meta.visitors').valueOf().should.be.equal(6); + save(doc); + }); + + function save(doc) { + saveQueue.push(doc); + if (saveQueue.length == 4) + saveQueue.forEach(function (doc) { + doc.save(function (err) { + if (err) throw err; + --totalDocs || complete(); + }); + }); + }; + + function complete () { + BlogPost.findOne({ _id: post.get('_id') }, function (err, doc) { + if (err) throw err; + doc.get('meta.visitors').valueOf().should.be.equal(9); + db.close(); + }); + }; + }); + }, + + 'test incrementing a number atomically with an arbitrary value': function () { + var db = start() + , BlogPost = db.model('BlogPost'); + + var post = new BlogPost(); + + post.meta.visitors = 0; + + post.save(function (err) { + should.strictEqual(err, null); + + post.meta.visitors.increment(50); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post._id, function (err, doc) { + should.strictEqual(err, null); + + (+doc.meta.visitors).should.eql(50); + db.close(); + }); + }); + }); + }, + + // GH-203 + 'test changing a number non-atomically': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + + post.meta.visitors = 5; + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post._id, function (err, doc) { + should.strictEqual(err, null); + + doc.meta.visitors -= 2; + + doc.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post._id, function (err, doc) { + should.strictEqual(err, null); + + (+doc.meta.visitors).should.eql(3); + db.close(); + }); + }); + }); + }); + }, + + 'test saving subdocuments atomically': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , totalDocs = 4 + , saveQueue = []; + + var post = new BlogPost(); + + post.save(function(err){ + if (err) throw err; + + BlogPost.findOne({ _id: post.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('comments').push({ title: '1' }); + save(doc); + }); + + BlogPost.findOne({ _id: post.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('comments').push({ title: '2' }); + save(doc); + }); + + BlogPost.findOne({ _id: post.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('comments').push({ title: '3' }); + save(doc); + }); + + BlogPost.findOne({ _id: post.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('comments').push({ title: '4' }, { title: '5' }); + save(doc); + }); + + function save(doc) { + saveQueue.push(doc); + if (saveQueue.length == 4) + saveQueue.forEach(function (doc) { + doc.save(function (err) { + if (err) throw err; + --totalDocs || complete(); + }); + }); + }; + + function complete () { + BlogPost.findOne({ _id: post.get('_id') }, function (err, doc) { + if (err) throw err; + + doc.get('comments').length.should.eql(5); + + doc.get('comments').some(function(comment){ + return comment.get('title') == '1'; + }).should.be.true; + + doc.get('comments').some(function(comment){ + return comment.get('title') == '2'; + }).should.be.true; + + doc.get('comments').some(function(comment){ + return comment.get('title') == '3'; + }).should.be.true; + + doc.get('comments').some(function(comment){ + return comment.get('title') == '4'; + }).should.be.true; + + doc.get('comments').some(function(comment){ + return comment.get('title') == '5'; + }).should.be.true; + + db.close(); + }); + }; + }); + }, + + // GH-310 + 'test setting a subdocument atomically': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + + BlogPost.create({ + comments: [{ title: 'first-title', body: 'first-body'}] + }, function (err, blog) { + should.strictEqual(null, err); + BlogPost.findById(blog.id, function (err, agent1blog) { + should.strictEqual(null, err); + BlogPost.findById(blog.id, function (err, agent2blog) { + should.strictEqual(null, err); + agent1blog.get('comments')[0].title = 'second-title'; + agent1blog.save( function (err) { + should.strictEqual(null, err); + agent2blog.get('comments')[0].body = 'second-body'; + agent2blog.save( function (err) { + should.strictEqual(null, err); + BlogPost.findById(blog.id, function (err, foundBlog) { + should.strictEqual(null, err); + db.close(); + var comment = foundBlog.get('comments')[0]; + comment.title.should.eql('second-title'); + comment.body.should.eql('second-body'); + }); + }); + }); + }); + }); + }); + }, + + 'test doubly nested array saving and loading': function(){ + var Inner = new Schema({ + arr: [Number] + }); + + var Outer = new Schema({ + inner: [Inner] + }); + mongoose.model('Outer', Outer); + + var db = start(); + var Outer = db.model('Outer', 'arr_test_' + random()); + + var outer = new Outer(); + outer.inner.push({}); + outer.save(function(err) { + should.strictEqual(err, null); + outer.get('_id').should.be.an.instanceof(DocumentObjectId); + + Outer.findById(outer.get('_id'), function(err, found) { + should.strictEqual(err, null); + should.equal(1, found.inner.length); + found.inner[0].arr.push(5); + found.save(function(err) { + should.strictEqual(err, null); + found.get('_id').should.be.an.instanceof(DocumentObjectId); + Outer.findById(found.get('_id'), function(err, found2) { + db.close(); + should.strictEqual(err, null); + should.equal(1, found2.inner.length); + should.equal(1, found2.inner[0].arr.length); + should.equal(5, found2.inner[0].arr[0]); + }); + }); + }); + }); + }, + + 'test updating multiple Number $pushes as a single $pushAll': function () { + var db = start() + , schema = new Schema({ + nested: { + nums: [Number] + } + }); + + mongoose.model('NestedPushes', schema); + var Temp = db.model('NestedPushes', collection); + + Temp.create({}, function (err, t) { + t.nested.nums.push(1); + t.nested.nums.push(2); + + t.nested.nums.should.have.length(2); + + t.save( function (err) { + should.strictEqual(null, err); + t.nested.nums.should.have.length(2); + Temp.findById(t._id, function (err, found) { + found.nested.nums.should.have.length(2); + db.close(); + }); + }); + }); + }, + + 'test updating at least a single $push and $pushAll as a single $pushAll': function () { + var db = start() + , schema = new Schema({ + nested: { + nums: [Number] + } + }); + + mongoose.model('NestedPushes', schema); + var Temp = db.model('NestedPushes', collection); + + Temp.create({}, function (err, t) { + t.nested.nums.push(1); + t.nested.nums.$pushAll([2, 3]); + + t.nested.nums.should.have.length(3); + + t.save( function (err) { + should.strictEqual(null, err); + t.nested.nums.should.have.length(3); + Temp.findById(t._id, function (err, found) { + found.nested.nums.should.have.length(3); + db.close(); + }); + }); + }); + }, + + 'test activePaths should be updated for nested modifieds': function () { + var db = start() + , schema = new Schema({ + nested: { + nums: [Number] + } + }); + + mongoose.model('NestedPushes', schema); + var Temp = db.model('NestedPushes', collection); + + Temp.create({nested: {nums: [1, 2, 3, 4, 5]}}, function (err, t) { + t.nested.nums.$pull(1); + t.nested.nums.$pull(2); + + t.activePaths.stateOf('nested.nums').should.equal('modify'); + db.close(); + + }); + }, + + '$pull should affect what you see in an array before a save': function () { + var db = start() + , schema = new Schema({ + nested: { + nums: [Number] + } + }); + + mongoose.model('NestedPushes', schema); + var Temp = db.model('NestedPushes', collection); + + Temp.create({nested: {nums: [1, 2, 3, 4, 5]}}, function (err, t) { + t.nested.nums.$pull(1); + + t.nested.nums.should.have.length(4); + + db.close(); + }); + }, + + '$pullAll should affect what you see in an array before a save': function () { + var db = start() + , schema = new Schema({ + nested: { + nums: [Number] + } + }); + + mongoose.model('NestedPushes', schema); + var Temp = db.model('NestedPushes', collection); + + Temp.create({nested: {nums: [1, 2, 3, 4, 5]}}, function (err, t) { + t.nested.nums.$pullAll([1, 2, 3]); + + t.nested.nums.should.have.length(2); + + db.close(); + }); + }, + + 'test updating multiple Number $pulls as a single $pullAll': function () { + var db = start() + , schema = new Schema({ + nested: { + nums: [Number] + } + }); + + mongoose.model('NestedPushes', schema); + var Temp = db.model('NestedPushes', collection); + + Temp.create({nested: {nums: [1, 2, 3, 4, 5]}}, function (err, t) { + t.nested.nums.$pull(1); + t.nested.nums.$pull(2); + + t.nested.nums.should.have.length(3); + + t.save( function (err) { + should.strictEqual(null, err); + t.nested.nums.should.have.length(3); + Temp.findById(t._id, function (err, found) { + found.nested.nums.should.have.length(3); + db.close(); + }); + }); + }); + }, + + 'having both a pull and pullAll should default to pullAll': function () { + var db = start() + , schema = new Schema({ + nested: { + nums: [Number] + } + }); + + mongoose.model('NestedPushes', schema); + var Temp = db.model('NestedPushes', collection); + + Temp.create({nested: {nums: [1, 2, 3, 4, 5]}}, function (err, t) { + t.nested.nums.$pull(1); + t.nested.nums.$pullAll([2, 3]); + + t.nested.nums.should.have.length(2); + + t.save( function (err) { + should.strictEqual(null, err); + t.nested.nums.should.have.length(2); + Temp.findById(t._id, function (err, found) { + found.nested.nums.should.have.length(2); + db.close(); + }); + }); + }); + }, + + '$shift': function () { + var db = start() + , schema = new Schema({ + nested: { + nums: [Number] + } + }); + + mongoose.model('TestingShift', schema); + var Temp = db.model('TestingShift', collection); + + Temp.create({ nested: { nums: [1,2,3] }}, function (err, t) { + should.strictEqual(null, err); + + Temp.findById(t._id, function (err, found) { + should.strictEqual(null, err); + found.nested.nums.should.have.length(3); + found.nested.nums.$pop(); + found.nested.nums.should.have.length(2); + found.nested.nums[0].should.eql(1); + found.nested.nums[1].should.eql(2); + + found.save(function (err) { + should.strictEqual(null, err); + Temp.findById(t._id, function (err, found) { + should.strictEqual(null, err); + found.nested.nums.should.have.length(2); + found.nested.nums[0].should.eql(1); + found.nested.nums[1].should.eql(2); + found.nested.nums.$shift(); + found.nested.nums.should.have.length(1); + found.nested.nums[0].should.eql(2); + + found.save(function (err) { + should.strictEqual(null, err); + Temp.findById(t._id, function (err, found) { + db.close(); + should.strictEqual(null, err); + found.nested.nums.should.have.length(1); + found.nested.nums[0].should.eql(2); + }); + }); + }); + }); + }); + }); + }, + + 'test saving embedded arrays of Numbers atomically': function () { + var db = start() + , TempSchema = new Schema({ + nums: [Number] + }) + , totalDocs = 2 + , saveQueue = []; + + mongoose.model('Temp', TempSchema); + var Temp = db.model('Temp', collection); + + var t = new Temp(); + + t.save(function(err){ + if (err) throw err; + + Temp.findOne({ _id: t.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('nums').push(1); + save(doc); + }); + + Temp.findOne({ _id: t.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('nums').push(2, 3); + save(doc); + }); + + + function save(doc) { + saveQueue.push(doc); + if (saveQueue.length == totalDocs) + saveQueue.forEach(function (doc) { + doc.save(function (err) { + if (err) throw err; + --totalDocs || complete(); + }); + }); + }; + + function complete () { + Temp.findOne({ _id: t.get('_id') }, function (err, doc) { + if (err) throw err; + + doc.get('nums').length.should.eql(3); + + doc.get('nums').some(function(num){ + return num.valueOf() == '1'; + }).should.be.true; + + doc.get('nums').some(function(num){ + return num.valueOf() == '2'; + }).should.be.true; + + doc.get('nums').some(function(num){ + return num.valueOf() == '3'; + }).should.be.true; + + + db.close(); + }); + }; + }); + }, + + 'test saving embedded arrays of Strings atomically': function () { + var db = start() + , StrListSchema = new Schema({ + strings: [String] + }) + , totalDocs = 2 + , saveQueue = []; + + mongoose.model('StrList', StrListSchema); + var StrList = db.model('StrList'); + + var t = new StrList(); + + t.save(function(err){ + if (err) throw err; + + StrList.findOne({ _id: t.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('strings').push('a'); + save(doc); + }); + + StrList.findOne({ _id: t.get('_id') }, function(err, doc){ + if (err) throw err; + doc.get('strings').push('b', 'c'); + save(doc); + }); + + + function save(doc) { + saveQueue.push(doc); + if (saveQueue.length == totalDocs) + saveQueue.forEach(function (doc) { + doc.save(function (err) { + if (err) throw err; + --totalDocs || complete(); + }); + }); + }; + + function complete () { + StrList.findOne({ _id: t.get('_id') }, function (err, doc) { + if (err) throw err; + + doc.get('strings').length.should.eql(3); + + doc.get('strings').some(function(str){ + return str == 'a'; + }).should.be.true; + + doc.get('strings').some(function(str){ + return str == 'b'; + }).should.be.true; + + doc.get('strings').some(function(str){ + return str == 'c'; + }).should.be.true; + + db.close(); + }); + }; + }); + }, + + // GH-255 + 'test updating an embedded document in an embedded array': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create({comments: [{title: 'woot'}]}, function (err, post) { + should.strictEqual(err, null); + BlogPost.findById(post._id, function (err, found) { + should.strictEqual(err, null); + found.comments[0].title.should.equal('woot'); + found.comments[0].title = 'notwoot'; + found.save( function (err) { + should.strictEqual(err, null); + BlogPost.findById(found._id, function (err, updated) { + db.close(); + should.strictEqual(err, null); + updated.comments[0].title.should.equal('notwoot'); + }); + }); + }); + }); + }, + + // GH-334 + 'test updating an embedded array document to an Object value': function () { + var db = start() + , SubSchema = new Schema({ + name : String , + subObj : { subName : String } + }); + var GH334Schema = new Schema ({ name : String , arrData : [ SubSchema] }); + + mongoose.model('GH334' , GH334Schema); + var AModel = db.model('GH334'); + var instance = new AModel(); + + instance.set( { name : 'name-value' , arrData : [ { name : 'arrName1' , subObj : { subName : 'subName1' } } ] }); + instance.save(function(err) { + AModel.findById(instance.id, function(err, doc) { + doc.arrData[0].set('subObj' , { subName : 'modified subName' }); + doc.save(function(err) { + should.strictEqual(null, err); + AModel.findById(instance.id, function (err, doc) { + db.close(); + should.strictEqual(null, err); + doc.arrData[0].subObj.subName.should.eql('modified subName'); + }); + }); + }); + }); + }, + + // GH-267 + 'saving an embedded document twice should not push that doc onto the parent doc twice': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , post = new BlogPost(); + + post.comments.push({title: 'woot'}); + post.save( function (err) { + should.strictEqual(err, null); + post.comments.should.have.length(1); + BlogPost.findById(post.id, function (err, found) { + should.strictEqual(err, null); + found.comments.should.have.length(1); + post.save( function (err) { + should.strictEqual(err, null); + post.comments.should.have.length(1); + BlogPost.findById(post.id, function (err, found) { + db.close(); + should.strictEqual(err, null); + found.comments.should.have.length(1); + }); + }); + }); + }); + }, + + 'test filtering an embedded array by the id shortcut function': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + + post.comments.push({ title: 'woot' }); + post.comments.push({ title: 'aaaa' }); + + var subdoc1 = post.comments[0]; + var subdoc2 = post.comments[1]; + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post.get('_id'), function (err, doc) { + should.strictEqual(err, null); + + // test with an objectid + doc.comments.id(subdoc1.get('_id')).title.should.eql('woot'); + + // test with a string + var id = DocumentObjectId.toString(subdoc2._id); + doc.comments.id(id).title.should.eql('aaaa'); + + db.close(); + }); + }); + }, + + 'test filtering an embedded array by the id with cast error': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post.get('_id'), function (err, doc) { + should.strictEqual(err, null); + should.strictEqual(doc.comments.id(null), null); + + db.close(); + }); + }); + }, + + 'test filtering an embedded array by the id shortcut with no match': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post.get('_id'), function (err, doc) { + should.strictEqual(err, null); + should.strictEqual(doc.comments.id(new DocumentObjectId), null); + + db.close(); + }); + }); + }, + + 'test for removing a subdocument atomically': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + post.title = 'hahaha'; + post.comments.push({ title: 'woot' }); + post.comments.push({ title: 'aaaa' }); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post.get('_id'), function (err, doc) { + should.strictEqual(err, null); + + doc.comments[0].remove(); + doc.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post.get('_id'), function (err, doc) { + should.strictEqual(err, null); + + doc.comments.should.have.length(1); + doc.comments[0].title.should.eql('aaaa'); + + db.close(); + }); + }); + }); + }); + }, + + 'try saving mixed data': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , count = 3; + + // string + var post = new BlogPost(); + post.mixed = 'woot'; + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post._id, function (err) { + should.strictEqual(err, null); + + --count || db.close(); + }); + }); + + // array + var post2 = new BlogPost(); + post2.mixed = { name: "mr bungle", arr: [] }; + post2.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post2._id, function (err, doc){ + should.strictEqual(err, null); + + Array.isArray(doc.mixed.arr).should.be.true; + + doc.mixed = [{foo: 'bar'}]; + doc.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(doc._id, function (err, doc){ + should.strictEqual(err, null); + + Array.isArray(doc.mixed).should.be.true; + doc.mixed.push({ hello: 'world' }); + doc.mixed.push([ 'foo', 'bar' ]); + doc.commit('mixed'); + + doc.save(function (err, doc) { + should.strictEqual(err, null); + + BlogPost.findById(post2._id, function (err, doc) { + should.strictEqual(err, null); + + doc.mixed[0].should.eql({ foo: 'bar' }); + doc.mixed[1].should.eql({ hello: 'world' }); + doc.mixed[2].should.eql(['foo','bar']); + --count || db.close(); + }); + }); + }); + + // date + var post3 = new BlogPost(); + post3.mixed = new Date; + post3.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post3._id, function (err, doc) { + should.strictEqual(err, null); + + doc.mixed.should.be.an.instanceof(Date); + --count || db.close(); + }); + }); + }); + + }); + }); + + }, + + // GH-200 + 'try populating mixed data from the constructor': function () { + var db = start() + , BlogPost = db.model('BlogPost'); + + var post = new BlogPost({ + mixed: { + type: 'test' + , github: 'rules' + , nested: { + number: 3 + } + } + }); + + post.mixed.type.should.eql('test'); + post.mixed.github.should.eql('rules'); + post.mixed.nested.number.should.eql(3); + + db.close(); + }, + + 'test that we don\'t instantiate MongooseNumber in arrays': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + post.numbers.push(1, '2', 3); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post._id, function (err, doc) { + should.strictEqual(err, null); + + (~doc.numbers.indexOf(1)).should.not.eql(0); + (~doc.numbers.indexOf(2)).should.not.eql(0); + (~doc.numbers.indexOf(3)).should.not.eql(0); + + db.close(); + }); + }); + }, + + 'test removing from an array atomically using MongooseArray#remove': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + post.numbers.push(1, 2, 3); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post._id, function (err, doc) { + should.strictEqual(err, null); + + doc.numbers.remove('1'); + doc.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post.get('_id'), function (err, doc) { + should.strictEqual(err, null); + + doc.numbers.should.have.length(2); + doc.numbers.remove('2', '3'); + + doc.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post._id, function (err, doc) { + should.strictEqual(err, null); + + doc.numbers.should.have.length(0); + db.close(); + }); + }); + }); + }); + }); + }); + }, + + 'test getting a virtual property via get(...)': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , post = new BlogPost({ + title: 'Letters from Earth' + , author: 'Mark Twain' + }); + + post.get('titleWithAuthor').should.equal('Letters from Earth by Mark Twain'); + + db.close(); + }, + + 'test setting a virtual property': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , post = new BlogPost(); + + post.set('titleWithAuthor', 'Huckleberry Finn by Mark Twain') + post.get('title').should.equal('Huckleberry Finn'); + post.get('author').should.equal('Mark Twain'); + + db.close(); + }, + + 'test getting a virtual property via shortcut getter': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , post = new BlogPost({ + title: 'Letters from Earth' + , author: 'Mark Twain' + }); + + post.titleWithAuthor.should.equal('Letters from Earth by Mark Twain'); + + db.close(); + }, + + 'saving a doc with a set virtual property should persist the real properties but not the virtual property': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection) + , post = new BlogPost(); + + post.set('titleWithAuthor', 'Huckleberry Finn by Mark Twain') + post.get('title').should.equal('Huckleberry Finn'); + post.get('author').should.equal('Mark Twain'); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post.get('_id'), function (err, found) { + should.strictEqual(err, null); + + found.get('title').should.equal('Huckleberry Finn'); + found.get('author').should.equal('Mark Twain'); + found.toObject().should.not.have.property('titleWithAuthor'); + db.close(); + }); + }); + }, + + 'test setting a pseudo-nested virtual property': function () { + var db = start() + , PersonSchema = new Schema({ + name: { + first: String + , last: String + } + }); + + PersonSchema.virtual('name.full') + .get( function () { + return this.get('name.first') + ' ' + this.get('name.last'); + }) + .set( function (fullName) { + var split = fullName.split(' '); + this.set('name.first', split[0]); + this.set('name.last', split[1]); + }); + + mongoose.model('Person', PersonSchema); + + var Person = db.model('Person') + , person = new Person({ + name: { + first: 'Michael' + , last: 'Sorrentino' + } + }); + + person.get('name.full').should.equal('Michael Sorrentino'); + person.set('name.full', 'The Situation'); + person.get('name.first').should.equal('The'); + person.get('name.last').should.equal('Situation'); + + person.name.full.should.equal('The Situation'); + person.name.full = 'Michael Sorrentino'; + person.name.first.should.equal('Michael'); + person.name.last.should.equal('Sorrentino'); + + db.close(); + }, + + 'test removing all documents from a collection via Model.remove': function () { + var db = start() + , collection = 'blogposts_' + random() + , BlogPost = db.model('BlogPost', collection) + , post = new BlogPost(); + + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.find({}, function (err, found) { + should.strictEqual(err, null); + + found.should.have.length(1); + + BlogPost.remove({}, function (err) { + should.strictEqual(!!err, false); + + BlogPost.find({}, function (err, found2) { + should.strictEqual(err, null); + + found2.should.have.length(0); + db.close(); + }); + }); + }); + }); + }, + + // GH-190 + 'test shorcut getter for a type defined with { type: Native }': function () { + var schema = new Schema({ + date: { type: Date } + }); + + mongoose.model('ShortcutGetterObject', schema); + + var db = start() + , ShortcutGetter = db.model('ShortcutGetterObject', 'shortcut' + random()) + , post = new ShortcutGetter(); + + post.set('date', Date.now()); + post.date.should.be.an.instanceof(Date); + + db.close(); + }, + + 'test shortcut getter for a nested path': function () { + var schema = new Schema({ + first: { + second: [Number] + } + }); + mongoose.model('ShortcutGetterNested', schema); + + var db = start() + , ShortcutGetterNested = db.model('ShortcutGetterNested', collection) + , doc = new ShortcutGetterNested(); + + doc.first.should.be.a('object'); + doc.first.second.should.be.an.instanceof(MongooseArray); + + db.close(); + }, + + // GH-195 + 'test that save on an unaltered model doesn\'t clear the document': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + post.title = 'woot'; + post.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(post._id, function (err, doc) { + should.strictEqual(err, null); + + // we deliberately make no alterations + doc.save(function (err) { + should.strictEqual(err, null); + + BlogPost.findById(doc._id, function (err, doc) { + should.strictEqual(err, null); + + doc.title.should.eql('woot'); + db.close(); + }); + }); + }); + }); + }, + + 'test that safe mode is the default and it works': function () { + var Human = new Schema({ + name : String + , email : { type: String, unique: true } + }); + + mongoose.model('SafeHuman', Human, true); + + var db = start() + , Human = db.model('SafeHuman', 'safehuman' + random()); + + var me = new Human({ + name : 'Guillermo Rauch' + , email : 'rauchg@gmail.com' + }); + + me.save(function (err) { + should.strictEqual(err, null); + + Human.findById(me._id, function (err, doc){ + should.strictEqual(err, null); + doc.email.should.eql('rauchg@gmail.com'); + + var copycat = new Human({ + name : 'Lionel Messi' + , email : 'rauchg@gmail.com' + }); + + copycat.save(function (err) { + /duplicate/.test(err.message).should.be.true; + err.should.be.an.instanceof(Error); + db.close(); + }); + }); + }); + }, + + 'test that safe mode can be turned off': function () { + var Human = new Schema({ + name : String + , email : { type: String, unique: true } + }); + + // turn it off + Human.set('safe', false); + + mongoose.model('UnsafeHuman', Human, true); + + var db = start() + , Human = db.model('UnsafeHuman', 'unsafehuman' + random()); + + var me = new Human({ + name : 'Guillermo Rauch' + , email : 'rauchg@gmail.com' + }); + + me.save(function (err) { + should.strictEqual(err, null); + + Human.findById(me._id, function (err, doc){ + should.strictEqual(err, null); + doc.email.should.eql('rauchg@gmail.com'); + + var copycat = new Human({ + name : 'Lionel Messi' + , email : 'rauchg@gmail.com' + }); + + copycat.save(function (err) { + should.strictEqual(err, null); + db.close(); + }); + }); + }); + }, + + 'passing null in pre hook works': function () { + var db = start(); + var schema = new Schema({ name: String }); + + schema.pre('save', function (next) { + next(null); // <<----- + }); + + var S = db.model('S', schema, collection); + var s = new S({name: 'zupa'}); + + s.save(function (err) { + db.close(); + should.strictEqual(null, err); + }); + + }, + + 'test post hooks': function () { + var schema = new Schema({ + title: String + }) + , save = false + , remove = false + , init = false; + + schema.post('save', function () { + save = true; + }); + + schema.post('init', function () { + init = true; + }); + + schema.post('remove', function () { + remove = true; + }); + + mongoose.model('PostHookTest', schema); + + var db = start() + , BlogPost = db.model('PostHookTest'); + + var post = new BlogPost(); + + post.save(function (err) { + process.nextTick(function () { + should.strictEqual(err, null); + save.should.be.true; + + BlogPost.findById(post._id, function (err, doc) { + process.nextTick(function () { + should.strictEqual(err, null); + init.should.be.true; + + doc.remove(function (err) { + process.nextTick(function () { + should.strictEqual(err, null); + remove.should.be.true; + db.close(); + }); + }); + }); + }); + }); + }); + }, + + 'test count querying via #run (aka #exec)': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create({title: 'interoperable count as promise'}, function (err, created) { + should.strictEqual(err, null); + var query = BlogPost.count({title: 'interoperable count as promise'}); + query.exec(function (err, count) { + should.strictEqual(err, null); + count.should.equal(1); + db.close(); + }); + }); + }, + + 'test update querying via #run (aka #exec)': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create({title: 'interoperable update as promise'}, function (err, created) { + should.strictEqual(err, null); + var query = BlogPost.update({title: 'interoperable update as promise'}, {title: 'interoperable update as promise delta'}); + query.exec(function (err) { + should.strictEqual(err, null); + BlogPost.count({title: 'interoperable update as promise delta'}, function (err, count) { + should.strictEqual(err, null); + count.should.equal(1); + db.close(); + }); + }); + }); + }, + + 'test findOne querying via #run (aka #exec)': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create({title: 'interoperable findOne as promise'}, function (err, created) { + should.strictEqual(err, null); + var query = BlogPost.findOne({title: 'interoperable findOne as promise'}); + query.exec(function (err, found) { + should.strictEqual(err, null); + found._id.should.eql(created._id); + db.close(); + }); + }); + }, + + 'test find querying via #run (aka #exec)': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create( + {title: 'interoperable find as promise'} + , {title: 'interoperable find as promise'} + , function (err, createdOne, createdTwo) { + should.strictEqual(err, null); + var query = BlogPost.find({title: 'interoperable find as promise'}); + query.exec(function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + found[0]._id.should.eql(createdOne._id); + found[1]._id.should.eql(createdTwo._id); + db.close(); + }); + }); + }, + + 'test remove querying via #run (aka #exec)': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create( + {title: 'interoperable remove as promise'} + , function (err, createdOne, createdTwo) { + should.strictEqual(err, null); + var query = BlogPost.remove({title: 'interoperable remove as promise'}); + query.exec(function (err) { + should.strictEqual(err, null); + BlogPost.count({title: 'interoperable remove as promise'}, function (err, count) { + db.close(); + count.should.equal(0); + }); + }); + }); + }, + + 'test changing query at the last minute via #run(op, callback)': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create({title: 'interoperable ad-hoc as promise'}, function (err, created) { + should.strictEqual(err, null); + var query = BlogPost.count({title: 'interoperable ad-hoc as promise'}); + query.exec('findOne', function (err, found) { + should.strictEqual(err, null); + found._id.should.eql(created._id); + db.close(); + }); + }); + }, + + 'test count querying via #run (aka #exec) with promise': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create({title: 'interoperable count as promise 2'}, function (err, created) { + should.strictEqual(err, null); + var query = BlogPost.count({title: 'interoperable count as promise 2'}); + var promise = query.exec(); + promise.addBack(function (err, count) { + should.strictEqual(err, null); + count.should.equal(1); + db.close(); + }); + }); + }, + + 'test update querying via #run (aka #exec) with promise': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create({title: 'interoperable update as promise 2'}, function (err, created) { + should.strictEqual(err, null); + var query = BlogPost.update({title: 'interoperable update as promise 2'}, {title: 'interoperable update as promise delta 2'}); + var promise = query.run(); + promise.addBack(function (err) { + should.strictEqual(err, null); + BlogPost.count({title: 'interoperable update as promise delta 2'}, function (err, count) { + should.strictEqual(err, null); + count.should.equal(1); + db.close(); + }); + }); + }); + }, + + 'test findOne querying via #run (aka #exec) with promise': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create({title: 'interoperable findOne as promise 2'}, function (err, created) { + should.strictEqual(err, null); + var query = BlogPost.findOne({title: 'interoperable findOne as promise 2'}); + var promise = query.exec(); + promise.addBack(function (err, found) { + should.strictEqual(err, null); + found._id.should.eql(created._id); + db.close(); + }); + }); + }, + + 'test find querying via #run (aka #exec) with promise': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create( + {title: 'interoperable find as promise 2'} + , {title: 'interoperable find as promise 2'} + , function (err, createdOne, createdTwo) { + should.strictEqual(err, null); + var query = BlogPost.find({title: 'interoperable find as promise 2'}); + var promise = query.run(); + promise.addBack(function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + found[0]._id.should.eql(createdOne._id); + found[1]._id.should.eql(createdTwo._id); + db.close(); + }); + }); + }, + + 'test remove querying via #run (aka #exec) with promise': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create( + {title: 'interoperable remove as promise 2'} + , function (err, createdOne, createdTwo) { + should.strictEqual(err, null); + var query = BlogPost.remove({title: 'interoperable remove as promise 2'}); + var promise = query.exec(); + promise.addBack(function (err) { + should.strictEqual(err, null); + BlogPost.count({title: 'interoperable remove as promise 2'}, function (err, count) { + count.should.equal(0); + db.close(); + }); + }); + }); + }, + + 'test changing query at the last minute via #run(op) with promise': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + BlogPost.create({title: 'interoperable ad-hoc as promise 2'}, function (err, created) { + should.strictEqual(err, null); + var query = BlogPost.count({title: 'interoperable ad-hoc as promise 2'}); + var promise = query.exec('findOne'); + promise.addBack(function (err, found) { + should.strictEqual(err, null); + found._id.should.eql(created._id); + db.close(); + }); + }); + }, + + 'test nested obj literal getter/setters': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var date = new Date; + + var meta = { + date: date + , visitors: 5 + }; + + var post = new BlogPost() + post.init({ + meta: meta + }); + + post.get('meta').date.should.be.an.instanceof(Date); + post.meta.date.should.be.an.instanceof(Date); + + var threw = false; + var getter1; + var getter2; + var strmet; + try { + strmet = JSON.stringify(meta); + getter1 = JSON.stringify(post.get('meta')); + getter2 = JSON.stringify(post.meta); + } catch (err) { + threw = true; + } + + threw.should.be.false; + getter1 = JSON.parse(getter1); + getter2 = JSON.parse(getter2); + getter1.visitors.should.eql(getter2.visitors); + getter1.date.should.eql(getter2.date); + + post.meta.date = new Date - 1000; + post.meta.date.should.be.an.instanceof(Date); + post.get('meta').date.should.be.an.instanceof(Date); + + post.meta.visitors = 2; + post.get('meta').visitors.should.be.an.instanceof(MongooseNumber); + post.meta.visitors.should.be.an.instanceof(MongooseNumber); + + var newmeta = { + date: date - 2000 + , visitors: 234 + }; + + post.set(newmeta, 'meta'); + + post.meta.date.should.be.an.instanceof(Date); + post.get('meta').date.should.be.an.instanceof(Date); + post.meta.visitors.should.be.an.instanceof(MongooseNumber); + post.get('meta').visitors.should.be.an.instanceof(MongooseNumber); + (+post.meta.date).should.eql(date - 2000); + (+post.get('meta').date).should.eql(date - 2000); + (+post.meta.visitors).should.eql(234); + (+post.get('meta').visitors).should.eql(234); + + // set object directly + post.meta = { + date: date - 3000 + , visitors: 4815162342 + }; + + post.meta.date.should.be.an.instanceof(Date); + post.get('meta').date.should.be.an.instanceof(Date); + post.meta.visitors.should.be.an.instanceof(MongooseNumber); + post.get('meta').visitors.should.be.an.instanceof(MongooseNumber); + (+post.meta.date).should.eql(date - 3000); + (+post.get('meta').date).should.eql(date - 3000); + (+post.meta.visitors).should.eql(4815162342); + (+post.get('meta').visitors).should.eql(4815162342); + + db.close(); + }, + + 'nested object property access works when root initd with null': function () { + var db = start() + + var schema = new Schema({ + nest: { + st: String + } + }); + + mongoose.model('NestedStringA', schema); + var T = db.model('NestedStringA', collection); + + var t = new T({ nest: null }); + + should.strictEqual(t.nest.st, null); + t.nest = { st: "jsconf rules" }; + t.nest.toObject().should.eql({ st: "jsconf rules" }); + t.nest.st.should.eql("jsconf rules"); + + t.save(function (err) { + should.strictEqual(err, null); + db.close(); + }) + + }, + + 'nested object property access works when root initd with undefined': function () { + var db = start() + + var schema = new Schema({ + nest: { + st: String + } + }); + + mongoose.model('NestedStringB', schema); + var T = db.model('NestedStringB', collection); + + var t = new T({ nest: undefined }); + + should.strictEqual(t.nest.st, undefined); + t.nest = { st: "jsconf rules" }; + t.nest.toObject().should.eql({ st: "jsconf rules" }); + t.nest.st.should.eql("jsconf rules"); + + t.save(function (err) { + should.strictEqual(err, null); + db.close(); + }) + }, + + 're-saving object with pre-existing null nested object': function(){ + var db = start() + + var schema = new Schema({ + nest: { + st: String + , yep: String + } + }); + + mongoose.model('NestedStringC', schema); + var T = db.model('NestedStringC', collection); + + var t = new T({ nest: null }); + + t.save(function (err) { + should.strictEqual(err, null); + + t.nest = { st: "jsconf rules", yep: "it does" }; + t.save(function (err) { + should.strictEqual(err, null); + + T.findById(t.id, function (err, t) { + should.strictEqual(err, null); + t.nest.st.should.eql("jsconf rules"); + t.nest.yep.should.eql("it does"); + + t.nest = null; + t.save(function (err) { + should.strictEqual(err, null); + should.strictEqual(t.doc.nest, null); + db.close(); + }); + }); + }); + }); + }, + + 'pushing to a nested array of Mixed works on existing doc': function () { + var db = start(); + + mongoose.model('MySchema', new Schema({ + nested: { + arrays: [] + } + })); + + var DooDad = db.model('MySchema') + , doodad = new DooDad({ nested: { arrays: [] } }) + , date = 1234567890; + + doodad.nested.arrays.push(["+10", "yup", date]); + + doodad.save(function (err) { + should.strictEqual(err, null); + + DooDad.findById(doodad._id, function (err, doodad) { + should.strictEqual(err, null); + + doodad.nested.arrays.toObject().should.eql([['+10','yup',date]]); + + doodad.nested.arrays.push(["another", 1]); + + doodad.save(function (err) { + should.strictEqual(err, null); + + DooDad.findById(doodad._id, function (err, doodad) { + should.strictEqual(err, null); + + doodad + .nested + .arrays + .toObject() + .should.eql([['+10','yup',date], ["another", 1]]); + + db.close(); + }); + }); + }) + }); + + }, + + 'directly setting nested props works when property is named "type"': function () { + var db = start(); + + function def () { + return [{ x: 1 }, { x: 2 }, { x:3 }] + } + + mongoose.model('MySchema2', new Schema({ + nested: { + type: { type: String, default: 'yep' } + , array: { + type: Array, default: def + } + } + })); + + var DooDad = db.model('MySchema2', collection) + , doodad = new DooDad() + + doodad.save(function (err) { + should.strictEqual(err, null); + + DooDad.findById(doodad._id, function (err, doodad) { + should.strictEqual(err, null); + + doodad.nested.type.should.eql("yep"); + doodad.nested.array.toObject().should.eql([{x:1},{x:2},{x:3}]); + + doodad.nested.type = "nope"; + doodad.nested.array = ["some", "new", "stuff"]; + + doodad.save(function (err) { + should.strictEqual(err, null); + + DooDad.findById(doodad._id, function (err, doodad) { + should.strictEqual(err, null); + db.close(); + + doodad.nested.type.should.eql("nope"); + + doodad + .nested + .array + .toObject() + .should.eql(["some", "new", "stuff"]); + + }); + }); + }) + }); + }, + + 'system.profile should be a default model': function () { + var Profile = mongoose.model('system.profile'); + Profile.schema.paths.ts.should.be.a('object'); + Profile.schema.paths.info.should.be.a('object'); + Profile.schema.paths.millis.should.be.a('object'); + + var db = start(); + Profile = db.model('system.profile'); + Profile.schema.paths.ts.should.be.a('object'); + Profile.schema.paths.info.should.be.a('object'); + Profile.schema.paths.millis.should.be.a('object'); + db.close(); + }, + + 'setting profiling levels': function () { + var db = start(); + db.setProfiling(3, function (err) { + err.message.should.eql('Invalid profiling level: 3'); + db.setProfiling('fail', function (err) { + err.message.should.eql('Invalid profiling level: fail'); + db.setProfiling(2, function (err, doc) { + should.strictEqual(err, null); + db.setProfiling(1, 50, function (err, doc) { + should.strictEqual(err, null); + doc.was.should.eql(2); + db.setProfiling(0, function (err, doc) { + db.close(); + should.strictEqual(err, null); + doc.was.should.eql(1); + doc.slowms.should.eql(50); + }); + }); + }); + }); + }); + }, + + 'test post hooks on embedded documents': function(){ + var save = false, + init = false, + remove = false; + + var EmbeddedSchema = new Schema({ + title : String + }); + + var ParentSchema = new Schema({ + embeds : [EmbeddedSchema] + }); + + EmbeddedSchema.post('save', function(next){ + save = true; + }); + + // Don't know how to test those on a embedded document. + /* + + EmbeddedSchema.post('init', function () { + init = true; + }); + + EmbeddedSchema.post('remove', function () { + remove = true; + }); + + */ + + mongoose.model('Parent', ParentSchema); + + var db = start(), + Parent = db.model('Parent'); + + var parent = new Parent(); + + parent.embeds.push({title: 'Testing post hooks for embedded docs'}); + + parent.save(function(err){ + db.close(); + should.strictEqual(err, null); + save.should.be.true; + }); + }, + + 'console.log shows helpful values': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var date = new Date(1305730951086); + var id0 = new DocumentObjectId('4dd3e169dbfb13b4570000b9'); + var id1 = new DocumentObjectId('4dd3e169dbfb13b4570000b6'); + var id2 = new DocumentObjectId('4dd3e169dbfb13b4570000b7'); + var id3 = new DocumentObjectId('4dd3e169dbfb13b4570000b8'); + + var post = new BlogPost({ + title: 'Test' + , _id: id0 + , date: date + , numbers: [5,6,7] + , owners: [id1] + , meta: { visitors: 45 } + , comments: [ + { _id: id2, title: 'my comment', date: date, body: 'this is a comment' }, + { _id: id3, title: 'the next thang', date: date, body: 'this is a comment too!' }] + }); + + db.close(); + + var a = '{ meta: { visitors: 45 },\n numbers: [ 5, 6, 7 ],\n owners: [ 4dd3e169dbfb13b4570000b6 ],\n comments: \n [{ _id: 4dd3e169dbfb13b4570000b7,\n comments: [],\n body: \'this is a comment\',\n date: Wed, 18 May 2011 15:02:31 GMT,\n title: \'my comment\' }\n { _id: 4dd3e169dbfb13b4570000b8,\n comments: [],\n body: \'this is a comment too!\',\n date: Wed, 18 May 2011 15:02:31 GMT,\n title: \'the next thang\' }],\n _id: 4dd3e169dbfb13b4570000b9,\n date: Wed, 18 May 2011 15:02:31 GMT,\n title: \'Test\' }' + + post.inspect().should.eql(a); + }, + + 'path can be used as pathname': function () { + var db = start() + , P = db.model('pathnametest', new Schema({ path: String })) + db.close(); + + var threw = false; + try { + new P({ path: 'i should not throw' }); + } catch (err) { + threw = true; + } + + threw.should.be.false; + + }, + + 'when mongo is down, save callback should fire with err': function () { + var db = start(); + var T = db.model('Thing', new Schema({ type: String })); + db.close(); + + var t = new T({ type: "monster" }); + + var worked = false; + t.save(function (err) { + worked = true; + err.message.should.eql('notConnected'); + }); + + setTimeout(function () { + worked.should.be.true; + }, 1000); + }, + + 'subdocuments with changed values should persist the values': function () { + var db = start() + var Subdoc = new Schema({ name: String, mixed: Schema.Types.Mixed }); + var T = db.model('SubDocMixed', new Schema({ subs: [Subdoc] })); + + var t = new T({ subs: [{ name: "Hubot", mixed: { w: 1, x: 2 }}] }); + t.subs[0].name.should.equal("Hubot"); + t.subs[0].mixed.w.should.equal(1); + t.subs[0].mixed.x.should.equal(2); + + t.save(function (err) { + should.strictEqual(null, err); + + T.findById(t._id, function (err, t) { + should.strictEqual(null, err); + t.subs[0].name.should.equal("Hubot"); + t.subs[0].mixed.w.should.equal(1); + t.subs[0].mixed.x.should.equal(2); + + var sub = t.subs[0]; + sub.name = "Hubot1"; + sub.name.should.equal("Hubot1"); + sub.isModified('name').should.be.true; + t.modified.should.be.true; + + t.save(function (err) { + should.strictEqual(null, err); + + T.findById(t._id, function (err, t) { + should.strictEqual(null, err); + should.strictEqual(t.subs[0].name, "Hubot1"); + + var sub = t.subs[0]; + sub.mixed.w = 5; + sub.mixed.w.should.equal(5); + sub.isModified('mixed').should.be.false; + sub.commit('mixed'); + sub.isModified('mixed').should.be.true; + sub.modified.should.be.true; + t.modified.should.be.true; + + t.save(function (err) { + should.strictEqual(null, err); + + T.findById(t._id, function (err, t) { + db.close(); + should.strictEqual(null, err); + should.strictEqual(t.subs[0].mixed.w, 5); + }) + }) + }); + }); + }) + }) + }, + + 'RegExps can be saved': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost({ mixed: { rgx: /^asdf$/ } }); + post.mixed.rgx.should.be.instanceof(RegExp); + post.mixed.rgx.source.should.eql('^asdf$'); + post.save(function (err) { + should.strictEqual(err, null); + BlogPost.findById(post._id, function (err, post) { + db.close(); + should.strictEqual(err, null); + post.mixed.rgx.should.be.instanceof(RegExp); + post.mixed.rgx.source.should.eql('^asdf$'); + }); + }); + }, + + 'null defaults are allowed': function () { + var db = start(); + var T = db.model('NullDefault', new Schema({ name: { type: String, default: null }}), collection); + var t = new T(); + + should.strictEqual(null, t.name); + + t.save(function (err) { + should.strictEqual(null, err); + + T.findById(t._id, function (err, t) { + db.close(); + should.strictEqual(null, err); + should.strictEqual(null, t.name); + }); + }); + }, + + // GH-365 + 'test that setters are used on embedded documents': function () { + var db = start(); + function setLat (val) { + return parseInt(val); + } + + var Location = new Schema({ + lat: {type: Number, default: 0, set: setLat} + }); + + var Deal = new Schema({ + title: String + , locations: [Location] + }); + + Location = db.model('Location', Location, 'locations_' + random()); + Deal = db.model('Deal', Deal, 'deals_' + random()); + + var location = new Location({lat: 1.2}); + location.lat.valueOf().should.equal(1); + + var deal = new Deal({title: "My deal", locations: [{lat: 1.2}]}); + deal.locations[0].lat.valueOf().should.equal(1); + db.close(); + }, + + // GH-289 + 'test that pre-init middleware has access to the true ObjectId when used with querying': function () { + var db = start() + , PreInitSchema = new Schema({}) + , preId; + PreInitSchema.pre('init', function (next) { + preId = this._id; + next(); + }); + var PreInit = db.model('PreInit', PreInitSchema, 'pre_inits' + random()); + + var doc = new PreInit(); + doc.save( function (err) { + should.strictEqual(err, null); + PreInit.findById(doc._id, function (err, found) { + db.close(); + should.strictEqual(err, null); + should.strictEqual(undefined, preId); + }); + }); + }, + + // Demonstration showing why GH-261 is a misunderstanding + 'a single instantiated document should be able to update its embedded documents more than once': function () { + var db = start() + , BlogPost = db.model('BlogPost', collection); + + var post = new BlogPost(); + post.comments.push({title: 'one'}); + post.save(function (err) { + should.strictEqual(err, null); + post.comments[0].title.should.eql('one'); + post.comments[0].title = 'two'; + post.comments[0].title.should.eql('two'); + post.save( function (err) { + should.strictEqual(err, null); + BlogPost.findById(post._id, function (err, found) { + should.strictEqual(err, null); + db.close(); + should.strictEqual(err, null); + found.comments[0].title.should.eql('two'); + }); + }); + }); + }, + + 'defining a method on a Schema corresponding to an EmbeddedDocument should generate an instance method for the ED': function () { + var db = start(); + var ChildSchema = new Schema({ name: String }); + ChildSchema.method('talk', function () { + return 'gaga'; + }); + + var ParentSchema = new Schema({ + children: [ChildSchema] + }); + + var ChildA = db.model('ChildA', ChildSchema, 'children_' + random()); + var ParentA = db.model('ParentA', ParentSchema, 'parents_' + random()); + + var c = new ChildA; + c.talk.should.be.a('function'); + + var p = new ParentA(); + p.children.push({}); + p.children[0].talk.should.be.a('function'); + db.close(); + }, + + 'Model#save should emit an error on its db if a callback is not passed to it': function () { + var db = start(); + + var DefaultErrSchema = new Schema({}); + + var err = ""; + + DefaultErrSchema.pre('save', function (next, fn) { + try { + next(new Error); + } catch (error) { + // throws b/c nothing is listening to the error event + error.should.be.instanceof(Error); + + db.on('error', function (err) { + db.close(); + err.should.be.an.instanceof(Error); + }); + + next(new Error); + } + }); + + var DefaultErr = db.model('DefaultErr', DefaultErrSchema, 'default_err_' + random()); + + var e = new DefaultErr(); + + e.save(); + }, + + 'ensureIndex error should emit on the db': function () { + var db = start(); + + db.on('error', function (err) { + /^E11000 duplicate key error index:/.test(err.message).should.equal(true); + db.close(); + }); + + var schema = new Schema({ name: { type: String } }) + , Test = db.model('IndexError', schema, "x"+random()); + + Test.create({ name: 'hi' }, { name: 'hi' }, function (err) { + should.strictEqual(err, null); + Test.schema.index({ name: 1 }, { unique: true }); + Test.init(); + }); + }, + + 'backward compatibility with conflicted data in the db': function () { + var db = start(); + var M = db.model('backwardDataConflict', new Schema({ namey: { first: String, last: String }})); + var m = new M({ namey: "[object Object]" }); + m.namey = { first: 'GI', last: 'Joe' };// <-- should overwrite the string + m.save(function (err) { + db.close(); + should.strictEqual(err, null); + should.strictEqual('GI', m.namey.first); + should.strictEqual('Joe', m.namey.last); + }); + }, + + '#push should work on EmbeddedDocuments more than 2 levels deep': function () { + var db = start() + , Post = db.model('BlogPost', collection) + , Comment = db.model('CommentNesting', Comments, collection); + + var p =new Post({ title: "comment nesting" }); + var c1 =new Comment({ title: "c1" }); + var c2 =new Comment({ title: "c2" }); + var c3 =new Comment({ title: "c3" }); + + p.comments.push(c1); + c1.comments.push(c2); + c2.comments.push(c3); + + p.save(function (err) { + should.strictEqual(err, null); + + Post.findById(p._id, function (err, p) { + should.strictEqual(err, null); + + var c4=new Comment({ title: "c4" }); + p.comments[0].comments[0].comments[0].comments.push(c4); + p.save(function (err) { + should.strictEqual(err, null); + + Post.findById(p._id, function (err, p) { + db.close(); + should.strictEqual(err, null); + p.comments[0].comments[0].comments[0].comments[0].title.should.equal('c4'); + }); + }); + }); + }) + + } + +}; diff --git a/node_modules/mongoose/test/namedscope.test.js b/node_modules/mongoose/test/namedscope.test.js new file mode 100644 index 0000000..d133541 --- /dev/null +++ b/node_modules/mongoose/test/namedscope.test.js @@ -0,0 +1,251 @@ +//Query.prototype.where(criteria, callback) +//Query.prototype.where(path, val, callback) +// +//UserNS.namedScope({ +// twenties: Query.where('age').gte(20).lt(30) +// , male: Query.where('gender', 'male') +// , lastLogin: Query.where('lastLogin').get(+new Date - (24 * 3600 * 1000)) +//}); +// +//UserNS.find(twenties, male, active, function (err, found) { +//}); +// +//// twenties.male OR twenties.active +//UserNS.twenties.male.OR.twenties.active.find(callback); +//UserNS.find(twenties.male, twenties.active, function (err, found) { +//}); +// +//UserNS.find(olderThan(20).male, olderThan(30).active, function (err, found) { +//}); +//UserNS.twenties.male.active.remove(callback); + +/** + * Test dependencies. + */ + +var start = require('./common') + , should = require('should') + , mongoose = start.mongoose + , random = require('mongoose/utils').random + , Schema = mongoose.Schema + , _24hours = 24 * 3600 * 1000; + +/** + * Setup. + */ + +var UserNSSchema = new Schema({ + age: Number + , gender: String + , lastLogin: Date +}); + +UserNSSchema.namedScope('olderThan', function (age) { + return this.where('age').gt(age); +}); + +UserNSSchema.namedScope('youngerThan', function (age) { + return this.where('age').lt(age); +}); + +UserNSSchema.namedScope('twenties').olderThan(19).youngerThan(30); + +UserNSSchema.namedScope('male').where('gender', 'male'); + +UserNSSchema.namedScope('female').where('gender', 'female'); + +UserNSSchema.namedScope('active', function () { + return this.where('lastLogin').gte(+new Date - _24hours) +}); + +mongoose.model('UserNS', UserNSSchema); + +// TODO Add in tests for using named scopes where findOne, update, remove +module.exports = { + 'basic named scopes should work, for find': function () { + var db = start() + , UserNS = db.model('UserNS', 'users_' + random()); + UserNS.create( + {gender: 'male'} + , {gender: 'male'} + , {gender: 'female'} + , function (err, _) { + should.strictEqual(err, null); + UserNS.male.find( function (err, found) { + db.close(); + should.strictEqual(err, null); + found.should.have.length(2); + }); + } + ); + }, + 'dynamic named scopes should work, for find': function () { + var db = start() + , UserNS = db.model('UserNS', 'users_' + random()); + UserNS.create( + {age: 21} + , {age: 22} + , {age: 19} + , function (err, _) { + should.strictEqual(err, null); + UserNS.olderThan(20).find( function (err, found) { + db.close(); + should.strictEqual(err, null); + found.should.have.length(2); + }); + } + ); + }, + 'named scopes built on top of dynamic named scopes should work, for find': function () { + var db = start() + , UserNS = db.model('UserNS', 'users_' + random()); + UserNS.create( + {age: 21} + , {age: 22} + , {age: 19} + , function (err, _) { + should.strictEqual(err, null); + UserNS.twenties.find( function (err, found) { + db.close(); + should.strictEqual(err, null); + found.should.have.length(2); + }); + } + ); + }, + 'chaining named scopes should work, for find': function () { + var db = start() + , UserNS = db.model('UserNS', 'users_' + random()); + UserNS.create( + {age: 21, gender: 'male', lastLogin: (+new Date) - _24hours - 3600} + , {age: 45, gender: 'male', lastLogin: +new Date} + , {age: 50, gender: 'female', lastLogin: +new Date} + , function (err, _, match, _) { + should.strictEqual(err, null); + UserNS.olderThan(40).active.male.find( function (err, found) { + db.close(); + should.strictEqual(err, null); + found.should.have.length(1); + found[0]._id.should.eql(match._id); + }); + } + ); + }, + + 'basic named scopes should work, for remove': function () { + var db = start() + , UserNS = db.model('UserNS', 'users_' + random()); + UserNS.create( + {gender: 'male'} + , {gender: 'male'} + , {gender: 'female'} + , function (err, _) { + UserNS.male.remove( function (err) { + should.strictEqual(!!err, false); + UserNS.male.find( function (err, found) { + db.close(); + should.strictEqual(err, null); + found.should.have.length(0); + }); + }); + } + ); + }, + + // TODO multi-updates + 'basic named scopes should work, for update': function () { + var db = start() + , UserNS = db.model('UserNS', 'users_' + random()); + UserNS.create( + {gender: 'male'} + , {gender: 'male'} + , {gender: 'female'} + , function (err, male1, male2, female1) { + should.strictEqual(err, null); + UserNS.male.update({gender: 'female'}, function (err) { + should.strictEqual(err, null); + UserNS.female.find( function (err, found) { + should.strictEqual(err, null); + found.should.have.length(2); + UserNS.male.find( function (err, found) { + db.close(); + should.strictEqual(err, null); + found.should.have.length(1); + }); + }); + }); + } + ); + }, + + 'chained named scopes should work, for findOne': function () { + var db = start() + , UserNS = db.model('UserNS', 'users_' + random()); + UserNS.create( + {age: 100, gender: 'male'} + , function (err, maleCentenarian) { + should.strictEqual(err, null); + UserNS.male.olderThan(99).findOne( function (err, found) { + db.close(); + should.strictEqual(err, null); + found._id.should.eql(maleCentenarian._id); + }); + } + ); + }, + + 'hybrid use of chained named scopes and ad hoc querying should work': function () { + var db = start() + , UserNS = db.model('UserNS', 'users_' + random()); + UserNS.create( + {age: 100, gender: 'female'} + , function (err, femaleCentenarian) { + should.strictEqual(null, err); + UserNS.female.where('age').gt(99).findOne( function (err, found) { + db.close(); + should.strictEqual(err, null); + found._id.should.eql(femaleCentenarian._id); + }); + } + ); + }, +// 'using chained named scopes in a find': function () { +// var db = start() +// , UserNS = db.model('UserNS', 'users_' + random()); +// UserNS.create({age: 21, gender: 'male', lastLogin: (+new Date) - _24hours - 3600}, function (err, _) { +// should.strictEqual(err, null); +// UserNS.create({age: 45, gender: 'male', lastLogin: +new Date}, function (err, match) { +// should.strictEqual(err, null); +// UserNS.create({age: 50, gender: 'female', lastLogin: +new Date}, function (err, _) { +// should.strictEqual(err, null); +// UserNS.find(olderThan(40).active.male, function (err, found) { +// db.close(); +// should.strictEqual(err, null); +// found.should.have.length(1); +// found[0]._id.should.eql(match._id); +// }); +// }); +// }); +// }); +// }, +// 'using multiple chained named scopes in a find to do an OR': function () { +// var db = start() +// , UserNS = db.model('UserNS', collection); +// var db = start() +// , UserNS = db.model('UserNS', collection); +// UserNS.create( +// {age: 21, gender: 'male', lastLogin: (+new Date) - _24hours - 3600} +// , {age: 45, gender: 'male', lastLogin: +new Date} +// , {age: 50, gender: 'female', lastLogin: +new Date} +// , {age: 35, gender: 'female', lastLogin: +new Date} +// , function (err, a, b, c, d) { +// should.strictEqual(err, null); +// UserNS.find(twenties.active.male, thirties.active.female, function (err, found) { +// db.close(); +// should.strictEqual(err, null); +// found.should.have.length(2); +// }); +// } +// ); +// }, +}; diff --git a/node_modules/mongoose/test/promise.test.js b/node_modules/mongoose/test/promise.test.js new file mode 100644 index 0000000..67f3ce4 --- /dev/null +++ b/node_modules/mongoose/test/promise.test.js @@ -0,0 +1,167 @@ + +/** + * Module dependencies. + */ + +var should = require('should') + , Promise = require('mongoose/promise'); + +/** + * Test. + */ + +module.exports = { + + 'test that events fire right away after complete()ing': function (beforeExit) { + var promise = new Promise() + , called = 0; + + promise.on('complete', function (a, b) { + a.should.eql('1'); + b.should.eql('2'); + called++; + }); + + promise.complete('1', '2'); + + promise.on('complete', function (a, b) { + a.should.eql('1'); + b.should.eql('2'); + called++; + }); + + beforeExit(function () { + called.should.eql(2); + }); + }, + + 'test that events fire right away after error()ing': function (beforeExit) { + var promise = new Promise() + , called = 0; + + promise.on('err', function (err) { + err.should.be.an.instanceof(Error); + called++; + }); + + promise.error(new Error('booyah')); + + promise.on('err', function (err) { + err.should.be.an.instanceof(Error); + called++; + }); + + beforeExit(function () { + called.should.eql(2); + }); + }, + + 'test errback+callback from constructor': function (beforeExit) { + var promise = new Promise(function (err) { + err.should.be.an.instanceof(Error); + called++; + }) + , called = 0; + + promise.error(new Error('dawg')); + + beforeExit(function () { + called.should.eql(1); + }); + }, + + 'test errback+callback after complete()ing': function (beforeExit) { + var promise = new Promise() + , called = 0; + + promise.complete('woot'); + + promise.addBack(function (err, data){ + data.should.eql('woot'); + called++; + }); + + promise.addBack(function (err, data){ + should.strictEqual(err, null); + called++; + }); + + beforeExit(function () { + called.should.eql(2); + }); + }, + + 'test errback+callback after error()ing': function (beforeExit) { + var promise = new Promise() + , called = 0; + + promise.error(new Error('woot')); + + promise.addBack(function (err){ + err.should.be.an.instanceof(Error); + called++; + }); + + promise.addBack(function (err){ + err.should.be.an.instanceof(Error); + called++; + }); + + beforeExit(function () { + called.should.eql(2); + }); + }, + + 'test addCallback shortcut': function (beforeExit) { + var promise = new Promise() + , called = 0; + + promise.addCallback(function (woot) { + should.strictEqual(woot, undefined); + called++; + }); + + promise.complete(); + + beforeExit(function () { + called.should.eql(1); + }); + }, + + 'test addErrback shortcut': function (beforeExit) { + var promise = new Promise() + , called = 0; + + promise.addErrback(function (err) { + err.should.be.an.instanceof(Error); + called++; + }); + + promise.error(new Error); + + beforeExit(function () { + called.should.eql(1); + }); + }, + + 'test return value of #on()': function () { + var promise = new Promise() + promise.on('jump', function(){}).should.be.an.instanceof(Promise); + }, + + 'test return value of #addCallback()': function () { + var promise = new Promise() + promise.addCallback(function(){}).should.be.an.instanceof(Promise); + }, + + 'test return value of #addErrback()': function () { + var promise = new Promise() + promise.addErrback(function(){}).should.be.an.instanceof(Promise); + }, + + 'test return value of #addBack()': function () { + var promise = new Promise() + promise.addBack(function(){}).should.be.an.instanceof(Promise); + } + +}; diff --git a/node_modules/mongoose/test/query.test.js b/node_modules/mongoose/test/query.test.js new file mode 100644 index 0000000..929332e --- /dev/null +++ b/node_modules/mongoose/test/query.test.js @@ -0,0 +1,751 @@ + +/** + * Module dependencies. + */ + +var Query = require('mongoose/query') + , start = require('./common') + , mongoose = start.mongoose + , DocumentObjectId = mongoose.Types.ObjectId + , Schema = mongoose.Schema + , should = require('should') + +var Comment = new Schema({ + text: String +}); + +var Product = new Schema({ + tags: {} // mixed + , array: Array + , ids: [Schema.ObjectId] + , strings: [String] + , numbers: [Number] + , comments: [Comment] +}); + +mongoose.model('Product', Product); +mongoose.model('Comment', Comment); + +/** + * Test. + */ + +module.exports = { + 'test query.fields({a: 1, b: 1, c: 1})': function () { + var query = new Query(); + query.fields({a: 1, b: 1, c: 1}); + query._fields.should.eql({a: 1, b: 1, c: 1}); + }, + 'test query.fields({only: "a b c"})': function () { + var query = new Query(); + query.fields({only: "a b c"}); + query._fields.should.eql({a: 1, b: 1, c: 1}); + }, + 'test query.fields({only: ["a", "b", "c"]})': function () { + var query = new Query(); + query.fields({only: ['a', 'b', 'c']}); + query._fields.should.eql({a: 1, b: 1, c: 1}); + }, + 'test query.fields("a b c")': function () { + var query = new Query(); + query.fields("a b c"); + query._fields.should.eql({a: 1, b: 1, c: 1}); + }, + 'test query.fields("a", "b", "c")': function () { + var query = new Query(); + query.fields('a', 'b', 'c'); + query._fields.should.eql({a: 1, b: 1, c: 1}); + }, + "test query.fields(['a', 'b', 'c'])": function () { + var query = new Query(); + query.fields(['a', 'b', 'c']); + query._fields.should.eql({a: 1, b: 1, c: 1}); + }, + "Query#fields should not over-ride fields set in prior calls to Query#fields": function () { + var query = new Query(); + query.fields('a'); + query._fields.should.eql({a: 1}); + query.fields('b'); + query._fields.should.eql({a: 1, b: 1}); + }, +// "Query#fields should be able to over-ride fields set in prior calls to Query#fields if you specify override": function () { +// var query = new Query(); +// query.fields('a'); +// query._fields.should.eql({a: 1}); +// query.override.fields('b'); +// query._fields.should.eql({b: 1}); +// } + + "test query.only('a b c')": function () { + var query = new Query(); + query.only("a b c"); + query._fields.should.eql({a: 1, b: 1, c: 1}); + }, + "test query.only('a', 'b', 'c')": function () { + var query = new Query(); + query.only('a', 'b', 'c'); + query._fields.should.eql({a: 1, b: 1, c: 1}); + }, + "test query.only('a', 'b', 'c')": function () { + var query = new Query(); + query.only(['a', 'b', 'c']); + query._fields.should.eql({a: 1, b: 1, c: 1}); + }, + "Query#only should not over-ride fields set in prior calls to Query#only": function () { + var query = new Query(); + query.only('a'); + query._fields.should.eql({a: 1}); + query.only('b'); + query._fields.should.eql({a: 1, b: 1}); + }, + + "test query.exclude('a b c')": function () { + var query = new Query(); + query.exclude("a b c"); + query._fields.should.eql({a: 0, b: 0, c: 0}); + }, + "test query.exclude('a', 'b', 'c')": function () { + var query = new Query(); + query.exclude('a', 'b', 'c'); + query._fields.should.eql({a: 0, b: 0, c: 0}); + }, + "test query.exclude('a', 'b', 'c')": function () { + var query = new Query(); + query.exclude(['a', 'b', 'c']); + query._fields.should.eql({a: 0, b: 0, c: 0}); + }, + "Query#exclude should not over-ride fields set in prior calls to Query#exclude": function () { + var query = new Query(); + query.exclude('a'); + query._fields.should.eql({a: 0}); + query.exclude('b'); + query._fields.should.eql({a: 0, b: 0}); + }, + + 'test setting a condition via where': function () { + var query = new Query(); + query.where('name', 'guillermo'); + query._conditions.should.eql({name: 'guillermo'}); + }, + + 'test Query#gte where 2 arguments': function () { + var query = new Query(); + query.gte('age', 18); + query._conditions.should.eql({age: {$gte: 18}}); + }, + + 'test Query#gt where 2 arguments': function () { + var query = new Query(); + query.gt('age', 17); + query._conditions.should.eql({age: {$gt: 17}}); + }, + + 'test Query#lte where 2 arguments': function () { + var query = new Query(); + query.lte('age', 65); + query._conditions.should.eql({age: {$lte: 65}}); + }, + + 'test Query#lt where 2 arguments': function () { + var query = new Query(); + query.lt('age', 66); + query._conditions.should.eql({age: {$lt: 66}}); + }, + + 'test Query#gte where 1 argument': function () { + var query = new Query(); + query.where("age").gte(18); + query._conditions.should.eql({age: {$gte: 18}}); + }, + + 'test Query#gt where 1 argument': function () { + var query = new Query(); + query.where("age").gt(17); + query._conditions.should.eql({age: {$gt: 17}}); + }, + + 'test Query#lte where 1 argument': function () { + var query = new Query(); + query.where("age").lte(65); + query._conditions.should.eql({age: {$lte: 65}}); + }, + + 'test Query#lt where 1 argument': function () { + var query = new Query(); + query.where("age").lt(66); + query._conditions.should.eql({age: {$lt: 66}}); + }, + + 'test combined Query#lt and Query#gt': function () { + var query = new Query(); + query.where("age").lt(66).gt(17); + query._conditions.should.eql({age: {$lt: 66, $gt: 17}}); + }, + + 'test Query#lt on one path and Query#gt on another path on the same query': function () { + var query = new Query(); + query + .where("age").lt(66) + .where("height").gt(5); + query._conditions.should.eql({age: {$lt: 66}, height: {$gt: 5}}); + }, + + 'test Query#ne where 2 arguments': function () { + var query = new Query(); + query.ne('age', 21); + query._conditions.should.eql({age: {$ne: 21}}); + }, + + 'test Query#gte where 1 argument': function () { + var query = new Query(); + query.where("age").ne(21); + query._conditions.should.eql({age: {$ne: 21}}); + }, + + 'test Query#ne alias Query#notEqualTo': function () { + var query = new Query(); + query.where('age').notEqualTo(21); + query._conditions.should.eql({age: {$ne: 21}}); + + query = new Query(); + query.notEqualTo('age', 21); + query._conditions.should.eql({age: {$ne: 21}}); + }, + + 'test Query#in where 2 arguments': function () { + var query = new Query(); + query.in('age', [21, 25, 30]); + query._conditions.should.eql({age: {$in: [21, 25, 30]}}); + }, + + 'test Query#in where 1 argument': function () { + var query = new Query(); + query.where("age").in([21, 25, 30]); + query._conditions.should.eql({age: {$in: [21, 25, 30]}}); + }, + + 'test Query#in where a non-array value not via where': function () { + var query = new Query(); + query.in('age', 21); + query._conditions.should.eql({age: {$in: 21}}); + }, + + 'test Query#in where a non-array value via where': function () { + var query = new Query(); + query.where('age').in(21); + query._conditions.should.eql({age: {$in: 21}}); + }, + + 'test Query#nin where 2 arguments': function () { + var query = new Query(); + query.nin('age', [21, 25, 30]); + query._conditions.should.eql({age: {$nin: [21, 25, 30]}}); + }, + + 'test Query#nin where 1 argument': function () { + var query = new Query(); + query.where("age").nin([21, 25, 30]); + query._conditions.should.eql({age: {$nin: [21, 25, 30]}}); + }, + + 'test Query#nin where a non-array value not via where': function () { + var query = new Query(); + query.nin('age', 21); + query._conditions.should.eql({age: {$nin: 21}}); + }, + + 'test Query#nin where a non-array value via where': function () { + var query = new Query(); + query.where('age').nin(21); + query._conditions.should.eql({age: {$nin: 21}}); + }, + + 'test Query#mod not via where, where [a, b] param': function () { + var query = new Query(); + query.mod('age', [5, 2]); + query._conditions.should.eql({age: {$mod: [5, 2]}}); + }, + + 'test Query#mod not via where, where a and b params': function () { + var query = new Query(); + query.mod('age', 5, 2); + query._conditions.should.eql({age: {$mod: [5, 2]}}); + }, + + 'test Query#mod via where, where [a, b] param': function () { + var query = new Query(); + query.where("age").mod([5, 2]); + query._conditions.should.eql({age: {$mod: [5, 2]}}); + }, + + 'test Query#mod via where, where a and b params': function () { + var query = new Query(); + query.where("age").mod(5, 2); + query._conditions.should.eql({age: {$mod: [5, 2]}}); + }, + + 'test Query#near via where, where [lat, long] param': function () { + var query = new Query(); + query.where('checkin').near([40, -72]); + query._conditions.should.eql({checkin: {$near: [40, -72]}}); + }, + + 'test Query#near via where, where lat and long params': function () { + var query = new Query(); + query.where('checkin').near(40, -72); + query._conditions.should.eql({checkin: {$near: [40, -72]}}); + }, + + 'test Query#near not via where, where [lat, long] param': function () { + var query = new Query(); + query.near('checkin', [40, -72]); + query._conditions.should.eql({checkin: {$near: [40, -72]}}); + }, + + 'test Query#near not via where, where lat and long params': function () { + var query = new Query(); + query.near('checkin', 40, -72); + query._conditions.should.eql({checkin: {$near: [40, -72]}}); + }, + + 'test Query#maxDistance via where': function () { + var query = new Query(); + query.where('checkin').near([40, -72]).maxDistance(1); + query._conditions.should.eql({checkin: {$near: [40, -72], $maxDistance: 1}}); + query = new Query(); + query.where('checkin').near([40, -72]).$maxDistance(1); + query._conditions.should.eql({checkin: {$near: [40, -72], $maxDistance: 1}}); + }, + + 'test Query#wherein.box not via where': function () { + var query = new Query(); + query.wherein.box('gps', {ll: [5, 25], ur: [10, 30]}); + query._conditions.should.eql({gps: {$wherein: {$box: [[5, 25], [10, 30]]}}}); + }, + + 'test Query#wherein.box via where': function () { + var query = new Query(); + query.where('gps').wherein.box({ll: [5, 25], ur: [10, 30]}); + query._conditions.should.eql({gps: {$wherein: {$box: [[5, 25], [10, 30]]}}}); + }, + + 'test Query#wherein.center not via where': function () { + var query = new Query(); + query.wherein.center('gps', {center: [5, 25], radius: 5}); + query._conditions.should.eql({gps: {$wherein: {$center: [[5, 25], 5]}}}); + }, + + 'test Query#wherein.center not via where': function () { + var query = new Query(); + query.where('gps').wherein.center({center: [5, 25], radius: 5}); + query._conditions.should.eql({gps: {$wherein: {$center: [[5, 25], 5]}}}); + }, + + 'test Query#exists where 0 arguments via where': function () { + var query = new Query(); + query.where("username").exists(); + query._conditions.should.eql({username: {$exists: true}}); + }, + + 'test Query#exists where 1 argument via where': function () { + var query = new Query(); + query.where("username").exists(false); + query._conditions.should.eql({username: {$exists: false}}); + }, + + 'test Query#exists where 1 argument not via where': function () { + var query = new Query(); + query.exists('username'); + query._conditions.should.eql({username: {$exists: true}}); + }, + + 'test Query#exists where 1 argument not via where': function () { + var query = new Query(); + query.exists("username", false); + query._conditions.should.eql({username: {$exists: false}}); + }, + + // TODO $not + + 'test Query#all via where': function () { + var query = new Query(); + query.where('pets').all(['dog', 'cat', 'ferret']); + query._conditions.should.eql({pets: {$all: ['dog', 'cat', 'ferret']}}); + }, + + 'test Query#all not via where': function () { + var query = new Query(); + query.all('pets', ['dog', 'cat', 'ferret']); + query._conditions.should.eql({pets: {$all: ['dog', 'cat', 'ferret']}}); + }, + + 'test strict array equivalence condition via Query#find': function () { + var query = new Query(); + query.find({'pets': ['dog', 'cat', 'ferret']}); + query._conditions.should.eql({pets: ['dog', 'cat', 'ferret']}); + }, + + // TODO Check key.index queries + + 'test Query#size via where': function () { + var query = new Query(); + query.where('collection').size(5); + query._conditions.should.eql({collection: {$size: 5}}); + }, + + 'test Query#size not via where': function () { + var query = new Query(); + query.size('collection', 5); + query._conditions.should.eql({collection: {$size: 5}}); + }, + + 'test Query#slice via where, where just positive limit param': function () { + var query = new Query(); + query.where('collection').slice(5); + query._fields.should.eql({collection: {$slice: 5}}); + }, + + 'test Query#slice via where, where just negative limit param': function () { + var query = new Query(); + query.where('collection').slice(-5); + query._fields.should.eql({collection: {$slice: -5}}); + }, + + 'test Query#slice via where, where [skip, limit] param': function () { + var query = new Query(); + query.where('collection').slice([14, 10]); // Return the 15th through 25th + query._fields.should.eql({collection: {$slice: [14, 10]}}); + }, + + 'test Query#slice via where, where skip and limit params': function () { + var query = new Query(); + query.where('collection').slice(14, 10); // Return the 15th through 25th + query._fields.should.eql({collection: {$slice: [14, 10]}}); + }, + + 'test Query#slice via where, where just positive limit param': function () { + var query = new Query(); + query.where('collection').slice(5); + query._fields.should.eql({collection: {$slice: 5}}); + }, + + 'test Query#slice via where, where just negative limit param': function () { + var query = new Query(); + query.where('collection').slice(-5); + query._fields.should.eql({collection: {$slice: -5}}); + }, + + 'test Query#slice via where, where the [skip, limit] param': function () { + var query = new Query(); + query.where('collection').slice([14, 10]); // Return the 15th through 25th + query._fields.should.eql({collection: {$slice: [14, 10]}}); + }, + + 'test Query#slice via where, where the skip and limit params': function () { + var query = new Query(); + query.where('collection').slice(14, 10); // Return the 15th through 25th + query._fields.should.eql({collection: {$slice: [14, 10]}}); + }, + + + 'test Query#slice not via where, where just positive limit param': function () { + var query = new Query(); + query.slice('collection', 5); + query._fields.should.eql({collection: {$slice: 5}}); + }, + + 'test Query#slice not via where, where just negative limit param': function () { + var query = new Query(); + query.slice('collection', -5); + query._fields.should.eql({collection: {$slice: -5}}); + }, + + 'test Query#slice not via where, where [skip, limit] param': function () { + var query = new Query(); + query.slice('collection', [14, 10]); // Return the 15th through 25th + query._fields.should.eql({collection: {$slice: [14, 10]}}); + }, + + 'test Query#slice not via where, where skip and limit params': function () { + var query = new Query(); + query.slice('collection', 14, 10); // Return the 15th through 25th + query._fields.should.eql({collection: {$slice: [14, 10]}}); + }, + + 'test Query#elemMatch not via where': function () { + var query = new Query(); + query.elemMatch('comments', {author: 'bnoguchi', votes: {$gte: 5}}); + query._conditions.should.eql({comments: {$elemMatch: {author: 'bnoguchi', votes: {$gte: 5}}}}); + }, + + 'test Query#elemMatch not via where, where block notation': function () { + var query = new Query(); + query.elemMatch('comments', function (elem) { + elem.where('author', 'bnoguchi') + elem.where('votes').gte(5); + }); + query._conditions.should.eql({comments: {$elemMatch: {author: 'bnoguchi', votes: {$gte: 5}}}}); + }, + + 'test Query#elemMatch via where': function () { + var query = new Query(); + query.where('comments').elemMatch({author: 'bnoguchi', votes: {$gte: 5}}); + query._conditions.should.eql({comments: {$elemMatch: {author: 'bnoguchi', votes: {$gte: 5}}}}); + }, + + 'test Query#elemMatch via where, where block notation': function () { + var query = new Query(); + query.where('comments').elemMatch(function (elem) { + elem.where('author', 'bnoguchi') + elem.where('votes').gte(5); + }); + query._conditions.should.eql({comments: {$elemMatch: {author: 'bnoguchi', votes: {$gte: 5}}}}); + }, + + + 'test Query#$where where a function arg': function () { + var query = new Query(); + function filter () { + return this.lastName === this.firstName; + } + query.$where(filter); + query._conditions.should.eql({$where: filter}); + }, + + 'test Query#where where a javascript string arg': function () { + var query = new Query(); + query.$where('this.lastName === this.firstName'); + query._conditions.should.eql({$where: 'this.lastName === this.firstName'}); + }, + + 'test Query#limit': function () { + var query = new Query(); + query.limit(5); + query.options.limit.should.equal(5); + }, + + 'test Query#skip': function () { + var query = new Query(); + query.skip(9); + query.options.skip.should.equal(9); + }, + + 'test Query#sort': function () { + var query = new Query(); + query.sort('a', 1, 'c', -1, 'b', 1); + query.options.sort.should.eql([['a', 1], ['c', -1], ['b', 1]]); + }, + + 'test Query#asc and Query#desc': function () { + var query = new Query(); + query.asc('a', 'z').desc('c', 'v').asc('b'); + query.options.sort.should.eql([['a', 1], ['z', 1], ['c', -1], ['v', -1], ['b', 1]]); + }, + + 'test running an empty Query should not throw': function () { + var query = new Query(); + var threw = false; + + try { + query.exec(); + } catch (err) { + threw = true; + } + + threw.should.eql(false); + }, + + 'test casting an array set to mixed type works': function () { + var query = new Query(); + var db = start(); + var Product = db.model('Product'); + var params = { _id: new DocumentObjectId, tags: { $in: [ 4, 8, 15, 16 ] }}; + + query.cast(Product, params); + + params.tags.$in.should.eql([4,8,15,16]); + db.close(); + }, + + //'throwing inside a query callback should not execute the callback again': function () { + //var query = new Query(); + //var db = start(); + //var Product = db.model('Product'); + + //var threw = false; + //Product.find({}, function (err) { + //if (!threw) { + //db.close(); + //threw = true; + //throw new Error("Double callback"); + //} + + //should.strictEqual(err, null, 'Double callback detected'); + //}); + //}, + + 'Query#find $ne should not cast single value to array for schematype of Array': function () { + var query = new Query(); + var db = start(); + var Product = db.model('Product'); + var Comment = db.model('Comment'); + db.close(); + + var id = new DocumentObjectId; + var castedComment = { _id: id, text: 'hello there' }; + var comment = new Comment(castedComment); + + var params = { + array: { $ne: 5 } + , ids: { $ne: id } + , comments: { $ne: comment } + , strings: { $ne: 'Hi there' } + , numbers: { $ne: 10000 } + }; + + query.cast(Product, params); + params.array.$ne.should.equal(5); + params.ids.$ne.should.eql(id); + params.comments.$ne.should.eql(castedComment); + params.strings.$ne.should.eql('Hi there'); + params.numbers.$ne.should.eql(10000); + + params.array.$ne = [5]; + params.ids.$ne = [id]; + params.comments.$ne = [comment]; + params.strings.$ne = ['Hi there']; + params.numbers.$ne = [10000]; + query.cast(Product, params); + params.array.$ne.should.be.instanceof(Array); + params.array.$ne[0].should.eql(5); + params.ids.$ne.should.be.instanceof(Array); + params.ids.$ne[0].toString().should.eql(id.toString()); + params.comments.$ne.should.be.instanceof(Array); + params.comments.$ne[0].toObject().should.eql(castedComment); + params.strings.$ne.should.be.instanceof(Array); + params.strings.$ne[0].should.eql('Hi there'); + params.numbers.$ne.should.be.instanceof(Array); + params.numbers.$ne[0].should.eql(10000); + }, + + 'Query#find should not cast single value to array for schematype of Array': function () { + var query = new Query(); + var db = start(); + var Product = db.model('Product'); + var Comment = db.model('Comment'); + db.close(); + + var id = new DocumentObjectId; + var castedComment = { _id: id, text: 'hello there' }; + var comment = new Comment(castedComment); + + var params = { + array: 5 + , ids: id + , comments: comment + , strings: 'Hi there' + , numbers: 10000 + }; + + query.cast(Product, params); + params.array.should.equal(5); + params.ids.should.eql(id); + params.comments.should.eql(castedComment); + params.strings.should.eql('Hi there'); + params.numbers.should.eql(10000); + + params.array = [5]; + params.ids = [id]; + params.comments = [comment]; + params.strings = ['Hi there']; + params.numbers = [10000]; + query.cast(Product, params); + params.array.should.be.instanceof(Array); + params.array[0].should.eql(5); + params.ids.should.be.instanceof(Array); + params.ids[0].toString().should.eql(id.toString()); + params.comments.should.be.instanceof(Array); + params.comments[0].toObject().should.eql(castedComment); + params.strings.should.be.instanceof(Array); + params.strings[0].should.eql('Hi there'); + params.numbers.should.be.instanceof(Array); + params.numbers[0].should.eql(10000); + }, + + 'distinct Query op should be "distinct"': function () { + var query = new Query(); + var db = start(); + var Product = db.model('Product'); + db.close(); + new Query().bind(Product, 'distinct').distinct('blah', function(){}).op.should.equal('distinct'); + }, + + // Advanced Query options + + 'test Query#maxscan': function () { + var query = new Query(); + query.maxscan(100); + query.options.maxscan.should.equal(100); + }, + + 'test Query#slaveOk': function () { + var query = new Query(); + query.slaveOk(); + query.options.slaveOk.should.be.true; + + var query = new Query(); + query.slaveOk(true); + query.options.slaveOk.should.be.true; + + var query = new Query(); + query.slaveOk(false); + query.options.slaveOk.should.be.false; + }, + + 'test Query#hint': function () { + var query = new Query(); + query.hint('indexAttributeA', 1, 'indexAttributeB', -1); + query.options.hint.should.eql({'indexAttributeA': 1, 'indexAttributeB': -1}); + + var query2 = new Query(); + query2.hint({'indexAttributeA': 1, 'indexAttributeB': -1}); + query2.options.hint.should.eql({'indexAttributeA': 1, 'indexAttributeB': -1}); + + var query3 = new Query(); + query3.hint('indexAttributeA'); + query3.options.hint.should.eql({}); + }, + + 'test Query#snapshot': function () { + var query = new Query(); + query.snapshot(true); + query.options.snapshot.should.be.true; + }, + + // TODO +// 'test Query#min': function () { +// var query = new Query(); +// query.min(10); +// query.options.min.should.equal(10); +// }, +// + //TODO +// 'test Query#max': function () { +// var query = new Query(); +// query.max(100); +// query.options.max.should.equal(100); +// }, + + // TODO +// 'test Query#explain': function () { +// } + +// 'queries should be composable': function () { +// var q1 = new Query({name: 'hello'}) +// , q2 = new Query({age: {$gte: 21}}) +// , q3 = q1.and(q2); +// +// q3.should.be.an.instanceof(Query); +// q3._conditions.should.eql({name: 'hello', age: {$gte: 21}}); +// } +}; diff --git a/node_modules/mongoose/test/schema.onthefly.test.js b/node_modules/mongoose/test/schema.onthefly.test.js new file mode 100644 index 0000000..928f510 --- /dev/null +++ b/node_modules/mongoose/test/schema.onthefly.test.js @@ -0,0 +1,105 @@ +var start = require('./common') + , should = require('should') + , mongoose = start.mongoose + , random = require('mongoose/utils').random + , Schema = mongoose.Schema + , ObjectId = Schema.ObjectId; + +/** + * Setup. + */ + +var DecoratedSchema = new Schema({ + title : String +}); + +mongoose.model('Decorated', DecoratedSchema); + +var collection = 'decorated_' + random(); + +module.exports = { + 'setting on the fly schemas should cache the type schema and cast values appropriately': function () { + var db = start() + , Decorated = db.model('Decorated', collection); + + var post = new Decorated(); + post.set('adhoc', '9', Number); + post.get('adhoc').valueOf().should.eql(9); + db.close(); + }, + + 'on the fly schemas should be local to the particular document': function () { + var db = start() + , Decorated = db.model('Decorated', collection); + + var postOne = new Decorated(); + postOne.set('adhoc', '9', Number); + postOne._path('adhoc').should.not.equal(undefined); + + var postTwo = new Decorated(); + postTwo._path('title').should.not.equal(undefined); + should.strictEqual(undefined, postTwo._path('adhoc')); + db.close(); + }, + + 'querying a document that had an on the fly schema should work': function () { + var db = start() + , Decorated = db.model('Decorated', collection); + + var post = new Decorated({title: 'AD HOC'}); + // Interpret adhoc as a Number + post.set('adhoc', '9', Number); + post.get('adhoc').valueOf().should.eql(9); + post.save( function (err) { + should.strictEqual(null, err); + Decorated.findById(post.id, function (err, found) { + db.close(); + should.strictEqual(null, err); + found.get('adhoc').should.eql(9); + // Interpret adhoc as a String instead of a Number now + found.get('adhoc', String).should.eql('9'); + found.get('adhoc').should.eql('9'); + }); + }); + }, + + 'on the fly Embedded Array schemas should cast properly': function () { + var db = start() + , Decorated = db.model('Decorated', collection); + + var post = new Decorated(); + post.set('moderators', [{name: 'alex trebek'}], [new Schema({name: String})]); + post.get('moderators')[0].name.should.eql('alex trebek'); + db.close(); + }, + + 'on the fly Embedded Array schemas should get from a fresh queried document properly': function () { + var db = start() + , Decorated = db.model('Decorated', collection); + + var post = new Decorated() + , ModeratorSchema = new Schema({name: String, ranking: Number}); + post.set('moderators', [{name: 'alex trebek', ranking: '1'}], [ModeratorSchema]); + post.get('moderators')[0].name.should.eql('alex trebek'); + post.save( function (err) { + should.strictEqual(null, err); + Decorated.findById(post.id, function (err, found) { + db.close(); + should.strictEqual(null, err); + var rankingPreCast = found.get('moderators')[0].ranking; + rankingPreCast.should.eql(1); + should.strictEqual(undefined, rankingPreCast.increment); + var rankingPostCast = found.get('moderators', [ModeratorSchema])[0].ranking; + rankingPostCast.valueOf().should.equal(1); + rankingPostCast.increment.should.not.equal(undefined); + + var NewModeratorSchema = new Schema({ name: String, ranking: String}); + rankingPostCast = found.get('moderators', [NewModeratorSchema])[0].ranking; + rankingPostCast.should.equal('1'); + }); + }); + }, + 'should support on the fly nested documents': function () { + // TODO + } +}; diff --git a/node_modules/mongoose/test/schema.test.js b/node_modules/mongoose/test/schema.test.js new file mode 100644 index 0000000..60e319b --- /dev/null +++ b/node_modules/mongoose/test/schema.test.js @@ -0,0 +1,842 @@ + +/** + * Module dependencies. + */ + +var mongoose = require('./common').mongoose + , should = require('should') + , Schema = mongoose.Schema + , Document = mongoose.Document + , SchemaType = mongoose.SchemaType + , VirtualType = mongoose.VirtualType + , ObjectId = Schema.ObjectId + , ValidatorError = SchemaType.ValidatorError + , CastError = SchemaType.CastError + , SchemaTypes = Schema.Types + , DocumentObjectId = mongoose.Types.ObjectId + , Mixed = SchemaTypes.Mixed + , MongooseNumber = mongoose.Types.Number + , MongooseArray = mongoose.Types.Array + , vm = require('vm') + +/** + * Test Document constructor. + */ + +function TestDocument () { + Document.apply(this, arguments); +}; + +/** + * Inherits from Document. + */ + +TestDocument.prototype.__proto__ = Document.prototype; + +/** + * Set a dummy schema to simulate compilation. + */ + +TestDocument.prototype.schema = new Schema({ + test : String +}); + +/** + * Test. + */ + +module.exports = { + + 'test different schema types support': function(){ + var Checkin = new Schema({ + date : Date + , location : { + lat: Number + , lng: Number + } + }); + + var Ferret = new Schema({ + name : String + , owner : ObjectId + , fur : String + , color : { type: String } + , age : Number + , checkins : [Checkin] + , friends : [ObjectId] + , likes : Array + , alive : Boolean + , extra : Mixed + }); + + Ferret.path('name').should.be.an.instanceof(SchemaTypes.String); + Ferret.path('owner').should.be.an.instanceof(SchemaTypes.ObjectId); + Ferret.path('fur').should.be.an.instanceof(SchemaTypes.String); + Ferret.path('color').should.be.an.instanceof(SchemaTypes.String); + Ferret.path('age').should.be.an.instanceof(SchemaTypes.Number); + Ferret.path('checkins').should.be.an.instanceof(SchemaTypes.DocumentArray); + Ferret.path('friends').should.be.an.instanceof(SchemaTypes.Array); + Ferret.path('likes').should.be.an.instanceof(SchemaTypes.Array); + Ferret.path('alive').should.be.an.instanceof(SchemaTypes.Boolean); + Ferret.path('extra').should.be.an.instanceof(SchemaTypes.Mixed); + + should.strictEqual(Ferret.path('unexistent'), undefined); + + Checkin.path('date').should.be.an.instanceof(SchemaTypes.Date); + }, + + 'dot notation support for accessing paths': function(){ + var Racoon = new Schema({ + name : { type: String, enum: ['Edwald', 'Tobi'] } + , age : Number + }); + + var Person = new Schema({ + name : String + , raccoons : [Racoon] + , location : { + city : String + , state : String + } + }); + + Person.path('name').should.be.an.instanceof(SchemaTypes.String); + Person.path('raccoons').should.be.an.instanceof(SchemaTypes.DocumentArray); + Person.path('location.city').should.be.an.instanceof(SchemaTypes.String); + Person.path('location.state').should.be.an.instanceof(SchemaTypes.String); + + should.strictEqual(Person.path('location.unexistent'), undefined); + }, + + 'nested paths more than 2 levels deep': function () { + var Nested = new Schema({ + first: { + second: { + third: String + } + } + }); + Nested.path('first.second.third').should.be.an.instanceof(SchemaTypes.String); + }, + + 'test default definition': function(){ + var Test = new Schema({ + simple : { type: String, default: 'a' } + , array : { type: Array, default: [1,2,3,4,5] } + , arrayX : { type: Array, default: 9 } + , arrayFn : { type: Array, default: function () { return [8] } } + , callback : { type: Number, default: function(){ + this.a.should.eql('b'); + return '3'; + }} + }); + + Test.path('simple').defaultValue.should.eql('a'); + Test.path('callback').defaultValue.should.be.a('function'); + + Test.path('simple').getDefault().should.eql('a'); + (+Test.path('callback').getDefault({ a: 'b' })).should.eql(3); + Test.path('array').defaultValue.should.be.a('function'); + Test.path('array').getDefault(new TestDocument)[3].should.eql(4); + Test.path('arrayX').getDefault(new TestDocument)[0].should.eql(9); + Test.path('arrayFn').defaultValue.should.be.a('function'); + Test.path('arrayFn').getDefault(new TestDocument).should.be.an.instanceof(MongooseArray); + }, + + 'test Mixed defaults can be empty arrays': function () { + var Test = new Schema({ + mixed1 : { type: Mixed, default: [] } + , mixed2 : { type: Mixed, default: Array } + }); + + Test.path('mixed1').getDefault().should.be.an.instanceof(Array); + Test.path('mixed1').getDefault().length.should.be.eql(0); + Test.path('mixed2').getDefault().should.be.an.instanceof(Array); + Test.path('mixed2').getDefault().length.should.be.eql(0); + }, + + 'test string required validation': function(){ + var Test = new Schema({ + simple: String + }); + + Test.path('simple').required(true); + Test.path('simple').validators.should.have.length(1); + + Test.path('simple').doValidate(null, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Test.path('simple').doValidate(undefined, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Test.path('simple').doValidate('', function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Test.path('simple').doValidate('woot', function(err){ + should.strictEqual(err, null); + }); + }, + + 'test string enum validation': function(){ + var Test = new Schema({ + complex: { type: String, enum: ['a', 'b', undefined, 'c', null] } + }); + + Test.path('complex').should.be.an.instanceof(SchemaTypes.String); + Test.path('complex').enumValues.should.eql(['a', 'b', 'c', null]); + Test.path('complex').validators.should.have.length(1); + + Test.path('complex').enum('d', 'e'); + + Test.path('complex').enumValues.should.eql(['a', 'b', 'c', null, 'd', 'e']); + + Test.path('complex').doValidate('x', function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Test.path('complex').doValidate(undefined, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Test.path('complex').doValidate(null, function(err){ + should.strictEqual(null, err); + }); + + Test.path('complex').doValidate('da', function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + }, + + 'test string regular expression validation': function(){ + var Test = new Schema({ + simple: { type: String, match: /[a-z]/ } + }); + + Test.path('simple').validators.should.have.length(1); + + Test.path('simple').doValidate('az', function(err){ + should.strictEqual(err, null); + }); + + Test.path('simple').match(/[0-9]/); + Test.path('simple').validators.should.have.length(2); + + Test.path('simple').doValidate('12', function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Test.path('simple').doValidate('a12', function(err){ + should.strictEqual(err, null); + }); + }, + + 'test string casting': function(){ + var Tobi = new Schema({ + nickname: String + }); + + function Test(){}; + Test.prototype.toString = function(){ + return 'woot'; + }; + + // test Number -> String cast + Tobi.path('nickname').cast(0).should.be.a('string'); + Tobi.path('nickname').cast(0).should.eql('0'); + + // test any object that implements toString + Tobi.path('nickname').cast(new Test()).should.be.a('string'); + Tobi.path('nickname').cast(new Test()).should.eql('woot'); + }, + + 'test number minimums and maximums validation': function(){ + var Tobi = new Schema({ + friends: { type: Number, max: 15, min: 5 } + }); + + Tobi.path('friends').validators.should.have.length(2); + + Tobi.path('friends').doValidate(10, function(err){ + should.strictEqual(err, null); + }); + + Tobi.path('friends').doValidate(100, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Tobi.path('friends').doValidate(1, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + }, + + 'test number required validation': function(){ + var Edwald = new Schema({ + friends: { type: Number, required: true } + }); + + Edwald.path('friends').doValidate(null, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Edwald.path('friends').doValidate(undefined, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Edwald.path('friends').doValidate(0, function(err){ + should.strictEqual(err, null); + }); + }, + + 'test number casting': function(){ + var Tobi = new Schema({ + age: Number + }); + + // test String -> Number cast + Tobi.path('age').cast('0').should.be.an.instanceof(MongooseNumber); + (+Tobi.path('age').cast('0')).should.eql(0); + + Tobi.path('age').cast(0).should.be.an.instanceof(MongooseNumber); + (+Tobi.path('age').cast(0)).should.eql(0); + }, + + 'test date required validation': function(){ + var Loki = new Schema({ + birth_date: { type: Date, required: true } + }); + + Loki.path('birth_date').doValidate(null, function (err) { + err.should.be.an.instanceof(ValidatorError); + }); + + Loki.path('birth_date').doValidate(undefined, function (err) { + err.should.be.an.instanceof(ValidatorError); + }); + + Loki.path('birth_date').doValidate(new Date(), function (err) { + should.strictEqual(err, null); + }); + }, + + 'test date casting': function(){ + var Loki = new Schema({ + birth_date: { type: Date } + }); + + Loki.path('birth_date').cast(1294525628301).should.be.an.instanceof(Date); + Loki.path('birth_date').cast('8/24/2000').should.be.an.instanceof(Date); + Loki.path('birth_date').cast(new Date).should.be.an.instanceof(Date); + }, + + 'test object id required validator': function(){ + var Loki = new Schema({ + owner: { type: ObjectId, required: true } + }); + + Loki.path('owner').doValidate(new DocumentObjectId(), function(err){ + should.strictEqual(err, null); + }); + + Loki.path('owner').doValidate(null, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Loki.path('owner').doValidate(undefined, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + }, + + 'test object id casting': function(){ + var Loki = new Schema({ + owner: { type: ObjectId } + }); + + var doc = new TestDocument() + , id = doc._id.toString(); + + Loki.path('owner').cast('4c54f3453e688c000000001a') + .should.be.an.instanceof(DocumentObjectId); + + Loki.path('owner').cast(new DocumentObjectId()) + .should.be.an.instanceof(DocumentObjectId); + + Loki.path('owner').cast(doc) + .should.be.an.instanceof(DocumentObjectId); + + Loki.path('owner').cast(doc).toString().should.eql(id); + }, + + 'test array required validation': function(){ + var Loki = new Schema({ + likes: { type: Array, required: true } + }); + + Loki.path('likes').doValidate(null, function (err) { + err.should.be.an.instanceof(ValidatorError); + }); + + Loki.path('likes').doValidate(undefined, function (err) { + err.should.be.an.instanceof(ValidatorError); + }); + + Loki.path('likes').doValidate([], function (err) { + err.should.be.an.instanceof(ValidatorError); + }); + }, + + 'test array casting': function(){ + var Loki = new Schema({ + oids : [ObjectId] + , dates : [Date] + , numbers : [Number] + , strings : [String] + , nocast : [] + , mixed : [Mixed] + }); + + var oids = Loki.path('oids').cast(['4c54f3453e688c000000001a', new DocumentObjectId]); + + oids[0].should.be.an.instanceof(DocumentObjectId); + oids[1].should.be.an.instanceof(DocumentObjectId); + + var dates = Loki.path('dates').cast(['8/24/2010', 1294541504958]); + + dates[0].should.be.an.instanceof(Date); + dates[1].should.be.an.instanceof(Date); + + var numbers = Loki.path('numbers').cast([152, '31']); + + numbers[0].should.be.a('number'); + numbers[1].should.be.a('number'); + + var strings = Loki.path('strings').cast(['test', 123]); + + strings[0].should.be.a('string'); + strings[0].should.eql('test'); + + strings[1].should.be.a('string'); + strings[1].should.eql('123'); + + var nocasts = Loki.path('nocast').cast(['test', 123]); + + nocasts[0].should.be.a('string'); + nocasts[0].should.eql('test'); + + nocasts[1].should.be.a('number'); + nocasts[1].should.eql(123); + + var mixed = Loki.path('mixed').cast(['test', 123, '123', {}, new Date, new DocumentObjectId]); + + mixed[0].should.be.a('string'); + mixed[1].should.be.a('number'); + mixed[2].should.be.a('string'); + mixed[3].should.be.a('object'); + mixed[4].should.be.an.instanceof(Date); + mixed[5].should.be.an.instanceof(DocumentObjectId); + }, + + 'test boolean required validator': function(){ + var Animal = new Schema({ + isFerret: { type: Boolean, required: true } + }); + + Animal.path('isFerret').doValidate(null, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Animal.path('isFerret').doValidate(undefined, function(err){ + err.should.be.an.instanceof(ValidatorError); + }); + + Animal.path('isFerret').doValidate(true, function(err){ + should.strictEqual(err, null); + }); + + Animal.path('isFerret').doValidate(false, function(err){ + should.strictEqual(err, null); + }); + }, + + 'test boolean casting': function(){ + var Animal = new Schema({ + isFerret: { type: Boolean, required: true } + }); + + Animal.path('isFerret').cast(null).should.be.false; + Animal.path('isFerret').cast(undefined).should.be.false; + Animal.path('isFerret').cast(false).should.be.false; + Animal.path('isFerret').cast(0).should.be.false; + Animal.path('isFerret').cast('0').should.be.false; + Animal.path('isFerret').cast({}).should.be.true; + Animal.path('isFerret').cast(true).should.be.true; + Animal.path('isFerret').cast(1).should.be.true; + Animal.path('isFerret').cast('1').should.be.true; + }, + + 'test async validators': function(beforeExit){ + var executed = 0; + + function validator (value, fn) { + setTimeout(function(){ + executed++; + fn(value === true); + }, 50); + }; + + var Animal = new Schema({ + ferret: { type: Boolean, validate: validator } + }); + + Animal.path('ferret').doValidate(true, function(err){ + should.strictEqual(err, null); + }); + + Animal.path('ferret').doValidate(false, function(err){ + err.should.be.an.instanceof(Error); + }); + + beforeExit(function(){ + executed.should.eql(2); + }); + }, + + 'test async validators scope': function(beforeExit){ + var executed = false; + + function validator (value, fn) { + this.a.should.eql('b'); + + setTimeout(function(){ + executed = true; + fn(true); + }, 50); + }; + + var Animal = new Schema({ + ferret: { type: Boolean, validate: validator } + }); + + Animal.path('ferret').doValidate(true, function(err){ + should.strictEqual(err, null); + }, { a: 'b' }); + + beforeExit(function(){ + executed.should.be.true; + }); + }, + + 'test declaring new methods': function(){ + var a = new Schema(); + a.method('test', function(){}); + a.method({ + a: function(){} + , b: function(){} + }); + + Object.keys(a.methods).should.have.length(3); + }, + + 'test declaring new statics': function(){ + var a = new Schema(); + a.static('test', function(){}); + a.static({ + a: function(){} + , b: function(){} + , c: function(){} + }); + + Object.keys(a.statics).should.have.length(4); + }, + + 'test setter(s)': function(){ + function lowercase (v) { + return v.toLowerCase(); + }; + + var Tobi = new Schema({ + name: { type: String, set: lowercase } + }); + + Tobi.path('name').applySetters('WOOT').should.eql('woot'); + Tobi.path('name').setters.should.have.length(1); + + Tobi.path('name').set(function(v){ + return v + 'WOOT'; + }); + + Tobi.path('name').applySetters('WOOT').should.eql('wootwoot'); + Tobi.path('name').setters.should.have.length(2); + }, + + 'test setters scope': function(){ + function lowercase (v) { + this.a.should.eql('b'); + return v.toLowerCase(); + }; + + var Tobi = new Schema({ + name: { type: String, set: lowercase } + }); + + Tobi.path('name').applySetters('WHAT', { a: 'b' }).should.eql('what'); + }, + + 'test string built-in setter `lowercase`': function () { + var Tobi = new Schema({ + name: { type: String, lowercase: true } + }); + + Tobi.path('name').applySetters('WHAT').should.eql('what'); + }, + + 'test string built-in setter `uppercase`': function () { + var Tobi = new Schema({ + name: { type: String, uppercase: true } + }); + + Tobi.path('name').applySetters('what').should.eql('WHAT'); + }, + + 'test string built-in setter `trim`': function () { + var Tobi = new Schema({ + name: { type: String, uppercase: true, trim: true } + }); + + Tobi.path('name').applySetters(' what ').should.eql('WHAT'); + }, + + 'test getter(s)': function(){ + function woot (v) { + return v + ' woot'; + }; + + var Tobi = new Schema({ + name: { type: String, get: woot } + }); + + Tobi.path('name').getters.should.have.length(1); + Tobi.path('name').applyGetters('test').should.eql('test woot'); + }, + + 'test getters scope': function(){ + function woot (v) { + this.a.should.eql('b'); + return v.toLowerCase(); + }; + + var Tobi = new Schema({ + name: { type: String, get: woot } + }); + + Tobi.path('name').applyGetters('YEP', { a: 'b' }).should.eql('yep'); + }, + + 'test setters casting': function(){ + function last (v) { + v.should.be.a('string'); + v.should.eql('0'); + return 'last'; + }; + + function first (v) { + return 0; + }; + + var Tobi = new Schema({ + name: { type: String, set: last } + }); + + Tobi.path('name').set(first); + Tobi.path('name').applySetters('woot').should.eql('last'); + }, + + 'test getters casting': function(){ + function last (v) { + v.should.be.a('string'); + v.should.eql('0'); + return 'last'; + }; + + function first (v) { + return 0; + }; + + var Tobi = new Schema({ + name: { type: String, get: last } + }); + + Tobi.path('name').get(first); + Tobi.path('name').applyGetters('woot').should.eql('last'); + }, + + 'test hooks registration': function(){ + var Tobi = new Schema(); + + Tobi.pre('save', function(){}); + Tobi.callQueue.should.have.length(1); + + Tobi.post('save', function(){}); + Tobi.callQueue.should.have.length(2); + + Tobi.pre('save', function(){}); + Tobi.callQueue.should.have.length(3); + }, + + 'test applying setters when none have been defined': function(){ + var Tobi = new Schema({ + name: String + }); + + Tobi.path('name').applySetters('woot').should.eql('woot'); + }, + + 'test applying getters when none have been defined': function(){ + var Tobi = new Schema({ + name: String + }); + + Tobi.path('name').applyGetters('woot').should.eql('woot'); + }, + + 'test defining an index': function(){ + var Tobi = new Schema({ + name: { type: String, index: true } + }); + + Tobi.path('name')._index.should.be.true; + Tobi.path('name').index({ unique: true }); + Tobi.path('name')._index.should.eql({ unique: true }); + Tobi.path('name').unique(false); + Tobi.path('name')._index.should.eql({ unique: false}); + + var T1 = new Schema({ + name: { type: String, sparse: true } + }); + T1.path('name')._index.should.eql({ sparse: true }); + + var T2 = new Schema({ + name: { type: String, unique: true } + }); + T2.path('name')._index.should.eql({ unique: true }); + + var T3 = new Schema({ + name: { type: String, sparse: true, unique: true } + }); + T3.path('name')._index.should.eql({ sparse: true, unique: true }); + + var T4 = new Schema({ + name: { type: String, unique: true, sparse: true } + }); + var i = T4.path('name')._index; + i.unique.should.be.true; + i.sparse.should.be.true; + + var T5 = new Schema({ + name: { type: String, index: { sparse: true, unique: true } } + }); + var i = T5.path('name')._index; + i.unique.should.be.true; + i.sparse.should.be.true; + }, + + 'test defining compound indexes': function(){ + var Tobi = new Schema({ + name: { type: String, index: true } + , last: { type: Number, sparse: true } + }); + + Tobi.index({ firstname: 1, last: 1 }, { unique: true }); + + Tobi.indexes.should.eql([ + [{ name: 1 }, {}] + , [{ last: 1 }, { sparse: true }] + , [{ firstname: 1, last: 1}, {unique: true}] + ]); + }, + + 'test plugins': function (beforeExit) { + var Tobi = new Schema() + , called = false; + + Tobi.plugin(function(schema){ + schema.should.equal(Tobi); + called = true; + }); + + beforeExit(function () { + called.should.be.true; + }); + }, + + 'test that default options are set': function () { + var Tobi = new Schema(); + + Tobi.options.should.be.a('object'); + Tobi.options.safe.should.be.true; + }, + + 'test setting options': function () { + var Tobi = new Schema(); + + Tobi.set('a', 'b'); + Tobi.set('safe', false); + + Tobi.options.a.should.eql('b'); + Tobi.options.safe.should.be.false; + }, + + 'test declaring virtual attributes': function () { + var Contact = new Schema({ + firstName: String + , lastName: String + }); + Contact.virtual('fullName') + .get( function () { + return this.get('firstName') + ' ' + this.get('lastName'); + }).set(function (fullName) { + var split = fullName.split(' '); + this.set('firstName', split[0]); + this.set('lastName', split[1]); + }); + + Contact.virtualpath('fullName').should.be.an.instanceof(VirtualType); + }, + + 'test GH-298 - The default creation of a virtual `id` should be muted when someone defines their own `id` attribute': function () { + new Schema({ id: String }); + }, + + 'allow disabling the auto .id virtual': function () { + var schema = new Schema({ name: String }, { noVirtualId: true }); + should.strictEqual(undefined, schema.virtuals.id); + }, + + 'schema creation works with objects from other contexts': function () { + var str = 'code = {' + + ' name: String' + + ', arr1: Array ' + + ', arr2: { type: [] }' + + ', date: Date ' + + ', num: { type: Number }' + + ', bool: Boolean' + + ', nest: { sub: { type: {}, required: true }}' + + '}'; + + var script = vm.createScript(str, 'testSchema.vm'); + var sandbox = { code: null }; + script.runInNewContext(sandbox); + + var Ferret = new Schema(sandbox.code); + Ferret.path('nest.sub').should.be.an.instanceof(SchemaTypes.Mixed); + Ferret.path('name').should.be.an.instanceof(SchemaTypes.String); + Ferret.path('arr1').should.be.an.instanceof(SchemaTypes.Array); + Ferret.path('arr2').should.be.an.instanceof(SchemaTypes.Array); + Ferret.path('date').should.be.an.instanceof(SchemaTypes.Date); + Ferret.path('num').should.be.an.instanceof(SchemaTypes.Number); + Ferret.path('bool').should.be.an.instanceof(SchemaTypes.Boolean); + } + +}; diff --git a/node_modules/mongoose/test/types.array.test.js b/node_modules/mongoose/test/types.array.test.js new file mode 100644 index 0000000..98898b3 --- /dev/null +++ b/node_modules/mongoose/test/types.array.test.js @@ -0,0 +1,111 @@ + +/** + * Module dependencies. + */ + +var start = require('./common') + , should = require('should') + , mongoose = require('./common').mongoose + , Schema = mongoose.Schema + , random = require('mongoose/utils').random + , MongooseArray = mongoose.Types.Array; + +var User = new Schema({ + name: String + , pets: [Schema.ObjectId] +}); + +mongoose.model('User', User); + +var Pet = new Schema({ + name: String +}); + +mongoose.model('Pet', Pet); + +/** + * Test. + */ + +module.exports = { + + 'test that a mongoose array behaves and quacks like an array': function(){ + var a = new MongooseArray; + + a.should.be.an.instanceof(Array); + a.should.be.an.instanceof(MongooseArray); + Array.isArray(a).should.be.true; + (a._atomics.constructor).should.eql(Object); + }, + + 'test indexOf()': function(){ + var db = start() + , User = db.model('User', 'users_' + random()) + , Pet = db.model('Pet', 'pets' + random()); + + var tj = new User({ name: 'tj' }) + , tobi = new Pet({ name: 'tobi' }) + , loki = new Pet({ name: 'loki' }) + , jane = new Pet({ name: 'jane' }) + , pets = []; + + tj.pets.push(tobi); + tj.pets.push(loki); + tj.pets.push(jane); + + var pending = 3; + + ;[tobi, loki, jane].forEach(function(pet){ + pet.save(function(){ + --pending || done(); + }); + }); + + function done() { + Pet.find({}, function(err, pets){ + tj.save(function(err){ + User.findOne({ name: 'tj' }, function(err, user){ + db.close(); + should.equal(null, err, 'error in callback'); + user.pets.should.have.length(3); + user.pets.indexOf(tobi.id).should.equal(0); + user.pets.indexOf(loki.id).should.equal(1); + user.pets.indexOf(jane.id).should.equal(2); + user.pets.indexOf(tobi._id).should.equal(0); + user.pets.indexOf(loki._id).should.equal(1); + user.pets.indexOf(jane._id).should.equal(2); + }); + }); + }); + } + }, + + 'test #splice()': function () { + var collection = 'splicetest' + random(); + var db = start() + , schema = new Schema({ numbers: Array }) + , A = db.model('splicetest', schema, collection); + + var a = new A({ numbers: [4,5,6,7] }); + a.save(function (err) { + should.equal(null, err, 'could not save splice test'); + A.findById(a._id, function (err, doc) { + should.equal(null, err, 'error finding splice doc'); + doc.numbers.splice(1, 1); + doc.numbers.toObject().should.eql([4,6,7]); + doc.save(function (err) { + should.equal(null, err, 'could not save splice test'); + A.findById(a._id, function (err, doc) { + should.equal(null, err, 'error finding splice doc'); + doc.numbers.toObject().should.eql([4,6,7]); + + A.collection.drop(function (err) { + db.close(); + should.strictEqual(err, null); + }); + }); + }); + }); + }); + } +}; diff --git a/node_modules/mongoose/test/types.document.test.js b/node_modules/mongoose/test/types.document.test.js new file mode 100644 index 0000000..41a7959 --- /dev/null +++ b/node_modules/mongoose/test/types.document.test.js @@ -0,0 +1,83 @@ + +/** + * Module dependencies. + */ + +var should = require('should') + , mongoose = require('./common').mongoose + , EmbeddedDocument = require('mongoose/types/document') + , DocumentArray = require('mongoose/types/documentarray') + , Schema = mongoose.Schema + , SchemaType = mongoose.SchemaType + , ValidatorError = SchemaType.ValidatorError + , ValidationError = mongoose.Document.ValidationError + +/** + * Setup. + */ + +function Subdocument () { + EmbeddedDocument.call(this, {}, new DocumentArray); +}; + +/** + * Inherits from EmbeddedDocument. + */ + +Subdocument.prototype.__proto__ = EmbeddedDocument.prototype; + +/** + * Set schema. + */ + +Subdocument.prototype.schema = new Schema({ + test: { type: String, required: true } + , work: { type: String, validate: /^good/ } +}); + +/** + * Test. + */ + +module.exports = { + + 'test that save fires errors': function(){ + var a = new Subdocument(); + a.set('test', ''); + a.set('work', 'nope'); + + a.save(function(err){ + err.should.be.an.instanceof(ValidationError); + err.toString().should.eql('ValidationError: Validator "required" failed for path test, Validator failed for path work'); + }); + }, + + 'test that save fires with null if no errors': function(){ + var a = new Subdocument(); + a.set('test', 'cool'); + a.set('work', 'goods'); + + a.save(function(err){ + should.strictEqual(err, null); + }); + }, + + 'objects can be passed to #set': function () { + var a = new Subdocument(); + a.set({ test: 'paradiddle', work: 'good flam'}); + a.test.should.eql('paradiddle'); + a.work.should.eql('good flam'); + }, + + 'Subdocuments can be passed to #set': function () { + var a = new Subdocument(); + a.set({ test: 'paradiddle', work: 'good flam'}); + a.test.should.eql('paradiddle'); + a.work.should.eql('good flam'); + var b = new Subdocument(); + b.set(a); + b.test.should.eql('paradiddle'); + b.work.should.eql('good flam'); + } + +}; diff --git a/node_modules/mongoose/test/types.documentarray.test.js b/node_modules/mongoose/test/types.documentarray.test.js new file mode 100644 index 0000000..44c701f --- /dev/null +++ b/node_modules/mongoose/test/types.documentarray.test.js @@ -0,0 +1,31 @@ + +/** + * Module dependencies. + */ + +var mongoose = require('./common').mongoose + , MongooseArray = mongoose.Types.Array + , MongooseDocumentArray = mongoose.Types.DocumentArray; + +/** + * Test. + */ + +module.exports = { + + 'test that a mongoose array behaves and quacks like an array': function(){ + var a = new MongooseDocumentArray(); + + a.should.be.an.instanceof(Array); + a.should.be.an.instanceof(MongooseArray); + a.should.be.an.instanceof(MongooseDocumentArray); + Array.isArray(a).should.be.true; + Array.isArray(a._atomics).should.be.true; + 'object'.should.eql(typeof a); + + var b = new MongooseArray([1,2,3,4]); + 'object'.should.eql(typeof b); + Object.keys(b).length.should.equal(4); + } + +}; diff --git a/node_modules/mongoose/test/types.number.test.js b/node_modules/mongoose/test/types.number.test.js new file mode 100644 index 0000000..e0daf0f --- /dev/null +++ b/node_modules/mongoose/test/types.number.test.js @@ -0,0 +1,32 @@ + +/** + * Module dependencies. + */ + +var mongoose = require('./common').mongoose + , MongooseNumber = mongoose.Types.Number + , SchemaNumber = mongoose.Schema.Types.Number + , should = require('should') + +/** + * Test. + */ + +module.exports = { + + 'test that a mongoose number behaves and quacks like a number': function(){ + var a = new MongooseNumber(5); + + a.should.be.an.instanceof(Number); + a.should.be.an.instanceof(MongooseNumber); + a.toString().should.eql('5'); + + (a._atomics.constructor).should.eql(Object); + }, + + 'an empty string casts to null': function () { + var n = new SchemaNumber(); + should.strictEqual(n.cast(''), null); + } + +}; diff --git a/node_modules/mongoose/test/utils.test.js b/node_modules/mongoose/test/utils.test.js new file mode 100644 index 0000000..97b9c1e --- /dev/null +++ b/node_modules/mongoose/test/utils.test.js @@ -0,0 +1,154 @@ + +/** + * Module dependencies. + */ + +require('./common'); + +var utils = require('mongoose/utils') + , StateMachine = utils.StateMachine; + +/** + * Setup. + */ + +var ActiveRoster = StateMachine.ctor('require', 'init', 'modify'); + +/** + * Test. + */ + +module.exports = { + + 'test array erasing util': function(){ + function fn(){}; + var arr = [fn, 'test', 1] + , arr2 = [fn, 'a', 'b', fn, 'c']; + + utils.erase(arr, fn); + arr.should.have.length(2); + arr.should.eql(['test', 1]); + + utils.erase(arr2, fn); + arr2.should.have.length(3); + arr2.should.eql(['a', 'b', 'c']); + }, + + 'should detect a path as required if it has been required': function () { + var ar = new ActiveRoster(); + ar.require('hello'); + ar.stateOf('hello').should.equal('require'); + }, + + 'should detect a path as inited if it has been inited': function () { + var ar = new ActiveRoster(); + ar.init('hello'); + ar.stateOf('hello').should.equal('init'); + }, + + 'should detect a path as modified': function () { + var ar = new ActiveRoster(); + ar.modify('hello'); + ar.stateOf('hello').should.equal('modify'); + }, + + 'should remove a path from an old state upon a state change': function () { + var ar = new ActiveRoster(); + ar.init('hello'); + ar.modify('hello'); + ar.states.init.should.not.have.property('hello'); + ar.states.modify.should.have.property('hello'); + }, + + + 'forEach should be able to iterate through the paths belonging to one state': function () { + var ar = new ActiveRoster(); + ar.init('hello'); + ar.init('goodbye'); + ar.modify('world'); + ar.require('foo'); + ar.forEach('init', function (path) { + ['hello', 'goodbye'].should.contain(path); + }); + }, + + 'forEach should be able to iterate through the paths in the union of two or more states': function () { + var ar = new ActiveRoster(); + ar.init('hello'); + ar.init('goodbye'); + ar.modify('world'); + ar.require('foo'); + ar.forEach('modify', 'require', function (path) { + ['world', 'foo'].should.contain(path); + }); + }, + + 'forEach should iterate through all paths that have any state if given no state arguments': function () { + var ar = new ActiveRoster(); + ar.init('hello'); + ar.init('goodbye'); + ar.modify('world'); + ar.require('foo'); + ar.forEach(function (path) { + ['hello', 'goodbye', 'world', 'foo'].should.contain(path); + }); + }, + + 'should be able to detect if at least one path exists in a set of states': function () { + var ar = new ActiveRoster(); + ar.init('hello'); + ar.modify('world'); + ar.some('init').should.be.true; + ar.some('modify').should.be.true; + ar.some('require').should.be.false; + ar.some('init', 'modify').should.be.true; + ar.some('init', 'require').should.be.true; + ar.some('modify', 'require').should.be.true; + }, + + 'should be able to `map` over the set of paths in a given state': function () { + var ar = new ActiveRoster(); + ar.init('hello'); + ar.modify('world'); + ar.require('iAmTheWalrus'); + var suffixedPaths = ar.map('init', 'modify', function (path) { + return path + '-suffix'; + }); + suffixedPaths.should.eql(['hello-suffix', 'world-suffix']); + }, + + "should `map` over all states' paths if no states are specified in a `map` invocation": function () { + var ar = new ActiveRoster(); + ar.init('hello'); + ar.modify('world'); + ar.require('iAmTheWalrus'); + var suffixedPaths = ar.map(function (path) { + return path + '-suffix'; + }); + suffixedPaths.should.eql(['iAmTheWalrus-suffix', 'hello-suffix', 'world-suffix']); + }, + + 'test utils.options': function () { + var o = { a: 1, b: 2, c: 3, 0: 'zero1' }; + var defaults = { b: 10, d: 20, 0: 'zero2' }; + var result = utils.options(defaults, o); + result.a.should.equal(1); + result.b.should.equal(2); + result.c.should.equal(3); + result.d.should.equal(20); + o.d.should.equal(result.d); + result['0'].should.equal('zero1'); + + var result2 = utils.options(defaults); + result2.b.should.equal(10); + result2.d.should.equal(20); + result2['0'].should.equal('zero2'); + + // same properties/vals + defaults.should.eql(result2); + + // same object + defaults.should.not.equal(result2); + } + +}; diff --git a/node_modules/mysql/License b/node_modules/mysql/License new file mode 100644 index 0000000..37f77ee --- /dev/null +++ b/node_modules/mysql/License @@ -0,0 +1,19 @@ +Copyright (c) 2010 Felix Geisendörfer (felix@debuggable.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/mysql/Makefile b/node_modules/mysql/Makefile new file mode 100644 index 0000000..046804e --- /dev/null +++ b/node_modules/mysql/Makefile @@ -0,0 +1,12 @@ +SHELL := /bin/bash + +test: + @./test/run.js +benchmark-node-mysql: + @find benchmark/node-mysql/*.js | xargs -n 1 -t node +benchmark-php: + @find benchmark/php/*.php | xargs -n 1 -t php +benchmark-all: benchmark-node-mysql benchmark-php +benchmark: benchmark-node-mysql + +.PHONY: test benchmark diff --git a/node_modules/mysql/Readme.md b/node_modules/mysql/Readme.md new file mode 100644 index 0000000..104684b --- /dev/null +++ b/node_modules/mysql/Readme.md @@ -0,0 +1,269 @@ +# node-mysql + +## Purpose + +A pure node.js JavaScript Client implementing the [MySQL protocol](http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol). + +## Support this module + +If you like this module, check out and spread the word about our service +[transloadit.com][]. We provide file uploading and encoding functionality to +other applications, and have performed billions of queries with this module so +far. + +[transloadit.com]: http://transloadit.com/ + +## Installation + +``` +npm install mysql +``` + +**Important**: If you are upgrading from 0.9.1 or below, there have been +backwards incompatible changes in the API. Please read the [upgrading guide][]. + +[upgrading guide]: https://github.com/felixge/node-mysql/wiki/Upgrading-to-0.9.2+ + +## Usage + +``` javascript +var mysql = require('mysql'); +var TEST_DATABASE = 'nodejs_mysql_test'; +var TEST_TABLE = 'test'; +var client = mysql.createClient({ + user: 'root', + password: 'root', +}); + +client.query('CREATE DATABASE '+TEST_DATABASE, function(err) { + if (err && err.number != mysql.ERROR_DB_CREATE_EXISTS) { + throw err; + } +}); + +// If no callback is provided, any errors will be emitted as `'error'` +// events by the client +client.query('USE '+TEST_DATABASE); + +client.query( + 'CREATE TEMPORARY TABLE '+TEST_TABLE+ + '(id INT(11) AUTO_INCREMENT, '+ + 'title VARCHAR(255), '+ + 'text TEXT, '+ + 'created DATETIME, '+ + 'PRIMARY KEY (id))' +); + +client.query( + 'INSERT INTO '+TEST_TABLE+' '+ + 'SET title = ?, text = ?, created = ?', + ['super cool', 'this is a nice text', '2010-08-16 10:00:23'] +); + +var query = client.query( + 'INSERT INTO '+TEST_TABLE+' '+ + 'SET title = ?, text = ?, created = ?', + ['another entry', 'because 2 entries make a better test', '2010-08-16 12:42:15'] +); + +client.query( + 'SELECT * FROM '+TEST_TABLE, + function selectCb(err, results, fields) { + if (err) { + throw err; + } + + console.log(results); + console.log(fields); + client.end(); + } +); +``` + +## API + +### mysql.createClient([options]) + +Creates a new client instance. Any client property can be set using the +`options` object. + +### client.host = 'localhost' + +The host to connect to. + +### client.port = 3306 + +The port to connect to. + +### client.user = null + +The username to authenticate as. + +### client.password = null + +The password to use. + +### client.database = null + +The name of the database to connect to (optional). + +### client.debug = false + +Prints incoming and outgoing packets, useful for development / testing purposes. + +### client.flags = Client.defaultFlags + +Connection flags send to the server. + +### client.query(sql, [params, cb]) + +Sends a `sql` query to the server. `'?'` characters can be used as placeholders +for an array of `params` that will be safely escaped before sending the final +query. + +This method returns a `Query` object which can be used to stream incoming row +data. + +**Warning:** `sql` statements with multiple queries separated by semicolons +are not supported yet. + +### client.ping([cb]) + +Sends a ping command to the server. + +### client.useDatabase(database, [cb]) + +Same as issuing a `'USE '` query. + +### client.statistics([cb]) + +Returns some server statistics provided by MySql. + +### client.format(sql, params) + +Allows to safely insert a list of `params` into a `sql` string using the +placeholder mechanism described above. + +### client.escape(val) + +Escapes a single `val` for use inside of a sql string. + +### client.destroy([cb]) + +Forces the client connection to be destroyed right away. This is not a +nice way to terminate the connection, use with caution. + +### client.end([cb]) + +Schedule a COM_QUIT packet for closing the connection. All currently queued +queries will still execute before the graceful termination of the connection +is attempted. + +### client event: 'error' (err) + +When the client has no callback / delegate for an error, it is emitted with this +event instead. + +### new mysql.Query() + +Query objects are not meant to be invoked manually. To get a query object, use +the `client.query` API. + +### query event: 'error' (err) + +Emitted when mysql returns an error packet for the query. + +### query event: 'field' (field) + +Emitted upon receiving a field packet from mysql. + +### query event: 'row' (row) + +Emitted upon receiving a row. An option for streaming the contents of the row +itself will be made available soon. + +### query event: 'end' ([result]) + +Emitted once the query is finished. In case there is no result set, a `result` +parameter is provided which contains the information from the mysql OK packet. + +## FAQ + +### How do I compile this module? + +This module is written entirely in JavaScript. There is no dependency on external +C libraries such as libmysql. That means you don't have to compile this module +at all. + +### How can I retrieve the id from the last inserted record? + + client.query('INSERT INTO my_table SET title = ?', function(err, info) { + console.log(info.insertId); + }); + +## Todo + +At this point the module is ready to be tried out, but a lot of things are yet to be done: + +* Implement retry +* Pause / resume +* Remaining mysql commands +* Prepared Statements +* Packet's > 16 MB +* Compression +* Decide how to handle queries with multiple statements + +## Contributors + +[Click here][contributors] for a full list of contributors. + +[contributors]: https://github.com/felixge/node-mysql/contributors + +## Sponsors + +* [Joyent](http://www.joyent.com/) - Main sponsor, you should check out their [node.js hosting](https://no.de/). +* [pinkbike.com](http://pinkbike.com/) - The most awesome biking site there is + +This is a rather large project requiring a significant amount of my limited resources. + +If your company could benefit from a well-engineered non-blocking mysql driver, and +wants to support this project, I would greatly appriciate any sponsorship you may be +able to provide. All sponsors will get lifetime display in this readme, priority +support on problems, and votes on roadmap decisions. If you are interested, contact +me at [felix@debuggable.com](mailto:felix@debuggable.com) for details. + +Of course I'm also happy about code contributions. If you're interested in +working on features, just get in touch so we can talk about API design and +testing. + +[transloadit]: http://transloadit.com/ + +## Changelog + +### v0.9.2 + +* The underlaying socket connection is now managed implicitly rather than explicitly. +* Check the [upgrading guide][] for a full list of changes. + +### v0.9.1 + +* Fix issue #49 / `client.escape()` throwing exceptions on objects. (Nick Payne) +* Drop < v0.4.x compatibility. From now on you need node v0.4.x to use this module. + +### Older releases + +These releases were done before starting to maintain the above Changelog: + +* [v0.9.0](https://github.com/felixge/node-mysql/compare/v0.8.0...v0.9.0) +* [v0.8.0](https://github.com/felixge/node-mysql/compare/v0.7.0...v0.8.0) +* [v0.7.0](https://github.com/felixge/node-mysql/compare/v0.6.0...v0.7.0) +* [v0.6.0](https://github.com/felixge/node-mysql/compare/v0.5.0...v0.6.0) +* [v0.5.0](https://github.com/felixge/node-mysql/compare/v0.4.0...v0.5.0) +* [v0.4.0](https://github.com/felixge/node-mysql/compare/v0.3.0...v0.4.0) +* [v0.3.0](https://github.com/felixge/node-mysql/compare/v0.2.0...v0.3.0) +* [v0.2.0](https://github.com/felixge/node-mysql/compare/v0.1.0...v0.2.0) +* [v0.1.0](https://github.com/felixge/node-mysql/commits/v0.1.0) + +## License + +node-mysql is licensed under the MIT license. diff --git a/node_modules/mysql/benchmark/.insert.js.un~ b/node_modules/mysql/benchmark/.insert.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..74b0fba13f76a69c8eaa54e258957a8e92d45a3e GIT binary patch literal 25784 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 HZ=d}S7J20v literal 0 HcmV?d00001 diff --git a/node_modules/mysql/benchmark/.select.js.un~ b/node_modules/mysql/benchmark/.select.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..f6010edb91d74a2a3669fd4fa57dc5a9f3e59fc2 GIT binary patch literal 102257 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 P#q-i|(UG_R{{8<0tL~?} literal 0 HcmV?d00001 diff --git a/node_modules/mysql/benchmark/node-mysql/.insert.js.un~ b/node_modules/mysql/benchmark/node-mysql/.insert.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..6bae21b33822dc887d278c61731c23d9e03f07c5 GIT binary patch literal 5117 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 literal 0 HcmV?d00001 diff --git a/node_modules/mysql/benchmark/php/insert-select.php b/node_modules/mysql/benchmark/php/insert-select.php new file mode 100644 index 0000000..c3c3a51 --- /dev/null +++ b/node_modules/mysql/benchmark/php/insert-select.php @@ -0,0 +1,40 @@ + 'localhost', + 'port' => 3306, + 'user' => 'root', + 'password' => 'root', + 'db' => 'node_mysql_test', + 'table' => 'post', +); +extract($config); + +$connection = mysql_connect($host, $user, $password); +mysql_query('USE '.$db, $connection); +mysql_query('CREATE TEMPORARY TABLE '.$table.' ('. +'id INT(11) AUTO_INCREMENT, '. +'title VARCHAR(255), '. +'text TEXT, '. +'created DATETIME, '. +'PRIMARY KEY (id));', $connection); + +$start = microtime(true); +for ($i = 0; $i < $INSERTS; $i++) { + mysql_query('INSERT INTO '.$table.' SET title = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";', $connection); +} +$duration = (microtime(true) - $start); +$insertsPerSecond = $INSERTS / $duration; +echo sprintf("%d inserts / second\n", $insertsPerSecond); +echo sprintf("%d ms\n", $duration * 1000); + +$start = microtime(true); +$q = mysql_query('SELECT * FROM '.$table); +while ($a = mysql_fetch_assoc($q)) { +} +$duration = (microtime(true) - $start); +$rowsPerSecond = $INSERTS / $duration; +echo sprintf("%d rows / second\n", $rowsPerSecond); +echo sprintf("%d ms\n", $duration * 1000); +?> diff --git a/node_modules/mysql/index.js b/node_modules/mysql/index.js new file mode 100644 index 0000000..782e199 --- /dev/null +++ b/node_modules/mysql/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/mysql'); diff --git a/node_modules/mysql/lib/.auth.js.un~ b/node_modules/mysql/lib/.auth.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..a1a720fbf2e5a01d4c61a7a1372fa0a40dafe127 GIT binary patch literal 1046 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%0DWH2Qni$WifKa78B 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⪚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 literal 0 HcmV?d00001 diff --git a/node_modules/mysql/lib/.constants.js.un~ b/node_modules/mysql/lib/.constants.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..0ddf52ae3dddf39dcbc788581b302525c025ae4a GIT binary patch literal 167305 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 &Ax^uPCo~a6Vgi*dTgt|GzTb1XO9gjQpS~UHN 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 literal 0 HcmV?d00001 diff --git a/node_modules/mysql/lib/.mysql.js.un~ b/node_modules/mysql/lib/.mysql.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..08715b14843f244a0cb1b12e0320628f8ae45a67 GIT binary patch literal 15348 zcmeI3&1+m$6u>8G+Q#}(YyF7UkC)V%1at%;S+uy2whM~{DcB+iWtdKzfpjLBnUsjQ z=t5k$XcQL;LN_i%p^Cb3DY%rPh!y_;ajoE5&+oi@-keN6`ZCYAy9e&v`|g`}-{t(~ zoO|whZ_YKZ+<2{Zs{Kc0^!n*{fBdld(ZYeXl{2@S-=6>M?D$J--yM4AgP)JyJbnE8 zhi@}uQ5|!YBpNEXOnunb*XuI_Jn+Czm%t>j7XW1f>2wj zEX?2fdyKQ=l?y*{R%A4-^pjH*m48M0N7ftb|4#!8^Vi=~9F@vH6Ef@`KeYA$XDsvr zW}>mS-0t+c)q1BPKZ29`8%SPEF6p;3bn;DYZ|begT~qL!^>^bwd+n+SUNljv2>5jm z-Vk$B(2TqtIC=h@gc&7~Qi+_6tw0iLTxJ4t zP#>Zrl0*w-ije%+ljL6B=^ZnYnM>_7R#uyx#>{l}`E;qBo;?v*!fv0Nt^FJxrZ2K| znkl6zEI-+bB}g!-bTOr2gl*Xa6hV@SU2!iR5uB-|tXja`*a_U^)mkUXV}NiQce8{k ztW_dM(?nUdaQsv`j-;lB(V6;bXHja#GHsau1lL_|a-hsYpoq_Drj(}O`@)-{g(kL) znYRSX0XGAX@!k9AiIlaX6j~@#1k^9vnU{G$klgPk0WM&wL`0^EvT8x}>mVXiza~0@C4oirh+!fi%l2du zQ(1UyT)}kPV`8NtrqE1N_6Wv$6x@bhT%%bW=pNuW2v`~KL5?Fzv`|1YP0ARw9|>b! zwYH%A&7%aC2X}-F)pD)3D9_xo1Tn|`Ub~|Y*WWegaA%aCE1tbsHmv;g?2UvMWtlO)#dR+-ycEc8f<;5fu zI7haojiPm7w$(wl)$D;=7MyN=djW`#y14^5LUjr$)XW3*%uWXT+#u9EOkwz#n>T!! ziAr?BrimfzJWOBlOfe@@zs8|34e#&zonz?gZyw>M8^thFm@lrnTP56iP^m}6<;4ZrCP^XWmBJA|m9mqCOLC{Yy`nE4X&M|D)&p93JinnItFtUC@FqD9l1R;n@qNIckU~|a z$)Ht@C#6l~qiunCUSaM_t#T0E;Y9O1?WIO_seO4y+-+utiHtEN#RQ7n4<8-P5G53m zJmlU`a{K$_xCp`MCN`3ruIu0W`ny7JbX)^U=<5<0y(lUvAUW{e`b+VRr}%hY&qcQ7 On7reEbLX!8`T2hUvQm8j literal 0 HcmV?d00001 diff --git a/node_modules/mysql/lib/.outgoing_packet.js.un~ b/node_modules/mysql/lib/.outgoing_packet.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..0c2f1f5adc5ab60b60f5a1da6c987653dc965bbe GIT binary patch literal 998 zcmWH`%$*;a=aT=Ffhm2e%CzKu4;7~KdptM3NH*7VE9uw!>vSws)iS{KMaEnP1_pm1 zMh1*P4ii)WM8hzHpM~rV7LY6>L;M9K1yCkX7$gM+|A7F(gNcsP)C&P%bX*5V2Lr=b z38=BK;0MtrnQ00d={fmHi8*@iu6`jtk(vrcsfDGPMX3t53J?*!jLfXWN;m8P literal 0 HcmV?d00001 diff --git a/node_modules/mysql/lib/.parser.js.un~ b/node_modules/mysql/lib/.parser.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..ff7b25cef8687f8f1fab6d0453670ce82ea01049 GIT binary patch literal 5173 zcmeI0OK;Oa5XZNsr95t&8Xl4_HZMw`~uiK*iRkhsD8opm~*sO_P9+mW0Z@7n9h{5-SkUGmy5?{uyQpM{l* zQcLcOsZVdV9;P=^m)|b_zB2L3+L(PmJ2>G@KHC(+dM<=G)o+A$FYd| z;@6ZKHVHrUd9P(>SNveP;X5~~^S9^jmn0uiW3KOu5GY^2wU}6E$Ywm?<#&zwkl+*TV6g{4H-Bu8;NT)sMuKP|i zXuD6mHP5{{s4dRbXF8D#I}N{Ezvg?g6V+tcmtlP&45FYJ_=-39PO$$3_J%hLh+dO; ze~c^c*#9eTl9s@7n7IOEqf|B3lSM|0NtnLyiBU~v@frwr+9tW$Yqey^S3=8iOD5+G zyYedM0B@4{39!h+xb7O5EHYY5g87xhRCzRlSp>{#pGs!6?L|~XIZ}!CE+OR?BwzvZ z2=f_`0o8zILD6Rt*l!%Hn%hQT&jReit-Cb>dcTmji=}ejE|*H@NEOPJN~KsRKS45d^J5Fu!w{co^lwI~&@+!j7_s(-Hw0k%6 zGWAf-Tt!mr_ixdgiTTINe4)Lxb1sCqpptItwvufcWhYxQ9mlYhWyLmX4bwJ~2?Oo* zgsSl$q^MUIJ*kAKj8Q@0DvQW1#A*>d4U2;(Jf%P<8F+-^#s@|3PPPWu|H}Yz?7195 zbSAym%JkzpXC5ob6RUElTiRMSx3y7F?O#8mt_13`i{*k!;v+;B{bufMoY zs3}hnV#92V(EL&j1X*T$sgj_@1?9RY1=9)z-zd4{;GNWi1>^`DGmwGpPS*gIWyY5( z!In6zoKq4u4%kiIu75uqX|q+gtv5m8Hp+$wQy2!0EGhm~$+65G<$5U{$KkkQnRKR= zXBP;`^D71hJ#>rXCYX81f}cTR6)x5{^ROxYX6Er(hXKPBFT;P7z!6FCHOR5*I)=Mv P(7vtl?|(8gt@iCFG3~>q literal 0 HcmV?d00001 diff --git a/node_modules/mysql/lib/auth.js b/node_modules/mysql/lib/auth.js new file mode 100644 index 0000000..0380aab --- /dev/null +++ b/node_modules/mysql/lib/auth.js @@ -0,0 +1,164 @@ +var Buffer = require('buffer').Buffer; +var crypto = require('crypto'); + +function sha1(msg) { + var hash = crypto.createHash('sha1'); + hash.update(msg); + // hash.digest() does not output buffers yet + return hash.digest('binary'); +}; +exports.sha1 = sha1; + +function xor(a, b) { + a = new Buffer(a, 'binary'); + b = new Buffer(b, 'binary'); + var result = new Buffer(a.length); + for (var i = 0; i < a.length; i++) { + result[i] = (a[i] ^ b[i]); + } + return result; +}; +exports.xor = xor; + +exports.token = function(password, scramble) { + if (!password) { + return new Buffer(0); + } + + var stage1 = sha1(password); + var stage2 = sha1(stage1); + var stage3 = sha1(scramble.toString('binary') + stage2); + return xor(stage3, stage1); +}; + +// This is a port of sql/password.c:hash_password which needs to be used for +// pre-4.1 passwords. +exports.hashPassword = function(password) { + var nr = [0x5030, 0x5735], + add = 7, + nr2 = [0x1234, 0x5671], + result = new Buffer(8); + + if (typeof password == 'string'){ + password = new Buffer(password); + } + + for (var i = 0; i < password.length; i++) { + var c = password[i]; + if (c == 32 || c == 9) { + // skip space in password + continue; + } + + // nr^= (((nr & 63)+add)*c)+ (nr << 8); + // nr = xor(nr, add(mul(add(and(nr, 63), add), c), shl(nr, 8))) + nr = this.xor32(nr, this.add32(this.mul32(this.add32(this.and32(nr, [0,63]), [0,add]), [0,c]), this.shl32(nr, 8))); + + // nr2+=(nr2 << 8) ^ nr; + // nr2 = add(nr2, xor(shl(nr2, 8), nr)) + nr2 = this.add32(nr2, this.xor32(this.shl32(nr2, 8), nr)); + + // add+=tmp; + add += c; + } + + this.int31Write(result, nr, 0); + this.int31Write(result, nr2, 4); + + return result; +}; + +exports.randomInit = function(seed1, seed2) { + return { + max_value: 0x3FFFFFFF, + max_value_dbl: 0x3FFFFFFF, + seed1: seed1 % 0x3FFFFFFF, + seed2: seed2 % 0x3FFFFFFF + }; +}; + +exports.myRnd = function(r){ + r.seed1 = (r.seed1 * 3 + r.seed2) % r.max_value; + r.seed2 = (r.seed1 + r.seed2 + 33) % r.max_value; + + return r.seed1 / r.max_value_dbl; +}; + +exports.scramble323 = function(message, password) { + var to = new Buffer(8), + hashPass = this.hashPassword(password), + hashMessage = this.hashPassword(message.slice(0, 8)), + seed1 = this.int32Read(hashPass, 0) ^ this.int32Read(hashMessage, 0), + seed2 = this.int32Read(hashPass, 4) ^ this.int32Read(hashMessage, 4), + r = this.randomInit(seed1, seed2); + + for (var i = 0; i < 8; i++){ + to[i] = Math.floor(this.myRnd(r) * 31) + 64; + } + var extra = (Math.floor(this.myRnd(r) * 31)); + + for (var i = 0; i < 8; i++){ + to[i] ^= extra; + } + + return to; +}; + +exports.fmt32 = function(x){ + var a = x[0].toString(16), + b = x[1].toString(16); + + if (a.length == 1) a = '000'+a; + if (a.length == 2) a = '00'+a; + if (a.length == 3) a = '0'+a; + if (b.length == 1) b = '000'+b; + if (b.length == 2) b = '00'+b; + if (b.length == 3) b = '0'+b; + return '' + a + '/' + b; +}; + +exports.xor32 = function(a,b){ + return [a[0] ^ b[0], a[1] ^ b[1]]; +}; + +exports.add32 = function(a,b){ + var w1 = a[1] + b[1], + w2 = a[0] + b[0] + ((w1 & 0xFFFF0000) >> 16); + + return [w2 & 0xFFFF, w1 & 0xFFFF]; +}; + +exports.mul32 = function(a,b){ + // based on this example of multiplying 32b ints using 16b + // http://www.dsprelated.com/showmessage/89790/1.php + var w1 = a[1] * b[1], + w2 = (((a[1] * b[1]) >> 16) & 0xFFFF) + ((a[0] * b[1]) & 0xFFFF) + (a[1] * b[0] & 0xFFFF); + + return [w2 & 0xFFFF, w1 & 0xFFFF]; +}; + +exports.and32 = function(a,b){ + return [a[0] & b[0], a[1] & b[1]]; +}; + +exports.shl32 = function(a,b){ + // assume b is 16 or less + var w1 = a[1] << b, + w2 = (a[0] << b) | ((w1 & 0xFFFF0000) >> 16); + + return [w2 & 0xFFFF, w1 & 0xFFFF]; +}; + +exports.int31Write = function(buffer, number, offset) { + buffer[offset] = (number[0] >> 8) & 0x7F; + buffer[offset + 1] = (number[0]) & 0xFF; + buffer[offset + 2] = (number[1] >> 8) & 0xFF; + buffer[offset + 3] = (number[1]) & 0xFF; +}; + +exports.int32Read = function(buffer, offset){ + return (buffer[offset] << 24) + + (buffer[offset+1] << 16) + + (buffer[offset+2] << 8) + + (buffer[offset+3]); +}; diff --git a/node_modules/mysql/lib/client.js b/node_modules/mysql/lib/client.js new file mode 100644 index 0000000..4888bad --- /dev/null +++ b/node_modules/mysql/lib/client.js @@ -0,0 +1,454 @@ +var util = require('util'); +var Socket = require('net').Socket; +var auth = require('./auth'); +var constants = require('./constants'); +var Parser = require('./parser'); +var OutgoingPacket = require('./outgoing_packet'); +var Query = require('./query'); +var EventEmitter = require('events').EventEmitter; + +function Client() { + if (!(this instanceof Client) || arguments.length) { + throw new Error('deprecated: use mysql.createClient() instead'); + } + + EventEmitter.call(this); + + this.host = 'localhost'; + this.port = 3306; + this.user = 'root'; + this.password = null; + this.database = ''; + + this.typeCast = true; + this.flags = Client.defaultFlags; + this.maxPacketSize = 0x01000000; + this.charsetNumber = constants.UTF8_UNICODE_CI; + this.debug = false; + this.ending = false; + this.connected = false; + + this._greeting = null; + this._queue = []; + this._socket = null; + this._parser = null; +}; +util.inherits(Client, EventEmitter); +module.exports = Client; + +Client.prototype.connect = function() { + throw new Error('deprecated: connect() is now done automatically.'); +}; + +Client.prototype._connect = function() { + this.destroy(); + + var socket = this._socket = new Socket(); + var parser = this._parser = new Parser(); + var self = this; + + socket + .on('error', this._connectionErrorHandler()) + .on('data', parser.write.bind(parser)) + .on('end', function() { + if (self.ending) { + // @todo destroy()? + self.connected = false; + self.ending = false; + + if (self._queue.length) { + self._connect(); + } + + return; + } + + // @TODO WTF is this supposed to do? + if (!self.connected) { + return; + } + + self._connect(); + }) + .connect(this.port, this.host); + + parser.on('packet', this._handlePacket.bind(this)); +}; + +Client.prototype.query = function(sql, params, cb) { + if (Array.isArray(params)) { + sql = this.format(sql, params); + } else { + cb = arguments[1]; + } + + var query = new Query({ + typeCast: this.typeCast, + sql: sql + }); + + var self = this; + if (cb) { + var rows = [], fields = {}; + query + .on('error', function(err) { + cb(err); + self._dequeue(); + }) + .on('field', function(field) { + fields[field.name] = field; + }) + .on('row', function(row) { + rows.push(row); + }) + .on('end', function(result) { + if (result) { + cb(null, result); + } else { + cb(null, rows, fields); + } + + self._dequeue(); + }); + } else { + query + .on('error', function(err) { + if (query.listeners('error').length <= 1) { + self.emit('error', err); + } + self._dequeue(); + }) + .on('end', function(result) { + self._dequeue(); + }); + } + + this._enqueue(function query() { + var packet = new OutgoingPacket(1 + Buffer.byteLength(sql, 'utf-8')); + + packet.writeNumber(1, constants.COM_QUERY); + packet.write(sql, 'utf-8'); + self.write(packet); + }, query); + + return query; +}; + +Client.prototype.write = function(packet) { + if (this.debug) { + console.log('-> %s', packet.buffer.inspect()); + } + + this._socket.write(packet.buffer); +}; + +Client.prototype.format = function(sql, params) { + var escape = this.escape; + params = params.concat(); + + sql = sql.replace(/\?/g, function() { + if (params.length == 0) { + throw new Error('too few parameters given'); + } + + return escape(params.shift()); + }); + + if (params.length) { + throw new Error('too many parameters given'); + } + + return sql; +}; + +Client.prototype.escape = function(val) { + if (val === undefined || val === null) { + return 'NULL'; + } + + switch (typeof val) { + case 'boolean': return (val) ? 'true' : 'false'; + case 'number': return val+''; + } + + if (typeof val === 'object') { + val = (typeof val.toISOString === 'function') + ? val.toISOString() + : val.toString(); + } + + val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) { + switch(s) { + case "\0": return "\\0"; + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\b": return "\\b"; + case "\t": return "\\t"; + case "\x1a": return "\\Z"; + default: return "\\"+s; + } + }); + return "'"+val+"'"; +}; + +Client.prototype.ping = function(cb) { + var self = this; + this._enqueue(function ping() { + var packet = new OutgoingPacket(1); + packet.writeNumber(1, constants.COM_PING); + self.write(packet); + }, cb); +}; + +Client.prototype.statistics = function(cb) { + var self = this; + this._enqueue(function statistics() { + var packet = new OutgoingPacket(1); + packet.writeNumber(1, constants.COM_STATISTICS); + self.write(packet); + }, cb); +}; + +Client.prototype.useDatabase = function(database, cb) { + var self = this; + this._enqueue(function useDatabase() { + var packet = new OutgoingPacket(1 + Buffer.byteLength(database, 'utf-8')); + packet.writeNumber(1, constants.COM_INIT_DB); + packet.write(database, 'utf-8'); + self.write(packet); + }, cb); +}; + +Client.prototype.destroy = function() { + if (this._socket) { + this._socket.destroy(); + } + + this._socket = null; + this._parser = null; + this.connected = false; +} + +Client.prototype.end = function(cb) { + var self = this; + + this.ending = true; + + this._enqueue(function end() { + var packet = new OutgoingPacket(1); + packet.writeNumber(1, constants.COM_QUIT); + self.write(packet); + + // @todo handle clean shut down properly + if (cb) { + self._socket.on('end', cb); + } + + self._dequeue(); + }, cb); +}; + +Client.prototype._enqueue = function(fn, delegate) { + if (!this._socket) { + this._connect(); + } + + this._queue.push({fn: fn, delegate: delegate}); + if (this._queue.length === 1 && this.connected) { + fn(); + } +}; + +Client.prototype._dequeue = function() { + this._queue.shift(); + + if (!this._queue.length) { + return; + } + + if (!this.connected) { + this._connect(); + return; + } + + this._queue[0].fn(); +}; + +Client.prototype._handlePacket = function(packet) { + if (this.debug) { + this._debugPacket(packet); + } + + if (packet.type == Parser.GREETING_PACKET) { + this._sendAuth(packet); + return; + } + + if (packet.type == Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET) { + this._sendOldAuth(this._greeting); + return; + } + + if (!this.connected) { + if (packet.type != Parser.ERROR_PACKET) { + this.connected = true; + + if (this._queue.length) this._queue[0].fn(); + return; + } + + this._connectionErrorHandler()(Client._packetToUserObject(packet)); + return; + } + + // @TODO Simplify the code below and above as well + var type = packet.type; + var task = this._queue[0]; + var delegate = (task) + ? task.delegate + : null; + + if (delegate instanceof Query) { + delegate._handlePacket(packet); + return; + } + + if (type != Parser.ERROR_PACKET) { + this.connected = true; + if (delegate) { + delegate(null, Client._packetToUserObject(packet)); + } + } else { + packet = Client._packetToUserObject(packet); + if (delegate) { + delegate(packet); + } else { + this.emit('error', packet); + } + } + this._dequeue(); +}; + +Client.prototype._connectionErrorHandler = function() { + return function(err) { + this.destroy(); + + var task = this._queue[0]; + var delegate = (task) + ? task.delegate + : null; + + if (delegate instanceof Query) { + delegate.emit('error', err); + return; + } + + if (!delegate) { + this.emit('error', err); + } else { + delegate(err); + this._queue.shift(); + } + + if (this._queue.length) { + this._connect(); + } + }.bind(this); +}; + +Client.prototype._sendAuth = function(greeting) { + var token = auth.token(this.password, greeting.scrambleBuffer); + var packetSize = ( + 4 + 4 + 1 + 23 + + this.user.length + 1 + + token.length + 1 + + this.database.length + 1 + ); + var packet = new OutgoingPacket(packetSize, greeting.number+1); + + packet.writeNumber(4, this.flags); + packet.writeNumber(4, this.maxPacketSize); + packet.writeNumber(1, this.charsetNumber); + packet.writeFiller(23); + packet.writeNullTerminated(this.user); + packet.writeLengthCoded(token); + packet.writeNullTerminated(this.database); + + this.write(packet); + + // Keep a reference to the greeting packet. We might receive a + // USE_OLD_PASSWORD_PROTOCOL_PACKET as a response, in which case we will need + // the greeting packet again. See _sendOldAuth() + this._greeting = greeting; +}; + +Client._packetToUserObject = function(packet) { + var userObject = (packet.type == Parser.ERROR_PACKET) + ? new Error() + : {}; + + for (var key in packet) { + var newKey = key; + if (key == 'type' || key == 'number' || key == 'length' || key == 'received') { + continue; + } + + if (key == 'errorMessage') { + newKey = 'message'; + } else if (key == 'errorNumber') { + newKey = 'number'; + } + + userObject[newKey] = packet[key]; + } + + return userObject; +}; + +Client.prototype._debugPacket = function(packet) { + var packetName = null; + for (var key in Parser) { + if (!key.match(/_PACKET$/)) { + continue; + } + + if (Parser[key] == packet.type) { + packetName = key; + break; + } + } + console.log('<- %s: %j', packetName, packet); +}; + +Client.prototype._sendOldAuth = function(greeting) { + var token = auth.scramble323(greeting.scrambleBuffer, this.password); + var packetSize = ( + token.length + 1 + ); + var packet = new OutgoingPacket(packetSize, greeting.number+3); + + // I could not find any official documentation for this, but from sniffing + // the mysql command line client, I think this is the right way to send the + // scrambled token after receiving the USE_OLD_PASSWORD_PROTOCOL_PACKET. + packet.write(token); + packet.writeFiller(1); + + this.write(packet); +}; + +Client.defaultFlags = + constants.CLIENT_LONG_PASSWORD + | constants.CLIENT_FOUND_ROWS + | constants.CLIENT_LONG_FLAG + | constants.CLIENT_CONNECT_WITH_DB + | constants.CLIENT_ODBC + | constants.CLIENT_LOCAL_FILES + | constants.CLIENT_IGNORE_SPACE + | constants.CLIENT_PROTOCOL_41 + | constants.CLIENT_INTERACTIVE + | constants.CLIENT_IGNORE_SIGPIPE + | constants.CLIENT_TRANSACTIONS + | constants.CLIENT_RESERVED + | constants.CLIENT_SECURE_CONNECTION + | constants.CLIENT_MULTI_STATEMENTS + | constants.CLIENT_MULTI_RESULTS; diff --git a/node_modules/mysql/lib/constants.js b/node_modules/mysql/lib/constants.js new file mode 100644 index 0000000..b5bdfc0 --- /dev/null +++ b/node_modules/mysql/lib/constants.js @@ -0,0 +1,673 @@ +var hashish = require('hashish'); + +// Connections Flags +hashish.update(exports, { + CLIENT_LONG_PASSWORD : 1, + CLIENT_FOUND_ROWS : 2, + CLIENT_LONG_FLAG : 4, + CLIENT_CONNECT_WITH_DB : 8, + CLIENT_NO_SCHEMA : 16, + CLIENT_COMPRESS : 32, + CLIENT_ODBC : 64, + CLIENT_LOCAL_FILES : 128, + CLIENT_IGNORE_SPACE : 256, + CLIENT_PROTOCOL_41 : 512, + CLIENT_INTERACTIVE : 1024, + CLIENT_SSL : 2048, + CLIENT_IGNORE_SIGPIPE : 4096, + CLIENT_TRANSACTIONS : 8192, + CLIENT_RESERVED : 16384, + CLIENT_SECURE_CONNECTION : 32768, + CLIENT_MULTI_STATEMENTS : 65536, + CLIENT_MULTI_RESULTS : 131072, +}); + +// Commands +hashish.update(exports, { + COM_SLEEP : 0x00, + COM_QUIT : 0x01, + COM_INIT_DB : 0x02, + COM_QUERY : 0x03, + COM_FIELD_LIST : 0x04, + COM_CREATE_DB : 0x05, + COM_DROP_DB : 0x06, + COM_REFRESH : 0x07, + COM_SHUTDOWN : 0x08, + COM_STATISTICS : 0x09, + COM_PROCESS_INFO : 0x0a, + COM_CONNECT : 0x0b, + COM_PROCESS_KILL : 0x0c, + COM_DEBUG : 0x0d, + COM_PING : 0x0e, + COM_TIME : 0x0f, + COM_DELAYED_INSERT : 0x10, + COM_CHANGE_USER : 0x11, + COM_BINLOG_DUMP : 0x12, + COM_TABLE_DUMP : 0x13, + COM_CONNECT_OUT : 0x14, + COM_REGISTER_SLAVE : 0x15, + COM_STMT_PREPARE : 0x16, + COM_STMT_EXECUTE : 0x17, + COM_STMT_SEND_LONG_DATA : 0x18, + COM_STMT_CLOSE : 0x19, + COM_STMT_RESET : 0x1a, + COM_SET_OPTION : 0x1b, + COM_STMT_FETCH : 0x1c, +}); + +// Collations / Charsets +hashish.update(exports, { + BIG5_CHINESE_CI : 1, + LATIN2_CZECH_CS : 2, + DEC8_SWEDISH_CI : 3, + CP850_GENERAL_CI : 4, + LATIN1_GERMAN1_CI : 5, + HP8_ENGLISH_CI : 6, + KOI8R_GENERAL_CI : 7, + LATIN1_SWEDISH_CI : 8, + LATIN2_GENERAL_CI : 9, + SWE7_SWEDISH_CI : 10, + ASCII_GENERAL_CI : 11, + UJIS_JAPANESE_CI : 12, + SJIS_JAPANESE_CI : 13, + CP1251_BULGARIAN_CI : 14, + LATIN1_DANISH_CI : 15, + HEBREW_GENERAL_CI : 16, + TIS620_THAI_CI : 18, + EUCKR_KOREAN_CI : 19, + LATIN7_ESTONIAN_CS : 20, + LATIN2_HUNGARIAN_CI : 21, + KOI8U_GENERAL_CI : 22, + CP1251_UKRAINIAN_CI : 23, + GB2312_CHINESE_CI : 24, + GREEK_GENERAL_CI : 25, + CP1250_GENERAL_CI : 26, + LATIN2_CROATIAN_CI : 27, + GBK_CHINESE_CI : 28, + CP1257_LITHUANIAN_CI : 29, + LATIN5_TURKISH_CI : 30, + LATIN1_GERMAN2_CI : 31, + ARMSCII8_GENERAL_CI : 32, + UTF8_GENERAL_CI : 33, + CP1250_CZECH_CS : 34, + UCS2_GENERAL_CI : 35, + CP866_GENERAL_CI : 36, + KEYBCS2_GENERAL_CI : 37, + MACCE_GENERAL_CI : 38, + MACROMAN_GENERAL_CI : 39, + CP852_GENERAL_CI : 40, + LATIN7_GENERAL_CI : 41, + LATIN7_GENERAL_CS : 42, + MACCE_BIN : 43, + CP1250_CROATIAN_CI : 44, + LATIN1_BIN : 47, + LATIN1_GENERAL_CI : 48, + LATIN1_GENERAL_CS : 49, + CP1251_BIN : 50, + CP1251_GENERAL_CI : 51, + CP1251_GENERAL_CS : 52, + MACROMAN_BIN : 53, + CP1256_GENERAL_CI : 57, + CP1257_BIN : 58, + CP1257_GENERAL_CI : 59, + BINARY : 63, + ARMSCII8_BIN : 64, + ASCII_BIN : 65, + CP1250_BIN : 66, + CP1256_BIN : 67, + CP866_BIN : 68, + DEC8_BIN : 69, + GREEK_BIN : 70, + HEBREW_BIN : 71, + HP8_BIN : 72, + KEYBCS2_BIN : 73, + KOI8R_BIN : 74, + KOI8U_BIN : 75, + LATIN2_BIN : 77, + LATIN5_BIN : 78, + LATIN7_BIN : 79, + CP850_BIN : 80, + CP852_BIN : 81, + SWE7_BIN : 82, + UTF8_BIN : 83, + BIG5_BIN : 84, + EUCKR_BIN : 85, + GB2312_BIN : 86, + GBK_BIN : 87, + SJIS_BIN : 88, + TIS620_BIN : 89, + UCS2_BIN : 90, + UJIS_BIN : 91, + GEOSTD8_GENERAL_CI : 92, + GEOSTD8_BIN : 93, + LATIN1_SPANISH_CI : 94, + CP932_JAPANESE_CI : 95, + CP932_BIN : 96, + EUCJPMS_JAPANESE_CI : 97, + EUCJPMS_BIN : 98, + CP1250_POLISH_CI : 99, + UCS2_UNICODE_CI : 128, + UCS2_ICELANDIC_CI : 129, + UCS2_LATVIAN_CI : 130, + UCS2_ROMANIAN_CI : 131, + UCS2_SLOVENIAN_CI : 132, + UCS2_POLISH_CI : 133, + UCS2_ESTONIAN_CI : 134, + UCS2_SPANISH_CI : 135, + UCS2_SWEDISH_CI : 136, + UCS2_TURKISH_CI : 137, + UCS2_CZECH_CI : 138, + UCS2_DANISH_CI : 139, + UCS2_LITHUANIAN_CI : 140, + UCS2_SLOVAK_CI : 141, + UCS2_SPANISH2_CI : 142, + UCS2_ROMAN_CI : 143, + UCS2_PERSIAN_CI : 144, + UCS2_ESPERANTO_CI : 145, + UCS2_HUNGARIAN_CI : 146, + UTF8_UNICODE_CI : 192, + UTF8_ICELANDIC_CI : 193, + UTF8_LATVIAN_CI : 194, + UTF8_ROMANIAN_CI : 195, + UTF8_SLOVENIAN_CI : 196, + UTF8_POLISH_CI : 197, + UTF8_ESTONIAN_CI : 198, + UTF8_SPANISH_CI : 199, + UTF8_SWEDISH_CI : 200, + UTF8_TURKISH_CI : 201, + UTF8_CZECH_CI : 202, + UTF8_DANISH_CI : 203, + UTF8_LITHUANIAN_CI : 204, + UTF8_SLOVAK_CI : 205, + UTF8_SPANISH2_CI : 206, + UTF8_ROMAN_CI : 207, + UTF8_PERSIAN_CI : 208, + UTF8_ESPERANTO_CI : 209, + UTF8_HUNGARIAN_CI : 210, +}); + +// Error numbers +// from: http://dev.mysql.com/doc/refman/5.0/en/error-messages-server.html +hashish.update(exports, { + ERROR_HASHCHK : 1000, + ERROR_NISAMCHK : 1001, + ERROR_NO : 1002, + ERROR_YES : 1003, + ERROR_CANT_CREATE_FILE : 1004, + ERROR_CANT_CREATE_TABLE : 1005, + ERROR_CANT_CREATE_DB : 1006, + ERROR_DB_CREATE_EXISTS : 1007, + ERROR_DB_DROP_EXISTS : 1008, + ERROR_DB_DROP_DELETE : 1009, + ERROR_DB_DROP_RMDIR : 1010, + ERROR_CANT_DELETE_FILE : 1011, + ERROR_CANT_FIND_SYSTEM_REC : 1012, + ERROR_CANT_GET_STAT : 1013, + ERROR_CANT_GET_WD : 1014, + ERROR_CANT_LOCK : 1015, + ERROR_CANT_OPEN_FILE : 1016, + ERROR_FILE_NOT_FOUND : 1017, + ERROR_CANT_READ_DIR : 1018, + ERROR_CANT_SET_WD : 1019, + ERROR_CHECKREAD : 1020, + ERROR_DISK_FULL : 1021, + ERROR_DUP_KEY : 1022, + ERROR_ERROR_ON_CLOSE : 1023, + ERROR_ERROR_ON_READ : 1024, + ERROR_ERROR_ON_RENAME : 1025, + ERROR_ERROR_ON_WRITE : 1026, + ERROR_FILE_USED : 1027, + ERROR_FILSORT_ABORT : 1028, + ERROR_FORM_NOT_FOUND : 1029, + ERROR_GET_ERRNO : 1030, + ERROR_ILLEGAL_HA : 1031, + ERROR_KEY_NOT_FOUND : 1032, + ERROR_NOT_FORM_FILE : 1033, + ERROR_NOT_KEYFILE : 1034, + ERROR_OLD_KEYFILE : 1035, + ERROR_OPEN_AS_READONLY : 1036, + ERROR_OUTOFMEMORY : 1037, + ERROR_OUT_OF_SORTMEMORY : 1038, + ERROR_UNEXPECTED_EOF : 1039, + ERROR_CON_COUNT_ERROR : 1040, + ERROR_OUT_OF_RESOURCES : 1041, + ERROR_BAD_HOST_ERROR : 1042, + ERROR_HANDSHAKE_ERROR : 1043, + ERROR_DBACCESS_DENIED_ERROR : 1044, + ERROR_ACCESS_DENIED_ERROR : 1045, + ERROR_NO_DB_ERROR : 1046, + ERROR_UNKNOWN_COM_ERROR : 1047, + ERROR_BAD_NULL_ERROR : 1048, + ERROR_BAD_DB_ERROR : 1049, + ERROR_TABLE_EXISTS_ERROR : 1050, + ERROR_BAD_TABLE_ERROR : 1051, + ERROR_NON_UNIQ_ERROR : 1052, + ERROR_SERVERROR_SHUTDOWN : 1053, + ERROR_BAD_FIELD_ERROR : 1054, + ERROR_WRONG_FIELD_WITH_GROUP : 1055, + ERROR_WRONG_GROUP_FIELD : 1056, + ERROR_WRONG_SUM_SELECT : 1057, + ERROR_WRONG_VALUE_COUNT : 1058, + ERROR_TOO_LONG_IDENT : 1059, + ERROR_DUP_FIELDNAME : 1060, + ERROR_DUP_KEYNAME : 1061, + ERROR_DUP_ENTRY : 1062, + ERROR_WRONG_FIELD_SPEC : 1063, + ERROR_PARSE_ERROR : 1064, + ERROR_EMPTY_QUERY : 1065, + ERROR_NONUNIQ_TABLE : 1066, + ERROR_INVALID_DEFAULT : 1067, + ERROR_MULTIPLE_PRI_KEY : 1068, + ERROR_TOO_MANY_KEYS : 1069, + ERROR_TOO_MANY_KEY_PARTS : 1070, + ERROR_TOO_LONG_KEY : 1071, + ERROR_KEY_COLUMN_DOES_NOT_EXITS : 1072, + ERROR_BLOB_USED_AS_KEY : 1073, + ERROR_TOO_BIG_FIELDLENGTH : 1074, + ERROR_WRONG_AUTO_KEY : 1075, + ERROR_READY : 1076, + ERROR_NORMAL_SHUTDOWN : 1077, + ERROR_GOT_SIGNAL : 1078, + ERROR_SHUTDOWN_COMPLETE : 1079, + ERROR_FORCING_CLOSE : 1080, + ERROR_IPSOCK_ERROR : 1081, + ERROR_NO_SUCH_INDEX : 1082, + ERROR_WRONG_FIELD_TERMINATORS : 1083, + ERROR_BLOBS_AND_NO_TERMINATED : 1084, + ERROR_TEXTFILE_NOT_READABLE : 1085, + ERROR_FILE_EXISTS_ERROR : 1086, + ERROR_LOAD_INFO : 1087, + ERROR_ALTERROR_INFO : 1088, + ERROR_WRONG_SUB_KEY : 1089, + ERROR_CANT_REMOVE_ALL_FIELDS : 1090, + ERROR_CANT_DROP_FIELD_OR_KEY : 1091, + ERROR_INSERT_INFO : 1092, + ERROR_UPDATE_TABLE_USED : 1093, + ERROR_NO_SUCH_THREAD : 1094, + ERROR_KILL_DENIED_ERROR : 1095, + ERROR_NO_TABLES_USED : 1096, + ERROR_TOO_BIG_SET : 1097, + ERROR_NO_UNIQUE_LOGFILE : 1098, + ERROR_TABLE_NOT_LOCKED_FOR_WRITE : 1099, + ERROR_TABLE_NOT_LOCKED : 1100, + ERROR_BLOB_CANT_HAVE_DEFAULT : 1101, + ERROR_WRONG_DB_NAME : 1102, + ERROR_WRONG_TABLE_NAME : 1103, + ERROR_TOO_BIG_SELECT : 1104, + ERROR_UNKNOWN_ERROR : 1105, + ERROR_UNKNOWN_PROCEDURE : 1106, + ERROR_WRONG_PARAMCOUNT_TO_PROCEDURE : 1107, + ERROR_WRONG_PARAMETERS_TO_PROCEDURE : 1108, + ERROR_UNKNOWN_TABLE : 1109, + ERROR_FIELD_SPECIFIED_TWICE : 1110, + ERROR_INVALID_GROUP_FUNC_USE : 1111, + ERROR_UNSUPPORTED_EXTENSION : 1112, + ERROR_TABLE_MUST_HAVE_COLUMNS : 1113, + ERROR_RECORD_FILE_FULL : 1114, + ERROR_UNKNOWN_CHARACTERROR_SET : 1115, + ERROR_TOO_MANY_TABLES : 1116, + ERROR_TOO_MANY_FIELDS : 1117, + ERROR_TOO_BIG_ROWSIZE : 1118, + ERROR_STACK_OVERRUN : 1119, + ERROR_WRONG_OUTERROR_JOIN : 1120, + ERROR_NULL_COLUMN_IN_INDEX : 1121, + ERROR_CANT_FIND_UDF : 1122, + ERROR_CANT_INITIALIZE_UDF : 1123, + ERROR_UDF_NO_PATHS : 1124, + ERROR_UDF_EXISTS : 1125, + ERROR_CANT_OPEN_LIBRARY : 1126, + ERROR_CANT_FIND_DL_ENTRY : 1127, + ERROR_FUNCTION_NOT_DEFINED : 1128, + ERROR_HOST_IS_BLOCKED : 1129, + ERROR_HOST_NOT_PRIVILEGED : 1130, + ERROR_PASSWORD_ANONYMOUS_USER : 1131, + ERROR_PASSWORD_NOT_ALLOWED : 1132, + ERROR_PASSWORD_NO_MATCH : 1133, + ERROR_UPDATE_INFO : 1134, + ERROR_CANT_CREATE_THREAD : 1135, + ERROR_WRONG_VALUE_COUNT_ON_ROW : 1136, + ERROR_CANT_REOPEN_TABLE : 1137, + ERROR_INVALID_USE_OF_NULL : 1138, + ERROR_REGEXP_ERROR : 1139, + ERROR_MIX_OF_GROUP_FUNC_AND_FIELDS : 1140, + ERROR_NONEXISTING_GRANT : 1141, + ERROR_TABLEACCESS_DENIED_ERROR : 1142, + ERROR_COLUMNACCESS_DENIED_ERROR : 1143, + ERROR_ILLEGAL_GRANT_FOR_TABLE : 1144, + ERROR_GRANT_WRONG_HOST_OR_USER : 1145, + ERROR_NO_SUCH_TABLE : 1146, + ERROR_NONEXISTING_TABLE_GRANT : 1147, + ERROR_NOT_ALLOWED_COMMAND : 1148, + ERROR_SYNTAX_ERROR : 1149, + ERROR_DELAYED_CANT_CHANGE_LOCK : 1150, + ERROR_TOO_MANY_DELAYED_THREADS : 1151, + ERROR_ABORTING_CONNECTION : 1152, + ERROR_NET_PACKET_TOO_LARGE : 1153, + ERROR_NET_READ_ERROR_FROM_PIPE : 1154, + ERROR_NET_FCNTL_ERROR : 1155, + ERROR_NET_PACKETS_OUT_OF_ORDER : 1156, + ERROR_NET_UNCOMPRESS_ERROR : 1157, + ERROR_NET_READ_ERROR : 1158, + ERROR_NET_READ_INTERRUPTED : 1159, + ERROR_NET_ERROR_ON_WRITE : 1160, + ERROR_NET_WRITE_INTERRUPTED : 1161, + ERROR_TOO_LONG_STRING : 1162, + ERROR_TABLE_CANT_HANDLE_BLOB : 1163, + ERROR_TABLE_CANT_HANDLE_AUTO_INCREMENT : 1164, + ERROR_DELAYED_INSERT_TABLE_LOCKED : 1165, + ERROR_WRONG_COLUMN_NAME : 1166, + ERROR_WRONG_KEY_COLUMN : 1167, + ERROR_WRONG_MRG_TABLE : 1168, + ERROR_DUP_UNIQUE : 1169, + ERROR_BLOB_KEY_WITHOUT_LENGTH : 1170, + ERROR_PRIMARY_CANT_HAVE_NULL : 1171, + ERROR_TOO_MANY_ROWS : 1172, + ERROR_REQUIRES_PRIMARY_KEY : 1173, + ERROR_NO_RAID_COMPILED : 1174, + ERROR_UPDATE_WITHOUT_KEY_IN_SAFE_MODE : 1175, + ERROR_KEY_DOES_NOT_EXITS : 1176, + ERROR_CHECK_NO_SUCH_TABLE : 1177, + ERROR_CHECK_NOT_IMPLEMENTED : 1178, + ERROR_CANT_DO_THIS_DURING_AN_TRANSACTION : 1179, + ERROR_ERROR_DURING_COMMIT : 1180, + ERROR_ERROR_DURING_ROLLBACK : 1181, + ERROR_ERROR_DURING_FLUSH_LOGS : 1182, + ERROR_ERROR_DURING_CHECKPOINT : 1183, + ERROR_NEW_ABORTING_CONNECTION : 1184, + ERROR_DUMP_NOT_IMPLEMENTED : 1185, + ERROR_FLUSH_MASTERROR_BINLOG_CLOSED : 1186, + ERROR_INDEX_REBUILD : 1187, + ERROR_MASTER : 1188, + ERROR_MASTERROR_NET_READ : 1189, + ERROR_MASTERROR_NET_WRITE : 1190, + ERROR_FT_MATCHING_KEY_NOT_FOUND : 1191, + ERROR_LOCK_OR_ACTIVE_TRANSACTION : 1192, + ERROR_UNKNOWN_SYSTEM_VARIABLE : 1193, + ERROR_CRASHED_ON_USAGE : 1194, + ERROR_CRASHED_ON_REPAIR : 1195, + ERROR_WARNING_NOT_COMPLETE_ROLLBACK : 1196, + ERROR_TRANS_CACHE_FULL : 1197, + ERROR_SLAVE_MUST_STOP : 1198, + ERROR_SLAVE_NOT_RUNNING : 1199, + ERROR_BAD_SLAVE : 1200, + ERROR_MASTERROR_INFO : 1201, + ERROR_SLAVE_THREAD : 1202, + ERROR_TOO_MANY_USERROR_CONNECTIONS : 1203, + ERROR_SET_CONSTANTS_ONLY : 1204, + ERROR_LOCK_WAIT_TIMEOUT : 1205, + ERROR_LOCK_TABLE_FULL : 1206, + ERROR_READ_ONLY_TRANSACTION : 1207, + ERROR_DROP_DB_WITH_READ_LOCK : 1208, + ERROR_CREATE_DB_WITH_READ_LOCK : 1209, + ERROR_WRONG_ARGUMENTS : 1210, + ERROR_NO_PERMISSION_TO_CREATE_USER : 1211, + ERROR_UNION_TABLES_IN_DIFFERENT_DIR : 1212, + ERROR_LOCK_DEADLOCK : 1213, + ERROR_TABLE_CANT_HANDLE_FT : 1214, + ERROR_CANNOT_ADD_FOREIGN : 1215, + ERROR_NO_REFERENCED_ROW : 1216, + ERROR_ROW_IS_REFERENCED : 1217, + ERROR_CONNECT_TO_MASTER : 1218, + ERROR_QUERY_ON_MASTER : 1219, + ERROR_ERROR_WHEN_EXECUTING_COMMAND : 1220, + ERROR_WRONG_USAGE : 1221, + ERROR_WRONG_NUMBERROR_OF_COLUMNS_IN_SELECT : 1222, + ERROR_CANT_UPDATE_WITH_READLOCK : 1223, + ERROR_MIXING_NOT_ALLOWED : 1224, + ERROR_DUP_ARGUMENT : 1225, + ERROR_USERROR_LIMIT_REACHED : 1226, + ERROR_SPECIFIC_ACCESS_DENIED_ERROR : 1227, + ERROR_LOCAL_VARIABLE : 1228, + ERROR_GLOBAL_VARIABLE : 1229, + ERROR_NO_DEFAULT : 1230, + ERROR_WRONG_VALUE_FOR_VAR : 1231, + ERROR_WRONG_TYPE_FOR_VAR : 1232, + ERROR_VAR_CANT_BE_READ : 1233, + ERROR_CANT_USE_OPTION_HERE : 1234, + ERROR_NOT_SUPPORTED_YET : 1235, + ERROR_MASTERROR_FATAL_ERROR_READING_BINLOG : 1236, + ERROR_SLAVE_IGNORED_TABLE : 1237, + ERROR_INCORRECT_GLOBAL_LOCAL_VAR : 1238, + ERROR_WRONG_FK_DEF : 1239, + ERROR_KEY_REF_DO_NOT_MATCH_TABLE_REF : 1240, + ERROR_OPERAND_COLUMNS : 1241, + ERROR_SUBQUERY_NO_1_ROW : 1242, + ERROR_UNKNOWN_STMT_HANDLER : 1243, + ERROR_CORRUPT_HELP_DB : 1244, + ERROR_CYCLIC_REFERENCE : 1245, + ERROR_AUTO_CONVERT : 1246, + ERROR_ILLEGAL_REFERENCE : 1247, + ERROR_DERIVED_MUST_HAVE_ALIAS : 1248, + ERROR_SELECT_REDUCED : 1249, + ERROR_TABLENAME_NOT_ALLOWED_HERE : 1250, + ERROR_NOT_SUPPORTED_AUTH_MODE : 1251, + ERROR_SPATIAL_CANT_HAVE_NULL : 1252, + ERROR_COLLATION_CHARSET_MISMATCH : 1253, + ERROR_SLAVE_WAS_RUNNING : 1254, + ERROR_SLAVE_WAS_NOT_RUNNING : 1255, + ERROR_TOO_BIG_FOR_UNCOMPRESS : 1256, + ERROR_ZLIB_Z_MEM_ERROR : 1257, + ERROR_ZLIB_Z_BUF_ERROR : 1258, + ERROR_ZLIB_Z_DATA_ERROR : 1259, + ERROR_CUT_VALUE_GROUP_CONCAT : 1260, + ERROR_WARN_TOO_FEW_RECORDS : 1261, + ERROR_WARN_TOO_MANY_RECORDS : 1262, + ERROR_WARN_NULL_TO_NOTNULL : 1263, + ERROR_WARN_DATA_OUT_OF_RANGE : 1264, + WARN_DATA_TRUNCATED : 1265, + ERROR_WARN_USING_OTHERROR_HANDLER : 1266, + ERROR_CANT_AGGREGATE_2COLLATIONS : 1267, + ERROR_DROP_USER : 1268, + ERROR_REVOKE_GRANTS : 1269, + ERROR_CANT_AGGREGATE_3COLLATIONS : 1270, + ERROR_CANT_AGGREGATE_NCOLLATIONS : 1271, + ERROR_VARIABLE_IS_NOT_STRUCT : 1272, + ERROR_UNKNOWN_COLLATION : 1273, + ERROR_SLAVE_IGNORED_SSL_PARAMS : 1274, + ERROR_SERVERROR_IS_IN_SECURE_AUTH_MODE : 1275, + ERROR_WARN_FIELD_RESOLVED : 1276, + ERROR_BAD_SLAVE_UNTIL_COND : 1277, + ERROR_MISSING_SKIP_SLAVE : 1278, + ERROR_UNTIL_COND_IGNORED : 1279, + ERROR_WRONG_NAME_FOR_INDEX : 1280, + ERROR_WRONG_NAME_FOR_CATALOG : 1281, + ERROR_WARN_QC_RESIZE : 1282, + ERROR_BAD_FT_COLUMN : 1283, + ERROR_UNKNOWN_KEY_CACHE : 1284, + ERROR_WARN_HOSTNAME_WONT_WORK : 1285, + ERROR_UNKNOWN_STORAGE_ENGINE : 1286, + ERROR_WARN_DEPRECATED_SYNTAX : 1287, + ERROR_NON_UPDATABLE_TABLE : 1288, + ERROR_FEATURE_DISABLED : 1289, + ERROR_OPTION_PREVENTS_STATEMENT : 1290, + ERROR_DUPLICATED_VALUE_IN_TYPE : 1291, + ERROR_TRUNCATED_WRONG_VALUE : 1292, + ERROR_TOO_MUCH_AUTO_TIMESTAMP_COLS : 1293, + ERROR_INVALID_ON_UPDATE : 1294, + ERROR_UNSUPPORTED_PS : 1295, + ERROR_GET_ERRMSG : 1296, + ERROR_GET_TEMPORARY_ERRMSG : 1297, + ERROR_UNKNOWN_TIME_ZONE : 1298, + ERROR_WARN_INVALID_TIMESTAMP : 1299, + ERROR_INVALID_CHARACTERROR_STRING : 1300, + ERROR_WARN_ALLOWED_PACKET_OVERFLOWED : 1301, + ERROR_CONFLICTING_DECLARATIONS : 1302, + ERROR_SP_NO_RECURSIVE_CREATE : 1303, + ERROR_SP_ALREADY_EXISTS : 1304, + ERROR_SP_DOES_NOT_EXIST : 1305, + ERROR_SP_DROP_FAILED : 1306, + ERROR_SP_STORE_FAILED : 1307, + ERROR_SP_LILABEL_MISMATCH : 1308, + ERROR_SP_LABEL_REDEFINE : 1309, + ERROR_SP_LABEL_MISMATCH : 1310, + ERROR_SP_UNINIT_VAR : 1311, + ERROR_SP_BADSELECT : 1312, + ERROR_SP_BADRETURN : 1313, + ERROR_SP_BADSTATEMENT : 1314, + ERROR_UPDATE_LOG_DEPRECATED_IGNORED : 1315, + ERROR_UPDATE_LOG_DEPRECATED_TRANSLATED : 1316, + ERROR_QUERY_INTERRUPTED : 1317, + ERROR_SP_WRONG_NO_OF_ARGS : 1318, + ERROR_SP_COND_MISMATCH : 1319, + ERROR_SP_NORETURN : 1320, + ERROR_SP_NORETURNEND : 1321, + ERROR_SP_BAD_CURSOR_QUERY : 1322, + ERROR_SP_BAD_CURSOR_SELECT : 1323, + ERROR_SP_CURSOR_MISMATCH : 1324, + ERROR_SP_CURSOR_ALREADY_OPEN : 1325, + ERROR_SP_CURSOR_NOT_OPEN : 1326, + ERROR_SP_UNDECLARED_VAR : 1327, + ERROR_SP_WRONG_NO_OF_FETCH_ARGS : 1328, + ERROR_SP_FETCH_NO_DATA : 1329, + ERROR_SP_DUP_PARAM : 1330, + ERROR_SP_DUP_VAR : 1331, + ERROR_SP_DUP_COND : 1332, + ERROR_SP_DUP_CURS : 1333, + ERROR_SP_CANT_ALTER : 1334, + ERROR_SP_SUBSELECT_NYI : 1335, + ERROR_STMT_NOT_ALLOWED_IN_SF_OR_TRG : 1336, + ERROR_SP_VARCOND_AFTERROR_CURSHNDLR : 1337, + ERROR_SP_CURSOR_AFTERROR_HANDLER : 1338, + ERROR_SP_CASE_NOT_FOUND : 1339, + ERROR_FPARSERROR_TOO_BIG_FILE : 1340, + ERROR_FPARSERROR_BAD_HEADER : 1341, + ERROR_FPARSERROR_EOF_IN_COMMENT : 1342, + ERROR_FPARSERROR_ERROR_IN_PARAMETER : 1343, + ERROR_FPARSERROR_EOF_IN_UNKNOWN_PARAMETER : 1344, + ERROR_VIEW_NO_EXPLAIN : 1345, + ERROR_FRM_UNKNOWN_TYPE : 1346, + ERROR_WRONG_OBJECT : 1347, + ERROR_NONUPDATEABLE_COLUMN : 1348, + ERROR_VIEW_SELECT_DERIVED : 1349, + ERROR_VIEW_SELECT_CLAUSE : 1350, + ERROR_VIEW_SELECT_VARIABLE : 1351, + ERROR_VIEW_SELECT_TMPTABLE : 1352, + ERROR_VIEW_WRONG_LIST : 1353, + ERROR_WARN_VIEW_MERGE : 1354, + ERROR_WARN_VIEW_WITHOUT_KEY : 1355, + ERROR_VIEW_INVALID : 1356, + ERROR_SP_NO_DROP_SP : 1357, + ERROR_SP_GOTO_IN_HNDLR : 1358, + ERROR_TRG_ALREADY_EXISTS : 1359, + ERROR_TRG_DOES_NOT_EXIST : 1360, + ERROR_TRG_ON_VIEW_OR_TEMP_TABLE : 1361, + ERROR_TRG_CANT_CHANGE_ROW : 1362, + ERROR_TRG_NO_SUCH_ROW_IN_TRG : 1363, + ERROR_NO_DEFAULT_FOR_FIELD : 1364, + ERROR_DIVISION_BY_ZERO : 1365, + ERROR_TRUNCATED_WRONG_VALUE_FOR_FIELD : 1366, + ERROR_ILLEGAL_VALUE_FOR_TYPE : 1367, + ERROR_VIEW_NONUPD_CHECK : 1368, + ERROR_VIEW_CHECK_FAILED : 1369, + ERROR_PROCACCESS_DENIED_ERROR : 1370, + ERROR_RELAY_LOG_FAIL : 1371, + ERROR_PASSWD_LENGTH : 1372, + ERROR_UNKNOWN_TARGET_BINLOG : 1373, + ERROR_IO_ERR_LOG_INDEX_READ : 1374, + ERROR_BINLOG_PURGE_PROHIBITED : 1375, + ERROR_FSEEK_FAIL : 1376, + ERROR_BINLOG_PURGE_FATAL_ERR : 1377, + ERROR_LOG_IN_USE : 1378, + ERROR_LOG_PURGE_UNKNOWN_ERR : 1379, + ERROR_RELAY_LOG_INIT : 1380, + ERROR_NO_BINARY_LOGGING : 1381, + ERROR_RESERVED_SYNTAX : 1382, + ERROR_WSAS_FAILED : 1383, + ERROR_DIFF_GROUPS_PROC : 1384, + ERROR_NO_GROUP_FOR_PROC : 1385, + ERROR_ORDERROR_WITH_PROC : 1386, + ERROR_LOGGING_PROHIBIT_CHANGING_OF : 1387, + ERROR_NO_FILE_MAPPING : 1388, + ERROR_WRONG_MAGIC : 1389, + ERROR_PS_MANY_PARAM : 1390, + ERROR_KEY_PART_0 : 1391, + ERROR_VIEW_CHECKSUM : 1392, + ERROR_VIEW_MULTIUPDATE : 1393, + ERROR_VIEW_NO_INSERT_FIELD_LIST : 1394, + ERROR_VIEW_DELETE_MERGE_VIEW : 1395, + ERROR_CANNOT_USER : 1396, + ERROR_XAERROR_NOTA : 1397, + ERROR_XAERROR_INVAL : 1398, + ERROR_XAERROR_RMFAIL : 1399, + ERROR_XAERROR_OUTSIDE : 1400, + ERROR_XAERROR_RMERR : 1401, + ERROR_XA_RBROLLBACK : 1402, + ERROR_NONEXISTING_PROC_GRANT : 1403, + ERROR_PROC_AUTO_GRANT_FAIL : 1404, + ERROR_PROC_AUTO_REVOKE_FAIL : 1405, + ERROR_DATA_TOO_LONG : 1406, + ERROR_SP_BAD_SQLSTATE : 1407, + ERROR_STARTUP : 1408, + ERROR_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR : 1409, + ERROR_CANT_CREATE_USERROR_WITH_GRANT : 1410, + ERROR_WRONG_VALUE_FOR_TYPE : 1411, + ERROR_TABLE_DEF_CHANGED : 1412, + ERROR_SP_DUP_HANDLER : 1413, + ERROR_SP_NOT_VAR_ARG : 1414, + ERROR_SP_NO_RETSET : 1415, + ERROR_CANT_CREATE_GEOMETRY_OBJECT : 1416, + ERROR_FAILED_ROUTINE_BREAK_BINLOG : 1417, + ERROR_BINLOG_UNSAFE_ROUTINE : 1418, + ERROR_BINLOG_CREATE_ROUTINE_NEED_SUPER : 1419, + ERROR_EXEC_STMT_WITH_OPEN_CURSOR : 1420, + ERROR_STMT_HAS_NO_OPEN_CURSOR : 1421, + ERROR_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG : 1422, + ERROR_NO_DEFAULT_FOR_VIEW_FIELD : 1423, + ERROR_SP_NO_RECURSION : 1424, + ERROR_TOO_BIG_SCALE : 1425, + ERROR_TOO_BIG_PRECISION : 1426, + ERROR_M_BIGGERROR_THAN_D : 1427, + ERROR_WRONG_LOCK_OF_SYSTEM_TABLE : 1428, + ERROR_CONNECT_TO_FOREIGN_DATA_SOURCE : 1429, + ERROR_QUERY_ON_FOREIGN_DATA_SOURCE : 1430, + ERROR_FOREIGN_DATA_SOURCE_DOESNT_EXIST : 1431, + ERROR_FOREIGN_DATA_STRING_INVALID_CANT_CREATE : 1432, + ERROR_FOREIGN_DATA_STRING_INVALID : 1433, + ERROR_CANT_CREATE_FEDERATED_TABLE : 1434, + ERROR_TRG_IN_WRONG_SCHEMA : 1435, + ERROR_STACK_OVERRUN_NEED_MORE : 1436, + ERROR_TOO_LONG_BODY : 1437, + ERROR_WARN_CANT_DROP_DEFAULT_KEYCACHE : 1438, + ERROR_TOO_BIG_DISPLAYWIDTH : 1439, + ERROR_XAERROR_DUPID : 1440, + ERROR_DATETIME_FUNCTION_OVERFLOW : 1441, + ERROR_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG : 1442, + ERROR_VIEW_PREVENT_UPDATE : 1443, + ERROR_PS_NO_RECURSION : 1444, + ERROR_SP_CANT_SET_AUTOCOMMIT : 1445, + ERROR_MALFORMED_DEFINER : 1446, + ERROR_VIEW_FRM_NO_USER : 1447, + ERROR_VIEW_OTHERROR_USER : 1448, + ERROR_NO_SUCH_USER : 1449, + ERROR_FORBID_SCHEMA_CHANGE : 1450, + ERROR_ROW_IS_REFERENCED_2 : 1451, + ERROR_NO_REFERENCED_ROW_2 : 1452, + ERROR_SP_BAD_VAR_SHADOW : 1453, + ERROR_TRG_NO_DEFINER : 1454, + ERROR_OLD_FILE_FORMAT : 1455, + ERROR_SP_RECURSION_LIMIT : 1456, + ERROR_SP_PROC_TABLE_CORRUPT : 1457, + ERROR_SP_WRONG_NAME : 1458, + ERROR_TABLE_NEEDS_UPGRADE : 1459, + ERROR_SP_NO_AGGREGATE : 1460, + ERROR_MAX_PREPARED_STMT_COUNT_REACHED : 1461, + ERROR_VIEW_RECURSIVE : 1462, + ERROR_NON_GROUPING_FIELD_USED : 1463, + ERROR_TABLE_CANT_HANDLE_SPKEYS : 1464, + ERROR_NO_TRIGGERS_ON_SYSTEM_SCHEMA : 1465, + ERROR_REMOVED_SPACES : 1466, + ERROR_AUTOINC_READ_FAILED : 1467, + ERROR_USERNAME : 1468, + ERROR_HOSTNAME : 1469, + ERROR_WRONG_STRING_LENGTH : 1470, + ERROR_NON_INSERTABLE_TABLE : 1471, + ERROR_ADMIN_WRONG_MRG_TABLE : 1472, + ERROR_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT : 1473, + ERROR_NAME_BECOMES_EMPTY : 1474, + ERROR_AMBIGUOUS_FIELD_TERM : 1475, + ERROR_LOAD_DATA_INVALID_COLUMN : 1476, + ERROR_LOG_PURGE_NO_FILE : 1477, + ERROR_XA_RBTIMEOUT : 1478, + ERROR_XA_RBDEADLOCK : 1479, + ERROR_TOO_MANY_CONCURRENT_TRXS : 1480, +}); diff --git a/node_modules/mysql/lib/mysql.js b/node_modules/mysql/lib/mysql.js new file mode 100644 index 0000000..9b25e13 --- /dev/null +++ b/node_modules/mysql/lib/mysql.js @@ -0,0 +1,11 @@ +var hashish = require('hashish'); +var Client = exports.Client = require('./client'); +var constants = require('./constants'); + +exports.createClient = function(config) { + var client = new Client(); + hashish.update(client, config || {}); + return client; +}; + +hashish.update(exports, constants); diff --git a/node_modules/mysql/lib/outgoing_packet.js b/node_modules/mysql/lib/outgoing_packet.js new file mode 100644 index 0000000..b46a7d4 --- /dev/null +++ b/node_modules/mysql/lib/outgoing_packet.js @@ -0,0 +1,79 @@ +var Buffer = require('buffer').Buffer; + +function OutgoingPacket(size, num) { + this.buffer = new Buffer(size + 3 + 1); + this.index = 0; + this.writeNumber(3, size); + this.writeNumber(1, num || 0); +}; +module.exports = OutgoingPacket; + +OutgoingPacket.prototype.writeNumber = function(bytes, number) { + for (var i = 0; i < bytes; i++) { + this.buffer[this.index++] = (number >> (i * 8)) & 0xff; + } +}; + +OutgoingPacket.prototype.writeFiller = function(bytes) { + for (var i = 0; i < bytes; i++) { + this.buffer[this.index++] = 0; + } +}; + +OutgoingPacket.prototype.write = function(bufferOrString, encoding) { + if (typeof bufferOrString == 'string') { + this.index += this.buffer.write(bufferOrString, this.index, encoding); + return; + } + + bufferOrString.copy(this.buffer, this.index, 0); + this.index += bufferOrString.length; +}; + +OutgoingPacket.prototype.writeNullTerminated = function(bufferOrString, encoding) { + this.write(bufferOrString, encoding); + this.buffer[this.index++] = 0; +}; + +OutgoingPacket.prototype.writeLengthCoded = function(bufferOrStringOrNumber, encoding) { + if (bufferOrStringOrNumber === null) { + this.buffer[this.index++] = 251; + return; + } + + if (typeof bufferOrStringOrNumber == 'number') { + if (bufferOrStringOrNumber <= 250) { + this.buffer[this.index++] = bufferOrStringOrNumber; + return; + } + + // @todo support 8-byte numbers and simplify this + if (bufferOrStringOrNumber < 0xffff) { + this.buffer[this.index++] = 252; + this.buffer[this.index++] = (bufferOrStringOrNumber >> 0) & 0xff; + this.buffer[this.index++] = (bufferOrStringOrNumber >> 8) & 0xff; + } else if (bufferOrStringOrNumber < 0xffffff) { + this.buffer[this.index++] = 253; + this.buffer[this.index++] = (bufferOrStringOrNumber >> 0) & 0xff; + this.buffer[this.index++] = (bufferOrStringOrNumber >> 8) & 0xff; + this.buffer[this.index++] = (bufferOrStringOrNumber >> 16) & 0xff; + } else { + throw new Error('8 byte length coded numbers not supported yet'); + } + return; + } + + if (bufferOrStringOrNumber instanceof Buffer) { + this.writeLengthCoded(bufferOrStringOrNumber.length); + this.write(bufferOrStringOrNumber); + return; + } + + if (typeof bufferOrStringOrNumber == 'string') { + this.writeLengthCoded(Buffer.byteLength(bufferOrStringOrNumber, encoding)); + this.write(bufferOrStringOrNumber, encoding); + return; + } + + throw new Error('passed argument not a buffer, string or number: '+bufferOrStringOrNumber); +}; diff --git a/node_modules/mysql/lib/parser.js b/node_modules/mysql/lib/parser.js new file mode 100644 index 0000000..c36d3ea --- /dev/null +++ b/node_modules/mysql/lib/parser.js @@ -0,0 +1,650 @@ +var util = require('util'); +var Buffer = require('buffer').Buffer; +var EventEmitter = require('events').EventEmitter; +var POWS = [1, 256, 65536, 16777216]; + +function Parser() { + EventEmitter.call(this); + + this.state = Parser.PACKET_LENGTH; + this.packet = null; + this.greeted = false; + this.authenticated = false; + this.receivingFieldPackets = false; + this.receivingRowPackets = false; + + this._lengthCodedLength = null; + this._lengthCodedStringLength = null; +}; +util.inherits(Parser, EventEmitter); +module.exports = Parser; + +Parser.prototype.write = function(buffer) { + var i = 0, + c = null, + self = this, + state = this.state, + length = buffer.length, + packet = this.packet, + advance = function(newState) { + self.state = state = (newState === undefined) + ? self.state + 1 + : newState; + + packet.index = -1; + }, + lengthCoded = function(val, nextState) { + if (self._lengthCodedLength === null) { + if (c === Parser.LENGTH_CODED_16BIT_WORD) { + self._lengthCodedLength = 2; + } else if (c === Parser.LENGTH_CODED_24BIT_WORD) { + self._lengthCodedLength = 3; + } else if (c === Parser.LENGTH_CODED_64BIT_WORD) { + self._lengthCodedLength = 8; + } else if (c === Parser.LENGTH_CODED_NULL) { + advance(nextState); + return null; + } else if (c < Parser.LENGTH_CODED_NULL) { + advance(nextState); + return c; + } + + return 0; + } + + if (c) { + val += POWS[packet.index - 1] * c; + } + + if (packet.index === self._lengthCodedLength) { + self._lengthCodedLength = null; + advance(nextState); + } + + return val; + }, + emitPacket = function() { + self.packet = null; + self.state = state = Parser.PACKET_LENGTH; + self.greeted = true; + delete packet.index; + self.emit('packet', packet); + packet = null; + }; + + for (; i < length; i++) { + c = buffer[i]; + + if (state > Parser.PACKET_NUMBER) { + packet.received++; + } + + switch (state) { + // PACKET HEADER + case 0: // PACKET_LENGTH: + if (!packet) { + packet = this.packet = new EventEmitter(); + packet.index = 0; + packet.length = 0; + packet.received = 0; + packet.number = 0; + } + + // 3 bytes - Little endian + packet.length += POWS[packet.index] * c; + + if (packet.index == 2) { + advance(); + } + break; + case 1: // PACKET_NUMBER: + // 1 byte + packet.number = c; + + if (!this.greeted) { + advance(Parser.GREETING_PROTOCOL_VERSION); + break; + } + + if (this.receivingFieldPackets) { + advance(Parser.FIELD_CATALOG_LENGTH); + } else if (this.receivingRowPackets) { + advance(Parser.COLUMN_VALUE_LENGTH); + } else { + advance(Parser.FIELD_COUNT); + } + break; + + // GREETING_PACKET + case 2: // GREETING_PROTOCOL_VERSION: + // Nice undocumented MySql gem, the initial greeting can be an error + // packet. Happens for too many connections errors. + if (c === 0xff) { + packet.type = Parser.ERROR_PACKET; + advance(Parser.ERROR_NUMBER); + break; + } + + // 1 byte + packet.type = Parser.GREETING_PACKET; + packet.protocolVersion = c; + advance(); + break; + case 3: // GREETING_SERVER_VERSION: + if (packet.index == 0) { + packet.serverVersion = ''; + } + + // Null-Terminated String + if (c != 0) { + packet.serverVersion += String.fromCharCode(c); + } else { + advance(); + } + break; + case 4: // GREETING_THREAD_ID: + if (packet.index == 0) { + packet.threadId = 0; + } + + // 4 bytes = probably Little endian, protocol docs are not clear + packet.threadId += POWS[packet.index] * c; + + if (packet.index == 3) { + advance(); + } + break; + case 5: // GREETING_SCRAMBLE_BUFF_1: + if (packet.index == 0) { + packet.scrambleBuffer = new Buffer(8 + 12); + } + + // 8 bytes + packet.scrambleBuffer[packet.index] = c; + + if (packet.index == 7) { + advance(); + } + break; + case 6: // GREETING_FILLER_1: + // 1 byte - 0x00 + advance(); + break; + case 7: // GREETING_SERVER_CAPABILITIES: + if (packet.index == 0) { + packet.serverCapabilities = 0; + } + // 2 bytes = probably Little endian, protocol docs are not clear + packet.serverCapabilities += POWS[packet.index] * c; + + if (packet.index == 1) { + advance(); + } + break; + case 8: // GREETING_SERVER_LANGUAGE: + packet.serverLanguage = c; + advance(); + break; + case 9: // GREETING_SERVER_STATUS: + if (packet.index == 0) { + packet.serverStatus = 0; + } + + // 2 bytes = probably Little endian, protocol docs are not clear + packet.serverStatus += POWS[packet.index] * c; + + if (packet.index == 1) { + advance(); + } + break; + case 10: // GREETING_FILLER_2: + // 13 bytes - 0x00 + if (packet.index == 12) { + advance(); + } + break; + case 11: // GREETING_SCRAMBLE_BUFF_2: + // 12 bytes - not 13 bytes like the protocol spec says ... + if (packet.index < 12) { + packet.scrambleBuffer[packet.index + 8] = c; + } + break; + + // OK_PACKET, ERROR_PACKET, or RESULT_SET_HEADER_PACKET + case 12: // FIELD_COUNT: + if (packet.index == 0) { + if (c === 0xff) { + packet.type = Parser.ERROR_PACKET; + advance(Parser.ERROR_NUMBER); + break; + } + + if (c == 0xfe && !this.authenticated) { + packet.type = Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET; + break; + } + + if (c === 0x00) { + // after the first OK PACKET, we are authenticated + this.authenticated = true; + packet.type = Parser.OK_PACKET; + advance(Parser.AFFECTED_ROWS); + break; + } + } + + this.receivingFieldPackets = true; + packet.type = Parser.RESULT_SET_HEADER_PACKET; + packet.fieldCount = lengthCoded(packet.fieldCount, Parser.EXTRA_LENGTH); + + break; + + // ERROR_PACKET + case 13: // ERROR_NUMBER: + if (packet.index == 0) { + packet.errorNumber = 0; + } + + // 2 bytes = Little endian + packet.errorNumber += POWS[packet.index] * c; + + if (packet.index == 1) { + if (!this.greeted) { + // Turns out error packets are confirming to the 4.0 protocol when + // not greeted yet. Oh MySql, you are such a thing of beauty ... + advance(Parser.ERROR_MESSAGE); + break; + } + + advance(); + } + break; + case 14: // ERROR_SQL_STATE_MARKER: + // 1 character - always # + packet.sqlStateMarker = String.fromCharCode(c); + packet.sqlState = ''; + advance(); + break; + case 15: // ERROR_SQL_STATE: + // 5 characters + if (packet.index < 5) { + packet.sqlState += String.fromCharCode(c); + } + + if (packet.index == 4) { + advance(Parser.ERROR_MESSAGE); + } + break; + case 16: // ERROR_MESSAGE: + if (packet.received <= packet.length) { + packet.errorMessage = (packet.errorMessage || '') + String.fromCharCode(c); + } + break; + + // OK_PACKET + case 17: // AFFECTED_ROWS: + packet.affectedRows = lengthCoded(packet.affectedRows); + break; + case 18: // INSERT_ID: + packet.insertId = lengthCoded(packet.insertId); + break; + case 19: // SERVER_STATUS: + if (packet.index == 0) { + packet.serverStatus = 0; + } + + // 2 bytes - Little endian + packet.serverStatus += POWS[packet.index] * c; + + if (packet.index == 1) { + advance(); + } + break; + case 20: // WARNING_COUNT: + if (packet.index == 0) { + packet.warningCount = 0; + } + + // 2 bytes - Little endian + packet.warningCount += POWS[packet.index] * c; + + if (packet.index == 1) { + packet.message = ''; + advance(); + } + break; + case 21: // MESSAGE: + if (packet.received <= packet.length) { + packet.message += String.fromCharCode(c); + } + break; + + // RESULT_SET_HEADER_PACKET + case 22: // EXTRA_LENGTH: + packet.extra = ''; + self._lengthCodedStringLength = lengthCoded(self._lengthCodedStringLength); + break; + case 23: // EXTRA_STRING: + packet.extra += String.fromCharCode(c); + break; + + // FIELD_PACKET or EOF_PACKET + case 24: // FIELD_CATALOG_LENGTH: + if (packet.index == 0) { + if (c === 0xfe) { + packet.type = Parser.EOF_PACKET; + advance(Parser.EOF_WARNING_COUNT); + break; + } + packet.type = Parser.FIELD_PACKET; + } + self._lengthCodedStringLength = lengthCoded(self._lengthCodedStringLength); + break; + case 25: // FIELD_CATALOG_STRING: + if (packet.index == 0) { + packet.catalog = ''; + } + packet.catalog += String.fromCharCode(c); + + if (packet.index + 1 === self._lengthCodedStringLength) { + advance(); + } + break; + case 26: // FIELD_DB_LENGTH: + self._lengthCodedStringLength = lengthCoded(self._lengthCodedStringLength); + if (self._lengthCodedStringLength == 0) { + advance(); + } + break; + case 27: // FIELD_DB_STRING: + if (packet.index == 0) { + packet.db = ''; + } + packet.db += String.fromCharCode(c); + + if (packet.index + 1 === self._lengthCodedStringLength) { + advance(); + } + break; + case 28: // FIELD_TABLE_LENGTH: + self._lengthCodedStringLength = lengthCoded(self._lengthCodedStringLength); + if (self._lengthCodedStringLength == 0) { + advance(); + } + break; + case 29: // FIELD_TABLE_STRING: + if (packet.index == 0) { + packet.table = ''; + } + packet.table += String.fromCharCode(c); + + if (packet.index + 1 === self._lengthCodedStringLength) { + advance(); + } + break; + case 30: // FIELD_ORIGINAL_TABLE_LENGTH: + self._lengthCodedStringLength = lengthCoded(self._lengthCodedStringLength); + if (self._lengthCodedStringLength == 0) { + advance(); + } + break; + case 31: // FIELD_ORIGINAL_TABLE_STRING: + if (packet.index == 0) { + packet.originalTable = ''; + } + packet.originalTable += String.fromCharCode(c); + + if (packet.index + 1 === self._lengthCodedStringLength) { + advance(); + } + break; + case 32: // FIELD_NAME_LENGTH: + self._lengthCodedStringLength = lengthCoded(self._lengthCodedStringLength); + break; + case 33: // FIELD_NAME_STRING: + if (packet.index == 0) { + packet.name = ''; + } + packet.name += String.fromCharCode(c); + + if (packet.index + 1 === self._lengthCodedStringLength) { + advance(); + } + break; + case 34: // FIELD_ORIGINAL_NAME_LENGTH: + self._lengthCodedStringLength = lengthCoded(self._lengthCodedStringLength); + if (self._lengthCodedStringLength == 0) { + advance(); + } + break; + case 35: // FIELD_ORIGINAL_NAME_STRING: + if (packet.index == 0) { + packet.originalName = ''; + } + packet.originalName += String.fromCharCode(c); + + if (packet.index + 1 === self._lengthCodedStringLength) { + advance(); + } + break; + case 36: // FIELD_FILLER_1: + // 1 bytes - 0x00 + advance(); + break; + case 37: // FIELD_CHARSET_NR: + if (packet.index == 0) { + packet.charsetNumber = 0; + } + + // 2 bytes - Little endian + packet.charsetNumber += Math.pow(256, packet.index) * c; + + if (packet.index == 1) { + advance(); + } + break; + case 38: // FIELD_LENGTH: + if (packet.index == 0) { + packet.fieldLength = 0; + } + + // 4 bytes - Little endian + packet.fieldLength += Math.pow(256, packet.index) * c; + + if (packet.index == 3) { + advance(); + } + break; + case 39: // FIELD_TYPE: + // 1 byte + packet.fieldType = c; + advance(); + case 40: // FIELD_FLAGS: + if (packet.index == 0) { + packet.flags = 0; + } + + // 2 bytes - Little endian + packet.flags += Math.pow(256, packet.index) * c; + + if (packet.index == 1) { + advance(); + } + break; + case 41: // FIELD_DECIMALS: + // 1 byte + packet.decimals = c; + advance(); + break; + case 42: // FIELD_FILLER_2: + // 2 bytes - 0x00 + if (packet.index == 1) { + advance(); + } + break; + case 43: // FIELD_DEFAULT: + // TODO: Only occurs for mysql_list_fields() + break; + + // EOF_PACKET + case 44: // EOF_WARNING_COUNT: + if (packet.index == 0) { + packet.warningCount = 0; + } + + // 2 bytes - Little endian + packet.warningCount += Math.pow(256, packet.index) * c; + + if (packet.index == 1) { + advance(); + } + break; + case 45: // EOF_SERVER_STATUS: + if (packet.index == 0) { + packet.serverStatus = 0; + } + + // 2 bytes - Little endian + packet.serverStatus += Math.pow(256, packet.index) * c; + + if (packet.index == 1) { + if (this.receivingFieldPackets) { + this.receivingFieldPackets = false; + this.receivingRowPackets = true; + } else { + } + } + break; + case 46: // COLUMN_VALUE_LENGTH: + if (packet.index == 0) { + packet.columnLength = 0; + packet.type = Parser.ROW_DATA_PACKET; + } + + if (packet.received == 1) { + if (c === 0xfe) { + packet.type = Parser.EOF_PACKET; + this.receivingRowPackets = false; + advance(Parser.EOF_WARNING_COUNT); + break; + } + this.emit('packet', packet); + } + + packet.columnLength = lengthCoded(packet.columnLength); + + if (!packet.columnLength && !this._lengthCodedLength) { + packet.emit('data', (packet.columnLength === null ? null : new Buffer(0)), 0); + if (packet.received < packet.length) { + advance(Parser.COLUMN_VALUE_LENGTH); + } else { + self.packet = packet = null; + self.state = state = Parser.PACKET_LENGTH; + continue; + } + } + break; + case 47: // COLUMN_VALUE_STRING: + var remaining = packet.columnLength - packet.index, read; + if (i + remaining > buffer.length) { + read = buffer.length - i; + packet.index += read; + packet.emit('data', buffer.slice(i, buffer.length), remaining - read); + // the -1 offsets are because these values are also manipulated by the loop itself + packet.received += read - 1; + i = buffer.length; + } else { + packet.emit('data', buffer.slice(i, i + remaining), 0); + i += remaining - 1; + packet.received += remaining - 1; + advance(Parser.COLUMN_VALUE_LENGTH); + // advance() sets this to -1, but packet.index++ is skipped, so we need to manually fix + packet.index = 0; + } + + if (packet.received == packet.length) { + self.packet = packet = null; + self.state = state = Parser.PACKET_LENGTH; + } + + continue; + } + + packet.index++; + + if (state > Parser.PACKET_NUMBER && packet.received === packet.length) { + emitPacket(); + } + } +}; + + +Parser.LENGTH_CODED_NULL = 251; +Parser.LENGTH_CODED_16BIT_WORD= 252; +Parser.LENGTH_CODED_24BIT_WORD= 253; +Parser.LENGTH_CODED_64BIT_WORD= 254; + +// Parser states +var s = 0; +Parser.PACKET_LENGTH = s++; +Parser.PACKET_NUMBER = s++; +Parser.GREETING_PROTOCOL_VERSION = s++; +Parser.GREETING_SERVER_VERSION = s++; +Parser.GREETING_THREAD_ID = s++; +Parser.GREETING_SCRAMBLE_BUFF_1 = s++; +Parser.GREETING_FILLER_1 = s++; +Parser.GREETING_SERVER_CAPABILITIES = s++; +Parser.GREETING_SERVER_LANGUAGE = s++; +Parser.GREETING_SERVER_STATUS = s++; +Parser.GREETING_FILLER_2 = s++; +Parser.GREETING_SCRAMBLE_BUFF_2 = s++; +Parser.FIELD_COUNT = s++; +Parser.ERROR_NUMBER = s++; +Parser.ERROR_SQL_STATE_MARKER = s++; +Parser.ERROR_SQL_STATE = s++; +Parser.ERROR_MESSAGE = s++; +Parser.AFFECTED_ROWS = s++; +Parser.INSERT_ID = s++; +Parser.SERVER_STATUS = s++; +Parser.WARNING_COUNT = s++; +Parser.MESSAGE = s++; +Parser.EXTRA_LENGTH = s++; +Parser.EXTRA_STRING = s++; +Parser.FIELD_CATALOG_LENGTH = s++; +Parser.FIELD_CATALOG_STRING = s++; +Parser.FIELD_DB_LENGTH = s++; +Parser.FIELD_DB_STRING = s++; +Parser.FIELD_TABLE_LENGTH = s++; +Parser.FIELD_TABLE_STRING = s++; +Parser.FIELD_ORIGINAL_TABLE_LENGTH = s++; +Parser.FIELD_ORIGINAL_TABLE_STRING = s++; +Parser.FIELD_NAME_LENGTH = s++; +Parser.FIELD_NAME_STRING = s++; +Parser.FIELD_ORIGINAL_NAME_LENGTH = s++; +Parser.FIELD_ORIGINAL_NAME_STRING = s++; +Parser.FIELD_FILLER_1 = s++; +Parser.FIELD_CHARSET_NR = s++; +Parser.FIELD_LENGTH = s++; +Parser.FIELD_TYPE = s++; +Parser.FIELD_FLAGS = s++; +Parser.FIELD_DECIMALS = s++; +Parser.FIELD_FILLER_2 = s++; +Parser.FIELD_DEFAULT = s++; +Parser.EOF_WARNING_COUNT = s++; +Parser.EOF_SERVER_STATUS = s++; +Parser.COLUMN_VALUE_LENGTH = s++; +Parser.COLUMN_VALUE_STRING = s++; + +// Packet types +var p = 0; +Parser.GREETING_PACKET = p++; +Parser.OK_PACKET = p++; +Parser.ERROR_PACKET = p++; +Parser.RESULT_SET_HEADER_PACKET = p++; +Parser.FIELD_PACKET = p++; +Parser.EOF_PACKET = p++; +Parser.ROW_DATA_PACKET = p++; +Parser.ROW_DATA_BINARY_PACKET = p++; +Parser.OK_FOR_PREPARED_STATEMENT_PACKET = p++; +Parser.PARAMETER_PACKET = p++; +Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET = p++; diff --git a/node_modules/mysql/lib/query.js b/node_modules/mysql/lib/query.js new file mode 100755 index 0000000..72e66c6 --- /dev/null +++ b/node_modules/mysql/lib/query.js @@ -0,0 +1,140 @@ +var util = require('util'); +var EventEmitter = require('events').EventEmitter; +var Parser = require('./parser'); +var Client; + +function Query(properties) { + EventEmitter.call(this); + + this.sql = null; + this.typeCast = true; + + for (var key in properties) { + this[key] = properties[key]; + } +}; +util.inherits(Query, EventEmitter); +module.exports = Query; + +Query.prototype._handlePacket = function(packet) { + var self = this; + + // We can't do this require() on top of the file. + // That's because there is circular dependency and we're overwriting + // module.exports + Client = Client || require('./client'); + + switch (packet.type) { + case Parser.OK_PACKET: + this.emit('end', Client._packetToUserObject(packet)); + break; + case Parser.ERROR_PACKET: + packet.sql = this.sql; + this.emit('error', Client._packetToUserObject(packet)); + break; + case Parser.FIELD_PACKET: + if (!this._fields) { + this._fields = []; + } + + this._fields.push(packet); + this.emit('field', packet); + break; + case Parser.EOF_PACKET: + if (!this._eofs) { + this._eofs = 1; + } else { + this._eofs++; + } + + if (this._eofs == 2) { + this.emit('end'); + } + break; + case Parser.ROW_DATA_PACKET: + var row = this._row = {}, field; + + this._rowIndex = 0; + + packet.on('data', function(buffer, remaining) { + if (!field) { + field = self._fields[self._rowIndex]; + row[field.name] = ''; + } + + if (buffer) { + row[field.name] += buffer.toString('utf-8'); + } else { + row[field.name] = null; + } + + if (remaining !== 0) { + return; + } + + self._rowIndex++; + if (self.typeCast && buffer !== null) { + switch (field.fieldType) { + case Query.FIELD_TYPE_TIMESTAMP: + case Query.FIELD_TYPE_DATE: + case Query.FIELD_TYPE_DATETIME: + case Query.FIELD_TYPE_NEWDATE: + row[field.name] = new Date(row[field.name]); + break; + case Query.FIELD_TYPE_TINY: + case Query.FIELD_TYPE_SHORT: + case Query.FIELD_TYPE_LONG: + case Query.FIELD_TYPE_LONGLONG: + case Query.FIELD_TYPE_INT24: + case Query.FIELD_TYPE_YEAR: + row[field.name] = parseInt(row[field.name], 10); + break; + case Query.FIELD_TYPE_FLOAT: + case Query.FIELD_TYPE_DOUBLE: + // decimal types cannot be parsed as floats because + // V8 Numbers have less precision than some MySQL Decimals + row[field.name] = parseFloat(row[field.name]); + break; + } + } + + if (self._rowIndex == self._fields.length) { + delete self._row; + delete self._rowIndex; + self.emit('row', row); + return; + } + + field = null; + }); + break; + } +}; + +Query.FIELD_TYPE_DECIMAL = 0x00; +Query.FIELD_TYPE_TINY = 0x01; +Query.FIELD_TYPE_SHORT = 0x02; +Query.FIELD_TYPE_LONG = 0x03; +Query.FIELD_TYPE_FLOAT = 0x04; +Query.FIELD_TYPE_DOUBLE = 0x05; +Query.FIELD_TYPE_NULL = 0x06; +Query.FIELD_TYPE_TIMESTAMP = 0x07; +Query.FIELD_TYPE_LONGLONG = 0x08; +Query.FIELD_TYPE_INT24 = 0x09; +Query.FIELD_TYPE_DATE = 0x0a; +Query.FIELD_TYPE_TIME = 0x0b; +Query.FIELD_TYPE_DATETIME = 0x0c; +Query.FIELD_TYPE_YEAR = 0x0d; +Query.FIELD_TYPE_NEWDATE = 0x0e; +Query.FIELD_TYPE_VARCHAR = 0x0f; +Query.FIELD_TYPE_BIT = 0x10; +Query.FIELD_TYPE_NEWDECIMAL = 0xf6; +Query.FIELD_TYPE_ENUM = 0xf7; +Query.FIELD_TYPE_SET = 0xf8; +Query.FIELD_TYPE_TINY_BLOB = 0xf9; +Query.FIELD_TYPE_MEDIUM_BLOB = 0xfa; +Query.FIELD_TYPE_LONG_BLOB = 0xfb; +Query.FIELD_TYPE_BLOB = 0xfc; +Query.FIELD_TYPE_VAR_STRING = 0xfd; +Query.FIELD_TYPE_STRING = 0xfe; +Query.FIELD_TYPE_GEOMETRY = 0xff; diff --git a/node_modules/mysql/node_modules/hashish/README.markdown b/node_modules/mysql/node_modules/hashish/README.markdown new file mode 100644 index 0000000..1f39d59 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/README.markdown @@ -0,0 +1,191 @@ +Hashish +======= + +Hashish is a node.js library for manipulating hash data structures. +It is distilled from the finest that ruby, perl, and haskell have to offer by +way of hash/map interfaces. + +Hashish provides a chaining interface, where you can do: + + var Hash = require('hashish'); + + Hash({ a : 1, b : 2, c : 3, d : 4 }) + .map(function (x) { return x * 10 }) + .filter(function (x) { return x < 30 }) + .forEach(function (x, key) { + console.log(key + ' => ' + x); + }) + ; + +Output: + + a => 10 + b => 20 + +Some functions and attributes in the chaining interface are terminal, like +`.items` or `.detect()`. They return values of their own instead of the chain +context. + +Each function in the chainable interface is also attached to `Hash` in chainless +form: + + var Hash = require('hashish'); + var obj = { a : 1, b : 2, c : 3, d : 4 }; + + var mapped = Hash.map(obj, function (x) { + return x * 10 + }); + + console.dir(mapped); + +Output: + + { a: 10, b: 20, c: 30, d: 40 } + +In either case, the 'this' context of the function calls is the same object that +the chained functions return, so you can make nested chains. + +Methods +======= + +forEach(cb) +----------- + +For each key/value in the hash, calls `cb(value, key)`. + +map(cb) +------- + +For each key/value in the hash, calls `cb(value, key)`. +The return value of `cb` is the new value at `key` in the resulting hash. + +filter(cb) +---------- + +For each key/value in the hash, calls `cb(value, key)`. +The resulting hash omits key/value pairs where `cb` returned a falsy value. + +detect(cb) +---------- + +Returns the first value in the hash for which `cb(value, key)` is non-falsy. +Order of hashes is not well-defined so watch out for that. + +reduce(cb) +---------- + +Returns the accumulated value of a left-fold over the key/value pairs. + +some(cb) +-------- + +Returns a boolean: whether or not `cb(value, key)` ever returned a non-falsy +value. + +update(obj1, [obj2, obj3, ...]) +----------- + +Mutate the context hash, merging the key/value pairs from the passed objects +and overwriting keys from the context hash if the current `obj` has keys of +the same name. Falsy arguments are silently ignored. + +updateAll([ obj1, obj2, ... ]) +------------------------------ + +Like multi-argument `update()` but operate on an array directly. + +merge(obj1, [obj2, obj3, ...]) +---------- + +Merge the key/value pairs from the passed objects into the resultant hash +without modifying the context hash. Falsy arguments are silently ignored. + +mergeAll([ obj1, obj2, ... ]) +------------------------------ + +Like multi-argument `merge()` but operate on an array directly. + +has(key) +-------- + +Return whether the hash has a key, `key`. + +valuesAt(keys) +-------------- + +Return an Array with the values at the keys from `keys`. + +tap(cb) +------- + +Call `cb` with the present raw hash. +This function is chainable. + +extract(keys) +------------- + +Filter by including only those keys in `keys` in the resulting hash. + +exclude(keys) +------------- + +Filter by excluding those keys in `keys` in the resulting hash. + +Attributes +========== + +These are attributes in the chaining interface and functions in the `Hash.xxx` +interface. + +keys +---- + +Return all the enumerable attribute keys in the hash. + +values +------ + +Return all the enumerable attribute values in the hash. + +compact +------- + +Filter out values which are `=== undefined`. + +clone +----- + +Make a deep copy of the hash. + +copy +---- + +Make a shallow copy of the hash. + +length +------ + +Return the number of key/value pairs in the hash. +Note: use `Hash.size()` for non-chain mode. + +size +---- + +Alias for `length` since `Hash.length` is masked by `Function.prototype`. + +See Also +======== + +See also [creationix's pattern/hash](http://github.com/creationix/pattern), +which does a similar thing except with hash inputs and array outputs. + +Installation +============ + +To install with [npm](http://github.com/isaacs/npm): + + npm install hashish + +To run the tests with [expresso](http://github.com/visionmedia/expresso): + + expresso diff --git a/node_modules/mysql/node_modules/hashish/examples/chain.js b/node_modules/mysql/node_modules/hashish/examples/chain.js new file mode 100644 index 0000000..74ded5e --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/examples/chain.js @@ -0,0 +1,9 @@ +var Hash = require('hashish'); + +Hash({ a : 1, b : 2, c : 3, d : 4 }) + .map(function (x) { return x * 10 }) + .filter(function (x) { return x < 30 }) + .forEach(function (x, key) { + console.log(key + ' => ' + x); + }) +; diff --git a/node_modules/mysql/node_modules/hashish/examples/map.js b/node_modules/mysql/node_modules/hashish/examples/map.js new file mode 100644 index 0000000..119d3d9 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/examples/map.js @@ -0,0 +1,7 @@ +var Hash = require('hashish'); +var obj = { a : 1, b : 2, c : 3, d : 4 }; + +var mapped = Hash.map(obj, function (x) { + return x * 10 +}); +console.dir(mapped); diff --git a/node_modules/mysql/node_modules/hashish/index.js b/node_modules/mysql/node_modules/hashish/index.js new file mode 100644 index 0000000..1bc28e2 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/index.js @@ -0,0 +1,253 @@ +module.exports = Hash; +var Traverse = require('traverse'); + +function Hash (hash, xs) { + if (Array.isArray(hash) && Array.isArray(xs)) { + var to = Math.min(hash.length, xs.length); + var acc = {}; + for (var i = 0; i < to; i++) { + acc[hash[i]] = xs[i]; + } + return Hash(acc); + } + + if (hash === undefined) return Hash({}); + + var self = { + map : function (f) { + var acc = { __proto__ : hash.__proto__ }; + Object.keys(hash).forEach(function (key) { + acc[key] = f.call(self, hash[key], key); + }); + return Hash(acc); + }, + forEach : function (f) { + Object.keys(hash).forEach(function (key) { + f.call(self, hash[key], key); + }); + return self; + }, + filter : function (f) { + var acc = { __proto__ : hash.__proto__ }; + Object.keys(hash).forEach(function (key) { + if (f.call(self, hash[key], key)) { + acc[key] = hash[key]; + } + }); + return Hash(acc); + }, + detect : function (f) { + for (var key in hash) { + if (f.call(self, hash[key], key)) { + return hash[key]; + } + } + return undefined; + }, + reduce : function (f, acc) { + var keys = Object.keys(hash); + if (acc === undefined) acc = keys.shift(); + keys.forEach(function (key) { + acc = f.call(self, acc, hash[key], key); + }); + return acc; + }, + some : function (f) { + for (var key in hash) { + if (f.call(self, hash[key], key)) return true; + } + return false; + }, + update : function (obj) { + if (arguments.length > 1) { + self.updateAll([].slice.call(arguments)); + } + else { + Object.keys(obj).forEach(function (key) { + hash[key] = obj[key]; + }); + } + return self; + }, + updateAll : function (xs) { + xs.filter(Boolean).forEach(function (x) { + self.update(x); + }); + return self; + }, + merge : function (obj) { + if (arguments.length > 1) { + return self.copy.updateAll([].slice.call(arguments)); + } + else { + return self.copy.update(obj); + } + }, + mergeAll : function (xs) { + return self.copy.updateAll(xs); + }, + has : function (key) { // only operates on enumerables + return Array.isArray(key) + ? key.every(function (k) { return self.has(k) }) + : self.keys.indexOf(key.toString()) >= 0; + }, + valuesAt : function (keys) { + return Array.isArray(keys) + ? keys.map(function (key) { return hash[key] }) + : hash[keys] + ; + }, + tap : function (f) { + f.call(self, hash); + return self; + }, + extract : function (keys) { + var acc = {}; + keys.forEach(function (key) { + acc[key] = hash[key]; + }); + return Hash(acc); + }, + exclude : function (keys) { + return self.filter(function (_, key) { + return keys.indexOf(key) < 0 + }); + }, + end : hash, + items : hash + }; + + var props = { + keys : function () { return Object.keys(hash) }, + values : function () { + return Object.keys(hash).map(function (key) { return hash[key] }); + }, + compact : function () { + return self.filter(function (x) { return x !== undefined }); + }, + clone : function () { return Hash(Hash.clone(hash)) }, + copy : function () { return Hash(Hash.copy(hash)) }, + length : function () { return Object.keys(hash).length }, + size : function () { return self.length } + }; + + if (Object.defineProperty) { + // es5-shim has an Object.defineProperty but it throws for getters + try { + for (var key in props) { + Object.defineProperty(self, key, { get : props[key] }); + } + } + catch (err) { + for (var key in props) { + if (key !== 'clone' && key !== 'copy' && key !== 'compact') { + // ^ those keys use Hash() so can't call them without + // a stack overflow + self[key] = props[key](); + } + } + } + } + else if (self.__defineGetter__) { + for (var key in props) { + self.__defineGetter__(key, props[key]); + } + } + else { + // non-lazy version for browsers that suck >_< + for (var key in props) { + self[key] = props[key](); + } + } + + return self; +}; + +// deep copy +Hash.clone = function (ref) { + return Traverse.clone(ref); +}; + +// shallow copy +Hash.copy = function (ref) { + var hash = { __proto__ : ref.__proto__ }; + Object.keys(ref).forEach(function (key) { + hash[key] = ref[key]; + }); + return hash; +}; + +Hash.map = function (ref, f) { + return Hash(ref).map(f).items; +}; + +Hash.forEach = function (ref, f) { + Hash(ref).forEach(f); +}; + +Hash.filter = function (ref, f) { + return Hash(ref).filter(f).items; +}; + +Hash.detect = function (ref, f) { + return Hash(ref).detect(f); +}; + +Hash.reduce = function (ref, f, acc) { + return Hash(ref).reduce(f, acc); +}; + +Hash.some = function (ref, f) { + return Hash(ref).some(f); +}; + +Hash.update = function (a /*, b, c, ... */) { + var args = Array.prototype.slice.call(arguments, 1); + var hash = Hash(a); + return hash.update.apply(hash, args).items; +}; + +Hash.merge = function (a /*, b, c, ... */) { + var args = Array.prototype.slice.call(arguments, 1); + var hash = Hash(a); + return hash.merge.apply(hash, args).items; +}; + +Hash.has = function (ref, key) { + return Hash(ref).has(key); +}; + +Hash.valuesAt = function (ref, keys) { + return Hash(ref).valuesAt(keys); +}; + +Hash.tap = function (ref, f) { + return Hash(ref).tap(f).items; +}; + +Hash.extract = function (ref, keys) { + return Hash(ref).extract(keys).items; +}; + +Hash.exclude = function (ref, keys) { + return Hash(ref).exclude(keys).items; +}; + +Hash.concat = function (xs) { + var hash = Hash({}); + xs.forEach(function (x) { hash.update(x) }); + return hash.items; +}; + +Hash.zip = function (xs, ys) { + return Hash(xs, ys).items; +}; + +// .length is already defined for function prototypes +Hash.size = function (ref) { + return Hash(ref).size; +}; + +Hash.compact = function (ref) { + return Hash(ref).compact.items; +}; diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/.npmignore b/node_modules/mysql/node_modules/hashish/node_modules/traverse/.npmignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/LICENSE b/node_modules/mysql/node_modules/hashish/node_modules/traverse/LICENSE new file mode 100644 index 0000000..7b75500 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/LICENSE @@ -0,0 +1,24 @@ +Copyright 2010 James Halliday (mail@substack.net) + +This project is free software released under the MIT/X11 license: +http://www.opensource.org/licenses/mit-license.php + +Copyright 2010 James Halliday (mail@substack.net) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/README.markdown b/node_modules/mysql/node_modules/hashish/node_modules/traverse/README.markdown new file mode 100644 index 0000000..053dc2d --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/README.markdown @@ -0,0 +1,237 @@ +traverse +======== + +Traverse and transform objects by visiting every node on a recursive walk. + +examples +======== + +transform negative numbers in-place +----------------------------------- + +negative.js + +````javascript +var traverse = require('traverse'); +var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; + +traverse(obj).forEach(function (x) { + if (x < 0) this.update(x + 128); +}); + +console.dir(obj); +```` + +Output: + + [ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ] + +collect leaf nodes +------------------ + +leaves.js + +````javascript +var traverse = require('traverse'); + +var obj = { + a : [1,2,3], + b : 4, + c : [5,6], + d : { e : [7,8], f : 9 }, +}; + +var leaves = traverse(obj).reduce(function (acc, x) { + if (this.isLeaf) acc.push(x); + return acc; +}, []); + +console.dir(leaves); +```` + +Output: + + [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] + +scrub circular references +------------------------- + +scrub.js: + +````javascript +var traverse = require('traverse'); + +var obj = { a : 1, b : 2, c : [ 3, 4 ] }; +obj.c.push(obj); + +var scrubbed = traverse(obj).map(function (x) { + if (this.circular) this.remove() +}); +console.dir(scrubbed); +```` + +output: + + { a: 1, b: 2, c: [ 3, 4 ] } + +context +======= + +Each method that takes a callback has a context (its `this` object) with these +attributes: + +this.node +--------- + +The present node on the recursive walk + +this.path +--------- + +An array of string keys from the root to the present node + +this.parent +----------- + +The context of the node's parent. +This is `undefined` for the root node. + +this.key +-------- + +The name of the key of the present node in its parent. +This is `undefined` for the root node. + +this.isRoot, this.notRoot +------------------------- + +Whether the present node is the root node + +this.isLeaf, this.notLeaf +------------------------- + +Whether or not the present node is a leaf node (has no children) + +this.level +---------- + +Depth of the node within the traversal + +this.circular +------------- + +If the node equals one of its parents, the `circular` attribute is set to the +context of that parent and the traversal progresses no deeper. + +this.update(value, stopHere=false) +---------------------------------- + +Set a new value for the present node. + +All the elements in `value` will be recursively traversed unless `stopHere` is +true. + +this.remove() +------------- + +Remove the current element from the output. If the node is in an Array it will +be spliced off. Otherwise it will be deleted from its parent. + +this.delete() +------------- + +Delete the current element from its parent in the output. Calls `delete` even on +Arrays. + +this.before(fn) +--------------- + +Call this function before any of the children are traversed. + +You can assign into `this.keys` here to traverse in a custom order. + +this.after(fn) +-------------- + +Call this function after any of the children are traversed. + +this.pre(fn) +------------ + +Call this function before each of the children are traversed. + +this.post(fn) +------------- + +Call this function after each of the children are traversed. + +methods +======= + +.map(fn) +-------- + +Execute `fn` for each node in the object and return a new object with the +results of the walk. To update nodes in the result use `this.update(value)`. + +.forEach(fn) +------------ + +Execute `fn` for each node in the object but unlike `.map()`, when +`this.update()` is called it updates the object in-place. + +.reduce(fn, acc) +---------------- + +For each node in the object, perform a +[left-fold](http://en.wikipedia.org/wiki/Fold_(higher-order_function)) +with the return value of `fn(acc, node)`. + +If `acc` isn't specified, `acc` is set to the root object for the first step +and the root element is skipped. + +.paths() +-------- + +Return an `Array` of every possible non-cyclic path in the object. +Paths are `Array`s of string keys. + +.nodes() +-------- + +Return an `Array` of every node in the object. + +.clone() +-------- + +Create a deep clone of the object. + +install +======= + +Using [npm](http://npmjs.org) do: + + $ npm install traverse + +test +==== + +Using [expresso](http://github.com/visionmedia/expresso) do: + + $ expresso + + 100% wahoo, your stuff is not broken! + +in the browser +============== + +Use [browserify](https://github.com/substack/node-browserify) to run traverse in +the browser. + +traverse has been tested and works with: + +* Internet Explorer 5.5, 6.0, 7.0, 8.0, 9.0 +* Firefox 3.5 +* Chrome 6.0 +* Opera 10.6 +* Safari 5.0 diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/json.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/json.js new file mode 100755 index 0000000..50d612e --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/json.js @@ -0,0 +1,16 @@ +var traverse = require('traverse'); + +var id = 54; +var callbacks = {}; +var obj = { moo : function () {}, foo : [2,3,4, function () {}] }; + +var scrubbed = traverse(obj).map(function (x) { + if (typeof x === 'function') { + callbacks[id] = { id : id, f : x, path : this.path }; + this.update('[Function]'); + id++; + } +}); + +console.dir(scrubbed); +console.dir(callbacks); diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/leaves.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/leaves.js new file mode 100755 index 0000000..c1b310b --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/leaves.js @@ -0,0 +1,15 @@ +var traverse = require('traverse'); + +var obj = { + a : [1,2,3], + b : 4, + c : [5,6], + d : { e : [7,8], f : 9 }, +}; + +var leaves = traverse(obj).reduce(function (acc, x) { + if (this.isLeaf) acc.push(x); + return acc; +}, []); + +console.dir(leaves); diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/negative.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/negative.js new file mode 100755 index 0000000..78608a0 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/negative.js @@ -0,0 +1,8 @@ +var traverse = require('traverse'); +var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; + +traverse(obj).forEach(function (x) { + if (x < 0) this.update(x + 128); +}); + +console.dir(obj); diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/scrub.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/scrub.js new file mode 100755 index 0000000..5d15b91 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/scrub.js @@ -0,0 +1,10 @@ +// scrub out circular references +var traverse = require('traverse'); + +var obj = { a : 1, b : 2, c : [ 3, 4 ] }; +obj.c.push(obj); + +var scrubbed = traverse(obj).map(function (x) { + if (this.circular) this.remove() +}); +console.dir(scrubbed); diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/stringify.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/stringify.js new file mode 100755 index 0000000..167b68b --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/examples/stringify.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node +var traverse = require('traverse'); + +var obj = [ 'five', 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; + +var s = ''; +traverse(obj).forEach(function to_s (node) { + if (Array.isArray(node)) { + this.before(function () { s += '[' }); + this.post(function (child) { + if (!child.isLast) s += ','; + }); + this.after(function () { s += ']' }); + } + else if (typeof node == 'object') { + this.before(function () { s += '{' }); + this.pre(function (x, key) { + to_s(key); + s += ':'; + }); + this.post(function (child) { + if (!child.isLast) s += ','; + }); + this.after(function () { s += '}' }); + } + else if (typeof node == 'string') { + s += '"' + node.toString().replace(/"/g, '\\"') + '"'; + } + else if (typeof node == 'function') { + s += 'null'; + } + else { + s += node.toString(); + } +}); + +console.log('JSON.stringify: ' + JSON.stringify(obj)); +console.log('this stringify: ' + s); diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/index.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/index.js new file mode 100644 index 0000000..b7d0d07 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/index.js @@ -0,0 +1,265 @@ +module.exports = Traverse; +function Traverse (obj) { + if (!(this instanceof Traverse)) return new Traverse(obj); + this.value = obj; +} + +Traverse.prototype.get = function (ps) { + var node = this.value; + for (var i = 0; i < ps.length; i ++) { + var key = ps[i]; + if (!Object.hasOwnProperty.call(node, key)) { + node = undefined; + break; + } + node = node[key]; + } + return node; +}; + +Traverse.prototype.set = function (ps, value) { + var node = this.value; + for (var i = 0; i < ps.length - 1; i ++) { + var key = ps[i]; + if (!Object.hasOwnProperty.call(node, key)) node[key] = {}; + node = node[key]; + } + node[ps[i]] = value; + return value; +}; + +Traverse.prototype.map = function (cb) { + return walk(this.value, cb, true); +}; + +Traverse.prototype.forEach = function (cb) { + this.value = walk(this.value, cb, false); + return this.value; +}; + +Traverse.prototype.reduce = function (cb, init) { + var skip = arguments.length === 1; + var acc = skip ? this.value : init; + this.forEach(function (x) { + if (!this.isRoot || !skip) { + acc = cb.call(this, acc, x); + } + }); + return acc; +}; + +Traverse.prototype.paths = function () { + var acc = []; + this.forEach(function (x) { + acc.push(this.path); + }); + return acc; +}; + +Traverse.prototype.nodes = function () { + var acc = []; + this.forEach(function (x) { + acc.push(this.node); + }); + return acc; +}; + +Traverse.prototype.clone = function () { + var parents = [], nodes = []; + + return (function clone (src) { + for (var i = 0; i < parents.length; i++) { + if (parents[i] === src) { + return nodes[i]; + } + } + + if (typeof src === 'object' && src !== null) { + var dst = copy(src); + + parents.push(src); + nodes.push(dst); + + forEach(Object_keys(src), function (key) { + dst[key] = clone(src[key]); + }); + + parents.pop(); + nodes.pop(); + return dst; + } + else { + return src; + } + })(this.value); +}; + +function walk (root, cb, immutable) { + var path = []; + var parents = []; + var alive = true; + + return (function walker (node_) { + var node = immutable ? copy(node_) : node_; + var modifiers = {}; + + var keepGoing = true; + + var state = { + node : node, + node_ : node_, + path : [].concat(path), + parent : parents[parents.length - 1], + parents : parents, + key : path.slice(-1)[0], + isRoot : path.length === 0, + level : path.length, + circular : null, + update : function (x, stopHere) { + if (!state.isRoot) { + state.parent.node[state.key] = x; + } + state.node = x; + if (stopHere) keepGoing = false; + }, + 'delete' : function () { + delete state.parent.node[state.key]; + }, + remove : function () { + if (Array_isArray(state.parent.node)) { + state.parent.node.splice(state.key, 1); + } + else { + delete state.parent.node[state.key]; + } + }, + keys : null, + before : function (f) { modifiers.before = f }, + after : function (f) { modifiers.after = f }, + pre : function (f) { modifiers.pre = f }, + post : function (f) { modifiers.post = f }, + stop : function () { alive = false }, + block : function () { keepGoing = false } + }; + + if (!alive) return state; + + if (typeof node === 'object' && node !== null) { + state.keys = Object_keys(node); + + state.isLeaf = state.keys.length == 0; + + for (var i = 0; i < parents.length; i++) { + if (parents[i].node_ === node_) { + state.circular = parents[i]; + break; + } + } + } + else { + state.isLeaf = true; + } + + state.notLeaf = !state.isLeaf; + state.notRoot = !state.isRoot; + + // use return values to update if defined + var ret = cb.call(state, state.node); + if (ret !== undefined && state.update) state.update(ret); + + if (modifiers.before) modifiers.before.call(state, state.node); + + if (!keepGoing) return state; + + if (typeof state.node == 'object' + && state.node !== null && !state.circular) { + parents.push(state); + + forEach(state.keys, function (key, i) { + path.push(key); + + if (modifiers.pre) modifiers.pre.call(state, state.node[key], key); + + var child = walker(state.node[key]); + if (immutable && Object.hasOwnProperty.call(state.node, key)) { + state.node[key] = child.node; + } + + child.isLast = i == state.keys.length - 1; + child.isFirst = i == 0; + + if (modifiers.post) modifiers.post.call(state, child); + + path.pop(); + }); + parents.pop(); + } + + if (modifiers.after) modifiers.after.call(state, state.node); + + return state; + })(root).node; +} + +function copy (src) { + if (typeof src === 'object' && src !== null) { + var dst; + + if (Array_isArray(src)) { + dst = []; + } + else if (src instanceof Date) { + dst = new Date(src); + } + else if (src instanceof Boolean) { + dst = new Boolean(src); + } + else if (src instanceof Number) { + dst = new Number(src); + } + else if (src instanceof String) { + dst = new String(src); + } + else if (Object.create && Object.getPrototypeOf) { + dst = Object.create(Object.getPrototypeOf(src)); + } + else if (src.__proto__ || src.constructor.prototype) { + var proto = src.__proto__ || src.constructor.prototype || {}; + var T = function () {}; + T.prototype = proto; + dst = new T; + if (!dst.__proto__) dst.__proto__ = proto; + } + + forEach(Object_keys(src), function (key) { + dst[key] = src[key]; + }); + return dst; + } + else return src; +} + +var Object_keys = Object.keys || function keys (obj) { + var res = []; + for (var key in obj) res.push(key) + return res; +}; + +var Array_isArray = Array.isArray || function isArray (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +var forEach = function (xs, fn) { + if (xs.forEach) return xs.forEach(fn) + else for (var i = 0; i < xs.length; i++) { + fn(xs[i], i, xs); + } +}; + +forEach(Object_keys(Traverse.prototype), function (key) { + Traverse[key] = function (obj) { + var args = [].slice.call(arguments, 1); + var t = Traverse(obj); + return t[key].apply(t, args); + }; +}); diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/package.json b/node_modules/mysql/node_modules/hashish/node_modules/traverse/package.json new file mode 100644 index 0000000..5510058 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/package.json @@ -0,0 +1,18 @@ +{ + "name" : "traverse", + "version" : "0.5.1", + "description" : "Traverse and transform objects by visiting every node on a recursive walk", + "author" : "James Halliday", + "license" : "MIT/X11", + "main" : "./index", + "repository" : { + "type" : "git", + "url" : "http://github.com/substack/js-traverse.git" + }, + "devDependencies" : { + "expresso" : "0.7.x" + }, + "scripts" : { + "test" : "expresso" + } +} diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/circular.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/circular.js new file mode 100644 index 0000000..9162601 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/circular.js @@ -0,0 +1,115 @@ +var assert = require('assert'); +var Traverse = require('../'); +var deepEqual = require('./lib/deep_equal'); +var util = require('util'); + +exports.circular = function () { + var obj = { x : 3 }; + obj.y = obj; + var foundY = false; + Traverse(obj).forEach(function (x) { + if (this.path.join('') == 'y') { + assert.equal( + util.inspect(this.circular.node), + util.inspect(obj) + ); + foundY = true; + } + }); + assert.ok(foundY); +}; + +exports.deepCirc = function () { + var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] }; + obj.y[2] = obj; + + var times = 0; + Traverse(obj).forEach(function (x) { + if (this.circular) { + assert.deepEqual(this.circular.path, []); + assert.deepEqual(this.path, [ 'y', 2 ]); + times ++; + } + }); + + assert.deepEqual(times, 1); +}; + +exports.doubleCirc = function () { + var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] }; + obj.y[2] = obj; + obj.x.push(obj.y); + + var circs = []; + Traverse(obj).forEach(function (x) { + if (this.circular) { + circs.push({ circ : this.circular, self : this, node : x }); + } + }); + + assert.deepEqual(circs[0].self.path, [ 'x', 3, 2 ]); + assert.deepEqual(circs[0].circ.path, []); + + assert.deepEqual(circs[1].self.path, [ 'y', 2 ]); + assert.deepEqual(circs[1].circ.path, []); + + assert.deepEqual(circs.length, 2); +}; + +exports.circDubForEach = function () { + var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] }; + obj.y[2] = obj; + obj.x.push(obj.y); + + Traverse(obj).forEach(function (x) { + if (this.circular) this.update('...'); + }); + + assert.deepEqual(obj, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] }); +}; + +exports.circDubMap = function () { + var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] }; + obj.y[2] = obj; + obj.x.push(obj.y); + + var c = Traverse(obj).map(function (x) { + if (this.circular) { + this.update('...'); + } + }); + + assert.deepEqual(c, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] }); +}; + +exports.circClone = function () { + var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] }; + obj.y[2] = obj; + obj.x.push(obj.y); + + var clone = Traverse.clone(obj); + assert.ok(obj !== clone); + + assert.ok(clone.y[2] === clone); + assert.ok(clone.y[2] !== obj); + assert.ok(clone.x[3][2] === clone); + assert.ok(clone.x[3][2] !== obj); + assert.deepEqual(clone.x.slice(0,3), [1,2,3]); + assert.deepEqual(clone.y.slice(0,2), [4,5]); +}; + +exports.circMapScrub = function () { + var obj = { a : 1, b : 2 }; + obj.c = obj; + + var scrubbed = Traverse(obj).map(function (node) { + if (this.circular) this.remove(); + }); + assert.deepEqual( + Object.keys(scrubbed).sort(), + [ 'a', 'b' ] + ); + assert.ok(deepEqual(scrubbed, { a : 1, b : 2 })); + + assert.equal(obj.c, obj); +}; diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/date.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/date.js new file mode 100644 index 0000000..4ca06dc --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/date.js @@ -0,0 +1,35 @@ +var assert = require('assert'); +var Traverse = require('../'); + +exports.dateEach = function () { + var obj = { x : new Date, y : 10, z : 5 }; + + var counts = {}; + + Traverse(obj).forEach(function (node) { + var t = (node instanceof Date && 'Date') || typeof node; + counts[t] = (counts[t] || 0) + 1; + }); + + assert.deepEqual(counts, { + object : 1, + Date : 1, + number : 2, + }); +}; + +exports.dateMap = function () { + var obj = { x : new Date, y : 10, z : 5 }; + + var res = Traverse(obj).map(function (node) { + if (typeof node === 'number') this.update(node + 100); + }); + + assert.ok(obj.x !== res.x); + assert.deepEqual(res, { + x : obj.x, + y : 110, + z : 105, + }); +}; + diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/equal.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/equal.js new file mode 100644 index 0000000..decc755 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/equal.js @@ -0,0 +1,220 @@ +var assert = require('assert'); +var traverse = require('../'); +var deepEqual = require('./lib/deep_equal'); + +exports.deepDates = function () { + assert.ok( + deepEqual( + { d : new Date, x : [ 1, 2, 3 ] }, + { d : new Date, x : [ 1, 2, 3 ] } + ), + 'dates should be equal' + ); + + var d0 = new Date; + setTimeout(function () { + assert.ok( + !deepEqual( + { d : d0, x : [ 1, 2, 3 ], }, + { d : new Date, x : [ 1, 2, 3 ] } + ), + 'microseconds should count in date equality' + ); + }, 5); +}; + +exports.deepCircular = function () { + var a = [1]; + a.push(a); // a = [ 1, *a ] + + var b = [1]; + b.push(a); // b = [ 1, [ 1, *a ] ] + + assert.ok( + !deepEqual(a, b), + 'circular ref mount points count towards equality' + ); + + var c = [1]; + c.push(c); // c = [ 1, *c ] + assert.ok( + deepEqual(a, c), + 'circular refs are structurally the same here' + ); + + var d = [1]; + d.push(a); // c = [ 1, [ 1, *d ] ] + assert.ok( + deepEqual(b, d), + 'non-root circular ref structural comparison' + ); +}; + +exports.deepInstances = function () { + assert.ok( + !deepEqual([ new Boolean(false) ], [ false ]), + 'boolean instances are not real booleans' + ); + + assert.ok( + !deepEqual([ new String('x') ], [ 'x' ]), + 'string instances are not real strings' + ); + + assert.ok( + !deepEqual([ new Number(4) ], [ 4 ]), + 'number instances are not real numbers' + ); + + assert.ok( + deepEqual([ new RegExp('x') ], [ /x/ ]), + 'regexp instances are real regexps' + ); + + assert.ok( + !deepEqual([ new RegExp(/./) ], [ /../ ]), + 'these regexps aren\'t the same' + ); + + assert.ok( + !deepEqual( + [ function (x) { return x * 2 } ], + [ function (x) { return x * 2 } ] + ), + 'functions with the same .toString() aren\'t necessarily the same' + ); + + var f = function (x) { return x * 2 }; + assert.ok( + deepEqual([ f ], [ f ]), + 'these functions are actually equal' + ); +}; + +exports.deepEqual = function () { + assert.ok( + !deepEqual([ 1, 2, 3 ], { 0 : 1, 1 : 2, 2 : 3 }), + 'arrays are not objects' + ); +}; + +exports.falsy = function () { + assert.ok( + !deepEqual([ undefined ], [ null ]), + 'null is not undefined!' + ); + + assert.ok( + !deepEqual([ null ], [ undefined ]), + 'undefined is not null!' + ); + + assert.ok( + !deepEqual( + { a : 1, b : 2, c : [ 3, undefined, 5 ] }, + { a : 1, b : 2, c : [ 3, null, 5 ] } + ), + 'undefined is not null, however deeply!' + ); + + assert.ok( + !deepEqual( + { a : 1, b : 2, c : [ 3, undefined, 5 ] }, + { a : 1, b : 2, c : [ 3, null, 5 ] } + ), + 'null is not undefined, however deeply!' + ); + + assert.ok( + !deepEqual( + { a : 1, b : 2, c : [ 3, undefined, 5 ] }, + { a : 1, b : 2, c : [ 3, null, 5 ] } + ), + 'null is not undefined, however deeply!' + ); +}; + +exports.deletedArrayEqual = function () { + var xs = [ 1, 2, 3, 4 ]; + delete xs[2]; + + var ys = Object.create(Array.prototype); + ys[0] = 1; + ys[1] = 2; + ys[3] = 4; + + assert.ok( + deepEqual(xs, ys), + 'arrays with deleted elements are only equal to' + + ' arrays with similarly deleted elements' + ); + + assert.ok( + !deepEqual(xs, [ 1, 2, undefined, 4 ]), + 'deleted array elements cannot be undefined' + ); + + assert.ok( + !deepEqual(xs, [ 1, 2, null, 4 ]), + 'deleted array elements cannot be null' + ); +}; + +exports.deletedObjectEqual = function () { + var obj = { a : 1, b : 2, c : 3 }; + delete obj.c; + + assert.ok( + deepEqual(obj, { a : 1, b : 2 }), + 'deleted object elements should not show up' + ); + + assert.ok( + !deepEqual(obj, { a : 1, b : 2, c : undefined }), + 'deleted object elements are not undefined' + ); + + assert.ok( + !deepEqual(obj, { a : 1, b : 2, c : null }), + 'deleted object elements are not null' + ); +}; + +exports.emptyKeyEqual = function () { + assert.ok(!deepEqual( + { a : 1 }, { a : 1, '' : 55 } + )); +}; + +exports.deepArguments = function () { + assert.ok( + !deepEqual( + [ 4, 5, 6 ], + (function () { return arguments })(4, 5, 6) + ), + 'arguments are not arrays' + ); + + assert.ok( + deepEqual( + (function () { return arguments })(4, 5, 6), + (function () { return arguments })(4, 5, 6) + ), + 'arguments should equal' + ); +}; + +exports.deepUn = function () { + assert.ok(!deepEqual({ a : 1, b : 2 }, undefined)); + assert.ok(!deepEqual({ a : 1, b : 2 }, {})); + assert.ok(!deepEqual(undefined, { a : 1, b : 2 })); + assert.ok(!deepEqual({}, { a : 1, b : 2 })); + assert.ok(deepEqual(undefined, undefined)); + assert.ok(deepEqual(null, null)); + assert.ok(!deepEqual(undefined, null)); +}; + +exports.deepLevels = function () { + var xs = [ 1, 2, [ 3, 4, [ 5, 6 ] ] ]; + assert.ok(!deepEqual(xs, [])); +}; diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/instance.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/instance.js new file mode 100644 index 0000000..8d73525 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/instance.js @@ -0,0 +1,17 @@ +var assert = require('assert'); +var Traverse = require('../'); +var EventEmitter = require('events').EventEmitter; + +exports['check instanceof on node elems'] = function () { + + var counts = { emitter : 0 }; + + Traverse([ new EventEmitter, 3, 4, { ev : new EventEmitter }]) + .forEach(function (node) { + if (node instanceof EventEmitter) counts.emitter ++; + }) + ; + + assert.equal(counts.emitter, 2); +}; + diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/interface.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/interface.js new file mode 100644 index 0000000..fce5bf9 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/interface.js @@ -0,0 +1,42 @@ +var assert = require('assert'); +var Traverse = require('../'); + +exports['interface map'] = function () { + var obj = { a : [ 5,6,7 ], b : { c : [8] } }; + + assert.deepEqual( + Traverse.paths(obj) + .sort() + .map(function (path) { return path.join('/') }) + .slice(1) + .join(' ') + , + 'a a/0 a/1 a/2 b b/c b/c/0' + ); + + assert.deepEqual( + Traverse.nodes(obj), + [ + { a: [ 5, 6, 7 ], b: { c: [ 8 ] } }, + [ 5, 6, 7 ], 5, 6, 7, + { c: [ 8 ] }, [ 8 ], 8 + ] + ); + + assert.deepEqual( + Traverse.map(obj, function (node) { + if (typeof node == 'number') { + return node + 1000; + } + else if (Array.isArray(node)) { + return node.join(' '); + } + }), + { a: '5 6 7', b: { c: '8' } } + ); + + var nodes = 0; + Traverse.forEach(obj, function (node) { nodes ++ }); + assert.deepEqual(nodes, 8); +}; + diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/json.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/json.js new file mode 100644 index 0000000..0a04529 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/json.js @@ -0,0 +1,47 @@ +var assert = require('assert'); +var Traverse = require('../'); + +exports['json test'] = function () { + var id = 54; + var callbacks = {}; + var obj = { moo : function () {}, foo : [2,3,4, function () {}] }; + + var scrubbed = Traverse(obj).map(function (x) { + if (typeof x === 'function') { + callbacks[id] = { id : id, f : x, path : this.path }; + this.update('[Function]'); + id++; + } + }); + + assert.equal( + scrubbed.moo, '[Function]', + 'obj.moo replaced with "[Function]"' + ); + + assert.equal( + scrubbed.foo[3], '[Function]', + 'obj.foo[3] replaced with "[Function]"' + ); + + assert.deepEqual(scrubbed, { + moo : '[Function]', + foo : [ 2, 3, 4, "[Function]" ] + }, 'Full JSON string matches'); + + assert.deepEqual( + typeof obj.moo, 'function', + 'Original obj.moo still a function' + ); + + assert.deepEqual( + typeof obj.foo[3], 'function', + 'Original obj.foo[3] still a function' + ); + + assert.deepEqual(callbacks, { + 54: { id: 54, f : obj.moo, path: [ 'moo' ] }, + 55: { id: 55, f : obj.foo[3], path: [ 'foo', '3' ] }, + }, 'Check the generated callbacks list'); +}; + diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/keys.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/keys.js new file mode 100644 index 0000000..7ecd545 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/keys.js @@ -0,0 +1,29 @@ +var assert = require('assert'); +var Traverse = require('../'); + +exports['sort test'] = function () { + var acc = []; + Traverse({ + a: 30, + b: 22, + id: 9 + }).forEach(function (node) { + if ((! Array.isArray(node)) && typeof node === 'object') { + this.before(function(node) { + this.keys = Object.keys(node); + this.keys.sort(function(a, b) { + a = [a === "id" ? 0 : 1, a]; + b = [b === "id" ? 0 : 1, b]; + return a < b ? -1 : a > b ? 1 : 0; + }); + }); + } + if (this.isLeaf) acc.push(node); + }); + + assert.equal( + acc.join(' '), + '9 30 22', + 'Traversal in a custom order' + ); +}; diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/leaves.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/leaves.js new file mode 100644 index 0000000..e520b72 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/leaves.js @@ -0,0 +1,21 @@ +var assert = require('assert'); +var Traverse = require('../'); + +exports['leaves test'] = function () { + var acc = []; + Traverse({ + a : [1,2,3], + b : 4, + c : [5,6], + d : { e : [7,8], f : 9 } + }).forEach(function (x) { + if (this.isLeaf) acc.push(x); + }); + + assert.equal( + acc.join(' '), + '1 2 3 4 5 6 7 8 9', + 'Traversal in the right(?) order' + ); +}; + diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/lib/deep_equal.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/lib/deep_equal.js new file mode 100644 index 0000000..4fa07bb --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/lib/deep_equal.js @@ -0,0 +1,92 @@ +var traverse = require('../../'); + +module.exports = function (a, b) { + if (arguments.length !== 2) { + throw new Error( + 'deepEqual requires exactly two objects to compare against' + ); + } + + var equal = true; + var node = b; + + traverse(a).forEach(function (y) { + var notEqual = (function () { + equal = false; + //this.stop(); + return undefined; + }).bind(this); + + //if (node === undefined || node === null) return notEqual(); + + if (!this.isRoot) { + /* + if (!Object.hasOwnProperty.call(node, this.key)) { + return notEqual(); + } + */ + if (typeof node !== 'object') return notEqual(); + node = node[this.key]; + } + + var x = node; + + this.post(function () { + node = x; + }); + + var toS = function (o) { + return Object.prototype.toString.call(o); + }; + + if (this.circular) { + if (traverse(b).get(this.circular.path) !== x) notEqual(); + } + else if (typeof x !== typeof y) { + notEqual(); + } + else if (x === null || y === null || x === undefined || y === undefined) { + if (x !== y) notEqual(); + } + else if (x.__proto__ !== y.__proto__) { + notEqual(); + } + else if (x === y) { + // nop + } + else if (typeof x === 'function') { + if (x instanceof RegExp) { + // both regexps on account of the __proto__ check + if (x.toString() != y.toString()) notEqual(); + } + else if (x !== y) notEqual(); + } + else if (typeof x === 'object') { + if (toS(y) === '[object Arguments]' + || toS(x) === '[object Arguments]') { + if (toS(x) !== toS(y)) { + notEqual(); + } + } + else if (x instanceof Date || y instanceof Date) { + if (!(x instanceof Date) || !(y instanceof Date) + || x.getTime() !== y.getTime()) { + notEqual(); + } + } + else { + var kx = Object.keys(x); + var ky = Object.keys(y); + if (kx.length !== ky.length) return notEqual(); + for (var i = 0; i < kx.length; i++) { + var k = kx[i]; + if (!Object.hasOwnProperty.call(y, k)) { + notEqual(); + } + } + } + } + }); + + return equal; +}; diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/mutability.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/mutability.js new file mode 100644 index 0000000..d2f4ce4 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/mutability.js @@ -0,0 +1,204 @@ +var assert = require('assert'); +var Traverse = require('../'); +var deepEqual = require('./lib/deep_equal'); + +exports.mutate = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + var res = Traverse(obj).forEach(function (x) { + if (typeof x === 'number' && x % 2 === 0) { + this.update(x * 10); + } + }); + assert.deepEqual(obj, res); + assert.deepEqual(obj, { a : 1, b : 20, c : [ 3, 40 ] }); +}; + +exports.mutateT = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + var res = Traverse.forEach(obj, function (x) { + if (typeof x === 'number' && x % 2 === 0) { + this.update(x * 10); + } + }); + assert.deepEqual(obj, res); + assert.deepEqual(obj, { a : 1, b : 20, c : [ 3, 40 ] }); +}; + +exports.map = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + var res = Traverse(obj).map(function (x) { + if (typeof x === 'number' && x % 2 === 0) { + this.update(x * 10); + } + }); + assert.deepEqual(obj, { a : 1, b : 2, c : [ 3, 4 ] }); + assert.deepEqual(res, { a : 1, b : 20, c : [ 3, 40 ] }); +}; + +exports.mapT = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + var res = Traverse.map(obj, function (x) { + if (typeof x === 'number' && x % 2 === 0) { + this.update(x * 10); + } + }); + assert.deepEqual(obj, { a : 1, b : 2, c : [ 3, 4 ] }); + assert.deepEqual(res, { a : 1, b : 20, c : [ 3, 40 ] }); +}; + +exports.clone = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + var res = Traverse(obj).clone(); + assert.deepEqual(obj, res); + assert.ok(obj !== res); + obj.a ++; + assert.deepEqual(res.a, 1); + obj.c.push(5); + assert.deepEqual(res.c, [ 3, 4 ]); +}; + +exports.cloneT = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + var res = Traverse.clone(obj); + assert.deepEqual(obj, res); + assert.ok(obj !== res); + obj.a ++; + assert.deepEqual(res.a, 1); + obj.c.push(5); + assert.deepEqual(res.c, [ 3, 4 ]); +}; + +exports.reduce = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + var res = Traverse(obj).reduce(function (acc, x) { + if (this.isLeaf) acc.push(x); + return acc; + }, []); + assert.deepEqual(obj, { a : 1, b : 2, c : [ 3, 4 ] }); + assert.deepEqual(res, [ 1, 2, 3, 4 ]); +}; + +exports.reduceInit = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + var res = Traverse(obj).reduce(function (acc, x) { + if (this.isRoot) assert.fail('got root'); + return acc; + }); + assert.deepEqual(obj, { a : 1, b : 2, c : [ 3, 4 ] }); + assert.deepEqual(res, obj); +}; + +exports.remove = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + Traverse(obj).forEach(function (x) { + if (this.isLeaf && x % 2 == 0) this.remove(); + }); + + assert.deepEqual(obj, { a : 1, c : [ 3 ] }); +}; + +exports.removeMap = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + var res = Traverse(obj).map(function (x) { + if (this.isLeaf && x % 2 == 0) this.remove(); + }); + + assert.deepEqual(obj, { a : 1, b : 2, c : [ 3, 4 ] }); + assert.deepEqual(res, { a : 1, c : [ 3 ] }); +}; + +exports.delete = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + Traverse(obj).forEach(function (x) { + if (this.isLeaf && x % 2 == 0) this.delete(); + }); + + assert.ok(!deepEqual( + obj, { a : 1, c : [ 3, undefined ] } + )); + + assert.ok(deepEqual( + obj, { a : 1, c : [ 3 ] } + )); + + assert.ok(!deepEqual( + obj, { a : 1, c : [ 3, null ] } + )); +}; + +exports.deleteRedux = function () { + var obj = { a : 1, b : 2, c : [ 3, 4, 5 ] }; + Traverse(obj).forEach(function (x) { + if (this.isLeaf && x % 2 == 0) this.delete(); + }); + + assert.ok(!deepEqual( + obj, { a : 1, c : [ 3, undefined, 5 ] } + )); + + assert.ok(deepEqual( + obj, { a : 1, c : [ 3 ,, 5 ] } + )); + + assert.ok(!deepEqual( + obj, { a : 1, c : [ 3, null, 5 ] } + )); + + assert.ok(!deepEqual( + obj, { a : 1, c : [ 3, 5 ] } + )); +}; + +exports.deleteMap = function () { + var obj = { a : 1, b : 2, c : [ 3, 4 ] }; + var res = Traverse(obj).map(function (x) { + if (this.isLeaf && x % 2 == 0) this.delete(); + }); + + assert.ok(deepEqual( + obj, + { a : 1, b : 2, c : [ 3, 4 ] } + )); + + var xs = [ 3, 4 ]; + delete xs[1]; + + assert.ok(deepEqual( + res, { a : 1, c : xs } + )); + + assert.ok(deepEqual( + res, { a : 1, c : [ 3, ] } + )); + + assert.ok(deepEqual( + res, { a : 1, c : [ 3 ] } + )); +}; + +exports.deleteMapRedux = function () { + var obj = { a : 1, b : 2, c : [ 3, 4, 5 ] }; + var res = Traverse(obj).map(function (x) { + if (this.isLeaf && x % 2 == 0) this.delete(); + }); + + assert.ok(deepEqual( + obj, + { a : 1, b : 2, c : [ 3, 4, 5 ] } + )); + + var xs = [ 3, 4, 5 ]; + delete xs[1]; + + assert.ok(deepEqual( + res, { a : 1, c : xs } + )); + + assert.ok(!deepEqual( + res, { a : 1, c : [ 3, 5 ] } + )); + + assert.ok(deepEqual( + res, { a : 1, c : [ 3 ,, 5 ] } + )); +}; diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/negative.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/negative.js new file mode 100644 index 0000000..f92dfb0 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/negative.js @@ -0,0 +1,20 @@ +var Traverse = require('../'); +var assert = require('assert'); + +exports['negative update test'] = function () { + var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; + var fixed = Traverse.map(obj, function (x) { + if (x < 0) this.update(x + 128); + }); + + assert.deepEqual(fixed, + [ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ], + 'Negative values += 128' + ); + + assert.deepEqual(obj, + [ 5, 6, -3, [ 7, 8, -2, 1 ], { f: 10, g: -13 } ], + 'Original references not modified' + ); +} + diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/obj.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/obj.js new file mode 100644 index 0000000..d46fd38 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/obj.js @@ -0,0 +1,15 @@ +var assert = require('assert'); +var Traverse = require('../'); + +exports['traverse an object with nested functions'] = function () { + var to = setTimeout(function () { + assert.fail('never ran'); + }, 1000); + + function Cons (x) { + clearTimeout(to); + assert.equal(x, 10); + }; + Traverse(new Cons(10)); +}; + diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/siblings.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/siblings.js new file mode 100644 index 0000000..99c0f1b --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/siblings.js @@ -0,0 +1,35 @@ +var assert = require('assert'); +var traverse = require('../'); + +exports.siblings = function () { + var obj = { a : 1, b : 2, c : [ 4, 5, 6 ] }; + + var res = traverse(obj).reduce(function (acc, x) { + var p = '/' + this.path.join('/'); + if (this.parent) { + acc[p] = { + siblings : this.parent.keys, + key : this.key, + index : this.parent.keys.indexOf(this.key) + }; + } + else { + acc[p] = { + siblings : [], + key : this.key, + index : -1 + } + } + return acc; + }, {}); + + assert.deepEqual(res, { + '/' : { siblings : [], key : undefined, index : -1 }, + '/a' : { siblings : [ 'a', 'b', 'c' ], key : 'a', index : 0 }, + '/b' : { siblings : [ 'a', 'b', 'c' ], key : 'b', index : 1 }, + '/c' : { siblings : [ 'a', 'b', 'c' ], key : 'c', index : 2 }, + '/c/0' : { siblings : [ '0', '1', '2' ], key : '0', index : 0 }, + '/c/1' : { siblings : [ '0', '1', '2' ], key : '1', index : 1 }, + '/c/2' : { siblings : [ '0', '1', '2' ], key : '2', index : 2 } + }); +}; diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/stop.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/stop.js new file mode 100644 index 0000000..3529847 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/stop.js @@ -0,0 +1,41 @@ +var assert = require('assert'); +var traverse = require('../'); + +exports.stop = function () { + var visits = 0; + traverse('abcdefghij'.split('')).forEach(function (node) { + if (typeof node === 'string') { + visits ++; + if (node === 'e') this.stop() + } + }); + + assert.equal(visits, 5); +}; + +exports.stopMap = function () { + var s = traverse('abcdefghij'.split('')).map(function (node) { + if (typeof node === 'string') { + if (node === 'e') this.stop() + return node.toUpperCase(); + } + }).join(''); + + assert.equal(s, 'ABCDEfghij'); +}; + +exports.stopReduce = function () { + var obj = { + a : [ 4, 5 ], + b : [ 6, [ 7, 8, 9 ] ] + }; + var xs = traverse(obj).reduce(function (acc, node) { + if (this.isLeaf) { + if (node === 7) this.stop(); + else acc.push(node) + } + return acc; + }, []); + + assert.deepEqual(xs, [ 4, 5, 6 ]); +}; diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/stringify.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/stringify.js new file mode 100644 index 0000000..932f5d3 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/stringify.js @@ -0,0 +1,36 @@ +var assert = require('assert'); +var Traverse = require('../'); + +exports.stringify = function () { + var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; + + var s = ''; + Traverse(obj).forEach(function (node) { + if (Array.isArray(node)) { + this.before(function () { s += '[' }); + this.post(function (child) { + if (!child.isLast) s += ','; + }); + this.after(function () { s += ']' }); + } + else if (typeof node == 'object') { + this.before(function () { s += '{' }); + this.pre(function (x, key) { + s += '"' + key + '"' + ':'; + }); + this.post(function (child) { + if (!child.isLast) s += ','; + }); + this.after(function () { s += '}' }); + } + else if (typeof node == 'function') { + s += 'null'; + } + else { + s += node.toString(); + } + }); + + assert.equal(s, JSON.stringify(obj)); +} + diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/subexpr.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/subexpr.js new file mode 100644 index 0000000..a217beb --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/subexpr.js @@ -0,0 +1,34 @@ +var traverse = require('../'); +var assert = require('assert'); + +exports.subexpr = function () { + var obj = [ 'a', 4, 'b', 5, 'c', 6 ]; + var r = traverse(obj).map(function (x) { + if (typeof x === 'number') { + this.update([ x - 0.1, x, x + 0.1 ], true); + } + }); + + assert.deepEqual(obj, [ 'a', 4, 'b', 5, 'c', 6 ]); + assert.deepEqual(r, [ + 'a', [ 3.9, 4, 4.1 ], + 'b', [ 4.9, 5, 5.1 ], + 'c', [ 5.9, 6, 6.1 ], + ]); +}; + +exports.block = function () { + var obj = [ [ 1 ], [ 2 ], [ 3 ] ]; + var r = traverse(obj).map(function (x) { + if (Array.isArray(x) && !this.isRoot) { + if (x[0] === 5) this.block() + else this.update([ [ x[0] + 1 ] ]) + } + }); + + assert.deepEqual(r, [ + [ [ [ [ [ 5 ] ] ] ] ], + [ [ [ [ 5 ] ] ] ], + [ [ [ 5 ] ] ], + ]); +}; diff --git a/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/super_deep.js b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/super_deep.js new file mode 100644 index 0000000..acac2fd --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/node_modules/traverse/test/super_deep.js @@ -0,0 +1,55 @@ +var assert = require('assert'); +var traverse = require('../'); +var deepEqual = require('./lib/deep_equal'); + +exports.super_deep = function () { + var util = require('util'); + var a0 = make(); + var a1 = make(); + assert.ok(deepEqual(a0, a1)); + + a0.c.d.moo = true; + assert.ok(!deepEqual(a0, a1)); + + a1.c.d.moo = true; + assert.ok(deepEqual(a0, a1)); + + // TODO: this one + //a0.c.a = a1; + //assert.ok(!deepEqual(a0, a1)); +}; + +function make () { + var a = { self : 'a' }; + var b = { self : 'b' }; + var c = { self : 'c' }; + var d = { self : 'd' }; + var e = { self : 'e' }; + + a.a = a; + a.b = b; + a.c = c; + + b.a = a; + b.b = b; + b.c = c; + + c.a = a; + c.b = b; + c.c = c; + c.d = d; + + d.a = a; + d.b = b; + d.c = c; + d.d = d; + d.e = e; + + e.a = a; + e.b = b; + e.c = c; + e.d = d; + e.e = e; + + return a; +} diff --git a/node_modules/mysql/node_modules/hashish/package.json b/node_modules/mysql/node_modules/hashish/package.json new file mode 100644 index 0000000..33c7f22 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/package.json @@ -0,0 +1,33 @@ +{ + "name" : "hashish", + "version" : "0.0.4", + "description" : "Hash data structure manipulation functions", + "main" : "./index.js", + "repository" : { + "type" : "git", + "url" : "http://github.com/substack/node-hashish.git" + }, + "keywords": [ + "hash", + "object", + "convenience", + "manipulation", + "data structure" + ], + "author" : { + "name" : "James Halliday", + "email" : "mail@substack.net", + "url" : "http://substack.net" + }, + "dependencies" : { + "traverse" : ">=0.2.4" + }, + "devDependencies" : { + "expresso" : ">=0.6.0" + }, + "scripts" : { + "test" : "expresso" + }, + "license" : "MIT/X11", + "engine" : ["node >=0.2.0"] +} diff --git a/node_modules/mysql/node_modules/hashish/test/hash.js b/node_modules/mysql/node_modules/hashish/test/hash.js new file mode 100644 index 0000000..6afce60 --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/test/hash.js @@ -0,0 +1,250 @@ +var Hash = require('hashish'); +var assert = require('assert'); + +exports.map = function () { + var ref = { a : 1, b : 2 }; + var items = Hash(ref).map(function (v) { return v + 1 }).items; + var hash = Hash.map(ref, function (v) { return v + 1 }); + assert.deepEqual(ref, { a : 1, b : 2 }); + assert.deepEqual(items, { a : 2, b : 3 }); + assert.deepEqual(hash, { a : 2, b : 3 }); +}; + +exports['cloned map'] = function () { + var ref = { foo : [1,2], bar : [4,5] }; + var hash = Hash(ref).clone.map( + function (v) { v.unshift(v[0] - 1); return v } + ).items; + assert.deepEqual(ref.foo, [1,2]); + assert.deepEqual(ref.bar, [4,5]); + assert.deepEqual(hash.foo, [0,1,2]); + assert.deepEqual(hash.bar, [3,4,5]); +}; + +exports.forEach = function () { + var ref = { a : 5, b : 2, c : 7, 1337 : 'leet' }; + var xs = []; + Hash(ref).forEach(function (x, i) { + xs.push([ i, x ]); + }); + + assert.eql( + xs.map(function (x) { return x[0] }).sort(), + [ '1337', 'a', 'b', 'c' ] + ); + + assert.eql( + xs.map(function (x) { return x[1] }).sort(), + [ 2, 5, 7, 'leet' ] + ); + + var ys = []; + Hash.forEach(ref, function (x, i) { + ys.push([ i, x ]); + }); + + assert.eql(xs.sort(), ys.sort()); +}; + +exports.filter_items = function () { + var ref = { a : 5, b : 2, c : 7, 1337 : 'leet' }; + var items = Hash(ref).filter(function (v, k) { + return v > 5 || k > 5 + }).items; + var hash = Hash.filter(ref, function (v, k) { return v > 5 || k > 5 }); + assert.deepEqual(items, { 1337 : 'leet', c : 7 }); + assert.deepEqual(hash, { 1337 : 'leet', c : 7 }); + assert.deepEqual(ref, { a : 5, b : 2, c : 7, 1337 : 'leet' }); + assert.equal(Hash(ref).length, 4); +}; + +exports.detect = function () { + var h = { a : 5, b : 6, c : 7, d : 8 }; + var hh = Hash(h); + var gt6hh = hh.detect(function (x) { return x > 6 }); + assert.ok(gt6hh == 7 || gt6hh == 8); + var gt6h = Hash.detect(h, function (x) { return x > 6 }); + assert.ok(gt6h == 7 || gt6h == 8); + assert.equal(hh.detect(function (x) { return x > 100 }), undefined); +}; + +exports.reduce = function () { + var ref = { foo : [1,2], bar : [4,5] }; + + var sum1 = Hash(ref).reduce(function (acc, v) { + return acc + v.length + }, 0); + assert.equal(sum1, 4); + + var sum2 = Hash.reduce(ref, function (acc, v) { + return acc + v.length + }, 0); + assert.equal(sum2, 4); +}; + +exports.some = function () { + var h = { a : 5, b : 6, c : 7, d : 8 }; + var hh = Hash(h); + assert.ok(Hash.some(h, function (x) { return x > 7 })); + assert.ok(Hash.some(h, function (x) { return x < 6 })); + assert.ok(!Hash.some(h, function (x) { return x > 10 })); + assert.ok(!Hash.some(h, function (x) { return x < 0 })); + + assert.ok(hh.some(function (x) { return x > 7 })); + assert.ok(hh.some(function (x) { return x < 6 })); + assert.ok(!hh.some(function (x) { return x > 10 })); + assert.ok(!hh.some(function (x) { return x < 0 })); +}; + +exports.update = function () { + var ref = { a : 1, b : 2 }; + var items = Hash(ref).clone.update({ c : 3, a : 0 }).items; + assert.deepEqual(ref, { a : 1, b : 2 }); + assert.deepEqual(items, { a : 0, b : 2, c : 3 }); + + var hash = Hash.update(ref, { c : 3, a : 0 }); + assert.deepEqual(ref, hash); + assert.deepEqual(hash, { a : 0, b : 2, c : 3 }); + + var ref2 = {a: 1}; + var hash2 = Hash.update(ref2, { b: 2, c: 3 }, undefined, { d: 4 }); + assert.deepEqual(ref2, { a: 1, b: 2, c: 3, d: 4 }); +}; + +exports.merge = function () { + var ref = { a : 1, b : 2 }; + var items = Hash(ref).merge({ b : 3, c : 3.14 }).items; + var hash = Hash.merge(ref, { b : 3, c : 3.14 }); + + assert.deepEqual(ref, { a : 1, b : 2 }); + assert.deepEqual(items, { a : 1, b : 3, c : 3.14 }); + assert.deepEqual(hash, { a : 1, b : 3, c : 3.14 }); + + var ref2 = { a : 1 }; + var hash2 = Hash.merge(ref, { b: 2, c: 3 }, undefined, { d: 4 }); + assert.deepEqual(hash2, { a: 1, b: 2, c: 3, d: 4 }); +}; + +exports.has = function () { + var h = { a : 4, b : 5 }; + var hh = Hash(h); + + assert.ok(hh.has('a')); + assert.equal(hh.has('c'), false); + assert.ok(hh.has(['a','b'])); + assert.equal(hh.has(['a','b','c']), false); + + assert.ok(Hash.has(h, 'a')); + assert.equal(Hash.has(h, 'c'), false); + assert.ok(Hash.has(h, ['a','b'])); + assert.equal(Hash.has(h, ['a','b','c']), false); +}; + +exports.valuesAt = function () { + var h = { a : 4, b : 5, c : 6 }; + assert.equal(Hash(h).valuesAt('a'), 4); + assert.equal(Hash(h).valuesAt(['a'])[0], 4); + assert.deepEqual(Hash(h).valuesAt(['a','b']), [4,5]); + assert.equal(Hash.valuesAt(h, 'a'), 4); + assert.deepEqual(Hash.valuesAt(h, ['a']), [4]); + assert.deepEqual(Hash.valuesAt(h, ['a','b']), [4,5]); +}; + +exports.tap = function () { + var h = { a : 4, b : 5, c : 6 }; + var hh = Hash(h); + hh.tap(function (x) { + assert.ok(this === hh) + assert.eql(x, h); + }); + + Hash.tap(h, function (x) { + assert.eql( + Object.keys(this).sort(), + Object.keys(hh).sort() + ); + assert.eql(x, h); + }); +}; + +exports.extract = function () { + var hash = Hash({ a : 1, b : 2, c : 3 }).clone; + var extracted = hash.extract(['a','b']); + assert.equal(extracted.length, 2); + assert.deepEqual(extracted.items, { a : 1, b : 2 }); +}; + +exports.exclude = function () { + var hash = Hash({ a : 1, b : 2, c : 3 }).clone; + var extracted = hash.exclude(['a','b']); + assert.equal(extracted.length, 1); + assert.deepEqual(extracted.items, { c : 3 }); +}; + +exports.concat = function () { + var ref1 = { a : 1, b : 2 }; + var ref2 = { foo : 100, bar : 200 }; + var ref3 = { b : 3, c : 4, bar : 300 }; + + assert.deepEqual( + Hash.concat([ ref1, ref2 ]), + { a : 1, b : 2, foo : 100, bar : 200 } + ); + + assert.deepEqual( + Hash.concat([ ref1, ref2, ref3 ]), + { a : 1, b : 3, c : 4, foo : 100, bar : 300 } + ); +}; + +exports.zip = function () { + var xs = ['a','b','c']; + var ys = [1,2,3,4]; + var h = Hash(xs,ys); + assert.equal(h.length, 3); + assert.deepEqual(h.items, { a : 1, b : 2, c : 3 }); + + var zipped = Hash.zip(xs,ys); + assert.deepEqual(zipped, { a : 1, b : 2, c : 3 }); +}; + +exports.length = function () { + assert.equal(Hash({ a : 1, b : [2,3], c : 4 }).length, 3); + assert.equal(Hash({ a : 1, b : [2,3], c : 4 }).size, 3); + assert.equal(Hash.size({ a : 1, b : [2,3], c : 4 }), 3); +}; + +exports.compact = function () { + var hash = { + a : 1, + b : undefined, + c : false, + d : 4, + e : [ undefined, 4 ], + f : null + }; + var compacted = Hash(hash).compact; + assert.deepEqual( + { + a : 1, + b : undefined, + c : false, + d : 4, + e : [ undefined, 4 ], + f : null + }, + hash, 'compact modified the hash' + ); + assert.deepEqual( + compacted.items, + { + a : 1, + c : false, + d : 4, + e : [ undefined, 4 ], + f : null + } + ); + var h = Hash.compact(hash); + assert.deepEqual(h, compacted.items); +}; diff --git a/node_modules/mysql/node_modules/hashish/test/property.js b/node_modules/mysql/node_modules/hashish/test/property.js new file mode 100644 index 0000000..1183c5d --- /dev/null +++ b/node_modules/mysql/node_modules/hashish/test/property.js @@ -0,0 +1,69 @@ +var Hash = require('hashish'); +var assert = require('assert'); +var vm = require('vm'); +var fs = require('fs'); + +var src = fs.readFileSync(__dirname + '/../index.js', 'utf8'); + +exports.defineGetter = function () { + var context = { + module : { exports : {} }, + Object : { + keys : Object.keys, + defineProperty : undefined, + }, + require : require, + }; + context.exports = context.module.exports; + + vm.runInNewContext('(function () {' + src + '})()', context); + var Hash_ = context.module.exports; + + var times = 0; + Hash_.__proto__.__proto__.__defineGetter__ = function () { + times ++; + return Object.__defineGetter__.apply(this, arguments); + }; + + assert.equal(vm.runInNewContext('Object.defineProperty', context), null); + + assert.deepEqual( + Hash_({ a : 1, b : 2, c : 3 }).values, + [ 1, 2, 3 ] + ); + + assert.ok(times > 5); +}; + +exports.defineProperty = function () { + var times = 0; + var context = { + module : { exports : {} }, + Object : { + keys : Object.keys, + defineProperty : function (prop) { + times ++; + if (prop.get) throw new TypeError('engine does not support') + assert.fail('should have asserted by now'); + }, + }, + require : require + }; + context.exports = context.module.exports; + + vm.runInNewContext('(function () {' + src + '})()', context); + var Hash_ = context.module.exports; + + Hash_.__proto__.__proto__.__defineGetter__ = function () { + assert.fail('getter called when a perfectly good' + + ' defineProperty was available' + ); + }; + + assert.deepEqual( + Hash_({ a : 1, b : 2, c : 3 }).values, + [ 1, 2, 3 ] + ); + + assert.equal(times, 1); +}; diff --git a/node_modules/mysql/package.json b/node_modules/mysql/package.json new file mode 100644 index 0000000..a17a5ad --- /dev/null +++ b/node_modules/mysql/package.json @@ -0,0 +1,26 @@ +{ + "name": "mysql", + "version": "0.9.3", + "author": "Felix Geisendörfer (http://debuggable.com/)", + "description": "A pure node.js JavaScript Client implementing the MySQL protocol.", + "homepage": "https://github.com/felixge/node-mysql", + "repository": { + "type": "git", + "url": "git://github.com/felixge/node-mysql.git" + }, + "main": "./index", + "scripts": { + "test": "make test" + }, + "dependencies": { + "hashish": "0.0.4" + }, + "devDependencies": { + "gently": "0.8.0", + "far": "0.0.6", + "fast-or-slow": "0.0.5" + }, + "engines": { + "node": "*" + } +} \ No newline at end of file diff --git a/node_modules/mysql/test/.common.js.un~ b/node_modules/mysql/test/.common.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..e95d8db147c20d15c4ab62c379783a3350e92005 GIT binary patch literal 22818 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 literal 0 HcmV?d00001 diff --git a/node_modules/mysql/test/fast/.test-client.js.un~ b/node_modules/mysql/test/fast/.test-client.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..cd0acf51be104591fc45c8e39294af881e362e72 GIT binary patch literal 13604 zcmeI3&5smC7{+_QToDl$Ma2bD;lh%@&PKDC1tBpKjvKQ^B#Bk;6|KL@hBz;mO+Ch0p(9*nSj6(c7jlW=&(p zl#{LlHA}R)RsVDz-!4Y=@7w`6fq}1H<%g#x?4{Td>gTM$=GJFFS{zaI=Ue95N96Tw z&ywkR&GiD#Om4diM(D!V|LKj^A6mlrb`D3l0Bzjn1$+*Kp+bcylr+~sn_TX&Z3zD? z36tmR<^Z5kxz6&H(=DAf(@sC{B=PC9sy&FCXs(=5_Z>!Hn>U34q{YnxM#@sME|het zj>GuJG>q>JF>dK*634okt5%{j6(_mMchY26HDaaHG)dKXx}dor#tzcOm;zm)Oqph( zq*HYq-6zxNuJ5P2o20igwcE*el{YN|da9Fg>-HW=5G1o{<)nLj)u*iU9x@E^ILdL_(P| zO%Fu%S?MIEGDnGEPr?d#%s~O_06x0_#NaKeQMHCe_<%us%;T*-Hw|2EC(rxYg<5Uf zJkSO=SDQ(%*4Ew5-ECcqla@Z$yO-VW);d`>&{=Kcyt5-Hz9a?@!j?Mvf*pl2Wtu)z z7bI1jK>6i^4Ok9}5dayEwGl8;iIR0GOqem{{0Jm3iva-FE2h{tGXarMrcBcZ(Lw2? zL*_1rP2q#>lrpQhPPW?Yc66Mtwv)8i$XCpicvkfrX``2&x#*@ufWz4gKn)l6!e(*{9H)zo1r z2N9}-54C0a$ioRBMrt${-?(rvK!#)Sr^A2=B2)<zmnD0!nD205A`T8SVpIwrOz%jC5fL$&ywNSf>pP9O)zu$0 znzwX5%KK?O4igqbu_;MNKPXGd+K1n}k{@v#GdCPJL)r(I%Rzt%R%3vDKu0yI);{Pq zrlDI>s#a4Um^}^gx#3m@$BiE42#e_w9l>&xrDW~H?Xu(s%fN0ZSS=q>3ORq@PLw9+ zzyIK(=^d^Ph>rGTvI2zYW5A{;Vf9T#s?3EGE}rN~1=V@F95B5}Y3yjq=NM6IhnTNPr9%x3mK$p-h>k52j6NG-m&h zADAu;_kCUK^mH=FRa)%sdzSrQV0v5(AG`x&AxNdB594do7@wcSI5Ar`M|=AwY}^FQ z6XFK|G=^k1-vc literal 0 HcmV?d00001 diff --git a/node_modules/mysql/test/fast/test-client.js b/node_modules/mysql/test/fast/test-client.js new file mode 100644 index 0000000..a8e868e --- /dev/null +++ b/node_modules/mysql/test/fast/test-client.js @@ -0,0 +1,26 @@ +var common = require('../common'); +var assert = require('assert'); +var test = common.fastOrSlow.fast(); +var Client = require(common.dir.lib + '/client'); + +var client; +test.before(function() { + client = new Client(); +}); + +test('#format() does not manipulate params parameter', function() { + var sql = '?'; + var params = [1]; + + client.format(sql, params); + assert.equal(params.length, 1); +}); + +// https://github.com/felixge/node-mysql/issues/96 +test('Timeout reconnect works with empty queue', function() { + // A non-error packet + var packet = {}; + + // This must not throw an error + client._handlePacket(packet); +}); diff --git a/node_modules/mysql/test/fixture/.column_order.sql.un~ b/node_modules/mysql/test/fixture/.column_order.sql.un~ new file mode 100644 index 0000000000000000000000000000000000000000..07203869ceb9d35ddc581dda922a16d05771df09 GIT binary patch literal 4070 zcmeI#J4*vW5C`xzFHIvs5Y&KPBiN+VSVwb0;56Y9AHl*j78aVqd;uG=&j+xvveU{! z!H*!=s@RA&0h=^7asHE?%W?#4a#lOAnS1A$A9J_2b98*UeNt?GsMywhuAaG?TK;*x zIN!}ZwC20T{m0C6^RAOxyiJ#Glu~&b)9b!lsJTw9u;#f=qjh-NYB)=@V~obQ&S}aB zWEsk9XH^16CDp+b_EN<9iGQ&RgQG{G;<9G*=qup0XP22nsqT!v{3>N82)4-o^466z zhQqQ+14Nw3!EgbiY_)lG6(G1g!^Qe==t?QS$pn^!@wXrgU@VhSnMfAB_S{Rjzd!;m zr8@~ENv!JtmnD*FM4pN0EleckH#-R|DdTQHCdVn;Nk(NNStO?SFq6Dr%qzU zwjQbwWsqQx1(O3oX)-Vj{~9ptCiLCGO}-A;(%MDohHH~uXV_yC6A;)f$d{bESt +#include +#include + +#define SCRAMBLE_LENGTH_323 8 + +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned char uchar; + +struct rand_struct { + unsigned long seed1,seed2,max_value; + double max_value_dbl; +}; + +void hash_password(ulong *result, const char *password, uint password_len) +{ + register ulong nr=1345345333L, add=7, nr2=0x12345671L; + ulong tmp; + const char *password_end= password + password_len; + for (; password < password_end; password++) + { + if (*password == ' ' || *password == '\t') + continue; /* skip space in password */ + tmp= (ulong) (uchar) *password; + nr^= (((nr & 63)+add)*tmp)+ (nr << 8); + nr2+=(nr2 << 8) ^ nr; + add+=tmp; + } + result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */; + result[1]=nr2 & (((ulong) 1L << 31) -1L); +} + +void randominit(struct rand_struct *rand_st, ulong seed1, ulong seed2) +{ /* For mysql 3.21.# */ +#ifdef HAVE_purify + bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */ +#endif + rand_st->max_value= 0x3FFFFFFFL; + rand_st->max_value_dbl=(double) rand_st->max_value; + rand_st->seed1=seed1%rand_st->max_value ; + rand_st->seed2=seed2%rand_st->max_value; +} + +double my_rnd(struct rand_struct *rand_st) +{ + rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value; + rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value; + return (((double) rand_st->seed1)/rand_st->max_value_dbl); +} + +void scramble_323(char *to, const char *message, const char *password) +{ + struct rand_struct rand_st; + ulong hash_pass[2], hash_message[2]; + + if (password && password[0]) + { + char extra, *to_start=to; + const char *message_end= message + SCRAMBLE_LENGTH_323; + hash_password(hash_pass,password, (uint) strlen(password)); + hash_password(hash_message, message, SCRAMBLE_LENGTH_323); + randominit(&rand_st,hash_pass[0] ^ hash_message[0], + hash_pass[1] ^ hash_message[1]); + for (; message < message_end; message++) + *to++= (char) (floor(my_rnd(&rand_st)*31)+64); + extra=(char) (floor(my_rnd(&rand_st)*31)); + while (to_start != to) + *(to_start++)^=extra; + } + *to= 0; +} + +int main() { + const char password1[] = "root"; + const char password2[] = "long password test"; + const char password3[] = "saf789yasfbsd89f"; + ulong result[2]; + char scrm[9]; // SCRAMBLE_LENGTH_323+1 + struct rand_struct rand_st; + int i; + + // test hash_password + hash_password((ulong*)result, password1, strlen(password1)); + printf("hash_password(\"%s\") = %08x%08x\n", password1, result[0], result[1]); + + hash_password((ulong*)result, password2, strlen(password2)); + printf("hash_password(\"%s\") = %08x%08x\n", password2, result[0], result[1]); + + hash_password((ulong*)result, password3, strlen(password3)); + printf("hash_password(\"%s\") = %08x%08x\n", password3, result[0], result[1]); + + + // test randominit + randominit(&rand_st, 0, 0); + printf("randominit(0x00000000,0x00000000) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + + randominit(&rand_st, 0xFFFF, 0xFFFF); + printf("randominit(0x0000FFFF,0x0000FFFF) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + + randominit(&rand_st, 0x50000000, 0x50000000); + printf("randominit(0x50000000,0x50000000) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + + randominit(&rand_st, 0xFFFFFFFF, 0xFFFFFFFF); + printf("randominit(0xFFFFFFFF,0xFFFFFFFF) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + + + // test my_rnd + randominit(&rand_st, 3252345, 7149734); + printf("randominit(3252345, 7149734) = %08x, %08x\n", rand_st.seed1, rand_st.seed2); + for (i=0; i<10; i++){ + printf("my_rnd() : %.16f\n", my_rnd(&rand_st)); + } + + + // test scramble_323 + scramble_323(scrm, "8bytesofstuff", "root"); + printf("scramble323(8bytesofstuff, root): %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + scrm[0], scrm[1], scrm[2], scrm[3], scrm[4], scrm[5], scrm[6], scrm[7], scrm[8]); + + scramble_323(scrm, "e8cf00cec9ec825af22", "saf789yasfbsd"); + printf("scramble323(e8cf00cec9ec825af22, saf789yasfbsd): %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + scrm[0], scrm[1], scrm[2], scrm[3], scrm[4], scrm[5], scrm[6], scrm[7], scrm[8]); + + return 23; +} + diff --git a/node_modules/mysql/test/legacy/.common.js.un~ b/node_modules/mysql/test/legacy/.common.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..ead60baac846ac2563255c8403967f5cda88460e GIT binary patch literal 7278 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 literal 0 HcmV?d00001 diff --git a/node_modules/mysql/test/legacy/simple/test-auth.js b/node_modules/mysql/test/legacy/simple/test-auth.js new file mode 100644 index 0000000..f1c2ec6 --- /dev/null +++ b/node_modules/mysql/test/legacy/simple/test-auth.js @@ -0,0 +1,118 @@ +var common = require('../common'); +var auth = require(common.dir.lib + '/auth'); + +function test(test) { + gently = new Gently(); + test(); + gently.verify(test.name); +} + +test(function sha1() { + assert.deepEqual( + auth.sha1('root'), + new Buffer([ + 220, 118, 233, 240, 192, + 0, 110, 143, 145, 158, + 12, 81, 92, 102, 219, + 186, 57, 130, 247, 133 + ]).toString('binary') + ); +}); + +test(function xor() { + var a = new Buffer([170, 220]), // 10101010 11011100 + b = new Buffer([220, 170]), // 11011100 10101010 + expected = new Buffer([118, 118]); // 01110110 01110110 + + assert.deepEqual(auth.xor(a.toString('binary'), b.toString('binary')), expected); +}); + +test(function token() { + var SCRAMBLE = new Buffer([0, 1, 2, 3, 4, 5]); + + (function testRegular() { + var PASS = 'root', + STAGE_1 = auth.sha1(PASS), + TOKEN = auth.xor( + auth.sha1(new Buffer(SCRAMBLE + auth.sha1(STAGE_1), 'binary')), + STAGE_1 + ); + + assert.deepEqual(auth.token('root', SCRAMBLE), TOKEN); + })(); + + (function testNoPassword() { + assert.deepEqual(auth.token(null, SCRAMBLE), new Buffer(0)); + })(); +}); + +test(function hashPassword() { + function verify(password, bytes){ + var expected = new Buffer(bytes); + var actual = auth.hashPassword(password); + + assert.deepEqual(actual, expected); + } + + verify('root', [0x67, 0x45, 0x7E, 0x22, 0x6a, 0x1a, 0x15, 0xbd]); + verify('long password test', [0x6c, 0x24, 0x68, 0x41, 0x2c, 0xa6, 0x86, 0x56]); + verify('saf789yasfbsd89f', [0x6c, 0x9b, 0x2f, 0x07, 0x17, 0xeb, 0x95, 0xc6]); +}); + + +test(function randomInit() { + function verify(in1, in2, out1, out2){ + var r = auth.randomInit(in1, in2); + assert.equal(out1, r.seed1); + assert.equal(out2, r.seed2); + } + + verify(0x00000000, 0x00000000, 0x00000000, 0x00000000); + verify(0x0000FFFF, 0x0000FFFF, 0x0000ffff, 0x0000ffff); + verify(0x50000000, 0x50000000, 0x10000001, 0x10000001); + verify(0xFFFFFFFF, 0xFFFFFFFF, 0x00000003, 0x00000003); + verify(3252345, 7149734, 0x0031a079, 0x006d18a6); +}); + +test(function myRnd() { + function verifySequence(seed1, seed2, expected){ + var r = auth.randomInit(seed1, seed2); + for (var i = 0; i < expected.length; i++){ + var n = auth.myRnd(r); + + // we will test to 14 digits, since + // we only ever use this function mutliplied + // by small numbers anyway + + var a = ':'+n; + var b = ':'+expected[i]; + + assert.equal(a.substr(1, 16), b.substr(1, 16)); + } + } + + verifySequence(3252345, 7149734, [ + 0.0157456556481734, + 0.0696413620092360, + 0.3009698738353047, + 0.2959253138824602, + 0.5767169786400320, + 0.9958089822864243, + 0.2488940062456708, + 0.2570431151027261, + 0.5385335875102631, + 0.9215386229767824, + ]); +}); + +test(function scramble323() { + function verify(message, password, bytes){ + var expected = new Buffer(bytes); + var actual = auth.scramble323(new Buffer(message), password); + + assert.deepEqual(actual, expected); + } + + verify('8bytesofstuff', 'root', [0x5a, 0x4d, 0x46, 0x47, 0x43, 0x53, 0x58, 0x5f]); + verify('e8cf00cec9ec825af22', 'saf789yasfbsd', [0x4d, 0x54, 0x5b, 0x47, 0x5f, 0x52, 0x4d, 0x45]); +}); diff --git a/node_modules/mysql/test/legacy/simple/test-client.js b/node_modules/mysql/test/legacy/simple/test-client.js new file mode 100644 index 0000000..073c38c --- /dev/null +++ b/node_modules/mysql/test/legacy/simple/test-client.js @@ -0,0 +1,95 @@ +var common = require('../common'); +var Parser = require(common.dir.lib + '/parser'); +var constants = require(common.dir.lib + '/constants'); +var Client = require(common.dir.lib + '/client'); + +function test(test) { + client = new Client(); + gently = new Gently(); + test(); + gently.verify(test.name); +}; + +test(function write() { + var PACKET = {buffer: []}, + CONNECTION = client._socket = {}; + + gently.expect(CONNECTION, 'write', function(buffer) { + assert.strictEqual(buffer, PACKET.buffer); + }); + + client.write(PACKET); +}); + +test(function format() { + var sql = client.format('? + ? = ?', [1, 2, 'great']); + assert.equal(sql, '1 + 2 = \'great\''); + + assert.throws(function() { + var sql = client.format('? + ? = ?', [1, 2]); + }); + + assert.throws(function() { + var sql = client.format('? + ? = ?', [1, 2, 3, 4]); + }); +}); + +test(function escape() { + assert.equal(client.escape(undefined), 'NULL'); + assert.equal(client.escape(null), 'NULL'); + assert.equal(client.escape(false), 'false'); + assert.equal(client.escape(true), 'true'); + assert.equal(client.escape(5), '5'); + assert.equal(client.escape({foo:'bar'}), "'[object Object]'"); + assert.equal(client.escape([1,2,3]), "'1,2,3'"); + assert.equal(client.escape(new Date(Date.UTC(2011,6,6,6,6,6,6))), "'2011-07-06T06:06:06.006Z'"); + + assert.equal(client.escape('Super'), "'Super'"); + assert.equal(client.escape('Sup\0er'), "'Sup\\0er'"); + assert.equal(client.escape('Sup\ber'), "'Sup\\ber'"); + assert.equal(client.escape('Sup\ner'), "'Sup\\ner'"); + assert.equal(client.escape('Sup\rer'), "'Sup\\rer'"); + assert.equal(client.escape('Sup\ter'), "'Sup\\ter'"); + assert.equal(client.escape('Sup\\er'), "'Sup\\\\er'"); + assert.equal(client.escape('Sup\u001aer'), "'Sup\\Zer'"); + assert.equal(client.escape('Sup\'er'), "'Sup\\'er'"); + assert.equal(client.escape('Sup"er'), "'Sup\\\"er'"); +}); + +test(function _packetToUserObject() { + (function testOkPacket() { + var PACKET = { + type: Parser.OK_PACKET, + length: 65, + received: 65, + number: 92, + foo: 'bar' + }; + + var ok = Client._packetToUserObject(PACKET); + + assert.notStrictEqual(PACKET, ok); + assert.ok(!(ok instanceof Error)); + assert.equal(ok.foo, PACKET.foo); + assert.equal(ok.type, undefined); + assert.equal(ok.length, undefined); + assert.equal(ok.received, undefined); + })(); + + (function testErrorPacket() { + var PACKET = { + type: Parser.ERROR_PACKET, + foo: 'bar', + errorMessage: 'oh no', + errorNumber: 1007 + }; + + var err = Client._packetToUserObject(PACKET); + + assert.ok(err instanceof Error); + assert.equal(err.message, 'oh no'); + assert.equal(err.errorMessage, undefined); + assert.equal(err.number, 1007); + assert.equal(err.errorNumber, undefined); + })(); +}); diff --git a/node_modules/mysql/test/legacy/simple/test-outgoing-packet.js b/node_modules/mysql/test/legacy/simple/test-outgoing-packet.js new file mode 100644 index 0000000..ff22c19 --- /dev/null +++ b/node_modules/mysql/test/legacy/simple/test-outgoing-packet.js @@ -0,0 +1,134 @@ +var common = require('../common'); +var OutgoingPacket = require(common.dir.lib + '/outgoing_packet'), + Buffer = require('buffer').Buffer; + +function test(test) { + gently = new Gently(); + test(); + gently.verify(test.name); +} + +test(function constructor() { + var packet = new OutgoingPacket(10, 5); + assert.equal(packet.buffer.length, 14); + assert.deepEqual( + packet.buffer.slice(0, 3), + new Buffer([10, 0, 0]) + ); + assert.equal(packet.buffer[3], 5); + assert.equal(packet.index, 4); +}); + +test(function writeNumber() { + var packet = new OutgoingPacket(4); + packet.writeNumber(4, 257); + assert.deepEqual( + packet.buffer.slice(4, 8), + new Buffer([1, 1, 0, 0]) + ); +}); + +test(function writeFiller() { + var packet = new OutgoingPacket(5); + packet.writeFiller(5); + assert.equal(packet.index, 9); + assert.deepEqual( + packet.buffer.slice(4, 9), + new Buffer([0, 0, 0, 0, 0]) + ); +}); + +test(function write() { + (function testBuffer() { + var packet = new OutgoingPacket(3), + BUFFER = new Buffer([1, 2, 3]); + + packet.write(BUFFER); + assert.equal(packet.index, 7); + assert.deepEqual(packet.buffer.slice(4, 7), BUFFER); + })(); + + (function testString() { + var packet = new OutgoingPacket(3), + STRING = 'abc'; + + packet.write(STRING); + assert.equal(packet.index, 7); + assert.equal(packet.buffer.slice(4, 7).toString(), STRING); + })(); +}); + +test(function writeNullTerminated() { + var packet = new OutgoingPacket(4), + BUFFER = new Buffer([17, 23, 42]); + + packet.buffer[7] = 100; // set last byte to non-0 + + gently.expect(packet, 'write', function(buffer) { + assert.strictEqual(buffer, BUFFER); + this.index += buffer.length; + }); + + packet.writeNullTerminated(BUFFER); + assert.equal(packet.buffer[7], 0); + assert.equal(packet.index, 8); +}); + +test(function writeLengthCoded() { + (function test1ByteNumber() { + var packet = new OutgoingPacket(1); + packet.writeLengthCoded(250); + assert.equal(packet.buffer[4], 250); + assert.equal(packet.index, 5); + })(); + + (function test2ByteNumber() { + var packet = new OutgoingPacket(6); + packet.writeLengthCoded(251); + assert.equal(packet.buffer[4], 252); + assert.equal(packet.buffer[5], 251); + assert.equal(packet.buffer[6], 0); + assert.equal(packet.index, 7); + + packet.writeLengthCoded(257); + assert.equal(packet.buffer[7], 252); + assert.equal(packet.buffer[8], 1); + assert.equal(packet.buffer[9], 1); + assert.equal(packet.index, 10); + })(); + + (function test3ByteNumber() { + var packet = new OutgoingPacket(4); + packet.writeLengthCoded(Math.pow(256, 0) * 5 + Math.pow(256, 1) * 6 + Math.pow(256, 2) * 7); + assert.equal(packet.buffer[4], 253); + assert.equal(packet.buffer[5], 5); + assert.equal(packet.buffer[6], 6); + assert.equal(packet.buffer[7], 7); + assert.equal(packet.index, 8); + })(); + + (function testNull() { + var packet = new OutgoingPacket(1); + packet.writeLengthCoded(null); + assert.equal(packet.buffer[4], 251); + assert.equal(packet.index, 5); + })(); + + (function testBuffer() { + var packet = new OutgoingPacket(4), + BUFFER = new Buffer([17, 23, 42]); + + packet.writeLengthCoded(BUFFER); + assert.equal(packet.buffer[4], 3); + assert.deepEqual(packet.buffer.slice(5, 8), BUFFER); + })(); + + (function testString() { + var packet = new OutgoingPacket(6), + STRING = 'über'; + + packet.writeLengthCoded(STRING); + assert.equal(packet.buffer[4], 5); + assert.equal(packet.buffer.slice(5, 10).toString(), STRING); + })(); +}); diff --git a/node_modules/mysql/test/legacy/simple/test-parser.js b/node_modules/mysql/test/legacy/simple/test-parser.js new file mode 100644 index 0000000..aaca153 --- /dev/null +++ b/node_modules/mysql/test/legacy/simple/test-parser.js @@ -0,0 +1,387 @@ +var common = require('../common'); +var EventEmitter = require('events').EventEmitter, + Parser = require(common.dir.lib + '/parser'), + parser, + gently; + +function test(test) { + parser = new Parser(); + gently = new Gently(); + test(); + gently.verify(test.name); +} + +test(function constructor() { + assert.strictEqual(parser.state, Parser.PACKET_LENGTH); + assert.strictEqual(parser.packet, null); + assert.strictEqual(parser.greeted, false); + assert.strictEqual(parser.authenticated, false); + assert.strictEqual(parser.receivingFieldPackets, false); + assert.strictEqual(parser.receivingRowPackets, false); + assert.strictEqual(parser._lengthCodedLength, null); + assert.strictEqual(parser._lengthCodedStringLength, null); + assert.ok(parser instanceof EventEmitter); +}); + +test(function write() { + var packet; + (function testPacketLength() { + var LENGTH = 56; + parser.write(new Buffer([LENGTH])); + + assert.equal(parser.state, Parser.PACKET_LENGTH); + + packet = parser.packet; + + assert.ok(packet instanceof EventEmitter); + assert.strictEqual(packet.number, 0); + assert.strictEqual(packet.length, LENGTH); + + parser.write(new Buffer([0])); + parser.write(new Buffer([0])); + assert.strictEqual( + packet.length, + Math.pow(256, 0) * LENGTH + Math.pow(256, 1) * 0 + Math.pow(256, 2) * 0 + ); + })(); + + (function testPacketNumber() { + parser.write(new Buffer([42])); + assert.strictEqual(packet.number, 42); + assert.equal(parser.state, Parser.GREETING_PROTOCOL_VERSION); + })(); + + (function testGreetingErrorPacket() { + parser.write(new Buffer([0xff])); + assert.equal(packet.type, Parser.ERROR_PACKET); + assert.equal(parser.state, Parser.ERROR_NUMBER); + + parser.write(new Buffer([5, 2])); + assert.equal(packet.errorNumber, Math.pow(256, 0) * 5 + Math.pow(256, 1) * 2); + + parser.write(new Buffer('Hello World')); + assert.equal(packet.errorMessage, 'Hello World'); + + // Reset back to previous state + packet.type = Parser.GREETING_PACKET; + packet.received = 0; + parser.state = Parser.GREETING_PROTOCOL_VERSION; + })(); + + (function testGreetingPacket() { + parser.write(new Buffer([15])); + assert.equal(packet.type, Parser.GREETING_PACKET); + assert.equal(packet.protocolVersion, 15); + assert.equal(parser.state, Parser.GREETING_SERVER_VERSION); + + var VERSION = 'MySql 5.1'; + parser.write(new Buffer(VERSION+'\0', 'binary')); + assert.equal(packet.serverVersion, VERSION); + assert.equal(parser.state, Parser.GREETING_THREAD_ID); + + parser.write(new Buffer([0, 0, 0, 1])); + assert.equal(packet.threadId, Math.pow(256, 3)); + + parser.write(new Buffer([1])); + assert.equal(packet.scrambleBuffer[0], 1); + assert.equal(packet.scrambleBuffer.length, 8 + 12); + assert.equal(parser.state, Parser.GREETING_SCRAMBLE_BUFF_1); + + parser.write(new Buffer([2, 3, 4, 5, 6, 7, 8])); + assert.deepEqual( + packet.scrambleBuffer.slice(0, 8), + new Buffer([1, 2, 3, 4, 5, 6, 7, 8]) + ); + assert.equal(parser.state, Parser.GREETING_FILLER_1); + + parser.write(new Buffer([0])); + assert.equal(parser.state, Parser.GREETING_SERVER_CAPABILITIES); + + parser.write(new Buffer([0, 1])); + assert.equal(packet.serverCapabilities, Math.pow(256, 1)); + + parser.write(new Buffer([17])); + assert.equal(packet.serverLanguage, 17); + assert.equal(parser.state, Parser.GREETING_SERVER_STATUS); + + parser.write(new Buffer([0, 1])); + assert.equal(packet.serverStatus, Math.pow(256, 1)); + + parser.write(new Buffer([0])); + assert.equal(parser.state, Parser.GREETING_FILLER_2); + parser.write(new Buffer(12)); + assert.equal(parser.state, Parser.GREETING_SCRAMBLE_BUFF_2); + + parser.write(new Buffer([9])); + assert.equal(packet.scrambleBuffer[8], 9); + assert.equal(parser.state, Parser.GREETING_SCRAMBLE_BUFF_2); + + gently.expect(parser, 'emit', function(event, val) { + assert.equal(event, 'packet'); + assert.ok(!('index' in val)); + assert.strictEqual(val, packet); + assert.equal(parser.state, Parser.PACKET_LENGTH); + assert.equal(parser.greeted, true); + }); + + parser.write(new Buffer([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0])); + assert.deepEqual( + packet.scrambleBuffer.slice(9, 20), + new Buffer([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]) + ); + assert.strictEqual(parser.packet, null); + })(); + + (function testUseOldPasswordProtocolPacket() { + parser.write(new Buffer([1, 0, 0, 1])); + + gently.expect(parser, 'emit', function(event, val) { + assert.equal(event, 'packet'); + assert.equal(val.type, Parser.USE_OLD_PASSWORD_PROTOCOL_PACKET); + }); + + parser.write(new Buffer([254])); + })(); + + + (function testErrorPacket() { + parser.write(new Buffer([12, 0, 0, 1])); + assert.equal(parser.state, Parser.FIELD_COUNT); + var packet = parser.packet; + + parser.write(new Buffer([0xff])); + assert.equal(packet.type, Parser.ERROR_PACKET); + assert.equal(parser.state, Parser.ERROR_NUMBER); + + parser.write(new Buffer([5, 2])); + assert.equal(packet.errorNumber, Math.pow(256, 0) * 5 + Math.pow(256, 1) * 2); + + parser.write(new Buffer('#')); + assert.equal(packet.sqlStateMarker, '#'); + assert.equal(parser.state, Parser.ERROR_SQL_STATE); + + parser.write(new Buffer('abcde')); + assert.equal(packet.sqlState, 'abcde'); + + parser.write(new Buffer('er')); + assert.equal(parser.state, Parser.ERROR_MESSAGE); + assert.equal(packet.errorMessage, 'er'); + + gently.expect(parser, 'emit', function(event, val) { + assert.equal(event, 'packet'); + assert.equal(packet.errorMessage, 'err'); + }); + + parser.write(new Buffer('r')); + })(); + + (function testOkPacket() { + parser.write(new Buffer([15, 0, 0, 1])); + var packet = parser.packet; + + parser.write(new Buffer([0x00])); + assert.equal(packet.type, Parser.OK_PACKET); + assert.equal(parser.authenticated, true); + assert.equal(parser.state, Parser.AFFECTED_ROWS); + + parser.write(new Buffer([252, 17, 23])); + assert.equal(packet.affectedRows, Math.pow(256, 0) * 17 + Math.pow(256, 1) * 23); + + parser.write(new Buffer([240])); + assert.equal(packet.insertId, 240); + + parser.write(new Buffer([42, 113])); + assert.equal(packet.serverStatus, Math.pow(256, 0) * 42 + Math.pow(256, 1) * 113); + + parser.write(new Buffer([32, 153])); + assert.equal(packet.warningCount, Math.pow(256, 0) * 32 + Math.pow(256, 1) * 153); + + assert.strictEqual(packet.message, ''); + + gently.expect(parser, 'emit', function(event, val) { + assert.equal(event, 'packet'); + assert.equal(packet.message, 'abcdef'); + }); + + parser.write(new Buffer('abcdef')); + })(); + + (function testResultHeaderPacket() { + parser.write(new Buffer([1, 0, 0, 1])); + var packet = parser.packet; + + gently.expect(parser, 'emit', function(event, val) { + assert.equal(event, 'packet'); + assert.equal(val.type, Parser.RESULT_SET_HEADER_PACKET); + assert.equal(val.fieldCount, 5); + }); + + parser.write(new Buffer([5])); + })(); + + (function testResultHeaderPacketWithExtra() { + parser.receivingFieldPackets = false; + + parser.write(new Buffer([5, 0, 0, 1])); + var packet = parser.packet; + + parser.write(new Buffer([23])); + assert.equal(parser.state, Parser.EXTRA_LENGTH); + assert.equal(packet.fieldCount, 23); + + parser.write(new Buffer([3])); + + gently.expect(parser, 'emit', function(event, val) { + assert.equal(event, 'packet'); + assert.equal(val.type, Parser.RESULT_SET_HEADER_PACKET); + assert.equal(val.extra, 'abc'); + }); + + parser.write(new Buffer('abc')); + })(); + + (function testFieldPacket() { + parser.write(new Buffer([43, 0, 0, 1])); + var packet = parser.packet; + + assert.equal(parser.state, Parser.FIELD_CATALOG_LENGTH); + parser.write(new Buffer([3])); + assert.equal(packet.type, Parser.FIELD_PACKET); + parser.write(new Buffer('abc')); + assert.equal(packet.catalog, 'abc'); + + assert.equal(parser.state, Parser.FIELD_DB_LENGTH); + parser.write(new Buffer([5])); + parser.write(new Buffer('hello')); + assert.equal(packet.db, 'hello'); + + assert.equal(parser.state, Parser.FIELD_TABLE_LENGTH); + parser.write(new Buffer([2])); + parser.write(new Buffer('ab')); + assert.equal(packet.table, 'ab'); + + assert.equal(parser.state, Parser.FIELD_ORIGINAL_TABLE_LENGTH); + parser.write(new Buffer([4])); + parser.write(new Buffer('1234')); + assert.equal(packet.originalTable, '1234'); + + assert.equal(parser.state, Parser.FIELD_NAME_LENGTH); + parser.write(new Buffer([1])); + parser.write(new Buffer('o')); + assert.equal(packet.name, 'o'); + + assert.equal(parser.state, Parser.FIELD_ORIGINAL_NAME_LENGTH); + parser.write(new Buffer([9])); + parser.write(new Buffer('wonderful')); + assert.equal(packet.originalName, 'wonderful'); + + assert.equal(parser.state, Parser.FIELD_FILLER_1); + parser.write(new Buffer([0])); + + assert.equal(parser.state, Parser.FIELD_CHARSET_NR); + parser.write(new Buffer([42, 113])); + assert.equal(packet.charsetNumber, Math.pow(256, 0) * 42 + Math.pow(256, 1) * 113); + + assert.equal(parser.state, Parser.FIELD_LENGTH); + parser.write(new Buffer([42, 113, 50, 30])); + assert.equal(packet.fieldLength, 42 + (256 * 113) + (256 * 256) * 50 + (256 * 256 * 256 * 30)); + + assert.equal(parser.state, Parser.FIELD_TYPE); + parser.write(new Buffer([58])); + assert.equal(packet.fieldType, 58); + + assert.equal(parser.state, Parser.FIELD_FLAGS); + parser.write(new Buffer([42, 113])); + assert.equal(packet.flags, Math.pow(256, 0) * 42 + Math.pow(256, 1) * 113); + + assert.equal(parser.state, Parser.FIELD_DECIMALS); + parser.write(new Buffer([58])); + assert.equal(packet.decimals, 58); + + gently.expect(parser, 'emit', function(event, val) { + assert.equal(event, 'packet'); + }); + + assert.equal(parser.state, Parser.FIELD_FILLER_2); + parser.write(new Buffer([0, 0])); + })(); + + (function testEofPacket() { + parser.write(new Buffer([5, 0, 0, 1])); + var packet = parser.packet; + + parser.write(new Buffer([0xfe])); + assert.equal(packet.type, Parser.EOF_PACKET); + + assert.equal(parser.state, Parser.EOF_WARNING_COUNT); + parser.write(new Buffer([42, 113])); + assert.equal(packet.warningCount, Math.pow(256, 0) * 42 + Math.pow(256, 1) * 113); + + gently.expect(parser, 'emit', function(event, val) { + assert.equal(event, 'packet'); + assert.equal(parser.receivingFieldPackets, false); + assert.equal(parser.receivingRowPackets, true); + }); + + assert.equal(parser.state, Parser.EOF_SERVER_STATUS); + parser.write(new Buffer([42, 113])); + assert.equal(packet.serverStatus, Math.pow(256, 0) * 42 + Math.pow(256, 1) * 113); + })(); + + (function testRowPacket() { + parser.write(new Buffer([23, 0, 0, 1])); + var packet = parser.packet; + + gently.expect(parser, 'emit', function(event, val) { + assert.equal(event, 'packet'); + }); + + parser.write(new Buffer([16])); + assert.equal(parser.state, Parser.COLUMN_VALUE_STRING); + assert.equal(packet.type, Parser.ROW_DATA_PACKET); + assert.equal(packet.columnLength, 16); + + gently.expect(packet, 'emit', function(event, val, remaining) { + assert.equal(event, 'data'); + assert.equal(val.toString(), 'hi, '); + assert.equal(remaining, 12); + }); + + parser.write(new Buffer('hi, ')); + + gently.expect(packet, 'emit', function(event, val, remaining) { + assert.equal(event, 'data'); + assert.equal(val.toString(), 'how'); + assert.equal(remaining, 9); + }); + + parser.write(new Buffer('how')); + + gently.expect(packet, 'emit', function(event, val, remaining) { + assert.equal(event, 'data'); + assert.equal(val.toString(), ' are you?'); + assert.equal(remaining, 0); + }); + + gently.expect(packet, 'emit', function(event, val, remaining) { + assert.equal(event, 'data'); + assert.equal(val.toString(), 'Fine!'); + assert.equal(remaining, 0); + assert.equal(packet.index, 0); + }); + + parser.write(new Buffer(' are you?\u0005Fine!')); + + assert.equal(parser.packet, null); + assert.equal(parser.state, Parser.PACKET_LENGTH); + })(); + + (function testEofPacketAfterRowPacket() { + parser.write(new Buffer([5, 0, 0, 1])); + var packet = parser.packet; + + parser.write(new Buffer([0xfe])); + assert.equal(packet.type, Parser.EOF_PACKET); + assert.equal(parser.receivingRowPackets, false); + })(); +}); diff --git a/node_modules/mysql/test/legacy/simple/test-query.js b/node_modules/mysql/test/legacy/simple/test-query.js new file mode 100644 index 0000000..c1842f5 --- /dev/null +++ b/node_modules/mysql/test/legacy/simple/test-query.js @@ -0,0 +1,68 @@ +var common = require('../common'); +var Query = require(common.dir.lib + '/query'); +var EventEmitter = require('events').EventEmitter; +var Parser = require(common.dir.lib + '/parser'); +var query; +var gently; + +function test(test) { + query = new Query(); + gently = new Gently(); + test(); + gently.verify(test.name); +} + +test(function constructor() { + assert.ok(query instanceof EventEmitter); + assert.strictEqual(query.typeCast, true); + assert.strictEqual(query.sql, null); + assert.equal(new Query({foo: 'bar'}).foo, 'bar'); +}); + +test(function _handlePacket() { + function typeCast(type, strValue) { + query._fields = [{name: 'my_field', fieldType: type}]; + + var PACKET = new EventEmitter(), r; + PACKET.type = Parser.ROW_DATA_PACKET; + + gently.expect(PACKET, 'on', function (event, fn) { + assert.equal(event, 'data'); + + gently.expect(query, 'emit', function (event, row) { + assert.equal(event, 'row'); + r = row.my_field; + }); + + var val = (strValue === null) + ? null + : new Buffer(strValue); + + fn(val, 0); + }); + + query._handlePacket(PACKET); + return r; + } + + assert.deepEqual(typeCast(Query.FIELD_TYPE_TIMESTAMP, '2010-10-05 06:23:42 UTC'), new Date('2010-10-05 06:23:42Z')); + + assert.deepEqual(typeCast(Query.FIELD_TYPE_TIMESTAMP, '2010-10-05 UTC'), new Date('2010-10-05Z')); + assert.deepEqual(typeCast(Query.FIELD_TYPE_DATE, '2010-10-05 UTC'), new Date('2010-10-05Z')); + assert.deepEqual(typeCast(Query.FIELD_TYPE_DATETIME, '2010-10-05 UTC'), new Date('2010-10-05Z')); + assert.deepEqual(typeCast(Query.FIELD_TYPE_NEWDATE, '2010-10-05 UTC'), new Date('2010-10-05Z')); + + assert.strictEqual(typeCast(Query.FIELD_TYPE_TINY, '08'), 8); + assert.strictEqual(typeCast(Query.FIELD_TYPE_SHORT, '08'), 8); + assert.strictEqual(typeCast(Query.FIELD_TYPE_LONG, '08'), 8); + assert.strictEqual(typeCast(Query.FIELD_TYPE_LONGLONG, '08'), 8); + assert.strictEqual(typeCast(Query.FIELD_TYPE_INT24, '08'), 8); + assert.strictEqual(typeCast(Query.FIELD_TYPE_YEAR, '08'), 8); + + assert.strictEqual(typeCast(Query.FIELD_TYPE_DECIMAL, '2.8'), '2.8'); + assert.strictEqual(typeCast(Query.FIELD_TYPE_FLOAT, '2.8'), 2.8); + assert.strictEqual(typeCast(Query.FIELD_TYPE_DOUBLE, '2.8'), 2.8); + assert.strictEqual(typeCast(Query.FIELD_TYPE_NEWDECIMAL, '2.8'), '2.8'); + + assert.strictEqual(typeCast(Query.FIELD_TYPE_DATE, null), null); +}); diff --git a/node_modules/mysql/test/run.js b/node_modules/mysql/test/run.js new file mode 100755 index 0000000..0bb8e82 --- /dev/null +++ b/node_modules/mysql/test/run.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var far = require('far').create(); + +far.add(__dirname); +far.include(/test-.*\.js$/); + +far.execute(); diff --git a/node_modules/mysql/test/slow/.test-client-commands.js.un~ b/node_modules/mysql/test/slow/.test-client-commands.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..6774a3a8aa7fbf51b2079313c69923b99791b5cd GIT binary patch literal 54167 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 literal 0 HcmV?d00001 diff --git a/node_modules/mysql/test/slow/.test-client-connect.js.un~ b/node_modules/mysql/test/slow/.test-client-connect.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..e655ac5b9b43d6fa74c5429020f345cd91a3b857 GIT binary patch literal 4199 zcmeHK&1(};5Z|P&MGzEE;%P3D6he|(yi^oX3xZN5)`DM6w#mdU-MqECFA25u;KBdE zd+%QLs24qmr}pT_O%TD0C(m_$Z}+83YoJDtJMi*8cIM5?@3%8=cG2r>-BDMAZ%+Q% z+y3nGR_^ta=N~VZd)II7*53bo{OHYxOJ}}b`>}ocmE$-|($X?6lgVTOy=~5XZRyK+ zPFC_xeJ4?vFw=Mf!@*{|A`X-@84ZB}l45=UN${WRV!LPa{5zqMiK|HN;s54ikz%i48X_gRTY!kc^@jhmn5|L(!)+MTm|@ z;_kTg7d1z^Sg3I`P>P$H0!7;EaM0C-5^W^ISvp&-RyRx3?y9Et0#$4Uil=A;I}lYW zG#_Y+x*?O-raqHmZjtNzG($m~^a@8@qUEl}aGhEKdeWiST$LSWNTyy?Zu%Z8U0&;Q zxLz#Wo?9SKX%1cS*yDO~6uLmug{kvmRvK#7cRhVjzdBT3v95>gwhr2e8|NfZ&kZSJ zzb(#j(m!~wM?rIyby=V(uxbf*1E^w{DkS1Y5r?|WYhBkbVnh3%6ZE+ycCH_>`Gasi z4YRc70G%6iR~7_{lp_wq*w+adk-)6Dh((-t5-Xc#IAI54GEc%ZokignA)94VAn`xs zFk$-HglT^7va|4;DkGr@hZ&QGHC%pqX@kwPY$|B{i{O$2s*nMyGEUbd@6y>6N|vT9 zni?pR_A zRP9#)vZ+~@FT9r~o95z6@2)(!pBR7&sS8nC{#Es3J{92^9wFFBD!6#7y^6@_!P!G7 Pi9qjYtYxaA?=OA>P1LdI literal 0 HcmV?d00001 diff --git a/node_modules/mysql/test/slow/.test-client-max-connections.js.un~ b/node_modules/mysql/test/slow/.test-client-max-connections.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..c41d4b3ab18b552bfcdff6fd201830b99474b734 GIT binary patch literal 32474 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 bvg#KZ?{BNKia#LZgZK$j%ei;|_{0AJb&?O$ literal 0 HcmV?d00001 diff --git a/node_modules/mysql/test/slow/.test-client-query-column-ordering.js.un~ b/node_modules/mysql/test/slow/.test-client-query-column-ordering.js.un~ new file mode 100644 index 0000000000000000000000000000000000000000..44c5fc724a73d0847f981a385b521a4fc7e4635c GIT binary patch literal 22081 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 Fe*t@@+ triggers connection error + this.client.port = 999999999; + + var callbacks = []; + this.client.query('SELECT 1', function(err) { + assert.ok(err); + callbacks.push(1); + }); + + this.client.query('SELECT 2', function(err) { + callbacks.push(2); + assert.ok(err); + + assert.deepEqual(callbacks, [1, 2]); + done(null); + }); +}); + +test('Bad credentials', function(done) { + this.client.password = 'thispassworddoesnotreallywork'; + + var callbacks = []; + this.client.query('SELECT 1', function(err) { + assert.ok(err); + callbacks.push(1); + }); + + this.client.query('SELECT 2', function(err) { + assert.ok(err); + callbacks.push(2); + + assert.deepEqual(callbacks, [1, 2]); + done(); + }); +}); + +test('Reconnecting a closed client works', function(done) { + var cbs = []; + this.client.query('SELECT 1', function() { + cbs.push(1); + }); + + this.client.end(function() { + cbs.push(2); + }); + + this.client.query('SELECT 1', function(err) { + assert.deepEqual(cbs, [1, 2]); + done(err); + }); +}); + +test('Reconnect on timeout', {timeout: 2000}, function(done) { + // Not sure if we need all 3 of these, but they do the trick + this.client.query('SET interactive_timeout = 1'); + this.client.query('SET wait_timeout = 1'); + this.client.query('SET net_read_timeout = 1'); + + var self = this; + this.client._socket.on('end', function() { + assert.equal(self.client.connected, false); + + self.client.query('SELECT 1', function(err) { + done(err); + }); + }); +}); diff --git a/node_modules/mysql/test/slow/test-client-max-connections.js b/node_modules/mysql/test/slow/test-client-max-connections.js new file mode 100644 index 0000000..7bbd394 --- /dev/null +++ b/node_modules/mysql/test/slow/test-client-max-connections.js @@ -0,0 +1,69 @@ +var common = require('../common'); +var assert = require('assert'); +var test = common.fastOrSlow.slow(); +var mysql = require(common.dir.lib + '/mysql'); + +test.before(function() { + this.client = common.createClient(); +}); + +test.after(function(done) { + this.client.end(done); +}); + + +test('max connection', function(done) { + var originalMaxConnections; + var self = this; + + function setMaxConnectionsToOne() { + // First we figure out the current max_connections value, so we can restore that after the test + self.client.query('SHOW VARIABLES WHERE Variable_name = ?', ['max_connections'], function(err, results) { + if (err) throw err; + + originalMaxConnections = parseInt(results[0].Value); + if (originalMaxConnections === 1) { + console.log( + 'MySql already had max_connections set to 1. '+ + 'This probably happened because of a mal-function in this test, so re-setting to the MySql default of 100. '+ + 'If you had a higher value configured, you need to manually fix this now.' + ); + originalMaxConnections = 100; + } + + // Now we set max connections to 1, then we continue with our test + self.client.query('SET GLOBAL max_connections = ?', [1], function() { + connectTwoClients(); + }); + }); + }; + + function connectTwoClients() { + var client1 = common.createClient(); + client1.query('SELECT 1', function(err) { + if (err) { + // There should be no error for the first connection, but if there is one + // anyway, let's try to at least restore the server config before throwing + restoreMaxConnections(function() { + throw err; + }); + return; + } + + var client2 = common.createClient(); + client2.query('SELECT 1', function(err) { + assert.strictEqual(err.number, mysql.ERROR_CON_COUNT_ERROR); + + client1.end(); + restoreMaxConnections(); + }); + }); + } + + function restoreMaxConnections(cb) { + self.client.query('SET GLOBAL max_connections = ?', [originalMaxConnections], cb); + done(); + } + + setMaxConnectionsToOne(); +}); diff --git a/node_modules/mysql/test/slow/test-client-query-column-ordering.js b/node_modules/mysql/test/slow/test-client-query-column-ordering.js new file mode 100644 index 0000000..47451d5 --- /dev/null +++ b/node_modules/mysql/test/slow/test-client-query-column-ordering.js @@ -0,0 +1,50 @@ +var common = require('../common'); +var assert = require('assert'); +var test = common.fastOrSlow.slow(); +var mysql = require(common.dir.lib + '/mysql'); +var fs = require('fs'); + +test.before(function() { + this.client = common.createClient(); +}); + +test.after(function(done) { + this.client.end(done); +}); + +test('Column ordering works properly', {timeout: 15 * 1000}, function(done) { + var REPEATS = 500; + + this.client.query('CREATE DATABASE ' + common.TEST_DB, function(err) { + if (err && err.number != mysql.ERROR_DB_CREATE_EXISTS) { + throw err; + } + }); + this.client.query('USE ' + common.TEST_DB); + + this.client.query('DROP TABLE IF EXISTS columnia'); + var fixture = fs.readFileSync(common.dir.fixture + '/columnia.sql', 'utf8'); + this.client.query(fixture); + + var finished = 0; + var self = this; + for (var i = 0; i < REPEATS; i++) { + (function(i) { + var query = self.client.query("SHOW COLUMNS FROM columnia"); + + query.on('row', function(row) { + if (!row.Type) { + throw new Error('Column order mixed up after '+i+' queries.'); + } + }); + + query.on('end', function() { + finished++; + if (finished === REPEATS) { + done(); + } + }); + })(i); + } +}); + diff --git a/node_modules/mysql/test/slow/test-client-query-error-handling.js b/node_modules/mysql/test/slow/test-client-query-error-handling.js new file mode 100644 index 0000000..611150d --- /dev/null +++ b/node_modules/mysql/test/slow/test-client-query-error-handling.js @@ -0,0 +1,67 @@ +var common = require('../common'); +var assert = require('assert'); +var test = common.fastOrSlow.slow(); +var mysql = require(common.dir.lib + '/mysql'); + +var INVALID_QUERY_1 = 'first invalid #*&% query'; +var INVALID_QUERY_2 = 'another #*&% wrong query'; + +test.before(function() { + this.client = common.createClient(); +}); + +test.after(function(done) { + this.client.end(done); +}); + +test('query callback should receive error', function(done) { + this.client.query(INVALID_QUERY_1, function(error) { + assert.ok(error); + assert.strictEqual(error.sql, INVALID_QUERY_1); + done(); + }); +}); + +test('query object should emit error event', function(done) { + var query = this.client.query(INVALID_QUERY_2); + + query.on('error', function(error) { + assert.ok(error); + assert.strictEqual(error.sql, INVALID_QUERY_2); + done(); + }); +}); + +test('query errors are delegated to client error event if needed', function(done) { + var query = this.client.query(INVALID_QUERY_1); + + this.client.on('error', function(error) { + assert.ok(error); + assert.strictEqual(error.sql, INVALID_QUERY_1); + done(); + }); +}); + +test('query errors should not leave client in a broken state', function(done) { + this.client.query(INVALID_QUERY_1, function(error) { + assert.ok(error); + assert.strictEqual(error.sql, INVALID_QUERY_1); + }); + + this.client.query('SHOW STATUS', function(error, rows, fields) { + assert.ifError(error); + assert.equal(rows.length >= 50, true); + assert.equal(Object.keys(fields).length, 2); + }); + + this.client.query(INVALID_QUERY_1, function(error) { + assert.ok(error); + assert.strictEqual(error.sql, INVALID_QUERY_1); + }); + + this.client.query(INVALID_QUERY_2, function(error) { + assert.ok(error); + assert.strictEqual(error.sql, INVALID_QUERY_2); + done(); + }); +}); diff --git a/node_modules/mysql/test/slow/test-client-query.js b/node_modules/mysql/test/slow/test-client-query.js new file mode 100644 index 0000000..b7e39b0 --- /dev/null +++ b/node_modules/mysql/test/slow/test-client-query.js @@ -0,0 +1,129 @@ +var common = require('../common'); +var assert = require('assert'); +var test = common.fastOrSlow.slow(); +var mysql = require(common.dir.lib + '/mysql'); + +test.before(function() { + this.client = common.createClient(); +}); + +test.after(function(done) { + this.client.end(done); +}); + +test('Virtual fields resulting from an operation', function(done) { + this.client.query('SELECT 1 as field_a, 2 as field_b', function(err, results) { + assert.equal(results[0].field_a, 1); + assert.equal(results[0].field_b, 2); + done(err); + }); +}); + +test('Selecting an empty string', function(done) { + this.client.query('SELECT "" as field_a', function(err, results) { + assert.strictEqual(results[0].field_a, ""); + done(err); + }); +}); + +test('Long fields', function(done) { + function makeString(length) { + var str = ''; + for (var i = 0; i < length; i++) { + str += 'x'; + } + return str; + } + + var field_a = makeString(250), + field_b = makeString(251), + field_c = makeString(512), + field_d = makeString(65537); + + var self = this; + function test(last) { + var query = self.client.query( + 'SELECT ? as field_a, ? as field_b, ? as field_c, ? as field_d', + [field_a, field_b, field_c, field_d], + function(err, results) { + if (err) throw err; + + assert.equal(results[0].field_a, field_a); + assert.equal(results[0].field_b, field_b); + assert.equal(results[0].field_c, field_c); + assert.equal(results[0].field_d, field_d); + + if (last) { + done(err); + } + }); + } + + // We execute this test twice to be sure the parser is in a good state after + // each run. + test(); + test(true); +}); + +test('Query a NULL value', function(done) { + this.client.query('SELECT NULL as field_a, NULL as field_b', function(err, results) { + assert.strictEqual(results[0].field_a, null); + assert.strictEqual(results[0].field_b, null); + done(err); + }); +}); + +test('Real world usage', function(done) { + this.client.query('CREATE DATABASE '+common.TEST_DB, function createDbCb(err) { + if (err && err.number != mysql.ERROR_DB_CREATE_EXISTS) { + done(err); + } + }); + + this.client.query('USE '+common.TEST_DB, function useDbCb(err) { + if (err) done(err); + }); + + this.client.query( + 'CREATE TEMPORARY TABLE '+common.TEST_TABLE+ + '(id INT(11) AUTO_INCREMENT, title VARCHAR(255), text TEXT, created DATETIME, PRIMARY KEY (id));', + function createTableCb(err) { + if (err) done (err); + } + ); + + this.client.query( + 'INSERT INTO '+common.TEST_TABLE+' '+ + 'SET title = ?, text = ?, created = ?', + ['super cool', 'this is a nice long text', '2010-08-16 10:00:23'], + function insertCb(err) { + if (err) done(err); + } + ); + + var query = this.client.query( + 'INSERT INTO '+common.TEST_TABLE+' '+ + 'SET title = ?, text = ?, created = ?', + ['another entry', 'because 2 entries make a better test', null] + ); + + var endCalled = false; + query.on('end', function insertOkCb(packet) { + endCalled = true; + }); + + var query = this.client.query( + 'SELECT * FROM '+common.TEST_TABLE, + function selectCb(err, results, fields) { + assert.ok(endCalled); + + assert.equal(results.length, 2); + assert.equal(results[1].title, 'another entry'); + assert.ok(typeof results[1].id == 'number'); + assert.ok(results[0].created instanceof Date); + assert.strictEqual(results[1].created, null); + done(err); + } + ); +}); + diff --git a/node_modules/mysql/tool/.pcap-mysql.js.un~ b/node_modules/mysql/tool/.pcap-mysql.js.un~ new file mode 100755 index 0000000000000000000000000000000000000000..02dcd96d49fedbd3fce66a2408bbc1238ccc03bd GIT binary patch literal 67872 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 z 0) { + dev.addresses.forEach(function (address) { + sys.print(address.addr + "/" + address.netmask); + }); + sys.print("\n"); + } else { + sys.print("no address\n"); + } +}); + +sys.puts(''); +sys.puts('Execute `./pcap-mysql.js ` to listen on another device.'); +sys.puts(''); + +// Listen for packets, decode them, and feed the simple printer. No tricks. +pcap_session.on('packet', function (raw_packet) { + var packet = pcap.decode.packet(raw_packet); + //sys.puts(pcap.print.packet(packet)); + var tcp = packet.link.ip.tcp; + if (!tcp.data) { + return; + } + + if (tcp.sport == mysqlPort) { + sys.puts('<- '+tcp.data.inspect()); + } else { + sys.puts('-> '+tcp.data.inspect()); + } +}); + diff --git a/node_modules/socket.io/.npmignore b/node_modules/socket.io/.npmignore new file mode 100644 index 0000000..39e9864 --- /dev/null +++ b/node_modules/socket.io/.npmignore @@ -0,0 +1,3 @@ +support +test +examples diff --git a/node_modules/socket.io/History.md b/node_modules/socket.io/History.md new file mode 100644 index 0000000..f4d472c --- /dev/null +++ b/node_modules/socket.io/History.md @@ -0,0 +1,95 @@ + +0.7.9 / 2011-08-12 +================== + + * Updated socket.io-client. + * Make sure we only do garbage collection when the server we receive is actually run. + +0.7.8 / 2011-08-08 +================== + + * Changed; make sure sio#listen passes options to both HTTP server and socket.io manager. + * Added docs for sio#listen. + * Added options parameter support for Manager constructor. + * Added memory leaks tests and test-leaks Makefile task. + * Removed auto npm-linking from make test. + * Make sure that you can disable heartbeats. [3rd-Eden] + * Fixed rooms memory leak [3rd-Eden] + * Send response once we got all POST data, not immediately [Pita] + * Fixed onLeave behavior with missing clientsk [3rd-Eden] + * Prevent duplicate references in rooms. + * Added alias for `to` to `in` and `in` to `to`. + * Fixed roomClients definition. + * Removed dependency on redis for installation without npm [3rd-Eden] + * Expose path and querystring in handshakeData [3rd-Eden] + +0.7.7 / 2011-07-12 +================== + + * Fixed double dispatch handling with emit to closed clients. + * Added test for emitting to closed clients to prevent regression. + * Fixed race condition in redis test. + * Changed Transport#end instrumentation. + * Leveraged $emit instead of emit internally. + * Made tests faster. + * Fixed double disconnect events. + * Fixed disconnect logic + * Simplified remote events handling in Socket. + * Increased testcase timeout. + * Fixed unknown room emitting (GH-291). [3rd-Eden] + * Fixed `address` in handshakeData. [3rd-Eden] + * Removed transports definition in chat example. + * Fixed room cleanup + * Fixed; make sure the client is cleaned up after booting. + * Make sure to mark the client as non-open if the connection is closed. + * Removed unneeded `buffer` declarations. + * Fixed; make sure to clear socket handlers and subscriptions upon transport close. + +0.7.6 / 2011-06-30 +================== + + * Fixed general dispatching when a client has closed. + +0.7.5 / 2011-06-30 +================== + + * Fixed dispatching to clients that are disconnected. + +0.7.4 / 2011-06-30 +================== + + * Fixed; only clear handlers if they were set. [level09] + +0.7.3 / 2011-06-30 +================== + + * Exposed handshake data to clients. + * Refactored dispatcher interface. + * Changed; Moved id generation method into the manager. + * Added sub-namespace authorization. [3rd-Eden] + * Changed; normalized SocketNamespace local eventing [dvv] + * Changed; Use packet.reason or default to 'packet' [3rd-Eden] + * Changed console.error to console.log. + * Fixed; bind both servers at the same time do that the test never times out. + * Added 304 support. + * Removed `Transport#name` for abstract interface. + * Changed; lazily require http and https module only when needed. [3rd-Eden] + +0.7.2 / 2011-06-22 +================== + + * Make sure to write a packet (of type `noop`) when closing a poll. + This solves a problem with cross-domain requests being flagged as aborted and + reconnection being triggered. + * Added `noop` message type. + +0.7.1 / 2011-06-21 +================== + + * Fixed cross-domain XHR. + * Added CORS test to xhr-polling suite. + +0.7.0 / 2010-06-21 +================== + + * http://socket.io/announcement.html diff --git a/node_modules/socket.io/Makefile b/node_modules/socket.io/Makefile new file mode 100644 index 0000000..7981705 --- /dev/null +++ b/node_modules/socket.io/Makefile @@ -0,0 +1,22 @@ + +ALL_TESTS = $(shell find test/ -name '*.test.js') + +run-tests: + @./node_modules/.bin/expresso \ + -t 3000 \ + -I support \ + -I lib \ + --serial \ + $(TESTFLAGS) \ + $(TESTS) + +test: + @$(MAKE) TESTS="$(ALL_TESTS)" run-tests + +test-cov: + @TESTFLAGS=--cov $(MAKE) test + +test-leaks: + @ls test/leaks/* | xargs node --expose_debug_as=debug --expose_gc + +.PHONY: test diff --git a/node_modules/socket.io/Readme.md b/node_modules/socket.io/Readme.md new file mode 100644 index 0000000..875e5df --- /dev/null +++ b/node_modules/socket.io/Readme.md @@ -0,0 +1,343 @@ +# Socket.IO + +Socket.IO is a Node.JS project that makes WebSockets and realtime possible in +all browsers. It also enhances WebSockets by providing built-in multiplexing, +horizontal scalability, automatic JSON encoding/decoding, and more. + +## How to Install + + npm install socket.io + +## How to use + +First, require `socket.io`: + +```js +var io = require('socket.io'); +``` + +Next, attach it to a HTTP/HTTPS server. If you're using the fantastic `express` +web framework: + +```js +var app = express.createServer() + , io = io.listen(app); + +app.listen(80); + +io.sockets.on('connection', function (socket) { + socket.emit('news', { hello: 'world' }); + socket.on('my other event', function (data) { + console.log(data); + }); +}); +``` + +Finally, load it from the client side code: + +```html + + +``` + +For more thorough examples, look at the `examples/` directory. + +## Short recipes + +### Sending and receiving events. + +Socket.IO allows you to emit and receive custom events. +Besides `connect`, `message` and `disconnect`, you can emit custom events: + +```js +// note, io.listen() will create a http server for you +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + io.sockets.emit('this', { will: 'be received by everyone'); + + socket.on('private message', function (from, msg) { + console.log('I received a private message by ', from, ' saying ', msg); + }); + + socket.on('disconnect', function () { + sockets.emit('user disconnected'); + }); +}); +``` + +### Storing data associated to a client + +Sometimes it's necessary to store data associated with a client that's +necessary for the duration of the session. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.on('set nickname', function (name) { + socket.set('nickname', name, function () { socket.emit('ready'); }); + }); + + socket.on('msg', function () { + socket.get('nickname', function (err, name) { + console.log('Chat message by ', name); + }); + }); +}); +``` + +#### Client side + +```html + +``` + +### Restricting yourself to a namespace + +If you have control over all the messages and events emitted for a particular +application, using the default `/` namespace works. + +If you want to leverage 3rd-party code, or produce code to share with others, +socket.io provides a way of namespacing a `socket`. + +This has the benefit of `multiplexing` a single connection. Instead of +socket.io using two `WebSocket` connections, it'll use one. + +The following example defines a socket that listens on '/chat' and one for +'/news': + +#### Server side + +```js +var io = require('socket.io').listen(80); + +var chat = io + .of('/chat'); + .on('connection', function (socket) { + socket.emit('a message', { that: 'only', '/chat': 'will get' }); + chat.emit('a message', { everyone: 'in', '/chat': 'will get' }); + }); + +var news = io + .of('/news'); + .on('connection', function (socket) { + socket.emit('item', { news: 'item' }); + }); +``` + +#### Client side: + +```html + +``` + +### Sending volatile messages. + +Sometimes certain messages can be dropped. Let's say you have an app that +shows realtime tweets for the keyword `bieber`. + +If a certain client is not ready to receive messages (because of network slowness +or other issues, or because he's connected through long polling and is in the +middle of a request-response cycle), if he doesn't receive ALL the tweets related +to bieber your application won't suffer. + +In that case, you might want to send those messages as volatile messages. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + var tweets = setInterval(function () { + getBieberTweet(function (tweet) { + socket.volatile.emit('bieber tweet', tweet); + }); + }, 100); + + socket.on('disconnect', function () { + clearInterval(tweets); + }); +}); +``` + +#### Client side + +In the client side, messages are received the same way whether they're volatile +or not. + +### Getting acknowledgements + +Sometimes, you might want to get a callback when the client confirmed the message +reception. + +To do this, simply pass a function as the last parameter of `.send` or `.emit`. +What's more, when you use `.emit`, the acknowledgement is done by you, which +means you can also pass data along: + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.on('ferret', function (name, fn) { + fn('woot'); + }); +}); +``` + +#### Client side + +```html + +``` + +### Broadcasting messages + +To broadcast, simply add a `broadcast` flag to `emit` and `send` method calls. +Broadcasting means sending a message to everyone else except for the socket +that starts it. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.broadcast.emit('user connected'); + socket.broadcast.json.send({ a: 'message' }); +}); +``` + +### Rooms + +Sometimes you want to put certain sockets in the same room, so that it's easy +to broadcast to all of them together. + +Think of this as built-in channels for sockets. Sockets `join` and `leave` +rooms in each socket. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.join('justin bieber fans'); + socket.broadcast.to('justin bieber fans').emit('new fan'); + io.sockets.in('rammstein fans').emit('new non-fan'); +}); +``` + +### Using it just as a cross-browser WebSocket + +If you just want the WebSocket semantics, you can do that too. +Simply leverage `send` and listen on the `message` event: + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.on('message', function () { }); + socket.on('disconnect', function () { }); +}); +``` + +#### Client side + +```html + +``` + +### Changing configuration + +Configuration in socket.io is TJ-style: + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.configure(function () { + io.set('transports', ['websocket', 'flashsocket', 'xhr-polling']); +}); + +io.configure('development', function () { + io.set('transports', ['websocket', 'xhr-polling']); + io.enable('log'); +}); +``` + +## License + +(The MIT License) + +Copyright (c) 2011 Guillermo Rauch <guillermo@learnboost.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/socket.io/examples/chat/app.js b/node_modules/socket.io/examples/chat/app.js new file mode 100644 index 0000000..23f09f0 --- /dev/null +++ b/node_modules/socket.io/examples/chat/app.js @@ -0,0 +1,87 @@ + +/** + * Bootstrap app. + */ + +require.paths.unshift(__dirname + '/../../lib/'); + +/** + * Module dependencies. + */ + +var express = require('express') + , stylus = require('stylus') + , nib = require('nib') + , sio = require('socket.io'); + +/** + * App. + */ + +var app = express.createServer(); + +/** + * App configuration. + */ + +app.configure(function () { + app.use(stylus.middleware({ src: __dirname + '/public', compile: compile })) + app.use(express.static(__dirname + '/public')); + app.set('views', __dirname); + app.set('view engine', 'jade'); + + function compile (str, path) { + return stylus(str) + .set('filename', path) + .use(nib()); + }; +}); + +/** + * App routes. + */ + +app.get('/', function (req, res) { + res.render('index', { layout: false }); +}); + +/** + * App listen. + */ + +app.listen(3000, function () { + var addr = app.address(); + console.log(' app listening on http://' + addr.address + ':' + addr.port); +}); + +/** + * Socket.IO server (single process only) + */ + +var io = sio.listen(app) + , nicknames = {}; + +io.sockets.on('connection', function (socket) { + socket.on('user message', function (msg) { + socket.broadcast.emit('user message', socket.nickname, msg); + }); + + socket.on('nickname', function (nick, fn) { + if (nicknames[nick]) { + fn(true); + } else { + fn(false); + nicknames[nick] = socket.nickname = nick; + socket.broadcast.emit('announcement', nick + ' connected'); + io.sockets.emit('nicknames', nicknames); + } + }); + + socket.on('disconnect', function () { + if (!socket.nickname) return; + + delete nicknames[socket.nickname]; + socket.broadcast.emit('announcement', socket.nickname + ' disconnected'); + socket.broadcast.emit('nicknames', nicknames); + }); +}); diff --git a/node_modules/socket.io/examples/chat/index.jade b/node_modules/socket.io/examples/chat/index.jade new file mode 100644 index 0000000..0633d8b --- /dev/null +++ b/node_modules/socket.io/examples/chat/index.jade @@ -0,0 +1,83 @@ +doctype 5 +html + head + link(href='/stylesheets/style.css', rel='stylesheet') + script(src='http://code.jquery.com/jquery-1.6.1.min.js') + script(src='/socket.io/socket.io.js') + script + // socket.io specific code + var socket = io.connect(); + + socket.on('connect', function () { + $('#chat').addClass('connected'); + }); + + socket.on('announcement', function (msg) { + $('#lines').append($('

    ').append($('').text(msg))); + }); + + socket.on('nicknames', function (nicknames) { + $('#nicknames').empty().append($('Online: ')); + for (var i in nicknames) { + $('#nicknames').append($('').text(nicknames[i])); + } + }); + + socket.on('user message', message); + socket.on('reconnect', function () { + $('#lines').remove(); + message('System', 'Reconnected to the server'); + }); + + socket.on('reconnecting', function () { + message('System', 'Attempting to re-connect to the server'); + }); + + socket.on('error', function (e) { + message('System', e ? e : 'A unknown error occurred'); + }); + + function message (from, msg) { + $('#lines').append($('

    ').append($('').text(from), msg)); + } + + // dom manipulation + $(function () { + $('#set-nickname').submit(function (ev) { + socket.emit('nickname', $('#nick').val(), function (set) { + if (!set) { + clear(); + return $('#chat').addClass('nickname-set'); + } + $('#nickname-err').css('visibility', 'visible'); + }); + return false; + }); + + $('#send-message').submit(function () { + message('me', $('#message').val()); + socket.emit('user message', $('#message').val()); + clear(); + $('#lines').get(0).scrollTop = 10000000; + return false; + }); + + function clear () { + $('#message').val('').focus(); + }; + }); + body + #chat + #nickname + form.wrap#set-nickname + p Please type in your nickname and press enter. + input#nick + p#nickname-err Nickname already in use + #connecting + .wrap Connecting to socket.io server + #messages + #nicknames + #lines + form#send-message + input#message + button Send diff --git a/node_modules/socket.io/examples/chat/package.json b/node_modules/socket.io/examples/chat/package.json new file mode 100644 index 0000000..f095e85 --- /dev/null +++ b/node_modules/socket.io/examples/chat/package.json @@ -0,0 +1,11 @@ +{ + "name": "chat.io" + , "description": "example chat application with socket.io" + , "version": "0.0.1" + , "dependencies": { + "express": "2.3.11" + , "jade": "0.12.1" + , "stylus": "0.13.3" + , "nib": "0.0.8" + } +} diff --git a/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl b/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl new file mode 100644 index 0000000..fb5644c --- /dev/null +++ b/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl @@ -0,0 +1,96 @@ +border-radius(n) + -webkit-border-radius n + -moz-border-radius n + border-radius n + +// replace str with val + +replace(expr, str, val) + expr = clone(expr) + for e, i in expr + if str == e + expr[i] = val + expr + +// normalize gradient point (webkit) + +grad-point(pos) + if length(pos) == 1 + return left pos if pos in (top bottom) + return pos top if pos in (left right) + else if pos[0] in (top bottom) + pos[1] pos[0] + else + pos + +// implicit color stop position + +pos-in-stops(i, stops) + len = length(stops) + if len - 1 == i + 100% + else if i + unit(i / len * 100, '%') + else + 0% + +// normalize color stops +// - (color pos) -> (pos color) +// - (color) -> (implied-pos color) + +normalize-stops(stops) + stops = clone(stops) + for stop, i in stops + if length(stop) == 1 + color = stop[0] + stop[0] = pos-in-stops(i, stops) + stop[1] = color + else if typeof(stop[1]) == 'unit' + pos = stop[1] + stop[1] = stop[0] + stop[0] = pos + stops + +// join color stops with the given translation function + +join-stops(stops, translate) + str = '' + len = length(stops) + for stop, i in stops + str += ', ' if i + pos = stop[0] + color = stop[1] + str += translate(color, pos) + unquote(str) + +// webkit translation function + +webkit-stop(color, pos) + s('color-stop(%d, %s)', pos / 100, color) + +// mozilla translation function + +moz-stop(color, pos) + s('%s %s', color, pos) + +// create a linear gradient with the given start +// position, followed by color stops + +linear-gradient(start, stops...) + error('color stops required') unless length(stops) + prop = current-property[0] + val = current-property[1] + stops = normalize-stops(stops) + + // webkit + end = grad-point(opposite-position(start)) + webkit = s('-webkit-gradient(linear, %s, %s, %s)', grad-point(start), end, join-stops(stops, webkit-stop)) + add-property(prop, replace(val, '__CALL__', webkit)) + + // moz + stops = join-stops(stops, moz-stop) + moz = s('-moz-linear-gradient(%s, %s)', start, stops) + add-property(prop, replace(val, '__CALL__', moz)) + + // literal + s('linear-gradient(%s, %s)', start, stops) diff --git a/node_modules/socket.io/examples/chat/public/stylesheets/style.css b/node_modules/socket.io/examples/chat/public/stylesheets/style.css new file mode 100644 index 0000000..42cf98f --- /dev/null +++ b/node_modules/socket.io/examples/chat/public/stylesheets/style.css @@ -0,0 +1,188 @@ +#chat, +#nickname, +#messages { + width: 600px; +} +#chat { + position: relative; + border: 1px solid #ccc; +} +#nickname, +#connecting { + position: absolute; + height: 410px; + z-index: 100; + left: 0; + top: 0; + background: #fff; + text-align: center; + width: 600px; + font: 15px Georgia; + color: #666; + display: block; +} +#nickname .wrap, +#connecting .wrap { + padding-top: 150px; +} +#nickname input { + border: 1px solid #ccc; + padding: 10px; +} +#nickname input:focus { + border-color: #999; + outline: 0; +} +#nickname #nickname-err { + color: #8b0000; + font-size: 12px; + visibility: hidden; +} +.connected #connecting { + display: none; +} +.nickname-set #nickname { + display: none; +} +#messages { + height: 380px; + background: #eee; +} +#messages em { + text-shadow: 0 1px 0 #fff; + color: #999; +} +#messages p { + padding: 0; + margin: 0; + font: 12px Helvetica, Arial; + padding: 5px 10px; +} +#messages p b { + display: inline-block; + padding-right: 10px; +} +#messages p:nth-child(even) { + background: #fafafa; +} +#messages #nicknames { + background: #ccc; + padding: 2px 4px 4px; + font: 11px Helvetica; +} +#messages #nicknames span { + color: #000; +} +#messages #nicknames b { + display: inline-block; + color: #fff; + background: #999; + padding: 3px 6px; + margin-right: 5px; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + text-shadow: 0 1px 0 #666; +} +#messages #lines { + height: 355px; + overflow: auto; + overflow-x: hidden; + overflow-y: auto; +} +#messages #lines::-webkit-scrollbar { + width: 6px; + height: 6px; +} +#messages #lines::-webkit-scrollbar-button:start:decrement, +#messages #lines ::-webkit-scrollbar-button:end:increment { + display: block; + height: 10px; +} +#messages #lines::-webkit-scrollbar-button:vertical:increment { + background-color: #fff; +} +#messages #lines::-webkit-scrollbar-track-piece { + background-color: #fff; + -webkit-border-radius: 3px; +} +#messages #lines::-webkit-scrollbar-thumb:vertical { + height: 50px; + background-color: #ccc; + -webkit-border-radius: 3px; +} +#messages #lines::-webkit-scrollbar-thumb:horizontal { + width: 50px; + background-color: #fff; + -webkit-border-radius: 3px; +} +#send-message { + background: #fff; + position: relative; +} +#send-message input { + border: none; + height: 30px; + padding: 0 10px; + line-height: 30px; + vertical-align: middle; + width: 580px; +} +#send-message input:focus { + outline: 0; +} +#send-message button { + position: absolute; + top: 5px; + right: 5px; +} +button { + margin: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + display: inline-block; + text-decoration: none; + background: #43a1f7; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #43a1f7), color-stop(1, #377ad0)); + background: -webkit-linear-gradient(top, #43a1f7 0%, #377ad0 100%); + background: -moz-linear-gradient(top, #43a1f7 0%, #377ad0 100%); + background: linear-gradient(top, #43a1f7 0%, #377ad0 100%); + border: 1px solid #2e70c4; + -webkit-border-radius: 16px; + -moz-border-radius: 16px; + border-radius: 16px; + color: #fff; + font-family: "lucida grande", sans-serif; + font-size: 11px; + font-weight: normal; + line-height: 1; + padding: 3px 10px 5px 10px; + text-align: center; + text-shadow: 0 -1px 1px #2d6dc0; +} +button:hover, +button.hover { + background: darker; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #43a1f7), color-stop(1, #2e70c4)); + background: -webkit-linear-gradient(top, #43a1f7 0%, #2e70c4 100%); + background: -moz-linear-gradient(top, #43a1f7 0%, #2e70c4 100%); + background: linear-gradient(top, #43a1f7 0%, #2e70c4 100%); + border: 1px solid #2e70c4; + cursor: pointer; + text-shadow: 0 -1px 1px #2c6bbb; +} +button:active, +button.active { + background: #2e70c4; + border: 1px solid #2e70c4; + border-bottom: 1px solid #2861aa; + text-shadow: 0 -1px 1px #2b67b5; +} +button:focus, +button.focus { + outline: none; + -webkit-box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0; + -moz-box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0; + box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0; +} diff --git a/node_modules/socket.io/examples/chat/public/stylesheets/style.styl b/node_modules/socket.io/examples/chat/public/stylesheets/style.styl new file mode 100644 index 0000000..6289c94 --- /dev/null +++ b/node_modules/socket.io/examples/chat/public/stylesheets/style.styl @@ -0,0 +1,118 @@ +@import 'nib' + +#chat, #nickname, #messages + width 600px + +#chat + position relative + border 1px solid #ccc + +#nickname, #connecting + position absolute + height 410px + z-index 100 + left 0 + top 0 + background #fff + text-align center + width 600px + font 15px Georgia + color #666 + display block + .wrap + padding-top 150px + +#nickname + input + border 1px solid #ccc + padding 10px + &:focus + border-color #999 + outline 0 + #nickname-err + color darkred + font-size 12px + visibility hidden + +.connected + #connecting + display none + +.nickname-set + #nickname + display none + +#messages + height 380px + background #eee + em + text-shadow 0 1px 0 #fff + color #999 + p + padding 0 + margin 0 + font 12px Helvetica, Arial + padding 5px 10px + b + display inline-block + padding-right 10px + p:nth-child(even) + background #fafafa + #nicknames + background #ccc + padding 2px 4px 4px + font 11px Helvetica + span + color black + b + display inline-block + color #fff + background #999 + padding 3px 6px + margin-right 5px + border-radius 10px + text-shadow 0 1px 0 #666 + #lines + height 355px + overflow auto + overflow-x hidden + overflow-y auto + &::-webkit-scrollbar + width 6px + height 6px + &::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment + display block + height 10px + &::-webkit-scrollbar-button:vertical:increment + background-color #fff + &::-webkit-scrollbar-track-piece + background-color #fff + -webkit-border-radius 3px + &::-webkit-scrollbar-thumb:vertical + height 50px + background-color #ccc + -webkit-border-radius 3px + &::-webkit-scrollbar-thumb:horizontal + width 50px + background-color #fff + -webkit-border-radius 3px + +#send-message + background #fff + position relative + input + border none + height 30px + padding 0 10px + line-height 30px + vertical-align middle + width 580px + &:focus + outline 0 + button + position absolute + top 5px + right 5px + +button + download-button() diff --git a/node_modules/socket.io/examples/irc-output/app.js b/node_modules/socket.io/examples/irc-output/app.js new file mode 100644 index 0000000..591ec2a --- /dev/null +++ b/node_modules/socket.io/examples/irc-output/app.js @@ -0,0 +1,81 @@ + +/** + * Bootstrap app. + */ + +require.paths.unshift(__dirname + '/../../lib/'); + +/** + * Module dependencies. + */ + +var express = require('express') + , stylus = require('stylus') + , nib = require('nib') + , sio = require('socket.io') + , irc = require('./irc'); + +/** + * App. + */ + +var app = express.createServer(); + +/** + * App configuration. + */ + +app.configure(function () { + app.use(stylus.middleware({ src: __dirname + '/public', compile: compile })) + app.use(express.static(__dirname + '/public')); + app.set('views', __dirname); + app.set('view engine', 'jade'); + + function compile (str, path) { + return stylus(str) + .set('filename', path) + .use(nib()); + }; +}); + +/** + * App routes. + */ + +app.get('/', function (req, res) { + res.render('index', { layout: false }); +}); + +/** + * App listen. + */ + +app.listen(3000, function () { + var addr = app.address(); + console.log(' app listening on http://' + addr.address + ':' + addr.port); +}); + +/** + * Socket.IO server + */ + +var io = sio.listen(app) + +/** + * Connect to IRC. + */ + +var client = new irc.Client('irc.freenode.net', 6667); +client.connect('socketio\\test\\' + String(Math.random()).substr(-3)); +client.on('001', function () { + this.send('JOIN', '#node.js'); +}); +client.on('PART', function (prefix) { + io.sockets.emit('announcement', irc.user(prefix) + ' left the channel'); +}); +client.on('JOIN', function (prefix) { + io.sockets.emit('announcement', irc.user(prefix) + ' joined the channel'); +}); +client.on('PRIVMSG', function (prefix, channel, text) { + io.sockets.emit('irc message', irc.user(prefix), text); +}); diff --git a/node_modules/socket.io/examples/irc-output/index.jade b/node_modules/socket.io/examples/irc-output/index.jade new file mode 100644 index 0000000..5468632 --- /dev/null +++ b/node_modules/socket.io/examples/irc-output/index.jade @@ -0,0 +1,28 @@ +doctype 5 +html + head + link(href='/stylesheets/style.css', rel='stylesheet') + script(src='http://code.jquery.com/jquery-1.6.1.min.js') + script(src='/socket.io/socket.io.js') + script + var socket = io.connect(); + + socket.on('connect', function () { + $('#irc').addClass('connected'); + }); + + socket.on('announcement', function (msg) { + $('#messages').append($('

    ').append($('').text(msg))); + $('#messages').get(0).scrollTop = 10000000; + }); + + socket.on('irc message', function (user, msg) { + $('#messages').append($('

    ').append($('').text(user), msg)); + $('#messages').get(0).scrollTop = 10000000; + }); + body + h2 Node.JS IRC + #irc + #connecting + .wrap Connecting to socket.io server + #messages diff --git a/node_modules/socket.io/examples/irc-output/irc.js b/node_modules/socket.io/examples/irc-output/irc.js new file mode 100644 index 0000000..c89ddb0 --- /dev/null +++ b/node_modules/socket.io/examples/irc-output/irc.js @@ -0,0 +1,164 @@ +/** + * From https://github.com/felixge/nodelog/ + */ + +var sys = require('sys'); +var tcp = require('net'); +var irc = exports; + +function bind(fn, scope) { + var bindArgs = Array.prototype.slice.call(arguments); + bindArgs.shift(); + bindArgs.shift(); + + return function() { + var args = Array.prototype.slice.call(arguments); + fn.apply(scope, bindArgs.concat(args)); + }; +} + +function each(set, iterator) { + for (var i = 0; i < set.length; i++) { + var r = iterator(set[i], i); + if (r === false) { + return; + } + } +} + +var Client = irc.Client = function(host, port) { + this.host = host || 'localhost'; + this.port = port || 6667; + + this.connection = null; + this.buffer = ''; + this.encoding = 'utf8'; + this.timeout = 10 * 60 * 60 * 1000; + + this.nick = null; + this.user = null; + this.real = null; +} +sys.inherits(Client, process.EventEmitter); + +Client.prototype.connect = function(nick, user, real) { + var connection = tcp.createConnection(this.port, this.host); + connection.setEncoding(this.encoding); + connection.setTimeout(this.timeout); + connection.addListener('connect', bind(this.onConnect, this)); + connection.addListener('data', bind(this.onReceive, this)); + connection.addListener('end', bind(this.onEof, this)); + connection.addListener('timeout', bind(this.onTimeout, this)); + connection.addListener('close', bind(this.onClose, this)); + + this.nick = nick; + this.user = user || 'guest'; + this.real = real || 'Guest'; + + this.connection = connection; +}; + +Client.prototype.disconnect = function(why) { + if (this.connection.readyState !== 'closed') { + this.connection.close(); + sys.puts('disconnected (reason: '+why+')'); + this.emit('DISCONNECT', why); + } +}; + +Client.prototype.send = function(arg1) { + if (this.connection.readyState !== 'open') { + return this.disconnect('cannot send with readyState: '+this.connection.readyState); + } + + var message = []; + for (var i = 0; i< arguments.length; i++) { + if (arguments[i]) { + message.push(arguments[i]); + } + } + message = message.join(' '); + + sys.puts('> '+message); + message = message + "\r\n"; + this.connection.write(message, this.encoding); +}; + +Client.prototype.parse = function(message) { + var match = message.match(/(?:(:[^\s]+) )?([^\s]+) (.+)/); + var parsed = { + prefix: match[1], + command: match[2] + }; + + var params = match[3].match(/(.*?) ?:(.*)/); + if (params) { + // Params before : + params[1] = (params[1]) + ? params[1].split(' ') + : []; + // Rest after : + params[2] = params[2] + ? [params[2]] + : []; + + params = params[1].concat(params[2]); + } else { + params = match[3].split(' '); + } + + parsed.params = params; + return parsed; +}; + +Client.prototype.onConnect = function() { + this.send('NICK', this.nick); + this.send('USER', this.user, '0', '*', ':'+this.real); +}; + +Client.prototype.onReceive = function(chunk) { + this.buffer = this.buffer + chunk; + + while (this.buffer) { + var offset = this.buffer.indexOf("\r\n"); + if (offset < 0) { + return; + } + + var message = this.buffer.substr(0, offset); + this.buffer = this.buffer.substr(offset + 2); + sys.puts('< '+message); + + message = this.parse(message); + + this.emit.apply(this, [message.command, message.prefix].concat(message.params)); + + if (message !== false) { + this.onMessage(message); + } + } +}; + +Client.prototype.onMessage = function(message) { + switch (message.command) { + case 'PING': + this.send('PONG', ':'+message.params[0]); + break; + } +}; + +Client.prototype.onEof = function() { + this.disconnect('eof'); +}; + +Client.prototype.onTimeout = function() { + this.disconnect('timeout'); +}; + +Client.prototype.onClose = function() { + this.disconnect('close'); +}; + +exports.user = function(prefix) { + return prefix.match(/:([^!]+)!/)[1] +}; diff --git a/node_modules/socket.io/examples/irc-output/package.json b/node_modules/socket.io/examples/irc-output/package.json new file mode 100644 index 0000000..88bf42f --- /dev/null +++ b/node_modules/socket.io/examples/irc-output/package.json @@ -0,0 +1,10 @@ +{ + "name": "socket.io-irc" + , "version": "0.0.1" + , "dependencies": { + "express": "2.3.11" + , "jade": "0.12.1" + , "stylus": "0.13.3" + , "nib": "0.0.8" + } +} diff --git a/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl b/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl new file mode 100644 index 0000000..2713512 --- /dev/null +++ b/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl @@ -0,0 +1,69 @@ +@import 'nib' + +h2 + font bold 18px Helvetica Neue, Arial + +#irc, #messages + width 600px + +#irc + position relative + border 1px solid #ccc + +#connecting + position absolute + height 410px + z-index 100 + left 0 + top 0 + background #fff + text-align center + width 600px + font 15px Georgia + color #666 + display block + .wrap + padding-top 150px + +.connected + #connecting + display none + +#messages + height 380px + background #eee + overflow auto + overflow-x hidden + overflow-y auto + &::-webkit-scrollbar + width 6px + height 6px + &::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment + display block + height 10px + &::-webkit-scrollbar-button:vertical:increment + background-color #fff + &::-webkit-scrollbar-track-piece + background-color #fff + -webkit-border-radius 3px + &::-webkit-scrollbar-thumb:vertical + height 50px + background-color #ccc + -webkit-border-radius 3px + &::-webkit-scrollbar-thumb:horizontal + width 50px + background-color #fff + -webkit-border-radius 3px + em + text-shadow 0 1px 0 #fff + color #999 + p + padding 0 + margin 0 + font 12px Helvetica, Arial + padding 5px 10px + b + display inline-block + padding-right 10px + p:nth-child(even) + background #fafafa diff --git a/node_modules/socket.io/index.js b/node_modules/socket.io/index.js new file mode 100644 index 0000000..cc00c10 --- /dev/null +++ b/node_modules/socket.io/index.js @@ -0,0 +1,8 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +module.exports = require('./lib/socket.io'); diff --git a/node_modules/socket.io/lib/logger.js b/node_modules/socket.io/lib/logger.js new file mode 100644 index 0000000..ce480ea --- /dev/null +++ b/node_modules/socket.io/lib/logger.js @@ -0,0 +1,96 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var util = require('./util') + , toArray = util.toArray; + +/** + * Log levels. + */ + +var levels = [ + 'error' + , 'warn' + , 'info' + , 'debug' +]; + +/** + * Colors for log levels. + */ + +var colors = [ + 31 + , 33 + , 36 + , 90 +]; + +/** + * Pads the nice output to the longest log level. + */ + +function pad (str) { + var max = 0; + + for (var i = 0, l = levels.length; i < l; i++) + max = Math.max(max, levels[i].length); + + if (str.length < max) + return str + new Array(max - str.length + 1).join(' '); + + return str; +}; + +/** + * Logger (console). + * + * @api public + */ + +var Logger = module.exports = function (opts) { + opts = opts || {} + this.colors = false !== opts.colors; + this.level = 3; +}; + +/** + * Log method. + * + * @api public + */ + +Logger.prototype.log = function (type) { + var index = levels.indexOf(type); + + if (index > this.level) + return this; + + console.log.apply( + console + , [this.colors + ? ' \033[' + colors[index] + 'm' + pad(type) + ' -\033[39m' + : type + ':' + ].concat(toArray(arguments).slice(1)) + ); + + return this; +}; + +/** + * Generate methods. + */ + +levels.forEach(function (name) { + Logger.prototype[name] = function () { + this.log.apply(this, [name].concat(toArray(arguments))); + }; +}); diff --git a/node_modules/socket.io/lib/manager.js b/node_modules/socket.io/lib/manager.js new file mode 100644 index 0000000..b5f32db --- /dev/null +++ b/node_modules/socket.io/lib/manager.js @@ -0,0 +1,1021 @@ +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , url = require('url') + , util = require('./util') + , store = require('./store') + , client = require('socket.io-client') + , transports = require('./transports') + , Logger = require('./logger') + , Socket = require('./socket') + , MemoryStore = require('./stores/memory') + , SocketNamespace = require('./namespace') + , EventEmitter = process.EventEmitter; + +/** + * Export the constructor. + */ + +exports = module.exports = Manager; + +/** + * Default transports. + */ + +var defaultTransports = exports.defaultTransports = [ + 'websocket' + , 'htmlfile' + , 'xhr-polling' + , 'jsonp-polling' +]; + +/** + * Inherited defaults. + */ + +var parent = module.parent.exports + , protocol = parent.protocol; + +/** + * Manager constructor. + * + * @param {HTTPServer} server + * @param {Object} options, optional + * @api public + */ + +function Manager (server, options) { + this.server = server; + this.namespaces = {}; + this.sockets = this.of(''); + this.settings = { + origins: '*:*' + , log: true + , store: new MemoryStore + , logger: new Logger + , heartbeats: true + , resource: '/socket.io' + , transports: defaultTransports + , authorization: false + , 'log level': 3 + , 'close timeout': 25 + , 'heartbeat timeout': 15 + , 'heartbeat interval': 20 + , 'polling duration': 20 + , 'flash policy server': true + , 'flash policy port': 843 + , 'destroy upgrade': true + , 'browser client': true + , 'browser client minification': false + , 'browser client etag': false + , 'browser client handler': false + , 'client store expiration': 15 + }; + + for (var i in options) { + this.settings[i] = options[i]; + } + + this.initStore(); + + // reset listeners + this.oldListeners = server.listeners('request'); + server.removeAllListeners('request'); + + var self = this; + + server.on('request', function (req, res) { + self.handleRequest(req, res); + }); + + server.on('upgrade', function (req, socket, head) { + self.handleUpgrade(req, socket, head); + }); + + server.on('close', function () { + clearInterval(self.gc); + }); + + server.once('listening', function () { + self.gc = setInterval(self.garbageCollection.bind(self), 10000); + }); + + for (var i in transports) { + if (transports[i].init) { + transports[i].init(this); + } + } + + this.log.info('socket.io started'); +}; + +Manager.prototype.__proto__ = EventEmitter.prototype + +/** + * Store accessor shortcut. + * + * @api public + */ + +Manager.prototype.__defineGetter__('store', function () { + var store = this.get('store'); + store.manager = this; + return store; +}); + +/** + * Logger accessor. + * + * @api public + */ + +Manager.prototype.__defineGetter__('log', function () { + if (this.disabled('log')) return; + + var logger = this.get('logger'); + logger.level = this.get('log level'); + + return logger; +}); + +/** + * Get settings. + * + * @api public + */ + +Manager.prototype.get = function (key) { + return this.settings[key]; +}; + +/** + * Set settings + * + * @api public + */ + +Manager.prototype.set = function (key, value) { + if (arguments.length == 1) return this.get(key); + this.settings[key] = value; + this.emit('set:' + key, this.settings[key], key); + return this; +}; + +/** + * Enable a setting + * + * @api public + */ + +Manager.prototype.enable = function (key) { + this.settings[key] = true; + this.emit('set:' + key, this.settings[key], key); + return this; +}; + +/** + * Disable a setting + * + * @api public + */ + +Manager.prototype.disable = function (key) { + this.settings[key] = false; + this.emit('set:' + key, this.settings[key], key); + return this; +}; + +/** + * Checks if a setting is enabled + * + * @api public + */ + +Manager.prototype.enabled = function (key) { + return !!this.settings[key]; +}; + +/** + * Checks if a setting is disabled + * + * @api public + */ + +Manager.prototype.disabled = function (key) { + return !this.settings[key]; +}; + +/** + * Configure callbacks. + * + * @api public + */ + +Manager.prototype.configure = function (env, fn) { + if ('function' == typeof env) { + env.call(this); + } else if (env == process.env.NODE_ENV) { + fn.call(this); + } + + return this; +}; + +/** + * Initializes everything related to the message dispatcher. + * + * @api private + */ + +Manager.prototype.initStore = function () { + this.handshaken = {}; + this.connected = {}; + this.open = {}; + this.closed = {}; + this.closedA = []; + this.rooms = {}; + this.roomClients = {}; + + var self = this; + + this.store.subscribe('handshake', function (id, data) { + self.onHandshake(id, data); + }); + + this.store.subscribe('connect', function (id) { + self.onConnect(id); + }); + + this.store.subscribe('open', function (id) { + self.onOpen(id); + }); + + this.store.subscribe('join', function (id, room) { + self.onJoin(id, room); + }); + + this.store.subscribe('leave', function (id, room) { + self.onLeave(id, room); + }); + + this.store.subscribe('close', function (id) { + self.onClose(id); + }); + + this.store.subscribe('dispatch', function (room, packet, volatile, exceptions) { + self.onDispatch(room, packet, volatile, exceptions); + }); + + this.store.subscribe('disconnect', function (id) { + self.onDisconnect(id); + }); +}; + +/** + * Called when a client handshakes. + * + * @param text + */ + +Manager.prototype.onHandshake = function (id, data) { + this.handshaken[id] = data; +}; + +/** + * Called when a client connects (ie: transport first opens) + * + * @api private + */ + +Manager.prototype.onConnect = function (id) { + this.connected[id] = true; +}; + +/** + * Called when a client opens a request in a different node. + * + * @api private + */ + +Manager.prototype.onOpen = function (id) { + this.open[id] = true; + + // if we were buffering messages for the client, clear them + if (this.closed[id]) { + var self = this; + + this.closedA.splice(this.closedA.indexOf(id), 1); + + this.store.unsubscribe('dispatch:' + id, function () { + delete self.closed[id]; + }); + } + + // clear the current transport + if (this.transports[id]) { + this.transports[id].discard(); + this.transports[id] = null; + } +}; + +/** + * Called when a message is sent to a namespace and/or room. + * + * @api private + */ + +Manager.prototype.onDispatch = function (room, packet, volatile, exceptions) { + if (this.rooms[room]) { + for (var i = 0, l = this.rooms[room].length; i < l; i++) { + var id = this.rooms[room][i]; + + if (!~exceptions.indexOf(id)) { + if (this.transports[id] && this.transports[id].open) { + this.transports[id].onDispatch(packet, volatile); + } else if (!volatile) { + this.onClientDispatch(id, packet); + } + } + } + } +}; + +/** + * Called when a client joins a nsp / room. + * + * @api private + */ + +Manager.prototype.onJoin = function (id, name) { + if (!this.roomClients[id]) { + this.roomClients[id] = {}; + } + + if (!this.rooms[name]) { + this.rooms[name] = []; + } + + if (!~this.rooms[name].indexOf(id)) { + this.rooms[name].push(id); + this.roomClients[id][name] = true; + } +}; + +/** + * Called when a client leaves a nsp / room. + * + * @param private + */ + +Manager.prototype.onLeave = function (id, room) { + if (this.rooms[room]) { + var index = this.rooms[room].indexOf(id); + + if (index >= 0) { + this.rooms[room].splice(index, 1); + } + + if (!this.rooms[room].length) { + delete this.rooms[room]; + } + delete this.roomClients[id][room]; + } +}; + +/** + * Called when a client closes a request in different node. + * + * @api private + */ + +Manager.prototype.onClose = function (id) { + if (this.open[id]) { + delete this.open[id]; + } + + this.closed[id] = []; + this.closedA.push(id); + + var self = this; + + this.store.subscribe('dispatch:' + id, function (packet, volatile) { + if (!volatile) { + self.onClientDispatch(id, packet); + } + }); +}; + +/** + * Dispatches a message for a closed client. + * + * @api private + */ + +Manager.prototype.onClientDispatch = function (id, packet) { + if (this.closed[id]) { + this.closed[id].push(packet); + } +}; + +/** + * Receives a message for a client. + * + * @api private + */ + +Manager.prototype.onClientMessage = function (id, packet) { + if (this.namespaces[packet.endpoint]) { + this.namespaces[packet.endpoint].handlePacket(id, packet); + } +}; + +/** + * Fired when a client disconnects (not triggered). + * + * @api private + */ + +Manager.prototype.onClientDisconnect = function (id, reason) { + for (var name in this.namespaces) { + if (this.roomClients[id][name]) { + this.namespaces[name].handleDisconnect(id, reason); + } + } + + this.onDisconnect(id); +}; + +/** + * Called when a client disconnects. + * + * @param text + */ + +Manager.prototype.onDisconnect = function (id, local) { + delete this.handshaken[id]; + + if (this.open[id]) { + delete this.open[id]; + } + + if (this.connected[id]) { + delete this.connected[id]; + } + + if (this.transports[id]) { + this.transports[id].discard(); + delete this.transports[id]; + } + + if (this.closed[id]) { + delete this.closed[id]; + this.closedA.splice(this.closedA.indexOf(id), 1); + } + + if (this.roomClients[id]) { + for (var room in this.roomClients[id]) { + this.onLeave(id, room); + } + delete this.roomClients[id] + } + + this.store.destroyClient(id, this.get('client store expiration')); + + this.store.unsubscribe('dispatch:' + id); + + if (local) { + this.store.unsubscribe('message:' + id); + this.store.unsubscribe('disconnect:' + id); + } +}; + +/** + * Handles an HTTP request. + * + * @api private + */ + +Manager.prototype.handleRequest = function (req, res) { + var data = this.checkRequest(req); + + if (!data) { + for (var i = 0, l = this.oldListeners.length; i < l; i++) { + this.oldListeners[i].call(this.server, req, res); + } + + return; + } + + if (data.static || !data.transport && !data.protocol) { + if (data.static && this.enabled('browser client')) { + this.handleClientRequest(req, res, data); + } else { + res.writeHead(200); + res.end('Welcome to socket.io.'); + + this.log.info('unhandled socket.io url'); + } + + return; + } + + if (data.protocol != protocol) { + res.writeHead(500); + res.end('Protocol version not supported.'); + + this.log.info('client protocol version unsupported'); + } else { + if (data.id) { + this.handleHTTPRequest(data, req, res); + } else { + this.handleHandshake(data, req, res); + } + } +}; + +/** + * Handles an HTTP Upgrade. + * + * @api private + */ + +Manager.prototype.handleUpgrade = function (req, socket, head) { + var data = this.checkRequest(req) + , self = this; + + if (!data) { + if (this.enabled('destroy upgrade')) { + socket.end(); + this.log.debug('destroying non-socket.io upgrade'); + } + + return; + } + + req.head = head; + this.handleClient(data, req); +}; + +/** + * Handles a normal handshaken HTTP request (eg: long-polling) + * + * @api private + */ + +Manager.prototype.handleHTTPRequest = function (data, req, res) { + req.res = res; + this.handleClient(data, req); +}; + +/** + * Intantiantes a new client. + * + * @api private + */ + +Manager.prototype.handleClient = function (data, req) { + var socket = req.socket + , store = this.store + , self = this; + + if (undefined != data.query.disconnect) { + if (this.transports[data.id] && this.transports[data.id].open) { + this.transports[data.id].onForcedDisconnect(); + } else { + this.store.publish('disconnect-force:' + data.id); + } + return; + } + + if (!~this.get('transports').indexOf(data.transport)) { + this.log.warn('unknown transport: "' + data.transport + '"'); + req.connection.end(); + return; + } + + var transport = new transports[data.transport](this, data, req) + , handshaken = this.handshaken[data.id]; + + if (handshaken) { + if (transport.open) { + if (this.closed[data.id] && this.closed[data.id].length) { + transport.payload(this.closed[data.id]); + this.closed[data.id] = []; + } + + this.onOpen(data.id); + this.store.publish('open', data.id); + this.transports[data.id] = transport; + } + + if (!this.connected[data.id]) { + this.onConnect(data.id); + this.store.publish('connect', data.id); + + // flag as used + delete handshaken.issued; + this.onHandshake(data.id, handshaken); + this.store.publish('handshake', data.id, handshaken); + + // initialize the socket for all namespaces + for (var i in this.namespaces) { + var socket = this.namespaces[i].socket(data.id, true); + + // echo back connect packet and fire connection event + if (i === '') { + this.namespaces[i].handlePacket(data.id, { type: 'connect' }); + } + } + + this.store.subscribe('message:' + data.id, function (packet) { + self.onClientMessage(data.id, packet); + }); + + this.store.subscribe('disconnect:' + data.id, function (reason) { + self.onClientDisconnect(data.id, reason); + }); + } + } else { + if (transport.open) { + transport.error('client not handshaken', 'reconnect'); + } + + transport.discard(); + } +}; + +/** + * Dictionary for static file serving + * + * @api public + */ + +Manager.static = { + cache: {} + , paths: { + '/static/flashsocket/WebSocketMain.swf': client.dist + '/WebSocketMain.swf' + , '/static/flashsocket/WebSocketMainInsecure.swf': + client.dist + '/WebSocketMainInsecure.swf' + , '/socket.io.js': client.dist + '/socket.io.js' + , '/socket.io.js.min': client.dist + '/socket.io.min.js' + } + , mime: { + 'js': { + contentType: 'application/javascript' + , encoding: 'utf8' + } + , 'swf': { + contentType: 'application/x-shockwave-flash' + , encoding: 'binary' + } + } +}; + +/** + * Serves the client. + * + * @api private + */ + +Manager.prototype.handleClientRequest = function (req, res, data) { + var static = Manager.static + , extension = data.path.split('.').pop() + , file = data.path + (this.enabled('browser client minification') + && extension == 'js' ? '.min' : '') + , location = static.paths[file] + , cache = static.cache[file]; + + var self = this; + + /** + * Writes a response, safely + * + * @api private + */ + + function write (status, headers, content, encoding) { + try { + res.writeHead(status, headers || null); + res.end(content || '', encoding || null); + } catch (e) {} + } + + function serve () { + if (req.headers['if-none-match'] === cache.Etag) { + return write(304); + } + + var mime = static.mime[extension] + , headers = { + 'Content-Type': mime.contentType + , 'Content-Length': cache.length + }; + + if (self.enabled('browser client etag') && cache.Etag) { + headers.Etag = cache.Etag; + } + + write(200, headers, cache.content, mime.encoding); + self.log.debug('served static ' + data.path); + } + + if (this.get('browser client handler')) { + this.get('browser client handler').call(this, req, res); + } else if (!cache) { + fs.readFile(location, function (err, data) { + if (err) { + write(500, null, 'Error serving static ' + data.path); + self.log.warn('Can\'t cache '+ data.path +', ' + err.message); + return; + } + + cache = Manager.static.cache[file] = { + content: data + , length: data.length + , Etag: client.version + }; + + serve(); + }); + } else { + serve(); + } +}; + +/** + * Generates a session id. + * + * @api private + */ + +Manager.prototype.generateId = function () { + return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString() + + Math.abs(Math.random() * Math.random() * Date.now() | 0).toString(); +}; + +/** + * Handles a handshake request. + * + * @api private + */ + +Manager.prototype.handleHandshake = function (data, req, res) { + var self = this; + + function writeErr (status, message) { + if (data.query.jsonp) { + res.writeHead(200, { 'Content-Type': 'application/javascript' }); + res.end('io.j[' + data.query.jsonp + '](new Error("' + message + '"));'); + } else { + res.writeHead(status); + res.end(message); + } + }; + + function error (err) { + writeErr(500, 'handshake error'); + self.log.warn('handshake error ' + err); + }; + + if (!this.verifyOrigin(req)) { + writeErr(403, 'handshake bad origin'); + return; + } + + var handshakeData = this.handshakeData(data); + + this.authorize(handshakeData, function (err, authorized, newData) { + if (err) return error(err); + + if (authorized) { + var id = self.generateId() + , hs = [ + id + , self.enabled('heartbeats') ? self.get('heartbeat timeout') || '' : '' + , self.get('close timeout') || '' + , self.transports(data).join(',') + ].join(':'); + + if (data.query.jsonp) { + hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');'; + res.writeHead(200, { 'Content-Type': 'application/javascript' }); + } else { + res.writeHead(200); + } + + res.end(hs); + + self.onHandshake(id, newData || handshakeData); + self.store.publish('handshake', id, newData || handshakeData); + + self.log.info('handshake authorized', id); + } else { + writeErr(403, 'handshake unauthorized'); + self.log.info('handshake unauthorized'); + } + }) +}; + +/** + * Gets normalized handshake data + * + * @api private + */ + +Manager.prototype.handshakeData = function (data) { + var connection = data.request.connection + , connectionAddress + , date = new Date; + + if (connection.remoteAddress) { + connectionAddress = { + address: connection.remoteAddress + , port: connection.remotePort + }; + } else if (connection.socket && connection.socket.remoteAddress) { + connectionAddress = { + address: connection.socket.remoteAddress + , port: connection.socket.remotePort + }; + } + + return { + headers: data.headers + , address: connectionAddress + , time: date.toString() + , query: data.query + , url: data.request.url + , xdomain: !!data.request.headers.origin + , secure: data.request.connection.secure + , issued: +date + }; +}; + +/** + * Verifies the origin of a request. + * + * @api private + */ + +Manager.prototype.verifyOrigin = function (request) { + var origin = request.headers.origin + , origins = this.get('origins'); + + if (origin === 'null') origin = '*'; + + if (origins.indexOf('*:*') !== -1) { + return true; + } + + if (origin) { + try { + var parts = url.parse(origin); + + return + ~origins.indexOf(parts.host + ':' + parts.port) || + ~origins.indexOf(parts.host + ':*') || + ~origins.indexOf('*:' + parts.port); + } catch (ex) {} + } + + return false; +}; + +/** + * Handles an incoming packet. + * + * @api private + */ + +Manager.prototype.handlePacket = function (sessid, packet) { + this.of(packet.endpoint || '').handlePacket(sessid, packet); +}; + +/** + * Performs authentication. + * + * @param Object client request data + * @api private + */ + +Manager.prototype.authorize = function (data, fn) { + if (this.get('authorization')) { + var self = this; + + this.get('authorization').call(this, data, function (err, authorized) { + self.log.debug('client ' + authorized ? 'authorized' : 'unauthorized'); + fn(err, authorized); + }); + } else { + this.log.debug('client authorized'); + fn(null, true); + } + + return this; +}; + +/** + * Retrieves the transports adviced to the user. + * + * @api private + */ + +Manager.prototype.transports = function (data) { + var transp = this.get('transports') + , ret = []; + + for (var i = 0, l = transp.length; i < l; i++) { + var transport = transp[i]; + + if (transport) { + if (!transport.checkClient || transport.checkClient(data)) { + ret.push(transport); + } + } + } + + return ret; +}; + +/** + * Checks whether a request is a socket.io one. + * + * @return {Object} a client request data object or `false` + * @api private + */ + +var regexp = /^\/([^\/]+)\/?([^\/]+)?\/?([^\/]+)?\/?$/ + +Manager.prototype.checkRequest = function (req) { + var resource = this.get('resource'); + + if (req.url.substr(0, resource.length) == resource) { + var uri = url.parse(req.url.substr(resource.length), true) + , path = uri.pathname || '' + , pieces = path.match(regexp); + + // client request data + var data = { + query: uri.query || {} + , headers: req.headers + , request: req + , path: path + }; + + if (pieces) { + data.protocol = Number(pieces[1]); + data.transport = pieces[2]; + data.id = pieces[3]; + data.static = !!Manager.static.paths[path]; + }; + + return data; + } + + return false; +}; + +/** + * Declares a socket namespace + * + * @api public + */ + +Manager.prototype.of = function (nsp) { + if (this.namespaces[nsp]) { + return this.namespaces[nsp]; + } + + return this.namespaces[nsp] = new SocketNamespace(this, nsp); +}; + +/** + * Perform garbage collection on long living objects and properties that cannot + * be removed automatically. + * + * @api private + */ + +Manager.prototype.garbageCollection = function () { + // clean up unused handshakes + var ids = Object.keys(this.handshaken) + , i = ids.length + , now = Date.now() + , handshake; + + while (i--) { + handshake = this.handshaken[ids[i]]; + + if ('issued' in handshake && (now - handshake.issued) >= 3E4) { + this.onDisconnect(ids[i]); + } + } +}; diff --git a/node_modules/socket.io/lib/namespace.js b/node_modules/socket.io/lib/namespace.js new file mode 100644 index 0000000..d09e5f6 --- /dev/null +++ b/node_modules/socket.io/lib/namespace.js @@ -0,0 +1,349 @@ +/** + * Module dependencies. + */ + +var Socket = require('./socket') + , EventEmitter = process.EventEmitter + , parser = require('./parser') + , util = require('./util'); + +/** + * Exports the constructor. + */ + +exports = module.exports = SocketNamespace; + +/** + * Constructor. + * + * @api public. + */ + +function SocketNamespace (mgr, name) { + this.manager = mgr; + this.name = name || ''; + this.sockets = {}; + this.auth = false; + this.setFlags(); +}; + +/** + * Inherits from EventEmitter. + */ + +SocketNamespace.prototype.__proto__ = EventEmitter.prototype; + +/** + * Copies emit since we override it + * + * @api private + */ + +SocketNamespace.prototype.$emit = EventEmitter.prototype.emit; + +/** + * Retrieves all clients as Socket instances as an array. + * + * @api public + */ + +SocketNamespace.prototype.clients = function (room) { + var room = this.name + (room !== undefined ? + '/' + room : ''); + + if (!this.manager.rooms[room]) { + return []; + } + + return this.manager.rooms[room].map(function (id) { + return this.socket(id); + }, this); +}; + +/** + * Access logger interface. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('log', function () { + return this.manager.log; +}); + +/** + * Access store. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('store', function () { + return this.manager.store; +}); + +/** + * JSON message flag. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('json', function () { + this.flags.json = true; + return this; +}); + +/** + * Volatile message flag. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('volatile', function () { + this.flags.volatile = true; + return this; +}); + +/** + * Overrides the room to relay messages to (flag) + * + * @api public + */ + +SocketNamespace.prototype.in = SocketNamespace.prototype.to = function (room) { + this.flags.endpoint = this.name + (room ? '/' + room : ''); + return this; +}; + +/** + * Adds a session id we should prevent relaying messages to (flag) + * + * @api public + */ + +SocketNamespace.prototype.except = function (id) { + this.flags.exceptions.push(id); + return this; +}; + +/** + * Sets the default flags. + * + * @api private + */ + +SocketNamespace.prototype.setFlags = function () { + this.flags = { + endpoint: this.name + , exceptions: [] + }; + return this; +}; + +/** + * Sends out a packet + * + * @api private + */ + +SocketNamespace.prototype.packet = function (packet) { + packet.endpoint = this.name; + + var store = this.store + , log = this.log + , volatile = this.flags.volatile + , exceptions = this.flags.exceptions + , packet = parser.encodePacket(packet); + + this.manager.onDispatch(this.flags.endpoint, packet, volatile, exceptions); + this.store.publish('dispatch', this.flags.endpoint, packet, volatile, exceptions); + + this.setFlags(); + + return this; +}; + +/** + * Sends to everyone. + * + * @api public + */ + +SocketNamespace.prototype.send = function (data) { + return this.packet({ + type: this.flags.json ? 'json' : 'message' + , data: data + }); +}; + +/** + * Emits to everyone (override) + * + * @api private + */ + +SocketNamespace.prototype.emit = function (name) { + if (name == 'newListener') { + return this.$emit.apply(this, arguments); + } + + return this.packet({ + type: 'event' + , name: name + , args: util.toArray(arguments).slice(1) + }); +}; + +/** + * Retrieves or creates a write-only socket for a client, unless specified. + * + * @param {Boolean} whether the socket will be readable when initialized + * @api private + */ + +SocketNamespace.prototype.socket = function (sid, readable) { + if (!this.sockets[sid]) { + this.sockets[sid] = new Socket(this.manager, sid, this, readable); + } + + return this.sockets[sid]; +}; + +/** + * Sets authorization for this namespace + * + * @api public + */ + +SocketNamespace.prototype.authorization = function (fn) { + this.auth = fn; + return this; +}; + +/** + * Called when a socket disconnects entirely. + * + * @api private + */ + +SocketNamespace.prototype.handleDisconnect = function (sid, reason) { + if (this.sockets[sid] && this.sockets[sid].readable) { + this.sockets[sid].onDisconnect(reason); + delete this.sockets[sid]; + } +}; + +/** + * Performs authentication. + * + * @param Object client request data + * @api private + */ + +SocketNamespace.prototype.authorize = function (data, fn) { + if (this.auth) { + var self = this; + + this.auth.call(this, data, function (err, authorized) { + self.log.debug('client ' + + (authorized ? '' : 'un') + 'authorized for ' + self.name); + fn(err, authorized); + }); + } else { + this.log.debug('client authorized for ' + this.name); + fn(null, true); + } + + return this; +}; + +/** + * Handles a packet. + * + * @api private + */ + +SocketNamespace.prototype.handlePacket = function (sessid, packet) { + var socket = this.socket(sessid) + , dataAck = packet.ack == 'data' + , self = this; + + function ack () { + self.log.debug('sending data ack packet'); + socket.packet({ + type: 'ack' + , args: util.toArray(arguments) + , ackId: packet.id + }); + }; + + function error (err) { + self.log.warn('handshake error ' + err + ' for ' + self.name); + socket.packet({ type: 'error', reason: err }); + }; + + function connect () { + self.manager.onJoin(sessid, self.name); + self.store.publish('join', sessid, self.name); + + // packet echo + socket.packet({ type: 'connect' }); + + // emit connection event + self.$emit('connection', socket); + }; + + switch (packet.type) { + case 'connect': + if (packet.endpoint == '') { + connect(); + } else { + var manager = this.manager + , handshakeData = manager.handshaken[sessid]; + + this.authorize(handshakeData, function (err, authorized, newData) { + if (err) return error(err); + + if (authorized) { + manager.onHandshake(sessid, newData || handshakeData); + self.store.publish('handshake', sessid, newData || handshakeData); + connect(); + } else { + error('unauthorized'); + } + }); + } + break; + + case 'ack': + if (socket.acks[packet.ackId]) { + socket.acks[packet.ackId].apply(socket, packet.args); + } else { + this.log.info('unknown ack packet'); + } + break; + + case 'event': + var params = [packet.name].concat(packet.args); + + if (dataAck) + params.push(ack); + + socket.$emit.apply(socket, params); + break; + + case 'disconnect': + this.manager.onLeave(sessid, this.name); + this.store.publish('leave', sessid, this.name); + + socket.$emit('disconnect', packet.reason || 'packet'); + break; + + case 'json': + case 'message': + var params = ['message', packet.data]; + + if (dataAck) + params.push(ack); + + socket.$emit.apply(socket, params); + }; +}; diff --git a/node_modules/socket.io/lib/parser.js b/node_modules/socket.io/lib/parser.js new file mode 100644 index 0000000..bdb27b2 --- /dev/null +++ b/node_modules/socket.io/lib/parser.js @@ -0,0 +1,243 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +/** + * Packet types. + */ + +var packets = exports.packets = [ + 'disconnect' + , 'connect' + , 'heartbeat' + , 'message' + , 'json' + , 'event' + , 'ack' + , 'error' + , 'noop' +]; + +/** + * Errors reasons. + */ + +var reasons = exports.reasons = [ + 'transport not supported' + , 'client not handshaken' + , 'unauthorized' +]; + +/** + * Errors advice. + */ + +var advice = exports.advice = [ + 'reconnect' +]; + +/** + * Encodes a packet. + * + * @api private + */ + +exports.encodePacket = function (packet) { + var type = packets.indexOf(packet.type) + , id = packet.id || '' + , endpoint = packet.endpoint || '' + , ack = packet.ack + , data = null; + + switch (packet.type) { + case 'error': + var reason = packet.reason ? reasons.indexOf(packet.reason) : '' + , adv = packet.advice ? advice.indexOf(packet.advice) : '' + + if (reason !== '' || adv !== '') + data = reason + (adv !== '' ? ('+' + adv) : '') + + break; + + case 'message': + if (packet.data !== '') + data = packet.data; + break; + + case 'event': + var ev = { name: packet.name }; + + if (packet.args && packet.args.length) { + ev.args = packet.args; + } + + data = JSON.stringify(ev); + break; + + case 'json': + data = JSON.stringify(packet.data); + break; + + case 'connect': + if (packet.qs) + data = packet.qs; + break; + + case 'ack': + data = packet.ackId + + (packet.args && packet.args.length + ? '+' + JSON.stringify(packet.args) : ''); + break; + } + + // construct packet with required fragments + var encoded = [ + type + , id + (ack == 'data' ? '+' : '') + , endpoint + ]; + + // data fragment is optional + if (data !== null && data !== undefined) + encoded.push(data); + + return encoded.join(':'); +}; + +/** + * Encodes multiple messages (payload). + * + * @param {Array} messages + * @api private + */ + +exports.encodePayload = function (packets) { + var decoded = ''; + + if (packets.length == 1) + return packets[0]; + + for (var i = 0, l = packets.length; i < l; i++) { + var packet = packets[i]; + decoded += '\ufffd' + packet.length + '\ufffd' + packets[i] + } + + return decoded; +}; + +/** + * Decodes a packet + * + * @api private + */ + +var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/; + +exports.decodePacket = function (data) { + var pieces = data.match(regexp); + + if (!pieces) return {}; + + var id = pieces[2] || '' + , data = pieces[5] || '' + , packet = { + type: packets[pieces[1]] + , endpoint: pieces[4] || '' + }; + + // whether we need to acknowledge the packet + if (id) { + packet.id = id; + if (pieces[3]) + packet.ack = 'data'; + else + packet.ack = true; + } + + // handle different packet types + switch (packet.type) { + case 'error': + var pieces = data.split('+'); + packet.reason = reasons[pieces[0]] || ''; + packet.advice = advice[pieces[1]] || ''; + break; + + case 'message': + packet.data = data || ''; + break; + + case 'event': + try { + var opts = JSON.parse(data); + packet.name = opts.name; + packet.args = opts.args; + } catch (e) { } + + packet.args = packet.args || []; + break; + + case 'json': + try { + packet.data = JSON.parse(data); + } catch (e) { } + break; + + case 'connect': + packet.qs = data || ''; + break; + + case 'ack': + var pieces = data.match(/^([0-9]+)(\+)?(.*)/); + if (pieces) { + packet.ackId = pieces[1]; + packet.args = []; + + if (pieces[3]) { + try { + packet.args = pieces[3] ? JSON.parse(pieces[3]) : []; + } catch (e) { } + } + } + break; + + case 'disconnect': + case 'heartbeat': + break; + }; + + return packet; +}; + +/** + * Decodes data payload. Detects multiple messages + * + * @return {Array} messages + * @api public + */ + +exports.decodePayload = function (data) { + if (data[0] == '\ufffd') { + var ret = []; + + for (var i = 1, length = ''; i < data.length; i++) { + if (data[i] == '\ufffd') { + ret.push(exports.decodePacket(data.substr(i + 1).substr(0, length))); + i += Number(length) + 1; + length = ''; + } else { + length += data[i]; + } + } + + return ret; + } else { + return [exports.decodePacket(data)]; + } +}; diff --git a/node_modules/socket.io/lib/socket.io.js b/node_modules/socket.io/lib/socket.io.js new file mode 100644 index 0000000..55870b5 --- /dev/null +++ b/node_modules/socket.io/lib/socket.io.js @@ -0,0 +1,128 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var client = require('socket.io-client'); + +/** + * Version. + */ + +exports.version = '0.7.9'; + +/** + * Supported protocol version. + */ + +exports.protocol = 1; + +/** + * Client that we serve. + */ + +exports.clientVersion = client.version; + +/** + * Attaches a manager + * + * @param {HTTPServer/Number} a HTTP/S server or a port number to listen on. + * @param {Object} opts to be passed to Manager and/or http server + * @param {Function} callback if a port is supplied + * @api public + */ + +exports.listen = function (server, options, fn) { + if ('function' == typeof options) { + fn = options; + options = {}; + } + + if ('undefined' == typeof server) { + // create a server that listens on port 80 + server = 80; + } + + if ('number' == typeof server) { + // if a port number is passed + var port = server; + + if (options && options.key) + server = require('https').createServer(options); + else + server = require('http').createServer(); + + // default response + server.on('request', function (req, res) { + res.writeHead(200); + res.end('Welcome to socket.io.'); + }); + + server.listen(port, fn); + } + + // otherwise assume a http/s server + return new exports.Manager(server, options); +}; + +/** + * Manager constructor. + * + * @api public + */ + +exports.Manager = require('./manager'); + +/** + * Transport constructor. + * + * @api public + */ + +exports.Transport = require('./transport'); + +/** + * Socket constructor. + * + * @api public + */ + +exports.Socket = require('./socket'); + +/** + * Store constructor. + * + * @api public + */ + +exports.Store = require('./store'); + +/** + * Memory Store constructor. + * + * @api public + */ + +exports.MemoryStore = require('./stores/memory'); + +/** + * Redis Store constructor. + * + * @api public + */ + +exports.RedisStore = require('./stores/redis'); + +/** + * Parser. + * + * @api public + */ + +exports.parser = require('./parser'); diff --git a/node_modules/socket.io/lib/socket.js b/node_modules/socket.io/lib/socket.js new file mode 100644 index 0000000..22a8abf --- /dev/null +++ b/node_modules/socket.io/lib/socket.js @@ -0,0 +1,345 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var parser = require('./parser') + , util = require('./util') + , EventEmitter = process.EventEmitter; + +/** + * Export the constructor. + */ + +exports = module.exports = Socket; + +/** + * Socket constructor. + * + * @param {Manager} manager instance + * @param {String} session id + * @param {Namespace} namespace the socket belongs to + * @param {Boolean} whether the + * @api public + */ + +function Socket (manager, id, nsp, readable) { + this.id = id; + this.namespace = nsp; + this.manager = manager; + this.disconnected = false; + this.ackPackets = 0; + this.acks = {}; + this.setFlags(); + this.readable = readable; + this.store = this.manager.store.client(this.id); +}; + +/** + * Inherits from EventEmitter. + */ + +Socket.prototype.__proto__ = EventEmitter.prototype; + +/** + * Accessor shortcut for the handshake data + * + * @api private + */ + +Socket.prototype.__defineGetter__('handshake', function () { + return this.manager.handshaken[this.id]; +}); + +/** + * Accessor shortcut for the logger. + * + * @api private + */ + +Socket.prototype.__defineGetter__('log', function () { + return this.manager.log; +}); + +/** + * JSON message flag. + * + * @api public + */ + +Socket.prototype.__defineGetter__('json', function () { + this.flags.json = true; + return this; +}); + +/** + * Volatile message flag. + * + * @api public + */ + +Socket.prototype.__defineGetter__('volatile', function () { + this.flags.volatile = true; + return this; +}); + +/** + * Broadcast message flag. + * + * @api public + */ + +Socket.prototype.__defineGetter__('broadcast', function () { + this.flags.broadcast = true; + return this; +}); + +/** + * Overrides the room to broadcast messages to (flag) + * + * @api public + */ + +Socket.prototype.to = Socket.prototype.in = function (room) { + this.flags.room = room; + return this; +}; + +/** + * Resets flags + * + * @api private + */ + +Socket.prototype.setFlags = function () { + this.flags = { + endpoint: this.namespace.name + , room: '' + }; + return this; +}; + +/** + * Triggered on disconnect + * + * @api private + */ + +Socket.prototype.onDisconnect = function (reason) { + if (!this.disconnected) { + this.$emit('disconnect', reason); + this.disconnected = true; + } +}; + +/** + * Joins a user to a room. + * + * @api public + */ + +Socket.prototype.join = function (name, fn) { + var nsp = this.namespace.name + , name = (nsp + '/') + name; + + this.manager.onJoin(this.id, name); + this.manager.store.publish('join', this.id, name); + + if (fn) { + this.log.warn('Client#join callback is deprecated'); + fn(); + } + + return this; +}; + +/** + * Joins a user to a room. + * + * @api public + */ + +Socket.prototype.leave = function (name, fn) { + var nsp = this.namespace.name + , name = (nsp + '/') + name; + + this.manager.onLeave(this.id, name); + this.manager.store.publish('leave', this.id, name); + + if (fn) { + this.log.warn('Client#leave callback is deprecated'); + fn(); + } + + return this; +}; + +/** + * Transmits a packet. + * + * @api private + */ + +Socket.prototype.packet = function (packet) { + if (this.flags.broadcast) { + this.log.debug('broadcasting packet'); + this.namespace.in(this.flags.room).except(this.id).packet(packet); + } else { + packet.endpoint = this.flags.endpoint; + packet = parser.encodePacket(packet); + + this.dispatch(packet, this.flags.volatile); + } + + this.setFlags(); + + return this; +}; + +/** + * Dispatches a packet + * + * @api private + */ + +Socket.prototype.dispatch = function (packet, volatile) { + if (this.manager.transports[this.id] && this.manager.transports[this.id].open) { + this.manager.transports[this.id].onDispatch(packet, volatile); + } else { + if (!volatile) { + this.manager.onClientDispatch(this.id, packet, volatile); + } + + this.manager.store.publish('dispatch:' + this.id, packet, volatile); + } +}; + +/** + * Stores data for the client. + * + * @api public + */ + +Socket.prototype.set = function (key, value, fn) { + this.store.set(key, value, fn); + return this; +}; + +/** + * Retrieves data for the client + * + * @api public + */ + +Socket.prototype.get = function (key, fn) { + this.store.get(key, fn); + return this; +}; + +/** + * Checks data for the client + * + * @api public + */ + +Socket.prototype.has = function (key, fn) { + this.store.has(key, fn); + return this; +}; + +/** + * Deletes data for the client + * + * @api public + */ + +Socket.prototype.del = function (key, fn) { + this.store.del(key, fn); + return this; +}; + +/** + * Kicks client + * + * @api public + */ + +Socket.prototype.disconnect = function () { + if (!this.disconnected) { + this.log.info('booting client'); + + if (this.manager.transports[this.id] && this.manager.transports[this.id].open) { + this.manager.transports[this.id].onForcedDisconnect(); + } else { + this.manager.onClientDisconnect(this.id); + this.manager.store.publish('disconnect:' + this.id); + } + } + + return this; +}; + +/** + * Send a message. + * + * @api public + */ + +Socket.prototype.send = function (data, fn) { + var packet = { + type: this.flags.json ? 'json' : 'message' + , data: data + }; + + if (fn) { + packet.id = ++this.ackPackets; + packet.ack = true; + this.acks[packet.id] = fn; + } + + return this.packet(packet); +}; + +/** + * Original emit function. + * + * @api private + */ + +Socket.prototype.$emit = EventEmitter.prototype.emit; + +/** + * Emit override for custom events. + * + * @api public + */ + +Socket.prototype.emit = function (ev) { + if (ev == 'newListener') { + return this.$emit.apply(this, arguments); + } + + var args = util.toArray(arguments).slice(1) + , lastArg = args[args.length - 1] + , packet = { + type: 'event' + , name: ev + }; + + if ('function' == typeof lastArg) { + packet.id = ++this.ackPackets; + packet.ack = lastArg.length ? 'data' : true; + this.acks[packet.id] = lastArg; + args = args.slice(0, args.length - 1); + } + + packet.args = args; + + return this.packet(packet); +}; diff --git a/node_modules/socket.io/lib/store.js b/node_modules/socket.io/lib/store.js new file mode 100644 index 0000000..06c0389 --- /dev/null +++ b/node_modules/socket.io/lib/store.js @@ -0,0 +1,98 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Expose the constructor. + */ + +exports = module.exports = Store; + +/** + * Module dependencies. + */ + +var EventEmitter = process.EventEmitter; + +/** + * Store interface + * + * @api public + */ + +function Store (options) { + this.options = options; + this.clients = {}; +}; + +/** + * Inherit from EventEmitter. + */ + +Store.prototype.__proto__ = EventEmitter.prototype; + +/** + * Initializes a client store + * + * @param {String} id + * @api public + */ + +Store.prototype.client = function (id) { + if (!this.clients[id]) { + this.clients[id] = new (this.constructor.Client)(this, id); + } + + return this.clients[id]; +}; + +/** + * Destroys a client + * + * @api {String} sid + * @param {Number} number of seconds to expire client data + * @api private + */ + +Store.prototype.destroyClient = function (id, expiration) { + if (this.clients[id]) { + this.clients[id].destroy(expiration); + delete this.clients[id]; + } + + return this; +}; + +/** + * Destroys the store + * + * @param {Number} number of seconds to expire client data + * @api private + */ + +Store.prototype.destroy = function (clientExpiration) { + var keys = Object.keys(this.clients) + , count = keys.length; + + for (var i = 0, l = count; i < l; i++) { + this.destroyClient(keys[i], clientExpiration); + } + + this.clients = {}; + + return this; +}; + +/** + * Client. + * + * @api public + */ + +Store.Client = function (store, id) { + this.store = store; + this.id = id; +}; diff --git a/node_modules/socket.io/lib/stores/memory.js b/node_modules/socket.io/lib/stores/memory.js new file mode 100644 index 0000000..8b731a7 --- /dev/null +++ b/node_modules/socket.io/lib/stores/memory.js @@ -0,0 +1,143 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var crypto = require('crypto') + , Store = require('../store'); + +/** + * Exports the constructor. + */ + +exports = module.exports = Memory; +Memory.Client = Client; + +/** + * Memory store + * + * @api public + */ + +function Memory (opts) { + Store.call(this, opts); +}; + +/** + * Inherits from Store. + */ + +Memory.prototype.__proto__ = Store.prototype; + +/** + * Publishes a message. + * + * @api private + */ + +Memory.prototype.publish = function () { }; + +/** + * Subscribes to a channel + * + * @api private + */ + +Memory.prototype.subscribe = function () { }; + +/** + * Unsubscribes + * + * @api private + */ + +Memory.prototype.unsubscribe = function () { }; + +/** + * Client constructor + * + * @api private + */ + +function Client () { + Store.Client.apply(this, arguments); + this.data = {}; +}; + +/** + * Inherits from Store.Client + */ + +Client.prototype.__proto__ = Store.Client; + +/** + * Gets a key + * + * @api public + */ + +Client.prototype.get = function (key, fn) { + fn(null, this.data[key] === undefined ? null : this.data[key]); + return this; +}; + +/** + * Sets a key + * + * @api public + */ + +Client.prototype.set = function (key, value, fn) { + this.data[key] = value; + fn && fn(null); + return this; +}; + +/** + * Has a key + * + * @api public + */ + +Client.prototype.has = function (key, fn) { + fn(null, key in this.data); +}; + +/** + * Deletes a key + * + * @api public + */ + +Client.prototype.del = function (key, fn) { + delete this.data[key]; + fn && fn(null); + return this; +}; + +/** + * Destroys the client. + * + * @param {Number} number of seconds to expire data + * @api private + */ + +Client.prototype.destroy = function (expiration) { + if ('number' != typeof expiration) { + this.data = {}; + } else { + var self = this; + + setTimeout(function () { + self.data = {}; + }, expiration * 1000); + } + + return this; +}; diff --git a/node_modules/socket.io/lib/stores/redis.js b/node_modules/socket.io/lib/stores/redis.js new file mode 100644 index 0000000..26f7a92 --- /dev/null +++ b/node_modules/socket.io/lib/stores/redis.js @@ -0,0 +1,250 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var crypto = require('crypto') + , Store = require('../store') + , assert = require('assert'); + +/** + * Exports the constructor. + */ + +exports = module.exports = Redis; +Redis.Client = Client; + +/** + * Redis store. + * Options: + * - nodeId (fn) gets an id that uniquely identifies this node + * - redis (fn) redis constructor, defaults to redis + * - redisPub (object) options to pass to the pub redis client + * - redisSub (object) options to pass to the sub redis client + * - redisClient (object) options to pass to the general redis client + * - pack (fn) custom packing, defaults to JSON or msgpack if installed + * - unpack (fn) custom packing, defaults to JSON or msgpack if installed + * + * @api public + */ + +function Redis (opts) { + opts = opts || {}; + + // node id to uniquely identify this node + var nodeId = opts.nodeId || function () { + // by default, we generate a random id + return Math.abs(Math.random() * Math.random() * Date.now() | 0); + }; + + this.nodeId = nodeId(); + + // packing / unpacking mechanism + if (opts.pack) { + this.pack = opts.pack; + this.unpack = opts.unpack; + } else { + try { + var msgpack = require('msgpack'); + this.pack = msgpack.pack; + this.unpack = msgpack.unpack; + } catch (e) { + this.pack = JSON.stringify; + this.unpack = JSON.parse; + } + } + + var redis = opts.redis || require('redis'); + + // initialize a pubsub client and a regular client + this.pub = redis.createClient(opts.redisPub); + this.sub = redis.createClient(opts.redisSub); + this.cmd = redis.createClient(opts.redisClient); + + Store.call(this, opts); +}; + +/** + * Inherits from Store. + */ + +Redis.prototype.__proto__ = Store.prototype; + +/** + * Publishes a message. + * + * @api private + */ + +Redis.prototype.publish = function (name) { + var args = Array.prototype.slice.call(arguments, 1); + this.pub.publish(name, this.pack({ nodeId: this.nodeId, args: args })); + this.emit.apply(this, ['publish', name].concat(args)); +}; + +/** + * Subscribes to a channel + * + * @api private + */ + +Redis.prototype.subscribe = function (name, consumer, fn) { + this.sub.subscribe(name); + + if (consumer || fn) { + var self = this; + + self.sub.on('subscribe', function subscribe (ch) { + if (name == ch) { + function message (ch, msg) { + if (name == ch) { + msg = self.unpack(msg); + + // we check that the message consumed wasnt emitted by this node + if (self.nodeId != msg.nodeId) { + consumer.apply(null, msg.args); + } + } + }; + + self.sub.on('message', message); + + self.on('unsubscribe', function unsubscribe (ch) { + if (name == ch) { + self.sub.removeListener('message', message); + self.removeEvent('unsubscribe', unsubscribe); + } + }); + + self.sub.removeListener('subscribe', subscribe); + + fn && fn(); + } + }); + } + + this.emit('subscribe', name, consumer, fn); +}; + +/** + * Unsubscribes + * + * @api private + */ + +Redis.prototype.unsubscribe = function (name, fn) { + this.sub.unsubscribe(name); + + if (fn) { + var client = this.sub; + + client.on('unsubscribe', function unsubscribe (ch) { + if (name == ch) { + fn(); + client.removeListener('unsubscribe', unsubscribe); + } + }); + } + + this.emit('unsubscribe', name, fn); +}; + +/** + * Destroys the store + * + * @api public + */ + +Redis.prototype.destroy = function () { + Store.prototype.destroy.call(this); + + this.pub.end(); + this.sub.end(); + this.cmd.end(); +}; + +/** + * Client constructor + * + * @api private + */ + +function Client (store, id) { + Store.Client.call(this, store, id); +}; + +/** + * Inherits from Store.Client + */ + +Client.prototype.__proto__ = Store.Client; + +/** + * Redis hash get + * + * @api private + */ + +Client.prototype.get = function (key, fn) { + this.store.cmd.hget(this.id, key, fn); + return this; +}; + +/** + * Redis hash set + * + * @api private + */ + +Client.prototype.set = function (key, value, fn) { + this.store.cmd.hset(this.id, key, value, fn); + return this; +}; + +/** + * Redis hash del + * + * @api private + */ + +Client.prototype.del = function (key, fn) { + this.store.cmd.hdel(this.id, key, fn); + return this; +}; + +/** + * Redis hash has + * + * @api private + */ + +Client.prototype.has = function (key, fn) { + this.store.cmd.hexists(this.id, key, function (err, has) { + if (err) return fn(err); + fn(null, !!has); + }); + return this; +}; + +/** + * Destroys client + * + * @param {Number} number of seconds to expire data + * @api private + */ + +Client.prototype.destroy = function (expiration) { + if ('number' != typeof expiration) { + this.store.cmd.del(this.id); + } else { + this.store.cmd.expire(this.id, expiration); + } + + return this; +}; diff --git a/node_modules/socket.io/lib/transport.js b/node_modules/socket.io/lib/transport.js new file mode 100644 index 0000000..61f456f --- /dev/null +++ b/node_modules/socket.io/lib/transport.js @@ -0,0 +1,534 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var parser = require('./parser'); + +/** + * Expose the constructor. + */ + +exports = module.exports = Transport; + +/** + * Transport constructor. + * + * @api public + */ + +function Transport (mng, data, req) { + this.manager = mng; + this.id = data.id; + this.disconnected = false; + this.drained = true; + this.handleRequest(req); +}; + +/** + * Access the logger. + * + * @api public + */ + +Transport.prototype.__defineGetter__('log', function () { + return this.manager.log; +}); + +/** + * Access the store. + * + * @api public + */ + +Transport.prototype.__defineGetter__('store', function () { + return this.manager.store; +}); + +/** + * Handles a request when it's set. + * + * @api private + */ + +Transport.prototype.handleRequest = function (req) { + this.log.debug('setting request', req.method, req.url); + this.req = req; + + if (req.method == 'GET') { + this.socket = req.socket; + this.open = true; + this.drained = true; + this.setHeartbeatInterval(); + + this.setHandlers(); + this.onSocketConnect(); + } +}; + +/** + * Called when a connection is first set. + * + * @api private + */ + +Transport.prototype.onSocketConnect = function () { }; + +/** + * Sets transport handlers + * + * @api private + */ + +Transport.prototype.setHandlers = function () { + var self = this; + + // we need to do this in a pub/sub way since the client can POST the message + // over a different socket (ie: different Transport instance) + this.store.subscribe('heartbeat-clear:' + this.id, function () { + self.onHeartbeatClear(); + }); + + this.store.subscribe('disconnect-force:' + this.id, function () { + self.onForcedDisconnect(); + }); + + this.store.subscribe('dispatch:' + this.id, function (packet, volatile) { + self.onDispatch(packet, volatile); + }); + + this.bound = { + end: this.onSocketEnd.bind(this) + , close: this.onSocketClose.bind(this) + , error: this.onSocketError.bind(this) + , drain: this.onSocketDrain.bind(this) + }; + + this.socket.on('end', this.bound.end); + this.socket.on('close', this.bound.close); + this.socket.on('error', this.bound.error); + this.socket.on('drain', this.bound.drain); + + this.handlersSet = true; +}; + +/** + * Removes transport handlers + * + * @api private + */ + +Transport.prototype.clearHandlers = function () { + if (this.handlersSet) { + this.store.unsubscribe('disconnect-force:' + this.id); + this.store.unsubscribe('heartbeat-clear:' + this.id); + this.store.unsubscribe('dispatch:' + this.id); + + this.socket.removeListener('end', this.bound.end); + this.socket.removeListener('close', this.bound.close); + this.socket.removeListener('error', this.bound.error); + this.socket.removeListener('drain', this.bound.drain); + } +}; + +/** + * Called when the connection dies + * + * @api private + */ + +Transport.prototype.onSocketEnd = function () { + this.end('socket end'); +}; + +/** + * Called when the connection dies + * + * @api private + */ + +Transport.prototype.onSocketClose = function (error) { + this.end(error ? 'socket error' : 'socket close'); +}; + +/** + * Called when the connection has an error. + * + * @api private + */ + +Transport.prototype.onSocketError = function (err) { + if (this.open) { + this.socket.destroy(); + this.onClose(); + } + + this.log.info('socket error ' + err.stack); +}; + +/** + * Called when the connection is drained. + * + * @api private + */ + +Transport.prototype.onSocketDrain = function () { + this.drained = true; +}; + +/** + * Called upon receiving a heartbeat packet. + * + * @api private + */ + +Transport.prototype.onHeartbeatClear = function () { + this.clearHeartbeatTimeout(); + this.setHeartbeatInterval(); +}; + +/** + * Called upon a forced disconnection. + * + * @api private + */ + +Transport.prototype.onForcedDisconnect = function () { + if (!this.disconnected) { + this.log.info('transport end by forced client disconnection'); + if (this.open) { + this.packet({ type: 'disconnect' }); + } + this.end('booted'); + } +}; + +/** + * Dispatches a packet. + * + * @api private + */ + +Transport.prototype.onDispatch = function (packet, volatile) { + if (volatile) { + this.writeVolatile(packet); + } else { + this.write(packet); + } +}; + +/** + * Sets the close timeout. + */ + +Transport.prototype.setCloseTimeout = function () { + if (!this.closeTimeout) { + var self = this; + + this.closeTimeout = setTimeout(function () { + self.log.debug('fired close timeout for client', self.id); + self.closeTimeout = null; + self.end('close timeout'); + }, this.manager.get('close timeout') * 1000); + + this.log.debug('set close timeout for client', this.id); + } +}; + +/** + * Clears the close timeout. + */ + +Transport.prototype.clearCloseTimeout = function () { + if (this.closeTimeout) { + clearTimeout(this.closeTimeout); + this.closeTimeout = null; + + this.log.debug('cleared close timeout for client', this.id); + } +}; + +/** + * Sets the heartbeat timeout + */ + +Transport.prototype.setHeartbeatTimeout = function () { + if (!this.heartbeatTimeout && this.manager.enabled('heartbeats')) { + var self = this; + + this.heartbeatTimeout = setTimeout(function () { + self.log.debug('fired heartbeat timeout for client', self.id); + self.heartbeatTimeout = null; + self.end('heartbeat timeout'); + }, this.manager.get('heartbeat timeout') * 1000); + + this.log.debug('set heartbeat timeout for client', this.id); + } +}; + +/** + * Clears the heartbeat timeout + * + * @param text + */ + +Transport.prototype.clearHeartbeatTimeout = function () { + if (this.heartbeatTimeout && this.manager.enabled('heartbeats')) { + clearTimeout(this.heartbeatTimeout); + this.heartbeatTimeout = null; + this.log.debug('cleared heartbeat timeout for client', this.id); + } +}; + +/** + * Sets the heartbeat interval. To be called when a connection opens and when + * a heartbeat is received. + * + * @api private + */ + +Transport.prototype.setHeartbeatInterval = function () { + if (!this.heartbeatInterval && this.manager.enabled('heartbeats')) { + var self = this; + + this.heartbeatInterval = setTimeout(function () { + self.heartbeat(); + self.heartbeatInterval = null; + }, this.manager.get('heartbeat interval') * 1000); + + this.log.debug('set heartbeat interval for client', this.id); + } +}; + +/** + * Clears all timeouts. + * + * @api private + */ + +Transport.prototype.clearTimeouts = function () { + this.clearCloseTimeout(); + this.clearHeartbeatTimeout(); + this.clearHeartbeatInterval(); +}; + +/** + * Sends a heartbeat + * + * @api private + */ + +Transport.prototype.heartbeat = function () { + if (this.open) { + this.log.debug('emitting heartbeat for client', this.id); + this.packet({ type: 'heartbeat' }); + this.setHeartbeatTimeout(); + } + + return this; +}; + +/** + * Handles a message. + * + * @param {Object} packet object + * @api private + */ + +Transport.prototype.onMessage = function (packet) { + var current = this.manager.transports[this.id]; + + if ('heartbeat' == packet.type) { + this.log.debug('got heartbeat packet'); + + if (current && current.open) { + current.onHeartbeatClear(); + } else { + this.store.publish('heartbeat-clear:' + this.id); + } + } else { + if ('disconnect' == packet.type && packet.endpoint == '') { + this.log.debug('got disconnection packet'); + + if (current) { + current.onForcedDisconnect(); + } else { + this.store.publish('disconnect-force:' + this.id); + } + + return; + } + + if (packet.id && packet.ack != 'data') { + this.log.debug('acknowledging packet automatically'); + + var ack = parser.encodePacket({ + type: 'ack' + , ackId: packet.id + , endpoint: packet.endpoint || '' + }); + + if (current && current.open) { + current.onDispatch(ack); + } else { + this.manager.onClientDispatch(this.id, ack); + this.store.publish('dispatch:' + this.id, ack); + } + } + + // handle packet locally or publish it + if (current) { + this.manager.onClientMessage(this.id, packet); + } else { + this.store.publish('message:' + this.id, packet); + } + } +}; + +/** + * Clears the heartbeat interval + * + * @api private + */ + +Transport.prototype.clearHeartbeatInterval = function () { + if (this.heartbeatInterval && this.manager.enabled('heartbeats')) { + clearTimeout(this.heartbeatInterval); + this.heartbeatInterval = null; + this.log.debug('cleared heartbeat interval for client', this.id); + } +}; + +/** + * Finishes the connection and makes sure client doesn't reopen + * + * @api private + */ + +Transport.prototype.disconnect = function (reason) { + this.packet({ type: 'disconnect' }); + this.end(reason); + + return this; +}; + +/** + * Closes the connection. + * + * @api private + */ + +Transport.prototype.close = function () { + if (this.open) { + this.doClose(); + this.onClose(); + } +}; + +/** + * Called upon a connection close. + * + * @api private + */ + +Transport.prototype.onClose = function () { + if (this.open) { + this.setCloseTimeout(); + this.clearHandlers(); + this.open = false; + this.manager.onClose(this.id); + this.store.publish('close', this.id); + } +}; + +/** + * Cleans up the connection, considers the client disconnected. + * + * @api private + */ + +Transport.prototype.end = function (reason) { + if (!this.disconnected) { + this.log.info('transport end'); + + var local = this.manager.transports[this.id]; + + this.close(); + this.clearTimeouts(); + this.disconnected = true; + + if (local) { + this.manager.onClientDisconnect(this.id, reason, true); + } else { + this.store.publish('disconnect:' + this.id, reason); + } + } +}; + +/** + * Signals that the transport should pause and buffer data. + * + * @api public + */ + +Transport.prototype.discard = function () { + this.log.debug('discarding transport'); + this.discarded = true; + this.clearTimeouts(); + this.clearHandlers(); + + return this; +}; + +/** + * Writes an error packet with the specified reason and advice. + * + * @param {Number} advice + * @param {Number} reason + * @api public + */ + +Transport.prototype.error = function (reason, advice) { + this.packet({ + type: 'error' + , reason: reason + , advice: advice + }); + + this.log.warn(reason, advice ? ('client should ' + advice) : ''); + this.end('error'); +}; + +/** + * Write a packet. + * + * @api public + */ + +Transport.prototype.packet = function (obj) { + return this.write(parser.encodePacket(obj)); +}; + +/** + * Writes a volatile message. + * + * @api private + */ + +Transport.prototype.writeVolatile = function (msg) { + if (this.open) { + if (this.drained) { + this.write(msg); + } else { + this.log.debug('ignoring volatile packet, buffer not drained'); + } + } else { + this.log.debug('ignoring volatile packet, transport not open'); + } +}; diff --git a/node_modules/socket.io/lib/transports/flashsocket.js b/node_modules/socket.io/lib/transports/flashsocket.js new file mode 100644 index 0000000..48b3d95 --- /dev/null +++ b/node_modules/socket.io/lib/transports/flashsocket.js @@ -0,0 +1,102 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ +var WebSocket = require('./websocket'); + +/** + * Export the constructor. + */ + +exports = module.exports = FlashSocket; + +/** + * The FlashSocket transport is just a proxy + * for WebSocket connections. + * + * @api public + */ + +function FlashSocket (mng, data, req) { + WebSocket.call(this, mng, data, req); +} + +/** + * Inherits from WebSocket. + */ + +FlashSocket.prototype.__proto__ = WebSocket.prototype; + +/** + * Transport name + * + * @api public + */ + +FlashSocket.prototype.name = 'flashsocket'; + +/** + * Listens for new configuration changes of the Manager + * this way we can enable and disable the flash server. + * + * @param {Manager} Manager instance. + * @api private + */ + +var server; + +FlashSocket.init = function (manager) { + function create () { + server = require('policyfile').createServer({ + log: function(msg){ + manager.log.info(msg.toLowerCase()); + } + }, manager.get('origins')); + + server.on('close', function (e) { + server = null; + }); + + server.listen(manager.get('flash policy port'), manager.server); + + manager.flashPolicyServer = server; + } + + // listen for origin changes, so we can update the server + manager.on('set:origins', function (value, key) { + if (!server) return; + + // update the origins and compile a new response buffer + server.origins = Array.isArray(value) ? value : [value]; + server.compile(); + }); + + // destory the server and create a new server + manager.on('set:flash policy port', function (value, key) { + var transports = manager.get('transports'); + + if (server && server.port !== value && ~transports.indexOf('flashsocket')) { + // destroy the server and rebuild it on a new port + server.close(); + create(); + } + }); + + // only start the server + manager.on('set:transports', function (value, key){ + if (!server && ~manager.get('transports').indexOf('flashsocket')) { + create(); + } + }); + + // check if we need to initialize at start + if (~manager.get('transports').indexOf('flashsocket')){ + create(); + } +}; diff --git a/node_modules/socket.io/lib/transports/htmlfile.js b/node_modules/socket.io/lib/transports/htmlfile.js new file mode 100644 index 0000000..6bbac75 --- /dev/null +++ b/node_modules/socket.io/lib/transports/htmlfile.js @@ -0,0 +1,82 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPTransport = require('./http'); + +/** + * Export the constructor. + */ + +exports = module.exports = HTMLFile; + +/** + * HTMLFile transport constructor. + * + * @api public + */ + +function HTMLFile (mng, data, req) { + HTTPTransport.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +HTMLFile.prototype.__proto__ = HTTPTransport.prototype; + +/** + * Transport name + * + * @api public + */ + +HTMLFile.prototype.name = 'htmlfile'; + +/** + * Handles the request. + * + * @api private + */ + +HTMLFile.prototype.handleRequest = function (req) { + HTTPTransport.prototype.handleRequest.call(this, req); + + if (req.method == 'GET') { + req.res.writeHead(200, { + 'Content-Type': 'text/html' + , 'Connection': 'keep-alive' + , 'Transfer-Encoding': 'chunked' + }); + + req.res.write( + '' + + '' + + new Array(174).join(' ') + ); + } +}; + +/** + * Performs the write. + * + * @api private + */ + +HTMLFile.prototype.write = function (data) { + data = ''; + + if (this.response.write(data)) { + this.drained = true; + } + + this.log.debug(this.name + ' writing', data); +}; diff --git a/node_modules/socket.io/lib/transports/http-polling.js b/node_modules/socket.io/lib/transports/http-polling.js new file mode 100644 index 0000000..c71fc9c --- /dev/null +++ b/node_modules/socket.io/lib/transports/http-polling.js @@ -0,0 +1,135 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPTransport = require('./http'); + +/** + * Exports the constructor. + */ + +exports = module.exports = HTTPPolling; + +/** + * HTTP polling constructor. + * + * @api public. + */ + +function HTTPPolling (mng, data, req) { + HTTPTransport.call(this, mng, data, req); +}; + +/** + * Inherits from HTTPTransport. + * + * @api public. + */ + +HTTPPolling.prototype.__proto__ = HTTPTransport.prototype; + +/** + * Transport name + * + * @api public + */ + +HTTPPolling.prototype.name = 'httppolling'; + +/** + * Removes heartbeat timeouts for polling. + */ + +HTTPPolling.prototype.setHeartbeatInterval = function () { + return this; +}; + +/** + * Handles a request + * + * @api private + */ + +HTTPPolling.prototype.handleRequest = function (req) { + HTTPTransport.prototype.handleRequest.call(this, req); + + if (req.method == 'GET') { + var self = this; + + this.pollTimeout = setTimeout(function () { + self.packet({ type: 'noop' }); + self.log.debug(self.name + ' closed due to exceeded duration'); + }, this.manager.get('polling duration') * 1000); + + this.log.debug('setting poll timeout'); + } +}; + +/** + * Clears polling timeout + * + * @api private + */ + +HTTPPolling.prototype.clearPollTimeout = function () { + if (this.pollTimeout) { + clearTimeout(this.pollTimeout); + this.pollTimeout = null; + this.log.debug('clearing poll timeout'); + } + + return this; +}; + +/** + * Override clear timeouts to clear the poll timeout + * + * @api private + */ + +HTTPPolling.prototype.clearTimeouts = function () { + HTTPTransport.prototype.clearTimeouts.call(this); + + this.clearPollTimeout(); +}; + +/** + * doWrite to clear poll timeout + * + * @api private + */ + +HTTPPolling.prototype.doWrite = function () { + this.clearPollTimeout(); +}; + +/** + * Performs a write. + * + * @api private. + */ + +HTTPPolling.prototype.write = function (data, close) { + this.doWrite(data); + this.response.end(); + this.onClose(); +}; + +/** + * Override end. + * + * @api private + */ + +HTTPPolling.prototype.end = function () { + this.clearPollTimeout(); + return HTTPTransport.prototype.end.call(this); +}; + diff --git a/node_modules/socket.io/lib/transports/http.js b/node_modules/socket.io/lib/transports/http.js new file mode 100644 index 0000000..cbf4e26 --- /dev/null +++ b/node_modules/socket.io/lib/transports/http.js @@ -0,0 +1,111 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var Transport = require('../transport') + , parser = require('../parser') + , qs = require('querystring'); + +/** + * Export the constructor. + */ + +exports = module.exports = HTTPTransport; + +/** + * HTTP interface constructor. For all non-websocket transports. + * + * @api public + */ + +function HTTPTransport (mng, data, req) { + Transport.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +HTTPTransport.prototype.__proto__ = Transport.prototype; + +/** + * Handles a request. + * + * @api private + */ + +HTTPTransport.prototype.handleRequest = function (req) { + if (req.method == 'POST') { + var buffer = '' + , res = req.res + , origin = req.headers.origin + , headers = { 'Content-Length': 1 } + , self = this; + + req.on('data', function (data) { + buffer += data; + }); + + req.on('end', function () { + res.writeHead(200, headers); + res.end('1'); + + self.onData(self.postEncoded ? qs.parse(buffer).d : buffer); + }); + + if (origin) { + // https://developer.mozilla.org/En/HTTP_Access_Control + headers['Access-Control-Allow-Origin'] = '*'; + + if (req.headers.cookie) { + headers['Access-Control-Allow-Credentials'] = 'true'; + } + } + } else { + this.response = req.res; + + Transport.prototype.handleRequest.call(this, req); + } +}; + +/** + * Handles data payload. + * + * @api private + */ + +HTTPTransport.prototype.onData = function (data) { + var messages = parser.decodePayload(data); + + for (var i = 0, l = messages.length; i < l; i++) { + this.log.debug(this.name + ' received data packet', data); + this.onMessage(messages[i]); + } +}; + +/** + * Closes the request-response cycle + * + * @api private + */ + +HTTPTransport.prototype.doClose = function () { + this.response.end(); +}; + +/** + * Writes a payload of messages + * + * @api private + */ + +HTTPTransport.prototype.payload = function (msgs) { + this.write(parser.encodePayload(msgs)); +}; diff --git a/node_modules/socket.io/lib/transports/index.js b/node_modules/socket.io/lib/transports/index.js new file mode 100644 index 0000000..b865559 --- /dev/null +++ b/node_modules/socket.io/lib/transports/index.js @@ -0,0 +1,12 @@ + +/** + * Export transports. + */ + +module.exports = { + websocket: require('./websocket') + , flashsocket: require('./flashsocket') + , htmlfile: require('./htmlfile') + , 'xhr-polling': require('./xhr-polling') + , 'jsonp-polling': require('./jsonp-polling') +}; diff --git a/node_modules/socket.io/lib/transports/jsonp-polling.js b/node_modules/socket.io/lib/transports/jsonp-polling.js new file mode 100644 index 0000000..86a23f0 --- /dev/null +++ b/node_modules/socket.io/lib/transports/jsonp-polling.js @@ -0,0 +1,78 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPPolling = require('./http-polling'); + +/** + * Export the constructor. + */ + +exports = module.exports = JSONPPolling; + +/** + * JSON-P polling transport. + * + * @api public + */ + +function JSONPPolling (mng, data, req) { + HTTPPolling.call(this, mng, data, req); + + this.head = 'io.j[0]('; + this.foot = ');'; + + if (data.query.i) { + this.head = 'io.j[' + data.query.i + ']('; + } +}; + +/** + * Inherits from Transport. + */ + +JSONPPolling.prototype.__proto__ = HTTPPolling.prototype; + +/** + * Transport name + * + * @api public + */ + +JSONPPolling.prototype.name = 'jsonppolling'; + +/** + * Make sure POST are decoded. + */ + +JSONPPolling.prototype.postEncoded = true; + +/** + * Performs the write. + * + * @api private + */ + +JSONPPolling.prototype.doWrite = function (data) { + HTTPPolling.prototype.doWrite.call(this); + + var data = data === undefined + ? '' : this.head + JSON.stringify(data) + this.foot; + + this.response.writeHead(200, { + 'Content-Type': 'text/javascript; charset=UTF-8' + , 'Content-Length': Buffer.byteLength(data) + , 'Connection': 'Keep-Alive' + , 'X-XSS-Protection': '0' + }); + + this.response.write(data); + this.log.debug(this.name + ' writing', data); +}; diff --git a/node_modules/socket.io/lib/transports/websocket.js b/node_modules/socket.io/lib/transports/websocket.js new file mode 100644 index 0000000..41f90dc --- /dev/null +++ b/node_modules/socket.io/lib/transports/websocket.js @@ -0,0 +1,350 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var Transport = require('../transport') + , EventEmitter = process.EventEmitter + , crypto = require('crypto') + , parser = require('../parser'); + +/** + * Export the constructor. + */ + +exports = module.exports = WebSocket; + +/** + * HTTP interface constructor. Interface compatible with all transports that + * depend on request-response cycles. + * + * @api public + */ + +function WebSocket (mng, data, req) { + // parser + var self = this; + + this.parser = new Parser(); + this.parser.on('data', function (packet) { + self.log.debug(self.name + ' received data packet', packet); + self.onMessage(parser.decodePacket(packet)); + }); + this.parser.on('close', function () { + self.end(); + }); + this.parser.on('error', function () { + self.end(); + }); + + Transport.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +WebSocket.prototype.__proto__ = Transport.prototype; + +/** + * Transport name + * + * @api public + */ + +WebSocket.prototype.name = 'websocket'; + +/** + * Called when the socket connects. + * + * @api private + */ + +WebSocket.prototype.onSocketConnect = function () { + var self = this; + + this.socket.setNoDelay(true); + + this.buffer = true; + this.buffered = []; + + if (this.req.headers.upgrade !== 'WebSocket') { + this.log.warn(this.name + ' connection invalid'); + this.end(); + return; + } + + var origin = this.req.headers.origin + , location = (this.socket.encrypted ? 'wss' : 'ws') + + '://' + this.req.headers.host + this.req.url + , waitingForNonce = false; + + if (this.req.headers['sec-websocket-key1']) { + // If we don't have the nonce yet, wait for it (HAProxy compatibility). + if (! (this.req.head && this.req.head.length >= 8)) { + waitingForNonce = true; + } + + var headers = [ + 'HTTP/1.1 101 WebSocket Protocol Handshake' + , 'Upgrade: WebSocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Origin: ' + origin + , 'Sec-WebSocket-Location: ' + location + ]; + + if (this.req.headers['sec-websocket-protocol']){ + headers.push('Sec-WebSocket-Protocol: ' + + this.req.headers['sec-websocket-protocol']); + } + } else { + var headers = [ + 'HTTP/1.1 101 Web Socket Protocol Handshake' + , 'Upgrade: WebSocket' + , 'Connection: Upgrade' + , 'WebSocket-Origin: ' + origin + , 'WebSocket-Location: ' + location + ]; + } + + try { + this.socket.write(headers.concat('', '').join('\r\n')); + this.socket.setTimeout(0); + this.socket.setNoDelay(true); + this.socket.setEncoding('utf8'); + } catch (e) { + this.end(); + return; + } + + if (waitingForNonce) { + this.socket.setEncoding('binary'); + } else if (this.proveReception(headers)) { + self.flush(); + } + + var headBuffer = ''; + + this.socket.on('data', function (data) { + if (waitingForNonce) { + headBuffer += data; + + if (headBuffer.length < 8) { + return; + } + + // Restore the connection to utf8 encoding after receiving the nonce + self.socket.setEncoding('utf8'); + waitingForNonce = false; + + // Stuff the nonce into the location where it's expected to be + self.req.head = headBuffer.substr(0, 8); + headBuffer = ''; + + if (self.proveReception(headers)) { + self.flush(); + } + + return; + } + + self.parser.add(data); + }); +}; + +/** + * Writes to the socket. + * + * @api private + */ + +WebSocket.prototype.write = function (data) { + if (this.open) { + this.drained = false; + + if (this.buffer) { + this.buffered.push(data); + return this; + } + + var length = Buffer.byteLength(data) + , buffer = new Buffer(2 + length); + + buffer.write('\u0000', 'binary'); + buffer.write(data, 1, 'utf8'); + buffer.write('\uffff', 1 + length, 'binary'); + + try { + if (this.socket.write(buffer)) { + this.drained = true; + } + } catch (e) { + this.end(); + } + + this.log.debug(this.name + ' writing', data); + } +}; + +/** + * Flushes the internal buffer + * + * @api private + */ + +WebSocket.prototype.flush = function () { + this.buffer = false; + + for (var i = 0, l = this.buffered.length; i < l; i++) { + this.write(this.buffered.splice(0, 1)[0]); + } +}; + +/** + * Finishes the handshake. + * + * @api private + */ + +WebSocket.prototype.proveReception = function (headers) { + var self = this + , k1 = this.req.headers['sec-websocket-key1'] + , k2 = this.req.headers['sec-websocket-key2']; + + if (k1 && k2){ + var md5 = crypto.createHash('md5'); + + [k1, k2].forEach(function (k) { + var n = parseInt(k.replace(/[^\d]/g, '')) + , spaces = k.replace(/[^ ]/g, '').length; + + if (spaces === 0 || n % spaces !== 0){ + self.log.warn('Invalid ' + self.name + ' key: "' + k + '".'); + self.end(); + return false; + } + + n /= spaces; + + md5.update(String.fromCharCode( + n >> 24 & 0xFF, + n >> 16 & 0xFF, + n >> 8 & 0xFF, + n & 0xFF)); + }); + + md5.update(this.req.head.toString('binary')); + + try { + this.socket.write(md5.digest('binary'), 'binary'); + } catch (e) { + this.end(); + } + } + + return true; +}; + +/** + * Writes a payload. + * + * @api private + */ + +WebSocket.prototype.payload = function (msgs) { + for (var i = 0, l = msgs.length; i < l; i++) { + this.write(msgs[i]); + } + + return this; +}; + +/** + * Closes the connection. + * + * @api private + */ + +WebSocket.prototype.doClose = function () { + this.socket.end(); +}; + +/** + * WebSocket parser + * + * @api public + */ + +function Parser () { + this.buffer = ''; + this.i = 0; +}; + +/** + * Inherits from EventEmitter. + */ + +Parser.prototype.__proto__ = EventEmitter.prototype; + +/** + * Adds data to the buffer. + * + * @api public + */ + +Parser.prototype.add = function (data) { + this.buffer += data; + this.parse(); +}; + +/** + * Parses the buffer. + * + * @api private + */ + +Parser.prototype.parse = function () { + for (var i = this.i, chr, l = this.buffer.length; i < l; i++){ + chr = this.buffer[i]; + + if (this.buffer.length == 2 && this.buffer[1] == '\u0000') { + this.emit('close'); + this.buffer = ''; + this.i = 0; + return; + } + + if (i === 0){ + if (chr != '\u0000') + this.error('Bad framing. Expected null byte as first frame'); + else + continue; + } + + if (chr == '\ufffd'){ + this.emit('data', this.buffer.substr(1, i - 1)); + this.buffer = this.buffer.substr(i + 1); + this.i = 0; + return this.parse(); + } + } +}; + +/** + * Handles an error + * + * @api private + */ + +Parser.prototype.error = function (reason) { + this.buffer = ''; + this.i = 0; + this.emit('error', reason); + return this; +}; diff --git a/node_modules/socket.io/lib/transports/xhr-polling.js b/node_modules/socket.io/lib/transports/xhr-polling.js new file mode 100644 index 0000000..fee2438 --- /dev/null +++ b/node_modules/socket.io/lib/transports/xhr-polling.js @@ -0,0 +1,72 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPPolling = require('./http-polling'); + +/** + * Export the constructor. + */ + +exports = module.exports = XHRPolling; + +/** + * Ajax polling transport. + * + * @api public + */ + +function XHRPolling (mng, data, req) { + HTTPPolling.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +XHRPolling.prototype.__proto__ = HTTPPolling.prototype; + +/** + * Transport name + * + * @api public + */ + +XHRPolling.prototype.name = 'xhr-polling'; + +/** + * Frames data prior to write. + * + * @api private + */ + +XHRPolling.prototype.doWrite = function (data) { + HTTPPolling.prototype.doWrite.call(this); + + var origin = this.req.headers.origin + , headers = { + 'Content-Type': 'text/plain; charset=UTF-8' + , 'Content-Length': data === undefined ? 0 : Buffer.byteLength(data) + , 'Connection': 'Keep-Alive' + }; + + if (origin) { + // https://developer.mozilla.org/En/HTTP_Access_Control + headers['Access-Control-Allow-Origin'] = '*'; + + if (this.req.headers.cookie) { + headers['Access-Control-Allow-Credentials'] = 'true'; + } + } + + this.response.writeHead(200, headers); + this.response.write(data); + this.log.debug(this.name + ' writing', data); +}; diff --git a/node_modules/socket.io/lib/util.js b/node_modules/socket.io/lib/util.js new file mode 100644 index 0000000..25f31f2 --- /dev/null +++ b/node_modules/socket.io/lib/util.js @@ -0,0 +1,25 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +/** + * Converts an enumerable to an array. + * + * @api public + */ + +exports.toArray = function (enu) { + var arr = []; + + for (var i = 0, l = enu.length; i < l; i++) + arr.push(enu[i]); + + return arr; +}; diff --git a/node_modules/socket.io/node_modules/policyfile/LICENSE b/node_modules/socket.io/node_modules/policyfile/LICENSE new file mode 100644 index 0000000..bdb8f61 --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Arnout Kazemier,3rd-Eden + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/socket.io/node_modules/policyfile/Makefile b/node_modules/socket.io/node_modules/policyfile/Makefile new file mode 100644 index 0000000..1362d66 --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/Makefile @@ -0,0 +1,7 @@ +doc: + dox --title "FlashPolicyFileServer" lib/* > doc/index.html + +test: + expresso -I lib $(TESTFLAGS) tests/*.test.js + +.PHONY: test doc \ No newline at end of file diff --git a/node_modules/socket.io/node_modules/policyfile/README.md b/node_modules/socket.io/node_modules/policyfile/README.md new file mode 100644 index 0000000..527921e --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/README.md @@ -0,0 +1,98 @@ +## LOL, WUT? +It basically allows you to allow or disallow Flash Player sockets from accessing your site. + +## Installation + +```bash +npm install policyfile +``` +## Usage + +The server is based on the regular and know `net` and `http` server patterns. So it you can just listen +for all the events that a `net` based server emits etc. But there is one extra event, the `connect_failed` +event. This event is triggered when we are unable to listen on the supplied port number. + +### createServer +Creates a new server instance and accepts 2 optional arguments: + +- `options` **Object** Options to configure the server instance + - `log` **Boolean** Enable logging to STDOUT and STDERR (defaults to true) +- `origins` **Array** An Array of origins that are allowed by the server (defaults to *:*) + +```js +var pf = require('policyfile'); +pf.createServer(); +pf.listen(); +``` + +#### server.listen +Start listening on the server and it takes 3 optional arguments + +- `port` **Number** On which port number should we listen? (defaults to 843, which is the first port number the FlashPlayer checks) +- `server` **Server** A http server, if we are unable to accept requests or run the server we can also answer the policy requests inline over the supplied HTTP server. +- `callback` **Function** A callback function that is called when listening to the server was successful. + +```js +var pf = require('policyfile'); +pf.createServer(); +pf.listen(1337, function(){ + console.log(':3 yay') +}); +``` + +Changing port numbers can be handy if you do not want to run your server as root and have port 843 forward to a non root port number (aka a number above 1024). + +```js +var pf = require('policyfile') + , http = require('http'); + +server = http.createServer(function(q,r){r.writeHead(200);r.end('hello world')}); +server.listen(80); + +pf.createServer(); +pf.listen(1337, server, function(){ + console.log(':3 yay') +}); +``` + +Support for serving inline requests over a existing HTTP connection as the FlashPlayer will first check port 843, but if it's unable to get a response there it will send a policy file request over port 80, which is usually your http server. + +#### server.add +Adds more origins to the policy file you can add as many arguments as you like. + +```js +var pf = require('policyfile'); +pf.createServer(['google.com:80']); +pf.listen(); +pf.add('blog.3rd-Eden.com:80', 'blog.3rd-Eden.com:8080'); // now has 3 origins +``` + +#### server.add +Adds more origins to the policy file you can add as many arguments as you like. + +```js +var pf = require('policyfile'); +pf.createServer(['blog.3rd-Eden.com:80', 'blog.3rd-Eden.com:8080']); +pf.listen(); +pf.remove('blog.3rd-Eden.com:8080'); // only contains the :80 version now +``` + +#### server.close +Shuts down the server + +```js +var pf = require('policyfile'); +pf.createServer(); +pf.listen(); +pf.close(); // OH NVM. +``` + +## API +http://3rd-eden.com/FlashPolicyFileServer/ + +## Examples +See https://github.com/3rd-Eden/FlashPolicyFileServer/tree/master/examples for examples + +## Licence + +MIT see LICENSE file in the repository \ No newline at end of file diff --git a/node_modules/socket.io/node_modules/policyfile/doc/index.html b/node_modules/socket.io/node_modules/policyfile/doc/index.html new file mode 100644 index 0000000..743fcda --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/doc/index.html @@ -0,0 +1,375 @@ + + + FlashPolicyFileServer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    FlashPolicyFileServer

    server

    lib/server.js
    +

    Module dependencies and cached references. +

    +
    +
    var slice = Array.prototype.slice
    +  , net = require('net');
    +
    +

    The server that does the Policy File severing

    + +

    Options

    + +
    • log false or a function that can output log information, defaults to console.log?
    + +

    + +
    • param: Object options Options to customize the servers functionality.

    • param: Array origins The origins that are allowed on this server, defaults to *:*.

    • api: public

    +
    +
    function Server(options, origins){
    +  var me = this;
    +  
    +  this.origins = origins || ['*:*'];
    +  this.port = 843;
    +  this.log = console.log;
    +  
    +  // merge `this` with the options
    +  Object.keys(options).forEach(function(key){
    +    me[key] &amp;&amp; (me[key] = options[key])
    +  });
    +  
    +  // create the net server
    +  this.socket = net.createServer(function createServer(socket){
    +    socket.on('error', function socketError(){ me.responder.call(me, socket) });
    +    me.responder.call(me, socket);
    +  });
    +  
    +  // Listen for errors as the port might be blocked because we do not have root priv.
    +  this.socket.on('error', function serverError(err){
    +    // Special and common case error handling
    +    if (err.errno == 13){
    +      me.log &amp;&amp; me.log(
    +        'Unable to listen to port `' + me.port + '` as your Node.js instance does not have root privileges. ' +
    +        (
    +          me.server
    +          ? 'The Flash Policy file will now be served inline over the supplied HTTP server, Flash Policy files request will suffer.'
    +          : 'No fallback server supplied.'
    +        )
    +      );
    +      
    +      me.socket.removeAllListeners();
    +      delete me.socket;
    +
    +      me.emit('connect_failed', err);
    +    } else {
    +      me.log &amp;&amp; me.log('FlashPolicyFileServer received a error event:\n' + (err.message ? err.message : err));
    +    }
    +  });
    +  
    +  this.socket.on('timeout', function serverTimeout(){});
    +  this.socket.on('close', function serverClosed(err){
    +    err &amp;&amp; me.log &amp;&amp; me.log('Server closing due to an error: \n' + (err.message ? err.message : err));
    +    
    +    if (me.server){
    +      // not online anymore
    +      delete me.server.online;
    +      
    +      // Remove the inline policy listener if we close down
    +      // but only when the server was `online` (see listen prototype)
    +      if( me.server['@'] &amp;&amp; me.server.online){
    +        me.server.removeListener('connection', me.server['@']);
    +      }
    +    }
    +    me.log &amp;&amp; me.log('Shutting down FlashPolicyFileServer');
    +  });
    +  
    +  // Compile the initial `buffer`
    +  this.compile();
    +}
    +
    +

    Start listening for requests

    + +

    + +
    • param: Number port The port number it should be listening to.

    • param: Server server A HTTP server instance, this will be used to listen for inline requests

    • param: Function cb The callback needs to be called once server is ready

    • api: public

    +
    +
    Server.prototype.listen = function listen(port, server, cb){
    +  var me = this
    +    , args = slice.call(arguments, 0)
    +    , callback;
    +  
    +  // assign the correct vars, for flexible arguments
    +  args.forEach(function args(arg){
    +    var type = typeof arg;
    +    
    +    if (type === 'number') me.port = arg;
    +    if (type === 'function') callback = arg;
    +    if (type === 'object') me.server = arg;
    +  });
    +  
    +  if (this.server){
    +    
    +    // no one in their right mind would ever create a `@` prototype, so Im just gonna store
    +    // my function on the server, so I can remove it later again once the server(s) closes
    +    this.server['@'] = function connection(socket){
    +      socket.once('data', function requestData(data){
    +        // if it's a Flash policy request, and we can write to the 
    +        if (
    +             data
    +          &amp;&amp; data[0] === 60
    +          &amp;&amp; data.toString() === '<policy-file-request/>\0'
    +          &amp;&amp; socket
    +          &amp;&amp; (socket.readyState === 'open' || socket.readyState === 'writeOnly')
    +        ){
    +          // send the buffer
    +          socket.end(me.buffer);
    +        }
    +      });
    +    };
    +    // attach it
    +    this.server.on('connection', this.server['@']);
    +  }
    +  
    +  // We add a callback method, so we can set a flag for when the server is `enabled` or `online`.
    +  // this flag is needed because if a error occurs and the we cannot boot up the server the
    +  // fallback functionality should not be removed during the `close` event
    +  this.socket.listen(this.port, function serverListening(){
    +   me.socket.online = true;
    +   
    +   if (callback) callback(), callback = undefined;
    +   
    +  });
    +  
    +  return this;
    +};
    +
    +

    Adds a new origin to the Flash Policy File.

    + +

    + +
    • param: Arguments The origins that need to be added.

    • api: public

    +
    +
    Server.prototype.add = function add(){
    +  var args = slice.call(arguments, 0)
    +    , i = args.length;
    +  
    +  // flag duplicates
    +  while (i--){
    +    if (this.origins.indexOf(args[i]) &gt;= 0){
    +      args[i] = null;
    +    }
    +  }
    +  
    +  // Add all the arguments to the array
    +  // but first we want to remove all `falsy` values from the args
    +  Array.prototype.push.apply(
    +    this.origins
    +  , args.filter(function(value){ return !!value })
    +  );
    +  
    +  this.compile();
    +  return this;
    +};
    +
    +

    Removes a origin from the Flash Policy File.

    + +

    + +
    • param: String origin The origin that needs to be removed from the server

    • api: public

    +
    +
    Server.prototype.remove = function remove(origin){
    +  var position = this.origins.indexOf(origin);
    +  
    +  // only remove and recompile if we have a match
    +  if (position &gt; 0){
    +    this.origins.splice(position,1);
    +    this.compile();
    +  }
    +  
    +  return this;
    +};
    +
    +

    Closes and cleans up the server

    + +
    • api: public

    +
    +
    Server.prototype.close = function close(){
    +  this.socket.removeAllListeners();
    +  this.socket.close();
    +  
    +  return this;
    +};
    +
    +

    Proxy the event listener requests to the created Net server +

    +
    +
    Object.keys(process.EventEmitter.prototype).forEach(function proxy(key){
    +  Server.prototype[key] = Server.prototype[key] || function (){
    +    if (this.socket) this.socket[key].apply(this.socket, arguments);
    +    return this;
    +  };
    +});
    +
    +

    Creates a new server instance.

    + +

    + +
    • param: Object options A options object to override the default config

    • param: Array origins The origins that should be allowed by the server

    • api: public

    +
    +
    exports.createServer = function createServer(options, origins){
    +  origins = Array.isArray(origins) ? origins : (Array.isArray(options) ? options : false);
    +  options = !Array.isArray(options) &amp;&amp; options ? options : {};
    +  
    +  return new Server(options, origins);
    +};
    +
    +

    Provide a hook to the original server, so it can be extended if needed. +

    +
    +
    exports.Server = Server;
    +
    +

    Module version +

    +
    +
    exports.version = '0.0.2';
    +
    +
    \ No newline at end of file diff --git a/node_modules/socket.io/node_modules/policyfile/examples/basic.fallback.js b/node_modules/socket.io/node_modules/policyfile/examples/basic.fallback.js new file mode 100644 index 0000000..b439449 --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/examples/basic.fallback.js @@ -0,0 +1,8 @@ +var http = require('http') + , fspfs = require('../'); + +var server = http.createServer(function(q,r){ r.writeHead(200); r.end(':3') }) + , flash = fspfs.createServer(); + +server.listen(8080); +flash.listen(8081,server); \ No newline at end of file diff --git a/node_modules/socket.io/node_modules/policyfile/examples/basic.js b/node_modules/socket.io/node_modules/policyfile/examples/basic.js new file mode 100644 index 0000000..5e2290f --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/examples/basic.js @@ -0,0 +1,5 @@ +var http = require('http') + , fspfs = require('../'); + +var flash = fspfs.createServer(); +flash.listen(); \ No newline at end of file diff --git a/node_modules/socket.io/node_modules/policyfile/index.js b/node_modules/socket.io/node_modules/policyfile/index.js new file mode 100644 index 0000000..60cf298 --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/server.js'); \ No newline at end of file diff --git a/node_modules/socket.io/node_modules/policyfile/lib/server.js b/node_modules/socket.io/node_modules/policyfile/lib/server.js new file mode 100644 index 0000000..a525772 --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/lib/server.js @@ -0,0 +1,289 @@ +/** + * Module dependencies and cached references. + */ + +var slice = Array.prototype.slice + , net = require('net'); + +/** + * The server that does the Policy File severing + * + * Options: + * - `log` false or a function that can output log information, defaults to console.log? + * + * @param {Object} options Options to customize the servers functionality. + * @param {Array} origins The origins that are allowed on this server, defaults to `*:*`. + * @api public + */ + +function Server (options, origins) { + var me = this; + + this.origins = origins || ['*:*']; + this.port = 843; + this.log = console.log; + + // merge `this` with the options + Object.keys(options).forEach(function (key) { + me[key] && (me[key] = options[key]) + }); + + // create the net server + this.socket = net.createServer(function createServer (socket) { + socket.on('error', function socketError () { + me.responder.call(me, socket); + }); + + me.responder.call(me, socket); + }); + + // Listen for errors as the port might be blocked because we do not have root priv. + this.socket.on('error', function serverError (err) { + // Special and common case error handling + if (err.errno == 13) { + me.log && me.log( + 'Unable to listen to port `' + me.port + '` as your Node.js instance does not have root privileges. ' + + ( + me.server + ? 'The Flash Policy File requests will only be served inline over the supplied HTTP server. Inline serving is slower than a dedicated server instance.' + : 'No fallback server supplied, we will be unable to answer Flash Policy File requests.' + ) + ); + + me.emit('connect_failed', err); + me.socket.removeAllListeners(); + delete me.socket; + } else { + me.log && me.log('FlashPolicyFileServer received an error event:\n' + (err.message ? err.message : err)); + } + }); + + this.socket.on('timeout', function serverTimeout () {}); + this.socket.on('close', function serverClosed (err) { + err && me.log && me.log('Server closing due to an error: \n' + (err.message ? err.message : err)); + + if (me.server) { + // Remove the inline policy listener if we close down + // but only when the server was `online` (see listen prototype) + if (me.server['@'] && me.server.online) { + me.server.removeListener('connection', me.server['@']); + } + + // not online anymore + delete me.server.online; + } + }); + + // Compile the initial `buffer` + this.compile(); +} + +/** + * Start listening for requests + * + * @param {Number} port The port number it should be listening to. + * @param {Server} server A HTTP server instance, this will be used to listen for inline requests + * @param {Function} cb The callback needs to be called once server is ready + * @api public + */ + +Server.prototype.listen = function listen (port, server, cb){ + var me = this + , args = slice.call(arguments, 0) + , callback; + + // assign the correct vars, for flexible arguments + args.forEach(function args (arg){ + var type = typeof arg; + + if (type === 'number') me.port = arg; + if (type === 'function') callback = arg; + if (type === 'object') me.server = arg; + }); + + if (this.server) { + + // no one in their right mind would ever create a `@` prototype, so Im just gonna store + // my function on the server, so I can remove it later again once the server(s) closes + this.server['@'] = function connection (socket) { + socket.once('data', function requestData (data) { + // if it's a Flash policy request, and we can write to the + if ( + data + && data[0] === 60 + && data.toString() === '\0' + && socket + && (socket.readyState === 'open' || socket.readyState === 'writeOnly') + ){ + // send the buffer + try { + socket.end(me.buffer); + } catch (e) {} + } + }); + }; + + // attach it + this.server.on('connection', this.server['@']); + } + + // We add a callback method, so we can set a flag for when the server is `enabled` or `online`. + // this flag is needed because if a error occurs and the we cannot boot up the server the + // fallback functionality should not be removed during the `close` event + this.port >= 0 && this.socket.listen(this.port, function serverListening () { + me.socket.online = true; + if (callback) { + callback.call(me); + callback = undefined; + } + }); + + return this; +}; + +/** + * Responds to socket connects and writes the compile policy file. + * + * @param {net.Socket} socket The socket that needs to receive the message + * @api private + */ + +Server.prototype.responder = function responder (socket){ + if (socket && socket.readyState == 'open' && socket.end) { + try { + socket.end(this.buffer); + } catch (e) {} + } +}; + +/** + * Compiles the supplied origins to a Flash Policy File format and stores it in a Node.js Buffer + * this way it can be send over the wire without any performance loss. + * + * @api private + */ + +Server.prototype.compile = function compile (){ + var xml = [ + '' + , '' + , '' + ]; + + // add the allow access element + this.origins.forEach(function origin (origin){ + var parts = origin.split(':'); + xml.push(''); + }); + + xml.push(''); + + // store the result in a buffer so we don't have to re-generate it all the time + this.buffer = new Buffer(xml.join(''), 'utf8'); + + return this; +}; + +/** + * Adds a new origin to the Flash Policy File. + * + * @param {Arguments} The origins that need to be added. + * @api public + */ + +Server.prototype.add = function add(){ + var args = slice.call(arguments, 0) + , i = args.length; + + // flag duplicates + while (i--) { + if (this.origins.indexOf(args[i]) >= 0){ + args[i] = null; + } + } + + // Add all the arguments to the array + // but first we want to remove all `falsy` values from the args + Array.prototype.push.apply( + this.origins + , args.filter(function filter (value) { + return !!value; + }) + ); + + this.compile(); + return this; +}; + +/** + * Removes a origin from the Flash Policy File. + * + * @param {String} origin The origin that needs to be removed from the server + * @api public + */ + +Server.prototype.remove = function remove (origin){ + var position = this.origins.indexOf(origin); + + // only remove and recompile if we have a match + if (position > 0) { + this.origins.splice(position,1); + this.compile(); + } + + return this; +}; + +/** + * Closes and cleans up the server + * + * @api public + */ + +Server.prototype.close = function close () { + this.socket.removeAllListeners(); + this.socket.close(); + + return this; +}; + +/** + * Proxy the event listener requests to the created Net server + */ + +Object.keys(process.EventEmitter.prototype).forEach(function proxy (key){ + Server.prototype[key] = Server.prototype[key] || function () { + if (this.socket) { + this.socket[key].apply(this.socket, arguments); + } + + return this; + }; +}); + +/** + * Creates a new server instance. + * + * @param {Object} options A options object to override the default config + * @param {Array} origins The origins that should be allowed by the server + * @api public + */ + +exports.createServer = function createServer(options, origins){ + origins = Array.isArray(origins) ? origins : (Array.isArray(options) ? options : false); + options = !Array.isArray(options) && options ? options : {}; + + return new Server(options, origins); +}; + +/** + * Provide a hook to the original server, so it can be extended if needed. + */ + +exports.Server = Server; + +/** + * Module version + */ + +exports.version = '0.0.4'; diff --git a/node_modules/socket.io/node_modules/policyfile/package.json b/node_modules/socket.io/node_modules/policyfile/package.json new file mode 100644 index 0000000..78526c5 --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/package.json @@ -0,0 +1,32 @@ +{ + "name": "policyfile" + , "version": "0.0.4" + , "author": "Arnout Kazemier" + , "description": "Flash Socket Policy File Server. A server to respond to Flash Socket Policy requests, both inline and through a dedicated server instance." + , "main": "index" + , "keywords":[ + "flash" + , "socket" + , "policy" + , "file" + , "server" + , "Flash Socket Policy File Server" + , "cross domain" + ] + , "directories": { + "lib": "./lib" + } + , "maintainers": [{ + "name":"Arnout Kazemier" + , "email":"info@3rd-Eden.com" + , "web":"http://blog.3rd-Eden.com" + }] + , "licenses": [{ + "type": "MIT" + , "url": "https://github.com/3rd-Eden/FlashPolicyFileServer/blob/master/LICENSE" + }] + , "repositories": [{ + "type": "git" + , "url" : "https://github.com/3rd-Eden/FlashPolicyFileServer.git" + }] +} diff --git a/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.crt b/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.crt new file mode 100644 index 0000000..5883cd4 --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAMUSOvlaeyQHMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTAxMTE2MDkzMjQ5WhcNMTMxMTE1MDkzMjQ5WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEVwfPQQp4X +wtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+1FAE0c5o +exPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404WthquTqg +S7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy25IyBK3QJ +c+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWAQsqW+COL +0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABo1AwTjAdBgNVHQ4EFgQUDnV4d6mD +tOnluLoCjkUHTX/n4agwHwYDVR0jBBgwFoAUDnV4d6mDtOnluLoCjkUHTX/n4agw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAFwV4MQfTo+qMv9JMiyno +IEiqfOz4RgtmBqRnXUffcjS2dhc7/z+FPZnM79Kej8eLHoVfxCyWRHFlzm93vEdv +wxOCrD13EDOi08OOZfxWyIlCa6Bg8cMAKqQzd2OvQOWqlRWBTThBJIhWflU33izX +Qn5GdmYqhfpc+9ZHHGhvXNydtRQkdxVK2dZNzLBvBlLlRmtoClU7xm3A+/5dddeP +AQHEPtyFlUw49VYtZ3ru6KqPms7MKvcRhYLsy9rwSfuuniMlx4d0bDR7TOkw0QQS +A0N8MGQRQpzl4mw4jLzyM5d5QtuGBh2P6hPGa0YQxtI3RPT/p6ENzzBiAKXiSfzo +xw== +-----END CERTIFICATE----- diff --git a/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.private.key b/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.private.key new file mode 100644 index 0000000..f31ff3d --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/tests/ssl/ssl.private.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEV +wfPQQp4XwtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+ +1FAE0c5oexPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404 +WthquTqgS7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy2 +5IyBK3QJc+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWA +QsqW+COL0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABAoIBAGe4+9VqZfJN+dsq +8Osyuz01uQ8OmC0sAWTIqUlQgENIyf9rCJsUBlYmwR5BT6Z69XP6QhHdpSK+TiAR +XUz0EqG9HYzcxHIBaACP7j6iRoQ8R4kbbiWKo0z3WqQGIOqFjvD/mKEuQdE5mEYw +eOUCG6BnX1WY2Yr8WKd2AA/tp0/Y4d8z04u9eodMpSTbHTzYMJb5SbBN1vo6FY7q +8zSuO0BMzXlAxUsCwHsk1GQHFr8Oh3zIR7bQGtMBouI+6Lhh7sjFYsfxJboqMTBV +IKaA216M6ggHG7MU1/jeKcMGDmEfqQLQoyWp29rMK6TklUgipME2L3UD7vTyAVzz +xbVOpZkCgYEA8CXW4sZBBrSSrLR5SB+Ubu9qNTggLowOsC/kVKB2WJ4+xooc5HQo +mFhq1v/WxPQoWIxdYsfg2odlL+JclK5Qcy6vXmRSdAQ5lK9gBDKxZSYc3NwAw2HA +zyHCTK+I0n8PBYQ+yGcrxu0WqTGnlLW+Otk4CejO34WlgHwbH9bbY5UCgYEA3ZvT +C4+OoMHXlmICSt29zUrYiL33IWsR3/MaONxTEDuvgkOSXXQOl/8Ebd6Nu+3WbsSN +bjiPC/JyL1YCVmijdvFpl4gjtgvfJifs4G+QHvO6YfsYoVANk4u6g6rUuBIOwNK4 +RwYxwDc0oysp+g7tPxoSgDHReEVKJNzGBe9NGGsCgYEA4O4QP4gCEA3B9BF2J5+s +n9uPVxmiyvZUK6Iv8zP4pThTBBMIzNIf09G9AHPQ7djikU2nioY8jXKTzC3xGTHM +GJZ5m6fLsu7iH+nDvSreDSeNkTBfZqGAvoGYQ8uGE+L+ZuRfCcXYsxIOT5s6o4c3 +Dle2rVFpsuKzCY00urW796ECgYBn3go75+xEwrYGQSer6WR1nTgCV29GVYXKPooy +zmmMOT1Yw80NSkEw0pFD4cTyqVYREsTrPU0mn1sPfrOXxnGfZSVFpcR/Je9QVfQ7 +eW7GYxwfom335aqHVj10SxRqteP+UoWWnHujCPz94VRKZMakBddYCIGSan+G6YdS +7sdmwwKBgBc2qj0wvGXDF2kCLwSGfWoMf8CS1+5fIiUIdT1e/+7MfDdbmLMIFVjF +QKS3zVViXCbrG5SY6wS9hxoc57f6E2A8vcaX6zy2xkZlGHQCpWRtEM5R01OWJQaH +HsHMmQZGUQVoDm1oRkDhrTFK4K3ukc3rAxzeTZ96utOQN8/KJsTv +-----END RSA PRIVATE KEY----- diff --git a/node_modules/socket.io/node_modules/policyfile/tests/unit.test.js b/node_modules/socket.io/node_modules/policyfile/tests/unit.test.js new file mode 100644 index 0000000..932b3c1 --- /dev/null +++ b/node_modules/socket.io/node_modules/policyfile/tests/unit.test.js @@ -0,0 +1,231 @@ +var fspfs = require('../') + , fs = require('fs') + , http = require('http') + , https = require('https') + , net = require('net') + , should = require('should') + , assert = require('assert'); + +module.exports = { + // Library version should be Semver compatible + 'Library version': function(){ + fspfs.version.should.match(/^\d+\.\d+\.\d+$/); + } + + // Creating a server instace should not cause any problems + // either using the new Server or createServer method. +, 'Create Server instance': function(){ + var server = fspfs.createServer() + , server2 = new fspfs.Server({log:false}, ['blog.3rd-Eden.com:1337']); + + // server 2 options test + server2.log.should.be.false; + server2.origins.length.should.equal(1); + server2.origins[0].should.equal('blog.3rd-Eden.com:1337'); + + // server defaults + (typeof server.log).should.be.equal('function'); + server.origins.length.should.equal(1); + server.origins[0].should.equal('*:*'); + + // instance checking, sanity check + assert.ok(server instanceof fspfs.Server); + assert.ok(!!server.buffer); + + // more options testing + server = fspfs.createServer(['blog.3rd-Eden.com:80']); + server.origins.length.should.equal(1); + server.origins[0].should.equal('blog.3rd-Eden.com:80'); + + server = fspfs.createServer({log:false},['blog.3rd-Eden.com:80']); + server.log.should.be.false; + server.origins.length.should.equal(1); + server.origins[0].should.equal('blog.3rd-Eden.com:80'); + + } + +, 'Add origin': function(){ + var server = fspfs.createServer(); + server.add('google.com:80', 'blog.3rd-Eden.com:1337'); + + server.origins.length.should.equal(3); + server.origins.indexOf('google.com:80').should.be.above(0); + + // don't allow duplicates + server.add('google.com:80', 'google.com:80'); + + var i = server.origins.length + , count = 0; + + while(i--){ + if (server.origins[i] === 'google.com:80'){ + count++; + } + } + + count.should.equal(1); + } + +, 'Remove origin': function(){ + var server = fspfs.createServer(); + server.add('google.com:80', 'blog.3rd-Eden.com:1337'); + server.origins.length.should.equal(3); + + server.remove('google.com:80'); + server.origins.length.should.equal(2); + server.origins.indexOf('google.com:80').should.equal(-1); + } + +, 'Buffer': function(){ + var server = fspfs.createServer(); + + Buffer.isBuffer(server.buffer).should.be.true; + server.buffer.toString().indexOf('to-ports="*"').should.be.above(0); + server.buffer.toString().indexOf('domain="*"').should.be.above(0); + server.buffer.toString().indexOf('domain="google.com"').should.equal(-1); + + // The buffers should be rebuild when new origins are added + server.add('google.com:80'); + server.buffer.toString().indexOf('to-ports="80"').should.be.above(0); + server.buffer.toString().indexOf('domain="google.com"').should.be.above(0); + + server.remove('google.com:80'); + server.buffer.toString().indexOf('to-ports="80"').should.equal(-1); + server.buffer.toString().indexOf('domain="google.com"').should.equal(-1); + } + +, 'Responder': function(){ + var server = fspfs.createServer() + , calls = 0 + // dummy socket to emulate a `real` socket + , dummySocket = { + readyState: 'open' + , end: function(buffer){ + calls++; + Buffer.isBuffer(buffer).should.be.true; + buffer.toString().should.equal(server.buffer.toString()); + } + }; + + server.responder(dummySocket); + calls.should.equal(1); + } + +, 'Event proxy': function(){ + var server = fspfs.createServer() + , calls = 0; + + Object.keys(process.EventEmitter.prototype).forEach(function proxy(key){ + assert.ok(!!server[key] && typeof server[key] === 'function'); + }); + + // test if it works by calling a none default event + server.on('pew', function(){ + calls++; + }); + + server.emit('pew'); + calls.should.equal(1); + } + +, 'inline response http': function(){ + var port = 1335 + , httpserver = http.createServer(function(q,r){r.writeHead(200);r.end(':3')}) + , server = fspfs.createServer(); + + httpserver.listen(port, function(){ + server.listen(port + 1, httpserver, function(){ + var client = net.createConnection(port); + client.write('\0'); + client.on('error', function(err){ + assert.ok(!err, err) + }); + client.on('data', function(data){ + + var response = data.toString(); + console.log(response); + + response.indexOf('to-ports="*"').should.be.above(0); + response.indexOf('domain="*"').should.be.above(0); + response.indexOf('domain="google.com"').should.equal(-1); + + // clean up + client.destroy(); + server.close(); + httpserver.close(); + }); + }); + }); + } + +, 'server response': function(){ + var port = 1340 + , server = fspfs.createServer(); + + server.listen(port, function(){ + var client = net.createConnection(port); + client.write('\0'); + client.on('error', function(err){ + assert.ok(!err, err) + }); + client.on('data', function(data){ + + var response = data.toString(); + + response.indexOf('to-ports="*"').should.be.above(0); + response.indexOf('domain="*"').should.be.above(0); + response.indexOf('domain="google.com"').should.equal(-1); + + // clean up + client.destroy(); + server.close(); + }); + }); + } + +, 'inline response https': function(){ + var port = 1345 + , ssl = { + key: fs.readFileSync(__dirname + '/ssl/ssl.private.key').toString() + , cert: fs.readFileSync(__dirname + '/ssl/ssl.crt').toString() + } + , httpserver = https.createServer(ssl, function(q,r){r.writeHead(200);r.end(':3')}) + , server = fspfs.createServer(); + + httpserver.listen(port, function(){ + server.listen(port + 1, httpserver, function(){ + var client = net.createConnection(port); + client.write('\0'); + client.on('error', function(err){ + assert.ok(!err, err) + }); + client.on('data', function(data){ + + var response = data.toString(); + + response.indexOf('to-ports="*"').should.be.above(0); + response.indexOf('domain="*"').should.be.above(0); + response.indexOf('domain="google.com"').should.equal(-1); + + // clean up + client.destroy(); + server.close(); + httpserver.close(); + }); + }); + }); + } + +, 'connect_failed': function(){ + var server = fspfs.createServer(); + + server.on('connect_failed', function(){ + assert.ok(true); + }); + + server.listen(function(){ + assert.ok(false, 'Run this test without root access'); + server.close(); + }); + } +}; \ No newline at end of file diff --git a/node_modules/socket.io/node_modules/redis/README.md b/node_modules/socket.io/node_modules/redis/README.md new file mode 100644 index 0000000..02a873b --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/README.md @@ -0,0 +1,567 @@ +redis - a node.js redis client +=========================== + +This is a complete Redis client for node.js. It supports all Redis commands, including many recently added commands like EVAL from +experimental Redis server branches. + + +Install with: + + npm install redis + +Pieter Noordhuis has provided a binding to the official `hiredis` C library, which is non-blocking and fast. To use `hiredis`, do: + + npm install hiredis redis + +If `hiredis` is installed, `node_redis` will use it by default. Otherwise, a pure JavaScript parser will be used. + +If you use `hiredis`, be sure to rebuild it whenever you upgrade your version of node. There are mysterious failures that can +happen between node and native code modules after a node upgrade. + + +## Usage + +Simple example, included as `examples/simple.js`: + + var redis = require("redis"), + client = redis.createClient(); + + client.on("error", function (err) { + console.log("Error " + err); + }); + + client.set("string key", "string val", redis.print); + client.hset("hash key", "hashtest 1", "some value", redis.print); + client.hset(["hash key", "hashtest 2", "some other value"], redis.print); + client.hkeys("hash key", function (err, replies) { + console.log(replies.length + " replies:"); + replies.forEach(function (reply, i) { + console.log(" " + i + ": " + reply); + }); + client.quit(); + }); + +This will display: + + mjr:~/work/node_redis (master)$ node example.js + Reply: OK + Reply: 0 + Reply: 0 + 2 replies: + 0: hashtest 1 + 1: hashtest 2 + mjr:~/work/node_redis (master)$ + + +## Performance + +Here are typical results of `multi_bench.js` which is similar to `redis-benchmark` from the Redis distribution. +It uses 50 concurrent connections with no pipelining. + +JavaScript parser: + + PING: 20000 ops 42283.30 ops/sec 0/5/1.182 + SET: 20000 ops 32948.93 ops/sec 1/7/1.515 + GET: 20000 ops 28694.40 ops/sec 0/9/1.740 + INCR: 20000 ops 39370.08 ops/sec 0/8/1.269 + LPUSH: 20000 ops 36429.87 ops/sec 0/8/1.370 + LRANGE (10 elements): 20000 ops 9891.20 ops/sec 1/9/5.048 + LRANGE (100 elements): 20000 ops 1384.56 ops/sec 10/91/36.072 + +hiredis parser: + + PING: 20000 ops 46189.38 ops/sec 1/4/1.082 + SET: 20000 ops 41237.11 ops/sec 0/6/1.210 + GET: 20000 ops 39682.54 ops/sec 1/7/1.257 + INCR: 20000 ops 40080.16 ops/sec 0/8/1.242 + LPUSH: 20000 ops 41152.26 ops/sec 0/3/1.212 + LRANGE (10 elements): 20000 ops 36563.07 ops/sec 1/8/1.363 + LRANGE (100 elements): 20000 ops 21834.06 ops/sec 0/9/2.287 + +The performance of `node_redis` improves dramatically with pipelining, which happens automatically in most normal programs. + + +### Sending Commands + +Each Redis command is exposed as a function on the `client` object. +All functions take either take either an `args` Array plus optional `callback` Function or +a variable number of individual arguments followed by an optional callback. +Here is an example of passing an array of arguments and a callback: + + client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], function (err, res) {}); + +Here is that same call in the second style: + + client.mset("test keys 1", "test val 1", "test keys 2", "test val 2", function (err, res) {}); + +Note that in either form the `callback` is optional: + + client.set("some key", "some val"); + client.set(["some other key", "some val"]); + +For a list of Redis commands, see [Redis Command Reference](http://redis.io/commands) + +The commands can be specified in uppercase or lowercase for convenience. `client.get()` is the same as `client.GET()`. + +Minimal parsing is done on the replies. Commands that return a single line reply return JavaScript Strings, +integer replies return JavaScript Numbers, "bulk" replies return node Buffers, and "multi bulk" replies return a +JavaScript Array of node Buffers. `HGETALL` returns an Object with Buffers keyed by the hash keys. + +# API + +## Connection Events + +`client` will emit some events about the state of the connection to the Redis server. + +### "ready" + +`client` will emit `ready` a connection is established to the Redis server and the server reports +that it is ready to receive commands. Commands issued before the `ready` event are queued, +then replayed just before this event is emitted. + +### "connect" + +`client` will emit `connect` at the same time as it emits `ready` unless `client.options.no_ready_check` +is set. If this options is set, `connect` will be emitted when the stream is connected, and then +you are free to try to send commands. + +### "error" + +`client` will emit `error` when encountering an error connecting to the Redis server. + +Note that "error" is a special event type in node. If there are no listeners for an +"error" event, node will exit. This is usually what you want, but it can lead to some +cryptic error messages like this: + + mjr:~/work/node_redis (master)$ node example.js + + node.js:50 + throw e; + ^ + Error: ECONNREFUSED, Connection refused + at IOWatcher.callback (net:870:22) + at node.js:607:9 + +Not very useful in diagnosing the problem, but if your program isn't ready to handle this, +it is probably the right thing to just exit. + +`client` will also emit `error` if an exception is thrown inside of `node_redis` for whatever reason. +It would be nice to distinguish these two cases. + +### "end" + +`client` will emit `end` when an established Redis server connection has closed. + +### "drain" + +`client` will emit `drain` when the TCP connection to the Redis server has been buffering, but is now +writable. This event can be used to stream commands in to Redis and adapt to backpressure. Right now, +you need to check `client.command_queue.length` to decide when to reduce your send rate. Then you can +resume sending when you get `drain`. + +### "idle" + +`client` will emit `idle` when there are no outstanding commands that are awaiting a response. + +## redis.createClient(port, host, options) + +Create a new client connection. `port` defaults to `6379` and `host` defaults +to `127.0.0.1`. If you have `redis-server` running on the same computer as node, then the defaults for +port and host are probably fine. `options` in an object with the following possible properties: + +* `parser`: which Redis protocol reply parser to use. Defaults to `hiredis` if that module is installed. +This may also be set to `javascript`. +* `return_buffers`: defaults to false. If set to `true`, then bulk data replies will be returned as node Buffer +objects instead of JavaScript Strings. + +`createClient()` returns a `RedisClient` object that is named `client` in all of the examples here. + +## client.auth(password, callback) + +When connecting to Redis servers that require authentication, the `AUTH` command must be sent as the +first command after connecting. This can be tricky to coordinate with reconnections, the ready check, +etc. To make this easier, `client.auth()` stashes `password` and will send it after each connection, +including reconnections. `callback` is invoked only once, after the response to the very first +`AUTH` command sent. + +## client.end() + +Forcibly close the connection to the Redis server. Note that this does not wait until all replies have been parsed. +If you want to exit cleanly, call `client.quit()` to send the `QUIT` command after you have handled all replies. + +This example closes the connection to the Redis server before the replies have been read. You probably don't +want to do this: + + var redis = require("redis"), + client = redis.createClient(); + + client.set("foo_rand000000000000", "some fantastic value"); + client.get("foo_rand000000000000", function (err, reply) { + console.log(reply.toString()); + }); + client.end(); + +`client.end()` is useful for timeout cases where something is stuck or taking too long and you want +to start over. + +## Friendlier hash commands + +Most Redis commands take a single String or an Array of Strings as arguments, and replies are sent back as a single String or an Array of Strings. When dealing with hash values, there are a couple of useful exceptions to this. + +### client.hgetall(hash) + +The reply from an HGETALL command will be converted into a JavaScript Object by `node_redis`. That way you can interact +with the responses using JavaScript syntax. + +Example: + + client.hmset("hosts", "mjr", "1", "another", "23", "home", "1234"); + client.hgetall("hosts", function (err, obj) { + console.dir(obj); + }); + +Output: + + { mjr: '1', another: '23', home: '1234' } + +### client.hmset(hash, obj, [callback]) + +Multiple values in a hash can be set by supplying an object: + + client.HMSET(key2, { + "0123456789": "abcdefghij", + "some manner of key": "a type of value" + }); + +The properties and values of this Object will be set as keys and values in the Redis hash. + +### client.hmset(hash, key1, val1, ... keyn, valn, [callback]) + +Multiple values may also be set by supplying a list: + + client.HMSET(key1, "0123456789", "abcdefghij", "some manner of key", "a type of value"); + + +## Publish / Subscribe + +Here is a simple example of the API for publish / subscribe. This program opens two +client connections, subscribes to a channel on one of them, and publishes to that +channel on the other: + + var redis = require("redis"), + client1 = redis.createClient(), client2 = redis.createClient(), + msg_count = 0; + + client1.on("subscribe", function (channel, count) { + client2.publish("a nice channel", "I am sending a message."); + client2.publish("a nice channel", "I am sending a second message."); + client2.publish("a nice channel", "I am sending my last message."); + }); + + client1.on("message", function (channel, message) { + console.log("client1 channel " + channel + ": " + message); + msg_count += 1; + if (msg_count === 3) { + client1.unsubscribe(); + client1.end(); + client2.end(); + } + }); + + client1.incr("did a thing"); + client1.subscribe("a nice channel"); + +When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into "pub/sub" mode. +At that point, only commands that modify the subscription set are valid. When the subscription +set is empty, the connection is put back into regular mode. + +If you need to send regular commands to Redis while in pub/sub mode, just open another connection. + +## Pub / Sub Events + +If a client has subscriptions active, it may emit these events: + +### "message" (channel, message) + +Client will emit `message` for every message received that matches an active subscription. +Listeners are passed the channel name as `channel` and the message Buffer as `message`. + +### "pmessage" (pattern, channel, message) + +Client will emit `pmessage` for every message received that matches an active subscription pattern. +Listeners are passed the original pattern used with `PSUBSCRIBE` as `pattern`, the sending channel +name as `channel`, and the message Buffer as `message`. + +### "subscribe" (channel, count) + +Client will emit `subscribe` in response to a `SUBSCRIBE` command. Listeners are passed the +channel name as `channel` and the new count of subscriptions for this client as `count`. + +### "psubscribe" (pattern, count) + +Client will emit `psubscribe` in response to a `PSUBSCRIBE` command. Listeners are passed the +original pattern as `pattern`, and the new count of subscriptions for this client as `count`. + +### "unsubscribe" (channel, count) + +Client will emit `unsubscribe` in response to a `UNSUBSCRIBE` command. Listeners are passed the +channel name as `channel` and the new count of subscriptions for this client as `count`. When +`count` is 0, this client has left pub/sub mode and no more pub/sub events will be emitted. + +### "punsubscribe" (pattern, count) + +Client will emit `punsubscribe` in response to a `PUNSUBSCRIBE` command. Listeners are passed the +channel name as `channel` and the new count of subscriptions for this client as `count`. When +`count` is 0, this client has left pub/sub mode and no more pub/sub events will be emitted. + +## client.multi([commands]) + +`MULTI` commands are queued up until an `EXEC` is issued, and then all commands are run atomically by +Redis. The interface in `node_redis` is to return an individual `Multi` object by calling `client.multi()`. + + var redis = require("./index"), + client = redis.createClient(), set_size = 20; + + client.sadd("bigset", "a member"); + client.sadd("bigset", "another member"); + + while (set_size > 0) { + client.sadd("bigset", "member " + set_size); + set_size -= 1; + } + + // multi chain with an individual callback + client.multi() + .scard("bigset") + .smembers("bigset") + .keys("*", function (err, replies) { + client.mget(replies, redis.print); + }) + .dbsize() + .exec(function (err, replies) { + console.log("MULTI got " + replies.length + " replies"); + replies.forEach(function (reply, index) { + console.log("Reply " + index + ": " + reply.toString()); + }); + }); + +`client.multi()` is a constructor that returns a `Multi` object. `Multi` objects share all of the +same command methods as `client` objects do. Commands are queued up inside the `Multi` object +until `Multi.exec()` is invoked. + +You can either chain together `MULTI` commands as in the above example, or you can queue individual +commands while still sending regular client command as in this example: + + var redis = require("redis"), + client = redis.createClient(), multi; + + // start a separate multi command queue + multi = client.multi(); + multi.incr("incr thing", redis.print); + multi.incr("incr other thing", redis.print); + + // runs immediately + client.mset("incr thing", 100, "incr other thing", 1, redis.print); + + // drains multi queue and runs atomically + multi.exec(function (err, replies) { + console.log(replies); // 101, 2 + }); + + // you can re-run the same transaction if you like + multi.exec(function (err, replies) { + console.log(replies); // 102, 3 + client.quit(); + }); + +In addition to adding commands to the `MULTI` queue individually, you can also pass an array +of commands and arguments to the constructor: + + var redis = require("redis"), + client = redis.createClient(), multi; + + client.multi([ + ["mget", "multifoo", "multibar", redis.print], + ["incr", "multifoo"], + ["incr", "multibar"] + ]).exec(function (err, replies) { + console.log(replies); + }); + + +## Monitor mode + +Redis supports the `MONITOR` command, which lets you see all commands received by the Redis server +across all client connections, including from other client libraries and other computers. + +After you send the `MONITOR` command, no other commands are valid on that connection. `node_redis` +will emit a `monitor` event for every new monitor message that comes across. The callback for the +`monitor` event takes a timestamp from the Redis server and an array of command arguments. + +Here is a simple example: + + var client = require("redis").createClient(), + util = require("util"); + + client.monitor(function (err, res) { + console.log("Entering monitoring mode."); + }); + + client.on("monitor", function (time, args) { + console.log(time + ": " + util.inspect(args)); + }); + + +# Extras + +Some other things you might like to know about. + +## client.server_info + +After the ready probe completes, the results from the INFO command are saved in the `client.server_info` +object. + +The `versions` key contains an array of the elements of the version string for easy comparison. + + > client.server_info.redis_version + '2.3.0' + > client.server_info.versions + [ 2, 3, 0 ] + +## redis.print() + +A handy callback function for displaying return values when testing. Example: + + var redis = require("redis"), + client = redis.createClient(); + + client.on("connect", function () { + client.set("foo_rand000000000000", "some fantastic value", redis.print); + client.get("foo_rand000000000000", redis.print); + }); + +This will print: + + Reply: OK + Reply: some fantastic value + +Note that this program will not exit cleanly because the client is still connected. + +## redis.debug_mode + +Boolean to enable debug mode and protocol tracing. + + var redis = require("redis"), + client = redis.createClient(); + + redis.debug_mode = true; + + client.on("connect", function () { + client.set("foo_rand000000000000", "some fantastic value"); + }); + +This will display: + + mjr:~/work/node_redis (master)$ node ~/example.js + send command: *3 + $3 + SET + $20 + foo_rand000000000000 + $20 + some fantastic value + + on_data: +OK + +`send command` is data sent into Redis and `on_data` is data received from Redis. + +## client.send_command(command_name, args, callback) + +Used internally to send commands to Redis. For convenience, nearly all commands that are published on the Redis +Wiki have been added to the `client` object. However, if I missed any, or if new commands are introduced before +this library is updated, you can use `send_command()` to send arbitrary commands to Redis. + +All commands are sent as multi-bulk commands. `args` can either be an Array of arguments, or individual arguments, +or omitted completely. + +## client.connected + +Boolean tracking the state of the connection to the Redis server. + +## client.command_queue.length + +The number of commands that have been sent to the Redis server but not yet replied to. You can use this to +enforce some kind of maximum queue depth for commands while connected. + +Don't mess with `client.command_queue` though unless you really know what you are doing. + +## client.offline_queue.length + +The number of commands that have been queued up for a future connection. You can use this to enforce +some kind of maximum queue depth for pre-connection commands. + +## client.retry_delay + +Current delay in milliseconds before a connection retry will be attempted. This starts at `250`. + +## client.retry_backoff + +Multiplier for future retry timeouts. This should be larger than 1 to add more time between retries. +Defaults to 1.7. The default initial connection retry is 250, so the second retry will be 425, followed by 723.5, etc. + + +## TODO + +Better tests for monitor mode, auth, disconnect/reconnect, and all combinations thereof. + +Stream large set/get values into and out of Redis. Otherwise the entire value must be in node's memory. + +Performance can be better for very large values. + +I think there are more performance improvements left in there for smaller values, especially for large lists of small values. + +## Contributors + +Some people have have added features and fixed bugs in `node_redis` other than me. + +In order of first contribution, they are: + +* [Tim Smart](https://github.com/Tim-Smart) +* [TJ Holowaychuk](https://github.com/visionmedia) +* [Rick Olson](https://github.com/technoweenie) +* [Orion Henry](https://github.com/orionz) +* [Hank Sims](https://github.com/hanksims) +* [Aivo Paas](https://github.com/aivopaas) +* [Paul Carey](https://github.com/paulcarey) +* [Pieter Noordhuis](https://github.com/pietern) +* [Vladimir Dronnikov](https://github.com/dvv) +* [Dave Hoover](https://github.com/redsquirrel) + +Thanks. + +## LICENSE - "MIT License" + +Copyright (c) 2010 Matthew Ranney, http://ranney.com/ + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +![spacer](http://ranney.com/1px.gif) diff --git a/node_modules/socket.io/node_modules/redis/changelog.md b/node_modules/socket.io/node_modules/redis/changelog.md new file mode 100644 index 0000000..524b125 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/changelog.md @@ -0,0 +1,174 @@ +Changelog +========= + +## v0.6.5 - July 6, 2011 + +Contributed changes: + +* Support SlowBuffers (Umair Siddique) +* Add Multi to exports (Louis-Philippe Perron) +* Fix for drain event calculation (Vladimir Dronnikov) + +Thanks! + +## v0.6.4 - June 30, 2011 + +Fix bug with optional callbacks for hmset. + +## v0.6.2 - June 30, 2011 + +Bugs fixed: + +* authentication retry while server is loading db (danmaz74) [GH-101] +* command arguments processing issue with arrays + +New features: + +* Auto update of new commands from redis.io (Dave Hoover) +* Performance improvements and backpressure controls. +* Commands now return the true/false value from the underlying socket write(s). +* Implement command_queue high water and low water for more better control of queueing. + +See `examples/backpressure_drain.js` for more information. + +## v0.6.1 - June 29, 2011 + +Add support and tests for Redis scripting through EXEC command. + +Bug fix for monitor mode. (forddg) + +Auto update of new commands from redis.io (Dave Hoover) + +## v0.6.0 - April 21, 2011 + +Lots of bugs fixed. + +* connection error did not properly trigger reconnection logic [GH-85] +* client.hmget(key, [val1, val2]) was not expanding properly [GH-66] +* client.quit() while in pub/sub mode would throw an error [GH-87] +* client.multi(['hmset', 'key', {foo: 'bar'}]) fails [GH-92] +* unsubscribe before subscribe would make things very confused [GH-88] +* Add BRPOPLPUSH [GH-79] + +## v0.5.11 - April 7, 2011 + +Added DISCARD + +I originally didn't think DISCARD would do anything here because of the clever MULTI interface, but somebody +pointed out to me that DISCARD can be used to flush the WATCH set. + +## v0.5.10 - April 6, 2011 + +Added HVALS + +## v0.5.9 - March 14, 2011 + +Fix bug with empty Array arguments - Andy Ray + +## v0.5.8 - March 14, 2011 + +Add `MONITOR` command and special monitor command reply parsing. + +## v0.5.7 - February 27, 2011 + +Add magical auth command. + +Authentication is now remembered by the client and will be automatically sent to the server +on every connection, including any reconnections. + +## v0.5.6 - February 22, 2011 + +Fix bug in ready check with `return_buffers` set to `true`. + +Thanks to Dean Mao and Austin Chau. + +## v0.5.5 - February 16, 2011 + +Add probe for server readiness. + +When a Redis server starts up, it might take a while to load the dataset into memory. +During this time, the server will accept connections, but will return errors for all non-INFO +commands. Now node_redis will send an INFO command whenever it connects to a server. +If the info command indicates that the server is not ready, the client will keep trying until +the server is ready. Once it is ready, the client will emit a "ready" event as well as the +"connect" event. The client will queue up all commands sent before the server is ready, just +like it did before. When the server is ready, all offline/non-ready commands will be replayed. +This should be backward compatible with previous versions. + +To disable this ready check behavior, set `options.no_ready_check` when creating the client. + +As a side effect of this change, the key/val params from the info command are available as +`client.server_options`. Further, the version string is decomposed into individual elements +in `client.server_options.versions`. + +## v0.5.4 - February 11, 2011 + +Fix excess memory consumption from Queue backing store. + +Thanks to Gustaf Sjöberg. + +## v0.5.3 - February 5, 2011 + +Fix multi/exec error reply callback logic. + +Thanks to Stella Laurenzo. + +## v0.5.2 - January 18, 2011 + +Fix bug where unhandled error replies confuse the parser. + +## v0.5.1 - January 18, 2011 + +Fix bug where subscribe commands would not handle redis-server startup error properly. + +## v0.5.0 - December 29, 2010 + +Some bug fixes: + +* An important bug fix in reconnection logic. Previously, reply callbacks would be invoked twice after + a reconnect. +* Changed error callback argument to be an actual Error object. + +New feature: + +* Add friendly syntax for HMSET using an object. + +## v0.4.1 - December 8, 2010 + +Remove warning about missing hiredis. You probably do want it though. + +## v0.4.0 - December 5, 2010 + +Support for multiple response parsers and hiredis C library from Pieter Noordhuis. +Return Strings instead of Buffers by default. +Empty nested mb reply bug fix. + +## v0.3.9 - November 30, 2010 + +Fix parser bug on failed EXECs. + +## v0.3.8 - November 10, 2010 + +Fix for null MULTI response when WATCH condition fails. + +## v0.3.7 - November 9, 2010 + +Add "drain" and "idle" events. + +## v0.3.6 - November 3, 2010 + +Add all known Redis commands from Redis master, even ones that are coming in 2.2 and beyond. + +Send a friendlier "error" event message on stream errors like connection refused / reset. + +## v0.3.5 - October 21, 2010 + +A few bug fixes. + +* Fixed bug with `nil` multi-bulk reply lengths that showed up with `BLPOP` timeouts. +* Only emit `end` once when connection goes away. +* Fixed bug in `test.js` where driver finished before all tests completed. + +## unversioned wasteland + +See the git history for what happened before. diff --git a/node_modules/socket.io/node_modules/redis/examples/auth.js b/node_modules/socket.io/node_modules/redis/examples/auth.js new file mode 100644 index 0000000..6c0a563 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/auth.js @@ -0,0 +1,5 @@ +var redis = require("redis"), + client = redis.createClient(); + +// This command is magical. Client stashes the password and will issue on every connect. +client.auth("somepass"); diff --git a/node_modules/socket.io/node_modules/redis/examples/extend.js b/node_modules/socket.io/node_modules/redis/examples/extend.js new file mode 100644 index 0000000..488b8c2 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/extend.js @@ -0,0 +1,24 @@ +var redis = require("redis"), + client = redis.createClient(); + +// Extend the RedisClient prototype to add a custom method +// This one converts the results from "INFO" into a JavaScript Object + +redis.RedisClient.prototype.parse_info = function (callback) { + this.info(function (err, res) { + var lines = res.toString().split("\r\n").sort(); + var obj = {}; + lines.forEach(function (line) { + var parts = line.split(':'); + if (parts[1]) { + obj[parts[0]] = parts[1]; + } + }); + callback(obj) + }); +}; + +client.parse_info(function (info) { + console.dir(info); + client.quit(); +}); diff --git a/node_modules/socket.io/node_modules/redis/examples/file.js b/node_modules/socket.io/node_modules/redis/examples/file.js new file mode 100644 index 0000000..4d2b5d1 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/file.js @@ -0,0 +1,32 @@ +// Read a file from disk, store it in Redis, then read it back from Redis. + +var redis = require("redis"), + client = redis.createClient(), + fs = require("fs"), + filename = "kids_in_cart.jpg"; + +// Get the file I use for testing like this: +// curl http://ranney.com/kids_in_cart.jpg -o kids_in_cart.jpg +// or just use your own file. + +// Read a file from fs, store it in Redis, get it back from Redis, write it back to fs. +fs.readFile(filename, function (err, data) { + if (err) throw err + console.log("Read " + data.length + " bytes from filesystem."); + + client.set(filename, data, redis.print); // set entire file + client.get(filename, function (err, reply) { // get entire file + if (err) { + console.log("Get error: " + err); + } else { + fs.writeFile("duplicate_" + filename, reply, function (err) { + if (err) { + console.log("Error on write: " + err) + } else { + console.log("File written."); + } + client.end(); + }); + } + }); +}); diff --git a/node_modules/socket.io/node_modules/redis/examples/mget.js b/node_modules/socket.io/node_modules/redis/examples/mget.js new file mode 100644 index 0000000..936740d --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/mget.js @@ -0,0 +1,5 @@ +var client = require("redis").createClient(); + +client.mget(["sessions started", "sessions started", "foo"], function (err, res) { + console.dir(res); +}); \ No newline at end of file diff --git a/node_modules/socket.io/node_modules/redis/examples/monitor.js b/node_modules/socket.io/node_modules/redis/examples/monitor.js new file mode 100644 index 0000000..2cb6a4e --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/monitor.js @@ -0,0 +1,10 @@ +var client = require("../index").createClient(), + util = require("util"); + +client.monitor(function (err, res) { + console.log("Entering monitoring mode."); +}); + +client.on("monitor", function (time, args) { + console.log(time + ": " + util.inspect(args)); +}); diff --git a/node_modules/socket.io/node_modules/redis/examples/multi.js b/node_modules/socket.io/node_modules/redis/examples/multi.js new file mode 100644 index 0000000..35c08e1 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/multi.js @@ -0,0 +1,46 @@ +var redis = require("redis"), + client = redis.createClient(), set_size = 20; + +client.sadd("bigset", "a member"); +client.sadd("bigset", "another member"); + +while (set_size > 0) { + client.sadd("bigset", "member " + set_size); + set_size -= 1; +} + +// multi chain with an individual callback +client.multi() + .scard("bigset") + .smembers("bigset") + .keys("*", function (err, replies) { + client.mget(replies, redis.print); + }) + .dbsize() + .exec(function (err, replies) { + console.log("MULTI got " + replies.length + " replies"); + replies.forEach(function (reply, index) { + console.log("Reply " + index + ": " + reply.toString()); + }); + }); + +client.mset("incr thing", 100, "incr other thing", 1, redis.print); + +// start a separate multi command queue +var multi = client.multi(); +multi.incr("incr thing", redis.print); +multi.incr("incr other thing", redis.print); + +// runs immediately +client.get("incr thing", redis.print); // 100 + +// drains multi queue and runs atomically +multi.exec(function (err, replies) { + console.log(replies); // 101, 2 +}); + +// you can re-run the same transaction if you like +multi.exec(function (err, replies) { + console.log(replies); // 102, 3 + client.quit(); +}); diff --git a/node_modules/socket.io/node_modules/redis/examples/multi2.js b/node_modules/socket.io/node_modules/redis/examples/multi2.js new file mode 100644 index 0000000..8be4d73 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/multi2.js @@ -0,0 +1,29 @@ +var redis = require("redis"), + client = redis.createClient(), multi; + +// start a separate command queue for multi +multi = client.multi(); +multi.incr("incr thing", redis.print); +multi.incr("incr other thing", redis.print); + +// runs immediately +client.mset("incr thing", 100, "incr other thing", 1, redis.print); + +// drains multi queue and runs atomically +multi.exec(function (err, replies) { + console.log(replies); // 101, 2 +}); + +// you can re-run the same transaction if you like +multi.exec(function (err, replies) { + console.log(replies); // 102, 3 + client.quit(); +}); + +client.multi([ + ["mget", "multifoo", "multibar", redis.print], + ["incr", "multifoo"], + ["incr", "multibar"] +]).exec(function (err, replies) { + console.log(replies.toString()); +}); diff --git a/node_modules/socket.io/node_modules/redis/examples/psubscribe.js b/node_modules/socket.io/node_modules/redis/examples/psubscribe.js new file mode 100644 index 0000000..c57117b --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/psubscribe.js @@ -0,0 +1,33 @@ +var redis = require("redis"), + client1 = redis.createClient(), + client2 = redis.createClient(), + client3 = redis.createClient(), + client4 = redis.createClient(), + msg_count = 0; + +redis.debug_mode = false; + +client1.on("psubscribe", function (pattern, count) { + console.log("client1 psubscribed to " + pattern + ", " + count + " total subscriptions"); + client2.publish("channeltwo", "Me!"); + client3.publish("channelthree", "Me too!"); + client4.publish("channelfour", "And me too!"); +}); + +client1.on("punsubscribe", function (pattern, count) { + console.log("client1 punsubscribed from " + pattern + ", " + count + " total subscriptions"); + client4.end(); + client3.end(); + client2.end(); + client1.end(); +}); + +client1.on("pmessage", function (pattern, channel, message) { + console.log("("+ pattern +")" + " client1 received message on " + channel + ": " + message); + msg_count += 1; + if (msg_count === 3) { + client1.punsubscribe(); + } +}); + +client1.psubscribe("channel*"); diff --git a/node_modules/socket.io/node_modules/redis/examples/pub_sub.js b/node_modules/socket.io/node_modules/redis/examples/pub_sub.js new file mode 100644 index 0000000..aa508d6 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/pub_sub.js @@ -0,0 +1,41 @@ +var redis = require("redis"), + client1 = redis.createClient(), msg_count = 0, + client2 = redis.createClient(); + +redis.debug_mode = false; + +// Most clients probably don't do much on "subscribe". This example uses it to coordinate things within one program. +client1.on("subscribe", function (channel, count) { + console.log("client1 subscribed to " + channel + ", " + count + " total subscriptions"); + if (count === 2) { + client2.publish("a nice channel", "I am sending a message."); + client2.publish("another one", "I am sending a second message."); + client2.publish("a nice channel", "I am sending my last message."); + } +}); + +client1.on("unsubscribe", function (channel, count) { + console.log("client1 unsubscribed from " + channel + ", " + count + " total subscriptions"); + if (count === 0) { + client2.end(); + client1.end(); + } +}); + +client1.on("message", function (channel, message) { + console.log("client1 channel " + channel + ": " + message); + msg_count += 1; + if (msg_count === 3) { + client1.unsubscribe(); + } +}); + +client1.on("ready", function () { + // if you need auth, do it here + client1.incr("did a thing"); + client1.subscribe("a nice channel", "another one"); +}); + +client2.on("ready", function () { + // if you need auth, do it here +}); diff --git a/node_modules/socket.io/node_modules/redis/examples/simple.js b/node_modules/socket.io/node_modules/redis/examples/simple.js new file mode 100644 index 0000000..b93c557 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/simple.js @@ -0,0 +1,17 @@ +var redis = require("redis"), + client = redis.createClient(); + +client.on("error", function (err) { + console.log("Redis connection error to " + client.host + ":" + client.port + " - " + err); +}); + +client.set("string key", "string val", redis.print); +client.hset("hash key", "hashtest 1", "some value", redis.print); +client.hset(["hash key", "hashtest 2", "some other value"], redis.print); +client.hkeys("hash key", function (err, replies) { + console.log(replies.length + " replies:"); + replies.forEach(function (reply, i) { + console.log(" " + i + ": " + reply); + }); + client.quit(); +}); diff --git a/node_modules/socket.io/node_modules/redis/examples/subqueries.js b/node_modules/socket.io/node_modules/redis/examples/subqueries.js new file mode 100644 index 0000000..560db24 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/subqueries.js @@ -0,0 +1,15 @@ +// Sending commands in response to other commands. +// This example runs "type" against every key in the database +// +var client = require("redis").createClient(); + +client.keys("*", function (err, keys) { + keys.forEach(function (key, pos) { + client.type(key, function (err, keytype) { + console.log(key + " is " + keytype); + if (pos === (keys.length - 1)) { + client.quit(); + } + }); + }); +}); diff --git a/node_modules/socket.io/node_modules/redis/examples/subquery.js b/node_modules/socket.io/node_modules/redis/examples/subquery.js new file mode 100644 index 0000000..861657e --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/subquery.js @@ -0,0 +1,19 @@ +var client = require("redis").createClient(); + +function print_results(obj) { + console.dir(obj); +} + +// build a map of all keys and their types +client.keys("*", function (err, all_keys) { + var key_types = {}; + + all_keys.forEach(function (key, pos) { // use second arg of forEach to get pos + client.type(key, function (err, type) { + key_types[key] = type; + if (pos === all_keys.length - 1) { // callbacks all run in order + print_results(key_types); + } + }); + }); +}); diff --git a/node_modules/socket.io/node_modules/redis/examples/unix_socket.js b/node_modules/socket.io/node_modules/redis/examples/unix_socket.js new file mode 100644 index 0000000..4a5e0bb --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/unix_socket.js @@ -0,0 +1,29 @@ +var redis = require("redis"), + client = redis.createClient("/tmp/redis.sock"), + profiler = require("v8-profiler"); + +client.on("connect", function () { + console.log("Got Unix socket connection.") +}); + +client.on("error", function (err) { + console.log(err.message); +}); + +client.set("space chars", "space value"); + +setInterval(function () { + client.get("space chars"); +}, 100); + +function done() { + client.info(function (err, reply) { + console.log(reply.toString()); + client.quit(); + }); +} + +setTimeout(function () { + console.log("Taking snapshot."); + var snap = profiler.takeSnapshot(); +}, 5000); diff --git a/node_modules/socket.io/node_modules/redis/examples/web_server.js b/node_modules/socket.io/node_modules/redis/examples/web_server.js new file mode 100644 index 0000000..9fd8592 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/examples/web_server.js @@ -0,0 +1,31 @@ +// A simple web server that generates dyanmic content based on responses from Redis + +var http = require("http"), server, + redis_client = require("redis").createClient(); + +server = http.createServer(function (request, response) { + response.writeHead(200, { + "Content-Type": "text/plain" + }); + + var redis_info, total_requests; + + redis_client.info(function (err, reply) { + redis_info = reply; // stash response in outer scope + }); + redis_client.incr("requests", function (err, reply) { + total_requests = reply; // stash response in outer scope + }); + redis_client.hincrby("ip", request.connection.remoteAddress, 1); + redis_client.hgetall("ip", function (err, reply) { + // This is the last reply, so all of the previous replies must have completed already + response.write("This page was generated after talking to redis.\n\n" + + "Redis info:\n" + redis_info + "\n" + + "Total requests: " + total_requests + "\n\n" + + "IP count: \n"); + Object.keys(reply).forEach(function (ip) { + response.write(" " + ip + ": " + reply[ip] + "\n"); + }); + response.end(); + }); +}).listen(80); diff --git a/node_modules/socket.io/node_modules/redis/index.js b/node_modules/socket.io/node_modules/redis/index.js new file mode 100644 index 0000000..001452b --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/index.js @@ -0,0 +1,850 @@ +/*global Buffer require exports console setTimeout */ + +var net = require("net"), + util = require("./lib/util").util, + Queue = require("./lib/queue").Queue, + to_array = require("./lib/to_array"), + events = require("events"), + parsers = [], commands, + default_port = 6379, + default_host = "127.0.0.1"; + +// can set this to true to enable for all connections +exports.debug_mode = false; + +// hiredis might not be installed +try { + require("./lib/parser/hiredis"); + parsers.push(require("./lib/parser/hiredis")); +} catch (err) { + if (exports.debug_mode) { + console.log("hiredis parser not installed."); + } +} + +parsers.push(require("./lib/parser/javascript")); + +function RedisClient(stream, options) { + this.stream = stream; + this.options = options || {}; + + this.connected = false; + this.ready = false; + this.connections = 0; + this.attempts = 1; + this.should_buffer = false; + this.command_queue_high_water = this.options.command_queue_high_water || 1000; + this.command_queue_low_water = this.options.command_queue_low_water || 0; + this.command_queue = new Queue(); // holds sent commands to de-pipeline them + this.offline_queue = new Queue(); // holds commands issued but not able to be sent + this.commands_sent = 0; + this.retry_delay = 250; // inital reconnection delay + this.current_retry_delay = this.retry_delay; + this.retry_backoff = 1.7; // each retry waits current delay * retry_backoff + this.subscriptions = false; + this.monitoring = false; + this.closing = false; + this.server_info = {}; + this.auth_pass = null; + + var parser_module, self = this; + + if (self.options.parser) { + if (! parsers.some(function (parser) { + if (parser.name === self.options.parser) { + parser_module = parser; + if (exports.debug_mode) { + console.log("Using parser module: " + parser_module.name); + } + return true; + } + })) { + throw new Error("Couldn't find named parser " + self.options.parser + " on this system"); + } + } else { + if (exports.debug_mode) { + console.log("Using default parser module: " + parsers[0].name); + } + parser_module = parsers[0]; + } + + parser_module.debug_mode = exports.debug_mode; + this.reply_parser = new parser_module.Parser({ + return_buffers: self.options.return_buffers || false + }); + + // "reply error" is an error sent back by Redis + this.reply_parser.on("reply error", function (reply) { + self.return_error(new Error(reply)); + }); + this.reply_parser.on("reply", function (reply) { + self.return_reply(reply); + }); + // "error" is bad. Somehow the parser got confused. It'll try to reset and continue. + this.reply_parser.on("error", function (err) { + self.emit("error", new Error("Redis reply parser error: " + err.stack)); + }); + + this.stream.on("connect", function () { + self.on_connect(); + }); + + this.stream.on("data", function (buffer_from_socket) { + self.on_data(buffer_from_socket); + }); + + this.stream.on("error", function (msg) { + if (this.closing) { + return; + } + + var message = "Redis connection to " + self.host + ":" + self.port + " failed - " + msg.message; + + if (exports.debug_mode) { + console.warn(message); + } + self.offline_queue.forEach(function (args) { + if (typeof args[2] === "function") { + args[2](message); + } + }); + self.offline_queue = new Queue(); + + self.command_queue.forEach(function (args) { + if (typeof args[2] === "function") { + args[2](message); + } + }); + self.command_queue = new Queue(); + + self.connected = false; + self.ready = false; + + self.emit("error", new Error(message)); + // "error" events get turned into exceptions if they aren't listened for. If the user handled this error + // then we should try to reconnect. + self.connection_gone("error"); + }); + + this.stream.on("close", function () { + self.connection_gone("close"); + }); + + this.stream.on("end", function () { + self.connection_gone("end"); + }); + + this.stream.on("drain", function () { + self.should_buffer = false; + self.emit("drain"); + }); + + events.EventEmitter.call(this); +} +util.inherits(RedisClient, events.EventEmitter); +exports.RedisClient = RedisClient; + +RedisClient.prototype.do_auth = function () { + var self = this; + + if (exports.debug_mode) { + console.log("Sending auth to " + self.host + ":" + self.port + " fd " + self.stream.fd); + } + self.send_anyway = true; + self.send_command("auth", [this.auth_pass], function (err, res) { + if (err) { + if (err.toString().match("LOADING")) { + // if redis is still loading the db, it will not authenticate and everything else will fail + console.log("Redis still loading, trying to authenticate later"); + setTimeout(function () { + self.do_auth(); + }, 2000); // TODO - magic number alert + return; + } else { + return self.emit("error", "Auth error: " + err); + } + } + if (res.toString() !== "OK") { + return self.emit("error", "Auth failed: " + res.toString()); + } + if (exports.debug_mode) { + console.log("Auth succeeded " + self.host + ":" + self.port + " fd " + self.stream.fd); + } + if (self.auth_callback) { + self.auth_callback(err, res); + self.auth_callback = null; + } + + // now we are really connected + self.emit("connect"); + if (self.options.no_ready_check) { + self.ready = true; + self.send_offline_queue(); + } else { + self.ready_check(); + } + }); + self.send_anyway = false; +}; + +RedisClient.prototype.on_connect = function () { + if (exports.debug_mode) { + console.log("Stream connected " + this.host + ":" + this.port + " fd " + this.stream.fd); + } + var self = this; + + this.connected = true; + this.ready = false; + this.attempts = 0; + this.connections += 1; + this.command_queue = new Queue(); + this.emitted_end = false; + this.retry_timer = null; + this.current_retry_delay = this.retry_time; + this.stream.setNoDelay(); + this.stream.setTimeout(0); + + if (this.auth_pass) { + this.do_auth(); + } else { + this.emit("connect"); + + if (this.options.no_ready_check) { + this.ready = true; + this.send_offline_queue(); + } else { + this.ready_check(); + } + } +}; + +RedisClient.prototype.ready_check = function () { + var self = this; + + function send_info_cmd() { + if (exports.debug_mode) { + console.log("checking server ready state..."); + } + + self.send_anyway = true; // secret flag to send_command to send something even if not "ready" + self.info(function (err, res) { + if (err) { + return self.emit("error", "Ready check failed: " + err); + } + + var lines = res.toString().split("\r\n"), obj = {}, retry_time; + + lines.forEach(function (line) { + var parts = line.split(':'); + if (parts[1]) { + obj[parts[0]] = parts[1]; + } + }); + + obj.versions = []; + obj.redis_version.split('.').forEach(function (num) { + obj.versions.push(+num); + }); + + // expose info key/vals to users + self.server_info = obj; + + if (!obj.loading || (obj.loading && obj.loading === "0")) { + if (exports.debug_mode) { + console.log("Redis server ready."); + } + self.ready = true; + + self.send_offline_queue(); + self.emit("ready"); + } else { + retry_time = obj.loading_eta_seconds * 1000; + if (retry_time > 1000) { + retry_time = 1000; + } + if (exports.debug_mode) { + console.log("Redis server still loading, trying again in " + retry_time); + } + setTimeout(send_info_cmd, retry_time); + } + }); + self.send_anyway = false; + } + + send_info_cmd(); +}; + +RedisClient.prototype.send_offline_queue = function () { + var command_obj, buffered_writes = 0; + while (this.offline_queue.length > 0) { + command_obj = this.offline_queue.shift(); + if (exports.debug_mode) { + console.log("Sending offline command: " + command_obj.command); + } + buffered_writes += !this.send_command(command_obj.command, command_obj.args, command_obj.callback); + } + this.offline_queue = new Queue(); + // Even though items were shifted off, Queue backing store still uses memory until next add, so just get a new Queue + + if (!buffered_writes) { + this.should_buffer = false; + this.emit("drain"); + } +}; + +RedisClient.prototype.connection_gone = function (why) { + var self = this; + + // If a retry is already in progress, just let that happen + if (this.retry_timer) { + return; + } + + // Note that this may trigger another "close" or "end" event + this.stream.destroy(); + + if (exports.debug_mode) { + console.warn("Redis connection is gone from " + why + " event."); + } + this.connected = false; + this.ready = false; + this.subscriptions = false; + this.monitoring = false; + + // since we are collapsing end and close, users don't expect to be called twice + if (! this.emitted_end) { + this.emit("end"); + this.emitted_end = true; + } + + this.command_queue.forEach(function (args) { + if (typeof args[2] === "function") { + args[2]("Server connection closed"); + } + }); + this.command_queue = new Queue(); + + // If this is a requested shutdown, then don't retry + if (this.closing) { + this.retry_timer = null; + return; + } + + this.current_retry_delay = this.retry_delay * this.retry_backoff; + + if (exports.debug_mode) { + console.log("Retry connection in " + this.current_retry_delay + " ms"); + } + this.attempts += 1; + this.emit("reconnecting", { + delay: this.current_retry_delay, + attempt: this.attempts + }); + this.retry_timer = setTimeout(function () { + if (exports.debug_mode) { + console.log("Retrying connection..."); + } + self.stream.connect(self.port, self.host); + self.retry_timer = null; + }, this.current_retry_delay); +}; + +RedisClient.prototype.on_data = function (data) { + if (exports.debug_mode) { + console.log("net read " + this.host + ":" + this.port + " fd " + this.stream.fd + ": " + data.toString()); + } + + try { + this.reply_parser.execute(data); + } catch (err) { + // This is an unexpected parser problem, an exception that came from the parser code itself. + // Parser should emit "error" events if it notices things are out of whack. + // Callbacks that throw exceptions will land in return_reply(), below. + // TODO - it might be nice to have a different "error" event for different types of errors + this.emit("error", err); + } +}; + +RedisClient.prototype.return_error = function (err) { + var command_obj = this.command_queue.shift(), queue_len = this.command_queue.getLength(); + + if (this.subscriptions === false && queue_len === 0) { + this.emit("idle"); + this.command_queue = new Queue(); + } + if (this.should_buffer && queue_len <= this.command_queue_low_water) { + this.emit("drain"); + this.should_buffer = false; + } + + if (command_obj && typeof command_obj.callback === "function") { + try { + command_obj.callback(err); + } catch (callback_err) { + // if a callback throws an exception, re-throw it on a new stack so the parser can keep going + process.nextTick(function () { + throw callback_err; + }); + } + } else { + console.log("node_redis: no callback to send error: " + err.message); + // this will probably not make it anywhere useful, but we might as well throw + process.nextTick(function () { + throw err; + }); + } +}; + +RedisClient.prototype.return_reply = function (reply) { + var command_obj = this.command_queue.shift(), + obj, i, len, key, val, type, timestamp, args, queue_len = this.command_queue.getLength(); + + if (this.subscriptions === false && queue_len === 0) { + this.emit("idle"); + this.command_queue = new Queue(); // explicitly reclaim storage from old Queue + } + if (this.should_buffer && queue_len <= this.command_queue_low_water) { + this.emit("drain"); + this.should_buffer = false; + } + + if (command_obj && !command_obj.sub_command) { + if (typeof command_obj.callback === "function") { + // HGETALL special case replies with keyed Buffers + if (reply && 'hgetall' === command_obj.command.toLowerCase()) { + obj = {}; + for (i = 0, len = reply.length; i < len; i += 2) { + key = reply[i].toString(); + val = reply[i + 1]; + obj[key] = val; + } + reply = obj; + } + + try { + command_obj.callback(null, reply); + } catch (err) { + // if a callback throws an exception, re-throw it on a new stack so the parser can keep going + process.nextTick(function () { + throw err; + }); + } + } else if (exports.debug_mode) { + console.log("no callback for reply: " + (reply && reply.toString && reply.toString())); + } + } else if (this.subscriptions || (command_obj && command_obj.sub_command)) { + if (Array.isArray(reply)) { + type = reply[0].toString(); + + if (type === "message") { + this.emit("message", reply[1].toString(), reply[2]); // channel, message + } else if (type === "pmessage") { + this.emit("pmessage", reply[1].toString(), reply[2].toString(), reply[3]); // pattern, channel, message + } else if (type === "subscribe" || type === "unsubscribe" || type === "psubscribe" || type === "punsubscribe") { + if (reply[2] === 0) { + this.subscriptions = false; + if (this.debug_mode) { + console.log("All subscriptions removed, exiting pub/sub mode"); + } + } + this.emit(type, reply[1].toString(), reply[2]); // channel, count + } else { + throw new Error("subscriptions are active but got unknown reply type " + type); + } + } else if (! this.closing) { + throw new Error("subscriptions are active but got an invalid reply: " + reply); + } + } else if (this.monitoring) { + len = reply.indexOf(" "); + timestamp = reply.slice(0, len); + args = reply.slice(len + 1).match(/"[^"]+"/g).map(function (elem) { + return elem.replace(/"/g, ""); + }); + this.emit("monitor", timestamp, args); + } else { + throw new Error("node_redis command queue state error. If you can reproduce this, please report it."); + } +}; + +// This Command constructor is ever so slightly faster than using an object literal +function Command(command, args, sub_command, callback) { + this.command = command; + this.args = args; + this.sub_command = sub_command; + this.callback = callback; +} + +RedisClient.prototype.send_command = function (command, args, callback) { + var arg, this_args, command_obj, i, il, elem_count, stream = this.stream, buffer_args, command_str = "", buffered_writes = 0; + + if (typeof command !== "string") { + throw new Error("First argument to send_command must be the command name string, not " + typeof command); + } + + if (Array.isArray(args)) { + if (typeof callback === "function") { + // probably the fastest way: + // client.command([arg1, arg2], cb); (straight passthrough) + // send_command(command, [arg1, arg2], cb); + } else if (! callback) { + // most people find this variable argument length form more convenient, but it uses arguments, which is slower + // client.command(arg1, arg2, cb); (wraps up arguments into an array) + // send_command(command, [arg1, arg2, cb]); + // client.command(arg1, arg2); (callback is optional) + // send_command(command, [arg1, arg2]); + if (typeof args[args.length - 1] === "function") { + callback = args[args.length - 1]; + args.length -= 1; + } + } else { + throw new Error("send_command: last argument must be a callback or undefined"); + } + } else { + throw new Error("send_command: second argument must be an array"); + } + + command_obj = new Command(command, args, false, callback); + + if ((!this.ready && !this.send_anyway) || !stream.writable) { + if (exports.debug_mode) { + if (!stream.writable) { + console.log("send command: stream is not writeable."); + } + + console.log("Queueing " + command + " for next server connection."); + } + this.offline_queue.push(command_obj); + this.should_buffer = true; + return false; + } + + if (command === "subscribe" || command === "psubscribe" || command === "unsubscribe" || command === "punsubscribe") { + if (this.subscriptions === false && exports.debug_mode) { + console.log("Entering pub/sub mode from " + command); + } + command_obj.sub_command = true; + this.subscriptions = true; + } else if (command === "monitor") { + this.monitoring = true; + } else if (command === "quit") { + this.closing = true; + } else if (this.subscriptions === true) { + throw new Error("Connection in pub/sub mode, only pub/sub commands may be used"); + } + this.command_queue.push(command_obj); + this.commands_sent += 1; + + elem_count = 1; + buffer_args = false; + + elem_count += args.length; + + // Always use "Multi bulk commands", but if passed any Buffer args, then do multiple writes, one for each arg + // This means that using Buffers in commands is going to be slower, so use Strings if you don't already have a Buffer. + // Also, why am I putting user documentation in the library source code? + + command_str = "*" + elem_count + "\r\n$" + command.length + "\r\n" + command + "\r\n"; + + for (i = 0, il = args.length, arg; i < il; i += 1) { + if (Buffer.isBuffer(args[i])) { + buffer_args = true; + } + } + + if (! buffer_args) { // Build up a string and send entire command in one write + for (i = 0, il = args.length, arg; i < il; i += 1) { + arg = args[i]; + if (typeof arg !== "string") { + arg = String(arg); + } + command_str += "$" + Buffer.byteLength(arg) + "\r\n" + arg + "\r\n"; + } + if (exports.debug_mode) { + console.log("send " + this.host + ":" + this.port + " fd " + this.stream.fd + ": " + command_str); + } + buffered_writes += !stream.write(command_str); + } else { + if (exports.debug_mode) { + console.log("send command (" + command_str + ") has Buffer arguments"); + } + buffered_writes += !stream.write(command_str); + + for (i = 0, il = args.length, arg; i < il; i += 1) { + arg = args[i]; + if (!(Buffer.isBuffer(arg) || arg instanceof String)) { + arg = String(arg); + } + + if (Buffer.isBuffer(arg)) { + if (arg.length === 0) { + if (exports.debug_mode) { + console.log("send_command: using empty string for 0 length buffer"); + } + buffered_writes += !stream.write("$0\r\n\r\n"); + } else { + buffered_writes += !stream.write("$" + arg.length + "\r\n"); + buffered_writes += !stream.write(arg); + buffered_writes += !stream.write("\r\n"); + if (exports.debug_mode) { + console.log("send_command: buffer send " + arg.length + " bytes"); + } + } + } else { + if (exports.debug_mode) { + console.log("send_command: string send " + Buffer.byteLength(arg) + " bytes: " + arg); + } + buffered_writes += !stream.write("$" + Buffer.byteLength(arg) + "\r\n" + arg + "\r\n"); + } + } + } + if (exports.debug_mode) { + console.log("send_command buffered_writes: " + buffered_writes, " should_buffer: " + this.should_buffer); + } + if (buffered_writes || this.command_queue.getLength() >= this.command_queue_high_water) { + this.should_buffer = true; + } + return !this.should_buffer; +}; + +RedisClient.prototype.end = function () { + this.stream._events = {}; + this.connected = false; + this.ready = false; + return this.stream.end(); +}; + +function Multi(client, args) { + this.client = client; + this.queue = [["MULTI"]]; + if (Array.isArray(args)) { + this.queue = this.queue.concat(args); + } +} + +exports.Multi = Multi; + +// take 2 arrays and return the union of their elements +function set_union(seta, setb) { + var obj = {}; + + seta.forEach(function (val) { + obj[val] = true; + }); + setb.forEach(function (val) { + obj[val] = true; + }); + return Object.keys(obj); +} + +// This static list of commands is updated from time to time. ./lib/commands.js can be updated with generate_commands.js +commands = set_union(["get", "set", "setnx", "setex", "append", "strlen", "del", "exists", "setbit", "getbit", "setrange", "getrange", "substr", + "incr", "decr", "mget", "rpush", "lpush", "rpushx", "lpushx", "linsert", "rpop", "lpop", "brpop", "brpoplpush", "blpop", "llen", "lindex", + "lset", "lrange", "ltrim", "lrem", "rpoplpush", "sadd", "srem", "smove", "sismember", "scard", "spop", "srandmember", "sinter", "sinterstore", + "sunion", "sunionstore", "sdiff", "sdiffstore", "smembers", "zadd", "zincrby", "zrem", "zremrangebyscore", "zremrangebyrank", "zunionstore", + "zinterstore", "zrange", "zrangebyscore", "zrevrangebyscore", "zcount", "zrevrange", "zcard", "zscore", "zrank", "zrevrank", "hset", "hsetnx", + "hget", "hmset", "hmget", "hincrby", "hdel", "hlen", "hkeys", "hvals", "hgetall", "hexists", "incrby", "decrby", "getset", "mset", "msetnx", + "randomkey", "select", "move", "rename", "renamenx", "expire", "expireat", "keys", "dbsize", "auth", "ping", "echo", "save", "bgsave", + "bgrewriteaof", "shutdown", "lastsave", "type", "multi", "exec", "discard", "sync", "flushdb", "flushall", "sort", "info", "monitor", "ttl", + "persist", "slaveof", "debug", "config", "subscribe", "unsubscribe", "psubscribe", "punsubscribe", "publish", "watch", "unwatch", "cluster", + "restore", "migrate", "dump", "object", "client", "eval", "evalsha"], require("./lib/commands")); + +commands.forEach(function (command) { + RedisClient.prototype[command] = function (args, callback) { + if (Array.isArray(args) && typeof callback === "function") { + return this.send_command(command, args, callback); + } else { + return this.send_command(command, to_array(arguments)); + } + }; + RedisClient.prototype[command.toUpperCase()] = RedisClient.prototype[command]; + + Multi.prototype[command] = function () { + this.queue.push([command].concat(to_array(arguments))); + return this; + }; + Multi.prototype[command.toUpperCase()] = Multi.prototype[command]; +}); + +// Stash auth for connect and reconnect. Send immediately if already connected. +RedisClient.prototype.auth = function () { + var args = to_array(arguments); + this.auth_pass = args[0]; + this.auth_callback = args[1]; + if (exports.debug_mode) { + console.log("Saving auth as " + this.auth_pass); + } + + if (this.connected) { + this.send_command("auth", args); + } +}; +RedisClient.prototype.AUTH = RedisClient.prototype.auth; + +RedisClient.prototype.hmget = function (arg1, arg2, arg3) { + if (Array.isArray(arg2) && typeof arg3 === "function") { + return this.send_command("hmget", [arg1].concat(arg2), arg3); + } else if (Array.isArray(arg1) && typeof arg2 === "function") { + return this.send_command("hmget", arg1, arg2); + } else { + return this.send_command("hmget", to_array(arguments)); + } +}; +RedisClient.prototype.HMGET = RedisClient.prototype.hmget; + +RedisClient.prototype.hmset = function (args, callback) { + var tmp_args, tmp_keys, i, il, key; + + if (Array.isArray(args) && typeof callback === "function") { + return this.send_command("hmset", args, callback); + } + + args = to_array(arguments); + if (typeof args[args.length - 1] === "function") { + callback = args[args.length - 1]; + args.length -= 1; + } else { + callback = null; + } + + if (args.length === 2 && typeof args[0] === "string" && typeof args[1] === "object") { + // User does: client.hmset(key, {key1: val1, key2: val2}) + tmp_args = [ args[0] ]; + tmp_keys = Object.keys(args[1]); + for (i = 0, il = tmp_keys.length; i < il ; i++) { + key = tmp_keys[i]; + tmp_args.push(key); + tmp_args.push(args[1][key]); + } + args = tmp_args; + } + + return this.send_command("hmset", args, callback); +}; +RedisClient.prototype.HMSET = RedisClient.prototype.hmset; + +Multi.prototype.hmset = function () { + var args = to_array(arguments), tmp_args; + if (args.length >= 2 && typeof args[0] === "string" && typeof args[1] === "object") { + tmp_args = [ "hmset", args[0] ]; + Object.keys(args[1]).map(function (key) { + tmp_args.push(key); + tmp_args.push(args[1][key]); + }); + if (args[2]) { + tmp_args.push(args[2]); + } + args = tmp_args; + } else { + args.unshift("hmset"); + } + + this.queue.push(args); + return this; +}; +Multi.prototype.HMSET = Multi.prototype.hmset; + +Multi.prototype.exec = function (callback) { + var self = this; + + // drain queue, callback will catch "QUEUED" or error + // TODO - get rid of all of these anonymous functions which are elegant but slow + this.queue.forEach(function (args, index) { + var command = args[0], obj; + if (typeof args[args.length - 1] === "function") { + args = args.slice(1, -1); + } else { + args = args.slice(1); + } + if (args.length === 1 && Array.isArray(args[0])) { + args = args[0]; + } + if (command === 'hmset' && typeof args[1] === 'object') { + obj = args.pop(); + Object.keys(obj).forEach(function (key) { + args.push(key); + args.push(obj[key]); + }); + } + this.client.send_command(command, args, function (err, reply) { + if (err) { + var cur = self.queue[index]; + if (typeof cur[cur.length - 1] === "function") { + cur[cur.length - 1](err); + } else { + throw new Error(err); + } + self.queue.splice(index, 1); + } + }); + }, this); + + // TODO - make this callback part of Multi.prototype instead of creating it each time + return this.client.send_command("EXEC", [], function (err, replies) { + if (err) { + if (callback) { + callback(new Error(err)); + return; + } else { + throw new Error(err); + } + } + + var i, il, j, jl, reply, args, obj, key, val; + + if (replies) { + for (i = 1, il = self.queue.length; i < il; i += 1) { + reply = replies[i - 1]; + args = self.queue[i]; + + // Convert HGETALL reply to object + if (reply && args[0].toLowerCase() === "hgetall") { + obj = {}; + for (j = 0, jl = reply.length; j < jl; j += 2) { + key = reply[j].toString(); + val = reply[j + 1]; + obj[key] = val; + } + replies[i - 1] = reply = obj; + } + + if (typeof args[args.length - 1] === "function") { + args[args.length - 1](null, reply); + } + } + } + + if (callback) { + callback(null, replies); + } + }); +}; + +RedisClient.prototype.multi = function (args) { + return new Multi(this, args); +}; +RedisClient.prototype.MULTI = function (args) { + return new Multi(this, args); +}; + +exports.createClient = function (port_arg, host_arg, options) { + var port = port_arg || default_port, + host = host_arg || default_host, + redis_client, net_client; + + net_client = net.createConnection(port, host); + + redis_client = new RedisClient(net_client, options); + + redis_client.port = port; + redis_client.host = host; + + return redis_client; +}; + +exports.print = function (err, reply) { + if (err) { + console.log("Error: " + err); + } else { + console.log("Reply: " + reply); + } +}; diff --git a/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js b/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js new file mode 100644 index 0000000..9dba8c9 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js @@ -0,0 +1,41 @@ +/*global Buffer require exports console setTimeout */ + +var events = require("events"), + util = require("../util").util, + hiredis = require("hiredis"); + +exports.debug_mode = false; +exports.name = "hiredis"; + +function HiredisReplyParser(options) { + this.name = exports.name; + this.options = options || {}; + this.reset(); + events.EventEmitter.call(this); +} + +util.inherits(HiredisReplyParser, events.EventEmitter); + +exports.Parser = HiredisReplyParser; + +HiredisReplyParser.prototype.reset = function () { + this.reader = new hiredis.Reader({ + return_buffers: this.options.return_buffers || false + }); +}; + +HiredisReplyParser.prototype.execute = function (data) { + var reply; + this.reader.feed(data); + try { + while ((reply = this.reader.get()) !== undefined) { + if (reply && reply.constructor === Error) { + this.emit("reply error", reply); + } else { + this.emit("reply", reply); + } + } + } catch (err) { + this.emit("error", err); + } +}; diff --git a/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js b/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js new file mode 100644 index 0000000..6f250c9 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js @@ -0,0 +1,316 @@ +/*global Buffer require exports console setTimeout */ + +// TODO - incorporate these V8 pro tips: +// pre-allocate Arrays if length is known in advance +// do not use delete +// use numbers for parser state + +var events = require("events"), + util = require("../util").util; + +exports.debug_mode = false; +exports.name = "javascript"; + +function RedisReplyParser(options) { + this.name = exports.name; + this.options = options || {}; + this.reset(); + events.EventEmitter.call(this); +} + +util.inherits(RedisReplyParser, events.EventEmitter); + +exports.Parser = RedisReplyParser; + +// Buffer.toString() is quite slow for small strings +function small_toString(buf, len) { + var tmp = "", i; + + for (i = 0; i < len; i += 1) { + tmp += String.fromCharCode(buf[i]); + } + + return tmp; +} + +// Reset parser to it's original state. +RedisReplyParser.prototype.reset = function () { + this.return_buffer = new Buffer(16384); // for holding replies, might grow + this.return_string = ""; + this.tmp_string = ""; // for holding size fields + + this.multi_bulk_length = 0; + this.multi_bulk_replies = null; + this.multi_bulk_pos = 0; + this.multi_bulk_nested_length = 0; + this.multi_bulk_nested_replies = null; + + this.states = { + TYPE: 1, + SINGLE_LINE: 2, + MULTI_BULK_COUNT: 3, + INTEGER_LINE: 4, + BULK_LENGTH: 5, + ERROR_LINE: 6, + BULK_DATA: 7, + UNKNOWN_TYPE: 8, + FINAL_CR: 9, + FINAL_LF: 10, + MULTI_BULK_COUNT_LF: 11 + }; + + this.state = this.states.TYPE; +}; + +RedisReplyParser.prototype.parser_error = function (message) { + this.emit("error", message); + this.reset(); +}; + +RedisReplyParser.prototype.execute = function (incoming_buf) { + var pos = 0, bd_tmp, bd_str, i, il, states = this.states; + //, state_times = {}, start_execute = new Date(), start_switch, end_switch, old_state; + //start_switch = new Date(); + + while (pos < incoming_buf.length) { + // old_state = this.state; + // console.log("execute: " + this.state + ", " + pos + "/" + incoming_buf.length + ", " + String.fromCharCode(incoming_buf[pos])); + + switch (this.state) { + case states.TYPE: + this.type = incoming_buf[pos]; + pos += 1; + + switch (this.type) { + case 43: // + + this.state = states.SINGLE_LINE; + this.return_buffer.end = 0; + this.return_string = ""; + break; + case 42: // * + this.state = states.MULTI_BULK_COUNT; + this.tmp_string = ""; + break; + case 58: // : + this.state = states.INTEGER_LINE; + this.return_buffer.end = 0; + this.return_string = ""; + break; + case 36: // $ + this.state = states.BULK_LENGTH; + this.tmp_string = ""; + break; + case 45: // - + this.state = states.ERROR_LINE; + this.return_buffer.end = 0; + this.return_string = ""; + break; + default: + this.state = states.UNKNOWN_TYPE; + } + break; + case states.INTEGER_LINE: + if (incoming_buf[pos] === 13) { + this.send_reply(+small_toString(this.return_buffer, this.return_buffer.end)); + this.state = states.FINAL_LF; + } else { + this.return_buffer[this.return_buffer.end] = incoming_buf[pos]; + this.return_buffer.end += 1; + } + pos += 1; + break; + case states.ERROR_LINE: + if (incoming_buf[pos] === 13) { + this.send_error(this.return_buffer.toString("ascii", 0, this.return_buffer.end)); + this.state = states.FINAL_LF; + } else { + this.return_buffer[this.return_buffer.end] = incoming_buf[pos]; + this.return_buffer.end += 1; + } + pos += 1; + break; + case states.SINGLE_LINE: + if (incoming_buf[pos] === 13) { + this.send_reply(this.return_string); + this.state = states.FINAL_LF; + } else { + this.return_string += String.fromCharCode(incoming_buf[pos]); + } + pos += 1; + break; + case states.MULTI_BULK_COUNT: + if (incoming_buf[pos] === 13) { // \r + this.state = states.MULTI_BULK_COUNT_LF; + } else { + this.tmp_string += String.fromCharCode(incoming_buf[pos]); + } + pos += 1; + break; + case states.MULTI_BULK_COUNT_LF: + if (incoming_buf[pos] === 10) { // \n + if (this.multi_bulk_length) { // nested multi-bulk + this.multi_bulk_nested_length = this.multi_bulk_length; + this.multi_bulk_nested_replies = this.multi_bulk_replies; + this.multi_bulk_nested_pos = this.multi_bulk_pos; + } + this.multi_bulk_length = +this.tmp_string; + this.multi_bulk_pos = 0; + this.state = states.TYPE; + if (this.multi_bulk_length < 0) { + this.send_reply(null); + this.multi_bulk_length = 0; + } else if (this.multi_bulk_length === 0) { + this.multi_bulk_pos = 0; + this.multi_bulk_replies = null; + this.send_reply([]); + } else { + this.multi_bulk_replies = new Array(this.multi_bulk_length); + } + } else { + this.parser_error(new Error("didn't see LF after NL reading multi bulk count")); + return; + } + pos += 1; + break; + case states.BULK_LENGTH: + if (incoming_buf[pos] === 13) { // \r + this.state = states.BULK_LF; + } else { + this.tmp_string += String.fromCharCode(incoming_buf[pos]); + } + pos += 1; + break; + case states.BULK_LF: + if (incoming_buf[pos] === 10) { // \n + this.bulk_length = +this.tmp_string; + if (this.bulk_length === -1) { + this.send_reply(null); + this.state = states.TYPE; + } else if (this.bulk_length === 0) { + this.send_reply(new Buffer("")); + this.state = states.FINAL_CR; + } else { + this.state = states.BULK_DATA; + if (this.bulk_length > this.return_buffer.length) { + if (exports.debug_mode) { + console.log("Growing return_buffer from " + this.return_buffer.length + " to " + this.bulk_length); + } + this.return_buffer = new Buffer(this.bulk_length); + } + this.return_buffer.end = 0; + } + } else { + this.parser_error(new Error("didn't see LF after NL while reading bulk length")); + return; + } + pos += 1; + break; + case states.BULK_DATA: + this.return_buffer[this.return_buffer.end] = incoming_buf[pos]; + this.return_buffer.end += 1; + pos += 1; + if (this.return_buffer.end === this.bulk_length) { + bd_tmp = new Buffer(this.bulk_length); + // When the response is small, Buffer.copy() is a lot slower. + if (this.bulk_length > 10) { + this.return_buffer.copy(bd_tmp, 0, 0, this.bulk_length); + } else { + for (i = 0, il = this.bulk_length; i < il; i += 1) { + bd_tmp[i] = this.return_buffer[i]; + } + } + this.send_reply(bd_tmp); + this.state = states.FINAL_CR; + } + break; + case states.FINAL_CR: + if (incoming_buf[pos] === 13) { // \r + this.state = states.FINAL_LF; + pos += 1; + } else { + this.parser_error(new Error("saw " + incoming_buf[pos] + " when expecting final CR")); + return; + } + break; + case states.FINAL_LF: + if (incoming_buf[pos] === 10) { // \n + this.state = states.TYPE; + pos += 1; + } else { + this.parser_error(new Error("saw " + incoming_buf[pos] + " when expecting final LF")); + return; + } + break; + default: + this.parser_error(new Error("invalid state " + this.state)); + } + // end_switch = new Date(); + // if (state_times[old_state] === undefined) { + // state_times[old_state] = 0; + // } + // state_times[old_state] += (end_switch - start_switch); + // start_switch = end_switch; + } + // console.log("execute ran for " + (Date.now() - start_execute) + " ms, on " + incoming_buf.length + " Bytes. "); + // Object.keys(state_times).forEach(function (state) { + // console.log(" " + state + ": " + state_times[state]); + // }); +}; + +RedisReplyParser.prototype.send_error = function (reply) { + if (this.multi_bulk_length > 0 || this.multi_bulk_nested_length > 0) { + // TODO - can this happen? Seems like maybe not. + this.add_multi_bulk_reply(reply); + } else { + this.emit("reply error", reply); + } +}; + +RedisReplyParser.prototype.send_reply = function (reply) { + if (this.multi_bulk_length > 0 || this.multi_bulk_nested_length > 0) { + if (!this.options.return_buffers && Buffer.isBuffer(reply)) { + this.add_multi_bulk_reply(reply.toString("utf8")); + } else { + this.add_multi_bulk_reply(reply); + } + } else { + if (!this.options.return_buffers && Buffer.isBuffer(reply)) { + this.emit("reply", reply.toString("utf8")); + } else { + this.emit("reply", reply); + } + } +}; + +RedisReplyParser.prototype.add_multi_bulk_reply = function (reply) { + if (this.multi_bulk_replies) { + this.multi_bulk_replies[this.multi_bulk_pos] = reply; + this.multi_bulk_pos += 1; + if (this.multi_bulk_pos < this.multi_bulk_length) { + return; + } + } else { + this.multi_bulk_replies = reply; + } + + if (this.multi_bulk_nested_length > 0) { + this.multi_bulk_nested_replies[this.multi_bulk_nested_pos] = this.multi_bulk_replies; + this.multi_bulk_nested_pos += 1; + + this.multi_bulk_length = 0; + this.multi_bulk_replies = null; + this.multi_bulk_pos = 0; + + if (this.multi_bulk_nested_length === this.multi_bulk_nested_pos) { + this.emit("reply", this.multi_bulk_nested_replies); + this.multi_bulk_nested_length = 0; + this.multi_bulk_nested_pos = 0; + this.multi_bulk_nested_replies = null; + } + } else { + this.emit("reply", this.multi_bulk_replies); + this.multi_bulk_length = 0; + this.multi_bulk_replies = null; + this.multi_bulk_pos = 0; + } +}; diff --git a/node_modules/socket.io/node_modules/redis/lib/queue.js b/node_modules/socket.io/node_modules/redis/lib/queue.js new file mode 100644 index 0000000..5cc3c42 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/lib/queue.js @@ -0,0 +1,58 @@ +var to_array = require("./to_array"); + +// Queue class adapted from Tim Caswell's pattern library +// http://github.com/creationix/pattern/blob/master/lib/pattern/queue.js + +function Queue() { + this.tail = []; + this.head = to_array(arguments); + this.offset = 0; +} + +Queue.prototype.shift = function () { + if (this.offset === this.head.length) { + var tmp = this.head; + tmp.length = 0; + this.head = this.tail; + this.tail = tmp; + this.offset = 0; + if (this.head.length === 0) { + return; + } + } + return this.head[this.offset++]; // sorry, JSLint +}; + +Queue.prototype.push = function (item) { + return this.tail.push(item); +}; + +Queue.prototype.forEach = function (fn, thisv) { + var array = this.head.slice(this.offset), i, il; + + array.push.apply(array, this.tail); + + if (thisv) { + for (i = 0, il = array.length; i < il; i += 1) { + fn.call(thisv, array[i], i, array); + } + } else { + for (i = 0, il = array.length; i < il; i += 1) { + fn(array[i], i, array); + } + } + + return array; +}; + +Queue.prototype.getLength = function () { + return this.head.length - this.offset + this.tail.length; +}; + +Object.defineProperty(Queue.prototype, 'length', { + get: function () { + return this.getLength(); + } +}); + +exports.Queue = Queue; diff --git a/node_modules/socket.io/node_modules/redis/lib/to_array.js b/node_modules/socket.io/node_modules/redis/lib/to_array.js new file mode 100644 index 0000000..88a57e1 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/lib/to_array.js @@ -0,0 +1,12 @@ +function to_array(args) { + var len = args.length, + arr = new Array(len), i; + + for (i = 0; i < len; i += 1) { + arr[i] = args[i]; + } + + return arr; +} + +module.exports = to_array; diff --git a/node_modules/socket.io/node_modules/redis/lib/util.js b/node_modules/socket.io/node_modules/redis/lib/util.js new file mode 100644 index 0000000..3dc41a5 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/lib/util.js @@ -0,0 +1,6 @@ +if (process.versions.node.match(/^0.3/)) { + exports.util = require("util"); +} else { + // This module is called "sys" in 0.2.x + exports.util = require("sys"); +} diff --git a/node_modules/socket.io/node_modules/redis/multi_bench.js b/node_modules/socket.io/node_modules/redis/multi_bench.js new file mode 100644 index 0000000..b78c126 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/multi_bench.js @@ -0,0 +1,135 @@ +var redis = require("./index"), + num_clients = parseInt(process.argv[2], 10) || 50, + active_clients = 0, + clients = new Array(num_clients), + num_requests = 20000, + issued_requests = 0, + latency = new Array(num_requests), + tests = [], + test_start, parser_logged = false, + client_options = { + return_buffers: false + }; + +redis.debug_mode = false; + +tests.push({ + descr: "PING", + command: ["ping"] +}); + +tests.push({ + descr: "SET", + command: ["set", "foo_rand000000000000", "bar"] +}); + +tests.push({ + descr: "GET", + command: ["get", "foo_rand000000000000"] +}); + +tests.push({ + descr: "INCR", + command: ["incr", "counter_rand000000000000"] +}); + +tests.push({ + descr: "LPUSH", + command: ["lpush", "mylist", new Array(8).join("-")] +}); + +tests.push({ + descr: "LRANGE (10 elements)", + command: ["lrange", "mylist", "0", "9"] +}); + +tests.push({ + descr: "LRANGE (100 elements)", + command: ["lrange", "mylist", "0", "99"] +}); + +function create_clients(callback) { + if (active_clients === num_clients) { + // common case is all clients are already created + console.log("create_clients: all clients already created " + num_clients); + callback(); + } else { + var client, connected = active_clients; + + while (active_clients < num_clients) { + client = clients[active_clients++] = redis.createClient(6379, "127.0.0.1", client_options); + if (! parser_logged) { + console.log("Using reply parser " + client.reply_parser.name); + parser_logged = true; + } + client.on("connect", function () { + // Fire callback when all clients are connected + connected += 1; + if (connected === num_clients) { + callback(); + } + }); + // TODO - need to check for client disconnect + client.on("error", function (msg) { + console.log("Connect problem:" + msg.stack); + }); + } + } +} + +function issue_request(client, test, cmd, args) { + var i = issued_requests++; + latency[i] = Date.now(); + + client[cmd](args, function() { + latency[i] = Date.now() - latency[i]; + if (issued_requests < num_requests) { + issue_request(client, test, cmd, args); + } else { + client.end(); + if (--active_clients == 0) + test_complete(test); + } + }); +} + +function test_run(test) { + create_clients(function() { + var i = num_clients, + cmd = test.command[0], + args = test.command.slice(1); + + test_start = Date.now(); + issued_requests = 0; + while(i-- && issued_requests < num_requests) { + issue_request(clients[i], test, cmd, args); + } + }); +} + +function test_complete(test) { + var min, max, sum, avg; + var total_time = Date.now() - test_start; + var op_rate = (issued_requests / (total_time / 1000.0)).toFixed(2); + var i; + + latency.sort(); + min = latency[0]; + max = latency[issued_requests-1]; + for (sum = 0, i = 0; i < issued_requests; i++) + sum += latency[i]; + avg = (sum / issued_requests).toFixed(3); + + console.log(test.descr + ": " + issued_requests + " ops " + op_rate + " ops/sec " + min + "/" + max + "/" + avg); + + next(); +} + +function next() { + var test = tests.shift(); + if (test) { + test_run(test); + } +} + +next(); diff --git a/node_modules/socket.io/node_modules/redis/package.json b/node_modules/socket.io/node_modules/redis/package.json new file mode 100644 index 0000000..a521de2 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/package.json @@ -0,0 +1,26 @@ +{ "name" : "redis", + "version" : "0.6.6", + "description" : "Redis client library", + "author": "Matt Ranney ", + "contributors": [ + "Rick Olson", + "Tim-Smart", + "TJ Holowaychuk", + "Orion Henry", + "Hank Sims", + "Aivo Paas", + "Paul Carey", + "Pieter Noordhuis", + "Andy Ray", + "Vladimir Dronnikov", + "Dave Hoover" + ], + "main": "./index.js", + "scripts": { + "test": "node ./test.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/mranney/node_redis.git" + } +} diff --git a/node_modules/socket.io/node_modules/redis/test.js b/node_modules/socket.io/node_modules/redis/test.js new file mode 100644 index 0000000..627f9c2 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/test.js @@ -0,0 +1,1234 @@ +/*global require console setTimeout process Buffer */ +var redis = require("./index"), + client = redis.createClient(), + client2 = redis.createClient(), + client3 = redis.createClient(), + client4 = redis.createClient(9006, "filefish.redistogo.com"), + assert = require("assert"), + util = require("./lib/util").util, + test_db_num = 15, // this DB will be flushed and used for testing + tests = {}, + connected = false, + ended = false, + next, cur_start, run_next_test, all_tests, all_start, test_count; + +// Set this to truthy to see the wire protocol and other debugging info +redis.debug_mode = process.argv[2]; + +function buffers_to_strings(arr) { + return arr.map(function (val) { + return val.toString(); + }); +} + +function require_number(expected, label) { + return function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(expected, results, label + " " + expected + " !== " + results); + assert.strictEqual(typeof results, "number", label); + return true; + }; +} + +function require_number_any(label) { + return function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(typeof results, "number", label + " " + results + " is not a number"); + return true; + }; +} + +function require_number_pos(label) { + return function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(true, (results > 0), label + " " + results + " is not a positive number"); + return true; + }; +} + +function require_string(str, label) { + return function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.equal(str, results, label + " " + str + " does not match " + results); + return true; + }; +} + +function require_null(label) { + return function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(null, results, label + ": " + results + " is not null"); + return true; + }; +} + +function require_error(label) { + return function (err, results) { + assert.notEqual(err, null, label + " err is null, but an error is expected here."); + return true; + }; +} + +function is_empty_array(obj) { + return Array.isArray(obj) && obj.length === 0; +} + +function last(name, fn) { + return function (err, results) { + fn(err, results); + next(name); + }; +} + +next = function next(name) { + console.log(" \x1b[33m" + (Date.now() - cur_start) + "\x1b[0m ms"); + run_next_test(); +}; + +// Tests are run in the order they are defined. So FLUSHDB should be stay first. + +tests.FLUSHDB = function () { + var name = "FLUSHDB"; + client.select(test_db_num, require_string("OK", name)); + client2.select(test_db_num, require_string("OK", name)); + client3.select(test_db_num, require_string("OK", name)); + client.mset("flush keys 1", "flush val 1", "flush keys 2", "flush val 2", require_string("OK", name)); + client.FLUSHDB(require_string("OK", name)); + client.dbsize(last(name, require_number(0, name))); +}; + +tests.MULTI_1 = function () { + var name = "MULTI_1", multi1, multi2; + + // Provoke an error at queue time + multi1 = client.multi(); + multi1.mset("multifoo", "10", "multibar", "20", require_string("OK", name)); + multi1.set("foo2", require_error(name)); + multi1.incr("multifoo", require_number(11, name)); + multi1.incr("multibar", require_number(21, name)); + multi1.exec(); + + // Confirm that the previous command, while containing an error, still worked. + multi2 = client.multi(); + multi2.incr("multibar", require_number(22, name)); + multi2.incr("multifoo", require_number(12, name)); + multi2.exec(function (err, replies) { + assert.strictEqual(22, replies[0]); + assert.strictEqual(12, replies[1]); + next(name); + }); +}; + +tests.MULTI_2 = function () { + var name = "MULTI_2"; + + // test nested multi-bulk replies + client.multi([ + ["mget", "multifoo", "multibar", function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("12", res[0].toString(), name); + assert.strictEqual("22", res[1].toString(), name); + }], + ["set", "foo2", require_error(name)], + ["incr", "multifoo", require_number(13, name)], + ["incr", "multibar", require_number(23, name)] + ]).exec(function (err, replies) { + assert.strictEqual(2, replies[0].length, name); + assert.strictEqual("12", replies[0][0].toString(), name); + assert.strictEqual("22", replies[0][1].toString(), name); + + assert.strictEqual("13", replies[1].toString()); + assert.strictEqual("23", replies[2].toString()); + next(name); + }); +}; + +tests.MULTI_3 = function () { + var name = "MULTI_3"; + + client.sadd("some set", "mem 1"); + client.sadd("some set", "mem 2"); + client.sadd("some set", "mem 3"); + client.sadd("some set", "mem 4"); + + // make sure empty mb reply works + client.del("some missing set"); + client.smembers("some missing set", function (err, reply) { + // make sure empty mb reply works + assert.strictEqual(true, is_empty_array(reply), name); + }); + + // test nested multi-bulk replies with empty mb elements. + client.multi([ + ["smembers", "some set"], + ["del", "some set"], + ["smembers", "some set"] + ]) + .scard("some set") + .exec(function (err, replies) { + assert.strictEqual(true, is_empty_array(replies[2]), name); + next(name); + }); +}; + +tests.MULTI_4 = function () { + var name = "MULTI_4"; + + client.multi() + .mset('some', '10', 'keys', '20') + .incr('some') + .incr('keys') + .mget('some', 'keys') + .exec(function (err, replies) { + assert.strictEqual(null, err); + assert.equal('OK', replies[0]); + assert.equal(11, replies[1]); + assert.equal(21, replies[2]); + assert.equal(11, replies[3][0].toString()); + assert.equal(21, replies[3][1].toString()); + next(name); + }); +}; + +tests.MULTI_5 = function () { + var name = "MULTI_5"; + + // test nested multi-bulk replies with nulls. + client.multi([ + ["mget", ["multifoo", "some", "random value", "keys"]], + ["incr", "multifoo"] + ]) + .exec(function (err, replies) { + assert.strictEqual(replies.length, 2, name); + assert.strictEqual(replies[0].length, 4, name); + next(name); + }); +}; + +tests.MULTI_6 = function () { + var name = "MULTI_6"; + + client.multi() + .hmset("multihash", "a", "foo", "b", 1) + .hmset("multihash", { + extra: "fancy", + things: "here" + }) + .hgetall("multihash") + .exec(function (err, replies) { + assert.strictEqual(null, err); + assert.equal("OK", replies[0]); + assert.equal(Object.keys(replies[2]).length, 4); + assert.equal("foo", replies[2].a); + assert.equal("1", replies[2].b); + assert.equal("fancy", replies[2].extra); + assert.equal("here", replies[2].things); + next(name); + }); +}; + +tests.EVAL_1 = function () { + var name = "EVAL_1"; + + if (client.server_info.versions[0] >= 2 && client.server_info.versions[1] >= 9) { + // test {EVAL - Lua integer -> Redis protocol type conversion} + client.eval("return 100.5", 0, require_number(100, name)); + // test {EVAL - Lua string -> Redis protocol type conversion} + client.eval("return 'hello world'", 0, require_string("hello world", name)); + // test {EVAL - Lua true boolean -> Redis protocol type conversion} + client.eval("return true", 0, require_number(1, name)); + // test {EVAL - Lua false boolean -> Redis protocol type conversion} + client.eval("return false", 0, require_null(name)); + // test {EVAL - Lua status code reply -> Redis protocol type conversion} + client.eval("return {ok='fine'}", 0, require_string("fine", name)); + // test {EVAL - Lua error reply -> Redis protocol type conversion} + client.eval("return {err='this is an error'}", 0, require_error(name)); + // test {EVAL - Lua table -> Redis protocol type conversion} + client.eval("return {1,2,3,'ciao',{1,2}}", 0, function (err, res) { + assert.strictEqual(5, res.length, name); + assert.strictEqual(1, res[0], name); + assert.strictEqual(2, res[1], name); + assert.strictEqual(3, res[2], name); + assert.strictEqual("ciao", res[3], name); + assert.strictEqual(2, res[4].length, name); + assert.strictEqual(1, res[4][0], name); + assert.strictEqual(2, res[4][1], name); + }); + // test {EVAL - Are the KEYS and ARGS arrays populated correctly?} + client.eval("return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "a", "b", "c", "d", function (err, res) { + assert.strictEqual(4, res.length, name); + assert.strictEqual("a", res[0], name); + assert.strictEqual("b", res[1], name); + assert.strictEqual("c", res[2], name); + assert.strictEqual("d", res[3], name); + }); + // test {EVAL - is Lua able to call Redis API?} + client.set("mykey", "myval"); + client.eval("return redis.call('get','mykey')", 0, require_string("myval", name)); + // test {EVALSHA - Can we call a SHA1 if already defined?} + client.evalsha("9bd632c7d33e571e9f24556ebed26c3479a87129", 0, require_string("myval", name)); + // test {EVALSHA - Do we get an error on non defined SHA1?} + client.evalsha("ffffffffffffffffffffffffffffffffffffffff", 0, require_error(name)); + // test {EVAL - Redis integer -> Lua type conversion} + client.set("x", 0); + client.eval("local foo = redis.call('incr','x')\n" + "return {type(foo),foo}", 0, function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("number", res[0], name); + assert.strictEqual(1, res[1], name); + }); + // test {EVAL - Redis bulk -> Lua type conversion} + client.eval("local foo = redis.call('get','mykey'); return {type(foo),foo}", 0, function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("string", res[0], name); + assert.strictEqual("myval", res[1], name); + }); + // test {EVAL - Redis multi bulk -> Lua type conversion} + client.del("mylist"); + client.rpush("mylist", "a"); + client.rpush("mylist", "b"); + client.rpush("mylist", "c"); + client.eval("local foo = redis.call('lrange','mylist',0,-1)\n" + "return {type(foo),foo[1],foo[2],foo[3],# foo}", 0, function (err, res) { + assert.strictEqual(5, res.length, name); + assert.strictEqual("table", res[0], name); + assert.strictEqual("a", res[1], name); + assert.strictEqual("b", res[2], name); + assert.strictEqual("c", res[3], name); + assert.strictEqual(3, res[4], name); + }); + // test {EVAL - Redis status reply -> Lua type conversion} + client.eval("local foo = redis.call('set','mykey','myval'); return {type(foo),foo['ok']}", 0, function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("table", res[0], name); + assert.strictEqual("OK", res[1], name); + }); + // test {EVAL - Redis error reply -> Lua type conversion} + client.set("mykey", "myval"); + client.eval("local foo = redis.call('incr','mykey'); return {type(foo),foo['err']}", 0, function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("table", res[0], name); + assert.strictEqual("ERR value is not an integer or out of range", res[1], name); + }); + // test {EVAL - Redis nil bulk reply -> Lua type conversion} + client.del("mykey"); + client.eval("local foo = redis.call('get','mykey'); return {type(foo),foo == false}", 0, function (err, res) { + assert.strictEqual(2, res.length, name); + assert.strictEqual("boolean", res[0], name); + assert.strictEqual(1, res[1], name); + }); + // test {EVAL - Script can't run more than configured time limit} { + client.config("set", "lua-time-limit", 1); + client.eval("local i = 0; while true do i=i+1 end", 0, last("name", require_error(name))); + } else { + console.log("Skipping " + name + " because server version isn't new enough."); + next(name); + } +}; + +tests.WATCH_MULTI = function () { + var name = 'WATCH_MULTI', multi; + + if (client.server_info.versions[0] >= 2 && client.server_info.versions[1] >= 1) { + client.watch(name); + client.incr(name); + multi = client.multi(); + multi.incr(name); + multi.exec(last(name, require_null(name))); + } else { + console.log("Skipping " + name + " because server version isn't new enough."); + next(name); + } +}; + +tests.reconnect = function () { + var name = "reconnect"; + + client.set("recon 1", "one"); + client.set("recon 2", "two", function (err, res) { + // Do not do this in normal programs. This is to simulate the server closing on us. + // For orderly shutdown in normal programs, do client.quit() + client.stream.destroy(); + }); + + client.on("reconnecting", function on_recon(params) { + client.on("connect", function on_connect() { + client.select(test_db_num, require_string("OK", name)); + client.get("recon 1", require_string("one", name)); + client.get("recon 1", require_string("one", name)); + client.get("recon 2", require_string("two", name)); + client.get("recon 2", require_string("two", name)); + client.removeListener("connect", on_connect); + client.removeListener("reconnecting", on_recon); + next(name); + }); + }); +}; + +tests.HSET = function () { + var key = "test hash", + field1 = new Buffer("0123456789"), + value1 = new Buffer("abcdefghij"), + field2 = new Buffer(0), + value2 = new Buffer(0), + name = "HSET"; + + client.HSET(key, field1, value1, require_number(1, name)); + client.HGET(key, field1, require_string(value1.toString(), name)); + + // Empty value + client.HSET(key, field1, value2, require_number(0, name)); + client.HGET([key, field1], require_string("", name)); + + // Empty key, empty value + client.HSET([key, field2, value1], require_number(1, name)); + client.HSET(key, field2, value2, last(name, require_number(0, name))); +}; + +tests.HMSET_BUFFER_AND_ARRAY = function () { + // Saving a buffer and an array to the same key should not error + var key = "test hash", + field1 = "buffer", + value1 = new Buffer("abcdefghij"), + field2 = "array", + value2 = [], + name = "HSET"; + + client.HMSET(key, field1, value1, field2, value2, last(name, require_string("OK", name))); +}; + +// TODO - add test for HMSET. It is special. Test for all forms as well as optional callbacks + +tests.HMGET = function () { + var key1 = "test hash 1", key2 = "test hash 2", name = "HMGET"; + + // redis-like hmset syntax + client.HMSET(key1, "0123456789", "abcdefghij", "some manner of key", "a type of value", require_string("OK", name)); + + // fancy hmset syntax + client.HMSET(key2, { + "0123456789": "abcdefghij", + "some manner of key": "a type of value" + }, require_string("OK", name)); + + client.HMGET(key1, "0123456789", "some manner of key", function (err, reply) { + assert.strictEqual("abcdefghij", reply[0].toString(), name); + assert.strictEqual("a type of value", reply[1].toString(), name); + }); + + client.HMGET(key2, "0123456789", "some manner of key", function (err, reply) { + assert.strictEqual("abcdefghij", reply[0].toString(), name); + assert.strictEqual("a type of value", reply[1].toString(), name); + }); + + client.HMGET(key1, ["0123456789"], function (err, reply) { + assert.strictEqual("abcdefghij", reply[0], name); + }); + + client.HMGET(key1, ["0123456789", "some manner of key"], function (err, reply) { + assert.strictEqual("abcdefghij", reply[0], name); + assert.strictEqual("a type of value", reply[1], name); + }); + + client.HMGET(key1, "missing thing", "another missing thing", function (err, reply) { + assert.strictEqual(null, reply[0], name); + assert.strictEqual(null, reply[1], name); + next(name); + }); +}; + +tests.HINCRBY = function () { + var name = "HINCRBY"; + client.hset("hash incr", "value", 10, require_number(1, name)); + client.HINCRBY("hash incr", "value", 1, require_number(11, name)); + client.HINCRBY("hash incr", "value 2", 1, last(name, require_number(1, name))); +}; + +tests.SUBSCRIBE = function () { + var client1 = client, msg_count = 0, name = "SUBSCRIBE"; + + client1.on("subscribe", function (channel, count) { + if (channel === "chan1") { + client2.publish("chan1", "message 1", require_number(1, name)); + client2.publish("chan2", "message 2", require_number(1, name)); + client2.publish("chan1", "message 3", require_number(1, name)); + } + }); + + client1.on("unsubscribe", function (channel, count) { + if (count === 0) { + // make sure this connection can go into and out of pub/sub mode + client1.incr("did a thing", last(name, require_number(2, name))); + } + }); + + client1.on("message", function (channel, message) { + msg_count += 1; + assert.strictEqual("message " + msg_count, message.toString()); + if (msg_count === 3) { + client1.unsubscribe("chan1", "chan2"); + } + }); + + client1.set("did a thing", 1, require_string("OK", name)); + client1.subscribe("chan1", "chan2"); +}; + +tests.SUBSCRIBE_QUIT = function () { + var name = "SUBSCRIBE_QUIT"; + client3.on("end", function () { + next(name); + }); + client3.on("subscribe", function (channel, count) { + client3.quit(); + }); + client3.subscribe("chan3"); +}; + +tests.EXISTS = function () { + var name = "EXISTS"; + client.del("foo", "foo2", require_number_any(name)); + client.set("foo", "bar", require_string("OK", name)); + client.EXISTS("foo", require_number(1, name)); + client.EXISTS("foo2", last(name, require_number(0, name))); +}; + +tests.DEL = function () { + var name = "DEL"; + client.DEL("delkey", require_number_any(name)); + client.set("delkey", "delvalue", require_string("OK", name)); + client.DEL("delkey", require_number(1, name)); + client.exists("delkey", require_number(0, name)); + client.DEL("delkey", require_number(0, name)); + client.mset("delkey", "delvalue", "delkey2", "delvalue2", require_string("OK", name)); + client.DEL("delkey", "delkey2", last(name, require_number(2, name))); +}; + +tests.TYPE = function () { + var name = "TYPE"; + client.set(["string key", "should be a string"], require_string("OK", name)); + client.rpush(["list key", "should be a list"], require_number_pos(name)); + client.sadd(["set key", "should be a set"], require_number_any(name)); + client.zadd(["zset key", "10.0", "should be a zset"], require_number_any(name)); + client.hset(["hash key", "hashtest", "should be a hash"], require_number_any(0, name)); + + client.TYPE(["string key"], require_string("string", name)); + client.TYPE(["list key"], require_string("list", name)); + client.TYPE(["set key"], require_string("set", name)); + client.TYPE(["zset key"], require_string("zset", name)); + client.TYPE("not here yet", require_string("none", name)); + client.TYPE(["hash key"], last(name, require_string("hash", name))); +}; + +tests.KEYS = function () { + var name = "KEYS"; + client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], require_string("OK", name)); + client.KEYS(["test keys*"], function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(2, results.length, name); + assert.strictEqual("test keys 1", results[0].toString(), name); + assert.strictEqual("test keys 2", results[1].toString(), name); + next(name); + }); +}; + +tests.MULTIBULK_ZERO_LENGTH = function () { + var name = "MULTIBULK_ZERO_LENGTH"; + client.KEYS(['users:*'], function (err, results) { + assert.strictEqual(null, err, 'error on empty multibulk reply'); + assert.strictEqual(true, is_empty_array(results), "not an empty array"); + next(name); + }); +}; + +tests.RANDOMKEY = function () { + var name = "RANDOMKEY"; + client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], require_string("OK", name)); + client.RANDOMKEY([], function (err, results) { + assert.strictEqual(null, err, name + " result sent back unexpected error: " + err); + assert.strictEqual(true, /\w+/.test(results), name); + next(name); + }); +}; + +tests.RENAME = function () { + var name = "RENAME"; + client.set(['foo', 'bar'], require_string("OK", name)); + client.RENAME(["foo", "new foo"], require_string("OK", name)); + client.exists(["foo"], require_number(0, name)); + client.exists(["new foo"], last(name, require_number(1, name))); +}; + +tests.RENAMENX = function () { + var name = "RENAMENX"; + client.set(['foo', 'bar'], require_string("OK", name)); + client.set(['foo2', 'bar2'], require_string("OK", name)); + client.RENAMENX(["foo", "foo2"], require_number(0, name)); + client.exists(["foo"], require_number(1, name)); + client.exists(["foo2"], require_number(1, name)); + client.del(["foo2"], require_number(1, name)); + client.RENAMENX(["foo", "foo2"], require_number(1, name)); + client.exists(["foo"], require_number(0, name)); + client.exists(["foo2"], last(name, require_number(1, name))); +}; + +tests.DBSIZE = function () { + var name = "DBSIZE"; + client.set(['foo', 'bar'], require_string("OK", name)); + client.DBSIZE([], last(name, require_number_pos("DBSIZE"))); +}; + +tests.GET = function () { + var name = "GET"; + client.set(["get key", "get val"], require_string("OK", name)); + client.GET(["get key"], last(name, require_string("get val", name))); +}; + +tests.SET = function () { + var name = "SET"; + client.SET(["set key", "set val"], require_string("OK", name)); + client.get(["set key"], last(name, require_string("set val", name))); +}; + +tests.GETSET = function () { + var name = "GETSET"; + client.set(["getset key", "getset val"], require_string("OK", name)); + client.GETSET(["getset key", "new getset val"], require_string("getset val", name)); + client.get(["getset key"], last(name, require_string("new getset val", name))); +}; + +tests.MGET = function () { + var name = "MGET"; + client.mset(["mget keys 1", "mget val 1", "mget keys 2", "mget val 2", "mget keys 3", "mget val 3"], require_string("OK", name)); + client.MGET("mget keys 1", "mget keys 2", "mget keys 3", function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(3, results.length, name); + assert.strictEqual("mget val 1", results[0].toString(), name); + assert.strictEqual("mget val 2", results[1].toString(), name); + assert.strictEqual("mget val 3", results[2].toString(), name); + }); + client.MGET(["mget keys 1", "mget keys 2", "mget keys 3"], function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(3, results.length, name); + assert.strictEqual("mget val 1", results[0].toString(), name); + assert.strictEqual("mget val 2", results[1].toString(), name); + assert.strictEqual("mget val 3", results[2].toString(), name); + }); + client.MGET(["mget keys 1", "some random shit", "mget keys 2", "mget keys 3"], function (err, results) { + assert.strictEqual(null, err, "result sent back unexpected error: " + err); + assert.strictEqual(4, results.length, name); + assert.strictEqual("mget val 1", results[0].toString(), name); + assert.strictEqual(null, results[1], name); + assert.strictEqual("mget val 2", results[2].toString(), name); + assert.strictEqual("mget val 3", results[3].toString(), name); + next(name); + }); +}; + +tests.SETNX = function () { + var name = "SETNX"; + client.set(["setnx key", "setnx value"], require_string("OK", name)); + client.SETNX(["setnx key", "new setnx value"], require_number(0, name)); + client.del(["setnx key"], require_number(1, name)); + client.exists(["setnx key"], require_number(0, name)); + client.SETNX(["setnx key", "new setnx value"], require_number(1, name)); + client.exists(["setnx key"], last(name, require_number(1, name))); +}; + +tests.SETEX = function () { + var name = "SETEX"; + client.SETEX(["setex key", "100", "setex val"], require_string("OK", name)); + client.exists(["setex key"], require_number(1, name)); + client.ttl(["setex key"], last(name, require_number_pos(name))); +}; + +tests.MSETNX = function () { + var name = "MSETNX"; + client.mset(["mset1", "val1", "mset2", "val2", "mset3", "val3"], require_string("OK", name)); + client.MSETNX(["mset3", "val3", "mset4", "val4"], require_number(0, name)); + client.del(["mset3"], require_number(1, name)); + client.MSETNX(["mset3", "val3", "mset4", "val4"], require_number(1, name)); + client.exists(["mset3"], require_number(1, name)); + client.exists(["mset4"], last(name, require_number(1, name))); +}; + +tests.HGETALL = function () { + var name = "HGETALL"; + client.hmset(["hosts", "mjr", "1", "another", "23", "home", "1234"], require_string("OK", name)); + client.HGETALL(["hosts"], function (err, obj) { + assert.strictEqual(null, err, name + " result sent back unexpected error: " + err); + assert.strictEqual(3, Object.keys(obj).length, name); + assert.strictEqual("1", obj.mjr.toString(), name); + assert.strictEqual("23", obj.another.toString(), name); + assert.strictEqual("1234", obj.home.toString(), name); + next(name); + }); +}; + +tests.HGETALL_NULL = function () { + var name = "HGETALL_NULL"; + + client.hgetall('missing', function (err, obj) { + assert.strictEqual(null, err); + assert.deepEqual([], obj); + next(name); + }); +}; + +tests.UTF8 = function () { + var name = "UTF8", + utf8_sample = "ಠ_ಠ"; + + client.set(["utf8test", utf8_sample], require_string("OK", name)); + client.get(["utf8test"], function (err, obj) { + assert.strictEqual(null, err); + assert.strictEqual(utf8_sample, obj); + next(name); + }); +}; + +// Set tests were adapted from Brian Hammond's redis-node-client.js, which has a comprehensive test suite + +tests.SADD = function () { + var name = "SADD"; + + client.del('set0'); + client.sadd('set0', 'member0', require_number(1, name)); + client.sadd('set0', 'member0', last(name, require_number(0, name))); +}; + +tests.SISMEMBER = function () { + var name = "SISMEMBER"; + + client.del('set0'); + client.sadd('set0', 'member0', require_number(1, name)); + client.sismember('set0', 'member0', require_number(1, name)); + client.sismember('set0', 'member1', last(name, require_number(0, name))); +}; + +tests.SCARD = function () { + var name = "SCARD"; + + client.del('set0'); + client.sadd('set0', 'member0', require_number(1, name)); + client.scard('set0', require_number(1, name)); + client.sadd('set0', 'member1', require_number(1, name)); + client.scard('set0', last(name, require_number(2, name))); +}; + +tests.SREM = function () { + var name = "SREM"; + + client.del('set0'); + client.sadd('set0', 'member0', require_number(1, name)); + client.srem('set0', 'foobar', require_number(0, name)); + client.srem('set0', 'member0', require_number(1, name)); + client.scard('set0', last(name, require_number(0, name))); +}; + +tests.SPOP = function () { + var name = "SPOP"; + + client.del('zzz'); + client.sadd('zzz', 'member0', require_number(1, name)); + client.scard('zzz', require_number(1, name)); + + client.spop('zzz', function (err, value) { + if (err) { + assert.fail(err); + } + assert.equal(value, 'member0', name); + }); + + client.scard('zzz', last(name, require_number(0, name))); +}; + +tests.SDIFF = function () { + var name = "SDIFF"; + + client.del('foo'); + client.sadd('foo', 'x', require_number(1, name)); + client.sadd('foo', 'a', require_number(1, name)); + client.sadd('foo', 'b', require_number(1, name)); + client.sadd('foo', 'c', require_number(1, name)); + + client.sadd('bar', 'c', require_number(1, name)); + + client.sadd('baz', 'a', require_number(1, name)); + client.sadd('baz', 'd', require_number(1, name)); + + client.sdiff('foo', 'bar', 'baz', function (err, values) { + if (err) { + assert.fail(err, name); + } + values.sort(); + assert.equal(values.length, 2, name); + assert.equal(values[0], 'b', name); + assert.equal(values[1], 'x', name); + next(name); + }); +}; + +tests.SDIFFSTORE = function () { + var name = "SDIFFSTORE"; + + client.del('foo'); + client.del('bar'); + client.del('baz'); + client.del('quux'); + + client.sadd('foo', 'x', require_number(1, name)); + client.sadd('foo', 'a', require_number(1, name)); + client.sadd('foo', 'b', require_number(1, name)); + client.sadd('foo', 'c', require_number(1, name)); + + client.sadd('bar', 'c', require_number(1, name)); + + client.sadd('baz', 'a', require_number(1, name)); + client.sadd('baz', 'd', require_number(1, name)); + + // NB: SDIFFSTORE returns the number of elements in the dstkey + + client.sdiffstore('quux', 'foo', 'bar', 'baz', require_number(2, name)); + + client.smembers('quux', function (err, values) { + if (err) { + assert.fail(err, name); + } + var members = buffers_to_strings(values).sort(); + + assert.deepEqual(members, [ 'b', 'x' ], name); + next(name); + }); +}; + +tests.SMEMBERS = function () { + var name = "SMEMBERS"; + + client.del('foo'); + client.sadd('foo', 'x', require_number(1, name)); + + client.smembers('foo', function (err, members) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(members), [ 'x' ], name); + }); + + client.sadd('foo', 'y', require_number(1, name)); + + client.smembers('foo', function (err, values) { + if (err) { + assert.fail(err, name); + } + assert.equal(values.length, 2, name); + var members = buffers_to_strings(values).sort(); + + assert.deepEqual(members, [ 'x', 'y' ], name); + next(name); + }); +}; + +tests.SMOVE = function () { + var name = "SMOVE"; + + client.del('foo'); + client.del('bar'); + + client.sadd('foo', 'x', require_number(1, name)); + client.smove('foo', 'bar', 'x', require_number(1, name)); + client.sismember('foo', 'x', require_number(0, name)); + client.sismember('bar', 'x', require_number(1, name)); + client.smove('foo', 'bar', 'x', last(name, require_number(0, name))); +}; + +tests.SINTER = function () { + var name = "SINTER"; + + client.del('sa'); + client.del('sb'); + client.del('sc'); + + client.sadd('sa', 'a', require_number(1, name)); + client.sadd('sa', 'b', require_number(1, name)); + client.sadd('sa', 'c', require_number(1, name)); + + client.sadd('sb', 'b', require_number(1, name)); + client.sadd('sb', 'c', require_number(1, name)); + client.sadd('sb', 'd', require_number(1, name)); + + client.sadd('sc', 'c', require_number(1, name)); + client.sadd('sc', 'd', require_number(1, name)); + client.sadd('sc', 'e', require_number(1, name)); + + client.sinter('sa', 'sb', function (err, intersection) { + if (err) { + assert.fail(err, name); + } + assert.equal(intersection.length, 2, name); + assert.deepEqual(buffers_to_strings(intersection).sort(), [ 'b', 'c' ], name); + }); + + client.sinter('sb', 'sc', function (err, intersection) { + if (err) { + assert.fail(err, name); + } + assert.equal(intersection.length, 2, name); + assert.deepEqual(buffers_to_strings(intersection).sort(), [ 'c', 'd' ], name); + }); + + client.sinter('sa', 'sc', function (err, intersection) { + if (err) { + assert.fail(err, name); + } + assert.equal(intersection.length, 1, name); + assert.equal(intersection[0], 'c', name); + }); + + // 3-way + + client.sinter('sa', 'sb', 'sc', function (err, intersection) { + if (err) { + assert.fail(err, name); + } + assert.equal(intersection.length, 1, name); + assert.equal(intersection[0], 'c', name); + next(name); + }); +}; + +tests.SINTERSTORE = function () { + var name = "SINTERSTORE"; + + client.del('sa'); + client.del('sb'); + client.del('sc'); + client.del('foo'); + + client.sadd('sa', 'a', require_number(1, name)); + client.sadd('sa', 'b', require_number(1, name)); + client.sadd('sa', 'c', require_number(1, name)); + + client.sadd('sb', 'b', require_number(1, name)); + client.sadd('sb', 'c', require_number(1, name)); + client.sadd('sb', 'd', require_number(1, name)); + + client.sadd('sc', 'c', require_number(1, name)); + client.sadd('sc', 'd', require_number(1, name)); + client.sadd('sc', 'e', require_number(1, name)); + + client.sinterstore('foo', 'sa', 'sb', 'sc', require_number(1, name)); + + client.smembers('foo', function (err, members) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(members), [ 'c' ], name); + next(name); + }); +}; + +tests.SUNION = function () { + var name = "SUNION"; + + client.del('sa'); + client.del('sb'); + client.del('sc'); + + client.sadd('sa', 'a', require_number(1, name)); + client.sadd('sa', 'b', require_number(1, name)); + client.sadd('sa', 'c', require_number(1, name)); + + client.sadd('sb', 'b', require_number(1, name)); + client.sadd('sb', 'c', require_number(1, name)); + client.sadd('sb', 'd', require_number(1, name)); + + client.sadd('sc', 'c', require_number(1, name)); + client.sadd('sc', 'd', require_number(1, name)); + client.sadd('sc', 'e', require_number(1, name)); + + client.sunion('sa', 'sb', 'sc', function (err, union) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(union).sort(), ['a', 'b', 'c', 'd', 'e'], name); + next(name); + }); +}; + +tests.SUNIONSTORE = function () { + var name = "SUNIONSTORE"; + + client.del('sa'); + client.del('sb'); + client.del('sc'); + client.del('foo'); + + client.sadd('sa', 'a', require_number(1, name)); + client.sadd('sa', 'b', require_number(1, name)); + client.sadd('sa', 'c', require_number(1, name)); + + client.sadd('sb', 'b', require_number(1, name)); + client.sadd('sb', 'c', require_number(1, name)); + client.sadd('sb', 'd', require_number(1, name)); + + client.sadd('sc', 'c', require_number(1, name)); + client.sadd('sc', 'd', require_number(1, name)); + client.sadd('sc', 'e', require_number(1, name)); + + client.sunionstore('foo', 'sa', 'sb', 'sc', function (err, cardinality) { + if (err) { + assert.fail(err, name); + } + assert.equal(cardinality, 5, name); + }); + + client.smembers('foo', function (err, members) { + if (err) { + assert.fail(err, name); + } + assert.equal(members.length, 5, name); + assert.deepEqual(buffers_to_strings(members).sort(), ['a', 'b', 'c', 'd', 'e'], name); + next(name); + }); +}; + +// SORT test adapted from Brian Hammond's redis-node-client.js, which has a comprehensive test suite + +tests.SORT = function () { + var name = "SORT"; + + client.del('y'); + client.del('x'); + + client.rpush('y', 'd', require_number(1, name)); + client.rpush('y', 'b', require_number(2, name)); + client.rpush('y', 'a', require_number(3, name)); + client.rpush('y', 'c', require_number(4, name)); + + client.rpush('x', '3', require_number(1, name)); + client.rpush('x', '9', require_number(2, name)); + client.rpush('x', '2', require_number(3, name)); + client.rpush('x', '4', require_number(4, name)); + + client.set('w3', '4', require_string("OK", name)); + client.set('w9', '5', require_string("OK", name)); + client.set('w2', '12', require_string("OK", name)); + client.set('w4', '6', require_string("OK", name)); + + client.set('o2', 'buz', require_string("OK", name)); + client.set('o3', 'foo', require_string("OK", name)); + client.set('o4', 'baz', require_string("OK", name)); + client.set('o9', 'bar', require_string("OK", name)); + + client.set('p2', 'qux', require_string("OK", name)); + client.set('p3', 'bux', require_string("OK", name)); + client.set('p4', 'lux', require_string("OK", name)); + client.set('p9', 'tux', require_string("OK", name)); + + // Now the data has been setup, we can test. + + // But first, test basic sorting. + + // y = [ d b a c ] + // sort y ascending = [ a b c d ] + // sort y descending = [ d c b a ] + + client.sort('y', 'asc', 'alpha', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), ['a', 'b', 'c', 'd'], name); + }); + + client.sort('y', 'desc', 'alpha', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), ['d', 'c', 'b', 'a'], name); + }); + + // Now try sorting numbers in a list. + // x = [ 3, 9, 2, 4 ] + + client.sort('x', 'asc', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), [2, 3, 4, 9], name); + }); + + client.sort('x', 'desc', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), [9, 4, 3, 2], name); + }); + + // Try sorting with a 'by' pattern. + + client.sort('x', 'by', 'w*', 'asc', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), [3, 9, 4, 2], name); + }); + + // Try sorting with a 'by' pattern and 1 'get' pattern. + + client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), ['foo', 'bar', 'baz', 'buz'], name); + }); + + // Try sorting with a 'by' pattern and 2 'get' patterns. + + client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', function (err, sorted) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(sorted), ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux'], name); + }); + + // Try sorting with a 'by' pattern and 2 'get' patterns. + // Instead of getting back the sorted set/list, store the values to a list. + // Then check that the values are there in the expected order. + + client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', 'store', 'bacon', function (err) { + if (err) { + assert.fail(err, name); + } + }); + + client.lrange('bacon', 0, -1, function (err, values) { + if (err) { + assert.fail(err, name); + } + assert.deepEqual(buffers_to_strings(values), ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux'], name); + next(name); + }); + + // TODO - sort by hash value +}; + +tests.BLPOP = function () { + var name = "BLPOP"; + + client.rpush("blocking list", "initial value", function (err, res) { + client2.BLPOP("blocking list", 0, function (err, res) { + assert.strictEqual("blocking list", res[0].toString()); + assert.strictEqual("initial value", res[1].toString()); + + client.rpush("blocking list", "wait for this value"); + }); + client2.BLPOP("blocking list", 0, function (err, res) { + assert.strictEqual("blocking list", res[0].toString()); + assert.strictEqual("wait for this value", res[1].toString()); + next(name); + }); + }); +}; + +tests.BLPOP_TIMEOUT = function () { + var name = "BLPOP_TIMEOUT"; + + // try to BLPOP the list again, which should be empty. This should timeout and return null. + client2.BLPOP("blocking list", 1, function (err, res) { + if (err) { + throw err; + } + + assert.strictEqual(res, null); + next(name); + }); +}; + +tests.EXPIRE = function () { + var name = "EXPIRE"; + client.set(['expiry key', 'bar'], require_string("OK", name)); + client.EXPIRE(["expiry key", "1"], require_number_pos(name)); + setTimeout(function () { + client.exists(["expiry key"], last(name, require_number(0, name))); + }, 2000); +}; + +tests.TTL = function () { + var name = "TTL"; + client.set(["ttl key", "ttl val"], require_string("OK", name)); + client.expire(["ttl key", "100"], require_number_pos(name)); + setTimeout(function () { + client.TTL(["ttl key"], last(name, require_number_pos(0, name))); + }, 500); +}; + +all_tests = Object.keys(tests); +all_start = new Date(); +test_count = 0; + +run_next_test = function run_next_test() { + var test_name = all_tests.shift(); + if (typeof tests[test_name] === "function") { + util.print('- \x1b[1m' + test_name.toLowerCase() + '\x1b[0m:'); + cur_start = new Date(); + test_count += 1; + tests[test_name](); + } else { + console.log('\n completed \x1b[32m%d\x1b[0m tests in \x1b[33m%d\x1b[0m ms\n', test_count, new Date() - all_start); + client.quit(); + client2.quit(); + client4.quit(); + } +}; + +console.log("Using reply parser " + client.reply_parser.name); + +client.once("ready", function start_tests() { + console.log("Connected to " + client.host + ":" + client.port + ", Redis server version " + client.server_info.redis_version + "\n"); + + run_next_test(); + + connected = true; +}); + +client.on('end', function () { + ended = true; +}); + +// TODO - need a better way to test auth, maybe auto-config a local Redis server? Sounds hard. +// Yes, this is the real password. Please be nice, thanks. +client4.auth("664b1b6aaf134e1ec281945a8de702a9", function (err, res) { + var name = "AUTH_4"; + + if (err) { + assert.fail(err, name); + } + assert.strictEqual("OK", res.toString(), "auth"); +}); + +// Exit immediately on connection failure, which triggers "exit", below, which fails the test +client.on("error", function (err) { + console.error("client: " + err.stack); + process.exit(); +}); +client2.on("error", function (err) { + console.error("client2: " + err.stack); + process.exit(); +}); +client3.on("error", function (err) { + console.error("client3: " + err.stack); + process.exit(); +}); + +client.on("reconnecting", function (params) { +// console.log("reconnecting: " + util.inspect(params)); +}); + +process.on('uncaughtException', function (err) { + console.error("Uncaught exception: " + err.stack); + process.exit(1); +}); + +process.on('exit', function (code) { + assert.equal(true, connected); + assert.equal(true, ended); +}); diff --git a/node_modules/socket.io/node_modules/redis/tests/buffer_bench.js b/node_modules/socket.io/node_modules/redis/tests/buffer_bench.js new file mode 100644 index 0000000..a504fbc --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/tests/buffer_bench.js @@ -0,0 +1,89 @@ +var source = new Buffer(100), + dest = new Buffer(100), i, j, k, tmp, count = 1000000, bytes = 100; + +for (i = 99 ; i >= 0 ; i--) { + source[i] = 120; +} + +var str = "This is a nice String.", + buf = new Buffer("This is a lovely Buffer."); + +var start = new Date(); +for (i = count * 100; i > 0 ; i--) { + if (Buffer.isBuffer(str)) {} +} +var end = new Date(); +console.log("Buffer.isBuffer(str) " + (end - start) + " ms"); + +var start = new Date(); +for (i = count * 100; i > 0 ; i--) { + if (Buffer.isBuffer(buf)) {} +} +var end = new Date(); +console.log("Buffer.isBuffer(buf) " + (end - start) + " ms"); + +var start = new Date(); +for (i = count * 100; i > 0 ; i--) { + if (str instanceof Buffer) {} +} +var end = new Date(); +console.log("str instanceof Buffer " + (end - start) + " ms"); + +var start = new Date(); +for (i = count * 100; i > 0 ; i--) { + if (buf instanceof Buffer) {} +} +var end = new Date(); +console.log("buf instanceof Buffer " + (end - start) + " ms"); + +for (i = bytes ; i > 0 ; i --) { + var start = new Date(); + for (j = count ; j > 0; j--) { + tmp = source.toString("ascii", 0, bytes); + } + var end = new Date(); + console.log("toString() " + i + " bytes " + (end - start) + " ms"); +} + +for (i = bytes ; i > 0 ; i --) { + var start = new Date(); + for (j = count ; j > 0; j--) { + tmp = ""; + for (k = 0; k <= i ; k++) { + tmp += String.fromCharCode(source[k]); + } + } + var end = new Date(); + console.log("manual string " + i + " bytes " + (end - start) + " ms"); +} + +for (i = bytes ; i > 0 ; i--) { + var start = new Date(); + for (j = count ; j > 0 ; j--) { + for (k = i ; k > 0 ; k--) { + dest[k] = source[k]; + } + } + var end = new Date(); + console.log("Manual copy " + i + " bytes " + (end - start) + " ms"); +} + +for (i = bytes ; i > 0 ; i--) { + var start = new Date(); + for (j = count ; j > 0 ; j--) { + for (k = i ; k > 0 ; k--) { + dest[k] = 120; + } + } + var end = new Date(); + console.log("Direct assignment " + i + " bytes " + (end - start) + " ms"); +} + +for (i = bytes ; i > 0 ; i--) { + var start = new Date(); + for (j = count ; j > 0 ; j--) { + source.copy(dest, 0, 0, i); + } + var end = new Date(); + console.log("Buffer.copy() " + i + " bytes " + (end - start) + " ms"); +} diff --git a/node_modules/socket.io/node_modules/redis/tests/reconnect_test.js b/node_modules/socket.io/node_modules/redis/tests/reconnect_test.js new file mode 100644 index 0000000..08a6ca6 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/tests/reconnect_test.js @@ -0,0 +1,27 @@ +var redis = require("redis").createClient(); + +redis.on("error", function (err) { + console.log("Redis says: " + err); +}); + +redis.on("ready", function () { + console.log("Redis ready."); +}); + +redis.on("reconnecting", function (arg) { + console.log("Redis reconnecting: " + JSON.stringify(arg)); +}); +redis.on("connect", function () { + console.log("Redis connected."); +}); + +setInterval(function () { + var now = Date.now(); + redis.set("now", now, function (err, res) { + if (err) { + console.log(now + " Redis reply error: " + err); + } else { + console.log(now + " Redis reply: " + res); + } + }); +}, 200); diff --git a/node_modules/socket.io/node_modules/redis/tests/sub_quit_test.js b/node_modules/socket.io/node_modules/redis/tests/sub_quit_test.js new file mode 100644 index 0000000..ad1f413 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/tests/sub_quit_test.js @@ -0,0 +1,18 @@ +var client = require("redis").createClient(), + client2 = require("redis").createClient(); + +client.subscribe("something"); +client.on("subscribe", function (channel, count) { + console.log("Got sub: " + channel); + client.unsubscribe("something"); +}); + +client.on("unsubscribe", function (channel, count) { + console.log("Got unsub: " + channel + ", quitting"); + client.quit(); +}); + +// exercise unsub before sub +client2.unsubscribe("something"); +client2.subscribe("another thing"); +client2.quit(); diff --git a/node_modules/socket.io/node_modules/redis/tests/test_start_stop.js b/node_modules/socket.io/node_modules/redis/tests/test_start_stop.js new file mode 100644 index 0000000..0770893 --- /dev/null +++ b/node_modules/socket.io/node_modules/redis/tests/test_start_stop.js @@ -0,0 +1,17 @@ +var redis = require("./index"), + client = redis.createClient(); + +// This currently doesn't work, due to what I beleive to be a bug in redis 2.0.1. +// INFO and QUIT are pipelined together, and the socket closes before the INFO +// command gets a reply. + +redis.debug_mode = true; +client.info(redis.print); +client.quit(); + +// A workaround is: +// client.info(function (err, res) { +// console.log(res.toString()); +// client.quit(); +// }); + diff --git a/node_modules/socket.io/node_modules/socket.io-client/.npmignore b/node_modules/socket.io/node_modules/socket.io-client/.npmignore new file mode 100644 index 0000000..c27cb50 --- /dev/null +++ b/node_modules/socket.io/node_modules/socket.io-client/.npmignore @@ -0,0 +1,2 @@ +test/node_modules +support diff --git a/node_modules/socket.io/node_modules/socket.io-client/History.md b/node_modules/socket.io/node_modules/socket.io-client/History.md new file mode 100644 index 0000000..afd1193 --- /dev/null +++ b/node_modules/socket.io/node_modules/socket.io-client/History.md @@ -0,0 +1,60 @@ + +0.7.9 / 2011-08-12 +================== + + * Added check on `Socket#onConnect` to prevent double `connect` events on the main manager. + * Fixed socket namespace connect test. Remove broken alternative namespace connect test. + * Removed test handler for removed test. + * Bumped version to match `socket.io` server. + +0.7.5 / 2011-08-08 +================== + + * Added querystring support for `connect` [3rd-Eden] + * Added partial Node.JS transports support [3rd-Eden, josephg] + * Fixed builder test. + * Changed `util.inherit` to replicate Object.create / __proto__. + * Changed and cleaned up some acceptance tests. + * Fixed race condition with a test that could not be run multiple times. + * Added test for encoding a payload. + * Added the ability to override the transport to use in acceptance test [3rd-Eden] + * Fixed multiple connect packets [DanielBaulig] + * Fixed jsonp-polling over-buffering [3rd-Eden] + * Fixed ascii preservation in minified socket.io client [3rd-Eden] + * Fixed socket.io in situations where the page is not served through utf8. + * Fixed namespaces not reconnecting after disconnect [3rd-Eden] + * Fixed default port for secure connections. + +0.7.4 / 2011-07-12 +================== + + * Added `SocketNamespace#of` shortcut. [3rd-Eden] + * Fixed a IE payload decoding bug. [3rd-Eden] + * Honor document protocol, unless overriden. [dvv] + * Fixed new builder dependencies. [3rd-Eden] + +0.7.3 / 2011-06-30 +================== + + * Fixed; acks don't depend on arity. They're automatic for `.send` and + callback based for `.emit`. [dvv] + * Added support for sub-sockets authorization. [3rd-Eden] + * Added BC support for `new io.connect`. [fat] + * Fixed double `connect` events. [3rd-Eden] + * Fixed reconnection with jsonp-polling maintaining old sessionid. [franck34] + +0.7.2 / 2011-06-22 +================== + + * Added `noop` message type. + +0.7.1 / 2011-06-21 +================== + + * Bumped socket.io dependency version for acceptance tests. + +0.7.0 / 2011-06-21 +================== + + * http://socket.io/announcement.html + diff --git a/node_modules/socket.io/node_modules/socket.io-client/Makefile b/node_modules/socket.io/node_modules/socket.io-client/Makefile new file mode 100644 index 0000000..f2d2f41 --- /dev/null +++ b/node_modules/socket.io/node_modules/socket.io-client/Makefile @@ -0,0 +1,20 @@ + +ALL_TESTS = $(shell find test/ -name '*.test.js') + +run-tests: + @./node_modules/.bin/expresso \ + -I lib \ + -I support \ + --serial \ + $(TESTS) + +test: + @$(MAKE) TESTS="$(ALL_TESTS)" run-tests + +test-acceptance: + @node support/test-runner/app $(TRANSPORT) + +build: + @node ./bin/builder.js + +.PHONY: test diff --git a/node_modules/socket.io/node_modules/socket.io-client/README.md b/node_modules/socket.io/node_modules/socket.io-client/README.md new file mode 100644 index 0000000..a36c1bf --- /dev/null +++ b/node_modules/socket.io/node_modules/socket.io-client/README.md @@ -0,0 +1,246 @@ +socket.io +========= + +#### Sockets for the rest of us + +The `socket.io` client is basically a simple HTTP Socket interface implementation. +It looks similar to WebSocket while providing additional features and +leveraging other transports when WebSocket is not supported by the user's +browser. + +```js +var socket = io.connect('http://domain.com'); +socket.on('connect', function () { + // socket connected +}); +socket.on('custom event', function () { + // server emitted a custom event +}); +socket.on('disconnect', function () { + // socket disconnected +}); +socket.send('hi there'); +``` + +### Recipes + +#### Utilizing namespaces (ie: multiple sockets) + +If you want to namespace all the messages and events emitted to a particular +endpoint, simply specify it as part of the `connect` uri: + +```js +var chat = io.connect('http://localhost/chat'); +chat.on('connect', function () { + // chat socket connected +}); + +var news = io.connect('/news'); // io.connect auto-detects host +news.on('connect', function () { + // news socket connected +}); +``` + +#### Emitting custom events + +To ease with the creation of applications, you can emit custom events outside +of the global `message` event. + +```js +var socket = io.connect(); +socket.emit('server custom event', { my: 'data' }); +``` + +#### Forcing disconnection + +```js +var socket = io.connect(); +socket.on('connect', function () { + socket.disconnect(); +}); +``` + +### Documentation + +#### io#connect + +```js +io.connect(uri, [options]); +``` + +##### Options: + +- *resource* + + socket.io + + The resource is what allows the `socket.io` server to identify incoming connections by `socket.io` clients. In other words, any HTTP server can implement socket.io and still serve other normal, non-realtime HTTP requests. + +- *transports* + +```js +['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling'] +``` + + A list of the transports to attempt to utilize (in order of preference). + +- *'connect timeout'* + +```js +5000 +``` + + The amount of milliseconds a transport has to create a connection before we consider it timed out. + +- *'try multiple transports'* + +```js +true +``` + + A boolean indicating if we should try other transports when the connectTimeout occurs. + +- *reconnect* + +```js +true +``` + + A boolean indicating if we should automatically reconnect if a connection is disconnected. + +- *'reconnection delay'* + +```js +500 +``` + + The amount of milliseconds before we try to connect to the server again. We are using a exponential back off algorithm for the following reconnections, on each reconnect attempt this value will get multiplied (500 > 1000 > 2000 > 4000 > 8000). + + +- *'max reconnection attempts'* + +```js +10 +``` + + The amount of attempts should we make using the current transport to connect to the server? After this we will do one final attempt, and re-try with all enabled transport methods before we give up. + +##### Properties: + +- *options* + + The passed in options combined with the defaults. + +- *connected* + + Whether the socket is connected or not. + +- *connecting* + + Whether the socket is connecting or not. + +- *reconnecting* + + Whether we are reconnecting or not. + +- *transport* + + The transport instance. + +##### Methods: + +- *connect(λ)* + + Establishes a connection. If λ is supplied as argument, it will be called once the connection is established. + +- *send(message)* + + A string of data to send. + +- *disconnect* + + Closes the connection. + +- *on(event, λ)* + + Adds a listener for the event *event*. + +- *once(event, λ)* + + Adds a one time listener for the event *event*. The listener is removed after the first time the event is fired. + +- *removeEvent(event, λ)* + + Removes the listener λ for the event *event*. + +##### Events: + +- *connect* + + Fired when the connection is established and the handshake successful. + +- *connecting(transport_type)* + + Fired when a connection is attempted, passing the transport name. + +- *connect_failed* + + Fired when the connection timeout occurs after the last connection attempt. + This only fires if the `connectTimeout` option is set. + If the `tryTransportsOnConnectTimeout` option is set, this only fires once all + possible transports have been tried. + +- *message(message)* + + Fired when a message arrives from the server + +- *close* + + Fired when the connection is closed. Be careful with using this event, as some transports will fire it even under temporary, expected disconnections (such as XHR-Polling). + +- *disconnect* + + Fired when the connection is considered disconnected. + +- *reconnect(transport_type,reconnectionAttempts)* + + Fired when the connection has been re-established. This only fires if the `reconnect` option is set. + +- *reconnecting(reconnectionDelay,reconnectionAttempts)* + + Fired when a reconnection is attempted, passing the next delay for the next reconnection. + +- *reconnect_failed* + + Fired when all reconnection attempts have failed and we where unsuccessful in reconnecting to the server. + +### Contributors + +Guillermo Rauch <guillermo@learnboost.com> + +Arnout Kazemier <info@3rd-eden.com> + +### License + +(The MIT License) + +Copyright (c) 2010 LearnBoost <dev@learnboost.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/socket.io/node_modules/socket.io-client/bin/builder.js b/node_modules/socket.io/node_modules/socket.io-client/bin/builder.js new file mode 100755 index 0000000..3206f04 --- /dev/null +++ b/node_modules/socket.io/node_modules/socket.io-client/bin/builder.js @@ -0,0 +1,285 @@ +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , socket = require('../lib/io') + , uglify = require('uglify-js'); + +/** + * License headers. + * + * @api private + */ + +var template = '/*! Socket.IO.%ext% build:' + socket.version + ', %type%. Copyright(c) 2011 LearnBoost MIT Licensed */\n' + , development = template.replace('%type%', 'development').replace('%ext%', 'js') + , production = template.replace('%type%', 'production').replace('%ext%', 'min.js'); + +/** + * If statements, these allows you to create serveride & client side compatible + * code using specially designed `if` statements that remove serverside + * designed code from the source files + * + * @api private + */ + +var starttagIF = '// if node' + , endtagIF = '// end node'; + +/** + * The modules that are required to create a base build of Socket.IO. + * + * @const + * @type {Array} + * @api private + */ + +var base = [ + 'io.js' + , 'util.js' + , 'events.js' + , 'json.js' + , 'parser.js' + , 'transport.js' + , 'socket.js' + , 'namespace.js' + ]; + +/** + * The available transports for Socket.IO. These are mapped as: + * + * - `key` the name of the transport + * - `value` the dependencies for the transport + * + * @const + * @type {Object} + * @api public + */ + +var baseTransports = { + 'websocket': ['transports/websocket.js'] + , 'flashsocket': [ + 'transports/websocket.js' + , 'transports/flashsocket.js' + , 'vendor/web-socket-js/swfobject.js' + , 'vendor/web-socket-js/web_socket.js' + ] + , 'htmlfile': ['transports/xhr.js', 'transports/htmlfile.js'] + /* FIXME: re-enable me once we have multi-part support + , 'xhr-multipart': ['transports/xhr.js', 'transports/xhr-multipart.js'] */ + , 'xhr-polling': ['transports/xhr.js', 'transports/xhr-polling.js'] + , 'jsonp-polling': [ + 'transports/xhr.js' + , 'transports/xhr-polling.js' + , 'transports/jsonp-polling.js' + ] +}; + +/** + * Builds a custom Socket.IO distribution based on the transports that you + * need. You can configure the build to create development build or production + * build (minified). + * + * @param {Array} transports The transports that needs to be bundled. + * @param {Object} [options] Options to configure the building process. + * @param {Function} callback Last argument should always be the callback + * @callback {String|Boolean} err An optional argument, if it exists than an error + * occurred during the build process. + * @callback {String} result The result of the build process. + * @api public + */ + +var builder = module.exports = function () { + var transports, options, callback, error = null + , args = Array.prototype.slice.call(arguments, 0) + , settings = { + minify: true + , node: false + , custom: [] + }; + + // Fancy pancy argument support this makes any pattern possible mainly + // because we require only one of each type + args.forEach(function (arg) { + var type = Object.prototype.toString.call(arg) + .replace(/\[object\s(\w+)\]/gi , '$1' ).toLowerCase(); + + switch (type) { + case 'array': + return transports = arg; + case 'object': + return options = arg; + case 'function': + return callback = arg; + } + }); + + // Add defaults + options = options || {}; + transports = transports || Object.keys(baseTransports); + + // Merge the data + for(var option in options) { + settings[option] = options[option]; + } + + // Start creating a dependencies chain with all the required files for the + // custom Socket.IO bundle. + var files = []; + base.forEach(function (file) { + files.push(__dirname + '/../lib/' + file); + }); + + transports.forEach(function (transport) { + var dependencies = baseTransports[transport]; + if (!dependencies) { + error = 'Unsupported transport `' + transport + '` supplied as argument.'; + return; + } + + // Add the files to the files list, but only if they are not added before + dependencies.forEach(function (file) { + var path = __dirname + '/../lib/' + file; + if (!~files.indexOf(path)) files.push(path); + }) + }); + + // check to see if the files tree compilation generated any errors. + if (error) return callback(error); + + var results = {}; + files.forEach(function (file) { + fs.readFile(file, function (err, content) { + if (err) error = err; + results[file] = content; + + // check if we are done yet, or not.. Just by checking the size of the result + // object. + if (Object.keys(results).length !== files.length) return; + + // we are done, did we error? + if (error) return callback(error); + + // concatinate the file contents in order + var code = development + , ignore = 0; + + files.forEach(function (file) { + code += results[file]; + }); + + // check if we need to add custom code + if (settings.custom.length) { + settings.custom.forEach(function (content) { + code += content; + }); + } + + // Search for conditional code blocks that need to be removed as they + // where designed for a server side env. but only if we don't want to + // make this build node compatible. + if (!settings.node) { + code = code.split('\n').filter(function (line) { + // check if there are tags in here + var start = line.indexOf(starttagIF) >= 0 + , end = line.indexOf(endtagIF) >= 0 + , ret = ignore; + + // ignore the current line + if (start) { + ignore++; + ret = ignore; + } + + // stop ignoring the next line + if (end) { + ignore--; + } + + return ret == 0; + }).join('\n'); + } + + // check if we need to process it any further + if (settings.minify) { + // uglify hate unicode chars... + var separator = '@@OMGYUCHANGEME@@@'; + code = code.replace(/(\\ufffd)/g, separator); + + var ast = uglify.parser.parse(code); + ast = uglify.uglify.ast_mangle(ast); + ast = uglify.uglify.ast_squeeze(ast); + + code = production + uglify.uglify.gen_code(ast); + + // restore the code + code = code.replace(new RegExp('('+ separator + ')', 'g'), '\\ufffd'); + } + + callback(error, code); + }) + }) +}; + +/** + * Builder version is also the current client version + * this way we don't have to do another include for the + * clients version number and we can just include the builder. + * + * @type {String} + * @api public + */ + +builder.version = socket.version; + +/** + * A list of all build in transport types. + * + * @type {Object} + * @api public + */ + +builder.transports = baseTransports; + +/** + * Command line support, this allows us to generate builds without having + * to load it as module. + */ + +if (!module.parent){ + // the first 2 are `node` and the path to this file, we don't need them + var args = process.argv.slice(2); + + // build a development build + builder(args.length ? args : false, { minify:false }, function (err, content) { + if (err) return console.error(err); + + fs.write( + fs.openSync(__dirname + '/../dist/socket.io.js', 'w') + , content + , 0 + , 'utf8' + ); + console.log('Successfully generated the development build: socket.io.js'); + }); + + // and build a production build + builder(args.length ? args : false, function (err, content) { + if (err) return console.error(err); + + fs.write( + fs.openSync(__dirname + '/../dist/socket.io.min.js', 'w') + , content + , 0 + , 'utf8' + ); + console.log('Successfully generated the production build: socket.io.min.js'); + }); +} diff --git a/node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMain.swf b/node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMain.swf new file mode 100644 index 0000000000000000000000000000000000000000..20a451f57ba342d27b1a485d2e3931ea79ed988b GIT binary patch literal 175830 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 z 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 literal 0 HcmV?d00001 diff --git a/node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMainInsecure.swf b/node_modules/socket.io/node_modules/socket.io-client/dist/WebSocketMainInsecure.swf new file mode 100644 index 0000000000000000000000000000000000000000..5949ff3d09e4dc669cb25144fa5775dba071b684 GIT binary patch literal 175953 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

    6_4TzBh#=34(fx0_pa7FIaK3=>Pm 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±k#VeO;J63S6QrHJIUFH4_gkHxsAIz7p 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 LboTr|Wyc*1(*E2! literal 0 HcmV?d00001 diff --git a/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js b/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js new file mode 100644 index 0000000..9927a88 --- /dev/null +++ b/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js @@ -0,0 +1,3692 @@ +/*! Socket.IO.js build:0.7.9, development. Copyright(c) 2011 LearnBoost MIT Licensed */ + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports) { + + /** + * IO namespace. + * + * @namespace + */ + + var io = exports; + + /** + * Socket.IO version + * + * @api public + */ + + io.version = '0.7.9'; + + /** + * Protocol implemented. + * + * @api public + */ + + io.protocol = 1; + + /** + * Available transports, these will be populated with the available transports + * + * @api public + */ + + io.transports = []; + + /** + * Keep track of jsonp callbacks. + * + * @api private + */ + + io.j = []; + + /** + * Keep track of our io.Sockets + * + * @api private + */ + io.sockets = {}; + + + /** + * Manages connections to hosts. + * + * @param {String} uri + * @Param {Boolean} force creation of new socket (defaults to false) + * @api public + */ + + io.connect = function (host, details) { + var uri = io.util.parseUri(host) + , uuri + , socket; + + if ('undefined' != typeof document) { + uri.protocol = uri.protocol || document.location.protocol.slice(0, -1); + uri.host = uri.host || document.domain; + uri.port = uri.port || document.location.port; + } + + uuri = io.util.uniqueUri(uri); + + var options = { + host: uri.host + , secure: 'https' == uri.protocol + , port: uri.port || ('https' == uri.protocol ? 443 : 80) + , query: uri.query || '' + }; + + io.util.merge(options, details); + + if (options['force new connection'] || !io.sockets[uuri]) { + socket = new io.Socket(options); + } + + if (!options['force new connection'] && socket) { + io.sockets[uuri] = socket; + } + + socket = socket || io.sockets[uuri]; + + // if path is different from '' or / + return socket.of(uri.path.length > 1 ? uri.path : ''); + }; + +})('object' === typeof module ? module.exports : (window.io = {})); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, global) { + + /** + * Utilities namespace. + * + * @namespace + */ + + var util = exports.util = {}; + + /** + * Parses an URI + * + * @author Steven Levithan (MIT license) + * @api public + */ + + var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; + + var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', + 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', + 'anchor']; + + util.parseUri = function (str) { + var m = re.exec(str || '') + , uri = {} + , i = 14; + + while (i--) { + uri[parts[i]] = m[i] || ''; + } + + return uri; + }; + + /** + * Produces a unique url that identifies a Socket.IO connection. + * + * @param {Object} uri + * @api public + */ + + util.uniqueUri = function (uri) { + var protocol = uri.protocol + , host = uri.host + , port = uri.port; + + if ('document' in global) { + host = host || document.domain; + port = port || (protocol == 'https' + && document.location.protocol !== 'https:' ? 443 : document.location.port); + } else { + host = host || 'localhost'; + + if (!port && protocol == 'https') { + port = 443; + } + } + + return (protocol || 'http') + '://' + host + ':' + (port || 80); + }; + + /** + * Mergest 2 query strings in to once unique query string + * + * @param {String} base + * @param {String} addition + * @api public + */ + + util.query = function (base, addition) { + var query = util.chunkQuery(base || '') + , components = []; + + util.merge(query, util.chunkQuery(addition || '')); + for (var part in query) { + if (query.hasOwnProperty(part)) { + components.push(part + '=' + query[part]); + } + } + + return components.length ? '?' + components.join('&') : ''; + }; + + /** + * Transforms a querystring in to an object + * + * @param {String} qs + * @api public + */ + + util.chunkQuery = function (qs) { + var query = {} + , params = qs.split('&') + , i = 0 + , l = params.length + , kv; + + for (; i < l; ++i) { + kv = params[i].split('='); + if (kv[0]) { + query[kv[0]] = decodeURIComponent(kv[1]); + } + } + + return query; + }; + + /** + * Executes the given function when the page is loaded. + * + * io.util.load(function () { console.log('page loaded'); }); + * + * @param {Function} fn + * @api public + */ + + var pageLoaded = false; + + util.load = function (fn) { + if ('document' in global && document.readyState === 'complete' || pageLoaded) { + return fn(); + } + + util.on(global, 'load', fn, false); + }; + + /** + * Adds an event. + * + * @api private + */ + + util.on = function (element, event, fn, capture) { + if (element.attachEvent) { + element.attachEvent('on' + event, fn); + } else if (element.addEventListener) { + element.addEventListener(event, fn, capture); + } + }; + + /** + * Generates the correct `XMLHttpRequest` for regular and cross domain requests. + * + * @param {Boolean} [xdomain] Create a request that can be used cross domain. + * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest. + * @api private + */ + + util.request = function (xdomain) { + + if ('undefined' != typeof window) { + if (xdomain && window.XDomainRequest) { + return new XDomainRequest(); + } + + if (window.XMLHttpRequest && (!xdomain || util.ua.hasCORS)) { + return new XMLHttpRequest(); + } + + if (!xdomain) { + try { + return new window.ActiveXObject('Microsoft.XMLHTTP'); + } catch(e) { } + } + } + + return null; + }; + + /** + * XHR based transport constructor. + * + * @constructor + * @api public + */ + + /** + * Change the internal pageLoaded value. + */ + + if ('undefined' != typeof window) { + util.load(function () { + pageLoaded = true; + }); + } + + /** + * Defers a function to ensure a spinner is not displayed by the browser + * + * @param {Function} fn + * @api public + */ + + util.defer = function (fn) { + if (!util.ua.webkit) { + return fn(); + } + + util.load(function () { + setTimeout(fn, 100); + }); + }; + + /** + * Merges two objects. + * + * @api public + */ + + util.merge = function merge (target, additional, deep, lastseen) { + var seen = lastseen || [] + , depth = typeof deep == 'undefined' ? 2 : deep + , prop; + + for (prop in additional) { + if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) { + if (typeof target[prop] !== 'object' || !depth) { + target[prop] = additional[prop]; + seen.push(additional[prop]); + } else { + util.merge(target[prop], additional[prop], depth - 1, seen); + } + } + } + + return target; + }; + + /** + * Merges prototypes from objects + * + * @api public + */ + + util.mixin = function (ctor, ctor2) { + util.merge(ctor.prototype, ctor2.prototype); + }; + + /** + * Shortcut for prototypical and static inheritance. + * + * @api private + */ + + util.inherit = function (ctor, ctor2) { + function f() {}; + f.prototype = ctor2.prototype; + ctor.prototype = new f; + }; + + /** + * Checks if the given object is an Array. + * + * io.util.isArray([]); // true + * io.util.isArray({}); // false + * + * @param Object obj + * @api public + */ + + util.isArray = Array.isArray || function (obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + }; + + /** + * Intersects values of two arrays into a third + * + * @api public + */ + + util.intersect = function (arr, arr2) { + var ret = [] + , longest = arr.length > arr2.length ? arr : arr2 + , shortest = arr.length > arr2.length ? arr2 : arr; + + for (var i = 0, l = shortest.length; i < l; i++) { + if (~util.indexOf(longest, shortest[i])) + ret.push(shortest[i]); + } + + return ret; + } + + /** + * Array indexOf compatibility. + * + * @see bit.ly/a5Dxa2 + * @api public + */ + + util.indexOf = function (arr, o, i) { + if (Array.prototype.indexOf) { + return Array.prototype.indexOf.call(arr, o, i); + } + + for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0; + i < j && arr[i] !== o; i++); + + return j <= i ? -1 : i; + }; + + /** + * Converts enumerables to array. + * + * @api public + */ + + util.toArray = function (enu) { + var arr = []; + + for (var i = 0, l = enu.length; i < l; i++) + arr.push(enu[i]); + + return arr; + }; + + /** + * UA / engines detection namespace. + * + * @namespace + */ + + util.ua = {}; + + /** + * Whether the UA supports CORS for XHR. + * + * @api public + */ + + util.ua.hasCORS = 'undefined' != typeof window && window.XMLHttpRequest && + (function () { + try { + var a = new XMLHttpRequest(); + } catch (e) { + return false; + } + + return a.withCredentials != undefined; + })(); + + /** + * Detect webkit. + * + * @api public + */ + + util.ua.webkit = 'undefined' != typeof navigator + && /webkit/i.test(navigator.userAgent); + +})( + 'undefined' != typeof window ? io : module.exports + , this +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.EventEmitter = EventEmitter; + + /** + * Event emitter constructor. + * + * @api public. + */ + + function EventEmitter () {}; + + /** + * Adds a listener + * + * @api public + */ + + EventEmitter.prototype.on = function (name, fn) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = fn; + } else if (io.util.isArray(this.$events[name])) { + this.$events[name].push(fn); + } else { + this.$events[name] = [this.$events[name], fn]; + } + + return this; + }; + + EventEmitter.prototype.addListener = EventEmitter.prototype.on; + + /** + * Adds a volatile listener. + * + * @api public + */ + + EventEmitter.prototype.once = function (name, fn) { + var self = this; + + function on () { + self.removeListener(name, on); + fn.apply(this, arguments); + }; + + on.listener = fn; + this.on(name, on); + + return this; + }; + + /** + * Removes a listener. + * + * @api public + */ + + EventEmitter.prototype.removeListener = function (name, fn) { + if (this.$events && this.$events[name]) { + var list = this.$events[name]; + + if (io.util.isArray(list)) { + var pos = -1; + + for (var i = 0, l = list.length; i < l; i++) { + if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { + pos = i; + break; + } + } + + if (pos < 0) { + return this; + } + + list.splice(pos, 1); + + if (!list.length) { + delete this.$events[name]; + } + } else if (list === fn || (list.listener && list.listener === fn)) { + delete this.$events[name]; + } + } + + return this; + }; + + /** + * Removes all listeners for an event. + * + * @api public + */ + + EventEmitter.prototype.removeAllListeners = function (name) { + // TODO: enable this when node 0.5 is stable + //if (name === undefined) { + //this.$events = {}; + //return this; + //} + + if (this.$events && this.$events[name]) { + this.$events[name] = null; + } + + return this; + }; + + /** + * Gets all listeners for a certain event. + * + * @api publci + */ + + EventEmitter.prototype.listeners = function (name) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = []; + } + + if (!io.util.isArray(this.$events[name])) { + this.$events[name] = [this.$events[name]]; + } + + return this.$events[name]; + }; + + /** + * Emits an event. + * + * @api public + */ + + EventEmitter.prototype.emit = function (name) { + if (!this.$events) { + return false; + } + + var handler = this.$events[name]; + + if (!handler) { + return false; + } + + var args = Array.prototype.slice.call(arguments, 1); + + if ('function' == typeof handler) { + handler.apply(this, args); + } else if (io.util.isArray(handler)) { + var listeners = handler.slice(); + + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + } else { + return false; + } + + return true; + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Based on JSON2 (http://www.JSON.org/js.html). + */ + +(function (exports, nativeJSON) { + "use strict"; + + // use native JSON if it's available + if (nativeJSON && nativeJSON.parse){ + return exports.JSON = { + parse: nativeJSON.parse + , stringify: nativeJSON.stringify + } + } + + var JSON = exports.JSON = {}; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + function date(d, key) { + return isFinite(d.valueOf()) ? + d.getUTCFullYear() + '-' + + f(d.getUTCMonth() + 1) + '-' + + f(d.getUTCDate()) + 'T' + + f(d.getUTCHours()) + ':' + + f(d.getUTCMinutes()) + ':' + + f(d.getUTCSeconds()) + 'Z' : null; + }; + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value instanceof Date) { + value = date(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : gap ? + '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + if (typeof rep[i] === 'string') { + k = rep[i]; + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : gap ? + '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : + '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + +// If the JSON object does not yet have a parse method, give it one. + + JSON.parse = function (text, reviver) { + // The parse method takes a text and an optional reviver function, and returns + // a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + + // The walk method is used to recursively walk the resulting structure so + // that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + + // Parsing happens in four stages. In the first stage, we replace certain + // Unicode characters with escape sequences. JavaScript handles many characters + // incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + + // In the second stage, we run the text against regular expressions that look + // for non-JSON patterns. We are especially concerned with '()' and 'new' + // because they can cause invocation, and '=' because it can cause mutation. + // But just to be safe, we want to reject all unexpected forms. + + // We split the second stage into 4 regexp operations in order to work around + // crippling inefficiencies in IE's and Safari's regexp engines. First we + // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we + // replace all simple value tokens with ']' characters. Third, we delete all + // open brackets that follow a colon or comma or that begin the text. Finally, + // we look to see that the remaining characters are only whitespace or ']' or + // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/ + .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') + .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + + // In the third stage we use the eval function to compile the text into a + // JavaScript structure. The '{' operator is subject to a syntactic ambiguity + // in JavaScript: it can begin a block or an object literal. We wrap the text + // in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + + // In the optional fourth stage, we recursively walk the new structure, passing + // each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + + // If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + +})( + 'undefined' != typeof io ? io : module.exports + , typeof JSON !== 'undefined' ? JSON : undefined +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Parser namespace. + * + * @namespace + */ + + var parser = exports.parser = {}; + + /** + * Packet types. + */ + + var packets = parser.packets = [ + 'disconnect' + , 'connect' + , 'heartbeat' + , 'message' + , 'json' + , 'event' + , 'ack' + , 'error' + , 'noop' + ]; + + /** + * Errors reasons. + */ + + var reasons = parser.reasons = [ + 'transport not supported' + , 'client not handshaken' + , 'unauthorized' + ]; + + /** + * Errors advice. + */ + + var advice = parser.advice = [ + 'reconnect' + ]; + + /** + * Shortcuts. + */ + + var JSON = io.JSON + , indexOf = io.util.indexOf; + + /** + * Encodes a packet. + * + * @api private + */ + + parser.encodePacket = function (packet) { + var type = indexOf(packets, packet.type) + , id = packet.id || '' + , endpoint = packet.endpoint || '' + , ack = packet.ack + , data = null; + + switch (packet.type) { + case 'error': + var reason = packet.reason ? indexOf(reasons, packet.reason) : '' + , adv = packet.advice ? indexOf(advice, packet.advice) : ''; + + if (reason !== '' || adv !== '') + data = reason + (adv !== '' ? ('+' + adv) : ''); + + break; + + case 'message': + if (packet.data !== '') + data = packet.data; + break; + + case 'event': + var ev = { name: packet.name }; + + if (packet.args && packet.args.length) { + ev.args = packet.args; + } + + data = JSON.stringify(ev); + break; + + case 'json': + data = JSON.stringify(packet.data); + break; + + case 'connect': + if (packet.qs) + data = packet.qs; + break; + + case 'ack': + data = packet.ackId + + (packet.args && packet.args.length + ? '+' + JSON.stringify(packet.args) : ''); + break; + } + + // construct packet with required fragments + var encoded = [ + type + , id + (ack == 'data' ? '+' : '') + , endpoint + ]; + + // data fragment is optional + if (data !== null && data !== undefined) + encoded.push(data); + + return encoded.join(':'); + }; + + /** + * Encodes multiple messages (payload). + * + * @param {Array} messages + * @api private + */ + + parser.encodePayload = function (packets) { + var decoded = ''; + + if (packets.length == 1) + return packets[0]; + + for (var i = 0, l = packets.length; i < l; i++) { + var packet = packets[i]; + decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]; + } + + return decoded; + }; + + /** + * Decodes a packet + * + * @api private + */ + + var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/; + + parser.decodePacket = function (data) { + var pieces = data.match(regexp); + + if (!pieces) return {}; + + var id = pieces[2] || '' + , data = pieces[5] || '' + , packet = { + type: packets[pieces[1]] + , endpoint: pieces[4] || '' + }; + + // whether we need to acknowledge the packet + if (id) { + packet.id = id; + if (pieces[3]) + packet.ack = 'data'; + else + packet.ack = true; + } + + // handle different packet types + switch (packet.type) { + case 'error': + var pieces = data.split('+'); + packet.reason = reasons[pieces[0]] || ''; + packet.advice = advice[pieces[1]] || ''; + break; + + case 'message': + packet.data = data || ''; + break; + + case 'event': + try { + var opts = JSON.parse(data); + packet.name = opts.name; + packet.args = opts.args; + } catch (e) { } + + packet.args = packet.args || []; + break; + + case 'json': + try { + packet.data = JSON.parse(data); + } catch (e) { } + break; + + case 'connect': + packet.qs = data || ''; + break; + + case 'ack': + var pieces = data.match(/^([0-9]+)(\+)?(.*)/); + if (pieces) { + packet.ackId = pieces[1]; + packet.args = []; + + if (pieces[3]) { + try { + packet.args = pieces[3] ? JSON.parse(pieces[3]) : []; + } catch (e) { } + } + } + break; + + case 'disconnect': + case 'heartbeat': + break; + }; + + return packet; + }; + + /** + * Decodes data payload. Detects multiple messages + * + * @return {Array} messages + * @api public + */ + + parser.decodePayload = function (data) { + // IE doesn't like data[i] for unicode chars, charAt works fine + if (data.charAt(0) == '\ufffd') { + var ret = []; + + for (var i = 1, length = ''; i < data.length; i++) { + if (data.charAt(i) == '\ufffd') { + ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length))); + i += Number(length) + 1; + length = ''; + } else { + length += data.charAt(i); + } + } + + return ret; + } else { + return [parser.decodePacket(data)]; + } + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.Transport = Transport; + + /** + * This is the transport template for all supported transport methods. + * + * @constructor + * @api public + */ + + function Transport (socket, sessid) { + this.socket = socket; + this.sessid = sessid; + }; + + /** + * Apply EventEmitter mixin. + */ + + io.util.mixin(Transport, io.EventEmitter); + + /** + * Handles the response from the server. When a new response is received + * it will automatically update the timeout, decode the message and + * forwards the response to the onMessage function for further processing. + * + * @param {String} data Response from the server. + * @api private + */ + + Transport.prototype.onData = function (data) { + this.clearCloseTimeout(); + this.setCloseTimeout(); + + if (data !== '') { + // todo: we should only do decodePayload for xhr transports + var msgs = io.parser.decodePayload(data); + + if (msgs && msgs.length) { + for (var i = 0, l = msgs.length; i < l; i++) { + this.onPacket(msgs[i]); + } + } + } + + return this; + }; + + /** + * Handles packets. + * + * @api private + */ + + Transport.prototype.onPacket = function (packet) { + if (packet.type == 'heartbeat') { + return this.onHeartbeat(); + } + + if (packet.type == 'connect' && packet.endpoint == '') { + this.onConnect(); + } + + this.socket.onPacket(packet); + + return this; + }; + + /** + * Sets close timeout + * + * @api private + */ + + Transport.prototype.setCloseTimeout = function () { + if (!this.closeTimeout) { + var self = this; + + this.closeTimeout = setTimeout(function () { + self.onDisconnect(); + }, this.socket.closeTimeout); + } + }; + + /** + * Called when transport disconnects. + * + * @api private + */ + + Transport.prototype.onDisconnect = function () { + if (this.close) this.close(); + this.clearTimeouts(); + this.socket.onDisconnect(); + return this; + }; + + /** + * Called when transport connects + * + * @api private + */ + + Transport.prototype.onConnect = function () { + this.socket.onConnect(); + return this; + } + + /** + * Clears close timeout + * + * @api private + */ + + Transport.prototype.clearCloseTimeout = function () { + if (this.closeTimeout) { + clearTimeout(this.closeTimeout); + this.closeTimeout = null; + } + }; + + /** + * Clear timeouts + * + * @api private + */ + + Transport.prototype.clearTimeouts = function () { + this.clearCloseTimeout(); + + if (this.reopenTimeout) { + clearTimeout(this.reopenTimeout); + } + }; + + /** + * Sends a packet + * + * @param {Object} packet object. + * @api private + */ + + Transport.prototype.packet = function (packet) { + this.send(io.parser.encodePacket(packet)); + }; + + /** + * Send the received heartbeat message back to server. So the server + * knows we are still connected. + * + * @param {String} heartbeat Heartbeat response from the server. + * @api private + */ + + Transport.prototype.onHeartbeat = function (heartbeat) { + this.packet({ type: 'heartbeat' }); + }; + + /** + * Called when the transport opens. + * + * @api private + */ + + Transport.prototype.onOpen = function () { + this.open = true; + this.clearCloseTimeout(); + this.socket.onOpen(); + }; + + /** + * Notifies the base when the connection with the Socket.IO server + * has been disconnected. + * + * @api private + */ + + Transport.prototype.onClose = function () { + var self = this; + + /* FIXME: reopen delay causing a infinit loop + this.reopenTimeout = setTimeout(function () { + self.open(); + }, this.socket.options['reopen delay']);*/ + + this.open = false; + this.setCloseTimeout(); + this.socket.onClose(); + }; + + /** + * Generates a connection url based on the Socket.IO URL Protocol. + * See for more details. + * + * @returns {String} Connection url + * @api private + */ + + Transport.prototype.prepareUrl = function () { + var options = this.socket.options; + + return this.scheme() + '://' + + options.host + ':' + options.port + '/' + + options.resource + '/' + io.protocol + + '/' + this.name + '/' + this.sessid; + }; + + /** + * Checks if the transport is ready to start a connection. + * + * @param {Socket} socket The socket instance that needs a transport + * @param {Function} fn The callback + * @api private + */ + + Transport.prototype.ready = function (socket, fn) { + fn.call(this); + }; +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + */ + + exports.Socket = Socket; + + /** + * Create a new `Socket.IO client` which can establish a persistent + * connection with a Socket.IO enabled server. + * + * @api public + */ + + function Socket (options) { + this.options = { + port: 80 + , secure: false + , document: 'document' in global ? document : false + , resource: 'socket.io' + , transports: io.transports + , 'connect timeout': 10000 + , 'try multiple transports': true + , 'reconnect': true + , 'reconnection delay': 500 + , 'reconnection limit': Infinity + , 'reopen delay': 3000 + , 'max reconnection attempts': 10 + , 'sync disconnect on unload': true + , 'auto connect': true + }; + + io.util.merge(this.options, options); + + this.connected = false; + this.open = false; + this.connecting = false; + this.reconnecting = false; + this.namespaces = {}; + this.buffer = []; + this.doBuffer = false; + + if (this.options['sync disconnect on unload'] && + (!this.isXDomain() || io.util.ua.hasCORS)) { + var self = this; + + io.util.on(global, 'beforeunload', function () { + self.disconnectSync(); + }, false); + } + + if (this.options['auto connect']) { + this.connect(); + } +}; + + /** + * Apply EventEmitter mixin. + */ + + io.util.mixin(Socket, io.EventEmitter); + + /** + * Returns a namespace listener/emitter for this socket + * + * @api public + */ + + Socket.prototype.of = function (name) { + if (!this.namespaces[name]) { + this.namespaces[name] = new io.SocketNamespace(this, name); + + if (name !== '') { + this.namespaces[name].packet({ type: 'connect' }); + } + } + + return this.namespaces[name]; + }; + + /** + * Emits the given event to the Socket and all namespaces + * + * @api private + */ + + Socket.prototype.publish = function () { + this.emit.apply(this, arguments); + + var nsp; + + for (var i in this.namespaces) { + if (this.namespaces.hasOwnProperty(i)) { + nsp = this.of(i); + nsp.$emit.apply(nsp, arguments); + } + } + }; + + /** + * Performs the handshake + * + * @api private + */ + + function empty () { }; + + Socket.prototype.handshake = function (fn) { + var self = this + , options = this.options; + + function complete (data) { + if (data instanceof Error) { + self.onError(data.message); + } else { + fn.apply(null, data.split(':')); + } + }; + + var url = [ + 'http' + (options.secure ? 's' : '') + ':/' + , options.host + ':' + options.port + , this.options.resource + , io.protocol + , io.util.query(this.options.query, 't=' + +new Date) + ].join('/'); + + if (this.isXDomain()) { + var insertAt = document.getElementsByTagName('script')[0] + , script = document.createElement('SCRIPT'); + + script.src = url + '&jsonp=' + io.j.length; + insertAt.parentNode.insertBefore(script, insertAt); + + io.j.push(function (data) { + complete(data); + script.parentNode.removeChild(script); + }); + } else { + var xhr = io.util.request(); + + xhr.open('GET', url, true); + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + xhr.onreadystatechange = empty; + + if (xhr.status == 200) { + complete(xhr.responseText); + } else { + !self.reconnecting && self.onError(xhr.responseText); + } + } + }; + xhr.send(null); + } + }; + + /** + * Find an available transport based on the options supplied in the constructor. + * + * @api private + */ + + Socket.prototype.getTransport = function (override) { + var transports = override || this.transports, match; + + for (var i = 0, transport; transport = transports[i]; i++) { + if (io.Transport[transport] + && io.Transport[transport].check(this) + && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) { + return new io.Transport[transport](this, this.sessionid); + } + } + + return null; + }; + + /** + * Connects to the server. + * + * @param {Function} [fn] Callback. + * @returns {io.Socket} + * @api public + */ + + Socket.prototype.connect = function (fn) { + if (this.connecting) { + return this; + } + + var self = this; + + this.handshake(function (sid, heartbeat, close, transports) { + self.sessionid = sid; + self.closeTimeout = close * 1000; + self.heartbeatTimeout = heartbeat * 1000; + self.transports = io.util.intersect( + transports.split(',') + , self.options.transports + ); + + function connect (transports){ + self.transport = self.getTransport(transports); + if (!self.transport) return self.publish('connect_failed'); + + // once the transport is ready + self.transport.ready(self, function () { + self.connecting = true; + self.publish('connecting', self.transport.name); + self.transport.open(); + + if (self.options['connect timeout']) { + self.connectTimeoutTimer = setTimeout(function () { + if (!self.connected) { + self.connecting = false; + + if (self.options['try multiple transports']) { + if (!self.remainingTransports) { + self.remainingTransports = self.transports.slice(0); + } + + var remaining = self.remainingTransports; + + while (remaining.length > 0 && remaining.splice(0,1)[0] != + self.transport.name) {} + + if (remaining.length){ + connect(remaining); + } else { + self.publish('connect_failed'); + } + } + } + }, self.options['connect timeout']); + } + }); + } + + connect(); + + self.once('connect', function (){ + clearTimeout(self.connectTimeoutTimer); + + fn && typeof fn == 'function' && fn(); + }); + }); + + return this; + }; + + /** + * Sends a message. + * + * @param {Object} data packet. + * @returns {io.Socket} + * @api public + */ + + Socket.prototype.packet = function (data) { + if (this.connected && !this.doBuffer) { + this.transport.packet(data); + } else { + this.buffer.push(data); + } + + return this; + }; + + /** + * Sets buffer state + * + * @api private + */ + + Socket.prototype.setBuffer = function (v) { + this.doBuffer = v; + + if (!v && this.connected && this.buffer.length) { + this.transport.payload(this.buffer); + this.buffer = []; + } + }; + + /** + * Disconnect the established connect. + * + * @returns {io.Socket} + * @api public + */ + + Socket.prototype.disconnect = function () { + if (this.connected) { + if (this.open) { + this.of('').packet({ type: 'disconnect' }); + } + + // handle disconnection immediately + this.onDisconnect('booted'); + } + + return this; + }; + + /** + * Disconnects the socket with a sync XHR. + * + * @api private + */ + + Socket.prototype.disconnectSync = function () { + // ensure disconnection + var xhr = io.util.request() + , uri = this.resource + '/' + io.protocol + '/' + this.sessionid; + + xhr.open('GET', uri, true); + + // handle disconnection immediately + this.onDisconnect('booted'); + }; + + /** + * Check if we need to use cross domain enabled transports. Cross domain would + * be a different port or different domain name. + * + * @returns {Boolean} + * @api private + */ + + Socket.prototype.isXDomain = function () { + + var locPort = window.location.port || 80; + return this.options.host !== document.domain || this.options.port != locPort; + }; + + /** + * Called upon handshake. + * + * @api private + */ + + Socket.prototype.onConnect = function () { + if (!this.connected) { + this.connected = true; + this.connecting = false; + if (!this.doBuffer) { + // make sure to flush the buffer + this.setBuffer(false); + } + this.emit('connect'); + } + }; + + /** + * Called when the transport opens + * + * @api private + */ + + Socket.prototype.onOpen = function () { + this.open = true; + }; + + /** + * Called when the transport closes. + * + * @api private + */ + + Socket.prototype.onClose = function () { + this.open = false; + }; + + /** + * Called when the transport first opens a connection + * + * @param text + */ + + Socket.prototype.onPacket = function (packet) { + this.of(packet.endpoint).onPacket(packet); + }; + + /** + * Handles an error. + * + * @api private + */ + + Socket.prototype.onError = function (err) { + if (err && err.advice) { + if (err.advice === 'reconnect' && this.connected) { + this.disconnect(); + this.reconnect(); + } + } + + this.publish('error', err && err.reason ? err.reason : err); + }; + + /** + * Called when the transport disconnects. + * + * @api private + */ + + Socket.prototype.onDisconnect = function (reason) { + var wasConnected = this.connected; + + this.connected = false; + this.connecting = false; + this.open = false; + + if (wasConnected) { + this.transport.close(); + this.transport.clearTimeouts(); + this.publish('disconnect', reason); + + if ('booted' != reason && this.options.reconnect && !this.reconnecting) { + this.reconnect(); + } + } + }; + + /** + * Called upon reconnection. + * + * @api private + */ + + Socket.prototype.reconnect = function () { + this.reconnecting = true; + this.reconnectionAttempts = 0; + this.reconnectionDelay = this.options['reconnection delay']; + + var self = this + , maxAttempts = this.options['max reconnection attempts'] + , tryMultiple = this.options['try multiple transports'] + , limit = this.options['reconnection limit']; + + function reset () { + if (self.connected) { + for (var i in self.namespaces) { + if (self.namespaces.hasOwnProperty(i) && '' !== i) { + self.namespaces[i].packet({ type: 'connect' }); + } + } + self.publish('reconnect', self.transport.name, self.reconnectionAttempts); + } + + self.removeListener('connect_failed', maybeReconnect); + self.removeListener('connect', maybeReconnect); + + self.reconnecting = false; + + delete self.reconnectionAttempts; + delete self.reconnectionDelay; + delete self.reconnectionTimer; + delete self.redoTransports; + + self.options['try multiple transports'] = tryMultiple; + }; + + function maybeReconnect () { + if (!self.reconnecting) { + return; + } + + if (self.connected) { + return reset(); + }; + + if (self.connecting && self.reconnecting) { + return self.reconnectionTimer = setTimeout(maybeReconnect, 1000); + } + + if (self.reconnectionAttempts++ >= maxAttempts) { + if (!self.redoTransports) { + self.on('connect_failed', maybeReconnect); + self.options['try multiple transports'] = true; + self.transport = self.getTransport(); + self.redoTransports = true; + self.connect(); + } else { + self.publish('reconnect_failed'); + reset(); + } + } else { + if (self.reconnectionDelay < limit) { + self.reconnectionDelay *= 2; // exponential back off + } + + self.connect(); + self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts); + self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay); + } + }; + + this.options['try multiple transports'] = false; + this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay); + + this.on('connect', maybeReconnect); + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.SocketNamespace = SocketNamespace; + + /** + * Socket namespace constructor. + * + * @constructor + * @api public + */ + + function SocketNamespace (socket, name) { + this.socket = socket; + this.name = name || ''; + this.flags = {}; + this.json = new Flag(this, 'json'); + this.ackPackets = 0; + this.acks = {}; + }; + + /** + * Apply EventEmitter mixin. + */ + + io.util.mixin(SocketNamespace, io.EventEmitter); + + /** + * Copies emit since we override it + * + * @api private + */ + + SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit; + + /** + * Creates a new namespace, by proxying the request to the socket. This + * allows us to use the synax as we do on the server. + * + * @api public + */ + + SocketNamespace.prototype.of = function () { + return this.socket.of.apply(this.socket, arguments); + }; + + /** + * Sends a packet. + * + * @api private + */ + + SocketNamespace.prototype.packet = function (packet) { + packet.endpoint = this.name; + this.socket.packet(packet); + this.flags = {}; + return this; + }; + + /** + * Sends a message + * + * @api public + */ + + SocketNamespace.prototype.send = function (data, fn) { + var packet = { + type: this.flags.json ? 'json' : 'message' + , data: data + }; + + if ('function' == typeof fn) { + packet.id = ++this.ackPackets; + packet.ack = true; + this.acks[packet.id] = fn; + } + + return this.packet(packet); + }; + + /** + * Emits an event + * + * @api public + */ + + SocketNamespace.prototype.emit = function (name) { + var args = Array.prototype.slice.call(arguments, 1) + , lastArg = args[args.length - 1] + , packet = { + type: 'event' + , name: name + }; + + if ('function' == typeof lastArg) { + packet.id = ++this.ackPackets; + packet.ack = 'data'; + this.acks[packet.id] = lastArg; + args = args.slice(0, args.length - 1); + } + + packet.args = args; + + return this.packet(packet); + }; + + /** + * Disconnects the namespace + * + * @api private + */ + + SocketNamespace.prototype.disconnect = function () { + if (this.name === '') { + this.socket.disconnect(); + } else { + this.packet({ type: 'disconnect' }); + this.$emit('disconnect'); + } + + return this; + }; + + /** + * Handles a packet + * + * @api private + */ + + SocketNamespace.prototype.onPacket = function (packet) { + var self = this; + + function ack () { + self.packet({ + type: 'ack' + , args: io.util.toArray(arguments) + , ackId: packet.id + }); + }; + + switch (packet.type) { + case 'connect': + this.$emit('connect'); + break; + + case 'disconnect': + if (this.name === '') { + this.socket.onDisconnect(packet.reason || 'booted'); + } else { + this.$emit('disconnect', packet.reason); + } + break; + + case 'message': + case 'json': + var params = ['message', packet.data]; + + if (packet.ack == 'data') { + params.push(ack); + } else if (packet.ack) { + this.packet({ type: 'ack', ackId: packet.id }); + } + + this.$emit.apply(this, params); + break; + + case 'event': + var params = [packet.name].concat(packet.args); + + if (packet.ack == 'data') + params.push(ack); + + this.$emit.apply(this, params); + break; + + case 'ack': + if (this.acks[packet.ackId]) { + this.acks[packet.ackId].apply(this, packet.args); + delete this.acks[packet.ackId]; + } + break; + + case 'error': + if (packet.advice){ + this.socket.onError(packet); + } else { + if (packet.reason == 'unauthorized') { + this.$emit('connect_failed', packet.reason); + } else { + this.$emit('error', packet.reason); + } + } + break; + } + }; + + /** + * Flag interface. + * + * @api private + */ + + function Flag (nsp, name) { + this.namespace = nsp; + this.name = name; + }; + + /** + * Send a message + * + * @api public + */ + + Flag.prototype.send = function () { + this.namespace.flags[this.name] = true; + this.namespace.send.apply(this.namespace, arguments); + }; + + /** + * Emit an event + * + * @api public + */ + + Flag.prototype.emit = function () { + this.namespace.flags[this.name] = true; + this.namespace.emit.apply(this.namespace, arguments); + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.websocket = WS; + + /** + * The WebSocket transport uses the HTML5 WebSocket API to establish an + * persistent connection with the Socket.IO server. This transport will also + * be inherited by the FlashSocket fallback as it provides a API compatible + * polyfill for the WebSockets. + * + * @constructor + * @extends {io.Transport} + * @api public + */ + + function WS (socket) { + io.Transport.apply(this, arguments); + }; + + /** + * Inherits from Transport. + */ + + io.util.inherit(WS, io.Transport); + + /** + * Transport name + * + * @api public + */ + + WS.prototype.name = 'websocket'; + + /** + * Initializes a new `WebSocket` connection with the Socket.IO server. We attach + * all the appropriate listeners to handle the responses from the server. + * + * @returns {Transport} + * @api public + */ + + WS.prototype.open = function () { + var self = this + , query = io.util.query(this.socket.options.query); + + this.websocket = new WebSocket(this.prepareUrl() + query); + + var self = this; + this.websocket.onopen = function () { + self.onOpen(); + self.socket.setBuffer(false); + }; + this.websocket.onmessage = function (ev) { + self.onData(ev.data); + }; + this.websocket.onclose = function () { + self.onClose(); + self.socket.setBuffer(true); + }; + this.websocket.onerror = function (e) { + self.onError(e); + }; + + return this; + }; + + /** + * Send a message to the Socket.IO server. The message will automatically be + * encoded in the correct message format. + * + * @returns {Transport} + * @api public + */ + + WS.prototype.send = function (data) { + this.websocket.send(data); + return this; + }; + + /** + * Payload + * + * @api private + */ + + WS.prototype.payload = function (arr) { + for (var i = 0, l = arr.length; i < l; i++) { + this.packet(arr[i]); + } + return this; + }; + + /** + * Disconnect the established `WebSocket` connection. + * + * @returns {Transport} + * @api public + */ + + WS.prototype.close = function () { + this.websocket.close(); + return this; + }; + + /** + * Handle the errors that `WebSocket` might be giving when we + * are attempting to connect or send messages. + * + * @param {Error} e The error. + * @api private + */ + + WS.prototype.onError = function (e) { + this.socket.onError(e); + }; + + /** + * Returns the appropriate scheme for the URI generation. + * + * @api private + */ + WS.prototype.scheme = function () { + return this.socket.options.secure ? 'wss' : 'ws'; + }; + + /** + * Checks if the browser has support for native `WebSockets` and that + * it's not the polyfill created for the FlashSocket transport. + * + * @return {Boolean} + * @api public + */ + + WS.check = function () { + return 'WebSocket' in window && !('__addTask' in WebSocket); + }; + + /** + * Check if the `WebSocket` transport support cross domain communications. + * + * @returns {Boolean} + * @api public + */ + + WS.xdomainCheck = function () { + return true; + }; + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('websocket'); + + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.flashsocket = Flashsocket; + + /** + * The FlashSocket transport. This is a API wrapper for the HTML5 WebSocket + * specification. It uses a .swf file to communicate with the server. If you want + * to serve the .swf file from a other server than where the Socket.IO script is + * coming from you need to use the insecure version of the .swf. More information + * about this can be found on the github page. + * + * @constructor + * @extends {io.Transport.websocket} + * @api public + */ + + function Flashsocket () { + io.Transport.websocket.apply(this, arguments); + }; + + /** + * Inherits from Transport. + */ + + io.util.inherit(Flashsocket, io.Transport.websocket); + + /** + * Transport name + * + * @api public + */ + + Flashsocket.prototype.name = 'flashsocket'; + + /** + *Disconnect the established `FlashSocket` connection. This is done by adding a + * new task to the FlashSocket. The rest will be handled off by the `WebSocket` + * transport. + * + * @returns {Transport} + * @api public + */ + + Flashsocket.prototype.open = function () { + var self = this + , args = arguments; + + WebSocket.__addTask(function () { + io.Transport.websocket.prototype.open.apply(self, args); + }); + return this; + }; + + /** + * Sends a message to the Socket.IO server. This is done by adding a new + * task to the FlashSocket. The rest will be handled off by the `WebSocket` + * transport. + * + * @returns {Transport} + * @api public + */ + + Flashsocket.prototype.send = function () { + var self = this, args = arguments; + WebSocket.__addTask(function () { + io.Transport.websocket.prototype.send.apply(self, args); + }); + return this; + }; + + /** + * Disconnects the established `FlashSocket` connection. + * + * @returns {Transport} + * @api public + */ + + Flashsocket.prototype.close = function () { + WebSocket.__tasks.length = 0; + io.Transport.websocket.prototype.close.call(this); + return this; + }; + + /** + * The WebSocket fall back needs to append the flash container to the body + * element, so we need to make sure we have access to it. Or defer the call + * until we are sure there is a body element. + * + * @param {Socket} socket The socket instance that needs a transport + * @param {Function} fn The callback + * @api private + */ + + Flashsocket.prototype.ready = function (socket, fn) { + function init () { + var options = socket.options + , path = [ + 'http' + (options.secure ? 's' : '') + ':/' + , options.host + ':' + options.port + , options.resource + , 'static/flashsocket' + , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf' + ]; + + // Only start downloading the swf file when the checked that this browser + // actually supports it + if (!Flashsocket.loaded) { + if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') { + // Set the correct file based on the XDomain settings + WEB_SOCKET_SWF_LOCATION = path.join('/'); + } + + WebSocket.__initialize(); + Flashsocket.loaded = true; + } + + fn.call(self); + } + + var self = this; + if (document.body) return init(); + + io.util.load(init); + }; + + /** + * Check if the FlashSocket transport is supported as it requires that the Adobe + * Flash Player plug-in version `10.0.0` or greater is installed. And also check if + * the polyfill is correctly loaded. + * + * @returns {Boolean} + * @api public + */ + + Flashsocket.check = function () { + if ( + typeof WebSocket == 'undefined' + || !('__initialize' in WebSocket) || !swfobject + ) return false; + + return swfobject.getFlashPlayerVersion().major >= 1; + }; + + /** + * Check if the FlashSocket transport can be used as cross domain / cross origin + * transport. Because we can't see which type (secure or insecure) of .swf is used + * we will just return true. + * + * @returns {Boolean} + * @api public + */ + + Flashsocket.xdomainCheck = function () { + return true; + }; + + /** + * Disable AUTO_INITIALIZATION + */ + + if (typeof window != 'undefined') { + WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true; + } + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('flashsocket'); +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); +/* SWFObject v2.2 + is released under the MIT License +*/ +var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab +// License: New BSD License +// Reference: http://dev.w3.org/html5/websockets/ +// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol + +(function() { + + if (window.WebSocket) return; + + var console = window.console; + if (!console || !console.log || !console.error) { + console = {log: function(){ }, error: function(){ }}; + } + + if (!swfobject.hasFlashPlayerVersion("10.0.0")) { + console.error("Flash Player >= 10.0.0 is required."); + return; + } + if (location.protocol == "file:") { + console.error( + "WARNING: web-socket-js doesn't work in file:///... URL " + + "unless you set Flash Security Settings properly. " + + "Open the page via Web server i.e. http://..."); + } + + /** + * This class represents a faux web socket. + * @param {string} url + * @param {array or string} protocols + * @param {string} proxyHost + * @param {int} proxyPort + * @param {string} headers + */ + WebSocket = function(url, protocols, proxyHost, proxyPort, headers) { + var self = this; + self.__id = WebSocket.__nextId++; + WebSocket.__instances[self.__id] = self; + self.readyState = WebSocket.CONNECTING; + self.bufferedAmount = 0; + self.__events = {}; + if (!protocols) { + protocols = []; + } else if (typeof protocols == "string") { + protocols = [protocols]; + } + // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc. + // Otherwise, when onopen fires immediately, onopen is called before it is set. + setTimeout(function() { + WebSocket.__addTask(function() { + WebSocket.__flash.create( + self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null); + }); + }, 0); + }; + + /** + * Send data to the web socket. + * @param {string} data The data to send to the socket. + * @return {boolean} True for success, false for failure. + */ + WebSocket.prototype.send = function(data) { + if (this.readyState == WebSocket.CONNECTING) { + throw "INVALID_STATE_ERR: Web Socket connection has not been established"; + } + // We use encodeURIComponent() here, because FABridge doesn't work if + // the argument includes some characters. We don't use escape() here + // because of this: + // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions + // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't + // preserve all Unicode characters either e.g. "\uffff" in Firefox. + // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require + // additional testing. + var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data)); + if (result < 0) { // success + return true; + } else { + this.bufferedAmount += result; + return false; + } + }; + + /** + * Close this web socket gracefully. + */ + WebSocket.prototype.close = function() { + if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) { + return; + } + this.readyState = WebSocket.CLOSING; + WebSocket.__flash.close(this.__id); + }; + + /** + * Implementation of {@link DOM 2 EventTarget Interface} + * + * @param {string} type + * @param {function} listener + * @param {boolean} useCapture + * @return void + */ + WebSocket.prototype.addEventListener = function(type, listener, useCapture) { + if (!(type in this.__events)) { + this.__events[type] = []; + } + this.__events[type].push(listener); + }; + + /** + * Implementation of {@link DOM 2 EventTarget Interface} + * + * @param {string} type + * @param {function} listener + * @param {boolean} useCapture + * @return void + */ + WebSocket.prototype.removeEventListener = function(type, listener, useCapture) { + if (!(type in this.__events)) return; + var events = this.__events[type]; + for (var i = events.length - 1; i >= 0; --i) { + if (events[i] === listener) { + events.splice(i, 1); + break; + } + } + }; + + /** + * Implementation of {@link DOM 2 EventTarget Interface} + * + * @param {Event} event + * @return void + */ + WebSocket.prototype.dispatchEvent = function(event) { + var events = this.__events[event.type] || []; + for (var i = 0; i < events.length; ++i) { + events[i](event); + } + var handler = this["on" + event.type]; + if (handler) handler(event); + }; + + /** + * Handles an event from Flash. + * @param {Object} flashEvent + */ + WebSocket.prototype.__handleEvent = function(flashEvent) { + if ("readyState" in flashEvent) { + this.readyState = flashEvent.readyState; + } + if ("protocol" in flashEvent) { + this.protocol = flashEvent.protocol; + } + + var jsEvent; + if (flashEvent.type == "open" || flashEvent.type == "error") { + jsEvent = this.__createSimpleEvent(flashEvent.type); + } else if (flashEvent.type == "close") { + // TODO implement jsEvent.wasClean + jsEvent = this.__createSimpleEvent("close"); + } else if (flashEvent.type == "message") { + var data = decodeURIComponent(flashEvent.message); + jsEvent = this.__createMessageEvent("message", data); + } else { + throw "unknown event type: " + flashEvent.type; + } + + this.dispatchEvent(jsEvent); + }; + + WebSocket.prototype.__createSimpleEvent = function(type) { + if (document.createEvent && window.Event) { + var event = document.createEvent("Event"); + event.initEvent(type, false, false); + return event; + } else { + return {type: type, bubbles: false, cancelable: false}; + } + }; + + WebSocket.prototype.__createMessageEvent = function(type, data) { + if (document.createEvent && window.MessageEvent && !window.opera) { + var event = document.createEvent("MessageEvent"); + event.initMessageEvent("message", false, false, data, null, null, window, null); + return event; + } else { + // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes. + return {type: type, data: data, bubbles: false, cancelable: false}; + } + }; + + /** + * Define the WebSocket readyState enumeration. + */ + WebSocket.CONNECTING = 0; + WebSocket.OPEN = 1; + WebSocket.CLOSING = 2; + WebSocket.CLOSED = 3; + + WebSocket.__flash = null; + WebSocket.__instances = {}; + WebSocket.__tasks = []; + WebSocket.__nextId = 0; + + /** + * Load a new flash security policy file. + * @param {string} url + */ + WebSocket.loadFlashPolicyFile = function(url){ + WebSocket.__addTask(function() { + WebSocket.__flash.loadManualPolicyFile(url); + }); + }; + + /** + * Loads WebSocketMain.swf and creates WebSocketMain object in Flash. + */ + WebSocket.__initialize = function() { + if (WebSocket.__flash) return; + + if (WebSocket.__swfLocation) { + // For backword compatibility. + window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation; + } + if (!window.WEB_SOCKET_SWF_LOCATION) { + console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf"); + return; + } + var container = document.createElement("div"); + container.id = "webSocketContainer"; + // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents + // Flash from loading at least in IE. So we move it out of the screen at (-100, -100). + // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash + // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is + // the best we can do as far as we know now. + container.style.position = "absolute"; + if (WebSocket.__isFlashLite()) { + container.style.left = "0px"; + container.style.top = "0px"; + } else { + container.style.left = "-100px"; + container.style.top = "-100px"; + } + var holder = document.createElement("div"); + holder.id = "webSocketFlash"; + container.appendChild(holder); + document.body.appendChild(container); + // See this article for hasPriority: + // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html + swfobject.embedSWF( + WEB_SOCKET_SWF_LOCATION, + "webSocketFlash", + "1" /* width */, + "1" /* height */, + "10.0.0" /* SWF version */, + null, + null, + {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"}, + null, + function(e) { + if (!e.success) { + console.error("[WebSocket] swfobject.embedSWF failed"); + } + }); + }; + + /** + * Called by Flash to notify JS that it's fully loaded and ready + * for communication. + */ + WebSocket.__onFlashInitialized = function() { + // We need to set a timeout here to avoid round-trip calls + // to flash during the initialization process. + setTimeout(function() { + WebSocket.__flash = document.getElementById("webSocketFlash"); + WebSocket.__flash.setCallerUrl(location.href); + WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG); + for (var i = 0; i < WebSocket.__tasks.length; ++i) { + WebSocket.__tasks[i](); + } + WebSocket.__tasks = []; + }, 0); + }; + + /** + * Called by Flash to notify WebSockets events are fired. + */ + WebSocket.__onFlashEvent = function() { + setTimeout(function() { + try { + // Gets events using receiveEvents() instead of getting it from event object + // of Flash event. This is to make sure to keep message order. + // It seems sometimes Flash events don't arrive in the same order as they are sent. + var events = WebSocket.__flash.receiveEvents(); + for (var i = 0; i < events.length; ++i) { + WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]); + } + } catch (e) { + console.error(e); + } + }, 0); + return true; + }; + + // Called by Flash. + WebSocket.__log = function(message) { + console.log(decodeURIComponent(message)); + }; + + // Called by Flash. + WebSocket.__error = function(message) { + console.error(decodeURIComponent(message)); + }; + + WebSocket.__addTask = function(task) { + if (WebSocket.__flash) { + task(); + } else { + WebSocket.__tasks.push(task); + } + }; + + /** + * Test if the browser is running flash lite. + * @return {boolean} True if flash lite is running, false otherwise. + */ + WebSocket.__isFlashLite = function() { + if (!window.navigator || !window.navigator.mimeTypes) { + return false; + } + var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"]; + if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) { + return false; + } + return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false; + }; + + if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) { + if (window.addEventListener) { + window.addEventListener("load", function(){ + WebSocket.__initialize(); + }, false); + } else { + window.attachEvent("onload", function(){ + WebSocket.__initialize(); + }); + } + } + +})(); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + * + * @api public + */ + + exports.XHR = XHR; + + /** + * XHR constructor + * + * @costructor + * @api public + */ + + function XHR (socket) { + if (!socket) return; + + io.Transport.apply(this, arguments); + this.sendBuffer = []; + }; + + /** + * Inherits from Transport. + */ + + io.util.inherit(XHR, io.Transport); + + /** + * Establish a connection + * + * @returns {Transport} + * @api public + */ + + XHR.prototype.open = function () { + this.socket.setBuffer(false); + this.onOpen(); + this.get(); + + // we need to make sure the request succeeds since we have no indication + // whether the request opened or not until it succeeded. + this.setCloseTimeout(); + + return this; + }; + + /** + * Check if we need to send data to the Socket.IO server, if we have data in our + * buffer we encode it and forward it to the `post` method. + * + * @api private + */ + + XHR.prototype.payload = function (payload) { + var msgs = []; + + for (var i = 0, l = payload.length; i < l; i++) { + msgs.push(io.parser.encodePacket(payload[i])); + } + + this.send(io.parser.encodePayload(msgs)); + }; + + /** + * Send data to the Socket.IO server. + * + * @param data The message + * @returns {Transport} + * @api public + */ + + XHR.prototype.send = function (data) { + this.post(data); + return this; + }; + + /** + * Posts a encoded message to the Socket.IO server. + * + * @param {String} data A encoded message. + * @api private + */ + + function empty () { }; + + XHR.prototype.post = function (data) { + var self = this; + this.socket.setBuffer(true); + + function stateChange () { + if (this.readyState == 4) { + this.onreadystatechange = empty; + self.posting = false; + + if (this.status == 200){ + self.socket.setBuffer(false); + } else { + self.onClose(); + } + } + } + + function onload () { + this.onload = empty; + self.socket.setBuffer(false); + }; + + this.sendXHR = this.request('POST'); + + if (global.XDomainRequest && this.sendXHR instanceof XDomainRequest) { + this.sendXHR.onload = this.sendXHR.onerror = onload; + } else { + this.sendXHR.onreadystatechange = stateChange; + } + + this.sendXHR.send(data); + }; + + /** + * Disconnects the established `XHR` connection. + * + * @returns {Transport} + * @api public + */ + + XHR.prototype.close = function () { + this.onClose(); + return this; + }; + + /** + * Generates a configured XHR request + * + * @param {String} url The url that needs to be requested. + * @param {String} method The method the request should use. + * @returns {XMLHttpRequest} + * @api private + */ + + XHR.prototype.request = function (method) { + var req = io.util.request(this.socket.isXDomain()) + , query = io.util.query(this.socket.options.query, 't=' + +new Date); + + req.open(method || 'GET', this.prepareUrl() + query, true); + + if (method == 'POST') { + try { + if (req.setRequestHeader) { + req.setRequestHeader('Content-type', 'text/plain;charset=UTF-8'); + } else { + // XDomainRequest + req.contentType = 'text/plain'; + } + } catch (e) {} + } + + return req; + }; + + /** + * Returns the scheme to use for the transport URLs. + * + * @api private + */ + + XHR.prototype.scheme = function () { + return this.socket.options.secure ? 'https' : 'http'; + }; + + /** + * Check if the XHR transports are supported + * + * @param {Boolean} xdomain Check if we support cross domain requests. + * @returns {Boolean} + * @api public + */ + + XHR.check = function (socket, xdomain) { + try { + if (io.util.request(xdomain)) { + return true; + } + } catch(e) {} + + return false; + }; + + /** + * Check if the XHR transport supports corss domain requests. + * + * @returns {Boolean} + * @api public + */ + + XHR.xdomainCheck = function () { + return XHR.check(null, true); + }; + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.htmlfile = HTMLFile; + + /** + * The HTMLFile transport creates a `forever iframe` based transport + * for Internet Explorer. Regular forever iframe implementations will + * continuously trigger the browsers buzy indicators. If the forever iframe + * is created inside a `htmlfile` these indicators will not be trigged. + * + * @constructor + * @extends {io.Transport.XHR} + * @api public + */ + + function HTMLFile (socket) { + io.Transport.XHR.apply(this, arguments); + }; + + /** + * Inherits from XHR transport. + */ + + io.util.inherit(HTMLFile, io.Transport.XHR); + + /** + * Transport name + * + * @api public + */ + + HTMLFile.prototype.name = 'htmlfile'; + + /** + * Creates a new ActiveX `htmlfile` with a forever loading iframe + * that can be used to listen to messages. Inside the generated + * `htmlfile` a reference will be made to the HTMLFile transport. + * + * @api private + */ + + HTMLFile.prototype.get = function () { + this.doc = new ActiveXObject('htmlfile'); + this.doc.open(); + this.doc.write(''); + this.doc.close(); + this.doc.parentWindow.s = this; + + var iframeC = this.doc.createElement('div'); + iframeC.className = 'socketio'; + + this.doc.body.appendChild(iframeC); + this.iframe = this.doc.createElement('iframe'); + + iframeC.appendChild(this.iframe); + + var self = this + , query = io.util.query(this.socket.options.query, 't='+ +new Date); + + this.iframe.src = this.prepareUrl() + query; + + io.util.on(window, 'unload', function () { + self.destroy(); + }); + }; + + /** + * The Socket.IO server will write script tags inside the forever + * iframe, this function will be used as callback for the incoming + * information. + * + * @param {String} data The message + * @param {document} doc Reference to the context + * @api private + */ + + HTMLFile.prototype._ = function (data, doc) { + this.onData(data); + try { + var script = doc.getElementsByTagName('script')[0]; + script.parentNode.removeChild(script); + } catch (e) { } + }; + + /** + * Destroy the established connection, iframe and `htmlfile`. + * And calls the `CollectGarbage` function of Internet Explorer + * to release the memory. + * + * @api private + */ + + HTMLFile.prototype.destroy = function () { + if (this.iframe){ + try { + this.iframe.src = 'about:blank'; + } catch(e){} + + this.doc = null; + this.iframe.parentNode.removeChild(this.iframe); + this.iframe = null; + + CollectGarbage(); + } + }; + + /** + * Disconnects the established connection. + * + * @returns {Transport} Chaining. + * @api public + */ + + HTMLFile.prototype.close = function () { + this.destroy(); + return io.Transport.XHR.prototype.close.call(this); + }; + + /** + * Checks if the browser supports this transport. The browser + * must have an `ActiveXObject` implementation. + * + * @return {Boolean} + * @api public + */ + + HTMLFile.check = function () { + if ('ActiveXObject' in window){ + try { + var a = new ActiveXObject('htmlfile'); + return a && io.Transport.XHR.check(); + } catch(e){} + } + return false; + }; + + /** + * Check if cross domain requests are supported. + * + * @returns {Boolean} + * @api public + */ + + HTMLFile.xdomainCheck = function () { + // we can probably do handling for sub-domains, we should + // test that it's cross domain but a subdomain here + return false; + }; + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('htmlfile'); + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + */ + + exports['xhr-polling'] = XHRPolling; + + /** + * The XHR-polling transport uses long polling XHR requests to create a + * "persistent" connection with the server. + * + * @constructor + * @api public + */ + + function XHRPolling () { + io.Transport.XHR.apply(this, arguments); + }; + + /** + * Inherits from XHR transport. + */ + + io.util.inherit(XHRPolling, io.Transport.XHR); + + /** + * Merge the properties from XHR transport + */ + + io.util.merge(XHRPolling, io.Transport.XHR); + + /** + * Transport name + * + * @api public + */ + + XHRPolling.prototype.name = 'xhr-polling'; + + /** + * Establish a connection, for iPhone and Android this will be done once the page + * is loaded. + * + * @returns {Transport} Chaining. + * @api public + */ + + XHRPolling.prototype.open = function () { + var self = this; + + io.Transport.XHR.prototype.open.call(self); + return false; + }; + + /** + * Starts a XHR request to wait for incoming messages. + * + * @api private + */ + + function empty () {}; + + XHRPolling.prototype.get = function () { + if (!this.open) return; + + var self = this; + + function stateChange () { + if (this.readyState == 4) { + this.onreadystatechange = empty; + + if (this.status == 200) { + self.onData(this.responseText); + self.get(); + } else { + self.onClose(); + } + } + }; + + function onload () { + this.onload = empty; + self.onData(this.responseText); + self.get(); + }; + + this.xhr = this.request(); + + if (global.XDomainRequest && this.xhr instanceof XDomainRequest) { + this.xhr.onload = this.xhr.onerror = onload; + } else { + this.xhr.onreadystatechange = stateChange; + } + + this.xhr.send(null); + }; + + /** + * Handle the unclean close behavior. + * + * @api private + */ + + XHRPolling.prototype.onClose = function () { + io.Transport.XHR.prototype.onClose.call(this); + + if (this.xhr) { + this.xhr.onreadystatechange = this.xhr.onload = empty; + try { + this.xhr.abort(); + } catch(e){} + this.xhr = null; + } + }; + + /** + * Webkit based browsers show a infinit spinner when you start a XHR request + * before the browsers onload event is called so we need to defer opening of + * the transport until the onload event is called. Wrapping the cb in our + * defer method solve this. + * + * @param {Socket} socket The socket instance that needs a transport + * @param {Function} fn The callback + * @api private + */ + + XHRPolling.prototype.ready = function (socket, fn) { + var self = this; + + io.util.defer(function () { + fn.call(self); + }); + }; + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('xhr-polling'); + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports['jsonp-polling'] = JSONPPolling; + + /** + * The JSONP transport creates an persistent connection by dynamically + * inserting a script tag in the page. This script tag will receive the + * information of the Socket.IO server. When new information is received + * it creates a new script tag for the new data stream. + * + * @constructor + * @extends {io.Transport.xhr-polling} + * @api public + */ + + function JSONPPolling (socket) { + io.Transport['xhr-polling'].apply(this, arguments); + + this.index = io.j.length; + + var self = this; + + io.j.push(function (msg) { + self._(msg); + }); + }; + + /** + * Inherits from XHR polling transport. + */ + + io.util.inherit(JSONPPolling, io.Transport['xhr-polling']); + + /** + * Transport name + * + * @api public + */ + + JSONPPolling.prototype.name = 'jsonp-polling'; + + /** + * Posts a encoded message to the Socket.IO server using an iframe. + * The iframe is used because script tags can create POST based requests. + * The iframe is positioned outside of the view so the user does not + * notice it's existence. + * + * @param {String} data A encoded message. + * @api private + */ + + JSONPPolling.prototype.post = function (data) { + var self = this + , query = io.util.query( + this.socket.options.query + , 't='+ (+new Date) + '&i=' + this.index + ); + + if (!this.form) { + var form = document.createElement('FORM') + , area = document.createElement('TEXTAREA') + , id = this.iframeId = 'socketio_iframe_' + this.index + , iframe; + + form.className = 'socketio'; + form.style.position = 'absolute'; + form.style.top = '-1000px'; + form.style.left = '-1000px'; + form.target = id; + form.method = 'POST'; + form.setAttribute('accept-charset', 'utf-8'); + area.name = 'd'; + form.appendChild(area); + document.body.appendChild(form); + + this.form = form; + this.area = area; + } + + this.form.action = this.prepareUrl() + query; + + function complete () { + initIframe(); + self.socket.setBuffer(false); + }; + + function initIframe () { + if (self.iframe) { + self.form.removeChild(self.iframe); + } + + try { + // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) + iframe = document.createElement('